History

Merge tag 'shmob-drm-atomic-dt-tag2' of git://git.kernel.org/pub/scm/linux/kernel/git/geert/renesas-drivers into drm-next

drm: renesas: shmobile: Atomic conversion + DT support Currently, there are two drivers for the LCD controller on Renesas SuperH-based and ARM-based SH-Mobile and R-Mobile SoCs: 1. sh_mobile_lcdcfb, using the fbdev framework, 2. shmob_drm, using the DRM framework. However, only the former driver is used, as all platform support integrates the former. None of these drivers support DT-based systems. Convert the SH-Mobile DRM driver to atomic modesetting, and add DT support, complemented by the customary set of fixes and improvements. Acked-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com> Link: https://lore.kernel.org/r/cover.1694767208.git.geert+renesas@glider.be/ Signed-off-by: Dave Airlie <airlied@redhat.com>

Dave Airlie committed 3 years ago

Commit 2ba446f2 parents 6318080 1399eba17 files · +860 −813Browse files

Unified · Split

17 files
  1. Documentation/devicetree/bindings/display/renesas,shmobile-lcdc.yaml +130 −0
  2. Documentation/userspace-api/media/v4l/subdev-formats.rst +72 −0
  3. MAINTAINERS +11 −2
  4. drivers/gpu/drm/renesas/shmobile/Kconfig +2 −1
  5. drivers/gpu/drm/renesas/shmobile/Makefile +1 −2
  6. drivers/gpu/drm/renesas/shmobile/shmob_drm_backlight.c +0 −82
  7. drivers/gpu/drm/renesas/shmobile/shmob_drm_backlight.h +0 −19
  8. drivers/gpu/drm/renesas/shmobile/shmob_drm_crtc.c +280 −370
  9. drivers/gpu/drm/renesas/shmobile/shmob_drm_crtc.h +9 −18
  10. drivers/gpu/drm/renesas/shmobile/shmob_drm_drv.c +83 −96
  11. drivers/gpu/drm/renesas/shmobile/shmob_drm_drv.h +14 −4
  12. drivers/gpu/drm/renesas/shmobile/shmob_drm_kms.c +55 −22
  13. drivers/gpu/drm/renesas/shmobile/shmob_drm_kms.h +6 −3
  14. drivers/gpu/drm/renesas/shmobile/shmob_drm_plane.c +189 −137
  15. drivers/gpu/drm/renesas/shmobile/shmob_drm_plane.h +3 −2
  16. include/linux/platform_data/shmob_drm.h +3 −54
  17. include/uapi/linux/media-bus-format.h +2 −1
Documentation/devicetree/bindings/display/renesas,shmobile-lcdc.yaml+130−0
@@ -0,0 +1,130 @@
1+# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
2+%YAML 1.2
3+---
4+$id: http://devicetree.org/schemas/display/renesas,shmobile-lcdc.yaml#
5+$schema: http://devicetree.org/meta-schemas/core.yaml#
6+
7+title: Renesas SH-Mobile LCD Controller (LCDC)
8+
9+maintainers:
10+ - Laurent Pinchart <laurent.pinchart+renesas@ideasonboard.com>
11+ - Geert Uytterhoeven <geert+renesas@glider.be>
12+
13+properties:
14+ compatible:
15+ enum:
16+ - renesas,r8a7740-lcdc # R-Mobile A1
17+ - renesas,sh73a0-lcdc # SH-Mobile AG5
18+
19+ reg:
20+ maxItems: 1
21+
22+ interrupts:
23+ maxItems: 1
24+
25+ clocks:
26+ minItems: 1
27+ maxItems: 5
28+ description:
29+ Only the functional clock is mandatory.
30+ Some of the optional clocks are model-dependent (e.g. "video" (a.k.a.
31+ "vou" or "dv_clk") is available on R-Mobile A1 only).
32+
33+ clock-names:
34+ minItems: 1
35+ items:
36+ - const: fck
37+ - enum: [ media, lclk, hdmi, video ]
38+ - enum: [ media, lclk, hdmi, video ]
39+ - enum: [ media, lclk, hdmi, video ]
40+ - enum: [ media, lclk, hdmi, video ]
41+
42+ power-domains:
43+ maxItems: 1
44+
45+ ports:
46+ $ref: /schemas/graph.yaml#/properties/ports
47+
48+ properties:
49+ port@0:
50+ $ref: /schemas/graph.yaml#/properties/port
51+ description: LCD port (R-Mobile A1 and SH-Mobile AG5)
52+ unevaluatedProperties: false
53+
54+ port@1:
55+ $ref: /schemas/graph.yaml#/properties/port
56+ description: HDMI port (R-Mobile A1 LCDC1 and SH-Mobile AG5)
57+ unevaluatedProperties: false
58+
59+ port@2:
60+ $ref: /schemas/graph.yaml#/properties/port
61+ description: MIPI-DSI port (SH-Mobile AG5)
62+ unevaluatedProperties: false
63+
64+ required:
65+ - port@0
66+
67+ unevaluatedProperties: false
68+
69+required:
70+ - compatible
71+ - reg
72+ - interrupts
73+ - clocks
74+ - clock-names
75+ - power-domains
76+ - ports
77+
78+additionalProperties: false
79+
80+allOf:
81+ - if:
82+ properties:
83+ compatible:
84+ contains:
85+ const: renesas,r8a7740-lcdc
86+ then:
87+ properties:
88+ ports:
89+ properties:
90+ port@2: false
91+
92+ - if:
93+ properties:
94+ compatible:
95+ contains:
96+ const: renesas,sh73a0-lcdc
97+ then:
98+ properties:
99+ ports:
100+ required:
101+ - port@1
102+ - port@2
103+
104+examples:
105+ - |
106+ #include <dt-bindings/clock/r8a7740-clock.h>
107+ #include <dt-bindings/interrupt-controller/arm-gic.h>
108+
109+ lcd-controller@fe940000 {
110+ compatible = "renesas,r8a7740-lcdc";
111+ reg = <0xfe940000 0x4000>;
112+ interrupts = <GIC_SPI 177 IRQ_TYPE_LEVEL_HIGH>;
113+ clocks = <&mstp1_clks R8A7740_CLK_LCDC0>,
114+ <&cpg_clocks R8A7740_CLK_M3>, <&lcdlclk0_clk>,
115+ <&vou_clk>;
116+ clock-names = "fck", "media", "lclk", "video";
117+ power-domains = <&pd_a4lc>;
118+
119+ ports {
120+ #address-cells = <1>;
121+ #size-cells = <0>;
122+
123+ port@0 {
124+ reg = <0>;
125+
126+ lcdc0_rgb: endpoint {
127+ };
128+ };
129+ };
130+ };
Documentation/userspace-api/media/v4l/subdev-formats.rst+72−0
@@ -949,6 +949,78 @@ The following tables list existing packed RGB formats. · 948 unmodified lines
949949 - b\ :sub:`2`
950950 - b\ :sub:`1`
951951 - b\ :sub:`0`
952+ * .. _MEDIA-BUS-FMT-RGB666-2X9-BE:
953+
954+ - MEDIA_BUS_FMT_RGB666_2X9_BE
955+ - 0x1025
956+ -
957+ -
958+ -
959+ -
960+ -
961+ -
962+ -
963+ -
964+ -
965+ -
966+ -
967+ -
968+ -
969+ -
970+ -
971+ -
972+ -
973+ -
974+ -
975+ -
976+ -
977+ -
978+ -
979+ -
980+ - r\ :sub:`5`
981+ - r\ :sub:`4`
982+ - r\ :sub:`3`
983+ - r\ :sub:`2`
984+ - r\ :sub:`1`
985+ - r\ :sub:`0`
986+ - g\ :sub:`5`
987+ - g\ :sub:`4`
988+ - g\ :sub:`3`
989+ * -
990+ -
991+ -
992+ -
993+ -
994+ -
995+ -
996+ -
997+ -
998+ -
999+ -
1000+ -
1001+ -
1002+ -
1003+ -
1004+ -
1005+ -
1006+ -
1007+ -
1008+ -
1009+ -
1010+ -
1011+ -
1012+ -
1013+ -
1014+ -
1015+ - g\ :sub:`2`
1016+ - g\ :sub:`1`
1017+ - g\ :sub:`0`
1018+ - b\ :sub:`5`
1019+ - b\ :sub:`4`
1020+ - b\ :sub:`3`
1021+ - b\ :sub:`2`
1022+ - b\ :sub:`1`
1023+ - b\ :sub:`0`
9521024 * .. _MEDIA-BUS-FMT-BGR666-1X18:
9531025
9541026 - MEDIA_BUS_FMT_BGR666_1X18
MAINTAINERS+11−2
@@ -7053,7 +7053,7 @@ F: drivers/gpu/host1x/ · 7052 unmodified lines
70537053 F: include/linux/host1x.h
70547054 F: include/uapi/drm/tegra_drm.h
70557055
7056−DRM DRIVERS FOR RENESAS
7056+DRM DRIVERS FOR RENESAS R-CAR
70577057 M: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
70587058 M: Kieran Bingham <kieran.bingham+renesas@ideasonboard.com>
70597059 L: dri-devel@lists.freedesktop.org
@@ -7064,7 +7064,16 @@ F: Documentation/devicetree/bindings/display/bridge/renesas,dsi-csi2-tx.yaml · 4 unmodified lines
70647064 F: Documentation/devicetree/bindings/display/bridge/renesas,dw-hdmi.yaml
70657065 F: Documentation/devicetree/bindings/display/bridge/renesas,lvds.yaml
70667066 F: Documentation/devicetree/bindings/display/renesas,du.yaml
7067−F: drivers/gpu/drm/renesas/
7067+F: drivers/gpu/drm/renesas/rcar-du/
7068+
7069+DRM DRIVERS FOR RENESAS SHMOBILE
7070+M: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
7071+M: Geert Uytterhoeven <geert+renesas@glider.be>
7072+L: dri-devel@lists.freedesktop.org
7073+L: linux-renesas-soc@vger.kernel.org
7074+S: Supported
7075+F: Documentation/devicetree/bindings/display/renesas,shmobile-lcdc.yaml
7076+F: drivers/gpu/drm/renesas/shmobile/
70687077 F: include/linux/platform_data/shmob_drm.h
70697078
70707079 DRM DRIVERS FOR ROCKCHIP
drivers/gpu/drm/renesas/shmobile/Kconfig+2−1
@@ -1,11 +1,12 @@
11 # SPDX-License-Identifier: GPL-2.0
22 config DRM_SHMOBILE
33 tristate "DRM Support for SH Mobile"
4− depends on DRM
4+ depends on DRM && PM
55 depends on ARCH_RENESAS || ARCH_SHMOBILE || COMPILE_TEST
66 select BACKLIGHT_CLASS_DEVICE
77 select DRM_KMS_HELPER
88 select DRM_GEM_DMA_HELPER
9+ select VIDEOMODE_HELPERS
910 help
1011 Choose this option if you have an SH Mobile chipset.
1112 If M is selected the module will be called shmob-drm.
drivers/gpu/drm/renesas/shmobile/Makefile+1−2
@@ -1,6 +1,5 @@
11 # SPDX-License-Identifier: GPL-2.0
2−shmob-drm-y := shmob_drm_backlight.o \
3− shmob_drm_crtc.o \
2+shmob-drm-y := shmob_drm_crtc.o \
43 shmob_drm_drv.o \
54 shmob_drm_kms.o \
65 shmob_drm_plane.o
drivers/gpu/drm/renesas/shmobile/shmob_drm_backlight.c+0−82
@@ -1,82 +0,0 @@
1−// SPDX-License-Identifier: GPL-2.0+
2−/*
3− * shmob_drm_backlight.c -- SH Mobile DRM Backlight
4− *
5− * Copyright (C) 2012 Renesas Electronics Corporation
6− *
7− * Laurent Pinchart (laurent.pinchart@ideasonboard.com)
8− */
9−
10−#include <linux/backlight.h>
11−
12−#include "shmob_drm_backlight.h"
13−#include "shmob_drm_crtc.h"
14−#include "shmob_drm_drv.h"
15−
16−static int shmob_drm_backlight_update(struct backlight_device *bdev)
17−{
18− struct shmob_drm_connector *scon = bl_get_data(bdev);
19− struct shmob_drm_device *sdev = scon->connector.dev->dev_private;
20− const struct shmob_drm_backlight_data *bdata = &sdev->pdata->backlight;
21− int brightness = backlight_get_brightness(bdev);
22−
23− return bdata->set_brightness(brightness);
24−}
25−
26−static int shmob_drm_backlight_get_brightness(struct backlight_device *bdev)
27−{
28− struct shmob_drm_connector *scon = bl_get_data(bdev);
29− struct shmob_drm_device *sdev = scon->connector.dev->dev_private;
30− const struct shmob_drm_backlight_data *bdata = &sdev->pdata->backlight;
31−
32− return bdata->get_brightness();
33−}
34−
35−static const struct backlight_ops shmob_drm_backlight_ops = {
36− .options = BL_CORE_SUSPENDRESUME,
37− .update_status = shmob_drm_backlight_update,
38− .get_brightness = shmob_drm_backlight_get_brightness,
39−};
40−
41−void shmob_drm_backlight_dpms(struct shmob_drm_connector *scon, int mode)
42−{
43− if (scon->backlight == NULL)
44− return;
45−
46− scon->backlight->props.power = mode == DRM_MODE_DPMS_ON
47− ? FB_BLANK_UNBLANK : FB_BLANK_POWERDOWN;
48− backlight_update_status(scon->backlight);
49−}
50−
51−int shmob_drm_backlight_init(struct shmob_drm_connector *scon)
52−{
53− struct shmob_drm_device *sdev = scon->connector.dev->dev_private;
54− const struct shmob_drm_backlight_data *bdata = &sdev->pdata->backlight;
55− struct drm_connector *connector = &scon->connector;
56− struct drm_device *dev = connector->dev;
57− struct backlight_device *backlight;
58−
59− if (!bdata->max_brightness)
60− return 0;
61−
62− backlight = backlight_device_register(bdata->name, dev->dev, scon,
63− &shmob_drm_backlight_ops, NULL);
64− if (IS_ERR(backlight)) {
65− dev_err(dev->dev, "unable to register backlight device: %ld\n",
66− PTR_ERR(backlight));
67− return PTR_ERR(backlight);
68− }
69−
70− backlight->props.max_brightness = bdata->max_brightness;
71− backlight->props.brightness = bdata->max_brightness;
72− backlight->props.power = FB_BLANK_POWERDOWN;
73− backlight_update_status(backlight);
74−
75− scon->backlight = backlight;
76− return 0;
77−}
78−
79−void shmob_drm_backlight_exit(struct shmob_drm_connector *scon)
80−{
81− backlight_device_unregister(scon->backlight);
82−}
drivers/gpu/drm/renesas/shmobile/shmob_drm_backlight.h+0−19
@@ -1,19 +0,0 @@
1−/* SPDX-License-Identifier: GPL-2.0+ */
2−/*
3− * shmob_drm_backlight.h -- SH Mobile DRM Backlight
4− *
5− * Copyright (C) 2012 Renesas Electronics Corporation
6− *
7− * Laurent Pinchart (laurent.pinchart@ideasonboard.com)
8− */
9−
10−#ifndef __SHMOB_DRM_BACKLIGHT_H__
11−#define __SHMOB_DRM_BACKLIGHT_H__
12−
13−struct shmob_drm_connector;
14−
15−void shmob_drm_backlight_dpms(struct shmob_drm_connector *scon, int mode);
16−int shmob_drm_backlight_init(struct shmob_drm_connector *scon);
17−void shmob_drm_backlight_exit(struct shmob_drm_connector *scon);
18−
19−#endif /* __SHMOB_DRM_BACKLIGHT_H__ */
drivers/gpu/drm/renesas/shmobile/shmob_drm_crtc.c+280−370
@@ -7,9 +7,18 @@ · 6 unmodified lines
77 * Laurent Pinchart (laurent.pinchart@ideasonboard.com)
88 */
99
10−#include <linux/backlight.h>
1110 #include <linux/clk.h>
12−
11+#include <linux/media-bus-format.h>
12+#include <linux/of.h>
13+#include <linux/of_graph.h>
14+#include <linux/pm_runtime.h>
15+
16+#include <drm/drm_atomic.h>
17+#include <drm/drm_atomic_helper.h>
18+#include <drm/drm_atomic_state_helper.h>
19+#include <drm/drm_atomic_uapi.h>
20+#include <drm/drm_bridge.h>
21+#include <drm/drm_bridge_connector.h>
1322 #include <drm/drm_crtc.h>
1423 #include <drm/drm_crtc_helper.h>
1524 #include <drm/drm_fb_dma_helper.h>
@@ -18,85 +27,123 @@ · 2 unmodified lines
1827 #include <drm/drm_gem_dma_helper.h>
1928 #include <drm/drm_modeset_helper.h>
2029 #include <drm/drm_modeset_helper_vtables.h>
21−#include <drm/drm_plane_helper.h>
30+#include <drm/drm_panel.h>
2231 #include <drm/drm_probe_helper.h>
2332 #include <drm/drm_simple_kms_helper.h>
2433 #include <drm/drm_vblank.h>
2534
26−#include "shmob_drm_backlight.h"
35+#include <video/videomode.h>
36+
2737 #include "shmob_drm_crtc.h"
2838 #include "shmob_drm_drv.h"
2939 #include "shmob_drm_kms.h"
3040 #include "shmob_drm_plane.h"
3141 #include "shmob_drm_regs.h"
3242
33−/*
34− * TODO: panel support
35− */
36−
3743 /* -----------------------------------------------------------------------------
38− * Clock management
44+ * Page Flip
3945 */
4046
41−static int shmob_drm_clk_on(struct shmob_drm_device *sdev)
47+void shmob_drm_crtc_finish_page_flip(struct shmob_drm_crtc *scrtc)
4248 {
43− int ret;
49+ struct drm_pending_vblank_event *event;
50+ struct drm_device *dev = scrtc->base.dev;
51+ unsigned long flags;
4452
45− if (sdev->clock) {
46− ret = clk_prepare_enable(sdev->clock);
47− if (ret < 0)
48− return ret;
53+ spin_lock_irqsave(&dev->event_lock, flags);
54+ event = scrtc->event;
55+ scrtc->event = NULL;
56+ if (event) {
57+ drm_crtc_send_vblank_event(&scrtc->base, event);
58+ wake_up(&scrtc->flip_wait);
59+ drm_crtc_vblank_put(&scrtc->base);
4960 }
61+ spin_unlock_irqrestore(&dev->event_lock, flags);
62+}
5063
51− return 0;
64+static bool shmob_drm_crtc_page_flip_pending(struct shmob_drm_crtc *scrtc)
65+{
66+ struct drm_device *dev = scrtc->base.dev;
67+ unsigned long flags;
68+ bool pending;
69+
70+ spin_lock_irqsave(&dev->event_lock, flags);
71+ pending = scrtc->event != NULL;
72+ spin_unlock_irqrestore(&dev->event_lock, flags);
73+
74+ return pending;
5275 }
5376
54−static void shmob_drm_clk_off(struct shmob_drm_device *sdev)
77+static void shmob_drm_crtc_wait_page_flip(struct shmob_drm_crtc *scrtc)
5578 {
56− if (sdev->clock)
57− clk_disable_unprepare(sdev->clock);
79+ struct drm_crtc *crtc = &scrtc->base;
80+ struct shmob_drm_device *sdev = to_shmob_device(crtc->dev);
81+
82+ if (wait_event_timeout(scrtc->flip_wait,
83+ !shmob_drm_crtc_page_flip_pending(scrtc),
84+ msecs_to_jiffies(50)))
85+ return;
86+
87+ dev_warn(sdev->dev, "page flip timeout\n");
88+
89+ shmob_drm_crtc_finish_page_flip(scrtc);
5890 }
5991
6092 /* -----------------------------------------------------------------------------
6193 * CRTC
6294 */
6395
96+static const struct {
97+ u32 fmt;
98+ u32 ldmt1r;
99+} shmob_drm_bus_fmts[] = {
100+ { MEDIA_BUS_FMT_RGB888_3X8, LDMT1R_MIFTYP_RGB8 },
101+ { MEDIA_BUS_FMT_RGB666_2X9_BE, LDMT1R_MIFTYP_RGB9 },
102+ { MEDIA_BUS_FMT_RGB888_2X12_BE, LDMT1R_MIFTYP_RGB12A },
103+ { MEDIA_BUS_FMT_RGB444_1X12, LDMT1R_MIFTYP_RGB12B },
104+ { MEDIA_BUS_FMT_RGB565_1X16, LDMT1R_MIFTYP_RGB16 },
105+ { MEDIA_BUS_FMT_RGB666_1X18, LDMT1R_MIFTYP_RGB18 },
106+ { MEDIA_BUS_FMT_RGB888_1X24, LDMT1R_MIFTYP_RGB24 },
107+ { MEDIA_BUS_FMT_UYVY8_1X16, LDMT1R_MIFTYP_YCBCR },
108+};
109+
64110 static void shmob_drm_crtc_setup_geometry(struct shmob_drm_crtc *scrtc)
65111 {
66− struct drm_crtc *crtc = &scrtc->crtc;
67− struct shmob_drm_device *sdev = crtc->dev->dev_private;
68− const struct shmob_drm_interface_data *idata = &sdev->pdata->iface;
112+ struct drm_crtc *crtc = &scrtc->base;
113+ struct shmob_drm_device *sdev = to_shmob_device(crtc->dev);
114+ const struct drm_display_info *info = &sdev->connector->display_info;
69115 const struct drm_display_mode *mode = &crtc->mode;
116+ unsigned int i;
70117 u32 value;
71118
72− value = sdev->ldmt1r
73− | ((mode->flags & DRM_MODE_FLAG_PVSYNC) ? 0 : LDMT1R_VPOL)
74− | ((mode->flags & DRM_MODE_FLAG_PHSYNC) ? 0 : LDMT1R_HPOL)
75− | ((idata->flags & SHMOB_DRM_IFACE_FL_DWPOL) ? LDMT1R_DWPOL : 0)
76− | ((idata->flags & SHMOB_DRM_IFACE_FL_DIPOL) ? LDMT1R_DIPOL : 0)
77− | ((idata->flags & SHMOB_DRM_IFACE_FL_DAPOL) ? LDMT1R_DAPOL : 0)
78− | ((idata->flags & SHMOB_DRM_IFACE_FL_HSCNT) ? LDMT1R_HSCNT : 0)
79− | ((idata->flags & SHMOB_DRM_IFACE_FL_DWCNT) ? LDMT1R_DWCNT : 0);
80− lcdc_write(sdev, LDMT1R, value);
81−
82− if (idata->interface >= SHMOB_DRM_IFACE_SYS8A &&
83− idata->interface <= SHMOB_DRM_IFACE_SYS24) {
84− /* Setup SYS bus. */
85− value = (idata->sys.cs_setup << LDMT2R_CSUP_SHIFT)
86− | (idata->sys.vsync_active_high ? LDMT2R_RSV : 0)
87− | (idata->sys.vsync_dir_input ? LDMT2R_VSEL : 0)
88− | (idata->sys.write_setup << LDMT2R_WCSC_SHIFT)
89− | (idata->sys.write_cycle << LDMT2R_WCEC_SHIFT)
90− | (idata->sys.write_strobe << LDMT2R_WCLW_SHIFT);
91− lcdc_write(sdev, LDMT2R, value);
92−
93− value = (idata->sys.read_latch << LDMT3R_RDLC_SHIFT)
94− | (idata->sys.read_setup << LDMT3R_RCSC_SHIFT)
95− | (idata->sys.read_cycle << LDMT3R_RCEC_SHIFT)
96− | (idata->sys.read_strobe << LDMT3R_RCLW_SHIFT);
97− lcdc_write(sdev, LDMT3R, value);
119+ if (!info->num_bus_formats || !info->bus_formats) {
120+ dev_warn(sdev->dev, "No bus format reported, using RGB888\n");
121+ value = LDMT1R_MIFTYP_RGB24;
122+ } else {
123+ for (i = 0; i < ARRAY_SIZE(shmob_drm_bus_fmts); i++) {
124+ if (shmob_drm_bus_fmts[i].fmt == info->bus_formats[0])
125+ break;
126+ }
127+ if (i < ARRAY_SIZE(shmob_drm_bus_fmts)) {
128+ value = shmob_drm_bus_fmts[i].ldmt1r;
129+ } else {
130+ dev_warn(sdev->dev,
131+ "unsupported bus format 0x%x, using RGB888\n",
132+ info->bus_formats[0]);
133+ value = LDMT1R_MIFTYP_RGB24;
134+ }
98135 }
99136
137+ if (info->bus_flags & DRM_BUS_FLAG_PIXDATA_DRIVE_POSEDGE)
138+ value |= LDMT1R_DWPOL;
139+ if (info->bus_flags & DRM_BUS_FLAG_DE_LOW)
140+ value |= LDMT1R_DIPOL;
141+ if (mode->flags & DRM_MODE_FLAG_NVSYNC)
142+ value |= LDMT1R_VPOL;
143+ if (mode->flags & DRM_MODE_FLAG_NHSYNC)
144+ value |= LDMT1R_HPOL;
145+ lcdc_write(sdev, LDMT1R, value);
146+
100147 value = ((mode->hdisplay / 8) << 16) /* HDCN */
101148 | (mode->htotal / 8); /* HTCN */
102149 lcdc_write(sdev, LDHCNR, value);
@@ -121,7 +168,7 @@ static void shmob_drm_crtc_setup_geometry(struct shmob_drm_crtc *scrtc) · 18 unmodified lines
121168
122169 static void shmob_drm_crtc_start_stop(struct shmob_drm_crtc *scrtc, bool start)
123170 {
124− struct shmob_drm_device *sdev = scrtc->crtc.dev->dev_private;
171+ struct shmob_drm_device *sdev = to_shmob_device(scrtc->base.dev);
125172 u32 value;
126173
127174 value = lcdc_read(sdev, LDCNT2R);
@@ -145,34 +192,23 @@ static void shmob_drm_crtc_start_stop(struct shmob_drm_crtc *scrtc, bool start) · 17 unmodified lines
145192 }
146193 }
147194
148−/*
149− * shmob_drm_crtc_start - Configure and start the LCDC
150− * @scrtc: the SH Mobile CRTC
151− *
152− * Configure and start the LCDC device. External devices (clocks, MERAM, panels,
153− * ...) are not touched by this function.
154− */
155−static void shmob_drm_crtc_start(struct shmob_drm_crtc *scrtc)
195+static inline struct shmob_drm_crtc *to_shmob_crtc(struct drm_crtc *crtc)
196+{
197+ return container_of(crtc, struct shmob_drm_crtc, base);
198+}
199+
200+static void shmob_drm_crtc_atomic_enable(struct drm_crtc *crtc,
201+ struct drm_atomic_state *state)
156202 {
157− struct drm_crtc *crtc = &scrtc->crtc;
158− struct shmob_drm_device *sdev = crtc->dev->dev_private;
159− const struct shmob_drm_interface_data *idata = &sdev->pdata->iface;
160− const struct shmob_drm_format_info *format;
161− struct drm_device *dev = sdev->ddev;
162− struct drm_plane *plane;
203+ struct shmob_drm_crtc *scrtc = to_shmob_crtc(crtc);
204+ struct shmob_drm_device *sdev = to_shmob_device(crtc->dev);
205+ unsigned int clk_div = sdev->config.clk_div;
206+ struct device *dev = sdev->dev;
163207 u32 value;
164208 int ret;
165209
166− if (scrtc->started)
167− return;
168−
169− format = shmob_drm_format_info(crtc->primary->fb->format->format);
170− if (WARN_ON(format == NULL))
171− return;
172−
173− /* Enable clocks before accessing the hardware. */
174− ret = shmob_drm_clk_on(sdev);
175− if (ret < 0)
210+ ret = pm_runtime_resume_and_get(dev);
211+ if (ret)
176212 return;
177213
178214 /* Reset and enable the LCDC. */
@@ -188,79 +224,50 @@ static void shmob_drm_crtc_start(struct shmob_drm_crtc *scrtc) · 9 unmodified lines
188224 lcdc_write(sdev, LDPMR, 0);
189225
190226 value = sdev->lddckr;
191− if (idata->clk_div) {
227+ if (clk_div) {
192228 /* FIXME: sh7724 can only use 42, 48, 54 and 60 for the divider
193229 * denominator.
194230 */
195231 lcdc_write(sdev, LDDCKPAT1R, 0);
196− lcdc_write(sdev, LDDCKPAT2R, (1 << (idata->clk_div / 2)) - 1);
232+ lcdc_write(sdev, LDDCKPAT2R, (1 << (clk_div / 2)) - 1);
197233
198− if (idata->clk_div == 1)
234+ if (clk_div == 1)
199235 value |= LDDCKR_MOSEL;
200236 else
201− value |= idata->clk_div;
237+ value |= clk_div;
202238 }
203239
204240 lcdc_write(sdev, LDDCKR, value);
205241 lcdc_write(sdev, LDDCKSTPR, 0);
206242 lcdc_wait_bit(sdev, LDDCKSTPR, ~0, 0);
207243
208− /* TODO: Setup SYS panel */
209−
210244 /* Setup geometry, format, frame buffer memory and operation mode. */
211245 shmob_drm_crtc_setup_geometry(scrtc);
212246
213− /* TODO: Handle YUV colorspaces. Hardcode REC709 for now. */
214− lcdc_write(sdev, LDDFR, format->lddfr | LDDFR_CF1);
215− lcdc_write(sdev, LDMLSR, scrtc->line_size);
216− lcdc_write(sdev, LDSA1R, scrtc->dma[0]);
217− if (format->yuv)
218− lcdc_write(sdev, LDSA2R, scrtc->dma[1]);
219247 lcdc_write(sdev, LDSM1R, 0);
220248
221− /* Word and long word swap. */
222− switch (format->fourcc) {
223− case DRM_FORMAT_RGB565:
224− case DRM_FORMAT_NV21:
225− case DRM_FORMAT_NV61:
226− case DRM_FORMAT_NV42:
227− value = LDDDSR_LS | LDDDSR_WS;
228− break;
229− case DRM_FORMAT_RGB888:
230− case DRM_FORMAT_NV12:
231− case DRM_FORMAT_NV16:
232− case DRM_FORMAT_NV24:
233− value = LDDDSR_LS | LDDDSR_WS | LDDDSR_BS;
234− break;
235− case DRM_FORMAT_ARGB8888:
236− case DRM_FORMAT_XRGB8888:
237− default:
238− value = LDDDSR_LS;
239− break;
240− }
241− lcdc_write(sdev, LDDDSR, value);
242−
243− /* Setup planes. */
244− drm_for_each_legacy_plane(plane, dev) {
245− if (plane->crtc == crtc)
246− shmob_drm_plane_setup(plane);
247− }
248−
249249 /* Enable the display output. */
250250 lcdc_write(sdev, LDCNT1R, LDCNT1R_DE);
251251
252252 shmob_drm_crtc_start_stop(scrtc, true);
253253
254− scrtc->started = true;
254+ /* Turn vertical blank interrupt reporting back on. */
255+ drm_crtc_vblank_on(crtc);
255256 }
256257
257−static void shmob_drm_crtc_stop(struct shmob_drm_crtc *scrtc)
258+static void shmob_drm_crtc_atomic_disable(struct drm_crtc *crtc,
259+ struct drm_atomic_state *state)
258260 {
259− struct drm_crtc *crtc = &scrtc->crtc;
260− struct shmob_drm_device *sdev = crtc->dev->dev_private;
261+ struct shmob_drm_crtc *scrtc = to_shmob_crtc(crtc);
262+ struct shmob_drm_device *sdev = to_shmob_device(crtc->dev);
261263
262− if (!scrtc->started)
263− return;
264+ /*
265+ * Disable vertical blank interrupt reporting. We first need to wait
266+ * for page flip completion before stopping the CRTC as userspace
267+ * expects page flips to eventually complete.
268+ */
269+ shmob_drm_crtc_wait_page_flip(scrtc);
270+ drm_crtc_vblank_off(crtc);
264271
265272 /* Stop the LCDC. */
266273 shmob_drm_crtc_start_stop(scrtc, false);
@@ -268,145 +275,31 @@ static void shmob_drm_crtc_stop(struct shmob_drm_crtc *scrtc) · 1 unmodified line
268275 /* Disable the display output. */
269276 lcdc_write(sdev, LDCNT1R, 0);
270277
271− /* Stop clocks. */
272− shmob_drm_clk_off(sdev);
273−
274− scrtc->started = false;
275−}
276−
277−void shmob_drm_crtc_suspend(struct shmob_drm_crtc *scrtc)
278−{
279− shmob_drm_crtc_stop(scrtc);
280−}
281−
282−void shmob_drm_crtc_resume(struct shmob_drm_crtc *scrtc)
283−{
284− if (scrtc->dpms != DRM_MODE_DPMS_ON)
285− return;
286−
287− shmob_drm_crtc_start(scrtc);
278+ pm_runtime_put(sdev->dev);
288279 }
289280
290−static void shmob_drm_crtc_compute_base(struct shmob_drm_crtc *scrtc,
291− int x, int y)
281+static void shmob_drm_crtc_atomic_flush(struct drm_crtc *crtc,
282+ struct drm_atomic_state *state)
292283 {
293− struct drm_crtc *crtc = &scrtc->crtc;
294− struct drm_framebuffer *fb = crtc->primary->fb;
295− struct drm_gem_dma_object *gem;
296− unsigned int bpp;
297−
298− bpp = scrtc->format->yuv ? 8 : scrtc->format->bpp;
299− gem = drm_fb_dma_get_gem_obj(fb, 0);
300− scrtc->dma[0] = gem->dma_addr + fb->offsets[0]
301− + y * fb->pitches[0] + x * bpp / 8;
302−
303− if (scrtc->format->yuv) {
304− bpp = scrtc->format->bpp - 8;
305− gem = drm_fb_dma_get_gem_obj(fb, 1);
306− scrtc->dma[1] = gem->dma_addr + fb->offsets[1]
307− + y / (bpp == 4 ? 2 : 1) * fb->pitches[1]
308− + x * (bpp == 16 ? 2 : 1);
309− }
310−}
311−
312−static void shmob_drm_crtc_update_base(struct shmob_drm_crtc *scrtc)
313−{
314− struct drm_crtc *crtc = &scrtc->crtc;
315− struct shmob_drm_device *sdev = crtc->dev->dev_private;
316−
317− shmob_drm_crtc_compute_base(scrtc, crtc->x, crtc->y);
318−
319− lcdc_write_mirror(sdev, LDSA1R, scrtc->dma[0]);
320− if (scrtc->format->yuv)
321− lcdc_write_mirror(sdev, LDSA2R, scrtc->dma[1]);
322−
323− lcdc_write(sdev, LDRCNTR, lcdc_read(sdev, LDRCNTR) ^ LDRCNTR_MRS);
324−}
325−
326−#define to_shmob_crtc(c) container_of(c, struct shmob_drm_crtc, crtc)
327−
328−static void shmob_drm_crtc_dpms(struct drm_crtc *crtc, int mode)
329−{
330− struct shmob_drm_crtc *scrtc = to_shmob_crtc(crtc);
331−
332− if (scrtc->dpms == mode)
333− return;
334−
335− if (mode == DRM_MODE_DPMS_ON)
336− shmob_drm_crtc_start(scrtc);
337− else
338− shmob_drm_crtc_stop(scrtc);
339−
340− scrtc->dpms = mode;
341−}
342−
343−static void shmob_drm_crtc_mode_prepare(struct drm_crtc *crtc)
344−{
345− shmob_drm_crtc_dpms(crtc, DRM_MODE_DPMS_OFF);
346−}
284+ struct drm_pending_vblank_event *event;
285+ struct drm_device *dev = crtc->dev;
286+ unsigned long flags;
347287
348−static int shmob_drm_crtc_mode_set(struct drm_crtc *crtc,
349− struct drm_display_mode *mode,
350− struct drm_display_mode *adjusted_mode,
351− int x, int y,
352− struct drm_framebuffer *old_fb)
353−{
354− struct shmob_drm_crtc *scrtc = to_shmob_crtc(crtc);
355− struct shmob_drm_device *sdev = crtc->dev->dev_private;
356− const struct shmob_drm_format_info *format;
357−
358− format = shmob_drm_format_info(crtc->primary->fb->format->format);
359− if (format == NULL) {
360− dev_dbg(sdev->dev, "mode_set: unsupported format %p4cc\n",
361− &crtc->primary->fb->format->format);
362− return -EINVAL;
288+ if (crtc->state->event) {
289+ spin_lock_irqsave(&dev->event_lock, flags);
290+ event = crtc->state->event;
291+ crtc->state->event = NULL;
292+ drm_crtc_send_vblank_event(crtc, event);
293+ spin_unlock_irqrestore(&dev->event_lock, flags);
363294 }
364−
365− scrtc->format = format;
366− scrtc->line_size = crtc->primary->fb->pitches[0];
367−
368− shmob_drm_crtc_compute_base(scrtc, x, y);
369−
370− return 0;
371−}
372−
373−static void shmob_drm_crtc_mode_commit(struct drm_crtc *crtc)
374−{
375− shmob_drm_crtc_dpms(crtc, DRM_MODE_DPMS_ON);
376−}
377−
378−static int shmob_drm_crtc_mode_set_base(struct drm_crtc *crtc, int x, int y,
379− struct drm_framebuffer *old_fb)
380−{
381− shmob_drm_crtc_update_base(to_shmob_crtc(crtc));
382−
383− return 0;
384295 }
385296
386297 static const struct drm_crtc_helper_funcs crtc_helper_funcs = {
387− .dpms = shmob_drm_crtc_dpms,
388− .prepare = shmob_drm_crtc_mode_prepare,
389− .commit = shmob_drm_crtc_mode_commit,
390− .mode_set = shmob_drm_crtc_mode_set,
391− .mode_set_base = shmob_drm_crtc_mode_set_base,
298+ .atomic_flush = shmob_drm_crtc_atomic_flush,
299+ .atomic_enable = shmob_drm_crtc_atomic_enable,
300+ .atomic_disable = shmob_drm_crtc_atomic_disable,
392301 };
393302
394−void shmob_drm_crtc_finish_page_flip(struct shmob_drm_crtc *scrtc)
395−{
396− struct drm_pending_vblank_event *event;
397− struct drm_device *dev = scrtc->crtc.dev;
398− unsigned long flags;
399−
400− spin_lock_irqsave(&dev->event_lock, flags);
401− event = scrtc->event;
402− scrtc->event = NULL;
403− if (event) {
404− drm_crtc_send_vblank_event(&scrtc->crtc, event);
405− drm_crtc_vblank_put(&scrtc->crtc);
406− }
407− spin_unlock_irqrestore(&dev->event_lock, flags);
408−}
409−
410303 static int shmob_drm_crtc_page_flip(struct drm_crtc *crtc,
411304 struct drm_framebuffer *fb,
412305 struct drm_pending_vblank_event *event,
@@ -414,7 +307,7 @@ static int shmob_drm_crtc_page_flip(struct drm_crtc *crtc, · 1 unmodified line
414307 struct drm_modeset_acquire_ctx *ctx)
415308 {
416309 struct shmob_drm_crtc *scrtc = to_shmob_crtc(crtc);
417− struct drm_device *dev = scrtc->crtc.dev;
310+ struct drm_device *dev = scrtc->base.dev;
418311 unsigned long flags;
419312
420313 spin_lock_irqsave(&dev->event_lock, flags);
@@ -424,12 +317,11 @@ static int shmob_drm_crtc_page_flip(struct drm_crtc *crtc, · 3 unmodified lines
424317 }
425318 spin_unlock_irqrestore(&dev->event_lock, flags);
426319
427− crtc->primary->fb = fb;
428− shmob_drm_crtc_update_base(scrtc);
320+ drm_atomic_set_fb_for_plane(crtc->primary->state, fb);
429321
430322 if (event) {
431323 event->pipe = 0;
432− drm_crtc_vblank_get(&scrtc->crtc);
324+ drm_crtc_vblank_get(&scrtc->base);
433325 spin_lock_irqsave(&dev->event_lock, flags);
434326 scrtc->event = event;
435327 spin_unlock_irqrestore(&dev->event_lock, flags);
@@ -457,7 +349,7 @@ static void shmob_drm_crtc_enable_vblank(struct shmob_drm_device *sdev, · 21 unmodified lines
457349
458350 static int shmob_drm_enable_vblank(struct drm_crtc *crtc)
459351 {
460− struct shmob_drm_device *sdev = crtc->dev->dev_private;
352+ struct shmob_drm_device *sdev = to_shmob_device(crtc->dev);
461353
462354 shmob_drm_crtc_enable_vblank(sdev, true);
463355
@@ -466,88 +358,65 @@ static int shmob_drm_enable_vblank(struct drm_crtc *crtc) · 2 unmodified lines
466358
467359 static void shmob_drm_disable_vblank(struct drm_crtc *crtc)
468360 {
469− struct shmob_drm_device *sdev = crtc->dev->dev_private;
361+ struct shmob_drm_device *sdev = to_shmob_device(crtc->dev);
470362
471363 shmob_drm_crtc_enable_vblank(sdev, false);
472364 }
473365
474366 static const struct drm_crtc_funcs crtc_funcs = {
367+ .reset = drm_atomic_helper_crtc_reset,
475368 .destroy = drm_crtc_cleanup,
476− .set_config = drm_crtc_helper_set_config,
369+ .set_config = drm_atomic_helper_set_config,
477370 .page_flip = shmob_drm_crtc_page_flip,
371+ .atomic_duplicate_state = drm_atomic_helper_crtc_duplicate_state,
372+ .atomic_destroy_state = drm_atomic_helper_crtc_destroy_state,
478373 .enable_vblank = shmob_drm_enable_vblank,
479374 .disable_vblank = shmob_drm_disable_vblank,
480375 };
481376
482−static const uint32_t modeset_formats[] = {
483− DRM_FORMAT_RGB565,
484− DRM_FORMAT_RGB888,
485− DRM_FORMAT_ARGB8888,
486− DRM_FORMAT_XRGB8888,
487−};
488−
489−static const struct drm_plane_funcs primary_plane_funcs = {
490− DRM_PLANE_NON_ATOMIC_FUNCS,
491−};
492−
493377 int shmob_drm_crtc_create(struct shmob_drm_device *sdev)
494378 {
495− struct drm_crtc *crtc = &sdev->crtc.crtc;
496− struct drm_plane *primary;
379+ struct drm_crtc *crtc = &sdev->crtc.base;
380+ struct drm_plane *primary, *plane;
381+ unsigned int i;
497382 int ret;
498383
499− sdev->crtc.dpms = DRM_MODE_DPMS_OFF;
384+ init_waitqueue_head(&sdev->crtc.flip_wait);
500385
501− primary = __drm_universal_plane_alloc(sdev->ddev, sizeof(*primary), 0,
502− 0, &primary_plane_funcs,
503− modeset_formats,
504− ARRAY_SIZE(modeset_formats),
505− NULL, DRM_PLANE_TYPE_PRIMARY,
506− NULL);
386+ primary = shmob_drm_plane_create(sdev, DRM_PLANE_TYPE_PRIMARY, 0);
507387 if (IS_ERR(primary))
508388 return PTR_ERR(primary);
509389
510− ret = drm_crtc_init_with_planes(sdev->ddev, crtc, primary, NULL,
390+ for (i = 1; i < 5; ++i) {
391+ plane = shmob_drm_plane_create(sdev, DRM_PLANE_TYPE_OVERLAY, i);
392+ if (IS_ERR(plane))
393+ return PTR_ERR(plane);
394+ }
395+
396+ ret = drm_crtc_init_with_planes(&sdev->ddev, crtc, primary, NULL,
511397 &crtc_funcs, NULL);
512− if (ret < 0) {
513− drm_plane_cleanup(primary);
514− kfree(primary);
398+ if (ret < 0)
515399 return ret;
516− }
517400
518401 drm_crtc_helper_add(crtc, &crtc_helper_funcs);
519402
403+ /* Start with vertical blank interrupt reporting disabled. */
404+ drm_crtc_vblank_off(crtc);
405+
520406 return 0;
521407 }
522408
523409 /* -----------------------------------------------------------------------------
524− * Encoder
410+ * Legacy Encoder
525411 */
526412
527−#define to_shmob_encoder(e) \
528− container_of(e, struct shmob_drm_encoder, encoder)
529−
530−static void shmob_drm_encoder_dpms(struct drm_encoder *encoder, int mode)
531−{
532− struct shmob_drm_encoder *senc = to_shmob_encoder(encoder);
533− struct shmob_drm_device *sdev = encoder->dev->dev_private;
534− struct shmob_drm_connector *scon = &sdev->connector;
535−
536− if (senc->dpms == mode)
537− return;
538−
539− shmob_drm_backlight_dpms(scon, mode);
540−
541− senc->dpms = mode;
542−}
543−
544413 static bool shmob_drm_encoder_mode_fixup(struct drm_encoder *encoder,
545414 const struct drm_display_mode *mode,
546415 struct drm_display_mode *adjusted_mode)
547416 {
548417 struct drm_device *dev = encoder->dev;
549− struct shmob_drm_device *sdev = dev->dev_private;
550− struct drm_connector *connector = &sdev->connector.connector;
418+ struct shmob_drm_device *sdev = to_shmob_device(dev);
419+ struct drm_connector *connector = sdev->connector;
551420 const struct drm_display_mode *panel_mode;
552421
553422 if (list_empty(&connector->modes)) {
@@ -563,60 +432,61 @@ static bool shmob_drm_encoder_mode_fixup(struct drm_encoder *encoder, · 9 unmodified lines
563432 return true;
564433 }
565434
566−static void shmob_drm_encoder_mode_prepare(struct drm_encoder *encoder)
567−{
568− /* No-op, everything is handled in the CRTC code. */
569−}
570−
571−static void shmob_drm_encoder_mode_set(struct drm_encoder *encoder,
572− struct drm_display_mode *mode,
573− struct drm_display_mode *adjusted_mode)
574−{
575− /* No-op, everything is handled in the CRTC code. */
576−}
577−
578−static void shmob_drm_encoder_mode_commit(struct drm_encoder *encoder)
579−{
580− /* No-op, everything is handled in the CRTC code. */
581−}
582−
583435 static const struct drm_encoder_helper_funcs encoder_helper_funcs = {
584− .dpms = shmob_drm_encoder_dpms,
585436 .mode_fixup = shmob_drm_encoder_mode_fixup,
586− .prepare = shmob_drm_encoder_mode_prepare,
587− .commit = shmob_drm_encoder_mode_commit,
588− .mode_set = shmob_drm_encoder_mode_set,
589437 };
590438
439+/* -----------------------------------------------------------------------------
440+ * Encoder
441+ */
442+
591443 int shmob_drm_encoder_create(struct shmob_drm_device *sdev)
592444 {
593− struct drm_encoder *encoder = &sdev->encoder.encoder;
445+ struct drm_encoder *encoder = &sdev->encoder;
446+ struct drm_bridge *bridge;
594447 int ret;
595448
596− sdev->encoder.dpms = DRM_MODE_DPMS_OFF;
597−
598449 encoder->possible_crtcs = 1;
599450
600− ret = drm_simple_encoder_init(sdev->ddev, encoder,
601− DRM_MODE_ENCODER_LVDS);
451+ ret = drm_simple_encoder_init(&sdev->ddev, encoder,
452+ DRM_MODE_ENCODER_DPI);
602453 if (ret < 0)
603454 return ret;
604455
605− drm_encoder_helper_add(encoder, &encoder_helper_funcs);
456+ if (sdev->pdata) {
457+ drm_encoder_helper_add(encoder, &encoder_helper_funcs);
458+ return 0;
459+ }
460+
461+ /* Create a panel bridge */
462+ bridge = devm_drm_of_get_bridge(sdev->dev, sdev->dev->of_node, 0, 0);
463+ if (IS_ERR(bridge))
464+ return PTR_ERR(bridge);
465+
466+ /* Attach the bridge to the encoder */
467+ ret = drm_bridge_attach(encoder, bridge, NULL,
468+ DRM_BRIDGE_ATTACH_NO_CONNECTOR);
469+ if (ret) {
470+ dev_err(sdev->dev, "failed to attach bridge: %pe\n",
471+ ERR_PTR(ret));
472+ return ret;
473+ }
606474
607475 return 0;
608476 }
609477
610478 /* -----------------------------------------------------------------------------
611− * Connector
479+ * Legacy Connector
612480 */
613481
614−#define to_shmob_connector(c) \
615− container_of(c, struct shmob_drm_connector, connector)
482+static inline struct shmob_drm_connector *to_shmob_connector(struct drm_connector *connector)
483+{
484+ return container_of(connector, struct shmob_drm_connector, base);
485+}
616486
617487 static int shmob_drm_connector_get_modes(struct drm_connector *connector)
618488 {
619− struct shmob_drm_device *sdev = connector->dev->dev_private;
489+ struct shmob_drm_connector *scon = to_shmob_connector(connector);
620490 struct drm_display_mode *mode;
621491
622492 mode = drm_mode_create(connector->dev);
@@ -624,22 +494,10 @@ static int shmob_drm_connector_get_modes(struct drm_connector *connector) · 1 unmodified line
624494 return 0;
625495
626496 mode->type = DRM_MODE_TYPE_PREFERRED | DRM_MODE_TYPE_DRIVER;
627− mode->clock = sdev->pdata->panel.mode.clock;
628− mode->hdisplay = sdev->pdata->panel.mode.hdisplay;
629− mode->hsync_start = sdev->pdata->panel.mode.hsync_start;
630− mode->hsync_end = sdev->pdata->panel.mode.hsync_end;
631− mode->htotal = sdev->pdata->panel.mode.htotal;
632− mode->vdisplay = sdev->pdata->panel.mode.vdisplay;
633− mode->vsync_start = sdev->pdata->panel.mode.vsync_start;
634− mode->vsync_end = sdev->pdata->panel.mode.vsync_end;
635− mode->vtotal = sdev->pdata->panel.mode.vtotal;
636− mode->flags = sdev->pdata->panel.mode.flags;
637−
638− drm_mode_set_name(mode);
639− drm_mode_probed_add(connector, mode);
640497
641− connector->display_info.width_mm = sdev->pdata->panel.width_mm;
642− connector->display_info.height_mm = sdev->pdata->panel.height_mm;
498+ drm_display_mode_from_videomode(scon->mode, mode);
499+
500+ drm_mode_probed_add(connector, mode);
643501
644502 return 1;
645503 }
@@ -659,54 +517,106 @@ static const struct drm_connector_helper_funcs connector_helper_funcs = { · 13 unmodified lines
659517
660518 static void shmob_drm_connector_destroy(struct drm_connector *connector)
661519 {
662− struct shmob_drm_connector *scon = to_shmob_connector(connector);
663−
664− shmob_drm_backlight_exit(scon);
665520 drm_connector_unregister(connector);
666521 drm_connector_cleanup(connector);
522+
523+ kfree(connector);
667524 }
668525
669526 static const struct drm_connector_funcs connector_funcs = {
670− .dpms = drm_helper_connector_dpms,
527+ .reset = drm_atomic_helper_connector_reset,
671528 .fill_modes = drm_helper_probe_single_connector_modes,
672529 .destroy = shmob_drm_connector_destroy,
530+ .atomic_duplicate_state = drm_atomic_helper_connector_duplicate_state,
531+ .atomic_destroy_state = drm_atomic_helper_connector_destroy_state,
673532 };
674533
675−int shmob_drm_connector_create(struct shmob_drm_device *sdev,
676− struct drm_encoder *encoder)
534+static struct drm_connector *
535+shmob_drm_connector_init(struct shmob_drm_device *sdev,
536+ struct drm_encoder *encoder)
677537 {
678− struct drm_connector *connector = &sdev->connector.connector;
538+ u32 bus_fmt = sdev->pdata->iface.bus_fmt;
539+ struct shmob_drm_connector *scon;
540+ struct drm_connector *connector;
541+ struct drm_display_info *info;
542+ unsigned int i;
679543 int ret;
680544
681− sdev->connector.encoder = encoder;
545+ for (i = 0; i < ARRAY_SIZE(shmob_drm_bus_fmts); i++) {
546+ if (shmob_drm_bus_fmts[i].fmt == bus_fmt)
547+ break;
548+ }
549+ if (i == ARRAY_SIZE(shmob_drm_bus_fmts)) {
550+ dev_err(sdev->dev, "unsupported bus format 0x%x\n", bus_fmt);
551+ return ERR_PTR(-EINVAL);
552+ }
682553
683− connector->display_info.width_mm = sdev->pdata->panel.width_mm;
684− connector->display_info.height_mm = sdev->pdata->panel.height_mm;
554+ scon = kzalloc(sizeof(*scon), GFP_KERNEL);
555+ if (!scon)
556+ return ERR_PTR(-ENOMEM);
685557
686− ret = drm_connector_init(sdev->ddev, connector, &connector_funcs,
687− DRM_MODE_CONNECTOR_LVDS);
688− if (ret < 0)
689− return ret;
558+ connector = &scon->base;
559+ scon->encoder = encoder;
560+ scon->mode = &sdev->pdata->panel.mode;
561+
562+ info = &connector->display_info;
563+ info->width_mm = sdev->pdata->panel.width_mm;
564+ info->height_mm = sdev->pdata->panel.height_mm;
565+
566+ if (scon->mode->flags & DISPLAY_FLAGS_PIXDATA_POSEDGE)
567+ info->bus_flags |= DRM_BUS_FLAG_PIXDATA_DRIVE_POSEDGE;
568+ if (scon->mode->flags & DISPLAY_FLAGS_DE_LOW)
569+ info->bus_flags |= DRM_BUS_FLAG_DE_LOW;
570+
571+ ret = drm_display_info_set_bus_formats(info, &bus_fmt, 1);
572+ if (ret < 0) {
573+ kfree(scon);
574+ return ERR_PTR(ret);
575+ }
576+
577+ ret = drm_connector_init(&sdev->ddev, connector, &connector_funcs,
578+ DRM_MODE_CONNECTOR_DPI);
579+ if (ret < 0) {
580+ kfree(scon);
581+ return ERR_PTR(ret);
582+ }
690583
691584 drm_connector_helper_add(connector, &connector_helper_funcs);
692585
693− ret = shmob_drm_backlight_init(&sdev->connector);
694− if (ret < 0)
695− goto err_cleanup;
586+ return connector;
587+}
588+
589+/* -----------------------------------------------------------------------------
590+ * Connector
591+ */
592+
593+int shmob_drm_connector_create(struct shmob_drm_device *sdev,
594+ struct drm_encoder *encoder)
595+{
596+ struct drm_connector *connector;
597+ int ret;
598+
599+ if (sdev->pdata)
600+ connector = shmob_drm_connector_init(sdev, encoder);
601+ else
602+ connector = drm_bridge_connector_init(&sdev->ddev, encoder);
603+ if (IS_ERR(connector)) {
604+ dev_err(sdev->dev, "failed to created connector: %pe\n",
605+ connector);
606+ return PTR_ERR(connector);
607+ }
696608
697609 ret = drm_connector_attach_encoder(connector, encoder);
698610 if (ret < 0)
699− goto err_backlight;
611+ goto error;
612+
613+ connector->dpms = DRM_MODE_DPMS_OFF;
700614
701− drm_helper_connector_dpms(connector, DRM_MODE_DPMS_OFF);
702− drm_object_property_set_value(&connector->base,
703− sdev->ddev->mode_config.dpms_property, DRM_MODE_DPMS_OFF);
615+ sdev->connector = connector;
704616
705617 return 0;
706618
707−err_backlight:
708− shmob_drm_backlight_exit(&sdev->connector);
709−err_cleanup:
619+error:
710620 drm_connector_cleanup(connector);
711621 return ret;
712622 }
drivers/gpu/drm/renesas/shmobile/shmob_drm_crtc.h+9−18
@@ -14,39 +14,30 @@ · 13 unmodified lines
1414 #include <drm/drm_connector.h>
1515 #include <drm/drm_encoder.h>
1616
17−struct backlight_device;
17+#include <linux/wait.h>
18+
19+#include <video/videomode.h>
20+
1821 struct drm_pending_vblank_event;
1922 struct shmob_drm_device;
2023 struct shmob_drm_format_info;
2124
2225 struct shmob_drm_crtc {
23− struct drm_crtc crtc;
26+ struct drm_crtc base;
2427
2528 struct drm_pending_vblank_event *event;
26− int dpms;
27−
28− const struct shmob_drm_format_info *format;
29− unsigned long dma[2];
30− unsigned int line_size;
31− bool started;
32−};
33−
34−struct shmob_drm_encoder {
35− struct drm_encoder encoder;
36− int dpms;
29+ wait_queue_head_t flip_wait;
3730 };
3831
32+/* Legacy connector */
3933 struct shmob_drm_connector {
40− struct drm_connector connector;
34+ struct drm_connector base;
4135 struct drm_encoder *encoder;
42−
43− struct backlight_device *backlight;
36+ const struct videomode *mode;
4437 };
4538
4639 int shmob_drm_crtc_create(struct shmob_drm_device *sdev);
4740 void shmob_drm_crtc_finish_page_flip(struct shmob_drm_crtc *scrtc);
48−void shmob_drm_crtc_suspend(struct shmob_drm_crtc *scrtc);
49−void shmob_drm_crtc_resume(struct shmob_drm_crtc *scrtc);
5041
5142 int shmob_drm_encoder_create(struct shmob_drm_device *sdev);
5243 int shmob_drm_connector_create(struct shmob_drm_device *sdev,
drivers/gpu/drm/renesas/shmobile/shmob_drm_drv.c+83−96
@@ -11,13 +11,17 @@ · 10 unmodified lines
1111 #include <linux/io.h>
1212 #include <linux/mm.h>
1313 #include <linux/module.h>
14+#include <linux/of.h>
1415 #include <linux/platform_device.h>
1516 #include <linux/pm.h>
17+#include <linux/pm_runtime.h>
1618 #include <linux/slab.h>
1719
20+#include <drm/drm_atomic_helper.h>
1821 #include <drm/drm_drv.h>
1922 #include <drm/drm_fbdev_generic.h>
2023 #include <drm/drm_gem_dma_helper.h>
24+#include <drm/drm_modeset_helper.h>
2125 #include <drm/drm_module.h>
2226 #include <drm/drm_probe_helper.h>
2327 #include <drm/drm_vblank.h>
@@ -31,57 +35,23 @@ · 7 unmodified lines
3135 * Hardware initialization
3236 */
3337
34−static int shmob_drm_init_interface(struct shmob_drm_device *sdev)
35−{
36− static const u32 ldmt1r[] = {
37− [SHMOB_DRM_IFACE_RGB8] = LDMT1R_MIFTYP_RGB8,
38− [SHMOB_DRM_IFACE_RGB9] = LDMT1R_MIFTYP_RGB9,
39− [SHMOB_DRM_IFACE_RGB12A] = LDMT1R_MIFTYP_RGB12A,
40− [SHMOB_DRM_IFACE_RGB12B] = LDMT1R_MIFTYP_RGB12B,
41− [SHMOB_DRM_IFACE_RGB16] = LDMT1R_MIFTYP_RGB16,
42− [SHMOB_DRM_IFACE_RGB18] = LDMT1R_MIFTYP_RGB18,
43− [SHMOB_DRM_IFACE_RGB24] = LDMT1R_MIFTYP_RGB24,
44− [SHMOB_DRM_IFACE_YUV422] = LDMT1R_MIFTYP_YCBCR,
45− [SHMOB_DRM_IFACE_SYS8A] = LDMT1R_IFM | LDMT1R_MIFTYP_SYS8A,
46− [SHMOB_DRM_IFACE_SYS8B] = LDMT1R_IFM | LDMT1R_MIFTYP_SYS8B,
47− [SHMOB_DRM_IFACE_SYS8C] = LDMT1R_IFM | LDMT1R_MIFTYP_SYS8C,
48− [SHMOB_DRM_IFACE_SYS8D] = LDMT1R_IFM | LDMT1R_MIFTYP_SYS8D,
49− [SHMOB_DRM_IFACE_SYS9] = LDMT1R_IFM | LDMT1R_MIFTYP_SYS9,
50− [SHMOB_DRM_IFACE_SYS12] = LDMT1R_IFM | LDMT1R_MIFTYP_SYS12,
51− [SHMOB_DRM_IFACE_SYS16A] = LDMT1R_IFM | LDMT1R_MIFTYP_SYS16A,
52− [SHMOB_DRM_IFACE_SYS16B] = LDMT1R_IFM | LDMT1R_MIFTYP_SYS16B,
53− [SHMOB_DRM_IFACE_SYS16C] = LDMT1R_IFM | LDMT1R_MIFTYP_SYS16C,
54− [SHMOB_DRM_IFACE_SYS18] = LDMT1R_IFM | LDMT1R_MIFTYP_SYS18,
55− [SHMOB_DRM_IFACE_SYS24] = LDMT1R_IFM | LDMT1R_MIFTYP_SYS24,
56− };
57−
58− if (sdev->pdata->iface.interface >= ARRAY_SIZE(ldmt1r)) {
59− dev_err(sdev->dev, "invalid interface type %u\n",
60− sdev->pdata->iface.interface);
61− return -EINVAL;
62− }
63−
64− sdev->ldmt1r = ldmt1r[sdev->pdata->iface.interface];
65− return 0;
66−}
67−
6838 static int shmob_drm_setup_clocks(struct shmob_drm_device *sdev,
69− enum shmob_drm_clk_source clksrc)
39+ enum shmob_drm_clk_source clksrc)
7040 {
7141 struct clk *clk;
7242 char *clkname;
7343
7444 switch (clksrc) {
7545 case SHMOB_DRM_CLK_BUS:
76− clkname = "bus_clk";
46+ clkname = "fck";
7747 sdev->lddckr = LDDCKR_ICKSEL_BUS;
7848 break;
7949 case SHMOB_DRM_CLK_PERIPHERAL:
80− clkname = "peripheral_clk";
50+ clkname = "media";
8151 sdev->lddckr = LDDCKR_ICKSEL_MIPI;
8252 break;
8353 case SHMOB_DRM_CLK_EXTERNAL:
84− clkname = NULL;
54+ clkname = "lclk";
8555 sdev->lddckr = LDDCKR_ICKSEL_HDMI;
8656 break;
8757 default:
@@ -105,7 +75,7 @@ static int shmob_drm_setup_clocks(struct shmob_drm_device *sdev, · 17 unmodified lines
10575 static irqreturn_t shmob_drm_irq(int irq, void *arg)
10676 {
10777 struct drm_device *dev = arg;
108− struct shmob_drm_device *sdev = dev->dev_private;
78+ struct shmob_drm_device *sdev = to_shmob_device(dev);
10979 unsigned long flags;
11080 u32 status;
11181
@@ -119,7 +89,7 @@ static irqreturn_t shmob_drm_irq(int irq, void *arg) · 7 unmodified lines
11989 spin_unlock_irqrestore(&sdev->irq_lock, flags);
12090
12191 if (status & LDINTR_VES) {
122− drm_handle_vblank(dev, 0);
92+ drm_crtc_handle_vblank(&sdev->crtc.base);
12393 shmob_drm_crtc_finish_page_flip(&sdev->crtc);
12494 }
12595
@@ -129,7 +99,7 @@ static irqreturn_t shmob_drm_irq(int irq, void *arg) · 3 unmodified lines
12999 DEFINE_DRM_GEM_DMA_FOPS(shmob_drm_fops);
130100
131101 static const struct drm_driver shmob_drm_driver = {
132− .driver_features = DRIVER_GEM | DRIVER_MODESET,
102+ .driver_features = DRIVER_GEM | DRIVER_MODESET | DRIVER_ATOMIC,
133103 DRM_GEM_DMA_DRIVER_OPS,
134104 .fops = &shmob_drm_fops,
135105 .name = "shmob-drm",
@@ -147,26 +117,45 @@ static int shmob_drm_pm_suspend(struct device *dev) · 11 unmodified lines
147117 {
148118 struct shmob_drm_device *sdev = dev_get_drvdata(dev);
149119
150− drm_kms_helper_poll_disable(sdev->ddev);
151− shmob_drm_crtc_suspend(&sdev->crtc);
120+ return drm_mode_config_helper_suspend(&sdev->ddev);
121+}
122+
123+static int shmob_drm_pm_resume(struct device *dev)
124+{
125+ struct shmob_drm_device *sdev = dev_get_drvdata(dev);
126+
127+ return drm_mode_config_helper_resume(&sdev->ddev);
128+}
129+
130+static int shmob_drm_pm_runtime_suspend(struct device *dev)
131+{
132+ struct shmob_drm_device *sdev = dev_get_drvdata(dev);
133+
134+ if (sdev->clock)
135+ clk_disable_unprepare(sdev->clock);
152136
153137 return 0;
154138 }
155139
156−static int shmob_drm_pm_resume(struct device *dev)
140+static int shmob_drm_pm_runtime_resume(struct device *dev)
157141 {
158142 struct shmob_drm_device *sdev = dev_get_drvdata(dev);
143+ int ret;
159144
160− drm_modeset_lock_all(sdev->ddev);
161− shmob_drm_crtc_resume(&sdev->crtc);
162− drm_modeset_unlock_all(sdev->ddev);
145+ if (sdev->clock) {
146+ ret = clk_prepare_enable(sdev->clock);
147+ if (ret < 0)
148+ return ret;
149+ }
163150
164− drm_kms_helper_poll_enable(sdev->ddev);
165151 return 0;
166152 }
167153
168−static DEFINE_SIMPLE_DEV_PM_OPS(shmob_drm_pm_ops,
169− shmob_drm_pm_suspend, shmob_drm_pm_resume);
154+static const struct dev_pm_ops shmob_drm_pm_ops = {
155+ SYSTEM_SLEEP_PM_OPS(shmob_drm_pm_suspend, shmob_drm_pm_resume)
156+ RUNTIME_PM_OPS(shmob_drm_pm_runtime_suspend,
157+ shmob_drm_pm_runtime_resume, NULL)
158+};
170159
171160 /* -----------------------------------------------------------------------------
172161 * Platform driver
@@ -175,37 +164,45 @@ static DEFINE_SIMPLE_DEV_PM_OPS(shmob_drm_pm_ops, · 2 unmodified lines
175164 static void shmob_drm_remove(struct platform_device *pdev)
176165 {
177166 struct shmob_drm_device *sdev = platform_get_drvdata(pdev);
178− struct drm_device *ddev = sdev->ddev;
167+ struct drm_device *ddev = &sdev->ddev;
179168
180169 drm_dev_unregister(ddev);
170+ drm_atomic_helper_shutdown(ddev);
181171 drm_kms_helper_poll_fini(ddev);
182− free_irq(sdev->irq, ddev);
183− drm_dev_put(ddev);
184172 }
185173
186174 static int shmob_drm_probe(struct platform_device *pdev)
187175 {
188176 struct shmob_drm_platform_data *pdata = pdev->dev.platform_data;
177+ const struct shmob_drm_config *config;
189178 struct shmob_drm_device *sdev;
190179 struct drm_device *ddev;
191− unsigned int i;
192180 int ret;
193181
194− if (pdata == NULL) {
182+ config = of_device_get_match_data(&pdev->dev);
183+ if (!config && !pdata) {
195184 dev_err(&pdev->dev, "no platform data\n");
196185 return -EINVAL;
197186 }
198187
199188 /*
200− * Allocate and initialize the driver private data, I/O resources and
201− * clocks.
189+ * Allocate and initialize the DRM device, driver private data, I/O
190+ * resources and clocks.
202191 */
203− sdev = devm_kzalloc(&pdev->dev, sizeof(*sdev), GFP_KERNEL);
204− if (sdev == NULL)
205− return -ENOMEM;
192+ sdev = devm_drm_dev_alloc(&pdev->dev, &shmob_drm_driver,
193+ struct shmob_drm_device, ddev);
194+ if (IS_ERR(sdev))
195+ return PTR_ERR(sdev);
206196
197+ ddev = &sdev->ddev;
207198 sdev->dev = &pdev->dev;
208− sdev->pdata = pdata;
199+ if (config) {
200+ sdev->config = *config;
201+ } else {
202+ sdev->pdata = pdata;
203+ sdev->config.clk_source = pdata->clk_source;
204+ sdev->config.clk_div = pdata->iface.clk_div;
205+ }
209206 spin_lock_init(&sdev->irq_lock);
210207
211208 platform_set_drvdata(pdev, sdev);
@@ -214,49 +211,32 @@ static int shmob_drm_probe(struct platform_device *pdev) · 2 unmodified lines
214211 if (IS_ERR(sdev->mmio))
215212 return PTR_ERR(sdev->mmio);
216213
217− ret = shmob_drm_setup_clocks(sdev, pdata->clk_source);
214+ ret = shmob_drm_setup_clocks(sdev, sdev->config.clk_source);
218215 if (ret < 0)
219216 return ret;
220217
221− ret = shmob_drm_init_interface(sdev);
222− if (ret < 0)
218+ ret = devm_pm_runtime_enable(&pdev->dev);
219+ if (ret)
223220 return ret;
224221
225− /* Allocate and initialize the DRM device. */
226− ddev = drm_dev_alloc(&shmob_drm_driver, &pdev->dev);
227− if (IS_ERR(ddev))
228− return PTR_ERR(ddev);
229−
230− sdev->ddev = ddev;
231− ddev->dev_private = sdev;
232−
233− ret = shmob_drm_modeset_init(sdev);
234− if (ret < 0) {
235− dev_err(&pdev->dev, "failed to initialize mode setting\n");
236− goto err_free_drm_dev;
237− }
238−
239− for (i = 0; i < 4; ++i) {
240− ret = shmob_drm_plane_create(sdev, i);
241− if (ret < 0) {
242− dev_err(&pdev->dev, "failed to create plane %u\n", i);
243− goto err_modeset_cleanup;
244− }
245− }
246−
247222 ret = drm_vblank_init(ddev, 1);
248223 if (ret < 0) {
249224 dev_err(&pdev->dev, "failed to initialize vblank\n");
250− goto err_modeset_cleanup;
225+ return ret;
251226 }
252227
228+ ret = shmob_drm_modeset_init(sdev);
229+ if (ret < 0)
230+ return dev_err_probe(&pdev->dev, ret,
231+ "failed to initialize mode setting\n");
232+
253233 ret = platform_get_irq(pdev, 0);
254234 if (ret < 0)
255235 goto err_modeset_cleanup;
256236 sdev->irq = ret;
257237
258− ret = request_irq(sdev->irq, shmob_drm_irq, 0, ddev->driver->name,
259− ddev);
238+ ret = devm_request_irq(&pdev->dev, sdev->irq, shmob_drm_irq, 0,
239+ ddev->driver->name, ddev);
260240 if (ret < 0) {
261241 dev_err(&pdev->dev, "failed to install IRQ handler\n");
262242 goto err_modeset_cleanup;
@@ -268,28 +248,35 @@ static int shmob_drm_probe(struct platform_device *pdev) · 5 unmodified lines
268248 */
269249 ret = drm_dev_register(ddev, 0);
270250 if (ret < 0)
271− goto err_irq_uninstall;
251+ goto err_modeset_cleanup;
272252
273253 drm_fbdev_generic_setup(ddev, 16);
274254
275255 return 0;
276256
277−err_irq_uninstall:
278− free_irq(sdev->irq, ddev);
279257 err_modeset_cleanup:
280258 drm_kms_helper_poll_fini(ddev);
281−err_free_drm_dev:
282− drm_dev_put(ddev);
283−
284259 return ret;
285260 }
286261
262+static const struct shmob_drm_config shmob_arm_config = {
263+ .clk_source = SHMOB_DRM_CLK_BUS,
264+ .clk_div = 5,
265+};
266+
267+static const struct of_device_id shmob_drm_of_table[] __maybe_unused = {
268+ { .compatible = "renesas,r8a7740-lcdc", .data = &shmob_arm_config, },
269+ { .compatible = "renesas,sh73a0-lcdc", .data = &shmob_arm_config, },
270+ { /* sentinel */ }
271+};
272+
287273 static struct platform_driver shmob_drm_platform_driver = {
288274 .probe = shmob_drm_probe,
289275 .remove_new = shmob_drm_remove,
290276 .driver = {
291277 .name = "shmob-drm",
292− .pm = pm_sleep_ptr(&shmob_drm_pm_ops),
278+ .of_match_table = of_match_ptr(shmob_drm_of_table),
279+ .pm = &shmob_drm_pm_ops,
293280 },
294281 };
295282
drivers/gpu/drm/renesas/shmobile/shmob_drm_drv.h+14−4
@@ -20,23 +20,33 @@ struct clk; · 19 unmodified lines
2020 struct device;
2121 struct drm_device;
2222
23+struct shmob_drm_config {
24+ enum shmob_drm_clk_source clk_source;
25+ unsigned int clk_div;
26+};
27+
2328 struct shmob_drm_device {
2429 struct device *dev;
2530 const struct shmob_drm_platform_data *pdata;
31+ struct shmob_drm_config config;
2632
2733 void __iomem *mmio;
2834 struct clk *clock;
2935 u32 lddckr;
30− u32 ldmt1r;
3136
3237 unsigned int irq;
3338 spinlock_t irq_lock; /* Protects hardware LDINTR register */
3439
35− struct drm_device *ddev;
40+ struct drm_device ddev;
3641
3742 struct shmob_drm_crtc crtc;
38− struct shmob_drm_encoder encoder;
39− struct shmob_drm_connector connector;
43+ struct drm_encoder encoder;
44+ struct drm_connector *connector;
4045 };
4146
47+static inline struct shmob_drm_device *to_shmob_device(struct drm_device *dev)
48+{
49+ return container_of(dev, struct shmob_drm_device, ddev);
50+}
51+
4252 #endif /* __SHMOB_DRM_DRV_H__ */
drivers/gpu/drm/renesas/shmobile/shmob_drm_kms.c+55−22
@@ -7,6 +7,7 @@ · 6 unmodified lines
77 * Laurent Pinchart (laurent.pinchart@ideasonboard.com)
88 */
99
10+#include <drm/drm_atomic_helper.h>
1011 #include <drm/drm_crtc.h>
1112 #include <drm/drm_crtc_helper.h>
1213 #include <drm/drm_fourcc.h>
@@ -17,6 +18,7 @@ · 4 unmodified lines
1718 #include "shmob_drm_crtc.h"
1819 #include "shmob_drm_drv.h"
1920 #include "shmob_drm_kms.h"
21+#include "shmob_drm_plane.h"
2022 #include "shmob_drm_regs.h"
2123
2224 /* -----------------------------------------------------------------------------
@@ -27,53 +29,73 @@ static const struct shmob_drm_format_info shmob_drm_format_infos[] = { · 4 unmodified lines
2729 {
2830 .fourcc = DRM_FORMAT_RGB565,
2931 .bpp = 16,
30− .yuv = false,
3132 .lddfr = LDDFR_PKF_RGB16,
33+ .ldddsr = LDDDSR_LS | LDDDSR_WS,
34+ .ldbbsifr = LDBBSIFR_AL_1 | LDBBSIFR_SWPL | LDBBSIFR_SWPW |
35+ LDBBSIFR_RY | LDBBSIFR_RPKF_RGB16,
3236 }, {
3337 .fourcc = DRM_FORMAT_RGB888,
3438 .bpp = 24,
35− .yuv = false,
3639 .lddfr = LDDFR_PKF_RGB24,
40+ .ldddsr = LDDDSR_LS | LDDDSR_WS | LDDDSR_BS,
41+ .ldbbsifr = LDBBSIFR_AL_1 | LDBBSIFR_SWPL | LDBBSIFR_SWPW |
42+ LDBBSIFR_SWPB | LDBBSIFR_RY | LDBBSIFR_RPKF_RGB24,
3743 }, {
3844 .fourcc = DRM_FORMAT_ARGB8888,
3945 .bpp = 32,
40− .yuv = false,
4146 .lddfr = LDDFR_PKF_ARGB32,
47+ .ldddsr = LDDDSR_LS,
48+ .ldbbsifr = LDBBSIFR_AL_PK | LDBBSIFR_SWPL | LDBBSIFR_RY |
49+ LDBBSIFR_RPKF_ARGB32,
4250 }, {
4351 .fourcc = DRM_FORMAT_XRGB8888,
4452 .bpp = 32,
45− .yuv = false,
4653 .lddfr = LDDFR_PKF_ARGB32,
54+ .ldddsr = LDDDSR_LS,
55+ .ldbbsifr = LDBBSIFR_AL_1 | LDBBSIFR_SWPL | LDBBSIFR_RY |
56+ LDBBSIFR_RPKF_ARGB32,
4757 }, {
4858 .fourcc = DRM_FORMAT_NV12,
4959 .bpp = 12,
50− .yuv = true,
5160 .lddfr = LDDFR_CC | LDDFR_YF_420,
61+ .ldddsr = LDDDSR_LS | LDDDSR_WS | LDDDSR_BS,
62+ .ldbbsifr = LDBBSIFR_AL_1 | LDBBSIFR_SWPL | LDBBSIFR_SWPW |
63+ LDBBSIFR_SWPB | LDBBSIFR_CHRR_420,
5264 }, {
5365 .fourcc = DRM_FORMAT_NV21,
5466 .bpp = 12,
55− .yuv = true,
5667 .lddfr = LDDFR_CC | LDDFR_YF_420,
68+ .ldddsr = LDDDSR_LS | LDDDSR_WS,
69+ .ldbbsifr = LDBBSIFR_AL_1 | LDBBSIFR_SWPL | LDBBSIFR_SWPW |
70+ LDBBSIFR_CHRR_420,
5771 }, {
5872 .fourcc = DRM_FORMAT_NV16,
5973 .bpp = 16,
60− .yuv = true,
6174 .lddfr = LDDFR_CC | LDDFR_YF_422,
75+ .ldddsr = LDDDSR_LS | LDDDSR_WS | LDDDSR_BS,
76+ .ldbbsifr = LDBBSIFR_AL_1 | LDBBSIFR_SWPL | LDBBSIFR_SWPW |
77+ LDBBSIFR_SWPB | LDBBSIFR_CHRR_422,
6278 }, {
6379 .fourcc = DRM_FORMAT_NV61,
6480 .bpp = 16,
65− .yuv = true,
6681 .lddfr = LDDFR_CC | LDDFR_YF_422,
82+ .ldddsr = LDDDSR_LS | LDDDSR_WS,
83+ .ldbbsifr = LDBBSIFR_AL_1 | LDBBSIFR_SWPL | LDBBSIFR_SWPW |
84+ LDBBSIFR_CHRR_422,
6785 }, {
6886 .fourcc = DRM_FORMAT_NV24,
6987 .bpp = 24,
70− .yuv = true,
7188 .lddfr = LDDFR_CC | LDDFR_YF_444,
89+ .ldddsr = LDDDSR_LS | LDDDSR_WS | LDDDSR_BS,
90+ .ldbbsifr = LDBBSIFR_AL_1 | LDBBSIFR_SWPL | LDBBSIFR_SWPW |
91+ LDBBSIFR_SWPB | LDBBSIFR_CHRR_444,
7292 }, {
7393 .fourcc = DRM_FORMAT_NV42,
7494 .bpp = 24,
75− .yuv = true,
7695 .lddfr = LDDFR_CC | LDDFR_YF_444,
96+ .ldddsr = LDDDSR_LS | LDDDSR_WS,
97+ .ldbbsifr = LDBBSIFR_AL_1 | LDBBSIFR_SWPL | LDBBSIFR_SWPW |
98+ LDBBSIFR_CHRR_444,
7799 },
78100 };
79101
@@ -112,7 +134,7 @@ shmob_drm_fb_create(struct drm_device *dev, struct drm_file *file_priv, · 32 unmodified lines
112134 return ERR_PTR(-EINVAL);
113135 }
114136
115− if (format->yuv) {
137+ if (shmob_drm_format_is_yuv(format)) {
116138 unsigned int chroma_cpp = format->bpp == 24 ? 2 : 1;
117139
118140 if (mode_cmd->pitches[1] != mode_cmd->pitches[0] * chroma_cpp) {
@@ -127,29 +149,40 @@ shmob_drm_fb_create(struct drm_device *dev, struct drm_file *file_priv, · 8 unmodified lines
127149
128150 static const struct drm_mode_config_funcs shmob_drm_mode_config_funcs = {
129151 .fb_create = shmob_drm_fb_create,
152+ .atomic_check = drm_atomic_helper_check,
153+ .atomic_commit = drm_atomic_helper_commit,
130154 };
131155
132156 int shmob_drm_modeset_init(struct shmob_drm_device *sdev)
133157 {
158+ struct drm_device *dev = &sdev->ddev;
134159 int ret;
135160
136− ret = drmm_mode_config_init(sdev->ddev);
161+ ret = drmm_mode_config_init(dev);
137162 if (ret)
138163 return ret;
139164
140− shmob_drm_crtc_create(sdev);
141− shmob_drm_encoder_create(sdev);
142− shmob_drm_connector_create(sdev, &sdev->encoder.encoder);
165+ ret = shmob_drm_crtc_create(sdev);
166+ if (ret < 0)
167+ return ret;
168+
169+ ret = shmob_drm_encoder_create(sdev);
170+ if (ret < 0)
171+ return ret;
172+
173+ ret = shmob_drm_connector_create(sdev, &sdev->encoder);
174+ if (ret < 0)
175+ return ret;
143176
144− drm_kms_helper_poll_init(sdev->ddev);
177+ drm_mode_config_reset(dev);
145178
146− sdev->ddev->mode_config.min_width = 0;
147− sdev->ddev->mode_config.min_height = 0;
148− sdev->ddev->mode_config.max_width = 4095;
149− sdev->ddev->mode_config.max_height = 4095;
150− sdev->ddev->mode_config.funcs = &shmob_drm_mode_config_funcs;
179+ drm_kms_helper_poll_init(dev);
151180
152− drm_helper_disable_unused_functions(sdev->ddev);
181+ sdev->ddev.mode_config.min_width = 0;
182+ sdev->ddev.mode_config.min_height = 0;
183+ sdev->ddev.mode_config.max_width = 4095;
184+ sdev->ddev.mode_config.max_height = 4095;
185+ sdev->ddev.mode_config.funcs = &shmob_drm_mode_config_funcs;
153186
154187 return 0;
155188 }
drivers/gpu/drm/renesas/shmobile/shmob_drm_kms.h+6−3
@@ -17,11 +17,14 @@ struct shmob_drm_device; · 16 unmodified lines
1717
1818 struct shmob_drm_format_info {
1919 u32 fourcc;
20− unsigned int bpp;
21− bool yuv;
22− u32 lddfr;
20+ u32 lddfr; /* LCD Data Format Register */
21+ u16 ldbbsifr; /* CHn Source Image Format Register low bits */
22+ u8 ldddsr; /* LCDC Input Image Data Swap Register low bits */
23+ u8 bpp;
2324 };
2425
26+#define shmob_drm_format_is_yuv(format) ((format)->lddfr & LDDFR_CC)
27+
2528 const struct shmob_drm_format_info *shmob_drm_format_info(u32 fourcc);
2629
2730 int shmob_drm_modeset_init(struct shmob_drm_device *sdev);
drivers/gpu/drm/renesas/shmobile/shmob_drm_plane.c+189−137
@@ -7,11 +7,14 @@ · 6 unmodified lines
77 * Laurent Pinchart (laurent.pinchart@ideasonboard.com)
88 */
99
10+#include <drm/drm_atomic.h>
11+#include <drm/drm_atomic_helper.h>
1012 #include <drm/drm_crtc.h>
1113 #include <drm/drm_fb_dma_helper.h>
1214 #include <drm/drm_fourcc.h>
1315 #include <drm/drm_framebuffer.h>
1416 #include <drm/drm_gem_dma_helper.h>
17+#include <drm/drm_plane_helper.h>
1518
1619 #include "shmob_drm_drv.h"
1720 #include "shmob_drm_kms.h"
@@ -19,102 +22,84 @@ · 1 unmodified line
1922 #include "shmob_drm_regs.h"
2023
2124 struct shmob_drm_plane {
22− struct drm_plane plane;
25+ struct drm_plane base;
2326 unsigned int index;
24− unsigned int alpha;
27+};
28+
29+struct shmob_drm_plane_state {
30+ struct drm_plane_state base;
2531
2632 const struct shmob_drm_format_info *format;
27− unsigned long dma[2];
28−
29− unsigned int src_x;
30− unsigned int src_y;
31− unsigned int crtc_x;
32− unsigned int crtc_y;
33− unsigned int crtc_w;
34− unsigned int crtc_h;
33+ u32 dma[2];
3534 };
3635
37−#define to_shmob_plane(p) container_of(p, struct shmob_drm_plane, plane)
36+static inline struct shmob_drm_plane *to_shmob_plane(struct drm_plane *plane)
37+{
38+ return container_of(plane, struct shmob_drm_plane, base);
39+}
40+
41+static inline struct shmob_drm_plane_state *to_shmob_plane_state(struct drm_plane_state *state)
42+{
43+ return container_of(state, struct shmob_drm_plane_state, base);
44+}
3845
39−static void shmob_drm_plane_compute_base(struct shmob_drm_plane *splane,
40− struct drm_framebuffer *fb,
41− int x, int y)
46+static void shmob_drm_plane_compute_base(struct shmob_drm_plane_state *sstate)
4247 {
48+ struct drm_framebuffer *fb = sstate->base.fb;
49+ unsigned int x = sstate->base.src_x >> 16;
50+ unsigned int y = sstate->base.src_y >> 16;
4351 struct drm_gem_dma_object *gem;
4452 unsigned int bpp;
4553
46− bpp = splane->format->yuv ? 8 : splane->format->bpp;
54+ bpp = shmob_drm_format_is_yuv(sstate->format) ? 8 : sstate->format->bpp;
4755 gem = drm_fb_dma_get_gem_obj(fb, 0);
48− splane->dma[0] = gem->dma_addr + fb->offsets[0]
56+ sstate->dma[0] = gem->dma_addr + fb->offsets[0]
4957 + y * fb->pitches[0] + x * bpp / 8;
5058
51− if (splane->format->yuv) {
52− bpp = splane->format->bpp - 8;
59+ if (shmob_drm_format_is_yuv(sstate->format)) {
60+ bpp = sstate->format->bpp - 8;
5361 gem = drm_fb_dma_get_gem_obj(fb, 1);
54− splane->dma[1] = gem->dma_addr + fb->offsets[1]
62+ sstate->dma[1] = gem->dma_addr + fb->offsets[1]
5563 + y / (bpp == 4 ? 2 : 1) * fb->pitches[1]
5664 + x * (bpp == 16 ? 2 : 1);
5765 }
5866 }
5967
60−static void __shmob_drm_plane_setup(struct shmob_drm_plane *splane,
61− struct drm_framebuffer *fb)
68+static void shmob_drm_primary_plane_setup(struct shmob_drm_plane *splane,
69+ struct drm_plane_state *state)
6270 {
63− struct shmob_drm_device *sdev = splane->plane.dev->dev_private;
71+ struct shmob_drm_plane_state *sstate = to_shmob_plane_state(state);
72+ struct shmob_drm_device *sdev = to_shmob_device(splane->base.dev);
73+ struct drm_framebuffer *fb = state->fb;
74+
75+ /* TODO: Handle YUV colorspaces. Hardcode REC709 for now. */
76+ lcdc_write(sdev, LDDFR, sstate->format->lddfr | LDDFR_CF1);
77+ lcdc_write(sdev, LDMLSR, fb->pitches[0]);
78+
79+ /* Word and long word swap. */
80+ lcdc_write(sdev, LDDDSR, sstate->format->ldddsr);
81+
82+ lcdc_write_mirror(sdev, LDSA1R, sstate->dma[0]);
83+ if (shmob_drm_format_is_yuv(sstate->format))
84+ lcdc_write_mirror(sdev, LDSA2R, sstate->dma[1]);
85+
86+ lcdc_write(sdev, LDRCNTR, lcdc_read(sdev, LDRCNTR) ^ LDRCNTR_MRS);
87+}
88+
89+static void shmob_drm_overlay_plane_setup(struct shmob_drm_plane *splane,
90+ struct drm_plane_state *state)
91+{
92+ struct shmob_drm_plane_state *sstate = to_shmob_plane_state(state);
93+ struct shmob_drm_device *sdev = to_shmob_device(splane->base.dev);
94+ struct drm_framebuffer *fb = state->fb;
6495 u32 format;
6596
6697 /* TODO: Support ROP3 mode */
67− format = LDBBSIFR_EN | (splane->alpha << LDBBSIFR_LAY_SHIFT);
68−
69− switch (splane->format->fourcc) {
70− case DRM_FORMAT_RGB565:
71− case DRM_FORMAT_NV21:
72− case DRM_FORMAT_NV61:
73− case DRM_FORMAT_NV42:
74− format |= LDBBSIFR_SWPL | LDBBSIFR_SWPW;
75− break;
76− case DRM_FORMAT_RGB888:
77− case DRM_FORMAT_NV12:
78− case DRM_FORMAT_NV16:
79− case DRM_FORMAT_NV24:
80− format |= LDBBSIFR_SWPL | LDBBSIFR_SWPW | LDBBSIFR_SWPB;
81− break;
82− case DRM_FORMAT_ARGB8888:
83− case DRM_FORMAT_XRGB8888:
84− default:
85− format |= LDBBSIFR_SWPL;
86− break;
87− }
88−
89− switch (splane->format->fourcc) {
90− case DRM_FORMAT_RGB565:
91− format |= LDBBSIFR_AL_1 | LDBBSIFR_RY | LDBBSIFR_RPKF_RGB16;
92− break;
93− case DRM_FORMAT_RGB888:
94− format |= LDBBSIFR_AL_1 | LDBBSIFR_RY | LDBBSIFR_RPKF_RGB24;
95− break;
96− case DRM_FORMAT_ARGB8888:
97− format |= LDBBSIFR_AL_PK | LDBBSIFR_RY | LDDFR_PKF_ARGB32;
98− break;
99− case DRM_FORMAT_XRGB8888:
100− format |= LDBBSIFR_AL_1 | LDBBSIFR_RY | LDDFR_PKF_ARGB32;
101− break;
102− case DRM_FORMAT_NV12:
103− case DRM_FORMAT_NV21:
104− format |= LDBBSIFR_AL_1 | LDBBSIFR_CHRR_420;
105− break;
106− case DRM_FORMAT_NV16:
107− case DRM_FORMAT_NV61:
108− format |= LDBBSIFR_AL_1 | LDBBSIFR_CHRR_422;
109− break;
110− case DRM_FORMAT_NV24:
111− case DRM_FORMAT_NV42:
112− format |= LDBBSIFR_AL_1 | LDBBSIFR_CHRR_444;
113− break;
114− }
98+ format = LDBBSIFR_EN | ((state->alpha >> 8) << LDBBSIFR_LAY_SHIFT) |
99+ sstate->format->ldbbsifr;
115100
116101 #define plane_reg_dump(sdev, splane, reg) \
117− dev_dbg(sdev->ddev->dev, "%s(%u): %s 0x%08x 0x%08x\n", __func__, \
102+ dev_dbg(sdev->ddev.dev, "%s(%u): %s 0x%08x 0x%08x\n", __func__, \
118103 splane->index, #reg, \
119104 lcdc_read(sdev, reg(splane->index)), \
120105 lcdc_read(sdev, reg(splane->index) + LCDC_SIDE_B_OFFSET))
@@ -127,29 +112,27 @@ static void __shmob_drm_plane_setup(struct shmob_drm_plane *splane, · 6 unmodified lines
127112 plane_reg_dump(sdev, splane, LDBnBSACR);
128113
129114 lcdc_write(sdev, LDBCR, LDBCR_UPC(splane->index));
130− dev_dbg(sdev->ddev->dev, "%s(%u): %s 0x%08x\n", __func__, splane->index,
115+ dev_dbg(sdev->ddev.dev, "%s(%u): %s 0x%08x\n", __func__, splane->index,
131116 "LDBCR", lcdc_read(sdev, LDBCR));
132117
133118 lcdc_write(sdev, LDBnBSIFR(splane->index), format);
134119
135120 lcdc_write(sdev, LDBnBSSZR(splane->index),
136− (splane->crtc_h << LDBBSSZR_BVSS_SHIFT) |
137− (splane->crtc_w << LDBBSSZR_BHSS_SHIFT));
121+ (state->crtc_h << LDBBSSZR_BVSS_SHIFT) |
122+ (state->crtc_w << LDBBSSZR_BHSS_SHIFT));
138123 lcdc_write(sdev, LDBnBLOCR(splane->index),
139− (splane->crtc_y << LDBBLOCR_CVLC_SHIFT) |
140− (splane->crtc_x << LDBBLOCR_CHLC_SHIFT));
124+ (state->crtc_y << LDBBLOCR_CVLC_SHIFT) |
125+ (state->crtc_x << LDBBLOCR_CHLC_SHIFT));
141126 lcdc_write(sdev, LDBnBSMWR(splane->index),
142127 fb->pitches[0] << LDBBSMWR_BSMW_SHIFT);
143128
144− shmob_drm_plane_compute_base(splane, fb, splane->src_x, splane->src_y);
145−
146− lcdc_write(sdev, LDBnBSAYR(splane->index), splane->dma[0]);
147− if (splane->format->yuv)
148− lcdc_write(sdev, LDBnBSACR(splane->index), splane->dma[1]);
129+ lcdc_write(sdev, LDBnBSAYR(splane->index), sstate->dma[0]);
130+ if (shmob_drm_format_is_yuv(sstate->format))
131+ lcdc_write(sdev, LDBnBSACR(splane->index), sstate->dma[1]);
149132
150133 lcdc_write(sdev, LDBCR,
151134 LDBCR_UPF(splane->index) | LDBCR_UPD(splane->index));
152− dev_dbg(sdev->ddev->dev, "%s(%u): %s 0x%08x\n", __func__, splane->index,
135+ dev_dbg(sdev->ddev.dev, "%s(%u): %s 0x%08x\n", __func__, splane->index,
153136 "LDBCR", lcdc_read(sdev, LDBCR));
154137
155138 plane_reg_dump(sdev, splane, LDBnBSIFR);
@@ -160,75 +143,143 @@ static void __shmob_drm_plane_setup(struct shmob_drm_plane *splane, · 4 unmodified lines
160143 plane_reg_dump(sdev, splane, LDBnBSACR);
161144 }
162145
163−void shmob_drm_plane_setup(struct drm_plane *plane)
146+static int shmob_drm_plane_atomic_check(struct drm_plane *plane,
147+ struct drm_atomic_state *state)
164148 {
165− struct shmob_drm_plane *splane = to_shmob_plane(plane);
149+ struct drm_plane_state *new_plane_state = drm_atomic_get_new_plane_state(state, plane);
150+ struct shmob_drm_plane_state *sstate = to_shmob_plane_state(new_plane_state);
151+ struct drm_crtc_state *crtc_state;
152+ bool is_primary = plane->type == DRM_PLANE_TYPE_PRIMARY;
153+ int ret;
166154
167− if (plane->fb == NULL)
168− return;
155+ if (!new_plane_state->crtc) {
156+ /*
157+ * The visible field is not reset by the DRM core but only
158+ * updated by drm_atomic_helper_check_plane_state(), set it
159+ * manually.
160+ */
161+ new_plane_state->visible = false;
162+ sstate->format = NULL;
163+ return 0;
164+ }
169165
170− __shmob_drm_plane_setup(splane, plane->fb);
171−}
166+ crtc_state = drm_atomic_get_crtc_state(state, new_plane_state->crtc);
167+ if (IS_ERR(crtc_state))
168+ return PTR_ERR(crtc_state);
172169
173−static int
174−shmob_drm_plane_update(struct drm_plane *plane, struct drm_crtc *crtc,
175− struct drm_framebuffer *fb, int crtc_x, int crtc_y,
176− unsigned int crtc_w, unsigned int crtc_h,
177− uint32_t src_x, uint32_t src_y,
178− uint32_t src_w, uint32_t src_h,
179− struct drm_modeset_acquire_ctx *ctx)
180−{
181− struct shmob_drm_plane *splane = to_shmob_plane(plane);
182− struct shmob_drm_device *sdev = plane->dev->dev_private;
183− const struct shmob_drm_format_info *format;
170+ ret = drm_atomic_helper_check_plane_state(new_plane_state, crtc_state,
171+ DRM_PLANE_NO_SCALING,
172+ DRM_PLANE_NO_SCALING,
173+ !is_primary, true);
174+ if (ret < 0)
175+ return ret;
184176
185− format = shmob_drm_format_info(fb->format->format);
186− if (format == NULL) {
187− dev_dbg(sdev->dev, "update_plane: unsupported format %08x\n",
188− fb->format->format);
189− return -EINVAL;
177+ if (!new_plane_state->visible) {
178+ sstate->format = NULL;
179+ return 0;
190180 }
191181
192− if (src_w >> 16 != crtc_w || src_h >> 16 != crtc_h) {
193− dev_dbg(sdev->dev, "%s: scaling not supported\n", __func__);
182+ sstate->format = shmob_drm_format_info(new_plane_state->fb->format->format);
183+ if (!sstate->format) {
184+ dev_dbg(plane->dev->dev,
185+ "plane_atomic_check: unsupported format %p4cc\n",
186+ &new_plane_state->fb->format->format);
194187 return -EINVAL;
195188 }
196189
197− splane->format = format;
190+ shmob_drm_plane_compute_base(sstate);
198191
199− splane->src_x = src_x >> 16;
200− splane->src_y = src_y >> 16;
201− splane->crtc_x = crtc_x;
202− splane->crtc_y = crtc_y;
203− splane->crtc_w = crtc_w;
204− splane->crtc_h = crtc_h;
205−
206− __shmob_drm_plane_setup(splane, fb);
207192 return 0;
208193 }
209194
210−static int shmob_drm_plane_disable(struct drm_plane *plane,
211− struct drm_modeset_acquire_ctx *ctx)
195+static void shmob_drm_plane_atomic_update(struct drm_plane *plane,
196+ struct drm_atomic_state *state)
212197 {
198+ struct drm_plane_state *new_plane_state = drm_atomic_get_new_plane_state(state, plane);
213199 struct shmob_drm_plane *splane = to_shmob_plane(plane);
214− struct shmob_drm_device *sdev = plane->dev->dev_private;
215200
216− splane->format = NULL;
201+ if (!new_plane_state->visible)
202+ return;
217203
204+ if (plane->type == DRM_PLANE_TYPE_PRIMARY)
205+ shmob_drm_primary_plane_setup(splane, new_plane_state);
206+ else
207+ shmob_drm_overlay_plane_setup(splane, new_plane_state);
208+}
209+
210+static void shmob_drm_plane_atomic_disable(struct drm_plane *plane,
211+ struct drm_atomic_state *state)
212+{
213+ struct drm_plane_state *old_state = drm_atomic_get_old_plane_state(state, plane);
214+ struct shmob_drm_device *sdev = to_shmob_device(plane->dev);
215+ struct shmob_drm_plane *splane = to_shmob_plane(plane);
216+
217+ if (!old_state->crtc)
218+ return;
219+
220+ if (plane->type != DRM_PLANE_TYPE_OVERLAY)
221+ return;
222+
223+ lcdc_write(sdev, LDBCR, LDBCR_UPC(splane->index));
218224 lcdc_write(sdev, LDBnBSIFR(splane->index), 0);
219− return 0;
225+ lcdc_write(sdev, LDBCR,
226+ LDBCR_UPF(splane->index) | LDBCR_UPD(splane->index));
220227 }
221228
222−static void shmob_drm_plane_destroy(struct drm_plane *plane)
229+static struct drm_plane_state *
230+shmob_drm_plane_atomic_duplicate_state(struct drm_plane *plane)
223231 {
224− drm_plane_force_disable(plane);
225− drm_plane_cleanup(plane);
232+ struct shmob_drm_plane_state *state;
233+ struct shmob_drm_plane_state *copy;
234+
235+ if (WARN_ON(!plane->state))
236+ return NULL;
237+
238+ state = to_shmob_plane_state(plane->state);
239+ copy = kmemdup(state, sizeof(*state), GFP_KERNEL);
240+ if (copy == NULL)
241+ return NULL;
242+
243+ __drm_atomic_helper_plane_duplicate_state(plane, &copy->base);
244+
245+ return &copy->base;
226246 }
227247
248+static void shmob_drm_plane_atomic_destroy_state(struct drm_plane *plane,
249+ struct drm_plane_state *state)
250+{
251+ __drm_atomic_helper_plane_destroy_state(state);
252+ kfree(to_shmob_plane_state(state));
253+}
254+
255+static void shmob_drm_plane_reset(struct drm_plane *plane)
256+{
257+ struct shmob_drm_plane_state *state;
258+
259+ if (plane->state) {
260+ shmob_drm_plane_atomic_destroy_state(plane, plane->state);
261+ plane->state = NULL;
262+ }
263+
264+ state = kzalloc(sizeof(*state), GFP_KERNEL);
265+ if (state == NULL)
266+ return;
267+
268+ __drm_atomic_helper_plane_reset(plane, &state->base);
269+}
270+
271+static const struct drm_plane_helper_funcs shmob_drm_plane_helper_funcs = {
272+ .atomic_check = shmob_drm_plane_atomic_check,
273+ .atomic_update = shmob_drm_plane_atomic_update,
274+ .atomic_disable = shmob_drm_plane_atomic_disable,
275+};
276+
228277 static const struct drm_plane_funcs shmob_drm_plane_funcs = {
229− .update_plane = shmob_drm_plane_update,
230− .disable_plane = shmob_drm_plane_disable,
231− .destroy = shmob_drm_plane_destroy,
278+ .update_plane = drm_atomic_helper_update_plane,
279+ .disable_plane = drm_atomic_helper_disable_plane,
280+ .reset = shmob_drm_plane_reset,
281+ .atomic_duplicate_state = shmob_drm_plane_atomic_duplicate_state,
282+ .atomic_destroy_state = shmob_drm_plane_atomic_destroy_state,
232283 };
233284
234285 static const uint32_t formats[] = {
@@ -244,22 +295,23 @@ static const uint32_t formats[] = { · 9 unmodified lines
244295 DRM_FORMAT_NV42,
245296 };
246297
247−int shmob_drm_plane_create(struct shmob_drm_device *sdev, unsigned int index)
298+struct drm_plane *shmob_drm_plane_create(struct shmob_drm_device *sdev,
299+ enum drm_plane_type type,
300+ unsigned int index)
248301 {
249302 struct shmob_drm_plane *splane;
250− int ret;
251303
252− splane = devm_kzalloc(sdev->dev, sizeof(*splane), GFP_KERNEL);
253− if (splane == NULL)
254− return -ENOMEM;
304+ splane = drmm_universal_plane_alloc(&sdev->ddev,
305+ struct shmob_drm_plane, base, 1,
306+ &shmob_drm_plane_funcs, formats,
307+ ARRAY_SIZE(formats), NULL, type,
308+ NULL);
309+ if (IS_ERR(splane))
310+ return ERR_CAST(splane);
255311
256312 splane->index = index;
257− splane->alpha = 255;
258313
259− ret = drm_universal_plane_init(sdev->ddev, &splane->plane, 1,
260− &shmob_drm_plane_funcs,
261− formats, ARRAY_SIZE(formats), NULL,
262− DRM_PLANE_TYPE_OVERLAY, NULL);
314+ drm_plane_helper_add(&splane->base, &shmob_drm_plane_helper_funcs);
263315
264− return ret;
316+ return &splane->base;
265317 }
drivers/gpu/drm/renesas/shmobile/shmob_drm_plane.h+3−2
@@ -13,7 +13,8 @@ · 12 unmodified lines
1313 struct drm_plane;
1414 struct shmob_drm_device;
1515
16−int shmob_drm_plane_create(struct shmob_drm_device *sdev, unsigned int index);
17−void shmob_drm_plane_setup(struct drm_plane *plane);
16+struct drm_plane *shmob_drm_plane_create(struct shmob_drm_device *sdev,
17+ enum drm_plane_type type,
18+ unsigned int index);
1819
1920 #endif /* __SHMOB_DRM_PLANE_H__ */
include/linux/platform_data/shmob_drm.h+3−54
@@ -10,7 +10,7 @@ · 9 unmodified lines
1010 #ifndef __SHMOB_DRM_H__
1111 #define __SHMOB_DRM_H__
1212
13−#include <drm/drm_mode.h>
13+#include <video/videomode.h>
1414
1515 enum shmob_drm_clk_source {
1616 SHMOB_DRM_CLK_BUS,
@@ -18,72 +18,21 @@ enum shmob_drm_clk_source { · 1 unmodified line
1818 SHMOB_DRM_CLK_EXTERNAL,
1919 };
2020
21−enum shmob_drm_interface {
22− SHMOB_DRM_IFACE_RGB8, /* 24bpp, 8:8:8 */
23− SHMOB_DRM_IFACE_RGB9, /* 18bpp, 9:9 */
24− SHMOB_DRM_IFACE_RGB12A, /* 24bpp, 12:12 */
25− SHMOB_DRM_IFACE_RGB12B, /* 12bpp */
26− SHMOB_DRM_IFACE_RGB16, /* 16bpp */
27− SHMOB_DRM_IFACE_RGB18, /* 18bpp */
28− SHMOB_DRM_IFACE_RGB24, /* 24bpp */
29− SHMOB_DRM_IFACE_YUV422, /* 16bpp */
30− SHMOB_DRM_IFACE_SYS8A, /* 24bpp, 8:8:8 */
31− SHMOB_DRM_IFACE_SYS8B, /* 18bpp, 8:8:2 */
32− SHMOB_DRM_IFACE_SYS8C, /* 18bpp, 2:8:8 */
33− SHMOB_DRM_IFACE_SYS8D, /* 16bpp, 8:8 */
34− SHMOB_DRM_IFACE_SYS9, /* 18bpp, 9:9 */
35− SHMOB_DRM_IFACE_SYS12, /* 24bpp, 12:12 */
36− SHMOB_DRM_IFACE_SYS16A, /* 16bpp */
37− SHMOB_DRM_IFACE_SYS16B, /* 18bpp, 16:2 */
38− SHMOB_DRM_IFACE_SYS16C, /* 18bpp, 2:16 */
39− SHMOB_DRM_IFACE_SYS18, /* 18bpp */
40− SHMOB_DRM_IFACE_SYS24, /* 24bpp */
41−};
42−
43−struct shmob_drm_backlight_data {
44− const char *name;
45− int max_brightness;
46− int (*get_brightness)(void);
47− int (*set_brightness)(int brightness);
48−};
49−
5021 struct shmob_drm_panel_data {
5122 unsigned int width_mm; /* Panel width in mm */
5223 unsigned int height_mm; /* Panel height in mm */
53− struct drm_mode_modeinfo mode;
24+ struct videomode mode;
5425 };
5526
56−struct shmob_drm_sys_interface_data {
57− unsigned int read_latch:6;
58− unsigned int read_setup:8;
59− unsigned int read_cycle:8;
60− unsigned int read_strobe:8;
61− unsigned int write_setup:8;
62− unsigned int write_cycle:8;
63− unsigned int write_strobe:8;
64− unsigned int cs_setup:3;
65− unsigned int vsync_active_high:1;
66− unsigned int vsync_dir_input:1;
67−};
68−
69−#define SHMOB_DRM_IFACE_FL_DWPOL (1 << 0) /* Rising edge dot clock data latch */
70−#define SHMOB_DRM_IFACE_FL_DIPOL (1 << 1) /* Active low display enable */
71−#define SHMOB_DRM_IFACE_FL_DAPOL (1 << 2) /* Active low display data */
72−#define SHMOB_DRM_IFACE_FL_HSCNT (1 << 3) /* Disable HSYNC during VBLANK */
73−#define SHMOB_DRM_IFACE_FL_DWCNT (1 << 4) /* Disable dotclock during blanking */
74−
7527 struct shmob_drm_interface_data {
76− enum shmob_drm_interface interface;
77− struct shmob_drm_sys_interface_data sys;
28+ unsigned int bus_fmt; /* MEDIA_BUS_FMT_* */
7829 unsigned int clk_div;
79− unsigned int flags;
8030 };
8131
8232 struct shmob_drm_platform_data {
8333 enum shmob_drm_clk_source clk_source;
8434 struct shmob_drm_interface_data iface;
8535 struct shmob_drm_panel_data panel;
86− struct shmob_drm_backlight_data backlight;
8736 };
8837
8938 #endif /* __SHMOB_DRM_H__ */
include/uapi/linux/media-bus-format.h+2−1
@@ -34,7 +34,7 @@ · 33 unmodified lines
3434
3535 #define MEDIA_BUS_FMT_FIXED 0x0001
3636
37−/* RGB - next is 0x1025 */
37+/* RGB - next is 0x1026 */
3838 #define MEDIA_BUS_FMT_RGB444_1X12 0x1016
3939 #define MEDIA_BUS_FMT_RGB444_2X8_PADHI_BE 0x1001
4040 #define MEDIA_BUS_FMT_RGB444_2X8_PADHI_LE 0x1002
@@ -46,6 +46,7 @@ · 5 unmodified lines
4646 #define MEDIA_BUS_FMT_RGB565_2X8_BE 0x1007
4747 #define MEDIA_BUS_FMT_RGB565_2X8_LE 0x1008
4848 #define MEDIA_BUS_FMT_RGB666_1X18 0x1009
49+#define MEDIA_BUS_FMT_RGB666_2X9_BE 0x1025
4950 #define MEDIA_BUS_FMT_BGR666_1X18 0x1023
5051 #define MEDIA_BUS_FMT_RBG888_1X24 0x100e
5152 #define MEDIA_BUS_FMT_RGB666_1X24_CPADHI 0x1015

Keyboard shortcuts

General

Show keyboard shortcuts
?
Focus the current search
/

Issues and pull requests

Open filters
f

Issues, pull requests and Inbox

Select next item
j↓
Select previous item
k↑
Open selected item
Enter
Dismiss filters or clear selection
Esc

Repository code

Go to file
t