drm-misc-next for v5.15:
UAPI Changes: Cross-subsystem Changes: Core Changes: - Assorted docbook updates. - Unbreak damage selftests. - Define DRM_FORMAT_MAX_PLANES, maximum planes for a planar format. - Add gem fb vmap/vunmap helpers, use them in gud and vkms drivers. Driver Changes: - Bridge fixes for ti-sn65dsi86. - Use a full-featured driver for ATNA33XC20 to get backlight right, instead of the simple panel driver. - Assorted fixes to pl111,. - Support E Ink VB3300-KCA panel. - Add support for Gopher 2b LCD and ilitek ili9341 panels. -----BEGIN PGP SIGNATURE----- iQIzBAABCgAdFiEEuXvWqAysSYEJGuVH/lWMcqZwE8MFAmELu+0ACgkQ/lWMcqZw E8PdYw//Xotxr/qu2/k9+NQYTbSpAgTUVcd9QRlY09+1vYDfldnl1xzPjh3irBIP hpGcHK/9Az0y1UogcHkxwoSnAlnn5fTEEM6ocA8o3bhzE/C2Fe6n+YOfIn9XiH27 PUvHlDFGAslOh6nXQmSO02hKxMrVldRqeYyFpHuv8w/B18HKYC6Zfe3aaM4A/8/a 98R8ifomFLoBfk3TsK188M1lcAosOZKhZTeqU8XPGOh3Jw2amVc4f2+jfn7llBMp lbIgTCzb2Rmbdk2VpaOjqNz/66ZcFsY73IGIBo4zsZCYsSS3WBirX33EBSSXhraf 5QPiIcpJGFgsigZrNDvTWsfC/mA14ejSTBrG2JjSYip7O4TBseh5FlX/UWhBMhPi qDnJsKfYGNEuPwXwTE1Ce5cv/bpzaYTPXMVlFjoH3/US+UsbrsXNTSsLHyRG5J0G FS/MU9jLQLNb3hWX4jL4DuD4M9pW8STjcpKXzcX2VAsUkw+n4uwNmXi8vPi39ZUw Xra4+rQFe5PkkqpjEu1oKZbRk+11IUDKFEMpMWPsrfWSANDh0fLz0cQj09FbeHma 46c0MqUCCYDwenqbjJTNZEHQ67MAKD8itTu/EITCqDRoz3Xp9/GjCLZ9ylEGBGk5 eCCRIlhydKjcBeWZAikfXkvPrXfCwhIZvz+ODknuDp27A/kVmko= =ozmA -----END PGP SIGNATURE----- Merge tag 'drm-misc-next-2021-08-05' of git://anongit.freedesktop.org/drm/drm-misc into drm-next drm-misc-next for v5.15: UAPI Changes: Cross-subsystem Changes: Core Changes: - Assorted docbook updates. - Unbreak damage selftests. - Define DRM_FORMAT_MAX_PLANES, maximum planes for a planar format. - Add gem fb vmap/vunmap helpers, use them in gud and vkms drivers. Driver Changes: - Bridge fixes for ti-sn65dsi86. - Use a full-featured driver for ATNA33XC20 to get backlight right, instead of the simple panel driver. - Assorted fixes to pl111,. - Support E Ink VB3300-KCA panel. - Add support for Gopher 2b LCD and ilitek ili9341 panels. Signed-off-by: Dave Airlie <airlied@redhat.com> From: Maarten Lankhorst <maarten.lankhorst@linux.intel.com> Link: https://patchwork.freedesktop.org/patch/msgid/e460fece-cfd9-6aa4-37c1-0fb1b473196d@linux.intel.com
This commit is contained in:
commit
49f7844b08
|
@ -0,0 +1,78 @@
|
|||
# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
|
||||
%YAML 1.2
|
||||
---
|
||||
$id: http://devicetree.org/schemas/display/panel/ilitek,ili9341.yaml#
|
||||
$schema: http://devicetree.org/meta-schemas/core.yaml#
|
||||
|
||||
title: Ilitek-9341 Display Panel
|
||||
|
||||
maintainers:
|
||||
- Dillon Min <dillon.minfei@gmail.com>
|
||||
|
||||
description: |
|
||||
Ilitek ILI9341 TFT panel driver with SPI control bus
|
||||
This is a driver for 320x240 TFT panels, accepting a rgb input
|
||||
streams with 16 bits or 18 bits.
|
||||
|
||||
allOf:
|
||||
- $ref: panel-common.yaml#
|
||||
|
||||
properties:
|
||||
compatible:
|
||||
items:
|
||||
- enum:
|
||||
# ili9341 240*320 Color on stm32f429-disco board
|
||||
- st,sf-tc240t-9370-t
|
||||
- const: ilitek,ili9341
|
||||
|
||||
reg: true
|
||||
|
||||
dc-gpios:
|
||||
maxItems: 1
|
||||
description: Display data/command selection (D/CX) of this DBI panel
|
||||
|
||||
spi-3wire: true
|
||||
|
||||
spi-max-frequency:
|
||||
const: 10000000
|
||||
|
||||
port: true
|
||||
|
||||
vci-supply:
|
||||
description: Analog voltage supply (2.5 .. 3.3V)
|
||||
|
||||
vddi-supply:
|
||||
description: Voltage supply for interface logic (1.65 .. 3.3 V)
|
||||
|
||||
vddi-led-supply:
|
||||
description: Voltage supply for the LED driver (1.65 .. 3.3 V)
|
||||
|
||||
additionalProperties: false
|
||||
|
||||
required:
|
||||
- compatible
|
||||
- reg
|
||||
- dc-gpios
|
||||
- port
|
||||
|
||||
examples:
|
||||
- |+
|
||||
spi {
|
||||
#address-cells = <1>;
|
||||
#size-cells = <0>;
|
||||
panel: display@0 {
|
||||
compatible = "st,sf-tc240t-9370-t",
|
||||
"ilitek,ili9341";
|
||||
reg = <0>;
|
||||
spi-3wire;
|
||||
spi-max-frequency = <10000000>;
|
||||
dc-gpios = <&gpiod 13 0>;
|
||||
port {
|
||||
panel_in: endpoint {
|
||||
remote-endpoint = <&display_out>;
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
...
|
||||
|
|
@ -138,6 +138,8 @@ properties:
|
|||
# Emerging Display Technology Corp. 5.7" VGA TFT LCD panel with
|
||||
# capacitive touch
|
||||
- edt,etmv570g2dhu
|
||||
# E Ink VB3300-KCA
|
||||
- eink,vb3300-kca
|
||||
# Evervision Electronics Co. Ltd. VGG804821 5.0" WVGA TFT LCD Panel
|
||||
- evervision,vgg804821
|
||||
# Foxlink Group 5" WVGA TFT LCD panel
|
||||
|
@ -254,6 +256,8 @@ properties:
|
|||
- powertip,ph800480t013-idf02
|
||||
# QiaoDian XianShi Corporation 4"3 TFT LCD panel
|
||||
- qiaodian,qd43003c0-40
|
||||
# Shenzhen QiShenglong Industrialist Co., Ltd. Gopher 2b 4.3" 480(RGB)x272 TFT LCD panel
|
||||
- qishenglong,gopher2b-lcd
|
||||
# Rocktech Displays Ltd. RK101II01D-CT 10.1" TFT 1280x800
|
||||
- rocktech,rk101ii01d-ct
|
||||
# Rocktech Display Ltd. RK070ER9427 800(RGB)x480 TFT LCD panel
|
||||
|
|
|
@ -339,6 +339,8 @@ patternProperties:
|
|||
description: eGalax_eMPIA Technology Inc
|
||||
"^einfochips,.*":
|
||||
description: Einfochips
|
||||
"^eink,.*":
|
||||
description: E Ink Corporation
|
||||
"^elan,.*":
|
||||
description: Elan Microelectronic Corp.
|
||||
"^element14,.*":
|
||||
|
|
|
@ -159,6 +159,8 @@ KMS Core Structures and Functions
|
|||
.. kernel-doc:: drivers/gpu/drm/drm_mode_config.c
|
||||
:export:
|
||||
|
||||
.. _kms_base_object_abstraction:
|
||||
|
||||
Modeset Base Object Abstraction
|
||||
===============================
|
||||
|
||||
|
|
|
@ -275,7 +275,7 @@ static void ast_set_std_reg(struct ast_private *ast,
|
|||
ast_set_index_reg_mask(ast, AST_IO_SEQ_PORT, 0x01, 0xdf, stdtable->seq[0]);
|
||||
for (i = 1; i < 4; i++) {
|
||||
jreg = stdtable->seq[i];
|
||||
ast_set_index_reg(ast, AST_IO_SEQ_PORT, (i + 1) , jreg);
|
||||
ast_set_index_reg(ast, AST_IO_SEQ_PORT, (i + 1), jreg);
|
||||
}
|
||||
|
||||
/* Set CRTC; except base address and offset */
|
||||
|
@ -498,13 +498,15 @@ static void ast_set_sync_reg(struct ast_private *ast,
|
|||
|
||||
jreg = ast_io_read8(ast, AST_IO_MISC_PORT_READ);
|
||||
jreg &= ~0xC0;
|
||||
if (vbios_mode->enh_table->flags & NVSync) jreg |= 0x80;
|
||||
if (vbios_mode->enh_table->flags & NHSync) jreg |= 0x40;
|
||||
if (vbios_mode->enh_table->flags & NVSync)
|
||||
jreg |= 0x80;
|
||||
if (vbios_mode->enh_table->flags & NHSync)
|
||||
jreg |= 0x40;
|
||||
ast_io_write8(ast, AST_IO_MISC_PORT_WRITE, jreg);
|
||||
}
|
||||
|
||||
static void ast_set_start_address_crt1(struct ast_private *ast,
|
||||
unsigned offset)
|
||||
unsigned int offset)
|
||||
{
|
||||
u32 addr;
|
||||
|
||||
|
@ -1211,6 +1213,7 @@ static int ast_get_modes(struct drm_connector *connector)
|
|||
struct edid *edid;
|
||||
int ret;
|
||||
bool flags = false;
|
||||
|
||||
if (ast->tx_chip_type == AST_TX_DP501) {
|
||||
ast->dp501_maxclk = 0xff;
|
||||
edid = kmalloc(128, GFP_KERNEL);
|
||||
|
@ -1230,8 +1233,8 @@ static int ast_get_modes(struct drm_connector *connector)
|
|||
ret = drm_add_edid_modes(connector, edid);
|
||||
kfree(edid);
|
||||
return ret;
|
||||
} else
|
||||
drm_connector_update_edid_property(&ast_connector->base, NULL);
|
||||
}
|
||||
drm_connector_update_edid_property(&ast_connector->base, NULL);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -1271,19 +1274,24 @@ static enum drm_mode_status ast_mode_valid(struct drm_connector *connector,
|
|||
}
|
||||
switch (mode->hdisplay) {
|
||||
case 640:
|
||||
if (mode->vdisplay == 480) flags = MODE_OK;
|
||||
if (mode->vdisplay == 480)
|
||||
flags = MODE_OK;
|
||||
break;
|
||||
case 800:
|
||||
if (mode->vdisplay == 600) flags = MODE_OK;
|
||||
if (mode->vdisplay == 600)
|
||||
flags = MODE_OK;
|
||||
break;
|
||||
case 1024:
|
||||
if (mode->vdisplay == 768) flags = MODE_OK;
|
||||
if (mode->vdisplay == 768)
|
||||
flags = MODE_OK;
|
||||
break;
|
||||
case 1280:
|
||||
if (mode->vdisplay == 1024) flags = MODE_OK;
|
||||
if (mode->vdisplay == 1024)
|
||||
flags = MODE_OK;
|
||||
break;
|
||||
case 1600:
|
||||
if (mode->vdisplay == 1200) flags = MODE_OK;
|
||||
if (mode->vdisplay == 1200)
|
||||
flags = MODE_OK;
|
||||
break;
|
||||
default:
|
||||
return flags;
|
||||
|
@ -1307,6 +1315,7 @@ static enum drm_connector_status ast_connector_detect(struct drm_connector
|
|||
static void ast_connector_destroy(struct drm_connector *connector)
|
||||
{
|
||||
struct ast_connector *ast_connector = to_ast_connector(connector);
|
||||
|
||||
ast_i2c_destroy(ast_connector->i2c);
|
||||
drm_connector_cleanup(connector);
|
||||
}
|
||||
|
|
|
@ -307,6 +307,9 @@ static int __maybe_unused ti_sn65dsi86_resume(struct device *dev)
|
|||
return ret;
|
||||
}
|
||||
|
||||
/* td2: min 100 us after regulators before enabling the GPIO */
|
||||
usleep_range(100, 110);
|
||||
|
||||
gpiod_set_value(pdata->enable_gpio, 1);
|
||||
|
||||
/*
|
||||
|
@ -766,10 +769,6 @@ static void ti_sn_bridge_disable(struct drm_bridge *bridge)
|
|||
|
||||
/* disable video stream */
|
||||
regmap_update_bits(pdata->regmap, SN_ENH_FRAME_REG, VSTREAM_ENABLE, 0);
|
||||
/* semi auto link training mode OFF */
|
||||
regmap_write(pdata->regmap, SN_ML_TX_MODE_REG, 0);
|
||||
/* disable DP PLL */
|
||||
regmap_write(pdata->regmap, SN_PLL_ENABLE_REG, 0);
|
||||
}
|
||||
|
||||
static void ti_sn_bridge_set_dsi_rate(struct ti_sn65dsi86 *pdata)
|
||||
|
@ -1100,12 +1099,22 @@ static void ti_sn_bridge_pre_enable(struct drm_bridge *bridge)
|
|||
|
||||
if (!pdata->refclk)
|
||||
ti_sn65dsi86_enable_comms(pdata);
|
||||
|
||||
/* td7: min 100 us after enable before DSI data */
|
||||
usleep_range(100, 110);
|
||||
}
|
||||
|
||||
static void ti_sn_bridge_post_disable(struct drm_bridge *bridge)
|
||||
{
|
||||
struct ti_sn65dsi86 *pdata = bridge_to_ti_sn65dsi86(bridge);
|
||||
|
||||
/* semi auto link training mode OFF */
|
||||
regmap_write(pdata->regmap, SN_ML_TX_MODE_REG, 0);
|
||||
/* Num lanes to 0 as per power sequencing in data sheet */
|
||||
regmap_update_bits(pdata->regmap, SN_SSC_CONFIG_REG, DP_NUM_LANES_MASK, 0);
|
||||
/* disable DP PLL */
|
||||
regmap_write(pdata->regmap, SN_PLL_ENABLE_REG, 0);
|
||||
|
||||
if (!pdata->refclk)
|
||||
ti_sn65dsi86_disable_comms(pdata);
|
||||
|
||||
|
|
|
@ -78,7 +78,7 @@
|
|||
*
|
||||
* Drivers that are susceptible to being removed by other drivers, such as
|
||||
* generic EFI or VESA drivers, have to register themselves as owners of their
|
||||
* given framebuffer memory. Ownership of the framebuffer memory is achived
|
||||
* given framebuffer memory. Ownership of the framebuffer memory is achieved
|
||||
* by calling devm_aperture_acquire_from_firmware(). On success, the driver
|
||||
* is the owner of the framebuffer range. The function fails if the
|
||||
* framebuffer is already by another driver. See below for an example.
|
||||
|
|
|
@ -723,7 +723,7 @@ static void drm_atomic_plane_print_state(struct drm_printer *p,
|
|||
* clocks, scaler units, bandwidth and fifo limits shared among a group of
|
||||
* planes or CRTCs, and so on) it makes sense to model these as independent
|
||||
* objects. Drivers then need to do similar state tracking and commit ordering for
|
||||
* such private (since not exposed to userpace) objects as the atomic core and
|
||||
* such private (since not exposed to userspace) objects as the atomic core and
|
||||
* helpers already provide for connectors, planes and CRTCs.
|
||||
*
|
||||
* To make this easier on drivers the atomic core provides some support to track
|
||||
|
|
|
@ -634,7 +634,7 @@ drm_atomic_helper_check_modeset(struct drm_device *dev,
|
|||
* connectors and a NULL mode.
|
||||
*
|
||||
* The other way around is true as well. enable != 0
|
||||
* iff connectors are attached and a mode is set.
|
||||
* implies that connectors are attached and a mode is set.
|
||||
*/
|
||||
new_crtc_state->mode_changed = true;
|
||||
new_crtc_state->connectors_changed = true;
|
||||
|
@ -1686,7 +1686,7 @@ static void commit_work(struct work_struct *work)
|
|||
}
|
||||
|
||||
/**
|
||||
* drm_atomic_helper_async_check - check if state can be commited asynchronously
|
||||
* drm_atomic_helper_async_check - check if state can be committed asynchronously
|
||||
* @dev: DRM device
|
||||
* @state: the driver state object
|
||||
*
|
||||
|
@ -1695,7 +1695,7 @@ static void commit_work(struct work_struct *work)
|
|||
* but just do in-place changes on the current state.
|
||||
*
|
||||
* It will return 0 if the commit can happen in an asynchronous fashion or error
|
||||
* if not. Note that error just mean it can't be commited asynchronously, if it
|
||||
* if not. Note that error just mean it can't be committed asynchronously, if it
|
||||
* fails the commit should be treated like a normal synchronous commit.
|
||||
*/
|
||||
int drm_atomic_helper_async_check(struct drm_device *dev,
|
||||
|
@ -2583,7 +2583,7 @@ EXPORT_SYMBOL(drm_atomic_helper_commit_planes);
|
|||
*
|
||||
* This function can only be savely used when planes are not allowed to move
|
||||
* between different CRTCs because this function doesn't handle inter-CRTC
|
||||
* depencies. Callers need to ensure that either no such depencies exist,
|
||||
* dependencies. Callers need to ensure that either no such dependencies exist,
|
||||
* resolve them through ordering of commit calls or through some other means.
|
||||
*/
|
||||
void
|
||||
|
@ -2720,7 +2720,7 @@ EXPORT_SYMBOL(drm_atomic_helper_cleanup_planes);
|
|||
/**
|
||||
* drm_atomic_helper_swap_state - store atomic state into current sw state
|
||||
* @state: atomic state
|
||||
* @stall: stall for preceeding commits
|
||||
* @stall: stall for preceding commits
|
||||
*
|
||||
* This function stores the atomic state into the current state pointers in all
|
||||
* driver objects. It should be called after all failing steps have been done
|
||||
|
|
|
@ -48,7 +48,7 @@
|
|||
* in all its forms: The monster ATOMIC IOCTL itself, code for GET_PROPERTY and
|
||||
* SET_PROPERTY IOCTLs. Plus interface functions for compatibility helpers and
|
||||
* drivers which have special needs to construct their own atomic updates, e.g.
|
||||
* for load detect or similiar.
|
||||
* for load detect or similar.
|
||||
*/
|
||||
|
||||
/**
|
||||
|
@ -753,7 +753,7 @@ static int drm_atomic_connector_set_property(struct drm_connector *connector,
|
|||
* restore the state it wants on VT switch. So if the userspace
|
||||
* tries to change the link_status from GOOD to BAD, driver
|
||||
* silently rejects it and returns a 0. This prevents userspace
|
||||
* from accidently breaking the display when it restores the
|
||||
* from accidentally breaking the display when it restores the
|
||||
* state.
|
||||
*/
|
||||
if (state->link_status != DRM_LINK_STATUS_GOOD)
|
||||
|
@ -1064,7 +1064,7 @@ int drm_atomic_set_property(struct drm_atomic_state *state,
|
|||
* DOC: explicit fencing properties
|
||||
*
|
||||
* Explicit fencing allows userspace to control the buffer synchronization
|
||||
* between devices. A Fence or a group of fences are transfered to/from
|
||||
* between devices. A Fence or a group of fences are transferred to/from
|
||||
* userspace using Sync File fds and there are two DRM properties for that.
|
||||
* IN_FENCE_FD on each DRM Plane to send fences to the kernel and
|
||||
* OUT_FENCE_PTR on each DRM CRTC to receive fences from the kernel.
|
||||
|
|
|
@ -52,7 +52,7 @@
|
|||
*
|
||||
* In addition only one &drm_master can be the current master for a &drm_device.
|
||||
* It can be switched through the DROP_MASTER and SET_MASTER IOCTL, or
|
||||
* implicitly through closing/openeing the primary device node. See also
|
||||
* implicitly through closing/opening the primary device node. See also
|
||||
* drm_is_current_master().
|
||||
*
|
||||
* Clients can authenticate against the current master (if it matches their own)
|
||||
|
|
|
@ -982,7 +982,7 @@ drm_atomic_bridge_propagate_bus_flags(struct drm_bridge *bridge,
|
|||
bridge_state->output_bus_cfg.flags = output_flags;
|
||||
|
||||
/*
|
||||
* Propage the output flags to the input end of the bridge. Again, it's
|
||||
* Propagate the output flags to the input end of the bridge. Again, it's
|
||||
* not necessarily what all bridges want, but that's what most of them
|
||||
* do, and by doing that by default we avoid forcing drivers to
|
||||
* duplicate the "dummy propagation" logic.
|
||||
|
|
|
@ -1502,7 +1502,7 @@ int drm_legacy_freebufs(struct drm_device *dev, void *data,
|
|||
*
|
||||
* Maps the AGP, SG or PCI buffer region with vm_mmap(), and copies information
|
||||
* about each buffer into user space. For PCI buffers, it calls vm_mmap() with
|
||||
* offset equal to 0, which drm_mmap() interpretes as PCI buffers and calls
|
||||
* offset equal to 0, which drm_mmap() interprets as PCI buffers and calls
|
||||
* drm_mmap_dma().
|
||||
*/
|
||||
int __drm_legacy_mapbufs(struct drm_device *dev, void *data, int *p,
|
||||
|
|
|
@ -170,7 +170,7 @@ drm_clflush_virt_range(void *addr, unsigned long length)
|
|||
for (; addr < end; addr += size)
|
||||
clflushopt(addr);
|
||||
clflushopt(end - 1); /* force serialisation */
|
||||
mb(); /*Ensure that evry data cache line entry is flushed*/
|
||||
mb(); /*Ensure that every data cache line entry is flushed*/
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
|
@ -116,7 +116,7 @@ int drm_atomic_helper_dirtyfb(struct drm_framebuffer *fb,
|
|||
int ret = 0;
|
||||
|
||||
/*
|
||||
* When called from ioctl, we are interruptable, but not when called
|
||||
* When called from ioctl, we are interruptible, but not when called
|
||||
* internally (ie. defio worker)
|
||||
*/
|
||||
drm_modeset_acquire_init(&ctx,
|
||||
|
|
|
@ -772,7 +772,7 @@ int drm_dp_downstream_max_tmds_clock(const u8 dpcd[DP_RECEIVER_CAP_SIZE],
|
|||
* It's left up to the driver to check the
|
||||
* DP dual mode adapter's max TMDS clock.
|
||||
*
|
||||
* Unfortunatley it looks like branch devices
|
||||
* Unfortunately it looks like branch devices
|
||||
* may not fordward that the DP dual mode i2c
|
||||
* access so we just usually get i2c nak :(
|
||||
*/
|
||||
|
@ -1365,7 +1365,7 @@ static int drm_dp_i2c_msg_duration(const struct drm_dp_aux_msg *msg,
|
|||
}
|
||||
|
||||
/*
|
||||
* Deterine how many retries should be attempted to successfully transfer
|
||||
* Determine how many retries should be attempted to successfully transfer
|
||||
* the specified message, based on the estimated durations of the
|
||||
* i2c and AUX transfers.
|
||||
*/
|
||||
|
@ -1418,7 +1418,7 @@ static int drm_dp_i2c_do_msg(struct drm_dp_aux *aux, struct drm_dp_aux_msg *msg)
|
|||
/*
|
||||
* While timeouts can be errors, they're usually normal
|
||||
* behavior (for instance, when a driver tries to
|
||||
* communicate with a non-existant DisplayPort device).
|
||||
* communicate with a non-existent DisplayPort device).
|
||||
* Avoid spamming the kernel log with timeout errors.
|
||||
*/
|
||||
if (ret == -ETIMEDOUT)
|
||||
|
@ -3229,10 +3229,12 @@ int drm_edp_backlight_enable(struct drm_dp_aux *aux, const struct drm_edp_backli
|
|||
new_dpcd_buf &= ~DP_EDP_BACKLIGHT_CONTROL_MODE_MASK;
|
||||
new_dpcd_buf |= DP_EDP_BACKLIGHT_CONTROL_MODE_DPCD;
|
||||
|
||||
ret = drm_dp_dpcd_writeb(aux, DP_EDP_PWMGEN_BIT_COUNT, bl->pwmgen_bit_count);
|
||||
if (ret != 1)
|
||||
drm_dbg_kms(aux->drm_dev, "%s: Failed to write aux pwmgen bit count: %d\n",
|
||||
aux->name, ret);
|
||||
if (bl->pwmgen_bit_count) {
|
||||
ret = drm_dp_dpcd_writeb(aux, DP_EDP_PWMGEN_BIT_COUNT, bl->pwmgen_bit_count);
|
||||
if (ret != 1)
|
||||
drm_dbg_kms(aux->drm_dev, "%s: Failed to write aux pwmgen bit count: %d\n",
|
||||
aux->name, ret);
|
||||
}
|
||||
}
|
||||
|
||||
if (bl->pwm_freq_pre_divider) {
|
||||
|
@ -3327,7 +3329,7 @@ drm_edp_backlight_probe_max(struct drm_dp_aux *aux, struct drm_edp_backlight_inf
|
|||
fxp = DIV_ROUND_CLOSEST(1000 * DP_EDP_BACKLIGHT_FREQ_BASE_KHZ, driver_pwm_freq_hz);
|
||||
|
||||
/* Use highest possible value of Pn for more granularity of brightness adjustment while
|
||||
* satifying the conditions below.
|
||||
* satisfying the conditions below.
|
||||
* - Pn is in the range of Pn_min and Pn_max
|
||||
* - F is in the range of 1 and 255
|
||||
* - FxP is within 25% of desired value.
|
||||
|
|
|
@ -249,7 +249,7 @@ void drm_minor_release(struct drm_minor *minor)
|
|||
* Finally when everything is up and running and ready for userspace the device
|
||||
* instance can be published using drm_dev_register().
|
||||
*
|
||||
* There is also deprecated support for initalizing device instances using
|
||||
* There is also deprecated support for initializing device instances using
|
||||
* bus-specific helpers and the &drm_driver.load callback. But due to
|
||||
* backwards-compatibility needs the device instance have to be published too
|
||||
* early, which requires unpretty global locking to make safe and is therefore
|
||||
|
@ -379,7 +379,7 @@ void drm_minor_release(struct drm_minor *minor)
|
|||
* shortcoming however, drm_dev_unplug() marks the drm_device as unplugged before
|
||||
* drm_atomic_helper_shutdown() is called. This means that if the disable code
|
||||
* paths are protected, they will not run on regular driver module unload,
|
||||
* possibily leaving the hardware enabled.
|
||||
* possibly leaving the hardware enabled.
|
||||
*/
|
||||
|
||||
/**
|
||||
|
|
|
@ -98,7 +98,7 @@ void drm_dsc_pps_payload_pack(struct drm_dsc_picture_parameter_set *pps_payload,
|
|||
{
|
||||
int i;
|
||||
|
||||
/* Protect against someone accidently changing struct size */
|
||||
/* Protect against someone accidentally changing struct size */
|
||||
BUILD_BUG_ON(sizeof(*pps_payload) !=
|
||||
DP_SDP_PPS_HEADER_PAYLOAD_BYTES_MINUS_1 + 1);
|
||||
|
||||
|
|
|
@ -1919,7 +1919,7 @@ EXPORT_SYMBOL(drm_add_override_edid_modes);
|
|||
* level, drivers must make all reasonable efforts to expose it as an I2C
|
||||
* adapter and use drm_get_edid() instead of abusing this function.
|
||||
*
|
||||
* The EDID may be overridden using debugfs override_edid or firmare EDID
|
||||
* The EDID may be overridden using debugfs override_edid or firmware EDID
|
||||
* (drm_load_edid_firmware() and drm.edid_firmware parameter), in this priority
|
||||
* order. Having either of them bypasses actual EDID reads.
|
||||
*
|
||||
|
@ -5906,7 +5906,7 @@ drm_hdmi_vendor_infoframe_from_display_mode(struct hdmi_vendor_infoframe *frame,
|
|||
* (ie.vic==0 and s3d_struct==0) we will still send it if we
|
||||
* know that the sink can handle it. This is based on a
|
||||
* suggestion in HDMI 2.0 Appendix F. Apparently some sinks
|
||||
* have trouble realizing that they shuld switch from 3D to 2D
|
||||
* have trouble realizing that they should switch from 3D to 2D
|
||||
* mode if the source simply stops sending the infoframe when
|
||||
* it wants to switch from 3D to 2D.
|
||||
*/
|
||||
|
|
|
@ -565,7 +565,7 @@ struct fb_info *drm_fb_helper_alloc_fbi(struct drm_fb_helper *fb_helper)
|
|||
goto err_release;
|
||||
|
||||
/*
|
||||
* TODO: We really should be smarter here and alloc an apperture
|
||||
* TODO: We really should be smarter here and alloc an aperture
|
||||
* for each IORESOURCE_MEM resource helper->dev->dev has and also
|
||||
* init the ranges of the appertures based on the resources.
|
||||
* Note some drivers currently count on there being only 1 empty
|
||||
|
|
|
@ -405,7 +405,7 @@ static int drm_open_helper(struct file *filp, struct drm_minor *minor)
|
|||
*
|
||||
* RETURNS:
|
||||
*
|
||||
* 0 on success or negative errno value on falure.
|
||||
* 0 on success or negative errno value on failure.
|
||||
*/
|
||||
int drm_open(struct inode *inode, struct file *filp)
|
||||
{
|
||||
|
@ -548,7 +548,7 @@ EXPORT_SYMBOL(drm_release_noglobal);
|
|||
* @offset: offset to read
|
||||
*
|
||||
* This function must be used by drivers as their &file_operations.read
|
||||
* method iff they use DRM events for asynchronous signalling to userspace.
|
||||
* method if they use DRM events for asynchronous signalling to userspace.
|
||||
* Since events are used by the KMS API for vblank and page flip completion this
|
||||
* means all modern display drivers must use it.
|
||||
*
|
||||
|
@ -641,7 +641,7 @@ EXPORT_SYMBOL(drm_read);
|
|||
* @wait: poll waiter table
|
||||
*
|
||||
* This function must be used by drivers as their &file_operations.read method
|
||||
* iff they use DRM events for asynchronous signalling to userspace. Since
|
||||
* if they use DRM events for asynchronous signalling to userspace. Since
|
||||
* events are used by the KMS API for vblank and page flip completion this means
|
||||
* all modern display drivers must use it.
|
||||
*
|
||||
|
|
|
@ -412,7 +412,7 @@ EXPORT_SYMBOL(drm_fb_blit_rect_dstclip);
|
|||
* of the display and the framebuffer mismatch, the copy function will
|
||||
* attempt to convert between them.
|
||||
*
|
||||
* See drm_fb_blit_rect_dstclip() for more inforamtion.
|
||||
* See drm_fb_blit_rect_dstclip() for more information.
|
||||
*
|
||||
* Returns:
|
||||
* 0 on success, or a negative error code otherwise.
|
||||
|
|
|
@ -1110,7 +1110,7 @@ void drm_framebuffer_remove(struct drm_framebuffer *fb)
|
|||
|
||||
/*
|
||||
* drm ABI mandates that we remove any deleted framebuffers from active
|
||||
* useage. But since most sane clients only remove framebuffers they no
|
||||
* usage. But since most sane clients only remove framebuffers they no
|
||||
* longer need, try to optimize this away.
|
||||
*
|
||||
* Since we're holding a reference ourselves, observing a refcount of 1
|
||||
|
|
|
@ -901,7 +901,7 @@ err:
|
|||
}
|
||||
|
||||
/**
|
||||
* drm_gem_open - initalizes GEM file-private structures at devnode open time
|
||||
* drm_gem_open - initializes GEM file-private structures at devnode open time
|
||||
* @dev: drm_device which is being opened by userspace
|
||||
* @file_private: drm file-private structure to set up
|
||||
*
|
||||
|
@ -936,7 +936,7 @@ drm_gem_release(struct drm_device *dev, struct drm_file *file_private)
|
|||
* drm_gem_object_release - release GEM buffer object resources
|
||||
* @obj: GEM buffer object
|
||||
*
|
||||
* This releases any structures and resources used by @obj and is the invers of
|
||||
* This releases any structures and resources used by @obj and is the inverse of
|
||||
* drm_gem_object_init().
|
||||
*/
|
||||
void
|
||||
|
|
|
@ -52,7 +52,7 @@
|
|||
*
|
||||
* The helpers for shadow-buffered planes establish and release mappings,
|
||||
* and provide struct drm_shadow_plane_state, which stores the plane's mapping
|
||||
* for commit-tail functons.
|
||||
* for commit-tail functions.
|
||||
*
|
||||
* Shadow-buffered planes can easily be enabled by using the provided macros
|
||||
* %DRM_GEM_SHADOW_PLANE_FUNCS and %DRM_GEM_SHADOW_PLANE_HELPER_FUNCS.
|
||||
|
@ -330,10 +330,7 @@ int drm_gem_prepare_shadow_fb(struct drm_plane *plane, struct drm_plane_state *p
|
|||
{
|
||||
struct drm_shadow_plane_state *shadow_plane_state = to_drm_shadow_plane_state(plane_state);
|
||||
struct drm_framebuffer *fb = plane_state->fb;
|
||||
struct drm_gem_object *obj;
|
||||
struct dma_buf_map map;
|
||||
int ret;
|
||||
size_t i;
|
||||
|
||||
if (!fb)
|
||||
return 0;
|
||||
|
@ -342,27 +339,7 @@ int drm_gem_prepare_shadow_fb(struct drm_plane *plane, struct drm_plane_state *p
|
|||
if (ret)
|
||||
return ret;
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(shadow_plane_state->map); ++i) {
|
||||
obj = drm_gem_fb_get_obj(fb, i);
|
||||
if (!obj)
|
||||
continue;
|
||||
ret = drm_gem_vmap(obj, &map);
|
||||
if (ret)
|
||||
goto err_drm_gem_vunmap;
|
||||
shadow_plane_state->map[i] = map;
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
err_drm_gem_vunmap:
|
||||
while (i) {
|
||||
--i;
|
||||
obj = drm_gem_fb_get_obj(fb, i);
|
||||
if (!obj)
|
||||
continue;
|
||||
drm_gem_vunmap(obj, &shadow_plane_state->map[i]);
|
||||
}
|
||||
return ret;
|
||||
return drm_gem_fb_vmap(fb, shadow_plane_state->map);
|
||||
}
|
||||
EXPORT_SYMBOL(drm_gem_prepare_shadow_fb);
|
||||
|
||||
|
@ -374,25 +351,17 @@ EXPORT_SYMBOL(drm_gem_prepare_shadow_fb);
|
|||
* This function implements struct &drm_plane_helper_funcs.cleanup_fb.
|
||||
* This function unmaps all buffer objects of the plane's framebuffer.
|
||||
*
|
||||
* See drm_gem_prepare_shadow_fb() for more inforamtion.
|
||||
* See drm_gem_prepare_shadow_fb() for more information.
|
||||
*/
|
||||
void drm_gem_cleanup_shadow_fb(struct drm_plane *plane, struct drm_plane_state *plane_state)
|
||||
{
|
||||
struct drm_shadow_plane_state *shadow_plane_state = to_drm_shadow_plane_state(plane_state);
|
||||
struct drm_framebuffer *fb = plane_state->fb;
|
||||
size_t i = ARRAY_SIZE(shadow_plane_state->map);
|
||||
struct drm_gem_object *obj;
|
||||
|
||||
if (!fb)
|
||||
return;
|
||||
|
||||
while (i) {
|
||||
--i;
|
||||
obj = drm_gem_fb_get_obj(fb, i);
|
||||
if (!obj)
|
||||
continue;
|
||||
drm_gem_vunmap(obj, &shadow_plane_state->map[i]);
|
||||
}
|
||||
drm_gem_fb_vunmap(fb, shadow_plane_state->map);
|
||||
}
|
||||
EXPORT_SYMBOL(drm_gem_cleanup_shadow_fb);
|
||||
|
||||
|
|
|
@ -15,6 +15,8 @@
|
|||
#include <drm/drm_gem_framebuffer_helper.h>
|
||||
#include <drm/drm_modeset_helper.h>
|
||||
|
||||
#include "drm_internal.h"
|
||||
|
||||
#define AFBC_HEADER_SIZE 16
|
||||
#define AFBC_TH_LAYOUT_ALIGNMENT 8
|
||||
#define AFBC_HDR_ALIGN 64
|
||||
|
@ -48,7 +50,7 @@
|
|||
struct drm_gem_object *drm_gem_fb_get_obj(struct drm_framebuffer *fb,
|
||||
unsigned int plane)
|
||||
{
|
||||
if (plane >= 4)
|
||||
if (plane >= ARRAY_SIZE(fb->obj))
|
||||
return NULL;
|
||||
|
||||
return fb->obj[plane];
|
||||
|
@ -62,7 +64,8 @@ drm_gem_fb_init(struct drm_device *dev,
|
|||
struct drm_gem_object **obj, unsigned int num_planes,
|
||||
const struct drm_framebuffer_funcs *funcs)
|
||||
{
|
||||
int ret, i;
|
||||
unsigned int i;
|
||||
int ret;
|
||||
|
||||
drm_helper_mode_fill_fb_struct(dev, fb, mode_cmd);
|
||||
|
||||
|
@ -86,9 +89,9 @@ drm_gem_fb_init(struct drm_device *dev,
|
|||
*/
|
||||
void drm_gem_fb_destroy(struct drm_framebuffer *fb)
|
||||
{
|
||||
int i;
|
||||
size_t i;
|
||||
|
||||
for (i = 0; i < 4; i++)
|
||||
for (i = 0; i < ARRAY_SIZE(fb->obj); i++)
|
||||
drm_gem_object_put(fb->obj[i]);
|
||||
|
||||
drm_framebuffer_cleanup(fb);
|
||||
|
@ -145,8 +148,9 @@ int drm_gem_fb_init_with_funcs(struct drm_device *dev,
|
|||
const struct drm_framebuffer_funcs *funcs)
|
||||
{
|
||||
const struct drm_format_info *info;
|
||||
struct drm_gem_object *objs[4];
|
||||
int ret, i;
|
||||
struct drm_gem_object *objs[DRM_FORMAT_MAX_PLANES];
|
||||
unsigned int i;
|
||||
int ret;
|
||||
|
||||
info = drm_get_format_info(dev, mode_cmd);
|
||||
if (!info) {
|
||||
|
@ -187,9 +191,10 @@ int drm_gem_fb_init_with_funcs(struct drm_device *dev,
|
|||
return 0;
|
||||
|
||||
err_gem_object_put:
|
||||
for (i--; i >= 0; i--)
|
||||
while (i > 0) {
|
||||
--i;
|
||||
drm_gem_object_put(objs[i]);
|
||||
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(drm_gem_fb_init_with_funcs);
|
||||
|
@ -306,6 +311,80 @@ drm_gem_fb_create_with_dirty(struct drm_device *dev, struct drm_file *file,
|
|||
}
|
||||
EXPORT_SYMBOL_GPL(drm_gem_fb_create_with_dirty);
|
||||
|
||||
/**
|
||||
* drm_gem_fb_vmap - maps all framebuffer BOs into kernel address space
|
||||
* @fb: the framebuffer
|
||||
* @map: returns the mapping's address for each BO
|
||||
*
|
||||
* This function maps all buffer objects of the given framebuffer into
|
||||
* kernel address space and stores them in struct dma_buf_map. If the
|
||||
* mapping operation fails for one of the BOs, the function unmaps the
|
||||
* already established mappings automatically.
|
||||
*
|
||||
* See drm_gem_fb_vunmap() for unmapping.
|
||||
*
|
||||
* Returns:
|
||||
* 0 on success, or a negative errno code otherwise.
|
||||
*/
|
||||
int drm_gem_fb_vmap(struct drm_framebuffer *fb,
|
||||
struct dma_buf_map map[static DRM_FORMAT_MAX_PLANES])
|
||||
{
|
||||
struct drm_gem_object *obj;
|
||||
unsigned int i;
|
||||
int ret;
|
||||
|
||||
for (i = 0; i < DRM_FORMAT_MAX_PLANES; ++i) {
|
||||
obj = drm_gem_fb_get_obj(fb, i);
|
||||
if (!obj) {
|
||||
dma_buf_map_clear(&map[i]);
|
||||
continue;
|
||||
}
|
||||
ret = drm_gem_vmap(obj, &map[i]);
|
||||
if (ret)
|
||||
goto err_drm_gem_vunmap;
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
err_drm_gem_vunmap:
|
||||
while (i) {
|
||||
--i;
|
||||
obj = drm_gem_fb_get_obj(fb, i);
|
||||
if (!obj)
|
||||
continue;
|
||||
drm_gem_vunmap(obj, &map[i]);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
EXPORT_SYMBOL(drm_gem_fb_vmap);
|
||||
|
||||
/**
|
||||
* drm_gem_fb_vunmap - unmaps framebuffer BOs from kernel address space
|
||||
* @fb: the framebuffer
|
||||
* @map: mapping addresses as returned by drm_gem_fb_vmap()
|
||||
*
|
||||
* This function unmaps all buffer objects of the given framebuffer.
|
||||
*
|
||||
* See drm_gem_fb_vmap() for more information.
|
||||
*/
|
||||
void drm_gem_fb_vunmap(struct drm_framebuffer *fb,
|
||||
struct dma_buf_map map[static DRM_FORMAT_MAX_PLANES])
|
||||
{
|
||||
unsigned int i = DRM_FORMAT_MAX_PLANES;
|
||||
struct drm_gem_object *obj;
|
||||
|
||||
while (i) {
|
||||
--i;
|
||||
obj = drm_gem_fb_get_obj(fb, i);
|
||||
if (!obj)
|
||||
continue;
|
||||
if (dma_buf_map_is_null(&map[i]))
|
||||
continue;
|
||||
drm_gem_vunmap(obj, &map[i]);
|
||||
}
|
||||
}
|
||||
EXPORT_SYMBOL(drm_gem_fb_vunmap);
|
||||
|
||||
/**
|
||||
* drm_gem_fb_begin_cpu_access - prepares GEM buffer objects for CPU access
|
||||
* @fb: the framebuffer
|
||||
|
|
|
@ -368,7 +368,7 @@ static void drm_gem_shmem_vunmap_locked(struct drm_gem_shmem_object *shmem,
|
|||
}
|
||||
|
||||
/*
|
||||
* drm_gem_shmem_vunmap - Unmap a virtual mapping fo a shmem GEM object
|
||||
* drm_gem_shmem_vunmap - Unmap a virtual mapping for a shmem GEM object
|
||||
* @shmem: shmem GEM object
|
||||
* @map: Kernel virtual address where the SHMEM GEM object was mapped
|
||||
*
|
||||
|
|
|
@ -96,7 +96,7 @@ static const struct drm_gem_object_funcs drm_gem_vram_object_funcs;
|
|||
* memory region. Call drm_gem_vram_offset() to retrieve this value. Typically
|
||||
* it's used to program the hardware's scanout engine for framebuffers, set
|
||||
* the cursor overlay's image for a mouse cursor, or use it as input to the
|
||||
* hardware's draing engine.
|
||||
* hardware's drawing engine.
|
||||
*
|
||||
* To access a buffer object's memory from the DRM driver, call
|
||||
* drm_gem_vram_vmap(). It maps the buffer into kernel address
|
||||
|
|
|
@ -280,7 +280,7 @@ exit:
|
|||
* https://www.digital-cp.com/sites/default/files/specifications/HDCP%20on%20HDMI%20Specification%20Rev2_2_Final1.pdf
|
||||
*
|
||||
* Returns:
|
||||
* Count of the revoked KSVs or -ve error number incase of the failure.
|
||||
* Count of the revoked KSVs or -ve error number in case of the failure.
|
||||
*/
|
||||
int drm_hdcp_check_ksvs_revoked(struct drm_device *drm_dev, u8 *ksvs,
|
||||
u32 ksv_count)
|
||||
|
|
|
@ -426,7 +426,7 @@ done:
|
|||
}
|
||||
|
||||
/**
|
||||
* drm_noop - DRM no-op ioctl implemntation
|
||||
* drm_noop - DRM no-op ioctl implementation
|
||||
* @dev: DRM device for the ioctl
|
||||
* @data: data pointer for the ioctl
|
||||
* @file_priv: DRM file for the ioctl call
|
||||
|
@ -446,7 +446,7 @@ int drm_noop(struct drm_device *dev, void *data,
|
|||
EXPORT_SYMBOL(drm_noop);
|
||||
|
||||
/**
|
||||
* drm_invalid_op - DRM invalid ioctl implemntation
|
||||
* drm_invalid_op - DRM invalid ioctl implementation
|
||||
* @dev: DRM device for the ioctl
|
||||
* @data: data pointer for the ioctl
|
||||
* @file_priv: DRM file for the ioctl call
|
||||
|
|
|
@ -72,7 +72,7 @@
|
|||
* The DRM core provides very simple support helpers to enable IRQ handling on a
|
||||
* device through the drm_irq_install() and drm_irq_uninstall() functions. This
|
||||
* only supports devices with a single interrupt on the main device stored in
|
||||
* &drm_device.dev and set as the device paramter in drm_dev_alloc().
|
||||
* &drm_device.dev and set as the device parameter in drm_dev_alloc().
|
||||
*
|
||||
* These IRQ helpers are strictly optional. Since these helpers don't automatically
|
||||
* clean up the requested interrupt like e.g. devm_request_irq() they're not really
|
||||
|
|
|
@ -71,14 +71,6 @@
|
|||
|
||||
static uint64_t drm_lease_idr_object;
|
||||
|
||||
/**
|
||||
* drm_lease_owner - return ancestor owner drm_master
|
||||
* @master: drm_master somewhere within tree of lessees and lessors
|
||||
*
|
||||
* RETURN:
|
||||
*
|
||||
* drm_master at the top of the tree (i.e, with lessor NULL
|
||||
*/
|
||||
struct drm_master *drm_lease_owner(struct drm_master *master)
|
||||
{
|
||||
while (master->lessor != NULL)
|
||||
|
@ -86,16 +78,6 @@ struct drm_master *drm_lease_owner(struct drm_master *master)
|
|||
return master;
|
||||
}
|
||||
|
||||
/**
|
||||
* _drm_find_lessee - find lessee by id (idr_mutex held)
|
||||
* @master: drm_master of lessor
|
||||
* @lessee_id: id
|
||||
*
|
||||
* RETURN:
|
||||
*
|
||||
* drm_master of the lessee if valid, NULL otherwise
|
||||
*/
|
||||
|
||||
static struct drm_master*
|
||||
_drm_find_lessee(struct drm_master *master, int lessee_id)
|
||||
{
|
||||
|
@ -103,17 +85,6 @@ _drm_find_lessee(struct drm_master *master, int lessee_id)
|
|||
return idr_find(&drm_lease_owner(master)->lessee_idr, lessee_id);
|
||||
}
|
||||
|
||||
/**
|
||||
* _drm_lease_held_master - check to see if an object is leased (or owned) by master (idr_mutex held)
|
||||
* @master: the master to check the lease status of
|
||||
* @id: the id to check
|
||||
*
|
||||
* Checks if the specified master holds a lease on the object. Return
|
||||
* value:
|
||||
*
|
||||
* true 'master' holds a lease on (or owns) the object
|
||||
* false 'master' does not hold a lease.
|
||||
*/
|
||||
static int _drm_lease_held_master(struct drm_master *master, int id)
|
||||
{
|
||||
lockdep_assert_held(&master->dev->mode_config.idr_mutex);
|
||||
|
@ -122,17 +93,7 @@ static int _drm_lease_held_master(struct drm_master *master, int id)
|
|||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* _drm_has_leased - check to see if an object has been leased (idr_mutex held)
|
||||
* @master: the master to check the lease status of
|
||||
* @id: the id to check
|
||||
*
|
||||
* Checks if any lessee of 'master' holds a lease on 'id'. Return
|
||||
* value:
|
||||
*
|
||||
* true Some lessee holds a lease on the object.
|
||||
* false No lessee has a lease on the object.
|
||||
*/
|
||||
/* Checks if the given object has been leased to some lessee of drm_master */
|
||||
static bool _drm_has_leased(struct drm_master *master, int id)
|
||||
{
|
||||
struct drm_master *lessee;
|
||||
|
@ -144,17 +105,7 @@ static bool _drm_has_leased(struct drm_master *master, int id)
|
|||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* _drm_lease_held - check drm_mode_object lease status (idr_mutex held)
|
||||
* @file_priv: the master drm_file
|
||||
* @id: the object id
|
||||
*
|
||||
* Checks if the specified master holds a lease on the object. Return
|
||||
* value:
|
||||
*
|
||||
* true 'master' holds a lease on (or owns) the object
|
||||
* false 'master' does not hold a lease.
|
||||
*/
|
||||
/* Called with idr_mutex held */
|
||||
bool _drm_lease_held(struct drm_file *file_priv, int id)
|
||||
{
|
||||
bool ret;
|
||||
|
@ -172,17 +123,6 @@ bool _drm_lease_held(struct drm_file *file_priv, int id)
|
|||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* drm_lease_held - check drm_mode_object lease status (idr_mutex not held)
|
||||
* @file_priv: the master drm_file
|
||||
* @id: the object id
|
||||
*
|
||||
* Checks if the specified master holds a lease on the object. Return
|
||||
* value:
|
||||
*
|
||||
* true 'master' holds a lease on (or owns) the object
|
||||
* false 'master' does not hold a lease.
|
||||
*/
|
||||
bool drm_lease_held(struct drm_file *file_priv, int id)
|
||||
{
|
||||
struct drm_master *master;
|
||||
|
@ -207,13 +147,9 @@ out:
|
|||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* drm_lease_filter_crtcs - restricted crtc set to leased values (idr_mutex not held)
|
||||
* @file_priv: requestor file
|
||||
* @crtcs_in: bitmask of crtcs to check
|
||||
*
|
||||
* Reconstructs a crtc mask based on the crtcs which are visible
|
||||
* through the specified file.
|
||||
/*
|
||||
* Given a bitmask of crtcs to check, reconstructs a crtc mask based on the
|
||||
* crtcs which are visible through the specified file.
|
||||
*/
|
||||
uint32_t drm_lease_filter_crtcs(struct drm_file *file_priv, uint32_t crtcs_in)
|
||||
{
|
||||
|
@ -258,10 +194,6 @@ out:
|
|||
}
|
||||
|
||||
/*
|
||||
* drm_lease_create - create a new drm_master with leased objects (idr_mutex not held)
|
||||
* @lessor: lease holder (or owner) of objects
|
||||
* @leases: objects to lease to the new drm_master
|
||||
*
|
||||
* Uses drm_master_create to allocate a new drm_master, then checks to
|
||||
* make sure all of the desired objects can be leased, atomically
|
||||
* leasing them to the new drmmaster.
|
||||
|
@ -330,15 +262,6 @@ out_lessee:
|
|||
return ERR_PTR(error);
|
||||
}
|
||||
|
||||
/**
|
||||
* drm_lease_destroy - a master is going away (idr_mutex not held)
|
||||
* @master: the drm_master being destroyed
|
||||
*
|
||||
* All lessees will have been destroyed as they
|
||||
* hold a reference on their lessor. Notify any
|
||||
* lessor for this master so that it can check
|
||||
* the list of lessees.
|
||||
*/
|
||||
void drm_lease_destroy(struct drm_master *master)
|
||||
{
|
||||
struct drm_device *dev = master->dev;
|
||||
|
@ -372,10 +295,6 @@ void drm_lease_destroy(struct drm_master *master)
|
|||
DRM_DEBUG_LEASE("drm_lease_destroy done %d\n", master->lessee_id);
|
||||
}
|
||||
|
||||
/**
|
||||
* _drm_lease_revoke - revoke access to all leased objects (idr_mutex held)
|
||||
* @top: the master losing its lease
|
||||
*/
|
||||
static void _drm_lease_revoke(struct drm_master *top)
|
||||
{
|
||||
int object;
|
||||
|
@ -414,10 +333,6 @@ static void _drm_lease_revoke(struct drm_master *top)
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* drm_lease_revoke - revoke access to all leased objects (idr_mutex not held)
|
||||
* @top: the master losing its lease
|
||||
*/
|
||||
void drm_lease_revoke(struct drm_master *top)
|
||||
{
|
||||
mutex_lock(&top->dev->mode_config.idr_mutex);
|
||||
|
@ -549,12 +464,7 @@ out_free_objects:
|
|||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* drm_mode_create_lease_ioctl - create a new lease
|
||||
* @dev: the drm device
|
||||
* @data: pointer to struct drm_mode_create_lease
|
||||
* @lessor_priv: the file being manipulated
|
||||
*
|
||||
/*
|
||||
* The master associated with the specified file will have a lease
|
||||
* created containing the objects specified in the ioctl structure.
|
||||
* A file descriptor will be allocated for that and returned to the
|
||||
|
@ -676,18 +586,6 @@ out_lessor:
|
|||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* drm_mode_list_lessees_ioctl - list lessee ids
|
||||
* @dev: the drm device
|
||||
* @data: pointer to struct drm_mode_list_lessees
|
||||
* @lessor_priv: the file being manipulated
|
||||
*
|
||||
* Starting from the master associated with the specified file,
|
||||
* the master with the provided lessee_id is found, and then
|
||||
* an array of lessee ids associated with leases from that master
|
||||
* are returned.
|
||||
*/
|
||||
|
||||
int drm_mode_list_lessees_ioctl(struct drm_device *dev,
|
||||
void *data, struct drm_file *lessor_priv)
|
||||
{
|
||||
|
@ -734,15 +632,7 @@ int drm_mode_list_lessees_ioctl(struct drm_device *dev,
|
|||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* drm_mode_get_lease_ioctl - list leased objects
|
||||
* @dev: the drm device
|
||||
* @data: pointer to struct drm_mode_get_lease
|
||||
* @lessee_priv: the file being manipulated
|
||||
*
|
||||
* Return the list of leased objects for the specified lessee
|
||||
*/
|
||||
|
||||
/* Return the list of leased objects for the specified lessee */
|
||||
int drm_mode_get_lease_ioctl(struct drm_device *dev,
|
||||
void *data, struct drm_file *lessee_priv)
|
||||
{
|
||||
|
@ -796,12 +686,7 @@ int drm_mode_get_lease_ioctl(struct drm_device *dev,
|
|||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* drm_mode_revoke_lease_ioctl - revoke lease
|
||||
* @dev: the drm device
|
||||
* @data: pointer to struct drm_mode_revoke_lease
|
||||
* @lessor_priv: the file being manipulated
|
||||
*
|
||||
/*
|
||||
* This removes all of the objects from the lease without
|
||||
* actually getting rid of the lease itself; that way all
|
||||
* references to it still work correctly
|
||||
|
|
|
@ -700,7 +700,7 @@ EXPORT_SYMBOL(drm_mm_replace_node);
|
|||
* interfaces. First a scan operation needs to be initialized with
|
||||
* drm_mm_scan_init() or drm_mm_scan_init_with_range(). The driver adds
|
||||
* objects to the roster, probably by walking an LRU list, but this can be
|
||||
* freely implemented. Eviction candiates are added using
|
||||
* freely implemented. Eviction candidates are added using
|
||||
* drm_mm_scan_add_block() until a suitable hole is found or there are no
|
||||
* further evictable objects. Eviction roster metadata is tracked in &struct
|
||||
* drm_mm_scan.
|
||||
|
|
|
@ -91,7 +91,7 @@ void drm_mode_object_register(struct drm_device *dev,
|
|||
}
|
||||
|
||||
/**
|
||||
* drm_mode_object_unregister - free a modeset identifer
|
||||
* drm_mode_object_unregister - free a modeset identifier
|
||||
* @dev: DRM device
|
||||
* @object: object to free
|
||||
*
|
||||
|
|
|
@ -1542,7 +1542,7 @@ static int drm_mode_parse_cmdline_int(const char *delim, unsigned int *int_ret)
|
|||
|
||||
/*
|
||||
* delim must point to the '=', otherwise it is a syntax error and
|
||||
* if delim points to the terminating zero, then delim + 1 wil point
|
||||
* if delim points to the terminating zero, then delim + 1 will point
|
||||
* past the end of the string.
|
||||
*/
|
||||
if (*delim != '=')
|
||||
|
@ -1972,7 +1972,7 @@ int drm_mode_convert_umode(struct drm_device *dev,
|
|||
out->flags = in->flags;
|
||||
/*
|
||||
* Old xf86-video-vmware (possibly others too) used to
|
||||
* leave 'type' unititialized. Just ignore any bits we
|
||||
* leave 'type' uninitialized. Just ignore any bits we
|
||||
* don't like. It's a just hint after all, and more
|
||||
* useful for the kernel->userspace direction anyway.
|
||||
*/
|
||||
|
|
|
@ -38,7 +38,7 @@
|
|||
/**
|
||||
* DOC: overview
|
||||
*
|
||||
* A plane represents an image source that can be blended with or overlayed on
|
||||
* A plane represents an image source that can be blended with or overlaid on
|
||||
* top of a CRTC during the scanout process. Planes take their input data from a
|
||||
* &drm_framebuffer object. The plane itself specifies the cropping and scaling
|
||||
* of that image, and where it is placed on the visible area of a display
|
||||
|
|
|
@ -210,7 +210,7 @@ static int drm_primary_helper_update(struct drm_plane *plane, struct drm_crtc *c
|
|||
* We call set_config() directly here rather than using
|
||||
* drm_mode_set_config_internal. We're reprogramming the same
|
||||
* connectors that were already in use, so we shouldn't need the extra
|
||||
* cross-CRTC fb refcounting to accomodate stealing connectors.
|
||||
* cross-CRTC fb refcounting to accommodate stealing connectors.
|
||||
* drm_mode_setplane() already handles the basic refcounting for the
|
||||
* framebuffers involved in this operation.
|
||||
*/
|
||||
|
|
|
@ -73,7 +73,7 @@
|
|||
* Thus the chain of references always flows in one direction, avoiding loops:
|
||||
* importing GEM object -> dma-buf -> exported GEM bo. A further complication
|
||||
* are the lookup caches for import and export. These are required to guarantee
|
||||
* that any given object will always have only one uniqe userspace handle. This
|
||||
* that any given object will always have only one unique userspace handle. This
|
||||
* is required to allow userspace to detect duplicated imports, since some GEM
|
||||
* drivers do fail command submissions if a given buffer object is listed more
|
||||
* than once. These import and export caches in &drm_prime_file_private only
|
||||
|
|
|
@ -757,7 +757,7 @@ EXPORT_SYMBOL(drm_kms_helper_poll_disable);
|
|||
* drm_kms_helper_poll_init - initialize and enable output polling
|
||||
* @dev: drm_device
|
||||
*
|
||||
* This function intializes and then also enables output polling support for
|
||||
* This function initializes and then also enables output polling support for
|
||||
* @dev. Drivers which do not have reliable hotplug support in hardware can use
|
||||
* this helper infrastructure to regularly poll such connectors for changes in
|
||||
* their connection state.
|
||||
|
|
|
@ -434,7 +434,7 @@ EXPORT_SYMBOL(drm_property_add_enum);
|
|||
/**
|
||||
* drm_property_destroy - destroy a drm property
|
||||
* @dev: drm device
|
||||
* @property: property to destry
|
||||
* @property: property to destroy
|
||||
*
|
||||
* This function frees a property including any attached resources like
|
||||
* enumeration values.
|
||||
|
|
|
@ -241,7 +241,7 @@ bool drm_scdc_set_high_tmds_clock_ratio(struct i2c_adapter *adapter, bool set)
|
|||
/*
|
||||
* The spec says that a source should wait minimum 1ms and maximum
|
||||
* 100ms after writing the TMDS config for clock ratio. Lets allow a
|
||||
* wait of upto 2ms here.
|
||||
* wait of up to 2ms here.
|
||||
*/
|
||||
usleep_range(1000, 2000);
|
||||
return true;
|
||||
|
|
|
@ -725,7 +725,7 @@ err_put_fd:
|
|||
return ret;
|
||||
}
|
||||
/**
|
||||
* drm_syncobj_open - initalizes syncobj file-private structures at devnode open time
|
||||
* drm_syncobj_open - initializes syncobj file-private structures at devnode open time
|
||||
* @file_private: drm file-private structure to set up
|
||||
*
|
||||
* Called at device open time, sets up the structure for handling refcounting
|
||||
|
|
|
@ -191,7 +191,7 @@ static u32 drm_max_vblank_count(struct drm_device *dev, unsigned int pipe)
|
|||
|
||||
/*
|
||||
* "No hw counter" fallback implementation of .get_vblank_counter() hook,
|
||||
* if there is no useable hardware frame counter available.
|
||||
* if there is no usable hardware frame counter available.
|
||||
*/
|
||||
static u32 drm_vblank_no_hw_counter(struct drm_device *dev, unsigned int pipe)
|
||||
{
|
||||
|
@ -905,7 +905,7 @@ drm_get_last_vbltimestamp(struct drm_device *dev, unsigned int pipe,
|
|||
* and drm_crtc_vblank_count() or drm_crtc_vblank_count_and_time()
|
||||
* provide a barrier: Any writes done before calling
|
||||
* drm_crtc_handle_vblank() will be visible to callers of the later
|
||||
* functions, iff the vblank count is the same or a later one.
|
||||
* functions, if the vblank count is the same or a later one.
|
||||
*
|
||||
* See also &drm_vblank_crtc.count.
|
||||
*
|
||||
|
@ -968,7 +968,7 @@ static u64 drm_vblank_count_and_time(struct drm_device *dev, unsigned int pipe,
|
|||
* and drm_crtc_vblank_count() or drm_crtc_vblank_count_and_time()
|
||||
* provide a barrier: Any writes done before calling
|
||||
* drm_crtc_handle_vblank() will be visible to callers of the later
|
||||
* functions, iff the vblank count is the same or a later one.
|
||||
* functions, if the vblank count is the same or a later one.
|
||||
*
|
||||
* See also &drm_vblank_crtc.count.
|
||||
*/
|
||||
|
@ -1997,7 +1997,7 @@ EXPORT_SYMBOL(drm_handle_vblank);
|
|||
* and drm_crtc_vblank_count() or drm_crtc_vblank_count_and_time()
|
||||
* provide a barrier: Any writes done before calling
|
||||
* drm_crtc_handle_vblank() will be visible to callers of the later
|
||||
* functions, iff the vblank count is the same or a later one.
|
||||
* functions, if the vblank count is the same or a later one.
|
||||
*
|
||||
* See also &drm_vblank_crtc.count.
|
||||
*
|
||||
|
@ -2014,7 +2014,7 @@ EXPORT_SYMBOL(drm_crtc_handle_vblank);
|
|||
* Get crtc VBLANK count.
|
||||
*
|
||||
* \param dev DRM device
|
||||
* \param data user arguement, pointing to a drm_crtc_get_sequence structure.
|
||||
* \param data user argument, pointing to a drm_crtc_get_sequence structure.
|
||||
* \param file_priv drm file private for the user's open file descriptor
|
||||
*/
|
||||
|
||||
|
@ -2070,7 +2070,7 @@ int drm_crtc_get_sequence_ioctl(struct drm_device *dev, void *data,
|
|||
* Queue a event for VBLANK sequence
|
||||
*
|
||||
* \param dev DRM device
|
||||
* \param data user arguement, pointing to a drm_crtc_queue_sequence structure.
|
||||
* \param data user argument, pointing to a drm_crtc_queue_sequence structure.
|
||||
* \param file_priv drm file private for the user's open file descriptor
|
||||
*/
|
||||
|
||||
|
|
|
@ -361,7 +361,7 @@ EXPORT_SYMBOL(drm_vma_node_revoke);
|
|||
* This is locked against concurrent access internally.
|
||||
*
|
||||
* RETURNS:
|
||||
* true iff @filp is on the list
|
||||
* true if @filp is on the list
|
||||
*/
|
||||
bool drm_vma_node_is_allowed(struct drm_vma_offset_node *node,
|
||||
struct drm_file *tag)
|
||||
|
|
|
@ -14,8 +14,8 @@
|
|||
#include <drm/drm_format_helper.h>
|
||||
#include <drm/drm_fourcc.h>
|
||||
#include <drm/drm_framebuffer.h>
|
||||
#include <drm/drm_gem.h>
|
||||
#include <drm/drm_gem_framebuffer_helper.h>
|
||||
#include <drm/drm_gem_shmem_helper.h>
|
||||
#include <drm/drm_print.h>
|
||||
#include <drm/drm_rect.h>
|
||||
#include <drm/drm_simple_kms_helper.h>
|
||||
|
@ -152,7 +152,7 @@ static int gud_prep_flush(struct gud_device *gdrm, struct drm_framebuffer *fb,
|
|||
{
|
||||
struct dma_buf_attachment *import_attach = fb->obj[0]->import_attach;
|
||||
u8 compression = gdrm->compression;
|
||||
struct dma_buf_map map;
|
||||
struct dma_buf_map map[DRM_FORMAT_MAX_PLANES];
|
||||
void *vaddr, *buf;
|
||||
size_t pitch, len;
|
||||
int ret = 0;
|
||||
|
@ -162,11 +162,11 @@ static int gud_prep_flush(struct gud_device *gdrm, struct drm_framebuffer *fb,
|
|||
if (len > gdrm->bulk_len)
|
||||
return -E2BIG;
|
||||
|
||||
ret = drm_gem_shmem_vmap(fb->obj[0], &map);
|
||||
ret = drm_gem_fb_vmap(fb, map);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
vaddr = map.vaddr + fb->offsets[0];
|
||||
vaddr = map[0].vaddr + fb->offsets[0];
|
||||
|
||||
ret = drm_gem_fb_begin_cpu_access(fb, DMA_FROM_DEVICE);
|
||||
if (ret)
|
||||
|
@ -225,7 +225,7 @@ retry:
|
|||
end_cpu_access:
|
||||
drm_gem_fb_end_cpu_access(fb, DMA_FROM_DEVICE);
|
||||
vunmap:
|
||||
drm_gem_shmem_vunmap(fb->obj[0], &map);
|
||||
drm_gem_fb_vunmap(fb, map);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
|
|
@ -125,6 +125,18 @@ config DRM_PANEL_ILITEK_IL9322
|
|||
Say Y here if you want to enable support for Ilitek IL9322
|
||||
QVGA (320x240) RGB, YUV and ITU-T BT.656 panels.
|
||||
|
||||
config DRM_PANEL_ILITEK_ILI9341
|
||||
tristate "Ilitek ILI9341 240x320 QVGA panels"
|
||||
depends on OF && SPI
|
||||
depends on DRM_KMS_HELPER
|
||||
depends on DRM_KMS_CMA_HELPER
|
||||
depends on BACKLIGHT_CLASS_DEVICE
|
||||
select DRM_MIPI_DBI
|
||||
help
|
||||
Say Y here if you want to enable support for Ilitek IL9341
|
||||
QVGA (240x320) RGB panels. support serial & parallel rgb
|
||||
interface.
|
||||
|
||||
config DRM_PANEL_ILITEK_ILI9881C
|
||||
tristate "Ilitek ILI9881C-based panels"
|
||||
depends on OF
|
||||
|
@ -353,6 +365,17 @@ config DRM_PANEL_RONBO_RB070D30
|
|||
Say Y here if you want to enable support for Ronbo Electronics
|
||||
RB070D30 1024x600 DSI panel.
|
||||
|
||||
config DRM_PANEL_SAMSUNG_ATNA33XC20
|
||||
tristate "Samsung ATNA33XC20 eDP panel"
|
||||
depends on OF
|
||||
depends on BACKLIGHT_CLASS_DEVICE
|
||||
depends on PM
|
||||
select DRM_DP_AUX_BUS
|
||||
help
|
||||
DRM panel driver for the Samsung ATNA33XC20 panel. This panel can't
|
||||
be handled by the DRM_PANEL_SIMPLE driver because its power
|
||||
sequencing is non-standard.
|
||||
|
||||
config DRM_PANEL_SAMSUNG_DB7430
|
||||
tristate "Samsung DB7430-based DPI panels"
|
||||
depends on OF && SPI && GPIOLIB
|
||||
|
|
|
@ -11,6 +11,7 @@ obj-$(CONFIG_DRM_PANEL_ELIDA_KD35T133) += panel-elida-kd35t133.o
|
|||
obj-$(CONFIG_DRM_PANEL_FEIXIN_K101_IM2BA02) += panel-feixin-k101-im2ba02.o
|
||||
obj-$(CONFIG_DRM_PANEL_FEIYANG_FY07024DI26A30D) += panel-feiyang-fy07024di26a30d.o
|
||||
obj-$(CONFIG_DRM_PANEL_ILITEK_IL9322) += panel-ilitek-ili9322.o
|
||||
obj-$(CONFIG_DRM_PANEL_ILITEK_ILI9341) += panel-ilitek-ili9341.o
|
||||
obj-$(CONFIG_DRM_PANEL_ILITEK_ILI9881C) += panel-ilitek-ili9881c.o
|
||||
obj-$(CONFIG_DRM_PANEL_INNOLUX_EJ030NA) += panel-innolux-ej030na.o
|
||||
obj-$(CONFIG_DRM_PANEL_INNOLUX_P079ZCA) += panel-innolux-p079zca.o
|
||||
|
@ -34,6 +35,7 @@ obj-$(CONFIG_DRM_PANEL_RASPBERRYPI_TOUCHSCREEN) += panel-raspberrypi-touchscreen
|
|||
obj-$(CONFIG_DRM_PANEL_RAYDIUM_RM67191) += panel-raydium-rm67191.o
|
||||
obj-$(CONFIG_DRM_PANEL_RAYDIUM_RM68200) += panel-raydium-rm68200.o
|
||||
obj-$(CONFIG_DRM_PANEL_RONBO_RB070D30) += panel-ronbo-rb070d30.o
|
||||
obj-$(CONFIG_DRM_PANEL_SAMSUNG_ATNA33XC20) += panel-samsung-atna33xc20.o
|
||||
obj-$(CONFIG_DRM_PANEL_SAMSUNG_DB7430) += panel-samsung-db7430.o
|
||||
obj-$(CONFIG_DRM_PANEL_SAMSUNG_LD9040) += panel-samsung-ld9040.o
|
||||
obj-$(CONFIG_DRM_PANEL_SAMSUNG_S6D16D0) += panel-samsung-s6d16d0.o
|
||||
|
|
|
@ -0,0 +1,792 @@
|
|||
// SPDX-License-Identifier: GPL-2.0-only
|
||||
/*
|
||||
* Ilitek ILI9341 TFT LCD drm_panel driver.
|
||||
*
|
||||
* This panel can be configured to support:
|
||||
* - 16-bit parallel RGB interface
|
||||
* - 18-bit parallel RGB interface
|
||||
* - 4-line serial spi interface
|
||||
*
|
||||
* Copyright (C) 2021 Dillon Min <dillon.minfei@gmail.com>
|
||||
*
|
||||
* For dbi+dpi part:
|
||||
* Derived from drivers/drm/gpu/panel/panel-ilitek-ili9322.c
|
||||
* the reuse of DBI abstraction part referred from Linus's patch
|
||||
* "drm/panel: s6e63m0: Switch to DBI abstraction for SPI"
|
||||
*
|
||||
* For only-dbi part, copy from David's code (drm/tiny/ili9341.c)
|
||||
* Copyright 2018 David Lechner <david@lechnology.com>
|
||||
*/
|
||||
|
||||
#include <linux/bitops.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/gpio/consumer.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/of_device.h>
|
||||
#include <linux/regulator/consumer.h>
|
||||
#include <linux/spi/spi.h>
|
||||
|
||||
#include <video/mipi_display.h>
|
||||
|
||||
#include <drm/drm_atomic_helper.h>
|
||||
#include <drm/drm_drv.h>
|
||||
#include <drm/drm_fb_helper.h>
|
||||
#include <drm/drm_gem_atomic_helper.h>
|
||||
#include <drm/drm_gem_cma_helper.h>
|
||||
#include <drm/drm_gem_framebuffer_helper.h>
|
||||
#include <drm/drm_mipi_dbi.h>
|
||||
#include <drm/drm_modes.h>
|
||||
#include <drm/drm_panel.h>
|
||||
#include <drm/drm_print.h>
|
||||
|
||||
#define ILI9341_RGB_INTERFACE 0xb0 /* RGB Interface Signal Control */
|
||||
#define ILI9341_FRC 0xb1 /* Frame Rate Control register */
|
||||
#define ILI9341_DFC 0xb6 /* Display Function Control register */
|
||||
#define ILI9341_POWER1 0xc0 /* Power Control 1 register */
|
||||
#define ILI9341_POWER2 0xc1 /* Power Control 2 register */
|
||||
#define ILI9341_VCOM1 0xc5 /* VCOM Control 1 register */
|
||||
#define ILI9341_VCOM2 0xc7 /* VCOM Control 2 register */
|
||||
#define ILI9341_POWERA 0xcb /* Power control A register */
|
||||
#define ILI9341_POWERB 0xcf /* Power control B register */
|
||||
#define ILI9341_PGAMMA 0xe0 /* Positive Gamma Correction register */
|
||||
#define ILI9341_NGAMMA 0xe1 /* Negative Gamma Correction register */
|
||||
#define ILI9341_DTCA 0xe8 /* Driver timing control A */
|
||||
#define ILI9341_DTCB 0xea /* Driver timing control B */
|
||||
#define ILI9341_POWER_SEQ 0xed /* Power on sequence register */
|
||||
#define ILI9341_3GAMMA_EN 0xf2 /* 3 Gamma enable register */
|
||||
#define ILI9341_INTERFACE 0xf6 /* Interface control register */
|
||||
#define ILI9341_PRC 0xf7 /* Pump ratio control register */
|
||||
#define ILI9341_ETMOD 0xb7 /* Entry mode set */
|
||||
|
||||
#define ILI9341_MADCTL_BGR BIT(3)
|
||||
#define ILI9341_MADCTL_MV BIT(5)
|
||||
#define ILI9341_MADCTL_MX BIT(6)
|
||||
#define ILI9341_MADCTL_MY BIT(7)
|
||||
|
||||
#define ILI9341_POWER_B_LEN 3
|
||||
#define ILI9341_POWER_SEQ_LEN 4
|
||||
#define ILI9341_DTCA_LEN 3
|
||||
#define ILI9341_DTCB_LEN 2
|
||||
#define ILI9341_POWER_A_LEN 5
|
||||
#define ILI9341_DFC_1_LEN 2
|
||||
#define ILI9341_FRC_LEN 2
|
||||
#define ILI9341_VCOM_1_LEN 2
|
||||
#define ILI9341_DFC_2_LEN 4
|
||||
#define ILI9341_COLUMN_ADDR_LEN 4
|
||||
#define ILI9341_PAGE_ADDR_LEN 4
|
||||
#define ILI9341_INTERFACE_LEN 3
|
||||
#define ILI9341_PGAMMA_LEN 15
|
||||
#define ILI9341_NGAMMA_LEN 15
|
||||
#define ILI9341_CA_LEN 3
|
||||
|
||||
#define ILI9341_PIXEL_DPI_16_BITS (BIT(6) | BIT(4))
|
||||
#define ILI9341_PIXEL_DPI_18_BITS (BIT(6) | BIT(5))
|
||||
#define ILI9341_GAMMA_CURVE_1 BIT(0)
|
||||
#define ILI9341_IF_WE_MODE BIT(0)
|
||||
#define ILI9341_IF_BIG_ENDIAN 0x00
|
||||
#define ILI9341_IF_DM_RGB BIT(2)
|
||||
#define ILI9341_IF_DM_INTERNAL 0x00
|
||||
#define ILI9341_IF_DM_VSYNC BIT(3)
|
||||
#define ILI9341_IF_RM_RGB BIT(1)
|
||||
#define ILI9341_IF_RIM_RGB 0x00
|
||||
|
||||
#define ILI9341_COLUMN_ADDR 0x00ef
|
||||
#define ILI9341_PAGE_ADDR 0x013f
|
||||
|
||||
#define ILI9341_RGB_EPL BIT(0)
|
||||
#define ILI9341_RGB_DPL BIT(1)
|
||||
#define ILI9341_RGB_HSPL BIT(2)
|
||||
#define ILI9341_RGB_VSPL BIT(3)
|
||||
#define ILI9341_RGB_DE_MODE BIT(6)
|
||||
#define ILI9341_RGB_DISP_PATH_MEM BIT(7)
|
||||
|
||||
#define ILI9341_DBI_VCOMH_4P6V 0x23
|
||||
#define ILI9341_DBI_PWR_2_DEFAULT 0x10
|
||||
#define ILI9341_DBI_PRC_NORMAL 0x20
|
||||
#define ILI9341_DBI_VCOM_1_VMH_4P25V 0x3e
|
||||
#define ILI9341_DBI_VCOM_1_VML_1P5V 0x28
|
||||
#define ILI9341_DBI_VCOM_2_DEC_58 0x86
|
||||
#define ILI9341_DBI_FRC_DIVA 0x00
|
||||
#define ILI9341_DBI_FRC_RTNA 0x1b
|
||||
#define ILI9341_DBI_EMS_GAS BIT(0)
|
||||
#define ILI9341_DBI_EMS_DTS BIT(1)
|
||||
#define ILI9341_DBI_EMS_GON BIT(2)
|
||||
|
||||
/* struct ili9341_config - the system specific ILI9341 configuration */
|
||||
struct ili9341_config {
|
||||
u32 max_spi_speed;
|
||||
/* mode: the drm display mode */
|
||||
const struct drm_display_mode mode;
|
||||
/* ca: TODO: need comments for this register */
|
||||
u8 ca[ILI9341_CA_LEN];
|
||||
/* power_b: TODO: need comments for this register */
|
||||
u8 power_b[ILI9341_POWER_B_LEN];
|
||||
/* power_seq: TODO: need comments for this register */
|
||||
u8 power_seq[ILI9341_POWER_SEQ_LEN];
|
||||
/* dtca: TODO: need comments for this register */
|
||||
u8 dtca[ILI9341_DTCA_LEN];
|
||||
/* dtcb: TODO: need comments for this register */
|
||||
u8 dtcb[ILI9341_DTCB_LEN];
|
||||
/* power_a: TODO: need comments for this register */
|
||||
u8 power_a[ILI9341_POWER_A_LEN];
|
||||
/* frc: Frame Rate Control (In Normal Mode/Full Colors) (B1h) */
|
||||
u8 frc[ILI9341_FRC_LEN];
|
||||
/* prc: TODO: need comments for this register */
|
||||
u8 prc;
|
||||
/* dfc_1: B6h DISCTRL (Display Function Control) */
|
||||
u8 dfc_1[ILI9341_DFC_1_LEN];
|
||||
/* power_1: Power Control 1 (C0h) */
|
||||
u8 power_1;
|
||||
/* power_2: Power Control 2 (C1h) */
|
||||
u8 power_2;
|
||||
/* vcom_1: VCOM Control 1(C5h) */
|
||||
u8 vcom_1[ILI9341_VCOM_1_LEN];
|
||||
/* vcom_2: VCOM Control 2(C7h) */
|
||||
u8 vcom_2;
|
||||
/* address_mode: Memory Access Control (36h) */
|
||||
u8 address_mode;
|
||||
/* g3amma_en: TODO: need comments for this register */
|
||||
u8 g3amma_en;
|
||||
/* rgb_interface: RGB Interface Signal Control (B0h) */
|
||||
u8 rgb_interface;
|
||||
/* dfc_2: refer to dfc_1 */
|
||||
u8 dfc_2[ILI9341_DFC_2_LEN];
|
||||
/* column_addr: Column Address Set (2Ah) */
|
||||
u8 column_addr[ILI9341_COLUMN_ADDR_LEN];
|
||||
/* page_addr: Page Address Set (2Bh) */
|
||||
u8 page_addr[ILI9341_PAGE_ADDR_LEN];
|
||||
/* interface: Interface Control (F6h) */
|
||||
u8 interface[ILI9341_INTERFACE_LEN];
|
||||
/*
|
||||
* pixel_format: This command sets the pixel format for the RGB
|
||||
* image data used by
|
||||
*/
|
||||
u8 pixel_format;
|
||||
/*
|
||||
* gamma_curve: This command is used to select the desired Gamma
|
||||
* curve for the
|
||||
*/
|
||||
u8 gamma_curve;
|
||||
/* pgamma: Positive Gamma Correction (E0h) */
|
||||
u8 pgamma[ILI9341_PGAMMA_LEN];
|
||||
/* ngamma: Negative Gamma Correction (E1h) */
|
||||
u8 ngamma[ILI9341_NGAMMA_LEN];
|
||||
};
|
||||
|
||||
struct ili9341 {
|
||||
struct device *dev;
|
||||
const struct ili9341_config *conf;
|
||||
struct drm_panel panel;
|
||||
struct gpio_desc *reset_gpio;
|
||||
struct gpio_desc *dc_gpio;
|
||||
struct mipi_dbi *dbi;
|
||||
u32 max_spi_speed;
|
||||
struct regulator_bulk_data supplies[3];
|
||||
};
|
||||
|
||||
/*
|
||||
* The Stm32f429-disco board has a panel ili9341 connected to ltdc controller
|
||||
*/
|
||||
static const struct ili9341_config ili9341_stm32f429_disco_data = {
|
||||
.max_spi_speed = 10000000,
|
||||
.mode = {
|
||||
.clock = 6100,
|
||||
.hdisplay = 240,
|
||||
.hsync_start = 240 + 10,/* hfp 10 */
|
||||
.hsync_end = 240 + 10 + 10,/* hsync 10 */
|
||||
.htotal = 240 + 10 + 10 + 20,/* hbp 20 */
|
||||
.vdisplay = 320,
|
||||
.vsync_start = 320 + 4,/* vfp 4 */
|
||||
.vsync_end = 320 + 4 + 2,/* vsync 2 */
|
||||
.vtotal = 320 + 4 + 2 + 2,/* vbp 2 */
|
||||
.flags = 0,
|
||||
.width_mm = 65,
|
||||
.height_mm = 50,
|
||||
.type = DRM_MODE_TYPE_DRIVER | DRM_MODE_TYPE_PREFERRED,
|
||||
},
|
||||
.ca = {0xc3, 0x08, 0x50},
|
||||
.power_b = {0x00, 0xc1, 0x30},
|
||||
.power_seq = {0x64, 0x03, 0x12, 0x81},
|
||||
.dtca = {0x85, 0x00, 0x78},
|
||||
.power_a = {0x39, 0x2c, 0x00, 0x34, 0x02},
|
||||
.prc = 0x20,
|
||||
.dtcb = {0x00, 0x00},
|
||||
/* 0x00 fosc, 0x1b 70hz */
|
||||
.frc = {0x00, 0x1b},
|
||||
/*
|
||||
* 0x0a Interval scan, AGND AGND AGND AGND
|
||||
* 0xa2 Normally white, G1 -> G320, S720 -> S1,
|
||||
* Scan Cycle 5 frames,85ms
|
||||
*/
|
||||
.dfc_1 = {0x0a, 0xa2},
|
||||
/* 0x10 3.65v */
|
||||
.power_1 = 0x10,
|
||||
/* 0x10 AVDD=vci*2, VGH=vci*7, VGL=-vci*4 */
|
||||
.power_2 = 0x10,
|
||||
/* 0x45 VCOMH 4.425v, 0x15 VCOML -1.975*/
|
||||
.vcom_1 = {0x45, 0x15},
|
||||
/* 0x90 offset voltage, VMH-48, VML-48 */
|
||||
.vcom_2 = 0x90,
|
||||
/*
|
||||
* 0xc8 Row Address Order, Column Address Order
|
||||
* BGR 1
|
||||
*/
|
||||
.address_mode = 0xc8,
|
||||
.g3amma_en = 0x00,
|
||||
/*
|
||||
* 0xc2
|
||||
* Display Data Path: Memory
|
||||
* RGB: DE mode
|
||||
* DOTCLK polarity set (data fetched at the falling time)
|
||||
*/
|
||||
.rgb_interface = ILI9341_RGB_DISP_PATH_MEM |
|
||||
ILI9341_RGB_DE_MODE |
|
||||
ILI9341_RGB_DPL,
|
||||
/*
|
||||
* 0x0a
|
||||
* Gate outputs in non-display area: Interval scan
|
||||
* Determine source/VCOM output in a non-display area in the partial
|
||||
* display mode: AGND AGND AGND AGND
|
||||
*
|
||||
* 0xa7
|
||||
* Scan Cycle: 15 frames
|
||||
* fFLM = 60Hz: 255ms
|
||||
* Liquid crystal type: Normally white
|
||||
* Gate Output Scan Direction: G1 -> G320
|
||||
* Source Output Scan Direction: S720 -> S1
|
||||
*
|
||||
* 0x27
|
||||
* LCD Driver Line: 320 lines
|
||||
*
|
||||
* 0x04
|
||||
* PCDIV: 4
|
||||
*/
|
||||
.dfc_2 = {0x0a, 0xa7, 0x27, 0x04},
|
||||
/* column address: 240 */
|
||||
.column_addr = {0x00, 0x00, (ILI9341_COLUMN_ADDR >> 4) & 0xff,
|
||||
ILI9341_COLUMN_ADDR & 0xff},
|
||||
/* page address: 320 */
|
||||
.page_addr = {0x00, 0x00, (ILI9341_PAGE_ADDR >> 4) & 0xff,
|
||||
ILI9341_PAGE_ADDR & 0xff},
|
||||
/*
|
||||
* Memory write control: When the transfer number of data exceeds
|
||||
* (EC-SC+1)*(EP-SP+1), the column and page number will be
|
||||
* reset, and the exceeding data will be written into the following
|
||||
* column and page.
|
||||
* Display Operation Mode: RGB Interface Mode
|
||||
* Interface for RAM Access: RGB interface
|
||||
* 16- bit RGB interface (1 transfer/pixel)
|
||||
*/
|
||||
.interface = {ILI9341_IF_WE_MODE, 0x00,
|
||||
ILI9341_IF_DM_RGB | ILI9341_IF_RM_RGB},
|
||||
/* DPI: 16 bits / pixel */
|
||||
.pixel_format = ILI9341_PIXEL_DPI_16_BITS,
|
||||
/* Curve Selected: Gamma curve 1 (G2.2) */
|
||||
.gamma_curve = ILI9341_GAMMA_CURVE_1,
|
||||
.pgamma = {0x0f, 0x29, 0x24, 0x0c, 0x0e,
|
||||
0x09, 0x4e, 0x78, 0x3c, 0x09,
|
||||
0x13, 0x05, 0x17, 0x11, 0x00},
|
||||
.ngamma = {0x00, 0x16, 0x1b, 0x04, 0x11,
|
||||
0x07, 0x31, 0x33, 0x42, 0x05,
|
||||
0x0c, 0x0a, 0x28, 0x2f, 0x0f},
|
||||
};
|
||||
|
||||
static inline struct ili9341 *panel_to_ili9341(struct drm_panel *panel)
|
||||
{
|
||||
return container_of(panel, struct ili9341, panel);
|
||||
}
|
||||
|
||||
static void ili9341_dpi_init(struct ili9341 *ili)
|
||||
{
|
||||
struct device *dev = (&ili->panel)->dev;
|
||||
struct mipi_dbi *dbi = ili->dbi;
|
||||
struct ili9341_config *cfg = (struct ili9341_config *)ili->conf;
|
||||
|
||||
/* Power Control */
|
||||
mipi_dbi_command_stackbuf(dbi, 0xca, cfg->ca, ILI9341_CA_LEN);
|
||||
mipi_dbi_command_stackbuf(dbi, ILI9341_POWERB, cfg->power_b,
|
||||
ILI9341_POWER_B_LEN);
|
||||
mipi_dbi_command_stackbuf(dbi, ILI9341_POWER_SEQ, cfg->power_seq,
|
||||
ILI9341_POWER_SEQ_LEN);
|
||||
mipi_dbi_command_stackbuf(dbi, ILI9341_DTCA, cfg->dtca,
|
||||
ILI9341_DTCA_LEN);
|
||||
mipi_dbi_command_stackbuf(dbi, ILI9341_POWERA, cfg->power_a,
|
||||
ILI9341_POWER_A_LEN);
|
||||
mipi_dbi_command(ili->dbi, ILI9341_PRC, cfg->prc);
|
||||
mipi_dbi_command_stackbuf(dbi, ILI9341_DTCB, cfg->dtcb,
|
||||
ILI9341_DTCB_LEN);
|
||||
mipi_dbi_command_stackbuf(dbi, ILI9341_FRC, cfg->frc, ILI9341_FRC_LEN);
|
||||
mipi_dbi_command_stackbuf(dbi, ILI9341_DFC, cfg->dfc_1,
|
||||
ILI9341_DFC_1_LEN);
|
||||
mipi_dbi_command(dbi, ILI9341_POWER1, cfg->power_1);
|
||||
mipi_dbi_command(dbi, ILI9341_POWER2, cfg->power_2);
|
||||
|
||||
/* VCOM */
|
||||
mipi_dbi_command_stackbuf(dbi, ILI9341_VCOM1, cfg->vcom_1,
|
||||
ILI9341_VCOM_1_LEN);
|
||||
mipi_dbi_command(dbi, ILI9341_VCOM2, cfg->vcom_2);
|
||||
mipi_dbi_command(dbi, MIPI_DCS_SET_ADDRESS_MODE, cfg->address_mode);
|
||||
|
||||
/* Gamma */
|
||||
mipi_dbi_command(dbi, ILI9341_3GAMMA_EN, cfg->g3amma_en);
|
||||
mipi_dbi_command(dbi, ILI9341_RGB_INTERFACE, cfg->rgb_interface);
|
||||
mipi_dbi_command_stackbuf(dbi, ILI9341_DFC, cfg->dfc_2,
|
||||
ILI9341_DFC_2_LEN);
|
||||
|
||||
/* Colomn address set */
|
||||
mipi_dbi_command_stackbuf(dbi, MIPI_DCS_SET_COLUMN_ADDRESS,
|
||||
cfg->column_addr, ILI9341_COLUMN_ADDR_LEN);
|
||||
|
||||
/* Page address set */
|
||||
mipi_dbi_command_stackbuf(dbi, MIPI_DCS_SET_PAGE_ADDRESS,
|
||||
cfg->page_addr, ILI9341_PAGE_ADDR_LEN);
|
||||
mipi_dbi_command_stackbuf(dbi, ILI9341_INTERFACE, cfg->interface,
|
||||
ILI9341_INTERFACE_LEN);
|
||||
|
||||
/* Format */
|
||||
mipi_dbi_command(dbi, MIPI_DCS_SET_PIXEL_FORMAT, cfg->pixel_format);
|
||||
mipi_dbi_command(dbi, MIPI_DCS_WRITE_MEMORY_START);
|
||||
msleep(200);
|
||||
mipi_dbi_command(dbi, MIPI_DCS_SET_GAMMA_CURVE, cfg->gamma_curve);
|
||||
mipi_dbi_command_stackbuf(dbi, ILI9341_PGAMMA, cfg->pgamma,
|
||||
ILI9341_PGAMMA_LEN);
|
||||
mipi_dbi_command_stackbuf(dbi, ILI9341_NGAMMA, cfg->ngamma,
|
||||
ILI9341_NGAMMA_LEN);
|
||||
mipi_dbi_command(dbi, MIPI_DCS_EXIT_SLEEP_MODE);
|
||||
msleep(200);
|
||||
mipi_dbi_command(dbi, MIPI_DCS_SET_DISPLAY_ON);
|
||||
mipi_dbi_command(dbi, MIPI_DCS_WRITE_MEMORY_START);
|
||||
|
||||
dev_info(dev, "Initialized display rgb interface\n");
|
||||
}
|
||||
|
||||
static int ili9341_dpi_power_on(struct ili9341 *ili)
|
||||
{
|
||||
struct device *dev = (&ili->panel)->dev;
|
||||
int ret = 0;
|
||||
|
||||
/* Assert RESET */
|
||||
gpiod_set_value(ili->reset_gpio, 1);
|
||||
|
||||
/* Enable power */
|
||||
ret = regulator_bulk_enable(ARRAY_SIZE(ili->supplies),
|
||||
ili->supplies);
|
||||
if (ret < 0) {
|
||||
dev_err(dev, "unable to enable vcc\n");
|
||||
return ret;
|
||||
}
|
||||
msleep(20);
|
||||
|
||||
/* De-assert RESET */
|
||||
gpiod_set_value(ili->reset_gpio, 0);
|
||||
msleep(20);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int ili9341_dpi_power_off(struct ili9341 *ili)
|
||||
{
|
||||
/* Assert RESET */
|
||||
gpiod_set_value(ili->reset_gpio, 1);
|
||||
|
||||
/* Disable power */
|
||||
return regulator_bulk_disable(ARRAY_SIZE(ili->supplies),
|
||||
ili->supplies);
|
||||
}
|
||||
|
||||
static int ili9341_dpi_disable(struct drm_panel *panel)
|
||||
{
|
||||
struct ili9341 *ili = panel_to_ili9341(panel);
|
||||
|
||||
mipi_dbi_command(ili->dbi, MIPI_DCS_SET_DISPLAY_OFF);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int ili9341_dpi_unprepare(struct drm_panel *panel)
|
||||
{
|
||||
struct ili9341 *ili = panel_to_ili9341(panel);
|
||||
|
||||
return ili9341_dpi_power_off(ili);
|
||||
}
|
||||
|
||||
static int ili9341_dpi_prepare(struct drm_panel *panel)
|
||||
{
|
||||
struct ili9341 *ili = panel_to_ili9341(panel);
|
||||
int ret;
|
||||
|
||||
ret = ili9341_dpi_power_on(ili);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
ili9341_dpi_init(ili);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int ili9341_dpi_enable(struct drm_panel *panel)
|
||||
{
|
||||
struct ili9341 *ili = panel_to_ili9341(panel);
|
||||
|
||||
mipi_dbi_command(ili->dbi, MIPI_DCS_SET_DISPLAY_ON);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int ili9341_dpi_get_modes(struct drm_panel *panel,
|
||||
struct drm_connector *connector)
|
||||
{
|
||||
struct ili9341 *ili = panel_to_ili9341(panel);
|
||||
struct drm_device *drm = connector->dev;
|
||||
struct drm_display_mode *mode;
|
||||
struct drm_display_info *info;
|
||||
|
||||
info = &connector->display_info;
|
||||
info->width_mm = ili->conf->mode.width_mm;
|
||||
info->height_mm = ili->conf->mode.height_mm;
|
||||
|
||||
if (ili->conf->rgb_interface & ILI9341_RGB_DPL)
|
||||
info->bus_flags |= DRM_BUS_FLAG_PIXDATA_DRIVE_POSEDGE;
|
||||
else
|
||||
info->bus_flags |= DRM_BUS_FLAG_PIXDATA_DRIVE_NEGEDGE;
|
||||
|
||||
if (ili->conf->rgb_interface & ILI9341_RGB_EPL)
|
||||
info->bus_flags |= DRM_BUS_FLAG_DE_LOW;
|
||||
else
|
||||
info->bus_flags |= DRM_BUS_FLAG_DE_HIGH;
|
||||
|
||||
mode = drm_mode_duplicate(drm, &ili->conf->mode);
|
||||
if (!mode) {
|
||||
drm_err(drm, "bad mode or failed to add mode\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
drm_mode_set_name(mode);
|
||||
|
||||
/* Set up the polarity */
|
||||
if (ili->conf->rgb_interface & ILI9341_RGB_HSPL)
|
||||
mode->flags |= DRM_MODE_FLAG_PHSYNC;
|
||||
else
|
||||
mode->flags |= DRM_MODE_FLAG_NHSYNC;
|
||||
|
||||
if (ili->conf->rgb_interface & ILI9341_RGB_VSPL)
|
||||
mode->flags |= DRM_MODE_FLAG_PVSYNC;
|
||||
else
|
||||
mode->flags |= DRM_MODE_FLAG_NVSYNC;
|
||||
|
||||
drm_mode_probed_add(connector, mode);
|
||||
|
||||
return 1; /* Number of modes */
|
||||
}
|
||||
|
||||
static const struct drm_panel_funcs ili9341_dpi_funcs = {
|
||||
.disable = ili9341_dpi_disable,
|
||||
.unprepare = ili9341_dpi_unprepare,
|
||||
.prepare = ili9341_dpi_prepare,
|
||||
.enable = ili9341_dpi_enable,
|
||||
.get_modes = ili9341_dpi_get_modes,
|
||||
};
|
||||
|
||||
static void ili9341_dbi_enable(struct drm_simple_display_pipe *pipe,
|
||||
struct drm_crtc_state *crtc_state,
|
||||
struct drm_plane_state *plane_state)
|
||||
{
|
||||
struct mipi_dbi_dev *dbidev = drm_to_mipi_dbi_dev(pipe->crtc.dev);
|
||||
struct mipi_dbi *dbi = &dbidev->dbi;
|
||||
u8 addr_mode;
|
||||
int ret, idx;
|
||||
|
||||
if (!drm_dev_enter(pipe->crtc.dev, &idx))
|
||||
return;
|
||||
|
||||
ret = mipi_dbi_poweron_conditional_reset(dbidev);
|
||||
if (ret < 0)
|
||||
goto out_exit;
|
||||
if (ret == 1)
|
||||
goto out_enable;
|
||||
|
||||
mipi_dbi_command(dbi, MIPI_DCS_SET_DISPLAY_OFF);
|
||||
|
||||
mipi_dbi_command(dbi, ILI9341_POWERB, 0x00, 0xc1, 0x30);
|
||||
mipi_dbi_command(dbi, ILI9341_POWER_SEQ, 0x64, 0x03, 0x12, 0x81);
|
||||
mipi_dbi_command(dbi, ILI9341_DTCA, 0x85, 0x00, 0x78);
|
||||
mipi_dbi_command(dbi, ILI9341_POWERA, 0x39, 0x2c, 0x00, 0x34, 0x02);
|
||||
mipi_dbi_command(dbi, ILI9341_PRC, ILI9341_DBI_PRC_NORMAL);
|
||||
mipi_dbi_command(dbi, ILI9341_DTCB, 0x00, 0x00);
|
||||
|
||||
/* Power Control */
|
||||
mipi_dbi_command(dbi, ILI9341_POWER1, ILI9341_DBI_VCOMH_4P6V);
|
||||
mipi_dbi_command(dbi, ILI9341_POWER2, ILI9341_DBI_PWR_2_DEFAULT);
|
||||
/* VCOM */
|
||||
mipi_dbi_command(dbi, ILI9341_VCOM1, ILI9341_DBI_VCOM_1_VMH_4P25V,
|
||||
ILI9341_DBI_VCOM_1_VML_1P5V);
|
||||
mipi_dbi_command(dbi, ILI9341_VCOM2, ILI9341_DBI_VCOM_2_DEC_58);
|
||||
|
||||
/* Memory Access Control */
|
||||
mipi_dbi_command(dbi, MIPI_DCS_SET_PIXEL_FORMAT,
|
||||
MIPI_DCS_PIXEL_FMT_16BIT);
|
||||
|
||||
/* Frame Rate */
|
||||
mipi_dbi_command(dbi, ILI9341_FRC, ILI9341_DBI_FRC_DIVA & 0x03,
|
||||
ILI9341_DBI_FRC_RTNA & 0x1f);
|
||||
|
||||
/* Gamma */
|
||||
mipi_dbi_command(dbi, ILI9341_3GAMMA_EN, 0x00);
|
||||
mipi_dbi_command(dbi, MIPI_DCS_SET_GAMMA_CURVE, ILI9341_GAMMA_CURVE_1);
|
||||
mipi_dbi_command(dbi, ILI9341_PGAMMA,
|
||||
0x0f, 0x31, 0x2b, 0x0c, 0x0e, 0x08, 0x4e, 0xf1,
|
||||
0x37, 0x07, 0x10, 0x03, 0x0e, 0x09, 0x00);
|
||||
mipi_dbi_command(dbi, ILI9341_NGAMMA,
|
||||
0x00, 0x0e, 0x14, 0x03, 0x11, 0x07, 0x31, 0xc1,
|
||||
0x48, 0x08, 0x0f, 0x0c, 0x31, 0x36, 0x0f);
|
||||
|
||||
/* DDRAM */
|
||||
mipi_dbi_command(dbi, ILI9341_ETMOD, ILI9341_DBI_EMS_GAS |
|
||||
ILI9341_DBI_EMS_DTS |
|
||||
ILI9341_DBI_EMS_GON);
|
||||
|
||||
/* Display */
|
||||
mipi_dbi_command(dbi, ILI9341_DFC, 0x08, 0x82, 0x27, 0x00);
|
||||
mipi_dbi_command(dbi, MIPI_DCS_EXIT_SLEEP_MODE);
|
||||
msleep(100);
|
||||
|
||||
mipi_dbi_command(dbi, MIPI_DCS_SET_DISPLAY_ON);
|
||||
msleep(100);
|
||||
|
||||
out_enable:
|
||||
switch (dbidev->rotation) {
|
||||
default:
|
||||
addr_mode = ILI9341_MADCTL_MX;
|
||||
break;
|
||||
case 90:
|
||||
addr_mode = ILI9341_MADCTL_MV;
|
||||
break;
|
||||
case 180:
|
||||
addr_mode = ILI9341_MADCTL_MY;
|
||||
break;
|
||||
case 270:
|
||||
addr_mode = ILI9341_MADCTL_MV | ILI9341_MADCTL_MY |
|
||||
ILI9341_MADCTL_MX;
|
||||
break;
|
||||
}
|
||||
|
||||
addr_mode |= ILI9341_MADCTL_BGR;
|
||||
mipi_dbi_command(dbi, MIPI_DCS_SET_ADDRESS_MODE, addr_mode);
|
||||
mipi_dbi_enable_flush(dbidev, crtc_state, plane_state);
|
||||
drm_info(&dbidev->drm, "Initialized display serial interface\n");
|
||||
out_exit:
|
||||
drm_dev_exit(idx);
|
||||
}
|
||||
|
||||
static const struct drm_simple_display_pipe_funcs ili9341_dbi_funcs = {
|
||||
.enable = ili9341_dbi_enable,
|
||||
.disable = mipi_dbi_pipe_disable,
|
||||
.update = mipi_dbi_pipe_update,
|
||||
.prepare_fb = drm_gem_simple_display_pipe_prepare_fb,
|
||||
};
|
||||
|
||||
static const struct drm_display_mode ili9341_dbi_mode = {
|
||||
DRM_SIMPLE_MODE(240, 320, 37, 49),
|
||||
};
|
||||
|
||||
DEFINE_DRM_GEM_CMA_FOPS(ili9341_dbi_fops);
|
||||
|
||||
static struct drm_driver ili9341_dbi_driver = {
|
||||
.driver_features = DRIVER_GEM | DRIVER_MODESET | DRIVER_ATOMIC,
|
||||
.fops = &ili9341_dbi_fops,
|
||||
DRM_GEM_CMA_DRIVER_OPS_VMAP,
|
||||
.debugfs_init = mipi_dbi_debugfs_init,
|
||||
.name = "ili9341",
|
||||
.desc = "Ilitek ILI9341",
|
||||
.date = "20210716",
|
||||
.major = 1,
|
||||
.minor = 0,
|
||||
};
|
||||
|
||||
static int ili9341_dbi_probe(struct spi_device *spi, struct gpio_desc *dc,
|
||||
struct gpio_desc *reset)
|
||||
{
|
||||
struct device *dev = &spi->dev;
|
||||
struct mipi_dbi_dev *dbidev;
|
||||
struct mipi_dbi *dbi;
|
||||
struct drm_device *drm;
|
||||
struct regulator *vcc;
|
||||
u32 rotation = 0;
|
||||
int ret;
|
||||
|
||||
vcc = devm_regulator_get_optional(dev, "vcc");
|
||||
if (IS_ERR(vcc))
|
||||
dev_err(dev, "get optional vcc failed\n");
|
||||
|
||||
dbidev = devm_drm_dev_alloc(dev, &ili9341_dbi_driver,
|
||||
struct mipi_dbi_dev, drm);
|
||||
if (IS_ERR(dbidev))
|
||||
return PTR_ERR(dbidev);
|
||||
|
||||
dbi = &dbidev->dbi;
|
||||
drm = &dbidev->drm;
|
||||
dbi->reset = reset;
|
||||
dbidev->regulator = vcc;
|
||||
|
||||
drm_mode_config_init(drm);
|
||||
|
||||
dbidev->backlight = devm_of_find_backlight(dev);
|
||||
if (IS_ERR(dbidev->backlight))
|
||||
return PTR_ERR(dbidev->backlight);
|
||||
|
||||
device_property_read_u32(dev, "rotation", &rotation);
|
||||
|
||||
ret = mipi_dbi_spi_init(spi, dbi, dc);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ret = mipi_dbi_dev_init(dbidev, &ili9341_dbi_funcs,
|
||||
&ili9341_dbi_mode, rotation);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
drm_mode_config_reset(drm);
|
||||
|
||||
ret = drm_dev_register(drm, 0);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
spi_set_drvdata(spi, drm);
|
||||
|
||||
drm_fbdev_generic_setup(drm, 0);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int ili9341_dpi_probe(struct spi_device *spi, struct gpio_desc *dc,
|
||||
struct gpio_desc *reset)
|
||||
{
|
||||
struct device *dev = &spi->dev;
|
||||
struct ili9341 *ili;
|
||||
int ret;
|
||||
|
||||
ili = devm_kzalloc(dev, sizeof(struct ili9341), GFP_KERNEL);
|
||||
if (!ili)
|
||||
return -ENOMEM;
|
||||
|
||||
ili->dbi = devm_kzalloc(dev, sizeof(struct mipi_dbi),
|
||||
GFP_KERNEL);
|
||||
if (!ili->dbi)
|
||||
return -ENOMEM;
|
||||
|
||||
ili->supplies[0].supply = "vci";
|
||||
ili->supplies[1].supply = "vddi";
|
||||
ili->supplies[2].supply = "vddi-led";
|
||||
ret = devm_regulator_bulk_get(dev, ARRAY_SIZE(ili->supplies),
|
||||
ili->supplies);
|
||||
if (ret < 0) {
|
||||
dev_err(dev, "failed to get regulators: %d\n", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret = mipi_dbi_spi_init(spi, ili->dbi, dc);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
spi_set_drvdata(spi, ili);
|
||||
ili->reset_gpio = reset;
|
||||
/*
|
||||
* Every new incarnation of this display must have a unique
|
||||
* data entry for the system in this driver.
|
||||
*/
|
||||
ili->conf = of_device_get_match_data(dev);
|
||||
if (!ili->conf) {
|
||||
dev_err(dev, "missing device configuration\n");
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
ili->max_spi_speed = ili->conf->max_spi_speed;
|
||||
drm_panel_init(&ili->panel, dev, &ili9341_dpi_funcs,
|
||||
DRM_MODE_CONNECTOR_DPI);
|
||||
drm_panel_add(&ili->panel);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int ili9341_probe(struct spi_device *spi)
|
||||
{
|
||||
struct device *dev = &spi->dev;
|
||||
struct gpio_desc *dc;
|
||||
struct gpio_desc *reset;
|
||||
const struct spi_device_id *id = spi_get_device_id(spi);
|
||||
|
||||
reset = devm_gpiod_get_optional(dev, "reset", GPIOD_OUT_HIGH);
|
||||
if (IS_ERR(reset))
|
||||
dev_err(dev, "Failed to get gpio 'reset'\n");
|
||||
|
||||
dc = devm_gpiod_get_optional(dev, "dc", GPIOD_OUT_LOW);
|
||||
if (IS_ERR(dc))
|
||||
dev_err(dev, "Failed to get gpio 'dc'\n");
|
||||
|
||||
if (!strcmp(id->name, "sf-tc240t-9370-t"))
|
||||
return ili9341_dpi_probe(spi, dc, reset);
|
||||
else if (!strcmp(id->name, "yx240qv29"))
|
||||
return ili9341_dbi_probe(spi, dc, reset);
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
static int ili9341_remove(struct spi_device *spi)
|
||||
{
|
||||
const struct spi_device_id *id = spi_get_device_id(spi);
|
||||
struct ili9341 *ili = spi_get_drvdata(spi);
|
||||
struct drm_device *drm = spi_get_drvdata(spi);
|
||||
|
||||
if (!strcmp(id->name, "sf-tc240t-9370-t")) {
|
||||
ili9341_dpi_power_off(ili);
|
||||
drm_panel_remove(&ili->panel);
|
||||
} else if (!strcmp(id->name, "yx240qv29")) {
|
||||
drm_dev_unplug(drm);
|
||||
drm_atomic_helper_shutdown(drm);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void ili9341_shutdown(struct spi_device *spi)
|
||||
{
|
||||
const struct spi_device_id *id = spi_get_device_id(spi);
|
||||
|
||||
if (!strcmp(id->name, "yx240qv29"))
|
||||
drm_atomic_helper_shutdown(spi_get_drvdata(spi));
|
||||
}
|
||||
|
||||
static const struct of_device_id ili9341_of_match[] = {
|
||||
{
|
||||
.compatible = "st,sf-tc240t-9370-t",
|
||||
.data = &ili9341_stm32f429_disco_data,
|
||||
},
|
||||
{
|
||||
/* porting from tiny/ili9341.c
|
||||
* for original mipi dbi compitable
|
||||
*/
|
||||
.compatible = "adafruit,yx240qv29",
|
||||
.data = NULL,
|
||||
},
|
||||
{ }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, ili9341_of_match);
|
||||
|
||||
static const struct spi_device_id ili9341_id[] = {
|
||||
{ "yx240qv29", 0 },
|
||||
{ "sf-tc240t-9370-t", 0 },
|
||||
{ }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(spi, ili9341_id);
|
||||
|
||||
static struct spi_driver ili9341_driver = {
|
||||
.probe = ili9341_probe,
|
||||
.remove = ili9341_remove,
|
||||
.shutdown = ili9341_shutdown,
|
||||
.id_table = ili9341_id,
|
||||
.driver = {
|
||||
.name = "panel-ilitek-ili9341",
|
||||
.of_match_table = ili9341_of_match,
|
||||
},
|
||||
};
|
||||
module_spi_driver(ili9341_driver);
|
||||
|
||||
MODULE_AUTHOR("Dillon Min <dillon.minfei@gmail.com>");
|
||||
MODULE_DESCRIPTION("ILI9341 LCD panel driver");
|
||||
MODULE_LICENSE("GPL v2");
|
|
@ -0,0 +1,366 @@
|
|||
// SPDX-License-Identifier: GPL-2.0
|
||||
/*
|
||||
* Copyright 2021 Google Inc.
|
||||
*
|
||||
* Panel driver for the Samsung ATNA33XC20 panel. This panel can't be handled
|
||||
* by the DRM_PANEL_SIMPLE driver because its power sequencing is non-standard.
|
||||
*/
|
||||
|
||||
#include <linux/backlight.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/gpio/consumer.h>
|
||||
#include <linux/iopoll.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/pm_runtime.h>
|
||||
#include <linux/regulator/consumer.h>
|
||||
|
||||
#include <drm/drm_dp_aux_bus.h>
|
||||
#include <drm/drm_dp_helper.h>
|
||||
#include <drm/drm_edid.h>
|
||||
#include <drm/drm_panel.h>
|
||||
|
||||
struct atana33xc20_panel {
|
||||
struct drm_panel base;
|
||||
bool prepared;
|
||||
bool enabled;
|
||||
bool el3_was_on;
|
||||
|
||||
bool no_hpd;
|
||||
struct gpio_desc *hpd_gpio;
|
||||
|
||||
struct regulator *supply;
|
||||
struct gpio_desc *el_on3_gpio;
|
||||
|
||||
struct edid *edid;
|
||||
|
||||
ktime_t powered_off_time;
|
||||
ktime_t powered_on_time;
|
||||
ktime_t el_on3_off_time;
|
||||
};
|
||||
|
||||
static inline struct atana33xc20_panel *to_atana33xc20(struct drm_panel *panel)
|
||||
{
|
||||
return container_of(panel, struct atana33xc20_panel, base);
|
||||
}
|
||||
|
||||
static void atana33xc20_wait(ktime_t start_ktime, unsigned int min_ms)
|
||||
{
|
||||
ktime_t now_ktime, min_ktime;
|
||||
|
||||
min_ktime = ktime_add(start_ktime, ms_to_ktime(min_ms));
|
||||
now_ktime = ktime_get();
|
||||
|
||||
if (ktime_before(now_ktime, min_ktime))
|
||||
msleep(ktime_to_ms(ktime_sub(min_ktime, now_ktime)) + 1);
|
||||
}
|
||||
|
||||
static int atana33xc20_suspend(struct device *dev)
|
||||
{
|
||||
struct atana33xc20_panel *p = dev_get_drvdata(dev);
|
||||
int ret;
|
||||
|
||||
/*
|
||||
* Note 3 (Example of power off sequence in detail) in spec
|
||||
* specifies to wait 150 ms after deasserting EL3_ON before
|
||||
* powering off.
|
||||
*/
|
||||
if (p->el3_was_on)
|
||||
atana33xc20_wait(p->el_on3_off_time, 150);
|
||||
|
||||
ret = regulator_disable(p->supply);
|
||||
if (ret)
|
||||
return ret;
|
||||
p->powered_off_time = ktime_get();
|
||||
p->el3_was_on = false;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int atana33xc20_resume(struct device *dev)
|
||||
{
|
||||
struct atana33xc20_panel *p = dev_get_drvdata(dev);
|
||||
bool hpd_asserted = false;
|
||||
int ret;
|
||||
|
||||
/* T12 (Power off time) is min 500 ms */
|
||||
atana33xc20_wait(p->powered_off_time, 500);
|
||||
|
||||
ret = regulator_enable(p->supply);
|
||||
if (ret)
|
||||
return ret;
|
||||
p->powered_on_time = ktime_get();
|
||||
|
||||
/*
|
||||
* Handle HPD. Note: if HPD is hooked up to a dedicated pin on the
|
||||
* eDP controller then "no_hpd" will be false _and_ "hpd_gpio" will be
|
||||
* NULL. It's up to the controller driver to wait for HPD after
|
||||
* preparing the panel in that case.
|
||||
*/
|
||||
if (p->no_hpd) {
|
||||
/* T3 VCC to HPD high is max 200 ms */
|
||||
msleep(200);
|
||||
} else if (p->hpd_gpio) {
|
||||
ret = readx_poll_timeout(gpiod_get_value_cansleep, p->hpd_gpio,
|
||||
hpd_asserted, hpd_asserted,
|
||||
1000, 200000);
|
||||
if (!hpd_asserted)
|
||||
dev_warn(dev, "Timeout waiting for HPD\n");
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int atana33xc20_disable(struct drm_panel *panel)
|
||||
{
|
||||
struct atana33xc20_panel *p = to_atana33xc20(panel);
|
||||
|
||||
/* Disabling when already disabled is a no-op */
|
||||
if (!p->enabled)
|
||||
return 0;
|
||||
|
||||
gpiod_set_value_cansleep(p->el_on3_gpio, 0);
|
||||
p->el_on3_off_time = ktime_get();
|
||||
p->enabled = false;
|
||||
|
||||
/*
|
||||
* Keep track of the fact that EL_ON3 was on but we haven't power
|
||||
* cycled yet. This lets us know that "el_on3_off_time" is recent (we
|
||||
* don't need to worry about ktime wraparounds) and also makes it
|
||||
* obvious if we try to enable again without a power cycle (see the
|
||||
* warning in atana33xc20_enable()).
|
||||
*/
|
||||
p->el3_was_on = true;
|
||||
|
||||
/*
|
||||
* Sleeping 20 ms here (after setting the GPIO) avoids a glitch when
|
||||
* powering off.
|
||||
*/
|
||||
msleep(20);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int atana33xc20_enable(struct drm_panel *panel)
|
||||
{
|
||||
struct atana33xc20_panel *p = to_atana33xc20(panel);
|
||||
|
||||
/* Enabling when already enabled is a no-op */
|
||||
if (p->enabled)
|
||||
return 0;
|
||||
|
||||
/*
|
||||
* Once EL_ON3 drops we absolutely need a power cycle before the next
|
||||
* enable or the backlight will never come on again. The code ensures
|
||||
* this because disable() is _always_ followed by unprepare() and
|
||||
* unprepare() forces a suspend with pm_runtime_put_sync_suspend(),
|
||||
* but let's track just to make sure since the requirement is so
|
||||
* non-obvious.
|
||||
*/
|
||||
if (WARN_ON(p->el3_was_on))
|
||||
return -EIO;
|
||||
|
||||
/*
|
||||
* Note 2 (Example of power on sequence in detail) in spec specifies
|
||||
* to wait 400 ms after powering on before asserting EL3_on.
|
||||
*/
|
||||
atana33xc20_wait(p->powered_on_time, 400);
|
||||
|
||||
gpiod_set_value_cansleep(p->el_on3_gpio, 1);
|
||||
p->enabled = true;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int atana33xc20_unprepare(struct drm_panel *panel)
|
||||
{
|
||||
struct atana33xc20_panel *p = to_atana33xc20(panel);
|
||||
int ret;
|
||||
|
||||
/* Unpreparing when already unprepared is a no-op */
|
||||
if (!p->prepared)
|
||||
return 0;
|
||||
|
||||
/*
|
||||
* Purposely do a put_sync, don't use autosuspend. The panel's tcon
|
||||
* seems to sometimes crash when you stop giving it data and this is
|
||||
* the best way to ensure it will come back.
|
||||
*
|
||||
* NOTE: we still want autosuspend for cases where we only turn on
|
||||
* to get the EDID or otherwise send DP AUX commands to the panel.
|
||||
*/
|
||||
ret = pm_runtime_put_sync_suspend(panel->dev);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
p->prepared = false;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int atana33xc20_prepare(struct drm_panel *panel)
|
||||
{
|
||||
struct atana33xc20_panel *p = to_atana33xc20(panel);
|
||||
int ret;
|
||||
|
||||
/* Preparing when already prepared is a no-op */
|
||||
if (p->prepared)
|
||||
return 0;
|
||||
|
||||
ret = pm_runtime_get_sync(panel->dev);
|
||||
if (ret < 0) {
|
||||
pm_runtime_put_autosuspend(panel->dev);
|
||||
return ret;
|
||||
}
|
||||
p->prepared = true;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int atana33xc20_get_modes(struct drm_panel *panel,
|
||||
struct drm_connector *connector)
|
||||
{
|
||||
struct atana33xc20_panel *p = to_atana33xc20(panel);
|
||||
struct dp_aux_ep_device *aux_ep = to_dp_aux_ep_dev(panel->dev);
|
||||
int num = 0;
|
||||
|
||||
pm_runtime_get_sync(panel->dev);
|
||||
|
||||
if (!p->edid)
|
||||
p->edid = drm_get_edid(connector, &aux_ep->aux->ddc);
|
||||
num = drm_add_edid_modes(connector, p->edid);
|
||||
|
||||
pm_runtime_mark_last_busy(panel->dev);
|
||||
pm_runtime_put_autosuspend(panel->dev);
|
||||
|
||||
return num;
|
||||
}
|
||||
|
||||
static const struct drm_panel_funcs atana33xc20_funcs = {
|
||||
.disable = atana33xc20_disable,
|
||||
.enable = atana33xc20_enable,
|
||||
.unprepare = atana33xc20_unprepare,
|
||||
.prepare = atana33xc20_prepare,
|
||||
.get_modes = atana33xc20_get_modes,
|
||||
};
|
||||
|
||||
static void atana33xc20_runtime_disable(void *data)
|
||||
{
|
||||
pm_runtime_disable(data);
|
||||
}
|
||||
|
||||
static void atana33xc20_dont_use_autosuspend(void *data)
|
||||
{
|
||||
pm_runtime_dont_use_autosuspend(data);
|
||||
}
|
||||
|
||||
static int atana33xc20_probe(struct dp_aux_ep_device *aux_ep)
|
||||
{
|
||||
struct atana33xc20_panel *panel;
|
||||
struct device *dev = &aux_ep->dev;
|
||||
int ret;
|
||||
|
||||
panel = devm_kzalloc(dev, sizeof(*panel), GFP_KERNEL);
|
||||
if (!panel)
|
||||
return -ENOMEM;
|
||||
dev_set_drvdata(dev, panel);
|
||||
|
||||
panel->supply = devm_regulator_get(dev, "power");
|
||||
if (IS_ERR(panel->supply))
|
||||
return dev_err_probe(dev, PTR_ERR(panel->supply),
|
||||
"Failed to get power supply\n");
|
||||
|
||||
panel->el_on3_gpio = devm_gpiod_get(dev, "enable", GPIOD_OUT_LOW);
|
||||
if (IS_ERR(panel->el_on3_gpio))
|
||||
return dev_err_probe(dev, PTR_ERR(panel->el_on3_gpio),
|
||||
"Failed to get enable GPIO\n");
|
||||
|
||||
panel->no_hpd = of_property_read_bool(dev->of_node, "no-hpd");
|
||||
if (!panel->no_hpd) {
|
||||
panel->hpd_gpio = devm_gpiod_get_optional(dev, "hpd", GPIOD_IN);
|
||||
if (IS_ERR(panel->hpd_gpio))
|
||||
return dev_err_probe(dev, PTR_ERR(panel->hpd_gpio),
|
||||
"Failed to get HPD GPIO\n");
|
||||
}
|
||||
|
||||
pm_runtime_enable(dev);
|
||||
ret = devm_add_action_or_reset(dev, atana33xc20_runtime_disable, dev);
|
||||
if (ret)
|
||||
return ret;
|
||||
pm_runtime_set_autosuspend_delay(dev, 1000);
|
||||
pm_runtime_use_autosuspend(dev);
|
||||
ret = devm_add_action_or_reset(dev, atana33xc20_dont_use_autosuspend, dev);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
drm_panel_init(&panel->base, dev, &atana33xc20_funcs, DRM_MODE_CONNECTOR_eDP);
|
||||
|
||||
pm_runtime_get_sync(dev);
|
||||
ret = drm_panel_dp_aux_backlight(&panel->base, aux_ep->aux);
|
||||
pm_runtime_mark_last_busy(dev);
|
||||
pm_runtime_put_autosuspend(dev);
|
||||
if (ret)
|
||||
return dev_err_probe(dev, ret,
|
||||
"failed to register dp aux backlight\n");
|
||||
|
||||
drm_panel_add(&panel->base);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void atana33xc20_remove(struct dp_aux_ep_device *aux_ep)
|
||||
{
|
||||
struct device *dev = &aux_ep->dev;
|
||||
struct atana33xc20_panel *panel = dev_get_drvdata(dev);
|
||||
|
||||
drm_panel_remove(&panel->base);
|
||||
drm_panel_disable(&panel->base);
|
||||
drm_panel_unprepare(&panel->base);
|
||||
|
||||
kfree(panel->edid);
|
||||
}
|
||||
|
||||
static void atana33xc20_shutdown(struct dp_aux_ep_device *aux_ep)
|
||||
{
|
||||
struct device *dev = &aux_ep->dev;
|
||||
struct atana33xc20_panel *panel = dev_get_drvdata(dev);
|
||||
|
||||
drm_panel_disable(&panel->base);
|
||||
drm_panel_unprepare(&panel->base);
|
||||
}
|
||||
|
||||
static const struct of_device_id atana33xc20_dt_match[] = {
|
||||
{ .compatible = "samsung,atna33xc20", },
|
||||
{ /* sentinal */ }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, atana33xc20_dt_match);
|
||||
|
||||
static const struct dev_pm_ops atana33xc20_pm_ops = {
|
||||
SET_RUNTIME_PM_OPS(atana33xc20_suspend, atana33xc20_resume, NULL)
|
||||
SET_SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend,
|
||||
pm_runtime_force_resume)
|
||||
};
|
||||
|
||||
static struct dp_aux_ep_driver atana33xc20_driver = {
|
||||
.driver = {
|
||||
.name = "samsung_atana33xc20",
|
||||
.of_match_table = atana33xc20_dt_match,
|
||||
.pm = &atana33xc20_pm_ops,
|
||||
},
|
||||
.probe = atana33xc20_probe,
|
||||
.remove = atana33xc20_remove,
|
||||
.shutdown = atana33xc20_shutdown,
|
||||
};
|
||||
|
||||
static int __init atana33xc20_init(void)
|
||||
{
|
||||
return dp_aux_dp_driver_register(&atana33xc20_driver);
|
||||
}
|
||||
module_init(atana33xc20_init);
|
||||
|
||||
static void __exit atana33xc20_exit(void)
|
||||
{
|
||||
dp_aux_dp_driver_unregister(&atana33xc20_driver);
|
||||
}
|
||||
module_exit(atana33xc20_exit);
|
||||
|
||||
MODULE_DESCRIPTION("Samsung ATANA33XC20 Panel Driver");
|
||||
MODULE_LICENSE("GPL v2");
|
|
@ -132,22 +132,6 @@ struct panel_desc {
|
|||
*/
|
||||
unsigned int prepare_to_enable;
|
||||
|
||||
/**
|
||||
* @delay.power_to_enable: Time for the power to enable the display on.
|
||||
*
|
||||
* The time (in milliseconds) to wait after powering up the display
|
||||
* before asserting its enable pin.
|
||||
*/
|
||||
unsigned int power_to_enable;
|
||||
|
||||
/**
|
||||
* @delay.disable_to_power_off: Time for the disable to power the display off.
|
||||
*
|
||||
* The time (in milliseconds) to wait before powering off the display
|
||||
* after deasserting its enable pin.
|
||||
*/
|
||||
unsigned int disable_to_power_off;
|
||||
|
||||
/**
|
||||
* @delay.enable: Time for the panel to display a valid frame.
|
||||
*
|
||||
|
@ -363,10 +347,6 @@ static int panel_simple_suspend(struct device *dev)
|
|||
struct panel_simple *p = dev_get_drvdata(dev);
|
||||
|
||||
gpiod_set_value_cansleep(p->enable_gpio, 0);
|
||||
|
||||
if (p->desc->delay.disable_to_power_off)
|
||||
msleep(p->desc->delay.disable_to_power_off);
|
||||
|
||||
regulator_disable(p->supply);
|
||||
p->unprepared_time = ktime_get();
|
||||
|
||||
|
@ -427,9 +407,6 @@ static int panel_simple_prepare_once(struct panel_simple *p)
|
|||
return err;
|
||||
}
|
||||
|
||||
if (p->desc->delay.power_to_enable)
|
||||
msleep(p->desc->delay.power_to_enable);
|
||||
|
||||
gpiod_set_value_cansleep(p->enable_gpio, 1);
|
||||
|
||||
delay = p->desc->delay.prepare;
|
||||
|
@ -803,11 +780,6 @@ static int panel_simple_probe(struct device *dev, const struct panel_desc *desc,
|
|||
break;
|
||||
}
|
||||
|
||||
if (!panel->enable_gpio && desc->delay.disable_to_power_off)
|
||||
dev_warn(dev, "Need a delay after disabling panel GPIO, but a GPIO wasn't provided\n");
|
||||
if (!panel->enable_gpio && desc->delay.power_to_enable)
|
||||
dev_warn(dev, "Need a delay before enabling panel GPIO, but a GPIO wasn't provided\n");
|
||||
|
||||
dev_set_drvdata(dev, panel);
|
||||
|
||||
/*
|
||||
|
@ -2206,6 +2178,33 @@ static const struct panel_desc edt_etmv570g2dhu = {
|
|||
.connector_type = DRM_MODE_CONNECTOR_DPI,
|
||||
};
|
||||
|
||||
static const struct display_timing eink_vb3300_kca_timing = {
|
||||
.pixelclock = { 40000000, 40000000, 40000000 },
|
||||
.hactive = { 334, 334, 334 },
|
||||
.hfront_porch = { 1, 1, 1 },
|
||||
.hback_porch = { 1, 1, 1 },
|
||||
.hsync_len = { 1, 1, 1 },
|
||||
.vactive = { 1405, 1405, 1405 },
|
||||
.vfront_porch = { 1, 1, 1 },
|
||||
.vback_porch = { 1, 1, 1 },
|
||||
.vsync_len = { 1, 1, 1 },
|
||||
.flags = DISPLAY_FLAGS_HSYNC_LOW | DISPLAY_FLAGS_VSYNC_LOW |
|
||||
DISPLAY_FLAGS_DE_HIGH | DISPLAY_FLAGS_PIXDATA_POSEDGE,
|
||||
};
|
||||
|
||||
static const struct panel_desc eink_vb3300_kca = {
|
||||
.timings = &eink_vb3300_kca_timing,
|
||||
.num_timings = 1,
|
||||
.bpc = 6,
|
||||
.size = {
|
||||
.width = 157,
|
||||
.height = 209,
|
||||
},
|
||||
.bus_format = MEDIA_BUS_FMT_RGB888_1X24,
|
||||
.bus_flags = DRM_BUS_FLAG_DE_HIGH | DRM_BUS_FLAG_PIXDATA_DRIVE_POSEDGE,
|
||||
.connector_type = DRM_MODE_CONNECTOR_DPI,
|
||||
};
|
||||
|
||||
static const struct display_timing evervision_vgg804821_timing = {
|
||||
.pixelclock = { 27600000, 33300000, 50000000 },
|
||||
.hactive = { 800, 800, 800 },
|
||||
|
@ -3623,6 +3622,46 @@ static const struct panel_desc qd43003c0_40 = {
|
|||
.bus_format = MEDIA_BUS_FMT_RGB888_1X24,
|
||||
};
|
||||
|
||||
static const struct drm_display_mode qishenglong_gopher2b_lcd_modes[] = {
|
||||
{ /* 60 Hz */
|
||||
.clock = 10800,
|
||||
.hdisplay = 480,
|
||||
.hsync_start = 480 + 77,
|
||||
.hsync_end = 480 + 77 + 41,
|
||||
.htotal = 480 + 77 + 41 + 2,
|
||||
.vdisplay = 272,
|
||||
.vsync_start = 272 + 16,
|
||||
.vsync_end = 272 + 16 + 10,
|
||||
.vtotal = 272 + 16 + 10 + 2,
|
||||
.flags = DRM_MODE_FLAG_NVSYNC | DRM_MODE_FLAG_NHSYNC,
|
||||
},
|
||||
{ /* 50 Hz */
|
||||
.clock = 10800,
|
||||
.hdisplay = 480,
|
||||
.hsync_start = 480 + 17,
|
||||
.hsync_end = 480 + 17 + 41,
|
||||
.htotal = 480 + 17 + 41 + 2,
|
||||
.vdisplay = 272,
|
||||
.vsync_start = 272 + 116,
|
||||
.vsync_end = 272 + 116 + 10,
|
||||
.vtotal = 272 + 116 + 10 + 2,
|
||||
.flags = DRM_MODE_FLAG_NVSYNC | DRM_MODE_FLAG_NHSYNC,
|
||||
},
|
||||
};
|
||||
|
||||
static const struct panel_desc qishenglong_gopher2b_lcd = {
|
||||
.modes = qishenglong_gopher2b_lcd_modes,
|
||||
.num_modes = ARRAY_SIZE(qishenglong_gopher2b_lcd_modes),
|
||||
.bpc = 8,
|
||||
.size = {
|
||||
.width = 95,
|
||||
.height = 54,
|
||||
},
|
||||
.bus_format = MEDIA_BUS_FMT_RGB888_1X24,
|
||||
.bus_flags = DRM_BUS_FLAG_DE_HIGH | DRM_BUS_FLAG_PIXDATA_SAMPLE_NEGEDGE,
|
||||
.connector_type = DRM_MODE_CONNECTOR_DPI,
|
||||
};
|
||||
|
||||
static const struct display_timing rocktech_rk070er9427_timing = {
|
||||
.pixelclock = { 26400000, 33300000, 46800000 },
|
||||
.hactive = { 800, 800, 800 },
|
||||
|
@ -3681,36 +3720,6 @@ static const struct panel_desc rocktech_rk101ii01d_ct = {
|
|||
.connector_type = DRM_MODE_CONNECTOR_LVDS,
|
||||
};
|
||||
|
||||
static const struct drm_display_mode samsung_atna33xc20_mode = {
|
||||
.clock = 138770,
|
||||
.hdisplay = 1920,
|
||||
.hsync_start = 1920 + 48,
|
||||
.hsync_end = 1920 + 48 + 32,
|
||||
.htotal = 1920 + 48 + 32 + 80,
|
||||
.vdisplay = 1080,
|
||||
.vsync_start = 1080 + 8,
|
||||
.vsync_end = 1080 + 8 + 8,
|
||||
.vtotal = 1080 + 8 + 8 + 16,
|
||||
.flags = DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_NVSYNC,
|
||||
};
|
||||
|
||||
static const struct panel_desc samsung_atna33xc20 = {
|
||||
.modes = &samsung_atna33xc20_mode,
|
||||
.num_modes = 1,
|
||||
.bpc = 10,
|
||||
.size = {
|
||||
.width = 294,
|
||||
.height = 165,
|
||||
},
|
||||
.delay = {
|
||||
.disable_to_power_off = 200,
|
||||
.power_to_enable = 400,
|
||||
.hpd_absent_delay = 200,
|
||||
.unprepare = 500,
|
||||
},
|
||||
.connector_type = DRM_MODE_CONNECTOR_eDP,
|
||||
};
|
||||
|
||||
static const struct drm_display_mode samsung_lsn122dl01_c01_mode = {
|
||||
.clock = 271560,
|
||||
.hdisplay = 2560,
|
||||
|
@ -4552,6 +4561,9 @@ static const struct of_device_id platform_of_match[] = {
|
|||
}, {
|
||||
.compatible = "edt,etmv570g2dhu",
|
||||
.data = &edt_etmv570g2dhu,
|
||||
}, {
|
||||
.compatible = "eink,vb3300-kca",
|
||||
.data = &eink_vb3300_kca,
|
||||
}, {
|
||||
.compatible = "evervision,vgg804821",
|
||||
.data = &evervision_vgg804821,
|
||||
|
@ -4717,15 +4729,15 @@ static const struct of_device_id platform_of_match[] = {
|
|||
}, {
|
||||
.compatible = "qiaodian,qd43003c0-40",
|
||||
.data = &qd43003c0_40,
|
||||
}, {
|
||||
.compatible = "qishenglong,gopher2b-lcd",
|
||||
.data = &qishenglong_gopher2b_lcd,
|
||||
}, {
|
||||
.compatible = "rocktech,rk070er9427",
|
||||
.data = &rocktech_rk070er9427,
|
||||
}, {
|
||||
.compatible = "rocktech,rk101ii01d-ct",
|
||||
.data = &rocktech_rk101ii01d_ct,
|
||||
}, {
|
||||
.compatible = "samsung,atna33xc20",
|
||||
.data = &samsung_atna33xc20,
|
||||
}, {
|
||||
.compatible = "samsung,lsn122dl01-c01",
|
||||
.data = &samsung_lsn122dl01_c01,
|
||||
|
|
|
@ -11,7 +11,6 @@
|
|||
|
||||
#include <linux/clk.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/version.h>
|
||||
#include <linux/dma-buf.h>
|
||||
#include <linux/of_graph.h>
|
||||
|
||||
|
|
|
@ -44,7 +44,6 @@
|
|||
#include <linux/of_reserved_mem.h>
|
||||
#include <linux/shmem_fs.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/version.h>
|
||||
|
||||
#include <drm/drm_atomic_helper.h>
|
||||
#include <drm/drm_bridge.h>
|
||||
|
|
|
@ -6,9 +6,37 @@
|
|||
#define pr_fmt(fmt) "drm_damage_helper: " fmt
|
||||
|
||||
#include <drm/drm_damage_helper.h>
|
||||
#include <drm/drm_plane.h>
|
||||
#include <drm/drm_drv.h>
|
||||
|
||||
#include "test-drm_modeset_common.h"
|
||||
|
||||
struct drm_driver mock_driver;
|
||||
static struct drm_device mock_device;
|
||||
static struct drm_object_properties mock_obj_props;
|
||||
static struct drm_plane mock_plane;
|
||||
static struct drm_property mock_prop;
|
||||
|
||||
static void mock_setup(struct drm_plane_state *state)
|
||||
{
|
||||
static bool setup_done = false;
|
||||
|
||||
state->plane = &mock_plane;
|
||||
|
||||
if (setup_done)
|
||||
return;
|
||||
|
||||
/* just enough so that drm_plane_enable_fb_damage_clips() works */
|
||||
mock_device.driver = &mock_driver;
|
||||
mock_device.mode_config.prop_fb_damage_clips = &mock_prop;
|
||||
mock_plane.dev = &mock_device;
|
||||
mock_plane.base.properties = &mock_obj_props;
|
||||
mock_prop.base.id = 1; /* 0 is an invalid id */
|
||||
mock_prop.dev = &mock_device;
|
||||
|
||||
drm_plane_enable_fb_damage_clips(&mock_plane);
|
||||
}
|
||||
|
||||
static void set_plane_src(struct drm_plane_state *state, int x1, int y1, int x2,
|
||||
int y2)
|
||||
{
|
||||
|
@ -70,23 +98,29 @@ static bool check_damage_clip(struct drm_plane_state *state, struct drm_rect *r,
|
|||
return true;
|
||||
}
|
||||
|
||||
const struct drm_framebuffer fb = {
|
||||
.width = 2048,
|
||||
.height = 2048
|
||||
};
|
||||
|
||||
/* common mocked structs many tests need */
|
||||
#define MOCK_VARIABLES() \
|
||||
struct drm_plane_state old_state; \
|
||||
struct drm_plane_state state = { \
|
||||
.crtc = ZERO_SIZE_PTR, \
|
||||
.fb = (struct drm_framebuffer *) &fb, \
|
||||
.visible = true, \
|
||||
}; \
|
||||
mock_setup(&old_state); \
|
||||
mock_setup(&state);
|
||||
|
||||
int igt_damage_iter_no_damage(void *ignored)
|
||||
{
|
||||
struct drm_atomic_helper_damage_iter iter;
|
||||
struct drm_plane_state old_state;
|
||||
struct drm_rect clip;
|
||||
uint32_t num_hits = 0;
|
||||
|
||||
struct drm_framebuffer fb = {
|
||||
.width = 2048,
|
||||
.height = 2048
|
||||
};
|
||||
|
||||
struct drm_plane_state state = {
|
||||
.crtc = ZERO_SIZE_PTR,
|
||||
.fb = &fb,
|
||||
.visible = true,
|
||||
};
|
||||
MOCK_VARIABLES();
|
||||
|
||||
/* Plane src same as fb size. */
|
||||
set_plane_src(&old_state, 0, 0, fb.width << 16, fb.height << 16);
|
||||
|
@ -104,20 +138,10 @@ int igt_damage_iter_no_damage(void *ignored)
|
|||
int igt_damage_iter_no_damage_fractional_src(void *ignored)
|
||||
{
|
||||
struct drm_atomic_helper_damage_iter iter;
|
||||
struct drm_plane_state old_state;
|
||||
struct drm_rect clip;
|
||||
uint32_t num_hits = 0;
|
||||
|
||||
struct drm_framebuffer fb = {
|
||||
.width = 2048,
|
||||
.height = 2048
|
||||
};
|
||||
|
||||
struct drm_plane_state state = {
|
||||
.crtc = ZERO_SIZE_PTR,
|
||||
.fb = &fb,
|
||||
.visible = true,
|
||||
};
|
||||
MOCK_VARIABLES();
|
||||
|
||||
/* Plane src has fractional part. */
|
||||
set_plane_src(&old_state, 0x3fffe, 0x3fffe,
|
||||
|
@ -137,20 +161,10 @@ int igt_damage_iter_no_damage_fractional_src(void *ignored)
|
|||
int igt_damage_iter_no_damage_src_moved(void *ignored)
|
||||
{
|
||||
struct drm_atomic_helper_damage_iter iter;
|
||||
struct drm_plane_state old_state;
|
||||
struct drm_rect clip;
|
||||
uint32_t num_hits = 0;
|
||||
|
||||
struct drm_framebuffer fb = {
|
||||
.width = 2048,
|
||||
.height = 2048
|
||||
};
|
||||
|
||||
struct drm_plane_state state = {
|
||||
.crtc = ZERO_SIZE_PTR,
|
||||
.fb = &fb,
|
||||
.visible = true,
|
||||
};
|
||||
MOCK_VARIABLES();
|
||||
|
||||
/* Plane src moved since old plane state. */
|
||||
set_plane_src(&old_state, 0, 0, 1024 << 16, 768 << 16);
|
||||
|
@ -169,20 +183,10 @@ int igt_damage_iter_no_damage_src_moved(void *ignored)
|
|||
int igt_damage_iter_no_damage_fractional_src_moved(void *ignored)
|
||||
{
|
||||
struct drm_atomic_helper_damage_iter iter;
|
||||
struct drm_plane_state old_state;
|
||||
struct drm_rect clip;
|
||||
uint32_t num_hits = 0;
|
||||
|
||||
struct drm_framebuffer fb = {
|
||||
.width = 2048,
|
||||
.height = 2048
|
||||
};
|
||||
|
||||
struct drm_plane_state state = {
|
||||
.crtc = ZERO_SIZE_PTR,
|
||||
.fb = &fb,
|
||||
.visible = true,
|
||||
};
|
||||
MOCK_VARIABLES();
|
||||
|
||||
/* Plane src has fractional part and it moved since old plane state. */
|
||||
set_plane_src(&old_state, 0x3fffe, 0x3fffe,
|
||||
|
@ -202,20 +206,14 @@ int igt_damage_iter_no_damage_fractional_src_moved(void *ignored)
|
|||
int igt_damage_iter_no_damage_not_visible(void *ignored)
|
||||
{
|
||||
struct drm_atomic_helper_damage_iter iter;
|
||||
struct drm_plane_state old_state;
|
||||
struct drm_rect clip;
|
||||
uint32_t num_hits = 0;
|
||||
|
||||
struct drm_framebuffer fb = {
|
||||
.width = 2048,
|
||||
.height = 2048
|
||||
};
|
||||
MOCK_VARIABLES();
|
||||
|
||||
struct drm_plane_state state = {
|
||||
.crtc = ZERO_SIZE_PTR,
|
||||
.fb = &fb,
|
||||
.visible = false,
|
||||
};
|
||||
state.visible = false;
|
||||
|
||||
mock_setup(&old_state);
|
||||
|
||||
set_plane_src(&old_state, 0, 0, 1024 << 16, 768 << 16);
|
||||
set_plane_src(&state, 0, 0, 1024 << 16, 768 << 16);
|
||||
|
@ -231,19 +229,12 @@ int igt_damage_iter_no_damage_not_visible(void *ignored)
|
|||
int igt_damage_iter_no_damage_no_crtc(void *ignored)
|
||||
{
|
||||
struct drm_atomic_helper_damage_iter iter;
|
||||
struct drm_plane_state old_state;
|
||||
struct drm_rect clip;
|
||||
uint32_t num_hits = 0;
|
||||
|
||||
struct drm_framebuffer fb = {
|
||||
.width = 2048,
|
||||
.height = 2048
|
||||
};
|
||||
MOCK_VARIABLES();
|
||||
|
||||
struct drm_plane_state state = {
|
||||
.crtc = 0,
|
||||
.fb = &fb,
|
||||
};
|
||||
state.crtc = NULL;
|
||||
|
||||
set_plane_src(&old_state, 0, 0, 1024 << 16, 768 << 16);
|
||||
set_plane_src(&state, 0, 0, 1024 << 16, 768 << 16);
|
||||
|
@ -268,6 +259,8 @@ int igt_damage_iter_no_damage_no_fb(void *ignored)
|
|||
.fb = 0,
|
||||
};
|
||||
|
||||
mock_setup(&old_state);
|
||||
|
||||
set_plane_src(&old_state, 0, 0, 1024 << 16, 768 << 16);
|
||||
set_plane_src(&state, 0, 0, 1024 << 16, 768 << 16);
|
||||
drm_atomic_helper_damage_iter_init(&iter, &old_state, &state);
|
||||
|
@ -282,22 +275,12 @@ int igt_damage_iter_no_damage_no_fb(void *ignored)
|
|||
int igt_damage_iter_simple_damage(void *ignored)
|
||||
{
|
||||
struct drm_atomic_helper_damage_iter iter;
|
||||
struct drm_plane_state old_state;
|
||||
struct drm_property_blob damage_blob;
|
||||
struct drm_mode_rect damage;
|
||||
struct drm_rect clip;
|
||||
uint32_t num_hits = 0;
|
||||
|
||||
struct drm_framebuffer fb = {
|
||||
.width = 2048,
|
||||
.height = 2048
|
||||
};
|
||||
|
||||
struct drm_plane_state state = {
|
||||
.crtc = ZERO_SIZE_PTR,
|
||||
.fb = &fb,
|
||||
.visible = true,
|
||||
};
|
||||
MOCK_VARIABLES();
|
||||
|
||||
set_plane_src(&old_state, 0, 0, 1024 << 16, 768 << 16);
|
||||
set_plane_src(&state, 0, 0, 1024 << 16, 768 << 16);
|
||||
|
@ -318,22 +301,12 @@ int igt_damage_iter_simple_damage(void *ignored)
|
|||
int igt_damage_iter_single_damage(void *ignored)
|
||||
{
|
||||
struct drm_atomic_helper_damage_iter iter;
|
||||
struct drm_plane_state old_state;
|
||||
struct drm_property_blob damage_blob;
|
||||
struct drm_mode_rect damage;
|
||||
struct drm_rect clip;
|
||||
uint32_t num_hits = 0;
|
||||
|
||||
struct drm_framebuffer fb = {
|
||||
.width = 2048,
|
||||
.height = 2048
|
||||
};
|
||||
|
||||
struct drm_plane_state state = {
|
||||
.crtc = ZERO_SIZE_PTR,
|
||||
.fb = &fb,
|
||||
.visible = true,
|
||||
};
|
||||
MOCK_VARIABLES();
|
||||
|
||||
set_plane_src(&old_state, 0, 0, 1024 << 16, 768 << 16);
|
||||
set_plane_src(&state, 0, 0, 1024 << 16, 768 << 16);
|
||||
|
@ -353,22 +326,12 @@ int igt_damage_iter_single_damage(void *ignored)
|
|||
int igt_damage_iter_single_damage_intersect_src(void *ignored)
|
||||
{
|
||||
struct drm_atomic_helper_damage_iter iter;
|
||||
struct drm_plane_state old_state;
|
||||
struct drm_property_blob damage_blob;
|
||||
struct drm_mode_rect damage;
|
||||
struct drm_rect clip;
|
||||
uint32_t num_hits = 0;
|
||||
|
||||
struct drm_framebuffer fb = {
|
||||
.width = 2048,
|
||||
.height = 2048
|
||||
};
|
||||
|
||||
struct drm_plane_state state = {
|
||||
.crtc = ZERO_SIZE_PTR,
|
||||
.fb = &fb,
|
||||
.visible = true,
|
||||
};
|
||||
MOCK_VARIABLES();
|
||||
|
||||
set_plane_src(&old_state, 0, 0, 1024 << 16, 768 << 16);
|
||||
set_plane_src(&state, 0, 0, 1024 << 16, 768 << 16);
|
||||
|
@ -389,22 +352,12 @@ int igt_damage_iter_single_damage_intersect_src(void *ignored)
|
|||
int igt_damage_iter_single_damage_outside_src(void *ignored)
|
||||
{
|
||||
struct drm_atomic_helper_damage_iter iter;
|
||||
struct drm_plane_state old_state;
|
||||
struct drm_property_blob damage_blob;
|
||||
struct drm_mode_rect damage;
|
||||
struct drm_rect clip;
|
||||
uint32_t num_hits = 0;
|
||||
|
||||
struct drm_framebuffer fb = {
|
||||
.width = 2048,
|
||||
.height = 2048
|
||||
};
|
||||
|
||||
struct drm_plane_state state = {
|
||||
.crtc = ZERO_SIZE_PTR,
|
||||
.fb = &fb,
|
||||
.visible = true,
|
||||
};
|
||||
MOCK_VARIABLES();
|
||||
|
||||
set_plane_src(&old_state, 0, 0, 1024 << 16, 768 << 16);
|
||||
set_plane_src(&state, 0, 0, 1024 << 16, 768 << 16);
|
||||
|
@ -424,22 +377,12 @@ int igt_damage_iter_single_damage_outside_src(void *ignored)
|
|||
int igt_damage_iter_single_damage_fractional_src(void *ignored)
|
||||
{
|
||||
struct drm_atomic_helper_damage_iter iter;
|
||||
struct drm_plane_state old_state;
|
||||
struct drm_property_blob damage_blob;
|
||||
struct drm_mode_rect damage;
|
||||
struct drm_rect clip;
|
||||
uint32_t num_hits = 0;
|
||||
|
||||
struct drm_framebuffer fb = {
|
||||
.width = 2048,
|
||||
.height = 2048
|
||||
};
|
||||
|
||||
struct drm_plane_state state = {
|
||||
.crtc = ZERO_SIZE_PTR,
|
||||
.fb = &fb,
|
||||
.visible = true,
|
||||
};
|
||||
MOCK_VARIABLES();
|
||||
|
||||
/* Plane src has fractional part. */
|
||||
set_plane_src(&old_state, 0x40002, 0x40002,
|
||||
|
@ -462,22 +405,12 @@ int igt_damage_iter_single_damage_fractional_src(void *ignored)
|
|||
int igt_damage_iter_single_damage_intersect_fractional_src(void *ignored)
|
||||
{
|
||||
struct drm_atomic_helper_damage_iter iter;
|
||||
struct drm_plane_state old_state;
|
||||
struct drm_property_blob damage_blob;
|
||||
struct drm_mode_rect damage;
|
||||
struct drm_rect clip;
|
||||
uint32_t num_hits = 0;
|
||||
|
||||
struct drm_framebuffer fb = {
|
||||
.width = 2048,
|
||||
.height = 2048
|
||||
};
|
||||
|
||||
struct drm_plane_state state = {
|
||||
.crtc = ZERO_SIZE_PTR,
|
||||
.fb = &fb,
|
||||
.visible = true,
|
||||
};
|
||||
MOCK_VARIABLES();
|
||||
|
||||
/* Plane src has fractional part. */
|
||||
set_plane_src(&old_state, 0x40002, 0x40002,
|
||||
|
@ -501,22 +434,12 @@ int igt_damage_iter_single_damage_intersect_fractional_src(void *ignored)
|
|||
int igt_damage_iter_single_damage_outside_fractional_src(void *ignored)
|
||||
{
|
||||
struct drm_atomic_helper_damage_iter iter;
|
||||
struct drm_plane_state old_state;
|
||||
struct drm_property_blob damage_blob;
|
||||
struct drm_mode_rect damage;
|
||||
struct drm_rect clip;
|
||||
uint32_t num_hits = 0;
|
||||
|
||||
struct drm_framebuffer fb = {
|
||||
.width = 2048,
|
||||
.height = 2048
|
||||
};
|
||||
|
||||
struct drm_plane_state state = {
|
||||
.crtc = ZERO_SIZE_PTR,
|
||||
.fb = &fb,
|
||||
.visible = true,
|
||||
};
|
||||
MOCK_VARIABLES();
|
||||
|
||||
/* Plane src has fractional part. */
|
||||
set_plane_src(&old_state, 0x40002, 0x40002,
|
||||
|
@ -539,22 +462,12 @@ int igt_damage_iter_single_damage_outside_fractional_src(void *ignored)
|
|||
int igt_damage_iter_single_damage_src_moved(void *ignored)
|
||||
{
|
||||
struct drm_atomic_helper_damage_iter iter;
|
||||
struct drm_plane_state old_state;
|
||||
struct drm_property_blob damage_blob;
|
||||
struct drm_mode_rect damage;
|
||||
struct drm_rect clip;
|
||||
uint32_t num_hits = 0;
|
||||
|
||||
struct drm_framebuffer fb = {
|
||||
.width = 2048,
|
||||
.height = 2048
|
||||
};
|
||||
|
||||
struct drm_plane_state state = {
|
||||
.crtc = ZERO_SIZE_PTR,
|
||||
.fb = &fb,
|
||||
.visible = true,
|
||||
};
|
||||
MOCK_VARIABLES();
|
||||
|
||||
/* Plane src moved since old plane state. */
|
||||
set_plane_src(&old_state, 0, 0, 1024 << 16, 768 << 16);
|
||||
|
@ -576,22 +489,12 @@ int igt_damage_iter_single_damage_src_moved(void *ignored)
|
|||
int igt_damage_iter_single_damage_fractional_src_moved(void *ignored)
|
||||
{
|
||||
struct drm_atomic_helper_damage_iter iter;
|
||||
struct drm_plane_state old_state;
|
||||
struct drm_property_blob damage_blob;
|
||||
struct drm_mode_rect damage;
|
||||
struct drm_rect clip;
|
||||
uint32_t num_hits = 0;
|
||||
|
||||
struct drm_framebuffer fb = {
|
||||
.width = 2048,
|
||||
.height = 2048
|
||||
};
|
||||
|
||||
struct drm_plane_state state = {
|
||||
.crtc = ZERO_SIZE_PTR,
|
||||
.fb = &fb,
|
||||
.visible = true,
|
||||
};
|
||||
MOCK_VARIABLES();
|
||||
|
||||
/* Plane src with fractional part moved since old plane state. */
|
||||
set_plane_src(&old_state, 0x3fffe, 0x3fffe,
|
||||
|
@ -615,22 +518,12 @@ int igt_damage_iter_single_damage_fractional_src_moved(void *ignored)
|
|||
int igt_damage_iter_damage(void *ignored)
|
||||
{
|
||||
struct drm_atomic_helper_damage_iter iter;
|
||||
struct drm_plane_state old_state;
|
||||
struct drm_property_blob damage_blob;
|
||||
struct drm_mode_rect damage[2];
|
||||
struct drm_rect clip;
|
||||
uint32_t num_hits = 0;
|
||||
|
||||
struct drm_framebuffer fb = {
|
||||
.width = 2048,
|
||||
.height = 2048
|
||||
};
|
||||
|
||||
struct drm_plane_state state = {
|
||||
.crtc = ZERO_SIZE_PTR,
|
||||
.fb = &fb,
|
||||
.visible = true,
|
||||
};
|
||||
MOCK_VARIABLES();
|
||||
|
||||
set_plane_src(&old_state, 0, 0, 1024 << 16, 768 << 16);
|
||||
set_plane_src(&state, 0, 0, 1024 << 16, 768 << 16);
|
||||
|
@ -656,22 +549,12 @@ int igt_damage_iter_damage(void *ignored)
|
|||
int igt_damage_iter_damage_one_intersect(void *ignored)
|
||||
{
|
||||
struct drm_atomic_helper_damage_iter iter;
|
||||
struct drm_plane_state old_state;
|
||||
struct drm_property_blob damage_blob;
|
||||
struct drm_mode_rect damage[2];
|
||||
struct drm_rect clip;
|
||||
uint32_t num_hits = 0;
|
||||
|
||||
struct drm_framebuffer fb = {
|
||||
.width = 2048,
|
||||
.height = 2048
|
||||
};
|
||||
|
||||
struct drm_plane_state state = {
|
||||
.crtc = ZERO_SIZE_PTR,
|
||||
.fb = &fb,
|
||||
.visible = true,
|
||||
};
|
||||
MOCK_VARIABLES();
|
||||
|
||||
set_plane_src(&old_state, 0x40002, 0x40002,
|
||||
0x40002 + (1024 << 16), 0x40002 + (768 << 16));
|
||||
|
@ -699,22 +582,12 @@ int igt_damage_iter_damage_one_intersect(void *ignored)
|
|||
int igt_damage_iter_damage_one_outside(void *ignored)
|
||||
{
|
||||
struct drm_atomic_helper_damage_iter iter;
|
||||
struct drm_plane_state old_state;
|
||||
struct drm_property_blob damage_blob;
|
||||
struct drm_mode_rect damage[2];
|
||||
struct drm_rect clip;
|
||||
uint32_t num_hits = 0;
|
||||
|
||||
struct drm_framebuffer fb = {
|
||||
.width = 2048,
|
||||
.height = 2048
|
||||
};
|
||||
|
||||
struct drm_plane_state state = {
|
||||
.crtc = ZERO_SIZE_PTR,
|
||||
.fb = &fb,
|
||||
.visible = true,
|
||||
};
|
||||
MOCK_VARIABLES();
|
||||
|
||||
set_plane_src(&old_state, 0, 0, 1024 << 16, 768 << 16);
|
||||
set_plane_src(&state, 0, 0, 1024 << 16, 768 << 16);
|
||||
|
@ -736,22 +609,12 @@ int igt_damage_iter_damage_one_outside(void *ignored)
|
|||
int igt_damage_iter_damage_src_moved(void *ignored)
|
||||
{
|
||||
struct drm_atomic_helper_damage_iter iter;
|
||||
struct drm_plane_state old_state;
|
||||
struct drm_property_blob damage_blob;
|
||||
struct drm_mode_rect damage[2];
|
||||
struct drm_rect clip;
|
||||
uint32_t num_hits = 0;
|
||||
|
||||
struct drm_framebuffer fb = {
|
||||
.width = 2048,
|
||||
.height = 2048
|
||||
};
|
||||
|
||||
struct drm_plane_state state = {
|
||||
.crtc = ZERO_SIZE_PTR,
|
||||
.fb = &fb,
|
||||
.visible = true,
|
||||
};
|
||||
MOCK_VARIABLES();
|
||||
|
||||
set_plane_src(&old_state, 0x40002, 0x40002,
|
||||
0x40002 + (1024 << 16), 0x40002 + (768 << 16));
|
||||
|
@ -775,22 +638,14 @@ int igt_damage_iter_damage_src_moved(void *ignored)
|
|||
int igt_damage_iter_damage_not_visible(void *ignored)
|
||||
{
|
||||
struct drm_atomic_helper_damage_iter iter;
|
||||
struct drm_plane_state old_state;
|
||||
struct drm_property_blob damage_blob;
|
||||
struct drm_mode_rect damage[2];
|
||||
struct drm_rect clip;
|
||||
uint32_t num_hits = 0;
|
||||
|
||||
struct drm_framebuffer fb = {
|
||||
.width = 2048,
|
||||
.height = 2048
|
||||
};
|
||||
MOCK_VARIABLES();
|
||||
|
||||
struct drm_plane_state state = {
|
||||
.crtc = ZERO_SIZE_PTR,
|
||||
.fb = &fb,
|
||||
.visible = false,
|
||||
};
|
||||
state.visible = false;
|
||||
|
||||
set_plane_src(&old_state, 0x40002, 0x40002,
|
||||
0x40002 + (1024 << 16), 0x40002 + (768 << 16));
|
||||
|
|
|
@ -257,7 +257,7 @@ void vkms_composer_worker(struct work_struct *work)
|
|||
return;
|
||||
|
||||
if (wb_pending)
|
||||
vaddr_out = crtc_state->active_writeback;
|
||||
vaddr_out = crtc_state->active_writeback->map[0].vaddr;
|
||||
|
||||
ret = compose_active_planes(&vaddr_out, primary_composer,
|
||||
crtc_state);
|
||||
|
|
|
@ -20,6 +20,10 @@
|
|||
#define XRES_MAX 8192
|
||||
#define YRES_MAX 8192
|
||||
|
||||
struct vkms_writeback_job {
|
||||
struct dma_buf_map map[DRM_FORMAT_MAX_PLANES];
|
||||
};
|
||||
|
||||
struct vkms_composer {
|
||||
struct drm_framebuffer fb;
|
||||
struct drm_rect src, dst;
|
||||
|
@ -57,7 +61,7 @@ struct vkms_crtc_state {
|
|||
int num_active_planes;
|
||||
/* stack of active planes for crc computation, should be in z order */
|
||||
struct vkms_plane_state **active_planes;
|
||||
void *active_writeback;
|
||||
struct vkms_writeback_job *active_writeback;
|
||||
|
||||
/* below four are protected by vkms_output.composer_lock */
|
||||
bool crc_pending;
|
||||
|
|
|
@ -65,41 +65,45 @@ static int vkms_wb_connector_get_modes(struct drm_connector *connector)
|
|||
static int vkms_wb_prepare_job(struct drm_writeback_connector *wb_connector,
|
||||
struct drm_writeback_job *job)
|
||||
{
|
||||
struct drm_gem_object *gem_obj;
|
||||
struct dma_buf_map map;
|
||||
struct vkms_writeback_job *vkmsjob;
|
||||
int ret;
|
||||
|
||||
if (!job->fb)
|
||||
return 0;
|
||||
|
||||
gem_obj = drm_gem_fb_get_obj(job->fb, 0);
|
||||
ret = drm_gem_shmem_vmap(gem_obj, &map);
|
||||
vkmsjob = kzalloc(sizeof(*vkmsjob), GFP_KERNEL);
|
||||
if (!vkmsjob)
|
||||
return -ENOMEM;
|
||||
|
||||
ret = drm_gem_fb_vmap(job->fb, vkmsjob->map);
|
||||
if (ret) {
|
||||
DRM_ERROR("vmap failed: %d\n", ret);
|
||||
return ret;
|
||||
goto err_kfree;
|
||||
}
|
||||
|
||||
job->priv = map.vaddr;
|
||||
job->priv = vkmsjob;
|
||||
|
||||
return 0;
|
||||
|
||||
err_kfree:
|
||||
kfree(vkmsjob);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void vkms_wb_cleanup_job(struct drm_writeback_connector *connector,
|
||||
struct drm_writeback_job *job)
|
||||
{
|
||||
struct drm_gem_object *gem_obj;
|
||||
struct vkms_writeback_job *vkmsjob = job->priv;
|
||||
struct vkms_device *vkmsdev;
|
||||
struct dma_buf_map map;
|
||||
|
||||
if (!job->fb)
|
||||
return;
|
||||
|
||||
gem_obj = drm_gem_fb_get_obj(job->fb, 0);
|
||||
dma_buf_map_set_vaddr(&map, job->priv);
|
||||
drm_gem_shmem_vunmap(gem_obj, &map);
|
||||
drm_gem_fb_vunmap(job->fb, vkmsjob->map);
|
||||
|
||||
vkmsdev = drm_device_to_vkms_device(gem_obj->dev);
|
||||
vkmsdev = drm_device_to_vkms_device(job->fb->dev);
|
||||
vkms_set_composer(&vkmsdev->output, false);
|
||||
kfree(vkmsjob);
|
||||
}
|
||||
|
||||
static void vkms_wb_atomic_commit(struct drm_connector *conn,
|
||||
|
|
|
@ -1740,6 +1740,11 @@ void drm_mode_put_tile_group(struct drm_device *dev,
|
|||
* drm_connector_list_iter_begin(), drm_connector_list_iter_end() and
|
||||
* drm_connector_list_iter_next() respectively the convenience macro
|
||||
* drm_for_each_connector_iter().
|
||||
*
|
||||
* Note that the return value of drm_connector_list_iter_next() is only valid
|
||||
* up to the next drm_connector_list_iter_next() or
|
||||
* drm_connector_list_iter_end() call. If you want to use the connector later,
|
||||
* then you need to grab your own reference first using drm_connector_get().
|
||||
*/
|
||||
struct drm_connector_list_iter {
|
||||
/* private: */
|
||||
|
|
|
@ -25,6 +25,11 @@
|
|||
#include <linux/types.h>
|
||||
#include <uapi/drm/drm_fourcc.h>
|
||||
|
||||
/**
|
||||
* DRM_FORMAT_MAX_PLANES - maximum number of planes a DRM format can have
|
||||
*/
|
||||
#define DRM_FORMAT_MAX_PLANES 4u
|
||||
|
||||
/*
|
||||
* DRM formats are little endian. Define host endian variants for the
|
||||
* most common formats here, to reduce the #ifdefs needed in drivers.
|
||||
|
@ -78,7 +83,7 @@ struct drm_format_info {
|
|||
* triplet @char_per_block, @block_w, @block_h for better
|
||||
* describing the pixel format.
|
||||
*/
|
||||
u8 cpp[4];
|
||||
u8 cpp[DRM_FORMAT_MAX_PLANES];
|
||||
|
||||
/**
|
||||
* @char_per_block:
|
||||
|
@ -104,7 +109,7 @@ struct drm_format_info {
|
|||
* information from their drm_mode_config.get_format_info hook
|
||||
* if they want the core to be validating the pitch.
|
||||
*/
|
||||
u8 char_per_block[4];
|
||||
u8 char_per_block[DRM_FORMAT_MAX_PLANES];
|
||||
};
|
||||
|
||||
/**
|
||||
|
@ -113,7 +118,7 @@ struct drm_format_info {
|
|||
* Block width in pixels, this is intended to be accessed through
|
||||
* drm_format_info_block_width()
|
||||
*/
|
||||
u8 block_w[4];
|
||||
u8 block_w[DRM_FORMAT_MAX_PLANES];
|
||||
|
||||
/**
|
||||
* @block_h:
|
||||
|
@ -121,7 +126,7 @@ struct drm_format_info {
|
|||
* Block height in pixels, this is intended to be accessed through
|
||||
* drm_format_info_block_height()
|
||||
*/
|
||||
u8 block_h[4];
|
||||
u8 block_h[DRM_FORMAT_MAX_PLANES];
|
||||
|
||||
/** @hsub: Horizontal chroma subsampling factor */
|
||||
u8 hsub;
|
||||
|
|
|
@ -27,12 +27,12 @@
|
|||
#include <linux/list.h>
|
||||
#include <linux/sched.h>
|
||||
|
||||
#include <drm/drm_fourcc.h>
|
||||
#include <drm/drm_mode_object.h>
|
||||
|
||||
struct drm_clip_rect;
|
||||
struct drm_device;
|
||||
struct drm_file;
|
||||
struct drm_format_info;
|
||||
struct drm_framebuffer;
|
||||
struct drm_gem_object;
|
||||
|
||||
|
@ -147,7 +147,7 @@ struct drm_framebuffer {
|
|||
* @pitches: Line stride per buffer. For userspace created object this
|
||||
* is copied from drm_mode_fb_cmd2.
|
||||
*/
|
||||
unsigned int pitches[4];
|
||||
unsigned int pitches[DRM_FORMAT_MAX_PLANES];
|
||||
/**
|
||||
* @offsets: Offset from buffer start to the actual pixel data in bytes,
|
||||
* per buffer. For userspace created object this is copied from
|
||||
|
@ -165,7 +165,7 @@ struct drm_framebuffer {
|
|||
* data (even for linear buffers). Specifying an x/y pixel offset is
|
||||
* instead done through the source rectangle in &struct drm_plane_state.
|
||||
*/
|
||||
unsigned int offsets[4];
|
||||
unsigned int offsets[DRM_FORMAT_MAX_PLANES];
|
||||
/**
|
||||
* @modifier: Data layout modifier. This is used to describe
|
||||
* tiling, or also special layouts (like compression) of auxiliary
|
||||
|
@ -210,7 +210,7 @@ struct drm_framebuffer {
|
|||
* This is used by the GEM framebuffer helpers, see e.g.
|
||||
* drm_gem_fb_create().
|
||||
*/
|
||||
struct drm_gem_object *obj[4];
|
||||
struct drm_gem_object *obj[DRM_FORMAT_MAX_PLANES];
|
||||
};
|
||||
|
||||
#define obj_to_fb(x) container_of(x, struct drm_framebuffer, base)
|
||||
|
|
|
@ -5,6 +5,7 @@
|
|||
|
||||
#include <linux/dma-buf-map.h>
|
||||
|
||||
#include <drm/drm_fourcc.h>
|
||||
#include <drm/drm_plane.h>
|
||||
|
||||
struct drm_simple_display_pipe;
|
||||
|
@ -40,7 +41,7 @@ struct drm_shadow_plane_state {
|
|||
* The memory mappings stored in map should be established in the plane's
|
||||
* prepare_fb callback and removed in the cleanup_fb callback.
|
||||
*/
|
||||
struct dma_buf_map map[4];
|
||||
struct dma_buf_map map[DRM_FORMAT_MAX_PLANES];
|
||||
};
|
||||
|
||||
/**
|
||||
|
|
|
@ -4,6 +4,8 @@
|
|||
#include <linux/dma-buf.h>
|
||||
#include <linux/dma-buf-map.h>
|
||||
|
||||
#include <drm/drm_fourcc.h>
|
||||
|
||||
struct drm_afbc_framebuffer;
|
||||
struct drm_device;
|
||||
struct drm_fb_helper_surface_size;
|
||||
|
@ -37,6 +39,10 @@ struct drm_framebuffer *
|
|||
drm_gem_fb_create_with_dirty(struct drm_device *dev, struct drm_file *file,
|
||||
const struct drm_mode_fb_cmd2 *mode_cmd);
|
||||
|
||||
int drm_gem_fb_vmap(struct drm_framebuffer *fb,
|
||||
struct dma_buf_map map[static DRM_FORMAT_MAX_PLANES]);
|
||||
void drm_gem_fb_vunmap(struct drm_framebuffer *fb,
|
||||
struct dma_buf_map map[static DRM_FORMAT_MAX_PLANES]);
|
||||
int drm_gem_fb_begin_cpu_access(struct drm_framebuffer *fb, enum dma_data_direction dir);
|
||||
void drm_gem_fb_end_cpu_access(struct drm_framebuffer *fb, enum dma_data_direction dir);
|
||||
|
||||
|
|
|
@ -541,22 +541,74 @@ struct drm_mode_get_connector {
|
|||
*/
|
||||
#define DRM_MODE_PROP_ATOMIC 0x80000000
|
||||
|
||||
/**
|
||||
* struct drm_mode_property_enum - Description for an enum/bitfield entry.
|
||||
* @value: numeric value for this enum entry.
|
||||
* @name: symbolic name for this enum entry.
|
||||
*
|
||||
* See struct drm_property_enum for details.
|
||||
*/
|
||||
struct drm_mode_property_enum {
|
||||
__u64 value;
|
||||
char name[DRM_PROP_NAME_LEN];
|
||||
};
|
||||
|
||||
/**
|
||||
* struct drm_mode_get_property - Get property metadata.
|
||||
*
|
||||
* User-space can perform a GETPROPERTY ioctl to retrieve information about a
|
||||
* property. The same property may be attached to multiple objects, see
|
||||
* "Modeset Base Object Abstraction".
|
||||
*
|
||||
* The meaning of the @values_ptr field changes depending on the property type.
|
||||
* See &drm_property.flags for more details.
|
||||
*
|
||||
* The @enum_blob_ptr and @count_enum_blobs fields are only meaningful when the
|
||||
* property has the type &DRM_MODE_PROP_ENUM or &DRM_MODE_PROP_BITMASK. For
|
||||
* backwards compatibility, the kernel will always set @count_enum_blobs to
|
||||
* zero when the property has the type &DRM_MODE_PROP_BLOB. User-space must
|
||||
* ignore these two fields if the property has a different type.
|
||||
*
|
||||
* User-space is expected to retrieve values and enums by performing this ioctl
|
||||
* at least twice: the first time to retrieve the number of elements, the
|
||||
* second time to retrieve the elements themselves.
|
||||
*
|
||||
* To retrieve the number of elements, set @count_values and @count_enum_blobs
|
||||
* to zero, then call the ioctl. @count_values will be updated with the number
|
||||
* of elements. If the property has the type &DRM_MODE_PROP_ENUM or
|
||||
* &DRM_MODE_PROP_BITMASK, @count_enum_blobs will be updated as well.
|
||||
*
|
||||
* To retrieve the elements themselves, allocate an array for @values_ptr and
|
||||
* set @count_values to its capacity. If the property has the type
|
||||
* &DRM_MODE_PROP_ENUM or &DRM_MODE_PROP_BITMASK, allocate an array for
|
||||
* @enum_blob_ptr and set @count_enum_blobs to its capacity. Calling the ioctl
|
||||
* again will fill the arrays.
|
||||
*/
|
||||
struct drm_mode_get_property {
|
||||
__u64 values_ptr; /* values and blob lengths */
|
||||
__u64 enum_blob_ptr; /* enum and blob id ptrs */
|
||||
/** @values_ptr: Pointer to a ``__u64`` array. */
|
||||
__u64 values_ptr;
|
||||
/** @enum_blob_ptr: Pointer to a struct drm_mode_property_enum array. */
|
||||
__u64 enum_blob_ptr;
|
||||
|
||||
/**
|
||||
* @prop_id: Object ID of the property which should be retrieved. Set
|
||||
* by the caller.
|
||||
*/
|
||||
__u32 prop_id;
|
||||
/**
|
||||
* @flags: ``DRM_MODE_PROP_*`` bitfield. See &drm_property.flags for
|
||||
* a definition of the flags.
|
||||
*/
|
||||
__u32 flags;
|
||||
/**
|
||||
* @name: Symbolic property name. User-space should use this field to
|
||||
* recognize properties.
|
||||
*/
|
||||
char name[DRM_PROP_NAME_LEN];
|
||||
|
||||
/** @count_values: Number of elements in @values_ptr. */
|
||||
__u32 count_values;
|
||||
/* This is only used to count enum values, not blobs. The _blobs is
|
||||
* simply because of a historical reason, i.e. backwards compat. */
|
||||
/** @count_enum_blobs: Number of elements in @enum_blob_ptr. */
|
||||
__u32 count_enum_blobs;
|
||||
};
|
||||
|
||||
|
|
Loading…
Reference in New Issue