drm-misc-next for 5.7:
UAPI Changes: Cross-subsystem Changes: Core Changes: - crtc: Drop get_crtc callback - dp: Add support for DP1.4 EDID corruption test - edid: Improve CEA detailed timings support - format-helper: Move to a GPL2/MIT dual license - mode: Drop drm_display_mode.private - vblank: Convert drm-driver vblank related code to CRTC equivalents and cleanup the core. - drm_global_mutex reworks Driver Changes: - hibmc: Add gamma_set support and improve DPMS support - pl111: Support Integrator IM-PD1 - sun4i: LVDS support for the A20, improvements to panel handling in DSI - virtio: job batching improvements, mem handling code rework - panel: Support for Rocktech RK101II01D-CT - bridge: Support for ADV7535, tc358768, improvements to ti-sn65dsi86 -----BEGIN PGP SIGNATURE----- iHUEABYIAB0WIQRcEzekXsqa64kGDp7j7w1vZxhRxQUCXk+sKwAKCRDj7w1vZxhR xcS3AQDfXBrUSIie1dYFjOj+WsmK51ZctshnZ5c5jAR5yrmctgEA7xAfn+ZL0F5R PEJoUwjboiw59Z7SsJq6Lw1L3t40Mwo= =OftW -----END PGP SIGNATURE----- Merge tag 'drm-misc-next-2020-02-21' of git://anongit.freedesktop.org/drm/drm-misc into drm-next drm-misc-next for 5.7: UAPI Changes: Cross-subsystem Changes: Core Changes: - crtc: Drop get_crtc callback - dp: Add support for DP1.4 EDID corruption test - edid: Improve CEA detailed timings support - format-helper: Move to a GPL2/MIT dual license - mode: Drop drm_display_mode.private - vblank: Convert drm-driver vblank related code to CRTC equivalents and cleanup the core. - drm_global_mutex reworks Driver Changes: - hibmc: Add gamma_set support and improve DPMS support - pl111: Support Integrator IM-PD1 - sun4i: LVDS support for the A20, improvements to panel handling in DSI - virtio: job batching improvements, mem handling code rework - panel: Support for Rocktech RK101II01D-CT - bridge: Support for ADV7535, tc358768, improvements to ti-sn65dsi86 Signed-off-by: Dave Airlie <airlied@redhat.com> From: Maxime Ripard <maxime@cerno.tech> Link: https://patchwork.freedesktop.org/patch/msgid/20200221100928.anipic2v7q5wswkb@gilmour.lanalistair/sensors
commit
aaa9d265a2
|
@ -34,6 +34,12 @@ properties:
|
|||
- const: allwinner,sun9i-a80-tcon-lcd
|
||||
- const: allwinner,sun9i-a80-tcon-tv
|
||||
|
||||
- items:
|
||||
- enum:
|
||||
- allwinner,sun7i-a20-tcon0
|
||||
- allwinner,sun7i-a20-tcon1
|
||||
- const: allwinner,sun7i-a20-tcon
|
||||
|
||||
- items:
|
||||
- enum:
|
||||
- allwinner,sun50i-a64-tcon-lcd
|
||||
|
|
|
@ -1,10 +1,10 @@
|
|||
Analog Device ADV7511(W)/13/33 HDMI Encoders
|
||||
Analog Device ADV7511(W)/13/33/35 HDMI Encoders
|
||||
-----------------------------------------
|
||||
|
||||
The ADV7511, ADV7511W, ADV7513 and ADV7533 are HDMI audio and video transmitters
|
||||
compatible with HDMI 1.4 and DVI 1.0. They support color space conversion,
|
||||
S/PDIF, CEC and HDCP. ADV7533 supports the DSI interface for input pixels, while
|
||||
the others support RGB interface.
|
||||
The ADV7511, ADV7511W, ADV7513, ADV7533 and ADV7535 are HDMI audio and video
|
||||
transmitters compatible with HDMI 1.4 and DVI 1.0. They support color space
|
||||
conversion, S/PDIF, CEC and HDCP. ADV7533/5 supports the DSI interface for input
|
||||
pixels, while the others support RGB interface.
|
||||
|
||||
Required properties:
|
||||
|
||||
|
@ -13,6 +13,7 @@ Required properties:
|
|||
"adi,adv7511w"
|
||||
"adi,adv7513"
|
||||
"adi,adv7533"
|
||||
"adi,adv7535"
|
||||
|
||||
- reg: I2C slave addresses
|
||||
The ADV7511 internal registers are split into four pages exposed through
|
||||
|
@ -52,14 +53,14 @@ The following input format properties are required except in "rgb 1x" and
|
|||
- bgvdd-supply: A 1.8V supply that powers up the BGVDD pin. This is
|
||||
needed only for ADV7511.
|
||||
|
||||
The following properties are required for ADV7533:
|
||||
The following properties are required for ADV7533 and ADV7535:
|
||||
|
||||
- adi,dsi-lanes: Number of DSI data lanes connected to the DSI host. It should
|
||||
be one of 1, 2, 3 or 4.
|
||||
- a2vdd-supply: 1.8V supply that powers up the A2VDD pin on the chip.
|
||||
- v3p3-supply: A 3.3V supply that powers up the V3P3 pin on the chip.
|
||||
- v1p2-supply: A supply that powers up the V1P2 pin on the chip. It can be
|
||||
either 1.2V or 1.8V.
|
||||
either 1.2V or 1.8V for ADV7533 but only 1.8V for ADV7535.
|
||||
|
||||
Optional properties:
|
||||
|
||||
|
@ -71,9 +72,9 @@ Optional properties:
|
|||
- adi,embedded-sync: The input uses synchronization signals embedded in the
|
||||
data stream (similar to BT.656). Defaults to separate H/V synchronization
|
||||
signals.
|
||||
- adi,disable-timing-generator: Only for ADV7533. Disables the internal timing
|
||||
generator. The chip will rely on the sync signals in the DSI data lanes,
|
||||
rather than generate its own timings for HDMI output.
|
||||
- adi,disable-timing-generator: Only for ADV7533 and ADV7535. Disables the
|
||||
internal timing generator. The chip will rely on the sync signals in the
|
||||
DSI data lanes, rather than generate its own timings for HDMI output.
|
||||
- clocks: from common clock binding: reference to the CEC clock.
|
||||
- clock-names: from common clock binding: must be "cec".
|
||||
- reg-names : Names of maps with programmable addresses.
|
||||
|
@ -85,7 +86,7 @@ Required nodes:
|
|||
The ADV7511 has two video ports. Their connections are modelled using the OF
|
||||
graph bindings specified in Documentation/devicetree/bindings/graph.txt.
|
||||
|
||||
- Video port 0 for the RGB, YUV or DSI input. In the case of ADV7533, the
|
||||
- Video port 0 for the RGB, YUV or DSI input. In the case of ADV7533/5, the
|
||||
remote endpoint phandle should be a reference to a valid mipi_dsi_host device
|
||||
node.
|
||||
- Video port 1 for the HDMI output
|
||||
|
|
|
@ -0,0 +1,159 @@
|
|||
# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
|
||||
%YAML 1.2
|
||||
---
|
||||
$id: http://devicetree.org/schemas/display/bridge/toshiba,tc358768.yaml#
|
||||
$schema: http://devicetree.org/meta-schemas/core.yaml#
|
||||
|
||||
title: Toschiba TC358768/TC358778 Parallel RGB to MIPI DSI bridge
|
||||
|
||||
maintainers:
|
||||
- Peter Ujfalusi <peter.ujfalusi@ti.com>
|
||||
|
||||
description: |
|
||||
The TC358768/TC358778 is bridge device which converts RGB to DSI.
|
||||
|
||||
properties:
|
||||
compatible:
|
||||
enum:
|
||||
- toshiba,tc358768
|
||||
- toshiba,tc358778
|
||||
|
||||
reg:
|
||||
maxItems: 1
|
||||
description: base I2C address of the device
|
||||
|
||||
reset-gpios:
|
||||
maxItems: 1
|
||||
description: GPIO connected to active low RESX pin
|
||||
|
||||
vddc-supply:
|
||||
description: Regulator for 1.2V internal core power.
|
||||
|
||||
vddmipi-supply:
|
||||
description: Regulator for 1.2V for the MIPI.
|
||||
|
||||
vddio-supply:
|
||||
description: Regulator for 1.8V - 3.3V IO power.
|
||||
|
||||
clocks:
|
||||
maxItems: 1
|
||||
|
||||
clock-names:
|
||||
const: refclk
|
||||
|
||||
ports:
|
||||
type: object
|
||||
|
||||
properties:
|
||||
"#address-cells":
|
||||
const: 1
|
||||
|
||||
"#size-cells":
|
||||
const: 0
|
||||
|
||||
port@0:
|
||||
type: object
|
||||
additionalProperties: false
|
||||
|
||||
description: |
|
||||
Video port for RGB input
|
||||
|
||||
properties:
|
||||
reg:
|
||||
const: 0
|
||||
|
||||
patternProperties:
|
||||
endpoint:
|
||||
type: object
|
||||
additionalProperties: false
|
||||
|
||||
properties:
|
||||
data-lines:
|
||||
enum: [ 16, 18, 24 ]
|
||||
|
||||
remote-endpoint: true
|
||||
|
||||
required:
|
||||
- reg
|
||||
|
||||
port@1:
|
||||
type: object
|
||||
additionalProperties: false
|
||||
|
||||
description: |
|
||||
Video port for DSI output (panel or connector).
|
||||
|
||||
properties:
|
||||
reg:
|
||||
const: 1
|
||||
|
||||
patternProperties:
|
||||
endpoint:
|
||||
type: object
|
||||
additionalProperties: false
|
||||
|
||||
properties:
|
||||
remote-endpoint: true
|
||||
|
||||
required:
|
||||
- reg
|
||||
|
||||
required:
|
||||
- "#address-cells"
|
||||
- "#size-cells"
|
||||
- port@0
|
||||
- port@1
|
||||
|
||||
required:
|
||||
- compatible
|
||||
- reg
|
||||
- vddc-supply
|
||||
- vddmipi-supply
|
||||
- vddio-supply
|
||||
- ports
|
||||
|
||||
additionalProperties: false
|
||||
|
||||
examples:
|
||||
- |
|
||||
#include <dt-bindings/gpio/gpio.h>
|
||||
|
||||
i2c1 {
|
||||
#address-cells = <1>;
|
||||
#size-cells = <0>;
|
||||
|
||||
dsi_bridge: dsi-bridge@e {
|
||||
compatible = "toshiba,tc358768";
|
||||
reg = <0xe>;
|
||||
|
||||
clocks = <&tc358768_refclk>;
|
||||
clock-names = "refclk";
|
||||
|
||||
reset-gpios = <&pcf_display_board 0 GPIO_ACTIVE_LOW>;
|
||||
|
||||
vddc-supply = <&v1_2d>;
|
||||
vddmipi-supply = <&v1_2d>;
|
||||
vddio-supply = <&v3_3d>;
|
||||
|
||||
dsi_bridge_ports: ports {
|
||||
#address-cells = <1>;
|
||||
#size-cells = <0>;
|
||||
|
||||
port@0 {
|
||||
reg = <0>;
|
||||
rgb_in: endpoint {
|
||||
remote-endpoint = <&dpi_out>;
|
||||
data-lines = <24>;
|
||||
};
|
||||
};
|
||||
|
||||
port@1 {
|
||||
reg = <1>;
|
||||
dsi_out: endpoint {
|
||||
remote-endpoint = <&lcd_in>;
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
|
|
@ -201,6 +201,8 @@ properties:
|
|||
- osddisplays,osd101t2045-53ts
|
||||
# QiaoDian XianShi Corporation 4"3 TFT LCD panel
|
||||
- qiaodian,qd43003c0-40
|
||||
# Rocktech Displays Ltd. RK101II01D-CT 10.1" TFT 1280x800
|
||||
- rocktech,rk101ii01d-ct
|
||||
# Rocktech Display Ltd. RK070ER9427 800(RGB)x480 TFT LCD panel
|
||||
- rocktech,rk070er9427
|
||||
# Samsung 12.2" (2560x1600 pixels) TFT LCD panel
|
||||
|
|
|
@ -6,7 +6,7 @@ config SYNC_FILE
|
|||
default n
|
||||
select DMA_SHARED_BUFFER
|
||||
---help---
|
||||
The Sync File Framework adds explicit syncronization via
|
||||
The Sync File Framework adds explicit synchronization via
|
||||
userspace. It enables send/receive 'struct dma_fence' objects to/from
|
||||
userspace via Sync File fds for synchronization between drivers via
|
||||
userspace components. It has been ported from Android.
|
||||
|
|
|
@ -1174,9 +1174,9 @@ void amdgpu_driver_postclose_kms(struct drm_device *dev,
|
|||
int amdgpu_device_ip_suspend(struct amdgpu_device *adev);
|
||||
int amdgpu_device_suspend(struct drm_device *dev, bool fbcon);
|
||||
int amdgpu_device_resume(struct drm_device *dev, bool fbcon);
|
||||
u32 amdgpu_get_vblank_counter_kms(struct drm_device *dev, unsigned int pipe);
|
||||
int amdgpu_enable_vblank_kms(struct drm_device *dev, unsigned int pipe);
|
||||
void amdgpu_disable_vblank_kms(struct drm_device *dev, unsigned int pipe);
|
||||
u32 amdgpu_get_vblank_counter_kms(struct drm_crtc *crtc);
|
||||
int amdgpu_enable_vblank_kms(struct drm_crtc *crtc);
|
||||
void amdgpu_disable_vblank_kms(struct drm_crtc *crtc);
|
||||
long amdgpu_kms_compat_ioctl(struct file *filp, unsigned int cmd,
|
||||
unsigned long arg);
|
||||
|
||||
|
|
|
@ -99,7 +99,7 @@ static void amdgpu_display_flip_work_func(struct work_struct *__work)
|
|||
& (DRM_SCANOUTPOS_VALID | DRM_SCANOUTPOS_IN_VBLANK)) ==
|
||||
(DRM_SCANOUTPOS_VALID | DRM_SCANOUTPOS_IN_VBLANK) &&
|
||||
(int)(work->target_vblank -
|
||||
amdgpu_get_vblank_counter_kms(adev->ddev, amdgpu_crtc->crtc_id)) > 0) {
|
||||
amdgpu_get_vblank_counter_kms(crtc)) > 0) {
|
||||
schedule_delayed_work(&work->flip_work, usecs_to_jiffies(1000));
|
||||
return;
|
||||
}
|
||||
|
@ -219,7 +219,7 @@ int amdgpu_display_crtc_page_flip_target(struct drm_crtc *crtc,
|
|||
if (!adev->enable_virtual_display)
|
||||
work->base = amdgpu_bo_gpu_offset(new_abo);
|
||||
work->target_vblank = target - (uint32_t)drm_crtc_vblank_count(crtc) +
|
||||
amdgpu_get_vblank_counter_kms(dev, work->crtc_id);
|
||||
amdgpu_get_vblank_counter_kms(crtc);
|
||||
|
||||
/* we borrow the event spin lock for protecting flip_wrok */
|
||||
spin_lock_irqsave(&crtc->dev->event_lock, flags);
|
||||
|
@ -924,3 +924,15 @@ int amdgpu_display_crtc_idx_to_irq_type(struct amdgpu_device *adev, int crtc)
|
|||
return AMDGPU_CRTC_IRQ_NONE;
|
||||
}
|
||||
}
|
||||
|
||||
bool amdgpu_crtc_get_scanout_position(struct drm_crtc *crtc,
|
||||
bool in_vblank_irq, int *vpos,
|
||||
int *hpos, ktime_t *stime, ktime_t *etime,
|
||||
const struct drm_display_mode *mode)
|
||||
{
|
||||
struct drm_device *dev = crtc->dev;
|
||||
unsigned int pipe = crtc->index;
|
||||
|
||||
return amdgpu_display_get_crtc_scanoutpos(dev, pipe, 0, vpos, hpos,
|
||||
stime, etime, mode);
|
||||
}
|
||||
|
|
|
@ -1377,16 +1377,6 @@ int amdgpu_file_to_fpriv(struct file *filp, struct amdgpu_fpriv **fpriv)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static bool
|
||||
amdgpu_get_crtc_scanout_position(struct drm_device *dev, unsigned int pipe,
|
||||
bool in_vblank_irq, int *vpos, int *hpos,
|
||||
ktime_t *stime, ktime_t *etime,
|
||||
const struct drm_display_mode *mode)
|
||||
{
|
||||
return amdgpu_display_get_crtc_scanoutpos(dev, pipe, 0, vpos, hpos,
|
||||
stime, etime, mode);
|
||||
}
|
||||
|
||||
static struct drm_driver kms_driver = {
|
||||
.driver_features =
|
||||
DRIVER_USE_AGP | DRIVER_ATOMIC |
|
||||
|
@ -1398,11 +1388,6 @@ static struct drm_driver kms_driver = {
|
|||
.postclose = amdgpu_driver_postclose_kms,
|
||||
.lastclose = amdgpu_driver_lastclose_kms,
|
||||
.unload = amdgpu_driver_unload_kms,
|
||||
.get_vblank_counter = amdgpu_get_vblank_counter_kms,
|
||||
.enable_vblank = amdgpu_enable_vblank_kms,
|
||||
.disable_vblank = amdgpu_disable_vblank_kms,
|
||||
.get_vblank_timestamp = drm_calc_vbltimestamp_from_scanoutpos,
|
||||
.get_scanout_position = amdgpu_get_crtc_scanout_position,
|
||||
.irq_handler = amdgpu_irq_handler,
|
||||
.ioctls = amdgpu_ioctls_kms,
|
||||
.gem_free_object_unlocked = amdgpu_gem_object_free,
|
||||
|
|
|
@ -1110,14 +1110,15 @@ void amdgpu_driver_postclose_kms(struct drm_device *dev,
|
|||
/**
|
||||
* amdgpu_get_vblank_counter_kms - get frame count
|
||||
*
|
||||
* @dev: drm dev pointer
|
||||
* @pipe: crtc to get the frame count from
|
||||
* @crtc: crtc to get the frame count from
|
||||
*
|
||||
* Gets the frame count on the requested crtc (all asics).
|
||||
* Returns frame count on success, -EINVAL on failure.
|
||||
*/
|
||||
u32 amdgpu_get_vblank_counter_kms(struct drm_device *dev, unsigned int pipe)
|
||||
u32 amdgpu_get_vblank_counter_kms(struct drm_crtc *crtc)
|
||||
{
|
||||
struct drm_device *dev = crtc->dev;
|
||||
unsigned int pipe = crtc->index;
|
||||
struct amdgpu_device *adev = dev->dev_private;
|
||||
int vpos, hpos, stat;
|
||||
u32 count;
|
||||
|
@ -1177,14 +1178,15 @@ u32 amdgpu_get_vblank_counter_kms(struct drm_device *dev, unsigned int pipe)
|
|||
/**
|
||||
* amdgpu_enable_vblank_kms - enable vblank interrupt
|
||||
*
|
||||
* @dev: drm dev pointer
|
||||
* @pipe: crtc to enable vblank interrupt for
|
||||
* @crtc: crtc to enable vblank interrupt for
|
||||
*
|
||||
* Enable the interrupt on the requested crtc (all asics).
|
||||
* Returns 0 on success, -EINVAL on failure.
|
||||
*/
|
||||
int amdgpu_enable_vblank_kms(struct drm_device *dev, unsigned int pipe)
|
||||
int amdgpu_enable_vblank_kms(struct drm_crtc *crtc)
|
||||
{
|
||||
struct drm_device *dev = crtc->dev;
|
||||
unsigned int pipe = crtc->index;
|
||||
struct amdgpu_device *adev = dev->dev_private;
|
||||
int idx = amdgpu_display_crtc_idx_to_irq_type(adev, pipe);
|
||||
|
||||
|
@ -1194,13 +1196,14 @@ int amdgpu_enable_vblank_kms(struct drm_device *dev, unsigned int pipe)
|
|||
/**
|
||||
* amdgpu_disable_vblank_kms - disable vblank interrupt
|
||||
*
|
||||
* @dev: drm dev pointer
|
||||
* @pipe: crtc to disable vblank interrupt for
|
||||
* @crtc: crtc to disable vblank interrupt for
|
||||
*
|
||||
* Disable the interrupt on the requested crtc (all asics).
|
||||
*/
|
||||
void amdgpu_disable_vblank_kms(struct drm_device *dev, unsigned int pipe)
|
||||
void amdgpu_disable_vblank_kms(struct drm_crtc *crtc)
|
||||
{
|
||||
struct drm_device *dev = crtc->dev;
|
||||
unsigned int pipe = crtc->index;
|
||||
struct amdgpu_device *adev = dev->dev_private;
|
||||
int idx = amdgpu_display_crtc_idx_to_irq_type(adev, pipe);
|
||||
|
||||
|
|
|
@ -612,6 +612,11 @@ void amdgpu_panel_mode_fixup(struct drm_encoder *encoder,
|
|||
struct drm_display_mode *adjusted_mode);
|
||||
int amdgpu_display_crtc_idx_to_irq_type(struct amdgpu_device *adev, int crtc);
|
||||
|
||||
bool amdgpu_crtc_get_scanout_position(struct drm_crtc *crtc,
|
||||
bool in_vblank_irq, int *vpos,
|
||||
int *hpos, ktime_t *stime, ktime_t *etime,
|
||||
const struct drm_display_mode *mode);
|
||||
|
||||
/* fbdev layer */
|
||||
int amdgpu_fbdev_init(struct amdgpu_device *adev);
|
||||
void amdgpu_fbdev_fini(struct amdgpu_device *adev);
|
||||
|
|
|
@ -2494,6 +2494,10 @@ static const struct drm_crtc_funcs dce_v10_0_crtc_funcs = {
|
|||
.set_config = amdgpu_display_crtc_set_config,
|
||||
.destroy = dce_v10_0_crtc_destroy,
|
||||
.page_flip_target = amdgpu_display_crtc_page_flip_target,
|
||||
.get_vblank_counter = amdgpu_get_vblank_counter_kms,
|
||||
.enable_vblank = amdgpu_enable_vblank_kms,
|
||||
.disable_vblank = amdgpu_disable_vblank_kms,
|
||||
.get_vblank_timestamp = drm_crtc_vblank_helper_get_vblank_timestamp,
|
||||
};
|
||||
|
||||
static void dce_v10_0_crtc_dpms(struct drm_crtc *crtc, int mode)
|
||||
|
@ -2685,6 +2689,7 @@ static const struct drm_crtc_helper_funcs dce_v10_0_crtc_helper_funcs = {
|
|||
.prepare = dce_v10_0_crtc_prepare,
|
||||
.commit = dce_v10_0_crtc_commit,
|
||||
.disable = dce_v10_0_crtc_disable,
|
||||
.get_scanout_position = amdgpu_crtc_get_scanout_position,
|
||||
};
|
||||
|
||||
static int dce_v10_0_crtc_init(struct amdgpu_device *adev, int index)
|
||||
|
|
|
@ -2573,6 +2573,10 @@ static const struct drm_crtc_funcs dce_v11_0_crtc_funcs = {
|
|||
.set_config = amdgpu_display_crtc_set_config,
|
||||
.destroy = dce_v11_0_crtc_destroy,
|
||||
.page_flip_target = amdgpu_display_crtc_page_flip_target,
|
||||
.get_vblank_counter = amdgpu_get_vblank_counter_kms,
|
||||
.enable_vblank = amdgpu_enable_vblank_kms,
|
||||
.disable_vblank = amdgpu_disable_vblank_kms,
|
||||
.get_vblank_timestamp = drm_crtc_vblank_helper_get_vblank_timestamp,
|
||||
};
|
||||
|
||||
static void dce_v11_0_crtc_dpms(struct drm_crtc *crtc, int mode)
|
||||
|
@ -2793,6 +2797,7 @@ static const struct drm_crtc_helper_funcs dce_v11_0_crtc_helper_funcs = {
|
|||
.prepare = dce_v11_0_crtc_prepare,
|
||||
.commit = dce_v11_0_crtc_commit,
|
||||
.disable = dce_v11_0_crtc_disable,
|
||||
.get_scanout_position = amdgpu_crtc_get_scanout_position,
|
||||
};
|
||||
|
||||
static int dce_v11_0_crtc_init(struct amdgpu_device *adev, int index)
|
||||
|
|
|
@ -2388,6 +2388,10 @@ static const struct drm_crtc_funcs dce_v6_0_crtc_funcs = {
|
|||
.set_config = amdgpu_display_crtc_set_config,
|
||||
.destroy = dce_v6_0_crtc_destroy,
|
||||
.page_flip_target = amdgpu_display_crtc_page_flip_target,
|
||||
.get_vblank_counter = amdgpu_get_vblank_counter_kms,
|
||||
.enable_vblank = amdgpu_enable_vblank_kms,
|
||||
.disable_vblank = amdgpu_disable_vblank_kms,
|
||||
.get_vblank_timestamp = drm_crtc_vblank_helper_get_vblank_timestamp,
|
||||
};
|
||||
|
||||
static void dce_v6_0_crtc_dpms(struct drm_crtc *crtc, int mode)
|
||||
|
@ -2575,6 +2579,7 @@ static const struct drm_crtc_helper_funcs dce_v6_0_crtc_helper_funcs = {
|
|||
.prepare = dce_v6_0_crtc_prepare,
|
||||
.commit = dce_v6_0_crtc_commit,
|
||||
.disable = dce_v6_0_crtc_disable,
|
||||
.get_scanout_position = amdgpu_crtc_get_scanout_position,
|
||||
};
|
||||
|
||||
static int dce_v6_0_crtc_init(struct amdgpu_device *adev, int index)
|
||||
|
|
|
@ -2395,6 +2395,10 @@ static const struct drm_crtc_funcs dce_v8_0_crtc_funcs = {
|
|||
.set_config = amdgpu_display_crtc_set_config,
|
||||
.destroy = dce_v8_0_crtc_destroy,
|
||||
.page_flip_target = amdgpu_display_crtc_page_flip_target,
|
||||
.get_vblank_counter = amdgpu_get_vblank_counter_kms,
|
||||
.enable_vblank = amdgpu_enable_vblank_kms,
|
||||
.disable_vblank = amdgpu_disable_vblank_kms,
|
||||
.get_vblank_timestamp = drm_crtc_vblank_helper_get_vblank_timestamp,
|
||||
};
|
||||
|
||||
static void dce_v8_0_crtc_dpms(struct drm_crtc *crtc, int mode)
|
||||
|
@ -2593,6 +2597,7 @@ static const struct drm_crtc_helper_funcs dce_v8_0_crtc_helper_funcs = {
|
|||
.prepare = dce_v8_0_crtc_prepare,
|
||||
.commit = dce_v8_0_crtc_commit,
|
||||
.disable = dce_v8_0_crtc_disable,
|
||||
.get_scanout_position = amdgpu_crtc_get_scanout_position,
|
||||
};
|
||||
|
||||
static int dce_v8_0_crtc_init(struct amdgpu_device *adev, int index)
|
||||
|
|
|
@ -123,6 +123,10 @@ static const struct drm_crtc_funcs dce_virtual_crtc_funcs = {
|
|||
.set_config = amdgpu_display_crtc_set_config,
|
||||
.destroy = dce_virtual_crtc_destroy,
|
||||
.page_flip_target = amdgpu_display_crtc_page_flip_target,
|
||||
.get_vblank_counter = amdgpu_get_vblank_counter_kms,
|
||||
.enable_vblank = amdgpu_enable_vblank_kms,
|
||||
.disable_vblank = amdgpu_disable_vblank_kms,
|
||||
.get_vblank_timestamp = drm_crtc_vblank_helper_get_vblank_timestamp,
|
||||
};
|
||||
|
||||
static void dce_virtual_crtc_dpms(struct drm_crtc *crtc, int mode)
|
||||
|
@ -218,6 +222,7 @@ static const struct drm_crtc_helper_funcs dce_virtual_crtc_helper_funcs = {
|
|||
.prepare = dce_virtual_crtc_prepare,
|
||||
.commit = dce_virtual_crtc_commit,
|
||||
.disable = dce_virtual_crtc_disable,
|
||||
.get_scanout_position = amdgpu_crtc_get_scanout_position,
|
||||
};
|
||||
|
||||
static int dce_virtual_crtc_init(struct amdgpu_device *adev, int index)
|
||||
|
|
|
@ -383,8 +383,8 @@ static void dm_pflip_high_irq(void *interrupt_params)
|
|||
* of pageflip completion, so last_flip_vblank is the forbidden count
|
||||
* for queueing new pageflips if vsync + VRR is enabled.
|
||||
*/
|
||||
amdgpu_crtc->last_flip_vblank = amdgpu_get_vblank_counter_kms(adev->ddev,
|
||||
amdgpu_crtc->crtc_id);
|
||||
amdgpu_crtc->last_flip_vblank =
|
||||
amdgpu_get_vblank_counter_kms(&amdgpu_crtc->base);
|
||||
|
||||
amdgpu_crtc->pflip_status = AMDGPU_FLIP_NONE;
|
||||
spin_unlock_irqrestore(&adev->ddev->event_lock, flags);
|
||||
|
@ -4269,8 +4269,10 @@ static const struct drm_crtc_funcs amdgpu_dm_crtc_funcs = {
|
|||
.set_crc_source = amdgpu_dm_crtc_set_crc_source,
|
||||
.verify_crc_source = amdgpu_dm_crtc_verify_crc_source,
|
||||
.get_crc_sources = amdgpu_dm_crtc_get_crc_sources,
|
||||
.get_vblank_counter = amdgpu_get_vblank_counter_kms,
|
||||
.enable_vblank = dm_enable_vblank,
|
||||
.disable_vblank = dm_disable_vblank,
|
||||
.get_vblank_timestamp = drm_crtc_vblank_helper_get_vblank_timestamp,
|
||||
};
|
||||
|
||||
static enum drm_connector_status
|
||||
|
@ -4876,7 +4878,8 @@ static bool dm_crtc_helper_mode_fixup(struct drm_crtc *crtc,
|
|||
static const struct drm_crtc_helper_funcs amdgpu_dm_crtc_helper_funcs = {
|
||||
.disable = dm_crtc_helper_disable,
|
||||
.atomic_check = dm_crtc_helper_atomic_check,
|
||||
.mode_fixup = dm_crtc_helper_mode_fixup
|
||||
.mode_fixup = dm_crtc_helper_mode_fixup,
|
||||
.get_scanout_position = amdgpu_crtc_get_scanout_position,
|
||||
};
|
||||
|
||||
static void dm_encoder_helper_disable(struct drm_encoder *encoder)
|
||||
|
@ -6480,7 +6483,7 @@ static void amdgpu_dm_commit_planes(struct drm_atomic_state *state,
|
|||
* clients using the GLX_OML_sync_control extension or
|
||||
* DRI3/Present extension with defined target_msc.
|
||||
*/
|
||||
last_flip_vblank = amdgpu_get_vblank_counter_kms(dm->ddev, acrtc_attach->crtc_id);
|
||||
last_flip_vblank = amdgpu_get_vblank_counter_kms(pcrtc);
|
||||
}
|
||||
else {
|
||||
/* For variable refresh rate mode only:
|
||||
|
@ -6509,7 +6512,7 @@ static void amdgpu_dm_commit_planes(struct drm_atomic_state *state,
|
|||
& (DRM_SCANOUTPOS_VALID | DRM_SCANOUTPOS_IN_VBLANK)) ==
|
||||
(DRM_SCANOUTPOS_VALID | DRM_SCANOUTPOS_IN_VBLANK) &&
|
||||
(int)(target_vblank -
|
||||
amdgpu_get_vblank_counter_kms(dm->ddev, acrtc_attach->crtc_id)) > 0)) {
|
||||
amdgpu_get_vblank_counter_kms(pcrtc)) > 0)) {
|
||||
usleep_range(1000, 1100);
|
||||
}
|
||||
|
||||
|
|
|
@ -23,7 +23,6 @@ static void bochs_unload(struct drm_device *dev)
|
|||
|
||||
bochs_kms_fini(bochs);
|
||||
bochs_mm_fini(bochs);
|
||||
bochs_hw_fini(dev);
|
||||
kfree(bochs);
|
||||
dev->dev_private = NULL;
|
||||
}
|
||||
|
@ -69,6 +68,7 @@ static struct drm_driver bochs_driver = {
|
|||
.major = 1,
|
||||
.minor = 0,
|
||||
DRM_GEM_VRAM_DRIVER,
|
||||
.release = bochs_unload,
|
||||
};
|
||||
|
||||
/* ---------------------------------------------------------------------- */
|
||||
|
@ -148,9 +148,9 @@ static void bochs_pci_remove(struct pci_dev *pdev)
|
|||
{
|
||||
struct drm_device *dev = pci_get_drvdata(pdev);
|
||||
|
||||
drm_dev_unplug(dev);
|
||||
drm_atomic_helper_shutdown(dev);
|
||||
drm_dev_unregister(dev);
|
||||
bochs_unload(dev);
|
||||
bochs_hw_fini(dev);
|
||||
drm_dev_put(dev);
|
||||
}
|
||||
|
||||
|
|
|
@ -4,6 +4,7 @@
|
|||
|
||||
#include <linux/pci.h>
|
||||
|
||||
#include <drm/drm_drv.h>
|
||||
#include <drm/drm_fourcc.h>
|
||||
|
||||
#include "bochs.h"
|
||||
|
@ -194,6 +195,8 @@ void bochs_hw_fini(struct drm_device *dev)
|
|||
{
|
||||
struct bochs_device *bochs = dev->dev_private;
|
||||
|
||||
/* TODO: shot down existing vram mappings */
|
||||
|
||||
if (bochs->mmio)
|
||||
iounmap(bochs->mmio);
|
||||
if (bochs->ioports)
|
||||
|
@ -207,6 +210,11 @@ void bochs_hw_fini(struct drm_device *dev)
|
|||
void bochs_hw_setmode(struct bochs_device *bochs,
|
||||
struct drm_display_mode *mode)
|
||||
{
|
||||
int idx;
|
||||
|
||||
if (!drm_dev_enter(bochs->dev, &idx))
|
||||
return;
|
||||
|
||||
bochs->xres = mode->hdisplay;
|
||||
bochs->yres = mode->vdisplay;
|
||||
bochs->bpp = 32;
|
||||
|
@ -232,11 +240,18 @@ void bochs_hw_setmode(struct bochs_device *bochs,
|
|||
|
||||
bochs_dispi_write(bochs, VBE_DISPI_INDEX_ENABLE,
|
||||
VBE_DISPI_ENABLED | VBE_DISPI_LFB_ENABLED);
|
||||
|
||||
drm_dev_exit(idx);
|
||||
}
|
||||
|
||||
void bochs_hw_setformat(struct bochs_device *bochs,
|
||||
const struct drm_format_info *format)
|
||||
{
|
||||
int idx;
|
||||
|
||||
if (!drm_dev_enter(bochs->dev, &idx))
|
||||
return;
|
||||
|
||||
DRM_DEBUG_DRIVER("format %c%c%c%c\n",
|
||||
(format->format >> 0) & 0xff,
|
||||
(format->format >> 8) & 0xff,
|
||||
|
@ -256,13 +271,18 @@ void bochs_hw_setformat(struct bochs_device *bochs,
|
|||
__func__, format->format);
|
||||
break;
|
||||
}
|
||||
|
||||
drm_dev_exit(idx);
|
||||
}
|
||||
|
||||
void bochs_hw_setbase(struct bochs_device *bochs,
|
||||
int x, int y, int stride, u64 addr)
|
||||
{
|
||||
unsigned long offset;
|
||||
unsigned int vx, vy, vwidth;
|
||||
unsigned int vx, vy, vwidth, idx;
|
||||
|
||||
if (!drm_dev_enter(bochs->dev, &idx))
|
||||
return;
|
||||
|
||||
bochs->stride = stride;
|
||||
offset = (unsigned long)addr +
|
||||
|
@ -277,4 +297,6 @@ void bochs_hw_setbase(struct bochs_device *bochs,
|
|||
bochs_dispi_write(bochs, VBE_DISPI_INDEX_VIRT_WIDTH, vwidth);
|
||||
bochs_dispi_write(bochs, VBE_DISPI_INDEX_X_OFFSET, vx);
|
||||
bochs_dispi_write(bochs, VBE_DISPI_INDEX_Y_OFFSET, vy);
|
||||
|
||||
drm_dev_exit(idx);
|
||||
}
|
||||
|
|
|
@ -163,6 +163,9 @@ int bochs_kms_init(struct bochs_device *bochs)
|
|||
|
||||
void bochs_kms_fini(struct bochs_device *bochs)
|
||||
{
|
||||
if (!bochs->dev->mode_config.num_connector)
|
||||
return;
|
||||
|
||||
drm_atomic_helper_shutdown(bochs->dev);
|
||||
drm_mode_config_cleanup(bochs->dev);
|
||||
}
|
||||
|
|
|
@ -98,6 +98,7 @@ config DRM_SII902X
|
|||
select DRM_KMS_HELPER
|
||||
select REGMAP_I2C
|
||||
select I2C_MUX
|
||||
select SND_SOC_HDMI_CODEC if SND_SOC
|
||||
---help---
|
||||
Silicon Image sii902x bridge chip driver.
|
||||
|
||||
|
@ -133,6 +134,16 @@ config DRM_TOSHIBA_TC358767
|
|||
---help---
|
||||
Toshiba TC358767 eDP bridge chip driver.
|
||||
|
||||
config DRM_TOSHIBA_TC358768
|
||||
tristate "Toshiba TC358768 MIPI DSI bridge"
|
||||
depends on OF
|
||||
select DRM_KMS_HELPER
|
||||
select REGMAP_I2C
|
||||
select DRM_PANEL
|
||||
select DRM_MIPI_DSI
|
||||
help
|
||||
Toshiba TC358768AXBG/TC358778XBG DSI bridge chip driver.
|
||||
|
||||
config DRM_TI_TFP410
|
||||
tristate "TI TFP410 DVI/HDMI bridge"
|
||||
depends on OF
|
||||
|
|
|
@ -12,6 +12,7 @@ obj-$(CONFIG_DRM_SII9234) += sii9234.o
|
|||
obj-$(CONFIG_DRM_THINE_THC63LVD1024) += thc63lvd1024.o
|
||||
obj-$(CONFIG_DRM_TOSHIBA_TC358764) += tc358764.o
|
||||
obj-$(CONFIG_DRM_TOSHIBA_TC358767) += tc358767.o
|
||||
obj-$(CONFIG_DRM_TOSHIBA_TC358768) += tc358768.o
|
||||
obj-$(CONFIG_DRM_I2C_ADV7511) += adv7511/
|
||||
obj-$(CONFIG_DRM_TI_SN65DSI86) += ti-sn65dsi86.o
|
||||
obj-$(CONFIG_DRM_TI_TFP410) += ti-tfp410.o
|
||||
|
|
|
@ -4,8 +4,9 @@ config DRM_I2C_ADV7511
|
|||
depends on OF
|
||||
select DRM_KMS_HELPER
|
||||
select REGMAP_I2C
|
||||
select DRM_MIPI_DSI
|
||||
help
|
||||
Support for the Analog Device ADV7511(W) and ADV7513 HDMI encoders.
|
||||
Support for the Analog Device ADV7511(W)/13/33/35 HDMI encoders.
|
||||
|
||||
config DRM_I2C_ADV7511_AUDIO
|
||||
bool "ADV7511 HDMI Audio driver"
|
||||
|
@ -15,16 +16,8 @@ config DRM_I2C_ADV7511_AUDIO
|
|||
Support the ADV7511 HDMI Audio interface. This is used in
|
||||
conjunction with the AV7511 HDMI driver.
|
||||
|
||||
config DRM_I2C_ADV7533
|
||||
bool "ADV7533 encoder"
|
||||
depends on DRM_I2C_ADV7511
|
||||
select DRM_MIPI_DSI
|
||||
default y
|
||||
help
|
||||
Support for the Analog Devices ADV7533 DSI to HDMI encoder.
|
||||
|
||||
config DRM_I2C_ADV7511_CEC
|
||||
bool "ADV7511/33 HDMI CEC driver"
|
||||
bool "ADV7511/33/35 HDMI CEC driver"
|
||||
depends on DRM_I2C_ADV7511
|
||||
select CEC_CORE
|
||||
default y
|
||||
|
|
|
@ -1,6 +1,5 @@
|
|||
# SPDX-License-Identifier: GPL-2.0-only
|
||||
adv7511-y := adv7511_drv.o
|
||||
adv7511-y := adv7511_drv.o adv7533.o
|
||||
adv7511-$(CONFIG_DRM_I2C_ADV7511_AUDIO) += adv7511_audio.o
|
||||
adv7511-$(CONFIG_DRM_I2C_ADV7511_CEC) += adv7511_cec.o
|
||||
adv7511-$(CONFIG_DRM_I2C_ADV7533) += adv7533.o
|
||||
obj-$(CONFIG_DRM_I2C_ADV7511) += adv7511.o
|
||||
|
|
|
@ -320,6 +320,7 @@ struct adv7511_video_config {
|
|||
enum adv7511_type {
|
||||
ADV7511,
|
||||
ADV7533,
|
||||
ADV7535,
|
||||
};
|
||||
|
||||
#define ADV7511_MAX_ADDRS 3
|
||||
|
@ -393,7 +394,6 @@ static inline int adv7511_cec_init(struct device *dev, struct adv7511 *adv7511)
|
|||
}
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_DRM_I2C_ADV7533
|
||||
void adv7533_dsi_power_on(struct adv7511 *adv);
|
||||
void adv7533_dsi_power_off(struct adv7511 *adv);
|
||||
void adv7533_mode_set(struct adv7511 *adv, const struct drm_display_mode *mode);
|
||||
|
@ -402,44 +402,6 @@ int adv7533_patch_cec_registers(struct adv7511 *adv);
|
|||
int adv7533_attach_dsi(struct adv7511 *adv);
|
||||
void adv7533_detach_dsi(struct adv7511 *adv);
|
||||
int adv7533_parse_dt(struct device_node *np, struct adv7511 *adv);
|
||||
#else
|
||||
static inline void adv7533_dsi_power_on(struct adv7511 *adv)
|
||||
{
|
||||
}
|
||||
|
||||
static inline void adv7533_dsi_power_off(struct adv7511 *adv)
|
||||
{
|
||||
}
|
||||
|
||||
static inline void adv7533_mode_set(struct adv7511 *adv,
|
||||
const struct drm_display_mode *mode)
|
||||
{
|
||||
}
|
||||
|
||||
static inline int adv7533_patch_registers(struct adv7511 *adv)
|
||||
{
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
static inline int adv7533_patch_cec_registers(struct adv7511 *adv)
|
||||
{
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
static inline int adv7533_attach_dsi(struct adv7511 *adv)
|
||||
{
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
static inline void adv7533_detach_dsi(struct adv7511 *adv)
|
||||
{
|
||||
}
|
||||
|
||||
static inline int adv7533_parse_dt(struct device_node *np, struct adv7511 *adv)
|
||||
{
|
||||
return -ENODEV;
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_DRM_I2C_ADV7511_AUDIO
|
||||
int adv7511_audio_init(struct device *dev, struct adv7511 *adv7511);
|
||||
|
|
|
@ -367,7 +367,7 @@ static void adv7511_power_on(struct adv7511 *adv7511)
|
|||
*/
|
||||
regcache_sync(adv7511->regmap);
|
||||
|
||||
if (adv7511->type == ADV7533)
|
||||
if (adv7511->type == ADV7533 || adv7511->type == ADV7535)
|
||||
adv7533_dsi_power_on(adv7511);
|
||||
adv7511->powered = true;
|
||||
}
|
||||
|
@ -387,7 +387,7 @@ static void __adv7511_power_off(struct adv7511 *adv7511)
|
|||
static void adv7511_power_off(struct adv7511 *adv7511)
|
||||
{
|
||||
__adv7511_power_off(adv7511);
|
||||
if (adv7511->type == ADV7533)
|
||||
if (adv7511->type == ADV7533 || adv7511->type == ADV7535)
|
||||
adv7533_dsi_power_off(adv7511);
|
||||
adv7511->powered = false;
|
||||
}
|
||||
|
@ -761,7 +761,7 @@ static void adv7511_mode_set(struct adv7511 *adv7511,
|
|||
regmap_update_bits(adv7511->regmap, 0x17,
|
||||
0x60, (vsync_polarity << 6) | (hsync_polarity << 5));
|
||||
|
||||
if (adv7511->type == ADV7533)
|
||||
if (adv7511->type == ADV7533 || adv7511->type == ADV7535)
|
||||
adv7533_mode_set(adv7511, adj_mode);
|
||||
|
||||
drm_mode_copy(&adv7511->curr_mode, adj_mode);
|
||||
|
@ -874,7 +874,7 @@ static int adv7511_bridge_attach(struct drm_bridge *bridge)
|
|||
&adv7511_connector_helper_funcs);
|
||||
drm_connector_attach_encoder(&adv->connector, bridge->encoder);
|
||||
|
||||
if (adv->type == ADV7533)
|
||||
if (adv->type == ADV7533 || adv->type == ADV7535)
|
||||
ret = adv7533_attach_dsi(adv);
|
||||
|
||||
if (adv->i2c_main->irq)
|
||||
|
@ -952,7 +952,7 @@ static bool adv7511_cec_register_volatile(struct device *dev, unsigned int reg)
|
|||
struct i2c_client *i2c = to_i2c_client(dev);
|
||||
struct adv7511 *adv7511 = i2c_get_clientdata(i2c);
|
||||
|
||||
if (adv7511->type == ADV7533)
|
||||
if (adv7511->type == ADV7533 || adv7511->type == ADV7535)
|
||||
reg -= ADV7533_REG_CEC_OFFSET;
|
||||
|
||||
switch (reg) {
|
||||
|
@ -994,7 +994,7 @@ static int adv7511_init_cec_regmap(struct adv7511 *adv)
|
|||
goto err;
|
||||
}
|
||||
|
||||
if (adv->type == ADV7533) {
|
||||
if (adv->type == ADV7533 || adv->type == ADV7535) {
|
||||
ret = adv7533_patch_cec_registers(adv);
|
||||
if (ret)
|
||||
goto err;
|
||||
|
@ -1242,7 +1242,7 @@ static int adv7511_remove(struct i2c_client *i2c)
|
|||
{
|
||||
struct adv7511 *adv7511 = i2c_get_clientdata(i2c);
|
||||
|
||||
if (adv7511->type == ADV7533)
|
||||
if (adv7511->type == ADV7533 || adv7511->type == ADV7535)
|
||||
adv7533_detach_dsi(adv7511);
|
||||
i2c_unregister_device(adv7511->i2c_cec);
|
||||
if (adv7511->cec_clk)
|
||||
|
@ -1266,9 +1266,8 @@ static const struct i2c_device_id adv7511_i2c_ids[] = {
|
|||
{ "adv7511", ADV7511 },
|
||||
{ "adv7511w", ADV7511 },
|
||||
{ "adv7513", ADV7511 },
|
||||
#ifdef CONFIG_DRM_I2C_ADV7533
|
||||
{ "adv7533", ADV7533 },
|
||||
#endif
|
||||
{ "adv7535", ADV7535 },
|
||||
{ }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(i2c, adv7511_i2c_ids);
|
||||
|
@ -1277,9 +1276,8 @@ static const struct of_device_id adv7511_of_ids[] = {
|
|||
{ .compatible = "adi,adv7511", .data = (void *)ADV7511 },
|
||||
{ .compatible = "adi,adv7511w", .data = (void *)ADV7511 },
|
||||
{ .compatible = "adi,adv7513", .data = (void *)ADV7511 },
|
||||
#ifdef CONFIG_DRM_I2C_ADV7533
|
||||
{ .compatible = "adi,adv7533", .data = (void *)ADV7533 },
|
||||
#endif
|
||||
{ .compatible = "adi,adv7535", .data = (void *)ADV7535 },
|
||||
{ }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, adv7511_of_ids);
|
||||
|
|
|
@ -151,7 +151,7 @@ static const struct drm_bridge_funcs panel_bridge_bridge_funcs = {
|
|||
* known type. Calling this function with a panel whose connector type is
|
||||
* DRM_MODE_CONNECTOR_Unknown will return NULL.
|
||||
*
|
||||
* See devm_drm_panel_bridge_add() for an automatically manged version of this
|
||||
* See devm_drm_panel_bridge_add() for an automatically managed version of this
|
||||
* function.
|
||||
*/
|
||||
struct drm_bridge *drm_panel_bridge_add(struct drm_panel *panel)
|
||||
|
|
|
@ -824,7 +824,8 @@ static void dw_mipi_dsi_bridge_post_disable(struct drm_bridge *bridge)
|
|||
* This needs to be fixed in the drm_bridge framework and the API
|
||||
* needs to be updated to manage our own call chains...
|
||||
*/
|
||||
dsi->panel_bridge->funcs->post_disable(dsi->panel_bridge);
|
||||
if (dsi->panel_bridge->funcs->post_disable)
|
||||
dsi->panel_bridge->funcs->post_disable(dsi->panel_bridge);
|
||||
|
||||
if (phy_ops->power_off)
|
||||
phy_ops->power_off(dsi->plat_data->priv_data);
|
||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -51,6 +51,7 @@
|
|||
#define SN_ENH_FRAME_REG 0x5A
|
||||
#define VSTREAM_ENABLE BIT(3)
|
||||
#define SN_DATA_FORMAT_REG 0x5B
|
||||
#define BPP_18_RGB BIT(0)
|
||||
#define SN_HPD_DISABLE_REG 0x5C
|
||||
#define HPD_DISABLE BIT(0)
|
||||
#define SN_AUX_WDATA_REG(x) (0x64 + (x))
|
||||
|
@ -100,6 +101,7 @@ struct ti_sn_bridge {
|
|||
struct drm_panel *panel;
|
||||
struct gpio_desc *enable_gpio;
|
||||
struct regulator_bulk_data supplies[SN_REGULATOR_SUPPLY_NUM];
|
||||
int dp_lanes;
|
||||
};
|
||||
|
||||
static const struct regmap_range ti_sn_bridge_volatile_ranges[] = {
|
||||
|
@ -312,7 +314,7 @@ static int ti_sn_bridge_attach(struct drm_bridge *bridge)
|
|||
goto err_dsi_host;
|
||||
}
|
||||
|
||||
/* TODO: setting to 4 lanes always for now */
|
||||
/* TODO: setting to 4 MIPI lanes always for now */
|
||||
dsi->lanes = 4;
|
||||
dsi->format = MIPI_DSI_FMT_RGB888;
|
||||
dsi->mode_flags = MIPI_DSI_MODE_VIDEO;
|
||||
|
@ -417,19 +419,10 @@ static void ti_sn_bridge_set_refclk_freq(struct ti_sn_bridge *pdata)
|
|||
REFCLK_FREQ(i));
|
||||
}
|
||||
|
||||
/**
|
||||
* LUT index corresponds to register value and
|
||||
* LUT values corresponds to dp data rate supported
|
||||
* by the bridge in Mbps unit.
|
||||
*/
|
||||
static const unsigned int ti_sn_bridge_dp_rate_lut[] = {
|
||||
0, 1620, 2160, 2430, 2700, 3240, 4320, 5400
|
||||
};
|
||||
|
||||
static void ti_sn_bridge_set_dsi_dp_rate(struct ti_sn_bridge *pdata)
|
||||
static void ti_sn_bridge_set_dsi_rate(struct ti_sn_bridge *pdata)
|
||||
{
|
||||
unsigned int bit_rate_mhz, clk_freq_mhz, dp_rate_mhz;
|
||||
unsigned int val, i;
|
||||
unsigned int bit_rate_mhz, clk_freq_mhz;
|
||||
unsigned int val;
|
||||
struct drm_display_mode *mode =
|
||||
&pdata->bridge.encoder->crtc->state->adjusted_mode;
|
||||
|
||||
|
@ -442,16 +435,125 @@ static void ti_sn_bridge_set_dsi_dp_rate(struct ti_sn_bridge *pdata)
|
|||
val = (MIN_DSI_CLK_FREQ_MHZ / 5) +
|
||||
(((clk_freq_mhz - MIN_DSI_CLK_FREQ_MHZ) / 5) & 0xFF);
|
||||
regmap_write(pdata->regmap, SN_DSIA_CLK_FREQ_REG, val);
|
||||
}
|
||||
|
||||
/* set DP data rate */
|
||||
dp_rate_mhz = ((bit_rate_mhz / pdata->dsi->lanes) * DP_CLK_FUDGE_NUM) /
|
||||
DP_CLK_FUDGE_DEN;
|
||||
for (i = 0; i < ARRAY_SIZE(ti_sn_bridge_dp_rate_lut) - 1; i++)
|
||||
static unsigned int ti_sn_bridge_get_bpp(struct ti_sn_bridge *pdata)
|
||||
{
|
||||
if (pdata->connector.display_info.bpc <= 6)
|
||||
return 18;
|
||||
else
|
||||
return 24;
|
||||
}
|
||||
|
||||
/**
|
||||
* LUT index corresponds to register value and
|
||||
* LUT values corresponds to dp data rate supported
|
||||
* by the bridge in Mbps unit.
|
||||
*/
|
||||
static const unsigned int ti_sn_bridge_dp_rate_lut[] = {
|
||||
0, 1620, 2160, 2430, 2700, 3240, 4320, 5400
|
||||
};
|
||||
|
||||
static int ti_sn_bridge_calc_min_dp_rate_idx(struct ti_sn_bridge *pdata)
|
||||
{
|
||||
unsigned int bit_rate_khz, dp_rate_mhz;
|
||||
unsigned int i;
|
||||
struct drm_display_mode *mode =
|
||||
&pdata->bridge.encoder->crtc->state->adjusted_mode;
|
||||
|
||||
/* Calculate minimum bit rate based on our pixel clock. */
|
||||
bit_rate_khz = mode->clock * ti_sn_bridge_get_bpp(pdata);
|
||||
|
||||
/* Calculate minimum DP data rate, taking 80% as per DP spec */
|
||||
dp_rate_mhz = DIV_ROUND_UP(bit_rate_khz * DP_CLK_FUDGE_NUM,
|
||||
1000 * pdata->dp_lanes * DP_CLK_FUDGE_DEN);
|
||||
|
||||
for (i = 1; i < ARRAY_SIZE(ti_sn_bridge_dp_rate_lut) - 1; i++)
|
||||
if (ti_sn_bridge_dp_rate_lut[i] > dp_rate_mhz)
|
||||
break;
|
||||
|
||||
regmap_update_bits(pdata->regmap, SN_DATARATE_CONFIG_REG,
|
||||
DP_DATARATE_MASK, DP_DATARATE(i));
|
||||
return i;
|
||||
}
|
||||
|
||||
static void ti_sn_bridge_read_valid_rates(struct ti_sn_bridge *pdata,
|
||||
bool rate_valid[])
|
||||
{
|
||||
unsigned int rate_per_200khz;
|
||||
unsigned int rate_mhz;
|
||||
u8 dpcd_val;
|
||||
int ret;
|
||||
int i, j;
|
||||
|
||||
ret = drm_dp_dpcd_readb(&pdata->aux, DP_EDP_DPCD_REV, &dpcd_val);
|
||||
if (ret != 1) {
|
||||
DRM_DEV_ERROR(pdata->dev,
|
||||
"Can't read eDP rev (%d), assuming 1.1\n", ret);
|
||||
dpcd_val = DP_EDP_11;
|
||||
}
|
||||
|
||||
if (dpcd_val >= DP_EDP_14) {
|
||||
/* eDP 1.4 devices must provide a custom table */
|
||||
__le16 sink_rates[DP_MAX_SUPPORTED_RATES];
|
||||
|
||||
ret = drm_dp_dpcd_read(&pdata->aux, DP_SUPPORTED_LINK_RATES,
|
||||
sink_rates, sizeof(sink_rates));
|
||||
|
||||
if (ret != sizeof(sink_rates)) {
|
||||
DRM_DEV_ERROR(pdata->dev,
|
||||
"Can't read supported rate table (%d)\n", ret);
|
||||
|
||||
/* By zeroing we'll fall back to DP_MAX_LINK_RATE. */
|
||||
memset(sink_rates, 0, sizeof(sink_rates));
|
||||
}
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(sink_rates); i++) {
|
||||
rate_per_200khz = le16_to_cpu(sink_rates[i]);
|
||||
|
||||
if (!rate_per_200khz)
|
||||
break;
|
||||
|
||||
rate_mhz = rate_per_200khz * 200 / 1000;
|
||||
for (j = 0;
|
||||
j < ARRAY_SIZE(ti_sn_bridge_dp_rate_lut);
|
||||
j++) {
|
||||
if (ti_sn_bridge_dp_rate_lut[j] == rate_mhz)
|
||||
rate_valid[j] = true;
|
||||
}
|
||||
}
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(ti_sn_bridge_dp_rate_lut); i++) {
|
||||
if (rate_valid[i])
|
||||
return;
|
||||
}
|
||||
DRM_DEV_ERROR(pdata->dev,
|
||||
"No matching eDP rates in table; falling back\n");
|
||||
}
|
||||
|
||||
/* On older versions best we can do is use DP_MAX_LINK_RATE */
|
||||
ret = drm_dp_dpcd_readb(&pdata->aux, DP_MAX_LINK_RATE, &dpcd_val);
|
||||
if (ret != 1) {
|
||||
DRM_DEV_ERROR(pdata->dev,
|
||||
"Can't read max rate (%d); assuming 5.4 GHz\n",
|
||||
ret);
|
||||
dpcd_val = DP_LINK_BW_5_4;
|
||||
}
|
||||
|
||||
switch (dpcd_val) {
|
||||
default:
|
||||
DRM_DEV_ERROR(pdata->dev,
|
||||
"Unexpected max rate (%#x); assuming 5.4 GHz\n",
|
||||
(int)dpcd_val);
|
||||
/* fall through */
|
||||
case DP_LINK_BW_5_4:
|
||||
rate_valid[7] = 1;
|
||||
/* fall through */
|
||||
case DP_LINK_BW_2_7:
|
||||
rate_valid[4] = 1;
|
||||
/* fall through */
|
||||
case DP_LINK_BW_1_62:
|
||||
rate_valid[1] = 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void ti_sn_bridge_set_video_timings(struct ti_sn_bridge *pdata)
|
||||
|
@ -493,24 +595,30 @@ static void ti_sn_bridge_set_video_timings(struct ti_sn_bridge *pdata)
|
|||
usleep_range(10000, 10500); /* 10ms delay recommended by spec */
|
||||
}
|
||||
|
||||
static void ti_sn_bridge_enable(struct drm_bridge *bridge)
|
||||
static unsigned int ti_sn_get_max_lanes(struct ti_sn_bridge *pdata)
|
||||
{
|
||||
u8 data;
|
||||
int ret;
|
||||
|
||||
ret = drm_dp_dpcd_readb(&pdata->aux, DP_MAX_LANE_COUNT, &data);
|
||||
if (ret != 1) {
|
||||
DRM_DEV_ERROR(pdata->dev,
|
||||
"Can't read lane count (%d); assuming 4\n", ret);
|
||||
return 4;
|
||||
}
|
||||
|
||||
return data & DP_LANE_COUNT_MASK;
|
||||
}
|
||||
|
||||
static int ti_sn_link_training(struct ti_sn_bridge *pdata, int dp_rate_idx,
|
||||
const char **last_err_str)
|
||||
{
|
||||
struct ti_sn_bridge *pdata = bridge_to_ti_sn_bridge(bridge);
|
||||
unsigned int val;
|
||||
int ret;
|
||||
|
||||
/* DSI_A lane config */
|
||||
val = CHA_DSI_LANES(4 - pdata->dsi->lanes);
|
||||
regmap_update_bits(pdata->regmap, SN_DSI_LANES_REG,
|
||||
CHA_DSI_LANES_MASK, val);
|
||||
|
||||
/* DP lane config */
|
||||
val = DP_NUM_LANES(pdata->dsi->lanes - 1);
|
||||
regmap_update_bits(pdata->regmap, SN_SSC_CONFIG_REG, DP_NUM_LANES_MASK,
|
||||
val);
|
||||
|
||||
/* set dsi/dp clk frequency value */
|
||||
ti_sn_bridge_set_dsi_dp_rate(pdata);
|
||||
/* set dp clk frequency value */
|
||||
regmap_update_bits(pdata->regmap, SN_DATARATE_CONFIG_REG,
|
||||
DP_DATARATE_MASK, DP_DATARATE(dp_rate_idx));
|
||||
|
||||
/* enable DP PLL */
|
||||
regmap_write(pdata->regmap, SN_PLL_ENABLE_REG, 1);
|
||||
|
@ -519,10 +627,62 @@ static void ti_sn_bridge_enable(struct drm_bridge *bridge)
|
|||
val & DPPLL_SRC_DP_PLL_LOCK, 1000,
|
||||
50 * 1000);
|
||||
if (ret) {
|
||||
DRM_ERROR("DP_PLL_LOCK polling failed (%d)\n", ret);
|
||||
return;
|
||||
*last_err_str = "DP_PLL_LOCK polling failed";
|
||||
goto exit;
|
||||
}
|
||||
|
||||
/* Semi auto link training mode */
|
||||
regmap_write(pdata->regmap, SN_ML_TX_MODE_REG, 0x0A);
|
||||
ret = regmap_read_poll_timeout(pdata->regmap, SN_ML_TX_MODE_REG, val,
|
||||
val == ML_TX_MAIN_LINK_OFF ||
|
||||
val == ML_TX_NORMAL_MODE, 1000,
|
||||
500 * 1000);
|
||||
if (ret) {
|
||||
*last_err_str = "Training complete polling failed";
|
||||
} else if (val == ML_TX_MAIN_LINK_OFF) {
|
||||
*last_err_str = "Link training failed, link is off";
|
||||
ret = -EIO;
|
||||
}
|
||||
|
||||
exit:
|
||||
/* Disable the PLL if we failed */
|
||||
if (ret)
|
||||
regmap_write(pdata->regmap, SN_PLL_ENABLE_REG, 0);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void ti_sn_bridge_enable(struct drm_bridge *bridge)
|
||||
{
|
||||
struct ti_sn_bridge *pdata = bridge_to_ti_sn_bridge(bridge);
|
||||
bool rate_valid[ARRAY_SIZE(ti_sn_bridge_dp_rate_lut)] = { };
|
||||
const char *last_err_str = "No supported DP rate";
|
||||
int dp_rate_idx;
|
||||
unsigned int val;
|
||||
int ret = -EINVAL;
|
||||
|
||||
/*
|
||||
* Run with the maximum number of lanes that the DP sink supports.
|
||||
*
|
||||
* Depending use cases, we might want to revisit this later because:
|
||||
* - It's plausible that someone may have run fewer lines to the
|
||||
* sink than the sink actually supports, assuming that the lines
|
||||
* will just be driven at a higher rate.
|
||||
* - The DP spec seems to indicate that it's more important to minimize
|
||||
* the number of lanes than the link rate.
|
||||
*
|
||||
* If we do revisit, it would be important to measure the power impact.
|
||||
*/
|
||||
pdata->dp_lanes = ti_sn_get_max_lanes(pdata);
|
||||
|
||||
/* DSI_A lane config */
|
||||
val = CHA_DSI_LANES(4 - pdata->dsi->lanes);
|
||||
regmap_update_bits(pdata->regmap, SN_DSI_LANES_REG,
|
||||
CHA_DSI_LANES_MASK, val);
|
||||
|
||||
/* set dsi clk frequency value */
|
||||
ti_sn_bridge_set_dsi_rate(pdata);
|
||||
|
||||
/**
|
||||
* The SN65DSI86 only supports ASSR Display Authentication method and
|
||||
* this method is enabled by default. An eDP panel must support this
|
||||
|
@ -532,17 +692,30 @@ static void ti_sn_bridge_enable(struct drm_bridge *bridge)
|
|||
drm_dp_dpcd_writeb(&pdata->aux, DP_EDP_CONFIGURATION_SET,
|
||||
DP_ALTERNATE_SCRAMBLER_RESET_ENABLE);
|
||||
|
||||
/* Semi auto link training mode */
|
||||
regmap_write(pdata->regmap, SN_ML_TX_MODE_REG, 0x0A);
|
||||
ret = regmap_read_poll_timeout(pdata->regmap, SN_ML_TX_MODE_REG, val,
|
||||
val == ML_TX_MAIN_LINK_OFF ||
|
||||
val == ML_TX_NORMAL_MODE, 1000,
|
||||
500 * 1000);
|
||||
/* Set the DP output format (18 bpp or 24 bpp) */
|
||||
val = (ti_sn_bridge_get_bpp(pdata) == 18) ? BPP_18_RGB : 0;
|
||||
regmap_update_bits(pdata->regmap, SN_DATA_FORMAT_REG, BPP_18_RGB, val);
|
||||
|
||||
/* DP lane config */
|
||||
val = DP_NUM_LANES(min(pdata->dp_lanes, 3));
|
||||
regmap_update_bits(pdata->regmap, SN_SSC_CONFIG_REG, DP_NUM_LANES_MASK,
|
||||
val);
|
||||
|
||||
ti_sn_bridge_read_valid_rates(pdata, rate_valid);
|
||||
|
||||
/* Train until we run out of rates */
|
||||
for (dp_rate_idx = ti_sn_bridge_calc_min_dp_rate_idx(pdata);
|
||||
dp_rate_idx < ARRAY_SIZE(ti_sn_bridge_dp_rate_lut);
|
||||
dp_rate_idx++) {
|
||||
if (!rate_valid[dp_rate_idx])
|
||||
continue;
|
||||
|
||||
ret = ti_sn_link_training(pdata, dp_rate_idx, &last_err_str);
|
||||
if (!ret)
|
||||
break;
|
||||
}
|
||||
if (ret) {
|
||||
DRM_ERROR("Training complete polling failed (%d)\n", ret);
|
||||
return;
|
||||
} else if (val == ML_TX_MAIN_LINK_OFF) {
|
||||
DRM_ERROR("Link training failed, link is off\n");
|
||||
DRM_DEV_ERROR(pdata->dev, "%s (%d)\n", last_err_str, ret);
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
|
@ -167,10 +167,23 @@ static void tfp410_disable(struct drm_bridge *bridge)
|
|||
gpiod_set_value_cansleep(dvi->powerdown, 1);
|
||||
}
|
||||
|
||||
static enum drm_mode_status tfp410_mode_valid(struct drm_bridge *bridge,
|
||||
const struct drm_display_mode *mode)
|
||||
{
|
||||
if (mode->clock < 25000)
|
||||
return MODE_CLOCK_LOW;
|
||||
|
||||
if (mode->clock > 165000)
|
||||
return MODE_CLOCK_HIGH;
|
||||
|
||||
return MODE_OK;
|
||||
}
|
||||
|
||||
static const struct drm_bridge_funcs tfp410_bridge_funcs = {
|
||||
.attach = tfp410_attach,
|
||||
.enable = tfp410_enable,
|
||||
.disable = tfp410_disable,
|
||||
.mode_valid = tfp410_mode_valid,
|
||||
};
|
||||
|
||||
static void tfp410_hpd_work_func(struct work_struct *work)
|
||||
|
|
|
@ -151,9 +151,13 @@ static int cirrus_pitch(struct drm_framebuffer *fb)
|
|||
|
||||
static void cirrus_set_start_address(struct cirrus_device *cirrus, u32 offset)
|
||||
{
|
||||
int idx;
|
||||
u32 addr;
|
||||
u8 tmp;
|
||||
|
||||
if (!drm_dev_enter(&cirrus->dev, &idx))
|
||||
return;
|
||||
|
||||
addr = offset >> 2;
|
||||
wreg_crt(cirrus, 0x0c, (u8)((addr >> 8) & 0xff));
|
||||
wreg_crt(cirrus, 0x0d, (u8)(addr & 0xff));
|
||||
|
@ -168,6 +172,8 @@ static void cirrus_set_start_address(struct cirrus_device *cirrus, u32 offset)
|
|||
tmp &= 0x7f;
|
||||
tmp |= (addr >> 12) & 0x80;
|
||||
wreg_crt(cirrus, 0x1d, tmp);
|
||||
|
||||
drm_dev_exit(idx);
|
||||
}
|
||||
|
||||
static int cirrus_mode_set(struct cirrus_device *cirrus,
|
||||
|
@ -176,9 +182,12 @@ static int cirrus_mode_set(struct cirrus_device *cirrus,
|
|||
{
|
||||
int hsyncstart, hsyncend, htotal, hdispend;
|
||||
int vtotal, vdispend;
|
||||
int tmp;
|
||||
int tmp, idx;
|
||||
int sr07 = 0, hdr = 0;
|
||||
|
||||
if (!drm_dev_enter(&cirrus->dev, &idx))
|
||||
return -1;
|
||||
|
||||
htotal = mode->htotal / 8;
|
||||
hsyncend = mode->hsync_end / 8;
|
||||
hsyncstart = mode->hsync_start / 8;
|
||||
|
@ -264,6 +273,7 @@ static int cirrus_mode_set(struct cirrus_device *cirrus,
|
|||
hdr = 0xc5;
|
||||
break;
|
||||
default:
|
||||
drm_dev_exit(idx);
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
@ -292,6 +302,8 @@ static int cirrus_mode_set(struct cirrus_device *cirrus,
|
|||
|
||||
/* Unblank (needed on S3 resume, vgabios doesn't do it then) */
|
||||
outb(0x20, 0x3c0);
|
||||
|
||||
drm_dev_exit(idx);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -300,10 +312,16 @@ static int cirrus_fb_blit_rect(struct drm_framebuffer *fb,
|
|||
{
|
||||
struct cirrus_device *cirrus = fb->dev->dev_private;
|
||||
void *vmap;
|
||||
int idx, ret;
|
||||
|
||||
ret = -ENODEV;
|
||||
if (!drm_dev_enter(&cirrus->dev, &idx))
|
||||
goto out;
|
||||
|
||||
ret = -ENOMEM;
|
||||
vmap = drm_gem_shmem_vmap(fb->obj[0]);
|
||||
if (!vmap)
|
||||
return -ENOMEM;
|
||||
goto out_dev_exit;
|
||||
|
||||
if (cirrus->cpp == fb->format->cpp[0])
|
||||
drm_fb_memcpy_dstclip(cirrus->vram,
|
||||
|
@ -323,7 +341,12 @@ static int cirrus_fb_blit_rect(struct drm_framebuffer *fb,
|
|||
WARN_ON_ONCE("cpp mismatch");
|
||||
|
||||
drm_gem_shmem_vunmap(fb->obj[0], vmap);
|
||||
return 0;
|
||||
ret = 0;
|
||||
|
||||
out_dev_exit:
|
||||
drm_dev_exit(idx);
|
||||
out:
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int cirrus_fb_blit_fullscreen(struct drm_framebuffer *fb)
|
||||
|
@ -502,6 +525,14 @@ static void cirrus_mode_config_init(struct cirrus_device *cirrus)
|
|||
|
||||
/* ------------------------------------------------------------------ */
|
||||
|
||||
static void cirrus_release(struct drm_device *dev)
|
||||
{
|
||||
struct cirrus_device *cirrus = dev->dev_private;
|
||||
|
||||
drm_mode_config_cleanup(dev);
|
||||
kfree(cirrus);
|
||||
}
|
||||
|
||||
DEFINE_DRM_GEM_FOPS(cirrus_fops);
|
||||
|
||||
static struct drm_driver cirrus_driver = {
|
||||
|
@ -515,6 +546,7 @@ static struct drm_driver cirrus_driver = {
|
|||
|
||||
.fops = &cirrus_fops,
|
||||
DRM_GEM_SHMEM_DRIVER_OPS,
|
||||
.release = cirrus_release,
|
||||
};
|
||||
|
||||
static int cirrus_pci_probe(struct pci_dev *pdev,
|
||||
|
@ -598,12 +630,11 @@ static void cirrus_pci_remove(struct pci_dev *pdev)
|
|||
struct drm_device *dev = pci_get_drvdata(pdev);
|
||||
struct cirrus_device *cirrus = dev->dev_private;
|
||||
|
||||
drm_dev_unregister(dev);
|
||||
drm_mode_config_cleanup(dev);
|
||||
drm_dev_unplug(dev);
|
||||
drm_atomic_helper_shutdown(dev);
|
||||
iounmap(cirrus->mmio);
|
||||
iounmap(cirrus->vram);
|
||||
drm_dev_put(dev);
|
||||
kfree(cirrus);
|
||||
pci_release_regions(pdev);
|
||||
}
|
||||
|
||||
|
|
|
@ -1098,8 +1098,9 @@ EXPORT_SYMBOL(drm_atomic_get_new_bridge_state);
|
|||
*
|
||||
* This function adds all bridges attached to @encoder. This is needed to add
|
||||
* bridge states to @state and make them available when
|
||||
* &bridge_funcs.atomic_{check,pre_enable,enable,disable_post_disable}() are
|
||||
* called
|
||||
* &drm_bridge_funcs.atomic_check(), &drm_bridge_funcs.atomic_pre_enable(),
|
||||
* &drm_bridge_funcs.atomic_enable(),
|
||||
* &drm_bridge_funcs.atomic_disable_post_disable() are called.
|
||||
*
|
||||
* Returns:
|
||||
* 0 on success or can fail with -EDEADLK or -ENOMEM. When the error is EDEADLK
|
||||
|
|
|
@ -635,7 +635,6 @@ EXPORT_SYMBOL(__drm_atomic_helper_bridge_reset);
|
|||
* drm_atomic_helper_bridge_reset() - Allocate and initialize a bridge state
|
||||
* to its default
|
||||
* @bridge: the bridge this state refers to
|
||||
* @state: bridge state to initialize
|
||||
*
|
||||
* Allocates the bridge state and initializes it to default values. This helper
|
||||
* is meant to be used as a bridge &drm_bridge_funcs.atomic_reset hook for
|
||||
|
|
|
@ -1094,15 +1094,17 @@ out:
|
|||
}
|
||||
|
||||
/**
|
||||
* drm_client_modeset_commit_force() - Force commit CRTC configuration
|
||||
* drm_client_modeset_commit_locked() - Force commit CRTC configuration
|
||||
* @client: DRM client
|
||||
*
|
||||
* Commit modeset configuration to crtcs without checking if there is a DRM master.
|
||||
* Commit modeset configuration to crtcs without checking if there is a DRM
|
||||
* master. The assumption is that the caller already holds an internal DRM
|
||||
* master reference acquired with drm_master_internal_acquire().
|
||||
*
|
||||
* Returns:
|
||||
* Zero on success or negative error code on failure.
|
||||
*/
|
||||
int drm_client_modeset_commit_force(struct drm_client_dev *client)
|
||||
int drm_client_modeset_commit_locked(struct drm_client_dev *client)
|
||||
{
|
||||
struct drm_device *dev = client->dev;
|
||||
int ret;
|
||||
|
@ -1116,7 +1118,7 @@ int drm_client_modeset_commit_force(struct drm_client_dev *client)
|
|||
|
||||
return ret;
|
||||
}
|
||||
EXPORT_SYMBOL(drm_client_modeset_commit_force);
|
||||
EXPORT_SYMBOL(drm_client_modeset_commit_locked);
|
||||
|
||||
/**
|
||||
* drm_client_modeset_commit() - Commit CRTC configuration
|
||||
|
@ -1135,7 +1137,7 @@ int drm_client_modeset_commit(struct drm_client_dev *client)
|
|||
if (!drm_master_internal_acquire(dev))
|
||||
return -EBUSY;
|
||||
|
||||
ret = drm_client_modeset_commit_force(client);
|
||||
ret = drm_client_modeset_commit_locked(client);
|
||||
|
||||
drm_master_internal_release(dev);
|
||||
|
||||
|
|
|
@ -244,10 +244,6 @@ drm_crtc_prepare_encoders(struct drm_device *dev)
|
|||
/* Disable unused encoders */
|
||||
if (encoder->crtc == NULL)
|
||||
drm_encoder_disable(encoder);
|
||||
/* Disable encoders whose CRTC is about to change */
|
||||
if (encoder_funcs->get_crtc &&
|
||||
encoder->crtc != (*encoder_funcs->get_crtc)(encoder))
|
||||
drm_encoder_disable(encoder);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -361,6 +361,65 @@ int drm_dp_dpcd_read_link_status(struct drm_dp_aux *aux,
|
|||
}
|
||||
EXPORT_SYMBOL(drm_dp_dpcd_read_link_status);
|
||||
|
||||
/**
|
||||
* drm_dp_send_real_edid_checksum() - send back real edid checksum value
|
||||
* @aux: DisplayPort AUX channel
|
||||
* @real_edid_checksum: real edid checksum for the last block
|
||||
*
|
||||
* Returns:
|
||||
* True on success
|
||||
*/
|
||||
bool drm_dp_send_real_edid_checksum(struct drm_dp_aux *aux,
|
||||
u8 real_edid_checksum)
|
||||
{
|
||||
u8 link_edid_read = 0, auto_test_req = 0, test_resp = 0;
|
||||
|
||||
if (drm_dp_dpcd_read(aux, DP_DEVICE_SERVICE_IRQ_VECTOR,
|
||||
&auto_test_req, 1) < 1) {
|
||||
DRM_ERROR("DPCD failed read at register 0x%x\n",
|
||||
DP_DEVICE_SERVICE_IRQ_VECTOR);
|
||||
return false;
|
||||
}
|
||||
auto_test_req &= DP_AUTOMATED_TEST_REQUEST;
|
||||
|
||||
if (drm_dp_dpcd_read(aux, DP_TEST_REQUEST, &link_edid_read, 1) < 1) {
|
||||
DRM_ERROR("DPCD failed read at register 0x%x\n",
|
||||
DP_TEST_REQUEST);
|
||||
return false;
|
||||
}
|
||||
link_edid_read &= DP_TEST_LINK_EDID_READ;
|
||||
|
||||
if (!auto_test_req || !link_edid_read) {
|
||||
DRM_DEBUG_KMS("Source DUT does not support TEST_EDID_READ\n");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (drm_dp_dpcd_write(aux, DP_DEVICE_SERVICE_IRQ_VECTOR,
|
||||
&auto_test_req, 1) < 1) {
|
||||
DRM_ERROR("DPCD failed write at register 0x%x\n",
|
||||
DP_DEVICE_SERVICE_IRQ_VECTOR);
|
||||
return false;
|
||||
}
|
||||
|
||||
/* send back checksum for the last edid extension block data */
|
||||
if (drm_dp_dpcd_write(aux, DP_TEST_EDID_CHECKSUM,
|
||||
&real_edid_checksum, 1) < 1) {
|
||||
DRM_ERROR("DPCD failed write at register 0x%x\n",
|
||||
DP_TEST_EDID_CHECKSUM);
|
||||
return false;
|
||||
}
|
||||
|
||||
test_resp |= DP_TEST_EDID_CHECKSUM_WRITE;
|
||||
if (drm_dp_dpcd_write(aux, DP_TEST_RESPONSE, &test_resp, 1) < 1) {
|
||||
DRM_ERROR("DPCD failed write at register 0x%x\n",
|
||||
DP_TEST_RESPONSE);
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
EXPORT_SYMBOL(drm_dp_send_real_edid_checksum);
|
||||
|
||||
/**
|
||||
* drm_dp_downstream_max_clock() - extract branch device max
|
||||
* pixel rate for legacy VGA
|
||||
|
|
|
@ -946,7 +946,8 @@ int drm_dev_register(struct drm_device *dev, unsigned long flags)
|
|||
struct drm_driver *driver = dev->driver;
|
||||
int ret;
|
||||
|
||||
mutex_lock(&drm_global_mutex);
|
||||
if (drm_dev_needs_global_mutex(dev))
|
||||
mutex_lock(&drm_global_mutex);
|
||||
|
||||
ret = drm_minor_register(dev, DRM_MINOR_RENDER);
|
||||
if (ret)
|
||||
|
@ -986,7 +987,8 @@ err_minors:
|
|||
drm_minor_unregister(dev, DRM_MINOR_PRIMARY);
|
||||
drm_minor_unregister(dev, DRM_MINOR_RENDER);
|
||||
out_unlock:
|
||||
mutex_unlock(&drm_global_mutex);
|
||||
if (drm_dev_needs_global_mutex(dev))
|
||||
mutex_unlock(&drm_global_mutex);
|
||||
return ret;
|
||||
}
|
||||
EXPORT_SYMBOL(drm_dev_register);
|
||||
|
@ -1079,17 +1081,14 @@ static int drm_stub_open(struct inode *inode, struct file *filp)
|
|||
|
||||
DRM_DEBUG("\n");
|
||||
|
||||
mutex_lock(&drm_global_mutex);
|
||||
minor = drm_minor_acquire(iminor(inode));
|
||||
if (IS_ERR(minor)) {
|
||||
err = PTR_ERR(minor);
|
||||
goto out_unlock;
|
||||
}
|
||||
if (IS_ERR(minor))
|
||||
return PTR_ERR(minor);
|
||||
|
||||
new_fops = fops_get(minor->dev->driver->fops);
|
||||
if (!new_fops) {
|
||||
err = -ENODEV;
|
||||
goto out_release;
|
||||
goto out;
|
||||
}
|
||||
|
||||
replace_fops(filp, new_fops);
|
||||
|
@ -1098,10 +1097,9 @@ static int drm_stub_open(struct inode *inode, struct file *filp)
|
|||
else
|
||||
err = 0;
|
||||
|
||||
out_release:
|
||||
out:
|
||||
drm_minor_release(minor);
|
||||
out_unlock:
|
||||
mutex_unlock(&drm_global_mutex);
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
|
|
|
@ -1590,11 +1590,22 @@ static int validate_displayid(u8 *displayid, int length, int idx);
|
|||
static int drm_edid_block_checksum(const u8 *raw_edid)
|
||||
{
|
||||
int i;
|
||||
u8 csum = 0;
|
||||
for (i = 0; i < EDID_LENGTH; i++)
|
||||
u8 csum = 0, crc = 0;
|
||||
|
||||
for (i = 0; i < EDID_LENGTH - 1; i++)
|
||||
csum += raw_edid[i];
|
||||
|
||||
return csum;
|
||||
crc = 0x100 - csum;
|
||||
|
||||
return crc;
|
||||
}
|
||||
|
||||
static bool drm_edid_block_checksum_diff(const u8 *raw_edid, u8 real_checksum)
|
||||
{
|
||||
if (raw_edid[EDID_LENGTH - 1] != real_checksum)
|
||||
return true;
|
||||
else
|
||||
return false;
|
||||
}
|
||||
|
||||
static bool drm_edid_is_zero(const u8 *in_edid, int length)
|
||||
|
@ -1652,7 +1663,7 @@ bool drm_edid_block_valid(u8 *raw_edid, int block, bool print_bad_edid,
|
|||
}
|
||||
|
||||
csum = drm_edid_block_checksum(raw_edid);
|
||||
if (csum) {
|
||||
if (drm_edid_block_checksum_diff(raw_edid, csum)) {
|
||||
if (edid_corrupt)
|
||||
*edid_corrupt = true;
|
||||
|
||||
|
@ -1793,6 +1804,11 @@ static void connector_bad_edid(struct drm_connector *connector,
|
|||
u8 *edid, int num_blocks)
|
||||
{
|
||||
int i;
|
||||
u8 num_of_ext = edid[0x7e];
|
||||
|
||||
/* Calculate real checksum for the last edid extension block data */
|
||||
connector->real_edid_checksum =
|
||||
drm_edid_block_checksum(edid + num_of_ext * EDID_LENGTH);
|
||||
|
||||
if (connector->bad_edid_counter++ && !drm_debug_enabled(DRM_UT_KMS))
|
||||
return;
|
||||
|
@ -2196,15 +2212,29 @@ struct drm_display_mode *drm_mode_find_dmt(struct drm_device *dev,
|
|||
}
|
||||
EXPORT_SYMBOL(drm_mode_find_dmt);
|
||||
|
||||
static bool is_display_descriptor(const u8 d[18], u8 tag)
|
||||
{
|
||||
return d[0] == 0x00 && d[1] == 0x00 &&
|
||||
d[2] == 0x00 && d[3] == tag;
|
||||
}
|
||||
|
||||
static bool is_detailed_timing_descriptor(const u8 d[18])
|
||||
{
|
||||
return d[0] != 0x00 || d[1] != 0x00;
|
||||
}
|
||||
|
||||
typedef void detailed_cb(struct detailed_timing *timing, void *closure);
|
||||
|
||||
static void
|
||||
cea_for_each_detailed_block(u8 *ext, detailed_cb *cb, void *closure)
|
||||
{
|
||||
int i, n = 0;
|
||||
int i, n;
|
||||
u8 d = ext[0x02];
|
||||
u8 *det_base = ext + d;
|
||||
|
||||
if (d < 4 || d > 127)
|
||||
return;
|
||||
|
||||
n = (127 - d) / 18;
|
||||
for (i = 0; i < n; i++)
|
||||
cb((struct detailed_timing *)(det_base + 18 * i), closure);
|
||||
|
@ -2254,9 +2284,12 @@ static void
|
|||
is_rb(struct detailed_timing *t, void *data)
|
||||
{
|
||||
u8 *r = (u8 *)t;
|
||||
if (r[3] == EDID_DETAIL_MONITOR_RANGE)
|
||||
if (r[15] & 0x10)
|
||||
*(bool *)data = true;
|
||||
|
||||
if (!is_display_descriptor(r, EDID_DETAIL_MONITOR_RANGE))
|
||||
return;
|
||||
|
||||
if (r[15] & 0x10)
|
||||
*(bool *)data = true;
|
||||
}
|
||||
|
||||
/* EDID 1.4 defines this explicitly. For EDID 1.3, we guess, badly. */
|
||||
|
@ -2276,7 +2309,11 @@ static void
|
|||
find_gtf2(struct detailed_timing *t, void *data)
|
||||
{
|
||||
u8 *r = (u8 *)t;
|
||||
if (r[3] == EDID_DETAIL_MONITOR_RANGE && r[10] == 0x02)
|
||||
|
||||
if (!is_display_descriptor(r, EDID_DETAIL_MONITOR_RANGE))
|
||||
return;
|
||||
|
||||
if (r[10] == 0x02)
|
||||
*(u8 **)data = r;
|
||||
}
|
||||
|
||||
|
@ -2815,13 +2852,13 @@ do_inferred_modes(struct detailed_timing *timing, void *c)
|
|||
struct detailed_non_pixel *data = &timing->data.other_data;
|
||||
struct detailed_data_monitor_range *range = &data->data.range;
|
||||
|
||||
if (data->type != EDID_DETAIL_MONITOR_RANGE)
|
||||
if (!is_display_descriptor((const u8 *)timing, EDID_DETAIL_MONITOR_RANGE))
|
||||
return;
|
||||
|
||||
closure->modes += drm_dmt_modes_for_range(closure->connector,
|
||||
closure->edid,
|
||||
timing);
|
||||
|
||||
|
||||
if (!version_greater(closure->edid, 1, 1))
|
||||
return; /* GTF not defined yet */
|
||||
|
||||
|
@ -2894,10 +2931,11 @@ static void
|
|||
do_established_modes(struct detailed_timing *timing, void *c)
|
||||
{
|
||||
struct detailed_mode_closure *closure = c;
|
||||
struct detailed_non_pixel *data = &timing->data.other_data;
|
||||
|
||||
if (data->type == EDID_DETAIL_EST_TIMINGS)
|
||||
closure->modes += drm_est3_modes(closure->connector, timing);
|
||||
if (!is_display_descriptor((const u8 *)timing, EDID_DETAIL_EST_TIMINGS))
|
||||
return;
|
||||
|
||||
closure->modes += drm_est3_modes(closure->connector, timing);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -2946,19 +2984,19 @@ do_standard_modes(struct detailed_timing *timing, void *c)
|
|||
struct detailed_non_pixel *data = &timing->data.other_data;
|
||||
struct drm_connector *connector = closure->connector;
|
||||
struct edid *edid = closure->edid;
|
||||
int i;
|
||||
|
||||
if (data->type == EDID_DETAIL_STD_MODES) {
|
||||
int i;
|
||||
for (i = 0; i < 6; i++) {
|
||||
struct std_timing *std;
|
||||
struct drm_display_mode *newmode;
|
||||
if (!is_display_descriptor((const u8 *)timing, EDID_DETAIL_STD_MODES))
|
||||
return;
|
||||
|
||||
std = &data->data.timings[i];
|
||||
newmode = drm_mode_std(connector, edid, std);
|
||||
if (newmode) {
|
||||
drm_mode_probed_add(connector, newmode);
|
||||
closure->modes++;
|
||||
}
|
||||
for (i = 0; i < 6; i++) {
|
||||
struct std_timing *std = &data->data.timings[i];
|
||||
struct drm_display_mode *newmode;
|
||||
|
||||
newmode = drm_mode_std(connector, edid, std);
|
||||
if (newmode) {
|
||||
drm_mode_probed_add(connector, newmode);
|
||||
closure->modes++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -3053,15 +3091,16 @@ static void
|
|||
do_cvt_mode(struct detailed_timing *timing, void *c)
|
||||
{
|
||||
struct detailed_mode_closure *closure = c;
|
||||
struct detailed_non_pixel *data = &timing->data.other_data;
|
||||
|
||||
if (data->type == EDID_DETAIL_CVT_3BYTE)
|
||||
closure->modes += drm_cvt_modes(closure->connector, timing);
|
||||
if (!is_display_descriptor((const u8 *)timing, EDID_DETAIL_CVT_3BYTE))
|
||||
return;
|
||||
|
||||
closure->modes += drm_cvt_modes(closure->connector, timing);
|
||||
}
|
||||
|
||||
static int
|
||||
add_cvt_modes(struct drm_connector *connector, struct edid *edid)
|
||||
{
|
||||
{
|
||||
struct detailed_mode_closure closure = {
|
||||
.connector = connector,
|
||||
.edid = edid,
|
||||
|
@ -3083,27 +3122,28 @@ do_detailed_mode(struct detailed_timing *timing, void *c)
|
|||
struct detailed_mode_closure *closure = c;
|
||||
struct drm_display_mode *newmode;
|
||||
|
||||
if (timing->pixel_clock) {
|
||||
newmode = drm_mode_detailed(closure->connector->dev,
|
||||
closure->edid, timing,
|
||||
closure->quirks);
|
||||
if (!newmode)
|
||||
return;
|
||||
if (!is_detailed_timing_descriptor((const u8 *)timing))
|
||||
return;
|
||||
|
||||
if (closure->preferred)
|
||||
newmode->type |= DRM_MODE_TYPE_PREFERRED;
|
||||
newmode = drm_mode_detailed(closure->connector->dev,
|
||||
closure->edid, timing,
|
||||
closure->quirks);
|
||||
if (!newmode)
|
||||
return;
|
||||
|
||||
/*
|
||||
* Detailed modes are limited to 10kHz pixel clock resolution,
|
||||
* so fix up anything that looks like CEA/HDMI mode, but the clock
|
||||
* is just slightly off.
|
||||
*/
|
||||
fixup_detailed_cea_mode_clock(newmode);
|
||||
if (closure->preferred)
|
||||
newmode->type |= DRM_MODE_TYPE_PREFERRED;
|
||||
|
||||
drm_mode_probed_add(closure->connector, newmode);
|
||||
closure->modes++;
|
||||
closure->preferred = false;
|
||||
}
|
||||
/*
|
||||
* Detailed modes are limited to 10kHz pixel clock resolution,
|
||||
* so fix up anything that looks like CEA/HDMI mode, but the clock
|
||||
* is just slightly off.
|
||||
*/
|
||||
fixup_detailed_cea_mode_clock(newmode);
|
||||
|
||||
drm_mode_probed_add(closure->connector, newmode);
|
||||
closure->modes++;
|
||||
closure->preferred = false;
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -3953,6 +3993,13 @@ cea_db_tag(const u8 *db)
|
|||
static int
|
||||
cea_revision(const u8 *cea)
|
||||
{
|
||||
/*
|
||||
* FIXME is this correct for the DispID variant?
|
||||
* The DispID spec doesn't really specify whether
|
||||
* this is the revision of the CEA extension or
|
||||
* the DispID CEA data block. And the only value
|
||||
* given as an example is 0.
|
||||
*/
|
||||
return cea[1];
|
||||
}
|
||||
|
||||
|
@ -3977,6 +4024,10 @@ cea_db_offsets(const u8 *cea, int *start, int *end)
|
|||
* no non-DTD data.
|
||||
*/
|
||||
if (cea[0] == DATA_BLOCK_CTA) {
|
||||
/*
|
||||
* for_each_displayid_db() has already verified
|
||||
* that these stay within expected bounds.
|
||||
*/
|
||||
*start = 3;
|
||||
*end = *start + cea[2];
|
||||
} else if (cea[0] == CEA_EXT) {
|
||||
|
@ -4282,8 +4333,10 @@ drm_parse_hdmi_vsdb_audio(struct drm_connector *connector, const u8 *db)
|
|||
static void
|
||||
monitor_name(struct detailed_timing *t, void *data)
|
||||
{
|
||||
if (t->data.other_data.type == EDID_DETAIL_MONITOR_NAME)
|
||||
*(u8 **)data = t->data.other_data.data.str.str;
|
||||
if (!is_display_descriptor((const u8 *)t, EDID_DETAIL_MONITOR_NAME))
|
||||
return;
|
||||
|
||||
*(u8 **)data = t->data.other_data.data.str.str;
|
||||
}
|
||||
|
||||
static int get_monitor_name(struct edid *edid, char name[13])
|
||||
|
@ -4316,7 +4369,7 @@ void drm_edid_get_monitor_name(struct edid *edid, char *name, int bufsize)
|
|||
{
|
||||
int name_length;
|
||||
char buf[13];
|
||||
|
||||
|
||||
if (bufsize <= 0)
|
||||
return;
|
||||
|
||||
|
|
|
@ -250,17 +250,7 @@ int drm_fb_helper_restore_fbdev_mode_unlocked(struct drm_fb_helper *fb_helper)
|
|||
return 0;
|
||||
|
||||
mutex_lock(&fb_helper->lock);
|
||||
/*
|
||||
* TODO:
|
||||
* We should bail out here if there is a master by dropping _force.
|
||||
* Currently these igt tests fail if we do that:
|
||||
* - kms_fbcon_fbt@psr
|
||||
* - kms_fbcon_fbt@psr-suspend
|
||||
*
|
||||
* So first these tests need to be fixed so they drop master or don't
|
||||
* have an fd open.
|
||||
*/
|
||||
ret = drm_client_modeset_commit_force(&fb_helper->client);
|
||||
ret = drm_client_modeset_commit(&fb_helper->client);
|
||||
|
||||
do_delayed = fb_helper->delayed_hotplug;
|
||||
if (do_delayed)
|
||||
|
@ -294,7 +284,7 @@ static bool drm_fb_helper_force_kernel_mode(void)
|
|||
continue;
|
||||
|
||||
mutex_lock(&helper->lock);
|
||||
ret = drm_client_modeset_commit_force(&helper->client);
|
||||
ret = drm_client_modeset_commit_locked(&helper->client);
|
||||
if (ret)
|
||||
error = true;
|
||||
mutex_unlock(&helper->lock);
|
||||
|
@ -1357,7 +1347,7 @@ static int pan_display_atomic(struct fb_var_screeninfo *var,
|
|||
|
||||
pan_set(fb_helper, var->xoffset, var->yoffset);
|
||||
|
||||
ret = drm_client_modeset_commit_force(&fb_helper->client);
|
||||
ret = drm_client_modeset_commit_locked(&fb_helper->client);
|
||||
if (!ret) {
|
||||
info->var.xoffset = var->xoffset;
|
||||
info->var.yoffset = var->yoffset;
|
||||
|
|
|
@ -51,6 +51,37 @@
|
|||
/* from BKL pushdown */
|
||||
DEFINE_MUTEX(drm_global_mutex);
|
||||
|
||||
bool drm_dev_needs_global_mutex(struct drm_device *dev)
|
||||
{
|
||||
/*
|
||||
* Legacy drivers rely on all kinds of BKL locking semantics, don't
|
||||
* bother. They also still need BKL locking for their ioctls, so better
|
||||
* safe than sorry.
|
||||
*/
|
||||
if (drm_core_check_feature(dev, DRIVER_LEGACY))
|
||||
return true;
|
||||
|
||||
/*
|
||||
* The deprecated ->load callback must be called after the driver is
|
||||
* already registered. This means such drivers rely on the BKL to make
|
||||
* sure an open can't proceed until the driver is actually fully set up.
|
||||
* Similar hilarity holds for the unload callback.
|
||||
*/
|
||||
if (dev->driver->load || dev->driver->unload)
|
||||
return true;
|
||||
|
||||
/*
|
||||
* Drivers with the lastclose callback assume that it's synchronized
|
||||
* against concurrent opens, which again needs the BKL. The proper fix
|
||||
* is to use the drm_client infrastructure with proper locking for each
|
||||
* client.
|
||||
*/
|
||||
if (dev->driver->lastclose)
|
||||
return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* DOC: file operations
|
||||
*
|
||||
|
@ -379,6 +410,9 @@ int drm_open(struct inode *inode, struct file *filp)
|
|||
return PTR_ERR(minor);
|
||||
|
||||
dev = minor->dev;
|
||||
if (drm_dev_needs_global_mutex(dev))
|
||||
mutex_lock(&drm_global_mutex);
|
||||
|
||||
if (!atomic_fetch_inc(&dev->open_count))
|
||||
need_setup = 1;
|
||||
|
||||
|
@ -395,10 +429,16 @@ int drm_open(struct inode *inode, struct file *filp)
|
|||
goto err_undo;
|
||||
}
|
||||
}
|
||||
|
||||
if (drm_dev_needs_global_mutex(dev))
|
||||
mutex_unlock(&drm_global_mutex);
|
||||
|
||||
return 0;
|
||||
|
||||
err_undo:
|
||||
atomic_dec(&dev->open_count);
|
||||
if (drm_dev_needs_global_mutex(dev))
|
||||
mutex_unlock(&drm_global_mutex);
|
||||
drm_minor_release(minor);
|
||||
return retcode;
|
||||
}
|
||||
|
@ -438,7 +478,8 @@ int drm_release(struct inode *inode, struct file *filp)
|
|||
struct drm_minor *minor = file_priv->minor;
|
||||
struct drm_device *dev = minor->dev;
|
||||
|
||||
mutex_lock(&drm_global_mutex);
|
||||
if (drm_dev_needs_global_mutex(dev))
|
||||
mutex_lock(&drm_global_mutex);
|
||||
|
||||
DRM_DEBUG("open_count = %d\n", atomic_read(&dev->open_count));
|
||||
|
||||
|
@ -447,7 +488,8 @@ int drm_release(struct inode *inode, struct file *filp)
|
|||
if (atomic_dec_and_test(&dev->open_count))
|
||||
drm_lastclose(dev);
|
||||
|
||||
mutex_unlock(&drm_global_mutex);
|
||||
if (drm_dev_needs_global_mutex(dev))
|
||||
mutex_unlock(&drm_global_mutex);
|
||||
|
||||
drm_minor_release(minor);
|
||||
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
/* SPDX-License-Identifier: GPL-2.0 */
|
||||
// SPDX-License-Identifier: GPL-2.0 or MIT
|
||||
/*
|
||||
* Copyright (C) 2016 Noralf Trønnes
|
||||
*
|
||||
|
|
|
@ -41,6 +41,7 @@ struct drm_printer;
|
|||
|
||||
/* drm_file.c */
|
||||
extern struct mutex drm_global_mutex;
|
||||
bool drm_dev_needs_global_mutex(struct drm_device *dev);
|
||||
struct drm_file *drm_file_alloc(struct drm_minor *minor);
|
||||
void drm_file_free(struct drm_file *file);
|
||||
void drm_lastclose(struct drm_device *dev);
|
||||
|
|
|
@ -111,10 +111,6 @@ int drm_irq_install(struct drm_device *dev, int irq)
|
|||
if (irq == 0)
|
||||
return -EINVAL;
|
||||
|
||||
/* Driver must have been initialized */
|
||||
if (!dev->dev_private)
|
||||
return -EINVAL;
|
||||
|
||||
if (dev->irq_enabled)
|
||||
return -EBUSY;
|
||||
dev->irq_enabled = true;
|
||||
|
|
|
@ -30,6 +30,7 @@
|
|||
#include <drm/drm_crtc.h>
|
||||
#include <drm/drm_drv.h>
|
||||
#include <drm/drm_framebuffer.h>
|
||||
#include <drm/drm_modeset_helper_vtables.h>
|
||||
#include <drm/drm_print.h>
|
||||
#include <drm/drm_vblank.h>
|
||||
|
||||
|
@ -143,10 +144,9 @@ static u32 __get_vblank_counter(struct drm_device *dev, unsigned int pipe)
|
|||
|
||||
if (crtc->funcs->get_vblank_counter)
|
||||
return crtc->funcs->get_vblank_counter(crtc);
|
||||
}
|
||||
|
||||
if (dev->driver->get_vblank_counter)
|
||||
} else if (dev->driver->get_vblank_counter) {
|
||||
return dev->driver->get_vblank_counter(dev, pipe);
|
||||
}
|
||||
|
||||
return drm_vblank_no_hw_counter(dev, pipe);
|
||||
}
|
||||
|
@ -338,7 +338,8 @@ u64 drm_crtc_accurate_vblank_count(struct drm_crtc *crtc)
|
|||
u64 vblank;
|
||||
unsigned long flags;
|
||||
|
||||
WARN_ONCE(drm_debug_enabled(DRM_UT_VBL) && !dev->driver->get_vblank_timestamp,
|
||||
WARN_ONCE(drm_debug_enabled(DRM_UT_VBL) &&
|
||||
!crtc->funcs->get_vblank_timestamp,
|
||||
"This function requires support for accurate vblank timestamps.");
|
||||
|
||||
spin_lock_irqsave(&dev->vblank_time_lock, flags);
|
||||
|
@ -360,13 +361,11 @@ static void __disable_vblank(struct drm_device *dev, unsigned int pipe)
|
|||
if (WARN_ON(!crtc))
|
||||
return;
|
||||
|
||||
if (crtc->funcs->disable_vblank) {
|
||||
if (crtc->funcs->disable_vblank)
|
||||
crtc->funcs->disable_vblank(crtc);
|
||||
return;
|
||||
}
|
||||
} else {
|
||||
dev->driver->disable_vblank(dev, pipe);
|
||||
}
|
||||
|
||||
dev->driver->disable_vblank(dev, pipe);
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -486,19 +485,6 @@ int drm_vblank_init(struct drm_device *dev, unsigned int num_crtcs)
|
|||
|
||||
DRM_INFO("Supports vblank timestamp caching Rev 2 (21.10.2013).\n");
|
||||
|
||||
/* Driver specific high-precision vblank timestamping supported? */
|
||||
if (dev->driver->get_vblank_timestamp)
|
||||
DRM_INFO("Driver supports precise vblank timestamp query.\n");
|
||||
else
|
||||
DRM_INFO("No driver support for vblank timestamp query.\n");
|
||||
|
||||
/* Must have precise timestamping for reliable vblank instant disable */
|
||||
if (dev->vblank_disable_immediate && !dev->driver->get_vblank_timestamp) {
|
||||
dev->vblank_disable_immediate = false;
|
||||
DRM_INFO("Setting vblank_disable_immediate to false because "
|
||||
"get_vblank_timestamp == NULL\n");
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
err:
|
||||
|
@ -551,9 +537,9 @@ EXPORT_SYMBOL(drm_crtc_vblank_waitqueue);
|
|||
*
|
||||
* Calculate and store various constants which are later needed by vblank and
|
||||
* swap-completion timestamping, e.g, by
|
||||
* drm_calc_vbltimestamp_from_scanoutpos(). They are derived from CRTC's true
|
||||
* scanout timing, so they take things like panel scaling or other adjustments
|
||||
* into account.
|
||||
* drm_crtc_vblank_helper_get_vblank_timestamp(). They are derived from
|
||||
* CRTC's true scanout timing, so they take things like panel scaling or
|
||||
* other adjustments into account.
|
||||
*/
|
||||
void drm_calc_timestamping_constants(struct drm_crtc *crtc,
|
||||
const struct drm_display_mode *mode)
|
||||
|
@ -604,7 +590,8 @@ void drm_calc_timestamping_constants(struct drm_crtc *crtc,
|
|||
EXPORT_SYMBOL(drm_calc_timestamping_constants);
|
||||
|
||||
/**
|
||||
* drm_calc_vbltimestamp_from_scanoutpos - precise vblank timestamp helper
|
||||
* drm_crtc_vblank_helper_get_vblank_timestamp_internal - precise vblank
|
||||
* timestamp helper
|
||||
* @dev: DRM device
|
||||
* @pipe: index of CRTC whose vblank timestamp to retrieve
|
||||
* @max_error: Desired maximum allowable error in timestamps (nanosecs)
|
||||
|
@ -614,11 +601,12 @@ EXPORT_SYMBOL(drm_calc_timestamping_constants);
|
|||
* True when called from drm_crtc_handle_vblank(). Some drivers
|
||||
* need to apply some workarounds for gpu-specific vblank irq quirks
|
||||
* if flag is set.
|
||||
* @get_scanout_position:
|
||||
* Callback function to retrieve the scanout position. See
|
||||
* @struct drm_crtc_helper_funcs.get_scanout_position.
|
||||
*
|
||||
* Implements calculation of exact vblank timestamps from given drm_display_mode
|
||||
* timings and current video scanout position of a CRTC. This can be directly
|
||||
* used as the &drm_driver.get_vblank_timestamp implementation of a kms driver
|
||||
* if &drm_driver.get_scanout_position is implemented.
|
||||
* timings and current video scanout position of a CRTC.
|
||||
*
|
||||
* The current implementation only handles standard video modes. For double scan
|
||||
* and interlaced modes the driver is supposed to adjust the hardware mode
|
||||
|
@ -634,34 +622,30 @@ EXPORT_SYMBOL(drm_calc_timestamping_constants);
|
|||
* Returns true on success, and false on failure, i.e. when no accurate
|
||||
* timestamp could be acquired.
|
||||
*/
|
||||
bool drm_calc_vbltimestamp_from_scanoutpos(struct drm_device *dev,
|
||||
unsigned int pipe,
|
||||
int *max_error,
|
||||
ktime_t *vblank_time,
|
||||
bool in_vblank_irq)
|
||||
bool
|
||||
drm_crtc_vblank_helper_get_vblank_timestamp_internal(
|
||||
struct drm_crtc *crtc, int *max_error, ktime_t *vblank_time,
|
||||
bool in_vblank_irq,
|
||||
drm_vblank_get_scanout_position_func get_scanout_position)
|
||||
{
|
||||
struct drm_device *dev = crtc->dev;
|
||||
unsigned int pipe = crtc->index;
|
||||
struct drm_vblank_crtc *vblank = &dev->vblank[pipe];
|
||||
struct timespec64 ts_etime, ts_vblank_time;
|
||||
ktime_t stime, etime;
|
||||
bool vbl_status;
|
||||
struct drm_crtc *crtc;
|
||||
const struct drm_display_mode *mode;
|
||||
struct drm_vblank_crtc *vblank = &dev->vblank[pipe];
|
||||
int vpos, hpos, i;
|
||||
int delta_ns, duration_ns;
|
||||
|
||||
if (!drm_core_check_feature(dev, DRIVER_MODESET))
|
||||
return false;
|
||||
|
||||
crtc = drm_crtc_from_index(dev, pipe);
|
||||
|
||||
if (pipe >= dev->num_crtcs || !crtc) {
|
||||
if (pipe >= dev->num_crtcs) {
|
||||
DRM_ERROR("Invalid crtc %u\n", pipe);
|
||||
return false;
|
||||
}
|
||||
|
||||
/* Scanout position query not supported? Should not happen. */
|
||||
if (!dev->driver->get_scanout_position) {
|
||||
DRM_ERROR("Called from driver w/o get_scanout_position()!?\n");
|
||||
if (!get_scanout_position) {
|
||||
DRM_ERROR("Called from CRTC w/o get_scanout_position()!?\n");
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -676,7 +660,6 @@ bool drm_calc_vbltimestamp_from_scanoutpos(struct drm_device *dev,
|
|||
if (mode->crtc_clock == 0) {
|
||||
DRM_DEBUG("crtc %u: Noop due to uninitialized mode.\n", pipe);
|
||||
WARN_ON_ONCE(drm_drv_uses_atomic_modeset(dev));
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -692,11 +675,10 @@ bool drm_calc_vbltimestamp_from_scanoutpos(struct drm_device *dev,
|
|||
* Get vertical and horizontal scanout position vpos, hpos,
|
||||
* and bounding timestamps stime, etime, pre/post query.
|
||||
*/
|
||||
vbl_status = dev->driver->get_scanout_position(dev, pipe,
|
||||
in_vblank_irq,
|
||||
&vpos, &hpos,
|
||||
&stime, &etime,
|
||||
mode);
|
||||
vbl_status = get_scanout_position(crtc, in_vblank_irq,
|
||||
&vpos, &hpos,
|
||||
&stime, &etime,
|
||||
mode);
|
||||
|
||||
/* Return as no-op if scanout query unsupported or failed. */
|
||||
if (!vbl_status) {
|
||||
|
@ -748,7 +730,49 @@ bool drm_calc_vbltimestamp_from_scanoutpos(struct drm_device *dev,
|
|||
|
||||
return true;
|
||||
}
|
||||
EXPORT_SYMBOL(drm_calc_vbltimestamp_from_scanoutpos);
|
||||
EXPORT_SYMBOL(drm_crtc_vblank_helper_get_vblank_timestamp_internal);
|
||||
|
||||
/**
|
||||
* drm_crtc_vblank_helper_get_vblank_timestamp - precise vblank timestamp
|
||||
* helper
|
||||
* @crtc: CRTC whose vblank timestamp to retrieve
|
||||
* @max_error: Desired maximum allowable error in timestamps (nanosecs)
|
||||
* On return contains true maximum error of timestamp
|
||||
* @vblank_time: Pointer to time which should receive the timestamp
|
||||
* @in_vblank_irq:
|
||||
* True when called from drm_crtc_handle_vblank(). Some drivers
|
||||
* need to apply some workarounds for gpu-specific vblank irq quirks
|
||||
* if flag is set.
|
||||
*
|
||||
* Implements calculation of exact vblank timestamps from given drm_display_mode
|
||||
* timings and current video scanout position of a CRTC. This can be directly
|
||||
* used as the &drm_crtc_funcs.get_vblank_timestamp implementation of a kms
|
||||
* driver if &drm_crtc_helper_funcs.get_scanout_position is implemented.
|
||||
*
|
||||
* The current implementation only handles standard video modes. For double scan
|
||||
* and interlaced modes the driver is supposed to adjust the hardware mode
|
||||
* (taken from &drm_crtc_state.adjusted mode for atomic modeset drivers) to
|
||||
* match the scanout position reported.
|
||||
*
|
||||
* Note that atomic drivers must call drm_calc_timestamping_constants() before
|
||||
* enabling a CRTC. The atomic helpers already take care of that in
|
||||
* drm_atomic_helper_update_legacy_modeset_state().
|
||||
*
|
||||
* Returns:
|
||||
*
|
||||
* Returns true on success, and false on failure, i.e. when no accurate
|
||||
* timestamp could be acquired.
|
||||
*/
|
||||
bool drm_crtc_vblank_helper_get_vblank_timestamp(struct drm_crtc *crtc,
|
||||
int *max_error,
|
||||
ktime_t *vblank_time,
|
||||
bool in_vblank_irq)
|
||||
{
|
||||
return drm_crtc_vblank_helper_get_vblank_timestamp_internal(
|
||||
crtc, max_error, vblank_time, in_vblank_irq,
|
||||
crtc->helper_private->get_scanout_position);
|
||||
}
|
||||
EXPORT_SYMBOL(drm_crtc_vblank_helper_get_vblank_timestamp);
|
||||
|
||||
/**
|
||||
* drm_get_last_vbltimestamp - retrieve raw timestamp for the most recent
|
||||
|
@ -775,15 +799,19 @@ static bool
|
|||
drm_get_last_vbltimestamp(struct drm_device *dev, unsigned int pipe,
|
||||
ktime_t *tvblank, bool in_vblank_irq)
|
||||
{
|
||||
struct drm_crtc *crtc = drm_crtc_from_index(dev, pipe);
|
||||
bool ret = false;
|
||||
|
||||
/* Define requested maximum error on timestamps (nanoseconds). */
|
||||
int max_error = (int) drm_timestamp_precision * 1000;
|
||||
|
||||
/* Query driver if possible and precision timestamping enabled. */
|
||||
if (dev->driver->get_vblank_timestamp && (max_error > 0))
|
||||
ret = dev->driver->get_vblank_timestamp(dev, pipe, &max_error,
|
||||
if (crtc && crtc->funcs->get_vblank_timestamp && max_error > 0) {
|
||||
struct drm_crtc *crtc = drm_crtc_from_index(dev, pipe);
|
||||
|
||||
ret = crtc->funcs->get_vblank_timestamp(crtc, &max_error,
|
||||
tvblank, in_vblank_irq);
|
||||
}
|
||||
|
||||
/* GPU high precision timestamp query unsupported or failed.
|
||||
* Return current monotonic/gettimeofday timestamp as best estimate.
|
||||
|
@ -1005,9 +1033,11 @@ static int __enable_vblank(struct drm_device *dev, unsigned int pipe)
|
|||
|
||||
if (crtc->funcs->enable_vblank)
|
||||
return crtc->funcs->enable_vblank(crtc);
|
||||
} else if (dev->driver->enable_vblank) {
|
||||
return dev->driver->enable_vblank(dev, pipe);
|
||||
}
|
||||
|
||||
return dev->driver->enable_vblank(dev, pipe);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
static int drm_vblank_enable(struct drm_device *dev, unsigned int pipe)
|
||||
|
@ -1766,6 +1796,8 @@ done:
|
|||
|
||||
static void drm_handle_vblank_events(struct drm_device *dev, unsigned int pipe)
|
||||
{
|
||||
struct drm_crtc *crtc = drm_crtc_from_index(dev, pipe);
|
||||
bool high_prec = false;
|
||||
struct drm_pending_vblank_event *e, *t;
|
||||
ktime_t now;
|
||||
u64 seq;
|
||||
|
@ -1788,8 +1820,10 @@ static void drm_handle_vblank_events(struct drm_device *dev, unsigned int pipe)
|
|||
send_vblank_event(dev, e, seq, now);
|
||||
}
|
||||
|
||||
trace_drm_vblank_event(pipe, seq, now,
|
||||
dev->driver->get_vblank_timestamp != NULL);
|
||||
if (crtc && crtc->funcs->get_vblank_timestamp)
|
||||
high_prec = true;
|
||||
|
||||
trace_drm_vblank_event(pipe, seq, now, high_prec);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -977,6 +977,9 @@ const struct drm_crtc_funcs cdv_intel_crtc_funcs = {
|
|||
.set_config = gma_crtc_set_config,
|
||||
.destroy = gma_crtc_destroy,
|
||||
.page_flip = gma_crtc_page_flip,
|
||||
.enable_vblank = psb_enable_vblank,
|
||||
.disable_vblank = psb_disable_vblank,
|
||||
.get_vblank_counter = psb_get_vblank_counter,
|
||||
};
|
||||
|
||||
const struct gma_clock_funcs cdv_clock_funcs = {
|
||||
|
|
|
@ -363,7 +363,6 @@ static int psb_driver_load(struct drm_device *dev, unsigned long flags)
|
|||
drm_irq_install(dev, dev->pdev->irq);
|
||||
|
||||
dev->max_vblank_count = 0xffffff; /* only 24 bits of frame count */
|
||||
dev->driver->get_vblank_counter = psb_get_vblank_counter;
|
||||
|
||||
psb_modeset_init(dev);
|
||||
psb_fbdev_init(dev);
|
||||
|
@ -507,9 +506,6 @@ static struct drm_driver driver = {
|
|||
.irq_postinstall = psb_irq_postinstall,
|
||||
.irq_uninstall = psb_irq_uninstall,
|
||||
.irq_handler = psb_irq_handler,
|
||||
.enable_vblank = psb_enable_vblank,
|
||||
.disable_vblank = psb_disable_vblank,
|
||||
.get_vblank_counter = psb_get_vblank_counter,
|
||||
|
||||
.gem_free_object = psb_gem_free_object,
|
||||
.gem_vm_ops = &psb_gem_vm_ops,
|
||||
|
|
|
@ -681,15 +681,15 @@ extern void psb_irq_turn_off_dpst(struct drm_device *dev);
|
|||
extern void psb_irq_uninstall_islands(struct drm_device *dev, int hw_islands);
|
||||
extern int psb_vblank_wait2(struct drm_device *dev, unsigned int *sequence);
|
||||
extern int psb_vblank_wait(struct drm_device *dev, unsigned int *sequence);
|
||||
extern int psb_enable_vblank(struct drm_device *dev, unsigned int pipe);
|
||||
extern void psb_disable_vblank(struct drm_device *dev, unsigned int pipe);
|
||||
extern int psb_enable_vblank(struct drm_crtc *crtc);
|
||||
extern void psb_disable_vblank(struct drm_crtc *crtc);
|
||||
void
|
||||
psb_enable_pipestat(struct drm_psb_private *dev_priv, int pipe, u32 mask);
|
||||
|
||||
void
|
||||
psb_disable_pipestat(struct drm_psb_private *dev_priv, int pipe, u32 mask);
|
||||
|
||||
extern u32 psb_get_vblank_counter(struct drm_device *dev, unsigned int pipe);
|
||||
extern u32 psb_get_vblank_counter(struct drm_crtc *crtc);
|
||||
|
||||
/* framebuffer.c */
|
||||
extern int psbfb_probed(struct drm_device *dev);
|
||||
|
|
|
@ -433,6 +433,9 @@ const struct drm_crtc_funcs psb_intel_crtc_funcs = {
|
|||
.set_config = gma_crtc_set_config,
|
||||
.destroy = gma_crtc_destroy,
|
||||
.page_flip = gma_crtc_page_flip,
|
||||
.enable_vblank = psb_enable_vblank,
|
||||
.disable_vblank = psb_disable_vblank,
|
||||
.get_vblank_counter = psb_get_vblank_counter,
|
||||
};
|
||||
|
||||
const struct gma_clock_funcs psb_clock_funcs = {
|
||||
|
|
|
@ -506,8 +506,10 @@ int psb_irq_disable_dpst(struct drm_device *dev)
|
|||
/*
|
||||
* It is used to enable VBLANK interrupt
|
||||
*/
|
||||
int psb_enable_vblank(struct drm_device *dev, unsigned int pipe)
|
||||
int psb_enable_vblank(struct drm_crtc *crtc)
|
||||
{
|
||||
struct drm_device *dev = crtc->dev;
|
||||
unsigned int pipe = crtc->index;
|
||||
struct drm_psb_private *dev_priv = dev->dev_private;
|
||||
unsigned long irqflags;
|
||||
uint32_t reg_val = 0;
|
||||
|
@ -545,8 +547,10 @@ int psb_enable_vblank(struct drm_device *dev, unsigned int pipe)
|
|||
/*
|
||||
* It is used to disable VBLANK interrupt
|
||||
*/
|
||||
void psb_disable_vblank(struct drm_device *dev, unsigned int pipe)
|
||||
void psb_disable_vblank(struct drm_crtc *crtc)
|
||||
{
|
||||
struct drm_device *dev = crtc->dev;
|
||||
unsigned int pipe = crtc->index;
|
||||
struct drm_psb_private *dev_priv = dev->dev_private;
|
||||
unsigned long irqflags;
|
||||
|
||||
|
@ -618,8 +622,10 @@ void mdfld_disable_te(struct drm_device *dev, int pipe)
|
|||
/* Called from drm generic code, passed a 'crtc', which
|
||||
* we use as a pipe index
|
||||
*/
|
||||
u32 psb_get_vblank_counter(struct drm_device *dev, unsigned int pipe)
|
||||
u32 psb_get_vblank_counter(struct drm_crtc *crtc)
|
||||
{
|
||||
struct drm_device *dev = crtc->dev;
|
||||
unsigned int pipe = crtc->index;
|
||||
uint32_t high_frame = PIPEAFRAMEHIGH;
|
||||
uint32_t low_frame = PIPEAFRAMEPIXEL;
|
||||
uint32_t pipeconf_reg = PIPEACONF;
|
||||
|
|
|
@ -12,6 +12,7 @@
|
|||
#ifndef _PSB_IRQ_H_
|
||||
#define _PSB_IRQ_H_
|
||||
|
||||
struct drm_crtc;
|
||||
struct drm_device;
|
||||
|
||||
bool sysirq_init(struct drm_device *dev);
|
||||
|
@ -26,9 +27,9 @@ int psb_irq_enable_dpst(struct drm_device *dev);
|
|||
int psb_irq_disable_dpst(struct drm_device *dev);
|
||||
void psb_irq_turn_on_dpst(struct drm_device *dev);
|
||||
void psb_irq_turn_off_dpst(struct drm_device *dev);
|
||||
int psb_enable_vblank(struct drm_device *dev, unsigned int pipe);
|
||||
void psb_disable_vblank(struct drm_device *dev, unsigned int pipe);
|
||||
u32 psb_get_vblank_counter(struct drm_device *dev, unsigned int pipe);
|
||||
int psb_enable_vblank(struct drm_crtc *crtc);
|
||||
void psb_disable_vblank(struct drm_crtc *crtc);
|
||||
u32 psb_get_vblank_counter(struct drm_crtc *crtc);
|
||||
|
||||
int mdfld_enable_te(struct drm_device *dev, int pipe);
|
||||
void mdfld_disable_te(struct drm_device *dev, int pipe);
|
||||
|
|
|
@ -80,6 +80,9 @@ static int hibmc_plane_atomic_check(struct drm_plane *plane,
|
|||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (!crtc_state->enable)
|
||||
return 0;
|
||||
|
||||
if (state->crtc_x + state->crtc_w >
|
||||
crtc_state->adjusted_mode.hdisplay ||
|
||||
state->crtc_y + state->crtc_h >
|
||||
|
@ -184,6 +187,20 @@ static struct drm_plane *hibmc_plane_init(struct hibmc_drm_private *priv)
|
|||
return plane;
|
||||
}
|
||||
|
||||
static void hibmc_crtc_dpms(struct drm_crtc *crtc, int dpms)
|
||||
{
|
||||
struct hibmc_drm_private *priv = crtc->dev->dev_private;
|
||||
unsigned int reg;
|
||||
|
||||
reg = readl(priv->mmio + HIBMC_CRT_DISP_CTL);
|
||||
reg &= ~HIBMC_CRT_DISP_CTL_DPMS_MASK;
|
||||
reg |= HIBMC_FIELD(HIBMC_CRT_DISP_CTL_DPMS, dpms);
|
||||
reg &= ~HIBMC_CRT_DISP_CTL_TIMING_MASK;
|
||||
if (dpms == HIBMC_CRT_DPMS_ON)
|
||||
reg |= HIBMC_CRT_DISP_CTL_TIMING(1);
|
||||
writel(reg, priv->mmio + HIBMC_CRT_DISP_CTL);
|
||||
}
|
||||
|
||||
static void hibmc_crtc_atomic_enable(struct drm_crtc *crtc,
|
||||
struct drm_crtc_state *old_state)
|
||||
{
|
||||
|
@ -200,6 +217,7 @@ static void hibmc_crtc_atomic_enable(struct drm_crtc *crtc,
|
|||
reg |= HIBMC_CURR_GATE_DISPLAY(1);
|
||||
hibmc_set_current_gate(priv, reg);
|
||||
drm_crtc_vblank_on(crtc);
|
||||
hibmc_crtc_dpms(crtc, HIBMC_CRT_DPMS_ON);
|
||||
}
|
||||
|
||||
static void hibmc_crtc_atomic_disable(struct drm_crtc *crtc,
|
||||
|
@ -208,6 +226,7 @@ static void hibmc_crtc_atomic_disable(struct drm_crtc *crtc,
|
|||
unsigned int reg;
|
||||
struct hibmc_drm_private *priv = crtc->dev->dev_private;
|
||||
|
||||
hibmc_crtc_dpms(crtc, HIBMC_CRT_DPMS_OFF);
|
||||
drm_crtc_vblank_off(crtc);
|
||||
|
||||
hibmc_set_power_mode(priv, HIBMC_PW_MODE_CTL_MODE_SLEEP);
|
||||
|
@ -435,6 +454,42 @@ static void hibmc_crtc_disable_vblank(struct drm_crtc *crtc)
|
|||
priv->mmio + HIBMC_RAW_INTERRUPT_EN);
|
||||
}
|
||||
|
||||
static void hibmc_crtc_load_lut(struct drm_crtc *crtc)
|
||||
{
|
||||
struct hibmc_drm_private *priv = crtc->dev->dev_private;
|
||||
void __iomem *mmio = priv->mmio;
|
||||
u16 *r, *g, *b;
|
||||
unsigned int reg;
|
||||
int i;
|
||||
|
||||
r = crtc->gamma_store;
|
||||
g = r + crtc->gamma_size;
|
||||
b = g + crtc->gamma_size;
|
||||
|
||||
for (i = 0; i < crtc->gamma_size; i++) {
|
||||
unsigned int offset = i << 2;
|
||||
u8 red = *r++ >> 8;
|
||||
u8 green = *g++ >> 8;
|
||||
u8 blue = *b++ >> 8;
|
||||
u32 rgb = (red << 16) | (green << 8) | blue;
|
||||
|
||||
writel(rgb, mmio + HIBMC_CRT_PALETTE + offset);
|
||||
}
|
||||
|
||||
reg = readl(priv->mmio + HIBMC_CRT_DISP_CTL);
|
||||
reg |= HIBMC_FIELD(HIBMC_CTL_DISP_CTL_GAMMA, 1);
|
||||
writel(reg, priv->mmio + HIBMC_CRT_DISP_CTL);
|
||||
}
|
||||
|
||||
static int hibmc_crtc_gamma_set(struct drm_crtc *crtc, u16 *red, u16 *green,
|
||||
u16 *blue, uint32_t size,
|
||||
struct drm_modeset_acquire_ctx *ctx)
|
||||
{
|
||||
hibmc_crtc_load_lut(crtc);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct drm_crtc_funcs hibmc_crtc_funcs = {
|
||||
.page_flip = drm_atomic_helper_page_flip,
|
||||
.set_config = drm_atomic_helper_set_config,
|
||||
|
@ -444,6 +499,7 @@ static const struct drm_crtc_funcs hibmc_crtc_funcs = {
|
|||
.atomic_destroy_state = drm_atomic_helper_crtc_destroy_state,
|
||||
.enable_vblank = hibmc_crtc_enable_vblank,
|
||||
.disable_vblank = hibmc_crtc_disable_vblank,
|
||||
.gamma_set = hibmc_crtc_gamma_set,
|
||||
};
|
||||
|
||||
static const struct drm_crtc_helper_funcs hibmc_crtc_helper_funcs = {
|
||||
|
|
|
@ -68,6 +68,12 @@
|
|||
|
||||
#define HIBMC_CRT_DISP_CTL 0x80200
|
||||
|
||||
#define HIBMC_CRT_DISP_CTL_DPMS(x) ((x) << 30)
|
||||
#define HIBMC_CRT_DISP_CTL_DPMS_MASK 0xc0000000
|
||||
|
||||
#define HIBMC_CRT_DPMS_ON 0
|
||||
#define HIBMC_CRT_DPMS_OFF 3
|
||||
|
||||
#define HIBMC_CRT_DISP_CTL_CRTSELECT(x) ((x) << 25)
|
||||
#define HIBMC_CRT_DISP_CTL_CRTSELECT_MASK 0x2000000
|
||||
|
||||
|
@ -85,6 +91,9 @@
|
|||
#define HIBMC_CRT_DISP_CTL_TIMING(x) ((x) << 8)
|
||||
#define HIBMC_CRT_DISP_CTL_TIMING_MASK 0x100
|
||||
|
||||
#define HIBMC_CTL_DISP_CTL_GAMMA(x) ((x) << 3)
|
||||
#define HIBMC_CTL_DISP_CTL_GAMMA_MASK 0x08
|
||||
|
||||
#define HIBMC_CRT_DISP_CTL_PLANE(x) ((x) << 2)
|
||||
#define HIBMC_CRT_DISP_CTL_PLANE_MASK 4
|
||||
|
||||
|
@ -187,5 +196,7 @@
|
|||
#define CRT_PLL2_HS_148MHZ 0xB0CCCCCD
|
||||
#define CRT_PLL2_HS_193MHZ 0xC0872B02
|
||||
|
||||
#define HIBMC_CRT_PALETTE 0x80C00
|
||||
|
||||
#define HIBMC_FIELD(field, value) (field(value) & field##_MASK)
|
||||
#endif
|
||||
|
|
|
@ -16328,6 +16328,7 @@ static const struct drm_crtc_funcs bdw_crtc_funcs = {
|
|||
.get_vblank_counter = g4x_get_vblank_counter,
|
||||
.enable_vblank = bdw_enable_vblank,
|
||||
.disable_vblank = bdw_disable_vblank,
|
||||
.get_vblank_timestamp = intel_crtc_get_vblank_timestamp,
|
||||
};
|
||||
|
||||
static const struct drm_crtc_funcs ilk_crtc_funcs = {
|
||||
|
@ -16336,6 +16337,7 @@ static const struct drm_crtc_funcs ilk_crtc_funcs = {
|
|||
.get_vblank_counter = g4x_get_vblank_counter,
|
||||
.enable_vblank = ilk_enable_vblank,
|
||||
.disable_vblank = ilk_disable_vblank,
|
||||
.get_vblank_timestamp = intel_crtc_get_vblank_timestamp,
|
||||
};
|
||||
|
||||
static const struct drm_crtc_funcs g4x_crtc_funcs = {
|
||||
|
@ -16344,6 +16346,7 @@ static const struct drm_crtc_funcs g4x_crtc_funcs = {
|
|||
.get_vblank_counter = g4x_get_vblank_counter,
|
||||
.enable_vblank = i965_enable_vblank,
|
||||
.disable_vblank = i965_disable_vblank,
|
||||
.get_vblank_timestamp = intel_crtc_get_vblank_timestamp,
|
||||
};
|
||||
|
||||
static const struct drm_crtc_funcs i965_crtc_funcs = {
|
||||
|
@ -16352,6 +16355,7 @@ static const struct drm_crtc_funcs i965_crtc_funcs = {
|
|||
.get_vblank_counter = i915_get_vblank_counter,
|
||||
.enable_vblank = i965_enable_vblank,
|
||||
.disable_vblank = i965_disable_vblank,
|
||||
.get_vblank_timestamp = intel_crtc_get_vblank_timestamp,
|
||||
};
|
||||
|
||||
static const struct drm_crtc_funcs i915gm_crtc_funcs = {
|
||||
|
@ -16360,6 +16364,7 @@ static const struct drm_crtc_funcs i915gm_crtc_funcs = {
|
|||
.get_vblank_counter = i915_get_vblank_counter,
|
||||
.enable_vblank = i915gm_enable_vblank,
|
||||
.disable_vblank = i915gm_disable_vblank,
|
||||
.get_vblank_timestamp = intel_crtc_get_vblank_timestamp,
|
||||
};
|
||||
|
||||
static const struct drm_crtc_funcs i915_crtc_funcs = {
|
||||
|
@ -16368,6 +16373,7 @@ static const struct drm_crtc_funcs i915_crtc_funcs = {
|
|||
.get_vblank_counter = i915_get_vblank_counter,
|
||||
.enable_vblank = i8xx_enable_vblank,
|
||||
.disable_vblank = i8xx_disable_vblank,
|
||||
.get_vblank_timestamp = intel_crtc_get_vblank_timestamp,
|
||||
};
|
||||
|
||||
static const struct drm_crtc_funcs i8xx_crtc_funcs = {
|
||||
|
@ -16376,6 +16382,7 @@ static const struct drm_crtc_funcs i8xx_crtc_funcs = {
|
|||
/* no hw vblank counter */
|
||||
.enable_vblank = i8xx_enable_vblank,
|
||||
.disable_vblank = i8xx_disable_vblank,
|
||||
.get_vblank_timestamp = intel_crtc_get_vblank_timestamp,
|
||||
};
|
||||
|
||||
static struct intel_crtc *intel_crtc_alloc(void)
|
||||
|
|
|
@ -2769,9 +2769,6 @@ static struct drm_driver driver = {
|
|||
.gem_prime_export = i915_gem_prime_export,
|
||||
.gem_prime_import = i915_gem_prime_import,
|
||||
|
||||
.get_vblank_timestamp = drm_calc_vbltimestamp_from_scanoutpos,
|
||||
.get_scanout_position = i915_get_crtc_scanoutpos,
|
||||
|
||||
.dumb_create = i915_gem_dumb_create,
|
||||
.dumb_map_offset = i915_gem_dumb_mmap_offset,
|
||||
|
||||
|
|
|
@ -762,13 +762,15 @@ static int __intel_get_crtc_scanline(struct intel_crtc *crtc)
|
|||
return (position + crtc->scanline_offset) % vtotal;
|
||||
}
|
||||
|
||||
bool i915_get_crtc_scanoutpos(struct drm_device *dev, unsigned int index,
|
||||
bool in_vblank_irq, int *vpos, int *hpos,
|
||||
ktime_t *stime, ktime_t *etime,
|
||||
const struct drm_display_mode *mode)
|
||||
static bool i915_get_crtc_scanoutpos(struct drm_crtc *_crtc,
|
||||
bool in_vblank_irq,
|
||||
int *vpos, int *hpos,
|
||||
ktime_t *stime, ktime_t *etime,
|
||||
const struct drm_display_mode *mode)
|
||||
{
|
||||
struct drm_device *dev = _crtc->dev;
|
||||
struct drm_i915_private *dev_priv = to_i915(dev);
|
||||
struct intel_crtc *crtc = to_intel_crtc(drm_crtc_from_index(dev, index));
|
||||
struct intel_crtc *crtc = to_intel_crtc(_crtc);
|
||||
enum pipe pipe = crtc->pipe;
|
||||
int position;
|
||||
int vbl_start, vbl_end, hsync_start, htotal, vtotal;
|
||||
|
@ -879,6 +881,14 @@ bool i915_get_crtc_scanoutpos(struct drm_device *dev, unsigned int index,
|
|||
return true;
|
||||
}
|
||||
|
||||
bool intel_crtc_get_vblank_timestamp(struct drm_crtc *crtc, int *max_error,
|
||||
ktime_t *vblank_time, bool in_vblank_irq)
|
||||
{
|
||||
return drm_crtc_vblank_helper_get_vblank_timestamp_internal(
|
||||
crtc, max_error, vblank_time, in_vblank_irq,
|
||||
i915_get_crtc_scanoutpos);
|
||||
}
|
||||
|
||||
int intel_get_crtc_scanline(struct intel_crtc *crtc)
|
||||
{
|
||||
struct drm_i915_private *dev_priv = to_i915(crtc->base.dev);
|
||||
|
|
|
@ -101,10 +101,8 @@ void gen8_irq_power_well_post_enable(struct drm_i915_private *dev_priv,
|
|||
void gen8_irq_power_well_pre_disable(struct drm_i915_private *dev_priv,
|
||||
u8 pipe_mask);
|
||||
|
||||
bool i915_get_crtc_scanoutpos(struct drm_device *dev, unsigned int pipe,
|
||||
bool in_vblank_irq, int *vpos, int *hpos,
|
||||
ktime_t *stime, ktime_t *etime,
|
||||
const struct drm_display_mode *mode);
|
||||
bool intel_crtc_get_vblank_timestamp(struct drm_crtc *crtc, int *max_error,
|
||||
ktime_t *vblank_time, bool in_vblank_irq);
|
||||
|
||||
u32 i915_get_vblank_counter(struct drm_crtc *crtc);
|
||||
u32 g4x_get_vblank_counter(struct drm_crtc *crtc);
|
||||
|
|
|
@ -231,8 +231,13 @@ static int lima_gp_task_recover(struct lima_sched_pipe *pipe)
|
|||
}
|
||||
|
||||
gp_write(LIMA_GP_INT_MASK, LIMA_GP_IRQ_MASK_USED);
|
||||
/* Resume from where we stopped, i.e. new start is old end */
|
||||
gp_write(LIMA_GP_PLBU_ALLOC_START_ADDR,
|
||||
f[LIMA_GP_PLBU_ALLOC_END_ADDR >> 2]);
|
||||
f[LIMA_GP_PLBU_ALLOC_END_ADDR >> 2] =
|
||||
f[LIMA_GP_PLBU_ALLOC_START_ADDR >> 2] + task->heap->heap_size;
|
||||
gp_write(LIMA_GP_PLBU_ALLOC_END_ADDR,
|
||||
f[LIMA_GP_PLBU_ALLOC_START_ADDR >> 2] + task->heap->heap_size);
|
||||
f[LIMA_GP_PLBU_ALLOC_END_ADDR >> 2]);
|
||||
gp_write(LIMA_GP_CMD, LIMA_GP_CMD_UPDATE_PLBU_ALLOC);
|
||||
return 0;
|
||||
}
|
||||
|
|
|
@ -20,11 +20,11 @@
|
|||
* input formats including most variants of RGB and YUV.
|
||||
*
|
||||
* The hardware has four display pipes, and the layout is a little
|
||||
* bit like this:
|
||||
* bit like this::
|
||||
*
|
||||
* Memory -> Overlay -> Channel -> FIFO -> 5 formatters -> DSI/DPI
|
||||
* External 0..5 0..3 A,B, 3 x DSI bridge
|
||||
* source 0..9 C0,C1 2 x DPI
|
||||
* Memory -> Overlay -> Channel -> FIFO -> 5 formatters -> DSI/DPI
|
||||
* External 0..5 0..3 A,B, 3 x DSI bridge
|
||||
* source 0..9 C0,C1 2 x DPI
|
||||
*
|
||||
* FIFOs A and B are for LCD and HDMI while FIFO CO/C1 are for
|
||||
* panels with embedded buffer.
|
||||
|
@ -43,6 +43,7 @@
|
|||
* to change as we exploit more of the hardware capabilities.
|
||||
*
|
||||
* TODO:
|
||||
*
|
||||
* - Enabled damaged rectangles using drm_plane_enable_fb_damage_clips()
|
||||
* so we can selectively just transmit the damaged area to a
|
||||
* command-only display.
|
||||
|
|
|
@ -1272,6 +1272,8 @@ static const struct drm_crtc_funcs dpu_crtc_funcs = {
|
|||
.atomic_destroy_state = dpu_crtc_destroy_state,
|
||||
.late_register = dpu_crtc_late_register,
|
||||
.early_unregister = dpu_crtc_early_unregister,
|
||||
.enable_vblank = msm_crtc_enable_vblank,
|
||||
.disable_vblank = msm_crtc_disable_vblank,
|
||||
};
|
||||
|
||||
static const struct drm_crtc_helper_funcs dpu_crtc_helper_funcs = {
|
||||
|
|
|
@ -512,7 +512,6 @@ static void _dpu_encoder_adjust_mode(struct drm_connector *connector,
|
|||
if (cur_mode->vdisplay == adj_mode->vdisplay &&
|
||||
cur_mode->hdisplay == adj_mode->hdisplay &&
|
||||
drm_mode_vrefresh(cur_mode) == drm_mode_vrefresh(adj_mode)) {
|
||||
adj_mode->private = cur_mode->private;
|
||||
adj_mode->private_flags |= cur_mode->private_flags;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -481,6 +481,8 @@ static const struct drm_crtc_funcs mdp4_crtc_funcs = {
|
|||
.reset = drm_atomic_helper_crtc_reset,
|
||||
.atomic_duplicate_state = drm_atomic_helper_crtc_duplicate_state,
|
||||
.atomic_destroy_state = drm_atomic_helper_crtc_destroy_state,
|
||||
.enable_vblank = msm_crtc_enable_vblank,
|
||||
.disable_vblank = msm_crtc_disable_vblank,
|
||||
};
|
||||
|
||||
static const struct drm_crtc_helper_funcs mdp4_crtc_helper_funcs = {
|
||||
|
|
|
@ -405,6 +405,83 @@ static void mdp5_crtc_mode_set_nofb(struct drm_crtc *crtc)
|
|||
spin_unlock_irqrestore(&mdp5_crtc->lm_lock, flags);
|
||||
}
|
||||
|
||||
static struct drm_encoder *get_encoder_from_crtc(struct drm_crtc *crtc)
|
||||
{
|
||||
struct drm_device *dev = crtc->dev;
|
||||
struct drm_encoder *encoder;
|
||||
|
||||
drm_for_each_encoder(encoder, dev)
|
||||
if (encoder->crtc == crtc)
|
||||
return encoder;
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static bool mdp5_crtc_get_scanout_position(struct drm_crtc *crtc,
|
||||
bool in_vblank_irq,
|
||||
int *vpos, int *hpos,
|
||||
ktime_t *stime, ktime_t *etime,
|
||||
const struct drm_display_mode *mode)
|
||||
{
|
||||
unsigned int pipe = crtc->index;
|
||||
struct drm_encoder *encoder;
|
||||
int line, vsw, vbp, vactive_start, vactive_end, vfp_end;
|
||||
|
||||
|
||||
encoder = get_encoder_from_crtc(crtc);
|
||||
if (!encoder) {
|
||||
DRM_ERROR("no encoder found for crtc %d\n", pipe);
|
||||
return false;
|
||||
}
|
||||
|
||||
vsw = mode->crtc_vsync_end - mode->crtc_vsync_start;
|
||||
vbp = mode->crtc_vtotal - mode->crtc_vsync_end;
|
||||
|
||||
/*
|
||||
* the line counter is 1 at the start of the VSYNC pulse and VTOTAL at
|
||||
* the end of VFP. Translate the porch values relative to the line
|
||||
* counter positions.
|
||||
*/
|
||||
|
||||
vactive_start = vsw + vbp + 1;
|
||||
|
||||
vactive_end = vactive_start + mode->crtc_vdisplay;
|
||||
|
||||
/* last scan line before VSYNC */
|
||||
vfp_end = mode->crtc_vtotal;
|
||||
|
||||
if (stime)
|
||||
*stime = ktime_get();
|
||||
|
||||
line = mdp5_encoder_get_linecount(encoder);
|
||||
|
||||
if (line < vactive_start)
|
||||
line -= vactive_start;
|
||||
else if (line > vactive_end)
|
||||
line = line - vfp_end - vactive_start;
|
||||
else
|
||||
line -= vactive_start;
|
||||
|
||||
*vpos = line;
|
||||
*hpos = 0;
|
||||
|
||||
if (etime)
|
||||
*etime = ktime_get();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static u32 mdp5_crtc_get_vblank_counter(struct drm_crtc *crtc)
|
||||
{
|
||||
struct drm_encoder *encoder;
|
||||
|
||||
encoder = get_encoder_from_crtc(crtc);
|
||||
if (!encoder)
|
||||
return 0;
|
||||
|
||||
return mdp5_encoder_get_framecount(encoder);
|
||||
}
|
||||
|
||||
static void mdp5_crtc_atomic_disable(struct drm_crtc *crtc,
|
||||
struct drm_crtc_state *old_state)
|
||||
{
|
||||
|
@ -1054,6 +1131,10 @@ static const struct drm_crtc_funcs mdp5_crtc_funcs = {
|
|||
.cursor_set = mdp5_crtc_cursor_set,
|
||||
.cursor_move = mdp5_crtc_cursor_move,
|
||||
.atomic_print_state = mdp5_crtc_atomic_print_state,
|
||||
.get_vblank_counter = mdp5_crtc_get_vblank_counter,
|
||||
.enable_vblank = msm_crtc_enable_vblank,
|
||||
.disable_vblank = msm_crtc_disable_vblank,
|
||||
.get_vblank_timestamp = drm_crtc_vblank_helper_get_vblank_timestamp,
|
||||
};
|
||||
|
||||
static const struct drm_crtc_helper_funcs mdp5_crtc_helper_funcs = {
|
||||
|
@ -1063,6 +1144,7 @@ static const struct drm_crtc_helper_funcs mdp5_crtc_helper_funcs = {
|
|||
.atomic_flush = mdp5_crtc_atomic_flush,
|
||||
.atomic_enable = mdp5_crtc_atomic_enable,
|
||||
.atomic_disable = mdp5_crtc_atomic_disable,
|
||||
.get_scanout_position = mdp5_crtc_get_scanout_position,
|
||||
};
|
||||
|
||||
static void mdp5_crtc_vblank_irq(struct mdp_irq *irq, uint32_t irqstatus)
|
||||
|
|
|
@ -583,98 +583,6 @@ static int get_clk(struct platform_device *pdev, struct clk **clkp,
|
|||
return 0;
|
||||
}
|
||||
|
||||
static struct drm_encoder *get_encoder_from_crtc(struct drm_crtc *crtc)
|
||||
{
|
||||
struct drm_device *dev = crtc->dev;
|
||||
struct drm_encoder *encoder;
|
||||
|
||||
drm_for_each_encoder(encoder, dev)
|
||||
if (encoder->crtc == crtc)
|
||||
return encoder;
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static bool mdp5_get_scanoutpos(struct drm_device *dev, unsigned int pipe,
|
||||
bool in_vblank_irq, int *vpos, int *hpos,
|
||||
ktime_t *stime, ktime_t *etime,
|
||||
const struct drm_display_mode *mode)
|
||||
{
|
||||
struct msm_drm_private *priv = dev->dev_private;
|
||||
struct drm_crtc *crtc;
|
||||
struct drm_encoder *encoder;
|
||||
int line, vsw, vbp, vactive_start, vactive_end, vfp_end;
|
||||
|
||||
crtc = priv->crtcs[pipe];
|
||||
if (!crtc) {
|
||||
DRM_ERROR("Invalid crtc %d\n", pipe);
|
||||
return false;
|
||||
}
|
||||
|
||||
encoder = get_encoder_from_crtc(crtc);
|
||||
if (!encoder) {
|
||||
DRM_ERROR("no encoder found for crtc %d\n", pipe);
|
||||
return false;
|
||||
}
|
||||
|
||||
vsw = mode->crtc_vsync_end - mode->crtc_vsync_start;
|
||||
vbp = mode->crtc_vtotal - mode->crtc_vsync_end;
|
||||
|
||||
/*
|
||||
* the line counter is 1 at the start of the VSYNC pulse and VTOTAL at
|
||||
* the end of VFP. Translate the porch values relative to the line
|
||||
* counter positions.
|
||||
*/
|
||||
|
||||
vactive_start = vsw + vbp + 1;
|
||||
|
||||
vactive_end = vactive_start + mode->crtc_vdisplay;
|
||||
|
||||
/* last scan line before VSYNC */
|
||||
vfp_end = mode->crtc_vtotal;
|
||||
|
||||
if (stime)
|
||||
*stime = ktime_get();
|
||||
|
||||
line = mdp5_encoder_get_linecount(encoder);
|
||||
|
||||
if (line < vactive_start) {
|
||||
line -= vactive_start;
|
||||
} else if (line > vactive_end) {
|
||||
line = line - vfp_end - vactive_start;
|
||||
} else {
|
||||
line -= vactive_start;
|
||||
}
|
||||
|
||||
*vpos = line;
|
||||
*hpos = 0;
|
||||
|
||||
if (etime)
|
||||
*etime = ktime_get();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static u32 mdp5_get_vblank_counter(struct drm_device *dev, unsigned int pipe)
|
||||
{
|
||||
struct msm_drm_private *priv = dev->dev_private;
|
||||
struct drm_crtc *crtc;
|
||||
struct drm_encoder *encoder;
|
||||
|
||||
if (pipe >= priv->num_crtcs)
|
||||
return 0;
|
||||
|
||||
crtc = priv->crtcs[pipe];
|
||||
if (!crtc)
|
||||
return 0;
|
||||
|
||||
encoder = get_encoder_from_crtc(crtc);
|
||||
if (!encoder)
|
||||
return 0;
|
||||
|
||||
return mdp5_encoder_get_framecount(encoder);
|
||||
}
|
||||
|
||||
struct msm_kms *mdp5_kms_init(struct drm_device *dev)
|
||||
{
|
||||
struct msm_drm_private *priv = dev->dev_private;
|
||||
|
@ -762,9 +670,6 @@ struct msm_kms *mdp5_kms_init(struct drm_device *dev)
|
|||
dev->mode_config.max_width = 0xffff;
|
||||
dev->mode_config.max_height = 0xffff;
|
||||
|
||||
dev->driver->get_vblank_timestamp = drm_calc_vbltimestamp_from_scanoutpos;
|
||||
dev->driver->get_scanout_position = mdp5_get_scanoutpos;
|
||||
dev->driver->get_vblank_counter = mdp5_get_vblank_counter;
|
||||
dev->max_vblank_count = 0; /* max_vblank_count is set on each CRTC */
|
||||
dev->vblank_disable_immediate = true;
|
||||
|
||||
|
|
|
@ -668,8 +668,10 @@ static void msm_irq_uninstall(struct drm_device *dev)
|
|||
kms->funcs->irq_uninstall(kms);
|
||||
}
|
||||
|
||||
static int msm_enable_vblank(struct drm_device *dev, unsigned int pipe)
|
||||
int msm_crtc_enable_vblank(struct drm_crtc *crtc)
|
||||
{
|
||||
struct drm_device *dev = crtc->dev;
|
||||
unsigned int pipe = crtc->index;
|
||||
struct msm_drm_private *priv = dev->dev_private;
|
||||
struct msm_kms *kms = priv->kms;
|
||||
if (!kms)
|
||||
|
@ -678,8 +680,10 @@ static int msm_enable_vblank(struct drm_device *dev, unsigned int pipe)
|
|||
return vblank_ctrl_queue_work(priv, pipe, true);
|
||||
}
|
||||
|
||||
static void msm_disable_vblank(struct drm_device *dev, unsigned int pipe)
|
||||
void msm_crtc_disable_vblank(struct drm_crtc *crtc)
|
||||
{
|
||||
struct drm_device *dev = crtc->dev;
|
||||
unsigned int pipe = crtc->index;
|
||||
struct msm_drm_private *priv = dev->dev_private;
|
||||
struct msm_kms *kms = priv->kms;
|
||||
if (!kms)
|
||||
|
@ -1004,8 +1008,6 @@ static struct drm_driver msm_driver = {
|
|||
.irq_preinstall = msm_irq_preinstall,
|
||||
.irq_postinstall = msm_irq_postinstall,
|
||||
.irq_uninstall = msm_irq_uninstall,
|
||||
.enable_vblank = msm_enable_vblank,
|
||||
.disable_vblank = msm_disable_vblank,
|
||||
.gem_free_object_unlocked = msm_gem_free_object,
|
||||
.gem_vm_ops = &vm_ops,
|
||||
.dumb_create = msm_gem_dumb_create,
|
||||
|
|
|
@ -232,6 +232,9 @@ struct drm_atomic_state *msm_atomic_state_alloc(struct drm_device *dev);
|
|||
void msm_atomic_state_clear(struct drm_atomic_state *state);
|
||||
void msm_atomic_state_free(struct drm_atomic_state *state);
|
||||
|
||||
int msm_crtc_enable_vblank(struct drm_crtc *crtc);
|
||||
void msm_crtc_disable_vblank(struct drm_crtc *crtc);
|
||||
|
||||
int msm_gem_init_vma(struct msm_gem_address_space *aspace,
|
||||
struct msm_gem_vma *vma, int npages);
|
||||
void msm_gem_purge_vma(struct msm_gem_address_space *aspace,
|
||||
|
|
|
@ -1248,6 +1248,9 @@ static const struct drm_crtc_funcs nv04_crtc_funcs = {
|
|||
.set_config = drm_crtc_helper_set_config,
|
||||
.page_flip = nv04_crtc_page_flip,
|
||||
.destroy = nv_crtc_destroy,
|
||||
.enable_vblank = nouveau_display_vblank_enable,
|
||||
.disable_vblank = nouveau_display_vblank_disable,
|
||||
.get_vblank_timestamp = drm_crtc_vblank_helper_get_vblank_timestamp,
|
||||
};
|
||||
|
||||
static const struct drm_crtc_helper_funcs nv04_crtc_helper_funcs = {
|
||||
|
@ -1258,6 +1261,7 @@ static const struct drm_crtc_helper_funcs nv04_crtc_helper_funcs = {
|
|||
.mode_set_base = nv04_crtc_mode_set_base,
|
||||
.mode_set_base_atomic = nv04_crtc_mode_set_base_atomic,
|
||||
.disable = nv_crtc_disable,
|
||||
.get_scanout_position = nouveau_display_scanoutpos,
|
||||
};
|
||||
|
||||
static const uint32_t modeset_formats[] = {
|
||||
|
|
|
@ -29,6 +29,7 @@
|
|||
|
||||
#include <drm/drm_atomic_helper.h>
|
||||
#include <drm/drm_crtc_helper.h>
|
||||
#include <drm/drm_vblank.h>
|
||||
#include "nouveau_connector.h"
|
||||
void
|
||||
nv50_head_flush_clr(struct nv50_head *head,
|
||||
|
@ -413,6 +414,7 @@ nv50_head_atomic_check(struct drm_crtc *crtc, struct drm_crtc_state *state)
|
|||
static const struct drm_crtc_helper_funcs
|
||||
nv50_head_help = {
|
||||
.atomic_check = nv50_head_atomic_check,
|
||||
.get_scanout_position = nouveau_display_scanoutpos,
|
||||
};
|
||||
|
||||
static void
|
||||
|
@ -481,6 +483,9 @@ nv50_head_func = {
|
|||
.page_flip = drm_atomic_helper_page_flip,
|
||||
.atomic_duplicate_state = nv50_head_atomic_duplicate_state,
|
||||
.atomic_destroy_state = nv50_head_atomic_destroy_state,
|
||||
.enable_vblank = nouveau_display_vblank_enable,
|
||||
.disable_vblank = nouveau_display_vblank_disable,
|
||||
.get_vblank_timestamp = drm_crtc_vblank_helper_get_vblank_timestamp,
|
||||
};
|
||||
|
||||
struct nv50_head *
|
||||
|
|
|
@ -54,15 +54,10 @@ nouveau_display_vblank_handler(struct nvif_notify *notify)
|
|||
}
|
||||
|
||||
int
|
||||
nouveau_display_vblank_enable(struct drm_device *dev, unsigned int pipe)
|
||||
nouveau_display_vblank_enable(struct drm_crtc *crtc)
|
||||
{
|
||||
struct drm_crtc *crtc;
|
||||
struct nouveau_crtc *nv_crtc;
|
||||
|
||||
crtc = drm_crtc_from_index(dev, pipe);
|
||||
if (!crtc)
|
||||
return -EINVAL;
|
||||
|
||||
nv_crtc = nouveau_crtc(crtc);
|
||||
nvif_notify_get(&nv_crtc->vblank);
|
||||
|
||||
|
@ -70,15 +65,10 @@ nouveau_display_vblank_enable(struct drm_device *dev, unsigned int pipe)
|
|||
}
|
||||
|
||||
void
|
||||
nouveau_display_vblank_disable(struct drm_device *dev, unsigned int pipe)
|
||||
nouveau_display_vblank_disable(struct drm_crtc *crtc)
|
||||
{
|
||||
struct drm_crtc *crtc;
|
||||
struct nouveau_crtc *nv_crtc;
|
||||
|
||||
crtc = drm_crtc_from_index(dev, pipe);
|
||||
if (!crtc)
|
||||
return;
|
||||
|
||||
nv_crtc = nouveau_crtc(crtc);
|
||||
nvif_notify_put(&nv_crtc->vblank);
|
||||
}
|
||||
|
@ -136,21 +126,13 @@ nouveau_display_scanoutpos_head(struct drm_crtc *crtc, int *vpos, int *hpos,
|
|||
}
|
||||
|
||||
bool
|
||||
nouveau_display_scanoutpos(struct drm_device *dev, unsigned int pipe,
|
||||
nouveau_display_scanoutpos(struct drm_crtc *crtc,
|
||||
bool in_vblank_irq, int *vpos, int *hpos,
|
||||
ktime_t *stime, ktime_t *etime,
|
||||
const struct drm_display_mode *mode)
|
||||
{
|
||||
struct drm_crtc *crtc;
|
||||
|
||||
list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) {
|
||||
if (nouveau_crtc(crtc)->index == pipe) {
|
||||
return nouveau_display_scanoutpos_head(crtc, vpos, hpos,
|
||||
stime, etime);
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
return nouveau_display_scanoutpos_head(crtc, vpos, hpos,
|
||||
stime, etime);
|
||||
}
|
||||
|
||||
static void
|
||||
|
|
|
@ -61,11 +61,12 @@ int nouveau_display_init(struct drm_device *dev, bool resume, bool runtime);
|
|||
void nouveau_display_fini(struct drm_device *dev, bool suspend, bool runtime);
|
||||
int nouveau_display_suspend(struct drm_device *dev, bool runtime);
|
||||
void nouveau_display_resume(struct drm_device *dev, bool runtime);
|
||||
int nouveau_display_vblank_enable(struct drm_device *, unsigned int);
|
||||
void nouveau_display_vblank_disable(struct drm_device *, unsigned int);
|
||||
bool nouveau_display_scanoutpos(struct drm_device *, unsigned int,
|
||||
bool, int *, int *, ktime_t *,
|
||||
ktime_t *, const struct drm_display_mode *);
|
||||
int nouveau_display_vblank_enable(struct drm_crtc *crtc);
|
||||
void nouveau_display_vblank_disable(struct drm_crtc *crtc);
|
||||
bool nouveau_display_scanoutpos(struct drm_crtc *crtc,
|
||||
bool in_vblank_irq, int *vpos, int *hpos,
|
||||
ktime_t *stime, ktime_t *etime,
|
||||
const struct drm_display_mode *mode);
|
||||
|
||||
int nouveau_display_dumb_create(struct drm_file *, struct drm_device *,
|
||||
struct drm_mode_create_dumb *args);
|
||||
|
|
|
@ -1120,11 +1120,6 @@ driver_stub = {
|
|||
.debugfs_init = nouveau_drm_debugfs_init,
|
||||
#endif
|
||||
|
||||
.enable_vblank = nouveau_display_vblank_enable,
|
||||
.disable_vblank = nouveau_display_vblank_disable,
|
||||
.get_scanout_position = nouveau_display_scanoutpos,
|
||||
.get_vblank_timestamp = drm_calc_vbltimestamp_from_scanoutpos,
|
||||
|
||||
.ioctls = nouveau_ioctls,
|
||||
.num_ioctls = ARRAY_SIZE(nouveau_ioctls),
|
||||
.fops = &nouveau_driver_fops,
|
||||
|
|
|
@ -678,7 +678,7 @@ static int dsicm_power_on(struct panel_drv_data *ddata)
|
|||
if (r)
|
||||
goto err;
|
||||
|
||||
ddata->enabled = 1;
|
||||
ddata->enabled = true;
|
||||
|
||||
if (!ddata->intro_printed) {
|
||||
dev_info(&ddata->pdev->dev, "panel revision %02x.%02x.%02x\n",
|
||||
|
@ -729,7 +729,7 @@ static void dsicm_power_off(struct panel_drv_data *ddata)
|
|||
if (ddata->vpnl)
|
||||
regulator_disable(ddata->vpnl);
|
||||
|
||||
ddata->enabled = 0;
|
||||
ddata->enabled = false;
|
||||
}
|
||||
|
||||
static int dsicm_panel_reset(struct panel_drv_data *ddata)
|
||||
|
|
|
@ -192,7 +192,7 @@ static int __init omapdss_boot_init(void)
|
|||
dss = of_find_matching_node(NULL, omapdss_of_match);
|
||||
|
||||
if (dss == NULL || !of_device_is_available(dss))
|
||||
return 0;
|
||||
goto put_node;
|
||||
|
||||
omapdss_walk_device(dss, true);
|
||||
|
||||
|
@ -217,6 +217,8 @@ static int __init omapdss_boot_init(void)
|
|||
kfree(n);
|
||||
}
|
||||
|
||||
put_node:
|
||||
of_node_put(dss);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
|
@ -831,7 +831,7 @@ struct drm_crtc *omap_crtc_init(struct drm_device *dev,
|
|||
* OMAP_DSS_CHANNEL_DIGIT. X server assumes 256 element gamma
|
||||
* tables so lets use that. Size of HW gamma table can be
|
||||
* extracted with dispc_mgr_gamma_size(). If it returns 0
|
||||
* gamma table is not supprted.
|
||||
* gamma table is not supported.
|
||||
*/
|
||||
if (priv->dispc_ops->mgr_gamma_size(priv->dispc, channel)) {
|
||||
unsigned int gamma_lut_size = 256;
|
||||
|
|
|
@ -82,12 +82,11 @@ static const u32 reg[][4] = {
|
|||
|
||||
static int dmm_dma_copy(struct dmm *dmm, dma_addr_t src, dma_addr_t dst)
|
||||
{
|
||||
struct dma_device *dma_dev = dmm->wa_dma_chan->device;
|
||||
struct dma_async_tx_descriptor *tx;
|
||||
enum dma_status status;
|
||||
dma_cookie_t cookie;
|
||||
|
||||
tx = dma_dev->device_prep_dma_memcpy(dmm->wa_dma_chan, dst, src, 4, 0);
|
||||
tx = dmaengine_prep_dma_memcpy(dmm->wa_dma_chan, dst, src, 4, 0);
|
||||
if (!tx) {
|
||||
dev_err(dmm->dev, "Failed to prepare DMA memcpy\n");
|
||||
return -EIO;
|
||||
|
@ -99,7 +98,6 @@ static int dmm_dma_copy(struct dmm *dmm, dma_addr_t src, dma_addr_t dst)
|
|||
return -EIO;
|
||||
}
|
||||
|
||||
dma_async_issue_pending(dmm->wa_dma_chan);
|
||||
status = dma_sync_wait(dmm->wa_dma_chan, cookie);
|
||||
if (status != DMA_COMPLETE)
|
||||
dev_err(dmm->dev, "i878 wa DMA copy failure\n");
|
||||
|
|
|
@ -2662,6 +2662,35 @@ static const struct panel_desc rocktech_rk070er9427 = {
|
|||
.bus_format = MEDIA_BUS_FMT_RGB666_1X18,
|
||||
};
|
||||
|
||||
static const struct drm_display_mode rocktech_rk101ii01d_ct_mode = {
|
||||
.clock = 71100,
|
||||
.hdisplay = 1280,
|
||||
.hsync_start = 1280 + 48,
|
||||
.hsync_end = 1280 + 48 + 32,
|
||||
.htotal = 1280 + 48 + 32 + 80,
|
||||
.vdisplay = 800,
|
||||
.vsync_start = 800 + 2,
|
||||
.vsync_end = 800 + 2 + 5,
|
||||
.vtotal = 800 + 2 + 5 + 16,
|
||||
.vrefresh = 60,
|
||||
};
|
||||
|
||||
static const struct panel_desc rocktech_rk101ii01d_ct = {
|
||||
.modes = &rocktech_rk101ii01d_ct_mode,
|
||||
.num_modes = 1,
|
||||
.size = {
|
||||
.width = 217,
|
||||
.height = 136,
|
||||
},
|
||||
.delay = {
|
||||
.prepare = 50,
|
||||
.disable = 50,
|
||||
},
|
||||
.bus_flags = DRM_BUS_FLAG_DE_HIGH,
|
||||
.bus_format = MEDIA_BUS_FMT_RGB888_1X7X4_SPWG,
|
||||
.connector_type = DRM_MODE_CONNECTOR_LVDS,
|
||||
};
|
||||
|
||||
static const struct drm_display_mode samsung_lsn122dl01_c01_mode = {
|
||||
.clock = 271560,
|
||||
.hdisplay = 2560,
|
||||
|
@ -3569,6 +3598,9 @@ static const struct of_device_id platform_of_match[] = {
|
|||
}, {
|
||||
.compatible = "rocktech,rk070er9427",
|
||||
.data = &rocktech_rk070er9427,
|
||||
}, {
|
||||
.compatible = "rocktech,rk101ii01d-ct",
|
||||
.data = &rocktech_rk101ii01d_ct,
|
||||
}, {
|
||||
.compatible = "samsung,lsn122dl01-c01",
|
||||
.data = &samsung_lsn122dl01_c01,
|
||||
|
|
|
@ -19,6 +19,7 @@ static struct regmap *versatile_syscon_map;
|
|||
* We detect the different syscon types from the compatible strings.
|
||||
*/
|
||||
enum versatile_clcd {
|
||||
INTEGRATOR_IMPD1,
|
||||
INTEGRATOR_CLCD_CM,
|
||||
VERSATILE_CLCD,
|
||||
REALVIEW_CLCD_EB,
|
||||
|
@ -65,6 +66,14 @@ static const struct of_device_id versatile_clcd_of_match[] = {
|
|||
{},
|
||||
};
|
||||
|
||||
static const struct of_device_id impd1_clcd_of_match[] = {
|
||||
{
|
||||
.compatible = "arm,im-pd1-syscon",
|
||||
.data = (void *)INTEGRATOR_IMPD1,
|
||||
},
|
||||
{},
|
||||
};
|
||||
|
||||
/*
|
||||
* Core module CLCD control on the Integrator/CP, bits
|
||||
* 8 thru 19 of the CM_CONTROL register controls a bunch
|
||||
|
@ -125,6 +134,36 @@ static void pl111_integrator_enable(struct drm_device *drm, u32 format)
|
|||
val);
|
||||
}
|
||||
|
||||
#define IMPD1_CTRL_OFFSET 0x18
|
||||
#define IMPD1_CTRL_DISP_LCD (0 << 0)
|
||||
#define IMPD1_CTRL_DISP_VGA (1 << 0)
|
||||
#define IMPD1_CTRL_DISP_LCD1 (2 << 0)
|
||||
#define IMPD1_CTRL_DISP_ENABLE (1 << 2)
|
||||
#define IMPD1_CTRL_DISP_MASK (7 << 0)
|
||||
|
||||
static void pl111_impd1_enable(struct drm_device *drm, u32 format)
|
||||
{
|
||||
u32 val;
|
||||
|
||||
dev_info(drm->dev, "enable IM-PD1 CLCD connectors\n");
|
||||
val = IMPD1_CTRL_DISP_VGA | IMPD1_CTRL_DISP_ENABLE;
|
||||
|
||||
regmap_update_bits(versatile_syscon_map,
|
||||
IMPD1_CTRL_OFFSET,
|
||||
IMPD1_CTRL_DISP_MASK,
|
||||
val);
|
||||
}
|
||||
|
||||
static void pl111_impd1_disable(struct drm_device *drm)
|
||||
{
|
||||
dev_info(drm->dev, "disable IM-PD1 CLCD connectors\n");
|
||||
|
||||
regmap_update_bits(versatile_syscon_map,
|
||||
IMPD1_CTRL_OFFSET,
|
||||
IMPD1_CTRL_DISP_MASK,
|
||||
0);
|
||||
}
|
||||
|
||||
/*
|
||||
* This configuration register in the Versatile and RealView
|
||||
* family is uniformly present but appears more and more
|
||||
|
@ -270,6 +309,20 @@ static const struct pl111_variant_data pl110_integrator = {
|
|||
.fb_bpp = 16,
|
||||
};
|
||||
|
||||
/*
|
||||
* The IM-PD1 variant is a PL110 with a bunch of broken, or not
|
||||
* yet implemented features
|
||||
*/
|
||||
static const struct pl111_variant_data pl110_impd1 = {
|
||||
.name = "PL110 IM-PD1",
|
||||
.is_pl110 = true,
|
||||
.broken_clockdivider = true,
|
||||
.broken_vblank = true,
|
||||
.formats = pl110_integrator_pixel_formats,
|
||||
.nformats = ARRAY_SIZE(pl110_integrator_pixel_formats),
|
||||
.fb_bpp = 16,
|
||||
};
|
||||
|
||||
/*
|
||||
* This is the in-between PL110 variant found in the ARM Versatile,
|
||||
* supporting RGB565/BGR565
|
||||
|
@ -322,8 +375,21 @@ int pl111_versatile_init(struct device *dev, struct pl111_drm_dev_private *priv)
|
|||
/* Non-ARM reference designs, just bail out */
|
||||
return 0;
|
||||
}
|
||||
|
||||
versatile_clcd_type = (enum versatile_clcd)clcd_id->data;
|
||||
|
||||
/*
|
||||
* On the Integrator, check if we should use the IM-PD1 instead,
|
||||
* if we find it, it will take precedence. This is on the Integrator/AP
|
||||
* which only has this option for PL110 graphics.
|
||||
*/
|
||||
if (versatile_clcd_type == INTEGRATOR_CLCD_CM) {
|
||||
np = of_find_matching_node_and_match(NULL, impd1_clcd_of_match,
|
||||
&clcd_id);
|
||||
if (np)
|
||||
versatile_clcd_type = (enum versatile_clcd)clcd_id->data;
|
||||
}
|
||||
|
||||
/* Versatile Express special handling */
|
||||
if (versatile_clcd_type == VEXPRESS_CLCD_V2M) {
|
||||
struct platform_device *pdev;
|
||||
|
@ -367,6 +433,13 @@ int pl111_versatile_init(struct device *dev, struct pl111_drm_dev_private *priv)
|
|||
priv->variant_display_enable = pl111_integrator_enable;
|
||||
dev_info(dev, "set up callbacks for Integrator PL110\n");
|
||||
break;
|
||||
case INTEGRATOR_IMPD1:
|
||||
versatile_syscon_map = map;
|
||||
priv->variant = &pl110_impd1;
|
||||
priv->variant_display_enable = pl111_impd1_enable;
|
||||
priv->variant_display_disable = pl111_impd1_disable;
|
||||
dev_info(dev, "set up callbacks for IM-PD1 PL110\n");
|
||||
break;
|
||||
case VERSATILE_CLCD:
|
||||
versatile_syscon_map = map;
|
||||
/* This can do RGB565 with external PLD */
|
||||
|
|
|
@ -36,7 +36,7 @@ static int qxl_reap_surface_id(struct qxl_device *qdev, int max_to_reap);
|
|||
|
||||
struct ring {
|
||||
struct qxl_ring_header header;
|
||||
uint8_t elements[0];
|
||||
uint8_t elements[];
|
||||
};
|
||||
|
||||
struct qxl_ring {
|
||||
|
|
|
@ -34,6 +34,7 @@
|
|||
#include <linux/pci.h>
|
||||
|
||||
#include <drm/drm.h>
|
||||
#include <drm/drm_atomic_helper.h>
|
||||
#include <drm/drm_drv.h>
|
||||
#include <drm/drm_file.h>
|
||||
#include <drm/drm_modeset_helper.h>
|
||||
|
@ -132,21 +133,30 @@ free_dev:
|
|||
return ret;
|
||||
}
|
||||
|
||||
static void qxl_drm_release(struct drm_device *dev)
|
||||
{
|
||||
struct qxl_device *qdev = dev->dev_private;
|
||||
|
||||
/*
|
||||
* TODO: qxl_device_fini() call should be in qxl_pci_remove(),
|
||||
* reodering qxl_modeset_fini() + qxl_device_fini() calls is
|
||||
* non-trivial though.
|
||||
*/
|
||||
qxl_modeset_fini(qdev);
|
||||
qxl_device_fini(qdev);
|
||||
dev->dev_private = NULL;
|
||||
kfree(qdev);
|
||||
}
|
||||
|
||||
static void
|
||||
qxl_pci_remove(struct pci_dev *pdev)
|
||||
{
|
||||
struct drm_device *dev = pci_get_drvdata(pdev);
|
||||
struct qxl_device *qdev = dev->dev_private;
|
||||
|
||||
drm_dev_unregister(dev);
|
||||
|
||||
qxl_modeset_fini(qdev);
|
||||
qxl_device_fini(qdev);
|
||||
drm_atomic_helper_shutdown(dev);
|
||||
if (is_vga(pdev))
|
||||
vga_put(pdev, VGA_RSRC_LEGACY_IO);
|
||||
|
||||
dev->dev_private = NULL;
|
||||
kfree(qdev);
|
||||
drm_dev_put(dev);
|
||||
}
|
||||
|
||||
|
@ -279,6 +289,8 @@ static struct drm_driver qxl_driver = {
|
|||
.major = 0,
|
||||
.minor = 1,
|
||||
.patchlevel = 0,
|
||||
|
||||
.release = qxl_drm_release,
|
||||
};
|
||||
|
||||
static int __init qxl_init(void)
|
||||
|
|
|
@ -299,12 +299,12 @@ void qxl_device_fini(struct qxl_device *qdev)
|
|||
{
|
||||
qxl_bo_unref(&qdev->current_release_bo[0]);
|
||||
qxl_bo_unref(&qdev->current_release_bo[1]);
|
||||
qxl_gem_fini(qdev);
|
||||
qxl_bo_fini(qdev);
|
||||
flush_work(&qdev->gc_work);
|
||||
qxl_ring_free(qdev->command_ring);
|
||||
qxl_ring_free(qdev->cursor_ring);
|
||||
qxl_ring_free(qdev->release_ring);
|
||||
qxl_gem_fini(qdev);
|
||||
qxl_bo_fini(qdev);
|
||||
io_mapping_free(qdev->surface_mapping);
|
||||
io_mapping_free(qdev->vram_mapping);
|
||||
iounmap(qdev->ram_header);
|
||||
|
|
|
@ -2231,6 +2231,7 @@ static const struct drm_crtc_helper_funcs atombios_helper_funcs = {
|
|||
.prepare = atombios_crtc_prepare,
|
||||
.commit = atombios_crtc_commit,
|
||||
.disable = atombios_crtc_disable,
|
||||
.get_scanout_position = radeon_get_crtc_scanout_position,
|
||||
};
|
||||
|
||||
void radeon_atombios_init_crtc(struct drm_device *dev,
|
||||
|
|
|
@ -45,6 +45,10 @@
|
|||
#include "atom.h"
|
||||
#include "radeon.h"
|
||||
|
||||
u32 radeon_get_vblank_counter_kms(struct drm_crtc *crtc);
|
||||
int radeon_enable_vblank_kms(struct drm_crtc *crtc);
|
||||
void radeon_disable_vblank_kms(struct drm_crtc *crtc);
|
||||
|
||||
static void avivo_crtc_load_lut(struct drm_crtc *crtc)
|
||||
{
|
||||
struct radeon_crtc *radeon_crtc = to_radeon_crtc(crtc);
|
||||
|
@ -460,7 +464,7 @@ static void radeon_flip_work_func(struct work_struct *__work)
|
|||
(DRM_SCANOUTPOS_VALID | DRM_SCANOUTPOS_IN_VBLANK) &&
|
||||
(!ASIC_IS_AVIVO(rdev) ||
|
||||
((int) (work->target_vblank -
|
||||
dev->driver->get_vblank_counter(dev, work->crtc_id)) > 0)))
|
||||
crtc->funcs->get_vblank_counter(crtc)) > 0)))
|
||||
usleep_range(1000, 2000);
|
||||
|
||||
/* We borrow the event spin lock for protecting flip_status */
|
||||
|
@ -576,7 +580,7 @@ static int radeon_crtc_page_flip_target(struct drm_crtc *crtc,
|
|||
}
|
||||
work->base = base;
|
||||
work->target_vblank = target - (uint32_t)drm_crtc_vblank_count(crtc) +
|
||||
dev->driver->get_vblank_counter(dev, work->crtc_id);
|
||||
crtc->funcs->get_vblank_counter(crtc);
|
||||
|
||||
/* We borrow the event spin lock for protecting flip_work */
|
||||
spin_lock_irqsave(&crtc->dev->event_lock, flags);
|
||||
|
@ -668,6 +672,10 @@ static const struct drm_crtc_funcs radeon_crtc_funcs = {
|
|||
.set_config = radeon_crtc_set_config,
|
||||
.destroy = radeon_crtc_destroy,
|
||||
.page_flip_target = radeon_crtc_page_flip_target,
|
||||
.get_vblank_counter = radeon_get_vblank_counter_kms,
|
||||
.enable_vblank = radeon_enable_vblank_kms,
|
||||
.disable_vblank = radeon_disable_vblank_kms,
|
||||
.get_vblank_timestamp = drm_crtc_vblank_helper_get_vblank_timestamp,
|
||||
};
|
||||
|
||||
static void radeon_crtc_init(struct drm_device *dev, int index)
|
||||
|
@ -1973,3 +1981,16 @@ int radeon_get_crtc_scanoutpos(struct drm_device *dev, unsigned int pipe,
|
|||
|
||||
return ret;
|
||||
}
|
||||
|
||||
bool
|
||||
radeon_get_crtc_scanout_position(struct drm_crtc *crtc,
|
||||
bool in_vblank_irq, int *vpos, int *hpos,
|
||||
ktime_t *stime, ktime_t *etime,
|
||||
const struct drm_display_mode *mode)
|
||||
{
|
||||
struct drm_device *dev = crtc->dev;
|
||||
unsigned int pipe = crtc->index;
|
||||
|
||||
return radeon_get_crtc_scanoutpos(dev, pipe, 0, vpos, hpos,
|
||||
stime, etime, mode);
|
||||
}
|
||||
|
|
|
@ -119,9 +119,6 @@ void radeon_driver_postclose_kms(struct drm_device *dev,
|
|||
int radeon_suspend_kms(struct drm_device *dev, bool suspend,
|
||||
bool fbcon, bool freeze);
|
||||
int radeon_resume_kms(struct drm_device *dev, bool resume, bool fbcon);
|
||||
u32 radeon_get_vblank_counter_kms(struct drm_device *dev, unsigned int pipe);
|
||||
int radeon_enable_vblank_kms(struct drm_device *dev, unsigned int pipe);
|
||||
void radeon_disable_vblank_kms(struct drm_device *dev, unsigned int pipe);
|
||||
void radeon_driver_irq_preinstall_kms(struct drm_device *dev);
|
||||
int radeon_driver_irq_postinstall_kms(struct drm_device *dev);
|
||||
void radeon_driver_irq_uninstall_kms(struct drm_device *dev);
|
||||
|
@ -563,16 +560,6 @@ static const struct file_operations radeon_driver_kms_fops = {
|
|||
#endif
|
||||
};
|
||||
|
||||
static bool
|
||||
radeon_get_crtc_scanout_position(struct drm_device *dev, unsigned int pipe,
|
||||
bool in_vblank_irq, int *vpos, int *hpos,
|
||||
ktime_t *stime, ktime_t *etime,
|
||||
const struct drm_display_mode *mode)
|
||||
{
|
||||
return radeon_get_crtc_scanoutpos(dev, pipe, 0, vpos, hpos,
|
||||
stime, etime, mode);
|
||||
}
|
||||
|
||||
static struct drm_driver kms_driver = {
|
||||
.driver_features =
|
||||
DRIVER_USE_AGP | DRIVER_GEM | DRIVER_RENDER,
|
||||
|
@ -581,11 +568,6 @@ static struct drm_driver kms_driver = {
|
|||
.postclose = radeon_driver_postclose_kms,
|
||||
.lastclose = radeon_driver_lastclose_kms,
|
||||
.unload = radeon_driver_unload_kms,
|
||||
.get_vblank_counter = radeon_get_vblank_counter_kms,
|
||||
.enable_vblank = radeon_enable_vblank_kms,
|
||||
.disable_vblank = radeon_disable_vblank_kms,
|
||||
.get_vblank_timestamp = drm_calc_vbltimestamp_from_scanoutpos,
|
||||
.get_scanout_position = radeon_get_crtc_scanout_position,
|
||||
.irq_preinstall = radeon_driver_irq_preinstall_kms,
|
||||
.irq_postinstall = radeon_driver_irq_postinstall_kms,
|
||||
.irq_uninstall = radeon_driver_irq_uninstall_kms,
|
||||
|
|
|
@ -739,14 +739,15 @@ void radeon_driver_postclose_kms(struct drm_device *dev,
|
|||
/**
|
||||
* radeon_get_vblank_counter_kms - get frame count
|
||||
*
|
||||
* @dev: drm dev pointer
|
||||
* @pipe: crtc to get the frame count from
|
||||
* @crtc: crtc to get the frame count from
|
||||
*
|
||||
* Gets the frame count on the requested crtc (all asics).
|
||||
* Returns frame count on success, -EINVAL on failure.
|
||||
*/
|
||||
u32 radeon_get_vblank_counter_kms(struct drm_device *dev, unsigned int pipe)
|
||||
u32 radeon_get_vblank_counter_kms(struct drm_crtc *crtc)
|
||||
{
|
||||
struct drm_device *dev = crtc->dev;
|
||||
unsigned int pipe = crtc->index;
|
||||
int vpos, hpos, stat;
|
||||
u32 count;
|
||||
struct radeon_device *rdev = dev->dev_private;
|
||||
|
@ -808,25 +809,26 @@ u32 radeon_get_vblank_counter_kms(struct drm_device *dev, unsigned int pipe)
|
|||
/**
|
||||
* radeon_enable_vblank_kms - enable vblank interrupt
|
||||
*
|
||||
* @dev: drm dev pointer
|
||||
* @crtc: crtc to enable vblank interrupt for
|
||||
*
|
||||
* Enable the interrupt on the requested crtc (all asics).
|
||||
* Returns 0 on success, -EINVAL on failure.
|
||||
*/
|
||||
int radeon_enable_vblank_kms(struct drm_device *dev, int crtc)
|
||||
int radeon_enable_vblank_kms(struct drm_crtc *crtc)
|
||||
{
|
||||
struct drm_device *dev = crtc->dev;
|
||||
unsigned int pipe = crtc->index;
|
||||
struct radeon_device *rdev = dev->dev_private;
|
||||
unsigned long irqflags;
|
||||
int r;
|
||||
|
||||
if (crtc < 0 || crtc >= rdev->num_crtc) {
|
||||
DRM_ERROR("Invalid crtc %d\n", crtc);
|
||||
if (pipe < 0 || pipe >= rdev->num_crtc) {
|
||||
DRM_ERROR("Invalid crtc %d\n", pipe);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
spin_lock_irqsave(&rdev->irq.lock, irqflags);
|
||||
rdev->irq.crtc_vblank_int[crtc] = true;
|
||||
rdev->irq.crtc_vblank_int[pipe] = true;
|
||||
r = radeon_irq_set(rdev);
|
||||
spin_unlock_irqrestore(&rdev->irq.lock, irqflags);
|
||||
return r;
|
||||
|
@ -835,23 +837,24 @@ int radeon_enable_vblank_kms(struct drm_device *dev, int crtc)
|
|||
/**
|
||||
* radeon_disable_vblank_kms - disable vblank interrupt
|
||||
*
|
||||
* @dev: drm dev pointer
|
||||
* @crtc: crtc to disable vblank interrupt for
|
||||
*
|
||||
* Disable the interrupt on the requested crtc (all asics).
|
||||
*/
|
||||
void radeon_disable_vblank_kms(struct drm_device *dev, int crtc)
|
||||
void radeon_disable_vblank_kms(struct drm_crtc *crtc)
|
||||
{
|
||||
struct drm_device *dev = crtc->dev;
|
||||
unsigned int pipe = crtc->index;
|
||||
struct radeon_device *rdev = dev->dev_private;
|
||||
unsigned long irqflags;
|
||||
|
||||
if (crtc < 0 || crtc >= rdev->num_crtc) {
|
||||
DRM_ERROR("Invalid crtc %d\n", crtc);
|
||||
if (pipe < 0 || pipe >= rdev->num_crtc) {
|
||||
DRM_ERROR("Invalid crtc %d\n", pipe);
|
||||
return;
|
||||
}
|
||||
|
||||
spin_lock_irqsave(&rdev->irq.lock, irqflags);
|
||||
rdev->irq.crtc_vblank_int[crtc] = false;
|
||||
rdev->irq.crtc_vblank_int[pipe] = false;
|
||||
radeon_irq_set(rdev);
|
||||
spin_unlock_irqrestore(&rdev->irq.lock, irqflags);
|
||||
}
|
||||
|
|
|
@ -1111,7 +1111,8 @@ static const struct drm_crtc_helper_funcs legacy_helper_funcs = {
|
|||
.mode_set_base_atomic = radeon_crtc_set_base_atomic,
|
||||
.prepare = radeon_crtc_prepare,
|
||||
.commit = radeon_crtc_commit,
|
||||
.disable = radeon_crtc_disable
|
||||
.disable = radeon_crtc_disable,
|
||||
.get_scanout_position = radeon_get_crtc_scanout_position,
|
||||
};
|
||||
|
||||
|
||||
|
|
|
@ -880,6 +880,12 @@ extern int radeon_get_crtc_scanoutpos(struct drm_device *dev, unsigned int pipe,
|
|||
ktime_t *stime, ktime_t *etime,
|
||||
const struct drm_display_mode *mode);
|
||||
|
||||
extern bool
|
||||
radeon_get_crtc_scanout_position(struct drm_crtc *crtc, bool in_vblank_irq,
|
||||
int *vpos, int *hpos,
|
||||
ktime_t *stime, ktime_t *etime,
|
||||
const struct drm_display_mode *mode);
|
||||
|
||||
extern bool radeon_combios_check_hardcoded_edid(struct radeon_device *rdev);
|
||||
extern struct edid *
|
||||
radeon_bios_get_hardcoded_edid(struct radeon_device *rdev);
|
||||
|
|
|
@ -279,12 +279,13 @@ int sti_crtc_vblank_cb(struct notifier_block *nb,
|
|||
return 0;
|
||||
}
|
||||
|
||||
int sti_crtc_enable_vblank(struct drm_device *dev, unsigned int pipe)
|
||||
static int sti_crtc_enable_vblank(struct drm_crtc *crtc)
|
||||
{
|
||||
struct drm_device *dev = crtc->dev;
|
||||
unsigned int pipe = crtc->index;
|
||||
struct sti_private *dev_priv = dev->dev_private;
|
||||
struct sti_compositor *compo = dev_priv->compo;
|
||||
struct notifier_block *vtg_vblank_nb = &compo->vtg_vblank_nb[pipe];
|
||||
struct drm_crtc *crtc = &compo->mixer[pipe]->drm_crtc;
|
||||
struct sti_vtg *vtg = compo->vtg[pipe];
|
||||
|
||||
DRM_DEBUG_DRIVER("\n");
|
||||
|
@ -297,8 +298,10 @@ int sti_crtc_enable_vblank(struct drm_device *dev, unsigned int pipe)
|
|||
return 0;
|
||||
}
|
||||
|
||||
void sti_crtc_disable_vblank(struct drm_device *drm_dev, unsigned int pipe)
|
||||
static void sti_crtc_disable_vblank(struct drm_crtc *crtc)
|
||||
{
|
||||
struct drm_device *drm_dev = crtc->dev;
|
||||
unsigned int pipe = crtc->index;
|
||||
struct sti_private *priv = drm_dev->dev_private;
|
||||
struct sti_compositor *compo = priv->compo;
|
||||
struct notifier_block *vtg_vblank_nb = &compo->vtg_vblank_nb[pipe];
|
||||
|
@ -330,6 +333,8 @@ static const struct drm_crtc_funcs sti_crtc_funcs = {
|
|||
.atomic_duplicate_state = drm_atomic_helper_crtc_duplicate_state,
|
||||
.atomic_destroy_state = drm_atomic_helper_crtc_destroy_state,
|
||||
.late_register = sti_crtc_late_register,
|
||||
.enable_vblank = sti_crtc_enable_vblank,
|
||||
.disable_vblank = sti_crtc_disable_vblank,
|
||||
};
|
||||
|
||||
bool sti_crtc_is_main(struct drm_crtc *crtc)
|
||||
|
|
|
@ -15,8 +15,6 @@ struct sti_mixer;
|
|||
|
||||
int sti_crtc_init(struct drm_device *drm_dev, struct sti_mixer *mixer,
|
||||
struct drm_plane *primary, struct drm_plane *cursor);
|
||||
int sti_crtc_enable_vblank(struct drm_device *dev, unsigned int pipe);
|
||||
void sti_crtc_disable_vblank(struct drm_device *dev, unsigned int pipe);
|
||||
int sti_crtc_vblank_cb(struct notifier_block *nb,
|
||||
unsigned long event, void *data);
|
||||
bool sti_crtc_is_main(struct drm_crtc *drm_crtc);
|
||||
|
|
|
@ -21,7 +21,6 @@
|
|||
#include <drm/drm_of.h>
|
||||
#include <drm/drm_probe_helper.h>
|
||||
|
||||
#include "sti_crtc.h"
|
||||
#include "sti_drv.h"
|
||||
#include "sti_plane.h"
|
||||
|
||||
|
@ -146,9 +145,6 @@ static struct drm_driver sti_driver = {
|
|||
.dumb_create = drm_gem_cma_dumb_create,
|
||||
.fops = &sti_driver_fops,
|
||||
|
||||
.enable_vblank = sti_crtc_enable_vblank,
|
||||
.disable_vblank = sti_crtc_disable_vblank,
|
||||
|
||||
.prime_handle_to_fd = drm_gem_prime_handle_to_fd,
|
||||
.prime_fd_to_handle = drm_gem_prime_fd_to_handle,
|
||||
.gem_prime_get_sg_table = drm_gem_cma_prime_get_sg_table,
|
||||
|
|
|
@ -72,8 +72,6 @@ static struct drm_driver drv_driver = {
|
|||
.gem_prime_vmap = drm_gem_cma_prime_vmap,
|
||||
.gem_prime_vunmap = drm_gem_cma_prime_vunmap,
|
||||
.gem_prime_mmap = drm_gem_cma_prime_mmap,
|
||||
.get_scanout_position = ltdc_crtc_scanoutpos,
|
||||
.get_vblank_timestamp = drm_calc_vbltimestamp_from_scanoutpos,
|
||||
};
|
||||
|
||||
static int drv_load(struct drm_device *ddev)
|
||||
|
|
|
@ -636,43 +636,13 @@ static void ltdc_crtc_atomic_flush(struct drm_crtc *crtc,
|
|||
}
|
||||
}
|
||||
|
||||
static const struct drm_crtc_helper_funcs ltdc_crtc_helper_funcs = {
|
||||
.mode_valid = ltdc_crtc_mode_valid,
|
||||
.mode_fixup = ltdc_crtc_mode_fixup,
|
||||
.mode_set_nofb = ltdc_crtc_mode_set_nofb,
|
||||
.atomic_flush = ltdc_crtc_atomic_flush,
|
||||
.atomic_enable = ltdc_crtc_atomic_enable,
|
||||
.atomic_disable = ltdc_crtc_atomic_disable,
|
||||
};
|
||||
|
||||
static int ltdc_crtc_enable_vblank(struct drm_crtc *crtc)
|
||||
{
|
||||
struct ltdc_device *ldev = crtc_to_ltdc(crtc);
|
||||
struct drm_crtc_state *state = crtc->state;
|
||||
|
||||
DRM_DEBUG_DRIVER("\n");
|
||||
|
||||
if (state->enable)
|
||||
reg_set(ldev->regs, LTDC_IER, IER_LIE);
|
||||
else
|
||||
return -EPERM;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void ltdc_crtc_disable_vblank(struct drm_crtc *crtc)
|
||||
{
|
||||
struct ltdc_device *ldev = crtc_to_ltdc(crtc);
|
||||
|
||||
DRM_DEBUG_DRIVER("\n");
|
||||
reg_clear(ldev->regs, LTDC_IER, IER_LIE);
|
||||
}
|
||||
|
||||
bool ltdc_crtc_scanoutpos(struct drm_device *ddev, unsigned int pipe,
|
||||
bool in_vblank_irq, int *vpos, int *hpos,
|
||||
ktime_t *stime, ktime_t *etime,
|
||||
const struct drm_display_mode *mode)
|
||||
static bool ltdc_crtc_get_scanout_position(struct drm_crtc *crtc,
|
||||
bool in_vblank_irq,
|
||||
int *vpos, int *hpos,
|
||||
ktime_t *stime, ktime_t *etime,
|
||||
const struct drm_display_mode *mode)
|
||||
{
|
||||
struct drm_device *ddev = crtc->dev;
|
||||
struct ltdc_device *ldev = ddev->dev_private;
|
||||
int line, vactive_start, vactive_end, vtotal;
|
||||
|
||||
|
@ -715,6 +685,39 @@ bool ltdc_crtc_scanoutpos(struct drm_device *ddev, unsigned int pipe,
|
|||
return true;
|
||||
}
|
||||
|
||||
static const struct drm_crtc_helper_funcs ltdc_crtc_helper_funcs = {
|
||||
.mode_valid = ltdc_crtc_mode_valid,
|
||||
.mode_fixup = ltdc_crtc_mode_fixup,
|
||||
.mode_set_nofb = ltdc_crtc_mode_set_nofb,
|
||||
.atomic_flush = ltdc_crtc_atomic_flush,
|
||||
.atomic_enable = ltdc_crtc_atomic_enable,
|
||||
.atomic_disable = ltdc_crtc_atomic_disable,
|
||||
.get_scanout_position = ltdc_crtc_get_scanout_position,
|
||||
};
|
||||
|
||||
static int ltdc_crtc_enable_vblank(struct drm_crtc *crtc)
|
||||
{
|
||||
struct ltdc_device *ldev = crtc_to_ltdc(crtc);
|
||||
struct drm_crtc_state *state = crtc->state;
|
||||
|
||||
DRM_DEBUG_DRIVER("\n");
|
||||
|
||||
if (state->enable)
|
||||
reg_set(ldev->regs, LTDC_IER, IER_LIE);
|
||||
else
|
||||
return -EPERM;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void ltdc_crtc_disable_vblank(struct drm_crtc *crtc)
|
||||
{
|
||||
struct ltdc_device *ldev = crtc_to_ltdc(crtc);
|
||||
|
||||
DRM_DEBUG_DRIVER("\n");
|
||||
reg_clear(ldev->regs, LTDC_IER, IER_LIE);
|
||||
}
|
||||
|
||||
static const struct drm_crtc_funcs ltdc_crtc_funcs = {
|
||||
.destroy = drm_crtc_cleanup,
|
||||
.set_config = drm_atomic_helper_set_config,
|
||||
|
@ -724,6 +727,7 @@ static const struct drm_crtc_funcs ltdc_crtc_funcs = {
|
|||
.atomic_destroy_state = drm_atomic_helper_crtc_destroy_state,
|
||||
.enable_vblank = ltdc_crtc_enable_vblank,
|
||||
.disable_vblank = ltdc_crtc_disable_vblank,
|
||||
.get_vblank_timestamp = drm_crtc_vblank_helper_get_vblank_timestamp,
|
||||
.gamma_set = drm_atomic_helper_legacy_gamma_set,
|
||||
};
|
||||
|
||||
|
|
|
@ -40,11 +40,6 @@ struct ltdc_device {
|
|||
struct drm_atomic_state *suspend_state;
|
||||
};
|
||||
|
||||
bool ltdc_crtc_scanoutpos(struct drm_device *dev, unsigned int pipe,
|
||||
bool in_vblank_irq, int *vpos, int *hpos,
|
||||
ktime_t *stime, ktime_t *etime,
|
||||
const struct drm_display_mode *mode);
|
||||
|
||||
int ltdc_load(struct drm_device *ddev);
|
||||
void ltdc_unload(struct drm_device *ddev);
|
||||
void ltdc_suspend(struct drm_device *ddev);
|
||||
|
|
|
@ -114,46 +114,71 @@ static void sun4i_tcon_channel_set_status(struct sun4i_tcon *tcon, int channel,
|
|||
}
|
||||
}
|
||||
|
||||
static void sun4i_tcon_setup_lvds_phy(struct sun4i_tcon *tcon,
|
||||
const struct drm_encoder *encoder)
|
||||
{
|
||||
regmap_write(tcon->regs, SUN4I_TCON0_LVDS_ANA0_REG,
|
||||
SUN4I_TCON0_LVDS_ANA0_CK_EN |
|
||||
SUN4I_TCON0_LVDS_ANA0_REG_V |
|
||||
SUN4I_TCON0_LVDS_ANA0_REG_C |
|
||||
SUN4I_TCON0_LVDS_ANA0_EN_MB |
|
||||
SUN4I_TCON0_LVDS_ANA0_PD |
|
||||
SUN4I_TCON0_LVDS_ANA0_DCHS);
|
||||
|
||||
udelay(2); /* delay at least 1200 ns */
|
||||
regmap_update_bits(tcon->regs, SUN4I_TCON0_LVDS_ANA1_REG,
|
||||
SUN4I_TCON0_LVDS_ANA1_INIT,
|
||||
SUN4I_TCON0_LVDS_ANA1_INIT);
|
||||
udelay(1); /* delay at least 120 ns */
|
||||
regmap_update_bits(tcon->regs, SUN4I_TCON0_LVDS_ANA1_REG,
|
||||
SUN4I_TCON0_LVDS_ANA1_UPDATE,
|
||||
SUN4I_TCON0_LVDS_ANA1_UPDATE);
|
||||
regmap_update_bits(tcon->regs, SUN4I_TCON0_LVDS_ANA0_REG,
|
||||
SUN4I_TCON0_LVDS_ANA0_EN_MB,
|
||||
SUN4I_TCON0_LVDS_ANA0_EN_MB);
|
||||
}
|
||||
|
||||
static void sun6i_tcon_setup_lvds_phy(struct sun4i_tcon *tcon,
|
||||
const struct drm_encoder *encoder)
|
||||
{
|
||||
u8 val;
|
||||
|
||||
regmap_write(tcon->regs, SUN4I_TCON0_LVDS_ANA0_REG,
|
||||
SUN6I_TCON0_LVDS_ANA0_C(2) |
|
||||
SUN6I_TCON0_LVDS_ANA0_V(3) |
|
||||
SUN6I_TCON0_LVDS_ANA0_PD(2) |
|
||||
SUN6I_TCON0_LVDS_ANA0_EN_LDO);
|
||||
udelay(2);
|
||||
|
||||
regmap_update_bits(tcon->regs, SUN4I_TCON0_LVDS_ANA0_REG,
|
||||
SUN6I_TCON0_LVDS_ANA0_EN_MB,
|
||||
SUN6I_TCON0_LVDS_ANA0_EN_MB);
|
||||
udelay(2);
|
||||
|
||||
regmap_update_bits(tcon->regs, SUN4I_TCON0_LVDS_ANA0_REG,
|
||||
SUN6I_TCON0_LVDS_ANA0_EN_DRVC,
|
||||
SUN6I_TCON0_LVDS_ANA0_EN_DRVC);
|
||||
|
||||
if (sun4i_tcon_get_pixel_depth(encoder) == 18)
|
||||
val = 7;
|
||||
else
|
||||
val = 0xf;
|
||||
|
||||
regmap_write_bits(tcon->regs, SUN4I_TCON0_LVDS_ANA0_REG,
|
||||
SUN6I_TCON0_LVDS_ANA0_EN_DRVD(0xf),
|
||||
SUN6I_TCON0_LVDS_ANA0_EN_DRVD(val));
|
||||
}
|
||||
|
||||
static void sun4i_tcon_lvds_set_status(struct sun4i_tcon *tcon,
|
||||
const struct drm_encoder *encoder,
|
||||
bool enabled)
|
||||
{
|
||||
if (enabled) {
|
||||
u8 val;
|
||||
|
||||
regmap_update_bits(tcon->regs, SUN4I_TCON0_LVDS_IF_REG,
|
||||
SUN4I_TCON0_LVDS_IF_EN,
|
||||
SUN4I_TCON0_LVDS_IF_EN);
|
||||
|
||||
/*
|
||||
* As their name suggest, these values only apply to the A31
|
||||
* and later SoCs. We'll have to rework this when merging
|
||||
* support for the older SoCs.
|
||||
*/
|
||||
regmap_write(tcon->regs, SUN4I_TCON0_LVDS_ANA0_REG,
|
||||
SUN6I_TCON0_LVDS_ANA0_C(2) |
|
||||
SUN6I_TCON0_LVDS_ANA0_V(3) |
|
||||
SUN6I_TCON0_LVDS_ANA0_PD(2) |
|
||||
SUN6I_TCON0_LVDS_ANA0_EN_LDO);
|
||||
udelay(2);
|
||||
|
||||
regmap_update_bits(tcon->regs, SUN4I_TCON0_LVDS_ANA0_REG,
|
||||
SUN6I_TCON0_LVDS_ANA0_EN_MB,
|
||||
SUN6I_TCON0_LVDS_ANA0_EN_MB);
|
||||
udelay(2);
|
||||
|
||||
regmap_update_bits(tcon->regs, SUN4I_TCON0_LVDS_ANA0_REG,
|
||||
SUN6I_TCON0_LVDS_ANA0_EN_DRVC,
|
||||
SUN6I_TCON0_LVDS_ANA0_EN_DRVC);
|
||||
|
||||
if (sun4i_tcon_get_pixel_depth(encoder) == 18)
|
||||
val = 7;
|
||||
else
|
||||
val = 0xf;
|
||||
|
||||
regmap_write_bits(tcon->regs, SUN4I_TCON0_LVDS_ANA0_REG,
|
||||
SUN6I_TCON0_LVDS_ANA0_EN_DRVD(0xf),
|
||||
SUN6I_TCON0_LVDS_ANA0_EN_DRVD(val));
|
||||
if (tcon->quirks->setup_lvds_phy)
|
||||
tcon->quirks->setup_lvds_phy(tcon, encoder);
|
||||
} else {
|
||||
regmap_update_bits(tcon->regs, SUN4I_TCON0_LVDS_IF_REG,
|
||||
SUN4I_TCON0_LVDS_IF_EN, 0);
|
||||
|
@ -1453,6 +1478,16 @@ static const struct sun4i_tcon_quirks sun6i_a31s_quirks = {
|
|||
.dclk_min_div = 1,
|
||||
};
|
||||
|
||||
static const struct sun4i_tcon_quirks sun7i_a20_tcon0_quirks = {
|
||||
.supports_lvds = true,
|
||||
.has_channel_0 = true,
|
||||
.has_channel_1 = true,
|
||||
.dclk_min_div = 4,
|
||||
/* Same display pipeline structure as A10 */
|
||||
.set_mux = sun4i_a10_tcon_set_mux,
|
||||
.setup_lvds_phy = sun4i_tcon_setup_lvds_phy,
|
||||
};
|
||||
|
||||
static const struct sun4i_tcon_quirks sun7i_a20_quirks = {
|
||||
.has_channel_0 = true,
|
||||
.has_channel_1 = true,
|
||||
|
@ -1465,12 +1500,14 @@ static const struct sun4i_tcon_quirks sun8i_a33_quirks = {
|
|||
.has_channel_0 = true,
|
||||
.has_lvds_alt = true,
|
||||
.dclk_min_div = 1,
|
||||
.setup_lvds_phy = sun6i_tcon_setup_lvds_phy,
|
||||
};
|
||||
|
||||
static const struct sun4i_tcon_quirks sun8i_a83t_lcd_quirks = {
|
||||
.supports_lvds = true,
|
||||
.has_channel_0 = true,
|
||||
.dclk_min_div = 1,
|
||||
.setup_lvds_phy = sun6i_tcon_setup_lvds_phy,
|
||||
};
|
||||
|
||||
static const struct sun4i_tcon_quirks sun8i_a83t_tv_quirks = {
|
||||
|
@ -1505,6 +1542,8 @@ const struct of_device_id sun4i_tcon_of_table[] = {
|
|||
{ .compatible = "allwinner,sun6i-a31-tcon", .data = &sun6i_a31_quirks },
|
||||
{ .compatible = "allwinner,sun6i-a31s-tcon", .data = &sun6i_a31s_quirks },
|
||||
{ .compatible = "allwinner,sun7i-a20-tcon", .data = &sun7i_a20_quirks },
|
||||
{ .compatible = "allwinner,sun7i-a20-tcon0", .data = &sun7i_a20_tcon0_quirks },
|
||||
{ .compatible = "allwinner,sun7i-a20-tcon1", .data = &sun7i_a20_quirks },
|
||||
{ .compatible = "allwinner,sun8i-a23-tcon", .data = &sun8i_a33_quirks },
|
||||
{ .compatible = "allwinner,sun8i-a33-tcon", .data = &sun8i_a33_quirks },
|
||||
{ .compatible = "allwinner,sun8i-a83t-tcon-lcd", .data = &sun8i_a83t_lcd_quirks },
|
||||
|
|
|
@ -193,6 +193,13 @@
|
|||
#define SUN4I_TCON_MUX_CTRL_REG 0x200
|
||||
|
||||
#define SUN4I_TCON0_LVDS_ANA0_REG 0x220
|
||||
#define SUN4I_TCON0_LVDS_ANA0_DCHS BIT(16)
|
||||
#define SUN4I_TCON0_LVDS_ANA0_PD (BIT(20) | BIT(21))
|
||||
#define SUN4I_TCON0_LVDS_ANA0_EN_MB BIT(22)
|
||||
#define SUN4I_TCON0_LVDS_ANA0_REG_C (BIT(24) | BIT(25))
|
||||
#define SUN4I_TCON0_LVDS_ANA0_REG_V (BIT(26) | BIT(27))
|
||||
#define SUN4I_TCON0_LVDS_ANA0_CK_EN (BIT(29) | BIT(28))
|
||||
|
||||
#define SUN6I_TCON0_LVDS_ANA0_EN_MB BIT(31)
|
||||
#define SUN6I_TCON0_LVDS_ANA0_EN_LDO BIT(30)
|
||||
#define SUN6I_TCON0_LVDS_ANA0_EN_DRVC BIT(24)
|
||||
|
@ -201,6 +208,10 @@
|
|||
#define SUN6I_TCON0_LVDS_ANA0_V(x) (((x) & 3) << 8)
|
||||
#define SUN6I_TCON0_LVDS_ANA0_PD(x) (((x) & 3) << 4)
|
||||
|
||||
#define SUN4I_TCON0_LVDS_ANA1_REG 0x224
|
||||
#define SUN4I_TCON0_LVDS_ANA1_INIT (0x1f << 26 | 0x1f << 10)
|
||||
#define SUN4I_TCON0_LVDS_ANA1_UPDATE (0x1f << 16 | 0x1f << 00)
|
||||
|
||||
#define SUN4I_TCON1_FILL_CTL_REG 0x300
|
||||
#define SUN4I_TCON1_FILL_BEG0_REG 0x304
|
||||
#define SUN4I_TCON1_FILL_END0_REG 0x308
|
||||
|
@ -228,6 +239,9 @@ struct sun4i_tcon_quirks {
|
|||
|
||||
/* callback to handle tcon muxing options */
|
||||
int (*set_mux)(struct sun4i_tcon *, const struct drm_encoder *);
|
||||
/* handler for LVDS setup routine */
|
||||
void (*setup_lvds_phy)(struct sun4i_tcon *tcon,
|
||||
const struct drm_encoder *encoder);
|
||||
};
|
||||
|
||||
struct sun4i_tcon {
|
||||
|
|
|
@ -14,7 +14,6 @@
|
|||
#include <linux/phy/phy-mipi-dphy.h>
|
||||
#include <linux/phy/phy.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/pm_runtime.h>
|
||||
#include <linux/regmap.h>
|
||||
#include <linux/regulator/consumer.h>
|
||||
#include <linux/reset.h>
|
||||
|
@ -27,7 +26,6 @@
|
|||
#include <drm/drm_probe_helper.h>
|
||||
|
||||
#include "sun4i_crtc.h"
|
||||
#include "sun4i_drv.h"
|
||||
#include "sun4i_tcon.h"
|
||||
#include "sun6i_mipi_dsi.h"
|
||||
|
||||
|
@ -722,10 +720,31 @@ static void sun6i_dsi_encoder_enable(struct drm_encoder *encoder)
|
|||
union phy_configure_opts opts = { 0 };
|
||||
struct phy_configure_opts_mipi_dphy *cfg = &opts.mipi_dphy;
|
||||
u16 delay;
|
||||
int err;
|
||||
|
||||
DRM_DEBUG_DRIVER("Enabling DSI output\n");
|
||||
|
||||
pm_runtime_get_sync(dsi->dev);
|
||||
err = regulator_enable(dsi->regulator);
|
||||
if (err)
|
||||
dev_warn(dsi->dev, "failed to enable VCC-DSI supply: %d\n", err);
|
||||
|
||||
reset_control_deassert(dsi->reset);
|
||||
clk_prepare_enable(dsi->mod_clk);
|
||||
|
||||
/*
|
||||
* Enable the DSI block.
|
||||
*/
|
||||
regmap_write(dsi->regs, SUN6I_DSI_CTL_REG, SUN6I_DSI_CTL_EN);
|
||||
|
||||
regmap_write(dsi->regs, SUN6I_DSI_BASIC_CTL0_REG,
|
||||
SUN6I_DSI_BASIC_CTL0_ECC_EN | SUN6I_DSI_BASIC_CTL0_CRC_EN);
|
||||
|
||||
regmap_write(dsi->regs, SUN6I_DSI_TRANS_START_REG, 10);
|
||||
regmap_write(dsi->regs, SUN6I_DSI_TRANS_ZERO_REG, 0);
|
||||
|
||||
sun6i_dsi_inst_init(dsi, dsi->device);
|
||||
|
||||
regmap_write(dsi->regs, SUN6I_DSI_DEBUG_DATA_REG, 0xff);
|
||||
|
||||
delay = sun6i_dsi_get_video_start_delay(dsi, mode);
|
||||
regmap_write(dsi->regs, SUN6I_DSI_BASIC_CTL1_REG,
|
||||
|
@ -749,7 +768,7 @@ static void sun6i_dsi_encoder_enable(struct drm_encoder *encoder)
|
|||
phy_configure(dsi->dphy, &opts);
|
||||
phy_power_on(dsi->dphy);
|
||||
|
||||
if (!IS_ERR(dsi->panel))
|
||||
if (dsi->panel)
|
||||
drm_panel_prepare(dsi->panel);
|
||||
|
||||
/*
|
||||
|
@ -764,7 +783,7 @@ static void sun6i_dsi_encoder_enable(struct drm_encoder *encoder)
|
|||
* ordering on the panels I've tested it with, so I guess this
|
||||
* will do for now, until that IP is better understood.
|
||||
*/
|
||||
if (!IS_ERR(dsi->panel))
|
||||
if (dsi->panel)
|
||||
drm_panel_enable(dsi->panel);
|
||||
|
||||
sun6i_dsi_start(dsi, DSI_START_HSC);
|
||||
|
@ -780,7 +799,7 @@ static void sun6i_dsi_encoder_disable(struct drm_encoder *encoder)
|
|||
|
||||
DRM_DEBUG_DRIVER("Disabling DSI output\n");
|
||||
|
||||
if (!IS_ERR(dsi->panel)) {
|
||||
if (dsi->panel) {
|
||||
drm_panel_disable(dsi->panel);
|
||||
drm_panel_unprepare(dsi->panel);
|
||||
}
|
||||
|
@ -788,7 +807,9 @@ static void sun6i_dsi_encoder_disable(struct drm_encoder *encoder)
|
|||
phy_power_off(dsi->dphy);
|
||||
phy_exit(dsi->dphy);
|
||||
|
||||
pm_runtime_put(dsi->dev);
|
||||
clk_disable_unprepare(dsi->mod_clk);
|
||||
reset_control_assert(dsi->reset);
|
||||
regulator_disable(dsi->regulator);
|
||||
}
|
||||
|
||||
static int sun6i_dsi_get_modes(struct drm_connector *connector)
|
||||
|
@ -805,7 +826,10 @@ static struct drm_connector_helper_funcs sun6i_dsi_connector_helper_funcs = {
|
|||
static enum drm_connector_status
|
||||
sun6i_dsi_connector_detect(struct drm_connector *connector, bool force)
|
||||
{
|
||||
return connector_status_connected;
|
||||
struct sun6i_dsi *dsi = connector_to_sun6i_dsi(connector);
|
||||
|
||||
return dsi->panel ? connector_status_connected :
|
||||
connector_status_disconnected;
|
||||
}
|
||||
|
||||
static const struct drm_connector_funcs sun6i_dsi_connector_funcs = {
|
||||
|
@ -942,11 +966,18 @@ static int sun6i_dsi_attach(struct mipi_dsi_host *host,
|
|||
struct mipi_dsi_device *device)
|
||||
{
|
||||
struct sun6i_dsi *dsi = host_to_sun6i_dsi(host);
|
||||
struct drm_panel *panel = of_drm_find_panel(device->dev.of_node);
|
||||
|
||||
if (IS_ERR(panel))
|
||||
return PTR_ERR(panel);
|
||||
if (!dsi->drm || !dsi->drm->registered)
|
||||
return -EPROBE_DEFER;
|
||||
|
||||
dsi->panel = panel;
|
||||
dsi->device = device;
|
||||
dsi->panel = of_drm_find_panel(device->dev.of_node);
|
||||
if (IS_ERR(dsi->panel))
|
||||
return PTR_ERR(dsi->panel);
|
||||
|
||||
drm_panel_attach(dsi->panel, &dsi->connector);
|
||||
drm_kms_helper_hotplug_event(dsi->drm);
|
||||
|
||||
dev_info(host->dev, "Attached device %s\n", device->name);
|
||||
|
||||
|
@ -957,10 +988,14 @@ static int sun6i_dsi_detach(struct mipi_dsi_host *host,
|
|||
struct mipi_dsi_device *device)
|
||||
{
|
||||
struct sun6i_dsi *dsi = host_to_sun6i_dsi(host);
|
||||
struct drm_panel *panel = dsi->panel;
|
||||
|
||||
dsi->panel = NULL;
|
||||
dsi->device = NULL;
|
||||
|
||||
drm_panel_detach(panel);
|
||||
drm_kms_helper_hotplug_event(dsi->drm);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -1022,15 +1057,9 @@ static int sun6i_dsi_bind(struct device *dev, struct device *master,
|
|||
void *data)
|
||||
{
|
||||
struct drm_device *drm = data;
|
||||
struct sun4i_drv *drv = drm->dev_private;
|
||||
struct sun6i_dsi *dsi = dev_get_drvdata(dev);
|
||||
int ret;
|
||||
|
||||
if (!dsi->panel)
|
||||
return -EPROBE_DEFER;
|
||||
|
||||
dsi->drv = drv;
|
||||
|
||||
drm_encoder_helper_add(&dsi->encoder,
|
||||
&sun6i_dsi_enc_helper_funcs);
|
||||
ret = drm_encoder_init(drm,
|
||||
|
@ -1056,7 +1085,8 @@ static int sun6i_dsi_bind(struct device *dev, struct device *master,
|
|||
}
|
||||
|
||||
drm_connector_attach_encoder(&dsi->connector, &dsi->encoder);
|
||||
drm_panel_attach(dsi->panel, &dsi->connector);
|
||||
|
||||
dsi->drm = drm;
|
||||
|
||||
return 0;
|
||||
|
||||
|
@ -1070,7 +1100,7 @@ static void sun6i_dsi_unbind(struct device *dev, struct device *master,
|
|||
{
|
||||
struct sun6i_dsi *dsi = dev_get_drvdata(dev);
|
||||
|
||||
drm_panel_detach(dsi->panel);
|
||||
dsi->drm = NULL;
|
||||
}
|
||||
|
||||
static const struct component_ops sun6i_dsi_ops = {
|
||||
|
@ -1157,12 +1187,10 @@ static int sun6i_dsi_probe(struct platform_device *pdev)
|
|||
goto err_unprotect_clk;
|
||||
}
|
||||
|
||||
pm_runtime_enable(dev);
|
||||
|
||||
ret = mipi_dsi_host_register(&dsi->host);
|
||||
if (ret) {
|
||||
dev_err(dev, "Couldn't register MIPI-DSI host\n");
|
||||
goto err_pm_disable;
|
||||
goto err_unprotect_clk;
|
||||
}
|
||||
|
||||
ret = component_add(&pdev->dev, &sun6i_dsi_ops);
|
||||
|
@ -1175,8 +1203,6 @@ static int sun6i_dsi_probe(struct platform_device *pdev)
|
|||
|
||||
err_remove_dsi_host:
|
||||
mipi_dsi_host_unregister(&dsi->host);
|
||||
err_pm_disable:
|
||||
pm_runtime_disable(dev);
|
||||
err_unprotect_clk:
|
||||
clk_rate_exclusive_put(dsi->mod_clk);
|
||||
err_attach_clk:
|
||||
|
@ -1192,7 +1218,6 @@ static int sun6i_dsi_remove(struct platform_device *pdev)
|
|||
|
||||
component_del(&pdev->dev, &sun6i_dsi_ops);
|
||||
mipi_dsi_host_unregister(&dsi->host);
|
||||
pm_runtime_disable(dev);
|
||||
clk_rate_exclusive_put(dsi->mod_clk);
|
||||
|
||||
if (!IS_ERR(dsi->bus_clk))
|
||||
|
@ -1201,59 +1226,6 @@ static int sun6i_dsi_remove(struct platform_device *pdev)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int __maybe_unused sun6i_dsi_runtime_resume(struct device *dev)
|
||||
{
|
||||
struct sun6i_dsi *dsi = dev_get_drvdata(dev);
|
||||
int err;
|
||||
|
||||
err = regulator_enable(dsi->regulator);
|
||||
if (err) {
|
||||
dev_err(dsi->dev, "failed to enable VCC-DSI supply: %d\n", err);
|
||||
return err;
|
||||
}
|
||||
|
||||
reset_control_deassert(dsi->reset);
|
||||
clk_prepare_enable(dsi->mod_clk);
|
||||
|
||||
/*
|
||||
* Enable the DSI block.
|
||||
*
|
||||
* Some part of it can only be done once we get a number of
|
||||
* lanes, see sun6i_dsi_inst_init
|
||||
*/
|
||||
regmap_write(dsi->regs, SUN6I_DSI_CTL_REG, SUN6I_DSI_CTL_EN);
|
||||
|
||||
regmap_write(dsi->regs, SUN6I_DSI_BASIC_CTL0_REG,
|
||||
SUN6I_DSI_BASIC_CTL0_ECC_EN | SUN6I_DSI_BASIC_CTL0_CRC_EN);
|
||||
|
||||
regmap_write(dsi->regs, SUN6I_DSI_TRANS_START_REG, 10);
|
||||
regmap_write(dsi->regs, SUN6I_DSI_TRANS_ZERO_REG, 0);
|
||||
|
||||
if (dsi->device)
|
||||
sun6i_dsi_inst_init(dsi, dsi->device);
|
||||
|
||||
regmap_write(dsi->regs, SUN6I_DSI_DEBUG_DATA_REG, 0xff);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int __maybe_unused sun6i_dsi_runtime_suspend(struct device *dev)
|
||||
{
|
||||
struct sun6i_dsi *dsi = dev_get_drvdata(dev);
|
||||
|
||||
clk_disable_unprepare(dsi->mod_clk);
|
||||
reset_control_assert(dsi->reset);
|
||||
regulator_disable(dsi->regulator);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct dev_pm_ops sun6i_dsi_pm_ops = {
|
||||
SET_RUNTIME_PM_OPS(sun6i_dsi_runtime_suspend,
|
||||
sun6i_dsi_runtime_resume,
|
||||
NULL)
|
||||
};
|
||||
|
||||
static const struct of_device_id sun6i_dsi_of_table[] = {
|
||||
{ .compatible = "allwinner,sun6i-a31-mipi-dsi" },
|
||||
{ .compatible = "allwinner,sun50i-a64-mipi-dsi" },
|
||||
|
@ -1267,7 +1239,6 @@ static struct platform_driver sun6i_dsi_platform_driver = {
|
|||
.driver = {
|
||||
.name = "sun6i-mipi-dsi",
|
||||
.of_match_table = sun6i_dsi_of_table,
|
||||
.pm = &sun6i_dsi_pm_ops,
|
||||
},
|
||||
};
|
||||
module_platform_driver(sun6i_dsi_platform_driver);
|
||||
|
|
|
@ -28,8 +28,8 @@ struct sun6i_dsi {
|
|||
struct phy *dphy;
|
||||
|
||||
struct device *dev;
|
||||
struct sun4i_drv *drv;
|
||||
struct mipi_dsi_device *device;
|
||||
struct drm_device *drm;
|
||||
struct drm_panel *panel;
|
||||
};
|
||||
|
||||
|
|
|
@ -145,26 +145,6 @@ static inline uint32_t ttm_bo_type_flags(unsigned type)
|
|||
return 1 << (type);
|
||||
}
|
||||
|
||||
static void ttm_bo_release_list(struct kref *list_kref)
|
||||
{
|
||||
struct ttm_buffer_object *bo =
|
||||
container_of(list_kref, struct ttm_buffer_object, list_kref);
|
||||
size_t acc_size = bo->acc_size;
|
||||
|
||||
BUG_ON(kref_read(&bo->list_kref));
|
||||
BUG_ON(kref_read(&bo->kref));
|
||||
BUG_ON(bo->mem.mm_node != NULL);
|
||||
BUG_ON(!list_empty(&bo->lru));
|
||||
BUG_ON(!list_empty(&bo->ddestroy));
|
||||
ttm_tt_destroy(bo->ttm);
|
||||
atomic_dec(&ttm_bo_glob.bo_count);
|
||||
dma_fence_put(bo->moving);
|
||||
if (!ttm_bo_uses_embedded_gem_object(bo))
|
||||
dma_resv_fini(&bo->base._resv);
|
||||
bo->destroy(bo);
|
||||
ttm_mem_global_free(&ttm_mem_glob, acc_size);
|
||||
}
|
||||
|
||||
static void ttm_bo_add_mem_to_lru(struct ttm_buffer_object *bo,
|
||||
struct ttm_mem_reg *mem)
|
||||
{
|
||||
|
@ -181,21 +161,14 @@ static void ttm_bo_add_mem_to_lru(struct ttm_buffer_object *bo,
|
|||
|
||||
man = &bdev->man[mem->mem_type];
|
||||
list_add_tail(&bo->lru, &man->lru[bo->priority]);
|
||||
kref_get(&bo->list_kref);
|
||||
|
||||
if (!(man->flags & TTM_MEMTYPE_FLAG_FIXED) && bo->ttm &&
|
||||
!(bo->ttm->page_flags & (TTM_PAGE_FLAG_SG |
|
||||
TTM_PAGE_FLAG_SWAPPED))) {
|
||||
list_add_tail(&bo->swap, &ttm_bo_glob.swap_lru[bo->priority]);
|
||||
kref_get(&bo->list_kref);
|
||||
}
|
||||
}
|
||||
|
||||
static void ttm_bo_ref_bug(struct kref *list_kref)
|
||||
{
|
||||
BUG();
|
||||
}
|
||||
|
||||
static void ttm_bo_del_from_lru(struct ttm_buffer_object *bo)
|
||||
{
|
||||
struct ttm_bo_device *bdev = bo->bdev;
|
||||
|
@ -203,12 +176,10 @@ static void ttm_bo_del_from_lru(struct ttm_buffer_object *bo)
|
|||
|
||||
if (!list_empty(&bo->swap)) {
|
||||
list_del_init(&bo->swap);
|
||||
kref_put(&bo->list_kref, ttm_bo_ref_bug);
|
||||
notify = true;
|
||||
}
|
||||
if (!list_empty(&bo->lru)) {
|
||||
list_del_init(&bo->lru);
|
||||
kref_put(&bo->list_kref, ttm_bo_ref_bug);
|
||||
notify = true;
|
||||
}
|
||||
|
||||
|
@ -421,94 +392,49 @@ static int ttm_bo_individualize_resv(struct ttm_buffer_object *bo)
|
|||
BUG_ON(!dma_resv_trylock(&bo->base._resv));
|
||||
|
||||
r = dma_resv_copy_fences(&bo->base._resv, bo->base.resv);
|
||||
dma_resv_unlock(&bo->base._resv);
|
||||
if (r)
|
||||
dma_resv_unlock(&bo->base._resv);
|
||||
return r;
|
||||
|
||||
if (bo->type != ttm_bo_type_sg) {
|
||||
/* This works because the BO is about to be destroyed and nobody
|
||||
* reference it any more. The only tricky case is the trylock on
|
||||
* the resv object while holding the lru_lock.
|
||||
*/
|
||||
spin_lock(&ttm_bo_glob.lru_lock);
|
||||
bo->base.resv = &bo->base._resv;
|
||||
spin_unlock(&ttm_bo_glob.lru_lock);
|
||||
}
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
static void ttm_bo_flush_all_fences(struct ttm_buffer_object *bo)
|
||||
{
|
||||
struct dma_resv *resv = &bo->base._resv;
|
||||
struct dma_resv_list *fobj;
|
||||
struct dma_fence *fence;
|
||||
int i;
|
||||
|
||||
fobj = dma_resv_get_list(&bo->base._resv);
|
||||
fence = dma_resv_get_excl(&bo->base._resv);
|
||||
rcu_read_lock();
|
||||
fobj = rcu_dereference(resv->fence);
|
||||
fence = rcu_dereference(resv->fence_excl);
|
||||
if (fence && !fence->ops->signaled)
|
||||
dma_fence_enable_sw_signaling(fence);
|
||||
|
||||
for (i = 0; fobj && i < fobj->shared_count; ++i) {
|
||||
fence = rcu_dereference_protected(fobj->shared[i],
|
||||
dma_resv_held(bo->base.resv));
|
||||
fence = rcu_dereference(fobj->shared[i]);
|
||||
|
||||
if (!fence->ops->signaled)
|
||||
dma_fence_enable_sw_signaling(fence);
|
||||
}
|
||||
}
|
||||
|
||||
static void ttm_bo_cleanup_refs_or_queue(struct ttm_buffer_object *bo)
|
||||
{
|
||||
struct ttm_bo_device *bdev = bo->bdev;
|
||||
int ret;
|
||||
|
||||
ret = ttm_bo_individualize_resv(bo);
|
||||
if (ret) {
|
||||
/* Last resort, if we fail to allocate memory for the
|
||||
* fences block for the BO to become idle
|
||||
*/
|
||||
dma_resv_wait_timeout_rcu(bo->base.resv, true, false,
|
||||
30 * HZ);
|
||||
spin_lock(&ttm_bo_glob.lru_lock);
|
||||
goto error;
|
||||
}
|
||||
|
||||
spin_lock(&ttm_bo_glob.lru_lock);
|
||||
ret = dma_resv_trylock(bo->base.resv) ? 0 : -EBUSY;
|
||||
if (!ret) {
|
||||
if (dma_resv_test_signaled_rcu(&bo->base._resv, true)) {
|
||||
ttm_bo_del_from_lru(bo);
|
||||
spin_unlock(&ttm_bo_glob.lru_lock);
|
||||
if (bo->base.resv != &bo->base._resv)
|
||||
dma_resv_unlock(&bo->base._resv);
|
||||
|
||||
ttm_bo_cleanup_memtype_use(bo);
|
||||
dma_resv_unlock(bo->base.resv);
|
||||
return;
|
||||
}
|
||||
|
||||
ttm_bo_flush_all_fences(bo);
|
||||
|
||||
/*
|
||||
* Make NO_EVICT bos immediately available to
|
||||
* shrinkers, now that they are queued for
|
||||
* destruction.
|
||||
*/
|
||||
if (bo->mem.placement & TTM_PL_FLAG_NO_EVICT) {
|
||||
bo->mem.placement &= ~TTM_PL_FLAG_NO_EVICT;
|
||||
ttm_bo_move_to_lru_tail(bo, NULL);
|
||||
}
|
||||
|
||||
dma_resv_unlock(bo->base.resv);
|
||||
}
|
||||
if (bo->base.resv != &bo->base._resv) {
|
||||
ttm_bo_flush_all_fences(bo);
|
||||
dma_resv_unlock(&bo->base._resv);
|
||||
}
|
||||
|
||||
error:
|
||||
kref_get(&bo->list_kref);
|
||||
list_add_tail(&bo->ddestroy, &bdev->ddestroy);
|
||||
spin_unlock(&ttm_bo_glob.lru_lock);
|
||||
|
||||
schedule_delayed_work(&bdev->wq,
|
||||
((HZ / 100) < 1) ? 1 : HZ / 100);
|
||||
rcu_read_unlock();
|
||||
}
|
||||
|
||||
/**
|
||||
* function ttm_bo_cleanup_refs
|
||||
* If bo idle, remove from delayed- and lru lists, and unref.
|
||||
* If not idle, do nothing.
|
||||
* If bo idle, remove from lru lists, and unref.
|
||||
* If not idle, block if possible.
|
||||
*
|
||||
* Must be called with lru_lock and reservation held, this function
|
||||
* will drop the lru lock and optionally the reservation lock before returning.
|
||||
|
@ -522,14 +448,9 @@ static int ttm_bo_cleanup_refs(struct ttm_buffer_object *bo,
|
|||
bool interruptible, bool no_wait_gpu,
|
||||
bool unlock_resv)
|
||||
{
|
||||
struct dma_resv *resv;
|
||||
struct dma_resv *resv = &bo->base._resv;
|
||||
int ret;
|
||||
|
||||
if (unlikely(list_empty(&bo->ddestroy)))
|
||||
resv = bo->base.resv;
|
||||
else
|
||||
resv = &bo->base._resv;
|
||||
|
||||
if (dma_resv_test_signaled_rcu(resv, true))
|
||||
ret = 0;
|
||||
else
|
||||
|
@ -542,9 +463,8 @@ static int ttm_bo_cleanup_refs(struct ttm_buffer_object *bo,
|
|||
dma_resv_unlock(bo->base.resv);
|
||||
spin_unlock(&ttm_bo_glob.lru_lock);
|
||||
|
||||
lret = dma_resv_wait_timeout_rcu(resv, true,
|
||||
interruptible,
|
||||
30 * HZ);
|
||||
lret = dma_resv_wait_timeout_rcu(resv, true, interruptible,
|
||||
30 * HZ);
|
||||
|
||||
if (lret < 0)
|
||||
return lret;
|
||||
|
@ -576,14 +496,14 @@ static int ttm_bo_cleanup_refs(struct ttm_buffer_object *bo,
|
|||
|
||||
ttm_bo_del_from_lru(bo);
|
||||
list_del_init(&bo->ddestroy);
|
||||
kref_put(&bo->list_kref, ttm_bo_ref_bug);
|
||||
|
||||
spin_unlock(&ttm_bo_glob.lru_lock);
|
||||
ttm_bo_cleanup_memtype_use(bo);
|
||||
|
||||
if (unlock_resv)
|
||||
dma_resv_unlock(bo->base.resv);
|
||||
|
||||
ttm_bo_put(bo);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -605,8 +525,9 @@ static bool ttm_bo_delayed_delete(struct ttm_bo_device *bdev, bool remove_all)
|
|||
|
||||
bo = list_first_entry(&bdev->ddestroy, struct ttm_buffer_object,
|
||||
ddestroy);
|
||||
kref_get(&bo->list_kref);
|
||||
list_move_tail(&bo->ddestroy, &removed);
|
||||
if (!ttm_bo_get_unless_zero(bo))
|
||||
continue;
|
||||
|
||||
if (remove_all || bo->base.resv != &bo->base._resv) {
|
||||
spin_unlock(&glob->lru_lock);
|
||||
|
@ -621,7 +542,7 @@ static bool ttm_bo_delayed_delete(struct ttm_bo_device *bdev, bool remove_all)
|
|||
spin_unlock(&glob->lru_lock);
|
||||
}
|
||||
|
||||
kref_put(&bo->list_kref, ttm_bo_release_list);
|
||||
ttm_bo_put(bo);
|
||||
spin_lock(&glob->lru_lock);
|
||||
}
|
||||
list_splice_tail(&removed, &bdev->ddestroy);
|
||||
|
@ -647,16 +568,68 @@ static void ttm_bo_release(struct kref *kref)
|
|||
container_of(kref, struct ttm_buffer_object, kref);
|
||||
struct ttm_bo_device *bdev = bo->bdev;
|
||||
struct ttm_mem_type_manager *man = &bdev->man[bo->mem.mem_type];
|
||||
size_t acc_size = bo->acc_size;
|
||||
int ret;
|
||||
|
||||
if (bo->bdev->driver->release_notify)
|
||||
bo->bdev->driver->release_notify(bo);
|
||||
if (!bo->deleted) {
|
||||
ret = ttm_bo_individualize_resv(bo);
|
||||
if (ret) {
|
||||
/* Last resort, if we fail to allocate memory for the
|
||||
* fences block for the BO to become idle
|
||||
*/
|
||||
dma_resv_wait_timeout_rcu(bo->base.resv, true, false,
|
||||
30 * HZ);
|
||||
}
|
||||
|
||||
drm_vma_offset_remove(bdev->vma_manager, &bo->base.vma_node);
|
||||
ttm_mem_io_lock(man, false);
|
||||
ttm_mem_io_free_vm(bo);
|
||||
ttm_mem_io_unlock(man);
|
||||
ttm_bo_cleanup_refs_or_queue(bo);
|
||||
kref_put(&bo->list_kref, ttm_bo_release_list);
|
||||
if (bo->bdev->driver->release_notify)
|
||||
bo->bdev->driver->release_notify(bo);
|
||||
|
||||
drm_vma_offset_remove(bdev->vma_manager, &bo->base.vma_node);
|
||||
ttm_mem_io_lock(man, false);
|
||||
ttm_mem_io_free_vm(bo);
|
||||
ttm_mem_io_unlock(man);
|
||||
}
|
||||
|
||||
if (!dma_resv_test_signaled_rcu(bo->base.resv, true)) {
|
||||
/* The BO is not idle, resurrect it for delayed destroy */
|
||||
ttm_bo_flush_all_fences(bo);
|
||||
bo->deleted = true;
|
||||
|
||||
spin_lock(&ttm_bo_glob.lru_lock);
|
||||
|
||||
/*
|
||||
* Make NO_EVICT bos immediately available to
|
||||
* shrinkers, now that they are queued for
|
||||
* destruction.
|
||||
*/
|
||||
if (bo->mem.placement & TTM_PL_FLAG_NO_EVICT) {
|
||||
bo->mem.placement &= ~TTM_PL_FLAG_NO_EVICT;
|
||||
ttm_bo_move_to_lru_tail(bo, NULL);
|
||||
}
|
||||
|
||||
kref_init(&bo->kref);
|
||||
list_add_tail(&bo->ddestroy, &bdev->ddestroy);
|
||||
spin_unlock(&ttm_bo_glob.lru_lock);
|
||||
|
||||
schedule_delayed_work(&bdev->wq,
|
||||
((HZ / 100) < 1) ? 1 : HZ / 100);
|
||||
return;
|
||||
}
|
||||
|
||||
spin_lock(&ttm_bo_glob.lru_lock);
|
||||
ttm_bo_del_from_lru(bo);
|
||||
list_del(&bo->ddestroy);
|
||||
spin_unlock(&ttm_bo_glob.lru_lock);
|
||||
|
||||
ttm_bo_cleanup_memtype_use(bo);
|
||||
|
||||
BUG_ON(bo->mem.mm_node != NULL);
|
||||
atomic_dec(&ttm_bo_glob.bo_count);
|
||||
dma_fence_put(bo->moving);
|
||||
if (!ttm_bo_uses_embedded_gem_object(bo))
|
||||
dma_resv_fini(&bo->base._resv);
|
||||
bo->destroy(bo);
|
||||
ttm_mem_global_free(&ttm_mem_glob, acc_size);
|
||||
}
|
||||
|
||||
void ttm_bo_put(struct ttm_buffer_object *bo)
|
||||
|
@ -759,8 +732,7 @@ static bool ttm_bo_evict_swapout_allowable(struct ttm_buffer_object *bo,
|
|||
|
||||
if (bo->base.resv == ctx->resv) {
|
||||
dma_resv_assert_held(bo->base.resv);
|
||||
if (ctx->flags & TTM_OPT_FLAG_ALLOW_RES_EVICT
|
||||
|| !list_empty(&bo->ddestroy))
|
||||
if (ctx->flags & TTM_OPT_FLAG_ALLOW_RES_EVICT)
|
||||
ret = true;
|
||||
*locked = false;
|
||||
if (busy)
|
||||
|
@ -841,6 +813,11 @@ static int ttm_mem_evict_first(struct ttm_bo_device *bdev,
|
|||
dma_resv_unlock(bo->base.resv);
|
||||
continue;
|
||||
}
|
||||
if (!ttm_bo_get_unless_zero(bo)) {
|
||||
if (locked)
|
||||
dma_resv_unlock(bo->base.resv);
|
||||
continue;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
|
@ -852,21 +829,19 @@ static int ttm_mem_evict_first(struct ttm_bo_device *bdev,
|
|||
}
|
||||
|
||||
if (!bo) {
|
||||
if (busy_bo)
|
||||
kref_get(&busy_bo->list_kref);
|
||||
if (busy_bo && !ttm_bo_get_unless_zero(busy_bo))
|
||||
busy_bo = NULL;
|
||||
spin_unlock(&ttm_bo_glob.lru_lock);
|
||||
ret = ttm_mem_evict_wait_busy(busy_bo, ctx, ticket);
|
||||
if (busy_bo)
|
||||
kref_put(&busy_bo->list_kref, ttm_bo_release_list);
|
||||
ttm_bo_put(busy_bo);
|
||||
return ret;
|
||||
}
|
||||
|
||||
kref_get(&bo->list_kref);
|
||||
|
||||
if (!list_empty(&bo->ddestroy)) {
|
||||
if (bo->deleted) {
|
||||
ret = ttm_bo_cleanup_refs(bo, ctx->interruptible,
|
||||
ctx->no_wait_gpu, locked);
|
||||
kref_put(&bo->list_kref, ttm_bo_release_list);
|
||||
ttm_bo_put(bo);
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
@ -876,7 +851,7 @@ static int ttm_mem_evict_first(struct ttm_bo_device *bdev,
|
|||
if (locked)
|
||||
ttm_bo_unreserve(bo);
|
||||
|
||||
kref_put(&bo->list_kref, ttm_bo_release_list);
|
||||
ttm_bo_put(bo);
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
@ -1288,7 +1263,6 @@ int ttm_bo_init_reserved(struct ttm_bo_device *bdev,
|
|||
bo->destroy = destroy ? destroy : ttm_bo_default_destroy;
|
||||
|
||||
kref_init(&bo->kref);
|
||||
kref_init(&bo->list_kref);
|
||||
INIT_LIST_HEAD(&bo->lru);
|
||||
INIT_LIST_HEAD(&bo->ddestroy);
|
||||
INIT_LIST_HEAD(&bo->swap);
|
||||
|
@ -1808,11 +1782,18 @@ int ttm_bo_swapout(struct ttm_bo_global *glob, struct ttm_operation_ctx *ctx)
|
|||
spin_lock(&glob->lru_lock);
|
||||
for (i = 0; i < TTM_MAX_BO_PRIORITY; ++i) {
|
||||
list_for_each_entry(bo, &glob->swap_lru[i], swap) {
|
||||
if (ttm_bo_evict_swapout_allowable(bo, ctx, &locked,
|
||||
NULL)) {
|
||||
ret = 0;
|
||||
break;
|
||||
if (!ttm_bo_evict_swapout_allowable(bo, ctx, &locked,
|
||||
NULL))
|
||||
continue;
|
||||
|
||||
if (!ttm_bo_get_unless_zero(bo)) {
|
||||
if (locked)
|
||||
dma_resv_unlock(bo->base.resv);
|
||||
continue;
|
||||
}
|
||||
|
||||
ret = 0;
|
||||
break;
|
||||
}
|
||||
if (!ret)
|
||||
break;
|
||||
|
@ -1823,11 +1804,9 @@ int ttm_bo_swapout(struct ttm_bo_global *glob, struct ttm_operation_ctx *ctx)
|
|||
return ret;
|
||||
}
|
||||
|
||||
kref_get(&bo->list_kref);
|
||||
|
||||
if (!list_empty(&bo->ddestroy)) {
|
||||
if (bo->deleted) {
|
||||
ret = ttm_bo_cleanup_refs(bo, false, false, locked);
|
||||
kref_put(&bo->list_kref, ttm_bo_release_list);
|
||||
ttm_bo_put(bo);
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
@ -1881,7 +1860,7 @@ out:
|
|||
*/
|
||||
if (locked)
|
||||
dma_resv_unlock(bo->base.resv);
|
||||
kref_put(&bo->list_kref, ttm_bo_release_list);
|
||||
ttm_bo_put(bo);
|
||||
return ret;
|
||||
}
|
||||
EXPORT_SYMBOL(ttm_bo_swapout);
|
||||
|
|
|
@ -507,11 +507,10 @@ static int ttm_buffer_object_transfer(struct ttm_buffer_object *bo,
|
|||
fbo->base.moving = NULL;
|
||||
drm_vma_node_reset(&fbo->base.base.vma_node);
|
||||
|
||||
kref_init(&fbo->base.list_kref);
|
||||
kref_init(&fbo->base.kref);
|
||||
fbo->base.destroy = &ttm_transfered_destroy;
|
||||
fbo->base.acc_size = 0;
|
||||
if (bo->base.resv == &bo->base._resv)
|
||||
if (bo->type != ttm_bo_type_sg)
|
||||
fbo->base.base.resv = &fbo->base.base._resv;
|
||||
|
||||
dma_resv_init(&fbo->base.base._resv);
|
||||
|
|
|
@ -84,13 +84,14 @@ static const struct debugfs_reg32 crtc_regs[] = {
|
|||
VC4_REG32(PV_HACT_ACT),
|
||||
};
|
||||
|
||||
bool vc4_crtc_get_scanoutpos(struct drm_device *dev, unsigned int crtc_id,
|
||||
bool in_vblank_irq, int *vpos, int *hpos,
|
||||
ktime_t *stime, ktime_t *etime,
|
||||
const struct drm_display_mode *mode)
|
||||
static bool vc4_crtc_get_scanout_position(struct drm_crtc *crtc,
|
||||
bool in_vblank_irq,
|
||||
int *vpos, int *hpos,
|
||||
ktime_t *stime, ktime_t *etime,
|
||||
const struct drm_display_mode *mode)
|
||||
{
|
||||
struct drm_device *dev = crtc->dev;
|
||||
struct vc4_dev *vc4 = to_vc4_dev(dev);
|
||||
struct drm_crtc *crtc = drm_crtc_from_index(dev, crtc_id);
|
||||
struct vc4_crtc *vc4_crtc = to_vc4_crtc(crtc);
|
||||
u32 val;
|
||||
int fifo_lines;
|
||||
|
@ -1030,6 +1031,7 @@ static const struct drm_crtc_funcs vc4_crtc_funcs = {
|
|||
.gamma_set = drm_atomic_helper_legacy_gamma_set,
|
||||
.enable_vblank = vc4_enable_vblank,
|
||||
.disable_vblank = vc4_disable_vblank,
|
||||
.get_vblank_timestamp = drm_crtc_vblank_helper_get_vblank_timestamp,
|
||||
};
|
||||
|
||||
static const struct drm_crtc_helper_funcs vc4_crtc_helper_funcs = {
|
||||
|
@ -1039,6 +1041,7 @@ static const struct drm_crtc_helper_funcs vc4_crtc_helper_funcs = {
|
|||
.atomic_flush = vc4_crtc_atomic_flush,
|
||||
.atomic_enable = vc4_crtc_atomic_enable,
|
||||
.atomic_disable = vc4_crtc_atomic_disable,
|
||||
.get_scanout_position = vc4_crtc_get_scanout_position,
|
||||
};
|
||||
|
||||
static const struct vc4_crtc_data pv0_data = {
|
||||
|
|
|
@ -190,9 +190,6 @@ static struct drm_driver vc4_drm_driver = {
|
|||
.irq_postinstall = vc4_irq_postinstall,
|
||||
.irq_uninstall = vc4_irq_uninstall,
|
||||
|
||||
.get_scanout_position = vc4_crtc_get_scanoutpos,
|
||||
.get_vblank_timestamp = drm_calc_vbltimestamp_from_scanoutpos,
|
||||
|
||||
#if defined(CONFIG_DEBUG_FS)
|
||||
.debugfs_init = vc4_debugfs_init,
|
||||
#endif
|
||||
|
|
|
@ -743,10 +743,6 @@ void vc4_bo_remove_from_purgeable_pool(struct vc4_bo *bo);
|
|||
|
||||
/* vc4_crtc.c */
|
||||
extern struct platform_driver vc4_crtc_driver;
|
||||
bool vc4_crtc_get_scanoutpos(struct drm_device *dev, unsigned int crtc_id,
|
||||
bool in_vblank_irq, int *vpos, int *hpos,
|
||||
ktime_t *stime, ktime_t *etime,
|
||||
const struct drm_display_mode *mode);
|
||||
void vc4_crtc_handle_vblank(struct vc4_crtc *crtc);
|
||||
void vc4_crtc_txp_armed(struct drm_crtc_state *state);
|
||||
void vc4_crtc_get_margins(struct drm_crtc_state *state,
|
||||
|
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue