Commit b558dfd5 authored by Dave Airlie's avatar Dave Airlie

Merge tag 'drm-misc-next-2017-03-06' of git://anongit.freedesktop.org/git/drm-misc into drm-next

First slice of drm-misc-next for 4.12:

Core/subsystem-wide:
- link status core patch from Manasi, for signalling link train fail
  to userspace. I also had the i915 patch in here, but that had a
  small buglet in our CI, so reverted.
- more debugfs_remove removal from Noralf, almost there now (Noralf
  said he'll try to follow up with the stragglers).
- drm todo moved into kerneldoc, for better visibility (see
  Documentation/gpu/todo.rst), lots of starter tasks in there.
- devm_ of helpers + use it in sti (from Ben Gaignard, acked by Rob
  Herring)
- extended framebuffer fbdev support (for fbdev flipping), and vblank
  wait ioctl fbdev support (Maxime Ripard)
- misc small things all over, as usual
- add vblank callbacks to drm_crtc_funcs, plus make lots of good use
  of this to simplify drivers (Shawn Guo)
- new atomic iterator macros to unconfuse old vs. new state

Small drivers:
- vc4 improvements from Eric
- vc4 kerneldocs (Eric)!
- tons of improvements for dw-mipi-dsi in rockchip from John Keeping
  and Chris Zhong.
- MAINTAINERS entries for drivers managed in drm-misc. It's not yet
  official, still an experiment, but definitely not complete fail and
  better to avoid confusion. We kinda screwed that up with drm-misc a
  bit when we started committers last year.
- qxl atomic conversion (Gabriel Krisman)
- bunch of virtual driver polish (qxl, virgl, ...)
- misc tiny patches all over

This is the first time we've done the same merge-window blackout for
drm-misc as we've done for drm-intel for ages, hence why we have a
_lot_ of stuff queued already. But it's still only half of drm-intel
(room to grow!), and the drivers in drm-misc experiment seems to work
at least insofar as that you also get lots of driver updates here
alredy.

* tag 'drm-misc-next-2017-03-06' of git://anongit.freedesktop.org/git/drm-misc: (141 commits)
  drm/vc4: Fix OOPSes from trying to cache a partially constructed BO.
  drm/vc4: Fulfill user BO creation requests from the kernel BO cache.
  Revert "drm/i915: Implement Link Rate fallback on Link training failure"
  drm/fb-helper: implement ioctl FBIO_WAITFORVSYNC
  drm: Update drm_fbdev_cma_init documentation
  drm/rockchip/dsi: add dw-mipi power domain support
  drm/rockchip/dsi: fix insufficient bandwidth of some panel
  dt-bindings: add power domain node for dw-mipi-rockchip
  drm/rockchip/dsi: remove mode_valid function
  drm/rockchip/dsi: dw-mipi: correct the coding style
  drm/rockchip/dsi: dw-mipi: support RK3399 mipi dsi
  dt-bindings: add rk3399 support for dw-mipi-rockchip
  drm/rockchip: dw-mipi-dsi: add reset control
  drm/rockchip: dw-mipi-dsi: support non-burst modes
  drm/rockchip: dw-mipi-dsi: defer probe if panel is not loaded
  drm/rockchip: vop: test for P{H,V}SYNC
  drm/rockchip: dw-mipi-dsi: use positive check for N{H, V}SYNC
  drm/rockchip: dw-mipi-dsi: use specific poll helper
  drm/rockchip: dw-mipi-dsi: improve PLL configuration
  drm/rockchip: dw-mipi-dsi: properly configure PHY timing
  ...
parents c1ae3cfa ca39b449
...@@ -5,14 +5,19 @@ Required properties: ...@@ -5,14 +5,19 @@ Required properties:
- #address-cells: Should be <1>. - #address-cells: Should be <1>.
- #size-cells: Should be <0>. - #size-cells: Should be <0>.
- compatible: "rockchip,rk3288-mipi-dsi", "snps,dw-mipi-dsi". - compatible: "rockchip,rk3288-mipi-dsi", "snps,dw-mipi-dsi".
"rockchip,rk3399-mipi-dsi", "snps,dw-mipi-dsi".
- reg: Represent the physical address range of the controller. - reg: Represent the physical address range of the controller.
- interrupts: Represent the controller's interrupt to the CPU(s). - interrupts: Represent the controller's interrupt to the CPU(s).
- clocks, clock-names: Phandles to the controller's pll reference - clocks, clock-names: Phandles to the controller's pll reference
clock(ref) and APB clock(pclk), as described in [1]. clock(ref) and APB clock(pclk). For RK3399, a phy config clock
(phy_cfg) is additional required. As described in [1].
- rockchip,grf: this soc should set GRF regs to mux vopl/vopb. - rockchip,grf: this soc should set GRF regs to mux vopl/vopb.
- ports: contain a port node with endpoint definitions as defined in [2]. - ports: contain a port node with endpoint definitions as defined in [2].
For vopb,set the reg = <0> and set the reg = <1> for vopl. For vopb,set the reg = <0> and set the reg = <1> for vopl.
Optional properties:
- power-domains: a phandle to mipi dsi power domain node.
[1] Documentation/devicetree/bindings/clock/clock-bindings.txt [1] Documentation/devicetree/bindings/clock/clock-bindings.txt
[2] Documentation/devicetree/bindings/media/video-interfaces.txt [2] Documentation/devicetree/bindings/media/video-interfaces.txt
......
...@@ -183,14 +183,12 @@ GEM Objects Lifetime ...@@ -183,14 +183,12 @@ GEM Objects Lifetime
-------------------- --------------------
All GEM objects are reference-counted by the GEM core. References can be All GEM objects are reference-counted by the GEM core. References can be
acquired and release by :c:func:`calling acquired and release by :c:func:`calling drm_gem_object_get()` and
drm_gem_object_reference()` and :c:func:`drm_gem_object_put()` respectively. The caller must hold the
:c:func:`drm_gem_object_unreference()` respectively. The caller :c:type:`struct drm_device <drm_device>` struct_mutex lock when calling
must hold the :c:type:`struct drm_device <drm_device>` :c:func:`drm_gem_object_get()`. As a convenience, GEM provides
struct_mutex lock when calling :c:func:`drm_gem_object_put_unlocked()` functions that can be called without
:c:func:`drm_gem_object_reference()`. As a convenience, GEM holding the lock.
provides :c:func:`drm_gem_object_unreference_unlocked()`
functions that can be called without holding the lock.
When the last reference to a GEM object is released the GEM core calls When the last reference to a GEM object is released the GEM core calls
the :c:type:`struct drm_driver <drm_driver>` gem_free_object the :c:type:`struct drm_driver <drm_driver>` gem_free_object
......
...@@ -12,8 +12,10 @@ Linux GPU Driver Developer's Guide ...@@ -12,8 +12,10 @@ Linux GPU Driver Developer's Guide
drm-uapi drm-uapi
i915 i915
tinydrm tinydrm
vc4
vga-switcheroo vga-switcheroo
vgaarbiter vgaarbiter
todo
.. only:: subproject and html .. only:: subproject and html
......
...@@ -50,3 +50,13 @@ names are "Notes" with information for dangerous or tricky corner cases, ...@@ -50,3 +50,13 @@ names are "Notes" with information for dangerous or tricky corner cases,
and "FIXME" where the interface could be cleaned up. and "FIXME" where the interface could be cleaned up.
Also read the :ref:`guidelines for the kernel documentation at large <doc_guide>`. Also read the :ref:`guidelines for the kernel documentation at large <doc_guide>`.
Getting Started
===============
Developers interested in helping out with the DRM subsystem are very welcome.
Often people will resort to sending in patches for various issues reported by
checkpatch or sparse. We welcome such contributions.
Anyone looking to kick it up a notch can find a list of janitorial tasks on
the :ref:`TODO list <todo>`.
This diff is collapsed.
=====================================
drm/vc4 Broadcom VC4 Graphics Driver
=====================================
.. kernel-doc:: drivers/gpu/drm/vc4/vc4_drv.c
:doc: Broadcom VC4 Graphics Driver
Display Hardware Handling
=========================
This section covers everything related to the display hardware including
the mode setting infrastructure, plane, sprite and cursor handling and
display, output probing and related topics.
Pixel Valve (DRM CRTC)
----------------------
.. kernel-doc:: drivers/gpu/drm/vc4/vc4_crtc.c
:doc: VC4 CRTC module
HVS
---
.. kernel-doc:: drivers/gpu/drm/vc4/vc4_hvs.c
:doc: VC4 HVS module.
HVS planes
----------
.. kernel-doc:: drivers/gpu/drm/vc4/vc4_plane.c
:doc: VC4 plane module
HDMI encoder
------------
.. kernel-doc:: drivers/gpu/drm/vc4/vc4_hdmi.c
:doc: VC4 Falcon HDMI module
DSI encoder
-----------
.. kernel-doc:: drivers/gpu/drm/vc4/vc4_dsi.c
:doc: VC4 DSI0/DSI1 module
DPI encoder
-----------
.. kernel-doc:: drivers/gpu/drm/vc4/vc4_dpi.c
:doc: VC4 DPI module
VEC (Composite TV out) encoder
------------------------------
.. kernel-doc:: drivers/gpu/drm/vc4/vc4_vec.c
:doc: VC4 SDTV module
Memory Management and 3D Command Submission
===========================================
This section covers the GEM implementation in the vc4 driver.
GPU buffer object (BO) management
---------------------------------
.. kernel-doc:: drivers/gpu/drm/vc4/vc4_bo.c
:doc: VC4 GEM BO management support
V3D binner command list (BCL) validation
----------------------------------------
.. kernel-doc:: drivers/gpu/drm/vc4/vc4_validate.c
:doc: Command list validator for VC4.
V3D render command list (RCL) generation
----------------------------------------
.. kernel-doc:: drivers/gpu/drm/vc4/vc4_render_cl.c
:doc: Render command list generation
Shader validator for VC4
---------------------------
.. kernel-doc:: drivers/gpu/drm/vc4/vc4_validate_shaders.c
:doc: Shader validator for VC4.
V3D Interrupts
--------------
.. kernel-doc:: drivers/gpu/drm/vc4/vc4_irq.c
:doc: Interrupt management for the V3D engine
...@@ -4174,7 +4174,7 @@ F: drivers/gpu/drm/bridge/ ...@@ -4174,7 +4174,7 @@ F: drivers/gpu/drm/bridge/
DRM DRIVER FOR BOCHS VIRTUAL GPU DRM DRIVER FOR BOCHS VIRTUAL GPU
M: Gerd Hoffmann <kraxel@redhat.com> M: Gerd Hoffmann <kraxel@redhat.com>
L: virtualization@lists.linux-foundation.org L: virtualization@lists.linux-foundation.org
T: git git://git.kraxel.org/linux drm-qemu T: git git://anongit.freedesktop.org/drm/drm-misc
S: Maintained S: Maintained
F: drivers/gpu/drm/bochs/ F: drivers/gpu/drm/bochs/
...@@ -4182,7 +4182,7 @@ DRM DRIVER FOR QEMU'S CIRRUS DEVICE ...@@ -4182,7 +4182,7 @@ DRM DRIVER FOR QEMU'S CIRRUS DEVICE
M: Dave Airlie <airlied@redhat.com> M: Dave Airlie <airlied@redhat.com>
M: Gerd Hoffmann <kraxel@redhat.com> M: Gerd Hoffmann <kraxel@redhat.com>
L: virtualization@lists.linux-foundation.org L: virtualization@lists.linux-foundation.org
T: git git://git.kraxel.org/linux drm-qemu T: git git://anongit.freedesktop.org/drm/drm-misc
S: Obsolete S: Obsolete
W: https://www.kraxel.org/blog/2014/10/qemu-using-cirrus-considered-harmful/ W: https://www.kraxel.org/blog/2014/10/qemu-using-cirrus-considered-harmful/
F: drivers/gpu/drm/cirrus/ F: drivers/gpu/drm/cirrus/
...@@ -4239,6 +4239,7 @@ L: dri-devel@lists.freedesktop.org ...@@ -4239,6 +4239,7 @@ L: dri-devel@lists.freedesktop.org
S: Supported S: Supported
F: drivers/gpu/drm/atmel-hlcdc/ F: drivers/gpu/drm/atmel-hlcdc/
F: Documentation/devicetree/bindings/drm/atmel/ F: Documentation/devicetree/bindings/drm/atmel/
T: git git://anongit.freedesktop.org/drm/drm-misc
DRM DRIVERS FOR ALLWINNER A10 DRM DRIVERS FOR ALLWINNER A10
M: Maxime Ripard <maxime.ripard@free-electrons.com> M: Maxime Ripard <maxime.ripard@free-electrons.com>
...@@ -4255,6 +4256,8 @@ W: http://linux-meson.com/ ...@@ -4255,6 +4256,8 @@ W: http://linux-meson.com/
S: Supported S: Supported
F: drivers/gpu/drm/meson/ F: drivers/gpu/drm/meson/
F: Documentation/devicetree/bindings/display/amlogic,meson-vpu.txt F: Documentation/devicetree/bindings/display/amlogic,meson-vpu.txt
T: git git://anongit.freedesktop.org/drm/drm-meson
T: git git://anongit.freedesktop.org/drm/drm-misc
DRM DRIVERS FOR EXYNOS DRM DRIVERS FOR EXYNOS
M: Inki Dae <inki.dae@samsung.com> M: Inki Dae <inki.dae@samsung.com>
...@@ -4385,7 +4388,7 @@ DRM DRIVER FOR QXL VIRTUAL GPU ...@@ -4385,7 +4388,7 @@ DRM DRIVER FOR QXL VIRTUAL GPU
M: Dave Airlie <airlied@redhat.com> M: Dave Airlie <airlied@redhat.com>
M: Gerd Hoffmann <kraxel@redhat.com> M: Gerd Hoffmann <kraxel@redhat.com>
L: virtualization@lists.linux-foundation.org L: virtualization@lists.linux-foundation.org
T: git git://git.kraxel.org/linux drm-qemu T: git git://anongit.freedesktop.org/drm/drm-misc
S: Maintained S: Maintained
F: drivers/gpu/drm/qxl/ F: drivers/gpu/drm/qxl/
F: include/uapi/drm/qxl_drm.h F: include/uapi/drm/qxl_drm.h
...@@ -4396,6 +4399,7 @@ L: dri-devel@lists.freedesktop.org ...@@ -4396,6 +4399,7 @@ L: dri-devel@lists.freedesktop.org
S: Maintained S: Maintained
F: drivers/gpu/drm/rockchip/ F: drivers/gpu/drm/rockchip/
F: Documentation/devicetree/bindings/display/rockchip/ F: Documentation/devicetree/bindings/display/rockchip/
T: git git://anongit.freedesktop.org/drm/drm-misc
DRM DRIVER FOR SAVAGE VIDEO CARDS DRM DRIVER FOR SAVAGE VIDEO CARDS
S: Orphan / Obsolete S: Orphan / Obsolete
...@@ -4454,6 +4458,7 @@ S: Supported ...@@ -4454,6 +4458,7 @@ S: Supported
F: drivers/gpu/drm/vc4/ F: drivers/gpu/drm/vc4/
F: include/uapi/drm/vc4_drm.h F: include/uapi/drm/vc4_drm.h
F: Documentation/devicetree/bindings/display/brcm,bcm-vc4.txt F: Documentation/devicetree/bindings/display/brcm,bcm-vc4.txt
T: git git://anongit.freedesktop.org/drm/drm-misc
DRM DRIVERS FOR TI OMAP DRM DRIVERS FOR TI OMAP
M: Tomi Valkeinen <tomi.valkeinen@ti.com> M: Tomi Valkeinen <tomi.valkeinen@ti.com>
...@@ -4476,6 +4481,7 @@ L: dri-devel@lists.freedesktop.org ...@@ -4476,6 +4481,7 @@ L: dri-devel@lists.freedesktop.org
S: Maintained S: Maintained
F: drivers/gpu/drm/zte/ F: drivers/gpu/drm/zte/
F: Documentation/devicetree/bindings/display/zte,vou.txt F: Documentation/devicetree/bindings/display/zte,vou.txt
T: git git://anongit.freedesktop.org/drm/drm-misc
DSBR100 USB FM RADIO DRIVER DSBR100 USB FM RADIO DRIVER
M: Alexey Klimov <klimov.linux@gmail.com> M: Alexey Klimov <klimov.linux@gmail.com>
...@@ -13314,7 +13320,7 @@ M: David Airlie <airlied@linux.ie> ...@@ -13314,7 +13320,7 @@ M: David Airlie <airlied@linux.ie>
M: Gerd Hoffmann <kraxel@redhat.com> M: Gerd Hoffmann <kraxel@redhat.com>
L: dri-devel@lists.freedesktop.org L: dri-devel@lists.freedesktop.org
L: virtualization@lists.linux-foundation.org L: virtualization@lists.linux-foundation.org
T: git git://git.kraxel.org/linux drm-qemu T: git git://anongit.freedesktop.org/drm/drm-misc
S: Maintained S: Maintained
F: drivers/gpu/drm/virtio/ F: drivers/gpu/drm/virtio/
F: include/uapi/linux/virtio_gpu.h F: include/uapi/linux/virtio_gpu.h
......
...@@ -240,6 +240,8 @@ EXPORT_SYMBOL(dma_fence_enable_sw_signaling); ...@@ -240,6 +240,8 @@ EXPORT_SYMBOL(dma_fence_enable_sw_signaling);
* after it signals with dma_fence_signal. The callback itself can be called * after it signals with dma_fence_signal. The callback itself can be called
* from irq context. * from irq context.
* *
* Returns 0 in case of success, -ENOENT if the fence is already signaled
* and -EINVAL in case of error.
*/ */
int dma_fence_add_callback(struct dma_fence *fence, struct dma_fence_cb *cb, int dma_fence_add_callback(struct dma_fence *fence, struct dma_fence_cb *cb,
dma_fence_func_t func) dma_fence_func_t func)
......
...@@ -99,6 +99,15 @@ config DRM_FBDEV_EMULATION ...@@ -99,6 +99,15 @@ config DRM_FBDEV_EMULATION
If in doubt, say "Y". If in doubt, say "Y".
config DRM_FBDEV_OVERALLOC
int "Overallocation of the fbdev buffer"
depends on DRM_FBDEV_EMULATION
default 100
help
Defines the fbdev buffer overallocation in percent. Default
is 100. Typical values for double buffering will be 200,
triple buffering 300.
config DRM_LOAD_EDID_FIRMWARE config DRM_LOAD_EDID_FIRMWARE
bool "Allow to specify an EDID data set instead of probing for it" bool "Allow to specify an EDID data set instead of probing for it"
depends on DRM_KMS_HELPER depends on DRM_KMS_HELPER
......
...@@ -224,7 +224,7 @@ static int amdgpufb_create(struct drm_fb_helper *helper, ...@@ -224,7 +224,7 @@ static int amdgpufb_create(struct drm_fb_helper *helper,
info = drm_fb_helper_alloc_fbi(helper); info = drm_fb_helper_alloc_fbi(helper);
if (IS_ERR(info)) { if (IS_ERR(info)) {
ret = PTR_ERR(info); ret = PTR_ERR(info);
goto out_unref; goto out;
} }
info->par = rfbdev; info->par = rfbdev;
...@@ -233,7 +233,7 @@ static int amdgpufb_create(struct drm_fb_helper *helper, ...@@ -233,7 +233,7 @@ static int amdgpufb_create(struct drm_fb_helper *helper,
ret = amdgpu_framebuffer_init(adev->ddev, &rfbdev->rfb, &mode_cmd, gobj); ret = amdgpu_framebuffer_init(adev->ddev, &rfbdev->rfb, &mode_cmd, gobj);
if (ret) { if (ret) {
DRM_ERROR("failed to initialize framebuffer %d\n", ret); DRM_ERROR("failed to initialize framebuffer %d\n", ret);
goto out_destroy_fbi; goto out;
} }
fb = &rfbdev->rfb.base; fb = &rfbdev->rfb.base;
...@@ -266,7 +266,7 @@ static int amdgpufb_create(struct drm_fb_helper *helper, ...@@ -266,7 +266,7 @@ static int amdgpufb_create(struct drm_fb_helper *helper,
if (info->screen_base == NULL) { if (info->screen_base == NULL) {
ret = -ENOSPC; ret = -ENOSPC;
goto out_destroy_fbi; goto out;
} }
DRM_INFO("fb mappable at 0x%lX\n", info->fix.smem_start); DRM_INFO("fb mappable at 0x%lX\n", info->fix.smem_start);
...@@ -278,9 +278,7 @@ static int amdgpufb_create(struct drm_fb_helper *helper, ...@@ -278,9 +278,7 @@ static int amdgpufb_create(struct drm_fb_helper *helper,
vga_switcheroo_client_fb_set(adev->ddev->pdev, info); vga_switcheroo_client_fb_set(adev->ddev->pdev, info);
return 0; return 0;
out_destroy_fbi: out:
drm_fb_helper_release_fbi(helper);
out_unref:
if (abo) { if (abo) {
} }
...@@ -304,7 +302,6 @@ static int amdgpu_fbdev_destroy(struct drm_device *dev, struct amdgpu_fbdev *rfb ...@@ -304,7 +302,6 @@ static int amdgpu_fbdev_destroy(struct drm_device *dev, struct amdgpu_fbdev *rfb
struct amdgpu_framebuffer *rfb = &rfbdev->rfb; struct amdgpu_framebuffer *rfb = &rfbdev->rfb;
drm_fb_helper_unregister_fbi(&rfbdev->helper); drm_fb_helper_unregister_fbi(&rfbdev->helper);
drm_fb_helper_release_fbi(&rfbdev->helper);
if (rfb->obj) { if (rfb->obj) {
amdgpufb_destroy_pinned_object(rfb->obj); amdgpufb_destroy_pinned_object(rfb->obj);
......
...@@ -175,7 +175,6 @@ static struct drm_driver arcpgu_drm_driver = { ...@@ -175,7 +175,6 @@ static struct drm_driver arcpgu_drm_driver = {
.dumb_create = drm_gem_cma_dumb_create, .dumb_create = drm_gem_cma_dumb_create,
.dumb_map_offset = drm_gem_cma_dumb_map_offset, .dumb_map_offset = drm_gem_cma_dumb_map_offset,
.dumb_destroy = drm_gem_dumb_destroy, .dumb_destroy = drm_gem_dumb_destroy,
.get_vblank_counter = drm_vblank_no_hw_counter,
.prime_handle_to_fd = drm_gem_prime_handle_to_fd, .prime_handle_to_fd = drm_gem_prime_handle_to_fd,
.prime_fd_to_handle = drm_gem_prime_fd_to_handle, .prime_fd_to_handle = drm_gem_prime_fd_to_handle,
.gem_free_object_unlocked = drm_gem_cma_free_object, .gem_free_object_unlocked = drm_gem_cma_free_object,
......
...@@ -42,6 +42,24 @@ static void hdlcd_crtc_cleanup(struct drm_crtc *crtc) ...@@ -42,6 +42,24 @@ static void hdlcd_crtc_cleanup(struct drm_crtc *crtc)
drm_crtc_cleanup(crtc); drm_crtc_cleanup(crtc);
} }
static int hdlcd_crtc_enable_vblank(struct drm_crtc *crtc)
{
struct hdlcd_drm_private *hdlcd = crtc_to_hdlcd_priv(crtc);
unsigned int mask = hdlcd_read(hdlcd, HDLCD_REG_INT_MASK);
hdlcd_write(hdlcd, HDLCD_REG_INT_MASK, mask | HDLCD_INTERRUPT_VSYNC);
return 0;
}
static void hdlcd_crtc_disable_vblank(struct drm_crtc *crtc)
{
struct hdlcd_drm_private *hdlcd = crtc_to_hdlcd_priv(crtc);
unsigned int mask = hdlcd_read(hdlcd, HDLCD_REG_INT_MASK);
hdlcd_write(hdlcd, HDLCD_REG_INT_MASK, mask & ~HDLCD_INTERRUPT_VSYNC);
}
static const struct drm_crtc_funcs hdlcd_crtc_funcs = { static const struct drm_crtc_funcs hdlcd_crtc_funcs = {
.destroy = hdlcd_crtc_cleanup, .destroy = hdlcd_crtc_cleanup,
.set_config = drm_atomic_helper_set_config, .set_config = drm_atomic_helper_set_config,
...@@ -49,6 +67,8 @@ static const struct drm_crtc_funcs hdlcd_crtc_funcs = { ...@@ -49,6 +67,8 @@ static const struct drm_crtc_funcs hdlcd_crtc_funcs = {
.reset = drm_atomic_helper_crtc_reset, .reset = drm_atomic_helper_crtc_reset,
.atomic_duplicate_state = drm_atomic_helper_crtc_duplicate_state, .atomic_duplicate_state = drm_atomic_helper_crtc_duplicate_state,
.atomic_destroy_state = drm_atomic_helper_crtc_destroy_state, .atomic_destroy_state = drm_atomic_helper_crtc_destroy_state,
.enable_vblank = hdlcd_crtc_enable_vblank,
.disable_vblank = hdlcd_crtc_disable_vblank,
}; };
static struct simplefb_format supported_formats[] = SIMPLEFB_FORMATS; static struct simplefb_format supported_formats[] = SIMPLEFB_FORMATS;
......
...@@ -199,24 +199,6 @@ static void hdlcd_irq_uninstall(struct drm_device *drm) ...@@ -199,24 +199,6 @@ static void hdlcd_irq_uninstall(struct drm_device *drm)
hdlcd_write(hdlcd, HDLCD_REG_INT_MASK, irq_mask); hdlcd_write(hdlcd, HDLCD_REG_INT_MASK, irq_mask);
} }
static int hdlcd_enable_vblank(struct drm_device *drm, unsigned int crtc)
{
struct hdlcd_drm_private *hdlcd = drm->dev_private;
unsigned int mask = hdlcd_read(hdlcd, HDLCD_REG_INT_MASK);
hdlcd_write(hdlcd, HDLCD_REG_INT_MASK, mask | HDLCD_INTERRUPT_VSYNC);
return 0;
}
static void hdlcd_disable_vblank(struct drm_device *drm, unsigned int crtc)
{
struct hdlcd_drm_private *hdlcd = drm->dev_private;
unsigned int mask = hdlcd_read(hdlcd, HDLCD_REG_INT_MASK);
hdlcd_write(hdlcd, HDLCD_REG_INT_MASK, mask & ~HDLCD_INTERRUPT_VSYNC);
}
#ifdef CONFIG_DEBUG_FS #ifdef CONFIG_DEBUG_FS
static int hdlcd_show_underrun_count(struct seq_file *m, void *arg) static int hdlcd_show_underrun_count(struct seq_file *m, void *arg)
{ {
...@@ -278,9 +260,6 @@ static struct drm_driver hdlcd_driver = { ...@@ -278,9 +260,6 @@ static struct drm_driver hdlcd_driver = {
.irq_preinstall = hdlcd_irq_preinstall, .irq_preinstall = hdlcd_irq_preinstall,
.irq_postinstall = hdlcd_irq_postinstall, .irq_postinstall = hdlcd_irq_postinstall,
.irq_uninstall = hdlcd_irq_uninstall, .irq_uninstall = hdlcd_irq_uninstall,
.get_vblank_counter = drm_vblank_no_hw_counter,
.enable_vblank = hdlcd_enable_vblank,
.disable_vblank = hdlcd_disable_vblank,
.gem_free_object_unlocked = drm_gem_cma_free_object, .gem_free_object_unlocked = drm_gem_cma_free_object,
.gem_vm_ops = &drm_gem_cma_vm_ops, .gem_vm_ops = &drm_gem_cma_vm_ops,
.dumb_create = drm_gem_cma_dumb_create, .dumb_create = drm_gem_cma_dumb_create,
......
...@@ -167,6 +167,25 @@ static const struct drm_crtc_helper_funcs malidp_crtc_helper_funcs = { ...@@ -167,6 +167,25 @@ static const struct drm_crtc_helper_funcs malidp_crtc_helper_funcs = {
.atomic_check = malidp_crtc_atomic_check, .atomic_check = malidp_crtc_atomic_check,
}; };
static int malidp_crtc_enable_vblank(struct drm_crtc *crtc)
{
struct malidp_drm *malidp = crtc_to_malidp_device(crtc);
struct malidp_hw_device *hwdev = malidp->dev;
malidp_hw_enable_irq(hwdev, MALIDP_DE_BLOCK,
hwdev->map.de_irq_map.vsync_irq);
return 0;
}
static void malidp_crtc_disable_vblank(struct drm_crtc *crtc)
{
struct malidp_drm *malidp = crtc_to_malidp_device(crtc);
struct malidp_hw_device *hwdev = malidp->dev;
malidp_hw_disable_irq(hwdev, MALIDP_DE_BLOCK,
hwdev->map.de_irq_map.vsync_irq);
}
static const struct drm_crtc_funcs malidp_crtc_funcs = { static const struct drm_crtc_funcs malidp_crtc_funcs = {
.destroy = drm_crtc_cleanup, .destroy = drm_crtc_cleanup,
.set_config = drm_atomic_helper_set_config, .set_config = drm_atomic_helper_set_config,
...@@ -174,6 +193,8 @@ static const struct drm_crtc_funcs malidp_crtc_funcs = { ...@@ -174,6 +193,8 @@ static const struct drm_crtc_funcs malidp_crtc_funcs = {
.reset = drm_atomic_helper_crtc_reset, .reset = drm_atomic_helper_crtc_reset,
.atomic_duplicate_state = drm_atomic_helper_crtc_duplicate_state, .atomic_duplicate_state = drm_atomic_helper_crtc_duplicate_state,
.atomic_destroy_state = drm_atomic_helper_crtc_destroy_state, .atomic_destroy_state = drm_atomic_helper_crtc_destroy_state,
.enable_vblank = malidp_crtc_enable_vblank,
.disable_vblank = malidp_crtc_disable_vblank,
}; };
int malidp_crtc_init(struct drm_device *drm) int malidp_crtc_init(struct drm_device *drm)
......
...@@ -100,7 +100,7 @@ static void malidp_atomic_commit_tail(struct drm_atomic_state *state) ...@@ -100,7 +100,7 @@ static void malidp_atomic_commit_tail(struct drm_atomic_state *state)
drm_atomic_helper_cleanup_planes(drm, state); drm_atomic_helper_cleanup_planes(drm, state);
} }
static struct drm_mode_config_helper_funcs malidp_mode_config_helpers = { static const struct drm_mode_config_helper_funcs malidp_mode_config_helpers = {
.atomic_commit_tail = malidp_atomic_commit_tail, .atomic_commit_tail = malidp_atomic_commit_tail,
}; };
...@@ -111,25 +111,6 @@ static const struct drm_mode_config_funcs malidp_mode_config_funcs = { ...@@ -111,25 +111,6 @@ static const struct drm_mode_config_funcs malidp_mode_config_funcs = {
.atomic_commit = drm_atomic_helper_commit, .atomic_commit = drm_atomic_helper_commit,
}; };
static int malidp_enable_vblank(struct drm_device *drm, unsigned int crtc)
{
struct malidp_drm *malidp = drm->dev_private;
struct malidp_hw_device *hwdev = malidp->dev;
malidp_hw_enable_irq(hwdev, MALIDP_DE_BLOCK,
hwdev->map.de_irq_map.vsync_irq);
return 0;
}
static void malidp_disable_vblank(struct drm_device *drm, unsigned int pipe)
{
struct malidp_drm *malidp = drm->dev_private;
struct malidp_hw_device *hwdev = malidp->dev;
malidp_hw_disable_irq(hwdev, MALIDP_DE_BLOCK,
hwdev->map.de_irq_map.vsync_irq);
}
static int malidp_init(struct drm_device *drm) static int malidp_init(struct drm_device *drm)
{ {
int ret; int ret;
...@@ -213,9 +194,6 @@ static struct drm_driver malidp_driver = { ...@@ -213,9 +194,6 @@ static struct drm_driver malidp_driver = {
.driver_features = DRIVER_GEM | DRIVER_MODESET | DRIVER_ATOMIC | .driver_features = DRIVER_GEM | DRIVER_MODESET | DRIVER_ATOMIC |
DRIVER_PRIME, DRIVER_PRIME,
.lastclose = malidp_lastclose, .lastclose = malidp_lastclose,
.get_vblank_counter = drm_vblank_no_hw_counter,
.enable_vblank = malidp_enable_vblank,
.disable_vblank = malidp_disable_vblank,
.gem_free_object_unlocked = drm_gem_cma_free_object, .gem_free_object_unlocked = drm_gem_cma_free_object,
.gem_vm_ops = &drm_gem_cma_vm_ops, .gem_vm_ops = &drm_gem_cma_vm_ops,
.dumb_create = drm_gem_cma_dumb_create, .dumb_create = drm_gem_cma_dumb_create,
......
...@@ -418,6 +418,25 @@ static bool armada_drm_crtc_mode_fixup(struct drm_crtc *crtc, ...@@ -418,6 +418,25 @@ static bool armada_drm_crtc_mode_fixup(struct drm_crtc *crtc,
return true; return true;
} }
/* These are locked by dev->vbl_lock */
static void armada_drm_crtc_disable_irq(struct armada_crtc *dcrtc, u32 mask)
{
if (dcrtc->irq_ena & mask) {
dcrtc->irq_ena &= ~mask;
writel(dcrtc->irq_ena, dcrtc->base + LCD_SPU_IRQ_ENA);
}
}
static void armada_drm_crtc_enable_irq(struct armada_crtc *dcrtc, u32 mask)
{
if ((dcrtc->irq_ena & mask) != mask) {
dcrtc->irq_ena |= mask;
writel(dcrtc->irq_ena, dcrtc->base + LCD_SPU_IRQ_ENA);
if (readl_relaxed(dcrtc->base + LCD_SPU_IRQ_ISR) & mask)
writel(0, dcrtc->base + LCD_SPU_IRQ_ISR);
}
}
static void armada_drm_crtc_irq(struct armada_crtc *dcrtc, u32 stat) static void armada_drm_crtc_irq(struct armada_crtc *dcrtc, u32 stat)
{ {
void __iomem *base = dcrtc->base; void __iomem *base = dcrtc->base;
...@@ -491,25 +510,6 @@ static irqreturn_t armada_drm_irq(int irq, void *arg) ...@@ -491,25 +510,6 @@ static irqreturn_t armada_drm_irq(int irq, void *arg)
return IRQ_NONE; return IRQ_NONE;
} }
/* These are locked by dev->vbl_lock */
void armada_drm_crtc_disable_irq(struct armada_crtc *dcrtc, u32 mask)
{
if (dcrtc->irq_ena & mask) {
dcrtc->irq_ena &= ~mask;
writel(dcrtc->irq_ena, dcrtc->base + LCD_SPU_IRQ_ENA);
}
}
void armada_drm_crtc_enable_irq(struct armada_crtc *dcrtc, u32 mask)
{
if ((dcrtc->irq_ena & mask) != mask) {
dcrtc->irq_ena |= mask;
writel(dcrtc->irq_ena, dcrtc->base + LCD_SPU_IRQ_ENA);
if (readl_relaxed(dcrtc->base + LCD_SPU_IRQ_ISR) & mask)
writel(0, dcrtc->base + LCD_SPU_IRQ_ISR);
}
}
static uint32_t armada_drm_crtc_calculate_csc(struct armada_crtc *dcrtc) static uint32_t armada_drm_crtc_calculate_csc(struct armada_crtc *dcrtc)
{ {
struct drm_display_mode *adj = &dcrtc->crtc.mode; struct drm_display_mode *adj = &dcrtc->crtc.mode;
...@@ -1109,6 +1109,22 @@ armada_drm_crtc_set_property(struct drm_crtc *crtc, ...@@ -1109,6 +1109,22 @@ armada_drm_crtc_set_property(struct drm_crtc *crtc,
return 0; return 0;
} }
/* These are called under the vbl_lock. */
static int armada_drm_crtc_enable_vblank(struct drm_crtc *crtc)
{
struct armada_crtc *dcrtc = drm_to_armada_crtc(crtc);
armada_drm_crtc_enable_irq(dcrtc, VSYNC_IRQ_ENA);
return 0;
}
static void armada_drm_crtc_disable_vblank(struct drm_crtc *crtc)
{
struct armada_crtc *dcrtc = drm_to_armada_crtc(crtc);
armada_drm_crtc_disable_irq(dcrtc, VSYNC_IRQ_ENA);
}
static const struct drm_crtc_funcs armada_crtc_funcs = { static const struct drm_crtc_funcs armada_crtc_funcs = {
.cursor_set = armada_drm_crtc_cursor_set, .cursor_set = armada_drm_crtc_cursor_set,
.cursor_move = armada_drm_crtc_cursor_move, .cursor_move = armada_drm_crtc_cursor_move,
...@@ -1116,6 +1132,8 @@ static const struct drm_crtc_funcs armada_crtc_funcs = { ...@@ -1116,6 +1132,8 @@ static const struct drm_crtc_funcs armada_crtc_funcs = {
.set_config = drm_crtc_helper_set_config, .set_config = drm_crtc_helper_set_config,
.page_flip = armada_drm_crtc_page_flip, .page_flip = armada_drm_crtc_page_flip,
.set_property = armada_drm_crtc_set_property, .set_property = armada_drm_crtc_set_property,
.enable_vblank = armada_drm_crtc_enable_vblank,
.disable_vblank = armada_drm_crtc_disable_vblank,
}; };
static const struct drm_plane_funcs armada_primary_plane_funcs = { static const struct drm_plane_funcs armada_primary_plane_funcs = {
......
...@@ -104,8 +104,6 @@ struct armada_crtc { ...@@ -104,8 +104,6 @@ struct armada_crtc {
void armada_drm_crtc_gamma_set(struct drm_crtc *, u16, u16, u16, int); void armada_drm_crtc_gamma_set(struct drm_crtc *, u16, u16, u16, int);
void armada_drm_crtc_gamma_get(struct drm_crtc *, u16 *, u16 *, u16 *, int); void armada_drm_crtc_gamma_get(struct drm_crtc *, u16 *, u16 *, u16 *, int);
void armada_drm_crtc_disable_irq(struct armada_crtc *, u32);
void armada_drm_crtc_enable_irq(struct armada_crtc *, u32);
void armada_drm_crtc_update_regs(struct armada_crtc *, struct armada_regs *); void armada_drm_crtc_update_regs(struct armada_crtc *, struct armada_regs *);
void armada_drm_crtc_plane_disable(struct armada_crtc *dcrtc, void armada_drm_crtc_plane_disable(struct armada_crtc *dcrtc,
......
...@@ -107,40 +107,9 @@ static struct drm_info_list armada_debugfs_list[] = { ...@@ -107,40 +107,9 @@ static struct drm_info_list armada_debugfs_list[] = {
}; };
#define ARMADA_DEBUGFS_ENTRIES ARRAY_SIZE(armada_debugfs_list) #define ARMADA_DEBUGFS_ENTRIES ARRAY_SIZE(armada_debugfs_list)
static int drm_add_fake_info_node(struct drm_minor *minor, struct dentry *ent,
const void *key)
{
struct drm_info_node *node;
node = kmalloc(sizeof(struct drm_info_node), GFP_KERNEL);
if (!node) {
debugfs_remove(ent);
return -ENOMEM;
}
node->minor = minor;
node->dent = ent;
node->info_ent = (void *) key;
mutex_lock(&minor->debugfs_lock);
list_add(&node->list, &minor->debugfs_list);
mutex_unlock(&minor->debugfs_lock);
return 0;
}
static int armada_debugfs_create(struct dentry *root, struct drm_minor *minor,
const char *name, umode_t mode, const struct file_operations *fops)
{
struct dentry *de;
de = debugfs_create_file(name, mode, root, minor->dev, fops);
return drm_add_fake_info_node(minor, de, fops);
}
int armada_drm_debugfs_init(struct drm_minor *minor) int armada_drm_debugfs_init(struct drm_minor *minor)
{ {
struct dentry *de;
int ret; int ret;
ret = drm_debugfs_create_files(armada_debugfs_list, ret = drm_debugfs_create_files(armada_debugfs_list,
...@@ -149,29 +118,15 @@ int armada_drm_debugfs_init(struct drm_minor *minor) ...@@ -149,29 +118,15 @@ int armada_drm_debugfs_init(struct drm_minor *minor)
if (ret) if (ret)
return ret; return ret;
ret = armada_debugfs_create(minor->debugfs_root, minor, de = debugfs_create_file("reg", S_IFREG | S_IRUSR,
"reg", S_IFREG | S_IRUSR, &fops_reg_r); minor->debugfs_root, minor->dev, &fops_reg_r);
if (ret) if (!de)
goto err_1; return -ENOMEM;
ret = armada_debugfs_create(minor->debugfs_root, minor,
"reg_wr", S_IFREG | S_IWUSR, &fops_reg_w);
if (ret)
goto err_2;
return ret;
err_2: de = debugfs_create_file("reg_wr", S_IFREG | S_IWUSR,
drm_debugfs_remove_files((struct drm_info_list *)&fops_reg_r, 1, minor); minor->debugfs_root, minor->dev, &fops_reg_w);
err_1: if (!de)
drm_debugfs_remove_files(armada_debugfs_list, ARMADA_DEBUGFS_ENTRIES, return -ENOMEM;
minor);
return ret;
}
void armada_drm_debugfs_cleanup(struct drm_minor *minor) return 0;
{
drm_debugfs_remove_files((struct drm_info_list *)&fops_reg_w, 1, minor);
drm_debugfs_remove_files((struct drm_info_list *)&fops_reg_r, 1, minor);
drm_debugfs_remove_files(armada_debugfs_list, ARMADA_DEBUGFS_ENTRIES,
minor);
} }
...@@ -90,6 +90,5 @@ void armada_fbdev_fini(struct drm_device *); ...@@ -90,6 +90,5 @@ void armada_fbdev_fini(struct drm_device *);
int armada_overlay_plane_create(struct drm_device *, unsigned long); int armada_overlay_plane_create(struct drm_device *, unsigned long);
int armada_drm_debugfs_init(struct drm_minor *); int armada_drm_debugfs_init(struct drm_minor *);
void armada_drm_debugfs_cleanup(struct drm_minor *);
#endif #endif
...@@ -49,20 +49,6 @@ void armada_drm_queue_unref_work(struct drm_device *dev, ...@@ -49,20 +49,6 @@ void armada_drm_queue_unref_work(struct drm_device *dev,
spin_unlock_irqrestore(&dev->event_lock, flags); spin_unlock_irqrestore(&dev->event_lock, flags);
} }
/* These are called under the vbl_lock. */
static int armada_drm_enable_vblank(struct drm_device *dev, unsigned int pipe)
{
struct armada_private *priv = dev->dev_private;
armada_drm_crtc_enable_irq(priv->dcrtc[pipe], VSYNC_IRQ_ENA);
return 0;
}
static void armada_drm_disable_vblank(struct drm_device *dev, unsigned int pipe)
{
struct armada_private *priv = dev->dev_private;
armada_drm_crtc_disable_irq(priv->dcrtc[pipe], VSYNC_IRQ_ENA);
}
static struct drm_ioctl_desc armada_ioctls[] = { static struct drm_ioctl_desc armada_ioctls[] = {
DRM_IOCTL_DEF_DRV(ARMADA_GEM_CREATE, armada_gem_create_ioctl,0), DRM_IOCTL_DEF_DRV(ARMADA_GEM_CREATE, armada_gem_create_ioctl,0),
DRM_IOCTL_DEF_DRV(ARMADA_GEM_MMAP, armada_gem_mmap_ioctl, 0), DRM_IOCTL_DEF_DRV(ARMADA_GEM_MMAP, armada_gem_mmap_ioctl, 0),
...@@ -87,9 +73,6 @@ static const struct file_operations armada_drm_fops = { ...@@ -87,9 +73,6 @@ static const struct file_operations armada_drm_fops = {
static struct drm_driver armada_drm_driver = { static struct drm_driver armada_drm_driver = {
.lastclose = armada_drm_lastclose, .lastclose = armada_drm_lastclose,
.get_vblank_counter = drm_vblank_no_hw_counter,
.enable_vblank = armada_drm_enable_vblank,
.disable_vblank = armada_drm_disable_vblank,
.gem_free_object_unlocked = armada_gem_free_object, .gem_free_object_unlocked = armada_gem_free_object,
.prime_handle_to_fd = drm_gem_prime_handle_to_fd, .prime_handle_to_fd = drm_gem_prime_handle_to_fd,
.prime_fd_to_handle = drm_gem_prime_fd_to_handle, .prime_fd_to_handle = drm_gem_prime_fd_to_handle,
...@@ -226,9 +209,6 @@ static void armada_drm_unbind(struct device *dev) ...@@ -226,9 +209,6 @@ static void armada_drm_unbind(struct device *dev)
drm_kms_helper_poll_fini(&priv->drm); drm_kms_helper_poll_fini(&priv->drm);
armada_fbdev_fini(&priv->drm); armada_fbdev_fini(&priv->drm);
#ifdef CONFIG_DEBUG_FS
armada_drm_debugfs_cleanup(priv->drm.primary);
#endif
drm_dev_unregister(&priv->drm); drm_dev_unregister(&priv->drm);
component_unbind_all(dev, &priv->drm); component_unbind_all(dev, &priv->drm);
......
...@@ -157,7 +157,6 @@ int armada_fbdev_init(struct drm_device *dev) ...@@ -157,7 +157,6 @@ int armada_fbdev_init(struct drm_device *dev)
return 0; return 0;
err_fb_setup: err_fb_setup:
drm_fb_helper_release_fbi(fbh);
drm_fb_helper_fini(fbh); drm_fb_helper_fini(fbh);
err_fb_helper: err_fb_helper:
priv->fbdev = NULL; priv->fbdev = NULL;
...@@ -179,7 +178,6 @@ void armada_fbdev_fini(struct drm_device *dev) ...@@ -179,7 +178,6 @@ void armada_fbdev_fini(struct drm_device *dev)
if (fbh) { if (fbh) {
drm_fb_helper_unregister_fbi(fbh); drm_fb_helper_unregister_fbi(fbh);
drm_fb_helper_release_fbi(fbh);
drm_fb_helper_fini(fbh); drm_fb_helper_fini(fbh);
......
...@@ -215,13 +215,13 @@ static int astfb_create(struct drm_fb_helper *helper, ...@@ -215,13 +215,13 @@ static int astfb_create(struct drm_fb_helper *helper,
info = drm_fb_helper_alloc_fbi(helper); info = drm_fb_helper_alloc_fbi(helper);
if (IS_ERR(info)) { if (IS_ERR(info)) {
ret = PTR_ERR(info); ret = PTR_ERR(info);
goto err_free_vram; goto out;
} }
info->par = afbdev; info->par = afbdev;
ret = ast_framebuffer_init(dev, &afbdev->afb, &mode_cmd, gobj); ret = ast_framebuffer_init(dev, &afbdev->afb, &mode_cmd, gobj);
if (ret) if (ret)
goto err_release_fbi; goto out;
afbdev->sysram = sysram; afbdev->sysram = sysram;
afbdev->size = size; afbdev->size = size;
...@@ -250,9 +250,7 @@ static int astfb_create(struct drm_fb_helper *helper, ...@@ -250,9 +250,7 @@ static int astfb_create(struct drm_fb_helper *helper,
return 0; return 0;
err_release_fbi: out:
drm_fb_helper_release_fbi(helper);
err_free_vram:
vfree(sysram); vfree(sysram);
return ret; return ret;
} }
...@@ -287,7 +285,6 @@ static void ast_fbdev_destroy(struct drm_device *dev, ...@@ -287,7 +285,6 @@ static void ast_fbdev_destroy(struct drm_device *dev,
struct ast_framebuffer *afb = &afbdev->afb; struct ast_framebuffer *afb = &afbdev->afb;
drm_fb_helper_unregister_fbi(&afbdev->helper); drm_fb_helper_unregister_fbi(&afbdev->helper);
drm_fb_helper_release_fbi(&afbdev->helper);
if (afb->obj) { if (afb->obj) {
drm_gem_object_unreference_unlocked(afb->obj); drm_gem_object_unreference_unlocked(afb->obj);
......
atmel-hlcdc-dc-y := atmel_hlcdc_crtc.o \ atmel-hlcdc-dc-y := atmel_hlcdc_crtc.o \
atmel_hlcdc_dc.o \ atmel_hlcdc_dc.o \
atmel_hlcdc_layer.o \
atmel_hlcdc_output.o \ atmel_hlcdc_output.o \
atmel_hlcdc_plane.o atmel_hlcdc_plane.o
......
...@@ -434,6 +434,25 @@ static void atmel_hlcdc_crtc_destroy_state(struct drm_crtc *crtc, ...@@ -434,6 +434,25 @@ static void atmel_hlcdc_crtc_destroy_state(struct drm_crtc *crtc,
kfree(state); kfree(state);
} }
static int atmel_hlcdc_crtc_enable_vblank(struct drm_crtc *c)
{
struct atmel_hlcdc_crtc *crtc = drm_crtc_to_atmel_hlcdc_crtc(c);
struct regmap *regmap = crtc->dc->hlcdc->regmap;
/* Enable SOF (Start Of Frame) interrupt for vblank counting */
regmap_write(regmap, ATMEL_HLCDC_IER, ATMEL_HLCDC_SOF);
return 0;
}
static void atmel_hlcdc_crtc_disable_vblank(struct drm_crtc *c)
{
struct atmel_hlcdc_crtc *crtc = drm_crtc_to_atmel_hlcdc_crtc(c);
struct regmap *regmap = crtc->dc->hlcdc->regmap;
regmap_write(regmap, ATMEL_HLCDC_IDR, ATMEL_HLCDC_SOF);
}
static const struct drm_crtc_funcs atmel_hlcdc_crtc_funcs = { static const struct drm_crtc_funcs atmel_hlcdc_crtc_funcs = {
.page_flip = drm_atomic_helper_page_flip, .page_flip = drm_atomic_helper_page_flip,
.set_config = drm_atomic_helper_set_config, .set_config = drm_atomic_helper_set_config,
...@@ -441,12 +460,14 @@ static const struct drm_crtc_funcs atmel_hlcdc_crtc_funcs = { ...@@ -441,12 +460,14 @@ static const struct drm_crtc_funcs atmel_hlcdc_crtc_funcs = {
.reset = atmel_hlcdc_crtc_reset, .reset = atmel_hlcdc_crtc_reset,
.atomic_duplicate_state = atmel_hlcdc_crtc_duplicate_state, .atomic_duplicate_state = atmel_hlcdc_crtc_duplicate_state,
.atomic_destroy_state = atmel_hlcdc_crtc_destroy_state, .atomic_destroy_state = atmel_hlcdc_crtc_destroy_state,
.enable_vblank = atmel_hlcdc_crtc_enable_vblank,
.disable_vblank = atmel_hlcdc_crtc_disable_vblank,
}; };
int atmel_hlcdc_crtc_create(struct drm_device *dev) int atmel_hlcdc_crtc_create(struct drm_device *dev)
{ {
struct atmel_hlcdc_plane *primary = NULL, *cursor = NULL;
struct atmel_hlcdc_dc *dc = dev->dev_private; struct atmel_hlcdc_dc *dc = dev->dev_private;
struct atmel_hlcdc_planes *planes = dc->planes;
struct atmel_hlcdc_crtc *crtc; struct atmel_hlcdc_crtc *crtc;
int ret; int ret;
int i; int i;
...@@ -457,20 +478,41 @@ int atmel_hlcdc_crtc_create(struct drm_device *dev) ...@@ -457,20 +478,41 @@ int atmel_hlcdc_crtc_create(struct drm_device *dev)
crtc->dc = dc; crtc->dc = dc;
ret = drm_crtc_init_with_planes(dev, &crtc->base, for (i = 0; i < ATMEL_HLCDC_MAX_LAYERS; i++) {
&planes->primary->base, if (!dc->layers[i])
planes->cursor ? &planes->cursor->base : NULL, continue;
&atmel_hlcdc_crtc_funcs, NULL);
switch (dc->layers[i]->desc->type) {
case ATMEL_HLCDC_BASE_LAYER:
primary = atmel_hlcdc_layer_to_plane(dc->layers[i]);
break;
case ATMEL_HLCDC_CURSOR_LAYER:
cursor = atmel_hlcdc_layer_to_plane(dc->layers[i]);
break;
default:
break;
}
}
ret = drm_crtc_init_with_planes(dev, &crtc->base, &primary->base,
&cursor->base, &atmel_hlcdc_crtc_funcs,
NULL);
if (ret < 0) if (ret < 0)
goto fail; goto fail;
crtc->id = drm_crtc_index(&crtc->base); crtc->id = drm_crtc_index(&crtc->base);
if (planes->cursor) for (i = 0; i < ATMEL_HLCDC_MAX_LAYERS; i++) {
planes->cursor->base.possible_crtcs = 1 << crtc->id; struct atmel_hlcdc_plane *overlay;
for (i = 0; i < planes->noverlays; i++) if (dc->layers[i] &&
planes->overlays[i]->base.possible_crtcs = 1 << crtc->id; dc->layers[i]->desc->type == ATMEL_HLCDC_OVERLAY_LAYER) {
overlay = atmel_hlcdc_layer_to_plane(dc->layers[i]);
overlay->base.possible_crtcs = 1 << crtc->id;
}
}
drm_crtc_helper_add(&crtc->base, &lcdc_crtc_helper_funcs); drm_crtc_helper_add(&crtc->base, &lcdc_crtc_helper_funcs);
drm_crtc_vblank_reset(&crtc->base); drm_crtc_vblank_reset(&crtc->base);
......
...@@ -36,7 +36,7 @@ static const struct atmel_hlcdc_layer_desc atmel_hlcdc_at91sam9n12_layers[] = { ...@@ -36,7 +36,7 @@ static const struct atmel_hlcdc_layer_desc atmel_hlcdc_at91sam9n12_layers[] = {
.regs_offset = 0x40, .regs_offset = 0x40,
.id = 0, .id = 0,
.type = ATMEL_HLCDC_BASE_LAYER, .type = ATMEL_HLCDC_BASE_LAYER,
.nconfigs = 5, .cfgs_offset = 0x2c,
.layout = { .layout = {
.xstride = { 2 }, .xstride = { 2 },
.default_color = 3, .default_color = 3,
...@@ -65,7 +65,7 @@ static const struct atmel_hlcdc_layer_desc atmel_hlcdc_at91sam9x5_layers[] = { ...@@ -65,7 +65,7 @@ static const struct atmel_hlcdc_layer_desc atmel_hlcdc_at91sam9x5_layers[] = {
.regs_offset = 0x40, .regs_offset = 0x40,
.id = 0, .id = 0,
.type = ATMEL_HLCDC_BASE_LAYER, .type = ATMEL_HLCDC_BASE_LAYER,
.nconfigs = 5, .cfgs_offset = 0x2c,
.layout = { .layout = {
.xstride = { 2 }, .xstride = { 2 },
.default_color = 3, .default_color = 3,
...@@ -80,7 +80,7 @@ static const struct atmel_hlcdc_layer_desc atmel_hlcdc_at91sam9x5_layers[] = { ...@@ -80,7 +80,7 @@ static const struct atmel_hlcdc_layer_desc atmel_hlcdc_at91sam9x5_layers[] = {
.regs_offset = 0x100, .regs_offset = 0x100,
.id = 1, .id = 1,
.type = ATMEL_HLCDC_OVERLAY_LAYER, .type = ATMEL_HLCDC_OVERLAY_LAYER,
.nconfigs = 10, .cfgs_offset = 0x2c,
.layout = { .layout = {
.pos = 2, .pos = 2,
.size = 3, .size = 3,
...@@ -98,7 +98,7 @@ static const struct atmel_hlcdc_layer_desc atmel_hlcdc_at91sam9x5_layers[] = { ...@@ -98,7 +98,7 @@ static const struct atmel_hlcdc_layer_desc atmel_hlcdc_at91sam9x5_layers[] = {
.regs_offset = 0x280, .regs_offset = 0x280,
.id = 2, .id = 2,
.type = ATMEL_HLCDC_OVERLAY_LAYER, .type = ATMEL_HLCDC_OVERLAY_LAYER,
.nconfigs = 17, .cfgs_offset = 0x4c,
.layout = { .layout = {
.pos = 2, .pos = 2,
.size = 3, .size = 3,
...@@ -109,6 +109,7 @@ static const struct atmel_hlcdc_layer_desc atmel_hlcdc_at91sam9x5_layers[] = { ...@@ -109,6 +109,7 @@ static const struct atmel_hlcdc_layer_desc atmel_hlcdc_at91sam9x5_layers[] = {
.chroma_key = 10, .chroma_key = 10,
.chroma_key_mask = 11, .chroma_key_mask = 11,
.general_config = 12, .general_config = 12,
.scaler_config = 13,
.csc = 14, .csc = 14,
}, },
}, },
...@@ -118,9 +119,9 @@ static const struct atmel_hlcdc_layer_desc atmel_hlcdc_at91sam9x5_layers[] = { ...@@ -118,9 +119,9 @@ static const struct atmel_hlcdc_layer_desc atmel_hlcdc_at91sam9x5_layers[] = {
.regs_offset = 0x340, .regs_offset = 0x340,
.id = 3, .id = 3,
.type = ATMEL_HLCDC_CURSOR_LAYER, .type = ATMEL_HLCDC_CURSOR_LAYER,
.nconfigs = 10,
.max_width = 128, .max_width = 128,
.max_height = 128, .max_height = 128,
.cfgs_offset = 0x2c,
.layout = { .layout = {
.pos = 2, .pos = 2,
.size = 3, .size = 3,
...@@ -153,7 +154,7 @@ static const struct atmel_hlcdc_layer_desc atmel_hlcdc_sama5d3_layers[] = { ...@@ -153,7 +154,7 @@ static const struct atmel_hlcdc_layer_desc atmel_hlcdc_sama5d3_layers[] = {
.regs_offset = 0x40, .regs_offset = 0x40,
.id = 0, .id = 0,
.type = ATMEL_HLCDC_BASE_LAYER, .type = ATMEL_HLCDC_BASE_LAYER,
.nconfigs = 7, .cfgs_offset = 0x2c,
.layout = { .layout = {
.xstride = { 2 }, .xstride = { 2 },
.default_color = 3, .default_color = 3,
...@@ -168,7 +169,7 @@ static const struct atmel_hlcdc_layer_desc atmel_hlcdc_sama5d3_layers[] = { ...@@ -168,7 +169,7 @@ static const struct atmel_hlcdc_layer_desc atmel_hlcdc_sama5d3_layers[] = {
.regs_offset = 0x140, .regs_offset = 0x140,
.id = 1, .id = 1,
.type = ATMEL_HLCDC_OVERLAY_LAYER, .type = ATMEL_HLCDC_OVERLAY_LAYER,
.nconfigs = 10, .cfgs_offset = 0x2c,
.layout = { .layout = {
.pos = 2, .pos = 2,
.size = 3, .size = 3,
...@@ -186,7 +187,7 @@ static const struct atmel_hlcdc_layer_desc atmel_hlcdc_sama5d3_layers[] = { ...@@ -186,7 +187,7 @@ static const struct atmel_hlcdc_layer_desc atmel_hlcdc_sama5d3_layers[] = {
.regs_offset = 0x240, .regs_offset = 0x240,
.id = 2, .id = 2,
.type = ATMEL_HLCDC_OVERLAY_LAYER, .type = ATMEL_HLCDC_OVERLAY_LAYER,
.nconfigs = 10, .cfgs_offset = 0x2c,
.layout = { .layout = {
.pos = 2, .pos = 2,
.size = 3, .size = 3,
...@@ -204,7 +205,7 @@ static const struct atmel_hlcdc_layer_desc atmel_hlcdc_sama5d3_layers[] = { ...@@ -204,7 +205,7 @@ static const struct atmel_hlcdc_layer_desc atmel_hlcdc_sama5d3_layers[] = {
.regs_offset = 0x340, .regs_offset = 0x340,
.id = 3, .id = 3,
.type = ATMEL_HLCDC_OVERLAY_LAYER, .type = ATMEL_HLCDC_OVERLAY_LAYER,
.nconfigs = 42, .cfgs_offset = 0x4c,
.layout = { .layout = {
.pos = 2, .pos = 2,
.size = 3, .size = 3,
...@@ -215,6 +216,11 @@ static const struct atmel_hlcdc_layer_desc atmel_hlcdc_sama5d3_layers[] = { ...@@ -215,6 +216,11 @@ static const struct atmel_hlcdc_layer_desc atmel_hlcdc_sama5d3_layers[] = {
.chroma_key = 10, .chroma_key = 10,
.chroma_key_mask = 11, .chroma_key_mask = 11,
.general_config = 12, .general_config = 12,
.scaler_config = 13,
.phicoeffs = {
.x = 17,
.y = 33,
},
.csc = 14, .csc = 14,
}, },
}, },
...@@ -224,9 +230,9 @@ static const struct atmel_hlcdc_layer_desc atmel_hlcdc_sama5d3_layers[] = { ...@@ -224,9 +230,9 @@ static const struct atmel_hlcdc_layer_desc atmel_hlcdc_sama5d3_layers[] = {
.regs_offset = 0x440, .regs_offset = 0x440,
.id = 4, .id = 4,
.type = ATMEL_HLCDC_CURSOR_LAYER, .type = ATMEL_HLCDC_CURSOR_LAYER,
.nconfigs = 10,
.max_width = 128, .max_width = 128,
.max_height = 128, .max_height = 128,
.cfgs_offset = 0x2c,
.layout = { .layout = {
.pos = 2, .pos = 2,
.size = 3, .size = 3,
...@@ -236,6 +242,7 @@ static const struct atmel_hlcdc_layer_desc atmel_hlcdc_sama5d3_layers[] = { ...@@ -236,6 +242,7 @@ static const struct atmel_hlcdc_layer_desc atmel_hlcdc_sama5d3_layers[] = {
.chroma_key = 7, .chroma_key = 7,
.chroma_key_mask = 8, .chroma_key_mask = 8,
.general_config = 9, .general_config = 9,
.scaler_config = 13,
}, },
}, },
}; };
...@@ -260,7 +267,7 @@ static const struct atmel_hlcdc_layer_desc atmel_hlcdc_sama5d4_layers[] = { ...@@ -260,7 +267,7 @@ static const struct atmel_hlcdc_layer_desc atmel_hlcdc_sama5d4_layers[] = {
.regs_offset = 0x40, .regs_offset = 0x40,
.id = 0, .id = 0,
.type = ATMEL_HLCDC_BASE_LAYER, .type = ATMEL_HLCDC_BASE_LAYER,
.nconfigs = 7, .cfgs_offset = 0x2c,
.layout = { .layout = {
.xstride = { 2 }, .xstride = { 2 },
.default_color = 3, .default_color = 3,
...@@ -275,7 +282,7 @@ static const struct atmel_hlcdc_layer_desc atmel_hlcdc_sama5d4_layers[] = { ...@@ -275,7 +282,7 @@ static const struct atmel_hlcdc_layer_desc atmel_hlcdc_sama5d4_layers[] = {
.regs_offset = 0x140, .regs_offset = 0x140,
.id = 1, .id = 1,
.type = ATMEL_HLCDC_OVERLAY_LAYER, .type = ATMEL_HLCDC_OVERLAY_LAYER,
.nconfigs = 10, .cfgs_offset = 0x2c,
.layout = { .layout = {
.pos = 2, .pos = 2,
.size = 3, .size = 3,
...@@ -293,7 +300,7 @@ static const struct atmel_hlcdc_layer_desc atmel_hlcdc_sama5d4_layers[] = { ...@@ -293,7 +300,7 @@ static const struct atmel_hlcdc_layer_desc atmel_hlcdc_sama5d4_layers[] = {
.regs_offset = 0x240, .regs_offset = 0x240,
.id = 2, .id = 2,
.type = ATMEL_HLCDC_OVERLAY_LAYER, .type = ATMEL_HLCDC_OVERLAY_LAYER,
.nconfigs = 10, .cfgs_offset = 0x2c,
.layout = { .layout = {
.pos = 2, .pos = 2,
.size = 3, .size = 3,
...@@ -311,7 +318,7 @@ static const struct atmel_hlcdc_layer_desc atmel_hlcdc_sama5d4_layers[] = { ...@@ -311,7 +318,7 @@ static const struct atmel_hlcdc_layer_desc atmel_hlcdc_sama5d4_layers[] = {
.regs_offset = 0x340, .regs_offset = 0x340,
.id = 3, .id = 3,
.type = ATMEL_HLCDC_OVERLAY_LAYER, .type = ATMEL_HLCDC_OVERLAY_LAYER,
.nconfigs = 42, .cfgs_offset = 0x4c,
.layout = { .layout = {
.pos = 2, .pos = 2,
.size = 3, .size = 3,
...@@ -322,6 +329,11 @@ static const struct atmel_hlcdc_layer_desc atmel_hlcdc_sama5d4_layers[] = { ...@@ -322,6 +329,11 @@ static const struct atmel_hlcdc_layer_desc atmel_hlcdc_sama5d4_layers[] = {
.chroma_key = 10, .chroma_key = 10,
.chroma_key_mask = 11, .chroma_key_mask = 11,
.general_config = 12, .general_config = 12,
.scaler_config = 13,
.phicoeffs = {
.x = 17,
.y = 33,
},
.csc = 14, .csc = 14,
}, },
}, },
...@@ -392,6 +404,17 @@ int atmel_hlcdc_dc_mode_valid(struct atmel_hlcdc_dc *dc, ...@@ -392,6 +404,17 @@ int atmel_hlcdc_dc_mode_valid(struct atmel_hlcdc_dc *dc,
return MODE_OK; return MODE_OK;
} }
static void atmel_hlcdc_layer_irq(struct atmel_hlcdc_layer *layer)
{
if (!layer)
return;
if (layer->desc->type == ATMEL_HLCDC_BASE_LAYER ||
layer->desc->type == ATMEL_HLCDC_OVERLAY_LAYER ||
layer->desc->type == ATMEL_HLCDC_CURSOR_LAYER)
atmel_hlcdc_plane_irq(atmel_hlcdc_layer_to_plane(layer));
}
static irqreturn_t atmel_hlcdc_dc_irq_handler(int irq, void *data) static irqreturn_t atmel_hlcdc_dc_irq_handler(int irq, void *data)
{ {
struct drm_device *dev = data; struct drm_device *dev = data;
...@@ -410,12 +433,8 @@ static irqreturn_t atmel_hlcdc_dc_irq_handler(int irq, void *data) ...@@ -410,12 +433,8 @@ static irqreturn_t atmel_hlcdc_dc_irq_handler(int irq, void *data)
atmel_hlcdc_crtc_irq(dc->crtc); atmel_hlcdc_crtc_irq(dc->crtc);
for (i = 0; i < ATMEL_HLCDC_MAX_LAYERS; i++) { for (i = 0; i < ATMEL_HLCDC_MAX_LAYERS; i++) {
struct atmel_hlcdc_layer *layer = dc->layers[i]; if (ATMEL_HLCDC_LAYER_STATUS(i) & status)
atmel_hlcdc_layer_irq(dc->layers[i]);
if (!(ATMEL_HLCDC_LAYER_STATUS(i) & status) || !layer)
continue;
atmel_hlcdc_layer_irq(layer);
} }
return IRQ_HANDLED; return IRQ_HANDLED;
...@@ -537,9 +556,7 @@ static const struct drm_mode_config_funcs mode_config_funcs = { ...@@ -537,9 +556,7 @@ static const struct drm_mode_config_funcs mode_config_funcs = {
static int atmel_hlcdc_dc_modeset_init(struct drm_device *dev) static int atmel_hlcdc_dc_modeset_init(struct drm_device *dev)
{ {
struct atmel_hlcdc_dc *dc = dev->dev_private; struct atmel_hlcdc_dc *dc = dev->dev_private;
struct atmel_hlcdc_planes *planes;
int ret; int ret;
int i;
drm_mode_config_init(dev); drm_mode_config_init(dev);
...@@ -549,25 +566,12 @@ static int atmel_hlcdc_dc_modeset_init(struct drm_device *dev) ...@@ -549,25 +566,12 @@ static int atmel_hlcdc_dc_modeset_init(struct drm_device *dev)
return ret; return ret;
} }
planes = atmel_hlcdc_create_planes(dev); ret = atmel_hlcdc_create_planes(dev);
if (IS_ERR(planes)) { if (ret) {
dev_err(dev->dev, "failed to create planes\n"); dev_err(dev->dev, "failed to create planes: %d\n", ret);
return PTR_ERR(planes); return ret;
} }
dc->planes = planes;
dc->layers[planes->primary->layer.desc->id] =
&planes->primary->layer;
if (planes->cursor)
dc->layers[planes->cursor->layer.desc->id] =
&planes->cursor->layer;
for (i = 0; i < planes->noverlays; i++)
dc->layers[planes->overlays[i]->layer.desc->id] =
&planes->overlays[i]->layer;
ret = atmel_hlcdc_crtc_create(dev); ret = atmel_hlcdc_crtc_create(dev);
if (ret) { if (ret) {
dev_err(dev->dev, "failed to create crtc\n"); dev_err(dev->dev, "failed to create crtc\n");
...@@ -720,25 +724,6 @@ static void atmel_hlcdc_dc_irq_uninstall(struct drm_device *dev) ...@@ -720,25 +724,6 @@ static void atmel_hlcdc_dc_irq_uninstall(struct drm_device *dev)
regmap_read(dc->hlcdc->regmap, ATMEL_HLCDC_ISR, &isr); regmap_read(dc->hlcdc->regmap, ATMEL_HLCDC_ISR, &isr);
} }
static int atmel_hlcdc_dc_enable_vblank(struct drm_device *dev,
unsigned int pipe)
{
struct atmel_hlcdc_dc *dc = dev->dev_private;
/* Enable SOF (Start Of Frame) interrupt for vblank counting */
regmap_write(dc->hlcdc->regmap, ATMEL_HLCDC_IER, ATMEL_HLCDC_SOF);
return 0;
}
static void atmel_hlcdc_dc_disable_vblank(struct drm_device *dev,
unsigned int pipe)
{
struct atmel_hlcdc_dc *dc = dev->dev_private;
regmap_write(dc->hlcdc->regmap, ATMEL_HLCDC_IDR, ATMEL_HLCDC_SOF);
}
static const struct file_operations fops = { static const struct file_operations fops = {
.owner = THIS_MODULE, .owner = THIS_MODULE,
.open = drm_open, .open = drm_open,
...@@ -760,9 +745,6 @@ static struct drm_driver atmel_hlcdc_dc_driver = { ...@@ -760,9 +745,6 @@ static struct drm_driver atmel_hlcdc_dc_driver = {
.irq_preinstall = atmel_hlcdc_dc_irq_uninstall, .irq_preinstall = atmel_hlcdc_dc_irq_uninstall,
.irq_postinstall = atmel_hlcdc_dc_irq_postinstall, .irq_postinstall = atmel_hlcdc_dc_irq_postinstall,
.irq_uninstall = atmel_hlcdc_dc_irq_uninstall, .irq_uninstall = atmel_hlcdc_dc_irq_uninstall,
.get_vblank_counter = drm_vblank_no_hw_counter,
.enable_vblank = atmel_hlcdc_dc_enable_vblank,
.disable_vblank = atmel_hlcdc_dc_disable_vblank,
.gem_free_object_unlocked = drm_gem_cma_free_object, .gem_free_object_unlocked = drm_gem_cma_free_object,
.gem_vm_ops = &drm_gem_cma_vm_ops, .gem_vm_ops = &drm_gem_cma_vm_ops,
.prime_handle_to_fd = drm_gem_prime_handle_to_fd, .prime_handle_to_fd = drm_gem_prime_handle_to_fd,
......
This diff is collapsed.
This diff is collapsed.
...@@ -107,10 +107,8 @@ static int bochsfb_create(struct drm_fb_helper *helper, ...@@ -107,10 +107,8 @@ static int bochsfb_create(struct drm_fb_helper *helper,
info->par = &bochs->fb.helper; info->par = &bochs->fb.helper;
ret = bochs_framebuffer_init(bochs->dev, &bochs->fb.gfb, &mode_cmd, gobj); ret = bochs_framebuffer_init(bochs->dev, &bochs->fb.gfb, &mode_cmd, gobj);
if (ret) { if (ret)
drm_fb_helper_release_fbi(helper);
return ret; return ret;
}
bochs->fb.size = size; bochs->fb.size = size;
...@@ -144,7 +142,6 @@ static int bochs_fbdev_destroy(struct bochs_device *bochs) ...@@ -144,7 +142,6 @@ static int bochs_fbdev_destroy(struct bochs_device *bochs)
DRM_DEBUG_DRIVER("\n"); DRM_DEBUG_DRIVER("\n");
drm_fb_helper_unregister_fbi(&bochs->fb.helper); drm_fb_helper_unregister_fbi(&bochs->fb.helper);
drm_fb_helper_release_fbi(&bochs->fb.helper);
if (gfb->obj) { if (gfb->obj) {
drm_gem_object_unreference_unlocked(gfb->obj); drm_gem_object_unreference_unlocked(gfb->obj);
......
...@@ -2184,6 +2184,10 @@ static int sii8620_probe(struct i2c_client *client, ...@@ -2184,6 +2184,10 @@ static int sii8620_probe(struct i2c_client *client,
sii8620_irq_thread, sii8620_irq_thread,
IRQF_TRIGGER_HIGH | IRQF_ONESHOT, IRQF_TRIGGER_HIGH | IRQF_ONESHOT,
"sii8620", ctx); "sii8620", ctx);
if (ret < 0) {
dev_err(dev, "failed to install IRQ handler\n");
return ret;
}
ctx->gpio_reset = devm_gpiod_get(dev, "reset", GPIOD_OUT_HIGH); ctx->gpio_reset = devm_gpiod_get(dev, "reset", GPIOD_OUT_HIGH);
if (IS_ERR(ctx->gpio_reset)) { if (IS_ERR(ctx->gpio_reset)) {
......
...@@ -220,7 +220,7 @@ static const struct of_device_id tfp410_match[] = { ...@@ -220,7 +220,7 @@ static const struct of_device_id tfp410_match[] = {
}; };
MODULE_DEVICE_TABLE(of, tfp410_match); MODULE_DEVICE_TABLE(of, tfp410_match);
struct platform_driver tfp410_platform_driver = { static struct platform_driver tfp410_platform_driver = {
.probe = tfp410_probe, .probe = tfp410_probe,
.remove = tfp410_remove, .remove = tfp410_remove,
.driver = { .driver = {
......
...@@ -250,7 +250,6 @@ static int cirrus_fbdev_destroy(struct drm_device *dev, ...@@ -250,7 +250,6 @@ static int cirrus_fbdev_destroy(struct drm_device *dev,
struct cirrus_framebuffer *gfb = &gfbdev->gfb; struct cirrus_framebuffer *gfb = &gfbdev->gfb;
drm_fb_helper_unregister_fbi(&gfbdev->helper); drm_fb_helper_unregister_fbi(&gfbdev->helper);
drm_fb_helper_release_fbi(&gfbdev->helper);
if (gfb->obj) { if (gfb->obj) {
drm_gem_object_unreference_unlocked(gfb->obj); drm_gem_object_unreference_unlocked(gfb->obj);
......
This diff is collapsed.
This diff is collapsed.
...@@ -88,7 +88,7 @@ drm_clflush_pages(struct page *pages[], unsigned long num_pages) ...@@ -88,7 +88,7 @@ drm_clflush_pages(struct page *pages[], unsigned long num_pages)
} }
if (wbinvd_on_all_cpus()) if (wbinvd_on_all_cpus())
printk(KERN_ERR "Timed out waiting for cache flush.\n"); pr_err("Timed out waiting for cache flush\n");
#elif defined(__powerpc__) #elif defined(__powerpc__)
unsigned long i; unsigned long i;
...@@ -105,7 +105,7 @@ drm_clflush_pages(struct page *pages[], unsigned long num_pages) ...@@ -105,7 +105,7 @@ drm_clflush_pages(struct page *pages[], unsigned long num_pages)
kunmap_atomic(page_virtual); kunmap_atomic(page_virtual);
} }
#else #else
printk(KERN_ERR "Architecture has no drm_cache.c support\n"); pr_err("Architecture has no drm_cache.c support\n");
WARN_ON_ONCE(1); WARN_ON_ONCE(1);
#endif #endif
} }
...@@ -134,9 +134,9 @@ drm_clflush_sg(struct sg_table *st) ...@@ -134,9 +134,9 @@ drm_clflush_sg(struct sg_table *st)
} }
if (wbinvd_on_all_cpus()) if (wbinvd_on_all_cpus())
printk(KERN_ERR "Timed out waiting for cache flush.\n"); pr_err("Timed out waiting for cache flush\n");
#else #else
printk(KERN_ERR "Architecture has no drm_cache.c support\n"); pr_err("Architecture has no drm_cache.c support\n");
WARN_ON_ONCE(1); WARN_ON_ONCE(1);
#endif #endif
} }
...@@ -167,9 +167,9 @@ drm_clflush_virt_range(void *addr, unsigned long length) ...@@ -167,9 +167,9 @@ drm_clflush_virt_range(void *addr, unsigned long length)
} }
if (wbinvd_on_all_cpus()) if (wbinvd_on_all_cpus())
printk(KERN_ERR "Timed out waiting for cache flush.\n"); pr_err("Timed out waiting for cache flush\n");
#else #else
printk(KERN_ERR "Architecture has no drm_cache.c support\n"); pr_err("Architecture has no drm_cache.c support\n");
WARN_ON_ONCE(1); WARN_ON_ONCE(1);
#endif #endif
} }
......
...@@ -35,8 +35,8 @@ ...@@ -35,8 +35,8 @@
* als fixed panels or anything else that can display pixels in some form. As * als fixed panels or anything else that can display pixels in some form. As
* opposed to all other KMS objects representing hardware (like CRTC, encoder or * opposed to all other KMS objects representing hardware (like CRTC, encoder or
* plane abstractions) connectors can be hotplugged and unplugged at runtime. * plane abstractions) connectors can be hotplugged and unplugged at runtime.
* Hence they are reference-counted using drm_connector_reference() and * Hence they are reference-counted using drm_connector_get() and
* drm_connector_unreference(). * drm_connector_put().
* *
* KMS driver must create, initialize, register and attach at a &struct * KMS driver must create, initialize, register and attach at a &struct
* drm_connector for each such sink. The instance is created as other KMS * drm_connector for each such sink. The instance is created as other KMS
...@@ -128,22 +128,8 @@ static void drm_connector_get_cmdline_mode(struct drm_connector *connector) ...@@ -128,22 +128,8 @@ static void drm_connector_get_cmdline_mode(struct drm_connector *connector)
return; return;
if (mode->force) { if (mode->force) {
const char *s; DRM_INFO("forcing %s connector %s\n", connector->name,
drm_get_connector_force_name(mode->force));
switch (mode->force) {
case DRM_FORCE_OFF:
s = "OFF";
break;
case DRM_FORCE_ON_DIGITAL:
s = "ON - dig";
break;
default:
case DRM_FORCE_ON:
s = "ON";
break;
}
DRM_INFO("forcing %s connector %s\n", connector->name, s);
connector->force = mode->force; connector->force = mode->force;
} }
...@@ -189,7 +175,7 @@ int drm_connector_init(struct drm_device *dev, ...@@ -189,7 +175,7 @@ int drm_connector_init(struct drm_device *dev,
struct ida *connector_ida = struct ida *connector_ida =
&drm_connector_enum_list[connector_type].ida; &drm_connector_enum_list[connector_type].ida;
ret = drm_mode_object_get_reg(dev, &connector->base, ret = __drm_mode_object_add(dev, &connector->base,
DRM_MODE_OBJECT_CONNECTOR, DRM_MODE_OBJECT_CONNECTOR,
false, drm_connector_free); false, drm_connector_free);
if (ret) if (ret)
...@@ -244,6 +230,10 @@ int drm_connector_init(struct drm_device *dev, ...@@ -244,6 +230,10 @@ int drm_connector_init(struct drm_device *dev,
drm_object_attach_property(&connector->base, drm_object_attach_property(&connector->base,
config->dpms_property, 0); config->dpms_property, 0);
drm_object_attach_property(&connector->base,
config->link_status_property,
0);
if (drm_core_check_feature(dev, DRIVER_ATOMIC)) { if (drm_core_check_feature(dev, DRIVER_ATOMIC)) {
drm_object_attach_property(&connector->base, config->prop_crtc_id, 0); drm_object_attach_property(&connector->base, config->prop_crtc_id, 0);
} }
...@@ -445,10 +435,10 @@ void drm_connector_unregister_all(struct drm_device *dev) ...@@ -445,10 +435,10 @@ void drm_connector_unregister_all(struct drm_device *dev)
struct drm_connector *connector; struct drm_connector *connector;
struct drm_connector_list_iter conn_iter; struct drm_connector_list_iter conn_iter;
drm_connector_list_iter_get(dev, &conn_iter); drm_connector_list_iter_begin(dev, &conn_iter);
drm_for_each_connector_iter(connector, &conn_iter) drm_for_each_connector_iter(connector, &conn_iter)
drm_connector_unregister(connector); drm_connector_unregister(connector);
drm_connector_list_iter_put(&conn_iter); drm_connector_list_iter_end(&conn_iter);
} }
int drm_connector_register_all(struct drm_device *dev) int drm_connector_register_all(struct drm_device *dev)
...@@ -457,13 +447,13 @@ int drm_connector_register_all(struct drm_device *dev) ...@@ -457,13 +447,13 @@ int drm_connector_register_all(struct drm_device *dev)
struct drm_connector_list_iter conn_iter; struct drm_connector_list_iter conn_iter;
int ret = 0; int ret = 0;
drm_connector_list_iter_get(dev, &conn_iter); drm_connector_list_iter_begin(dev, &conn_iter);
drm_for_each_connector_iter(connector, &conn_iter) { drm_for_each_connector_iter(connector, &conn_iter) {
ret = drm_connector_register(connector); ret = drm_connector_register(connector);
if (ret) if (ret)
break; break;
} }
drm_connector_list_iter_put(&conn_iter); drm_connector_list_iter_end(&conn_iter);
if (ret) if (ret)
drm_connector_unregister_all(dev); drm_connector_unregister_all(dev);
...@@ -488,6 +478,28 @@ const char *drm_get_connector_status_name(enum drm_connector_status status) ...@@ -488,6 +478,28 @@ const char *drm_get_connector_status_name(enum drm_connector_status status)
} }
EXPORT_SYMBOL(drm_get_connector_status_name); EXPORT_SYMBOL(drm_get_connector_status_name);
/**
* drm_get_connector_force_name - return a string for connector force
* @force: connector force to get name of
*
* Returns: const pointer to name.
*/
const char *drm_get_connector_force_name(enum drm_connector_force force)
{
switch (force) {
case DRM_FORCE_UNSPECIFIED:
return "unspecified";
case DRM_FORCE_OFF:
return "off";
case DRM_FORCE_ON:
return "on";
case DRM_FORCE_ON_DIGITAL:
return "digital";
default:
return "unknown";
}
}
#ifdef CONFIG_LOCKDEP #ifdef CONFIG_LOCKDEP
static struct lockdep_map connector_list_iter_dep_map = { static struct lockdep_map connector_list_iter_dep_map = {
.name = "drm_connector_list_iter" .name = "drm_connector_list_iter"
...@@ -495,23 +507,23 @@ static struct lockdep_map connector_list_iter_dep_map = { ...@@ -495,23 +507,23 @@ static struct lockdep_map connector_list_iter_dep_map = {
#endif #endif
/** /**
* drm_connector_list_iter_get - initialize a connector_list iterator * drm_connector_list_iter_begin - initialize a connector_list iterator
* @dev: DRM device * @dev: DRM device
* @iter: connector_list iterator * @iter: connector_list iterator
* *
* Sets @iter up to walk the &drm_mode_config.connector_list of @dev. @iter * Sets @iter up to walk the &drm_mode_config.connector_list of @dev. @iter
* must always be cleaned up again by calling drm_connector_list_iter_put(). * must always be cleaned up again by calling drm_connector_list_iter_end().
* Iteration itself happens using drm_connector_list_iter_next() or * Iteration itself happens using drm_connector_list_iter_next() or
* drm_for_each_connector_iter(). * drm_for_each_connector_iter().
*/ */
void drm_connector_list_iter_get(struct drm_device *dev, void drm_connector_list_iter_begin(struct drm_device *dev,
struct drm_connector_list_iter *iter) struct drm_connector_list_iter *iter)
{ {
iter->dev = dev; iter->dev = dev;
iter->conn = NULL; iter->conn = NULL;
lock_acquire_shared_recursive(&connector_list_iter_dep_map, 0, 1, NULL, _RET_IP_); lock_acquire_shared_recursive(&connector_list_iter_dep_map, 0, 1, NULL, _RET_IP_);
} }
EXPORT_SYMBOL(drm_connector_list_iter_get); EXPORT_SYMBOL(drm_connector_list_iter_begin);
/** /**
* drm_connector_list_iter_next - return next connector * drm_connector_list_iter_next - return next connector
...@@ -545,14 +557,14 @@ drm_connector_list_iter_next(struct drm_connector_list_iter *iter) ...@@ -545,14 +557,14 @@ drm_connector_list_iter_next(struct drm_connector_list_iter *iter)
spin_unlock_irqrestore(&config->connector_list_lock, flags); spin_unlock_irqrestore(&config->connector_list_lock, flags);
if (old_conn) if (old_conn)
drm_connector_unreference(old_conn); drm_connector_put(old_conn);
return iter->conn; return iter->conn;
} }
EXPORT_SYMBOL(drm_connector_list_iter_next); EXPORT_SYMBOL(drm_connector_list_iter_next);
/** /**
* drm_connector_list_iter_put - tear down a connector_list iterator * drm_connector_list_iter_end - tear down a connector_list iterator
* @iter: connector_list iterator * @iter: connector_list iterator
* *
* Tears down @iter and releases any resources (like &drm_connector references) * Tears down @iter and releases any resources (like &drm_connector references)
...@@ -560,14 +572,14 @@ EXPORT_SYMBOL(drm_connector_list_iter_next); ...@@ -560,14 +572,14 @@ EXPORT_SYMBOL(drm_connector_list_iter_next);
* iteration completes fully or when it was aborted without walking the entire * iteration completes fully or when it was aborted without walking the entire
* list. * list.
*/ */
void drm_connector_list_iter_put(struct drm_connector_list_iter *iter) void drm_connector_list_iter_end(struct drm_connector_list_iter *iter)
{ {
iter->dev = NULL; iter->dev = NULL;
if (iter->conn) if (iter->conn)
drm_connector_unreference(iter->conn); drm_connector_put(iter->conn);
lock_release(&connector_list_iter_dep_map, 0, _RET_IP_); lock_release(&connector_list_iter_dep_map, 0, _RET_IP_);
} }
EXPORT_SYMBOL(drm_connector_list_iter_put); EXPORT_SYMBOL(drm_connector_list_iter_end);
static const struct drm_prop_enum_list drm_subpixel_enum_list[] = { static const struct drm_prop_enum_list drm_subpixel_enum_list[] = {
{ SubPixelUnknown, "Unknown" }, { SubPixelUnknown, "Unknown" },
...@@ -599,6 +611,12 @@ static const struct drm_prop_enum_list drm_dpms_enum_list[] = { ...@@ -599,6 +611,12 @@ static const struct drm_prop_enum_list drm_dpms_enum_list[] = {
}; };
DRM_ENUM_NAME_FN(drm_get_dpms_name, drm_dpms_enum_list) DRM_ENUM_NAME_FN(drm_get_dpms_name, drm_dpms_enum_list)
static const struct drm_prop_enum_list drm_link_status_enum_list[] = {
{ DRM_MODE_LINK_STATUS_GOOD, "Good" },
{ DRM_MODE_LINK_STATUS_BAD, "Bad" },
};
DRM_ENUM_NAME_FN(drm_get_link_status_name, drm_link_status_enum_list)
/** /**
* drm_display_info_set_bus_formats - set the supported bus formats * drm_display_info_set_bus_formats - set the supported bus formats
* @info: display info to store bus formats in * @info: display info to store bus formats in
...@@ -718,6 +736,11 @@ DRM_ENUM_NAME_FN(drm_get_tv_subconnector_name, ...@@ -718,6 +736,11 @@ DRM_ENUM_NAME_FN(drm_get_tv_subconnector_name,
* tiling and virtualize both &drm_crtc and &drm_plane if needed. Drivers * tiling and virtualize both &drm_crtc and &drm_plane if needed. Drivers
* should update this value using drm_mode_connector_set_tile_property(). * should update this value using drm_mode_connector_set_tile_property().
* Userspace cannot change this property. * Userspace cannot change this property.
* link-status:
* Connector link-status property to indicate the status of link. The default
* value of link-status is "GOOD". If something fails during or after modeset,
* the kernel driver may set this to "BAD" and issue a hotplug uevent. Drivers
* should update this value using drm_mode_connector_set_link_status_property().
* *
* Connectors also have one standardized atomic property: * Connectors also have one standardized atomic property:
* *
...@@ -759,6 +782,13 @@ int drm_connector_create_standard_properties(struct drm_device *dev) ...@@ -759,6 +782,13 @@ int drm_connector_create_standard_properties(struct drm_device *dev)
return -ENOMEM; return -ENOMEM;
dev->mode_config.tile_property = prop; dev->mode_config.tile_property = prop;
prop = drm_property_create_enum(dev, 0, "link-status",
drm_link_status_enum_list,
ARRAY_SIZE(drm_link_status_enum_list));
if (!prop)
return -ENOMEM;
dev->mode_config.link_status_property = prop;
return 0; return 0;
} }
...@@ -1088,6 +1118,36 @@ int drm_mode_connector_update_edid_property(struct drm_connector *connector, ...@@ -1088,6 +1118,36 @@ int drm_mode_connector_update_edid_property(struct drm_connector *connector,
} }
EXPORT_SYMBOL(drm_mode_connector_update_edid_property); EXPORT_SYMBOL(drm_mode_connector_update_edid_property);
/**
* drm_mode_connector_set_link_status_property - Set link status property of a connector
* @connector: drm connector
* @link_status: new value of link status property (0: Good, 1: Bad)
*
* In usual working scenario, this link status property will always be set to
* "GOOD". If something fails during or after a mode set, the kernel driver
* may set this link status property to "BAD". The caller then needs to send a
* hotplug uevent for userspace to re-check the valid modes through
* GET_CONNECTOR_IOCTL and retry modeset.
*
* Note: Drivers cannot rely on userspace to support this property and
* issue a modeset. As such, they may choose to handle issues (like
* re-training a link) without userspace's intervention.
*
* The reason for adding this property is to handle link training failures, but
* it is not limited to DP or link training. For example, if we implement
* asynchronous setcrtc, this property can be used to report any failures in that.
*/
void drm_mode_connector_set_link_status_property(struct drm_connector *connector,
uint64_t link_status)
{
struct drm_device *dev = connector->dev;
drm_modeset_lock(&dev->mode_config.connection_mutex, NULL);
connector->state->link_status = link_status;
drm_modeset_unlock(&dev->mode_config.connection_mutex);
}
EXPORT_SYMBOL(drm_mode_connector_set_link_status_property);
int drm_mode_connector_set_obj_prop(struct drm_mode_object *obj, int drm_mode_connector_set_obj_prop(struct drm_mode_object *obj,
struct drm_property *property, struct drm_property *property,
uint64_t value) uint64_t value)
...@@ -1249,7 +1309,7 @@ int drm_mode_getconnector(struct drm_device *dev, void *data, ...@@ -1249,7 +1309,7 @@ int drm_mode_getconnector(struct drm_device *dev, void *data,
out: out:
mutex_unlock(&dev->mode_config.mutex); mutex_unlock(&dev->mode_config.mutex);
out_unref: out_unref:
drm_connector_unreference(connector); drm_connector_put(connector);
return ret; return ret;
} }
......
...@@ -282,7 +282,7 @@ int drm_crtc_init_with_planes(struct drm_device *dev, struct drm_crtc *crtc, ...@@ -282,7 +282,7 @@ int drm_crtc_init_with_planes(struct drm_device *dev, struct drm_crtc *crtc,
spin_lock_init(&crtc->commit_lock); spin_lock_init(&crtc->commit_lock);
drm_modeset_lock_init(&crtc->mutex); drm_modeset_lock_init(&crtc->mutex);
ret = drm_mode_object_get(dev, &crtc->base, DRM_MODE_OBJECT_CRTC); ret = drm_mode_object_add(dev, &crtc->base, DRM_MODE_OBJECT_CRTC);
if (ret) if (ret)
return ret; return ret;
...@@ -471,9 +471,9 @@ int drm_mode_set_config_internal(struct drm_mode_set *set) ...@@ -471,9 +471,9 @@ int drm_mode_set_config_internal(struct drm_mode_set *set)
drm_for_each_crtc(tmp, crtc->dev) { drm_for_each_crtc(tmp, crtc->dev) {
if (tmp->primary->fb) if (tmp->primary->fb)
drm_framebuffer_reference(tmp->primary->fb); drm_framebuffer_get(tmp->primary->fb);
if (tmp->primary->old_fb) if (tmp->primary->old_fb)
drm_framebuffer_unreference(tmp->primary->old_fb); drm_framebuffer_put(tmp->primary->old_fb);
tmp->primary->old_fb = NULL; tmp->primary->old_fb = NULL;
} }
...@@ -567,7 +567,7 @@ int drm_mode_setcrtc(struct drm_device *dev, void *data, ...@@ -567,7 +567,7 @@ int drm_mode_setcrtc(struct drm_device *dev, void *data,
} }
fb = crtc->primary->fb; fb = crtc->primary->fb;
/* Make refcounting symmetric with the lookup path. */ /* Make refcounting symmetric with the lookup path. */
drm_framebuffer_reference(fb); drm_framebuffer_get(fb);
} else { } else {
fb = drm_framebuffer_lookup(dev, crtc_req->fb_id); fb = drm_framebuffer_lookup(dev, crtc_req->fb_id);
if (!fb) { if (!fb) {
...@@ -680,12 +680,12 @@ int drm_mode_setcrtc(struct drm_device *dev, void *data, ...@@ -680,12 +680,12 @@ int drm_mode_setcrtc(struct drm_device *dev, void *data,
out: out:
if (fb) if (fb)
drm_framebuffer_unreference(fb); drm_framebuffer_put(fb);
if (connector_set) { if (connector_set) {
for (i = 0; i < crtc_req->count_connectors; i++) { for (i = 0; i < crtc_req->count_connectors; i++) {
if (connector_set[i]) if (connector_set[i])
drm_connector_unreference(connector_set[i]); drm_connector_put(connector_set[i]);
} }
} }
kfree(connector_set); kfree(connector_set);
......
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
...@@ -386,6 +386,8 @@ const char *drm_dp_get_dual_mode_type_name(enum drm_dp_dual_mode_type type) ...@@ -386,6 +386,8 @@ const char *drm_dp_get_dual_mode_type_name(enum drm_dp_dual_mode_type type)
return "type 2 DVI"; return "type 2 DVI";
case DRM_DP_DUAL_MODE_TYPE2_HDMI: case DRM_DP_DUAL_MODE_TYPE2_HDMI:
return "type 2 HDMI"; return "type 2 HDMI";
case DRM_DP_DUAL_MODE_LSPCON:
return "lspcon";
default: default:
WARN_ON(type != DRM_DP_DUAL_MODE_UNKNOWN); WARN_ON(type != DRM_DP_DUAL_MODE_UNKNOWN);
return "unknown"; return "unknown";
......
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment