From 676f11b5a4a06281420070ffdbb09c05851fa819 Mon Sep 17 00:00:00 2001 From: Desmond Cheong Zhi Xi Date: Fri, 30 Jul 2021 13:17:59 +0800 Subject: [PATCH 01/23] drm: clean up unused kerneldoc in drm_lease.c The kerneldoc in drm_lease.c is unused because none of the functions are driver interfaces as the symbols are not exported. Since they aren't used and much of the existing comments don't provide any insights (e.g. they just repeat the function name or list out the function parameters), they should be removed to make them easier to maintain and to make useful info more obvious. As a note, many of the comments mention whether idr_mutex should be held, but these are mostly redundant in cases where the function contains lockdep assertions or grabs the mutex. To simplify review, here's the reasoning behind each update. drm_lease_owner: function name is self-descriptive _drm_find_lessee: function name is self-descriptive _drm_lease_held_master: function name and signature are self-descriptive _drm_has_leased: kerneldoc is summarized into a comment because the function name could be interpreted ambiguously (check if the object has been leased VS check if the master has a lease on the object) _drm_lease_held: Retain the idr_mutex comment because the function does not directly grab the mutex or use a lockdep assertion. Otherwise, the function name is self-descriptive. drm_lease_held: function name is self-descriptive drm_lease_filter_crtcs: Kerneldoc is summarized into a comment because the function name could be interpreted ambiguously (filter leases based on crtcs mask VS filter crtcs mask based on leases) drm_lease_create: Kerneldoc removed. Useful function details such as atomic leasing are retained. Errno interpretations are useful and retained. drm_lease_destroy: function name is self-descriptive. Additional information is also removed as they're already present as comments inside the function. _drm_lease_revoke: function name is self-descriptive drm_lease_revoke: function name is self-descriptive drm_mode_create_lease_ioctl: Kerneldoc removed, but useful function details retained. drm_mode_list_lessees_ioctl: function name is self-descriptive. Additional details restate what the code does. drm_mode_get_lease_ioctl: Function summary retained to clarify that it's the leased objects that are returned, not the lease structure. drm_mode_revoke_lease_ioctl: Kerneldoc removed, but useful function details retained. Signed-off-by: Desmond Cheong Zhi Xi Signed-off-by: Daniel Vetter Link: https://patchwork.freedesktop.org/patch/msgid/20210730051759.1570630-1-desmondcheongzx@gmail.com --- drivers/gpu/drm/drm_lease.c | 131 +++--------------------------------- 1 file changed, 8 insertions(+), 123 deletions(-) diff --git a/drivers/gpu/drm/drm_lease.c b/drivers/gpu/drm/drm_lease.c index 79be797e8689..dee4f24a1808 100644 --- a/drivers/gpu/drm/drm_lease.c +++ b/drivers/gpu/drm/drm_lease.c @@ -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 @@ bool drm_lease_held(struct drm_file *file_priv, int id) 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 @@ uint32_t drm_lease_filter_crtcs(struct drm_file *file_priv, uint32_t crtcs_in) } /* - * 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 @@ static struct drm_master *drm_lease_create(struct drm_master *lessor, struct idr 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 @@ static int fill_object_idr(struct drm_device *dev, 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 @@ int drm_mode_create_lease_ioctl(struct drm_device *dev, 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 From 64c0274fb15c1daf6618f5f4d2b3ed80822e5e8d Mon Sep 17 00:00:00 2001 From: Douglas Anderson Date: Fri, 30 Jul 2021 08:46:00 -0700 Subject: [PATCH 02/23] drm/dp: Don't zero PWMGEN_BIT_COUNT when driver_pwm_freq_hz not specified The function drm_edp_backlight_init() is defined such that the "driver_pwm_freq_hz" parameter is optional--it's 0 if you don't want to futz with it. If you follow this variable through, you'll find out that if it's 0 we won't ever set the "bl->pwmgen_bit_count", leaving it as 0. That means that before using it in drm_edp_backlight_enable() we need to check to see if it's non-zero. Programming this field to zero was confusing the panel I tested with (Samsung ATNA33XC20). The backlight still worked somewhat but the brightness values didn't correspond to what they should have been. Fixes: 867cf9cd73c3 ("drm/dp: Extract i915's eDP backlight code into DRM helpers") Signed-off-by: Douglas Anderson Reviewed-by: Sean Paul Signed-off-by: Sam Ravnborg Link: https://patchwork.freedesktop.org/patch/msgid/20210730084534.v2.1.If017efce7116ae8ba015ed7def840c390a0e0c77@changeid --- drivers/gpu/drm/drm_dp_helper.c | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/drivers/gpu/drm/drm_dp_helper.c b/drivers/gpu/drm/drm_dp_helper.c index b5f75ca05774..2b6c35965459 100644 --- a/drivers/gpu/drm/drm_dp_helper.c +++ b/drivers/gpu/drm/drm_dp_helper.c @@ -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) { From acb06210b096830e28e9ffd2c6501fe99bdb10fd Mon Sep 17 00:00:00 2001 From: Douglas Anderson Date: Fri, 30 Jul 2021 08:46:01 -0700 Subject: [PATCH 03/23] drm/bridge: ti-sn65dsi86: Fix power off sequence When testing with a panel that's apparently a little more persnickety about the correct power sequence (specifically Samsung ATNA33XC20), we found that the ti-sn65dsi86 was doing things just slightly wrong. Looking closely at the ti-sn65dsi86's datasheet, the power off sequence is supposed to be: 1. Clear VSTREAM_ENABLE bit 2. Stop DSI stream from GPU. DSI lanes must be placed in LP11 state. 3. Program the ML_TX_MODE to 0x0 (OFF) 4. Program the DP_NUM_LANES register to 0x0 5. Clear the DP_PLL_EN bit. 6. Deassert the EN pin. 7. Remove power from supply pins Since we were doing the whole sequence in the "disable", I believe that step #2 (stopping the DSI stream from the GPU) wasn't happening. We also weren't setting DP_NUM_LANES to 0. Let's fix this. NOTE: things are a little asymmetric now. For instance, we turn the PLL on in "enable" but now we're not turning it off until "post_disable". It would seem to make sense to move the PLL turning on to "pre_enable" to match. Unfortunately, I don't believe that's allowed. It looks as if (in the non-refclk mode which probably nobody is using) we have to wait until the MIPI clock is there before we can enable the PLL. In any case, the way it is here won't really hurt--it'll just leave the PLL on a little longer. Fixes: a095f15c00e2 ("drm/bridge: add support for sn65dsi86 bridge driver") Signed-off-by: Douglas Anderson Acked-by: Robert Foss Reviewed-by: Sean Paul Signed-off-by: Sam Ravnborg Link: https://patchwork.freedesktop.org/patch/msgid/20210730084534.v2.2.If8a8ec3bf1855cf0dbb62c005a71d6698c99c125@changeid --- drivers/gpu/drm/bridge/ti-sn65dsi86.c | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/drivers/gpu/drm/bridge/ti-sn65dsi86.c b/drivers/gpu/drm/bridge/ti-sn65dsi86.c index 9bf889302bcc..5e932070a1c3 100644 --- a/drivers/gpu/drm/bridge/ti-sn65dsi86.c +++ b/drivers/gpu/drm/bridge/ti-sn65dsi86.c @@ -766,10 +766,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) @@ -1106,6 +1102,13 @@ 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); From e183bf31cf0d3a05162e633e428350ed176ce926 Mon Sep 17 00:00:00 2001 From: Douglas Anderson Date: Fri, 30 Jul 2021 08:46:02 -0700 Subject: [PATCH 04/23] drm/bridge: ti-sn65dsi86: Add some 100 us delays The manual has always said that we need 100 us delays in a few places. Though it hasn't seemed to be a big deal to skip these, let's add them in case it makes something happier. NOTE: this fixes no known issues but it seems good to make it right. Fixes: a095f15c00e2 ("drm/bridge: add support for sn65dsi86 bridge driver") Signed-off-by: Douglas Anderson Acked-by: Robert Foss Reviewed-by: Sean Paul Signed-off-by: Sam Ravnborg Link: https://patchwork.freedesktop.org/patch/msgid/20210730084534.v2.3.I842d483139531aa4651da8338512fdf0171ff23c@changeid --- drivers/gpu/drm/bridge/ti-sn65dsi86.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/drivers/gpu/drm/bridge/ti-sn65dsi86.c b/drivers/gpu/drm/bridge/ti-sn65dsi86.c index 5e932070a1c3..cd0fccdd8dfd 100644 --- a/drivers/gpu/drm/bridge/ti-sn65dsi86.c +++ b/drivers/gpu/drm/bridge/ti-sn65dsi86.c @@ -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); /* @@ -1096,6 +1099,9 @@ 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) From 7c4125b093d5e20d1c074fa160c8f07d9a72c435 Mon Sep 17 00:00:00 2001 From: Douglas Anderson Date: Fri, 30 Jul 2021 08:46:03 -0700 Subject: [PATCH 05/23] Revert "drm/panel-simple: Add Samsung ATNA33XC20" This reverts commit 4bfe6c8f7c23b01719671b69fd29b87a35ccd9d6. This panel's power sequencing really can't be handled properly by panel-simple because of the special sequencing needed for the EL_ON3 GPIO. The only way it was sorta working in the past was by trying to jam that signal into the "enable-gpio", but that really wasn't a good fit. We'll add a custom panel driver for this panel to do it right. Signed-off-by: Douglas Anderson Reviewed-by: Sean Paul Signed-off-by: Sam Ravnborg Link: https://patchwork.freedesktop.org/patch/msgid/20210730084534.v2.4.Id9f076ec5f35633f8ce931051af268a04c45c075@changeid --- drivers/gpu/drm/panel/panel-simple.c | 33 ---------------------------- 1 file changed, 33 deletions(-) diff --git a/drivers/gpu/drm/panel/panel-simple.c b/drivers/gpu/drm/panel/panel-simple.c index dff3dedd734b..a5038b968b08 100644 --- a/drivers/gpu/drm/panel/panel-simple.c +++ b/drivers/gpu/drm/panel/panel-simple.c @@ -3681,36 +3681,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, @@ -4723,9 +4693,6 @@ static const struct of_device_id platform_of_match[] = { }, { .compatible = "rocktech,rk101ii01d-ct", .data = &rocktech_rk101ii01d_ct, - }, { - .compatible = "samsung,atna33xc20", - .data = &samsung_atna33xc20, }, { .compatible = "samsung,lsn122dl01-c01", .data = &samsung_lsn122dl01_c01, From 81c3212dd5fbd5274e673c4fb3bf60879d020b35 Mon Sep 17 00:00:00 2001 From: Douglas Anderson Date: Fri, 30 Jul 2021 08:46:04 -0700 Subject: [PATCH 06/23] Revert "drm/panel-simple: Support for delays between GPIO & regulator" This reverts commit 18a1488bf1e13fc3fc96d7948466b2166067c6c8. Those delays were added to support the Samsung ATNA33XC20 panel. However, we've moving that to its own panel driver and out of panel-simple. That means we don't need the ability to specify this delay. NOTE: it's unlikely we want to keep this delay "just in case" some other panel needs it. The enable-gpio and the power supply are really supposed to be different ways to specify the same thing: the main enable of the panel. Supporting a delay between them doesn't really make sense. Signed-off-by: Douglas Anderson Reviewed-by: Sean Paul Signed-off-by: Sam Ravnborg Link: https://patchwork.freedesktop.org/patch/msgid/20210730084534.v2.5.Ie44e3e5b7a926392541d575ca84c56931596513f@changeid --- drivers/gpu/drm/panel/panel-simple.c | 28 ---------------------------- 1 file changed, 28 deletions(-) diff --git a/drivers/gpu/drm/panel/panel-simple.c b/drivers/gpu/drm/panel/panel-simple.c index a5038b968b08..a54e9dc694a8 100644 --- a/drivers/gpu/drm/panel/panel-simple.c +++ b/drivers/gpu/drm/panel/panel-simple.c @@ -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); /* From 32ce3b320343acf8871c63b98e72778f5f60cefc Mon Sep 17 00:00:00 2001 From: Douglas Anderson Date: Fri, 30 Jul 2021 08:46:05 -0700 Subject: [PATCH 07/23] drm/panel: atna33xc20: Introduce the Samsung ATNA33XC20 panel The Samsung ATNA33XC20 panel is an AMOLED eDP panel that has backlight control over the DP AUX channel. This panel is _almost_ able to be controlled in a "simple" way (and it originally was implemented in panel-simple.c), but it's really impossible to get the backlight semantics right there without adding wacky special-case code to panel-simple. Let's give up and clone the parts of panel-simple that we need and implement the power sequence that this panel needs. NOTE: we'll still leave the devicetree bindings alone. Even though the power-sequencing is non-standard the bindings are still "simple". Signed-off-by: Douglas Anderson Reviewed-by: Sean Paul Signed-off-by: Sam Ravnborg Link: https://patchwork.freedesktop.org/patch/msgid/20210730084534.v2.6.I3a2900080f8749d2bb4baf49ca902db4b0e1df7d@changeid --- drivers/gpu/drm/panel/Kconfig | 11 + drivers/gpu/drm/panel/Makefile | 1 + .../gpu/drm/panel/panel-samsung-atna33xc20.c | 366 ++++++++++++++++++ 3 files changed, 378 insertions(+) create mode 100644 drivers/gpu/drm/panel/panel-samsung-atna33xc20.c diff --git a/drivers/gpu/drm/panel/Kconfig b/drivers/gpu/drm/panel/Kconfig index 6b3eb041182c..f5a65f3bd5b4 100644 --- a/drivers/gpu/drm/panel/Kconfig +++ b/drivers/gpu/drm/panel/Kconfig @@ -353,6 +353,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 diff --git a/drivers/gpu/drm/panel/Makefile b/drivers/gpu/drm/panel/Makefile index 08debae9b314..1b6fe2008861 100644 --- a/drivers/gpu/drm/panel/Makefile +++ b/drivers/gpu/drm/panel/Makefile @@ -34,6 +34,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 diff --git a/drivers/gpu/drm/panel/panel-samsung-atna33xc20.c b/drivers/gpu/drm/panel/panel-samsung-atna33xc20.c new file mode 100644 index 000000000000..221db6512859 --- /dev/null +++ b/drivers/gpu/drm/panel/panel-samsung-atna33xc20.c @@ -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 +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +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"); From 853bc39570853a42dfe5d6071d46bb7c69430584 Mon Sep 17 00:00:00 2001 From: Cai Huoqing Date: Tue, 27 Jul 2021 13:21:07 +0800 Subject: [PATCH 08/23] drm/pl111: Remove unused including Remove including that don't need it. Signed-off-by: Cai Huoqing Acked-by: Randy Dunlap Signed-off-by: Sam Ravnborg Link: https://patchwork.freedesktop.org/patch/msgid/20210727052107.659-1-caihuoqing@baidu.com --- drivers/gpu/drm/pl111/pl111_display.c | 1 - drivers/gpu/drm/pl111/pl111_drv.c | 1 - 2 files changed, 2 deletions(-) diff --git a/drivers/gpu/drm/pl111/pl111_display.c b/drivers/gpu/drm/pl111/pl111_display.c index b5a8859739a2..443e3b932322 100644 --- a/drivers/gpu/drm/pl111/pl111_display.c +++ b/drivers/gpu/drm/pl111/pl111_display.c @@ -11,7 +11,6 @@ #include #include -#include #include #include diff --git a/drivers/gpu/drm/pl111/pl111_drv.c b/drivers/gpu/drm/pl111/pl111_drv.c index fa0a737e9dea..520301b405f1 100644 --- a/drivers/gpu/drm/pl111/pl111_drv.c +++ b/drivers/gpu/drm/pl111/pl111_drv.c @@ -44,7 +44,6 @@ #include #include #include -#include #include #include From 9746f5fe70aa16182bcb505265c4800365438585 Mon Sep 17 00:00:00 2001 From: Alistair Francis Date: Sun, 1 Aug 2021 10:47:00 +1000 Subject: [PATCH 09/23] drm/panel: Add support for E Ink VB3300-KCA Add support for the 10.3" E Ink panel described at: https://www.eink.com/product.html?type=productdetail&id=7 Signed-off-by: Alistair Francis Acked-by: Rob Herring Reviewed-by: Sam Ravnborg Signed-off-by: Sam Ravnborg Link: https://patchwork.freedesktop.org/patch/msgid/20210801004701.831-1-alistair@alistair23.me --- .../bindings/display/panel/panel-simple.yaml | 2 ++ .../devicetree/bindings/vendor-prefixes.yaml | 2 ++ drivers/gpu/drm/panel/panel-simple.c | 30 +++++++++++++++++++ 3 files changed, 34 insertions(+) diff --git a/Documentation/devicetree/bindings/display/panel/panel-simple.yaml b/Documentation/devicetree/bindings/display/panel/panel-simple.yaml index eda427ddca1b..81bdfb03bcea 100644 --- a/Documentation/devicetree/bindings/display/panel/panel-simple.yaml +++ b/Documentation/devicetree/bindings/display/panel/panel-simple.yaml @@ -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 diff --git a/Documentation/devicetree/bindings/vendor-prefixes.yaml b/Documentation/devicetree/bindings/vendor-prefixes.yaml index 3c6918dde429..5713e6672ddb 100644 --- a/Documentation/devicetree/bindings/vendor-prefixes.yaml +++ b/Documentation/devicetree/bindings/vendor-prefixes.yaml @@ -339,6 +339,8 @@ patternProperties: description: eGalax_eMPIA Technology Inc "^einfochips,.*": description: Einfochips + "^eink,.*": + description: E Ink Corporation "^elan,.*": description: Elan Microelectronic Corp. "^element14,.*": diff --git a/drivers/gpu/drm/panel/panel-simple.c b/drivers/gpu/drm/panel/panel-simple.c index a54e9dc694a8..e592551c9523 100644 --- a/drivers/gpu/drm/panel/panel-simple.c +++ b/drivers/gpu/drm/panel/panel-simple.c @@ -2178,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 }, @@ -4494,6 +4521,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, From 6c9bd4432b252765b38bfc0bbe4847f43604f06e Mon Sep 17 00:00:00 2001 From: Gregory Williams Date: Fri, 30 Jul 2021 20:53:28 -0400 Subject: [PATCH 10/23] DRM: ast: Fixed coding style issues of ast_mode.c Removed space before comma, fixed if statements by putting trailing statements on new line, fixed unsigned int declaration, and removed not needed else statement after return. Signed-off-by: Gregory Williams Signed-off-by: Thomas Zimmermann Link: https://patchwork.freedesktop.org/patch/msgid/20210731005328.GA19016@devbox --- drivers/gpu/drm/ast/ast_mode.c | 31 ++++++++++++++++++++----------- 1 file changed, 20 insertions(+), 11 deletions(-) diff --git a/drivers/gpu/drm/ast/ast_mode.c b/drivers/gpu/drm/ast/ast_mode.c index f32da620a123..15319967164e 100644 --- a/drivers/gpu/drm/ast/ast_mode.c +++ b/drivers/gpu/drm/ast/ast_mode.c @@ -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); } From 33e1fc062456f43f17e5240d6e9be11e95ef5103 Mon Sep 17 00:00:00 2001 From: Simon Ser Date: Wed, 9 Jun 2021 21:24:10 +0000 Subject: [PATCH 11/23] drm/connector: add ref to drm_connector_get in iter docs Mention that connectors need to be referenced manually if they are to be accessed after the iteration has progressed or ended. Signed-off-by: Simon Ser Reviewed-by: Daniel Vetter Link: https://patchwork.freedesktop.org/patch/msgid/KRoUI7OC9lRIvk3YzdGm6tcMVAVlG1fR78Ll7kTZZT4@cp3-web-051.plabs.ch --- include/drm/drm_connector.h | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/include/drm/drm_connector.h b/include/drm/drm_connector.h index 0a1d9a0fcbb2..1647960c9e50 100644 --- a/include/drm/drm_connector.h +++ b/include/drm/drm_connector.h @@ -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: */ From 0ae865ef92f1920bd2ca3fc7b6b5a9555b4641cc Mon Sep 17 00:00:00 2001 From: Cai Huoqing Date: Fri, 30 Jul 2021 21:27:29 +0800 Subject: [PATCH 12/23] drm: Fix typo in comments fix typo for drm v1->v2: respin with the change "iff ==> implies that" Signed-off-by: Cai Huoqing Signed-off-by: Daniel Vetter Link: https://patchwork.freedesktop.org/patch/msgid/20210730132729.376-1-caihuoqing@baidu.com --- drivers/gpu/drm/drm_aperture.c | 2 +- drivers/gpu/drm/drm_atomic.c | 2 +- drivers/gpu/drm/drm_atomic_helper.c | 10 +++++----- drivers/gpu/drm/drm_atomic_uapi.c | 6 +++--- drivers/gpu/drm/drm_auth.c | 2 +- drivers/gpu/drm/drm_bridge.c | 2 +- drivers/gpu/drm/drm_bufs.c | 2 +- drivers/gpu/drm/drm_cache.c | 2 +- drivers/gpu/drm/drm_damage_helper.c | 2 +- drivers/gpu/drm/drm_dp_helper.c | 8 ++++---- drivers/gpu/drm/drm_drv.c | 4 ++-- drivers/gpu/drm/drm_dsc.c | 2 +- drivers/gpu/drm/drm_edid.c | 4 ++-- drivers/gpu/drm/drm_fb_helper.c | 2 +- drivers/gpu/drm/drm_file.c | 6 +++--- drivers/gpu/drm/drm_format_helper.c | 2 +- drivers/gpu/drm/drm_framebuffer.c | 2 +- drivers/gpu/drm/drm_gem.c | 4 ++-- drivers/gpu/drm/drm_gem_atomic_helper.c | 4 ++-- drivers/gpu/drm/drm_gem_shmem_helper.c | 2 +- drivers/gpu/drm/drm_gem_vram_helper.c | 2 +- drivers/gpu/drm/drm_hdcp.c | 2 +- drivers/gpu/drm/drm_ioctl.c | 4 ++-- drivers/gpu/drm/drm_irq.c | 2 +- drivers/gpu/drm/drm_mm.c | 2 +- drivers/gpu/drm/drm_mode_object.c | 2 +- drivers/gpu/drm/drm_modes.c | 4 ++-- drivers/gpu/drm/drm_plane.c | 2 +- drivers/gpu/drm/drm_plane_helper.c | 2 +- drivers/gpu/drm/drm_prime.c | 2 +- drivers/gpu/drm/drm_probe_helper.c | 2 +- drivers/gpu/drm/drm_property.c | 2 +- drivers/gpu/drm/drm_scdc_helper.c | 2 +- drivers/gpu/drm/drm_syncobj.c | 2 +- drivers/gpu/drm/drm_vblank.c | 12 ++++++------ drivers/gpu/drm/drm_vma_manager.c | 2 +- 36 files changed, 58 insertions(+), 58 deletions(-) diff --git a/drivers/gpu/drm/drm_aperture.c b/drivers/gpu/drm/drm_aperture.c index 9ac39cf11694..74bd4a76b253 100644 --- a/drivers/gpu/drm/drm_aperture.c +++ b/drivers/gpu/drm/drm_aperture.c @@ -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. diff --git a/drivers/gpu/drm/drm_atomic.c b/drivers/gpu/drm/drm_atomic.c index c85dcfd69158..ff1416cd609a 100644 --- a/drivers/gpu/drm/drm_atomic.c +++ b/drivers/gpu/drm/drm_atomic.c @@ -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 diff --git a/drivers/gpu/drm/drm_atomic_helper.c b/drivers/gpu/drm/drm_atomic_helper.c index f7bf1ea62d58..2c0c6ec92820 100644 --- a/drivers/gpu/drm/drm_atomic_helper.c +++ b/drivers/gpu/drm/drm_atomic_helper.c @@ -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 diff --git a/drivers/gpu/drm/drm_atomic_uapi.c b/drivers/gpu/drm/drm_atomic_uapi.c index 7e48d40600ff..909f31833181 100644 --- a/drivers/gpu/drm/drm_atomic_uapi.c +++ b/drivers/gpu/drm/drm_atomic_uapi.c @@ -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. diff --git a/drivers/gpu/drm/drm_auth.c b/drivers/gpu/drm/drm_auth.c index 5b1d92f5afea..53e58bbb6cf5 100644 --- a/drivers/gpu/drm/drm_auth.c +++ b/drivers/gpu/drm/drm_auth.c @@ -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) diff --git a/drivers/gpu/drm/drm_bridge.c b/drivers/gpu/drm/drm_bridge.c index 11ec2846addb..a8ed66751c2d 100644 --- a/drivers/gpu/drm/drm_bridge.c +++ b/drivers/gpu/drm/drm_bridge.c @@ -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. diff --git a/drivers/gpu/drm/drm_bufs.c b/drivers/gpu/drm/drm_bufs.c index ae8e4d76209c..fcca21e8efac 100644 --- a/drivers/gpu/drm/drm_bufs.c +++ b/drivers/gpu/drm/drm_bufs.c @@ -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, diff --git a/drivers/gpu/drm/drm_cache.c b/drivers/gpu/drm/drm_cache.c index 546599f19a93..30cc59fe6ef7 100644 --- a/drivers/gpu/drm/drm_cache.c +++ b/drivers/gpu/drm/drm_cache.c @@ -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; } diff --git a/drivers/gpu/drm/drm_damage_helper.c b/drivers/gpu/drm/drm_damage_helper.c index 245959dad7bb..8eeff0c7bdd4 100644 --- a/drivers/gpu/drm/drm_damage_helper.c +++ b/drivers/gpu/drm/drm_damage_helper.c @@ -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, diff --git a/drivers/gpu/drm/drm_dp_helper.c b/drivers/gpu/drm/drm_dp_helper.c index 2b6c35965459..6d0f2c447f3b 100644 --- a/drivers/gpu/drm/drm_dp_helper.c +++ b/drivers/gpu/drm/drm_dp_helper.c @@ -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) @@ -3329,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. diff --git a/drivers/gpu/drm/drm_drv.c b/drivers/gpu/drm/drm_drv.c index 8804ec7d3215..7a5097467ba5 100644 --- a/drivers/gpu/drm/drm_drv.c +++ b/drivers/gpu/drm/drm_drv.c @@ -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. */ /** diff --git a/drivers/gpu/drm/drm_dsc.c b/drivers/gpu/drm/drm_dsc.c index ff602f7ec65b..46a3c1b62463 100644 --- a/drivers/gpu/drm/drm_dsc.c +++ b/drivers/gpu/drm/drm_dsc.c @@ -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); diff --git a/drivers/gpu/drm/drm_edid.c b/drivers/gpu/drm/drm_edid.c index 81d5f2524246..6325877c5fd6 100644 --- a/drivers/gpu/drm/drm_edid.c +++ b/drivers/gpu/drm/drm_edid.c @@ -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. */ diff --git a/drivers/gpu/drm/drm_fb_helper.c b/drivers/gpu/drm/drm_fb_helper.c index d77a24507d30..3ab078321045 100644 --- a/drivers/gpu/drm/drm_fb_helper.c +++ b/drivers/gpu/drm/drm_fb_helper.c @@ -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 diff --git a/drivers/gpu/drm/drm_file.c b/drivers/gpu/drm/drm_file.c index ceb1a9723855..ed25168619fc 100644 --- a/drivers/gpu/drm/drm_file.c +++ b/drivers/gpu/drm/drm_file.c @@ -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. * diff --git a/drivers/gpu/drm/drm_format_helper.c b/drivers/gpu/drm/drm_format_helper.c index 0e885cd34107..5231104b1498 100644 --- a/drivers/gpu/drm/drm_format_helper.c +++ b/drivers/gpu/drm/drm_format_helper.c @@ -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. diff --git a/drivers/gpu/drm/drm_framebuffer.c b/drivers/gpu/drm/drm_framebuffer.c index d3d09aba9833..07f5abc875e9 100644 --- a/drivers/gpu/drm/drm_framebuffer.c +++ b/drivers/gpu/drm/drm_framebuffer.c @@ -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 diff --git a/drivers/gpu/drm/drm_gem.c b/drivers/gpu/drm/drm_gem.c index 96d642f29fa4..09c820045859 100644 --- a/drivers/gpu/drm/drm_gem.c +++ b/drivers/gpu/drm/drm_gem.c @@ -901,7 +901,7 @@ drm_gem_open_ioctl(struct drm_device *dev, void *data, } /** - * 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 diff --git a/drivers/gpu/drm/drm_gem_atomic_helper.c b/drivers/gpu/drm/drm_gem_atomic_helper.c index 26af09b959d4..86b3c676e0b1 100644 --- a/drivers/gpu/drm/drm_gem_atomic_helper.c +++ b/drivers/gpu/drm/drm_gem_atomic_helper.c @@ -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. @@ -374,7 +374,7 @@ 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) { diff --git a/drivers/gpu/drm/drm_gem_shmem_helper.c b/drivers/gpu/drm/drm_gem_shmem_helper.c index d5e6d4568f99..a61946374c82 100644 --- a/drivers/gpu/drm/drm_gem_shmem_helper.c +++ b/drivers/gpu/drm/drm_gem_shmem_helper.c @@ -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 * diff --git a/drivers/gpu/drm/drm_gem_vram_helper.c b/drivers/gpu/drm/drm_gem_vram_helper.c index 1e9b82e51a07..43cf7e887d1a 100644 --- a/drivers/gpu/drm/drm_gem_vram_helper.c +++ b/drivers/gpu/drm/drm_gem_vram_helper.c @@ -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 diff --git a/drivers/gpu/drm/drm_hdcp.c b/drivers/gpu/drm/drm_hdcp.c index 910108ccaae1..ca9b8f697202 100644 --- a/drivers/gpu/drm/drm_hdcp.c +++ b/drivers/gpu/drm/drm_hdcp.c @@ -280,7 +280,7 @@ static int drm_hdcp_request_srm(struct drm_device *drm_dev, * 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) diff --git a/drivers/gpu/drm/drm_ioctl.c b/drivers/gpu/drm/drm_ioctl.c index f454e0424086..be4a52dc4d6f 100644 --- a/drivers/gpu/drm/drm_ioctl.c +++ b/drivers/gpu/drm/drm_ioctl.c @@ -426,7 +426,7 @@ static int drm_setversion(struct drm_device *dev, void *data, struct drm_file *f } /** - * 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 diff --git a/drivers/gpu/drm/drm_irq.c b/drivers/gpu/drm/drm_irq.c index 201eae4bba6c..4a853011549a 100644 --- a/drivers/gpu/drm/drm_irq.c +++ b/drivers/gpu/drm/drm_irq.c @@ -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 diff --git a/drivers/gpu/drm/drm_mm.c b/drivers/gpu/drm/drm_mm.c index a4a04d246135..93d48a6f04ab 100644 --- a/drivers/gpu/drm/drm_mm.c +++ b/drivers/gpu/drm/drm_mm.c @@ -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. diff --git a/drivers/gpu/drm/drm_mode_object.c b/drivers/gpu/drm/drm_mode_object.c index b26588b52795..86d9e907c0b2 100644 --- a/drivers/gpu/drm/drm_mode_object.c +++ b/drivers/gpu/drm/drm_mode_object.c @@ -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 * diff --git a/drivers/gpu/drm/drm_modes.c b/drivers/gpu/drm/drm_modes.c index ae53ea624c73..1c72208d8133 100644 --- a/drivers/gpu/drm/drm_modes.c +++ b/drivers/gpu/drm/drm_modes.c @@ -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. */ diff --git a/drivers/gpu/drm/drm_plane.c b/drivers/gpu/drm/drm_plane.c index f5fe8255597c..82afb854141b 100644 --- a/drivers/gpu/drm/drm_plane.c +++ b/drivers/gpu/drm/drm_plane.c @@ -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 diff --git a/drivers/gpu/drm/drm_plane_helper.c b/drivers/gpu/drm/drm_plane_helper.c index 3aae7ea522f2..5b2d0ca03705 100644 --- a/drivers/gpu/drm/drm_plane_helper.c +++ b/drivers/gpu/drm/drm_plane_helper.c @@ -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. */ diff --git a/drivers/gpu/drm/drm_prime.c b/drivers/gpu/drm/drm_prime.c index 178e18c28cab..1d009494af8b 100644 --- a/drivers/gpu/drm/drm_prime.c +++ b/drivers/gpu/drm/drm_prime.c @@ -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 diff --git a/drivers/gpu/drm/drm_probe_helper.c b/drivers/gpu/drm/drm_probe_helper.c index e7e1ee2aa352..5606bca3caa8 100644 --- a/drivers/gpu/drm/drm_probe_helper.c +++ b/drivers/gpu/drm/drm_probe_helper.c @@ -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. diff --git a/drivers/gpu/drm/drm_property.c b/drivers/gpu/drm/drm_property.c index 27c824a6eb60..6c353c9dc772 100644 --- a/drivers/gpu/drm/drm_property.c +++ b/drivers/gpu/drm/drm_property.c @@ -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. diff --git a/drivers/gpu/drm/drm_scdc_helper.c b/drivers/gpu/drm/drm_scdc_helper.c index 991b8c86d78d..48a382464d54 100644 --- a/drivers/gpu/drm/drm_scdc_helper.c +++ b/drivers/gpu/drm/drm_scdc_helper.c @@ -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; diff --git a/drivers/gpu/drm/drm_syncobj.c b/drivers/gpu/drm/drm_syncobj.c index 1c5b9ef6da37..c9a9d74f338c 100644 --- a/drivers/gpu/drm/drm_syncobj.c +++ b/drivers/gpu/drm/drm_syncobj.c @@ -725,7 +725,7 @@ static int drm_syncobj_export_sync_file(struct drm_file *file_private, 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 diff --git a/drivers/gpu/drm/drm_vblank.c b/drivers/gpu/drm/drm_vblank.c index bba6781cc48f..977b6509bb4b 100644 --- a/drivers/gpu/drm/drm_vblank.c +++ b/drivers/gpu/drm/drm_vblank.c @@ -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 */ diff --git a/drivers/gpu/drm/drm_vma_manager.c b/drivers/gpu/drm/drm_vma_manager.c index 4565319fa6b3..7de37f8c68fd 100644 --- a/drivers/gpu/drm/drm_vma_manager.c +++ b/drivers/gpu/drm/drm_vma_manager.c @@ -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) From 2f425cf5242a019e9e8a6b1fe684b022c94fa7f1 Mon Sep 17 00:00:00 2001 From: Daniel Vetter Date: Fri, 30 Jul 2021 11:52:51 +0200 Subject: [PATCH 13/23] drm: Fix oops in damage self-tests by mocking damage property MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit I've added a new check to make sure that drivers which insepct the damage property have it set up correctly, but somehow missed that this borke the damage selftest in the CI result noise. Fix it up by mocking enough of drm_device and drm_plane so we can call drm_plane_enable_fb_damage_clips() to make the new check happy. Since there's a lot of duplicated mock code already copy-pasted into each test I've also refactored this a bit to trim it down. v2: Squash in fixup from 0day for drivers/gpu/drm/selftests/test-drm_damage_helper.c:15:19: warning: symbol 'mock_device' was not declared. Should it be static? drivers/gpu/drm/selftests/test-drm_damage_helper.c:16:30: warning: symbol 'mock_obj_props' was not declared. Should it be static? drivers/gpu/drm/selftests/test-drm_damage_helper.c:17:18: warning: symbol 'mock_plane' was not declared. Should it be static? drivers/gpu/drm/selftests/test-drm_damage_helper.c:18:21: warning: symbol 'mock_prop' was not declared. Should it be static? Reported-by: kernel test robot Signed-off-by: kernel test robot Reviewed-by: Maarten Lankhorst Signed-off-by: Daniel Vetter Fixes: c7fcbf251397 ("drm/plane: check that fb_damage is set up when used") Cc: José Roberto de Souza (v1) Cc: Ville Syrjälä Cc: Gwan-gyeong Mun Cc: José Roberto de Souza Cc: Hans de Goede Cc: Daniel Vetter Cc: Maarten Lankhorst Cc: Maxime Ripard Cc: Thomas Zimmermann Link: https://patchwork.freedesktop.org/patch/msgid/20210730095251.4343-1-daniel.vetter@ffwll.ch Link: https://patchwork.freedesktop.org/patch/msgid/20210730141948.GA11955@243d74413310 --- .../drm/selftests/test-drm_damage_helper.c | 287 +++++------------- 1 file changed, 71 insertions(+), 216 deletions(-) diff --git a/drivers/gpu/drm/selftests/test-drm_damage_helper.c b/drivers/gpu/drm/selftests/test-drm_damage_helper.c index 9d2bcdf8bc29..1c19a5d3eefb 100644 --- a/drivers/gpu/drm/selftests/test-drm_damage_helper.c +++ b/drivers/gpu/drm/selftests/test-drm_damage_helper.c @@ -6,9 +6,37 @@ #define pr_fmt(fmt) "drm_damage_helper: " fmt #include +#include +#include #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)); From 6e5b47a4f1dde38d42b054cc6d16b6840de08bd2 Mon Sep 17 00:00:00 2001 From: Simon Ser Date: Mon, 2 Aug 2021 07:28:35 +0000 Subject: [PATCH 14/23] drm: document drm_mode_get_property It's not obvious what the fields mean and how they should be used. The most important detail is the link to drm_property.flags, which describes how property types work. v2: document enum drm_mode_property_enum, add ref to "Modeset Base Object Abstraction" (Daniel) Signed-off-by: Simon Ser Acked-by: Pekka Paalanen Acked-by: Daniel Vetter Cc: Leandro Ribeiro Link: https://patchwork.freedesktop.org/patch/msgid/20210802072826.500078-1-contact@emersion.fr --- Documentation/gpu/drm-kms.rst | 2 ++ include/uapi/drm/drm_mode.h | 60 ++++++++++++++++++++++++++++++++--- 2 files changed, 58 insertions(+), 4 deletions(-) diff --git a/Documentation/gpu/drm-kms.rst b/Documentation/gpu/drm-kms.rst index 0cc21f6aaef5..1ef7951ded5e 100644 --- a/Documentation/gpu/drm-kms.rst +++ b/Documentation/gpu/drm-kms.rst @@ -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 =============================== diff --git a/include/uapi/drm/drm_mode.h b/include/uapi/drm/drm_mode.h index 98bf130feda5..90c55383f1ee 100644 --- a/include/uapi/drm/drm_mode.h +++ b/include/uapi/drm/drm_mode.h @@ -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; }; From 279cc2e9543eb357c0ef299cf398b2e74a021f6b Mon Sep 17 00:00:00 2001 From: Thomas Zimmermann Date: Fri, 30 Jul 2021 20:35:07 +0200 Subject: [PATCH 15/23] drm: Define DRM_FORMAT_MAX_PLANES DRM uses a magic number of 4 for the maximum number of planes per color format. Declare this constant via DRM_FORMAT_MAX_PLANES and update the related code. Some code depends on the length of arrays that are now declared with DRM_FORMAT_MAX_PLANES. Convert it from '4' to ARRAY_SIZE. v2: * mention usage of ARRAY_SIZE() in the commit message (Maxime) * also fix error handling in drm_gem_fb_init_with_funcs() (kernel test robot) * include for DRM_FORMAT_MAX_PLANES Signed-off-by: Thomas Zimmermann Reviewed-by: Sam Ravnborg Link: https://patchwork.freedesktop.org/patch/msgid/20210730183511.20080-2-tzimmermann@suse.de --- drivers/gpu/drm/drm_gem_framebuffer_helper.c | 19 +++++++++++-------- include/drm/drm_fourcc.h | 13 +++++++++---- include/drm/drm_framebuffer.h | 8 ++++---- include/drm/drm_gem_atomic_helper.h | 3 ++- 4 files changed, 26 insertions(+), 17 deletions(-) diff --git a/drivers/gpu/drm/drm_gem_framebuffer_helper.c b/drivers/gpu/drm/drm_gem_framebuffer_helper.c index 67bc9edc1d98..421e029a6b3e 100644 --- a/drivers/gpu/drm/drm_gem_framebuffer_helper.c +++ b/drivers/gpu/drm/drm_gem_framebuffer_helper.c @@ -48,7 +48,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 +62,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 +87,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 +146,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 +189,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); diff --git a/include/drm/drm_fourcc.h b/include/drm/drm_fourcc.h index 3b138d4ae67e..22aa64d07c79 100644 --- a/include/drm/drm_fourcc.h +++ b/include/drm/drm_fourcc.h @@ -25,6 +25,11 @@ #include #include +/** + * 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; diff --git a/include/drm/drm_framebuffer.h b/include/drm/drm_framebuffer.h index be658ebbec72..f67c5b7bcb68 100644 --- a/include/drm/drm_framebuffer.h +++ b/include/drm/drm_framebuffer.h @@ -27,12 +27,12 @@ #include #include +#include #include 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) diff --git a/include/drm/drm_gem_atomic_helper.h b/include/drm/drm_gem_atomic_helper.h index d82c23622156..f9f8b6f0494a 100644 --- a/include/drm/drm_gem_atomic_helper.h +++ b/include/drm/drm_gem_atomic_helper.h @@ -5,6 +5,7 @@ #include +#include #include 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]; }; /** From f6424ecdb3c8aba18997a6992f780ab9c27734bc Mon Sep 17 00:00:00 2001 From: Thomas Zimmermann Date: Fri, 30 Jul 2021 20:35:08 +0200 Subject: [PATCH 16/23] drm/gem: Provide drm_gem_fb_{vmap,vunmap}() Move framebuffer vmap code from shadow-buffered plane state into the new interfaces drm_gem_fb_vmap() and drm_gem_fb_vunmap(). These functions provide mappings of a framebuffer's BOs into kernel address space. No functional changes. v4: * remove duplicated blank line v2: * using [static N] for array parameters enables compile-time checks * include for DRM_FORMAT_MAX_PLANES (kernel test robot) Signed-off-by: Thomas Zimmermann Reviewed-by: Sam Ravnborg Link: https://patchwork.freedesktop.org/patch/msgid/20210730183511.20080-3-tzimmermann@suse.de --- drivers/gpu/drm/drm_gem_atomic_helper.c | 35 +--------- drivers/gpu/drm/drm_gem_framebuffer_helper.c | 72 ++++++++++++++++++++ include/drm/drm_gem_framebuffer_helper.h | 6 ++ 3 files changed, 80 insertions(+), 33 deletions(-) diff --git a/drivers/gpu/drm/drm_gem_atomic_helper.c b/drivers/gpu/drm/drm_gem_atomic_helper.c index 86b3c676e0b1..4865870cc60e 100644 --- a/drivers/gpu/drm/drm_gem_atomic_helper.c +++ b/drivers/gpu/drm/drm_gem_atomic_helper.c @@ -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); @@ -380,19 +357,11 @@ void drm_gem_cleanup_shadow_fb(struct drm_plane *plane, struct drm_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); diff --git a/drivers/gpu/drm/drm_gem_framebuffer_helper.c b/drivers/gpu/drm/drm_gem_framebuffer_helper.c index 421e029a6b3e..2bc0605c8bca 100644 --- a/drivers/gpu/drm/drm_gem_framebuffer_helper.c +++ b/drivers/gpu/drm/drm_gem_framebuffer_helper.c @@ -15,6 +15,8 @@ #include #include +#include "drm_internal.h" + #define AFBC_HEADER_SIZE 16 #define AFBC_TH_LAYOUT_ALIGNMENT 8 #define AFBC_HDR_ALIGN 64 @@ -309,6 +311,76 @@ 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) + 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; + 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 diff --git a/include/drm/drm_gem_framebuffer_helper.h b/include/drm/drm_gem_framebuffer_helper.h index 5705722f0855..ff2024dd7b77 100644 --- a/include/drm/drm_gem_framebuffer_helper.h +++ b/include/drm/drm_gem_framebuffer_helper.h @@ -4,6 +4,8 @@ #include #include +#include + 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); From 0ec77bd92b513aa4e556e5b92ccd993677d21cbc Mon Sep 17 00:00:00 2001 From: Thomas Zimmermann Date: Fri, 30 Jul 2021 20:35:09 +0200 Subject: [PATCH 17/23] drm/gem: Clear mapping addresses for unused framebuffer planes Set the returned mapping address to NULL if a framebuffer plane does not have a BO associated with it. Likewise, ignore mappings of NULL during framebuffer unmap operations. Allows users of the functions to perform unmap operations of certain BOs by themselfes. Signed-off-by: Thomas Zimmermann Reviewed-by: Sam Ravnborg Link: https://patchwork.freedesktop.org/patch/msgid/20210730183511.20080-4-tzimmermann@suse.de --- drivers/gpu/drm/drm_gem_framebuffer_helper.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/drivers/gpu/drm/drm_gem_framebuffer_helper.c b/drivers/gpu/drm/drm_gem_framebuffer_helper.c index 2bc0605c8bca..5731a6a1dfa5 100644 --- a/drivers/gpu/drm/drm_gem_framebuffer_helper.c +++ b/drivers/gpu/drm/drm_gem_framebuffer_helper.c @@ -335,8 +335,10 @@ int drm_gem_fb_vmap(struct drm_framebuffer *fb, for (i = 0; i < DRM_FORMAT_MAX_PLANES; ++i) { obj = drm_gem_fb_get_obj(fb, i); - if (!obj) + if (!obj) { + dma_buf_map_clear(&map[i]); continue; + } ret = drm_gem_vmap(obj, &map[i]); if (ret) goto err_drm_gem_vunmap; @@ -376,6 +378,8 @@ void drm_gem_fb_vunmap(struct drm_framebuffer *fb, 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]); } } From 0029d3182969d8dc67e4fedb00d6cf50eee74670 Mon Sep 17 00:00:00 2001 From: Thomas Zimmermann Date: Fri, 30 Jul 2021 20:35:10 +0200 Subject: [PATCH 18/23] drm/gud: Map framebuffer BOs with drm_gem_fb_vmap() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Abstract the framebuffer details by mapping its BOs with a call to drm_gem_fb_vmap(). Unmap with drm_gem_fb_vunmap(). The call to drm_gem_fb_vmap() ensures that all BOs are mapped correctly. Gud still only supports single-plane formats. No functional changes. Signed-off-by: Thomas Zimmermann Acked-by: Noralf Trønnes Acked-by: Sam Ravnborg Link: https://patchwork.freedesktop.org/patch/msgid/20210730183511.20080-5-tzimmermann@suse.de --- drivers/gpu/drm/gud/gud_pipe.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/drivers/gpu/drm/gud/gud_pipe.c b/drivers/gpu/drm/gud/gud_pipe.c index 4d7a26b68a2e..7e009f562b30 100644 --- a/drivers/gpu/drm/gud/gud_pipe.c +++ b/drivers/gpu/drm/gud/gud_pipe.c @@ -14,8 +14,8 @@ #include #include #include +#include #include -#include #include #include #include @@ -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 @@ static int gud_prep_flush(struct gud_device *gdrm, struct drm_framebuffer *fb, 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; } From 50fff206c5e3a04fcb239ad58d89cad166711b7f Mon Sep 17 00:00:00 2001 From: Thomas Zimmermann Date: Fri, 30 Jul 2021 20:35:11 +0200 Subject: [PATCH 19/23] drm/vkms: Map output framebuffer BOs with drm_gem_fb_vmap() Abstract the framebuffer details by mappings its BOs with a call to drm_gem_fb_vmap(). Unmap with drm_gem_fb_vunamp(). Before, the output address with stored as raw pointer in the priv field of struct drm_writeback_job. Introduce the new type struct vkms_writeback_job, which holds the output mappings addresses while the writeback job is active. The patchset also cleans up some internal casting an setup of the output addresses. No functional changes. v3: * free instances of struct vkms_writeback_job on cleanup or errors Signed-off-by: Thomas Zimmermann Reviewed-by: Rodrigo Siqueira Acked-by: Sam Ravnborg Link: https://patchwork.freedesktop.org/patch/msgid/20210730183511.20080-6-tzimmermann@suse.de --- drivers/gpu/drm/vkms/vkms_composer.c | 2 +- drivers/gpu/drm/vkms/vkms_drv.h | 6 +++++- drivers/gpu/drm/vkms/vkms_writeback.c | 28 +++++++++++++++------------ 3 files changed, 22 insertions(+), 14 deletions(-) diff --git a/drivers/gpu/drm/vkms/vkms_composer.c b/drivers/gpu/drm/vkms/vkms_composer.c index ead8fff81f30..49f109c3a2b3 100644 --- a/drivers/gpu/drm/vkms/vkms_composer.c +++ b/drivers/gpu/drm/vkms/vkms_composer.c @@ -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); diff --git a/drivers/gpu/drm/vkms/vkms_drv.h b/drivers/gpu/drm/vkms/vkms_drv.h index 8c731b6dcba7..8bc9e3f52e1f 100644 --- a/drivers/gpu/drm/vkms/vkms_drv.h +++ b/drivers/gpu/drm/vkms/vkms_drv.h @@ -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; diff --git a/drivers/gpu/drm/vkms/vkms_writeback.c b/drivers/gpu/drm/vkms/vkms_writeback.c index 0935686475a0..425b6c6b8cad 100644 --- a/drivers/gpu/drm/vkms/vkms_writeback.c +++ b/drivers/gpu/drm/vkms/vkms_writeback.c @@ -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, From fed4c105acff35bc6e996b28aee5e91faaf5c192 Mon Sep 17 00:00:00 2001 From: Artjom Vejsel Date: Wed, 4 Aug 2021 03:23:52 +0300 Subject: [PATCH 20/23] dt-bindings: Add DT bindings for QiShenglong Gopher 2b panel Add DT bindings for QiShenglong Gopher 2b 4.3" 480(RGB)x272 TFT LCD panel. Signed-off-by: Artjom Vejsel Signed-off-by: Paul Cercueil Link: https://patchwork.freedesktop.org/patch/msgid/20210804002353.76385-3-akawolf0@gmail.com --- .../devicetree/bindings/display/panel/panel-simple.yaml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/Documentation/devicetree/bindings/display/panel/panel-simple.yaml b/Documentation/devicetree/bindings/display/panel/panel-simple.yaml index 81bdfb03bcea..335776c45474 100644 --- a/Documentation/devicetree/bindings/display/panel/panel-simple.yaml +++ b/Documentation/devicetree/bindings/display/panel/panel-simple.yaml @@ -256,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 From 49179e6657a252242ee912472c9d9c81a33800a6 Mon Sep 17 00:00:00 2001 From: Artjom Vejsel Date: Wed, 4 Aug 2021 03:23:53 +0300 Subject: [PATCH 21/23] drm/panel-simple: add Gopher 2b LCD panel The Gopher 2b LCD panel is used in Gopher 2b handhelds. It's simple panel with NewVision NV3047 driver, but SPI lines are not connected. It has no specific name, since it's unique to that handheld. lot name at AliExpress: 4.3 inch 40PIN TFT LCD Screen COG NV3047 Drive IC 480(RGB)*272 No Touch 24Bit RGB Interface Signed-off-by: Artjom Vejsel Signed-off-by: Paul Cercueil Link: https://patchwork.freedesktop.org/patch/msgid/20210804002353.76385-4-akawolf0@gmail.com --- drivers/gpu/drm/panel/panel-simple.c | 43 ++++++++++++++++++++++++++++ 1 file changed, 43 insertions(+) diff --git a/drivers/gpu/drm/panel/panel-simple.c b/drivers/gpu/drm/panel/panel-simple.c index e592551c9523..8e021b57875d 100644 --- a/drivers/gpu/drm/panel/panel-simple.c +++ b/drivers/gpu/drm/panel/panel-simple.c @@ -3622,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 }, @@ -4689,6 +4729,9 @@ 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, From 7dbdce8062687de103cba58bb2eded922cd41110 Mon Sep 17 00:00:00 2001 From: Dillon Min Date: Sat, 24 Jul 2021 11:44:01 +0800 Subject: [PATCH 22/23] dt-bindings: display: panel: Add ilitek ili9341 panel bindings Add documentation for "ilitek,ili9341" panel. Signed-off-by: Dillon Min Reviewed-by: Linus Walleij Reviewed-by: Rob Herring Link: https://lore.kernel.org/lkml/1626853288-31223-2-git-send-email-dillon.minfei@gmail.com/ Signed-off-by: Linus Walleij Link: https://patchwork.freedesktop.org/patch/msgid/1627098243-2742-2-git-send-email-dillon.minfei@gmail.com --- .../display/panel/ilitek,ili9341.yaml | 78 +++++++++++++++++++ 1 file changed, 78 insertions(+) create mode 100644 Documentation/devicetree/bindings/display/panel/ilitek,ili9341.yaml diff --git a/Documentation/devicetree/bindings/display/panel/ilitek,ili9341.yaml b/Documentation/devicetree/bindings/display/panel/ilitek,ili9341.yaml new file mode 100644 index 000000000000..2ed010f91e2d --- /dev/null +++ b/Documentation/devicetree/bindings/display/panel/ilitek,ili9341.yaml @@ -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 + +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>; + }; + }; + }; + }; +... + From 5a04227326b04c15b015181772f5c853172fdb68 Mon Sep 17 00:00:00 2001 From: Dillon Min Date: Sat, 24 Jul 2021 11:44:03 +0800 Subject: [PATCH 23/23] drm/panel: Add ilitek ili9341 panel driver This driver combines tiny/ili9341.c mipi_dbi_interface driver with mipi_dpi_interface driver, can support ili9341 with serial mode and parallel rgb interface mode by different dts bindings. Signed-off-by: Dillon Min Reported-by: kernel test robot Reviewed-by: Linus Walleij Reviewed-by: Jagan Teki Signed-off-by: Linus Walleij Link: https://patchwork.freedesktop.org/patch/msgid/1627098243-2742-4-git-send-email-dillon.minfei@gmail.com --- drivers/gpu/drm/panel/Kconfig | 12 + drivers/gpu/drm/panel/Makefile | 1 + drivers/gpu/drm/panel/panel-ilitek-ili9341.c | 792 +++++++++++++++++++ 3 files changed, 805 insertions(+) create mode 100644 drivers/gpu/drm/panel/panel-ilitek-ili9341.c diff --git a/drivers/gpu/drm/panel/Kconfig b/drivers/gpu/drm/panel/Kconfig index f5a65f3bd5b4..beb581b96ecd 100644 --- a/drivers/gpu/drm/panel/Kconfig +++ b/drivers/gpu/drm/panel/Kconfig @@ -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 diff --git a/drivers/gpu/drm/panel/Makefile b/drivers/gpu/drm/panel/Makefile index 1b6fe2008861..c8132050bcec 100644 --- a/drivers/gpu/drm/panel/Makefile +++ b/drivers/gpu/drm/panel/Makefile @@ -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 diff --git a/drivers/gpu/drm/panel/panel-ilitek-ili9341.c b/drivers/gpu/drm/panel/panel-ilitek-ili9341.c new file mode 100644 index 000000000000..2c3378a259b1 --- /dev/null +++ b/drivers/gpu/drm/panel/panel-ilitek-ili9341.c @@ -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 + * + * 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 + */ + +#include +#include +#include +#include +#include +#include +#include + +#include