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:
Dave Airlie 2021-08-06 06:55:58 +10:00
commit 49f7844b08
62 changed files with 1716 additions and 552 deletions

View File

@ -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>;
};
};
};
};
...

View File

@ -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

View File

@ -339,6 +339,8 @@ patternProperties:
description: eGalax_eMPIA Technology Inc
"^einfochips,.*":
description: Einfochips
"^eink,.*":
description: E Ink Corporation
"^elan,.*":
description: Elan Microelectronic Corp.
"^element14,.*":

View File

@ -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
===============================

View File

@ -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);
}

View File

@ -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);

View File

@ -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.

View File

@ -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

View File

@ -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

View File

@ -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.

View File

@ -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)

View File

@ -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.

View File

@ -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,

View File

@ -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;
}

View File

@ -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,

View File

@ -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.

View File

@ -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.
*/
/**

View File

@ -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);

View File

@ -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.
*/

View File

@ -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

View File

@ -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.
*

View File

@ -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.

View File

@ -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

View File

@ -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

View File

@ -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);

View File

@ -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

View File

@ -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
*

View File

@ -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

View File

@ -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)

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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.

View File

@ -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
*

View File

@ -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.
*/

View File

@ -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

View File

@ -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.
*/

View File

@ -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

View File

@ -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.

View File

@ -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.

View File

@ -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;

View File

@ -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

View File

@ -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
*/

View File

@ -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)

View File

@ -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;
}

View File

@ -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

View File

@ -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

View File

@ -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");

View File

@ -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");

View File

@ -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,

View File

@ -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>

View File

@ -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>

View File

@ -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));

View File

@ -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);

View File

@ -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;

View File

@ -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,

View File

@ -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: */

View File

@ -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;

View File

@ -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)

View File

@ -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];
};
/**

View File

@ -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);

View File

@ -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;
};