diff --git a/Documentation/devicetree/bindings/display/panel/leadtek,ltk500hd1829.yaml b/Documentation/devicetree/bindings/display/panel/leadtek,ltk500hd1829.yaml new file mode 100644 index 000000000000..4ebcea7d0c63 --- /dev/null +++ b/Documentation/devicetree/bindings/display/panel/leadtek,ltk500hd1829.yaml @@ -0,0 +1,49 @@ +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/display/panel/leadtek,ltk500hd1829.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Leadtek LTK500HD1829 5.0in 720x1280 DSI panel + +maintainers: + - Heiko Stuebner + +allOf: + - $ref: panel-common.yaml# + +properties: + compatible: + const: leadtek,ltk500hd1829 + reg: true + backlight: true + reset-gpios: true + iovcc-supply: + description: regulator that supplies the iovcc voltage + vcc-supply: + description: regulator that supplies the vcc voltage + +required: + - compatible + - reg + - backlight + - iovcc-supply + - vcc-supply + +additionalProperties: false + +examples: + - | + dsi@ff450000 { + #address-cells = <1>; + #size-cells = <0>; + panel@0 { + compatible = "leadtek,ltk500hd1829"; + reg = <0>; + backlight = <&backlight>; + iovcc-supply = <&vcc_1v8>; + vcc-supply = <&vcc_2v8>; + }; + }; + +... diff --git a/Documentation/devicetree/bindings/display/panel/xinpeng,xpp055c272.yaml b/Documentation/devicetree/bindings/display/panel/xinpeng,xpp055c272.yaml new file mode 100644 index 000000000000..186e5e1c8fa3 --- /dev/null +++ b/Documentation/devicetree/bindings/display/panel/xinpeng,xpp055c272.yaml @@ -0,0 +1,49 @@ +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/display/panel/xinpeng,xpp055c272.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Xinpeng XPP055C272 5.5in 720x1280 DSI panel + +maintainers: + - Heiko Stuebner + +allOf: + - $ref: panel-common.yaml# + +properties: + compatible: + const: xinpeng,xpp055c272 + reg: true + backlight: true + reset-gpios: true + iovcc-supply: + description: regulator that supplies the iovcc voltage + vci-supply: + description: regulator that supplies the vci voltage + +required: + - compatible + - reg + - backlight + - iovcc-supply + - vci-supply + +additionalProperties: false + +examples: + - | + dsi@ff450000 { + #address-cells = <1>; + #size-cells = <0>; + panel@0 { + compatible = "xinpeng,xpp055c272"; + reg = <0>; + backlight = <&backlight>; + iovcc-supply = <&vcc_1v8>; + vci-supply = <&vcc3v3_lcd>; + }; + }; + +... diff --git a/Documentation/devicetree/bindings/display/rockchip/rockchip-lvds.txt b/Documentation/devicetree/bindings/display/rockchip/rockchip-lvds.txt index 7849ff039229..aaf8c44cf90f 100644 --- a/Documentation/devicetree/bindings/display/rockchip/rockchip-lvds.txt +++ b/Documentation/devicetree/bindings/display/rockchip/rockchip-lvds.txt @@ -4,6 +4,7 @@ Rockchip RK3288 LVDS interface Required properties: - compatible: matching the soc type, one of - "rockchip,rk3288-lvds"; + - "rockchip,px30-lvds"; - reg: physical base address of the controller and length of memory mapped region. @@ -18,6 +19,9 @@ Required properties: - rockchip,grf: phandle to the general register files syscon - rockchip,output: "rgb", "lvds" or "duallvds", This describes the output interface +- phys: LVDS/DSI DPHY (px30 only) +- phy-names: name of the PHY, must be "dphy" (px30 only) + Optional properties: - pinctrl-names: must contain a "lcdc" entry. - pinctrl-0: pin control group to be used for this controller. diff --git a/Documentation/devicetree/bindings/vendor-prefixes.yaml b/Documentation/devicetree/bindings/vendor-prefixes.yaml index 6046f4555852..4e6248ec5ed9 100644 --- a/Documentation/devicetree/bindings/vendor-prefixes.yaml +++ b/Documentation/devicetree/bindings/vendor-prefixes.yaml @@ -513,6 +513,8 @@ patternProperties: description: Lantiq Semiconductor "^lattice,.*": description: Lattice Semiconductor + "^leadtek,.*": + description: Shenzhen Leadtek Technology Co., Ltd. "^leez,.*": description: Leez "^lego,.*": @@ -1056,6 +1058,8 @@ patternProperties: description: Extreme Engineering Solutions (X-ES) "^xillybus,.*": description: Xillybus Ltd. + "^xinpeng,.*": + description: Shenzhen Xinpeng Technology Co., Ltd "^xlnx,.*": description: Xilinx "^xunlong,.*": diff --git a/Documentation/fb/fbcon.rst b/Documentation/fb/fbcon.rst index ebca41785abe..e57a3d1d085a 100644 --- a/Documentation/fb/fbcon.rst +++ b/Documentation/fb/fbcon.rst @@ -127,7 +127,7 @@ C. Boot options is typically located on the same video card. Thus, the consoles that are controlled by the VGA console will be garbled. -4. fbcon=rotate: +5. fbcon=rotate: This option changes the orientation angle of the console display. The value 'n' accepts the following: @@ -152,21 +152,21 @@ C. Boot options Actually, the underlying fb driver is totally ignorant of console rotation. -5. fbcon=margin: +6. fbcon=margin: This option specifies the color of the margins. The margins are the leftover area at the right and the bottom of the screen that are not used by text. By default, this area will be black. The 'color' value is an integer number that depends on the framebuffer driver being used. -6. fbcon=nodefer +7. fbcon=nodefer If the kernel is compiled with deferred fbcon takeover support, normally the framebuffer contents, left in place by the firmware/bootloader, will be preserved until there actually is some text is output to the console. This option causes fbcon to bind immediately to the fbdev device. -7. fbcon=logo-pos: +8. fbcon=logo-pos: The only possible 'location' is 'center' (without quotes), and when given, the bootup logo is moved from the default top-left corner @@ -174,6 +174,11 @@ C. Boot options displayed due to multiple CPUs, the collected line of logos is moved as a whole. +9. fbcon=logo-count: + + The value 'n' overrides the number of bootup logos. 0 disables the + logo, and -1 gives the default which is the number of online CPUs. + C. Attaching, Detaching and Unloading Before going on to how to attach, detach and unload the framebuffer console, an diff --git a/drivers/gpu/drm/ast/ast_mode.c b/drivers/gpu/drm/ast/ast_mode.c index cde1cae073ec..34608f0499eb 100644 --- a/drivers/gpu/drm/ast/ast_mode.c +++ b/drivers/gpu/drm/ast/ast_mode.c @@ -1144,8 +1144,7 @@ static int ast_cursor_init(struct drm_device *dev) size = roundup(AST_HWC_SIZE + AST_HWC_SIGNATURE_SIZE, PAGE_SIZE); for (i = 0; i < ARRAY_SIZE(ast->cursor.gbo); ++i) { - gbo = drm_gem_vram_create(dev, &dev->vram_mm->bdev, - size, 0, false); + gbo = drm_gem_vram_create(dev, size, 0); if (IS_ERR(gbo)) { ret = PTR_ERR(gbo); goto err_drm_gem_vram_put; diff --git a/drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_crtc.c b/drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_crtc.c index f2e73e6d46b8..10985134ce0b 100644 --- a/drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_crtc.c +++ b/drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_crtc.c @@ -73,7 +73,11 @@ static void atmel_hlcdc_crtc_mode_set_nofb(struct drm_crtc *c) unsigned long prate; unsigned int mask = ATMEL_HLCDC_CLKDIV_MASK | ATMEL_HLCDC_CLKPOL; unsigned int cfg = 0; - int div; + int div, ret; + + ret = clk_prepare_enable(crtc->dc->hlcdc->sys_clk); + if (ret) + return; vm.vfront_porch = adj->crtc_vsync_start - adj->crtc_vdisplay; vm.vback_porch = adj->crtc_vtotal - adj->crtc_vsync_end; @@ -95,14 +99,14 @@ static void atmel_hlcdc_crtc_mode_set_nofb(struct drm_crtc *c) (adj->crtc_hdisplay - 1) | ((adj->crtc_vdisplay - 1) << 16)); + prate = clk_get_rate(crtc->dc->hlcdc->sys_clk); + mode_rate = adj->crtc_clock * 1000; if (!crtc->dc->desc->fixed_clksrc) { + prate *= 2; cfg |= ATMEL_HLCDC_CLKSEL; mask |= ATMEL_HLCDC_CLKSEL; } - prate = 2 * clk_get_rate(crtc->dc->hlcdc->sys_clk); - mode_rate = adj->crtc_clock * 1000; - div = DIV_ROUND_UP(prate, mode_rate); if (div < 2) { div = 2; @@ -117,8 +121,8 @@ static void atmel_hlcdc_crtc_mode_set_nofb(struct drm_crtc *c) int div_low = prate / mode_rate; if (div_low >= 2 && - ((prate / div_low - mode_rate) < - 10 * (mode_rate - prate / div))) + (10 * (prate / div_low - mode_rate) < + (mode_rate - prate / div))) /* * At least 10 times better when using a higher * frequency than requested, instead of a lower. @@ -147,6 +151,8 @@ static void atmel_hlcdc_crtc_mode_set_nofb(struct drm_crtc *c) ATMEL_HLCDC_VSPSU | ATMEL_HLCDC_VSPHO | ATMEL_HLCDC_GUARDTIME_MASK | ATMEL_HLCDC_MODE_MASK, cfg); + + clk_disable_unprepare(crtc->dc->hlcdc->sys_clk); } static enum drm_mode_status diff --git a/drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_dc.c b/drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_dc.c index 8dc917a1270b..112aa5066cee 100644 --- a/drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_dc.c +++ b/drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_dc.c @@ -721,18 +721,10 @@ static int atmel_hlcdc_dc_load(struct drm_device *dev) dc->hlcdc = dev_get_drvdata(dev->dev->parent); dev->dev_private = dc; - if (dc->desc->fixed_clksrc) { - ret = clk_prepare_enable(dc->hlcdc->sys_clk); - if (ret) { - dev_err(dev->dev, "failed to enable sys_clk\n"); - goto err_destroy_wq; - } - } - ret = clk_prepare_enable(dc->hlcdc->periph_clk); if (ret) { dev_err(dev->dev, "failed to enable periph_clk\n"); - goto err_sys_clk_disable; + goto err_destroy_wq; } pm_runtime_enable(dev->dev); @@ -768,9 +760,6 @@ static int atmel_hlcdc_dc_load(struct drm_device *dev) err_periph_clk_disable: pm_runtime_disable(dev->dev); clk_disable_unprepare(dc->hlcdc->periph_clk); -err_sys_clk_disable: - if (dc->desc->fixed_clksrc) - clk_disable_unprepare(dc->hlcdc->sys_clk); err_destroy_wq: destroy_workqueue(dc->wq); @@ -795,8 +784,6 @@ static void atmel_hlcdc_dc_unload(struct drm_device *dev) pm_runtime_disable(dev->dev); clk_disable_unprepare(dc->hlcdc->periph_clk); - if (dc->desc->fixed_clksrc) - clk_disable_unprepare(dc->hlcdc->sys_clk); destroy_workqueue(dc->wq); } @@ -910,8 +897,6 @@ static int atmel_hlcdc_dc_drm_suspend(struct device *dev) regmap_read(regmap, ATMEL_HLCDC_IMR, &dc->suspend.imr); regmap_write(regmap, ATMEL_HLCDC_IDR, dc->suspend.imr); clk_disable_unprepare(dc->hlcdc->periph_clk); - if (dc->desc->fixed_clksrc) - clk_disable_unprepare(dc->hlcdc->sys_clk); return 0; } @@ -921,8 +906,6 @@ static int atmel_hlcdc_dc_drm_resume(struct device *dev) struct drm_device *drm_dev = dev_get_drvdata(dev); struct atmel_hlcdc_dc *dc = drm_dev->dev_private; - if (dc->desc->fixed_clksrc) - clk_prepare_enable(dc->hlcdc->sys_clk); clk_prepare_enable(dc->hlcdc->periph_clk); regmap_write(dc->hlcdc->regmap, ATMEL_HLCDC_IER, dc->suspend.imr); diff --git a/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c b/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c index 6effe532f820..6fab71985cd4 100644 --- a/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c +++ b/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c @@ -1289,19 +1289,21 @@ struct drm_crtc *analogix_dp_get_new_crtc(struct analogix_dp_device *dp, return conn_state->crtc; } -static void analogix_dp_bridge_atomic_pre_enable(struct drm_bridge *bridge, - struct drm_atomic_state *state) +static void +analogix_dp_bridge_atomic_pre_enable(struct drm_bridge *bridge, + struct drm_bridge_state *old_bridge_state) { + struct drm_atomic_state *old_state = old_bridge_state->base.state; struct analogix_dp_device *dp = bridge->driver_private; struct drm_crtc *crtc; struct drm_crtc_state *old_crtc_state; int ret; - crtc = analogix_dp_get_new_crtc(dp, state); + crtc = analogix_dp_get_new_crtc(dp, old_state); if (!crtc) return; - old_crtc_state = drm_atomic_get_old_crtc_state(state, crtc); + old_crtc_state = drm_atomic_get_old_crtc_state(old_state, crtc); /* Don't touch the panel if we're coming back from PSR */ if (old_crtc_state && old_crtc_state->self_refresh_active) return; @@ -1366,20 +1368,22 @@ out_dp_clk_pre: return ret; } -static void analogix_dp_bridge_atomic_enable(struct drm_bridge *bridge, - struct drm_atomic_state *state) +static void +analogix_dp_bridge_atomic_enable(struct drm_bridge *bridge, + struct drm_bridge_state *old_bridge_state) { + struct drm_atomic_state *old_state = old_bridge_state->base.state; struct analogix_dp_device *dp = bridge->driver_private; struct drm_crtc *crtc; struct drm_crtc_state *old_crtc_state; int timeout_loop = 0; int ret; - crtc = analogix_dp_get_new_crtc(dp, state); + crtc = analogix_dp_get_new_crtc(dp, old_state); if (!crtc) return; - old_crtc_state = drm_atomic_get_old_crtc_state(state, crtc); + old_crtc_state = drm_atomic_get_old_crtc_state(old_state, crtc); /* Not a full enable, just disable PSR and continue */ if (old_crtc_state && old_crtc_state->self_refresh_active) { ret = analogix_dp_disable_psr(dp); @@ -1440,18 +1444,20 @@ static void analogix_dp_bridge_disable(struct drm_bridge *bridge) dp->dpms_mode = DRM_MODE_DPMS_OFF; } -static void analogix_dp_bridge_atomic_disable(struct drm_bridge *bridge, - struct drm_atomic_state *state) +static void +analogix_dp_bridge_atomic_disable(struct drm_bridge *bridge, + struct drm_bridge_state *old_bridge_state) { + struct drm_atomic_state *old_state = old_bridge_state->base.state; struct analogix_dp_device *dp = bridge->driver_private; struct drm_crtc *crtc; struct drm_crtc_state *new_crtc_state = NULL; - crtc = analogix_dp_get_new_crtc(dp, state); + crtc = analogix_dp_get_new_crtc(dp, old_state); if (!crtc) goto out; - new_crtc_state = drm_atomic_get_new_crtc_state(state, crtc); + new_crtc_state = drm_atomic_get_new_crtc_state(old_state, crtc); if (!new_crtc_state) goto out; @@ -1463,20 +1469,21 @@ out: analogix_dp_bridge_disable(bridge); } -static -void analogix_dp_bridge_atomic_post_disable(struct drm_bridge *bridge, - struct drm_atomic_state *state) +static void +analogix_dp_bridge_atomic_post_disable(struct drm_bridge *bridge, + struct drm_bridge_state *old_bridge_state) { + struct drm_atomic_state *old_state = old_bridge_state->base.state; struct analogix_dp_device *dp = bridge->driver_private; struct drm_crtc *crtc; struct drm_crtc_state *new_crtc_state; int ret; - crtc = analogix_dp_get_new_crtc(dp, state); + crtc = analogix_dp_get_new_crtc(dp, old_state); if (!crtc) return; - new_crtc_state = drm_atomic_get_new_crtc_state(state, crtc); + new_crtc_state = drm_atomic_get_new_crtc_state(old_state, crtc); if (!new_crtc_state || !new_crtc_state->self_refresh_active) return; diff --git a/drivers/gpu/drm/bridge/cdns-dsi.c b/drivers/gpu/drm/bridge/cdns-dsi.c index 3a5bd4e7fd1e..b7c97f060241 100644 --- a/drivers/gpu/drm/bridge/cdns-dsi.c +++ b/drivers/gpu/drm/bridge/cdns-dsi.c @@ -512,7 +512,7 @@ static int cdns_dsi_mode2cfg(struct cdns_dsi *dsi, struct cdns_dsi_output *output = &dsi->output; unsigned int tmp; bool sync_pulse = false; - int bpp, nlanes; + int bpp; memset(dsi_cfg, 0, sizeof(*dsi_cfg)); @@ -520,7 +520,6 @@ static int cdns_dsi_mode2cfg(struct cdns_dsi *dsi, sync_pulse = true; bpp = mipi_dsi_pixel_format_to_bpp(output->dev->format); - nlanes = output->dev->lanes; if (mode_valid_check) tmp = mode->htotal - @@ -785,13 +784,12 @@ static void cdns_dsi_bridge_enable(struct drm_bridge *bridge) unsigned long tx_byte_period; struct cdns_dsi_cfg dsi_cfg; u32 tmp, reg_wakeup, div; - int bpp, nlanes; + int nlanes; if (WARN_ON(pm_runtime_get_sync(dsi->base.dev) < 0)) return; mode = &bridge->encoder->crtc->state->adjusted_mode; - bpp = mipi_dsi_pixel_format_to_bpp(output->dev->format); nlanes = output->dev->lanes; WARN_ON_ONCE(cdns_dsi_check_conf(dsi, mode, &dsi_cfg, false)); diff --git a/drivers/gpu/drm/bridge/synopsys/dw-hdmi-ahb-audio.c b/drivers/gpu/drm/bridge/synopsys/dw-hdmi-ahb-audio.c index 2b7539701b42..dd56996fe9c7 100644 --- a/drivers/gpu/drm/bridge/synopsys/dw-hdmi-ahb-audio.c +++ b/drivers/gpu/drm/bridge/synopsys/dw-hdmi-ahb-audio.c @@ -291,7 +291,7 @@ static irqreturn_t snd_dw_hdmi_irq(int irq, void *data) return IRQ_HANDLED; } -static struct snd_pcm_hardware dw_hdmi_hw = { +static const struct snd_pcm_hardware dw_hdmi_hw = { .info = SNDRV_PCM_INFO_INTERLEAVED | SNDRV_PCM_INFO_BLOCK_TRANSFER | SNDRV_PCM_INFO_MMAP | diff --git a/drivers/gpu/drm/drm_atomic.c b/drivers/gpu/drm/drm_atomic.c index d33691512a8e..bf1b9c37d515 100644 --- a/drivers/gpu/drm/drm_atomic.c +++ b/drivers/gpu/drm/drm_atomic.c @@ -30,6 +30,7 @@ #include #include +#include #include #include #include @@ -1017,6 +1018,44 @@ static void drm_atomic_connector_print_state(struct drm_printer *p, connector->funcs->atomic_print_state(p, state); } +/** + * drm_atomic_add_encoder_bridges - add bridges attached to an encoder + * @state: atomic state + * @encoder: DRM encoder + * + * This function adds all bridges attached to @encoder. This is needed to add + * bridge states to @state and make them available when + * &bridge_funcs.atomic_{check,pre_enable,enable,disable_post_disable}() are + * called + * + * Returns: + * 0 on success or can fail with -EDEADLK or -ENOMEM. When the error is EDEADLK + * then the w/w mutex code has detected a deadlock and the entire atomic + * sequence must be restarted. All other errors are fatal. + */ +int +drm_atomic_add_encoder_bridges(struct drm_atomic_state *state, + struct drm_encoder *encoder) +{ + struct drm_bridge_state *bridge_state; + struct drm_bridge *bridge; + + if (!encoder) + return 0; + + DRM_DEBUG_ATOMIC("Adding all bridges for [encoder:%d:%s] to %p\n", + encoder->base.id, encoder->name, state); + + drm_for_each_bridge_in_chain(encoder, bridge) { + bridge_state = drm_atomic_get_bridge_state(state, bridge); + if (IS_ERR(bridge_state)) + return PTR_ERR(bridge_state); + } + + return 0; +} +EXPORT_SYMBOL(drm_atomic_add_encoder_bridges); + /** * drm_atomic_add_affected_connectors - add connectors for CRTC * @state: atomic state diff --git a/drivers/gpu/drm/drm_atomic_helper.c b/drivers/gpu/drm/drm_atomic_helper.c index 4511c2e07bb9..afe14f72a824 100644 --- a/drivers/gpu/drm/drm_atomic_helper.c +++ b/drivers/gpu/drm/drm_atomic_helper.c @@ -437,12 +437,12 @@ mode_fixup(struct drm_atomic_state *state) funcs = encoder->helper_private; bridge = drm_bridge_chain_get_first_bridge(encoder); - ret = drm_bridge_chain_mode_fixup(bridge, - &new_crtc_state->mode, - &new_crtc_state->adjusted_mode); - if (!ret) { - DRM_DEBUG_ATOMIC("Bridge fixup failed\n"); - return -EINVAL; + ret = drm_atomic_bridge_chain_check(bridge, + new_crtc_state, + new_conn_state); + if (ret) { + DRM_DEBUG_ATOMIC("Bridge atomic check failed\n"); + return ret; } if (funcs && funcs->atomic_check) { @@ -730,6 +730,26 @@ drm_atomic_helper_check_modeset(struct drm_device *dev, return ret; } + /* + * Iterate over all connectors again, and add all affected bridges to + * the state. + */ + for_each_oldnew_connector_in_state(state, connector, + old_connector_state, + new_connector_state, i) { + struct drm_encoder *encoder; + + encoder = old_connector_state->best_encoder; + ret = drm_atomic_add_encoder_bridges(state, encoder); + if (ret) + return ret; + + encoder = new_connector_state->best_encoder; + ret = drm_atomic_add_encoder_bridges(state, encoder); + if (ret) + return ret; + } + ret = mode_valid(state); if (ret) return ret; diff --git a/drivers/gpu/drm/drm_bridge.c b/drivers/gpu/drm/drm_bridge.c index c2cf0c90fa26..37400607e9b7 100644 --- a/drivers/gpu/drm/drm_bridge.c +++ b/drivers/gpu/drm/drm_bridge.c @@ -25,6 +25,7 @@ #include #include +#include #include #include @@ -89,6 +90,74 @@ void drm_bridge_remove(struct drm_bridge *bridge) } EXPORT_SYMBOL(drm_bridge_remove); +static struct drm_bridge_state * +drm_atomic_default_bridge_duplicate_state(struct drm_bridge *bridge) +{ + struct drm_bridge_state *new; + + if (WARN_ON(!bridge->base.state)) + return NULL; + + new = kzalloc(sizeof(*new), GFP_KERNEL); + if (new) + __drm_atomic_helper_bridge_duplicate_state(bridge, new); + + return new; +} + +static struct drm_private_state * +drm_bridge_atomic_duplicate_priv_state(struct drm_private_obj *obj) +{ + struct drm_bridge *bridge = drm_priv_to_bridge(obj); + struct drm_bridge_state *state; + + if (bridge->funcs->atomic_duplicate_state) + state = bridge->funcs->atomic_duplicate_state(bridge); + else + state = drm_atomic_default_bridge_duplicate_state(bridge); + + return state ? &state->base : NULL; +} + +static void +drm_atomic_default_bridge_destroy_state(struct drm_bridge *bridge, + struct drm_bridge_state *state) +{ + /* Just a simple kfree() for now */ + kfree(state); +} + +static void +drm_bridge_atomic_destroy_priv_state(struct drm_private_obj *obj, + struct drm_private_state *s) +{ + struct drm_bridge_state *state = drm_priv_to_bridge_state(s); + struct drm_bridge *bridge = drm_priv_to_bridge(obj); + + if (bridge->funcs->atomic_destroy_state) + bridge->funcs->atomic_destroy_state(bridge, state); + else + drm_atomic_default_bridge_destroy_state(bridge, state); +} + +static const struct drm_private_state_funcs drm_bridge_priv_state_funcs = { + .atomic_duplicate_state = drm_bridge_atomic_duplicate_priv_state, + .atomic_destroy_state = drm_bridge_atomic_destroy_priv_state, +}; + +static struct drm_bridge_state * +drm_atomic_default_bridge_reset(struct drm_bridge *bridge) +{ + struct drm_bridge_state *bridge_state; + + bridge_state = kzalloc(sizeof(*bridge_state), GFP_KERNEL); + if (!bridge_state) + return ERR_PTR(-ENOMEM); + + __drm_atomic_helper_bridge_reset(bridge, bridge_state); + return bridge_state; +} + /** * drm_bridge_attach - attach the bridge to an encoder's chain * @@ -114,6 +183,7 @@ EXPORT_SYMBOL(drm_bridge_remove); int drm_bridge_attach(struct drm_encoder *encoder, struct drm_bridge *bridge, struct drm_bridge *previous) { + struct drm_bridge_state *state; int ret; if (!encoder || !bridge) @@ -135,15 +205,35 @@ int drm_bridge_attach(struct drm_encoder *encoder, struct drm_bridge *bridge, if (bridge->funcs->attach) { ret = bridge->funcs->attach(bridge); - if (ret < 0) { - list_del(&bridge->chain_node); - bridge->dev = NULL; - bridge->encoder = NULL; - return ret; - } + if (ret < 0) + goto err_reset_bridge; } + if (bridge->funcs->atomic_reset) + state = bridge->funcs->atomic_reset(bridge); + else + state = drm_atomic_default_bridge_reset(bridge); + + if (IS_ERR(state)) { + ret = PTR_ERR(state); + goto err_detach_bridge; + } + + drm_atomic_private_obj_init(bridge->dev, &bridge->base, + &state->base, + &drm_bridge_priv_state_funcs); + return 0; + +err_detach_bridge: + if (bridge->funcs->detach) + bridge->funcs->detach(bridge); + +err_reset_bridge: + bridge->dev = NULL; + bridge->encoder = NULL; + list_del(&bridge->chain_node); + return ret; } EXPORT_SYMBOL(drm_bridge_attach); @@ -155,6 +245,8 @@ void drm_bridge_detach(struct drm_bridge *bridge) if (WARN_ON(!bridge->dev)) return; + drm_atomic_private_obj_fini(&bridge->base); + if (bridge->funcs->detach) bridge->funcs->detach(bridge); @@ -409,10 +501,19 @@ void drm_atomic_bridge_chain_disable(struct drm_bridge *bridge, encoder = bridge->encoder; list_for_each_entry_reverse(iter, &encoder->bridge_chain, chain_node) { - if (iter->funcs->atomic_disable) - iter->funcs->atomic_disable(iter, old_state); - else if (iter->funcs->disable) + if (iter->funcs->atomic_disable) { + struct drm_bridge_state *old_bridge_state; + + old_bridge_state = + drm_atomic_get_old_bridge_state(old_state, + iter); + if (WARN_ON(!old_bridge_state)) + return; + + iter->funcs->atomic_disable(iter, old_bridge_state); + } else if (iter->funcs->disable) { iter->funcs->disable(iter); + } if (iter == bridge) break; @@ -443,10 +544,20 @@ void drm_atomic_bridge_chain_post_disable(struct drm_bridge *bridge, encoder = bridge->encoder; list_for_each_entry_from(bridge, &encoder->bridge_chain, chain_node) { - if (bridge->funcs->atomic_post_disable) - bridge->funcs->atomic_post_disable(bridge, old_state); - else if (bridge->funcs->post_disable) + if (bridge->funcs->atomic_post_disable) { + struct drm_bridge_state *old_bridge_state; + + old_bridge_state = + drm_atomic_get_old_bridge_state(old_state, + bridge); + if (WARN_ON(!old_bridge_state)) + return; + + bridge->funcs->atomic_post_disable(bridge, + old_bridge_state); + } else if (bridge->funcs->post_disable) { bridge->funcs->post_disable(bridge); + } } } EXPORT_SYMBOL(drm_atomic_bridge_chain_post_disable); @@ -475,10 +586,19 @@ void drm_atomic_bridge_chain_pre_enable(struct drm_bridge *bridge, encoder = bridge->encoder; list_for_each_entry_reverse(iter, &encoder->bridge_chain, chain_node) { - if (iter->funcs->atomic_pre_enable) - iter->funcs->atomic_pre_enable(iter, old_state); - else if (iter->funcs->pre_enable) + if (iter->funcs->atomic_pre_enable) { + struct drm_bridge_state *old_bridge_state; + + old_bridge_state = + drm_atomic_get_old_bridge_state(old_state, + iter); + if (WARN_ON(!old_bridge_state)) + return; + + iter->funcs->atomic_pre_enable(iter, old_bridge_state); + } else if (iter->funcs->pre_enable) { iter->funcs->pre_enable(iter); + } if (iter == bridge) break; @@ -508,14 +628,385 @@ void drm_atomic_bridge_chain_enable(struct drm_bridge *bridge, encoder = bridge->encoder; list_for_each_entry_from(bridge, &encoder->bridge_chain, chain_node) { - if (bridge->funcs->atomic_enable) - bridge->funcs->atomic_enable(bridge, old_state); - else if (bridge->funcs->enable) + if (bridge->funcs->atomic_enable) { + struct drm_bridge_state *old_bridge_state; + + old_bridge_state = + drm_atomic_get_old_bridge_state(old_state, + bridge); + if (WARN_ON(!old_bridge_state)) + return; + + bridge->funcs->atomic_enable(bridge, old_bridge_state); + } else if (bridge->funcs->enable) { bridge->funcs->enable(bridge); + } } } EXPORT_SYMBOL(drm_atomic_bridge_chain_enable); +static int drm_atomic_bridge_check(struct drm_bridge *bridge, + struct drm_crtc_state *crtc_state, + struct drm_connector_state *conn_state) +{ + if (bridge->funcs->atomic_check) { + struct drm_bridge_state *bridge_state; + int ret; + + bridge_state = drm_atomic_get_new_bridge_state(crtc_state->state, + bridge); + if (WARN_ON(!bridge_state)) + return -EINVAL; + + ret = bridge->funcs->atomic_check(bridge, bridge_state, + crtc_state, conn_state); + if (ret) + return ret; + } else if (bridge->funcs->mode_fixup) { + if (!bridge->funcs->mode_fixup(bridge, &crtc_state->mode, + &crtc_state->adjusted_mode)) + return -EINVAL; + } + + return 0; +} + +/** + * drm_atomic_helper_bridge_propagate_bus_fmt() - Propagate output format to + * the input end of a bridge + * @bridge: bridge control structure + * @bridge_state: new bridge state + * @crtc_state: new CRTC state + * @conn_state: new connector state + * @output_fmt: tested output bus format + * @num_input_fmts: will contain the size of the returned array + * + * This helper is a pluggable implementation of the + * &drm_bridge_funcs.atomic_get_input_bus_fmts operation for bridges that don't + * modify the bus configuration between their input and their output. It + * returns an array of input formats with a single element set to @output_fmt. + * + * RETURNS: + * a valid format array of size @num_input_fmts, or NULL if the allocation + * failed + */ +u32 * +drm_atomic_helper_bridge_propagate_bus_fmt(struct drm_bridge *bridge, + struct drm_bridge_state *bridge_state, + struct drm_crtc_state *crtc_state, + struct drm_connector_state *conn_state, + u32 output_fmt, + unsigned int *num_input_fmts) +{ + u32 *input_fmts; + + input_fmts = kzalloc(sizeof(*input_fmts), GFP_KERNEL); + if (!input_fmts) { + *num_input_fmts = 0; + return NULL; + } + + *num_input_fmts = 1; + input_fmts[0] = output_fmt; + return input_fmts; +} +EXPORT_SYMBOL(drm_atomic_helper_bridge_propagate_bus_fmt); + +static int select_bus_fmt_recursive(struct drm_bridge *first_bridge, + struct drm_bridge *cur_bridge, + struct drm_crtc_state *crtc_state, + struct drm_connector_state *conn_state, + u32 out_bus_fmt) +{ + struct drm_bridge_state *cur_state; + unsigned int num_in_bus_fmts, i; + struct drm_bridge *prev_bridge; + u32 *in_bus_fmts; + int ret; + + prev_bridge = drm_bridge_get_prev_bridge(cur_bridge); + cur_state = drm_atomic_get_new_bridge_state(crtc_state->state, + cur_bridge); + if (WARN_ON(!cur_state)) + return -EINVAL; + + /* + * If bus format negotiation is not supported by this bridge, let's + * pass MEDIA_BUS_FMT_FIXED to the previous bridge in the chain and + * hope that it can handle this situation gracefully (by providing + * appropriate default values). + */ + if (!cur_bridge->funcs->atomic_get_input_bus_fmts) { + if (cur_bridge != first_bridge) { + ret = select_bus_fmt_recursive(first_bridge, + prev_bridge, crtc_state, + conn_state, + MEDIA_BUS_FMT_FIXED); + if (ret) + return ret; + } + + cur_state->input_bus_cfg.format = MEDIA_BUS_FMT_FIXED; + cur_state->output_bus_cfg.format = out_bus_fmt; + return 0; + } + + in_bus_fmts = cur_bridge->funcs->atomic_get_input_bus_fmts(cur_bridge, + cur_state, + crtc_state, + conn_state, + out_bus_fmt, + &num_in_bus_fmts); + if (!num_in_bus_fmts) + return -ENOTSUPP; + else if (!in_bus_fmts) + return -ENOMEM; + + if (first_bridge == cur_bridge) { + cur_state->input_bus_cfg.format = in_bus_fmts[0]; + cur_state->output_bus_cfg.format = out_bus_fmt; + kfree(in_bus_fmts); + return 0; + } + + for (i = 0; i < num_in_bus_fmts; i++) { + ret = select_bus_fmt_recursive(first_bridge, prev_bridge, + crtc_state, conn_state, + in_bus_fmts[i]); + if (ret != -ENOTSUPP) + break; + } + + if (!ret) { + cur_state->input_bus_cfg.format = in_bus_fmts[i]; + cur_state->output_bus_cfg.format = out_bus_fmt; + } + + kfree(in_bus_fmts); + return ret; +} + +/* + * This function is called by &drm_atomic_bridge_chain_check() just before + * calling &drm_bridge_funcs.atomic_check() on all elements of the chain. + * It performs bus format negotiation between bridge elements. The negotiation + * happens in reverse order, starting from the last element in the chain up to + * @bridge. + * + * Negotiation starts by retrieving supported output bus formats on the last + * bridge element and testing them one by one. The test is recursive, meaning + * that for each tested output format, the whole chain will be walked backward, + * and each element will have to choose an input bus format that can be + * transcoded to the requested output format. When a bridge element does not + * support transcoding into a specific output format -ENOTSUPP is returned and + * the next bridge element will have to try a different format. If none of the + * combinations worked, -ENOTSUPP is returned and the atomic modeset will fail. + * + * This implementation is relying on + * &drm_bridge_funcs.atomic_get_output_bus_fmts() and + * &drm_bridge_funcs.atomic_get_input_bus_fmts() to gather supported + * input/output formats. + * + * When &drm_bridge_funcs.atomic_get_output_bus_fmts() is not implemented by + * the last element of the chain, &drm_atomic_bridge_chain_select_bus_fmts() + * tries a single format: &drm_connector.display_info.bus_formats[0] if + * available, MEDIA_BUS_FMT_FIXED otherwise. + * + * When &drm_bridge_funcs.atomic_get_input_bus_fmts() is not implemented, + * &drm_atomic_bridge_chain_select_bus_fmts() skips the negotiation on the + * bridge element that lacks this hook and asks the previous element in the + * chain to try MEDIA_BUS_FMT_FIXED. It's up to bridge drivers to decide what + * to do in that case (fail if they want to enforce bus format negotiation, or + * provide a reasonable default if they need to support pipelines where not + * all elements support bus format negotiation). + */ +static int +drm_atomic_bridge_chain_select_bus_fmts(struct drm_bridge *bridge, + struct drm_crtc_state *crtc_state, + struct drm_connector_state *conn_state) +{ + struct drm_connector *conn = conn_state->connector; + struct drm_encoder *encoder = bridge->encoder; + struct drm_bridge_state *last_bridge_state; + unsigned int i, num_out_bus_fmts; + struct drm_bridge *last_bridge; + u32 *out_bus_fmts; + int ret = 0; + + last_bridge = list_last_entry(&encoder->bridge_chain, + struct drm_bridge, chain_node); + last_bridge_state = drm_atomic_get_new_bridge_state(crtc_state->state, + last_bridge); + if (WARN_ON(!last_bridge_state)) + return -EINVAL; + + if (last_bridge->funcs->atomic_get_output_bus_fmts) { + const struct drm_bridge_funcs *funcs = last_bridge->funcs; + + out_bus_fmts = funcs->atomic_get_output_bus_fmts(last_bridge, + last_bridge_state, + crtc_state, + conn_state, + &num_out_bus_fmts); + if (!num_out_bus_fmts) + return -ENOTSUPP; + else if (!out_bus_fmts) + return -ENOMEM; + } else { + num_out_bus_fmts = 1; + out_bus_fmts = kmalloc(sizeof(*out_bus_fmts), GFP_KERNEL); + if (!out_bus_fmts) + return -ENOMEM; + + if (conn->display_info.num_bus_formats && + conn->display_info.bus_formats) + out_bus_fmts[0] = conn->display_info.bus_formats[0]; + else + out_bus_fmts[0] = MEDIA_BUS_FMT_FIXED; + } + + for (i = 0; i < num_out_bus_fmts; i++) { + ret = select_bus_fmt_recursive(bridge, last_bridge, crtc_state, + conn_state, out_bus_fmts[i]); + if (ret != -ENOTSUPP) + break; + } + + kfree(out_bus_fmts); + + return ret; +} + +static void +drm_atomic_bridge_propagate_bus_flags(struct drm_bridge *bridge, + struct drm_connector *conn, + struct drm_atomic_state *state) +{ + struct drm_bridge_state *bridge_state, *next_bridge_state; + struct drm_bridge *next_bridge; + u32 output_flags; + + bridge_state = drm_atomic_get_new_bridge_state(state, bridge); + next_bridge = drm_bridge_get_next_bridge(bridge); + + /* + * Let's try to apply the most common case here, that is, propagate + * display_info flags for the last bridge, and propagate the input + * flags of the next bridge element to the output end of the current + * bridge when the bridge is not the last one. + * There are exceptions to this rule, like when signal inversion is + * happening at the board level, but that's something drivers can deal + * with from their &drm_bridge_funcs.atomic_check() implementation by + * simply overriding the flags value we've set here. + */ + if (!next_bridge) { + output_flags = conn->display_info.bus_flags; + } else { + next_bridge_state = drm_atomic_get_new_bridge_state(state, + next_bridge); + output_flags = next_bridge_state->input_bus_cfg.flags; + } + + bridge_state->output_bus_cfg.flags = output_flags; + + /* + * Propage 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. + */ + bridge_state->input_bus_cfg.flags = output_flags; +} + +/** + * drm_atomic_bridge_chain_check() - Do an atomic check on the bridge chain + * @bridge: bridge control structure + * @crtc_state: new CRTC state + * @conn_state: new connector state + * + * First trigger a bus format negotiation before calling + * &drm_bridge_funcs.atomic_check() (falls back on + * &drm_bridge_funcs.mode_fixup()) op for all the bridges in the encoder chain, + * starting from the last bridge to the first. These are called before calling + * &drm_encoder_helper_funcs.atomic_check() + * + * RETURNS: + * 0 on success, a negative error code on failure + */ +int drm_atomic_bridge_chain_check(struct drm_bridge *bridge, + struct drm_crtc_state *crtc_state, + struct drm_connector_state *conn_state) +{ + struct drm_connector *conn = conn_state->connector; + struct drm_encoder *encoder = bridge->encoder; + struct drm_bridge *iter; + int ret; + + ret = drm_atomic_bridge_chain_select_bus_fmts(bridge, crtc_state, + conn_state); + if (ret) + return ret; + + list_for_each_entry_reverse(iter, &encoder->bridge_chain, chain_node) { + int ret; + + /* + * Bus flags are propagated by default. If a bridge needs to + * tweak the input bus flags for any reason, it should happen + * in its &drm_bridge_funcs.atomic_check() implementation such + * that preceding bridges in the chain can propagate the new + * bus flags. + */ + drm_atomic_bridge_propagate_bus_flags(iter, conn, + crtc_state->state); + + ret = drm_atomic_bridge_check(iter, crtc_state, conn_state); + if (ret) + return ret; + + if (iter == bridge) + break; + } + + return 0; +} +EXPORT_SYMBOL(drm_atomic_bridge_chain_check); + +/** + * __drm_atomic_helper_bridge_reset() - Initialize a bridge state to its + * default + * @bridge: the bridge this state is refers to + * @state: bridge state to initialize + * + * Initialize the bridge state to default values. This is meant to be* called + * by the bridge &drm_plane_funcs.reset hook for bridges that subclass the + * bridge state. + */ +void __drm_atomic_helper_bridge_reset(struct drm_bridge *bridge, + struct drm_bridge_state *state) +{ + memset(state, 0, sizeof(*state)); + state->bridge = bridge; +} +EXPORT_SYMBOL(__drm_atomic_helper_bridge_reset); + +/** + * __drm_atomic_helper_bridge_duplicate_state() - Copy atomic bridge state + * @bridge: bridge object + * @state: atomic bridge state + * + * Copies atomic state from a bridge's current state and resets inferred values. + * This is useful for drivers that subclass the bridge state. + */ +void __drm_atomic_helper_bridge_duplicate_state(struct drm_bridge *bridge, + struct drm_bridge_state *state) +{ + __drm_atomic_helper_private_obj_duplicate_state(&bridge->base, + &state->base); + state->bridge = bridge; +} +EXPORT_SYMBOL(__drm_atomic_helper_bridge_duplicate_state); + #ifdef CONFIG_OF /** * of_drm_find_bridge - find the bridge corresponding to the device node in diff --git a/drivers/gpu/drm/drm_gem_vram_helper.c b/drivers/gpu/drm/drm_gem_vram_helper.c index 666cb4c22bb9..a4863326061a 100644 --- a/drivers/gpu/drm/drm_gem_vram_helper.c +++ b/drivers/gpu/drm/drm_gem_vram_helper.c @@ -2,6 +2,7 @@ #include #include +#include #include #include #include @@ -92,14 +93,18 @@ static void drm_gem_vram_placement(struct drm_gem_vram_object *gbo, } static int drm_gem_vram_init(struct drm_device *dev, - struct ttm_bo_device *bdev, struct drm_gem_vram_object *gbo, - size_t size, unsigned long pg_align, - bool interruptible) + size_t size, unsigned long pg_align) { + struct drm_vram_mm *vmm = dev->vram_mm; + struct ttm_bo_device *bdev; int ret; size_t acc_size; + if (WARN_ONCE(!vmm, "VRAM MM not initialized")) + return -EINVAL; + bdev = &vmm->bdev; + gbo->bo.base.funcs = &drm_gem_vram_object_funcs; ret = drm_gem_object_init(dev, &gbo->bo.base, size); @@ -112,7 +117,7 @@ static int drm_gem_vram_init(struct drm_device *dev, drm_gem_vram_placement(gbo, TTM_PL_FLAG_VRAM | TTM_PL_FLAG_SYSTEM); ret = ttm_bo_init(bdev, &gbo->bo, size, ttm_bo_type_device, - &gbo->placement, pg_align, interruptible, acc_size, + &gbo->placement, pg_align, false, acc_size, NULL, NULL, ttm_buffer_object_destroy); if (ret) goto err_drm_gem_object_release; @@ -127,29 +132,33 @@ err_drm_gem_object_release: /** * drm_gem_vram_create() - Creates a VRAM-backed GEM object * @dev: the DRM device - * @bdev: the TTM BO device backing the object * @size: the buffer size in bytes * @pg_align: the buffer's alignment in multiples of the page size - * @interruptible: sleep interruptible if waiting for memory * * Returns: * A new instance of &struct drm_gem_vram_object on success, or * an ERR_PTR()-encoded error code otherwise. */ struct drm_gem_vram_object *drm_gem_vram_create(struct drm_device *dev, - struct ttm_bo_device *bdev, size_t size, - unsigned long pg_align, - bool interruptible) + unsigned long pg_align) { struct drm_gem_vram_object *gbo; int ret; - gbo = kzalloc(sizeof(*gbo), GFP_KERNEL); - if (!gbo) - return ERR_PTR(-ENOMEM); + if (dev->driver->gem_create_object) { + struct drm_gem_object *gem = + dev->driver->gem_create_object(dev, size); + if (!gem) + return ERR_PTR(-ENOMEM); + gbo = drm_gem_vram_of_gem(gem); + } else { + gbo = kzalloc(sizeof(*gbo), GFP_KERNEL); + if (!gbo) + return ERR_PTR(-ENOMEM); + } - ret = drm_gem_vram_init(dev, bdev, gbo, size, pg_align, interruptible); + ret = drm_gem_vram_init(dev, gbo, size, pg_align); if (ret < 0) goto err_kfree; @@ -483,9 +492,8 @@ EXPORT_SYMBOL(drm_gem_vram_vunmap); Helper for implementing &struct drm_driver.dumb_create * @file: the DRM file * @dev: the DRM device - * @bdev: the TTM BO device managing the buffer object * @pg_align: the buffer's alignment in multiples of the page size - * @interruptible: sleep interruptible if waiting for memory + * @pitch_align: the scanline's alignment in powers of 2 * @args: the arguments as provided to \ &struct drm_driver.dumb_create * @@ -500,9 +508,8 @@ EXPORT_SYMBOL(drm_gem_vram_vunmap); */ int drm_gem_vram_fill_create_dumb(struct drm_file *file, struct drm_device *dev, - struct ttm_bo_device *bdev, unsigned long pg_align, - bool interruptible, + unsigned long pitch_align, struct drm_mode_create_dumb *args) { size_t pitch, size; @@ -510,14 +517,19 @@ int drm_gem_vram_fill_create_dumb(struct drm_file *file, int ret; u32 handle; - pitch = args->width * ((args->bpp + 7) / 8); + pitch = args->width * DIV_ROUND_UP(args->bpp, 8); + if (pitch_align) { + if (WARN_ON_ONCE(!is_power_of_2(pitch_align))) + return -EINVAL; + pitch = ALIGN(pitch, pitch_align); + } size = pitch * args->height; size = roundup(size, PAGE_SIZE); if (!size) return -EINVAL; - gbo = drm_gem_vram_create(dev, bdev, size, pg_align, interruptible); + gbo = drm_gem_vram_create(dev, size, pg_align); if (IS_ERR(gbo)) return PTR_ERR(gbo); @@ -612,8 +624,7 @@ int drm_gem_vram_driver_dumb_create(struct drm_file *file, if (WARN_ONCE(!dev->vram_mm, "VRAM MM not initialized")) return -EINVAL; - return drm_gem_vram_fill_create_dumb(file, dev, &dev->vram_mm->bdev, 0, - false, args); + return drm_gem_vram_fill_create_dumb(file, dev, 0, 0, args); } EXPORT_SYMBOL(drm_gem_vram_driver_dumb_create); diff --git a/drivers/gpu/drm/drm_mipi_dbi.c b/drivers/gpu/drm/drm_mipi_dbi.c index e34058c721be..16bff1be4b8a 100644 --- a/drivers/gpu/drm/drm_mipi_dbi.c +++ b/drivers/gpu/drm/drm_mipi_dbi.c @@ -367,9 +367,9 @@ static void mipi_dbi_blank(struct mipi_dbi_dev *dbidev) memset(dbidev->tx_buf, 0, len); mipi_dbi_command(dbi, MIPI_DCS_SET_COLUMN_ADDRESS, 0, 0, - (width >> 8) & 0xFF, (width - 1) & 0xFF); + ((width - 1) >> 8) & 0xFF, (width - 1) & 0xFF); mipi_dbi_command(dbi, MIPI_DCS_SET_PAGE_ADDRESS, 0, 0, - (height >> 8) & 0xFF, (height - 1) & 0xFF); + ((height - 1) >> 8) & 0xFF, (height - 1) & 0xFF); mipi_dbi_command_buf(dbi, MIPI_DCS_WRITE_MEMORY_START, (u8 *)dbidev->tx_buf, len); diff --git a/drivers/gpu/drm/hisilicon/hibmc/Makefile b/drivers/gpu/drm/hisilicon/hibmc/Makefile index 0c2d4296bccd..f99132715597 100644 --- a/drivers/gpu/drm/hisilicon/hibmc/Makefile +++ b/drivers/gpu/drm/hisilicon/hibmc/Makefile @@ -1,4 +1,4 @@ # SPDX-License-Identifier: GPL-2.0-only -hibmc-drm-y := hibmc_drm_drv.o hibmc_drm_de.o hibmc_drm_vdac.o hibmc_drm_fbdev.o hibmc_ttm.o +hibmc-drm-y := hibmc_drm_drv.o hibmc_drm_de.o hibmc_drm_vdac.o hibmc_ttm.o obj-$(CONFIG_DRM_HISI_HIBMC) += hibmc-drm.o diff --git a/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_de.c b/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_de.c index 6527a97f68a3..7fa7d4933f60 100644 --- a/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_de.c +++ b/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_de.c @@ -99,14 +99,12 @@ static void hibmc_plane_atomic_update(struct drm_plane *plane, s64 gpu_addr = 0; unsigned int line_l; struct hibmc_drm_private *priv = plane->dev->dev_private; - struct hibmc_framebuffer *hibmc_fb; struct drm_gem_vram_object *gbo; if (!state->fb) return; - hibmc_fb = to_hibmc_framebuffer(state->fb); - gbo = drm_gem_vram_of_gem(hibmc_fb->obj); + gbo = drm_gem_vram_of_gem(state->fb->obj[0]); gpu_addr = drm_gem_vram_offset(gbo); if (WARN_ON_ONCE(gpu_addr < 0)) diff --git a/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.c b/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.c index 2fd4ca91a62d..11d1b0761c9a 100644 --- a/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.c +++ b/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.c @@ -17,6 +17,7 @@ #include #include +#include #include #include #include @@ -54,6 +55,7 @@ static struct drm_driver hibmc_driver = { .desc = "hibmc drm driver", .major = 1, .minor = 0, + .debugfs_init = drm_vram_mm_debugfs_init, .dumb_create = hibmc_dumb_create, .dumb_map_offset = drm_gem_vram_driver_dumb_mmap_offset, .gem_prime_mmap = drm_gem_prime_mmap, @@ -247,8 +249,6 @@ static int hibmc_unload(struct drm_device *dev) { struct hibmc_drm_private *priv = dev->dev_private; - hibmc_fbdev_fini(priv); - drm_atomic_helper_shutdown(dev); if (dev->irq_enabled) @@ -307,7 +307,7 @@ static int hibmc_load(struct drm_device *dev) /* reset all the states of crtc/plane/encoder/connector */ drm_mode_config_reset(dev); - ret = hibmc_fbdev_init(priv); + ret = drm_fbdev_generic_setup(dev, 16); if (ret) { DRM_ERROR("failed to initialize fbdev: %d\n", ret); goto err; diff --git a/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.h b/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.h index e58ecd7edcf8..50a0c1f9d211 100644 --- a/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.h +++ b/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.h @@ -18,18 +18,6 @@ #include struct drm_device; -struct drm_gem_object; - -struct hibmc_framebuffer { - struct drm_framebuffer fb; - struct drm_gem_object *obj; -}; - -struct hibmc_fbdev { - struct drm_fb_helper helper; /* must be first */ - struct hibmc_framebuffer *fb; - int size; -}; struct hibmc_drm_private { /* hw */ @@ -42,13 +30,8 @@ struct hibmc_drm_private { /* drm */ struct drm_device *dev; bool mode_config_initialized; - - /* fbdev */ - struct hibmc_fbdev *fbdev; }; -#define to_hibmc_framebuffer(x) container_of(x, struct hibmc_framebuffer, fb) - void hibmc_set_power_mode(struct hibmc_drm_private *priv, unsigned int power_mode); void hibmc_set_current_gate(struct hibmc_drm_private *priv, @@ -56,15 +39,6 @@ void hibmc_set_current_gate(struct hibmc_drm_private *priv, int hibmc_de_init(struct hibmc_drm_private *priv); int hibmc_vdac_init(struct hibmc_drm_private *priv); -int hibmc_fbdev_init(struct hibmc_drm_private *priv); -void hibmc_fbdev_fini(struct hibmc_drm_private *priv); - -int hibmc_gem_create(struct drm_device *dev, u32 size, bool iskernel, - struct drm_gem_object **obj); -struct hibmc_framebuffer * -hibmc_framebuffer_init(struct drm_device *dev, - const struct drm_mode_fb_cmd2 *mode_cmd, - struct drm_gem_object *obj); int hibmc_mm_init(struct hibmc_drm_private *hibmc); void hibmc_mm_fini(struct hibmc_drm_private *hibmc); diff --git a/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_fbdev.c b/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_fbdev.c deleted file mode 100644 index 1d15560ccb6e..000000000000 --- a/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_fbdev.c +++ /dev/null @@ -1,240 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-or-later -/* Hisilicon Hibmc SoC drm driver - * - * Based on the bochs drm driver. - * - * Copyright (c) 2016 Huawei Limited. - * - * Author: - * Rongrong Zou - * Rongrong Zou - * Jianhua Li - */ - -#include -#include -#include -#include -#include - -#include "hibmc_drm_drv.h" - -static int hibmcfb_create_object( - struct hibmc_drm_private *priv, - const struct drm_mode_fb_cmd2 *mode_cmd, - struct drm_gem_object **gobj_p) -{ - struct drm_gem_object *gobj; - struct drm_device *dev = priv->dev; - u32 size; - int ret = 0; - - size = mode_cmd->pitches[0] * mode_cmd->height; - ret = hibmc_gem_create(dev, size, true, &gobj); - if (ret) - return ret; - - *gobj_p = gobj; - return ret; -} - -static const struct fb_ops hibmc_drm_fb_ops = { - .owner = THIS_MODULE, - .fb_check_var = drm_fb_helper_check_var, - .fb_set_par = drm_fb_helper_set_par, - .fb_fillrect = drm_fb_helper_sys_fillrect, - .fb_copyarea = drm_fb_helper_sys_copyarea, - .fb_imageblit = drm_fb_helper_sys_imageblit, - .fb_pan_display = drm_fb_helper_pan_display, - .fb_blank = drm_fb_helper_blank, - .fb_setcmap = drm_fb_helper_setcmap, -}; - -static int hibmc_drm_fb_create(struct drm_fb_helper *helper, - struct drm_fb_helper_surface_size *sizes) -{ - struct hibmc_fbdev *hi_fbdev = - container_of(helper, struct hibmc_fbdev, helper); - struct hibmc_drm_private *priv = helper->dev->dev_private; - struct fb_info *info; - struct drm_mode_fb_cmd2 mode_cmd; - struct drm_gem_object *gobj = NULL; - int ret = 0; - size_t size; - unsigned int bytes_per_pixel; - struct drm_gem_vram_object *gbo = NULL; - void *base; - - DRM_DEBUG_DRIVER("surface width(%d), height(%d) and bpp(%d)\n", - sizes->surface_width, sizes->surface_height, - sizes->surface_bpp); - - bytes_per_pixel = DIV_ROUND_UP(sizes->surface_bpp, 8); - - mode_cmd.width = sizes->surface_width; - mode_cmd.height = sizes->surface_height; - mode_cmd.pitches[0] = mode_cmd.width * bytes_per_pixel; - mode_cmd.pixel_format = drm_mode_legacy_fb_format(sizes->surface_bpp, - sizes->surface_depth); - - size = PAGE_ALIGN(mode_cmd.pitches[0] * mode_cmd.height); - - ret = hibmcfb_create_object(priv, &mode_cmd, &gobj); - if (ret) { - DRM_ERROR("failed to create fbcon backing object: %d\n", ret); - return -ENOMEM; - } - - gbo = drm_gem_vram_of_gem(gobj); - - ret = drm_gem_vram_pin(gbo, DRM_GEM_VRAM_PL_FLAG_VRAM); - if (ret) { - DRM_ERROR("failed to pin fbcon: %d\n", ret); - goto out_unref_gem; - } - - base = drm_gem_vram_kmap(gbo, true, NULL); - if (IS_ERR(base)) { - ret = PTR_ERR(base); - DRM_ERROR("failed to kmap fbcon: %d\n", ret); - goto out_unpin_bo; - } - - info = drm_fb_helper_alloc_fbi(helper); - if (IS_ERR(info)) { - ret = PTR_ERR(info); - DRM_ERROR("failed to allocate fbi: %d\n", ret); - goto out_release_fbi; - } - - hi_fbdev->fb = hibmc_framebuffer_init(priv->dev, &mode_cmd, gobj); - if (IS_ERR(hi_fbdev->fb)) { - ret = PTR_ERR(hi_fbdev->fb); - hi_fbdev->fb = NULL; - DRM_ERROR("failed to initialize framebuffer: %d\n", ret); - goto out_release_fbi; - } - - priv->fbdev->size = size; - hi_fbdev->helper.fb = &hi_fbdev->fb->fb; - - info->fbops = &hibmc_drm_fb_ops; - - drm_fb_helper_fill_info(info, &priv->fbdev->helper, sizes); - - info->screen_base = base; - info->screen_size = size; - - info->fix.smem_start = gbo->bo.mem.bus.offset + gbo->bo.mem.bus.base; - info->fix.smem_len = size; - return 0; - -out_release_fbi: - drm_gem_vram_kunmap(gbo); -out_unpin_bo: - drm_gem_vram_unpin(gbo); -out_unref_gem: - drm_gem_object_put_unlocked(gobj); - - return ret; -} - -static void hibmc_fbdev_destroy(struct hibmc_fbdev *fbdev) -{ - struct hibmc_framebuffer *gfb = fbdev->fb; - struct drm_fb_helper *fbh = &fbdev->helper; - - drm_fb_helper_unregister_fbi(fbh); - - drm_fb_helper_fini(fbh); - - if (gfb) - drm_framebuffer_put(&gfb->fb); -} - -static const struct drm_fb_helper_funcs hibmc_fbdev_helper_funcs = { - .fb_probe = hibmc_drm_fb_create, -}; - -int hibmc_fbdev_init(struct hibmc_drm_private *priv) -{ - int ret; - struct fb_var_screeninfo *var; - struct fb_fix_screeninfo *fix; - struct hibmc_fbdev *hifbdev; - - hifbdev = devm_kzalloc(priv->dev->dev, sizeof(*hifbdev), GFP_KERNEL); - if (!hifbdev) { - DRM_ERROR("failed to allocate hibmc_fbdev\n"); - return -ENOMEM; - } - - priv->fbdev = hifbdev; - drm_fb_helper_prepare(priv->dev, &hifbdev->helper, - &hibmc_fbdev_helper_funcs); - - /* Now just one crtc and one channel */ - ret = drm_fb_helper_init(priv->dev, &hifbdev->helper, 1); - if (ret) { - DRM_ERROR("failed to initialize fb helper: %d\n", ret); - return ret; - } - - ret = drm_fb_helper_single_add_all_connectors(&hifbdev->helper); - if (ret) { - DRM_ERROR("failed to add all connectors: %d\n", ret); - goto fini; - } - - ret = drm_fb_helper_initial_config(&hifbdev->helper, 16); - if (ret) { - DRM_ERROR("failed to setup initial conn config: %d\n", ret); - goto fini; - } - - var = &hifbdev->helper.fbdev->var; - fix = &hifbdev->helper.fbdev->fix; - - DRM_DEBUG_DRIVER("Member of info->var is :\n" - "xres=%d\n" - "yres=%d\n" - "xres_virtual=%d\n" - "yres_virtual=%d\n" - "xoffset=%d\n" - "yoffset=%d\n" - "bits_per_pixel=%d\n" - "...\n", var->xres, var->yres, var->xres_virtual, - var->yres_virtual, var->xoffset, var->yoffset, - var->bits_per_pixel); - DRM_DEBUG_DRIVER("Member of info->fix is :\n" - "smem_start=%lx\n" - "smem_len=%d\n" - "type=%d\n" - "type_aux=%d\n" - "visual=%d\n" - "xpanstep=%d\n" - "ypanstep=%d\n" - "ywrapstep=%d\n" - "line_length=%d\n" - "accel=%d\n" - "capabilities=%d\n" - "...\n", fix->smem_start, fix->smem_len, fix->type, - fix->type_aux, fix->visual, fix->xpanstep, - fix->ypanstep, fix->ywrapstep, fix->line_length, - fix->accel, fix->capabilities); - - return 0; - -fini: - drm_fb_helper_fini(&hifbdev->helper); - return ret; -} - -void hibmc_fbdev_fini(struct hibmc_drm_private *priv) -{ - if (!priv->fbdev) - return; - - hibmc_fbdev_destroy(priv->fbdev); - priv->fbdev = NULL; -} diff --git a/drivers/gpu/drm/hisilicon/hibmc/hibmc_ttm.c b/drivers/gpu/drm/hisilicon/hibmc/hibmc_ttm.c index 21b684eab5c9..50b988fdd5cc 100644 --- a/drivers/gpu/drm/hisilicon/hibmc/hibmc_ttm.c +++ b/drivers/gpu/drm/hisilicon/hibmc/hibmc_ttm.c @@ -15,6 +15,7 @@ #include #include +#include #include #include @@ -46,125 +47,14 @@ void hibmc_mm_fini(struct hibmc_drm_private *hibmc) drm_vram_helper_release_mm(hibmc->dev); } -int hibmc_gem_create(struct drm_device *dev, u32 size, bool iskernel, - struct drm_gem_object **obj) -{ - struct drm_gem_vram_object *gbo; - int ret; - - *obj = NULL; - - size = roundup(size, PAGE_SIZE); - if (size == 0) - return -EINVAL; - - gbo = drm_gem_vram_create(dev, &dev->vram_mm->bdev, size, 0, false); - if (IS_ERR(gbo)) { - ret = PTR_ERR(gbo); - if (ret != -ERESTARTSYS) - DRM_ERROR("failed to allocate GEM object: %d\n", ret); - return ret; - } - *obj = &gbo->bo.base; - return 0; -} - int hibmc_dumb_create(struct drm_file *file, struct drm_device *dev, struct drm_mode_create_dumb *args) { - struct drm_gem_object *gobj; - u32 handle; - int ret; - - args->pitch = ALIGN(args->width * DIV_ROUND_UP(args->bpp, 8), 16); - args->size = args->pitch * args->height; - - ret = hibmc_gem_create(dev, args->size, false, - &gobj); - if (ret) { - DRM_ERROR("failed to create GEM object: %d\n", ret); - return ret; - } - - ret = drm_gem_handle_create(file, gobj, &handle); - drm_gem_object_put_unlocked(gobj); - if (ret) { - DRM_ERROR("failed to unreference GEM object: %d\n", ret); - return ret; - } - - args->handle = handle; - return 0; -} - -static void hibmc_user_framebuffer_destroy(struct drm_framebuffer *fb) -{ - struct hibmc_framebuffer *hibmc_fb = to_hibmc_framebuffer(fb); - - drm_gem_object_put_unlocked(hibmc_fb->obj); - drm_framebuffer_cleanup(fb); - kfree(hibmc_fb); -} - -static const struct drm_framebuffer_funcs hibmc_fb_funcs = { - .destroy = hibmc_user_framebuffer_destroy, -}; - -struct hibmc_framebuffer * -hibmc_framebuffer_init(struct drm_device *dev, - const struct drm_mode_fb_cmd2 *mode_cmd, - struct drm_gem_object *obj) -{ - struct hibmc_framebuffer *hibmc_fb; - int ret; - - hibmc_fb = kzalloc(sizeof(*hibmc_fb), GFP_KERNEL); - if (!hibmc_fb) { - DRM_ERROR("failed to allocate hibmc_fb\n"); - return ERR_PTR(-ENOMEM); - } - - drm_helper_mode_fill_fb_struct(dev, &hibmc_fb->fb, mode_cmd); - hibmc_fb->obj = obj; - ret = drm_framebuffer_init(dev, &hibmc_fb->fb, &hibmc_fb_funcs); - if (ret) { - DRM_ERROR("drm_framebuffer_init failed: %d\n", ret); - kfree(hibmc_fb); - return ERR_PTR(ret); - } - - return hibmc_fb; -} - -static struct drm_framebuffer * -hibmc_user_framebuffer_create(struct drm_device *dev, - struct drm_file *filp, - const struct drm_mode_fb_cmd2 *mode_cmd) -{ - struct drm_gem_object *obj; - struct hibmc_framebuffer *hibmc_fb; - - DRM_DEBUG_DRIVER("%dx%d, format %c%c%c%c\n", - mode_cmd->width, mode_cmd->height, - (mode_cmd->pixel_format) & 0xff, - (mode_cmd->pixel_format >> 8) & 0xff, - (mode_cmd->pixel_format >> 16) & 0xff, - (mode_cmd->pixel_format >> 24) & 0xff); - - obj = drm_gem_object_lookup(filp, mode_cmd->handles[0]); - if (!obj) - return ERR_PTR(-ENOENT); - - hibmc_fb = hibmc_framebuffer_init(dev, mode_cmd, obj); - if (IS_ERR(hibmc_fb)) { - drm_gem_object_put_unlocked(obj); - return ERR_PTR((long)hibmc_fb); - } - return &hibmc_fb->fb; + return drm_gem_vram_fill_create_dumb(file, dev, 0, 16, args); } const struct drm_mode_config_funcs hibmc_mode_funcs = { .atomic_check = drm_atomic_helper_check, .atomic_commit = drm_atomic_helper_commit, - .fb_create = hibmc_user_framebuffer_create, + .fb_create = drm_gem_fb_create, }; diff --git a/drivers/gpu/drm/meson/meson_crtc.c b/drivers/gpu/drm/meson/meson_crtc.c index 8366a0ed37af..e66b6271ff58 100644 --- a/drivers/gpu/drm/meson/meson_crtc.c +++ b/drivers/gpu/drm/meson/meson_crtc.c @@ -413,7 +413,7 @@ void meson_crtc_irq(struct meson_drm *priv) MESON_CANVAS_WRAP_NONE, MESON_CANVAS_BLKMODE_LINEAR, MESON_CANVAS_ENDIAN_SWAP64); - }; + } writel_relaxed(priv->viu.vd1_if0_gen_reg, priv->io_base + meson_crtc->viu_offset + diff --git a/drivers/gpu/drm/meson/meson_plane.c b/drivers/gpu/drm/meson/meson_plane.c index 534c62879796..d5cbc47835bf 100644 --- a/drivers/gpu/drm/meson/meson_plane.c +++ b/drivers/gpu/drm/meson/meson_plane.c @@ -237,7 +237,7 @@ static void meson_plane_atomic_update(struct drm_plane *plane, /* For ARGB, use the pixel's alpha */ priv->viu.osd1_ctrl_stat2 &= ~OSD_REPLACE_EN; break; - }; + } /* Default scaler parameters */ vsc_bot_rcv_num = 0; diff --git a/drivers/gpu/drm/mgag200/mgag200_cursor.c b/drivers/gpu/drm/mgag200/mgag200_cursor.c index 5444cf1573a3..d491edd317ff 100644 --- a/drivers/gpu/drm/mgag200/mgag200_cursor.c +++ b/drivers/gpu/drm/mgag200/mgag200_cursor.c @@ -208,8 +208,7 @@ int mgag200_cursor_init(struct mga_device *mdev) return -ENOMEM; for (i = 0; i < ncursors; ++i) { - gbo = drm_gem_vram_create(dev, &dev->vram_mm->bdev, - size, 0, false); + gbo = drm_gem_vram_create(dev, size, 0); if (IS_ERR(gbo)) { ret = PTR_ERR(gbo); goto err_drm_gem_vram_put; diff --git a/drivers/gpu/drm/mgag200/mgag200_drv.c b/drivers/gpu/drm/mgag200/mgag200_drv.c index 9f4f5f071add..7a5bad2f57d7 100644 --- a/drivers/gpu/drm/mgag200/mgag200_drv.c +++ b/drivers/gpu/drm/mgag200/mgag200_drv.c @@ -27,6 +27,10 @@ int mgag200_modeset = -1; MODULE_PARM_DESC(modeset, "Disable/Enable modesetting"); module_param_named(modeset, mgag200_modeset, int, 0400); +int mgag200_hw_bug_no_startadd = -1; +MODULE_PARM_DESC(modeset, "HW does not interpret scanout-buffer start address correctly"); +module_param_named(hw_bug_no_startadd, mgag200_hw_bug_no_startadd, int, 0400); + static struct drm_driver driver; static const struct pci_device_id pciidlist[] = { @@ -97,6 +101,16 @@ DEFINE_DRM_GEM_FOPS(mgag200_driver_fops); static bool mgag200_pin_bo_at_0(const struct mga_device *mdev) { + if (mgag200_hw_bug_no_startadd > 0) { + DRM_WARN_ONCE("Option hw_bug_no_startradd is enabled. Please " + "report the output of 'lspci -vvnn' to " + " if this " + "option is required to make mgag200 work " + "correctly on your system.\n"); + return true; + } else if (!mgag200_hw_bug_no_startadd) { + return false; + } return mdev->flags & MGAG200_FLAG_HW_BUG_NO_STARTADD; } @@ -120,8 +134,7 @@ int mgag200_driver_dumb_create(struct drm_file *file, if (mgag200_pin_bo_at_0(mdev)) pg_align = PFN_UP(mdev->mc.vram_size); - return drm_gem_vram_fill_create_dumb(file, dev, &dev->vram_mm->bdev, - pg_align, false, args); + return drm_gem_vram_fill_create_dumb(file, dev, pg_align, 0, args); } static struct drm_driver driver = { diff --git a/drivers/gpu/drm/panel/Kconfig b/drivers/gpu/drm/panel/Kconfig index 683ff77a3733..41f796b28dd5 100644 --- a/drivers/gpu/drm/panel/Kconfig +++ b/drivers/gpu/drm/panel/Kconfig @@ -109,6 +109,17 @@ config DRM_PANEL_KINGDISPLAY_KD097D04 24 bit RGB per pixel. It provides a MIPI DSI interface to the host and has a built-in LED backlight. +config DRM_PANEL_LEADTEK_LTK500HD1829 + tristate "Leadtek LTK500HD1829 panel" + depends on OF + depends on DRM_MIPI_DSI + depends on BACKLIGHT_CLASS_DEVICE + help + Say Y here if you want to enable support for Kingdisplay kd097d04 + TFT-LCD modules. The panel has a 1536x2048 resolution and uses + 24 bit RGB per pixel. It provides a MIPI DSI interface to + the host and has a built-in LED backlight. + config DRM_PANEL_SAMSUNG_LD9040 tristate "Samsung LD9040 RGB/SPI panel" depends on OF && SPI @@ -366,4 +377,14 @@ config DRM_PANEL_TRULY_NT35597_WQXGA help Say Y here if you want to enable support for Truly NT35597 WQXGA Dual DSI Video Mode panel + +config DRM_PANEL_XINPENG_XPP055C272 + tristate "Xinpeng XPP055C272 panel driver" + depends on OF + depends on DRM_MIPI_DSI + depends on BACKLIGHT_CLASS_DEVICE + help + Say Y here if you want to enable support for the Xinpeng + XPP055C272 controller for 720x1280 LCD panels with MIPI/RGB/SPI + system interfaces. endmenu diff --git a/drivers/gpu/drm/panel/Makefile b/drivers/gpu/drm/panel/Makefile index 8783476110a3..4dc7acff21b9 100644 --- a/drivers/gpu/drm/panel/Makefile +++ b/drivers/gpu/drm/panel/Makefile @@ -9,6 +9,7 @@ obj-$(CONFIG_DRM_PANEL_ILITEK_ILI9881C) += panel-ilitek-ili9881c.o obj-$(CONFIG_DRM_PANEL_INNOLUX_P079ZCA) += panel-innolux-p079zca.o obj-$(CONFIG_DRM_PANEL_JDI_LT070ME05000) += panel-jdi-lt070me05000.o obj-$(CONFIG_DRM_PANEL_KINGDISPLAY_KD097D04) += panel-kingdisplay-kd097d04.o +obj-$(CONFIG_DRM_PANEL_LEADTEK_LTK500HD1829) += panel-leadtek-ltk500hd1829.o obj-$(CONFIG_DRM_PANEL_LG_LB035Q02) += panel-lg-lb035q02.o obj-$(CONFIG_DRM_PANEL_LG_LG4573) += panel-lg-lg4573.o obj-$(CONFIG_DRM_PANEL_NEC_NL8048HL11) += panel-nec-nl8048hl11.o @@ -39,3 +40,4 @@ obj-$(CONFIG_DRM_PANEL_TPO_TD028TTEC1) += panel-tpo-td028ttec1.o obj-$(CONFIG_DRM_PANEL_TPO_TD043MTEA1) += panel-tpo-td043mtea1.o obj-$(CONFIG_DRM_PANEL_TPO_TPG110) += panel-tpo-tpg110.o obj-$(CONFIG_DRM_PANEL_TRULY_NT35597_WQXGA) += panel-truly-nt35597.o +obj-$(CONFIG_DRM_PANEL_XINPENG_XPP055C272) += panel-xinpeng-xpp055c272.o diff --git a/drivers/gpu/drm/panel/panel-leadtek-ltk500hd1829.c b/drivers/gpu/drm/panel/panel-leadtek-ltk500hd1829.c new file mode 100644 index 000000000000..76ecf2de9c44 --- /dev/null +++ b/drivers/gpu/drm/panel/panel-leadtek-ltk500hd1829.c @@ -0,0 +1,531 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Copyright (c) 2019 Theobroma Systems Design und Consulting GmbH + * + * base on panel-kingdisplay-kd097d04.c + * Copyright (c) 2017, Fuzhou Rockchip Electronics Co., Ltd + */ + +#include +#include +#include +#include +#include +#include + +#include