diff --git a/Documentation/devicetree/bindings/display/bridge/chrontel,ch7033.yaml b/Documentation/devicetree/bindings/display/bridge/chrontel,ch7033.yaml new file mode 100644 index 000000000000..9f38f55fc990 --- /dev/null +++ b/Documentation/devicetree/bindings/display/bridge/chrontel,ch7033.yaml @@ -0,0 +1,77 @@ +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +# Copyright (C) 2019,2020 Lubomir Rintel +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/display/bridge/chrontel,ch7033.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Chrontel CH7033 Video Encoder Device Tree Bindings + +maintainers: + - Lubomir Rintel + +properties: + compatible: + const: chrontel,ch7033 + + reg: + maxItems: 1 + description: I2C address of the device + + ports: + type: object + + properties: + port@0: + type: object + description: | + Video port for RGB input. + + port@1: + type: object + description: | + DVI port, should be connected to a node compatible with the + dvi-connector binding. + + required: + - port@0 + - port@1 + +required: + - compatible + - reg + - ports + +additionalProperties: false + +examples: + - | + i2c { + #address-cells = <1>; + #size-cells = <0>; + + vga-dvi-encoder@76 { + compatible = "chrontel,ch7033"; + reg = <0x76>; + + ports { + #address-cells = <1>; + #size-cells = <0>; + + port@0 { + reg = <0>; + endpoint { + remote-endpoint = <&lcd0_rgb_out>; + }; + }; + + port@1 { + reg = <1>; + endpoint { + remote-endpoint = <&dvi_in>; + }; + }; + + }; + }; + }; diff --git a/Documentation/devicetree/bindings/display/bridge/dw_mipi_dsi.txt b/Documentation/devicetree/bindings/display/bridge/dw_mipi_dsi.txt deleted file mode 100644 index b13adf30b8d3..000000000000 --- a/Documentation/devicetree/bindings/display/bridge/dw_mipi_dsi.txt +++ /dev/null @@ -1,32 +0,0 @@ -Synopsys DesignWare MIPI DSI host controller -============================================ - -This document defines device tree properties for the Synopsys DesignWare MIPI -DSI host controller. It doesn't constitue a device tree binding specification -by itself but is meant to be referenced by platform-specific device tree -bindings. - -When referenced from platform device tree bindings the properties defined in -this document are defined as follows. The platform device tree bindings are -responsible for defining whether each optional property is used or not. - -- reg: Memory mapped base address and length of the DesignWare MIPI DSI - host controller registers. (mandatory) - -- clocks: References to all the clocks specified in the clock-names property - as specified in [1]. (mandatory) - -- clock-names: - - "pclk" is the peripheral clock for either AHB and APB. (mandatory) - - "px_clk" is the pixel clock for the DPI/RGB input. (optional) - -- resets: References to all the resets specified in the reset-names property - as specified in [2]. (optional) - -- reset-names: string reset name, must be "apb" if used. (optional) - -- panel or bridge node: see [3]. (mandatory) - -[1] Documentation/devicetree/bindings/clock/clock-bindings.txt -[2] Documentation/devicetree/bindings/reset/reset.txt -[3] Documentation/devicetree/bindings/display/mipi-dsi-bus.txt diff --git a/Documentation/devicetree/bindings/display/bridge/ite,it6505.yaml b/Documentation/devicetree/bindings/display/bridge/ite,it6505.yaml new file mode 100644 index 000000000000..2c500166c65d --- /dev/null +++ b/Documentation/devicetree/bindings/display/bridge/ite,it6505.yaml @@ -0,0 +1,91 @@ +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/display/bridge/ite,it6505.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: ITE it6505 Device Tree Bindings + +maintainers: + - Allen Chen + +description: | + The IT6505 is a high-performance DisplayPort 1.1a transmitter, + fully compliant with DisplayPort 1.1a, HDCP 1.3 specifications. + The IT6505 supports color depth of up to 36 bits (12 bits/color) + and ensures robust transmission of high-quality uncompressed video + content, along with uncompressed and compressed digital audio content. + + Aside from the various video output formats supported, the IT6505 + also encodes and transmits up to 8 channels of I2S digital audio, + with sampling rate up to 192kHz and sample size up to 24 bits. + In addition, an S/PDIF input port takes in compressed audio of up to + 192kHz frame rate. + + Each IT6505 chip comes preprogrammed with an unique HDCP key, + in compliance with the HDCP 1.3 standard so as to provide secure + transmission of high-definition content. Users of the IT6505 need not + purchase any HDCP keys or ROMs. + +properties: + compatible: + const: ite,it6505 + + ovdd-supply: + maxItems: 1 + description: I/O voltage + + pwr18-supply: + maxItems: 1 + description: core voltage + + interrupts: + maxItems: 1 + description: interrupt specifier of INT pin + + reset-gpios: + maxItems: 1 + description: gpio specifier of RESET pin + + extcon: + maxItems: 1 + description: extcon specifier for the Power Delivery + + port: + type: object + description: A port node pointing to DPI host port node + +required: + - compatible + - ovdd-supply + - pwr18-supply + - interrupts + - reset-gpios + - extcon + +examples: + - | + #include + + i2c { + #address-cells = <1>; + #size-cells = <0>; + + dp-bridge@5c { + compatible = "ite,it6505"; + interrupts = <152 IRQ_TYPE_EDGE_FALLING 152 0>; + reg = <0x5c>; + pinctrl-names = "default"; + pinctrl-0 = <&it6505_pins>; + ovdd-supply = <&mt6358_vsim1_reg>; + pwr18-supply = <&it6505_pp18_reg>; + reset-gpios = <&pio 179 1>; + extcon = <&usbc_extcon>; + + port { + it6505_in: endpoint { + remote-endpoint = <&dpi_out>; + }; + }; + }; + }; diff --git a/Documentation/devicetree/bindings/display/bridge/snps,dw-mipi-dsi.yaml b/Documentation/devicetree/bindings/display/bridge/snps,dw-mipi-dsi.yaml new file mode 100644 index 000000000000..012aa8e7cb8c --- /dev/null +++ b/Documentation/devicetree/bindings/display/bridge/snps,dw-mipi-dsi.yaml @@ -0,0 +1,68 @@ +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/display/bridge/snps,dw-mipi-dsi.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Synopsys DesignWare MIPI DSI host controller + +maintainers: + - Philippe CORNU + +description: | + This document defines device tree properties for the Synopsys DesignWare MIPI + DSI host controller. It doesn't constitue a device tree binding specification + by itself but is meant to be referenced by platform-specific device tree + bindings. + + When referenced from platform device tree bindings the properties defined in + this document are defined as follows. The platform device tree bindings are + responsible for defining whether each property is required or optional. + +allOf: + - $ref: ../dsi-controller.yaml# + +properties: + reg: + maxItems: 1 + + clocks: + items: + - description: Module clock + - description: DSI bus clock for either AHB and APB + - description: Pixel clock for the DPI/RGB input + minItems: 2 + + clock-names: + items: + - const: ref + - const: pclk + - const: px_clk + minItems: 2 + + resets: + maxItems: 1 + + reset-names: + const: apb + + ports: + type: object + + properties: + port@0: + type: object + description: Input node to receive pixel data. + port@1: + type: object + description: DSI output node to panel. + + required: + - port@0 + - port@1 + +required: + - clock-names + - clocks + - ports + - reg diff --git a/Documentation/devicetree/bindings/display/panel/panel-simple-dsi.yaml b/Documentation/devicetree/bindings/display/panel/panel-simple-dsi.yaml index 423532f57e89..16778ce782fc 100644 --- a/Documentation/devicetree/bindings/display/panel/panel-simple-dsi.yaml +++ b/Documentation/devicetree/bindings/display/panel/panel-simple-dsi.yaml @@ -42,6 +42,8 @@ properties: # One Stop Displays OSD101T2587-53TS 10.1" 1920x1200 panel - osddisplays,osd101t2587-53ts # Panasonic 10" WUXGA TFT LCD panel + - panasonic,vvx10f004b00 + # Panasonic 10" WUXGA TFT LCD panel - panasonic,vvx10f034n00 reg: diff --git a/Documentation/devicetree/bindings/display/panel/panel-simple.yaml b/Documentation/devicetree/bindings/display/panel/panel-simple.yaml index 989cb3ca6d58..fdd74d07f645 100644 --- a/Documentation/devicetree/bindings/display/panel/panel-simple.yaml +++ b/Documentation/devicetree/bindings/display/panel/panel-simple.yaml @@ -53,10 +53,16 @@ properties: - auo,g101evn010 # AU Optronics Corporation 10.4" (800x600) color TFT LCD panel - auo,g104sn02 + # AU Optronics Corporation 12.1" (1280x800) TFT LCD panel + - auo,g121ean01 # AU Optronics Corporation 13.3" FHD (1920x1080) TFT LCD panel - auo,g133han01 + # AU Optronics Corporation 15.6" (1366x768) TFT LCD panel + - auo,g156xtn01 # AU Optronics Corporation 18.5" FHD (1920x1080) TFT LCD panel - auo,g185han01 + # AU Optronics Corporation 19.0" (1280x1024) TFT LCD panel + - auo,g190ean01 # AU Optronics Corporation 31.5" FHD (1920x1080) TFT LCD panel - auo,p320hvn03 # AU Optronics Corporation 21.5" FHD (1920x1080) color TFT LCD panel @@ -67,6 +73,8 @@ properties: - boe,hv070wsa-100 # BOE OPTOELECTRONICS TECHNOLOGY 10.1" WXGA TFT LCD panel - boe,nv101wxmn51 + # BOE NV133FHM-N61 13.3" FHD (1920x1080) TFT LCD Panel + - boe,nv133fhm-n61 # BOE NV140FHM-N49 14.0" FHD a-Si FT panel - boe,nv140fhmn49 # CDTech(H.K.) Electronics Limited 4.3" 480x272 color TFT-LCD panel @@ -78,6 +86,8 @@ properties: # Chunghwa Picture Tubes Ltd. 10.1" WXGA TFT LCD panel - chunghwa,claa101wa01a # Chunghwa Picture Tubes Ltd. 10.1" WXGA TFT LCD panel + - chunghwa,claa101wb01 + # Chunghwa Picture Tubes Ltd. 10.1" WXGA TFT LCD panel - chunghwa,claa101wb03 # DataImage, Inc. 7" WVGA (800x480) TFT LCD panel with 24-bit parallel interface. - dataimage,scf0700c48ggu18 @@ -123,6 +133,8 @@ properties: - hannstar,hsd100pxn1 # Hitachi Ltd. Corporation 9" WVGA (800x480) TFT LCD panel - hit,tx23d38vm0caa + # InfoVision Optoelectronics M133NWF4 R0 13.3" FHD (1920x1080) TFT LCD panel + - ivo,m133nwf4-r0 # Innolux AT043TN24 4.3" WQVGA TFT LCD panel - innolux,at043tn24 # Innolux AT070TN92 7.0" WQVGA TFT LCD panel diff --git a/Documentation/devicetree/bindings/vendor-prefixes.yaml b/Documentation/devicetree/bindings/vendor-prefixes.yaml index d3891386d671..7a39732c582d 100644 --- a/Documentation/devicetree/bindings/vendor-prefixes.yaml +++ b/Documentation/devicetree/bindings/vendor-prefixes.yaml @@ -187,6 +187,8 @@ patternProperties: description: ChipOne "^chipspark,.*": description: ChipSPARK + "^chrontel,.*": + description: Chrontel, Inc. "^chrp,.*": description: Common Hardware Reference Platform "^chunghwa,.*": @@ -463,6 +465,8 @@ patternProperties: description: Infineon Technologies "^inforce,.*": description: Inforce Computing + "^ivo,.*": + description: InfoVision Optoelectronics Kunshan Co. Ltd. "^ingenic,.*": description: Ingenic Semiconductor "^innolux,.*": @@ -488,7 +492,7 @@ patternProperties: "^issi,.*": description: Integrated Silicon Solutions Inc. "^ite,.*": - description: ITE Tech, Inc. + description: ITE Tech. Inc. "^itead,.*": description: ITEAD Intelligent Systems Co.Ltd "^iwave,.*": @@ -1039,6 +1043,8 @@ patternProperties: description: Tronsmart "^truly,.*": description: Truly Semiconductors Limited + "^visionox,.*": + description: Visionox "^tsd,.*": description: Theobroma Systems Design und Consulting GmbH "^tyan,.*": diff --git a/Documentation/gpu/todo.rst b/Documentation/gpu/todo.rst index 439656f55c5d..658b52f7ffc6 100644 --- a/Documentation/gpu/todo.rst +++ b/Documentation/gpu/todo.rst @@ -347,18 +347,6 @@ Contact: Sean Paul Level: Starter -Remove drm_display_mode.hsync ------------------------------ - -We have drm_mode_hsync() to calculate this from hsync_start/end, since drivers -shouldn't/don't use this, remove this member to avoid any temptations to use it -in the future. If there is any debug code using drm_display_mode.hsync, convert -it to use drm_mode_hsync() instead. - -Contact: Sean Paul - -Level: Starter - connector register/unregister fixes ----------------------------------- diff --git a/MAINTAINERS b/MAINTAINERS index 24d0226abc8e..225bc22c4106 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -5400,7 +5400,7 @@ L: virtualization@lists.linux-foundation.org S: Obsolete W: https://www.kraxel.org/blog/2014/10/qemu-using-cirrus-considered-harmful/ T: git git://anongit.freedesktop.org/drm/drm-misc -F: drivers/gpu/drm/cirrus/ +F: drivers/gpu/drm/tiny/cirrus.c DRM DRIVER FOR QXL VIRTUAL GPU M: Dave Airlie diff --git a/drivers/gpu/drm/Kconfig b/drivers/gpu/drm/Kconfig index 43594978958e..4f4e7fa001c1 100644 --- a/drivers/gpu/drm/Kconfig +++ b/drivers/gpu/drm/Kconfig @@ -310,8 +310,6 @@ source "drivers/gpu/drm/ast/Kconfig" source "drivers/gpu/drm/mgag200/Kconfig" -source "drivers/gpu/drm/cirrus/Kconfig" - source "drivers/gpu/drm/armada/Kconfig" source "drivers/gpu/drm/atmel-hlcdc/Kconfig" diff --git a/drivers/gpu/drm/Makefile b/drivers/gpu/drm/Makefile index f34d08c83485..2c0e5a7e5953 100644 --- a/drivers/gpu/drm/Makefile +++ b/drivers/gpu/drm/Makefile @@ -74,7 +74,6 @@ obj-$(CONFIG_DRM_I915) += i915/ obj-$(CONFIG_DRM_MGAG200) += mgag200/ obj-$(CONFIG_DRM_V3D) += v3d/ obj-$(CONFIG_DRM_VC4) += vc4/ -obj-$(CONFIG_DRM_CIRRUS_QEMU) += cirrus/ obj-$(CONFIG_DRM_SIS) += sis/ obj-$(CONFIG_DRM_SAVAGE)+= savage/ obj-$(CONFIG_DRM_VMWGFX)+= vmwgfx/ diff --git a/drivers/gpu/drm/amd/display/dc/dsc/dc_dsc.c b/drivers/gpu/drm/amd/display/dc/dsc/dc_dsc.c index 87d682d25278..0ea6662a1563 100644 --- a/drivers/gpu/drm/amd/display/dc/dsc/dc_dsc.c +++ b/drivers/gpu/drm/amd/display/dc/dsc/dc_dsc.c @@ -129,7 +129,7 @@ static bool dsc_line_buff_depth_from_dpcd(int dpcd_line_buff_bit_depth, int *lin static bool dsc_throughput_from_dpcd(int dpcd_throughput, int *throughput) { switch (dpcd_throughput) { - case DP_DSC_THROUGHPUT_MODE_0_UPSUPPORTED: + case DP_DSC_THROUGHPUT_MODE_0_UNSUPPORTED: *throughput = 0; break; case DP_DSC_THROUGHPUT_MODE_0_170: diff --git a/drivers/gpu/drm/arm/display/komeda/komeda_kms.c b/drivers/gpu/drm/arm/display/komeda/komeda_kms.c index 16dfd5cdb66c..6b85d5f4caa8 100644 --- a/drivers/gpu/drm/arm/display/komeda/komeda_kms.c +++ b/drivers/gpu/drm/arm/display/komeda/komeda_kms.c @@ -261,18 +261,16 @@ static void komeda_kms_mode_config_init(struct komeda_kms_dev *kms, struct komeda_kms_dev *komeda_kms_attach(struct komeda_dev *mdev) { - struct komeda_kms_dev *kms = kzalloc(sizeof(*kms), GFP_KERNEL); + struct komeda_kms_dev *kms; struct drm_device *drm; int err; - if (!kms) - return ERR_PTR(-ENOMEM); + kms = devm_drm_dev_alloc(mdev->dev, &komeda_kms_driver, + struct komeda_kms_dev, base); + if (IS_ERR(kms)) + return kms; drm = &kms->base; - err = drm_dev_init(drm, &komeda_kms_driver, mdev->dev); - if (err) - goto free_kms; - drmm_add_final_kfree(drm, kms); drm->dev_private = mdev; @@ -329,9 +327,6 @@ cleanup_mode_config: drm_mode_config_cleanup(drm); komeda_kms_cleanup_private_objs(kms); drm->dev_private = NULL; - drm_dev_put(drm); -free_kms: - kfree(kms); return ERR_PTR(err); } @@ -348,5 +343,4 @@ void komeda_kms_detach(struct komeda_kms_dev *kms) drm_mode_config_cleanup(drm); komeda_kms_cleanup_private_objs(kms); drm->dev_private = NULL; - drm_dev_put(drm); } diff --git a/drivers/gpu/drm/aspeed/aspeed_gfx.h b/drivers/gpu/drm/aspeed/aspeed_gfx.h index a10358bb61ec..e7ca95827ae8 100644 --- a/drivers/gpu/drm/aspeed/aspeed_gfx.h +++ b/drivers/gpu/drm/aspeed/aspeed_gfx.h @@ -5,6 +5,7 @@ #include struct aspeed_gfx { + struct drm_device drm; void __iomem *base; struct clk *clk; struct reset_control *rst; @@ -12,8 +13,8 @@ struct aspeed_gfx { struct drm_simple_display_pipe pipe; struct drm_connector connector; - struct drm_fbdev_cma *fbdev; }; +#define to_aspeed_gfx(x) container_of(x, struct aspeed_gfx, drm) int aspeed_gfx_create_pipe(struct drm_device *drm); int aspeed_gfx_create_output(struct drm_device *drm); diff --git a/drivers/gpu/drm/aspeed/aspeed_gfx_crtc.c b/drivers/gpu/drm/aspeed/aspeed_gfx_crtc.c index 2184b8be6fd4..e54686c31a90 100644 --- a/drivers/gpu/drm/aspeed/aspeed_gfx_crtc.c +++ b/drivers/gpu/drm/aspeed/aspeed_gfx_crtc.c @@ -231,7 +231,7 @@ static const uint32_t aspeed_gfx_formats[] = { int aspeed_gfx_create_pipe(struct drm_device *drm) { - struct aspeed_gfx *priv = drm->dev_private; + struct aspeed_gfx *priv = to_aspeed_gfx(drm); return drm_simple_display_pipe_init(drm, &priv->pipe, &aspeed_gfx_funcs, aspeed_gfx_formats, diff --git a/drivers/gpu/drm/aspeed/aspeed_gfx_drv.c b/drivers/gpu/drm/aspeed/aspeed_gfx_drv.c index ada2f6aca906..6b27242b9ee3 100644 --- a/drivers/gpu/drm/aspeed/aspeed_gfx_drv.c +++ b/drivers/gpu/drm/aspeed/aspeed_gfx_drv.c @@ -77,7 +77,7 @@ static void aspeed_gfx_setup_mode_config(struct drm_device *drm) static irqreturn_t aspeed_gfx_irq_handler(int irq, void *data) { struct drm_device *drm = data; - struct aspeed_gfx *priv = drm->dev_private; + struct aspeed_gfx *priv = to_aspeed_gfx(drm); u32 reg; reg = readl(priv->base + CRT_CTRL1); @@ -96,15 +96,10 @@ static irqreturn_t aspeed_gfx_irq_handler(int irq, void *data) static int aspeed_gfx_load(struct drm_device *drm) { struct platform_device *pdev = to_platform_device(drm->dev); - struct aspeed_gfx *priv; + struct aspeed_gfx *priv = to_aspeed_gfx(drm); struct resource *res; int ret; - priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL); - if (!priv) - return -ENOMEM; - drm->dev_private = priv; - res = platform_get_resource(pdev, IORESOURCE_MEM, 0); priv->base = devm_ioremap_resource(drm->dev, res); if (IS_ERR(priv->base)) @@ -187,8 +182,6 @@ static void aspeed_gfx_unload(struct drm_device *drm) { drm_kms_helper_poll_fini(drm); drm_mode_config_cleanup(drm); - - drm->dev_private = NULL; } DEFINE_DRM_GEM_CMA_FOPS(fops); @@ -216,27 +209,26 @@ static const struct of_device_id aspeed_gfx_match[] = { static int aspeed_gfx_probe(struct platform_device *pdev) { - struct drm_device *drm; + struct aspeed_gfx *priv; int ret; - drm = drm_dev_alloc(&aspeed_gfx_driver, &pdev->dev); - if (IS_ERR(drm)) - return PTR_ERR(drm); + priv = devm_drm_dev_alloc(&pdev->dev, &aspeed_gfx_driver, + struct aspeed_gfx, drm); + if (IS_ERR(priv)) + return PTR_ERR(priv); - ret = aspeed_gfx_load(drm); + ret = aspeed_gfx_load(&priv->drm); if (ret) - goto err_free; + return ret; - ret = drm_dev_register(drm, 0); + ret = drm_dev_register(&priv->drm, 0); if (ret) goto err_unload; return 0; err_unload: - aspeed_gfx_unload(drm); -err_free: - drm_dev_put(drm); + aspeed_gfx_unload(&priv->drm); return ret; } @@ -247,7 +239,6 @@ static int aspeed_gfx_remove(struct platform_device *pdev) drm_dev_unregister(drm); aspeed_gfx_unload(drm); - drm_dev_put(drm); return 0; } diff --git a/drivers/gpu/drm/aspeed/aspeed_gfx_out.c b/drivers/gpu/drm/aspeed/aspeed_gfx_out.c index 67ee5fa10055..6759cb88415a 100644 --- a/drivers/gpu/drm/aspeed/aspeed_gfx_out.c +++ b/drivers/gpu/drm/aspeed/aspeed_gfx_out.c @@ -28,7 +28,7 @@ static const struct drm_connector_funcs aspeed_gfx_connector_funcs = { int aspeed_gfx_create_output(struct drm_device *drm) { - struct aspeed_gfx *priv = drm->dev_private; + struct aspeed_gfx *priv = to_aspeed_gfx(drm); int ret; priv->connector.dpms = DRM_MODE_DPMS_OFF; diff --git a/drivers/gpu/drm/ast/ast_mode.c b/drivers/gpu/drm/ast/ast_mode.c index 7a9f20a2fd30..7062bcd78740 100644 --- a/drivers/gpu/drm/ast/ast_mode.c +++ b/drivers/gpu/drm/ast/ast_mode.c @@ -931,7 +931,6 @@ static void ast_crtc_atomic_destroy_state(struct drm_crtc *crtc, static const struct drm_crtc_funcs ast_crtc_funcs = { .reset = ast_crtc_reset, - .set_config = drm_crtc_helper_set_config, .gamma_set = drm_atomic_helper_legacy_gamma_set, .destroy = ast_crtc_destroy, .set_config = drm_atomic_helper_set_config, @@ -1080,7 +1079,6 @@ 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_unregister(connector); drm_connector_cleanup(connector); kfree(connector); } @@ -1123,8 +1121,6 @@ static int ast_connector_init(struct drm_device *dev) connector->interlace_allowed = 0; connector->doublescan_allowed = 0; - drm_connector_register(connector); - connector->polled = DRM_CONNECTOR_POLL_CONNECT; encoder = list_first_entry(&dev->mode_config.encoder_list, struct drm_encoder, head); diff --git a/drivers/gpu/drm/bochs/bochs_kms.c b/drivers/gpu/drm/bochs/bochs_kms.c index 7f4bcfad87e9..05d8373888e8 100644 --- a/drivers/gpu/drm/bochs/bochs_kms.c +++ b/drivers/gpu/drm/bochs/bochs_kms.c @@ -104,7 +104,6 @@ static void bochs_connector_init(struct drm_device *dev) DRM_MODE_CONNECTOR_VIRTUAL); drm_connector_helper_add(connector, &bochs_connector_connector_helper_funcs); - drm_connector_register(connector); bochs_hw_load_edid(bochs); if (bochs->edid) { diff --git a/drivers/gpu/drm/bridge/Kconfig b/drivers/gpu/drm/bridge/Kconfig index 6ec945f837b8..04f876e985de 100644 --- a/drivers/gpu/drm/bridge/Kconfig +++ b/drivers/gpu/drm/bridge/Kconfig @@ -27,6 +27,16 @@ config DRM_CDNS_DSI Support Cadence DPI to DSI bridge. This is an internal bridge and is meant to be directly embedded in a SoC. +config DRM_CHRONTEL_CH7033 + tristate "Chrontel CH7033 Video Encoder" + depends on OF + select DRM_KMS_HELPER + help + Enable support for the Chrontel CH7033 VGA/DVI/HDMI Encoder, as + found in the Dell Wyse 3020 thin client. + + If in doubt, say "N". + config DRM_DISPLAY_CONNECTOR tristate "Display connector support" depends on OF diff --git a/drivers/gpu/drm/bridge/Makefile b/drivers/gpu/drm/bridge/Makefile index b04ac2dfa22c..d63d4b7e4347 100644 --- a/drivers/gpu/drm/bridge/Makefile +++ b/drivers/gpu/drm/bridge/Makefile @@ -1,5 +1,6 @@ # SPDX-License-Identifier: GPL-2.0 obj-$(CONFIG_DRM_CDNS_DSI) += cdns-dsi.o +obj-$(CONFIG_DRM_CHRONTEL_CH7033) += chrontel-ch7033.o obj-$(CONFIG_DRM_DISPLAY_CONNECTOR) += display-connector.o obj-$(CONFIG_DRM_LVDS_CODEC) += lvds-codec.o obj-$(CONFIG_DRM_MEGACHIPS_STDPXXXX_GE_B850V3_FW) += megachips-stdpxxxx-ge-b850v3-fw.o diff --git a/drivers/gpu/drm/bridge/chrontel-ch7033.c b/drivers/gpu/drm/bridge/chrontel-ch7033.c new file mode 100644 index 000000000000..f8675d82974b --- /dev/null +++ b/drivers/gpu/drm/bridge/chrontel-ch7033.c @@ -0,0 +1,620 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Chrontel CH7033 Video Encoder Driver + * + * Copyright (C) 2019,2020 Lubomir Rintel + */ + +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +/* Page 0, Register 0x07 */ +enum { + DRI_PD = BIT(3), + IO_PD = BIT(5), +}; + +/* Page 0, Register 0x08 */ +enum { + DRI_PDDRI = GENMASK(7, 4), + PDDAC = GENMASK(3, 1), + PANEN = BIT(0), +}; + +/* Page 0, Register 0x09 */ +enum { + DPD = BIT(7), + GCKOFF = BIT(6), + TV_BP = BIT(5), + SCLPD = BIT(4), + SDPD = BIT(3), + VGA_PD = BIT(2), + HDBKPD = BIT(1), + HDMI_PD = BIT(0), +}; + +/* Page 0, Register 0x0a */ +enum { + MEMINIT = BIT(7), + MEMIDLE = BIT(6), + MEMPD = BIT(5), + STOP = BIT(4), + LVDS_PD = BIT(3), + HD_DVIB = BIT(2), + HDCP_PD = BIT(1), + MCU_PD = BIT(0), +}; + +/* Page 0, Register 0x18 */ +enum { + IDF = GENMASK(7, 4), + INTEN = BIT(3), + SWAP = GENMASK(2, 0), +}; + +enum { + BYTE_SWAP_RGB = 0, + BYTE_SWAP_RBG = 1, + BYTE_SWAP_GRB = 2, + BYTE_SWAP_GBR = 3, + BYTE_SWAP_BRG = 4, + BYTE_SWAP_BGR = 5, +}; + +/* Page 0, Register 0x19 */ +enum { + HPO_I = BIT(5), + VPO_I = BIT(4), + DEPO_I = BIT(3), + CRYS_EN = BIT(2), + GCLKFREQ = GENMASK(2, 0), +}; + +/* Page 0, Register 0x2e */ +enum { + HFLIP = BIT(7), + VFLIP = BIT(6), + DEPO_O = BIT(5), + HPO_O = BIT(4), + VPO_O = BIT(3), + TE = GENMASK(2, 0), +}; + +/* Page 0, Register 0x2b */ +enum { + SWAPS = GENMASK(7, 4), + VFMT = GENMASK(3, 0), +}; + +/* Page 0, Register 0x54 */ +enum { + COMP_BP = BIT(7), + DAC_EN_T = BIT(6), + HWO_HDMI_HI = GENMASK(5, 3), + HOO_HDMI_HI = GENMASK(2, 0), +}; + +/* Page 0, Register 0x57 */ +enum { + FLDSEN = BIT(7), + VWO_HDMI_HI = GENMASK(5, 3), + VOO_HDMI_HI = GENMASK(2, 0), +}; + +/* Page 0, Register 0x7e */ +enum { + HDMI_LVDS_SEL = BIT(7), + DE_GEN = BIT(6), + PWM_INDEX_HI = BIT(5), + USE_DE = BIT(4), + R_INT = GENMASK(3, 0), +}; + +/* Page 1, Register 0x07 */ +enum { + BPCKSEL = BIT(7), + DRI_CMFB_EN = BIT(6), + CEC_PUEN = BIT(5), + CEC_T = BIT(3), + CKINV = BIT(2), + CK_TVINV = BIT(1), + DRI_CKS2 = BIT(0), +}; + +/* Page 1, Register 0x08 */ +enum { + DACG = BIT(6), + DACKTST = BIT(5), + DEDGEB = BIT(4), + SYO = BIT(3), + DRI_IT_LVDS = GENMASK(2, 1), + DISPON = BIT(0), +}; + +/* Page 1, Register 0x0c */ +enum { + DRI_PLL_CP = GENMASK(7, 6), + DRI_PLL_DIVSEL = BIT(5), + DRI_PLL_N1_1 = BIT(4), + DRI_PLL_N1_0 = BIT(3), + DRI_PLL_N3_1 = BIT(2), + DRI_PLL_N3_0 = BIT(1), + DRI_PLL_CKTSTEN = BIT(0), +}; + +/* Page 1, Register 0x6b */ +enum { + VCO3CS = GENMASK(7, 6), + ICPGBK2_0 = GENMASK(5, 3), + DRI_VCO357SC = BIT(2), + PDPLL2 = BIT(1), + DRI_PD_SER = BIT(0), +}; + +/* Page 1, Register 0x6c */ +enum { + PLL2N11 = GENMASK(7, 4), + PLL2N5_4 = BIT(3), + PLL2N5_TOP = BIT(2), + DRI_PLL_PD = BIT(1), + PD_I2CM = BIT(0), +}; + +/* Page 3, Register 0x28 */ +enum { + DIFF_EN = GENMASK(7, 6), + CORREC_EN = GENMASK(5, 4), + VGACLK_BP = BIT(3), + HM_LV_SEL = BIT(2), + HD_VGA_SEL = BIT(1), +}; + +/* Page 3, Register 0x2a */ +enum { + LVDSCLK_BP = BIT(7), + HDTVCLK_BP = BIT(6), + HDMICLK_BP = BIT(5), + HDTV_BP = BIT(4), + HDMI_BP = BIT(3), + THRWL = GENMASK(2, 0), +}; + +/* Page 4, Register 0x52 */ +enum { + PGM_ARSTB = BIT(7), + MCU_ARSTB = BIT(6), + MCU_RETB = BIT(2), + RESETIB = BIT(1), + RESETDB = BIT(0), +}; + +struct ch7033_priv { + struct regmap *regmap; + struct drm_bridge *next_bridge; + struct drm_bridge bridge; + struct drm_connector connector; +}; + +#define conn_to_ch7033_priv(x) \ + container_of(x, struct ch7033_priv, connector) +#define bridge_to_ch7033_priv(x) \ + container_of(x, struct ch7033_priv, bridge) + + +static enum drm_connector_status ch7033_connector_detect( + struct drm_connector *connector, bool force) +{ + struct ch7033_priv *priv = conn_to_ch7033_priv(connector); + + return drm_bridge_detect(priv->next_bridge); +} + +static const struct drm_connector_funcs ch7033_connector_funcs = { + .reset = drm_atomic_helper_connector_reset, + .fill_modes = drm_helper_probe_single_connector_modes, + .detect = ch7033_connector_detect, + .destroy = drm_connector_cleanup, + .atomic_duplicate_state = drm_atomic_helper_connector_duplicate_state, + .atomic_destroy_state = drm_atomic_helper_connector_destroy_state, +}; + +static int ch7033_connector_get_modes(struct drm_connector *connector) +{ + struct ch7033_priv *priv = conn_to_ch7033_priv(connector); + struct edid *edid; + int ret; + + edid = drm_bridge_get_edid(priv->next_bridge, connector); + drm_connector_update_edid_property(connector, edid); + if (edid) { + ret = drm_add_edid_modes(connector, edid); + kfree(edid); + } else { + ret = drm_add_modes_noedid(connector, 1920, 1080); + drm_set_preferred_mode(connector, 1024, 768); + } + + return ret; +} + +static struct drm_encoder *ch7033_connector_best_encoder( + struct drm_connector *connector) +{ + struct ch7033_priv *priv = conn_to_ch7033_priv(connector); + + return priv->bridge.encoder; +} + +static const struct drm_connector_helper_funcs ch7033_connector_helper_funcs = { + .get_modes = ch7033_connector_get_modes, + .best_encoder = ch7033_connector_best_encoder, +}; + +static void ch7033_hpd_event(void *arg, enum drm_connector_status status) +{ + struct ch7033_priv *priv = arg; + + if (priv->bridge.dev) + drm_helper_hpd_irq_event(priv->connector.dev); +} + +static int ch7033_bridge_attach(struct drm_bridge *bridge, + enum drm_bridge_attach_flags flags) +{ + struct ch7033_priv *priv = bridge_to_ch7033_priv(bridge); + struct drm_connector *connector = &priv->connector; + int ret; + + ret = drm_bridge_attach(bridge->encoder, priv->next_bridge, bridge, + DRM_BRIDGE_ATTACH_NO_CONNECTOR); + if (ret) + return ret; + + if (flags & DRM_BRIDGE_ATTACH_NO_CONNECTOR) + return 0; + + if (priv->next_bridge->ops & DRM_BRIDGE_OP_DETECT) { + connector->polled = DRM_CONNECTOR_POLL_HPD; + } else { + connector->polled = DRM_CONNECTOR_POLL_CONNECT | + DRM_CONNECTOR_POLL_DISCONNECT; + } + + if (priv->next_bridge->ops & DRM_BRIDGE_OP_HPD) { + drm_bridge_hpd_enable(priv->next_bridge, ch7033_hpd_event, + priv); + } + + drm_connector_helper_add(connector, + &ch7033_connector_helper_funcs); + ret = drm_connector_init_with_ddc(bridge->dev, &priv->connector, + &ch7033_connector_funcs, + priv->next_bridge->type, + priv->next_bridge->ddc); + if (ret) { + DRM_ERROR("Failed to initialize connector\n"); + return ret; + } + + return drm_connector_attach_encoder(&priv->connector, bridge->encoder); +} + +static void ch7033_bridge_detach(struct drm_bridge *bridge) +{ + struct ch7033_priv *priv = bridge_to_ch7033_priv(bridge); + + if (priv->next_bridge->ops & DRM_BRIDGE_OP_HPD) + drm_bridge_hpd_disable(priv->next_bridge); + drm_connector_cleanup(&priv->connector); +} + +static enum drm_mode_status ch7033_bridge_mode_valid(struct drm_bridge *bridge, + const struct drm_display_mode *mode) +{ + if (mode->clock > 165000) + return MODE_CLOCK_HIGH; + if (mode->hdisplay >= 1920) + return MODE_BAD_HVALUE; + if (mode->vdisplay >= 1080) + return MODE_BAD_VVALUE; + return MODE_OK; +} + +static void ch7033_bridge_disable(struct drm_bridge *bridge) +{ + struct ch7033_priv *priv = bridge_to_ch7033_priv(bridge); + + regmap_write(priv->regmap, 0x03, 0x04); + regmap_update_bits(priv->regmap, 0x52, RESETDB, 0x00); +} + +static void ch7033_bridge_enable(struct drm_bridge *bridge) +{ + struct ch7033_priv *priv = bridge_to_ch7033_priv(bridge); + + regmap_write(priv->regmap, 0x03, 0x04); + regmap_update_bits(priv->regmap, 0x52, RESETDB, RESETDB); +} + +static void ch7033_bridge_mode_set(struct drm_bridge *bridge, + const struct drm_display_mode *mode, + const struct drm_display_mode *adjusted_mode) +{ + struct ch7033_priv *priv = bridge_to_ch7033_priv(bridge); + int hbporch = mode->hsync_start - mode->hdisplay; + int hsynclen = mode->hsync_end - mode->hsync_start; + int vbporch = mode->vsync_start - mode->vdisplay; + int vsynclen = mode->vsync_end - mode->vsync_start; + + /* + * Page 4 + */ + regmap_write(priv->regmap, 0x03, 0x04); + + /* Turn everything off to set all the registers to their defaults. */ + regmap_write(priv->regmap, 0x52, 0x00); + /* Bring I/O block up. */ + regmap_write(priv->regmap, 0x52, RESETIB); + + /* + * Page 0 + */ + regmap_write(priv->regmap, 0x03, 0x00); + + /* Bring up parts we need from the power down. */ + regmap_update_bits(priv->regmap, 0x07, DRI_PD | IO_PD, 0); + regmap_update_bits(priv->regmap, 0x08, DRI_PDDRI | PDDAC | PANEN, 0); + regmap_update_bits(priv->regmap, 0x09, DPD | GCKOFF | + HDMI_PD | VGA_PD, 0); + regmap_update_bits(priv->regmap, 0x0a, HD_DVIB, 0); + + /* Horizontal input timing. */ + regmap_write(priv->regmap, 0x0b, (mode->htotal >> 8) << 3 | + (mode->hdisplay >> 8)); + regmap_write(priv->regmap, 0x0c, mode->hdisplay); + regmap_write(priv->regmap, 0x0d, mode->htotal); + regmap_write(priv->regmap, 0x0e, (hsynclen >> 8) << 3 | + (hbporch >> 8)); + regmap_write(priv->regmap, 0x0f, hbporch); + regmap_write(priv->regmap, 0x10, hsynclen); + + /* Vertical input timing. */ + regmap_write(priv->regmap, 0x11, (mode->vtotal >> 8) << 3 | + (mode->vdisplay >> 8)); + regmap_write(priv->regmap, 0x12, mode->vdisplay); + regmap_write(priv->regmap, 0x13, mode->vtotal); + regmap_write(priv->regmap, 0x14, ((vsynclen >> 8) << 3) | + (vbporch >> 8)); + regmap_write(priv->regmap, 0x15, vbporch); + regmap_write(priv->regmap, 0x16, vsynclen); + + /* Input color swap. */ + regmap_update_bits(priv->regmap, 0x18, SWAP, BYTE_SWAP_BGR); + + /* Input clock and sync polarity. */ + regmap_update_bits(priv->regmap, 0x19, 0x1, mode->clock >> 16); + regmap_update_bits(priv->regmap, 0x19, HPO_I | VPO_I | GCLKFREQ, + (mode->flags & DRM_MODE_FLAG_PHSYNC) ? HPO_I : 0 | + (mode->flags & DRM_MODE_FLAG_PVSYNC) ? VPO_I : 0 | + mode->clock >> 16); + regmap_write(priv->regmap, 0x1a, mode->clock >> 8); + regmap_write(priv->regmap, 0x1b, mode->clock); + + /* Horizontal output timing. */ + regmap_write(priv->regmap, 0x1f, (mode->htotal >> 8) << 3 | + (mode->hdisplay >> 8)); + regmap_write(priv->regmap, 0x20, mode->hdisplay); + regmap_write(priv->regmap, 0x21, mode->htotal); + + /* Vertical output timing. */ + regmap_write(priv->regmap, 0x25, (mode->vtotal >> 8) << 3 | + (mode->vdisplay >> 8)); + regmap_write(priv->regmap, 0x26, mode->vdisplay); + regmap_write(priv->regmap, 0x27, mode->vtotal); + + /* VGA channel bypass */ + regmap_update_bits(priv->regmap, 0x2b, VFMT, 9); + + /* Output sync polarity. */ + regmap_update_bits(priv->regmap, 0x2e, HPO_O | VPO_O, + (mode->flags & DRM_MODE_FLAG_PHSYNC) ? HPO_O : 0 | + (mode->flags & DRM_MODE_FLAG_PVSYNC) ? VPO_O : 0); + + /* HDMI horizontal output timing. */ + regmap_update_bits(priv->regmap, 0x54, HWO_HDMI_HI | HOO_HDMI_HI, + (hsynclen >> 8) << 3 | + (hbporch >> 8)); + regmap_write(priv->regmap, 0x55, hbporch); + regmap_write(priv->regmap, 0x56, hsynclen); + + /* HDMI vertical output timing. */ + regmap_update_bits(priv->regmap, 0x57, VWO_HDMI_HI | VOO_HDMI_HI, + (vsynclen >> 8) << 3 | + (vbporch >> 8)); + regmap_write(priv->regmap, 0x58, vbporch); + regmap_write(priv->regmap, 0x59, vsynclen); + + /* Pick HDMI, not LVDS. */ + regmap_update_bits(priv->regmap, 0x7e, HDMI_LVDS_SEL, HDMI_LVDS_SEL); + + /* + * Page 1 + */ + regmap_write(priv->regmap, 0x03, 0x01); + + /* No idea what these do, but VGA is wobbly and blinky without them. */ + regmap_update_bits(priv->regmap, 0x07, CKINV, CKINV); + regmap_update_bits(priv->regmap, 0x08, DISPON, DISPON); + + /* DRI PLL */ + regmap_update_bits(priv->regmap, 0x0c, DRI_PLL_DIVSEL, DRI_PLL_DIVSEL); + if (mode->clock <= 40000) { + regmap_update_bits(priv->regmap, 0x0c, DRI_PLL_N1_1 | + DRI_PLL_N1_0 | + DRI_PLL_N3_1 | + DRI_PLL_N3_0, + 0); + } else if (mode->clock < 80000) { + regmap_update_bits(priv->regmap, 0x0c, DRI_PLL_N1_1 | + DRI_PLL_N1_0 | + DRI_PLL_N3_1 | + DRI_PLL_N3_0, + DRI_PLL_N3_0 | + DRI_PLL_N1_0); + } else { + regmap_update_bits(priv->regmap, 0x0c, DRI_PLL_N1_1 | + DRI_PLL_N1_0 | + DRI_PLL_N3_1 | + DRI_PLL_N3_0, + DRI_PLL_N3_1 | + DRI_PLL_N1_1); + } + + /* This seems to be color calibration for VGA. */ + regmap_write(priv->regmap, 0x64, 0x29); /* LSB Blue */ + regmap_write(priv->regmap, 0x65, 0x29); /* LSB Green */ + regmap_write(priv->regmap, 0x66, 0x29); /* LSB Red */ + regmap_write(priv->regmap, 0x67, 0x00); /* MSB Blue */ + regmap_write(priv->regmap, 0x68, 0x00); /* MSB Green */ + regmap_write(priv->regmap, 0x69, 0x00); /* MSB Red */ + + regmap_update_bits(priv->regmap, 0x6b, DRI_PD_SER, 0x00); + regmap_update_bits(priv->regmap, 0x6c, DRI_PLL_PD, 0x00); + + /* + * Page 3 + */ + regmap_write(priv->regmap, 0x03, 0x03); + + /* More bypasses and apparently another HDMI/LVDS selector. */ + regmap_update_bits(priv->regmap, 0x28, VGACLK_BP | HM_LV_SEL, + VGACLK_BP | HM_LV_SEL); + regmap_update_bits(priv->regmap, 0x2a, HDMICLK_BP | HDMI_BP, + HDMICLK_BP | HDMI_BP); + + /* + * Page 4 + */ + regmap_write(priv->regmap, 0x03, 0x04); + + /* Output clock. */ + regmap_write(priv->regmap, 0x10, mode->clock >> 16); + regmap_write(priv->regmap, 0x11, mode->clock >> 8); + regmap_write(priv->regmap, 0x12, mode->clock); +} + +static const struct drm_bridge_funcs ch7033_bridge_funcs = { + .attach = ch7033_bridge_attach, + .detach = ch7033_bridge_detach, + .mode_valid = ch7033_bridge_mode_valid, + .disable = ch7033_bridge_disable, + .enable = ch7033_bridge_enable, + .mode_set = ch7033_bridge_mode_set, +}; + +static const struct regmap_config ch7033_regmap_config = { + .reg_bits = 8, + .val_bits = 8, + .max_register = 0x7f, +}; + +static int ch7033_probe(struct i2c_client *client, + const struct i2c_device_id *id) +{ + struct device *dev = &client->dev; + struct ch7033_priv *priv; + unsigned int val; + int ret; + + priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL); + if (!priv) + return -ENOMEM; + + dev_set_drvdata(dev, priv); + + ret = drm_of_find_panel_or_bridge(dev->of_node, 1, -1, NULL, + &priv->next_bridge); + if (ret) + return ret; + + priv->regmap = devm_regmap_init_i2c(client, &ch7033_regmap_config); + if (IS_ERR(priv->regmap)) { + dev_err(&client->dev, "regmap init failed\n"); + return PTR_ERR(priv->regmap); + } + + ret = regmap_read(priv->regmap, 0x00, &val); + if (ret < 0) { + dev_err(&client->dev, "error reading the model id: %d\n", ret); + return ret; + } + if ((val & 0xf7) != 0x56) { + dev_err(&client->dev, "the device is not a ch7033\n"); + return -ENODEV; + } + + regmap_write(priv->regmap, 0x03, 0x04); + ret = regmap_read(priv->regmap, 0x51, &val); + if (ret < 0) { + dev_err(&client->dev, "error reading the model id: %d\n", ret); + return ret; + } + if ((val & 0x0f) != 3) { + dev_err(&client->dev, "unknown revision %u\n", val); + return -ENODEV; + } + + INIT_LIST_HEAD(&priv->bridge.list); + priv->bridge.funcs = &ch7033_bridge_funcs; + priv->bridge.of_node = dev->of_node; + drm_bridge_add(&priv->bridge); + + dev_info(dev, "Chrontel CH7033 Video Encoder\n"); + return 0; +} + +static int ch7033_remove(struct i2c_client *client) +{ + struct device *dev = &client->dev; + struct ch7033_priv *priv = dev_get_drvdata(dev); + + drm_bridge_remove(&priv->bridge); + + return 0; +} + +static const struct of_device_id ch7033_dt_ids[] = { + { .compatible = "chrontel,ch7033", }, + { } +}; +MODULE_DEVICE_TABLE(of, ch7033_dt_ids); + +static const struct i2c_device_id ch7033_ids[] = { + { "ch7033", 0 }, + { } +}; +MODULE_DEVICE_TABLE(i2c, ch7033_ids); + +static struct i2c_driver ch7033_driver = { + .probe = ch7033_probe, + .remove = ch7033_remove, + .driver = { + .name = "ch7033", + .of_match_table = of_match_ptr(ch7033_dt_ids), + }, + .id_table = ch7033_ids, +}; + +module_i2c_driver(ch7033_driver); + +MODULE_AUTHOR("Lubomir Rintel "); +MODULE_DESCRIPTION("Chrontel CH7033 Video Encoder Driver"); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/gpu/drm/bridge/panel.c b/drivers/gpu/drm/bridge/panel.c index e933f1c47f5d..1e63ed6b18aa 100644 --- a/drivers/gpu/drm/bridge/panel.c +++ b/drivers/gpu/drm/bridge/panel.c @@ -166,7 +166,7 @@ static const struct drm_bridge_funcs panel_bridge_bridge_funcs = { * * The connector type is set to @panel->connector_type, which must be set to a * known type. Calling this function with a panel whose connector type is - * DRM_MODE_CONNECTOR_Unknown will return NULL. + * DRM_MODE_CONNECTOR_Unknown will return ERR_PTR(-EINVAL). * * See devm_drm_panel_bridge_add() for an automatically managed version of this * function. @@ -174,7 +174,7 @@ static const struct drm_bridge_funcs panel_bridge_bridge_funcs = { struct drm_bridge *drm_panel_bridge_add(struct drm_panel *panel) { if (WARN_ON(panel->connector_type == DRM_MODE_CONNECTOR_Unknown)) - return NULL; + return ERR_PTR(-EINVAL); return drm_panel_bridge_add_typed(panel, panel->connector_type); } @@ -265,7 +265,7 @@ struct drm_bridge *devm_drm_panel_bridge_add(struct device *dev, struct drm_panel *panel) { if (WARN_ON(panel->connector_type == DRM_MODE_CONNECTOR_Unknown)) - return NULL; + return ERR_PTR(-EINVAL); return devm_drm_panel_bridge_add_typed(dev, panel, panel->connector_type); diff --git a/drivers/gpu/drm/bridge/parade-ps8640.c b/drivers/gpu/drm/bridge/parade-ps8640.c index d3a53442d449..4b099196afeb 100644 --- a/drivers/gpu/drm/bridge/parade-ps8640.c +++ b/drivers/gpu/drm/bridge/parade-ps8640.c @@ -268,8 +268,6 @@ static int ps8640_probe(struct i2c_client *client) if (!panel) return -ENODEV; - panel->connector_type = DRM_MODE_CONNECTOR_eDP; - ps_bridge->panel_bridge = devm_drm_panel_bridge_add(dev, panel); if (IS_ERR(ps_bridge->panel_bridge)) return PTR_ERR(ps_bridge->panel_bridge); diff --git a/drivers/gpu/drm/bridge/tc358768.c b/drivers/gpu/drm/bridge/tc358768.c index 1b39e8d37834..6650fe4cfc20 100644 --- a/drivers/gpu/drm/bridge/tc358768.c +++ b/drivers/gpu/drm/bridge/tc358768.c @@ -178,6 +178,8 @@ static int tc358768_clear_error(struct tc358768_priv *priv) static void tc358768_write(struct tc358768_priv *priv, u32 reg, u32 val) { + /* work around https://gcc.gnu.org/bugzilla/show_bug.cgi?id=81715 */ + int tmpval = val; size_t count = 2; if (priv->error) @@ -187,7 +189,7 @@ static void tc358768_write(struct tc358768_priv *priv, u32 reg, u32 val) if (reg < 0x100 || reg >= 0x600) count = 1; - priv->error = regmap_bulk_write(priv->regmap, reg, &val, count); + priv->error = regmap_bulk_write(priv->regmap, reg, &tmpval, count); } static void tc358768_read(struct tc358768_priv *priv, u32 reg, u32 *val) diff --git a/drivers/gpu/drm/cirrus/Kconfig b/drivers/gpu/drm/cirrus/Kconfig deleted file mode 100644 index c6bbd988b0e5..000000000000 --- a/drivers/gpu/drm/cirrus/Kconfig +++ /dev/null @@ -1,19 +0,0 @@ -# SPDX-License-Identifier: GPL-2.0-only -config DRM_CIRRUS_QEMU - tristate "Cirrus driver for QEMU emulated device" - depends on DRM && PCI && MMU - select DRM_KMS_HELPER - select DRM_GEM_SHMEM_HELPER - help - This is a KMS driver for emulated cirrus device in qemu. - It is *NOT* intended for real cirrus devices. This requires - the modesetting userspace X.org driver. - - Cirrus is obsolete, the hardware was designed in the 90ies - and can't keep up with todays needs. More background: - https://www.kraxel.org/blog/2014/10/qemu-using-cirrus-considered-harmful/ - - Better alternatives are: - - stdvga (DRM_BOCHS, qemu -vga std, default in qemu 2.2+) - - qxl (DRM_QXL, qemu -vga qxl, works best with spice) - - virtio (DRM_VIRTIO_GPU), qemu -vga virtio) diff --git a/drivers/gpu/drm/cirrus/Makefile b/drivers/gpu/drm/cirrus/Makefile deleted file mode 100644 index 0c1ed3f99725..000000000000 --- a/drivers/gpu/drm/cirrus/Makefile +++ /dev/null @@ -1,2 +0,0 @@ -# SPDX-License-Identifier: GPL-2.0-only -obj-$(CONFIG_DRM_CIRRUS_QEMU) += cirrus.o diff --git a/drivers/gpu/drm/drm_dp_mst_topology.c b/drivers/gpu/drm/drm_dp_mst_topology.c index 13213c4b77d1..b90cca361afe 100644 --- a/drivers/gpu/drm/drm_dp_mst_topology.c +++ b/drivers/gpu/drm/drm_dp_mst_topology.c @@ -1197,14 +1197,8 @@ static int drm_dp_mst_wait_tx_reply(struct drm_dp_mst_branch *mstb, /* remove from q */ if (txmsg->state == DRM_DP_SIDEBAND_TX_QUEUED || - txmsg->state == DRM_DP_SIDEBAND_TX_START_SEND) { + txmsg->state == DRM_DP_SIDEBAND_TX_START_SEND) list_del(&txmsg->next); - } - - if (txmsg->state == DRM_DP_SIDEBAND_TX_START_SEND || - txmsg->state == DRM_DP_SIDEBAND_TX_SENT) { - mstb->tx_slots[txmsg->seqno] = NULL; - } } out: if (unlikely(ret == -EIO) && drm_debug_enabled(DRM_UT_DP)) { @@ -1214,6 +1208,7 @@ out: } mutex_unlock(&mgr->qlock); + drm_dp_mst_kick_tx(mgr); return ret; } @@ -2682,22 +2677,6 @@ static int set_hdr_from_dst_qlock(struct drm_dp_sideband_msg_hdr *hdr, struct drm_dp_mst_branch *mstb = txmsg->dst; u8 req_type; - /* both msg slots are full */ - if (txmsg->seqno == -1) { - if (mstb->tx_slots[0] && mstb->tx_slots[1]) { - DRM_DEBUG_KMS("%s: failed to find slot\n", __func__); - return -EAGAIN; - } - if (mstb->tx_slots[0] == NULL && mstb->tx_slots[1] == NULL) { - txmsg->seqno = mstb->last_seqno; - mstb->last_seqno ^= 1; - } else if (mstb->tx_slots[0] == NULL) - txmsg->seqno = 0; - else - txmsg->seqno = 1; - mstb->tx_slots[txmsg->seqno] = txmsg; - } - req_type = txmsg->msg[0] & 0x7f; if (req_type == DP_CONNECTION_STATUS_NOTIFY || req_type == DP_RESOURCE_STATUS_NOTIFY) @@ -2709,7 +2688,7 @@ static int set_hdr_from_dst_qlock(struct drm_dp_sideband_msg_hdr *hdr, hdr->lcr = mstb->lct - 1; if (mstb->lct > 1) memcpy(hdr->rad, mstb->rad, mstb->lct / 2); - hdr->seqno = txmsg->seqno; + return 0; } /* @@ -2724,15 +2703,15 @@ static int process_single_tx_qlock(struct drm_dp_mst_topology_mgr *mgr, int len, space, idx, tosend; int ret; + if (txmsg->state == DRM_DP_SIDEBAND_TX_SENT) + return 0; + memset(&hdr, 0, sizeof(struct drm_dp_sideband_msg_hdr)); - if (txmsg->state == DRM_DP_SIDEBAND_TX_QUEUED) { - txmsg->seqno = -1; + if (txmsg->state == DRM_DP_SIDEBAND_TX_QUEUED) txmsg->state = DRM_DP_SIDEBAND_TX_START_SEND; - } - /* make hdr from dst mst - for replies use seqno - otherwise assign one */ + /* make hdr from dst mst */ ret = set_hdr_from_dst_qlock(&hdr, txmsg); if (ret < 0) return ret; @@ -2785,40 +2764,17 @@ static void process_single_down_tx_qlock(struct drm_dp_mst_topology_mgr *mgr) if (list_empty(&mgr->tx_msg_downq)) return; - txmsg = list_first_entry(&mgr->tx_msg_downq, struct drm_dp_sideband_msg_tx, next); + txmsg = list_first_entry(&mgr->tx_msg_downq, + struct drm_dp_sideband_msg_tx, next); ret = process_single_tx_qlock(mgr, txmsg, false); - if (ret == 1) { - /* txmsg is sent it should be in the slots now */ - list_del(&txmsg->next); - } else if (ret) { + if (ret < 0) { DRM_DEBUG_KMS("failed to send msg in q %d\n", ret); list_del(&txmsg->next); - if (txmsg->seqno != -1) - txmsg->dst->tx_slots[txmsg->seqno] = NULL; txmsg->state = DRM_DP_SIDEBAND_TX_TIMEOUT; wake_up_all(&mgr->tx_waitq); } } -/* called holding qlock */ -static void process_single_up_tx_qlock(struct drm_dp_mst_topology_mgr *mgr, - struct drm_dp_sideband_msg_tx *txmsg) -{ - int ret; - - /* construct a chunk from the first msg in the tx_msg queue */ - ret = process_single_tx_qlock(mgr, txmsg, true); - - if (ret != 1) - DRM_DEBUG_KMS("failed to send msg in q %d\n", ret); - - if (txmsg->seqno != -1) { - WARN_ON((unsigned int)txmsg->seqno > - ARRAY_SIZE(txmsg->dst->tx_slots)); - txmsg->dst->tx_slots[txmsg->seqno] = NULL; - } -} - static void drm_dp_queue_down_tx(struct drm_dp_mst_topology_mgr *mgr, struct drm_dp_sideband_msg_tx *txmsg) { @@ -3451,7 +3407,7 @@ static int drm_dp_encode_up_ack_reply(struct drm_dp_sideband_msg_tx *msg, u8 req static int drm_dp_send_up_ack_reply(struct drm_dp_mst_topology_mgr *mgr, struct drm_dp_mst_branch *mstb, - int req_type, int seqno, bool broadcast) + int req_type, bool broadcast) { struct drm_dp_sideband_msg_tx *txmsg; @@ -3460,13 +3416,11 @@ static int drm_dp_send_up_ack_reply(struct drm_dp_mst_topology_mgr *mgr, return -ENOMEM; txmsg->dst = mstb; - txmsg->seqno = seqno; drm_dp_encode_up_ack_reply(txmsg, req_type); mutex_lock(&mgr->qlock); - - process_single_up_tx_qlock(mgr, txmsg); - + /* construct a chunk from the first msg in the tx_msg queue */ + process_single_tx_qlock(mgr, txmsg, true); mutex_unlock(&mgr->qlock); kfree(txmsg); @@ -3691,8 +3645,9 @@ out_fail: } EXPORT_SYMBOL(drm_dp_mst_topology_mgr_resume); -static bool drm_dp_get_one_sb_msg(struct drm_dp_mst_topology_mgr *mgr, bool up, - struct drm_dp_mst_branch **mstb, int *seqno) +static bool +drm_dp_get_one_sb_msg(struct drm_dp_mst_topology_mgr *mgr, bool up, + struct drm_dp_mst_branch **mstb) { int len; u8 replyblock[32]; @@ -3700,13 +3655,13 @@ static bool drm_dp_get_one_sb_msg(struct drm_dp_mst_topology_mgr *mgr, bool up, int ret; u8 hdrlen; struct drm_dp_sideband_msg_hdr hdr; - struct drm_dp_sideband_msg_rx *msg; + struct drm_dp_sideband_msg_rx *msg = + up ? &mgr->up_req_recv : &mgr->down_rep_recv; int basereg = up ? DP_SIDEBAND_MSG_UP_REQ_BASE : DP_SIDEBAND_MSG_DOWN_REP_BASE; if (!up) *mstb = NULL; - *seqno = -1; len = min(mgr->max_dpcd_transaction_bytes, 16); ret = drm_dp_dpcd_read(mgr->aux, basereg, replyblock, len); @@ -3723,11 +3678,7 @@ static bool drm_dp_get_one_sb_msg(struct drm_dp_mst_topology_mgr *mgr, bool up, return false; } - *seqno = hdr.seqno; - - if (up) { - msg = &mgr->up_req_recv; - } else { + if (!up) { /* Caller is responsible for giving back this reference */ *mstb = drm_dp_get_mst_branch_device(mgr, hdr.lct, hdr.rad); if (!*mstb) { @@ -3735,7 +3686,6 @@ static bool drm_dp_get_one_sb_msg(struct drm_dp_mst_topology_mgr *mgr, bool up, hdr.lct); return false; } - msg = &(*mstb)->down_rep_recv[hdr.seqno]; } if (!drm_dp_sideband_msg_set_header(msg, &hdr, hdrlen)) { @@ -3779,13 +3729,10 @@ static int drm_dp_mst_handle_down_rep(struct drm_dp_mst_topology_mgr *mgr) { struct drm_dp_sideband_msg_tx *txmsg; struct drm_dp_mst_branch *mstb = NULL; - struct drm_dp_sideband_msg_rx *msg = NULL; - int seqno = -1; + struct drm_dp_sideband_msg_rx *msg = &mgr->down_rep_recv; - if (!drm_dp_get_one_sb_msg(mgr, false, &mstb, &seqno)) - goto out_clear_reply; - - msg = &mstb->down_rep_recv[seqno]; + if (!drm_dp_get_one_sb_msg(mgr, false, &mstb)) + goto out; /* Multi-packet message transmission, don't clear the reply */ if (!msg->have_eomt) @@ -3793,11 +3740,12 @@ static int drm_dp_mst_handle_down_rep(struct drm_dp_mst_topology_mgr *mgr) /* find the message */ mutex_lock(&mgr->qlock); - txmsg = mstb->tx_slots[seqno]; - /* remove from slots */ + txmsg = list_first_entry_or_null(&mgr->tx_msg_downq, + struct drm_dp_sideband_msg_tx, next); mutex_unlock(&mgr->qlock); - if (!txmsg) { + /* Were we actually expecting a response, and from this mstb? */ + if (!txmsg || txmsg->dst != mstb) { struct drm_dp_sideband_msg_hdr *hdr; hdr = &msg->initial_hdr; DRM_DEBUG_KMS("Got MST reply with no msg %p %d %d %02x %02x\n", @@ -3822,7 +3770,7 @@ static int drm_dp_mst_handle_down_rep(struct drm_dp_mst_topology_mgr *mgr) mutex_lock(&mgr->qlock); txmsg->state = DRM_DP_SIDEBAND_TX_RX; - mstb->tx_slots[seqno] = NULL; + list_del(&txmsg->next); mutex_unlock(&mgr->qlock); wake_up_all(&mgr->tx_waitq); @@ -3830,8 +3778,7 @@ static int drm_dp_mst_handle_down_rep(struct drm_dp_mst_topology_mgr *mgr) return 0; out_clear_reply: - if (msg) - memset(msg, 0, sizeof(struct drm_dp_sideband_msg_rx)); + memset(msg, 0, sizeof(struct drm_dp_sideband_msg_rx)); out: if (mstb) drm_dp_mst_topology_put_mstb(mstb); @@ -3911,9 +3858,8 @@ static void drm_dp_mst_up_req_work(struct work_struct *work) static int drm_dp_mst_handle_up_req(struct drm_dp_mst_topology_mgr *mgr) { struct drm_dp_pending_up_req *up_req; - int seqno; - if (!drm_dp_get_one_sb_msg(mgr, true, NULL, &seqno)) + if (!drm_dp_get_one_sb_msg(mgr, true, NULL)) goto out; if (!mgr->up_req_recv.have_eomt) @@ -3937,7 +3883,7 @@ static int drm_dp_mst_handle_up_req(struct drm_dp_mst_topology_mgr *mgr) } drm_dp_send_up_ack_reply(mgr, mgr->mst_primary, up_req->msg.req_type, - seqno, false); + false); if (up_req->msg.req_type == DP_CONNECTION_STATUS_NOTIFY) { const struct drm_dp_connection_status_notify *conn_stat = @@ -4703,26 +4649,25 @@ static inline void drm_dp_delayed_destroy_mstb(struct drm_dp_mst_branch *mstb) { struct drm_dp_mst_topology_mgr *mgr = mstb->mgr; - struct drm_dp_mst_port *port, *tmp; + struct drm_dp_mst_port *port, *port_tmp; + struct drm_dp_sideband_msg_tx *txmsg, *txmsg_tmp; bool wake_tx = false; mutex_lock(&mgr->lock); - list_for_each_entry_safe(port, tmp, &mstb->ports, next) { + list_for_each_entry_safe(port, port_tmp, &mstb->ports, next) { list_del(&port->next); drm_dp_mst_topology_put_port(port); } mutex_unlock(&mgr->lock); - /* drop any tx slots msg */ + /* drop any tx slot msg */ mutex_lock(&mstb->mgr->qlock); - if (mstb->tx_slots[0]) { - mstb->tx_slots[0]->state = DRM_DP_SIDEBAND_TX_TIMEOUT; - mstb->tx_slots[0] = NULL; - wake_tx = true; - } - if (mstb->tx_slots[1]) { - mstb->tx_slots[1]->state = DRM_DP_SIDEBAND_TX_TIMEOUT; - mstb->tx_slots[1] = NULL; + list_for_each_entry_safe(txmsg, txmsg_tmp, &mgr->tx_msg_downq, next) { + if (txmsg->dst != mstb) + continue; + + txmsg->state = DRM_DP_SIDEBAND_TX_TIMEOUT; + list_del(&txmsg->next); wake_tx = true; } mutex_unlock(&mstb->mgr->qlock); diff --git a/drivers/gpu/drm/drm_drv.c b/drivers/gpu/drm/drm_drv.c index c15c9b4540e1..bc38322f306e 100644 --- a/drivers/gpu/drm/drm_drv.c +++ b/drivers/gpu/drm/drm_drv.c @@ -739,6 +739,29 @@ int devm_drm_dev_init(struct device *parent, } EXPORT_SYMBOL(devm_drm_dev_init); +void *__devm_drm_dev_alloc(struct device *parent, struct drm_driver *driver, + size_t size, size_t offset) +{ + void *container; + struct drm_device *drm; + int ret; + + container = kzalloc(size, GFP_KERNEL); + if (!container) + return ERR_PTR(-ENOMEM); + + drm = container + offset; + ret = devm_drm_dev_init(parent, drm, driver); + if (ret) { + kfree(container); + return ERR_PTR(ret); + } + drmm_add_final_kfree(drm, container); + + return container; +} +EXPORT_SYMBOL(__devm_drm_dev_alloc); + /** * drm_dev_alloc - Allocate new DRM device * @driver: DRM driver to allocate device for diff --git a/drivers/gpu/drm/drm_edid.c b/drivers/gpu/drm/drm_edid.c index 43b6ca364daa..3bd95c4b02eb 100644 --- a/drivers/gpu/drm/drm_edid.c +++ b/drivers/gpu/drm/drm_edid.c @@ -2380,6 +2380,14 @@ bad_std_timing(u8 a, u8 b) (a == 0x20 && b == 0x20); } +static int drm_mode_hsync(const struct drm_display_mode *mode) +{ + if (mode->htotal <= 0) + return 0; + + return DIV_ROUND_CLOSEST(mode->clock, mode->htotal); +} + /** * drm_mode_std - convert standard mode info (width, height, refresh) into mode * @connector: connector of for the EDID block diff --git a/drivers/gpu/drm/drm_file.c b/drivers/gpu/drm/drm_file.c index eb009d3ab48f..7194e67e78bd 100644 --- a/drivers/gpu/drm/drm_file.c +++ b/drivers/gpu/drm/drm_file.c @@ -613,7 +613,8 @@ put_back_event: file_priv->event_space -= length; list_add(&e->link, &file_priv->event_list); spin_unlock_irq(&dev->event_lock); - wake_up_interruptible(&file_priv->event_wait); + wake_up_interruptible_poll(&file_priv->event_wait, + EPOLLIN | EPOLLRDNORM); break; } @@ -809,7 +810,8 @@ void drm_send_event_locked(struct drm_device *dev, struct drm_pending_event *e) list_del(&e->pending_link); list_add_tail(&e->link, &e->file_priv->event_list); - wake_up_interruptible(&e->file_priv->event_wait); + wake_up_interruptible_poll(&e->file_priv->event_wait, + EPOLLIN | EPOLLRDNORM); } EXPORT_SYMBOL(drm_send_event_locked); diff --git a/drivers/gpu/drm/drm_mm.c b/drivers/gpu/drm/drm_mm.c index 8981abe8b7c9..f4ca1ff80af9 100644 --- a/drivers/gpu/drm/drm_mm.c +++ b/drivers/gpu/drm/drm_mm.c @@ -212,20 +212,6 @@ static void drm_mm_interval_tree_add_node(struct drm_mm_node *hole_node, &drm_mm_interval_tree_augment); } -#define RB_INSERT(root, member, expr) do { \ - struct rb_node **link = &root.rb_node, *rb = NULL; \ - u64 x = expr(node); \ - while (*link) { \ - rb = *link; \ - if (x < expr(rb_entry(rb, struct drm_mm_node, member))) \ - link = &rb->rb_left; \ - else \ - link = &rb->rb_right; \ - } \ - rb_link_node(&node->member, rb, link); \ - rb_insert_color(&node->member, &root); \ -} while (0) - #define HOLE_SIZE(NODE) ((NODE)->hole_size) #define HOLE_ADDR(NODE) (__drm_mm_hole_node_start(NODE)) @@ -255,16 +241,42 @@ static void insert_hole_size(struct rb_root_cached *root, rb_insert_color_cached(&node->rb_hole_size, root, first); } +RB_DECLARE_CALLBACKS_MAX(static, augment_callbacks, + struct drm_mm_node, rb_hole_addr, + u64, subtree_max_hole, HOLE_SIZE) + +static void insert_hole_addr(struct rb_root *root, struct drm_mm_node *node) +{ + struct rb_node **link = &root->rb_node, *rb_parent = NULL; + u64 start = HOLE_ADDR(node), subtree_max_hole = node->subtree_max_hole; + struct drm_mm_node *parent; + + while (*link) { + rb_parent = *link; + parent = rb_entry(rb_parent, struct drm_mm_node, rb_hole_addr); + if (parent->subtree_max_hole < subtree_max_hole) + parent->subtree_max_hole = subtree_max_hole; + if (start < HOLE_ADDR(parent)) + link = &parent->rb_hole_addr.rb_left; + else + link = &parent->rb_hole_addr.rb_right; + } + + rb_link_node(&node->rb_hole_addr, rb_parent, link); + rb_insert_augmented(&node->rb_hole_addr, root, &augment_callbacks); +} + static void add_hole(struct drm_mm_node *node) { struct drm_mm *mm = node->mm; node->hole_size = __drm_mm_hole_node_end(node) - __drm_mm_hole_node_start(node); + node->subtree_max_hole = node->hole_size; DRM_MM_BUG_ON(!drm_mm_hole_follows(node)); insert_hole_size(&mm->holes_size, node); - RB_INSERT(mm->holes_addr, rb_hole_addr, HOLE_ADDR); + insert_hole_addr(&mm->holes_addr, node); list_add(&node->hole_stack, &mm->hole_stack); } @@ -275,8 +287,10 @@ static void rm_hole(struct drm_mm_node *node) list_del(&node->hole_stack); rb_erase_cached(&node->rb_hole_size, &node->mm->holes_size); - rb_erase(&node->rb_hole_addr, &node->mm->holes_addr); + rb_erase_augmented(&node->rb_hole_addr, &node->mm->holes_addr, + &augment_callbacks); node->hole_size = 0; + node->subtree_max_hole = 0; DRM_MM_BUG_ON(drm_mm_hole_follows(node)); } @@ -361,9 +375,90 @@ first_hole(struct drm_mm *mm, } } +/** + * next_hole_high_addr - returns next hole for a DRM_MM_INSERT_HIGH mode request + * @entry: previously selected drm_mm_node + * @size: size of the a hole needed for the request + * + * This function will verify whether left subtree of @entry has hole big enough + * to fit the requtested size. If so, it will return previous node of @entry or + * else it will return parent node of @entry + * + * It will also skip the complete left subtree if subtree_max_hole of that + * subtree is same as the subtree_max_hole of the @entry. + * + * Returns: + * previous node of @entry if left subtree of @entry can serve the request or + * else return parent of @entry + */ +static struct drm_mm_node * +next_hole_high_addr(struct drm_mm_node *entry, u64 size) +{ + struct rb_node *rb_node, *left_rb_node, *parent_rb_node; + struct drm_mm_node *left_node; + + if (!entry) + return NULL; + + rb_node = &entry->rb_hole_addr; + if (rb_node->rb_left) { + left_rb_node = rb_node->rb_left; + parent_rb_node = rb_parent(rb_node); + left_node = rb_entry(left_rb_node, + struct drm_mm_node, rb_hole_addr); + if ((left_node->subtree_max_hole < size || + entry->size == entry->subtree_max_hole) && + parent_rb_node && parent_rb_node->rb_left != rb_node) + return rb_hole_addr_to_node(parent_rb_node); + } + + return rb_hole_addr_to_node(rb_prev(rb_node)); +} + +/** + * next_hole_low_addr - returns next hole for a DRM_MM_INSERT_LOW mode request + * @entry: previously selected drm_mm_node + * @size: size of the a hole needed for the request + * + * This function will verify whether right subtree of @entry has hole big enough + * to fit the requtested size. If so, it will return next node of @entry or + * else it will return parent node of @entry + * + * It will also skip the complete right subtree if subtree_max_hole of that + * subtree is same as the subtree_max_hole of the @entry. + * + * Returns: + * next node of @entry if right subtree of @entry can serve the request or + * else return parent of @entry + */ +static struct drm_mm_node * +next_hole_low_addr(struct drm_mm_node *entry, u64 size) +{ + struct rb_node *rb_node, *right_rb_node, *parent_rb_node; + struct drm_mm_node *right_node; + + if (!entry) + return NULL; + + rb_node = &entry->rb_hole_addr; + if (rb_node->rb_right) { + right_rb_node = rb_node->rb_right; + parent_rb_node = rb_parent(rb_node); + right_node = rb_entry(right_rb_node, + struct drm_mm_node, rb_hole_addr); + if ((right_node->subtree_max_hole < size || + entry->size == entry->subtree_max_hole) && + parent_rb_node && parent_rb_node->rb_right != rb_node) + return rb_hole_addr_to_node(parent_rb_node); + } + + return rb_hole_addr_to_node(rb_next(rb_node)); +} + static struct drm_mm_node * next_hole(struct drm_mm *mm, struct drm_mm_node *node, + u64 size, enum drm_mm_insert_mode mode) { switch (mode) { @@ -372,10 +467,10 @@ next_hole(struct drm_mm *mm, return rb_hole_size_to_node(rb_prev(&node->rb_hole_size)); case DRM_MM_INSERT_LOW: - return rb_hole_addr_to_node(rb_next(&node->rb_hole_addr)); + return next_hole_low_addr(node, size); case DRM_MM_INSERT_HIGH: - return rb_hole_addr_to_node(rb_prev(&node->rb_hole_addr)); + return next_hole_high_addr(node, size); case DRM_MM_INSERT_EVICT: node = list_next_entry(node, hole_stack); @@ -489,7 +584,7 @@ int drm_mm_insert_node_in_range(struct drm_mm * const mm, remainder_mask = is_power_of_2(alignment) ? alignment - 1 : 0; for (hole = first_hole(mm, range_start, range_end, size, mode); hole; - hole = once ? NULL : next_hole(mm, hole, mode)) { + hole = once ? NULL : next_hole(mm, hole, size, mode)) { u64 hole_start = __drm_mm_hole_node_start(hole); u64 hole_end = hole_start + hole->hole_size; u64 adj_start, adj_end; diff --git a/drivers/gpu/drm/drm_mode_object.c b/drivers/gpu/drm/drm_mode_object.c index 35c2719407a8..901b078abf40 100644 --- a/drivers/gpu/drm/drm_mode_object.c +++ b/drivers/gpu/drm/drm_mode_object.c @@ -402,12 +402,13 @@ int drm_mode_obj_get_properties_ioctl(struct drm_device *dev, void *data, { struct drm_mode_obj_get_properties *arg = data; struct drm_mode_object *obj; + struct drm_modeset_acquire_ctx ctx; int ret = 0; if (!drm_core_check_feature(dev, DRIVER_MODESET)) return -EOPNOTSUPP; - drm_modeset_lock_all(dev); + DRM_MODESET_LOCK_ALL_BEGIN(dev, ctx, 0, ret); obj = drm_mode_object_find(dev, file_priv, arg->obj_id, arg->obj_type); if (!obj) { @@ -427,7 +428,7 @@ int drm_mode_obj_get_properties_ioctl(struct drm_device *dev, void *data, out_unref: drm_mode_object_put(obj); out: - drm_modeset_unlock_all(dev); + DRM_MODESET_LOCK_ALL_END(ctx, ret); return ret; } @@ -449,12 +450,13 @@ static int set_property_legacy(struct drm_mode_object *obj, { struct drm_device *dev = prop->dev; struct drm_mode_object *ref; + struct drm_modeset_acquire_ctx ctx; int ret = -EINVAL; if (!drm_property_change_valid_get(prop, prop_value, &ref)) return -EINVAL; - drm_modeset_lock_all(dev); + DRM_MODESET_LOCK_ALL_BEGIN(dev, ctx, 0, ret); switch (obj->type) { case DRM_MODE_OBJECT_CONNECTOR: ret = drm_connector_set_obj_prop(obj, prop, prop_value); @@ -468,7 +470,7 @@ static int set_property_legacy(struct drm_mode_object *obj, break; } drm_property_change_valid_put(prop, ref); - drm_modeset_unlock_all(dev); + DRM_MODESET_LOCK_ALL_END(ctx, ret); return ret; } diff --git a/drivers/gpu/drm/drm_modes.c b/drivers/gpu/drm/drm_modes.c index d4d64518e11b..fec1c33b3045 100644 --- a/drivers/gpu/drm/drm_modes.c +++ b/drivers/gpu/drm/drm_modes.c @@ -747,32 +747,6 @@ void drm_mode_set_name(struct drm_display_mode *mode) } EXPORT_SYMBOL(drm_mode_set_name); -/** - * drm_mode_hsync - get the hsync of a mode - * @mode: mode - * - * Returns: - * @modes's hsync rate in kHz, rounded to the nearest integer. Calculates the - * value first if it is not yet set. - */ -int drm_mode_hsync(const struct drm_display_mode *mode) -{ - unsigned int calc_val; - - if (mode->hsync) - return mode->hsync; - - if (mode->htotal <= 0) - return 0; - - calc_val = (mode->clock * 1000) / mode->htotal; /* hsync in Hz */ - calc_val += 500; /* round to 1000Hz */ - calc_val /= 1000; /* truncate to kHz */ - - return calc_val; -} -EXPORT_SYMBOL(drm_mode_hsync); - /** * drm_mode_vrefresh - get the vrefresh of a mode * @mode: mode diff --git a/drivers/gpu/drm/i915/display/intel_display.c b/drivers/gpu/drm/i915/display/intel_display.c index af5b4055b38a..3afcfedb8627 100644 --- a/drivers/gpu/drm/i915/display/intel_display.c +++ b/drivers/gpu/drm/i915/display/intel_display.c @@ -8875,7 +8875,6 @@ void intel_mode_from_pipe_config(struct drm_display_mode *mode, mode->clock = pipe_config->hw.adjusted_mode.crtc_clock; - mode->hsync = drm_mode_hsync(mode); mode->vrefresh = drm_mode_vrefresh(mode); drm_mode_set_name(mode); } diff --git a/drivers/gpu/drm/i915/i915_drv.c b/drivers/gpu/drm/i915/i915_drv.c index 641f5e03b661..ff9a5b1b4c6d 100644 --- a/drivers/gpu/drm/i915/i915_drv.c +++ b/drivers/gpu/drm/i915/i915_drv.c @@ -877,19 +877,11 @@ i915_driver_create(struct pci_dev *pdev, const struct pci_device_id *ent) (struct intel_device_info *)ent->driver_data; struct intel_device_info *device_info; struct drm_i915_private *i915; - int err; - i915 = kzalloc(sizeof(*i915), GFP_KERNEL); - if (!i915) - return ERR_PTR(-ENOMEM); - - err = drm_dev_init(&i915->drm, &driver, &pdev->dev); - if (err) { - kfree(i915); - return ERR_PTR(err); - } - - drmm_add_final_kfree(&i915->drm, i915); + i915 = devm_drm_dev_alloc(&pdev->dev, &driver, + struct drm_i915_private, drm); + if (IS_ERR(i915)) + return i915; i915->drm.pdev = pdev; pci_set_drvdata(pdev, i915); @@ -1006,7 +998,6 @@ out_pci_disable: pci_disable_device(pdev); out_fini: i915_probe_error(i915, "Device initialization failed (%d)\n", ret); - drm_dev_put(&i915->drm); return ret; } diff --git a/drivers/gpu/drm/i915/i915_pci.c b/drivers/gpu/drm/i915/i915_pci.c index 66738f2c4f28..2741fb3e30cb 100644 --- a/drivers/gpu/drm/i915/i915_pci.c +++ b/drivers/gpu/drm/i915/i915_pci.c @@ -941,8 +941,6 @@ static void i915_pci_remove(struct pci_dev *pdev) i915_driver_remove(i915); pci_set_drvdata(pdev, NULL); - - drm_dev_put(&i915->drm); } /* is device_id present in comma separated list of ids */ diff --git a/drivers/gpu/drm/ingenic/ingenic-drm.c b/drivers/gpu/drm/ingenic/ingenic-drm.c index 24cc3587cea5..632d72177123 100644 --- a/drivers/gpu/drm/ingenic/ingenic-drm.c +++ b/drivers/gpu/drm/ingenic/ingenic-drm.c @@ -611,24 +611,17 @@ static int ingenic_drm_probe(struct platform_device *pdev) return -EINVAL; } - priv = kzalloc(sizeof(*priv), GFP_KERNEL); - if (!priv) - return -ENOMEM; + priv = devm_drm_dev_alloc(dev, &ingenic_drm_driver_data, + struct ingenic_drm, drm); + if (IS_ERR(priv)) + return PTR_ERR(priv); priv->soc_info = soc_info; priv->dev = dev; drm = &priv->drm; - drm->dev_private = priv; platform_set_drvdata(pdev, priv); - ret = devm_drm_dev_init(dev, drm, &ingenic_drm_driver_data); - if (ret) { - kfree(priv); - return ret; - } - drmm_add_final_kfree(drm, priv); - ret = drmm_mode_config_init(drm); if (ret) return ret; diff --git a/drivers/gpu/drm/lima/lima_bcast.c b/drivers/gpu/drm/lima/lima_bcast.c index 288398027bfa..fbc43f243c54 100644 --- a/drivers/gpu/drm/lima/lima_bcast.c +++ b/drivers/gpu/drm/lima/lima_bcast.c @@ -26,18 +26,33 @@ void lima_bcast_enable(struct lima_device *dev, int num_pp) bcast_write(LIMA_BCAST_BROADCAST_MASK, mask); } +static int lima_bcast_hw_init(struct lima_ip *ip) +{ + bcast_write(LIMA_BCAST_BROADCAST_MASK, ip->data.mask << 16); + bcast_write(LIMA_BCAST_INTERRUPT_MASK, ip->data.mask); + return 0; +} + +int lima_bcast_resume(struct lima_ip *ip) +{ + return lima_bcast_hw_init(ip); +} + +void lima_bcast_suspend(struct lima_ip *ip) +{ + +} + int lima_bcast_init(struct lima_ip *ip) { - int i, mask = 0; + int i; for (i = lima_ip_pp0; i <= lima_ip_pp7; i++) { if (ip->dev->ip[i].present) - mask |= 1 << (i - lima_ip_pp0); + ip->data.mask |= 1 << (i - lima_ip_pp0); } - bcast_write(LIMA_BCAST_BROADCAST_MASK, mask << 16); - bcast_write(LIMA_BCAST_INTERRUPT_MASK, mask); - return 0; + return lima_bcast_hw_init(ip); } void lima_bcast_fini(struct lima_ip *ip) diff --git a/drivers/gpu/drm/lima/lima_bcast.h b/drivers/gpu/drm/lima/lima_bcast.h index c47e58563d0a..465ee587bceb 100644 --- a/drivers/gpu/drm/lima/lima_bcast.h +++ b/drivers/gpu/drm/lima/lima_bcast.h @@ -6,6 +6,8 @@ struct lima_ip; +int lima_bcast_resume(struct lima_ip *ip); +void lima_bcast_suspend(struct lima_ip *ip); int lima_bcast_init(struct lima_ip *ip); void lima_bcast_fini(struct lima_ip *ip); diff --git a/drivers/gpu/drm/lima/lima_devfreq.c b/drivers/gpu/drm/lima/lima_devfreq.c index 8c4d21d07529..bbe02817721b 100644 --- a/drivers/gpu/drm/lima/lima_devfreq.c +++ b/drivers/gpu/drm/lima/lima_devfreq.c @@ -101,13 +101,12 @@ void lima_devfreq_fini(struct lima_device *ldev) } if (devfreq->devfreq) { - devm_devfreq_remove_device(&ldev->pdev->dev, - devfreq->devfreq); + devm_devfreq_remove_device(ldev->dev, devfreq->devfreq); devfreq->devfreq = NULL; } if (devfreq->opp_of_table_added) { - dev_pm_opp_of_remove_table(&ldev->pdev->dev); + dev_pm_opp_of_remove_table(ldev->dev); devfreq->opp_of_table_added = false; } @@ -125,7 +124,7 @@ void lima_devfreq_fini(struct lima_device *ldev) int lima_devfreq_init(struct lima_device *ldev) { struct thermal_cooling_device *cooling; - struct device *dev = &ldev->pdev->dev; + struct device *dev = ldev->dev; struct opp_table *opp_table; struct devfreq *devfreq; struct lima_devfreq *ldevfreq = &ldev->devfreq; @@ -232,3 +231,27 @@ void lima_devfreq_record_idle(struct lima_devfreq *devfreq) spin_unlock_irqrestore(&devfreq->lock, irqflags); } + +int lima_devfreq_resume(struct lima_devfreq *devfreq) +{ + unsigned long irqflags; + + if (!devfreq->devfreq) + return 0; + + spin_lock_irqsave(&devfreq->lock, irqflags); + + lima_devfreq_reset(devfreq); + + spin_unlock_irqrestore(&devfreq->lock, irqflags); + + return devfreq_resume_device(devfreq->devfreq); +} + +int lima_devfreq_suspend(struct lima_devfreq *devfreq) +{ + if (!devfreq->devfreq) + return 0; + + return devfreq_suspend_device(devfreq->devfreq); +} diff --git a/drivers/gpu/drm/lima/lima_devfreq.h b/drivers/gpu/drm/lima/lima_devfreq.h index 8d71ba9fb22a..5eed2975a375 100644 --- a/drivers/gpu/drm/lima/lima_devfreq.h +++ b/drivers/gpu/drm/lima/lima_devfreq.h @@ -38,4 +38,7 @@ void lima_devfreq_fini(struct lima_device *ldev); void lima_devfreq_record_busy(struct lima_devfreq *devfreq); void lima_devfreq_record_idle(struct lima_devfreq *devfreq); +int lima_devfreq_resume(struct lima_devfreq *devfreq); +int lima_devfreq_suspend(struct lima_devfreq *devfreq); + #endif diff --git a/drivers/gpu/drm/lima/lima_device.c b/drivers/gpu/drm/lima/lima_device.c index 247f51fd40a2..65fdca366e41 100644 --- a/drivers/gpu/drm/lima/lima_device.c +++ b/drivers/gpu/drm/lima/lima_device.c @@ -25,6 +25,8 @@ struct lima_ip_desc { int (*init)(struct lima_ip *ip); void (*fini)(struct lima_ip *ip); + int (*resume)(struct lima_ip *ip); + void (*suspend)(struct lima_ip *ip); }; #define LIMA_IP_DESC(ipname, mst0, mst1, off0, off1, func, irq) \ @@ -41,6 +43,8 @@ struct lima_ip_desc { }, \ .init = lima_##func##_init, \ .fini = lima_##func##_fini, \ + .resume = lima_##func##_resume, \ + .suspend = lima_##func##_suspend, \ } static struct lima_ip_desc lima_ip_desc[lima_ip_num] = { @@ -77,26 +81,10 @@ const char *lima_ip_name(struct lima_ip *ip) return lima_ip_desc[ip->id].name; } -static int lima_clk_init(struct lima_device *dev) +static int lima_clk_enable(struct lima_device *dev) { int err; - dev->clk_bus = devm_clk_get(dev->dev, "bus"); - if (IS_ERR(dev->clk_bus)) { - err = PTR_ERR(dev->clk_bus); - if (err != -EPROBE_DEFER) - dev_err(dev->dev, "get bus clk failed %d\n", err); - return err; - } - - dev->clk_gpu = devm_clk_get(dev->dev, "core"); - if (IS_ERR(dev->clk_gpu)) { - err = PTR_ERR(dev->clk_gpu); - if (err != -EPROBE_DEFER) - dev_err(dev->dev, "get core clk failed %d\n", err); - return err; - } - err = clk_prepare_enable(dev->clk_bus); if (err) return err; @@ -105,15 +93,7 @@ static int lima_clk_init(struct lima_device *dev) if (err) goto error_out0; - dev->reset = devm_reset_control_array_get_optional_shared(dev->dev); - - if (IS_ERR(dev->reset)) { - err = PTR_ERR(dev->reset); - if (err != -EPROBE_DEFER) - dev_err(dev->dev, "get reset controller failed %d\n", - err); - goto error_out1; - } else if (dev->reset != NULL) { + if (dev->reset) { err = reset_control_deassert(dev->reset); if (err) { dev_err(dev->dev, @@ -131,14 +111,76 @@ error_out0: return err; } -static void lima_clk_fini(struct lima_device *dev) +static void lima_clk_disable(struct lima_device *dev) { - if (dev->reset != NULL) + if (dev->reset) reset_control_assert(dev->reset); clk_disable_unprepare(dev->clk_gpu); clk_disable_unprepare(dev->clk_bus); } +static int lima_clk_init(struct lima_device *dev) +{ + int err; + + dev->clk_bus = devm_clk_get(dev->dev, "bus"); + if (IS_ERR(dev->clk_bus)) { + err = PTR_ERR(dev->clk_bus); + if (err != -EPROBE_DEFER) + dev_err(dev->dev, "get bus clk failed %d\n", err); + dev->clk_bus = NULL; + return err; + } + + dev->clk_gpu = devm_clk_get(dev->dev, "core"); + if (IS_ERR(dev->clk_gpu)) { + err = PTR_ERR(dev->clk_gpu); + if (err != -EPROBE_DEFER) + dev_err(dev->dev, "get core clk failed %d\n", err); + dev->clk_gpu = NULL; + return err; + } + + dev->reset = devm_reset_control_array_get_optional_shared(dev->dev); + if (IS_ERR(dev->reset)) { + err = PTR_ERR(dev->reset); + if (err != -EPROBE_DEFER) + dev_err(dev->dev, "get reset controller failed %d\n", + err); + dev->reset = NULL; + return err; + } + + return lima_clk_enable(dev); +} + +static void lima_clk_fini(struct lima_device *dev) +{ + lima_clk_disable(dev); +} + +static int lima_regulator_enable(struct lima_device *dev) +{ + int ret; + + if (!dev->regulator) + return 0; + + ret = regulator_enable(dev->regulator); + if (ret < 0) { + dev_err(dev->dev, "failed to enable regulator: %d\n", ret); + return ret; + } + + return 0; +} + +static void lima_regulator_disable(struct lima_device *dev) +{ + if (dev->regulator) + regulator_disable(dev->regulator); +} + static int lima_regulator_init(struct lima_device *dev) { int ret; @@ -154,25 +196,20 @@ static int lima_regulator_init(struct lima_device *dev) return ret; } - ret = regulator_enable(dev->regulator); - if (ret < 0) { - dev_err(dev->dev, "failed to enable regulator: %d\n", ret); - return ret; - } - - return 0; + return lima_regulator_enable(dev); } static void lima_regulator_fini(struct lima_device *dev) { - if (dev->regulator) - regulator_disable(dev->regulator); + lima_regulator_disable(dev); } static int lima_init_ip(struct lima_device *dev, int index) { + struct platform_device *pdev = to_platform_device(dev->dev); struct lima_ip_desc *desc = lima_ip_desc + index; struct lima_ip *ip = dev->ip + index; + const char *irq_name = desc->irq_name; int offset = desc->offset[dev->id]; bool must = desc->must_have[dev->id]; int err; @@ -183,8 +220,9 @@ static int lima_init_ip(struct lima_device *dev, int index) ip->dev = dev; ip->id = index; ip->iomem = dev->iomem + offset; - if (desc->irq_name) { - err = platform_get_irq_byname(dev->pdev, desc->irq_name); + if (irq_name) { + err = must ? platform_get_irq_byname(pdev, irq_name) : + platform_get_irq_byname_optional(pdev, irq_name); if (err < 0) goto out; ip->irq = err; @@ -209,6 +247,27 @@ static void lima_fini_ip(struct lima_device *ldev, int index) desc->fini(ip); } +static int lima_resume_ip(struct lima_device *ldev, int index) +{ + struct lima_ip_desc *desc = lima_ip_desc + index; + struct lima_ip *ip = ldev->ip + index; + int ret = 0; + + if (ip->present) + ret = desc->resume(ip); + + return ret; +} + +static void lima_suspend_ip(struct lima_device *ldev, int index) +{ + struct lima_ip_desc *desc = lima_ip_desc + index; + struct lima_ip *ip = ldev->ip + index; + + if (ip->present) + desc->suspend(ip); +} + static int lima_init_gp_pipe(struct lima_device *dev) { struct lima_sched_pipe *pipe = dev->pipe + lima_pipe_gp; @@ -294,8 +353,8 @@ static void lima_fini_pp_pipe(struct lima_device *dev) int lima_device_init(struct lima_device *ldev) { + struct platform_device *pdev = to_platform_device(ldev->dev); int err, i; - struct resource *res; dma_set_coherent_mask(ldev->dev, DMA_BIT_MASK(32)); @@ -326,8 +385,7 @@ int lima_device_init(struct lima_device *ldev) } else ldev->va_end = LIMA_VA_RESERVE_END; - res = platform_get_resource(ldev->pdev, IORESOURCE_MEM, 0); - ldev->iomem = devm_ioremap_resource(ldev->dev, res); + ldev->iomem = devm_platform_ioremap_resource(pdev, 0); if (IS_ERR(ldev->iomem)) { dev_err(ldev->dev, "fail to ioremap iomem\n"); err = PTR_ERR(ldev->iomem); @@ -404,3 +462,72 @@ void lima_device_fini(struct lima_device *ldev) lima_clk_fini(ldev); } + +int lima_device_resume(struct device *dev) +{ + struct lima_device *ldev = dev_get_drvdata(dev); + int i, err; + + err = lima_clk_enable(ldev); + if (err) { + dev_err(dev, "resume clk fail %d\n", err); + return err; + } + + err = lima_regulator_enable(ldev); + if (err) { + dev_err(dev, "resume regulator fail %d\n", err); + goto err_out0; + } + + for (i = 0; i < lima_ip_num; i++) { + err = lima_resume_ip(ldev, i); + if (err) { + dev_err(dev, "resume ip %d fail\n", i); + goto err_out1; + } + } + + err = lima_devfreq_resume(&ldev->devfreq); + if (err) { + dev_err(dev, "devfreq resume fail\n"); + goto err_out1; + } + + return 0; + +err_out1: + while (--i >= 0) + lima_suspend_ip(ldev, i); + lima_regulator_disable(ldev); +err_out0: + lima_clk_disable(ldev); + return err; +} + +int lima_device_suspend(struct device *dev) +{ + struct lima_device *ldev = dev_get_drvdata(dev); + int i, err; + + /* check any task running */ + for (i = 0; i < lima_pipe_num; i++) { + if (atomic_read(&ldev->pipe[i].base.hw_rq_count)) + return -EBUSY; + } + + err = lima_devfreq_suspend(&ldev->devfreq); + if (err) { + dev_err(dev, "devfreq suspend fail\n"); + return err; + } + + for (i = lima_ip_num - 1; i >= 0; i--) + lima_suspend_ip(ldev, i); + + lima_regulator_disable(ldev); + + lima_clk_disable(ldev); + + return 0; +} diff --git a/drivers/gpu/drm/lima/lima_device.h b/drivers/gpu/drm/lima/lima_device.h index 06fd9636dd72..41b9d7b4bcc7 100644 --- a/drivers/gpu/drm/lima/lima_device.h +++ b/drivers/gpu/drm/lima/lima_device.h @@ -64,6 +64,8 @@ struct lima_ip { bool async_reset; /* l2 cache */ spinlock_t lock; + /* pmu/bcast */ + u32 mask; } data; }; @@ -76,7 +78,6 @@ enum lima_pipe_id { struct lima_device { struct device *dev; struct drm_device *ddev; - struct platform_device *pdev; enum lima_gpu_id id; u32 gp_version; @@ -139,4 +140,7 @@ static inline int lima_poll_timeout(struct lima_ip *ip, lima_poll_func_t func, return 0; } +int lima_device_suspend(struct device *dev); +int lima_device_resume(struct device *dev); + #endif diff --git a/drivers/gpu/drm/lima/lima_dlbu.c b/drivers/gpu/drm/lima/lima_dlbu.c index 8399ceffb94b..c1d5ea35daa7 100644 --- a/drivers/gpu/drm/lima/lima_dlbu.c +++ b/drivers/gpu/drm/lima/lima_dlbu.c @@ -42,7 +42,7 @@ void lima_dlbu_set_reg(struct lima_ip *ip, u32 *reg) dlbu_write(LIMA_DLBU_START_TILE_POS, reg[3]); } -int lima_dlbu_init(struct lima_ip *ip) +static int lima_dlbu_hw_init(struct lima_ip *ip) { struct lima_device *dev = ip->dev; @@ -52,6 +52,21 @@ int lima_dlbu_init(struct lima_ip *ip) return 0; } +int lima_dlbu_resume(struct lima_ip *ip) +{ + return lima_dlbu_hw_init(ip); +} + +void lima_dlbu_suspend(struct lima_ip *ip) +{ + +} + +int lima_dlbu_init(struct lima_ip *ip) +{ + return lima_dlbu_hw_init(ip); +} + void lima_dlbu_fini(struct lima_ip *ip) { diff --git a/drivers/gpu/drm/lima/lima_dlbu.h b/drivers/gpu/drm/lima/lima_dlbu.h index 16f877984466..be71daaaee89 100644 --- a/drivers/gpu/drm/lima/lima_dlbu.h +++ b/drivers/gpu/drm/lima/lima_dlbu.h @@ -12,6 +12,8 @@ void lima_dlbu_disable(struct lima_device *dev); void lima_dlbu_set_reg(struct lima_ip *ip, u32 *reg); +int lima_dlbu_resume(struct lima_ip *ip); +void lima_dlbu_suspend(struct lima_ip *ip); int lima_dlbu_init(struct lima_ip *ip); void lima_dlbu_fini(struct lima_ip *ip); diff --git a/drivers/gpu/drm/lima/lima_drv.c b/drivers/gpu/drm/lima/lima_drv.c index bbbdc8455e2f..a831565af813 100644 --- a/drivers/gpu/drm/lima/lima_drv.c +++ b/drivers/gpu/drm/lima/lima_drv.c @@ -5,6 +5,7 @@ #include #include #include +#include #include #include #include @@ -380,7 +381,6 @@ static int lima_pdev_probe(struct platform_device *pdev) goto err_out0; } - ldev->pdev = pdev; ldev->dev = &pdev->dev; ldev->id = (enum lima_gpu_id)of_device_get_match_data(&pdev->dev); @@ -404,6 +404,12 @@ static int lima_pdev_probe(struct platform_device *pdev) goto err_out2; } + pm_runtime_set_active(ldev->dev); + pm_runtime_mark_last_busy(ldev->dev); + pm_runtime_set_autosuspend_delay(ldev->dev, 200); + pm_runtime_use_autosuspend(ldev->dev); + pm_runtime_enable(ldev->dev); + /* * Register the DRM device with the core and the connectors with * sysfs. @@ -412,17 +418,16 @@ static int lima_pdev_probe(struct platform_device *pdev) if (err < 0) goto err_out3; - platform_set_drvdata(pdev, ldev); - if (sysfs_create_bin_file(&ldev->dev->kobj, &lima_error_state_attr)) dev_warn(ldev->dev, "fail to create error state sysfs\n"); return 0; err_out3: - lima_device_fini(ldev); -err_out2: + pm_runtime_disable(ldev->dev); lima_devfreq_fini(ldev); +err_out2: + lima_device_fini(ldev); err_out1: drm_dev_put(ddev); err_out0: @@ -436,10 +441,16 @@ static int lima_pdev_remove(struct platform_device *pdev) struct drm_device *ddev = ldev->ddev; sysfs_remove_bin_file(&ldev->dev->kobj, &lima_error_state_attr); - platform_set_drvdata(pdev, NULL); + drm_dev_unregister(ddev); + + /* stop autosuspend to make sure device is in active state */ + pm_runtime_set_autosuspend_delay(ldev->dev, -1); + pm_runtime_disable(ldev->dev); + lima_devfreq_fini(ldev); lima_device_fini(ldev); + drm_dev_put(ddev); lima_sched_slab_fini(); return 0; @@ -452,26 +463,22 @@ static const struct of_device_id dt_match[] = { }; MODULE_DEVICE_TABLE(of, dt_match); +static const struct dev_pm_ops lima_pm_ops = { + SET_SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend, pm_runtime_force_resume) + SET_RUNTIME_PM_OPS(lima_device_suspend, lima_device_resume, NULL) +}; + static struct platform_driver lima_platform_driver = { .probe = lima_pdev_probe, .remove = lima_pdev_remove, .driver = { .name = "lima", + .pm = &lima_pm_ops, .of_match_table = dt_match, }, }; -static int __init lima_init(void) -{ - return platform_driver_register(&lima_platform_driver); -} -module_init(lima_init); - -static void __exit lima_exit(void) -{ - platform_driver_unregister(&lima_platform_driver); -} -module_exit(lima_exit); +module_platform_driver(lima_platform_driver); MODULE_AUTHOR("Lima Project Developers"); MODULE_DESCRIPTION("Lima DRM Driver"); diff --git a/drivers/gpu/drm/lima/lima_gp.c b/drivers/gpu/drm/lima/lima_gp.c index d8841c870d90..8dd501b7a3d0 100644 --- a/drivers/gpu/drm/lima/lima_gp.c +++ b/drivers/gpu/drm/lima/lima_gp.c @@ -274,6 +274,23 @@ static void lima_gp_print_version(struct lima_ip *ip) static struct kmem_cache *lima_gp_task_slab; static int lima_gp_task_slab_refcnt; +static int lima_gp_hw_init(struct lima_ip *ip) +{ + ip->data.async_reset = false; + lima_gp_soft_reset_async(ip); + return lima_gp_soft_reset_async_wait(ip); +} + +int lima_gp_resume(struct lima_ip *ip) +{ + return lima_gp_hw_init(ip); +} + +void lima_gp_suspend(struct lima_ip *ip) +{ + +} + int lima_gp_init(struct lima_ip *ip) { struct lima_device *dev = ip->dev; @@ -281,9 +298,7 @@ int lima_gp_init(struct lima_ip *ip) lima_gp_print_version(ip); - ip->data.async_reset = false; - lima_gp_soft_reset_async(ip); - err = lima_gp_soft_reset_async_wait(ip); + err = lima_gp_hw_init(ip); if (err) return err; diff --git a/drivers/gpu/drm/lima/lima_gp.h b/drivers/gpu/drm/lima/lima_gp.h index 516e5c1babbb..02ec9af78a51 100644 --- a/drivers/gpu/drm/lima/lima_gp.h +++ b/drivers/gpu/drm/lima/lima_gp.h @@ -7,6 +7,8 @@ struct lima_ip; struct lima_device; +int lima_gp_resume(struct lima_ip *ip); +void lima_gp_suspend(struct lima_ip *ip); int lima_gp_init(struct lima_ip *ip); void lima_gp_fini(struct lima_ip *ip); diff --git a/drivers/gpu/drm/lima/lima_l2_cache.c b/drivers/gpu/drm/lima/lima_l2_cache.c index 6873a7af5a5c..c4080a02957b 100644 --- a/drivers/gpu/drm/lima/lima_l2_cache.c +++ b/drivers/gpu/drm/lima/lima_l2_cache.c @@ -38,9 +38,35 @@ int lima_l2_cache_flush(struct lima_ip *ip) return ret; } +static int lima_l2_cache_hw_init(struct lima_ip *ip) +{ + int err; + + err = lima_l2_cache_flush(ip); + if (err) + return err; + + l2_cache_write(LIMA_L2_CACHE_ENABLE, + LIMA_L2_CACHE_ENABLE_ACCESS | + LIMA_L2_CACHE_ENABLE_READ_ALLOCATE); + l2_cache_write(LIMA_L2_CACHE_MAX_READS, 0x1c); + + return 0; +} + +int lima_l2_cache_resume(struct lima_ip *ip) +{ + return lima_l2_cache_hw_init(ip); +} + +void lima_l2_cache_suspend(struct lima_ip *ip) +{ + +} + int lima_l2_cache_init(struct lima_ip *ip) { - int i, err; + int i; u32 size; struct lima_device *dev = ip->dev; @@ -63,15 +89,7 @@ int lima_l2_cache_init(struct lima_ip *ip) 1 << (size & 0xff), 1 << ((size >> 24) & 0xff)); - err = lima_l2_cache_flush(ip); - if (err) - return err; - - l2_cache_write(LIMA_L2_CACHE_ENABLE, - LIMA_L2_CACHE_ENABLE_ACCESS|LIMA_L2_CACHE_ENABLE_READ_ALLOCATE); - l2_cache_write(LIMA_L2_CACHE_MAX_READS, 0x1c); - - return 0; + return lima_l2_cache_hw_init(ip); } void lima_l2_cache_fini(struct lima_ip *ip) diff --git a/drivers/gpu/drm/lima/lima_l2_cache.h b/drivers/gpu/drm/lima/lima_l2_cache.h index c63fb676ff14..1aeeefd53fb9 100644 --- a/drivers/gpu/drm/lima/lima_l2_cache.h +++ b/drivers/gpu/drm/lima/lima_l2_cache.h @@ -6,6 +6,8 @@ struct lima_ip; +int lima_l2_cache_resume(struct lima_ip *ip); +void lima_l2_cache_suspend(struct lima_ip *ip); int lima_l2_cache_init(struct lima_ip *ip); void lima_l2_cache_fini(struct lima_ip *ip); diff --git a/drivers/gpu/drm/lima/lima_mmu.c b/drivers/gpu/drm/lima/lima_mmu.c index f79d2af427e7..a1ae6c252dc2 100644 --- a/drivers/gpu/drm/lima/lima_mmu.c +++ b/drivers/gpu/drm/lima/lima_mmu.c @@ -59,12 +59,44 @@ static irqreturn_t lima_mmu_irq_handler(int irq, void *data) return IRQ_HANDLED; } -int lima_mmu_init(struct lima_ip *ip) +static int lima_mmu_hw_init(struct lima_ip *ip) { struct lima_device *dev = ip->dev; int err; u32 v; + mmu_write(LIMA_MMU_COMMAND, LIMA_MMU_COMMAND_HARD_RESET); + err = lima_mmu_send_command(LIMA_MMU_COMMAND_HARD_RESET, + LIMA_MMU_DTE_ADDR, v, v == 0); + if (err) + return err; + + mmu_write(LIMA_MMU_INT_MASK, + LIMA_MMU_INT_PAGE_FAULT | LIMA_MMU_INT_READ_BUS_ERROR); + mmu_write(LIMA_MMU_DTE_ADDR, dev->empty_vm->pd.dma); + return lima_mmu_send_command(LIMA_MMU_COMMAND_ENABLE_PAGING, + LIMA_MMU_STATUS, v, + v & LIMA_MMU_STATUS_PAGING_ENABLED); +} + +int lima_mmu_resume(struct lima_ip *ip) +{ + if (ip->id == lima_ip_ppmmu_bcast) + return 0; + + return lima_mmu_hw_init(ip); +} + +void lima_mmu_suspend(struct lima_ip *ip) +{ + +} + +int lima_mmu_init(struct lima_ip *ip) +{ + struct lima_device *dev = ip->dev; + int err; + if (ip->id == lima_ip_ppmmu_bcast) return 0; @@ -74,12 +106,6 @@ int lima_mmu_init(struct lima_ip *ip) return -EIO; } - mmu_write(LIMA_MMU_COMMAND, LIMA_MMU_COMMAND_HARD_RESET); - err = lima_mmu_send_command(LIMA_MMU_COMMAND_HARD_RESET, - LIMA_MMU_DTE_ADDR, v, v == 0); - if (err) - return err; - err = devm_request_irq(dev->dev, ip->irq, lima_mmu_irq_handler, IRQF_SHARED, lima_ip_name(ip), ip); if (err) { @@ -87,11 +113,7 @@ int lima_mmu_init(struct lima_ip *ip) return err; } - mmu_write(LIMA_MMU_INT_MASK, LIMA_MMU_INT_PAGE_FAULT | LIMA_MMU_INT_READ_BUS_ERROR); - mmu_write(LIMA_MMU_DTE_ADDR, dev->empty_vm->pd.dma); - return lima_mmu_send_command(LIMA_MMU_COMMAND_ENABLE_PAGING, - LIMA_MMU_STATUS, v, - v & LIMA_MMU_STATUS_PAGING_ENABLED); + return lima_mmu_hw_init(ip); } void lima_mmu_fini(struct lima_ip *ip) @@ -113,8 +135,7 @@ void lima_mmu_switch_vm(struct lima_ip *ip, struct lima_vm *vm) LIMA_MMU_STATUS, v, v & LIMA_MMU_STATUS_STALL_ACTIVE); - if (vm) - mmu_write(LIMA_MMU_DTE_ADDR, vm->pd.dma); + mmu_write(LIMA_MMU_DTE_ADDR, vm->pd.dma); /* flush the TLB */ mmu_write(LIMA_MMU_COMMAND, LIMA_MMU_COMMAND_ZAP_CACHE); diff --git a/drivers/gpu/drm/lima/lima_mmu.h b/drivers/gpu/drm/lima/lima_mmu.h index 4f8ccbebcba1..f0c97ac75ea0 100644 --- a/drivers/gpu/drm/lima/lima_mmu.h +++ b/drivers/gpu/drm/lima/lima_mmu.h @@ -7,6 +7,8 @@ struct lima_ip; struct lima_vm; +int lima_mmu_resume(struct lima_ip *ip); +void lima_mmu_suspend(struct lima_ip *ip); int lima_mmu_init(struct lima_ip *ip); void lima_mmu_fini(struct lima_ip *ip); diff --git a/drivers/gpu/drm/lima/lima_pmu.c b/drivers/gpu/drm/lima/lima_pmu.c index 571f6d661581..e397e1146e96 100644 --- a/drivers/gpu/drm/lima/lima_pmu.c +++ b/drivers/gpu/drm/lima/lima_pmu.c @@ -21,7 +21,7 @@ static int lima_pmu_wait_cmd(struct lima_ip *ip) v, v & LIMA_PMU_INT_CMD_MASK, 100, 100000); if (err) { - dev_err(dev->dev, "timeout wait pmd cmd\n"); + dev_err(dev->dev, "timeout wait pmu cmd\n"); return err; } @@ -29,7 +29,41 @@ static int lima_pmu_wait_cmd(struct lima_ip *ip) return 0; } -int lima_pmu_init(struct lima_ip *ip) +static u32 lima_pmu_get_ip_mask(struct lima_ip *ip) +{ + struct lima_device *dev = ip->dev; + u32 ret = 0; + int i; + + ret |= LIMA_PMU_POWER_GP0_MASK; + + if (dev->id == lima_gpu_mali400) { + ret |= LIMA_PMU_POWER_L2_MASK; + for (i = 0; i < 4; i++) { + if (dev->ip[lima_ip_pp0 + i].present) + ret |= LIMA_PMU_POWER_PP_MASK(i); + } + } else { + if (dev->ip[lima_ip_pp0].present) + ret |= LIMA450_PMU_POWER_PP0_MASK; + for (i = lima_ip_pp1; i <= lima_ip_pp3; i++) { + if (dev->ip[i].present) { + ret |= LIMA450_PMU_POWER_PP13_MASK; + break; + } + } + for (i = lima_ip_pp4; i <= lima_ip_pp7; i++) { + if (dev->ip[i].present) { + ret |= LIMA450_PMU_POWER_PP47_MASK; + break; + } + } + } + + return ret; +} + +static int lima_pmu_hw_init(struct lima_ip *ip) { int err; u32 stat; @@ -54,7 +88,44 @@ int lima_pmu_init(struct lima_ip *ip) return 0; } +static void lima_pmu_hw_fini(struct lima_ip *ip) +{ + u32 stat; + + if (!ip->data.mask) + ip->data.mask = lima_pmu_get_ip_mask(ip); + + stat = ~pmu_read(LIMA_PMU_STATUS) & ip->data.mask; + if (stat) { + pmu_write(LIMA_PMU_POWER_DOWN, stat); + + /* Don't wait for interrupt on Mali400 if all domains are + * powered off because the HW won't generate an interrupt + * in this case. + */ + if (ip->dev->id == lima_gpu_mali400) + pmu_write(LIMA_PMU_INT_CLEAR, LIMA_PMU_INT_CMD_MASK); + else + lima_pmu_wait_cmd(ip); + } +} + +int lima_pmu_resume(struct lima_ip *ip) +{ + return lima_pmu_hw_init(ip); +} + +void lima_pmu_suspend(struct lima_ip *ip) +{ + lima_pmu_hw_fini(ip); +} + +int lima_pmu_init(struct lima_ip *ip) +{ + return lima_pmu_hw_init(ip); +} + void lima_pmu_fini(struct lima_ip *ip) { - + lima_pmu_hw_fini(ip); } diff --git a/drivers/gpu/drm/lima/lima_pmu.h b/drivers/gpu/drm/lima/lima_pmu.h index a2a18775eb07..652dc7af3047 100644 --- a/drivers/gpu/drm/lima/lima_pmu.h +++ b/drivers/gpu/drm/lima/lima_pmu.h @@ -6,6 +6,8 @@ struct lima_ip; +int lima_pmu_resume(struct lima_ip *ip); +void lima_pmu_suspend(struct lima_ip *ip); int lima_pmu_init(struct lima_ip *ip); void lima_pmu_fini(struct lima_ip *ip); diff --git a/drivers/gpu/drm/lima/lima_pp.c b/drivers/gpu/drm/lima/lima_pp.c index 8fef224b93c8..33f01383409c 100644 --- a/drivers/gpu/drm/lima/lima_pp.c +++ b/drivers/gpu/drm/lima/lima_pp.c @@ -223,6 +223,23 @@ static void lima_pp_print_version(struct lima_ip *ip) lima_ip_name(ip), name, major, minor); } +static int lima_pp_hw_init(struct lima_ip *ip) +{ + ip->data.async_reset = false; + lima_pp_soft_reset_async(ip); + return lima_pp_soft_reset_async_wait(ip); +} + +int lima_pp_resume(struct lima_ip *ip) +{ + return lima_pp_hw_init(ip); +} + +void lima_pp_suspend(struct lima_ip *ip) +{ + +} + int lima_pp_init(struct lima_ip *ip) { struct lima_device *dev = ip->dev; @@ -230,9 +247,7 @@ int lima_pp_init(struct lima_ip *ip) lima_pp_print_version(ip); - ip->data.async_reset = false; - lima_pp_soft_reset_async(ip); - err = lima_pp_soft_reset_async_wait(ip); + err = lima_pp_hw_init(ip); if (err) return err; @@ -254,6 +269,16 @@ void lima_pp_fini(struct lima_ip *ip) } +int lima_pp_bcast_resume(struct lima_ip *ip) +{ + return 0; +} + +void lima_pp_bcast_suspend(struct lima_ip *ip) +{ + +} + int lima_pp_bcast_init(struct lima_ip *ip) { struct lima_device *dev = ip->dev; diff --git a/drivers/gpu/drm/lima/lima_pp.h b/drivers/gpu/drm/lima/lima_pp.h index bf60c77b2633..16ec96de15a9 100644 --- a/drivers/gpu/drm/lima/lima_pp.h +++ b/drivers/gpu/drm/lima/lima_pp.h @@ -7,9 +7,13 @@ struct lima_ip; struct lima_device; +int lima_pp_resume(struct lima_ip *ip); +void lima_pp_suspend(struct lima_ip *ip); int lima_pp_init(struct lima_ip *ip); void lima_pp_fini(struct lima_ip *ip); +int lima_pp_bcast_resume(struct lima_ip *ip); +void lima_pp_bcast_suspend(struct lima_ip *ip); int lima_pp_bcast_init(struct lima_ip *ip); void lima_pp_bcast_fini(struct lima_ip *ip); diff --git a/drivers/gpu/drm/lima/lima_sched.c b/drivers/gpu/drm/lima/lima_sched.c index a2db1c937424..e6cefda00279 100644 --- a/drivers/gpu/drm/lima/lima_sched.c +++ b/drivers/gpu/drm/lima/lima_sched.c @@ -4,6 +4,7 @@ #include #include #include +#include #include "lima_devfreq.h" #include "lima_drv.h" @@ -194,14 +195,36 @@ static struct dma_fence *lima_sched_dependency(struct drm_sched_job *job, return NULL; } +static int lima_pm_busy(struct lima_device *ldev) +{ + int ret; + + /* resume GPU if it has been suspended by runtime PM */ + ret = pm_runtime_get_sync(ldev->dev); + if (ret < 0) + return ret; + + lima_devfreq_record_busy(&ldev->devfreq); + return 0; +} + +static void lima_pm_idle(struct lima_device *ldev) +{ + lima_devfreq_record_idle(&ldev->devfreq); + + /* GPU can do auto runtime suspend */ + pm_runtime_mark_last_busy(ldev->dev); + pm_runtime_put_autosuspend(ldev->dev); +} + static struct dma_fence *lima_sched_run_job(struct drm_sched_job *job) { struct lima_sched_task *task = to_lima_task(job); struct lima_sched_pipe *pipe = to_lima_pipe(job->sched); + struct lima_device *ldev = pipe->ldev; struct lima_fence *fence; struct dma_fence *ret; - struct lima_vm *vm = NULL, *last_vm = NULL; - int i; + int i, err; /* after GPU reset */ if (job->s_fence->finished.error < 0) @@ -210,6 +233,13 @@ static struct dma_fence *lima_sched_run_job(struct drm_sched_job *job) fence = lima_fence_create(pipe); if (!fence) return NULL; + + err = lima_pm_busy(ldev); + if (err < 0) { + dma_fence_put(&fence->base); + return NULL; + } + task->fence = &fence->base; /* for caller usage of the fence, otherwise irq handler @@ -217,8 +247,6 @@ static struct dma_fence *lima_sched_run_job(struct drm_sched_job *job) */ ret = dma_fence_get(task->fence); - lima_devfreq_record_busy(&pipe->ldev->devfreq); - pipe->current_task = task; /* this is needed for MMU to work correctly, otherwise GP/PP @@ -239,22 +267,16 @@ static struct dma_fence *lima_sched_run_job(struct drm_sched_job *job) for (i = 0; i < pipe->num_l2_cache; i++) lima_l2_cache_flush(pipe->l2_cache[i]); - if (task->vm != pipe->current_vm) { - vm = lima_vm_get(task->vm); - last_vm = pipe->current_vm; - pipe->current_vm = task->vm; - } + lima_vm_put(pipe->current_vm); + pipe->current_vm = lima_vm_get(task->vm); if (pipe->bcast_mmu) - lima_mmu_switch_vm(pipe->bcast_mmu, vm); + lima_mmu_switch_vm(pipe->bcast_mmu, pipe->current_vm); else { for (i = 0; i < pipe->num_mmu; i++) - lima_mmu_switch_vm(pipe->mmu[i], vm); + lima_mmu_switch_vm(pipe->mmu[i], pipe->current_vm); } - if (last_vm) - lima_vm_put(last_vm); - trace_lima_task_run(task); pipe->error = false; @@ -285,7 +307,8 @@ static void lima_sched_build_error_task_list(struct lima_sched_task *task) mutex_lock(&dev->error_task_list_lock); if (dev->dump.num_tasks >= lima_max_error_tasks) { - dev_info(dev->dev, "fail to save task state: error task list is full\n"); + dev_info(dev->dev, "fail to save task state from %s pid %d: " + "error task list is full\n", ctx->pname, ctx->pid); goto out; } @@ -394,6 +417,7 @@ static void lima_sched_timedout_job(struct drm_sched_job *job) { struct lima_sched_pipe *pipe = to_lima_pipe(job->sched); struct lima_sched_task *task = to_lima_task(job); + struct lima_device *ldev = pipe->ldev; if (!pipe->error) DRM_ERROR("lima job timeout\n"); @@ -415,13 +439,11 @@ static void lima_sched_timedout_job(struct drm_sched_job *job) lima_mmu_page_fault_resume(pipe->mmu[i]); } - if (pipe->current_vm) - lima_vm_put(pipe->current_vm); - + lima_vm_put(pipe->current_vm); pipe->current_vm = NULL; pipe->current_task = NULL; - lima_devfreq_record_idle(&pipe->ldev->devfreq); + lima_pm_idle(ldev); drm_sched_resubmit_jobs(&pipe->base); drm_sched_start(&pipe->base, true); @@ -493,6 +515,7 @@ void lima_sched_pipe_fini(struct lima_sched_pipe *pipe) void lima_sched_pipe_task_done(struct lima_sched_pipe *pipe) { struct lima_sched_task *task = pipe->current_task; + struct lima_device *ldev = pipe->ldev; if (pipe->error) { if (task && task->recoverable) @@ -503,6 +526,6 @@ void lima_sched_pipe_task_done(struct lima_sched_pipe *pipe) pipe->task_fini(pipe); dma_fence_signal(task->fence); - lima_devfreq_record_idle(&pipe->ldev->devfreq); + lima_pm_idle(ldev); } } diff --git a/drivers/gpu/drm/lima/lima_vm.h b/drivers/gpu/drm/lima/lima_vm.h index 22aeec77d84d..3a7c74822d8b 100644 --- a/drivers/gpu/drm/lima/lima_vm.h +++ b/drivers/gpu/drm/lima/lima_vm.h @@ -54,7 +54,8 @@ static inline struct lima_vm *lima_vm_get(struct lima_vm *vm) static inline void lima_vm_put(struct lima_vm *vm) { - kref_put(&vm->refcount, lima_vm_release); + if (vm) + kref_put(&vm->refcount, lima_vm_release); } void lima_vm_print(struct lima_vm *vm); diff --git a/drivers/gpu/drm/mcde/mcde_display.c b/drivers/gpu/drm/mcde/mcde_display.c index e59907e68854..04e1d38d41f7 100644 --- a/drivers/gpu/drm/mcde/mcde_display.c +++ b/drivers/gpu/drm/mcde/mcde_display.c @@ -948,7 +948,7 @@ static void mcde_display_disable(struct drm_simple_display_pipe *pipe) { struct drm_crtc *crtc = &pipe->crtc; struct drm_device *drm = crtc->dev; - struct mcde *mcde = drm->dev_private; + struct mcde *mcde = to_mcde(drm); struct drm_pending_vblank_event *event; drm_crtc_vblank_off(crtc); @@ -1020,7 +1020,7 @@ static void mcde_display_update(struct drm_simple_display_pipe *pipe, { struct drm_crtc *crtc = &pipe->crtc; struct drm_device *drm = crtc->dev; - struct mcde *mcde = drm->dev_private; + struct mcde *mcde = to_mcde(drm); struct drm_pending_vblank_event *event = crtc->state->event; struct drm_plane *plane = &pipe->plane; struct drm_plane_state *pstate = plane->state; @@ -1078,7 +1078,7 @@ static int mcde_display_enable_vblank(struct drm_simple_display_pipe *pipe) { struct drm_crtc *crtc = &pipe->crtc; struct drm_device *drm = crtc->dev; - struct mcde *mcde = drm->dev_private; + struct mcde *mcde = to_mcde(drm); u32 val; /* Enable all VBLANK IRQs */ @@ -1097,7 +1097,7 @@ static void mcde_display_disable_vblank(struct drm_simple_display_pipe *pipe) { struct drm_crtc *crtc = &pipe->crtc; struct drm_device *drm = crtc->dev; - struct mcde *mcde = drm->dev_private; + struct mcde *mcde = to_mcde(drm); /* Disable all VBLANK IRQs */ writel(0, mcde->regs + MCDE_IMSCPP); @@ -1117,7 +1117,7 @@ static struct drm_simple_display_pipe_funcs mcde_display_funcs = { int mcde_display_init(struct drm_device *drm) { - struct mcde *mcde = drm->dev_private; + struct mcde *mcde = to_mcde(drm); int ret; static const u32 formats[] = { DRM_FORMAT_ARGB8888, diff --git a/drivers/gpu/drm/mcde/mcde_drm.h b/drivers/gpu/drm/mcde/mcde_drm.h index 80edd6628979..679c2c4e6d9d 100644 --- a/drivers/gpu/drm/mcde/mcde_drm.h +++ b/drivers/gpu/drm/mcde/mcde_drm.h @@ -34,6 +34,8 @@ struct mcde { struct regulator *vana; }; +#define to_mcde(dev) container_of(dev, struct mcde, drm) + bool mcde_dsi_irq(struct mipi_dsi_device *mdsi); void mcde_dsi_te_request(struct mipi_dsi_device *mdsi); extern struct platform_driver mcde_dsi_driver; diff --git a/drivers/gpu/drm/mcde/mcde_drv.c b/drivers/gpu/drm/mcde/mcde_drv.c index 88cc6b4a7a64..84f3e2dbd77b 100644 --- a/drivers/gpu/drm/mcde/mcde_drv.c +++ b/drivers/gpu/drm/mcde/mcde_drv.c @@ -164,7 +164,7 @@ static irqreturn_t mcde_irq(int irq, void *data) static int mcde_modeset_init(struct drm_device *drm) { struct drm_mode_config *mode_config; - struct mcde *mcde = drm->dev_private; + struct mcde *mcde = to_mcde(drm); int ret; if (!mcde->bridge) { @@ -307,24 +307,15 @@ static int mcde_probe(struct platform_device *pdev) int ret; int i; - mcde = kzalloc(sizeof(*mcde), GFP_KERNEL); - if (!mcde) - return -ENOMEM; - mcde->dev = dev; - - ret = devm_drm_dev_init(dev, &mcde->drm, &mcde_drm_driver); - if (ret) { - kfree(mcde); - return ret; - } + mcde = devm_drm_dev_alloc(dev, &mcde_drm_driver, struct mcde, drm); + if (IS_ERR(mcde)) + return PTR_ERR(mcde); drm = &mcde->drm; - drm->dev_private = mcde; - drmm_add_final_kfree(drm, mcde); + mcde->dev = dev; platform_set_drvdata(pdev, drm); /* Enable continuous updates: this is what Linux' framebuffer expects */ mcde->oneshot_mode = false; - drm->dev_private = mcde; /* First obtain and turn on the main power */ mcde->epod = devm_regulator_get(dev, "epod"); @@ -494,7 +485,7 @@ regulator_epod_off: static int mcde_remove(struct platform_device *pdev) { struct drm_device *drm = platform_get_drvdata(pdev); - struct mcde *mcde = drm->dev_private; + struct mcde *mcde = to_mcde(drm); component_master_del(&pdev->dev, &mcde_drm_comp_ops); clk_disable_unprepare(mcde->mcde_clk); diff --git a/drivers/gpu/drm/mcde/mcde_dsi.c b/drivers/gpu/drm/mcde/mcde_dsi.c index 7af5ebb0c436..1baa2324cdb9 100644 --- a/drivers/gpu/drm/mcde/mcde_dsi.c +++ b/drivers/gpu/drm/mcde/mcde_dsi.c @@ -1020,7 +1020,7 @@ static int mcde_dsi_bind(struct device *dev, struct device *master, void *data) { struct drm_device *drm = data; - struct mcde *mcde = drm->dev_private; + struct mcde *mcde = to_mcde(drm); struct mcde_dsi *d = dev_get_drvdata(dev); struct device_node *child; struct drm_panel *panel = NULL; diff --git a/drivers/gpu/drm/meson/meson_drv.c b/drivers/gpu/drm/meson/meson_drv.c index 6f29fab79952..621f6de0f076 100644 --- a/drivers/gpu/drm/meson/meson_drv.c +++ b/drivers/gpu/drm/meson/meson_drv.c @@ -11,6 +11,7 @@ #include #include #include +#include #include #include @@ -183,6 +184,24 @@ static void meson_remove_framebuffers(void) kfree(ap); } +struct meson_drm_soc_attr { + struct meson_drm_soc_limits limits; + const struct soc_device_attribute *attrs; +}; + +static const struct meson_drm_soc_attr meson_drm_soc_attrs[] = { + /* S805X/S805Y HDMI PLL won't lock for HDMI PHY freq > 1,65GHz */ + { + .limits = { + .max_hdmi_phy_freq = 1650000, + }, + .attrs = (const struct soc_device_attribute []) { + { .soc_id = "GXL (S805*)", }, + { /* sentinel */ }, + } + }, +}; + static int meson_drv_bind_master(struct device *dev, bool has_components) { struct platform_device *pdev = to_platform_device(dev); @@ -191,7 +210,7 @@ static int meson_drv_bind_master(struct device *dev, bool has_components) struct drm_device *drm; struct resource *res; void __iomem *regs; - int ret; + int ret, i; /* Checks if an output connector is available */ if (!meson_vpu_has_available_connectors(dev)) { @@ -281,6 +300,14 @@ static int meson_drv_bind_master(struct device *dev, bool has_components) if (ret) goto free_drm; + /* Assign limits per soc revision/package */ + for (i = 0 ; i < ARRAY_SIZE(meson_drm_soc_attrs) ; ++i) { + if (soc_device_match(meson_drm_soc_attrs[i].attrs)) { + priv->limits = &meson_drm_soc_attrs[i].limits; + break; + } + } + /* Remove early framebuffers (ie. simplefb) */ meson_remove_framebuffers(); diff --git a/drivers/gpu/drm/meson/meson_drv.h b/drivers/gpu/drm/meson/meson_drv.h index 04fdf3826643..5b23704a80d6 100644 --- a/drivers/gpu/drm/meson/meson_drv.h +++ b/drivers/gpu/drm/meson/meson_drv.h @@ -30,6 +30,10 @@ struct meson_drm_match_data { struct meson_afbcd_ops *afbcd_ops; }; +struct meson_drm_soc_limits { + unsigned int max_hdmi_phy_freq; +}; + struct meson_drm { struct device *dev; enum vpu_compatible compat; @@ -48,6 +52,8 @@ struct meson_drm { struct drm_plane *primary_plane; struct drm_plane *overlay_plane; + const struct meson_drm_soc_limits *limits; + /* Components Data */ struct { bool osd1_enabled; diff --git a/drivers/gpu/drm/meson/meson_dw_hdmi.c b/drivers/gpu/drm/meson/meson_dw_hdmi.c index e8c94915a4fc..5be963e9db05 100644 --- a/drivers/gpu/drm/meson/meson_dw_hdmi.c +++ b/drivers/gpu/drm/meson/meson_dw_hdmi.c @@ -695,7 +695,7 @@ dw_hdmi_mode_valid(struct drm_connector *connector, dev_dbg(connector->dev->dev, "%s: vclk:%d phy=%d venc=%d hdmi=%d\n", __func__, phy_freq, vclk_freq, venc_freq, hdmi_freq); - return meson_vclk_vic_supported_freq(phy_freq, vclk_freq); + return meson_vclk_vic_supported_freq(priv, phy_freq, vclk_freq); } /* Encoder */ diff --git a/drivers/gpu/drm/meson/meson_plane.c b/drivers/gpu/drm/meson/meson_plane.c index d5cbc47835bf..35338ed18209 100644 --- a/drivers/gpu/drm/meson/meson_plane.c +++ b/drivers/gpu/drm/meson/meson_plane.c @@ -223,7 +223,7 @@ static void meson_plane_atomic_update(struct drm_plane *plane, priv->viu.osd1_blk0_cfg[0] |= OSD_BLK_MODE_16 | OSD_COLOR_MATRIX_16_RGB565; break; - }; + } } switch (fb->format->format) { diff --git a/drivers/gpu/drm/meson/meson_vclk.c b/drivers/gpu/drm/meson/meson_vclk.c index fdf26dac9fa8..0eb86943a358 100644 --- a/drivers/gpu/drm/meson/meson_vclk.c +++ b/drivers/gpu/drm/meson/meson_vclk.c @@ -725,6 +725,13 @@ meson_vclk_dmt_supported_freq(struct meson_drm *priv, unsigned int freq) /* In DMT mode, path after PLL is always /10 */ freq *= 10; + /* Check against soc revision/package limits */ + if (priv->limits) { + if (priv->limits->max_hdmi_phy_freq && + freq > priv->limits->max_hdmi_phy_freq) + return MODE_CLOCK_HIGH; + } + if (meson_hdmi_pll_find_params(priv, freq, &m, &frac, &od)) return MODE_OK; @@ -762,7 +769,7 @@ static void meson_hdmi_pll_generic_set(struct meson_drm *priv, } enum drm_mode_status -meson_vclk_vic_supported_freq(unsigned int phy_freq, +meson_vclk_vic_supported_freq(struct meson_drm *priv, unsigned int phy_freq, unsigned int vclk_freq) { int i; @@ -770,6 +777,13 @@ meson_vclk_vic_supported_freq(unsigned int phy_freq, DRM_DEBUG_DRIVER("phy_freq = %d vclk_freq = %d\n", phy_freq, vclk_freq); + /* Check against soc revision/package limits */ + if (priv->limits) { + if (priv->limits->max_hdmi_phy_freq && + phy_freq > priv->limits->max_hdmi_phy_freq) + return MODE_CLOCK_HIGH; + } + for (i = 0 ; params[i].pixel_freq ; ++i) { DRM_DEBUG_DRIVER("i = %d pixel_freq = %d alt = %d\n", i, params[i].pixel_freq, diff --git a/drivers/gpu/drm/meson/meson_vclk.h b/drivers/gpu/drm/meson/meson_vclk.h index aed0ab2efa71..60617aaf18dd 100644 --- a/drivers/gpu/drm/meson/meson_vclk.h +++ b/drivers/gpu/drm/meson/meson_vclk.h @@ -25,7 +25,8 @@ enum { enum drm_mode_status meson_vclk_dmt_supported_freq(struct meson_drm *priv, unsigned int freq); enum drm_mode_status -meson_vclk_vic_supported_freq(unsigned int phy_freq, unsigned int vclk_freq); +meson_vclk_vic_supported_freq(struct meson_drm *priv, unsigned int phy_freq, + unsigned int vclk_freq); void meson_vclk_setup(struct meson_drm *priv, unsigned int target, unsigned int phy_freq, unsigned int vclk_freq, diff --git a/drivers/gpu/drm/omapdrm/dss/dispc.c b/drivers/gpu/drm/omapdrm/dss/dispc.c index dbb90f2d2ccd..6639ee9b05d3 100644 --- a/drivers/gpu/drm/omapdrm/dss/dispc.c +++ b/drivers/gpu/drm/omapdrm/dss/dispc.c @@ -3137,33 +3137,12 @@ static void _dispc_mgr_set_lcd_timings(struct dispc_device *dispc, dispc_write_reg(dispc, DISPC_TIMING_H(channel), timing_h); dispc_write_reg(dispc, DISPC_TIMING_V(channel), timing_v); - if (vm->flags & DISPLAY_FLAGS_VSYNC_HIGH) - vs = false; - else - vs = true; - - if (vm->flags & DISPLAY_FLAGS_HSYNC_HIGH) - hs = false; - else - hs = true; - - if (vm->flags & DISPLAY_FLAGS_DE_HIGH) - de = false; - else - de = true; - - if (vm->flags & DISPLAY_FLAGS_PIXDATA_POSEDGE) - ipc = false; - else - ipc = true; - - /* always use the 'rf' setting */ - onoff = true; - - if (vm->flags & DISPLAY_FLAGS_SYNC_POSEDGE) - rf = true; - else - rf = false; + vs = !!(vm->flags & DISPLAY_FLAGS_VSYNC_LOW); + hs = !!(vm->flags & DISPLAY_FLAGS_HSYNC_LOW); + de = !!(vm->flags & DISPLAY_FLAGS_DE_LOW); + ipc = !!(vm->flags & DISPLAY_FLAGS_PIXDATA_NEGEDGE); + onoff = true; /* always use the 'rf' setting */ + rf = !!(vm->flags & DISPLAY_FLAGS_SYNC_POSEDGE); l = FLD_VAL(onoff, 17, 17) | FLD_VAL(rf, 16, 16) | diff --git a/drivers/gpu/drm/omapdrm/dss/venc.c b/drivers/gpu/drm/omapdrm/dss/venc.c index 766553bb2f87..9701843ccf09 100644 --- a/drivers/gpu/drm/omapdrm/dss/venc.c +++ b/drivers/gpu/drm/omapdrm/dss/venc.c @@ -208,49 +208,6 @@ static const struct venc_config venc_config_ntsc_trm = { .gen_ctrl = 0x00F90000, }; -static const struct venc_config venc_config_pal_bdghi = { - .f_control = 0, - .vidout_ctrl = 0, - .sync_ctrl = 0, - .hfltr_ctrl = 0, - .x_color = 0, - .line21 = 0, - .ln_sel = 21, - .htrigger_vtrigger = 0, - .tvdetgp_int_start_stop_x = 0x00140001, - .tvdetgp_int_start_stop_y = 0x00010001, - .gen_ctrl = 0x00FB0000, - - .llen = 864-1, - .flens = 625-1, - .cc_carr_wss_carr = 0x2F7625ED, - .c_phase = 0xDF, - .gain_u = 0x111, - .gain_v = 0x181, - .gain_y = 0x140, - .black_level = 0x3e, - .blank_level = 0x3e, - .m_control = 0<<2 | 1<<1, - .bstamp_wss_data = 0x42, - .s_carr = 0x2a098acb, - .l21__wc_ctl = 0<<13 | 0x16<<8 | 0<<0, - .savid__eavid = 0x06A70108, - .flen__fal = 23<<16 | 624<<0, - .lal__phase_reset = 2<<17 | 310<<0, - .hs_int_start_stop_x = 0x00920358, - .hs_ext_start_stop_x = 0x000F035F, - .vs_int_start_x = 0x1a7<<16, - .vs_int_stop_x__vs_int_start_y = 0x000601A7, - .vs_int_stop_y__vs_ext_start_x = 0x01AF0036, - .vs_ext_stop_x__vs_ext_start_y = 0x27101af, - .vs_ext_stop_y = 0x05, - .avid_start_stop_x = 0x03530082, - .avid_start_stop_y = 0x0270002E, - .fid_int_start_x__fid_int_start_y = 0x0005008A, - .fid_int_offset_y__fid_ext_start_x = 0x002E0138, - .fid_ext_start_y__fid_ext_offset_y = 0x01380005, -}; - enum venc_videomode { VENC_MODE_UNKNOWN, VENC_MODE_PAL, diff --git a/drivers/gpu/drm/panel/Kconfig b/drivers/gpu/drm/panel/Kconfig index d56258b9fcaf..4b6131f5893d 100644 --- a/drivers/gpu/drm/panel/Kconfig +++ b/drivers/gpu/drm/panel/Kconfig @@ -444,6 +444,14 @@ config DRM_PANEL_TRULY_NT35597_WQXGA Say Y here if you want to enable support for Truly NT35597 WQXGA Dual DSI Video Mode panel +config DRM_PANEL_VISIONOX_RM69299 + tristate "Visionox RM69299" + depends on OF + depends on DRM_MIPI_DSI + help + Say Y here if you want to enable support for Visionox + RM69299 DSI Video Mode panel. + config DRM_PANEL_XINPENG_XPP055C272 tristate "Xinpeng XPP055C272 panel driver" depends on OF diff --git a/drivers/gpu/drm/panel/Makefile b/drivers/gpu/drm/panel/Makefile index 2335a1e32ae0..8eac3e6fa82c 100644 --- a/drivers/gpu/drm/panel/Makefile +++ b/drivers/gpu/drm/panel/Makefile @@ -47,4 +47,5 @@ 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_VISIONOX_RM69299) += panel-visionox-rm69299.o obj-$(CONFIG_DRM_PANEL_XINPENG_XPP055C272) += panel-xinpeng-xpp055c272.o diff --git a/drivers/gpu/drm/panel/panel-boe-tv101wum-nl6.c b/drivers/gpu/drm/panel/panel-boe-tv101wum-nl6.c index f89861c8598a..46fe1805c588 100644 --- a/drivers/gpu/drm/panel/panel-boe-tv101wum-nl6.c +++ b/drivers/gpu/drm/panel/panel-boe-tv101wum-nl6.c @@ -697,15 +697,15 @@ static const struct panel_desc auo_b101uan08_3_desc = { }; static const struct drm_display_mode boe_tv105wum_nw0_default_mode = { - .clock = 159260, + .clock = 159916, .hdisplay = 1200, .hsync_start = 1200 + 80, .hsync_end = 1200 + 80 + 24, .htotal = 1200 + 80 + 24 + 60, .vdisplay = 1920, - .vsync_start = 1920 + 10, - .vsync_end = 1920 + 10 + 2, - .vtotal = 1920 + 10 + 2 + 14, + .vsync_start = 1920 + 20, + .vsync_end = 1920 + 20 + 4, + .vtotal = 1920 + 20 + 4 + 10, .vrefresh = 60, .type = DRM_MODE_TYPE_DRIVER | DRM_MODE_TYPE_PREFERRED, }; diff --git a/drivers/gpu/drm/panel/panel-ilitek-ili9322.c b/drivers/gpu/drm/panel/panel-ilitek-ili9322.c index 09935520e606..873b1c7059bd 100644 --- a/drivers/gpu/drm/panel/panel-ilitek-ili9322.c +++ b/drivers/gpu/drm/panel/panel-ilitek-ili9322.c @@ -379,7 +379,7 @@ static int ili9322_init(struct drm_panel *panel, struct ili9322 *ili) "can't set up VCOM amplitude (%d)\n", ret); return ret; } - }; + } if (ili->vcom_high != U8_MAX) { ret = regmap_write(ili->regmap, ILI9322_VCOM_HIGH, @@ -388,7 +388,7 @@ static int ili9322_init(struct drm_panel *panel, struct ili9322 *ili) dev_err(ili->dev, "can't set up VCOM high (%d)\n", ret); return ret; } - }; + } /* Set up gamma correction */ for (i = 0; i < ARRAY_SIZE(ili->gamma); i++) { diff --git a/drivers/gpu/drm/panel/panel-simple.c b/drivers/gpu/drm/panel/panel-simple.c index 003b54ea90d5..d6c29543e510 100644 --- a/drivers/gpu/drm/panel/panel-simple.c +++ b/drivers/gpu/drm/panel/panel-simple.c @@ -836,7 +836,8 @@ static const struct panel_desc auo_g101evn010 = { .width = 216, .height = 135, }, - .bus_format = MEDIA_BUS_FMT_RGB666_1X18, + .bus_format = MEDIA_BUS_FMT_RGB666_1X7X3_SPWG, + .connector_type = DRM_MODE_CONNECTOR_LVDS, }; static const struct drm_display_mode auo_g104sn02_mode = { @@ -862,6 +863,31 @@ static const struct panel_desc auo_g104sn02 = { }, }; +static const struct drm_display_mode auo_g121ean01_mode = { + .clock = 66700, + .hdisplay = 1280, + .hsync_start = 1280 + 58, + .hsync_end = 1280 + 58 + 8, + .htotal = 1280 + 58 + 8 + 70, + .vdisplay = 800, + .vsync_start = 800 + 6, + .vsync_end = 800 + 6 + 4, + .vtotal = 800 + 6 + 4 + 10, + .vrefresh = 60, +}; + +static const struct panel_desc auo_g121ean01 = { + .modes = &auo_g121ean01_mode, + .num_modes = 1, + .bpc = 8, + .size = { + .width = 261, + .height = 163, + }, + .bus_format = MEDIA_BUS_FMT_RGB888_1X7X4_SPWG, + .connector_type = DRM_MODE_CONNECTOR_LVDS, +}; + static const struct display_timing auo_g133han01_timings = { .pixelclock = { 134000000, 141200000, 149000000 }, .hactive = { 1920, 1920, 1920 }, @@ -892,6 +918,31 @@ static const struct panel_desc auo_g133han01 = { .connector_type = DRM_MODE_CONNECTOR_LVDS, }; +static const struct drm_display_mode auo_g156xtn01_mode = { + .clock = 76000, + .hdisplay = 1366, + .hsync_start = 1366 + 33, + .hsync_end = 1366 + 33 + 67, + .htotal = 1560, + .vdisplay = 768, + .vsync_start = 768 + 4, + .vsync_end = 768 + 4 + 4, + .vtotal = 806, + .vrefresh = 60, +}; + +static const struct panel_desc auo_g156xtn01 = { + .modes = &auo_g156xtn01_mode, + .num_modes = 1, + .bpc = 8, + .size = { + .width = 344, + .height = 194, + }, + .bus_format = MEDIA_BUS_FMT_RGB888_1X7X4_SPWG, + .connector_type = DRM_MODE_CONNECTOR_LVDS, +}; + static const struct display_timing auo_g185han01_timings = { .pixelclock = { 120000000, 144000000, 175000000 }, .hactive = { 1920, 1920, 1920 }, @@ -922,6 +973,36 @@ static const struct panel_desc auo_g185han01 = { .connector_type = DRM_MODE_CONNECTOR_LVDS, }; +static const struct display_timing auo_g190ean01_timings = { + .pixelclock = { 90000000, 108000000, 135000000 }, + .hactive = { 1280, 1280, 1280 }, + .hfront_porch = { 126, 184, 1266 }, + .hback_porch = { 84, 122, 844 }, + .hsync_len = { 70, 102, 704 }, + .vactive = { 1024, 1024, 1024 }, + .vfront_porch = { 4, 26, 76 }, + .vback_porch = { 2, 8, 25 }, + .vsync_len = { 2, 8, 25 }, +}; + +static const struct panel_desc auo_g190ean01 = { + .timings = &auo_g190ean01_timings, + .num_timings = 1, + .bpc = 8, + .size = { + .width = 376, + .height = 301, + }, + .delay = { + .prepare = 50, + .enable = 200, + .disable = 110, + .unprepare = 1000, + }, + .bus_format = MEDIA_BUS_FMT_RGB888_1X7X4_SPWG, + .connector_type = DRM_MODE_CONNECTOR_LVDS, +}; + static const struct display_timing auo_p320hvn03_timings = { .pixelclock = { 106000000, 148500000, 164000000 }, .hactive = { 1920, 1920, 1920 }, @@ -1092,6 +1173,36 @@ static const struct panel_desc boe_nv101wxmn51 = { }, }; +static const struct drm_display_mode boe_nv133fhm_n61_modes = { + .clock = 147840, + .hdisplay = 1920, + .hsync_start = 1920 + 48, + .hsync_end = 1920 + 48 + 32, + .htotal = 1920 + 48 + 32 + 200, + .vdisplay = 1080, + .vsync_start = 1080 + 3, + .vsync_end = 1080 + 3 + 6, + .vtotal = 1080 + 3 + 6 + 31, + .vrefresh = 60, +}; + +static const struct panel_desc boe_nv133fhm_n61 = { + .modes = &boe_nv133fhm_n61_modes, + .num_modes = 1, + .bpc = 8, + .size = { + .width = 300, + .height = 187, + }, + .delay = { + .hpd_absent_delay = 200, + .unprepare = 500, + }, + .bus_format = MEDIA_BUS_FMT_RGB888_1X24, + .bus_flags = DRM_BUS_FLAG_DATA_MSB_TO_LSB, + .connector_type = DRM_MODE_CONNECTOR_eDP, +}; + static const struct drm_display_mode boe_nv140fhmn49_modes[] = { { .clock = 148500, @@ -1980,6 +2091,37 @@ static const struct panel_desc innolux_zj070na_01p = { }, }; +static const struct drm_display_mode ivo_m133nwf4_r0_mode = { + .clock = 138778, + .hdisplay = 1920, + .hsync_start = 1920 + 24, + .hsync_end = 1920 + 24 + 48, + .htotal = 1920 + 24 + 48 + 88, + .vdisplay = 1080, + .vsync_start = 1080 + 3, + .vsync_end = 1080 + 3 + 12, + .vtotal = 1080 + 3 + 12 + 17, + .vrefresh = 60, + .flags = DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC, +}; + +static const struct panel_desc ivo_m133nwf4_r0 = { + .modes = &ivo_m133nwf4_r0_mode, + .num_modes = 1, + .bpc = 8, + .size = { + .width = 294, + .height = 165, + }, + .delay = { + .hpd_absent_delay = 200, + .unprepare = 500, + }, + .bus_format = MEDIA_BUS_FMT_RGB888_1X24, + .bus_flags = DRM_BUS_FLAG_DATA_MSB_TO_LSB, + .connector_type = DRM_MODE_CONNECTOR_eDP, +}; + static const struct display_timing koe_tx14d24vm1bpa_timing = { .pixelclock = { 5580000, 5850000, 6200000 }, .hactive = { 320, 320, 320 }, @@ -2168,6 +2310,7 @@ static const struct panel_desc lg_lp120up1 = { .width = 267, .height = 183, }, + .connector_type = DRM_MODE_CONNECTOR_eDP, }; static const struct drm_display_mode lg_lp129qe_mode = { @@ -3480,12 +3623,21 @@ static const struct of_device_id platform_of_match[] = { }, { .compatible = "auo,g104sn02", .data = &auo_g104sn02, + }, { + .compatible = "auo,g121ean01", + .data = &auo_g121ean01, }, { .compatible = "auo,g133han01", .data = &auo_g133han01, + }, { + .compatible = "auo,g156xtn01", + .data = &auo_g156xtn01, }, { .compatible = "auo,g185han01", .data = &auo_g185han01, + }, { + .compatible = "auo,g190ean01", + .data = &auo_g190ean01, }, { .compatible = "auo,p320hvn03", .data = &auo_p320hvn03, @@ -3504,6 +3656,9 @@ static const struct of_device_id platform_of_match[] = { }, { .compatible = "boe,nv101wxmn51", .data = &boe_nv101wxmn51, + }, { + .compatible = "boe,nv133fhm-n61", + .data = &boe_nv133fhm_n61, }, { .compatible = "boe,nv140fhmn49", .data = &boe_nv140fhmn49, @@ -3612,6 +3767,9 @@ static const struct of_device_id platform_of_match[] = { }, { .compatible = "innolux,zj070na-01p", .data = &innolux_zj070na_01p, + }, { + .compatible = "ivo,m133nwf4-r0", + .data = &ivo_m133nwf4_r0, }, { .compatible = "koe,tx14d24vm1bpa", .data = &koe_tx14d24vm1bpa, diff --git a/drivers/gpu/drm/panel/panel-truly-nt35597.c b/drivers/gpu/drm/panel/panel-truly-nt35597.c index 012ca62bf30e..f0ad6081570f 100644 --- a/drivers/gpu/drm/panel/panel-truly-nt35597.c +++ b/drivers/gpu/drm/panel/panel-truly-nt35597.c @@ -490,9 +490,7 @@ static int truly_nt35597_panel_add(struct truly_nt35597 *ctx) { struct device *dev = ctx->dev; int ret, i; - const struct nt35597_config *config; - config = ctx->config; for (i = 0; i < ARRAY_SIZE(ctx->supplies); i++) ctx->supplies[i].supply = regulator_names[i]; diff --git a/drivers/gpu/drm/panel/panel-visionox-rm69299.c b/drivers/gpu/drm/panel/panel-visionox-rm69299.c new file mode 100644 index 000000000000..25fe8b0bb040 --- /dev/null +++ b/drivers/gpu/drm/panel/panel-visionox-rm69299.c @@ -0,0 +1,302 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (c) 2019, The Linux Foundation. All rights reserved. + */ + +#include +#include +#include +#include +#include + +#include