forked from Minki/linux
drm-misc-next for 4.17:
Cross-subsystem Changes: - Backlight helpers to enable/disable and find devices in dt (Meghana) Core Changes: - Documentation improvements (Chris/Daniel/Jani) - simple_kms_helper: Add mode_valid() support (Linus) - mm: Fix bug in interval_tree causing nodes to be out-of-order (Chris) Driver Changes: - tinydrm/panel: Use the new backlight helpers (Meghana) - rockchip: Support gem_prime_import_sg_table + some fixes (Various) - sun4i: Add A83T HDMI support using dw-hdmi (Jernej) Cc: Meghana Madhyastha <meghana.madhyastha@gmail.com> Cc: Jani Nikula <jani.nikula@intel.com> Cc: Daniel Vetter <daniel.vetter@ffwll.ch> Cc: Chris Wilson <chris@chris-wilson.co.uk> Cc: Linus Walleij <linus.walleij@linaro.org> Cc: Heiko Stuebner <heiko@sntech.de> Cc: Jernej Skrabec <jernej.skrabec@siol.net> -----BEGIN PGP SIGNATURE----- iQEzBAABCAAdFiEEfxcpfMSgdnQMs+QqlvcN/ahKBwoFAlqN15UACgkQlvcN/ahK BwrQZwf/UMzK235ccIKn5OQRd2t4bi8aTTqa1Rfh0+t6Vw6gJvNG6aIuj4Nb5SUd 9PNJJOX3ENBuTEiQiuENF0oXBGU3bsZNb5TcasEg9ShhD6b59gS9k1HI+Qwzr4uB xHL85yVPaOP2vNCywwDoWhPjNMySv0PDScEVVLK2CTqpllZuB0FzEOOUknRk7Phn 1jeVeAe0sfx27EJSOtandNewa3JvAtSRAjeFQ3EBfbc43opi1LxURnOig8Gz3csf b7x46lYtweZ9NH0Ybg584nLppAdG6hUnb7VPsAJK+KiR5Bn57J6et1g7WEzaRhSI hO6B5AcMspsFRMkWcyPiIEdqv9mVkQ== =kZmv -----END PGP SIGNATURE----- Merge tag 'drm-misc-next-2018-02-21' of git://anongit.freedesktop.org/drm/drm-misc into drm-next drm-misc-next for 4.17: Cross-subsystem Changes: - Backlight helpers to enable/disable and find devices in dt (Meghana) Core Changes: - Documentation improvements (Chris/Daniel/Jani) - simple_kms_helper: Add mode_valid() support (Linus) - mm: Fix bug in interval_tree causing nodes to be out-of-order (Chris) Driver Changes: - tinydrm/panel: Use the new backlight helpers (Meghana) - rockchip: Support gem_prime_import_sg_table + some fixes (Various) - sun4i: Add A83T HDMI support using dw-hdmi (Jernej) Cc: Meghana Madhyastha <meghana.madhyastha@gmail.com> Cc: Jani Nikula <jani.nikula@intel.com> Cc: Daniel Vetter <daniel.vetter@ffwll.ch> Cc: Chris Wilson <chris@chris-wilson.co.uk> Cc: Linus Walleij <linus.walleij@linaro.org> Cc: Heiko Stuebner <heiko@sntech.de> Cc: Jernej Skrabec <jernej.skrabec@siol.net> * tag 'drm-misc-next-2018-02-21' of git://anongit.freedesktop.org/drm/drm-misc: (41 commits) drm/omapdrm: Use of_find_backlight helper drm/panel: Use of_find_backlight helper drm/omapdrm: Use backlight_enable/disable helpers drm/panel: Use backlight_enable/disable helpers drm/tinydrm: Call devres version of of_find_backlight drm/tinydrm: Replace tinydrm_of_find_backlight with of_find_backlight drm/tinydrm: Convert tinydrm_enable/disable_backlight to backlight_enable/disable drm: add documentation for tv connector state margins drm/doc: Use new substruct support drm/doc: Polish for drm_mode_parse_command_line_for_connector drm/docs: Document "scaling mode" property better drm/docs: Align layout of optional plane blending properties drm/docs: Discourage adding more to kms-properties.csv drm: simple_kms_helper: Add mode_valid() callback support drm/todo: Add idr_init_base todo drm: Use idr_init_base(1) when using id==0 for invalid drm: NULL pointer dereference [null-pointer-deref] (CWE 476) problem drm: NULL pointer dereference [null-pointer-deref] (CWE 476) problem dma-buf/sw_sync: Fix kerneldoc warnings drm: Fix kerneldoc warnings for drm_lease ...
This commit is contained in:
commit
727edc7440
@ -0,0 +1,74 @@
|
||||
Rockchip RK3399 specific extensions to the cdn Display Port
|
||||
================================
|
||||
|
||||
Required properties:
|
||||
- compatible: must be "rockchip,rk3399-cdn-dp"
|
||||
|
||||
- reg: physical base address of the controller and length
|
||||
|
||||
- clocks: from common clock binding: handle to dp clock.
|
||||
|
||||
- clock-names: from common clock binding:
|
||||
Required elements: "core-clk" "pclk" "spdif" "grf"
|
||||
|
||||
- resets : a list of phandle + reset specifier pairs
|
||||
- reset-names : string of reset names
|
||||
Required elements: "apb", "core", "dptx", "spdif"
|
||||
- power-domains : power-domain property defined with a phandle
|
||||
to respective power domain.
|
||||
- assigned-clocks: main clock, should be <&cru SCLK_DP_CORE>
|
||||
- assigned-clock-rates : the DP core clk frequency, shall be: 100000000
|
||||
|
||||
- rockchip,grf: this soc should set GRF regs, so need get grf here.
|
||||
|
||||
- ports: contain a port nodes with endpoint definitions as defined in
|
||||
Documentation/devicetree/bindings/media/video-interfaces.txt.
|
||||
contained 2 endpoints, connecting to the output of vop.
|
||||
|
||||
- phys: from general PHY binding: the phandle for the PHY device.
|
||||
|
||||
- extcon: extcon specifier for the Power Delivery
|
||||
|
||||
- #sound-dai-cells = it must be 1 if your system is using 2 DAIs: I2S, SPDIF
|
||||
|
||||
-------------------------------------------------------------------------------
|
||||
|
||||
Example:
|
||||
cdn_dp: dp@fec00000 {
|
||||
compatible = "rockchip,rk3399-cdn-dp";
|
||||
reg = <0x0 0xfec00000 0x0 0x100000>;
|
||||
interrupts = <GIC_SPI 9 IRQ_TYPE_LEVEL_HIGH>;
|
||||
clocks = <&cru SCLK_DP_CORE>, <&cru PCLK_DP_CTRL>,
|
||||
<&cru SCLK_SPDIF_REC_DPTX>, <&cru PCLK_VIO_GRF>;
|
||||
clock-names = "core-clk", "pclk", "spdif", "grf";
|
||||
assigned-clocks = <&cru SCLK_DP_CORE>;
|
||||
assigned-clock-rates = <100000000>;
|
||||
power-domains = <&power RK3399_PD_HDCP>;
|
||||
phys = <&tcphy0_dp>, <&tcphy1_dp>;
|
||||
resets = <&cru SRST_DPTX_SPDIF_REC>;
|
||||
reset-names = "spdif";
|
||||
extcon = <&fusb0>, <&fusb1>;
|
||||
rockchip,grf = <&grf>;
|
||||
#address-cells = <1>;
|
||||
#size-cells = <0>;
|
||||
#sound-dai-cells = <1>;
|
||||
|
||||
ports {
|
||||
#address-cells = <1>;
|
||||
#size-cells = <0>;
|
||||
|
||||
dp_in: port {
|
||||
#address-cells = <1>;
|
||||
#size-cells = <0>;
|
||||
dp_in_vopb: endpoint@0 {
|
||||
reg = <0>;
|
||||
remote-endpoint = <&vopb_out_dp>;
|
||||
};
|
||||
|
||||
dp_in_vopl: endpoint@1 {
|
||||
reg = <1>;
|
||||
remote-endpoint = <&vopl_out_dp>;
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
@ -64,6 +64,52 @@ Required properties:
|
||||
first port should be the input endpoint. The second should be the
|
||||
output, usually to an HDMI connector.
|
||||
|
||||
DWC HDMI TX Encoder
|
||||
-------------------
|
||||
|
||||
The HDMI transmitter is a Synopsys DesignWare HDMI 1.4 TX controller IP
|
||||
with Allwinner's own PHY IP. It supports audio and video outputs and CEC.
|
||||
|
||||
These DT bindings follow the Synopsys DWC HDMI TX bindings defined in
|
||||
Documentation/devicetree/bindings/display/bridge/dw_hdmi.txt with the
|
||||
following device-specific properties.
|
||||
|
||||
Required properties:
|
||||
|
||||
- compatible: value must be one of:
|
||||
* "allwinner,sun8i-a83t-dw-hdmi"
|
||||
- reg: base address and size of memory-mapped region
|
||||
- reg-io-width: See dw_hdmi.txt. Shall be 1.
|
||||
- interrupts: HDMI interrupt number
|
||||
- clocks: phandles to the clocks feeding the HDMI encoder
|
||||
* iahb: the HDMI bus clock
|
||||
* isfr: the HDMI register clock
|
||||
* tmds: TMDS clock
|
||||
- clock-names: the clock names mentioned above
|
||||
- resets: phandle to the reset controller
|
||||
- reset-names: must be "ctrl"
|
||||
- phys: phandle to the DWC HDMI PHY
|
||||
- phy-names: must be "phy"
|
||||
|
||||
- ports: A ports node with endpoint definitions as defined in
|
||||
Documentation/devicetree/bindings/media/video-interfaces.txt. The
|
||||
first port should be the input endpoint. The second should be the
|
||||
output, usually to an HDMI connector.
|
||||
|
||||
DWC HDMI PHY
|
||||
------------
|
||||
|
||||
Required properties:
|
||||
- compatible: value must be one of:
|
||||
* allwinner,sun8i-a83t-hdmi-phy
|
||||
- reg: base address and size of memory-mapped region
|
||||
- clocks: phandles to the clocks feeding the HDMI PHY
|
||||
* bus: the HDMI PHY interface clock
|
||||
* mod: the HDMI PHY module clock
|
||||
- clock-names: the clock names mentioned above
|
||||
- resets: phandle to the reset controller driving the PHY
|
||||
- reset-names: must be "phy"
|
||||
|
||||
TV Encoder
|
||||
----------
|
||||
|
||||
@ -94,24 +140,26 @@ Required properties:
|
||||
* allwinner,sun7i-a20-tcon
|
||||
* allwinner,sun8i-a33-tcon
|
||||
* allwinner,sun8i-a83t-tcon-lcd
|
||||
* allwinner,sun8i-a83t-tcon-tv
|
||||
* allwinner,sun8i-v3s-tcon
|
||||
- reg: base address and size of memory-mapped region
|
||||
- interrupts: interrupt associated to this IP
|
||||
- clocks: phandles to the clocks feeding the TCON. Three are needed:
|
||||
- clocks: phandles to the clocks feeding the TCON.
|
||||
- 'ahb': the interface clocks
|
||||
- 'tcon-ch0': The clock driving the TCON channel 0
|
||||
- 'tcon-ch0': The clock driving the TCON channel 0, except for A83T TV TCON
|
||||
- resets: phandles to the reset controllers driving the encoder
|
||||
- "lcd": the reset line for the TCON channel 0
|
||||
|
||||
- clock-names: the clock names mentioned above
|
||||
- reset-names: the reset names mentioned above
|
||||
- clock-output-names: Name of the pixel clock created
|
||||
- clock-output-names: Name of the pixel clock created, if TCON supports
|
||||
channel 0.
|
||||
|
||||
- ports: A ports node with endpoint definitions as defined in
|
||||
Documentation/devicetree/bindings/media/video-interfaces.txt. The
|
||||
first port should be the input endpoint, the second one the output
|
||||
|
||||
The output may have multiple endpoints. The TCON has two channels,
|
||||
The output may have multiple endpoints. TCON can have 1 or 2 channels,
|
||||
usually with the first channel being used for the panels interfaces
|
||||
(RGB, LVDS, etc.), and the second being used for the outputs that
|
||||
require another controller (TV Encoder, HDMI, etc.). The endpoints
|
||||
@ -122,8 +170,8 @@ Required properties:
|
||||
On SoCs other than the A33 and V3s, there is one more clock required:
|
||||
- 'tcon-ch1': The clock driving the TCON channel 1
|
||||
|
||||
On SoCs that support LVDS (all SoCs but the A13, H3, H5 and V3s), you
|
||||
need one more reset line:
|
||||
When TCON support LVDS (all TCONs except TV TCON on A83T and those found
|
||||
in A13, H3, H5 and V3s SoCs), you need one more reset line:
|
||||
- 'lvds': The reset line driving the LVDS logic
|
||||
|
||||
And on the A23, A31, A31s and A33, you need one more clock line:
|
||||
@ -226,6 +274,7 @@ supported.
|
||||
Required properties:
|
||||
- compatible: value must be one of:
|
||||
* allwinner,sun8i-a83t-de2-mixer-0
|
||||
* allwinner,sun8i-a83t-de2-mixer-1
|
||||
* allwinner,sun8i-v3s-de2-mixer
|
||||
- reg: base address and size of the memory-mapped region.
|
||||
- clocks: phandles to the clocks feeding the mixer
|
||||
|
@ -547,8 +547,9 @@ Explicit Fencing Properties
|
||||
Existing KMS Properties
|
||||
-----------------------
|
||||
|
||||
The following table gives description of drm properties exposed by
|
||||
various modules/drivers.
|
||||
The following table gives description of drm properties exposed by various
|
||||
modules/drivers. Because this table is very unwieldy, do not add any new
|
||||
properties here. Instead document them in a section above.
|
||||
|
||||
.. csv-table::
|
||||
:header-rows: 1
|
||||
|
@ -1,5 +1,4 @@
|
||||
Owner Module/Drivers,Group,Property Name,Type,Property Values,Object attached,Description/Restrictions
|
||||
,,“scaling mode”,ENUM,"{ ""None"", ""Full"", ""Center"", ""Full aspect"" }",Connector,"Supported by: amdgpu, gma500, i915, nouveau and radeon."
|
||||
,DVI-I,“subconnector”,ENUM,"{ “Unknown”, “DVI-D”, “DVI-A” }",Connector,TBD
|
||||
,,“select subconnector”,ENUM,"{ “Automatic”, “DVI-D”, “DVI-A” }",Connector,TBD
|
||||
,TV,“subconnector”,ENUM,"{ ""Unknown"", ""Composite"", ""SVIDEO"", ""Component"", ""SCART"" }",Connector,TBD
|
||||
|
|
@ -212,6 +212,16 @@ probably use drm_fb_helper_fbdev_teardown().
|
||||
|
||||
Contact: Maintainer of the driver you plan to convert
|
||||
|
||||
idr_init_base()
|
||||
---------------
|
||||
|
||||
DRM core&drivers uses a lot of idr (integer lookup directories) for mapping
|
||||
userspace IDs to internal objects, and in most places ID=0 means NULL and hence
|
||||
is never used. Switching to idr_init_base() for these would make the idr more
|
||||
efficient.
|
||||
|
||||
Contact: Daniel Vetter
|
||||
|
||||
Core refactorings
|
||||
=================
|
||||
|
||||
|
@ -235,10 +235,10 @@ static void sync_timeline_signal(struct sync_timeline *obj, unsigned int inc)
|
||||
|
||||
/**
|
||||
* sync_pt_create() - creates a sync pt
|
||||
* @parent: fence's parent sync_timeline
|
||||
* @inc: value of the fence
|
||||
* @obj: parent sync_timeline
|
||||
* @value: value of the fence
|
||||
*
|
||||
* Creates a new sync_pt as a child of @parent. @size bytes will be
|
||||
* Creates a new sync_pt (fence) as a child of @parent. @size bytes will be
|
||||
* allocated allowing for implementation specific data to be kept after
|
||||
* the generic sync_timeline struct. Returns the sync_pt object or
|
||||
* NULL in case of error.
|
||||
|
@ -194,7 +194,7 @@ static struct ttm_tt *bochs_ttm_tt_create(struct ttm_bo_device *bdev,
|
||||
return tt;
|
||||
}
|
||||
|
||||
struct ttm_bo_driver bochs_bo_driver = {
|
||||
static struct ttm_bo_driver bochs_bo_driver = {
|
||||
.ttm_tt_create = bochs_ttm_tt_create,
|
||||
.ttm_tt_populate = ttm_pool_populate,
|
||||
.ttm_tt_unpopulate = ttm_pool_unpopulate,
|
||||
|
@ -1037,19 +1037,21 @@ static void dw_hdmi_phy_enable_svsret(struct dw_hdmi *hdmi, u8 enable)
|
||||
HDMI_PHY_CONF0_SVSRET_MASK);
|
||||
}
|
||||
|
||||
static void dw_hdmi_phy_gen2_pddq(struct dw_hdmi *hdmi, u8 enable)
|
||||
void dw_hdmi_phy_gen2_pddq(struct dw_hdmi *hdmi, u8 enable)
|
||||
{
|
||||
hdmi_mask_writeb(hdmi, enable, HDMI_PHY_CONF0,
|
||||
HDMI_PHY_CONF0_GEN2_PDDQ_OFFSET,
|
||||
HDMI_PHY_CONF0_GEN2_PDDQ_MASK);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(dw_hdmi_phy_gen2_pddq);
|
||||
|
||||
static void dw_hdmi_phy_gen2_txpwron(struct dw_hdmi *hdmi, u8 enable)
|
||||
void dw_hdmi_phy_gen2_txpwron(struct dw_hdmi *hdmi, u8 enable)
|
||||
{
|
||||
hdmi_mask_writeb(hdmi, enable, HDMI_PHY_CONF0,
|
||||
HDMI_PHY_CONF0_GEN2_TXPWRON_OFFSET,
|
||||
HDMI_PHY_CONF0_GEN2_TXPWRON_MASK);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(dw_hdmi_phy_gen2_txpwron);
|
||||
|
||||
static void dw_hdmi_phy_sel_data_en_pol(struct dw_hdmi *hdmi, u8 enable)
|
||||
{
|
||||
@ -1065,6 +1067,22 @@ static void dw_hdmi_phy_sel_interface_control(struct dw_hdmi *hdmi, u8 enable)
|
||||
HDMI_PHY_CONF0_SELDIPIF_MASK);
|
||||
}
|
||||
|
||||
void dw_hdmi_phy_reset(struct dw_hdmi *hdmi)
|
||||
{
|
||||
/* 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);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(dw_hdmi_phy_reset);
|
||||
|
||||
void dw_hdmi_phy_i2c_set_addr(struct dw_hdmi *hdmi, u8 address)
|
||||
{
|
||||
hdmi_phy_test_clear(hdmi, 1);
|
||||
hdmi_writeb(hdmi, address, HDMI_PHY_I2CM_SLAVE_ADDR);
|
||||
hdmi_phy_test_clear(hdmi, 0);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(dw_hdmi_phy_i2c_set_addr);
|
||||
|
||||
static void dw_hdmi_phy_power_off(struct dw_hdmi *hdmi)
|
||||
{
|
||||
const struct dw_hdmi_phy_data *phy = hdmi->phy.data;
|
||||
@ -1203,16 +1221,11 @@ static int hdmi_phy_configure(struct dw_hdmi *hdmi)
|
||||
if (phy->has_svsret)
|
||||
dw_hdmi_phy_enable_svsret(hdmi, 1);
|
||||
|
||||
/* PHY reset. The reset signal is active high on Gen2 PHYs. */
|
||||
hdmi_writeb(hdmi, HDMI_MC_PHYRSTZ_PHYRSTZ, HDMI_MC_PHYRSTZ);
|
||||
hdmi_writeb(hdmi, 0, HDMI_MC_PHYRSTZ);
|
||||
dw_hdmi_phy_reset(hdmi);
|
||||
|
||||
hdmi_writeb(hdmi, HDMI_MC_HEACPHY_RST_ASSERT, HDMI_MC_HEACPHY_RST);
|
||||
|
||||
hdmi_phy_test_clear(hdmi, 1);
|
||||
hdmi_writeb(hdmi, HDMI_PHY_I2CM_SLAVE_ADDR_PHY_GEN2,
|
||||
HDMI_PHY_I2CM_SLAVE_ADDR);
|
||||
hdmi_phy_test_clear(hdmi, 0);
|
||||
dw_hdmi_phy_i2c_set_addr(hdmi, HDMI_PHY_I2CM_SLAVE_ADDR_PHY_GEN2);
|
||||
|
||||
/* Write to the PHY as configured by the platform */
|
||||
if (pdata->configure_phy)
|
||||
@ -1251,15 +1264,16 @@ static void dw_hdmi_phy_disable(struct dw_hdmi *hdmi, void *data)
|
||||
dw_hdmi_phy_power_off(hdmi);
|
||||
}
|
||||
|
||||
static enum drm_connector_status dw_hdmi_phy_read_hpd(struct dw_hdmi *hdmi,
|
||||
void *data)
|
||||
enum drm_connector_status dw_hdmi_phy_read_hpd(struct dw_hdmi *hdmi,
|
||||
void *data)
|
||||
{
|
||||
return hdmi_readb(hdmi, HDMI_PHY_STAT0) & HDMI_PHY_HPD ?
|
||||
connector_status_connected : connector_status_disconnected;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(dw_hdmi_phy_read_hpd);
|
||||
|
||||
static void dw_hdmi_phy_update_hpd(struct dw_hdmi *hdmi, void *data,
|
||||
bool force, bool disabled, bool rxsense)
|
||||
void dw_hdmi_phy_update_hpd(struct dw_hdmi *hdmi, void *data,
|
||||
bool force, bool disabled, bool rxsense)
|
||||
{
|
||||
u8 old_mask = hdmi->phy_mask;
|
||||
|
||||
@ -1271,8 +1285,9 @@ static void dw_hdmi_phy_update_hpd(struct dw_hdmi *hdmi, void *data,
|
||||
if (old_mask != hdmi->phy_mask)
|
||||
hdmi_writeb(hdmi, hdmi->phy_mask, HDMI_PHY_MASK0);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(dw_hdmi_phy_update_hpd);
|
||||
|
||||
static void dw_hdmi_phy_setup_hpd(struct dw_hdmi *hdmi, void *data)
|
||||
void dw_hdmi_phy_setup_hpd(struct dw_hdmi *hdmi, void *data)
|
||||
{
|
||||
/*
|
||||
* Configure the PHY RX SENSE and HPD interrupts polarities and clear
|
||||
@ -1291,6 +1306,7 @@ static void dw_hdmi_phy_setup_hpd(struct dw_hdmi *hdmi, void *data)
|
||||
hdmi_writeb(hdmi, ~(HDMI_IH_PHY_STAT0_HPD | HDMI_IH_PHY_STAT0_RX_SENSE),
|
||||
HDMI_IH_MUTE_PHY_STAT0);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(dw_hdmi_phy_setup_hpd);
|
||||
|
||||
static const struct dw_hdmi_phy_ops dw_hdmi_synopsys_phy_ops = {
|
||||
.init = dw_hdmi_phy_init,
|
||||
@ -1634,9 +1650,10 @@ static void dw_hdmi_clear_overflow(struct dw_hdmi *hdmi)
|
||||
* 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.
|
||||
* (and possibly on the platform). So far i.MX6Q (v1.30a), i.MX6DL
|
||||
* (v1.31a) and multiple Allwinner SoCs (v1.32a) have been identified
|
||||
* as needing the workaround, with 4 iterations for v1.30a and 1
|
||||
* iteration for others.
|
||||
*/
|
||||
|
||||
switch (hdmi->version) {
|
||||
@ -1644,6 +1661,7 @@ static void dw_hdmi_clear_overflow(struct dw_hdmi *hdmi)
|
||||
count = 4;
|
||||
break;
|
||||
case 0x131a:
|
||||
case 0x132a:
|
||||
count = 1;
|
||||
break;
|
||||
default:
|
||||
@ -2525,8 +2543,6 @@ __dw_hdmi_probe(struct platform_device *pdev,
|
||||
if (hdmi->i2c)
|
||||
dw_hdmi_i2c_init(hdmi);
|
||||
|
||||
platform_set_drvdata(pdev, hdmi);
|
||||
|
||||
return hdmi;
|
||||
|
||||
err_iahb:
|
||||
@ -2576,25 +2592,23 @@ static void __dw_hdmi_remove(struct dw_hdmi *hdmi)
|
||||
/* -----------------------------------------------------------------------------
|
||||
* 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 *dw_hdmi_probe(struct platform_device *pdev,
|
||||
const struct dw_hdmi_plat_data *plat_data)
|
||||
{
|
||||
struct dw_hdmi *hdmi;
|
||||
|
||||
hdmi = __dw_hdmi_probe(pdev, plat_data);
|
||||
if (IS_ERR(hdmi))
|
||||
return PTR_ERR(hdmi);
|
||||
return hdmi;
|
||||
|
||||
drm_bridge_add(&hdmi->bridge);
|
||||
|
||||
return 0;
|
||||
return hdmi;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(dw_hdmi_probe);
|
||||
|
||||
void dw_hdmi_remove(struct platform_device *pdev)
|
||||
void dw_hdmi_remove(struct dw_hdmi *hdmi)
|
||||
{
|
||||
struct dw_hdmi *hdmi = platform_get_drvdata(pdev);
|
||||
|
||||
drm_bridge_remove(&hdmi->bridge);
|
||||
|
||||
__dw_hdmi_remove(hdmi);
|
||||
@ -2604,31 +2618,30 @@ 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 *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);
|
||||
return hdmi;
|
||||
|
||||
ret = drm_bridge_attach(encoder, &hdmi->bridge, NULL);
|
||||
if (ret) {
|
||||
dw_hdmi_remove(pdev);
|
||||
dw_hdmi_remove(hdmi);
|
||||
DRM_ERROR("Failed to initialize bridge with drm\n");
|
||||
return ret;
|
||||
return ERR_PTR(ret);
|
||||
}
|
||||
|
||||
return 0;
|
||||
return hdmi;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(dw_hdmi_bind);
|
||||
|
||||
void dw_hdmi_unbind(struct device *dev)
|
||||
void dw_hdmi_unbind(struct dw_hdmi *hdmi)
|
||||
{
|
||||
struct dw_hdmi *hdmi = dev_get_drvdata(dev);
|
||||
|
||||
__dw_hdmi_remove(hdmi);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(dw_hdmi_unbind);
|
||||
|
@ -88,15 +88,17 @@
|
||||
* On top of this basic transformation additional properties can be exposed by
|
||||
* the driver:
|
||||
*
|
||||
* - Rotation is set up with drm_plane_create_rotation_property(). It adds a
|
||||
* rotation and reflection step between the source and destination rectangles.
|
||||
* Without this property the rectangle is only scaled, but not rotated or
|
||||
* reflected.
|
||||
* rotation:
|
||||
* Rotation is set up with drm_plane_create_rotation_property(). It adds a
|
||||
* rotation and reflection step between the source and destination rectangles.
|
||||
* Without this property the rectangle is only scaled, but not rotated or
|
||||
* reflected.
|
||||
*
|
||||
* - Z position is set up with drm_plane_create_zpos_immutable_property() and
|
||||
* drm_plane_create_zpos_property(). It controls the visibility of overlapping
|
||||
* planes. Without this property the primary plane is always below the cursor
|
||||
* plane, and ordering between all other planes is undefined.
|
||||
* zpos:
|
||||
* Z position is set up with drm_plane_create_zpos_immutable_property() and
|
||||
* drm_plane_create_zpos_property(). It controls the visibility of overlapping
|
||||
* planes. Without this property the primary plane is always below the cursor
|
||||
* plane, and ordering between all other planes is undefined.
|
||||
*
|
||||
* Note that all the property extensions described here apply either to the
|
||||
* plane or the CRTC (e.g. for the background color, which currently is not
|
||||
|
@ -849,13 +849,13 @@ DRM_ENUM_NAME_FN(drm_get_content_protection_name, drm_cp_enum_list)
|
||||
*
|
||||
* The value of this property can be one of the following:
|
||||
*
|
||||
* - DRM_MODE_CONTENT_PROTECTION_UNDESIRED = 0
|
||||
* DRM_MODE_CONTENT_PROTECTION_UNDESIRED = 0
|
||||
* The link is not protected, content is transmitted in the clear.
|
||||
* - DRM_MODE_CONTENT_PROTECTION_DESIRED = 1
|
||||
* DRM_MODE_CONTENT_PROTECTION_DESIRED = 1
|
||||
* Userspace has requested content protection, but the link is not
|
||||
* currently protected. When in this state, kernel should enable
|
||||
* Content Protection as soon as possible.
|
||||
* - DRM_MODE_CONTENT_PROTECTION_ENABLED = 2
|
||||
* DRM_MODE_CONTENT_PROTECTION_ENABLED = 2
|
||||
* Userspace has requested content protection, and the link is
|
||||
* protected. Only the driver can set the property to this value.
|
||||
* If userspace attempts to set to ENABLED, kernel will return
|
||||
@ -889,7 +889,31 @@ DRM_ENUM_NAME_FN(drm_get_content_protection_name, drm_cp_enum_list)
|
||||
* INPUT_PROP_DIRECT) will still map 1:1 to the actual LCD panel
|
||||
* coordinates, so if userspace rotates the picture to adjust for
|
||||
* the orientation it must also apply the same transformation to the
|
||||
* touchscreen input coordinates.
|
||||
* touchscreen input coordinates. This property is initialized by calling
|
||||
* drm_connector_init_panel_orientation_property().
|
||||
*
|
||||
* scaling mode:
|
||||
* This property defines how a non-native mode is upscaled to the native
|
||||
* mode of an LCD panel:
|
||||
*
|
||||
* None:
|
||||
* No upscaling happens, scaling is left to the panel. Not all
|
||||
* drivers expose this mode.
|
||||
* Full:
|
||||
* The output is upscaled to the full resolution of the panel,
|
||||
* ignoring the aspect ratio.
|
||||
* Center:
|
||||
* No upscaling happens, the output is centered within the native
|
||||
* resolution the panel.
|
||||
* Full aspect:
|
||||
* The output is upscaled to maximize either the width or height
|
||||
* while retaining the aspect ratio.
|
||||
*
|
||||
* This property should be set up by calling
|
||||
* drm_connector_attach_scaling_mode_property(). Note that drivers
|
||||
* can also expose this property to external outputs, in which case they
|
||||
* must support "None", which should be the default (since external screens
|
||||
* have a built-in scaler).
|
||||
*/
|
||||
|
||||
int drm_connector_create_standard_properties(struct drm_device *dev)
|
||||
|
@ -1082,10 +1082,12 @@ static bool drm_dp_port_setup_pdt(struct drm_dp_mst_port *port)
|
||||
lct = drm_dp_calculate_rad(port, rad);
|
||||
|
||||
port->mstb = drm_dp_add_mst_branch_device(lct, rad);
|
||||
port->mstb->mgr = port->mgr;
|
||||
port->mstb->port_parent = port;
|
||||
if (port->mstb) {
|
||||
port->mstb->mgr = port->mgr;
|
||||
port->mstb->port_parent = port;
|
||||
|
||||
send_link = true;
|
||||
send_link = true;
|
||||
}
|
||||
break;
|
||||
}
|
||||
return send_link;
|
||||
|
@ -2083,6 +2083,8 @@ drm_mode_std(struct drm_connector *connector, struct edid *edid,
|
||||
if (hsize == 1366 && vsize == 768 && vrefresh_rate == 60) {
|
||||
mode = drm_cvt_mode(dev, 1366, 768, vrefresh_rate, 0, 0,
|
||||
false);
|
||||
if (!mode)
|
||||
return NULL;
|
||||
mode->hdisplay = 1366;
|
||||
mode->hsync_start = mode->hsync_start - 1;
|
||||
mode->hsync_end = mode->hsync_end - 1;
|
||||
|
@ -98,7 +98,7 @@ drm_gem_init(struct drm_device *dev)
|
||||
struct drm_vma_offset_manager *vma_offset_manager;
|
||||
|
||||
mutex_init(&dev->object_name_lock);
|
||||
idr_init(&dev->object_name_idr);
|
||||
idr_init_base(&dev->object_name_idr, 1);
|
||||
|
||||
vma_offset_manager = kzalloc(sizeof(*vma_offset_manager), GFP_KERNEL);
|
||||
if (!vma_offset_manager) {
|
||||
@ -776,7 +776,7 @@ drm_gem_open_ioctl(struct drm_device *dev, void *data,
|
||||
void
|
||||
drm_gem_open(struct drm_device *dev, struct drm_file *file_private)
|
||||
{
|
||||
idr_init(&file_private->object_idr);
|
||||
idr_init_base(&file_private->object_idr, 1);
|
||||
spin_lock_init(&file_private->table_lock);
|
||||
}
|
||||
|
||||
|
@ -44,7 +44,7 @@ EXPORT_SYMBOL(drm_lease_owner);
|
||||
/**
|
||||
* _drm_find_lessee - find lessee by id (idr_mutex held)
|
||||
* @master: drm_master of lessor
|
||||
* @id: lessee_id
|
||||
* @lessee_id: id
|
||||
*
|
||||
* RETURN:
|
||||
*
|
||||
@ -101,7 +101,7 @@ static bool _drm_has_leased(struct drm_master *master, int id)
|
||||
|
||||
/**
|
||||
* _drm_lease_held - check drm_mode_object lease status (idr_mutex held)
|
||||
* @master: the drm_master
|
||||
* @file_priv: the master drm_file
|
||||
* @id: the object id
|
||||
*
|
||||
* Checks if the specified master holds a lease on the object. Return
|
||||
@ -121,7 +121,7 @@ EXPORT_SYMBOL(_drm_lease_held);
|
||||
|
||||
/**
|
||||
* drm_lease_held - check drm_mode_object lease status (idr_mutex not held)
|
||||
* @master: the drm_master
|
||||
* @file_priv: the master drm_file
|
||||
* @id: the object id
|
||||
*
|
||||
* Checks if the specified master holds a lease on the object. Return
|
||||
@ -149,7 +149,7 @@ EXPORT_SYMBOL(drm_lease_held);
|
||||
/**
|
||||
* drm_lease_filter_crtcs - restricted crtc set to leased values (idr_mutex not held)
|
||||
* @file_priv: requestor file
|
||||
* @crtcs: bitmask of crtcs to check
|
||||
* @crtcs_in: bitmask of crtcs to check
|
||||
*
|
||||
* Reconstructs a crtc mask based on the crtcs which are visible
|
||||
* through the specified file.
|
||||
@ -305,7 +305,7 @@ void drm_lease_destroy(struct drm_master *master)
|
||||
|
||||
/**
|
||||
* _drm_lease_revoke - revoke access to all leased objects (idr_mutex held)
|
||||
* @master: the master losing its lease
|
||||
* @top: the master losing its lease
|
||||
*/
|
||||
static void _drm_lease_revoke(struct drm_master *top)
|
||||
{
|
||||
@ -482,7 +482,7 @@ out_free_objects:
|
||||
* drm_mode_create_lease_ioctl - create a new lease
|
||||
* @dev: the drm device
|
||||
* @data: pointer to struct drm_mode_create_lease
|
||||
* @file_priv: the file being manipulated
|
||||
* @lessor_priv: the file being manipulated
|
||||
*
|
||||
* The master associated with the specified file will have a lease
|
||||
* created containing the objects specified in the ioctl structure.
|
||||
@ -662,7 +662,7 @@ int drm_mode_list_lessees_ioctl(struct drm_device *dev,
|
||||
* drm_mode_get_lease_ioctl - list leased objects
|
||||
* @dev: the drm device
|
||||
* @data: pointer to struct drm_mode_get_lease
|
||||
* @file_priv: the file being manipulated
|
||||
* @lessee_priv: the file being manipulated
|
||||
*
|
||||
* Return the list of leased objects for the specified lessee
|
||||
*/
|
||||
@ -722,7 +722,7 @@ int drm_mode_get_lease_ioctl(struct drm_device *dev,
|
||||
* drm_mode_revoke_lease_ioctl - revoke lease
|
||||
* @dev: the drm device
|
||||
* @data: pointer to struct drm_mode_revoke_lease
|
||||
* @file_priv: the file being manipulated
|
||||
* @lessor_priv: the file being manipulated
|
||||
*
|
||||
* This removes all of the objects from the lease without
|
||||
* actually getting rid of the lease itself; that way all
|
||||
|
@ -1346,9 +1346,9 @@ EXPORT_SYMBOL(drm_mode_connector_list_update);
|
||||
* modeline in fb_mode_option will be parsed instead.
|
||||
*
|
||||
* This uses the same parameters as the fb modedb.c, except for an extra
|
||||
* force-enable, force-enable-digital and force-disable bit at the end:
|
||||
* force-enable, force-enable-digital and force-disable bit at the end::
|
||||
*
|
||||
* <xres>x<yres>[M][R][-<bpp>][@<refresh>][i][m][eDd]
|
||||
* <xres>x<yres>[M][R][-<bpp>][@<refresh>][i][m][eDd]
|
||||
*
|
||||
* The intermediate drm_cmdline_mode structure is required to store additional
|
||||
* options from the command line modline like the force-enable/disable flag.
|
||||
|
@ -34,6 +34,20 @@ static const struct drm_encoder_funcs drm_simple_kms_encoder_funcs = {
|
||||
.destroy = drm_encoder_cleanup,
|
||||
};
|
||||
|
||||
static enum drm_mode_status
|
||||
drm_simple_kms_crtc_mode_valid(struct drm_crtc *crtc,
|
||||
const struct drm_display_mode *mode)
|
||||
{
|
||||
struct drm_simple_display_pipe *pipe;
|
||||
|
||||
pipe = container_of(crtc, struct drm_simple_display_pipe, crtc);
|
||||
if (!pipe->funcs || !pipe->funcs->mode_valid)
|
||||
/* Anything goes */
|
||||
return MODE_OK;
|
||||
|
||||
return pipe->funcs->mode_valid(crtc, mode);
|
||||
}
|
||||
|
||||
static int drm_simple_kms_crtc_check(struct drm_crtc *crtc,
|
||||
struct drm_crtc_state *state)
|
||||
{
|
||||
@ -72,6 +86,7 @@ static void drm_simple_kms_crtc_disable(struct drm_crtc *crtc,
|
||||
}
|
||||
|
||||
static const struct drm_crtc_helper_funcs drm_simple_kms_crtc_helper_funcs = {
|
||||
.mode_valid = drm_simple_kms_crtc_mode_valid,
|
||||
.atomic_check = drm_simple_kms_crtc_check,
|
||||
.atomic_enable = drm_simple_kms_crtc_enable,
|
||||
.atomic_disable = drm_simple_kms_crtc_disable,
|
||||
|
@ -546,7 +546,7 @@ err_put_fd:
|
||||
void
|
||||
drm_syncobj_open(struct drm_file *file_private)
|
||||
{
|
||||
idr_init(&file_private->syncobj_idr);
|
||||
idr_init_base(&file_private->syncobj_idr, 1);
|
||||
spin_lock_init(&file_private->syncobj_table_lock);
|
||||
}
|
||||
|
||||
|
@ -25,6 +25,7 @@
|
||||
struct imx_hdmi {
|
||||
struct device *dev;
|
||||
struct drm_encoder encoder;
|
||||
struct dw_hdmi *hdmi;
|
||||
struct regmap *regmap;
|
||||
};
|
||||
|
||||
@ -239,14 +240,18 @@ static int dw_hdmi_imx_bind(struct device *dev, struct device *master,
|
||||
drm_encoder_init(drm, encoder, &dw_hdmi_imx_encoder_funcs,
|
||||
DRM_MODE_ENCODER_TMDS, NULL);
|
||||
|
||||
ret = dw_hdmi_bind(pdev, encoder, plat_data);
|
||||
platform_set_drvdata(pdev, hdmi);
|
||||
|
||||
hdmi->hdmi = dw_hdmi_bind(pdev, encoder, plat_data);
|
||||
|
||||
/*
|
||||
* If dw_hdmi_bind() fails we'll never call dw_hdmi_unbind(),
|
||||
* which would have called the encoder cleanup. Do it manually.
|
||||
*/
|
||||
if (ret)
|
||||
if (IS_ERR(hdmi->hdmi)) {
|
||||
ret = PTR_ERR(hdmi->hdmi);
|
||||
drm_encoder_cleanup(encoder);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
@ -254,7 +259,9 @@ static int dw_hdmi_imx_bind(struct device *dev, struct device *master,
|
||||
static void dw_hdmi_imx_unbind(struct device *dev, struct device *master,
|
||||
void *data)
|
||||
{
|
||||
return dw_hdmi_unbind(dev);
|
||||
struct imx_hdmi *hdmi = dev_get_drvdata(dev);
|
||||
|
||||
dw_hdmi_unbind(hdmi->hdmi);
|
||||
}
|
||||
|
||||
static const struct component_ops dw_hdmi_imx_ops = {
|
||||
|
@ -140,6 +140,7 @@ struct meson_dw_hdmi {
|
||||
struct clk *venci_clk;
|
||||
struct regulator *hdmi_supply;
|
||||
u32 irq_stat;
|
||||
struct dw_hdmi *hdmi;
|
||||
};
|
||||
#define encoder_to_meson_dw_hdmi(x) \
|
||||
container_of(x, struct meson_dw_hdmi, encoder)
|
||||
@ -302,7 +303,7 @@ static void meson_hdmi_phy_setup_mode(struct meson_dw_hdmi *dw_hdmi,
|
||||
}
|
||||
}
|
||||
|
||||
static inline void dw_hdmi_phy_reset(struct meson_dw_hdmi *dw_hdmi)
|
||||
static inline void meson_dw_hdmi_phy_reset(struct meson_dw_hdmi *dw_hdmi)
|
||||
{
|
||||
struct meson_drm *priv = dw_hdmi->priv;
|
||||
|
||||
@ -409,9 +410,9 @@ static int dw_hdmi_phy_init(struct dw_hdmi *hdmi, void *data,
|
||||
msleep(100);
|
||||
|
||||
/* Reset PHY 3 times in a row */
|
||||
dw_hdmi_phy_reset(dw_hdmi);
|
||||
dw_hdmi_phy_reset(dw_hdmi);
|
||||
dw_hdmi_phy_reset(dw_hdmi);
|
||||
meson_dw_hdmi_phy_reset(dw_hdmi);
|
||||
meson_dw_hdmi_phy_reset(dw_hdmi);
|
||||
meson_dw_hdmi_phy_reset(dw_hdmi);
|
||||
|
||||
/* Temporary Disable VENC video stream */
|
||||
if (priv->venc.hdmi_use_enci)
|
||||
@ -878,9 +879,12 @@ static int meson_dw_hdmi_bind(struct device *dev, struct device *master,
|
||||
dw_plat_data->input_bus_format = MEDIA_BUS_FMT_YUV8_1X24;
|
||||
dw_plat_data->input_bus_encoding = V4L2_YCBCR_ENC_709;
|
||||
|
||||
ret = dw_hdmi_bind(pdev, encoder, &meson_dw_hdmi->dw_plat_data);
|
||||
if (ret)
|
||||
return ret;
|
||||
platform_set_drvdata(pdev, meson_dw_hdmi);
|
||||
|
||||
meson_dw_hdmi->hdmi = dw_hdmi_bind(pdev, encoder,
|
||||
&meson_dw_hdmi->dw_plat_data);
|
||||
if (IS_ERR(meson_dw_hdmi->hdmi))
|
||||
return PTR_ERR(meson_dw_hdmi->hdmi);
|
||||
|
||||
DRM_DEBUG_DRIVER("HDMI controller initialized\n");
|
||||
|
||||
@ -890,7 +894,9 @@ static int meson_dw_hdmi_bind(struct device *dev, struct device *master,
|
||||
static void meson_dw_hdmi_unbind(struct device *dev, struct device *master,
|
||||
void *data)
|
||||
{
|
||||
dw_hdmi_unbind(dev);
|
||||
struct meson_dw_hdmi *meson_dw_hdmi = dev_get_drvdata(dev);
|
||||
|
||||
dw_hdmi_unbind(meson_dw_hdmi->hdmi);
|
||||
}
|
||||
|
||||
static const struct component_ops meson_dw_hdmi_ops = {
|
||||
|
@ -87,11 +87,7 @@ static int panel_dpi_enable(struct omap_dss_device *dssdev)
|
||||
}
|
||||
|
||||
gpiod_set_value_cansleep(ddata->enable_gpio, 1);
|
||||
|
||||
if (ddata->backlight) {
|
||||
ddata->backlight->props.power = FB_BLANK_UNBLANK;
|
||||
backlight_update_status(ddata->backlight);
|
||||
}
|
||||
backlight_enable(ddata->backlight);
|
||||
|
||||
dssdev->state = OMAP_DSS_DISPLAY_ACTIVE;
|
||||
|
||||
@ -106,10 +102,7 @@ static void panel_dpi_disable(struct omap_dss_device *dssdev)
|
||||
if (!omapdss_device_is_enabled(dssdev))
|
||||
return;
|
||||
|
||||
if (ddata->backlight) {
|
||||
ddata->backlight->props.power = FB_BLANK_POWERDOWN;
|
||||
backlight_update_status(ddata->backlight);
|
||||
}
|
||||
backlight_disable(ddata->backlight);
|
||||
|
||||
gpiod_set_value_cansleep(ddata->enable_gpio, 0);
|
||||
regulator_disable(ddata->vcc_supply);
|
||||
@ -164,7 +157,6 @@ static int panel_dpi_probe_of(struct platform_device *pdev)
|
||||
{
|
||||
struct panel_drv_data *ddata = platform_get_drvdata(pdev);
|
||||
struct device_node *node = pdev->dev.of_node;
|
||||
struct device_node *bl_node;
|
||||
struct omap_dss_device *in;
|
||||
int r;
|
||||
struct display_timing timing;
|
||||
@ -190,19 +182,15 @@ static int panel_dpi_probe_of(struct platform_device *pdev)
|
||||
if (IS_ERR(ddata->vcc_supply))
|
||||
return PTR_ERR(ddata->vcc_supply);
|
||||
|
||||
bl_node = of_parse_phandle(node, "backlight", 0);
|
||||
if (bl_node) {
|
||||
ddata->backlight = of_find_backlight_by_node(bl_node);
|
||||
of_node_put(bl_node);
|
||||
ddata->backlight = devm_of_find_backlight(&pdev->dev);
|
||||
|
||||
if (!ddata->backlight)
|
||||
return -EPROBE_DEFER;
|
||||
}
|
||||
if (IS_ERR(ddata->backlight))
|
||||
return PTR_ERR(ddata->backlight);
|
||||
|
||||
r = of_get_display_timing(node, "panel-timing", &timing);
|
||||
if (r) {
|
||||
dev_err(&pdev->dev, "failed to get video timing\n");
|
||||
goto error_free_backlight;
|
||||
return r;
|
||||
}
|
||||
|
||||
videomode_from_timing(&timing, &ddata->vm);
|
||||
@ -210,19 +198,12 @@ static int panel_dpi_probe_of(struct platform_device *pdev)
|
||||
in = omapdss_of_find_source_for_first_ep(node);
|
||||
if (IS_ERR(in)) {
|
||||
dev_err(&pdev->dev, "failed to find video source\n");
|
||||
r = PTR_ERR(in);
|
||||
goto error_free_backlight;
|
||||
return PTR_ERR(in);
|
||||
}
|
||||
|
||||
ddata->in = in;
|
||||
|
||||
return 0;
|
||||
|
||||
error_free_backlight:
|
||||
if (ddata->backlight)
|
||||
put_device(&ddata->backlight->dev);
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
static int panel_dpi_probe(struct platform_device *pdev)
|
||||
@ -277,9 +258,6 @@ static int __exit panel_dpi_remove(struct platform_device *pdev)
|
||||
|
||||
omap_dss_put_device(in);
|
||||
|
||||
if (ddata->backlight)
|
||||
put_device(&ddata->backlight->dev);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -45,8 +45,7 @@ static int innolux_panel_disable(struct drm_panel *panel)
|
||||
if (!innolux->enabled)
|
||||
return 0;
|
||||
|
||||
innolux->backlight->props.power = FB_BLANK_POWERDOWN;
|
||||
backlight_update_status(innolux->backlight);
|
||||
backlight_disable(innolux->backlight);
|
||||
|
||||
err = mipi_dsi_dcs_set_display_off(innolux->link);
|
||||
if (err < 0)
|
||||
@ -151,8 +150,7 @@ static int innolux_panel_enable(struct drm_panel *panel)
|
||||
if (innolux->enabled)
|
||||
return 0;
|
||||
|
||||
innolux->backlight->props.power = FB_BLANK_UNBLANK;
|
||||
ret = backlight_update_status(innolux->backlight);
|
||||
ret = backlight_enable(innolux->backlight);
|
||||
if (ret) {
|
||||
DRM_DEV_ERROR(panel->drm->dev,
|
||||
"Failed to enable backlight %d\n", ret);
|
||||
@ -217,7 +215,6 @@ MODULE_DEVICE_TABLE(of, innolux_of_match);
|
||||
static int innolux_panel_add(struct innolux_panel *innolux)
|
||||
{
|
||||
struct device *dev = &innolux->link->dev;
|
||||
struct device_node *np;
|
||||
int err;
|
||||
|
||||
innolux->supply = devm_regulator_get(dev, "power");
|
||||
@ -232,37 +229,22 @@ static int innolux_panel_add(struct innolux_panel *innolux)
|
||||
innolux->enable_gpio = NULL;
|
||||
}
|
||||
|
||||
np = of_parse_phandle(dev->of_node, "backlight", 0);
|
||||
if (np) {
|
||||
innolux->backlight = of_find_backlight_by_node(np);
|
||||
of_node_put(np);
|
||||
innolux->backlight = devm_of_find_backlight(dev);
|
||||
|
||||
if (!innolux->backlight)
|
||||
return -EPROBE_DEFER;
|
||||
}
|
||||
if (IS_ERR(innolux->backlight))
|
||||
return PTR_ERR(innolux->backlight);
|
||||
|
||||
drm_panel_init(&innolux->base);
|
||||
innolux->base.funcs = &innolux_panel_funcs;
|
||||
innolux->base.dev = &innolux->link->dev;
|
||||
|
||||
err = drm_panel_add(&innolux->base);
|
||||
if (err < 0)
|
||||
goto put_backlight;
|
||||
|
||||
return 0;
|
||||
|
||||
put_backlight:
|
||||
put_device(&innolux->backlight->dev);
|
||||
|
||||
return err;
|
||||
return drm_panel_add(&innolux->base);
|
||||
}
|
||||
|
||||
static void innolux_panel_del(struct innolux_panel *innolux)
|
||||
{
|
||||
if (innolux->base.dev)
|
||||
drm_panel_remove(&innolux->base);
|
||||
|
||||
put_device(&innolux->backlight->dev);
|
||||
}
|
||||
|
||||
static int innolux_panel_probe(struct mipi_dsi_device *dsi)
|
||||
|
@ -192,8 +192,7 @@ static int jdi_panel_disable(struct drm_panel *panel)
|
||||
if (!jdi->enabled)
|
||||
return 0;
|
||||
|
||||
jdi->backlight->props.power = FB_BLANK_POWERDOWN;
|
||||
backlight_update_status(jdi->backlight);
|
||||
backlight_disable(jdi->backlight);
|
||||
|
||||
jdi->enabled = false;
|
||||
|
||||
@ -289,8 +288,7 @@ static int jdi_panel_enable(struct drm_panel *panel)
|
||||
if (jdi->enabled)
|
||||
return 0;
|
||||
|
||||
jdi->backlight->props.power = FB_BLANK_UNBLANK;
|
||||
backlight_update_status(jdi->backlight);
|
||||
backlight_enable(jdi->backlight);
|
||||
|
||||
jdi->enabled = true;
|
||||
|
||||
|
@ -96,10 +96,7 @@ static int sharp_panel_disable(struct drm_panel *panel)
|
||||
if (!sharp->enabled)
|
||||
return 0;
|
||||
|
||||
if (sharp->backlight) {
|
||||
sharp->backlight->props.power = FB_BLANK_POWERDOWN;
|
||||
backlight_update_status(sharp->backlight);
|
||||
}
|
||||
backlight_disable(sharp->backlight);
|
||||
|
||||
sharp->enabled = false;
|
||||
|
||||
@ -263,10 +260,7 @@ static int sharp_panel_enable(struct drm_panel *panel)
|
||||
if (sharp->enabled)
|
||||
return 0;
|
||||
|
||||
if (sharp->backlight) {
|
||||
sharp->backlight->props.power = FB_BLANK_UNBLANK;
|
||||
backlight_update_status(sharp->backlight);
|
||||
}
|
||||
backlight_enable(sharp->backlight);
|
||||
|
||||
sharp->enabled = true;
|
||||
|
||||
@ -324,8 +318,7 @@ MODULE_DEVICE_TABLE(of, sharp_of_match);
|
||||
|
||||
static int sharp_panel_add(struct sharp_panel *sharp)
|
||||
{
|
||||
struct device_node *np;
|
||||
int err;
|
||||
struct device *dev = &sharp->link1->dev;
|
||||
|
||||
sharp->mode = &default_mode;
|
||||
|
||||
@ -333,30 +326,16 @@ static int sharp_panel_add(struct sharp_panel *sharp)
|
||||
if (IS_ERR(sharp->supply))
|
||||
return PTR_ERR(sharp->supply);
|
||||
|
||||
np = of_parse_phandle(sharp->link1->dev.of_node, "backlight", 0);
|
||||
if (np) {
|
||||
sharp->backlight = of_find_backlight_by_node(np);
|
||||
of_node_put(np);
|
||||
sharp->backlight = devm_of_find_backlight(dev);
|
||||
|
||||
if (!sharp->backlight)
|
||||
return -EPROBE_DEFER;
|
||||
}
|
||||
if (IS_ERR(sharp->backlight))
|
||||
return PTR_ERR(sharp->backlight);
|
||||
|
||||
drm_panel_init(&sharp->base);
|
||||
sharp->base.funcs = &sharp_panel_funcs;
|
||||
sharp->base.dev = &sharp->link1->dev;
|
||||
|
||||
err = drm_panel_add(&sharp->base);
|
||||
if (err < 0)
|
||||
goto put_backlight;
|
||||
|
||||
return 0;
|
||||
|
||||
put_backlight:
|
||||
if (sharp->backlight)
|
||||
put_device(&sharp->backlight->dev);
|
||||
|
||||
return err;
|
||||
return drm_panel_add(&sharp->base);
|
||||
}
|
||||
|
||||
static void sharp_panel_del(struct sharp_panel *sharp)
|
||||
@ -364,9 +343,6 @@ static void sharp_panel_del(struct sharp_panel *sharp)
|
||||
if (sharp->base.dev)
|
||||
drm_panel_remove(&sharp->base);
|
||||
|
||||
if (sharp->backlight)
|
||||
put_device(&sharp->backlight->dev);
|
||||
|
||||
if (sharp->link2)
|
||||
put_device(&sharp->link2->dev);
|
||||
}
|
||||
|
@ -117,10 +117,7 @@ static int sharp_nt_panel_disable(struct drm_panel *panel)
|
||||
if (!sharp_nt->enabled)
|
||||
return 0;
|
||||
|
||||
if (sharp_nt->backlight) {
|
||||
sharp_nt->backlight->props.power = FB_BLANK_POWERDOWN;
|
||||
backlight_update_status(sharp_nt->backlight);
|
||||
}
|
||||
backlight_disable(sharp_nt->backlight);
|
||||
|
||||
sharp_nt->enabled = false;
|
||||
|
||||
@ -203,10 +200,7 @@ static int sharp_nt_panel_enable(struct drm_panel *panel)
|
||||
if (sharp_nt->enabled)
|
||||
return 0;
|
||||
|
||||
if (sharp_nt->backlight) {
|
||||
sharp_nt->backlight->props.power = FB_BLANK_UNBLANK;
|
||||
backlight_update_status(sharp_nt->backlight);
|
||||
}
|
||||
backlight_enable(sharp_nt->backlight);
|
||||
|
||||
sharp_nt->enabled = true;
|
||||
|
||||
@ -259,8 +253,6 @@ static const struct drm_panel_funcs sharp_nt_panel_funcs = {
|
||||
static int sharp_nt_panel_add(struct sharp_nt_panel *sharp_nt)
|
||||
{
|
||||
struct device *dev = &sharp_nt->dsi->dev;
|
||||
struct device_node *np;
|
||||
int ret;
|
||||
|
||||
sharp_nt->mode = &default_mode;
|
||||
|
||||
@ -277,39 +269,22 @@ static int sharp_nt_panel_add(struct sharp_nt_panel *sharp_nt)
|
||||
gpiod_set_value(sharp_nt->reset_gpio, 0);
|
||||
}
|
||||
|
||||
np = of_parse_phandle(dev->of_node, "backlight", 0);
|
||||
if (np) {
|
||||
sharp_nt->backlight = of_find_backlight_by_node(np);
|
||||
of_node_put(np);
|
||||
sharp_nt->backlight = devm_of_find_backlight(dev);
|
||||
|
||||
if (!sharp_nt->backlight)
|
||||
return -EPROBE_DEFER;
|
||||
}
|
||||
if (IS_ERR(sharp_nt->backlight))
|
||||
return PTR_ERR(sharp_nt->backlight);
|
||||
|
||||
drm_panel_init(&sharp_nt->base);
|
||||
sharp_nt->base.funcs = &sharp_nt_panel_funcs;
|
||||
sharp_nt->base.dev = &sharp_nt->dsi->dev;
|
||||
|
||||
ret = drm_panel_add(&sharp_nt->base);
|
||||
if (ret < 0)
|
||||
goto put_backlight;
|
||||
|
||||
return 0;
|
||||
|
||||
put_backlight:
|
||||
if (sharp_nt->backlight)
|
||||
put_device(&sharp_nt->backlight->dev);
|
||||
|
||||
return ret;
|
||||
return drm_panel_add(&sharp_nt->base);
|
||||
}
|
||||
|
||||
static void sharp_nt_panel_del(struct sharp_nt_panel *sharp_nt)
|
||||
{
|
||||
if (sharp_nt->base.dev)
|
||||
drm_panel_remove(&sharp_nt->base);
|
||||
|
||||
if (sharp_nt->backlight)
|
||||
put_device(&sharp_nt->backlight->dev);
|
||||
}
|
||||
|
||||
static int sharp_nt_panel_probe(struct mipi_dsi_device *dsi)
|
||||
|
@ -68,12 +68,22 @@ static const struct dw_hdmi_plat_data rcar_dw_hdmi_plat_data = {
|
||||
|
||||
static int rcar_dw_hdmi_probe(struct platform_device *pdev)
|
||||
{
|
||||
return dw_hdmi_probe(pdev, &rcar_dw_hdmi_plat_data);
|
||||
struct dw_hdmi *hdmi;
|
||||
|
||||
hdmi = dw_hdmi_probe(pdev, &rcar_dw_hdmi_plat_data);
|
||||
if (IS_ERR(hdmi))
|
||||
return PTR_ERR(hdmi);
|
||||
|
||||
platform_set_drvdata(pdev, hdmi);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int rcar_dw_hdmi_remove(struct platform_device *pdev)
|
||||
{
|
||||
dw_hdmi_remove(pdev);
|
||||
struct dw_hdmi *hdmi = platform_get_drvdata(pdev);
|
||||
|
||||
dw_hdmi_remove(hdmi);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -1202,9 +1202,6 @@ static int dw_mipi_dsi_bind(struct device *dev, struct device *master,
|
||||
return ret;
|
||||
|
||||
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
|
||||
if (!res)
|
||||
return -ENODEV;
|
||||
|
||||
dsi->base = devm_ioremap_resource(dev, res);
|
||||
if (IS_ERR(dsi->base))
|
||||
return PTR_ERR(dsi->base);
|
||||
|
@ -48,6 +48,7 @@ struct rockchip_hdmi {
|
||||
const struct rockchip_hdmi_chip_data *chip_data;
|
||||
struct clk *vpll_clk;
|
||||
struct clk *grf_clk;
|
||||
struct dw_hdmi *hdmi;
|
||||
};
|
||||
|
||||
#define to_rockchip_hdmi(x) container_of(x, struct rockchip_hdmi, x)
|
||||
@ -377,14 +378,18 @@ static int dw_hdmi_rockchip_bind(struct device *dev, struct device *master,
|
||||
drm_encoder_init(drm, encoder, &dw_hdmi_rockchip_encoder_funcs,
|
||||
DRM_MODE_ENCODER_TMDS, NULL);
|
||||
|
||||
ret = dw_hdmi_bind(pdev, encoder, plat_data);
|
||||
platform_set_drvdata(pdev, hdmi);
|
||||
|
||||
hdmi->hdmi = dw_hdmi_bind(pdev, encoder, plat_data);
|
||||
|
||||
/*
|
||||
* If dw_hdmi_bind() fails we'll never call dw_hdmi_unbind(),
|
||||
* which would have called the encoder cleanup. Do it manually.
|
||||
*/
|
||||
if (ret)
|
||||
if (IS_ERR(hdmi->hdmi)) {
|
||||
ret = PTR_ERR(hdmi->hdmi);
|
||||
drm_encoder_cleanup(encoder);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
@ -392,7 +397,9 @@ static int dw_hdmi_rockchip_bind(struct device *dev, struct device *master,
|
||||
static void dw_hdmi_rockchip_unbind(struct device *dev, struct device *master,
|
||||
void *data)
|
||||
{
|
||||
return dw_hdmi_unbind(dev);
|
||||
struct rockchip_hdmi *hdmi = dev_get_drvdata(dev);
|
||||
|
||||
dw_hdmi_unbind(hdmi->hdmi);
|
||||
}
|
||||
|
||||
static const struct component_ops dw_hdmi_rockchip_ops = {
|
||||
|
@ -831,9 +831,6 @@ static int inno_hdmi_bind(struct device *dev, struct device *master,
|
||||
hdmi->drm_dev = drm;
|
||||
|
||||
iores = platform_get_resource(pdev, IORESOURCE_MEM, 0);
|
||||
if (!iores)
|
||||
return -ENXIO;
|
||||
|
||||
hdmi->regs = devm_ioremap_resource(dev, iores);
|
||||
if (IS_ERR(hdmi->regs))
|
||||
return PTR_ERR(hdmi->regs);
|
||||
|
@ -230,6 +230,7 @@ static struct drm_driver rockchip_drm_driver = {
|
||||
.gem_prime_import = drm_gem_prime_import,
|
||||
.gem_prime_export = drm_gem_prime_export,
|
||||
.gem_prime_get_sg_table = rockchip_gem_prime_get_sg_table,
|
||||
.gem_prime_import_sg_table = rockchip_gem_prime_import_sg_table,
|
||||
.gem_prime_vmap = rockchip_gem_prime_vmap,
|
||||
.gem_prime_vunmap = rockchip_gem_prime_vunmap,
|
||||
.gem_prime_mmap = rockchip_gem_mmap_buf,
|
||||
|
@ -16,6 +16,8 @@
|
||||
#include <drm/drmP.h>
|
||||
#include <drm/drm_gem.h>
|
||||
#include <drm/drm_vma_manager.h>
|
||||
|
||||
#include <linux/dma-buf.h>
|
||||
#include <linux/iommu.h>
|
||||
|
||||
#include "rockchip_drm_drv.h"
|
||||
@ -262,7 +264,6 @@ static int rockchip_drm_gem_object_mmap(struct drm_gem_object *obj,
|
||||
* VM_PFNMAP flag that was set by drm_gem_mmap_obj()/drm_gem_mmap().
|
||||
*/
|
||||
vma->vm_flags &= ~VM_PFNMAP;
|
||||
vma->vm_pgoff = 0;
|
||||
|
||||
if (rk_obj->pages)
|
||||
ret = rockchip_drm_gem_object_mmap_iommu(obj, vma);
|
||||
@ -297,6 +298,12 @@ int rockchip_gem_mmap(struct file *filp, struct vm_area_struct *vma)
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
/*
|
||||
* Set vm_pgoff (used as a fake buffer offset by DRM) to 0 and map the
|
||||
* whole buffer from the start.
|
||||
*/
|
||||
vma->vm_pgoff = 0;
|
||||
|
||||
obj = vma->vm_private_data;
|
||||
|
||||
return rockchip_drm_gem_object_mmap(obj, vma);
|
||||
@ -309,12 +316,10 @@ static void rockchip_gem_release_object(struct rockchip_gem_object *rk_obj)
|
||||
}
|
||||
|
||||
struct rockchip_gem_object *
|
||||
rockchip_gem_create_object(struct drm_device *drm, unsigned int size,
|
||||
bool alloc_kmap)
|
||||
rockchip_gem_alloc_object(struct drm_device *drm, unsigned int size)
|
||||
{
|
||||
struct rockchip_gem_object *rk_obj;
|
||||
struct drm_gem_object *obj;
|
||||
int ret;
|
||||
|
||||
size = round_up(size, PAGE_SIZE);
|
||||
|
||||
@ -326,6 +331,20 @@ struct rockchip_gem_object *
|
||||
|
||||
drm_gem_object_init(drm, obj, size);
|
||||
|
||||
return rk_obj;
|
||||
}
|
||||
|
||||
struct rockchip_gem_object *
|
||||
rockchip_gem_create_object(struct drm_device *drm, unsigned int size,
|
||||
bool alloc_kmap)
|
||||
{
|
||||
struct rockchip_gem_object *rk_obj;
|
||||
int ret;
|
||||
|
||||
rk_obj = rockchip_gem_alloc_object(drm, size);
|
||||
if (IS_ERR(rk_obj))
|
||||
return rk_obj;
|
||||
|
||||
ret = rockchip_gem_alloc_buf(rk_obj, alloc_kmap);
|
||||
if (ret)
|
||||
goto err_free_rk_obj;
|
||||
@ -343,11 +362,21 @@ err_free_rk_obj:
|
||||
*/
|
||||
void rockchip_gem_free_object(struct drm_gem_object *obj)
|
||||
{
|
||||
struct rockchip_gem_object *rk_obj;
|
||||
struct drm_device *drm = obj->dev;
|
||||
struct rockchip_drm_private *private = drm->dev_private;
|
||||
struct rockchip_gem_object *rk_obj = to_rockchip_obj(obj);
|
||||
|
||||
rk_obj = to_rockchip_obj(obj);
|
||||
|
||||
rockchip_gem_free_buf(rk_obj);
|
||||
if (obj->import_attach) {
|
||||
if (private->domain) {
|
||||
rockchip_gem_iommu_unmap(rk_obj);
|
||||
} else {
|
||||
dma_unmap_sg(drm->dev, rk_obj->sgt->sgl,
|
||||
rk_obj->sgt->nents, DMA_BIDIRECTIONAL);
|
||||
}
|
||||
drm_prime_gem_destroy(obj, rk_obj->sgt);
|
||||
} else {
|
||||
rockchip_gem_free_buf(rk_obj);
|
||||
}
|
||||
|
||||
rockchip_gem_release_object(rk_obj);
|
||||
}
|
||||
@ -451,6 +480,86 @@ struct sg_table *rockchip_gem_prime_get_sg_table(struct drm_gem_object *obj)
|
||||
return sgt;
|
||||
}
|
||||
|
||||
static unsigned long rockchip_sg_get_contiguous_size(struct sg_table *sgt,
|
||||
int count)
|
||||
{
|
||||
struct scatterlist *s;
|
||||
dma_addr_t expected = sg_dma_address(sgt->sgl);
|
||||
unsigned int i;
|
||||
unsigned long size = 0;
|
||||
|
||||
for_each_sg(sgt->sgl, s, count, i) {
|
||||
if (sg_dma_address(s) != expected)
|
||||
break;
|
||||
expected = sg_dma_address(s) + sg_dma_len(s);
|
||||
size += sg_dma_len(s);
|
||||
}
|
||||
return size;
|
||||
}
|
||||
|
||||
static int
|
||||
rockchip_gem_iommu_map_sg(struct drm_device *drm,
|
||||
struct dma_buf_attachment *attach,
|
||||
struct sg_table *sg,
|
||||
struct rockchip_gem_object *rk_obj)
|
||||
{
|
||||
rk_obj->sgt = sg;
|
||||
return rockchip_gem_iommu_map(rk_obj);
|
||||
}
|
||||
|
||||
static int
|
||||
rockchip_gem_dma_map_sg(struct drm_device *drm,
|
||||
struct dma_buf_attachment *attach,
|
||||
struct sg_table *sg,
|
||||
struct rockchip_gem_object *rk_obj)
|
||||
{
|
||||
int count = dma_map_sg(drm->dev, sg->sgl, sg->nents,
|
||||
DMA_BIDIRECTIONAL);
|
||||
if (!count)
|
||||
return -EINVAL;
|
||||
|
||||
if (rockchip_sg_get_contiguous_size(sg, count) < attach->dmabuf->size) {
|
||||
DRM_ERROR("failed to map sg_table to contiguous linear address.\n");
|
||||
dma_unmap_sg(drm->dev, sg->sgl, sg->nents,
|
||||
DMA_BIDIRECTIONAL);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
rk_obj->dma_addr = sg_dma_address(sg->sgl);
|
||||
rk_obj->sgt = sg;
|
||||
return 0;
|
||||
}
|
||||
|
||||
struct drm_gem_object *
|
||||
rockchip_gem_prime_import_sg_table(struct drm_device *drm,
|
||||
struct dma_buf_attachment *attach,
|
||||
struct sg_table *sg)
|
||||
{
|
||||
struct rockchip_drm_private *private = drm->dev_private;
|
||||
struct rockchip_gem_object *rk_obj;
|
||||
int ret;
|
||||
|
||||
rk_obj = rockchip_gem_alloc_object(drm, attach->dmabuf->size);
|
||||
if (IS_ERR(rk_obj))
|
||||
return ERR_CAST(rk_obj);
|
||||
|
||||
if (private->domain)
|
||||
ret = rockchip_gem_iommu_map_sg(drm, attach, sg, rk_obj);
|
||||
else
|
||||
ret = rockchip_gem_dma_map_sg(drm, attach, sg, rk_obj);
|
||||
|
||||
if (ret < 0) {
|
||||
DRM_ERROR("failed to import sg table: %d\n", ret);
|
||||
goto err_free_rk_obj;
|
||||
}
|
||||
|
||||
return &rk_obj->base;
|
||||
|
||||
err_free_rk_obj:
|
||||
rockchip_gem_release_object(rk_obj);
|
||||
return ERR_PTR(ret);
|
||||
}
|
||||
|
||||
void *rockchip_gem_prime_vmap(struct drm_gem_object *obj)
|
||||
{
|
||||
struct rockchip_gem_object *rk_obj = to_rockchip_obj(obj);
|
||||
|
@ -36,8 +36,9 @@ struct rockchip_gem_object {
|
||||
|
||||
struct sg_table *rockchip_gem_prime_get_sg_table(struct drm_gem_object *obj);
|
||||
struct drm_gem_object *
|
||||
rockchip_gem_prime_import_sg_table(struct drm_device *dev, size_t size,
|
||||
struct sg_table *sgt);
|
||||
rockchip_gem_prime_import_sg_table(struct drm_device *dev,
|
||||
struct dma_buf_attachment *attach,
|
||||
struct sg_table *sg);
|
||||
void *rockchip_gem_prime_vmap(struct drm_gem_object *obj);
|
||||
void rockchip_gem_prime_vunmap(struct drm_gem_object *obj, void *vaddr);
|
||||
|
||||
|
@ -95,9 +95,6 @@ struct vop {
|
||||
struct drm_device *drm_dev;
|
||||
bool is_enabled;
|
||||
|
||||
/* mutex vsync_ work */
|
||||
struct mutex vsync_mutex;
|
||||
bool vsync_work_pending;
|
||||
struct completion dsp_hold_completion;
|
||||
|
||||
/* protected by dev->event_lock */
|
||||
@ -1555,8 +1552,6 @@ static int vop_bind(struct device *dev, struct device *master, void *data)
|
||||
spin_lock_init(&vop->reg_lock);
|
||||
spin_lock_init(&vop->irq_lock);
|
||||
|
||||
mutex_init(&vop->vsync_mutex);
|
||||
|
||||
ret = devm_request_irq(dev, vop->irq, vop_isr,
|
||||
IRQF_SHARED, dev_name(dev), vop);
|
||||
if (ret)
|
||||
|
@ -40,6 +40,15 @@ config DRM_SUN4I_BACKEND
|
||||
do some alpha blending and feed graphics to TCON. If M is
|
||||
selected the module will be called sun4i-backend.
|
||||
|
||||
config DRM_SUN8I_DW_HDMI
|
||||
tristate "Support for Allwinner version of DesignWare HDMI"
|
||||
depends on DRM_SUN4I
|
||||
select DRM_DW_HDMI
|
||||
help
|
||||
Choose this option if you have an Allwinner SoC with the
|
||||
DesignWare HDMI controller with custom HDMI PHY. If M is
|
||||
selected the module will be called sun8i_dw_hdmi.
|
||||
|
||||
config DRM_SUN8I_MIXER
|
||||
tristate "Support for Allwinner Display Engine 2.0 Mixer"
|
||||
default MACH_SUN8I
|
||||
|
@ -10,6 +10,9 @@ sun4i-drm-hdmi-y += sun4i_hdmi_enc.o
|
||||
sun4i-drm-hdmi-y += sun4i_hdmi_i2c.o
|
||||
sun4i-drm-hdmi-y += sun4i_hdmi_tmds_clk.o
|
||||
|
||||
sun8i-drm-hdmi-y += sun8i_dw_hdmi.o
|
||||
sun8i-drm-hdmi-y += sun8i_hdmi_phy.o
|
||||
|
||||
sun8i-mixer-y += sun8i_mixer.o sun8i_ui_layer.o \
|
||||
sun8i_vi_layer.o sun8i_ui_scaler.o \
|
||||
sun8i_vi_scaler.o sun8i_csc.o
|
||||
@ -27,4 +30,5 @@ obj-$(CONFIG_DRM_SUN4I) += sun6i_drc.o
|
||||
|
||||
obj-$(CONFIG_DRM_SUN4I_BACKEND) += sun4i-backend.o sun4i-frontend.o
|
||||
obj-$(CONFIG_DRM_SUN4I_HDMI) += sun4i-drm-hdmi.o
|
||||
obj-$(CONFIG_DRM_SUN8I_DW_HDMI) += sun8i-drm-hdmi.o
|
||||
obj-$(CONFIG_DRM_SUN8I_MIXER) += sun8i-mixer.o
|
||||
|
@ -84,6 +84,7 @@ static void sun4i_tcon_channel_set_status(struct sun4i_tcon *tcon, int channel,
|
||||
|
||||
switch (channel) {
|
||||
case 0:
|
||||
WARN_ON(!tcon->quirks->has_channel_0);
|
||||
regmap_update_bits(tcon->regs, SUN4I_TCON0_CTL_REG,
|
||||
SUN4I_TCON0_CTL_TCON_ENABLE,
|
||||
enabled ? SUN4I_TCON0_CTL_TCON_ENABLE : 0);
|
||||
@ -276,6 +277,8 @@ static void sun4i_tcon0_mode_set_lvds(struct sun4i_tcon *tcon,
|
||||
u8 clk_delay;
|
||||
u32 reg, val = 0;
|
||||
|
||||
WARN_ON(!tcon->quirks->has_channel_0);
|
||||
|
||||
tcon->dclk_min_div = 7;
|
||||
tcon->dclk_max_div = 7;
|
||||
sun4i_tcon0_mode_set_common(tcon, mode);
|
||||
@ -344,6 +347,8 @@ static void sun4i_tcon0_mode_set_rgb(struct sun4i_tcon *tcon,
|
||||
u8 clk_delay;
|
||||
u32 val = 0;
|
||||
|
||||
WARN_ON(!tcon->quirks->has_channel_0);
|
||||
|
||||
tcon->dclk_min_div = 6;
|
||||
tcon->dclk_max_div = 127;
|
||||
sun4i_tcon0_mode_set_common(tcon, mode);
|
||||
@ -389,10 +394,10 @@ static void sun4i_tcon0_mode_set_rgb(struct sun4i_tcon *tcon,
|
||||
SUN4I_TCON0_BASIC3_H_SYNC(hsync));
|
||||
|
||||
/* Setup the polarity of the various signals */
|
||||
if (!(mode->flags & DRM_MODE_FLAG_PHSYNC))
|
||||
if (mode->flags & DRM_MODE_FLAG_PHSYNC)
|
||||
val |= SUN4I_TCON0_IO_POL_HSYNC_POSITIVE;
|
||||
|
||||
if (!(mode->flags & DRM_MODE_FLAG_PVSYNC))
|
||||
if (mode->flags & DRM_MODE_FLAG_PVSYNC)
|
||||
val |= SUN4I_TCON0_IO_POL_VSYNC_POSITIVE;
|
||||
|
||||
regmap_update_bits(tcon->regs, SUN4I_TCON0_IO_POL_REG,
|
||||
@ -574,10 +579,12 @@ static int sun4i_tcon_init_clocks(struct device *dev,
|
||||
}
|
||||
clk_prepare_enable(tcon->clk);
|
||||
|
||||
tcon->sclk0 = devm_clk_get(dev, "tcon-ch0");
|
||||
if (IS_ERR(tcon->sclk0)) {
|
||||
dev_err(dev, "Couldn't get the TCON channel 0 clock\n");
|
||||
return PTR_ERR(tcon->sclk0);
|
||||
if (tcon->quirks->has_channel_0) {
|
||||
tcon->sclk0 = devm_clk_get(dev, "tcon-ch0");
|
||||
if (IS_ERR(tcon->sclk0)) {
|
||||
dev_err(dev, "Couldn't get the TCON channel 0 clock\n");
|
||||
return PTR_ERR(tcon->sclk0);
|
||||
}
|
||||
}
|
||||
|
||||
if (tcon->quirks->has_channel_1) {
|
||||
@ -934,10 +941,12 @@ static int sun4i_tcon_bind(struct device *dev, struct device *master,
|
||||
goto err_free_clocks;
|
||||
}
|
||||
|
||||
ret = sun4i_dclk_create(dev, tcon);
|
||||
if (ret) {
|
||||
dev_err(dev, "Couldn't create our TCON dot clock\n");
|
||||
goto err_free_clocks;
|
||||
if (tcon->quirks->has_channel_0) {
|
||||
ret = sun4i_dclk_create(dev, tcon);
|
||||
if (ret) {
|
||||
dev_err(dev, "Couldn't create our TCON dot clock\n");
|
||||
goto err_free_clocks;
|
||||
}
|
||||
}
|
||||
|
||||
ret = sun4i_tcon_init_irq(dev, tcon);
|
||||
@ -995,7 +1004,8 @@ static int sun4i_tcon_bind(struct device *dev, struct device *master,
|
||||
return 0;
|
||||
|
||||
err_free_dotclock:
|
||||
sun4i_dclk_free(tcon);
|
||||
if (tcon->quirks->has_channel_0)
|
||||
sun4i_dclk_free(tcon);
|
||||
err_free_clocks:
|
||||
sun4i_tcon_free_clocks(tcon);
|
||||
err_assert_reset:
|
||||
@ -1009,7 +1019,8 @@ static void sun4i_tcon_unbind(struct device *dev, struct device *master,
|
||||
struct sun4i_tcon *tcon = dev_get_drvdata(dev);
|
||||
|
||||
list_del(&tcon->list);
|
||||
sun4i_dclk_free(tcon);
|
||||
if (tcon->quirks->has_channel_0)
|
||||
sun4i_dclk_free(tcon);
|
||||
sun4i_tcon_free_clocks(tcon);
|
||||
}
|
||||
|
||||
@ -1106,16 +1117,19 @@ static int sun6i_tcon_set_mux(struct sun4i_tcon *tcon,
|
||||
}
|
||||
|
||||
static const struct sun4i_tcon_quirks sun4i_a10_quirks = {
|
||||
.has_channel_0 = true,
|
||||
.has_channel_1 = true,
|
||||
.set_mux = sun4i_a10_tcon_set_mux,
|
||||
};
|
||||
|
||||
static const struct sun4i_tcon_quirks sun5i_a13_quirks = {
|
||||
.has_channel_0 = true,
|
||||
.has_channel_1 = true,
|
||||
.set_mux = sun5i_a13_tcon_set_mux,
|
||||
};
|
||||
|
||||
static const struct sun4i_tcon_quirks sun6i_a31_quirks = {
|
||||
.has_channel_0 = true,
|
||||
.has_channel_1 = true,
|
||||
.has_lvds_alt = true,
|
||||
.needs_de_be_mux = true,
|
||||
@ -1123,26 +1137,33 @@ static const struct sun4i_tcon_quirks sun6i_a31_quirks = {
|
||||
};
|
||||
|
||||
static const struct sun4i_tcon_quirks sun6i_a31s_quirks = {
|
||||
.has_channel_0 = true,
|
||||
.has_channel_1 = true,
|
||||
.needs_de_be_mux = true,
|
||||
};
|
||||
|
||||
static const struct sun4i_tcon_quirks sun7i_a20_quirks = {
|
||||
.has_channel_0 = true,
|
||||
.has_channel_1 = true,
|
||||
/* Same display pipeline structure as A10 */
|
||||
.set_mux = sun4i_a10_tcon_set_mux,
|
||||
};
|
||||
|
||||
static const struct sun4i_tcon_quirks sun8i_a33_quirks = {
|
||||
.has_channel_0 = true,
|
||||
.has_lvds_alt = true,
|
||||
};
|
||||
|
||||
static const struct sun4i_tcon_quirks sun8i_a83t_lcd_quirks = {
|
||||
/* nothing is supported */
|
||||
.has_channel_0 = true,
|
||||
};
|
||||
|
||||
static const struct sun4i_tcon_quirks sun8i_a83t_tv_quirks = {
|
||||
.has_channel_1 = true,
|
||||
};
|
||||
|
||||
static const struct sun4i_tcon_quirks sun8i_v3s_quirks = {
|
||||
/* nothing is supported */
|
||||
.has_channel_0 = true,
|
||||
};
|
||||
|
||||
/* sun4i_drv uses this list to check if a device node is a TCON */
|
||||
@ -1154,6 +1175,7 @@ const struct of_device_id sun4i_tcon_of_table[] = {
|
||||
{ .compatible = "allwinner,sun7i-a20-tcon", .data = &sun7i_a20_quirks },
|
||||
{ .compatible = "allwinner,sun8i-a33-tcon", .data = &sun8i_a33_quirks },
|
||||
{ .compatible = "allwinner,sun8i-a83t-tcon-lcd", .data = &sun8i_a83t_lcd_quirks },
|
||||
{ .compatible = "allwinner,sun8i-a83t-tcon-tv", .data = &sun8i_a83t_tv_quirks },
|
||||
{ .compatible = "allwinner,sun8i-v3s-tcon", .data = &sun8i_v3s_quirks },
|
||||
{ }
|
||||
};
|
||||
|
@ -172,6 +172,7 @@
|
||||
struct sun4i_tcon;
|
||||
|
||||
struct sun4i_tcon_quirks {
|
||||
bool has_channel_0; /* a83t does not have channel 0 on second TCON */
|
||||
bool has_channel_1; /* a33 does not have channel 1 */
|
||||
bool has_lvds_alt; /* Does the LVDS clock have a parent other than the TCON clock? */
|
||||
bool needs_de_be_mux; /* sun6i needs mux to select backend */
|
||||
|
196
drivers/gpu/drm/sun4i/sun8i_dw_hdmi.c
Normal file
196
drivers/gpu/drm/sun4i/sun8i_dw_hdmi.c
Normal file
@ -0,0 +1,196 @@
|
||||
// SPDX-License-Identifier: GPL-2.0+
|
||||
/*
|
||||
* Copyright (c) 2018 Jernej Skrabec <jernej.skrabec@siol.net>
|
||||
*/
|
||||
|
||||
#include <linux/component.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/platform_device.h>
|
||||
|
||||
#include <drm/drm_of.h>
|
||||
#include <drm/drmP.h>
|
||||
#include <drm/drm_crtc_helper.h>
|
||||
|
||||
#include "sun8i_dw_hdmi.h"
|
||||
|
||||
static void sun8i_dw_hdmi_encoder_mode_set(struct drm_encoder *encoder,
|
||||
struct drm_display_mode *mode,
|
||||
struct drm_display_mode *adj_mode)
|
||||
{
|
||||
struct sun8i_dw_hdmi *hdmi = encoder_to_sun8i_dw_hdmi(encoder);
|
||||
|
||||
clk_set_rate(hdmi->clk_tmds, mode->crtc_clock * 1000);
|
||||
}
|
||||
|
||||
static const struct drm_encoder_helper_funcs
|
||||
sun8i_dw_hdmi_encoder_helper_funcs = {
|
||||
.mode_set = sun8i_dw_hdmi_encoder_mode_set,
|
||||
};
|
||||
|
||||
static const struct drm_encoder_funcs sun8i_dw_hdmi_encoder_funcs = {
|
||||
.destroy = drm_encoder_cleanup,
|
||||
};
|
||||
|
||||
static enum drm_mode_status
|
||||
sun8i_dw_hdmi_mode_valid(struct drm_connector *connector,
|
||||
const struct drm_display_mode *mode)
|
||||
{
|
||||
if (mode->clock > 297000)
|
||||
return MODE_CLOCK_HIGH;
|
||||
|
||||
return MODE_OK;
|
||||
}
|
||||
|
||||
static int sun8i_dw_hdmi_bind(struct device *dev, struct device *master,
|
||||
void *data)
|
||||
{
|
||||
struct platform_device *pdev = to_platform_device(dev);
|
||||
struct dw_hdmi_plat_data *plat_data;
|
||||
struct drm_device *drm = data;
|
||||
struct device_node *phy_node;
|
||||
struct drm_encoder *encoder;
|
||||
struct sun8i_dw_hdmi *hdmi;
|
||||
int ret;
|
||||
|
||||
if (!pdev->dev.of_node)
|
||||
return -ENODEV;
|
||||
|
||||
hdmi = devm_kzalloc(&pdev->dev, sizeof(*hdmi), GFP_KERNEL);
|
||||
if (!hdmi)
|
||||
return -ENOMEM;
|
||||
|
||||
plat_data = &hdmi->plat_data;
|
||||
hdmi->dev = &pdev->dev;
|
||||
encoder = &hdmi->encoder;
|
||||
|
||||
encoder->possible_crtcs = drm_of_find_possible_crtcs(drm, dev->of_node);
|
||||
/*
|
||||
* If we failed to find the CRTC(s) which this encoder is
|
||||
* supposed to be connected to, it's because the CRTC has
|
||||
* not been registered yet. Defer probing, and hope that
|
||||
* the required CRTC is added later.
|
||||
*/
|
||||
if (encoder->possible_crtcs == 0)
|
||||
return -EPROBE_DEFER;
|
||||
|
||||
hdmi->rst_ctrl = devm_reset_control_get(dev, "ctrl");
|
||||
if (IS_ERR(hdmi->rst_ctrl)) {
|
||||
dev_err(dev, "Could not get ctrl reset control\n");
|
||||
return PTR_ERR(hdmi->rst_ctrl);
|
||||
}
|
||||
|
||||
hdmi->clk_tmds = devm_clk_get(dev, "tmds");
|
||||
if (IS_ERR(hdmi->clk_tmds)) {
|
||||
dev_err(dev, "Couldn't get the tmds clock\n");
|
||||
return PTR_ERR(hdmi->clk_tmds);
|
||||
}
|
||||
|
||||
ret = reset_control_deassert(hdmi->rst_ctrl);
|
||||
if (ret) {
|
||||
dev_err(dev, "Could not deassert ctrl reset control\n");
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret = clk_prepare_enable(hdmi->clk_tmds);
|
||||
if (ret) {
|
||||
dev_err(dev, "Could not enable tmds clock\n");
|
||||
goto err_assert_ctrl_reset;
|
||||
}
|
||||
|
||||
phy_node = of_parse_phandle(dev->of_node, "phys", 0);
|
||||
if (!phy_node) {
|
||||
dev_err(dev, "Can't found PHY phandle\n");
|
||||
goto err_disable_clk_tmds;
|
||||
}
|
||||
|
||||
ret = sun8i_hdmi_phy_probe(hdmi, phy_node);
|
||||
of_node_put(phy_node);
|
||||
if (ret) {
|
||||
dev_err(dev, "Couldn't get the HDMI PHY\n");
|
||||
goto err_disable_clk_tmds;
|
||||
}
|
||||
|
||||
drm_encoder_helper_add(encoder, &sun8i_dw_hdmi_encoder_helper_funcs);
|
||||
drm_encoder_init(drm, encoder, &sun8i_dw_hdmi_encoder_funcs,
|
||||
DRM_MODE_ENCODER_TMDS, NULL);
|
||||
|
||||
sun8i_hdmi_phy_init(hdmi->phy);
|
||||
|
||||
plat_data->mode_valid = &sun8i_dw_hdmi_mode_valid;
|
||||
plat_data->phy_ops = sun8i_hdmi_phy_get_ops();
|
||||
plat_data->phy_name = "sun8i_dw_hdmi_phy";
|
||||
plat_data->phy_data = hdmi->phy;
|
||||
|
||||
platform_set_drvdata(pdev, hdmi);
|
||||
|
||||
hdmi->hdmi = dw_hdmi_bind(pdev, encoder, plat_data);
|
||||
|
||||
/*
|
||||
* If dw_hdmi_bind() fails we'll never call dw_hdmi_unbind(),
|
||||
* which would have called the encoder cleanup. Do it manually.
|
||||
*/
|
||||
if (IS_ERR(hdmi->hdmi)) {
|
||||
ret = PTR_ERR(hdmi->hdmi);
|
||||
goto cleanup_encoder;
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
cleanup_encoder:
|
||||
drm_encoder_cleanup(encoder);
|
||||
sun8i_hdmi_phy_remove(hdmi);
|
||||
err_disable_clk_tmds:
|
||||
clk_disable_unprepare(hdmi->clk_tmds);
|
||||
err_assert_ctrl_reset:
|
||||
reset_control_assert(hdmi->rst_ctrl);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void sun8i_dw_hdmi_unbind(struct device *dev, struct device *master,
|
||||
void *data)
|
||||
{
|
||||
struct sun8i_dw_hdmi *hdmi = dev_get_drvdata(dev);
|
||||
|
||||
dw_hdmi_unbind(hdmi->hdmi);
|
||||
sun8i_hdmi_phy_remove(hdmi);
|
||||
clk_disable_unprepare(hdmi->clk_tmds);
|
||||
reset_control_assert(hdmi->rst_ctrl);
|
||||
}
|
||||
|
||||
static const struct component_ops sun8i_dw_hdmi_ops = {
|
||||
.bind = sun8i_dw_hdmi_bind,
|
||||
.unbind = sun8i_dw_hdmi_unbind,
|
||||
};
|
||||
|
||||
static int sun8i_dw_hdmi_probe(struct platform_device *pdev)
|
||||
{
|
||||
return component_add(&pdev->dev, &sun8i_dw_hdmi_ops);
|
||||
}
|
||||
|
||||
static int sun8i_dw_hdmi_remove(struct platform_device *pdev)
|
||||
{
|
||||
component_del(&pdev->dev, &sun8i_dw_hdmi_ops);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct of_device_id sun8i_dw_hdmi_dt_ids[] = {
|
||||
{ .compatible = "allwinner,sun8i-a83t-dw-hdmi" },
|
||||
{ /* sentinel */ },
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, sun8i_dw_hdmi_dt_ids);
|
||||
|
||||
struct platform_driver sun8i_dw_hdmi_pltfm_driver = {
|
||||
.probe = sun8i_dw_hdmi_probe,
|
||||
.remove = sun8i_dw_hdmi_remove,
|
||||
.driver = {
|
||||
.name = "sun8i-dw-hdmi",
|
||||
.of_match_table = sun8i_dw_hdmi_dt_ids,
|
||||
},
|
||||
};
|
||||
module_platform_driver(sun8i_dw_hdmi_pltfm_driver);
|
||||
|
||||
MODULE_AUTHOR("Jernej Skrabec <jernej.skrabec@siol.net>");
|
||||
MODULE_DESCRIPTION("Allwinner DW HDMI bridge");
|
||||
MODULE_LICENSE("GPL");
|
44
drivers/gpu/drm/sun4i/sun8i_dw_hdmi.h
Normal file
44
drivers/gpu/drm/sun4i/sun8i_dw_hdmi.h
Normal file
@ -0,0 +1,44 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0+ */
|
||||
/*
|
||||
* Copyright (C) 2018 Jernej Skrabec <jernej.skrabec@siol.net>
|
||||
*/
|
||||
|
||||
#ifndef _SUN8I_DW_HDMI_H_
|
||||
#define _SUN8I_DW_HDMI_H_
|
||||
|
||||
#include <drm/bridge/dw_hdmi.h>
|
||||
#include <drm/drm_encoder.h>
|
||||
#include <linux/clk.h>
|
||||
#include <linux/regmap.h>
|
||||
#include <linux/reset.h>
|
||||
|
||||
struct sun8i_hdmi_phy {
|
||||
struct clk *clk_bus;
|
||||
struct clk *clk_mod;
|
||||
struct regmap *regs;
|
||||
struct reset_control *rst_phy;
|
||||
};
|
||||
|
||||
struct sun8i_dw_hdmi {
|
||||
struct clk *clk_tmds;
|
||||
struct device *dev;
|
||||
struct dw_hdmi *hdmi;
|
||||
struct drm_encoder encoder;
|
||||
struct sun8i_hdmi_phy *phy;
|
||||
struct dw_hdmi_plat_data plat_data;
|
||||
struct reset_control *rst_ctrl;
|
||||
};
|
||||
|
||||
static inline struct sun8i_dw_hdmi *
|
||||
encoder_to_sun8i_dw_hdmi(struct drm_encoder *encoder)
|
||||
{
|
||||
return container_of(encoder, struct sun8i_dw_hdmi, encoder);
|
||||
}
|
||||
|
||||
int sun8i_hdmi_phy_probe(struct sun8i_dw_hdmi *hdmi, struct device_node *node);
|
||||
void sun8i_hdmi_phy_remove(struct sun8i_dw_hdmi *hdmi);
|
||||
|
||||
void sun8i_hdmi_phy_init(struct sun8i_hdmi_phy *phy);
|
||||
const struct dw_hdmi_phy_ops *sun8i_hdmi_phy_get_ops(void);
|
||||
|
||||
#endif /* _SUN8I_DW_HDMI_H_ */
|
270
drivers/gpu/drm/sun4i/sun8i_hdmi_phy.c
Normal file
270
drivers/gpu/drm/sun4i/sun8i_hdmi_phy.c
Normal file
@ -0,0 +1,270 @@
|
||||
// SPDX-License-Identifier: GPL-2.0+
|
||||
/*
|
||||
* Copyright (c) 2018 Jernej Skrabec <jernej.skrabec@siol.net>
|
||||
*/
|
||||
|
||||
#include <linux/of_address.h>
|
||||
|
||||
#include "sun8i_dw_hdmi.h"
|
||||
|
||||
#define SUN8I_HDMI_PHY_DBG_CTRL_REG 0x0000
|
||||
#define SUN8I_HDMI_PHY_DBG_CTRL_PX_LOCK BIT(0)
|
||||
#define SUN8I_HDMI_PHY_DBG_CTRL_POL_MASK GENMASK(15, 8)
|
||||
#define SUN8I_HDMI_PHY_DBG_CTRL_POL(val) (val << 8)
|
||||
#define SUN8I_HDMI_PHY_DBG_CTRL_ADDR_MASK GENMASK(23, 16)
|
||||
#define SUN8I_HDMI_PHY_DBG_CTRL_ADDR(addr) (addr << 16)
|
||||
|
||||
#define SUN8I_HDMI_PHY_REXT_CTRL_REG 0x0004
|
||||
#define SUN8I_HDMI_PHY_REXT_CTRL_REXT_EN BIT(31)
|
||||
|
||||
#define SUN8I_HDMI_PHY_READ_EN_REG 0x0010
|
||||
#define SUN8I_HDMI_PHY_READ_EN_MAGIC 0x54524545
|
||||
|
||||
#define SUN8I_HDMI_PHY_UNSCRAMBLE_REG 0x0014
|
||||
#define SUN8I_HDMI_PHY_UNSCRAMBLE_MAGIC 0x42494E47
|
||||
|
||||
/*
|
||||
* Address can be actually any value. Here is set to same value as
|
||||
* it is set in BSP driver.
|
||||
*/
|
||||
#define I2C_ADDR 0x69
|
||||
|
||||
static int sun8i_hdmi_phy_config(struct dw_hdmi *hdmi, void *data,
|
||||
struct drm_display_mode *mode)
|
||||
{
|
||||
struct sun8i_hdmi_phy *phy = (struct sun8i_hdmi_phy *)data;
|
||||
u32 val = 0;
|
||||
|
||||
if ((mode->flags & DRM_MODE_FLAG_NHSYNC) &&
|
||||
(mode->flags & DRM_MODE_FLAG_NHSYNC)) {
|
||||
val = 0x03;
|
||||
}
|
||||
|
||||
regmap_update_bits(phy->regs, SUN8I_HDMI_PHY_DBG_CTRL_REG,
|
||||
SUN8I_HDMI_PHY_DBG_CTRL_POL_MASK,
|
||||
SUN8I_HDMI_PHY_DBG_CTRL_POL(val));
|
||||
|
||||
regmap_update_bits(phy->regs, SUN8I_HDMI_PHY_REXT_CTRL_REG,
|
||||
SUN8I_HDMI_PHY_REXT_CTRL_REXT_EN,
|
||||
SUN8I_HDMI_PHY_REXT_CTRL_REXT_EN);
|
||||
|
||||
/* power down */
|
||||
dw_hdmi_phy_gen2_txpwron(hdmi, 0);
|
||||
dw_hdmi_phy_gen2_pddq(hdmi, 1);
|
||||
|
||||
dw_hdmi_phy_reset(hdmi);
|
||||
|
||||
dw_hdmi_phy_gen2_pddq(hdmi, 0);
|
||||
|
||||
dw_hdmi_phy_i2c_set_addr(hdmi, I2C_ADDR);
|
||||
|
||||
/*
|
||||
* Values are taken from BSP HDMI driver. Although AW didn't
|
||||
* release any documentation, explanation of this values can
|
||||
* be found in i.MX 6Dual/6Quad Reference Manual.
|
||||
*/
|
||||
if (mode->crtc_clock <= 27000) {
|
||||
dw_hdmi_phy_i2c_write(hdmi, 0x01e0, 0x06);
|
||||
dw_hdmi_phy_i2c_write(hdmi, 0x0000, 0x15);
|
||||
dw_hdmi_phy_i2c_write(hdmi, 0x08da, 0x10);
|
||||
dw_hdmi_phy_i2c_write(hdmi, 0x0007, 0x19);
|
||||
dw_hdmi_phy_i2c_write(hdmi, 0x0318, 0x0e);
|
||||
dw_hdmi_phy_i2c_write(hdmi, 0x8009, 0x09);
|
||||
} else if (mode->crtc_clock <= 74250) {
|
||||
dw_hdmi_phy_i2c_write(hdmi, 0x0540, 0x06);
|
||||
dw_hdmi_phy_i2c_write(hdmi, 0x0005, 0x15);
|
||||
dw_hdmi_phy_i2c_write(hdmi, 0x0000, 0x10);
|
||||
dw_hdmi_phy_i2c_write(hdmi, 0x0007, 0x19);
|
||||
dw_hdmi_phy_i2c_write(hdmi, 0x02b5, 0x0e);
|
||||
dw_hdmi_phy_i2c_write(hdmi, 0x8009, 0x09);
|
||||
} else if (mode->crtc_clock <= 148500) {
|
||||
dw_hdmi_phy_i2c_write(hdmi, 0x04a0, 0x06);
|
||||
dw_hdmi_phy_i2c_write(hdmi, 0x000a, 0x15);
|
||||
dw_hdmi_phy_i2c_write(hdmi, 0x0000, 0x10);
|
||||
dw_hdmi_phy_i2c_write(hdmi, 0x0002, 0x19);
|
||||
dw_hdmi_phy_i2c_write(hdmi, 0x0021, 0x0e);
|
||||
dw_hdmi_phy_i2c_write(hdmi, 0x8029, 0x09);
|
||||
} else {
|
||||
dw_hdmi_phy_i2c_write(hdmi, 0x0000, 0x06);
|
||||
dw_hdmi_phy_i2c_write(hdmi, 0x000f, 0x15);
|
||||
dw_hdmi_phy_i2c_write(hdmi, 0x0000, 0x10);
|
||||
dw_hdmi_phy_i2c_write(hdmi, 0x0002, 0x19);
|
||||
dw_hdmi_phy_i2c_write(hdmi, 0x0000, 0x0e);
|
||||
dw_hdmi_phy_i2c_write(hdmi, 0x802b, 0x09);
|
||||
}
|
||||
|
||||
dw_hdmi_phy_i2c_write(hdmi, 0x0000, 0x1e);
|
||||
dw_hdmi_phy_i2c_write(hdmi, 0x0000, 0x13);
|
||||
dw_hdmi_phy_i2c_write(hdmi, 0x0000, 0x17);
|
||||
|
||||
dw_hdmi_phy_gen2_txpwron(hdmi, 1);
|
||||
|
||||
return 0;
|
||||
};
|
||||
|
||||
static void sun8i_hdmi_phy_disable(struct dw_hdmi *hdmi, void *data)
|
||||
{
|
||||
struct sun8i_hdmi_phy *phy = (struct sun8i_hdmi_phy *)data;
|
||||
|
||||
dw_hdmi_phy_gen2_txpwron(hdmi, 0);
|
||||
dw_hdmi_phy_gen2_pddq(hdmi, 1);
|
||||
|
||||
regmap_update_bits(phy->regs, SUN8I_HDMI_PHY_REXT_CTRL_REG,
|
||||
SUN8I_HDMI_PHY_REXT_CTRL_REXT_EN, 0);
|
||||
}
|
||||
|
||||
static const struct dw_hdmi_phy_ops sun8i_hdmi_phy_ops = {
|
||||
.init = &sun8i_hdmi_phy_config,
|
||||
.disable = &sun8i_hdmi_phy_disable,
|
||||
.read_hpd = &dw_hdmi_phy_read_hpd,
|
||||
.update_hpd = &dw_hdmi_phy_update_hpd,
|
||||
.setup_hpd = &dw_hdmi_phy_setup_hpd,
|
||||
};
|
||||
|
||||
void sun8i_hdmi_phy_init(struct sun8i_hdmi_phy *phy)
|
||||
{
|
||||
/* enable read access to HDMI controller */
|
||||
regmap_write(phy->regs, SUN8I_HDMI_PHY_READ_EN_REG,
|
||||
SUN8I_HDMI_PHY_READ_EN_MAGIC);
|
||||
|
||||
/* unscramble register offsets */
|
||||
regmap_write(phy->regs, SUN8I_HDMI_PHY_UNSCRAMBLE_REG,
|
||||
SUN8I_HDMI_PHY_UNSCRAMBLE_MAGIC);
|
||||
|
||||
regmap_update_bits(phy->regs, SUN8I_HDMI_PHY_DBG_CTRL_REG,
|
||||
SUN8I_HDMI_PHY_DBG_CTRL_PX_LOCK,
|
||||
SUN8I_HDMI_PHY_DBG_CTRL_PX_LOCK);
|
||||
|
||||
/*
|
||||
* Set PHY I2C address. It must match to the address set by
|
||||
* dw_hdmi_phy_set_slave_addr().
|
||||
*/
|
||||
regmap_update_bits(phy->regs, SUN8I_HDMI_PHY_DBG_CTRL_REG,
|
||||
SUN8I_HDMI_PHY_DBG_CTRL_ADDR_MASK,
|
||||
SUN8I_HDMI_PHY_DBG_CTRL_ADDR(I2C_ADDR));
|
||||
}
|
||||
|
||||
const struct dw_hdmi_phy_ops *sun8i_hdmi_phy_get_ops(void)
|
||||
{
|
||||
return &sun8i_hdmi_phy_ops;
|
||||
}
|
||||
|
||||
static struct regmap_config sun8i_hdmi_phy_regmap_config = {
|
||||
.reg_bits = 32,
|
||||
.val_bits = 32,
|
||||
.reg_stride = 4,
|
||||
.max_register = SUN8I_HDMI_PHY_UNSCRAMBLE_REG,
|
||||
.name = "phy"
|
||||
};
|
||||
|
||||
static const struct of_device_id sun8i_hdmi_phy_of_table[] = {
|
||||
{ .compatible = "allwinner,sun8i-a83t-hdmi-phy" },
|
||||
{ /* sentinel */ }
|
||||
};
|
||||
|
||||
int sun8i_hdmi_phy_probe(struct sun8i_dw_hdmi *hdmi, struct device_node *node)
|
||||
{
|
||||
struct device *dev = hdmi->dev;
|
||||
struct sun8i_hdmi_phy *phy;
|
||||
struct resource res;
|
||||
void __iomem *regs;
|
||||
int ret;
|
||||
|
||||
if (!of_match_node(sun8i_hdmi_phy_of_table, node)) {
|
||||
dev_err(dev, "Incompatible HDMI PHY\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
phy = devm_kzalloc(dev, sizeof(*phy), GFP_KERNEL);
|
||||
if (!phy)
|
||||
return -ENOMEM;
|
||||
|
||||
ret = of_address_to_resource(node, 0, &res);
|
||||
if (ret) {
|
||||
dev_err(dev, "phy: Couldn't get our resources\n");
|
||||
return ret;
|
||||
}
|
||||
|
||||
regs = devm_ioremap_resource(dev, &res);
|
||||
if (IS_ERR(regs)) {
|
||||
dev_err(dev, "Couldn't map the HDMI PHY registers\n");
|
||||
return PTR_ERR(regs);
|
||||
}
|
||||
|
||||
phy->regs = devm_regmap_init_mmio(dev, regs,
|
||||
&sun8i_hdmi_phy_regmap_config);
|
||||
if (IS_ERR(phy->regs)) {
|
||||
dev_err(dev, "Couldn't create the HDMI PHY regmap\n");
|
||||
return PTR_ERR(phy->regs);
|
||||
}
|
||||
|
||||
phy->clk_bus = of_clk_get_by_name(node, "bus");
|
||||
if (IS_ERR(phy->clk_bus)) {
|
||||
dev_err(dev, "Could not get bus clock\n");
|
||||
return PTR_ERR(phy->clk_bus);
|
||||
}
|
||||
|
||||
phy->clk_mod = of_clk_get_by_name(node, "mod");
|
||||
if (IS_ERR(phy->clk_mod)) {
|
||||
dev_err(dev, "Could not get mod clock\n");
|
||||
ret = PTR_ERR(phy->clk_mod);
|
||||
goto err_put_clk_bus;
|
||||
}
|
||||
|
||||
phy->rst_phy = of_reset_control_get_shared(node, "phy");
|
||||
if (IS_ERR(phy->rst_phy)) {
|
||||
dev_err(dev, "Could not get phy reset control\n");
|
||||
ret = PTR_ERR(phy->rst_phy);
|
||||
goto err_put_clk_mod;
|
||||
}
|
||||
|
||||
ret = reset_control_deassert(phy->rst_phy);
|
||||
if (ret) {
|
||||
dev_err(dev, "Cannot deassert phy reset control: %d\n", ret);
|
||||
goto err_put_rst_phy;
|
||||
}
|
||||
|
||||
ret = clk_prepare_enable(phy->clk_bus);
|
||||
if (ret) {
|
||||
dev_err(dev, "Cannot enable bus clock: %d\n", ret);
|
||||
goto err_deassert_rst_phy;
|
||||
}
|
||||
|
||||
ret = clk_prepare_enable(phy->clk_mod);
|
||||
if (ret) {
|
||||
dev_err(dev, "Cannot enable mod clock: %d\n", ret);
|
||||
goto err_disable_clk_bus;
|
||||
}
|
||||
|
||||
hdmi->phy = phy;
|
||||
|
||||
return 0;
|
||||
|
||||
err_disable_clk_bus:
|
||||
clk_disable_unprepare(phy->clk_bus);
|
||||
err_deassert_rst_phy:
|
||||
reset_control_assert(phy->rst_phy);
|
||||
err_put_rst_phy:
|
||||
reset_control_put(phy->rst_phy);
|
||||
err_put_clk_mod:
|
||||
clk_put(phy->clk_mod);
|
||||
err_put_clk_bus:
|
||||
clk_put(phy->clk_bus);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
void sun8i_hdmi_phy_remove(struct sun8i_dw_hdmi *hdmi)
|
||||
{
|
||||
struct sun8i_hdmi_phy *phy = hdmi->phy;
|
||||
|
||||
clk_disable_unprepare(phy->clk_mod);
|
||||
clk_disable_unprepare(phy->clk_bus);
|
||||
|
||||
reset_control_assert(phy->rst_phy);
|
||||
|
||||
reset_control_put(phy->rst_phy);
|
||||
|
||||
clk_put(phy->clk_mod);
|
||||
clk_put(phy->clk_bus);
|
||||
}
|
@ -485,6 +485,13 @@ static const struct sun8i_mixer_cfg sun8i_a83t_mixer0_cfg = {
|
||||
.vi_num = 1,
|
||||
};
|
||||
|
||||
static const struct sun8i_mixer_cfg sun8i_a83t_mixer1_cfg = {
|
||||
.ccsc = 1,
|
||||
.scaler_mask = 0x3,
|
||||
.ui_num = 1,
|
||||
.vi_num = 1,
|
||||
};
|
||||
|
||||
static const struct sun8i_mixer_cfg sun8i_v3s_mixer_cfg = {
|
||||
.vi_num = 2,
|
||||
.ui_num = 1,
|
||||
@ -498,6 +505,10 @@ static const struct of_device_id sun8i_mixer_of_table[] = {
|
||||
.compatible = "allwinner,sun8i-a83t-de2-mixer-0",
|
||||
.data = &sun8i_a83t_mixer0_cfg,
|
||||
},
|
||||
{
|
||||
.compatible = "allwinner,sun8i-a83t-de2-mixer-1",
|
||||
.data = &sun8i_a83t_mixer1_cfg,
|
||||
},
|
||||
{
|
||||
.compatible = "allwinner,sun8i-v3s-de2-mixer",
|
||||
.data = &sun8i_v3s_mixer_cfg,
|
||||
|
@ -3,8 +3,6 @@ menuconfig DRM_TINYDRM
|
||||
depends on DRM
|
||||
select DRM_KMS_HELPER
|
||||
select DRM_KMS_CMA_HELPER
|
||||
select BACKLIGHT_LCD_SUPPORT
|
||||
select BACKLIGHT_CLASS_DEVICE
|
||||
help
|
||||
Choose this option if you have a tinydrm supported display.
|
||||
If M is selected the module will be called tinydrm.
|
||||
|
@ -236,101 +236,6 @@ void tinydrm_xrgb8888_to_gray8(u8 *dst, void *vaddr, struct drm_framebuffer *fb,
|
||||
}
|
||||
EXPORT_SYMBOL(tinydrm_xrgb8888_to_gray8);
|
||||
|
||||
/**
|
||||
* tinydrm_of_find_backlight - Find backlight device in device-tree
|
||||
* @dev: Device
|
||||
*
|
||||
* This function looks for a DT node pointed to by a property named 'backlight'
|
||||
* and uses of_find_backlight_by_node() to get the backlight device.
|
||||
* Additionally if the brightness property is zero, it is set to
|
||||
* max_brightness.
|
||||
*
|
||||
* Returns:
|
||||
* NULL if there's no backlight property.
|
||||
* Error pointer -EPROBE_DEFER if the DT node is found, but no backlight device
|
||||
* is found.
|
||||
* If the backlight device is found, a pointer to the structure is returned.
|
||||
*/
|
||||
struct backlight_device *tinydrm_of_find_backlight(struct device *dev)
|
||||
{
|
||||
struct backlight_device *backlight;
|
||||
struct device_node *np;
|
||||
|
||||
np = of_parse_phandle(dev->of_node, "backlight", 0);
|
||||
if (!np)
|
||||
return NULL;
|
||||
|
||||
backlight = of_find_backlight_by_node(np);
|
||||
of_node_put(np);
|
||||
|
||||
if (!backlight)
|
||||
return ERR_PTR(-EPROBE_DEFER);
|
||||
|
||||
if (!backlight->props.brightness) {
|
||||
backlight->props.brightness = backlight->props.max_brightness;
|
||||
DRM_DEBUG_KMS("Backlight brightness set to %d\n",
|
||||
backlight->props.brightness);
|
||||
}
|
||||
|
||||
return backlight;
|
||||
}
|
||||
EXPORT_SYMBOL(tinydrm_of_find_backlight);
|
||||
|
||||
/**
|
||||
* tinydrm_enable_backlight - Enable backlight helper
|
||||
* @backlight: Backlight device
|
||||
*
|
||||
* Returns:
|
||||
* Zero on success, negative error code on failure.
|
||||
*/
|
||||
int tinydrm_enable_backlight(struct backlight_device *backlight)
|
||||
{
|
||||
unsigned int old_state;
|
||||
int ret;
|
||||
|
||||
if (!backlight)
|
||||
return 0;
|
||||
|
||||
old_state = backlight->props.state;
|
||||
backlight->props.state &= ~BL_CORE_FBBLANK;
|
||||
DRM_DEBUG_KMS("Backlight state: 0x%x -> 0x%x\n", old_state,
|
||||
backlight->props.state);
|
||||
|
||||
ret = backlight_update_status(backlight);
|
||||
if (ret)
|
||||
DRM_ERROR("Failed to enable backlight %d\n", ret);
|
||||
|
||||
return ret;
|
||||
}
|
||||
EXPORT_SYMBOL(tinydrm_enable_backlight);
|
||||
|
||||
/**
|
||||
* tinydrm_disable_backlight - Disable backlight helper
|
||||
* @backlight: Backlight device
|
||||
*
|
||||
* Returns:
|
||||
* Zero on success, negative error code on failure.
|
||||
*/
|
||||
int tinydrm_disable_backlight(struct backlight_device *backlight)
|
||||
{
|
||||
unsigned int old_state;
|
||||
int ret;
|
||||
|
||||
if (!backlight)
|
||||
return 0;
|
||||
|
||||
old_state = backlight->props.state;
|
||||
backlight->props.state |= BL_CORE_FBBLANK;
|
||||
DRM_DEBUG_KMS("Backlight state: 0x%x -> 0x%x\n", old_state,
|
||||
backlight->props.state);
|
||||
ret = backlight_update_status(backlight);
|
||||
if (ret)
|
||||
DRM_ERROR("Failed to disable backlight %d\n", ret);
|
||||
|
||||
return ret;
|
||||
}
|
||||
EXPORT_SYMBOL(tinydrm_disable_backlight);
|
||||
|
||||
#if IS_ENABLED(CONFIG_SPI)
|
||||
|
||||
/**
|
||||
|
@ -9,6 +9,7 @@
|
||||
* (at your option) any later version.
|
||||
*/
|
||||
|
||||
#include <linux/backlight.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/gpio/consumer.h>
|
||||
#include <linux/module.h>
|
||||
@ -195,7 +196,7 @@ static int mi0283qt_probe(struct spi_device *spi)
|
||||
if (IS_ERR(mipi->regulator))
|
||||
return PTR_ERR(mipi->regulator);
|
||||
|
||||
mipi->backlight = tinydrm_of_find_backlight(dev);
|
||||
mipi->backlight = devm_of_find_backlight(dev);
|
||||
if (IS_ERR(mipi->backlight))
|
||||
return PTR_ERR(mipi->backlight);
|
||||
|
||||
|
@ -286,7 +286,7 @@ void mipi_dbi_enable_flush(struct mipi_dbi *mipi)
|
||||
if (fb)
|
||||
fb->funcs->dirty(fb, NULL, 0, 0, NULL, 0);
|
||||
|
||||
tinydrm_enable_backlight(mipi->backlight);
|
||||
backlight_enable(mipi->backlight);
|
||||
}
|
||||
EXPORT_SYMBOL(mipi_dbi_enable_flush);
|
||||
|
||||
@ -325,7 +325,7 @@ void mipi_dbi_pipe_disable(struct drm_simple_display_pipe *pipe)
|
||||
mipi->enabled = false;
|
||||
|
||||
if (mipi->backlight)
|
||||
tinydrm_disable_backlight(mipi->backlight);
|
||||
backlight_disable(mipi->backlight);
|
||||
else
|
||||
mipi_dbi_blank(mipi);
|
||||
|
||||
|
@ -5,6 +5,7 @@
|
||||
* Copyright 2017 David Lechner <david@lechnology.com>
|
||||
*/
|
||||
|
||||
#include <linux/backlight.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/dma-buf.h>
|
||||
#include <linux/gpio/consumer.h>
|
||||
@ -163,7 +164,7 @@ static int st7735r_probe(struct spi_device *spi)
|
||||
return PTR_ERR(dc);
|
||||
}
|
||||
|
||||
mipi->backlight = tinydrm_of_find_backlight(dev);
|
||||
mipi->backlight = devm_of_find_backlight(dev);
|
||||
if (IS_ERR(mipi->backlight))
|
||||
return PTR_ERR(mipi->backlight);
|
||||
|
||||
|
@ -580,6 +580,79 @@ struct backlight_device *of_find_backlight_by_node(struct device_node *node)
|
||||
EXPORT_SYMBOL(of_find_backlight_by_node);
|
||||
#endif
|
||||
|
||||
/**
|
||||
* of_find_backlight - Get backlight device
|
||||
* @dev: Device
|
||||
*
|
||||
* This function looks for a property named 'backlight' on the DT node
|
||||
* connected to @dev and looks up the backlight device.
|
||||
*
|
||||
* Call backlight_put() to drop the reference on the backlight device.
|
||||
*
|
||||
* Returns:
|
||||
* A pointer to the backlight device if found.
|
||||
* Error pointer -EPROBE_DEFER if the DT property is set, but no backlight
|
||||
* device is found.
|
||||
* NULL if there's no backlight property.
|
||||
*/
|
||||
struct backlight_device *of_find_backlight(struct device *dev)
|
||||
{
|
||||
struct backlight_device *bd = NULL;
|
||||
struct device_node *np;
|
||||
|
||||
if (!dev)
|
||||
return NULL;
|
||||
|
||||
if (IS_ENABLED(CONFIG_OF) && dev->of_node) {
|
||||
np = of_parse_phandle(dev->of_node, "backlight", 0);
|
||||
if (np) {
|
||||
bd = of_find_backlight_by_node(np);
|
||||
of_node_put(np);
|
||||
if (!bd)
|
||||
return ERR_PTR(-EPROBE_DEFER);
|
||||
/*
|
||||
* Note: gpio_backlight uses brightness as
|
||||
* power state during probe
|
||||
*/
|
||||
if (!bd->props.brightness)
|
||||
bd->props.brightness = bd->props.max_brightness;
|
||||
}
|
||||
}
|
||||
|
||||
return bd;
|
||||
}
|
||||
EXPORT_SYMBOL(of_find_backlight);
|
||||
|
||||
static void devm_backlight_release(void *data)
|
||||
{
|
||||
backlight_put(data);
|
||||
}
|
||||
|
||||
/**
|
||||
* devm_of_find_backlight - Resource-managed of_find_backlight()
|
||||
* @dev: Device
|
||||
*
|
||||
* Device managed version of of_find_backlight().
|
||||
* The reference on the backlight device is automatically
|
||||
* dropped on driver detach.
|
||||
*/
|
||||
struct backlight_device *devm_of_find_backlight(struct device *dev)
|
||||
{
|
||||
struct backlight_device *bd;
|
||||
int ret;
|
||||
|
||||
bd = of_find_backlight(dev);
|
||||
if (IS_ERR_OR_NULL(bd))
|
||||
return bd;
|
||||
ret = devm_add_action(dev, devm_backlight_release, bd);
|
||||
if (ret) {
|
||||
backlight_put(bd);
|
||||
return ERR_PTR(ret);
|
||||
}
|
||||
return bd;
|
||||
}
|
||||
EXPORT_SYMBOL(devm_of_find_backlight);
|
||||
|
||||
static void __exit backlight_class_exit(void)
|
||||
{
|
||||
class_destroy(backlight_class);
|
||||
|
@ -143,12 +143,13 @@ struct dw_hdmi_plat_data {
|
||||
unsigned long mpixelclock);
|
||||
};
|
||||
|
||||
int dw_hdmi_probe(struct platform_device *pdev,
|
||||
const struct dw_hdmi_plat_data *plat_data);
|
||||
void dw_hdmi_remove(struct platform_device *pdev);
|
||||
void dw_hdmi_unbind(struct device *dev);
|
||||
int dw_hdmi_bind(struct platform_device *pdev, struct drm_encoder *encoder,
|
||||
const struct dw_hdmi_plat_data *plat_data);
|
||||
struct dw_hdmi *dw_hdmi_probe(struct platform_device *pdev,
|
||||
const struct dw_hdmi_plat_data *plat_data);
|
||||
void dw_hdmi_remove(struct dw_hdmi *hdmi);
|
||||
void dw_hdmi_unbind(struct dw_hdmi *hdmi);
|
||||
struct dw_hdmi *dw_hdmi_bind(struct platform_device *pdev,
|
||||
struct drm_encoder *encoder,
|
||||
const struct dw_hdmi_plat_data *plat_data);
|
||||
|
||||
void dw_hdmi_setup_rx_sense(struct device *dev, bool hpd, bool rx_sense);
|
||||
|
||||
@ -157,7 +158,18 @@ void dw_hdmi_audio_enable(struct dw_hdmi *hdmi);
|
||||
void dw_hdmi_audio_disable(struct dw_hdmi *hdmi);
|
||||
|
||||
/* PHY configuration */
|
||||
void dw_hdmi_phy_i2c_set_addr(struct dw_hdmi *hdmi, u8 address);
|
||||
void dw_hdmi_phy_i2c_write(struct dw_hdmi *hdmi, unsigned short data,
|
||||
unsigned char addr);
|
||||
|
||||
void dw_hdmi_phy_gen2_pddq(struct dw_hdmi *hdmi, u8 enable);
|
||||
void dw_hdmi_phy_gen2_txpwron(struct dw_hdmi *hdmi, u8 enable);
|
||||
void dw_hdmi_phy_reset(struct dw_hdmi *hdmi);
|
||||
|
||||
enum drm_connector_status dw_hdmi_phy_read_hpd(struct dw_hdmi *hdmi,
|
||||
void *data);
|
||||
void dw_hdmi_phy_update_hpd(struct dw_hdmi *hdmi, void *data,
|
||||
bool force, bool disabled, bool rxsense);
|
||||
void dw_hdmi_phy_setup_hpd(struct dw_hdmi *hdmi, void *data);
|
||||
|
||||
#endif /* __IMX_HDMI_H__ */
|
||||
|
@ -342,7 +342,11 @@ int drm_display_info_set_bus_formats(struct drm_display_info *info,
|
||||
/**
|
||||
* struct drm_tv_connector_state - TV connector related states
|
||||
* @subconnector: selected subconnector
|
||||
* @margins: left/right/top/bottom margins
|
||||
* @margins: margins
|
||||
* @margins.left: left margin
|
||||
* @margins.right: right margin
|
||||
* @margins.top: top margin
|
||||
* @margins.bottom: bottom margin
|
||||
* @mode: TV mode
|
||||
* @brightness: brightness in percent
|
||||
* @contrast: contrast in percent
|
||||
|
@ -329,6 +329,13 @@
|
||||
# define DP_DS_12BPC 2
|
||||
# define DP_DS_16BPC 3
|
||||
|
||||
/* DP Forward error Correction Registers */
|
||||
#define DP_FEC_CAPABILITY 0x090 /* 1.4 */
|
||||
# define DP_FEC_CAPABLE (1 << 0)
|
||||
# define DP_FEC_UNCORR_BLK_ERROR_COUNT_CAP (1 << 1)
|
||||
# define DP_FEC_CORR_BLK_ERROR_COUNT_CAP (1 << 2)
|
||||
# define DP_FEC_BIT_ERROR_COUNT_CAP (1 << 3)
|
||||
|
||||
/* link configuration */
|
||||
#define DP_LINK_BW_SET 0x100
|
||||
# define DP_LINK_RATE_TABLE 0x00 /* eDP 1.4 */
|
||||
@ -445,6 +452,19 @@
|
||||
#define DP_UPSTREAM_DEVICE_DP_PWR_NEED 0x118 /* 1.2 */
|
||||
# define DP_PWR_NOT_NEEDED (1 << 0)
|
||||
|
||||
#define DP_FEC_CONFIGURATION 0x120 /* 1.4 */
|
||||
# define DP_FEC_READY (1 << 0)
|
||||
# define DP_FEC_ERR_COUNT_SEL_MASK (7 << 1)
|
||||
# define DP_FEC_ERR_COUNT_DIS (0 << 1)
|
||||
# define DP_FEC_UNCORR_BLK_ERROR_COUNT (1 << 1)
|
||||
# define DP_FEC_CORR_BLK_ERROR_COUNT (2 << 1)
|
||||
# define DP_FEC_BIT_ERROR_COUNT (3 << 1)
|
||||
# define DP_FEC_LANE_SELECT_MASK (3 << 4)
|
||||
# define DP_FEC_LANE_0_SELECT (0 << 4)
|
||||
# define DP_FEC_LANE_1_SELECT (1 << 4)
|
||||
# define DP_FEC_LANE_2_SELECT (2 << 4)
|
||||
# define DP_FEC_LANE_3_SELECT (3 << 4)
|
||||
|
||||
#define DP_AUX_FRAME_SYNC_VALUE 0x15c /* eDP 1.4 */
|
||||
# define DP_AUX_FRAME_SYNC_VALID (1 << 0)
|
||||
|
||||
@ -620,6 +640,16 @@
|
||||
#define DP_TEST_SINK 0x270
|
||||
# define DP_TEST_SINK_START (1 << 0)
|
||||
|
||||
#define DP_FEC_STATUS 0x280 /* 1.4 */
|
||||
# define DP_FEC_DECODE_EN_DETECTED (1 << 0)
|
||||
# define DP_FEC_DECODE_DIS_DETECTED (1 << 1)
|
||||
|
||||
#define DP_FEC_ERROR_COUNT_LSB 0x0281 /* 1.4 */
|
||||
|
||||
#define DP_FEC_ERROR_COUNT_MSB 0x0282 /* 1.4 */
|
||||
# define DP_FEC_ERROR_COUNT_MASK 0x7F
|
||||
# define DP_FEC_ERR_COUNT_VALID (1 << 7)
|
||||
|
||||
#define DP_PAYLOAD_TABLE_UPDATE_STATUS 0x2c0 /* 1.2 MST */
|
||||
# define DP_PAYLOAD_TABLE_UPDATED (1 << 0)
|
||||
# define DP_PAYLOAD_ACT_HANDLED (1 << 1)
|
||||
|
@ -21,6 +21,20 @@ struct drm_simple_display_pipe;
|
||||
* display pipeline
|
||||
*/
|
||||
struct drm_simple_display_pipe_funcs {
|
||||
/**
|
||||
* @mode_valid:
|
||||
*
|
||||
* This function is called to filter out valid modes from the
|
||||
* suggestions suggested by the bridge or display. This optional
|
||||
* hook is passed in when initializing the pipeline.
|
||||
*
|
||||
* RETURNS:
|
||||
*
|
||||
* drm_mode_status Enum
|
||||
*/
|
||||
enum drm_mode_status (*mode_valid)(struct drm_crtc *crtc,
|
||||
const struct drm_display_mode *mode);
|
||||
|
||||
/**
|
||||
* @enable:
|
||||
*
|
||||
|
@ -55,8 +55,24 @@ struct drm_pending_vblank_event {
|
||||
* @event: Actual event which will be sent to userspace.
|
||||
*/
|
||||
union {
|
||||
/**
|
||||
* @event.base: DRM event base class.
|
||||
*/
|
||||
struct drm_event base;
|
||||
|
||||
/**
|
||||
* @event.vbl:
|
||||
*
|
||||
* Event payload for vblank events, requested through
|
||||
* either the MODE_PAGE_FLIP or MODE_ATOMIC IOCTL. Also
|
||||
* generated by the legacy WAIT_VBLANK IOCTL, but new userspace
|
||||
* should use MODE_QUEUE_SEQUENCE and &event.seq instead.
|
||||
*/
|
||||
struct drm_event_vblank vbl;
|
||||
|
||||
/**
|
||||
* @event.seq: Event payload for the MODE_QUEUEU_SEQUENCE IOCTL.
|
||||
*/
|
||||
struct drm_event_crtc_sequence seq;
|
||||
} event;
|
||||
};
|
||||
|
@ -46,10 +46,6 @@ void tinydrm_xrgb8888_to_rgb565(u16 *dst, void *vaddr,
|
||||
void tinydrm_xrgb8888_to_gray8(u8 *dst, void *vaddr, struct drm_framebuffer *fb,
|
||||
struct drm_clip_rect *clip);
|
||||
|
||||
struct backlight_device *tinydrm_of_find_backlight(struct device *dev);
|
||||
int tinydrm_enable_backlight(struct backlight_device *backlight);
|
||||
int tinydrm_disable_backlight(struct backlight_device *backlight);
|
||||
|
||||
size_t tinydrm_spi_max_transfer_size(struct spi_device *spi, size_t max_len);
|
||||
bool tinydrm_spi_bpw_supported(struct spi_device *spi, u8 bpw);
|
||||
int tinydrm_spi_transfer(struct spi_device *spi, u32 speed_hz,
|
||||
|
@ -130,6 +130,48 @@ static inline int backlight_update_status(struct backlight_device *bd)
|
||||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* backlight_enable - Enable backlight
|
||||
* @bd: the backlight device to enable
|
||||
*/
|
||||
static inline int backlight_enable(struct backlight_device *bd)
|
||||
{
|
||||
if (!bd)
|
||||
return 0;
|
||||
|
||||
bd->props.power = FB_BLANK_UNBLANK;
|
||||
bd->props.fb_blank = FB_BLANK_UNBLANK;
|
||||
bd->props.state &= ~BL_CORE_FBBLANK;
|
||||
|
||||
return backlight_update_status(bd);
|
||||
}
|
||||
|
||||
/**
|
||||
* backlight_disable - Disable backlight
|
||||
* @bd: the backlight device to disable
|
||||
*/
|
||||
static inline int backlight_disable(struct backlight_device *bd)
|
||||
{
|
||||
if (!bd)
|
||||
return 0;
|
||||
|
||||
bd->props.power = FB_BLANK_POWERDOWN;
|
||||
bd->props.fb_blank = FB_BLANK_POWERDOWN;
|
||||
bd->props.state |= BL_CORE_FBBLANK;
|
||||
|
||||
return backlight_update_status(bd);
|
||||
}
|
||||
|
||||
/**
|
||||
* backlight_put - Drop backlight reference
|
||||
* @bd: the backlight device to put
|
||||
*/
|
||||
static inline void backlight_put(struct backlight_device *bd)
|
||||
{
|
||||
if (bd)
|
||||
put_device(&bd->dev);
|
||||
}
|
||||
|
||||
extern struct backlight_device *backlight_device_register(const char *name,
|
||||
struct device *dev, void *devdata, const struct backlight_ops *ops,
|
||||
const struct backlight_properties *props);
|
||||
@ -173,4 +215,20 @@ of_find_backlight_by_node(struct device_node *node)
|
||||
}
|
||||
#endif
|
||||
|
||||
#if IS_ENABLED(CONFIG_BACKLIGHT_CLASS_DEVICE)
|
||||
struct backlight_device *of_find_backlight(struct device *dev);
|
||||
struct backlight_device *devm_of_find_backlight(struct device *dev);
|
||||
#else
|
||||
static inline struct backlight_device *of_find_backlight(struct device *dev)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static inline struct backlight_device *
|
||||
devm_of_find_backlight(struct device *dev)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
Loading…
Reference in New Issue
Block a user