drm: Add support for IPK DSI Host Driver
Subsystems (3)
v2 cover drm: Add support for IPK DSI Host Driver
This patch series adds support for the display subsystem in the Synopsys DesignWare IPK devices.
The display pipeline is limited and does not have access to memory, the validation is done using a VPG (Video Pattern Generator), as DPI stimulus for the DW MIPI DSI Host.
A Synopsys DesignWare MIPI DSI Host v1.40 is used in the IPK device, that so far, is fully compatible with the driver dw-mipi-dsi.
To activate the VPG use the sysfs pattern variable, assigning values from 0 (shutdown) to 4. The usage of the VPG and the Synopsys DesignWare MIPI DSI Host internal video generator is mutually exclusive.
The submission of this driver aims to be used as a work base for the submission of enhancements over the Synopsys DesignWare MIPI DSI Host.
Changes in v2:
- Fixed dt-bindings issues, see
https://patchwork.ozlabs.org/patch/1260819/.
Angelo Ribeiro (4):
dt-bindings: display: Add IPK DSI subsystem bindings
drm: ipk: Add DRM driver for DesignWare IPK DSI
drm: ipk: Add extensions for DW MIPI DSI Host driver
MAINTAINERS: Add IPK MIPI DSI Host driver entry
.../bindings/display/snps,dw-ipk-dsi.yaml | 162 ++++++ .../bindings/display/snps,dw-ipk-vpg.yaml | 75 +++ MAINTAINERS | 8 + drivers/gpu/drm/Kconfig | 2 + drivers/gpu/drm/Makefile | 1 + drivers/gpu/drm/ipk/Kconfig | 22 + drivers/gpu/drm/ipk/Makefile | 8 + drivers/gpu/drm/ipk/dw-drv.c | 189 +++++++ drivers/gpu/drm/ipk/dw-ipk.h | 30 ++ drivers/gpu/drm/ipk/dw-mipi-dsi-ipk.c | 556 ++++++++++++++++++++ drivers/gpu/drm/ipk/dw-vpg.c | 559 +++++++++++++++++++++ drivers/gpu/drm/ipk/dw-vpg.h | 55 ++ 12 files changed, 1667 insertions(+) create mode 100644 Documentation/devicetree/bindings/display/snps,dw-ipk-dsi.yaml create mode 100644 Documentation/devicetree/bindings/display/snps,dw-ipk-vpg.yaml create mode 100644 drivers/gpu/drm/ipk/Kconfig create mode 100644 drivers/gpu/drm/ipk/Makefile create mode 100644 drivers/gpu/drm/ipk/dw-drv.c create mode 100644 drivers/gpu/drm/ipk/dw-ipk.h create mode 100644 drivers/gpu/drm/ipk/dw-mipi-dsi-ipk.c create mode 100644 drivers/gpu/drm/ipk/dw-vpg.c create mode 100644 drivers/gpu/drm/ipk/dw-vpg.h
Signature · 1 line
2.7.4
PATCH v2 1/4 dt-bindings: display: Add IPK DSI subsystem bindings
Add dt-bindings for Synopsys DesignWare MIPI DSI Host and VPG (Video Pattern Generator) support in the IPK display subsystem.
The Synopsys DesignWare IPK display video pipeline is composed by a DSI controller (snps,dw-ipk-dsi) and a VPG (snps,dw-ipk-vpg) as DPI stimulus. Typically is used the Raspberry Pi (raspberrypi,7inch-touchscreen-panel) as DSI panel that requires a I2C controller (snps,designware-i2c).
--- .../bindings/display/snps,dw-ipk-dsi.yaml | 162 +++++++++++++++++++++ .../bindings/display/snps,dw-ipk-vpg.yaml | 75 ++++++++++ 2 files changed, 237 insertions(+) create mode 100644 Documentation/devicetree/bindings/display/snps,dw-ipk-dsi.yaml create mode 100644 Documentation/devicetree/bindings/display/snps,dw-ipk-vpg.yaml
Documentation/devicetree/bindings/display/snps,dw-ipk-dsi.yaml new file +162 -0
@@ -0,0 +1,162 @@ +# SPDX-License-Identifier: GPL-2.0 +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/display/snps,dw-ipk-dsi.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Synopsys DesignWare IPK specific extensions for the Synopsys DSI host + controller. + +maintainers: + - Angelo Ribeiro <[email protected]> + +description: + The Synopsys DesignWare IPK DSI controller uses the Synopsys DesignWare MIPI + DSI host controller. + For more info please refer to + Documentation/devicetree/bindings/display/bridge/dw_mipi_dsi.txt. + +properties: + compatible: + const: snps,dw-ipk-dsi + + reg: + minItems: 2 + items: + - description: DW MIPI DSI Host registers + - description: DW Phy registers + + reg-names: + items: + - const: dsi + - const: phy + + clocks: + minItems: 2 + maxItems: 3 + items: + - description: Peripheral clock + - description: PLL clock + - description: Pixel clock + + clock-names: + items: + - const: pclk + - const: ref + - const: px_clk + + resets: + minItems: 1 + items: + - description: APB reset line + + reset-names: + items: + - const: apb + + ports: + type: object + description: + A port node as defined in + Documentation/devicetree/bindings/media/video-interfaces.txt and + Documentation/devicetree/bindings/graph.txt. + properties: + port@0: + type: object + description: + Input endpoint of the controller, connects to a DPI source. + + port@1: + type: object + description: + Output endpoint of the controller, connects to a panel or a bridge + input port. + +patternProperties: + "^(panel|panel-dsi)@[0-9]$": + type: object + description: + A node containing the panel or bridge description as defined in + Documentation/devicetree/bindings/display/mipi-dsi-bus.txt. + properties: + port: + type: object + description: + Panel or bridge port node connected to the DSI output port (port@1). + + "#address-cells": + const: 1 + + "#size-cells": + const: 0 + +required: + - "#address-cells" + - "#size-cells" + - compatible + - reg + - reg-names + - clocks + - clock-names + - reset + - reset-names + - ports + +additionalProperties: false + +examples: + - | + dsi1: dw-ipk-dsi@0x02000 { + compatible = "snps,dw-ipk-dsi"; + reg = <0x02000 0xfff>, <0x05000 0xfff>; + reg-names = "dsi", "phy"; + clocks = <&apb_clk>, <&pll_clk>; + clock-names = "pclk", "ref"; + resets = <&ipk_rst 1>; + reset-names = "apb"; + + #address-cells = <1>; + #size-cells = <0>; + + ports { + #address-cells = <1>; + #size-cells = <0>; + + port@0 { + reg = <0>; + dsi1_in: endpoint@0 { + remote-endpoint = <&vbridge_out>; + }; + }; + + port@1 { + reg = <1>; + dsi_out_port: endpoint { + remote-endpoint = <&panel_dsi_port>; + }; + }; + }; + }; + + i2c@0x01000 { + compatible = "snps,designware-i2c"; + reg = <0x01000 0x100>; + clock-frequency = <400000>; + clocks = <&i2cclk>; + interrupts = <0>; + resets = <&ipk_rst 0>; + reset-names = "i2c"; + + lcd@45 { + compatible = "raspberrypi,7inch-touchscreen-panel"; + reg = <0x45>; + + port { + panel_dsi_port: endpoint { + remote-endpoint = <&dsi_out_port>; + }; + }; + }; + }; + +...
Documentation/devicetree/bindings/display/snps,dw-ipk-vpg.yaml new file +75 -0
75 lines not on this page · raw message
Signature · 1 line
2.7.4
Rob Herring
maintainerRe: [PATCH v2 1/4] dt-bindings: display: Add IPK DSI subsystem bindings
Quoted 17 lines · Angelo Ribeiro
Add dt-bindings for Synopsys DesignWare MIPI DSI Host and VPG (Video Pattern Generator) support in the IPK display subsystem.
The Synopsys DesignWare IPK display video pipeline is composed by a DSI controller (snps,dw-ipk-dsi) and a VPG (snps,dw-ipk-vpg) as DPI stimulus. Typically is used the Raspberry Pi (raspberrypi,7inch-touchscreen-panel) as DSI panel that requires a I2C controller (snps,designware-i2c).
Reported-by Rob Herring <[email protected]>Cc David Airlie <[email protected]>Cc Daniel Vetter <[email protected]>Cc Rob Herring <[email protected]>Cc Mark Rutland <[email protected]>Cc Gustavo Pimentel <[email protected]>Cc Joao Pinto <[email protected]>Signed-off-by Angelo Ribeiro <[email protected]>
Quoted 7 lines
--- .../bindings/display/snps,dw-ipk-dsi.yaml | 162 +++++++++++++++++++++ .../bindings/display/snps,dw-ipk-vpg.yaml | 75 ++++++++++ 2 files changed, 237 insertions(+) create mode 100644 Documentation/devicetree/bindings/display/snps,dw-ipk-dsi.yaml create mode 100644 Documentation/devicetree/bindings/display/snps,dw-ipk-vpg.yaml
My bot found errors running 'make dt_binding_check' on your patch:
Documentation/devicetree/bindings/display/snps,dw-ipk-dsi.example.dts:60.17-30: Warning (reg_format): /example-0/i2c@0x01000/lcd@45:reg: property has invalid length (4 bytes) (#address-cells == 2, #size-cells == 1)Documentation/devicetree/bindings/display/snps,dw-ipk-dsi.example.dt.yaml: Warning (pci_device_bus_num): Failed prerequisite 'reg_format'
Documentation/devicetree/bindings/display/snps,dw-ipk-dsi.example.dts:49.21-68.11: Warning (i2c_bus_bridge): /example-0/i2c@0x01000: incorrect #address-cells for I2C bus
Documentation/devicetree/bindings/display/snps,dw-ipk-dsi.example.dts:49.21-68.11: Warning (i2c_bus_bridge): /example-0/i2c@0x01000: incorrect #size-cells for I2C busDocumentation/devicetree/bindings/display/snps,dw-ipk-dsi.example.dt.yaml: Warning (i2c_bus_reg): Failed prerequisite 'reg_format'Documentation/devicetree/bindings/display/snps,dw-ipk-dsi.example.dt.yaml: Warning (i2c_bus_reg): Failed prerequisite 'i2c_bus_bridge'Documentation/devicetree/bindings/display/snps,dw-ipk-dsi.example.dt.yaml: Warning (spi_bus_reg): Failed prerequisite 'reg_format'
Documentation/devicetree/bindings/display/snps,dw-ipk-dsi.example.dts:58.20-67.15: Warning (avoid_default_addr_size): /example-0/i2c@0x01000/lcd@45: Relying on default #address-cells value
Documentation/devicetree/bindings/display/snps,dw-ipk-dsi.example.dts:58.20-67.15: Warning (avoid_default_addr_size): /example-0/i2c@0x01000/lcd@45: Relying on default #size-cells value
/builds/robherring/linux-dt-review/Documentation/devicetree/bindings/display/snps,dw-ipk-vpg.example.dt.yaml: example-0: 'dw-dsi-vpg@0x03000' does not match any of the regexes: '.*-names$', '.*-supply$', '^#.*-cells$', '^#[a-zA-Z0-9,+\\-._]{0,63}$', '^[a-zA-Z][a-zA-Z0-9,+\\-._]{0,63}$', '^[a-zA-Z][a-zA-Z0-9,+\\-._]{0,63}@[0-9a-fA-F]+(,[0-9a-fA-F]+)*$', '^__.*__$', 'pinctrl-[0-9]+' /builds/robherring/linux-dt-review/Documentation/devicetree/bindings/display/snps,dw-ipk-vpg.example.dt.yaml: dw-dsi-vpg@0x03000: '#address-cells', '#size-cells' do not match any of the regexes: 'pinctrl-[0-9]+'
/builds/robherring/linux-dt-review/Documentation/devicetree/bindings/display/snps,dw-ipk-dsi.example.dt.yaml: example-0: 'dw-ipk-dsi@0x02000', 'i2c@0x01000' do not match any of the regexes: '.*-names$', '.*-supply$', '^#.*-cells$', '^#[a-zA-Z0-9,+\\-._]{0,63}$', '^[a-zA-Z][a-zA-Z0-9,+\\-._]{0,63}$', '^[a-zA-Z][a-zA-Z0-9,+\\-._]{0,63}@[0-9a-fA-F]+(,[0-9a-fA-F]+)*$', '^__.*__$', 'pinctrl-[0-9]+' /builds/robherring/linux-dt-review/Documentation/devicetree/bindings/display/snps,dw-ipk-dsi.example.dt.yaml: dw-ipk-dsi@0x02000: clock-names: ['pclk', 'ref'] is too short
/builds/robherring/linux-dt-review/Documentation/devicetree/bindings/display/snps,dw-ipk-dsi.example.dt.yaml: dw-ipk-dsi@0x02000: 'reset' is a required property
See https://patchwork.ozlabs.org/patch/1266879
If you already ran 'make dt_binding_check' and didn't see the above error(s), then make sure dt-schema is up to date:
pip3 install git+https://github.com/devicetree-org/dt-schema.git@master --upgrade
Please check and re-submit.
_______________________________________________
dri-devel mailing list
[email protected]
https://lists.freedesktop.org/mailman/listinfo/dri-devel
PATCH v2 2/4 drm: ipk: Add DRM driver for DesignWare IPK DSI
In reply to Angelo RibeiroAdd support for Synopsys DesignWare VPG (Video Pattern Generator) and DRM driver for Synopsys DesignWare DSI Host IPK solution.
--- drivers/gpu/drm/Kconfig | 2 + drivers/gpu/drm/Makefile | 1 + drivers/gpu/drm/ipk/Kconfig | 13 + drivers/gpu/drm/ipk/Makefile | 6 + drivers/gpu/drm/ipk/dw-drv.c | 189 +++++++++++++++ drivers/gpu/drm/ipk/dw-ipk.h | 30 +++ drivers/gpu/drm/ipk/dw-vpg.c | 559 +++++++++++++++++++++++++++++++++++++++++++ drivers/gpu/drm/ipk/dw-vpg.h | 55 +++++ 8 files changed, 855 insertions(+) create mode 100644 drivers/gpu/drm/ipk/Kconfig create mode 100644 drivers/gpu/drm/ipk/Makefile create mode 100644 drivers/gpu/drm/ipk/dw-drv.c create mode 100644 drivers/gpu/drm/ipk/dw-ipk.h create mode 100644 drivers/gpu/drm/ipk/dw-vpg.c create mode 100644 drivers/gpu/drm/ipk/dw-vpg.h
drivers/gpu/drm/Kconfig +2 -0
@@ -388,6 +388,8 @@ source "drivers/gpu/drm/mcde/Kconfig" source "drivers/gpu/drm/tidss/Kconfig" +source "drivers/gpu/drm/ipk/Kconfig" + # Keep legacy drivers last menuconfig DRM_LEGACY
drivers/gpu/drm/Makefile +1 -0
@@ -125,3 +125,4 @@ obj-$(CONFIG_DRM_PANFROST) += panfrost/ obj-$(CONFIG_DRM_ASPEED_GFX) += aspeed/ obj-$(CONFIG_DRM_MCDE) += mcde/ obj-$(CONFIG_DRM_TIDSS) += tidss/ +obj-$(CONFIG_DRM_IPK) += ipk/
drivers/gpu/drm/ipk/Kconfig new file +13 -0
@@ -0,0 +1,13 @@ +# SPDX-License-Identifier: GPL-2.0-only +config DRM_IPK + tristate "DRM Support for Synopsys DesignWare IPK DSI" + depends on DRM + select DRM_KMS_HELPER + select DRM_GEM_CMA_HELPER + select DRM_KMS_CMA_HELPER + select DRM_PANEL_BRIDGE + select VIDEOMODE_HELPERS + help + Enable support for the Synopsys DesignWare DRM DSI. + To compile this driver as a module, choose M here: the module + will be called ipk-drm.
drivers/gpu/drm/ipk/Makefile new file +6 -0
@@ -0,0 +1,6 @@ +# SPDX-License-Identifier: GPL-2.0-only +ipk-drm-y := \ + dw-drv.o \ + dw-vpg.o + +obj-$(CONFIG_DRM_IPK) += ipk-drm.o
drivers/gpu/drm/ipk/dw-drv.c new file +189 -0
189 lines not on this page · raw message
drivers/gpu/drm/ipk/dw-ipk.h new file +30 -0
@@ -0,0 +1,30 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* +* Copyright (c) 2019-2020 Synopsys, Inc. and/or its affiliates. +* Synopsys DesignWare MIPI DSI Controller +*/ + +#ifndef _DW_IPK_H +#define _DW_IPK_H + +#include "drm/drm_device.h" +#include <drm/bridge/dw_mipi_dsi.h> + +struct ipk_pipeline { +struct drm_framebuffer *fb; +struct drm_crtc crtc; +struct drm_plane *plane; +struct drm_bridge *bridge; +}; + +struct ipk_device { +struct drm_device drm; +struct platform_device *platform; +struct ipk_pipeline pipeline; +struct vpg_device *vpg; +}; + +#define drm_device_to_ipk_device (target) \ + container_of(target, struct ipk_device, drm) + +#endif /* _DW_IPK_H */
drivers/gpu/drm/ipk/dw-vpg.c new file +559 -0
559 lines not on this page · raw message
drivers/gpu/drm/ipk/dw-vpg.h new file +55 -0
55 lines not on this page · raw message
Signature · 1 line
2.7.4
Re: [PATCH v2 2/4] drm: ipk: Add DRM driver for DesignWare IPK DSI
Quoted 214 lines · Angelo Ribeiro
Add support for Synopsys DesignWare VPG (Video Pattern Generator) and DRM driver for Synopsys DesignWare DSI Host IPK solution.
Cc Maarten Lankhorst <[email protected]>Cc Maxime Ripard <[email protected]>Cc David Airlie <[email protected]>Cc Daniel Vetter <[email protected]>Cc Gustavo Pimentel <[email protected]>Cc Joao Pinto <[email protected]>Signed-off-by Angelo Ribeiro <[email protected]>--- drivers/gpu/drm/Kconfig | 2 + drivers/gpu/drm/Makefile | 1 + drivers/gpu/drm/ipk/Kconfig | 13 + drivers/gpu/drm/ipk/Makefile | 6 + drivers/gpu/drm/ipk/dw-drv.c | 189 +++++++++++++++ drivers/gpu/drm/ipk/dw-ipk.h | 30 +++ drivers/gpu/drm/ipk/dw-vpg.c | 559 +++++++++++++++++++++++++++++++++++++++++++ drivers/gpu/drm/ipk/dw-vpg.h | 55 +++++ 8 files changed, 855 insertions(+) create mode 100644 drivers/gpu/drm/ipk/Kconfig create mode 100644 drivers/gpu/drm/ipk/Makefile create mode 100644 drivers/gpu/drm/ipk/dw-drv.c create mode 100644 drivers/gpu/drm/ipk/dw-ipk.h create mode 100644 drivers/gpu/drm/ipk/dw-vpg.c create mode 100644 drivers/gpu/drm/ipk/dw-vpg.hdrivers/gpu/drm/Kconfig +2
-0@@ -388,6 +388,8 @@ source "drivers/gpu/drm/mcde/Kconfig" source "drivers/gpu/drm/tidss/Kconfig" +source "drivers/gpu/drm/ipk/Kconfig" + # Keep legacy drivers last menuconfig DRM_LEGACYdrivers/gpu/drm/Makefile +1
-0@@ -125,3 +125,4 @@ obj-$(CONFIG_DRM_PANFROST) += panfrost/ obj-$(CONFIG_DRM_ASPEED_GFX) += aspeed/ obj-$(CONFIG_DRM_MCDE) += mcde/ obj-$(CONFIG_DRM_TIDSS) += tidss/ +obj-$(CONFIG_DRM_IPK) += ipk/drivers/gpu/drm/ipk/Kconfig new file +13
-0@@ -0,0 +1,13 @@ +# SPDX-License-Identifier: GPL-2.0-only +config DRM_IPK + tristate "DRM Support for Synopsys DesignWare IPK DSI" + depends on DRM + select DRM_KMS_HELPER + select DRM_GEM_CMA_HELPER + select DRM_KMS_CMA_HELPER + select DRM_PANEL_BRIDGE + select VIDEOMODE_HELPERS + help + Enable support for the Synopsys DesignWare DRM DSI. + To compile this driver as a module, choose M here: the module + will be called ipk-drm.drivers/gpu/drm/ipk/Makefile new file +6
-0@@ -0,0 +1,6 @@ +# SPDX-License-Identifier: GPL-2.0-only +ipk-drm-y := \ + dw-drv.o \ + dw-vpg.o + +obj-$(CONFIG_DRM_IPK) += ipk-drm.odrivers/gpu/drm/ipk/dw-drv.c new file +128
-0@@ -0,0 +1,189 @@ +// SPDX-License-Identifier: GPL-2.0 +/* +* Copyright (c) 2019-2020 Synopsys, Inc. and/or its affiliates. +* Synopsys DesignWare MIPI DSI DRM driver +* +* Author: Angelo Ribeiro <[email protected]> +*/ + +#include <linux/component.h> +#include <linux/module.h> +#include <linux/of_platform.h> +#include <linux/clk.h> +#include <drm/drm_crtc_helper.h> +#include <drm/drm_fb_cma_helper.h> +#include <drm/drm_fb_helper.h> +#include <drm/drm_gem_cma_helper.h> +#include <drm/drm_gem_framebuffer_helper.h> +#include <drm/drm_atomic_helper.h> +#include <drm/drm_bridge.h> +#include <drm/drm_drv.h> +#include <drm/drm_probe_helper.h> + +#include "dw-ipk.h" +#include "dw-vpg.h" + +static const struct drm_mode_config_funcs dw_ipk_drm_modecfg_funcs = { + .fb_create = drm_gem_fb_create_with_dirty, + .atomic_check = drm_atomic_helper_check, + .atomic_commit = drm_atomic_helper_commit, +}; + +static int dw_ipk_load (struct drm_device *drm) +{ +int ret; + +drm_mode_config_init (drm); + + drm->mode_config.min_width =0 ; + drm->mode_config.min_height =0 ; + +/* To handle orientation */ + drm->mode_config.max_width =2048 ; + drm->mode_config.max_height =2048 ; + + drm->mode_config.funcs = &dw_ipk_drm_modecfg_funcs; + +/* TODO +* Optional framebuffer memory resources allocation +*/ + + ret =vpg_load (drm); +if (ret) +return ret; + +/* Calls all the crtc's, encoder's and connector's reset */ +drm_mode_config_reset (drm); + +/* Initialize and enable output polling */ +drm_kms_helper_poll_init (drm); + +return ret; +} + +static void dw_ipk_unload (struct drm_device *drm) +{ +DRM_DEBUG_DRIVER ("\n" ); + +drm_kms_helper_poll_fini (drm); +vpg_unload (drm); +} + +DEFINE_DRM_GEM_CMA_FOPS (ipk_drm_driver_fops); + +static int ipk_gem_cma_dumb_create (struct drm_file *file, +struct drm_device *dev, +struct drm_mode_create_dumb *args) +{ +unsigned int min_pitch =DIV_ROUND_UP (args->width * args->bpp,8 ); +int err; + +/* +* In order to optimize data transfer, pitch is aligned on +* 128 bytes, height is aligned on 4 bytes +*/ + args->pitch =roundup (min_pitch,128 ); + args->height =roundup (args->height,4 ); + + err =drm_gem_cma_dumb_create_internal (file, dev, args); +if (err <0 ) +drm_err (dev,"dumb_create failed %d\n" , err); + +return err; +} + +static struct drm_driver dw_ipk_drm_driver = { + .driver_features =DRIVER_MODESET |DRIVER_GEM |DRIVER_ATOMIC , + .name ="dw_ipk" , + .desc ="DW IPK DSI Host Controller" , + .date ="20190725" , + .major =1 , + .minor =0 , + .patchlevel =0 , + .fops = &ipk_drm_driver_fops, + .dumb_create = ipk_gem_cma_dumb_create, + .prime_handle_to_fd = drm_gem_prime_handle_to_fd, + .prime_fd_to_handle = drm_gem_prime_fd_to_handle, + .gem_free_object_unlocked = drm_gem_cma_free_object, + .gem_vm_ops = &drm_gem_cma_vm_ops, + .gem_prime_export = drm_gem_prime_export, + .gem_prime_import = drm_gem_prime_import, + .gem_prime_get_sg_table = drm_gem_cma_prime_get_sg_table, + .gem_prime_import_sg_table = drm_gem_cma_prime_import_sg_table, + .gem_prime_vmap = drm_gem_cma_prime_vmap, + .gem_prime_vunmap = drm_gem_cma_prime_vunmap, + .gem_prime_mmap = drm_gem_cma_prime_mmap, +}; + +static int dw_ipk_drm_platform_probe (struct platform_device *pdev) +{ +struct device *dev = &pdev->dev; +struct drm_device *drm; +struct ipk_device *ipk; +int ret; + +DRM_DEBUG_DRIVER ("\n" ); + + ipk =kzalloc (sizeof (*ipk),GFP_KERNEL ); +if (!ipk)
drivers/gpu/drm/ipk/dw-drv.c line 138
Quoted 10 lines
drivers/gpu/drm/ipk/dw-drv.c new file +10
-0+return -ENOMEM ; + + ipk->platform = pdev; + drm = &ipk->drm; + + ret =drm_dev_init (&ipk->drm, &dw_ipk_drm_driver, dev); +if (ret) { +kfree (ipk); +return ret; + }
I'm reworking this right now, you're missing a call to drmm_add_final_kfree here. But I think even better would be to rebase on top of my patch here:
https://patchwork.freedesktop.org/patch/359897/
Which would allow you to drop a bunch of code from your load/unload code. See that patch series for a lot of example conversions. I plan to land that patch pretty soon in drm-misc-next so shouldn't hold up merging your driver.
-Daniel
Quoted 716 lines
drivers/gpu/drm/ipk/dw-drv.c new file +51
-0+ +platform_set_drvdata (pdev, drm); + + ret =dw_ipk_load (drm); +if (ret) + goto err_put; + + ret =drm_dev_register (drm,0 ); +if (ret) + goto err_put; + +drm_fbdev_generic_setup (drm,24 ); + +return ret; + +err_put: +drm_dev_put (drm); +return ret; +} + +static int dw_ipk_drm_platform_remove (struct platform_device *pdev) +{ +struct drm_device *drm =platform_get_drvdata (pdev); + +drm_dev_unregister (drm); +dw_ipk_unload (drm); +drm_dev_put (drm); + +return 0 ; +} + +static const struct of_device_id dw_ipk_dt_ids[] = { + {.compatible ="snps,dw-ipk-vpg" }, + {/* sentinel */ } +}; +MODULE_DEVICE_TABLE (of, dw_ipk_dt_ids); + +static struct platform_driver dw_ipk_drm_platform_driver = { + .probe = dw_ipk_drm_platform_probe, + .remove = dw_ipk_drm_platform_remove, + .driver = { + .name ="dw-ipk-drm" , + .of_match_table = dw_ipk_dt_ids, + }, +}; + +module_platform_driver (dw_ipk_drm_platform_driver); + +MODULE_DESCRIPTION ("Synopsys DesignWare IPK DRM driver" ); +MODULE_LICENSE ("GPL v2" ); +MODULE_AUTHOR ("Angelo Ribeiro <[email protected]>" );drivers/gpu/drm/ipk/dw-ipk.h new file +30
-0@@ -0,0 +1,30 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* +* Copyright (c) 2019-2020 Synopsys, Inc. and/or its affiliates. +* Synopsys DesignWare MIPI DSI Controller +*/ + +#ifndef _DW_IPK_H +#define _DW_IPK_H + +#include "drm/drm_device.h" +#include <drm/bridge/dw_mipi_dsi.h> + +struct ipk_pipeline { +struct drm_framebuffer *fb; +struct drm_crtc crtc; +struct drm_plane *plane; +struct drm_bridge *bridge; +}; + +struct ipk_device { +struct drm_device drm; +struct platform_device *platform; +struct ipk_pipeline pipeline; +struct vpg_device *vpg; +}; + +#define drm_device_to_ipk_device (target) \ + container_of(target, struct ipk_device, drm) + +#endif /* _DW_IPK_H */ drivers/gpu/drm/ipk/dw-vpg.c new file +559
-0@@ -0,0 +1,559 @@ +// SPDX-License-Identifier: GPL-2.0 +/* +* Copyright (c) 2019-2020 Synopsys, Inc. and/or its affiliates. +* Synopsys DesignWare MIPI DSI controller +* +* Author: Angelo Ribeiro <[email protected]> +* Author: Luis Oliveira <[email protected]> +*/ + +#include <linux/clk.h> +#include <linux/component.h> +#include <linux/delay.h> +#include <linux/interrupt.h> +#include <linux/module.h> +#include <linux/of_address.h> +#include <linux/of_graph.h> +#include <linux/platform_device.h> +#include <linux/reset.h> + +#include <drm/drm_atomic.h> +#include <drm/drm_atomic_helper.h> +#include <drm/drm_bridge.h> +#include <drm/drm_device.h> +#include <drm/drm_fb_cma_helper.h> +#include <drm/drm_fourcc.h> +#include <drm/drm_gem_cma_helper.h> +#include <drm/drm_of.h> +#include <drm/drm_vblank.h> +#include <linux/platform_data/simplefb.h> +#include <video/videomode.h> + +#include "dw-ipk.h" +#include "dw-vpg.h" + +#define NB_CRTC 1 +#define CRTC_MASK GENMASK(NB_CRTC - 1, 0) +#define MAX_ENDPOINTS 1 + +struct vpg_device { +void __iomem *base; +void __iomem *base_mmcm; +}; + +enum vpg_pixel_fmt { +VIF_COLOR_CODE_16BIT_CONFIG1 =0 , +VIF_COLOR_CODE_16BIT_CONFIG2 , +VIF_COLOR_CODE_16BIT_CONFIG3 , +VIF_COLOR_CODE_18BIT_CONFIG1 , +VIF_COLOR_CODE_18BIT_CONFIG2 , +VIF_COLOR_CODE_24BIT , +VIF_COLOR_CODE_MAX +}; + +static enum vpg_pixel_fmt to_vpg_pixel_format (u32 drm_fmt) +{ +enum vpg_pixel_fmt pf; + +switch (drm_fmt) { +case DRM_FORMAT_RGB888 : + pf =VIF_COLOR_CODE_24BIT ; +break ; +case DRM_FORMAT_RGB565 : + pf =VIF_COLOR_CODE_16BIT_CONFIG1 ; +break ; +default : + pf =VIF_COLOR_CODE_MAX ; +break ; + } +return pf; +} + +static struct simplefb_format supported_formats[] = { + {"r5g6b5" ,16 , {11 ,5 }, {5 ,6 }, {0 ,5 }, {0 ,0 },DRM_FORMAT_RGB565 }, + {"r8g8b8" ,24 , {16 ,8 }, {8 ,8 }, {0 ,8 }, {0 ,0 },DRM_FORMAT_RGB888 }, + {"x8r8g8b8" ,32 , {16 ,8 }, {8 ,8 }, {0 ,8 }, {0 ,0 },DRM_FORMAT_XRGB8888 }, +}; + +static const u64 vpg_format_modifiers[] = { +DRM_FORMAT_MOD_LINEAR , +DRM_FORMAT_MOD_INVALID +}; + +static const struct drm_encoder_funcs ipk_encoder_funcs = { + .destroy = drm_encoder_cleanup, +}; + +static int ipk_encoder_init (struct drm_device *drm, +struct drm_bridge *bridge) +{ +struct ipk_device *ipk =drm_device_to_ipk_device (drm); +struct drm_encoder *encoder; +int ret; + + encoder =devm_kzalloc (drm->dev,sizeof (*encoder),GFP_KERNEL ); +if (!encoder) +return -ENOMEM ; + +/* Only one CRTC can be attached in IPK_DSI */ + encoder->possible_crtcs =CRTC_MASK ; + encoder->possible_clones =0 ; + + ret =drm_encoder_init (drm, encoder, &ipk_encoder_funcs, +DRM_MODE_ENCODER_DPI ,NULL ); +if (ret) +return ret; + + ret =drm_bridge_attach (encoder, bridge,NULL ,0 ); +if (ret) + goto err_attach; + +/* Add to the internal struct */ + ipk->pipeline.bridge = bridge; + +DRM_DEBUG_DRIVER ("Num of connectors = %d\n" , + drm->mode_config.num_connector); +DRM_DEBUG_DRIVER ("Bridge encoder:%d created\n" , encoder->base.id); + +return ret; + +err_attach: +drm_encoder_cleanup (encoder); +return ret; +} + +/* +* CRTC +*/ +static u32 vpg_read (struct vpg_device *dev,u32 reg) +{ +return readl (dev->base + reg); +} + +static void vpg_write (struct vpg_device *dev,u32 reg,u32 val) +{ +writel (val, dev->base + reg); +} + +static void vpg_write_part (struct vpg_device *dev,u32 reg, +u32 val,u8 shift,u8 width) +{ +u32 mask = (1 << width) -1 ; + +vpg_write (dev, reg, (vpg_read (dev, reg) & + ~(mask << shift)) | ((val & mask) << shift)); +} + +static u32 mmcm_read (struct vpg_device *dev,u32 reg) +{ +return readl (dev->base_mmcm + reg); +} + +static void mmcm_write (struct vpg_device *dev,u32 reg,u32 value) +{ +writel (value, dev->base_mmcm + reg); +} + +static void mmcm_configure (struct vpg_device *vpg,struct videomode *v_mode) +{ +int div, mul, cur_freq, cur_deviat, temp; +int out_freq = v_mode->pixelclock /1000 ; +int in_freq =100000 ; +int deviat =1000 ;/* Deviation from desired master clock */ +int best_div =0 ;/* Divider for PLL */ +int best_mul =0 ;/* Multiplier for PLL */ + +DRM_DEBUG_DRIVER ("out_freq = %d\n" , out_freq); + +for (div =1 ; div <150 && deviat >50 ; div++) { +for (mul =1 ; mul <=10 && deviat >50 ; mul++) { + cur_freq = in_freq * mul / div; + cur_deviat =abs (out_freq - cur_freq); +if (cur_deviat < deviat) { + best_div = div; + best_mul = mul; + deviat = cur_deviat; + } + } + } + +DRM_DEBUG_DRIVER ("deviat = %d\n best_div = %d\n best_mul = %d\n" , + deviat, best_div, best_mul); + + temp =mmcm_read (vpg,DW_MMCM_CLKOUT0_REG_1 ) &DW_MMCM_MASK ; +mmcm_write (vpg,DW_MMCM_CLKOUT0_REG_1 , temp | (best_div <<6 ) | + best_div); + + temp =mmcm_read (vpg,DW_MMCM_CLKFBOUT_REG_1 ) &DW_MMCM_MASK ; +mmcm_write (vpg,DW_MMCM_CLKFBOUT_REG_1 , temp | (best_mul <<6 ) | + best_mul); +} + +static void vpg_set_fps (struct vpg_device *vpg, +const struct drm_display_mode *mode) +{ +/* IF_Freq is in KHz */ +u32 line_time = (1000 *DW_VPG_FREQ ) / (mode->vrefresh * mode->vtotal); + +vpg_write (vpg,DW_VPG_LINE_TIME , line_time); +} + +static void vpg_select_pattern (struct vpg_device *vpg,unsigned int value) +{ +vpg_write (vpg,DW_VPG_TESTMODE , value); +} + +static void vpg_vertical_set (struct vpg_device *vpg,struct videomode *v_mode) +{ +vpg_write_part (vpg,DW_VPG_CANVAS , v_mode->vactive,16 ,16 ); +vpg_write_part (vpg,DW_VPG_VBP_VFP_VSA , v_mode->vsync_len,0 ,8 ); +vpg_write_part (vpg,DW_VPG_VBP_VFP_VSA , v_mode->vback_porch,20 ,12 ); +vpg_write_part (vpg,DW_VPG_VBP_VFP_VSA , v_mode->vfront_porch,8 ,11 ); +} + +static void vpg_horizontal_set (struct vpg_device *vpg,struct videomode *v_mode) +{ +vpg_write_part (vpg,DW_VPG_CANVAS , v_mode->hactive,0 ,16 ); +vpg_write_part (vpg,DW_VPG_HBP_HSA , v_mode->hsync_len,0 ,16 ); +vpg_write_part (vpg,DW_VPG_HBP_HSA , v_mode->hback_porch,16 ,16 ); +} + +static ssize_t show_pattern (struct device *dev, +struct device_attribute *attr,char *buf) +{ +struct drm_device *drm =dev_get_drvdata (dev); +struct ipk_device *ipk =drm_device_to_ipk_device (drm); +struct vpg_device *vpg = ipk->vpg; + +return sprintf (buf,"%d\n" ,vpg_read (vpg,DW_VPG_TESTMODE )); +} + +static ssize_t store_pattern (struct device *dev,struct device_attribute *attr, +const char *buf,size_t count) +{ +struct drm_device *drm =dev_get_drvdata (dev); +struct ipk_device *ipk =drm_device_to_ipk_device (drm); +struct vpg_device *vpg = ipk->vpg; +long pattern; +int ret; + + ret =kstrtol (buf,0 , &pattern); +if (ret <0 ) +return ret; + +vpg_select_pattern (vpg, pattern); + +return count; +} + +static struct kobj_attribute vpg_pattern =__ATTR (pattern,0660 , + (void *)show_pattern, + (void *)store_pattern); + +static struct attribute *vpg_attr[] = { + &vpg_pattern.attr, +NULL , +}; + +static const struct attribute_group vpg_attr_group = { + .attrs = vpg_attr, +}; + +static void vpg_crtc_mode_set_nofb (struct drm_crtc *crtc) +{ +struct ipk_device *ipk =drm_device_to_ipk_device (crtc->dev); +struct drm_display_mode *mode = &crtc->state->adjusted_mode; +struct vpg_device *vpg = ipk->vpg; +struct videomode v_mode; + +DRM_DEBUG_DRIVER ("\n" ); + +drm_display_mode_to_videomode (mode, &v_mode); + +DRM_DEBUG_DRIVER ("CRTC:%d mode:%s\n" , crtc->base.id, mode->name); +DRM_DEBUG_DRIVER ("Video mode: %dx%d" , v_mode.hactive, v_mode.vactive); +DRM_DEBUG_DRIVER (" hfp %d hbp %d hsl %d vfp %d vbp %d vsl %d\n" , + v_mode.hfront_porch, v_mode.hback_porch, + v_mode.hsync_len, v_mode.vfront_porch, + v_mode.vback_porch, v_mode.vsync_len); + +mmcm_configure (vpg, &v_mode); + +vpg_write (vpg,DW_VPG_SEL_DATA ,0x01 ); +vpg_write (vpg,DW_VPG_SEL_DATA ,0x03 ); + +vpg_horizontal_set (vpg, &v_mode); + +vpg_vertical_set (vpg, &v_mode); + +vpg_set_fps (vpg, mode); + +vpg_select_pattern (vpg,0 ); +} + +static void vpg_crtc_atomic_begin (struct drm_crtc *crtc, +struct drm_crtc_state *state) +{ +struct drm_pending_vblank_event *event = crtc->state->event; + +if (event) { + crtc->state->event =NULL ; +spin_lock_irq (&crtc->dev->event_lock); +drm_crtc_send_vblank_event (crtc, event); +spin_unlock_irq (&crtc->dev->event_lock); + } +} + +static struct drm_crtc_helper_funcs vpg_crtc_helper_funcs = { + .mode_set_nofb = vpg_crtc_mode_set_nofb, + .atomic_begin = vpg_crtc_atomic_begin, +}; + +static int vpg_crtc_late_register (struct drm_crtc *crtc) +{ +struct ipk_device *ipk =drm_device_to_ipk_device (crtc->dev); +struct platform_device *pdev = ipk->platform; +int ret; + + ret =sysfs_create_group (&pdev->dev.kobj, &vpg_attr_group); +if (ret) +drm_err (crtc->dev,"Failed to create sysfs entries" ); + +return ret; +} + +static void vpg_crtc_early_unregister (struct drm_crtc *crtc) +{ +struct ipk_device *ipk =drm_device_to_ipk_device (crtc->dev); +struct platform_device *pdev = ipk->platform; + +sysfs_remove_group (&pdev->dev.kobj, &vpg_attr_group); +} + +static const struct drm_crtc_funcs vpg_crtc_funcs = { + .reset = drm_atomic_helper_crtc_reset, + .destroy = drm_crtc_cleanup, + .set_config = drm_atomic_helper_set_config, + .page_flip = drm_atomic_helper_page_flip, + .atomic_duplicate_state = drm_atomic_helper_crtc_duplicate_state, + .atomic_destroy_state = drm_atomic_helper_crtc_destroy_state, + .late_register = vpg_crtc_late_register, + .early_unregister = vpg_crtc_early_unregister +}; + +/* +* Plane +*/ +static void vpg_plane_atomic_update (struct drm_plane *plane, +struct drm_plane_state *old_state) +{ +struct ipk_device *ipk =drm_device_to_ipk_device (plane->dev); +struct drm_plane_state *state = plane->state; +struct drm_framebuffer *fb = state->fb; +struct vpg_device *vpg = ipk->vpg; +enum vpg_pixel_fmt pixel_format; + + pixel_format =to_vpg_pixel_format (fb->format->format); + +vpg_write (vpg,DW_VPG_DPICOLORMODE , pixel_format); +} + +static void vpg_plane_atomic_disable (struct drm_plane *plane, +struct drm_plane_state *oldstate) +{ +DRM_DEBUG_DRIVER ("\n" ); +} + +static const struct drm_plane_helper_funcs vpg_plane_helper_funcs = { + .atomic_update = vpg_plane_atomic_update, + .atomic_disable = vpg_plane_atomic_disable, +}; + +static const struct drm_plane_funcs vpg_plane_funcs = { + .update_plane = drm_atomic_helper_update_plane, + .disable_plane = drm_atomic_helper_disable_plane, + .destroy = drm_plane_cleanup, + .reset = drm_atomic_helper_plane_reset, + .atomic_duplicate_state = drm_atomic_helper_plane_duplicate_state, + .atomic_destroy_state = drm_atomic_helper_plane_destroy_state, +}; + +static void vpg_plane_destroy_all (struct drm_device *drm) +{ +struct drm_plane *plane, *plane_temp; + +list_for_each_entry_safe (plane, plane_temp, + &drm->mode_config.plane_list, head) +drm_plane_cleanup (plane); +} + +static int vpg_crtc_init (struct drm_device *drm,struct drm_crtc *crtc) +{ +u32 formats[ARRAY_SIZE (supported_formats)], i; +const u64 *modifiers = vpg_format_modifiers; +unsigned long possible_crtcs =CRTC_MASK ; +struct device *drm_dev = drm->dev; +struct drm_plane *plane; +int ret; + + plane =devm_kzalloc (drm_dev,sizeof (*plane),GFP_KERNEL ); +if (!plane) +return -ENOMEM ; + +for (i =0 ; i <ARRAY_SIZE (supported_formats); i++) + formats[i] = supported_formats[i].fourcc; + + ret =drm_universal_plane_init (drm, plane, possible_crtcs, + &vpg_plane_funcs, formats, +ARRAY_SIZE (formats), modifiers, +DRM_PLANE_TYPE_PRIMARY ,NULL ); +if (ret) + goto cleanup_planes; + +drm_plane_helper_add (plane, &vpg_plane_helper_funcs); + +DRM_DEBUG_DRIVER ("plane:%d created\n" , plane->base.id); + + ret =drm_crtc_init_with_planes (drm, crtc, plane,NULL , + &vpg_crtc_funcs,"DSI-VPG" ); +if (ret) { +DRM_DEBUG_DRIVER ("Failed initialize CRTC\n" ); + goto cleanup_crtc; + } + +drm_crtc_helper_add (crtc, &vpg_crtc_helper_funcs); + +DRM_DEBUG_DRIVER ("CRTC:%d created\n" , crtc->base.id); + +return ret; + +cleanup_crtc: +drm_crtc_cleanup (crtc); +cleanup_planes: +vpg_plane_destroy_all (drm); +return ret; +} + +int vpg_load (struct drm_device *drm) +{ +struct ipk_device *ipk =drm_device_to_ipk_device (drm); +struct drm_bridge *bridge[MAX_ENDPOINTS ] = {NULL }; +struct drm_panel *panel[MAX_ENDPOINTS ] = {NULL }; +struct platform_device *pdev = ipk->platform; +struct device_node *np = drm->dev->of_node; +int ret, i, endpoint_not_ready = -ENODEV ; +struct reset_control *vpg_rst, *mmcm_rst; +struct device *dev = drm->dev; +struct vpg_device *vpg; +struct drm_crtc *crtc; +struct resource *res; + +DRM_DEBUG_DRIVER ("\n" ); + + vpg =devm_kzalloc (&pdev->dev,sizeof (*vpg),GFP_KERNEL ); +if (!vpg) +return -ENOMEM ; + + ipk->vpg = vpg; + +/* Get endpoints if any */ +for (i =0 ; i <MAX_ENDPOINTS ; i++) { + ret =drm_of_find_panel_or_bridge (np,0 , i, &panel[i], + &bridge[i]); +if (ret == -EPROBE_DEFER ) +return ret; +else if (!ret) + endpoint_not_ready =0 ; + } + +if (endpoint_not_ready) +return endpoint_not_ready; + + res =platform_get_resource_byname (pdev,IORESOURCE_MEM ,"vpg" ); + vpg->base =devm_ioremap_resource (dev, res); +if (IS_ERR (vpg->base)) { +drm_err (drm,"Unable to get VPG registers\n" ); + ret =PTR_ERR (vpg->base); + goto err; + } + + vpg_rst =devm_reset_control_get_optional_exclusive (dev,"vpg" ); +if (IS_ERR (vpg_rst)) { + ret =PTR_ERR (vpg_rst); +if (ret != -EPROBE_DEFER ) +drm_err (drm,"Unable to get reset control: %d\n" , ret); + goto err; + } + +if (vpg_rst) { +reset_control_assert (vpg_rst); +usleep_range (10 ,20 ); +reset_control_deassert (vpg_rst); + } + + res =platform_get_resource_byname (pdev,IORESOURCE_MEM ,"mmcm" ); + vpg->base_mmcm =devm_ioremap_resource (dev, res); +if (IS_ERR (vpg->base)) { + ret =PTR_ERR (vpg->base); + goto err; + } + + mmcm_rst =devm_reset_control_get_optional_exclusive (dev,"mmcm" ); +if (IS_ERR (mmcm_rst)) { + ret =PTR_ERR (mmcm_rst); +if (ret != -EPROBE_DEFER ) +drm_err (drm,"Unable to get reset control: %d\n" , ret); + goto err; + } + +if (mmcm_rst) { +reset_control_assert (mmcm_rst); +usleep_range (10 ,20 ); +reset_control_deassert (mmcm_rst); + } + +/* Add endpoints panels or bridges if any */ +for (i =0 ; i <MAX_ENDPOINTS ; i++) { +if (panel[i]) { + bridge[i] =drm_panel_bridge_add_typed (panel[i], +DRM_MODE_CONNECTOR_DSI ); +if (IS_ERR (bridge[i])) { + ret =PTR_ERR (bridge[i]); + goto err; + } + } + +if (bridge[i]) { + ret =ipk_encoder_init (drm, bridge[i]); +if (ret) + goto err; + } + } + + crtc =devm_kzalloc (dev,sizeof (*crtc),GFP_KERNEL ); +if (!crtc) { + ret = -ENOMEM ; + goto err; + } + + ret =vpg_crtc_init (drm, crtc); +if (ret) + goto err; + +return ret; + +err: +for (i =0 ; i <MAX_ENDPOINTS ; i++) +drm_panel_bridge_remove (bridge[i]); + +return ret; +} + +void vpg_unload (struct drm_device *drm) +{ +int i; + +DRM_DEBUG_DRIVER ("\n" ); +for (i =0 ; i <MAX_ENDPOINTS ; i++) +drm_of_panel_bridge_remove (drm->dev->of_node,0 , i); +}drivers/gpu/drm/ipk/dw-vpg.h new file +55
-0@@ -0,0 +1,55 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* +* Copyright (c) 2019-2020 Synopsys, Inc. and/or its affiliates. +* Synopsys DesignWare VPG +*/ + +#ifndef _VPG_H_ +#define _VPG_H_ + +#define DW_VPG_PANX 0x00 +#define DW_VPG_PANY 0x04 +#define DW_VPG_PHASE_SEL 0x08 +#define DW_VPG_SEL_DATA 0x0C +#define DW_VPG_SWAP_BAY 0x10 +#define DW_VPG_TESTMODE 0x14 +#define DW_VPG_ZOOM_OUT 0x18 +#define DW_VPG_EDPICTRL 0x1C +#define DW_VPG_CANVAS 0x20 +#define DW_VPG_HBP_HSA 0x24 +#define DW_VPG_LINE_TIME 0x28 +#define DW_VPG_VBP_VFP_VSA 0x2C +#define DW_VPG_DPICOLORMODE 0x30 +#define DW_VPG_VERSION 0x34 +#define DW_VPG_EXTRNAL_EDPI 0x38 +#define DW_VPG_PVO_CEAVID 0x3C +#define DW_VPG_PAN_VALID 0x40 +#define DW_VPG_TECONTROL 0x44 +#define DW_VPG_IMAGE_START_POSITION_X 0x4C +#define DW_VPG_IMAGE_START_POSITION_Y 0x50 +#define DW_VPG_IMAGE_Y 0x54 +#define DW_VPG_IMAGE_WORD_COUNT 0x58 +#define DW_VPG_IMAGE_DATA_TYPE 0x5C +#define DW_VPG_LINE_PIXS_CNT 0x60 +#define DW_VPG_FRAME_LINES_CNT 0x64 + +#define DW_MMCM_MASK 0x1000 +#define DW_MMCM_CLKOUT0_REG_1 0x20 +#define DW_MMCM_CLKOUT0_REG_2 0x24 +#define DW_MMCM_CLKFBOUT_REG_1 0x50 +#define DW_MMCM_CLKFBOUT_REG_2 0x54 +#define DW_MMCM_POWER_REG 0xA0 + +#define DW_VPG_ZOOM_OUT_STEP 1 +#define DW_VPG_PAN_STEP 40 +#define DW_VPG_FREQ 25000/* [KHz] */ +#define DW_VPG_V_FRONT_PORCH 2 +#define DW_VPG_V_BACK_PORCH 2 +#define DW_VPG_V_SYNC 2 +#define SCREEN_SIZE_X 800 +#define SCREEN_SIZE_Y 480 + +int vpg_load (struct drm_device *ddev); +void vpg_unload (struct drm_device *ddev); + +#endif /* _VPG_H_ */ Signature · 1 line
2.7.4
Signature · 7 lines
Daniel Vetter Software Engineer, Intel Corporation http://blog.ffwll.ch _______________________________________________ dri-devel mailing list [email protected] https://lists.freedesktop.org/mailman/listinfo/dri-devel
RE: [PATCH v2 2/4] drm: ipk: Add DRM driver for DesignWare IPK DSI
Hi Daniel,
From: Daniel Vetter <[email protected]>
Date: Tue, Apr 07, 2020 at 09:13:33
Quoted 230 lines · Angelo Ribeiro
Quoted 214 lines
Add support for Synopsys DesignWare VPG (Video Pattern Generator) and DRM driver for Synopsys DesignWare DSI Host IPK solution.
Cc Maarten Lankhorst <[email protected]>Cc Maxime Ripard <[email protected]>Cc David Airlie <[email protected]>Cc Daniel Vetter <[email protected]>Cc Gustavo Pimentel <[email protected]>Cc Joao Pinto <[email protected]>Signed-off-by Angelo Ribeiro <[email protected]>--- drivers/gpu/drm/Kconfig | 2 + drivers/gpu/drm/Makefile | 1 + drivers/gpu/drm/ipk/Kconfig | 13 + drivers/gpu/drm/ipk/Makefile | 6 + drivers/gpu/drm/ipk/dw-drv.c | 189 +++++++++++++++ drivers/gpu/drm/ipk/dw-ipk.h | 30 +++ drivers/gpu/drm/ipk/dw-vpg.c | 559 +++++++++++++++++++++++++++++++++++++++++++ drivers/gpu/drm/ipk/dw-vpg.h | 55 +++++ 8 files changed, 855 insertions(+) create mode 100644 drivers/gpu/drm/ipk/Kconfig create mode 100644 drivers/gpu/drm/ipk/Makefile create mode 100644 drivers/gpu/drm/ipk/dw-drv.c create mode 100644 drivers/gpu/drm/ipk/dw-ipk.h create mode 100644 drivers/gpu/drm/ipk/dw-vpg.c create mode 100644 drivers/gpu/drm/ipk/dw-vpg.hdrivers/gpu/drm/Kconfig +2
-0@@ -388,6 +388,8 @@ source "drivers/gpu/drm/mcde/Kconfig" source "drivers/gpu/drm/tidss/Kconfig" +source "drivers/gpu/drm/ipk/Kconfig" + # Keep legacy drivers last menuconfig DRM_LEGACYdrivers/gpu/drm/Makefile +1
-0@@ -125,3 +125,4 @@ obj-$(CONFIG_DRM_PANFROST) += panfrost/ obj-$(CONFIG_DRM_ASPEED_GFX) += aspeed/ obj-$(CONFIG_DRM_MCDE) += mcde/ obj-$(CONFIG_DRM_TIDSS) += tidss/ +obj-$(CONFIG_DRM_IPK) += ipk/drivers/gpu/drm/ipk/Kconfig new file +13
-0@@ -0,0 +1,13 @@ +# SPDX-License-Identifier: GPL-2.0-only +config DRM_IPK + tristate "DRM Support for Synopsys DesignWare IPK DSI" + depends on DRM + select DRM_KMS_HELPER + select DRM_GEM_CMA_HELPER + select DRM_KMS_CMA_HELPER + select DRM_PANEL_BRIDGE + select VIDEOMODE_HELPERS + help + Enable support for the Synopsys DesignWare DRM DSI. + To compile this driver as a module, choose M here: the module + will be called ipk-drm.drivers/gpu/drm/ipk/Makefile new file +6
-0@@ -0,0 +1,6 @@ +# SPDX-License-Identifier: GPL-2.0-only +ipk-drm-y := \ + dw-drv.o \ + dw-vpg.o + +obj-$(CONFIG_DRM_IPK) += ipk-drm.odrivers/gpu/drm/ipk/dw-drv.c new file +128
-0@@ -0,0 +1,189 @@ +// SPDX-License-Identifier: GPL-2.0 +/* +* Copyright (c) 2019-2020 Synopsys, Inc. and/or its affiliates. +* Synopsys DesignWare MIPI DSI DRM driver +* +* Author: Angelo Ribeiro <[email protected]> +*/ + +#include <linux/component.h> +#include <linux/module.h> +#include <linux/of_platform.h> +#include <linux/clk.h> +#include <drm/drm_crtc_helper.h> +#include <drm/drm_fb_cma_helper.h> +#include <drm/drm_fb_helper.h> +#include <drm/drm_gem_cma_helper.h> +#include <drm/drm_gem_framebuffer_helper.h> +#include <drm/drm_atomic_helper.h> +#include <drm/drm_bridge.h> +#include <drm/drm_drv.h> +#include <drm/drm_probe_helper.h> + +#include "dw-ipk.h" +#include "dw-vpg.h" + +static const struct drm_mode_config_funcs dw_ipk_drm_modecfg_funcs = { + .fb_create = drm_gem_fb_create_with_dirty, + .atomic_check = drm_atomic_helper_check, + .atomic_commit = drm_atomic_helper_commit, +}; + +static int dw_ipk_load (struct drm_device *drm) +{ +int ret; + +drm_mode_config_init (drm); + + drm->mode_config.min_width =0 ; + drm->mode_config.min_height =0 ; + +/* To handle orientation */ + drm->mode_config.max_width =2048 ; + drm->mode_config.max_height =2048 ; + + drm->mode_config.funcs = &dw_ipk_drm_modecfg_funcs; + +/* TODO +* Optional framebuffer memory resources allocation +*/ + + ret =vpg_load (drm); +if (ret) +return ret; + +/* Calls all the crtc's, encoder's and connector's reset */ +drm_mode_config_reset (drm); + +/* Initialize and enable output polling */ +drm_kms_helper_poll_init (drm); + +return ret; +} + +static void dw_ipk_unload (struct drm_device *drm) +{ +DRM_DEBUG_DRIVER ("\n" ); + +drm_kms_helper_poll_fini (drm); +vpg_unload (drm); +} + +DEFINE_DRM_GEM_CMA_FOPS (ipk_drm_driver_fops); + +static int ipk_gem_cma_dumb_create (struct drm_file *file, +struct drm_device *dev, +struct drm_mode_create_dumb *args) +{ +unsigned int min_pitch =DIV_ROUND_UP (args->width * args->bpp,8 ); +int err; + +/* +* In order to optimize data transfer, pitch is aligned on +* 128 bytes, height is aligned on 4 bytes +*/ + args->pitch =roundup (min_pitch,128 ); + args->height =roundup (args->height,4 ); + + err =drm_gem_cma_dumb_create_internal (file, dev, args); +if (err <0 ) +drm_err (dev,"dumb_create failed %d\n" , err); + +return err; +} + +static struct drm_driver dw_ipk_drm_driver = { + .driver_features =DRIVER_MODESET |DRIVER_GEM |DRIVER_ATOMIC , + .name ="dw_ipk" , + .desc ="DW IPK DSI Host Controller" , + .date ="20190725" , + .major =1 , + .minor =0 , + .patchlevel =0 , + .fops = &ipk_drm_driver_fops, + .dumb_create = ipk_gem_cma_dumb_create, + .prime_handle_to_fd = drm_gem_prime_handle_to_fd, + .prime_fd_to_handle = drm_gem_prime_fd_to_handle, + .gem_free_object_unlocked = drm_gem_cma_free_object, + .gem_vm_ops = &drm_gem_cma_vm_ops, + .gem_prime_export = drm_gem_prime_export, + .gem_prime_import = drm_gem_prime_import, + .gem_prime_get_sg_table = drm_gem_cma_prime_get_sg_table, + .gem_prime_import_sg_table = drm_gem_cma_prime_import_sg_table, + .gem_prime_vmap = drm_gem_cma_prime_vmap, + .gem_prime_vunmap = drm_gem_cma_prime_vunmap, + .gem_prime_mmap = drm_gem_cma_prime_mmap, +}; + +static int dw_ipk_drm_platform_probe (struct platform_device *pdev) +{ +struct device *dev = &pdev->dev; +struct drm_device *drm; +struct ipk_device *ipk; +int ret; + +DRM_DEBUG_DRIVER ("\n" ); + + ipk =kzalloc (sizeof (*ipk),GFP_KERNEL ); +if (!ipk)drivers/gpu/drm/ipk/dw-drv.c line 138
Quoted 10 lines
drivers/gpu/drm/ipk/dw-drv.c new file +10
-0+return -ENOMEM ; + + ipk->platform = pdev; + drm = &ipk->drm; + + ret =drm_dev_init (&ipk->drm, &dw_ipk_drm_driver, dev); +if (ret) { +kfree (ipk); +return ret; + }I'm reworking this right now, you're missing a call to
drmm_add_final_kfreehere. But I think even better would be to rebase on top of my patch here:
Quoted 7 lines
Which would allow you to drop a bunch of code from your load/unload code. See that patch series for a lot of example conversions. I plan to land that patch pretty soon in drm-misc-next so shouldn't hold up merging your driver.
-Daniel
Thank you for the revision, I will do it.
Quoted 709 lines
Quoted 709 lines
drivers/gpu/drm/ipk/dw-drv.c new file +51
-0+ +platform_set_drvdata (pdev, drm); + + ret =dw_ipk_load (drm); +if (ret) + goto err_put; + + ret =drm_dev_register (drm,0 ); +if (ret) + goto err_put; + +drm_fbdev_generic_setup (drm,24 ); + +return ret; + +err_put: +drm_dev_put (drm); +return ret; +} + +static int dw_ipk_drm_platform_remove (struct platform_device *pdev) +{ +struct drm_device *drm =platform_get_drvdata (pdev); + +drm_dev_unregister (drm); +dw_ipk_unload (drm); +drm_dev_put (drm); + +return 0 ; +} + +static const struct of_device_id dw_ipk_dt_ids[] = { + {.compatible ="snps,dw-ipk-vpg" }, + {/* sentinel */ } +}; +MODULE_DEVICE_TABLE (of, dw_ipk_dt_ids); + +static struct platform_driver dw_ipk_drm_platform_driver = { + .probe = dw_ipk_drm_platform_probe, + .remove = dw_ipk_drm_platform_remove, + .driver = { + .name ="dw-ipk-drm" , + .of_match_table = dw_ipk_dt_ids, + }, +}; + +module_platform_driver (dw_ipk_drm_platform_driver); + +MODULE_DESCRIPTION ("Synopsys DesignWare IPK DRM driver" ); +MODULE_LICENSE ("GPL v2" ); +MODULE_AUTHOR ("Angelo Ribeiro <[email protected]>" );drivers/gpu/drm/ipk/dw-ipk.h new file +30
-0@@ -0,0 +1,30 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* +* Copyright (c) 2019-2020 Synopsys, Inc. and/or its affiliates. +* Synopsys DesignWare MIPI DSI Controller +*/ + +#ifndef _DW_IPK_H +#define _DW_IPK_H + +#include "drm/drm_device.h" +#include <drm/bridge/dw_mipi_dsi.h> + +struct ipk_pipeline { +struct drm_framebuffer *fb; +struct drm_crtc crtc; +struct drm_plane *plane; +struct drm_bridge *bridge; +}; + +struct ipk_device { +struct drm_device drm; +struct platform_device *platform; +struct ipk_pipeline pipeline; +struct vpg_device *vpg; +}; + +#define drm_device_to_ipk_device (target) \ + container_of(target, struct ipk_device, drm) + +#endif /* _DW_IPK_H */ drivers/gpu/drm/ipk/dw-vpg.c new file +559
-0@@ -0,0 +1,559 @@ +// SPDX-License-Identifier: GPL-2.0 +/* +* Copyright (c) 2019-2020 Synopsys, Inc. and/or its affiliates. +* Synopsys DesignWare MIPI DSI controller +* +* Author: Angelo Ribeiro <[email protected]> +* Author: Luis Oliveira <[email protected]> +*/ + +#include <linux/clk.h> +#include <linux/component.h> +#include <linux/delay.h> +#include <linux/interrupt.h> +#include <linux/module.h> +#include <linux/of_address.h> +#include <linux/of_graph.h> +#include <linux/platform_device.h> +#include <linux/reset.h> + +#include <drm/drm_atomic.h> +#include <drm/drm_atomic_helper.h> +#include <drm/drm_bridge.h> +#include <drm/drm_device.h> +#include <drm/drm_fb_cma_helper.h> +#include <drm/drm_fourcc.h> +#include <drm/drm_gem_cma_helper.h> +#include <drm/drm_of.h> +#include <drm/drm_vblank.h> +#include <linux/platform_data/simplefb.h> +#include <video/videomode.h> + +#include "dw-ipk.h" +#include "dw-vpg.h" + +#define NB_CRTC 1 +#define CRTC_MASK GENMASK(NB_CRTC - 1, 0) +#define MAX_ENDPOINTS 1 + +struct vpg_device { +void __iomem *base; +void __iomem *base_mmcm; +}; + +enum vpg_pixel_fmt { +VIF_COLOR_CODE_16BIT_CONFIG1 =0 , +VIF_COLOR_CODE_16BIT_CONFIG2 , +VIF_COLOR_CODE_16BIT_CONFIG3 , +VIF_COLOR_CODE_18BIT_CONFIG1 , +VIF_COLOR_CODE_18BIT_CONFIG2 , +VIF_COLOR_CODE_24BIT , +VIF_COLOR_CODE_MAX +}; + +static enum vpg_pixel_fmt to_vpg_pixel_format (u32 drm_fmt) +{ +enum vpg_pixel_fmt pf; + +switch (drm_fmt) { +case DRM_FORMAT_RGB888 : + pf =VIF_COLOR_CODE_24BIT ; +break ; +case DRM_FORMAT_RGB565 : + pf =VIF_COLOR_CODE_16BIT_CONFIG1 ; +break ; +default : + pf =VIF_COLOR_CODE_MAX ; +break ; + } +return pf; +} + +static struct simplefb_format supported_formats[] = { + {"r5g6b5" ,16 , {11 ,5 }, {5 ,6 }, {0 ,5 }, {0 ,0 },DRM_FORMAT_RGB565 }, + {"r8g8b8" ,24 , {16 ,8 }, {8 ,8 }, {0 ,8 }, {0 ,0 },DRM_FORMAT_RGB888 }, + {"x8r8g8b8" ,32 , {16 ,8 }, {8 ,8 }, {0 ,8 }, {0 ,0 },DRM_FORMAT_XRGB8888 }, +}; + +static const u64 vpg_format_modifiers[] = { +DRM_FORMAT_MOD_LINEAR , +DRM_FORMAT_MOD_INVALID +}; + +static const struct drm_encoder_funcs ipk_encoder_funcs = { + .destroy = drm_encoder_cleanup, +}; + +static int ipk_encoder_init (struct drm_device *drm, +struct drm_bridge *bridge) +{ +struct ipk_device *ipk =drm_device_to_ipk_device (drm); +struct drm_encoder *encoder; +int ret; + + encoder =devm_kzalloc (drm->dev,sizeof (*encoder),GFP_KERNEL ); +if (!encoder) +return -ENOMEM ; + +/* Only one CRTC can be attached in IPK_DSI */ + encoder->possible_crtcs =CRTC_MASK ; + encoder->possible_clones =0 ; + + ret =drm_encoder_init (drm, encoder, &ipk_encoder_funcs, +DRM_MODE_ENCODER_DPI ,NULL ); +if (ret) +return ret; + + ret =drm_bridge_attach (encoder, bridge,NULL ,0 ); +if (ret) + goto err_attach; + +/* Add to the internal struct */ + ipk->pipeline.bridge = bridge; + +DRM_DEBUG_DRIVER ("Num of connectors = %d\n" , + drm->mode_config.num_connector); +DRM_DEBUG_DRIVER ("Bridge encoder:%d created\n" , encoder->base.id); + +return ret; + +err_attach: +drm_encoder_cleanup (encoder); +return ret; +} + +/* +* CRTC +*/ +static u32 vpg_read (struct vpg_device *dev,u32 reg) +{ +return readl (dev->base + reg); +} + +static void vpg_write (struct vpg_device *dev,u32 reg,u32 val) +{ +writel (val, dev->base + reg); +} + +static void vpg_write_part (struct vpg_device *dev,u32 reg, +u32 val,u8 shift,u8 width) +{ +u32 mask = (1 << width) -1 ; + +vpg_write (dev, reg, (vpg_read (dev, reg) & + ~(mask << shift)) | ((val & mask) << shift)); +} + +static u32 mmcm_read (struct vpg_device *dev,u32 reg) +{ +return readl (dev->base_mmcm + reg); +} + +static void mmcm_write (struct vpg_device *dev,u32 reg,u32 value) +{ +writel (value, dev->base_mmcm + reg); +} + +static void mmcm_configure (struct vpg_device *vpg,struct videomode *v_mode) +{ +int div, mul, cur_freq, cur_deviat, temp; +int out_freq = v_mode->pixelclock /1000 ; +int in_freq =100000 ; +int deviat =1000 ;/* Deviation from desired master clock */ +int best_div =0 ;/* Divider for PLL */ +int best_mul =0 ;/* Multiplier for PLL */ + +DRM_DEBUG_DRIVER ("out_freq = %d\n" , out_freq); + +for (div =1 ; div <150 && deviat >50 ; div++) { +for (mul =1 ; mul <=10 && deviat >50 ; mul++) { + cur_freq = in_freq * mul / div; + cur_deviat =abs (out_freq - cur_freq); +if (cur_deviat < deviat) { + best_div = div; + best_mul = mul; + deviat = cur_deviat; + } + } + } + +DRM_DEBUG_DRIVER ("deviat = %d\n best_div = %d\n best_mul = %d\n" , + deviat, best_div, best_mul); + + temp =mmcm_read (vpg,DW_MMCM_CLKOUT0_REG_1 ) &DW_MMCM_MASK ; +mmcm_write (vpg,DW_MMCM_CLKOUT0_REG_1 , temp | (best_div <<6 ) | + best_div); + + temp =mmcm_read (vpg,DW_MMCM_CLKFBOUT_REG_1 ) &DW_MMCM_MASK ; +mmcm_write (vpg,DW_MMCM_CLKFBOUT_REG_1 , temp | (best_mul <<6 ) | + best_mul); +} + +static void vpg_set_fps (struct vpg_device *vpg, +const struct drm_display_mode *mode) +{ +/* IF_Freq is in KHz */ +u32 line_time = (1000 *DW_VPG_FREQ ) / (mode->vrefresh * mode->vtotal); + +vpg_write (vpg,DW_VPG_LINE_TIME , line_time); +} + +static void vpg_select_pattern (struct vpg_device *vpg,unsigned int value) +{ +vpg_write (vpg,DW_VPG_TESTMODE , value); +} + +static void vpg_vertical_set (struct vpg_device *vpg,struct videomode *v_mode) +{ +vpg_write_part (vpg,DW_VPG_CANVAS , v_mode->vactive,16 ,16 ); +vpg_write_part (vpg,DW_VPG_VBP_VFP_VSA , v_mode->vsync_len,0 ,8 ); +vpg_write_part (vpg,DW_VPG_VBP_VFP_VSA , v_mode->vback_porch,20 ,12 ); +vpg_write_part (vpg,DW_VPG_VBP_VFP_VSA , v_mode->vfront_porch,8 ,11 ); +} + +static void vpg_horizontal_set (struct vpg_device *vpg,struct videomode *v_mode) +{ +vpg_write_part (vpg,DW_VPG_CANVAS , v_mode->hactive,0 ,16 ); +vpg_write_part (vpg,DW_VPG_HBP_HSA , v_mode->hsync_len,0 ,16 ); +vpg_write_part (vpg,DW_VPG_HBP_HSA , v_mode->hback_porch,16 ,16 ); +} + +static ssize_t show_pattern (struct device *dev, +struct device_attribute *attr,char *buf) +{ +struct drm_device *drm =dev_get_drvdata (dev); +struct ipk_device *ipk =drm_device_to_ipk_device (drm); +struct vpg_device *vpg = ipk->vpg; + +return sprintf (buf,"%d\n" ,vpg_read (vpg,DW_VPG_TESTMODE )); +} + +static ssize_t store_pattern (struct device *dev,struct device_attribute *attr, +const char *buf,size_t count) +{ +struct drm_device *drm =dev_get_drvdata (dev); +struct ipk_device *ipk =drm_device_to_ipk_device (drm); +struct vpg_device *vpg = ipk->vpg; +long pattern; +int ret; + + ret =kstrtol (buf,0 , &pattern); +if (ret <0 ) +return ret; + +vpg_select_pattern (vpg, pattern); + +return count; +} + +static struct kobj_attribute vpg_pattern =__ATTR (pattern,0660 , + (void *)show_pattern, + (void *)store_pattern); + +static struct attribute *vpg_attr[] = { + &vpg_pattern.attr, +NULL , +}; + +static const struct attribute_group vpg_attr_group = { + .attrs = vpg_attr, +}; + +static void vpg_crtc_mode_set_nofb (struct drm_crtc *crtc) +{ +struct ipk_device *ipk =drm_device_to_ipk_device (crtc->dev); +struct drm_display_mode *mode = &crtc->state->adjusted_mode; +struct vpg_device *vpg = ipk->vpg; +struct videomode v_mode; + +DRM_DEBUG_DRIVER ("\n" ); + +drm_display_mode_to_videomode (mode, &v_mode); + +DRM_DEBUG_DRIVER ("CRTC:%d mode:%s\n" , crtc->base.id, mode->name); +DRM_DEBUG_DRIVER ("Video mode: %dx%d" , v_mode.hactive, v_mode.vactive); +DRM_DEBUG_DRIVER (" hfp %d hbp %d hsl %d vfp %d vbp %d vsl %d\n" , + v_mode.hfront_porch, v_mode.hback_porch, + v_mode.hsync_len, v_mode.vfront_porch, + v_mode.vback_porch, v_mode.vsync_len); + +mmcm_configure (vpg, &v_mode); + +vpg_write (vpg,DW_VPG_SEL_DATA ,0x01 ); +vpg_write (vpg,DW_VPG_SEL_DATA ,0x03 ); + +vpg_horizontal_set (vpg, &v_mode); + +vpg_vertical_set (vpg, &v_mode); + +vpg_set_fps (vpg, mode); + +vpg_select_pattern (vpg,0 ); +} + +static void vpg_crtc_atomic_begin (struct drm_crtc *crtc, +struct drm_crtc_state *state) +{ +struct drm_pending_vblank_event *event = crtc->state->event; + +if (event) { + crtc->state->event =NULL ; +spin_lock_irq (&crtc->dev->event_lock); +drm_crtc_send_vblank_event (crtc, event); +spin_unlock_irq (&crtc->dev->event_lock); + } +} + +static struct drm_crtc_helper_funcs vpg_crtc_helper_funcs = { + .mode_set_nofb = vpg_crtc_mode_set_nofb, + .atomic_begin = vpg_crtc_atomic_begin, +}; + +static int vpg_crtc_late_register (struct drm_crtc *crtc) +{ +struct ipk_device *ipk =drm_device_to_ipk_device (crtc->dev); +struct platform_device *pdev = ipk->platform; +int ret; + + ret =sysfs_create_group (&pdev->dev.kobj, &vpg_attr_group); +if (ret) +drm_err (crtc->dev,"Failed to create sysfs entries" ); + +return ret; +} + +static void vpg_crtc_early_unregister (struct drm_crtc *crtc) +{ +struct ipk_device *ipk =drm_device_to_ipk_device (crtc->dev); +struct platform_device *pdev = ipk->platform; + +sysfs_remove_group (&pdev->dev.kobj, &vpg_attr_group); +} + +static const struct drm_crtc_funcs vpg_crtc_funcs = { + .reset = drm_atomic_helper_crtc_reset, + .destroy = drm_crtc_cleanup, + .set_config = drm_atomic_helper_set_config, + .page_flip = drm_atomic_helper_page_flip, + .atomic_duplicate_state = drm_atomic_helper_crtc_duplicate_state, + .atomic_destroy_state = drm_atomic_helper_crtc_destroy_state, + .late_register = vpg_crtc_late_register, + .early_unregister = vpg_crtc_early_unregister +}; + +/* +* Plane +*/ +static void vpg_plane_atomic_update (struct drm_plane *plane, +struct drm_plane_state *old_state) +{ +struct ipk_device *ipk =drm_device_to_ipk_device (plane->dev); +struct drm_plane_state *state = plane->state; +struct drm_framebuffer *fb = state->fb; +struct vpg_device *vpg = ipk->vpg; +enum vpg_pixel_fmt pixel_format; + + pixel_format =to_vpg_pixel_format (fb->format->format); + +vpg_write (vpg,DW_VPG_DPICOLORMODE , pixel_format); +} + +static void vpg_plane_atomic_disable (struct drm_plane *plane, +struct drm_plane_state *oldstate) +{ +DRM_DEBUG_DRIVER ("\n" ); +} + +static const struct drm_plane_helper_funcs vpg_plane_helper_funcs = { + .atomic_update = vpg_plane_atomic_update, + .atomic_disable = vpg_plane_atomic_disable, +}; + +static const struct drm_plane_funcs vpg_plane_funcs = { + .update_plane = drm_atomic_helper_update_plane, + .disable_plane = drm_atomic_helper_disable_plane, + .destroy = drm_plane_cleanup, + .reset = drm_atomic_helper_plane_reset, + .atomic_duplicate_state = drm_atomic_helper_plane_duplicate_state, + .atomic_destroy_state = drm_atomic_helper_plane_destroy_state, +}; + +static void vpg_plane_destroy_all (struct drm_device *drm) +{ +struct drm_plane *plane, *plane_temp; + +list_for_each_entry_safe (plane, plane_temp, + &drm->mode_config.plane_list, head) +drm_plane_cleanup (plane); +} + +static int vpg_crtc_init (struct drm_device *drm,struct drm_crtc *crtc) +{ +u32 formats[ARRAY_SIZE (supported_formats)], i; +const u64 *modifiers = vpg_format_modifiers; +unsigned long possible_crtcs =CRTC_MASK ; +struct device *drm_dev = drm->dev; +struct drm_plane *plane; +int ret; + + plane =devm_kzalloc (drm_dev,sizeof (*plane),GFP_KERNEL ); +if (!plane) +return -ENOMEM ; + +for (i =0 ; i <ARRAY_SIZE (supported_formats); i++) + formats[i] = supported_formats[i].fourcc; + + ret =drm_universal_plane_init (drm, plane, possible_crtcs, + &vpg_plane_funcs, formats, +ARRAY_SIZE (formats), modifiers, +DRM_PLANE_TYPE_PRIMARY ,NULL ); +if (ret) + goto cleanup_planes; + +drm_plane_helper_add (plane, &vpg_plane_helper_funcs); + +DRM_DEBUG_DRIVER ("plane:%d created\n" , plane->base.id); + + ret =drm_crtc_init_with_planes (drm, crtc, plane,NULL , + &vpg_crtc_funcs,"DSI-VPG" ); +if (ret) { +DRM_DEBUG_DRIVER ("Failed initialize CRTC\n" ); + goto cleanup_crtc; + } + +drm_crtc_helper_add (crtc, &vpg_crtc_helper_funcs); + +DRM_DEBUG_DRIVER ("CRTC:%d created\n" , crtc->base.id); + +return ret; + +cleanup_crtc: +drm_crtc_cleanup (crtc); +cleanup_planes: +vpg_plane_destroy_all (drm); +return ret; +} + +int vpg_load (struct drm_device *drm) +{ +struct ipk_device *ipk =drm_device_to_ipk_device (drm); +struct drm_bridge *bridge[MAX_ENDPOINTS ] = {NULL }; +struct drm_panel *panel[MAX_ENDPOINTS ] = {NULL }; +struct platform_device *pdev = ipk->platform; +struct device_node *np = drm->dev->of_node; +int ret, i, endpoint_not_ready = -ENODEV ; +struct reset_control *vpg_rst, *mmcm_rst; +struct device *dev = drm->dev; +struct vpg_device *vpg; +struct drm_crtc *crtc; +struct resource *res; + +DRM_DEBUG_DRIVER ("\n" ); + + vpg =devm_kzalloc (&pdev->dev,sizeof (*vpg),GFP_KERNEL ); +if (!vpg) +return -ENOMEM ; + + ipk->vpg = vpg; + +/* Get endpoints if any */ +for (i =0 ; i <MAX_ENDPOINTS ; i++) { + ret =drm_of_find_panel_or_bridge (np,0 , i, &panel[i], + &bridge[i]); +if (ret == -EPROBE_DEFER ) +return ret; +else if (!ret) + endpoint_not_ready =0 ; + } + +if (endpoint_not_ready) +return endpoint_not_ready; + + res =platform_get_resource_byname (pdev,IORESOURCE_MEM ,"vpg" ); + vpg->base =devm_ioremap_resource (dev, res); +if (IS_ERR (vpg->base)) { +drm_err (drm,"Unable to get VPG registers\n" ); + ret =PTR_ERR (vpg->base); + goto err; + } + + vpg_rst =devm_reset_control_get_optional_exclusive (dev,"vpg" ); +if (IS_ERR (vpg_rst)) { + ret =PTR_ERR (vpg_rst); +if (ret != -EPROBE_DEFER ) +drm_err (drm,"Unable to get reset control: %d\n" , ret); + goto err; + } + +if (vpg_rst) { +reset_control_assert (vpg_rst); +usleep_range (10 ,20 ); +reset_control_deassert (vpg_rst); + } + + res =platform_get_resource_byname (pdev,IORESOURCE_MEM ,"mmcm" ); + vpg->base_mmcm =devm_ioremap_resource (dev, res); +if (IS_ERR (vpg->base)) { + ret =PTR_ERR (vpg->base); + goto err; + } + + mmcm_rst =devm_reset_control_get_optional_exclusive (dev,"mmcm" ); +if (IS_ERR (mmcm_rst)) { + ret =PTR_ERR (mmcm_rst); +if (ret != -EPROBE_DEFER ) +drm_err (drm,"Unable to get reset control: %d\n" , ret); + goto err; + } + +if (mmcm_rst) { +reset_control_assert (mmcm_rst); +usleep_range (10 ,20 ); +reset_control_deassert (mmcm_rst); + } + +/* Add endpoints panels or bridges if any */ +for (i =0 ; i <MAX_ENDPOINTS ; i++) { +if (panel[i]) { + bridge[i] =drm_panel_bridge_add_typed (panel[i], +DRM_MODE_CONNECTOR_DSI ); +if (IS_ERR (bridge[i])) { + ret =PTR_ERR (bridge[i]); + goto err; + } + } + +if (bridge[i]) { + ret =ipk_encoder_init (drm, bridge[i]); +if (ret) + goto err; + } + } + + crtc =devm_kzalloc (dev,sizeof (*crtc),GFP_KERNEL ); +if (!crtc) { + ret = -ENOMEM ; + goto err; + } + + ret =vpg_crtc_init (drm, crtc); +if (ret) + goto err; + +return ret; + +err: +for (i =0 ; i <MAX_ENDPOINTS ; i++) +drm_panel_bridge_remove (bridge[i]); + +return ret; +} + +void vpg_unload (struct drm_device *drm) +{ +int i; + +DRM_DEBUG_DRIVER ("\n" ); +for (i =0 ; i <MAX_ENDPOINTS ; i++) +drm_of_panel_bridge_remove (drm->dev->of_node,0 , i); +}drivers/gpu/drm/ipk/dw-vpg.h new file +50
-0@@ -0,0 +1,55 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* +* Copyright (c) 2019-2020 Synopsys, Inc. and/or its affiliates. +* Synopsys DesignWare VPG +*/ + +#ifndef _VPG_H_ +#define _VPG_H_ + +#define DW_VPG_PANX 0x00 +#define DW_VPG_PANY 0x04 +#define DW_VPG_PHASE_SEL 0x08 +#define DW_VPG_SEL_DATA 0x0C +#define DW_VPG_SWAP_BAY 0x10 +#define DW_VPG_TESTMODE 0x14 +#define DW_VPG_ZOOM_OUT 0x18 +#define DW_VPG_EDPICTRL 0x1C +#define DW_VPG_CANVAS 0x20 +#define DW_VPG_HBP_HSA 0x24 +#define DW_VPG_LINE_TIME 0x28 +#define DW_VPG_VBP_VFP_VSA 0x2C +#define DW_VPG_DPICOLORMODE 0x30 +#define DW_VPG_VERSION 0x34 +#define DW_VPG_EXTRNAL_EDPI 0x38 +#define DW_VPG_PVO_CEAVID 0x3C +#define DW_VPG_PAN_VALID 0x40 +#define DW_VPG_TECONTROL 0x44 +#define DW_VPG_IMAGE_START_POSITION_X 0x4C +#define DW_VPG_IMAGE_START_POSITION_Y 0x50 +#define DW_VPG_IMAGE_Y 0x54 +#define DW_VPG_IMAGE_WORD_COUNT 0x58 +#define DW_VPG_IMAGE_DATA_TYPE 0x5C +#define DW_VPG_LINE_PIXS_CNT 0x60 +#define DW_VPG_FRAME_LINES_CNT 0x64 + +#define DW_MMCM_MASK 0x1000 +#define DW_MMCM_CLKOUT0_REG_1 0x20 +#define DW_MMCM_CLKOUT0_REG_2 0x24 +#define DW_MMCM_CLKFBOUT_REG_1 0x50 +#define DW_MMCM_CLKFBOUT_REG_2 0x54 +#define DW_MMCM_POWER_REG 0xA0 + +#define DW_VPG_ZOOM_OUT_STEP 1 +#define DW_VPG_PAN_STEP 40 +#define DW_VPG_FREQ 25000/* [KHz] */ +#define DW_VPG_V_FRONT_PORCH 2 +#define DW_VPG_V_BACK_PORCH 2 +#define DW_VPG_V_SYNC 2 +#define SCREEN_SIZE_X 800 +#define SCREEN_SIZE_Y 480
Quoted 13 lines
Quoted 8 lines
drivers/gpu/drm/ipk/dw-vpg.h new file +5
-0+ +int vpg_load (struct drm_device *ddev); +void vpg_unload (struct drm_device *ddev); + +#endif /* _VPG_H_ */ Signature · 1 line
2.7.4Signature · 3 lines
Daniel Vetter Software Engineer, Intel Corporation https://urldefense.proofpoint.com/v2/url?u=http-3A__blog.ffwll.ch&d=DwIBAg&c=DPL6_X_6JkXFx7AXWqB0tg&r=-1lJkMi2j8IE8jpsNWO99o9zJFwyv1Mbjj3vJBR__i0&m=knxu5BXoiypjzq6gobgbIqbrpnkIlWKYlpnGtKMLvnw&s=obntSCr3Ev8khEsp1VLKqczn-yc69G5IuHbSBcRS24k&e=
Thanks,
Angelo Ribeiro
Re: [PATCH v2 2/4] drm: ipk: Add DRM driver for DesignWare IPK DSI
In reply to Angelo RibeiroHi Angelo.
Has it been evaluated if the drm_simple_* stuff can be used? It looks like this is a single plane, single connector thing so a good candidate.
Some nits below.
Sam
Quoted 74 lines · Angelo Ribeiro
Add support for Synopsys DesignWare VPG (Video Pattern Generator) and DRM driver for Synopsys DesignWare DSI Host IPK solution.
Cc Maarten Lankhorst <[email protected]>Cc Maxime Ripard <[email protected]>Cc David Airlie <[email protected]>Cc Daniel Vetter <[email protected]>Cc Gustavo Pimentel <[email protected]>Cc Joao Pinto <[email protected]>Signed-off-by Angelo Ribeiro <[email protected]>--- drivers/gpu/drm/Kconfig | 2 + drivers/gpu/drm/Makefile | 1 + drivers/gpu/drm/ipk/Kconfig | 13 + drivers/gpu/drm/ipk/Makefile | 6 + drivers/gpu/drm/ipk/dw-drv.c | 189 +++++++++++++++ drivers/gpu/drm/ipk/dw-ipk.h | 30 +++ drivers/gpu/drm/ipk/dw-vpg.c | 559 +++++++++++++++++++++++++++++++++++++++++++ drivers/gpu/drm/ipk/dw-vpg.h | 55 +++++ 8 files changed, 855 insertions(+) create mode 100644 drivers/gpu/drm/ipk/Kconfig create mode 100644 drivers/gpu/drm/ipk/Makefile create mode 100644 drivers/gpu/drm/ipk/dw-drv.c create mode 100644 drivers/gpu/drm/ipk/dw-ipk.h create mode 100644 drivers/gpu/drm/ipk/dw-vpg.c create mode 100644 drivers/gpu/drm/ipk/dw-vpg.hdrivers/gpu/drm/Kconfig +2
-0@@ -388,6 +388,8 @@ source "drivers/gpu/drm/mcde/Kconfig" source "drivers/gpu/drm/tidss/Kconfig" +source "drivers/gpu/drm/ipk/Kconfig" + # Keep legacy drivers last menuconfig DRM_LEGACYdrivers/gpu/drm/Makefile +1
-0@@ -125,3 +125,4 @@ obj-$(CONFIG_DRM_PANFROST) += panfrost/ obj-$(CONFIG_DRM_ASPEED_GFX) += aspeed/ obj-$(CONFIG_DRM_MCDE) += mcde/ obj-$(CONFIG_DRM_TIDSS) += tidss/ +obj-$(CONFIG_DRM_IPK) += ipk/drivers/gpu/drm/ipk/Kconfig new file +13
-0@@ -0,0 +1,13 @@ +# SPDX-License-Identifier: GPL-2.0-only +config DRM_IPK + tristate "DRM Support for Synopsys DesignWare IPK DSI" + depends on DRM + select DRM_KMS_HELPER + select DRM_GEM_CMA_HELPER + select DRM_KMS_CMA_HELPER + select DRM_PANEL_BRIDGE + select VIDEOMODE_HELPERS + help + Enable support for the Synopsys DesignWare DRM DSI. + To compile this driver as a module, choose M here: the module + will be called ipk-drm.drivers/gpu/drm/ipk/Makefile new file +0
-0
drivers/gpu/drm/ipk/Makefile line 4
Quoted 4 lines
drivers/gpu/drm/ipk/Makefile new file +4
-0@@ -0,0 +1,6 @@ +# SPDX-License-Identifier: GPL-2.0-only +ipk-drm-y := \ + dw-drv.o \ + dw-vpg.o
There is no point in adding '\' here.
A simple:
ipk-drm-y := dw-drv.o dw-vpg.o
Lot's of Makefile uses the ugly '\' where they should use a += instead :-(
Quoted 21 lines
drivers/gpu/drm/ipk/Makefile new file +1
-0+obj-$(CONFIG_DRM_IPK) += ipk-drm.odrivers/gpu/drm/ipk/dw-drv.c new file +14
-0@@ -0,0 +1,189 @@ +// SPDX-License-Identifier: GPL-2.0 +/* +* Copyright (c) 2019-2020 Synopsys, Inc. and/or its affiliates. +* Synopsys DesignWare MIPI DSI DRM driver +* +* Author: Angelo Ribeiro <[email protected]> +*/ + +#include <linux/component.h> +#include <linux/module.h> +#include <linux/of_platform.h> +#include <linux/clk.h> +#include <drm/drm_crtc_helper.h> +#include <drm/drm_fb_cma_helper.h>
drivers/gpu/drm/ipk/dw-drv.c line 24
Quoted 10 lines
drivers/gpu/drm/ipk/dw-drv.c new file +10
-0+#include <drm/drm_fb_helper.h> +#include <drm/drm_gem_cma_helper.h> +#include <drm/drm_gem_framebuffer_helper.h> +#include <drm/drm_atomic_helper.h> +#include <drm/drm_bridge.h> +#include <drm/drm_drv.h> +#include <drm/drm_probe_helper.h> + +#include "dw-ipk.h" +#include "dw-vpg.h"
Please order thei ncludes like this:
#include <linux/*>
[empty line]
#include <drm/*>
[empty line]
#include "dw*.h"
Within each block - sort alphabetically.
Drop unused includes - drm_probe_helper is IIRC for legacy stuff mostly/only.
drivers/gpu/drm/ipk/dw-drv.c line 36
Quoted 12 lines
drivers/gpu/drm/ipk/dw-drv.c new file +12
-0+ +static const struct drm_mode_config_funcs dw_ipk_drm_modecfg_funcs = { + .fb_create = drm_gem_fb_create_with_dirty, + .atomic_check = drm_atomic_helper_check, + .atomic_commit = drm_atomic_helper_commit, +}; + +static int dw_ipk_load (struct drm_device *drm) +{ +int ret; + +drm_mode_config_init (drm);
drmm_mode_config_init(drm);
And remember to check return value.
Quoted 20 lines
drivers/gpu/drm/ipk/dw-drv.c new file +20
-0+ + drm->mode_config.min_width =0 ; + drm->mode_config.min_height =0 ; + +/* To handle orientation */ + drm->mode_config.max_width =2048 ; + drm->mode_config.max_height =2048 ; + + drm->mode_config.funcs = &dw_ipk_drm_modecfg_funcs; + +/* TODO +* Optional framebuffer memory resources allocation +*/ + + ret =vpg_load (drm); +if (ret) +return ret; + +/* Calls all the crtc's, encoder's and connector's reset */ +drm_mode_config_reset (drm);
drivers/gpu/drm/ipk/dw-drv.c line 66
Quoted 10 lines
drivers/gpu/drm/ipk/dw-drv.c new file +10
-0+ +/* Initialize and enable output polling */ +drm_kms_helper_poll_init (drm); + +return ret; +} + +static void dw_ipk_unload (struct drm_device *drm) +{ +DRM_DEBUG_DRIVER ("\n" );
when you have a drm_device - then please use drm_xxx for debug/warnings/errors - and also drm_WARN as applicable. This goes for everywhere that DRM_XXX is used. In this case use:
drm_dbg(drm, "\n");
Quoted 31 lines
drivers/gpu/drm/ipk/dw-drv.c new file +31
-0+ +drm_kms_helper_poll_fini (drm); +vpg_unload (drm); +} + +DEFINE_DRM_GEM_CMA_FOPS (ipk_drm_driver_fops); + +static int ipk_gem_cma_dumb_create (struct drm_file *file, +struct drm_device *dev, +struct drm_mode_create_dumb *args) +{ +unsigned int min_pitch =DIV_ROUND_UP (args->width * args->bpp,8 ); +int err; + +/* +* In order to optimize data transfer, pitch is aligned on +* 128 bytes, height is aligned on 4 bytes +*/ + args->pitch =roundup (min_pitch,128 ); + args->height =roundup (args->height,4 ); + + err =drm_gem_cma_dumb_create_internal (file, dev, args); +if (err <0 ) +drm_err (dev,"dumb_create failed %d\n" , err); + +return err; +} + +static struct drm_driver dw_ipk_drm_driver = { + .driver_features =DRIVER_MODESET |DRIVER_GEM |DRIVER_ATOMIC , + .name ="dw_ipk" ,
drivers/gpu/drm/ipk/dw-drv.c line 107
Quoted 10 lines
drivers/gpu/drm/ipk/dw-drv.c new file +10
-0+ .desc = "DW IPK DSI Host Controller", + .date = "20190725", + .major = 1, + .minor = 0, + .patchlevel = 0, + .fops = &ipk_drm_driver_fops, + .dumb_create = ipk_gem_cma_dumb_create, + .prime_handle_to_fd = drm_gem_prime_handle_to_fd, + .prime_fd_to_handle = drm_gem_prime_fd_to_handle, + .gem_free_object_unlocked = drm_gem_cma_free_object,
From the documentation:
This is deprecated and should not be used by new drivers. Use &drm_gem_object_funcs.free instead.
drivers/gpu/drm/ipk/dw-drv.c line 109
Quoted 2 lines
drivers/gpu/drm/ipk/dw-drv.c new file +2
-0+ .gem_vm_ops = &drm_gem_cma_vm_ops, + .gem_prime_export = drm_gem_prime_export,
From documentation:
Export hook for GEM drivers. Deprecated in favour of &drm_gem_object_funcs.export.
drivers/gpu/drm/ipk/dw-drv.c line 110
Quoted 1 line
drivers/gpu/drm/ipk/dw-drv.c new file +1
-0+ .gem_prime_import = drm_gem_prime_import,
From documentation:
This defaults to drm_gem_prime_import() if not set.
drivers/gpu/drm/ipk/dw-drv.c line 116
Quoted 6 lines
drivers/gpu/drm/ipk/dw-drv.c new file +6
-0+ .gem_prime_get_sg_table = drm_gem_cma_prime_get_sg_table, + .gem_prime_import_sg_table = drm_gem_cma_prime_import_sg_table, + .gem_prime_vmap = drm_gem_cma_prime_vmap, + .gem_prime_vunmap = drm_gem_cma_prime_vunmap, + .gem_prime_mmap = drm_gem_cma_prime_mmap, +};
Did not check all - please go through drm_drv.h - and fix so the driver do not use any deprecated stuff.
drivers/gpu/drm/ipk/dw-drv.c line 127
Quoted 11 lines
drivers/gpu/drm/ipk/dw-drv.c new file +11
-0+ +static int dw_ipk_drm_platform_probe (struct platform_device *pdev) +{ +struct device *dev = &pdev->dev; +struct drm_device *drm; +struct ipk_device *ipk; +int ret; + +DRM_DEBUG_DRIVER ("\n" ); + + ipk =kzalloc (sizeof (*ipk),GFP_KERNEL );
drmm_kzalloc() - but see feedback from Daniel too.
Quoted 69 lines
drivers/gpu/drm/ipk/dw-drv.c new file +62
-0+if (!ipk) +return -ENOMEM ; + + ipk->platform = pdev; + drm = &ipk->drm; + + ret =drm_dev_init (&ipk->drm, &dw_ipk_drm_driver, dev); +if (ret) { +kfree (ipk); +return ret; + } + +platform_set_drvdata (pdev, drm); + + ret =dw_ipk_load (drm); +if (ret) + goto err_put; + + ret =drm_dev_register (drm,0 ); +if (ret) + goto err_put; + +drm_fbdev_generic_setup (drm,24 ); + +return ret; + +err_put: +drm_dev_put (drm); +return ret; +} + +static int dw_ipk_drm_platform_remove (struct platform_device *pdev) +{ +struct drm_device *drm =platform_get_drvdata (pdev); + +drm_dev_unregister (drm); +dw_ipk_unload (drm); +drm_dev_put (drm); + +return 0 ; +} + +static const struct of_device_id dw_ipk_dt_ids[] = { + {.compatible ="snps,dw-ipk-vpg" }, + {/* sentinel */ } +}; +MODULE_DEVICE_TABLE (of, dw_ipk_dt_ids); + +static struct platform_driver dw_ipk_drm_platform_driver = { + .probe = dw_ipk_drm_platform_probe, + .remove = dw_ipk_drm_platform_remove, + .driver = { + .name ="dw-ipk-drm" , + .of_match_table = dw_ipk_dt_ids, + }, +}; + +module_platform_driver (dw_ipk_drm_platform_driver); + +MODULE_DESCRIPTION ("Synopsys DesignWare IPK DRM driver" ); +MODULE_LICENSE ("GPL v2" ); +MODULE_AUTHOR ("Angelo Ribeiro <[email protected]>" );drivers/gpu/drm/ipk/dw-ipk.h new file +1
-0@@ -0,0 +1,30 @@ +/* SPDX-License-Identifier: GPL-2.0 */
drivers/gpu/drm/ipk/dw-ipk.h line 11
Quoted 10 lines
drivers/gpu/drm/ipk/dw-ipk.h new file +10
-0+/* +* Copyright (c) 2019-2020 Synopsys, Inc. and/or its affiliates. +* Synopsys DesignWare MIPI DSI Controller +*/ + +#ifndef _DW_IPK_H +#define _DW_IPK_H + +#include "drm/drm_device.h" +#include <drm/bridge/dw_mipi_dsi.h>
Add the inlcudes so the header file is standalone . the header file should not relay on other files being includes.
Use forward as appropriate - like for example:
struct drm_bridge;
struct drm_framebuffer;
stuct drm_plane;
Keep the forwards alphabetically sorted.
Quoted 48 lines
drivers/gpu/drm/ipk/dw-ipk.h new file +19
-0+ +struct ipk_pipeline { +struct drm_framebuffer *fb; +struct drm_crtc crtc; +struct drm_plane *plane; +struct drm_bridge *bridge; +}; + +struct ipk_device { +struct drm_device drm; +struct platform_device *platform; +struct ipk_pipeline pipeline; +struct vpg_device *vpg; +}; + +#define drm_device_to_ipk_device (target) \ + container_of(target, struct ipk_device, drm) + +#endif /* _DW_IPK_H */ drivers/gpu/drm/ipk/dw-vpg.c new file +23
-0@@ -0,0 +1,559 @@ +// SPDX-License-Identifier: GPL-2.0 +/* +* Copyright (c) 2019-2020 Synopsys, Inc. and/or its affiliates. +* Synopsys DesignWare MIPI DSI controller +* +* Author: Angelo Ribeiro <[email protected]> +* Author: Luis Oliveira <[email protected]> +*/ + +#include <linux/clk.h> +#include <linux/component.h> +#include <linux/delay.h> +#include <linux/interrupt.h> +#include <linux/module.h> +#include <linux/of_address.h> +#include <linux/of_graph.h> +#include <linux/platform_device.h> +#include <linux/reset.h> + +#include <drm/drm_atomic.h> +#include <drm/drm_atomic_helper.h> +#include <drm/drm_bridge.h> +#include <drm/drm_device.h>
drivers/gpu/drm/ipk/dw-vpg.c line 33
Quoted 10 lines
drivers/gpu/drm/ipk/dw-vpg.c new file +10
-0+#include <drm/drm_fb_cma_helper.h> +#include <drm/drm_fourcc.h> +#include <drm/drm_gem_cma_helper.h> +#include <drm/drm_of.h> +#include <drm/drm_vblank.h> +#include <linux/platform_data/simplefb.h> +#include <video/videomode.h> + +#include "dw-ipk.h" +#include "dw-vpg.h"
See earlier rant on include files.
Quoted 42 lines
drivers/gpu/drm/ipk/dw-vpg.c new file +42
-0+ +#define NB_CRTC 1 +#define CRTC_MASK GENMASK(NB_CRTC - 1, 0) +#define MAX_ENDPOINTS 1 + +struct vpg_device { +void __iomem *base; +void __iomem *base_mmcm; +}; + +enum vpg_pixel_fmt { +VIF_COLOR_CODE_16BIT_CONFIG1 =0 , +VIF_COLOR_CODE_16BIT_CONFIG2 , +VIF_COLOR_CODE_16BIT_CONFIG3 , +VIF_COLOR_CODE_18BIT_CONFIG1 , +VIF_COLOR_CODE_18BIT_CONFIG2 , +VIF_COLOR_CODE_24BIT , +VIF_COLOR_CODE_MAX +}; + +static enum vpg_pixel_fmt to_vpg_pixel_format (u32 drm_fmt) +{ +enum vpg_pixel_fmt pf; + +switch (drm_fmt) { +case DRM_FORMAT_RGB888 : + pf =VIF_COLOR_CODE_24BIT ; +break ; +case DRM_FORMAT_RGB565 : + pf =VIF_COLOR_CODE_16BIT_CONFIG1 ; +break ; +default : + pf =VIF_COLOR_CODE_MAX ; +break ; + } +return pf; +} + +static struct simplefb_format supported_formats[] = { + {"r5g6b5" ,16 , {11 ,5 }, {5 ,6 }, {0 ,5 }, {0 ,0 },DRM_FORMAT_RGB565 }, + {"r8g8b8" ,24 , {16 ,8 }, {8 ,8 }, {0 ,8 }, {0 ,0 },DRM_FORMAT_RGB888 }, + {"x8r8g8b8" ,32 , {16 ,8 }, {8 ,8 }, {0 ,8 }, {0 ,0 },DRM_FORMAT_XRGB8888 },
drivers/gpu/drm/ipk/dw-vpg.c line 85
Quoted 10 lines
drivers/gpu/drm/ipk/dw-vpg.c new file +10
-0+}; + +static const u64 vpg_format_modifiers[] = { +DRM_FORMAT_MOD_LINEAR , +DRM_FORMAT_MOD_INVALID +}; + +static const struct drm_encoder_funcs ipk_encoder_funcs = { + .destroy = drm_encoder_cleanup, +};
This driver is a candidate to use drm_simple_encoder_init() This would get rid of the above ipk_encoder_funcs variable.
Quoted 21 lines
drivers/gpu/drm/ipk/dw-vpg.c new file +21
-0+ +static int ipk_encoder_init (struct drm_device *drm, +struct drm_bridge *bridge) +{ +struct ipk_device *ipk =drm_device_to_ipk_device (drm); +struct drm_encoder *encoder; +int ret; + + encoder =devm_kzalloc (drm->dev,sizeof (*encoder),GFP_KERNEL ); +if (!encoder) +return -ENOMEM ; + +/* Only one CRTC can be attached in IPK_DSI */ + encoder->possible_crtcs =CRTC_MASK ; + encoder->possible_clones =0 ; + + ret =drm_encoder_init (drm, encoder, &ipk_encoder_funcs, +DRM_MODE_ENCODER_DPI ,NULL ); +if (ret) +return ret; +
drivers/gpu/drm/ipk/dw-vpg.c line 116
Quoted 10 lines
drivers/gpu/drm/ipk/dw-vpg.c new file +10
-0+ ret =drm_bridge_attach (encoder, bridge,NULL ,0 ); +if (ret) + goto err_attach; + +/* Add to the internal struct */ + ipk->pipeline.bridge = bridge; + +DRM_DEBUG_DRIVER ("Num of connectors = %d\n" , + drm->mode_config.num_connector); +DRM_DEBUG_DRIVER ("Bridge encoder:%d created\n" , encoder->base.id);
drm_dbg(drm, ...)
Quoted 145 lines
drivers/gpu/drm/ipk/dw-vpg.c new file +145
-0+ +return ret; + +err_attach: +drm_encoder_cleanup (encoder); +return ret; +} + +/* +* CRTC +*/ +static u32 vpg_read (struct vpg_device *dev,u32 reg) +{ +return readl (dev->base + reg); +} + +static void vpg_write (struct vpg_device *dev,u32 reg,u32 val) +{ +writel (val, dev->base + reg); +} + +static void vpg_write_part (struct vpg_device *dev,u32 reg, +u32 val,u8 shift,u8 width) +{ +u32 mask = (1 << width) -1 ; + +vpg_write (dev, reg, (vpg_read (dev, reg) & + ~(mask << shift)) | ((val & mask) << shift)); +} + +static u32 mmcm_read (struct vpg_device *dev,u32 reg) +{ +return readl (dev->base_mmcm + reg); +} + +static void mmcm_write (struct vpg_device *dev,u32 reg,u32 value) +{ +writel (value, dev->base_mmcm + reg); +} + +static void mmcm_configure (struct vpg_device *vpg,struct videomode *v_mode) +{ +int div, mul, cur_freq, cur_deviat, temp; +int out_freq = v_mode->pixelclock /1000 ; +int in_freq =100000 ; +int deviat =1000 ;/* Deviation from desired master clock */ +int best_div =0 ;/* Divider for PLL */ +int best_mul =0 ;/* Multiplier for PLL */ + +DRM_DEBUG_DRIVER ("out_freq = %d\n" , out_freq); + +for (div =1 ; div <150 && deviat >50 ; div++) { +for (mul =1 ; mul <=10 && deviat >50 ; mul++) { + cur_freq = in_freq * mul / div; + cur_deviat =abs (out_freq - cur_freq); +if (cur_deviat < deviat) { + best_div = div; + best_mul = mul; + deviat = cur_deviat; + } + } + } + +DRM_DEBUG_DRIVER ("deviat = %d\n best_div = %d\n best_mul = %d\n" , + deviat, best_div, best_mul); + + temp =mmcm_read (vpg,DW_MMCM_CLKOUT0_REG_1 ) &DW_MMCM_MASK ; +mmcm_write (vpg,DW_MMCM_CLKOUT0_REG_1 , temp | (best_div <<6 ) | + best_div); + + temp =mmcm_read (vpg,DW_MMCM_CLKFBOUT_REG_1 ) &DW_MMCM_MASK ; +mmcm_write (vpg,DW_MMCM_CLKFBOUT_REG_1 , temp | (best_mul <<6 ) | + best_mul); +} + +static void vpg_set_fps (struct vpg_device *vpg, +const struct drm_display_mode *mode) +{ +/* IF_Freq is in KHz */ +u32 line_time = (1000 *DW_VPG_FREQ ) / (mode->vrefresh * mode->vtotal); + +vpg_write (vpg,DW_VPG_LINE_TIME , line_time); +} + +static void vpg_select_pattern (struct vpg_device *vpg,unsigned int value) +{ +vpg_write (vpg,DW_VPG_TESTMODE , value); +} + +static void vpg_vertical_set (struct vpg_device *vpg,struct videomode *v_mode) +{ +vpg_write_part (vpg,DW_VPG_CANVAS , v_mode->vactive,16 ,16 ); +vpg_write_part (vpg,DW_VPG_VBP_VFP_VSA , v_mode->vsync_len,0 ,8 ); +vpg_write_part (vpg,DW_VPG_VBP_VFP_VSA , v_mode->vback_porch,20 ,12 ); +vpg_write_part (vpg,DW_VPG_VBP_VFP_VSA , v_mode->vfront_porch,8 ,11 ); +} + +static void vpg_horizontal_set (struct vpg_device *vpg,struct videomode *v_mode) +{ +vpg_write_part (vpg,DW_VPG_CANVAS , v_mode->hactive,0 ,16 ); +vpg_write_part (vpg,DW_VPG_HBP_HSA , v_mode->hsync_len,0 ,16 ); +vpg_write_part (vpg,DW_VPG_HBP_HSA , v_mode->hback_porch,16 ,16 ); +} + +static ssize_t show_pattern (struct device *dev, +struct device_attribute *attr,char *buf) +{ +struct drm_device *drm =dev_get_drvdata (dev); +struct ipk_device *ipk =drm_device_to_ipk_device (drm); +struct vpg_device *vpg = ipk->vpg; + +return sprintf (buf,"%d\n" ,vpg_read (vpg,DW_VPG_TESTMODE )); +} + +static ssize_t store_pattern (struct device *dev,struct device_attribute *attr, +const char *buf,size_t count) +{ +struct drm_device *drm =dev_get_drvdata (dev); +struct ipk_device *ipk =drm_device_to_ipk_device (drm); +struct vpg_device *vpg = ipk->vpg; +long pattern; +int ret; + + ret =kstrtol (buf,0 , &pattern); +if (ret <0 ) +return ret; + +vpg_select_pattern (vpg, pattern); + +return count; +} + +static struct kobj_attribute vpg_pattern =__ATTR (pattern,0660 , + (void *)show_pattern, + (void *)store_pattern); + +static struct attribute *vpg_attr[] = { + &vpg_pattern.attr, +NULL , +}; + +static const struct attribute_group vpg_attr_group = { + .attrs = vpg_attr, +}; +
drivers/gpu/drm/ipk/dw-vpg.c line 271
Quoted 10 lines
drivers/gpu/drm/ipk/dw-vpg.c new file +10
-0+static void vpg_crtc_mode_set_nofb (struct drm_crtc *crtc) +{ +struct ipk_device *ipk =drm_device_to_ipk_device (crtc->dev); +struct drm_display_mode *mode = &crtc->state->adjusted_mode; +struct vpg_device *vpg = ipk->vpg; +struct videomode v_mode; + +DRM_DEBUG_DRIVER ("\n" ); + +drm_display_mode_to_videomode (mode, &v_mode);
Could be dropped, and all users of videomode could use drm_display_mode. One less indirection.
Quoted 356 lines
drivers/gpu/drm/ipk/dw-vpg.c new file +288
-0+ +DRM_DEBUG_DRIVER ("CRTC:%d mode:%s\n" , crtc->base.id, mode->name); +DRM_DEBUG_DRIVER ("Video mode: %dx%d" , v_mode.hactive, v_mode.vactive); +DRM_DEBUG_DRIVER (" hfp %d hbp %d hsl %d vfp %d vbp %d vsl %d\n" , + v_mode.hfront_porch, v_mode.hback_porch, + v_mode.hsync_len, v_mode.vfront_porch, + v_mode.vback_porch, v_mode.vsync_len); + +mmcm_configure (vpg, &v_mode); + +vpg_write (vpg,DW_VPG_SEL_DATA ,0x01 ); +vpg_write (vpg,DW_VPG_SEL_DATA ,0x03 ); + +vpg_horizontal_set (vpg, &v_mode); + +vpg_vertical_set (vpg, &v_mode); + +vpg_set_fps (vpg, mode); + +vpg_select_pattern (vpg,0 ); +} + +static void vpg_crtc_atomic_begin (struct drm_crtc *crtc, +struct drm_crtc_state *state) +{ +struct drm_pending_vblank_event *event = crtc->state->event; + +if (event) { + crtc->state->event =NULL ; +spin_lock_irq (&crtc->dev->event_lock); +drm_crtc_send_vblank_event (crtc, event); +spin_unlock_irq (&crtc->dev->event_lock); + } +} + +static struct drm_crtc_helper_funcs vpg_crtc_helper_funcs = { + .mode_set_nofb = vpg_crtc_mode_set_nofb, + .atomic_begin = vpg_crtc_atomic_begin, +}; + +static int vpg_crtc_late_register (struct drm_crtc *crtc) +{ +struct ipk_device *ipk =drm_device_to_ipk_device (crtc->dev); +struct platform_device *pdev = ipk->platform; +int ret; + + ret =sysfs_create_group (&pdev->dev.kobj, &vpg_attr_group); +if (ret) +drm_err (crtc->dev,"Failed to create sysfs entries" ); + +return ret; +} + +static void vpg_crtc_early_unregister (struct drm_crtc *crtc) +{ +struct ipk_device *ipk =drm_device_to_ipk_device (crtc->dev); +struct platform_device *pdev = ipk->platform; + +sysfs_remove_group (&pdev->dev.kobj, &vpg_attr_group); +} + +static const struct drm_crtc_funcs vpg_crtc_funcs = { + .reset = drm_atomic_helper_crtc_reset, + .destroy = drm_crtc_cleanup, + .set_config = drm_atomic_helper_set_config, + .page_flip = drm_atomic_helper_page_flip, + .atomic_duplicate_state = drm_atomic_helper_crtc_duplicate_state, + .atomic_destroy_state = drm_atomic_helper_crtc_destroy_state, + .late_register = vpg_crtc_late_register, + .early_unregister = vpg_crtc_early_unregister +}; + +/* +* Plane +*/ +static void vpg_plane_atomic_update (struct drm_plane *plane, +struct drm_plane_state *old_state) +{ +struct ipk_device *ipk =drm_device_to_ipk_device (plane->dev); +struct drm_plane_state *state = plane->state; +struct drm_framebuffer *fb = state->fb; +struct vpg_device *vpg = ipk->vpg; +enum vpg_pixel_fmt pixel_format; + + pixel_format =to_vpg_pixel_format (fb->format->format); + +vpg_write (vpg,DW_VPG_DPICOLORMODE , pixel_format); +} + +static void vpg_plane_atomic_disable (struct drm_plane *plane, +struct drm_plane_state *oldstate) +{ +DRM_DEBUG_DRIVER ("\n" ); +} + +static const struct drm_plane_helper_funcs vpg_plane_helper_funcs = { + .atomic_update = vpg_plane_atomic_update, + .atomic_disable = vpg_plane_atomic_disable, +}; + +static const struct drm_plane_funcs vpg_plane_funcs = { + .update_plane = drm_atomic_helper_update_plane, + .disable_plane = drm_atomic_helper_disable_plane, + .destroy = drm_plane_cleanup, + .reset = drm_atomic_helper_plane_reset, + .atomic_duplicate_state = drm_atomic_helper_plane_duplicate_state, + .atomic_destroy_state = drm_atomic_helper_plane_destroy_state, +}; + +static void vpg_plane_destroy_all (struct drm_device *drm) +{ +struct drm_plane *plane, *plane_temp; + +list_for_each_entry_safe (plane, plane_temp, + &drm->mode_config.plane_list, head) +drm_plane_cleanup (plane); +} + +static int vpg_crtc_init (struct drm_device *drm,struct drm_crtc *crtc) +{ +u32 formats[ARRAY_SIZE (supported_formats)], i; +const u64 *modifiers = vpg_format_modifiers; +unsigned long possible_crtcs =CRTC_MASK ; +struct device *drm_dev = drm->dev; +struct drm_plane *plane; +int ret; + + plane =devm_kzalloc (drm_dev,sizeof (*plane),GFP_KERNEL ); +if (!plane) +return -ENOMEM ; + +for (i =0 ; i <ARRAY_SIZE (supported_formats); i++) + formats[i] = supported_formats[i].fourcc; + + ret =drm_universal_plane_init (drm, plane, possible_crtcs, + &vpg_plane_funcs, formats, +ARRAY_SIZE (formats), modifiers, +DRM_PLANE_TYPE_PRIMARY ,NULL ); +if (ret) + goto cleanup_planes; + +drm_plane_helper_add (plane, &vpg_plane_helper_funcs); + +DRM_DEBUG_DRIVER ("plane:%d created\n" , plane->base.id); + + ret =drm_crtc_init_with_planes (drm, crtc, plane,NULL , + &vpg_crtc_funcs,"DSI-VPG" ); +if (ret) { +DRM_DEBUG_DRIVER ("Failed initialize CRTC\n" ); + goto cleanup_crtc; + } + +drm_crtc_helper_add (crtc, &vpg_crtc_helper_funcs); + +DRM_DEBUG_DRIVER ("CRTC:%d created\n" , crtc->base.id); + +return ret; + +cleanup_crtc: +drm_crtc_cleanup (crtc); +cleanup_planes: +vpg_plane_destroy_all (drm); +return ret; +} + +int vpg_load (struct drm_device *drm) +{ +struct ipk_device *ipk =drm_device_to_ipk_device (drm); +struct drm_bridge *bridge[MAX_ENDPOINTS ] = {NULL }; +struct drm_panel *panel[MAX_ENDPOINTS ] = {NULL }; +struct platform_device *pdev = ipk->platform; +struct device_node *np = drm->dev->of_node; +int ret, i, endpoint_not_ready = -ENODEV ; +struct reset_control *vpg_rst, *mmcm_rst; +struct device *dev = drm->dev; +struct vpg_device *vpg; +struct drm_crtc *crtc; +struct resource *res; + +DRM_DEBUG_DRIVER ("\n" ); + + vpg =devm_kzalloc (&pdev->dev,sizeof (*vpg),GFP_KERNEL ); +if (!vpg) +return -ENOMEM ; + + ipk->vpg = vpg; + +/* Get endpoints if any */ +for (i =0 ; i <MAX_ENDPOINTS ; i++) { + ret =drm_of_find_panel_or_bridge (np,0 , i, &panel[i], + &bridge[i]); +if (ret == -EPROBE_DEFER ) +return ret; +else if (!ret) + endpoint_not_ready =0 ; + } + +if (endpoint_not_ready) +return endpoint_not_ready; + + res =platform_get_resource_byname (pdev,IORESOURCE_MEM ,"vpg" ); + vpg->base =devm_ioremap_resource (dev, res); +if (IS_ERR (vpg->base)) { +drm_err (drm,"Unable to get VPG registers\n" ); + ret =PTR_ERR (vpg->base); + goto err; + } + + vpg_rst =devm_reset_control_get_optional_exclusive (dev,"vpg" ); +if (IS_ERR (vpg_rst)) { + ret =PTR_ERR (vpg_rst); +if (ret != -EPROBE_DEFER ) +drm_err (drm,"Unable to get reset control: %d\n" , ret); + goto err; + } + +if (vpg_rst) { +reset_control_assert (vpg_rst); +usleep_range (10 ,20 ); +reset_control_deassert (vpg_rst); + } + + res =platform_get_resource_byname (pdev,IORESOURCE_MEM ,"mmcm" ); + vpg->base_mmcm =devm_ioremap_resource (dev, res); +if (IS_ERR (vpg->base)) { + ret =PTR_ERR (vpg->base); + goto err; + } + + mmcm_rst =devm_reset_control_get_optional_exclusive (dev,"mmcm" ); +if (IS_ERR (mmcm_rst)) { + ret =PTR_ERR (mmcm_rst); +if (ret != -EPROBE_DEFER ) +drm_err (drm,"Unable to get reset control: %d\n" , ret); + goto err; + } + +if (mmcm_rst) { +reset_control_assert (mmcm_rst); +usleep_range (10 ,20 ); +reset_control_deassert (mmcm_rst); + } + +/* Add endpoints panels or bridges if any */ +for (i =0 ; i <MAX_ENDPOINTS ; i++) { +if (panel[i]) { + bridge[i] =drm_panel_bridge_add_typed (panel[i], +DRM_MODE_CONNECTOR_DSI ); +if (IS_ERR (bridge[i])) { + ret =PTR_ERR (bridge[i]); + goto err; + } + } + +if (bridge[i]) { + ret =ipk_encoder_init (drm, bridge[i]); +if (ret) + goto err; + } + } + + crtc =devm_kzalloc (dev,sizeof (*crtc),GFP_KERNEL ); +if (!crtc) { + ret = -ENOMEM ; + goto err; + } + + ret =vpg_crtc_init (drm, crtc); +if (ret) + goto err; + +return ret; + +err: +for (i =0 ; i <MAX_ENDPOINTS ; i++) +drm_panel_bridge_remove (bridge[i]); + +return ret; +} + +void vpg_unload (struct drm_device *drm) +{ +int i; + +DRM_DEBUG_DRIVER ("\n" ); +for (i =0 ; i <MAX_ENDPOINTS ; i++) +drm_of_panel_bridge_remove (drm->dev->of_node,0 , i); +}drivers/gpu/drm/ipk/dw-vpg.h new file +55
-0@@ -0,0 +1,55 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* +* Copyright (c) 2019-2020 Synopsys, Inc. and/or its affiliates. +* Synopsys DesignWare VPG +*/ + +#ifndef _VPG_H_ +#define _VPG_H_ + +#define DW_VPG_PANX 0x00 +#define DW_VPG_PANY 0x04 +#define DW_VPG_PHASE_SEL 0x08 +#define DW_VPG_SEL_DATA 0x0C +#define DW_VPG_SWAP_BAY 0x10 +#define DW_VPG_TESTMODE 0x14 +#define DW_VPG_ZOOM_OUT 0x18 +#define DW_VPG_EDPICTRL 0x1C +#define DW_VPG_CANVAS 0x20 +#define DW_VPG_HBP_HSA 0x24 +#define DW_VPG_LINE_TIME 0x28 +#define DW_VPG_VBP_VFP_VSA 0x2C +#define DW_VPG_DPICOLORMODE 0x30 +#define DW_VPG_VERSION 0x34 +#define DW_VPG_EXTRNAL_EDPI 0x38 +#define DW_VPG_PVO_CEAVID 0x3C +#define DW_VPG_PAN_VALID 0x40 +#define DW_VPG_TECONTROL 0x44 +#define DW_VPG_IMAGE_START_POSITION_X 0x4C +#define DW_VPG_IMAGE_START_POSITION_Y 0x50 +#define DW_VPG_IMAGE_Y 0x54 +#define DW_VPG_IMAGE_WORD_COUNT 0x58 +#define DW_VPG_IMAGE_DATA_TYPE 0x5C +#define DW_VPG_LINE_PIXS_CNT 0x60 +#define DW_VPG_FRAME_LINES_CNT 0x64 + +#define DW_MMCM_MASK 0x1000 +#define DW_MMCM_CLKOUT0_REG_1 0x20 +#define DW_MMCM_CLKOUT0_REG_2 0x24 +#define DW_MMCM_CLKFBOUT_REG_1 0x50 +#define DW_MMCM_CLKFBOUT_REG_2 0x54 +#define DW_MMCM_POWER_REG 0xA0 + +#define DW_VPG_ZOOM_OUT_STEP 1 +#define DW_VPG_PAN_STEP 40 +#define DW_VPG_FREQ 25000/* [KHz] */ +#define DW_VPG_V_FRONT_PORCH 2 +#define DW_VPG_V_BACK_PORCH 2 +#define DW_VPG_V_SYNC 2 +#define SCREEN_SIZE_X 800 +#define SCREEN_SIZE_Y 480 + +int vpg_load (struct drm_device *ddev); +void vpg_unload (struct drm_device *ddev); + +#endif /* _VPG_H_ */ Signature · 6 lines
2.7.4 _______________________________________________ dri-devel mailing list [email protected] https://lists.freedesktop.org/mailman/listinfo/dri-devel
_______________________________________________
dri-devel mailing list
[email protected]
https://lists.freedesktop.org/mailman/listinfo/dri-devel
PATCH v2 3/4 drm: ipk: Add extensions for DW MIPI DSI Host driver
In reply to Angelo RibeiroAdd Synopsys DesignWare IPK specific extensions for Synopsys DesignWare MIPI DSI Host driver.
--- drivers/gpu/drm/ipk/Kconfig | 9 + drivers/gpu/drm/ipk/Makefile | 2 + drivers/gpu/drm/ipk/dw-mipi-dsi-ipk.c | 556 ++++++++++++++++++++++++++++++++++ 3 files changed, 567 insertions(+) create mode 100644 drivers/gpu/drm/ipk/dw-mipi-dsi-ipk.c
drivers/gpu/drm/ipk/Kconfig +9 -0
@@ -11,3 +11,12 @@ config DRM_IPK Enable support for the Synopsys DesignWare DRM DSI. To compile this driver as a module, choose M here: the module will be called ipk-drm. + +config DRM_IPK_DSI + tristate "Synopsys DesignWare IPK specific extensions for MIPI DSI" + depends on DRM_IPK + select DRM_DW_MIPI_DSI + help + Choose this option for Synopsys DesignWare IPK MIPI DSI support. + To compile this driver as a module, choose M here: the module + will be called dw-mipi-dsi-ipk.
drivers/gpu/drm/ipk/Makefile +2 -0
@@ -4,3 +4,5 @@ ipk-drm-y := \ dw-vpg.o obj-$(CONFIG_DRM_IPK) += ipk-drm.o + +obj-$(CONFIG_DRM_IPK_DSI) += dw-mipi-dsi-ipk.o
drivers/gpu/drm/ipk/dw-mipi-dsi-ipk.c new file +556 -0
556 lines not on this page · raw message
Signature · 1 line
2.7.4
Re: [PATCH v2 3/4] drm: ipk: Add extensions for DW MIPI DSI Host driver
Hi Angelo.
One nit below.
Sam
Quoted 61 lines · Angelo Ribeiro
Add Synopsys DesignWare IPK specific extensions for Synopsys DesignWare MIPI DSI Host driver.
Cc Maarten Lankhorst <[email protected]>Cc Maxime Ripard <[email protected]>Cc David Airlie <[email protected]>Cc Daniel Vetter <[email protected]>Cc Gustavo Pimentel <[email protected]>Cc Joao Pinto <[email protected]>Signed-off-by Angelo Ribeiro <[email protected]>--- drivers/gpu/drm/ipk/Kconfig | 9 + drivers/gpu/drm/ipk/Makefile | 2 + drivers/gpu/drm/ipk/dw-mipi-dsi-ipk.c | 556 ++++++++++++++++++++++++++++++++++ 3 files changed, 567 insertions(+) create mode 100644 drivers/gpu/drm/ipk/dw-mipi-dsi-ipk.cdrivers/gpu/drm/ipk/Kconfig +9
-0@@ -11,3 +11,12 @@ config DRM_IPK Enable support for the Synopsys DesignWare DRM DSI. To compile this driver as a module, choose M here: the module will be called ipk-drm. + +config DRM_IPK_DSI + tristate "Synopsys DesignWare IPK specific extensions for MIPI DSI" + depends on DRM_IPK + select DRM_DW_MIPI_DSI + help + Choose this option for Synopsys DesignWare IPK MIPI DSI support. + To compile this driver as a module, choose M here: the module + will be called dw-mipi-dsi-ipk.drivers/gpu/drm/ipk/Makefile +2
-0@@ -4,3 +4,5 @@ ipk-drm-y := \ dw-vpg.o obj-$(CONFIG_DRM_IPK) += ipk-drm.o + +obj-$(CONFIG_DRM_IPK_DSI) += dw-mipi-dsi-ipk.odrivers/gpu/drm/ipk/dw-mipi-dsi-ipk.c new file +11
-0@@ -0,0 +1,556 @@ +// SPDX-License-Identifier: GPL-2.0 +/* +* Copyright (c) 2019-2020 Synopsys, Inc. and/or its affiliates. +* Synopsys DesignWare MIPI DSI solution driver +* +* Author: Angelo Ribeiro <[email protected]> +* Author: Luis Oliveira <[email protected]> +*/ + +#include <linux/clk.h> +#include <linux/iopoll.h>
drivers/gpu/drm/ipk/dw-mipi-dsi-ipk.c line 21
Quoted 10 lines
drivers/gpu/drm/ipk/dw-mipi-dsi-ipk.c new file +10
-0+#include <linux/module.h> +#include <drm/drm_mipi_dsi.h> +#include <drm/bridge/dw_mipi_dsi.h> +#include <video/mipi_display.h> +#include <linux/of.h> +#include <linux/platform_device.h> + +#include <drm/drm_crtc.h> +#include <drm/drm_device.h> +#include <drm/drm_print.h>
Same rant as in previous mail about include file.
Rest of the driver looked good while quickly browsing the code.
Sam
_______________________________________________
dri-devel mailing list
[email protected]
https://lists.freedesktop.org/mailman/listinfo/dri-devel
RE: [PATCH v2 3/4] drm: ipk: Add extensions for DW MIPI DSI Host driver
Hi Sam,
Thanks for your revision
Angelo
From: Sam Ravnborg <[email protected]>
Date: Tue, Apr 07, 2020 at 18:51:59
Quoted 84 lines
Hi Angelo.
One nit below.
Sam
Quoted 61 lines · Angelo Ribeiro
Add Synopsys DesignWare IPK specific extensions for Synopsys DesignWare MIPI DSI Host driver.
Cc Maarten Lankhorst <[email protected]>Cc Maxime Ripard <[email protected]>Cc David Airlie <[email protected]>Cc Daniel Vetter <[email protected]>Cc Gustavo Pimentel <[email protected]>Cc Joao Pinto <[email protected]>Signed-off-by Angelo Ribeiro <[email protected]>--- drivers/gpu/drm/ipk/Kconfig | 9 + drivers/gpu/drm/ipk/Makefile | 2 + drivers/gpu/drm/ipk/dw-mipi-dsi-ipk.c | 556 ++++++++++++++++++++++++++++++++++ 3 files changed, 567 insertions(+) create mode 100644 drivers/gpu/drm/ipk/dw-mipi-dsi-ipk.cdrivers/gpu/drm/ipk/Kconfig +9
-0@@ -11,3 +11,12 @@ config DRM_IPK Enable support for the Synopsys DesignWare DRM DSI. To compile this driver as a module, choose M here: the module will be called ipk-drm. + +config DRM_IPK_DSI + tristate "Synopsys DesignWare IPK specific extensions for MIPI DSI" + depends on DRM_IPK + select DRM_DW_MIPI_DSI + help + Choose this option for Synopsys DesignWare IPK MIPI DSI support. + To compile this driver as a module, choose M here: the module + will be called dw-mipi-dsi-ipk.drivers/gpu/drm/ipk/Makefile +2
-0@@ -4,3 +4,5 @@ ipk-drm-y := \ dw-vpg.o obj-$(CONFIG_DRM_IPK) += ipk-drm.o + +obj-$(CONFIG_DRM_IPK_DSI) += dw-mipi-dsi-ipk.odrivers/gpu/drm/ipk/dw-mipi-dsi-ipk.c new file +11
-0@@ -0,0 +1,556 @@ +// SPDX-License-Identifier: GPL-2.0 +/* +* Copyright (c) 2019-2020 Synopsys, Inc. and/or its affiliates. +* Synopsys DesignWare MIPI DSI solution driver +* +* Author: Angelo Ribeiro <[email protected]> +* Author: Luis Oliveira <[email protected]> +*/ + +#include <linux/clk.h> +#include <linux/iopoll.h> drivers/gpu/drm/ipk/dw-mipi-dsi-ipk.c line 21
Quoted 10 lines
drivers/gpu/drm/ipk/dw-mipi-dsi-ipk.c new file +10
-0+#include <linux/module.h> +#include <drm/drm_mipi_dsi.h> +#include <drm/bridge/dw_mipi_dsi.h> +#include <video/mipi_display.h> +#include <linux/of.h> +#include <linux/platform_device.h> + +#include <drm/drm_crtc.h> +#include <drm/drm_device.h> +#include <drm/drm_print.h> Same rant as in previous mail about include file.
Rest of the driver looked good while quickly browsing the code.
Sam
PATCH v2 4/4 MAINTAINERS: Add IPK MIPI DSI Host driver entry
In reply to Angelo RibeiroCreates entry for Synopsys DesignWare IPK MIPI DSI host driver and adds myself as maintainer.
--- MAINTAINERS | 8 ++++++++ 1 file changed, 8 insertions(+)
MAINTAINERS +8 -0
@@ -5445,6 +5445,14 @@ S: Maintained F: drivers/gpu/drm/mcde/ F: Documentation/devicetree/bindings/display/ste,mcde.txt +DRM DRIVER FOR SYNOPSYS DESIGNWARE IPK +M: Angelo Ribeiro <[email protected]> +L: [email protected] +S: Maintained +F: drivers/gpu/drm/ipk/ +F: Documentation/devicetree/bindings/display/ipk/ +T: git git://anongit.freedesktop.org/drm/drm-misc + DRM DRIVER FOR TDFX VIDEO CARDS S: Orphan / Obsolete F: drivers/gpu/drm/tdfx/
Signature · 1 line
2.7.4