提交 e98c58e5 编写于 作者: D Dave Airlie

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

UAPI Changes:
- Return -ENODEV instead of -ENXIO when creating cma fb w/o valid gem (Daniel)
- Add aspect ratio and custom scaling propertis to connector state (Maarten)

Cross-subsystem Changes:
- None

Core Changes:
- Add Laurent as bridge reviewer and Andrzej as bridge maintainer (Archit)
- Maintain new STM driver through -misc (Yannick)
- Misc doc improvements (as is tradition) (Daniel)
- Add driver-private objects to atomic state (Dhinakaran)
- Deprecate preclose hook in modern drivers (use postclose) (Daniel)
- Add hwmode to vblank struct. This fixes mode access in irq context and reduced
  a bunch of boilerplate (Daniel)

Driver Changes:
- vc4: Add out-fence support to vc4 V3D rendering (Eric)
- stm: Add stm32f429 display hw and am-480272h3tmqw-t01h panel support (Yannick)
- vc4: Remove 256MB cma limit from vc4 (Eric)
- dw-hdmi: Disable audio when inactive, instead of always enabled (Romain)
- zte: Add support for VGA to the ZTE driver (Shawn)
- i915: Track DP MST bandwidth and check it in atomic_check (Dhinakaran)
- vgem: Enable gem dmabuf import iface to facilitate ion testing (Laura)
- vc4: Add support for Cygnus (new dt compat string + couple bug fixes) (Eric)
- pl111: Add driver for pl111 CLCD display controller (Eric/Tom)
- vgem: Subclass drm_device instead of standalone platform device (Chris)

Cc: Archit Taneja <architt@codeaurora.org>
Cc: Eric Anholt <eric@anholt.net>
Cc: Yannick Fertre <yannick.fertre@st.com>
Cc: Romain Perier <romain.perier@collabora.com>
Cc: Navare, Manasi D <manasi.d.navare@intel.com>
Cc: Shawn Guo <shawn.guo@linaro.org>
Cc: Dhinakaran Pandiyan <dhinakaran.pandiyan@intel.com>
Cc: Laura Abbott <labbott@redhat.com>
Cc: Maarten Lankhorst <maarten.lankhorst@linux.intel.com>
Cc: Tom Cooksey <tom.cooksey@arm.com>
Cc: Daniel Vetter <daniel.vetter@intel.com>
Cc: Chris Wilson <chris@chris-wilson.co.uk>

* tag 'drm-misc-next-2017-05-16' of git://anongit.freedesktop.org/git/drm-misc: (72 commits)
  drm: add missing declaration to drm_blend.h
  drm/dp: Wait up all outstanding tx waiters
  drm/dp: Read the tx msg state once after checking for an event
  drm/prime: Forward declare struct device
  drm/vblank: Lock down vblank->hwmode more
  drm/vblank: drop the mode argument from drm_calc_vbltimestamp_from_scanoutpos
  drm/vblank: Add FIXME comments about moving the vblank ts hooks
  drm/vblank: Switch to bool in_vblank_irq in get_vblank_timestamp
  drm/vblank: Switch drm_driver->get_vblank_timestamp to return a bool
  drm/vgem: Convert to a struct drm_device subclass
  gpu: drm: gma500: remove dead code
  drm/sti: Adjust two checks for null pointers in sti_hqvdp_probe()
  drm/sti: Fix typos in a comment line
  drm/sti: Fix a typo in a comment line
  drm/sti: Replace 17 seq_puts() calls by seq_putc()
  drm/sti: Reduce function calls for sequence output at five places
  drm/sti: use seq_puts to display a string
  drm: Nerf the preclose callback for modern drivers
  drm/exynos: Merge pre/postclose hooks
  drm/tegra: switch to postclose
  ...
...@@ -5,7 +5,7 @@ with HDMI output and the HVS (Hardware Video Scaler) for compositing ...@@ -5,7 +5,7 @@ with HDMI output and the HVS (Hardware Video Scaler) for compositing
display planes. display planes.
Required properties for VC4: Required properties for VC4:
- compatible: Should be "brcm,bcm2835-vc4" - compatible: Should be "brcm,bcm2835-vc4" or "brcm,cygnus-vc4"
Required properties for Pixel Valve: Required properties for Pixel Valve:
- compatible: Should be one of "brcm,bcm2835-pixelvalve0", - compatible: Should be one of "brcm,bcm2835-pixelvalve0",
...@@ -54,11 +54,14 @@ Required properties for VEC: ...@@ -54,11 +54,14 @@ Required properties for VEC:
See bindings/interrupt-controller/brcm,bcm2835-armctrl-ic.txt See bindings/interrupt-controller/brcm,bcm2835-armctrl-ic.txt
Required properties for V3D: Required properties for V3D:
- compatible: Should be "brcm,bcm2835-v3d" - compatible: Should be "brcm,bcm2835-v3d" or "brcm,cygnus-v3d"
- reg: Physical base address and length of the V3D's registers - reg: Physical base address and length of the V3D's registers
- interrupts: The interrupt number - interrupts: The interrupt number
See bindings/interrupt-controller/brcm,bcm2835-armctrl-ic.txt See bindings/interrupt-controller/brcm,bcm2835-armctrl-ic.txt
Optional properties for V3D:
- clocks: The clock the unit runs on
Required properties for DSI: Required properties for DSI:
- compatible: Should be "brcm,bcm2835-dsi0" or "brcm,bcm2835-dsi1" - compatible: Should be "brcm,bcm2835-dsi0" or "brcm,bcm2835-dsi1"
- reg: Physical base address and length of the DSI block's registers - reg: Physical base address and length of the DSI block's registers
......
* STMicroelectronics STM32 lcd-tft display controller
- ltdc: lcd-tft display controller host
must be a sub-node of st-display-subsystem
Required properties:
- compatible: "st,stm32-ltdc"
- reg: Physical base address of the IP registers and length of memory mapped region.
- clocks: A list of phandle + clock-specifier pairs, one for each
entry in 'clock-names'.
- clock-names: A list of clock names. For ltdc it should contain:
- "lcd" for the clock feeding the output pixel clock & IP clock.
- resets: reset to be used by the device (defined by use of RCC macro).
Required nodes:
- Video port for RGB output.
Example:
/ {
...
soc {
...
ltdc: display-controller@40016800 {
compatible = "st,stm32-ltdc";
reg = <0x40016800 0x200>;
interrupts = <88>, <89>;
resets = <&rcc STM32F4_APB2_RESET(LTDC)>;
clocks = <&rcc 1 CLK_LCD>;
clock-names = "lcd";
port {
ltdc_out_rgb: endpoint {
};
};
};
};
};
...@@ -58,6 +58,18 @@ Required properties: ...@@ -58,6 +58,18 @@ Required properties:
integer cells. The first cell is the offset of SYSCTRL register used integer cells. The first cell is the offset of SYSCTRL register used
to control TV Encoder DAC power, and the second cell is the bit mask. to control TV Encoder DAC power, and the second cell is the bit mask.
* VGA output device
Required properties:
- compatible: should be "zte,zx296718-vga"
- reg: Physical base address and length of the VGA device IO region
- interrupts : VGA interrupt number to CPU
- clocks: Phandle with clock-specifier pointing to VGA I2C clock.
- clock-names: Must be "i2c_wclk".
- zte,vga-power-control: the phandle to SYSCTRL block followed by two
integer cells. The first cell is the offset of SYSCTRL register used
to control VGA DAC power, and the second cell is the bit mask.
Example: Example:
vou: vou@1440000 { vou: vou@1440000 {
...@@ -81,6 +93,15 @@ vou: vou@1440000 { ...@@ -81,6 +93,15 @@ vou: vou@1440000 {
"main_wclk", "aux_wclk"; "main_wclk", "aux_wclk";
}; };
vga: vga@8000 {
compatible = "zte,zx296718-vga";
reg = <0x8000 0x1000>;
interrupts = <GIC_SPI 86 IRQ_TYPE_LEVEL_HIGH>;
clocks = <&topcrm VGA_I2C_WCLK>;
clock-names = "i2c_wclk";
zte,vga-power-control = <&sysctrl 0x170 0xe0>;
};
hdmi: hdmi@c000 { hdmi: hdmi@c000 {
compatible = "zte,zx296718-hdmi"; compatible = "zte,zx296718-hdmi";
reg = <0xc000 0x4000>; reg = <0xc000 0x4000>;
......
...@@ -12,6 +12,7 @@ Linux GPU Driver Developer's Guide ...@@ -12,6 +12,7 @@ Linux GPU Driver Developer's Guide
drm-uapi drm-uapi
i915 i915
meson meson
pl111
tinydrm tinydrm
vc4 vc4
vga-switcheroo vga-switcheroo
......
==========================================
drm/pl111 ARM PrimeCell PL111 CLCD Driver
==========================================
.. kernel-doc:: drivers/gpu/drm/pl111/pl111_drv.c
:doc: ARM PrimeCell PL111 CLCD Driver
...@@ -4228,6 +4228,12 @@ F: include/drm/drm* ...@@ -4228,6 +4228,12 @@ F: include/drm/drm*
F: include/uapi/drm/drm* F: include/uapi/drm/drm*
F: include/linux/vga* F: include/linux/vga*
DRM DRIVER FOR ARM PL111 CLCD
M: Eric Anholt <eric@anholt.net>
T: git git://anongit.freedesktop.org/drm/drm-misc
S: Supported
F: drivers/gpu/drm/pl111/
DRM DRIVER FOR AST SERVER GRAPHICS CHIPS DRM DRIVER FOR AST SERVER GRAPHICS CHIPS
M: Dave Airlie <airlied@redhat.com> M: Dave Airlie <airlied@redhat.com>
S: Odd Fixes S: Odd Fixes
...@@ -4235,6 +4241,8 @@ F: drivers/gpu/drm/ast/ ...@@ -4235,6 +4241,8 @@ F: drivers/gpu/drm/ast/
DRM DRIVERS FOR BRIDGE CHIPS DRM DRIVERS FOR BRIDGE CHIPS
M: Archit Taneja <architt@codeaurora.org> M: Archit Taneja <architt@codeaurora.org>
M: Andrzej Hajda <a.hajda@samsung.com>
R: Laurent Pinchart <Laurent.pinchart@ideasonboard.com>
S: Maintained S: Maintained
T: git git://anongit.freedesktop.org/drm/drm-misc T: git git://anongit.freedesktop.org/drm/drm-misc
F: drivers/gpu/drm/bridge/ F: drivers/gpu/drm/bridge/
...@@ -4491,6 +4499,15 @@ S: Maintained ...@@ -4491,6 +4499,15 @@ S: Maintained
F: drivers/gpu/drm/sti F: drivers/gpu/drm/sti
F: Documentation/devicetree/bindings/display/st,stih4xx.txt F: Documentation/devicetree/bindings/display/st,stih4xx.txt
DRM DRIVERS FOR STM
M: Yannick Fertre <yannick.fertre@st.com>
M: Philippe Cornu <philippe.cornu@st.com>
L: dri-devel@lists.freedesktop.org
T: git git://anongit.freedesktop.org/drm/drm-misc
S: Maintained
F: drivers/gpu/drm/stm
F: Documentation/devicetree/bindings/display/st,stm32-ltdc.txt
DRM DRIVER FOR TDFX VIDEO CARDS DRM DRIVER FOR TDFX VIDEO CARDS
S: Orphan / Obsolete S: Orphan / Obsolete
F: drivers/gpu/drm/tdfx/ F: drivers/gpu/drm/tdfx/
......
...@@ -558,8 +558,8 @@ struct dma_buf_attachment *dma_buf_attach(struct dma_buf *dmabuf, ...@@ -558,8 +558,8 @@ struct dma_buf_attachment *dma_buf_attach(struct dma_buf *dmabuf,
if (WARN_ON(!dmabuf || !dev)) if (WARN_ON(!dmabuf || !dev))
return ERR_PTR(-EINVAL); return ERR_PTR(-EINVAL);
attach = kzalloc(sizeof(struct dma_buf_attachment), GFP_KERNEL); attach = kzalloc(sizeof(*attach), GFP_KERNEL);
if (attach == NULL) if (!attach)
return ERR_PTR(-ENOMEM); return ERR_PTR(-ENOMEM);
attach->dev = dev; attach->dev = dev;
...@@ -1122,9 +1122,7 @@ static int dma_buf_debug_show(struct seq_file *s, void *unused) ...@@ -1122,9 +1122,7 @@ static int dma_buf_debug_show(struct seq_file *s, void *unused)
attach_count = 0; attach_count = 0;
list_for_each_entry(attach_obj, &buf_obj->attachments, node) { list_for_each_entry(attach_obj, &buf_obj->attachments, node) {
seq_puts(s, "\t"); seq_printf(s, "\t%s\n", dev_name(attach_obj->dev));
seq_printf(s, "%s\n", dev_name(attach_obj->dev));
attach_count++; attach_count++;
} }
......
...@@ -402,6 +402,11 @@ dma_fence_default_wait(struct dma_fence *fence, bool intr, signed long timeout) ...@@ -402,6 +402,11 @@ dma_fence_default_wait(struct dma_fence *fence, bool intr, signed long timeout)
} }
} }
if (!timeout) {
ret = 0;
goto out;
}
cb.base.func = dma_fence_default_wait_cb; cb.base.func = dma_fence_default_wait_cb;
cb.task = current; cb.task = current;
list_add(&cb.base.node, &fence->cb_list); list_add(&cb.base.node, &fence->cb_list);
......
...@@ -110,7 +110,7 @@ static void sync_print_fence(struct seq_file *s, ...@@ -110,7 +110,7 @@ static void sync_print_fence(struct seq_file *s,
} }
} }
seq_puts(s, "\n"); seq_putc(s, '\n');
} }
static void sync_print_obj(struct seq_file *s, struct sync_timeline *obj) static void sync_print_obj(struct seq_file *s, struct sync_timeline *obj)
...@@ -161,7 +161,7 @@ static int sync_debugfs_show(struct seq_file *s, void *unused) ...@@ -161,7 +161,7 @@ static int sync_debugfs_show(struct seq_file *s, void *unused)
sync_timeline_list); sync_timeline_list);
sync_print_obj(s, obj); sync_print_obj(s, obj);
seq_puts(s, "\n"); seq_putc(s, '\n');
} }
spin_unlock_irqrestore(&sync_timeline_list_lock, flags); spin_unlock_irqrestore(&sync_timeline_list_lock, flags);
...@@ -173,7 +173,7 @@ static int sync_debugfs_show(struct seq_file *s, void *unused) ...@@ -173,7 +173,7 @@ static int sync_debugfs_show(struct seq_file *s, void *unused)
container_of(pos, struct sync_file, sync_file_list); container_of(pos, struct sync_file, sync_file_list);
sync_print_sync_file(s, sync_file); sync_print_sync_file(s, sync_file);
seq_puts(s, "\n"); seq_putc(s, '\n');
} }
spin_unlock_irqrestore(&sync_file_list_lock, flags); spin_unlock_irqrestore(&sync_file_list_lock, flags);
return 0; return 0;
......
...@@ -41,8 +41,6 @@ static struct sync_file *sync_file_alloc(void) ...@@ -41,8 +41,6 @@ static struct sync_file *sync_file_alloc(void)
if (IS_ERR(sync_file->file)) if (IS_ERR(sync_file->file))
goto err; goto err;
kref_init(&sync_file->kref);
init_waitqueue_head(&sync_file->wq); init_waitqueue_head(&sync_file->wq);
INIT_LIST_HEAD(&sync_file->cb.node); INIT_LIST_HEAD(&sync_file->cb.node);
...@@ -277,22 +275,15 @@ static struct sync_file *sync_file_merge(const char *name, struct sync_file *a, ...@@ -277,22 +275,15 @@ static struct sync_file *sync_file_merge(const char *name, struct sync_file *a,
} }
static void sync_file_free(struct kref *kref) static int sync_file_release(struct inode *inode, struct file *file)
{ {
struct sync_file *sync_file = container_of(kref, struct sync_file, struct sync_file *sync_file = file->private_data;
kref);
if (test_bit(POLL_ENABLED, &sync_file->fence->flags)) if (test_bit(POLL_ENABLED, &sync_file->fence->flags))
dma_fence_remove_callback(sync_file->fence, &sync_file->cb); dma_fence_remove_callback(sync_file->fence, &sync_file->cb);
dma_fence_put(sync_file->fence); dma_fence_put(sync_file->fence);
kfree(sync_file); kfree(sync_file);
}
static int sync_file_release(struct inode *inode, struct file *file)
{
struct sync_file *sync_file = file->private_data;
kref_put(&sync_file->kref, sync_file_free);
return 0; return 0;
} }
......
...@@ -246,6 +246,8 @@ source "drivers/gpu/drm/fsl-dcu/Kconfig" ...@@ -246,6 +246,8 @@ source "drivers/gpu/drm/fsl-dcu/Kconfig"
source "drivers/gpu/drm/tegra/Kconfig" source "drivers/gpu/drm/tegra/Kconfig"
source "drivers/gpu/drm/stm/Kconfig"
source "drivers/gpu/drm/panel/Kconfig" source "drivers/gpu/drm/panel/Kconfig"
source "drivers/gpu/drm/bridge/Kconfig" source "drivers/gpu/drm/bridge/Kconfig"
...@@ -274,6 +276,8 @@ source "drivers/gpu/drm/meson/Kconfig" ...@@ -274,6 +276,8 @@ source "drivers/gpu/drm/meson/Kconfig"
source "drivers/gpu/drm/tinydrm/Kconfig" source "drivers/gpu/drm/tinydrm/Kconfig"
source "drivers/gpu/drm/pl111/Kconfig"
# Keep legacy drivers last # Keep legacy drivers last
menuconfig DRM_LEGACY menuconfig DRM_LEGACY
......
...@@ -82,6 +82,7 @@ obj-$(CONFIG_DRM_BOCHS) += bochs/ ...@@ -82,6 +82,7 @@ obj-$(CONFIG_DRM_BOCHS) += bochs/
obj-$(CONFIG_DRM_VIRTIO_GPU) += virtio/ obj-$(CONFIG_DRM_VIRTIO_GPU) += virtio/
obj-$(CONFIG_DRM_MSM) += msm/ obj-$(CONFIG_DRM_MSM) += msm/
obj-$(CONFIG_DRM_TEGRA) += tegra/ obj-$(CONFIG_DRM_TEGRA) += tegra/
obj-$(CONFIG_DRM_STM) += stm/
obj-$(CONFIG_DRM_STI) += sti/ obj-$(CONFIG_DRM_STI) += sti/
obj-$(CONFIG_DRM_IMX) += imx/ obj-$(CONFIG_DRM_IMX) += imx/
obj-$(CONFIG_DRM_MEDIATEK) += mediatek/ obj-$(CONFIG_DRM_MEDIATEK) += mediatek/
...@@ -96,3 +97,4 @@ obj-y += hisilicon/ ...@@ -96,3 +97,4 @@ obj-y += hisilicon/
obj-$(CONFIG_DRM_ZTE) += zte/ obj-$(CONFIG_DRM_ZTE) += zte/
obj-$(CONFIG_DRM_MXSFB) += mxsfb/ obj-$(CONFIG_DRM_MXSFB) += mxsfb/
obj-$(CONFIG_DRM_TINYDRM) += tinydrm/ obj-$(CONFIG_DRM_TINYDRM) += tinydrm/
obj-$(CONFIG_DRM_PL111) += pl111/
...@@ -1912,10 +1912,6 @@ int amdgpu_device_resume(struct drm_device *dev, bool resume, bool fbcon); ...@@ -1912,10 +1912,6 @@ int amdgpu_device_resume(struct drm_device *dev, bool resume, bool fbcon);
u32 amdgpu_get_vblank_counter_kms(struct drm_device *dev, unsigned int pipe); u32 amdgpu_get_vblank_counter_kms(struct drm_device *dev, unsigned int pipe);
int amdgpu_enable_vblank_kms(struct drm_device *dev, unsigned int pipe); int amdgpu_enable_vblank_kms(struct drm_device *dev, unsigned int pipe);
void amdgpu_disable_vblank_kms(struct drm_device *dev, unsigned int pipe); void amdgpu_disable_vblank_kms(struct drm_device *dev, unsigned int pipe);
int amdgpu_get_vblank_timestamp_kms(struct drm_device *dev, unsigned int pipe,
int *max_error,
struct timeval *vblank_time,
unsigned flags);
long amdgpu_kms_compat_ioctl(struct file *filp, unsigned int cmd, long amdgpu_kms_compat_ioctl(struct file *filp, unsigned int cmd,
unsigned long arg); unsigned long arg);
......
...@@ -715,6 +715,16 @@ static const struct file_operations amdgpu_driver_kms_fops = { ...@@ -715,6 +715,16 @@ static const struct file_operations amdgpu_driver_kms_fops = {
#endif #endif
}; };
static bool
amdgpu_get_crtc_scanout_position(struct drm_device *dev, unsigned int pipe,
bool in_vblank_irq, int *vpos, int *hpos,
ktime_t *stime, ktime_t *etime,
const struct drm_display_mode *mode)
{
return amdgpu_get_crtc_scanoutpos(dev, pipe, 0, vpos, hpos,
stime, etime, mode);
}
static struct drm_driver kms_driver = { static struct drm_driver kms_driver = {
.driver_features = .driver_features =
DRIVER_USE_AGP | DRIVER_USE_AGP |
...@@ -729,8 +739,8 @@ static struct drm_driver kms_driver = { ...@@ -729,8 +739,8 @@ static struct drm_driver kms_driver = {
.get_vblank_counter = amdgpu_get_vblank_counter_kms, .get_vblank_counter = amdgpu_get_vblank_counter_kms,
.enable_vblank = amdgpu_enable_vblank_kms, .enable_vblank = amdgpu_enable_vblank_kms,
.disable_vblank = amdgpu_disable_vblank_kms, .disable_vblank = amdgpu_disable_vblank_kms,
.get_vblank_timestamp = amdgpu_get_vblank_timestamp_kms, .get_vblank_timestamp = drm_calc_vbltimestamp_from_scanoutpos,
.get_scanout_position = amdgpu_get_crtc_scanoutpos, .get_scanout_position = amdgpu_get_crtc_scanout_position,
#if defined(CONFIG_DEBUG_FS) #if defined(CONFIG_DEBUG_FS)
.debugfs_init = amdgpu_debugfs_init, .debugfs_init = amdgpu_debugfs_init,
#endif #endif
......
...@@ -945,47 +945,6 @@ void amdgpu_disable_vblank_kms(struct drm_device *dev, unsigned int pipe) ...@@ -945,47 +945,6 @@ void amdgpu_disable_vblank_kms(struct drm_device *dev, unsigned int pipe)
amdgpu_irq_put(adev, &adev->crtc_irq, idx); amdgpu_irq_put(adev, &adev->crtc_irq, idx);
} }
/**
* amdgpu_get_vblank_timestamp_kms - get vblank timestamp
*
* @dev: drm dev pointer
* @crtc: crtc to get the timestamp for
* @max_error: max error
* @vblank_time: time value
* @flags: flags passed to the driver
*
* Gets the timestamp on the requested crtc based on the
* scanout position. (all asics).
* Returns postive status flags on success, negative error on failure.
*/
int amdgpu_get_vblank_timestamp_kms(struct drm_device *dev, unsigned int pipe,
int *max_error,
struct timeval *vblank_time,
unsigned flags)
{
struct drm_crtc *crtc;
struct amdgpu_device *adev = dev->dev_private;
if (pipe >= dev->num_crtcs) {
DRM_ERROR("Invalid crtc %u\n", pipe);
return -EINVAL;
}
/* Get associated drm_crtc: */
crtc = &adev->mode_info.crtcs[pipe]->base;
if (!crtc) {
/* This can occur on driver load if some component fails to
* initialize completely and driver is unloaded */
DRM_ERROR("Uninitialized crtc %d\n", pipe);
return -EINVAL;
}
/* Helper routine in DRM core does all the work: */
return drm_calc_vbltimestamp_from_scanoutpos(dev, pipe, max_error,
vblank_time, flags,
&crtc->hwmode);
}
const struct drm_ioctl_desc amdgpu_ioctls_kms[] = { const struct drm_ioctl_desc amdgpu_ioctls_kms[] = {
DRM_IOCTL_DEF_DRV(AMDGPU_GEM_CREATE, amdgpu_gem_create_ioctl, DRM_AUTH|DRM_RENDER_ALLOW), DRM_IOCTL_DEF_DRV(AMDGPU_GEM_CREATE, amdgpu_gem_create_ioctl, DRM_AUTH|DRM_RENDER_ALLOW),
DRM_IOCTL_DEF_DRV(AMDGPU_CTX, amdgpu_ctx_ioctl, DRM_AUTH|DRM_RENDER_ALLOW), DRM_IOCTL_DEF_DRV(AMDGPU_CTX, amdgpu_ctx_ioctl, DRM_AUTH|DRM_RENDER_ALLOW),
......
...@@ -534,6 +534,9 @@ struct amdgpu_framebuffer { ...@@ -534,6 +534,9 @@ struct amdgpu_framebuffer {
((em) == ATOM_ENCODER_MODE_DP_MST)) ((em) == ATOM_ENCODER_MODE_DP_MST))
/* Driver internal use only flags of amdgpu_get_crtc_scanoutpos() */ /* Driver internal use only flags of amdgpu_get_crtc_scanoutpos() */
#define DRM_SCANOUTPOS_VALID (1 << 0)
#define DRM_SCANOUTPOS_IN_VBLANK (1 << 1)
#define DRM_SCANOUTPOS_ACCURATE (1 << 2)
#define USE_REAL_VBLANKSTART (1 << 30) #define USE_REAL_VBLANKSTART (1 << 30)
#define GET_DISTANCE_TO_VBLANKSTART (1 << 31) #define GET_DISTANCE_TO_VBLANKSTART (1 << 31)
......
...@@ -160,7 +160,7 @@ static int sii902x_get_modes(struct drm_connector *connector) ...@@ -160,7 +160,7 @@ static int sii902x_get_modes(struct drm_connector *connector)
time_before(jiffies, timeout)); time_before(jiffies, timeout));
if (!(status & SII902X_SYS_CTRL_DDC_BUS_GRTD)) { if (!(status & SII902X_SYS_CTRL_DDC_BUS_GRTD)) {
dev_err(&sii902x->i2c->dev, "failed to acquire the i2c bus"); dev_err(&sii902x->i2c->dev, "failed to acquire the i2c bus\n");
return -ETIMEDOUT; return -ETIMEDOUT;
} }
...@@ -202,7 +202,7 @@ static int sii902x_get_modes(struct drm_connector *connector) ...@@ -202,7 +202,7 @@ static int sii902x_get_modes(struct drm_connector *connector)
if (status & (SII902X_SYS_CTRL_DDC_BUS_REQ | if (status & (SII902X_SYS_CTRL_DDC_BUS_REQ |
SII902X_SYS_CTRL_DDC_BUS_GRTD)) { SII902X_SYS_CTRL_DDC_BUS_GRTD)) {
dev_err(&sii902x->i2c->dev, "failed to release the i2c bus"); dev_err(&sii902x->i2c->dev, "failed to release the i2c bus\n");
return -ETIMEDOUT; return -ETIMEDOUT;
} }
...@@ -298,7 +298,7 @@ static int sii902x_bridge_attach(struct drm_bridge *bridge) ...@@ -298,7 +298,7 @@ static int sii902x_bridge_attach(struct drm_bridge *bridge)
if (!drm_core_check_feature(drm, DRIVER_ATOMIC)) { if (!drm_core_check_feature(drm, DRIVER_ATOMIC)) {
dev_err(&sii902x->i2c->dev, dev_err(&sii902x->i2c->dev,
"sii902x driver is only compatible with DRM devices supporting atomic updates"); "sii902x driver is only compatible with DRM devices supporting atomic updates\n");
return -ENOTSUPP; return -ENOTSUPP;
} }
......
...@@ -173,6 +173,8 @@ struct dw_hdmi { ...@@ -173,6 +173,8 @@ struct dw_hdmi {
unsigned int reg_shift; unsigned int reg_shift;
struct regmap *regm; struct regmap *regm;
void (*enable_audio)(struct dw_hdmi *hdmi);
void (*disable_audio)(struct dw_hdmi *hdmi);
}; };
#define HDMI_IH_PHY_STAT0_RX_SENSE \ #define HDMI_IH_PHY_STAT0_RX_SENSE \
...@@ -542,13 +544,41 @@ void dw_hdmi_set_sample_rate(struct dw_hdmi *hdmi, unsigned int rate) ...@@ -542,13 +544,41 @@ void dw_hdmi_set_sample_rate(struct dw_hdmi *hdmi, unsigned int rate)
} }
EXPORT_SYMBOL_GPL(dw_hdmi_set_sample_rate); EXPORT_SYMBOL_GPL(dw_hdmi_set_sample_rate);
static void hdmi_enable_audio_clk(struct dw_hdmi *hdmi, bool enable)
{
hdmi_modb(hdmi, enable ? 0 : HDMI_MC_CLKDIS_AUDCLK_DISABLE,
HDMI_MC_CLKDIS_AUDCLK_DISABLE, HDMI_MC_CLKDIS);
}
static void dw_hdmi_ahb_audio_enable(struct dw_hdmi *hdmi)
{
hdmi_set_cts_n(hdmi, hdmi->audio_cts, hdmi->audio_n);
}
static void dw_hdmi_ahb_audio_disable(struct dw_hdmi *hdmi)
{
hdmi_set_cts_n(hdmi, hdmi->audio_cts, 0);
}
static void dw_hdmi_i2s_audio_enable(struct dw_hdmi *hdmi)
{
hdmi_set_cts_n(hdmi, hdmi->audio_cts, hdmi->audio_n);
hdmi_enable_audio_clk(hdmi, true);
}
static void dw_hdmi_i2s_audio_disable(struct dw_hdmi *hdmi)
{
hdmi_enable_audio_clk(hdmi, false);
}
void dw_hdmi_audio_enable(struct dw_hdmi *hdmi) void dw_hdmi_audio_enable(struct dw_hdmi *hdmi)
{ {
unsigned long flags; unsigned long flags;
spin_lock_irqsave(&hdmi->audio_lock, flags); spin_lock_irqsave(&hdmi->audio_lock, flags);
hdmi->audio_enable = true; hdmi->audio_enable = true;
hdmi_set_cts_n(hdmi, hdmi->audio_cts, hdmi->audio_n); if (hdmi->enable_audio)
hdmi->enable_audio(hdmi);
spin_unlock_irqrestore(&hdmi->audio_lock, flags); spin_unlock_irqrestore(&hdmi->audio_lock, flags);
} }
EXPORT_SYMBOL_GPL(dw_hdmi_audio_enable); EXPORT_SYMBOL_GPL(dw_hdmi_audio_enable);
...@@ -559,7 +589,8 @@ void dw_hdmi_audio_disable(struct dw_hdmi *hdmi) ...@@ -559,7 +589,8 @@ void dw_hdmi_audio_disable(struct dw_hdmi *hdmi)
spin_lock_irqsave(&hdmi->audio_lock, flags); spin_lock_irqsave(&hdmi->audio_lock, flags);
hdmi->audio_enable = false; hdmi->audio_enable = false;
hdmi_set_cts_n(hdmi, hdmi->audio_cts, 0); if (hdmi->disable_audio)
hdmi->disable_audio(hdmi);
spin_unlock_irqrestore(&hdmi->audio_lock, flags); spin_unlock_irqrestore(&hdmi->audio_lock, flags);
} }
EXPORT_SYMBOL_GPL(dw_hdmi_audio_disable); EXPORT_SYMBOL_GPL(dw_hdmi_audio_disable);
...@@ -1573,11 +1604,6 @@ static void dw_hdmi_enable_video_path(struct dw_hdmi *hdmi) ...@@ -1573,11 +1604,6 @@ static void dw_hdmi_enable_video_path(struct dw_hdmi *hdmi)
HDMI_MC_FLOWCTRL); HDMI_MC_FLOWCTRL);
} }
static void hdmi_enable_audio_clk(struct dw_hdmi *hdmi)
{
hdmi_modb(hdmi, 0, HDMI_MC_CLKDIS_AUDCLK_DISABLE, HDMI_MC_CLKDIS);
}
/* Workaround to clear the overflow condition */ /* Workaround to clear the overflow condition */
static void dw_hdmi_clear_overflow(struct dw_hdmi *hdmi) static void dw_hdmi_clear_overflow(struct dw_hdmi *hdmi)
{ {
...@@ -1691,7 +1717,7 @@ static int dw_hdmi_setup(struct dw_hdmi *hdmi, struct drm_display_mode *mode) ...@@ -1691,7 +1717,7 @@ static int dw_hdmi_setup(struct dw_hdmi *hdmi, struct drm_display_mode *mode)
/* HDMI Initialization Step E - Configure audio */ /* HDMI Initialization Step E - Configure audio */
hdmi_clk_regenerator_update_pixel_clock(hdmi); hdmi_clk_regenerator_update_pixel_clock(hdmi);
hdmi_enable_audio_clk(hdmi); hdmi_enable_audio_clk(hdmi, true);
} }
/* not for DVI mode */ /* not for DVI mode */
...@@ -2403,6 +2429,8 @@ __dw_hdmi_probe(struct platform_device *pdev, ...@@ -2403,6 +2429,8 @@ __dw_hdmi_probe(struct platform_device *pdev,
audio.irq = irq; audio.irq = irq;
audio.hdmi = hdmi; audio.hdmi = hdmi;
audio.eld = hdmi->connector.eld; audio.eld = hdmi->connector.eld;
hdmi->enable_audio = dw_hdmi_ahb_audio_enable;
hdmi->disable_audio = dw_hdmi_ahb_audio_disable;
pdevinfo.name = "dw-hdmi-ahb-audio"; pdevinfo.name = "dw-hdmi-ahb-audio";
pdevinfo.data = &audio; pdevinfo.data = &audio;
...@@ -2415,6 +2443,8 @@ __dw_hdmi_probe(struct platform_device *pdev, ...@@ -2415,6 +2443,8 @@ __dw_hdmi_probe(struct platform_device *pdev,
audio.hdmi = hdmi; audio.hdmi = hdmi;
audio.write = hdmi_writeb; audio.write = hdmi_writeb;
audio.read = hdmi_readb; audio.read = hdmi_readb;
hdmi->enable_audio = dw_hdmi_i2s_audio_enable;
hdmi->disable_audio = dw_hdmi_i2s_audio_disable;
pdevinfo.name = "dw-hdmi-i2s-audio"; pdevinfo.name = "dw-hdmi-i2s-audio";
pdevinfo.data = &audio; pdevinfo.data = &audio;
......
...@@ -57,6 +57,7 @@ void drm_atomic_state_default_release(struct drm_atomic_state *state) ...@@ -57,6 +57,7 @@ void drm_atomic_state_default_release(struct drm_atomic_state *state)
kfree(state->connectors); kfree(state->connectors);
kfree(state->crtcs); kfree(state->crtcs);
kfree(state->planes); kfree(state->planes);
kfree(state->private_objs);
} }
EXPORT_SYMBOL(drm_atomic_state_default_release); EXPORT_SYMBOL(drm_atomic_state_default_release);
...@@ -184,6 +185,17 @@ void drm_atomic_state_default_clear(struct drm_atomic_state *state) ...@@ -184,6 +185,17 @@ void drm_atomic_state_default_clear(struct drm_atomic_state *state)
state->planes[i].ptr = NULL; state->planes[i].ptr = NULL;
state->planes[i].state = NULL; state->planes[i].state = NULL;
} }
for (i = 0; i < state->num_private_objs; i++) {
void *obj_state = state->private_objs[i].obj_state;
state->private_objs[i].funcs->destroy_state(obj_state);
state->private_objs[i].obj = NULL;
state->private_objs[i].obj_state = NULL;
state->private_objs[i].funcs = NULL;
}
state->num_private_objs = 0;
} }
EXPORT_SYMBOL(drm_atomic_state_default_clear); EXPORT_SYMBOL(drm_atomic_state_default_clear);
...@@ -425,7 +437,7 @@ drm_atomic_replace_property_blob(struct drm_property_blob **blob, ...@@ -425,7 +437,7 @@ drm_atomic_replace_property_blob(struct drm_property_blob **blob,
} }
static int static int
drm_atomic_replace_property_blob_from_id(struct drm_crtc *crtc, drm_atomic_replace_property_blob_from_id(struct drm_device *dev,
struct drm_property_blob **blob, struct drm_property_blob **blob,
uint64_t blob_id, uint64_t blob_id,
ssize_t expected_size, ssize_t expected_size,
...@@ -434,7 +446,7 @@ drm_atomic_replace_property_blob_from_id(struct drm_crtc *crtc, ...@@ -434,7 +446,7 @@ drm_atomic_replace_property_blob_from_id(struct drm_crtc *crtc,
struct drm_property_blob *new_blob = NULL; struct drm_property_blob *new_blob = NULL;
if (blob_id != 0) { if (blob_id != 0) {
new_blob = drm_property_lookup_blob(crtc->dev, blob_id); new_blob = drm_property_lookup_blob(dev, blob_id);
if (new_blob == NULL) if (new_blob == NULL)
return -EINVAL; return -EINVAL;
...@@ -483,7 +495,7 @@ int drm_atomic_crtc_set_property(struct drm_crtc *crtc, ...@@ -483,7 +495,7 @@ int drm_atomic_crtc_set_property(struct drm_crtc *crtc,
drm_property_blob_put(mode); drm_property_blob_put(mode);
return ret; return ret;
} else if (property == config->degamma_lut_property) { } else if (property == config->degamma_lut_property) {
ret = drm_atomic_replace_property_blob_from_id(crtc, ret = drm_atomic_replace_property_blob_from_id(dev,
&state->degamma_lut, &state->degamma_lut,
val, val,
-1, -1,
...@@ -491,7 +503,7 @@ int drm_atomic_crtc_set_property(struct drm_crtc *crtc, ...@@ -491,7 +503,7 @@ int drm_atomic_crtc_set_property(struct drm_crtc *crtc,
state->color_mgmt_changed |= replaced; state->color_mgmt_changed |= replaced;
return ret; return ret;
} else if (property == config->ctm_property) { } else if (property == config->ctm_property) {
ret = drm_atomic_replace_property_blob_from_id(crtc, ret = drm_atomic_replace_property_blob_from_id(dev,
&state->ctm, &state->ctm,
val, val,
sizeof(struct drm_color_ctm), sizeof(struct drm_color_ctm),
...@@ -499,7 +511,7 @@ int drm_atomic_crtc_set_property(struct drm_crtc *crtc, ...@@ -499,7 +511,7 @@ int drm_atomic_crtc_set_property(struct drm_crtc *crtc,
state->color_mgmt_changed |= replaced; state->color_mgmt_changed |= replaced;
return ret; return ret;
} else if (property == config->gamma_lut_property) { } else if (property == config->gamma_lut_property) {
ret = drm_atomic_replace_property_blob_from_id(crtc, ret = drm_atomic_replace_property_blob_from_id(dev,
&state->gamma_lut, &state->gamma_lut,
val, val,
-1, -1,
...@@ -977,6 +989,59 @@ static void drm_atomic_plane_print_state(struct drm_printer *p, ...@@ -977,6 +989,59 @@ static void drm_atomic_plane_print_state(struct drm_printer *p,
plane->funcs->atomic_print_state(p, state); plane->funcs->atomic_print_state(p, state);
} }
/**
* drm_atomic_get_private_obj_state - get private object state
* @state: global atomic state
* @obj: private object to get the state for
* @funcs: pointer to the struct of function pointers that identify the object
* type
*
* This function returns the private object state for the given private object,
* allocating the state if needed. It does not grab any locks as the caller is
* expected to care of any required locking.
*
* RETURNS:
*
* Either the allocated state or the error code encoded into a pointer.
*/
void *
drm_atomic_get_private_obj_state(struct drm_atomic_state *state, void *obj,
const struct drm_private_state_funcs *funcs)
{
int index, num_objs, i;
size_t size;
struct __drm_private_objs_state *arr;
for (i = 0; i < state->num_private_objs; i++)
if (obj == state->private_objs[i].obj &&
state->private_objs[i].obj_state)
return state->private_objs[i].obj_state;
num_objs = state->num_private_objs + 1;
size = sizeof(*state->private_objs) * num_objs;
arr = krealloc(state->private_objs, size, GFP_KERNEL);
if (!arr)
return ERR_PTR(-ENOMEM);
state->private_objs = arr;
index = state->num_private_objs;
memset(&state->private_objs[index], 0, sizeof(*state->private_objs));
state->private_objs[index].obj_state = funcs->duplicate_state(state, obj);
if (!state->private_objs[index].obj_state)
return ERR_PTR(-ENOMEM);
state->private_objs[index].obj = obj;
state->private_objs[index].funcs = funcs;
state->num_private_objs = num_objs;
DRM_DEBUG_ATOMIC("Added new private object state %p to %p\n",
state->private_objs[index].obj_state, state);
return state->private_objs[index].obj_state;
}
EXPORT_SYMBOL(drm_atomic_get_private_obj_state);
/** /**
* drm_atomic_get_connector_state - get connector state * drm_atomic_get_connector_state - get connector state
* @state: global atomic state object * @state: global atomic state object
...@@ -1123,6 +1188,10 @@ int drm_atomic_connector_set_property(struct drm_connector *connector, ...@@ -1123,6 +1188,10 @@ int drm_atomic_connector_set_property(struct drm_connector *connector,
*/ */
if (state->link_status != DRM_LINK_STATUS_GOOD) if (state->link_status != DRM_LINK_STATUS_GOOD)
state->link_status = val; state->link_status = val;
} else if (property == config->aspect_ratio_property) {
state->picture_aspect_ratio = val;
} else if (property == connector->scaling_mode_property) {
state->scaling_mode = val;
} else if (connector->funcs->atomic_set_property) { } else if (connector->funcs->atomic_set_property) {
return connector->funcs->atomic_set_property(connector, return connector->funcs->atomic_set_property(connector,
state, property, val); state, property, val);
...@@ -1199,6 +1268,10 @@ drm_atomic_connector_get_property(struct drm_connector *connector, ...@@ -1199,6 +1268,10 @@ drm_atomic_connector_get_property(struct drm_connector *connector,
*val = state->tv.hue; *val = state->tv.hue;
} else if (property == config->link_status_property) { } else if (property == config->link_status_property) {
*val = state->link_status; *val = state->link_status;
} else if (property == config->aspect_ratio_property) {
*val = state->picture_aspect_ratio;
} else if (property == connector->scaling_mode_property) {
*val = state->scaling_mode;
} else if (connector->funcs->atomic_get_property) { } else if (connector->funcs->atomic_get_property) {
return connector->funcs->atomic_get_property(connector, return connector->funcs->atomic_get_property(connector,
state, property, val); state, property, val);
...@@ -1618,7 +1691,7 @@ int drm_atomic_commit(struct drm_atomic_state *state) ...@@ -1618,7 +1691,7 @@ int drm_atomic_commit(struct drm_atomic_state *state)
if (ret) if (ret)
return ret; return ret;
DRM_DEBUG_ATOMIC("commiting %p\n", state); DRM_DEBUG_ATOMIC("committing %p\n", state);
return config->funcs->atomic_commit(state->dev, state, false); return config->funcs->atomic_commit(state->dev, state, false);
} }
...@@ -1647,7 +1720,7 @@ int drm_atomic_nonblocking_commit(struct drm_atomic_state *state) ...@@ -1647,7 +1720,7 @@ int drm_atomic_nonblocking_commit(struct drm_atomic_state *state)
if (ret) if (ret)
return ret; return ret;
DRM_DEBUG_ATOMIC("commiting %p nonblocking\n", state); DRM_DEBUG_ATOMIC("committing %p nonblocking\n", state);
return config->funcs->atomic_commit(state->dev, state, true); return config->funcs->atomic_commit(state->dev, state, true);
} }
......
...@@ -1070,8 +1070,8 @@ EXPORT_SYMBOL(drm_atomic_helper_commit_modeset_enables); ...@@ -1070,8 +1070,8 @@ EXPORT_SYMBOL(drm_atomic_helper_commit_modeset_enables);
* *
* Note that @pre_swap is needed since the point where we block for fences moves * Note that @pre_swap is needed since the point where we block for fences moves
* around depending upon whether an atomic commit is blocking or * around depending upon whether an atomic commit is blocking or
* non-blocking. For async commit all waiting needs to happen after * non-blocking. For non-blocking commit all waiting needs to happen after
* drm_atomic_helper_swap_state() is called, but for synchronous commits we want * drm_atomic_helper_swap_state() is called, but for blocking commits we want
* to wait **before** we do anything that can't be easily rolled back. That is * to wait **before** we do anything that can't be easily rolled back. That is
* before we call drm_atomic_helper_swap_state(). * before we call drm_atomic_helper_swap_state().
* *
...@@ -2032,6 +2032,8 @@ void drm_atomic_helper_swap_state(struct drm_atomic_state *state, ...@@ -2032,6 +2032,8 @@ void drm_atomic_helper_swap_state(struct drm_atomic_state *state,
struct drm_plane *plane; struct drm_plane *plane;
struct drm_plane_state *old_plane_state, *new_plane_state; struct drm_plane_state *old_plane_state, *new_plane_state;
struct drm_crtc_commit *commit; struct drm_crtc_commit *commit;
void *obj, *obj_state;
const struct drm_private_state_funcs *funcs;
if (stall) { if (stall) {
for_each_new_crtc_in_state(state, crtc, new_crtc_state, i) { for_each_new_crtc_in_state(state, crtc, new_crtc_state, i) {
...@@ -2092,6 +2094,9 @@ void drm_atomic_helper_swap_state(struct drm_atomic_state *state, ...@@ -2092,6 +2094,9 @@ void drm_atomic_helper_swap_state(struct drm_atomic_state *state,
state->planes[i].state = old_plane_state; state->planes[i].state = old_plane_state;
plane->state = new_plane_state; plane->state = new_plane_state;
} }
__for_each_private_obj(state, obj, obj_state, i, funcs)
funcs->swap_state(obj, &state->private_objs[i].obj_state);
} }
EXPORT_SYMBOL(drm_atomic_helper_swap_state); EXPORT_SYMBOL(drm_atomic_helper_swap_state);
...@@ -3517,7 +3522,8 @@ EXPORT_SYMBOL(drm_atomic_helper_connector_destroy_state); ...@@ -3517,7 +3522,8 @@ EXPORT_SYMBOL(drm_atomic_helper_connector_destroy_state);
* *
* Implements support for legacy gamma correction table for drivers * Implements support for legacy gamma correction table for drivers
* that support color management through the DEGAMMA_LUT/GAMMA_LUT * that support color management through the DEGAMMA_LUT/GAMMA_LUT
* properties. * properties. See drm_crtc_enable_color_mgmt() and the containing chapter for
* how the atomic color management and gamma tables work.
*/ */
int drm_atomic_helper_legacy_gamma_set(struct drm_crtc *crtc, int drm_atomic_helper_legacy_gamma_set(struct drm_crtc *crtc,
u16 *red, u16 *green, u16 *blue, u16 *red, u16 *green, u16 *blue,
......
...@@ -43,7 +43,8 @@ ...@@ -43,7 +43,8 @@
* *
* Setting this to NULL (blob property value set to 0) means a * Setting this to NULL (blob property value set to 0) means a
* linear/pass-thru gamma table should be used. This is generally the * linear/pass-thru gamma table should be used. This is generally the
* driver boot-up state too. * driver boot-up state too. Drivers can access this blob through
* &drm_crtc_state.degamma_lut.
* *
* “DEGAMMA_LUT_SIZE”: * “DEGAMMA_LUT_SIZE”:
* Unsinged range property to give the size of the lookup table to be set * Unsinged range property to give the size of the lookup table to be set
...@@ -60,7 +61,8 @@ ...@@ -60,7 +61,8 @@
* *
* Setting this to NULL (blob property value set to 0) means a * Setting this to NULL (blob property value set to 0) means a
* unit/pass-thru matrix should be used. This is generally the driver * unit/pass-thru matrix should be used. This is generally the driver
* boot-up state too. * boot-up state too. Drivers can access the blob for the color conversion
* matrix through &drm_crtc_state.ctm.
* *
* “GAMMA_LUT”: * “GAMMA_LUT”:
* Blob property to set the gamma lookup table (LUT) mapping pixel data * Blob property to set the gamma lookup table (LUT) mapping pixel data
...@@ -72,7 +74,8 @@ ...@@ -72,7 +74,8 @@
* *
* Setting this to NULL (blob property value set to 0) means a * Setting this to NULL (blob property value set to 0) means a
* linear/pass-thru gamma table should be used. This is generally the * linear/pass-thru gamma table should be used. This is generally the
* driver boot-up state too. * driver boot-up state too. Drivers can access this blob through
* &drm_crtc_state.gamma_lut.
* *
* “GAMMA_LUT_SIZE”: * “GAMMA_LUT_SIZE”:
* Unsigned range property to give the size of the lookup table to be set * Unsigned range property to give the size of the lookup table to be set
......
...@@ -941,6 +941,10 @@ EXPORT_SYMBOL(drm_mode_create_tv_properties); ...@@ -941,6 +941,10 @@ EXPORT_SYMBOL(drm_mode_create_tv_properties);
* *
* Called by a driver the first time it's needed, must be attached to desired * Called by a driver the first time it's needed, must be attached to desired
* connectors. * connectors.
*
* Atomic drivers should use drm_connector_attach_scaling_mode_property()
* instead to correctly assign &drm_connector_state.picture_aspect_ratio
* in the atomic state.
*/ */
int drm_mode_create_scaling_mode_property(struct drm_device *dev) int drm_mode_create_scaling_mode_property(struct drm_device *dev)
{ {
...@@ -960,6 +964,66 @@ int drm_mode_create_scaling_mode_property(struct drm_device *dev) ...@@ -960,6 +964,66 @@ int drm_mode_create_scaling_mode_property(struct drm_device *dev)
} }
EXPORT_SYMBOL(drm_mode_create_scaling_mode_property); EXPORT_SYMBOL(drm_mode_create_scaling_mode_property);
/**
* drm_connector_attach_scaling_mode_property - attach atomic scaling mode property
* @connector: connector to attach scaling mode property on.
* @scaling_mode_mask: or'ed mask of BIT(%DRM_MODE_SCALE_\*).
*
* This is used to add support for scaling mode to atomic drivers.
* The scaling mode will be set to &drm_connector_state.picture_aspect_ratio
* and can be used from &drm_connector_helper_funcs->atomic_check for validation.
*
* This is the atomic version of drm_mode_create_scaling_mode_property().
*
* Returns:
* Zero on success, negative errno on failure.
*/
int drm_connector_attach_scaling_mode_property(struct drm_connector *connector,
u32 scaling_mode_mask)
{
struct drm_device *dev = connector->dev;
struct drm_property *scaling_mode_property;
int i, j = 0;
const unsigned valid_scaling_mode_mask =
(1U << ARRAY_SIZE(drm_scaling_mode_enum_list)) - 1;
if (WARN_ON(hweight32(scaling_mode_mask) < 2 ||
scaling_mode_mask & ~valid_scaling_mode_mask))
return -EINVAL;
scaling_mode_property =
drm_property_create(dev, DRM_MODE_PROP_ENUM, "scaling mode",
hweight32(scaling_mode_mask));
if (!scaling_mode_property)
return -ENOMEM;
for (i = 0; i < ARRAY_SIZE(drm_scaling_mode_enum_list); i++) {
int ret;
if (!(BIT(i) & scaling_mode_mask))
continue;
ret = drm_property_add_enum(scaling_mode_property, j++,
drm_scaling_mode_enum_list[i].type,
drm_scaling_mode_enum_list[i].name);
if (ret) {
drm_property_destroy(dev, scaling_mode_property);
return ret;
}
}
drm_object_attach_property(&connector->base,
scaling_mode_property, 0);
connector->scaling_mode_property = scaling_mode_property;
return 0;
}
EXPORT_SYMBOL(drm_connector_attach_scaling_mode_property);
/** /**
* drm_mode_create_aspect_ratio_property - create aspect ratio property * drm_mode_create_aspect_ratio_property - create aspect ratio property
* @dev: DRM device * @dev: DRM device
......
...@@ -737,16 +737,16 @@ static void drm_dp_mst_put_payload_id(struct drm_dp_mst_topology_mgr *mgr, ...@@ -737,16 +737,16 @@ static void drm_dp_mst_put_payload_id(struct drm_dp_mst_topology_mgr *mgr,
static bool check_txmsg_state(struct drm_dp_mst_topology_mgr *mgr, static bool check_txmsg_state(struct drm_dp_mst_topology_mgr *mgr,
struct drm_dp_sideband_msg_tx *txmsg) struct drm_dp_sideband_msg_tx *txmsg)
{ {
bool ret; unsigned int state;
/* /*
* All updates to txmsg->state are protected by mgr->qlock, and the two * All updates to txmsg->state are protected by mgr->qlock, and the two
* cases we check here are terminal states. For those the barriers * cases we check here are terminal states. For those the barriers
* provided by the wake_up/wait_event pair are enough. * provided by the wake_up/wait_event pair are enough.
*/ */
ret = (txmsg->state == DRM_DP_SIDEBAND_TX_RX || state = READ_ONCE(txmsg->state);
txmsg->state == DRM_DP_SIDEBAND_TX_TIMEOUT); return (state == DRM_DP_SIDEBAND_TX_RX ||
return ret; state == DRM_DP_SIDEBAND_TX_TIMEOUT);
} }
static int drm_dp_mst_wait_tx_reply(struct drm_dp_mst_branch *mstb, static int drm_dp_mst_wait_tx_reply(struct drm_dp_mst_branch *mstb,
...@@ -855,7 +855,7 @@ static void drm_dp_destroy_mst_branch_device(struct kref *kref) ...@@ -855,7 +855,7 @@ static void drm_dp_destroy_mst_branch_device(struct kref *kref)
mutex_unlock(&mstb->mgr->qlock); mutex_unlock(&mstb->mgr->qlock);
if (wake_tx) if (wake_tx)
wake_up(&mstb->mgr->tx_waitq); wake_up_all(&mstb->mgr->tx_waitq);
kref_put(kref, drm_dp_free_mst_branch_device); kref_put(kref, drm_dp_free_mst_branch_device);
} }
...@@ -1510,7 +1510,7 @@ static void process_single_down_tx_qlock(struct drm_dp_mst_topology_mgr *mgr) ...@@ -1510,7 +1510,7 @@ static void process_single_down_tx_qlock(struct drm_dp_mst_topology_mgr *mgr)
if (txmsg->seqno != -1) if (txmsg->seqno != -1)
txmsg->dst->tx_slots[txmsg->seqno] = NULL; txmsg->dst->tx_slots[txmsg->seqno] = NULL;
txmsg->state = DRM_DP_SIDEBAND_TX_TIMEOUT; txmsg->state = DRM_DP_SIDEBAND_TX_TIMEOUT;
wake_up(&mgr->tx_waitq); wake_up_all(&mgr->tx_waitq);
} }
} }
...@@ -2258,7 +2258,7 @@ static int drm_dp_mst_handle_down_rep(struct drm_dp_mst_topology_mgr *mgr) ...@@ -2258,7 +2258,7 @@ static int drm_dp_mst_handle_down_rep(struct drm_dp_mst_topology_mgr *mgr)
mstb->tx_slots[slot] = NULL; mstb->tx_slots[slot] = NULL;
mutex_unlock(&mgr->qlock); mutex_unlock(&mgr->qlock);
wake_up(&mgr->tx_waitq); wake_up_all(&mgr->tx_waitq);
} }
return ret; return ret;
} }
...@@ -2497,6 +2497,81 @@ static int drm_dp_init_vcpi(struct drm_dp_mst_topology_mgr *mgr, ...@@ -2497,6 +2497,81 @@ static int drm_dp_init_vcpi(struct drm_dp_mst_topology_mgr *mgr,
return 0; return 0;
} }
/**
* drm_dp_atomic_find_vcpi_slots() - Find and add vcpi slots to the state
* @state: global atomic state
* @mgr: MST topology manager for the port
* @port: port to find vcpi slots for
* @pbn: bandwidth required for the mode in PBN
*
* RETURNS:
* Total slots in the atomic state assigned for this port or error
*/
int drm_dp_atomic_find_vcpi_slots(struct drm_atomic_state *state,
struct drm_dp_mst_topology_mgr *mgr,
struct drm_dp_mst_port *port, int pbn)
{
struct drm_dp_mst_topology_state *topology_state;
int req_slots;
topology_state = drm_atomic_get_mst_topology_state(state, mgr);
if (topology_state == NULL)
return -ENOMEM;
port = drm_dp_get_validated_port_ref(mgr, port);
if (port == NULL)
return -EINVAL;
req_slots = DIV_ROUND_UP(pbn, mgr->pbn_div);
DRM_DEBUG_KMS("vcpi slots req=%d, avail=%d\n",
req_slots, topology_state->avail_slots);
if (req_slots > topology_state->avail_slots) {
drm_dp_put_port(port);
return -ENOSPC;
}
topology_state->avail_slots -= req_slots;
DRM_DEBUG_KMS("vcpi slots avail=%d", topology_state->avail_slots);
drm_dp_put_port(port);
return req_slots;
}
EXPORT_SYMBOL(drm_dp_atomic_find_vcpi_slots);
/**
* drm_dp_atomic_release_vcpi_slots() - Release allocated vcpi slots
* @state: global atomic state
* @mgr: MST topology manager for the port
* @slots: number of vcpi slots to release
*
* RETURNS:
* 0 if @slots were added back to &drm_dp_mst_topology_state->avail_slots or
* negative error code
*/
int drm_dp_atomic_release_vcpi_slots(struct drm_atomic_state *state,
struct drm_dp_mst_topology_mgr *mgr,
int slots)
{
struct drm_dp_mst_topology_state *topology_state;
topology_state = drm_atomic_get_mst_topology_state(state, mgr);
if (topology_state == NULL)
return -ENOMEM;
/* We cannot rely on port->vcpi.num_slots to update
* topology_state->avail_slots as the port may not exist if the parent
* branch device was unplugged. This should be fixed by tracking
* per-port slot allocation in drm_dp_mst_topology_state instead of
* depending on the caller to tell us how many slots to release.
*/
topology_state->avail_slots += slots;
DRM_DEBUG_KMS("vcpi slots released=%d, avail=%d\n",
slots, topology_state->avail_slots);
return 0;
}
EXPORT_SYMBOL(drm_dp_atomic_release_vcpi_slots);
/** /**
* drm_dp_mst_allocate_vcpi() - Allocate a virtual channel * drm_dp_mst_allocate_vcpi() - Allocate a virtual channel
* @mgr: manager for this port * @mgr: manager for this port
...@@ -2936,6 +3011,69 @@ static void drm_dp_destroy_connector_work(struct work_struct *work) ...@@ -2936,6 +3011,69 @@ static void drm_dp_destroy_connector_work(struct work_struct *work)
(*mgr->cbs->hotplug)(mgr); (*mgr->cbs->hotplug)(mgr);
} }
void *drm_dp_mst_duplicate_state(struct drm_atomic_state *state, void *obj)
{
struct drm_dp_mst_topology_mgr *mgr = obj;
struct drm_dp_mst_topology_state *new_mst_state;
if (WARN_ON(!mgr->state))
return NULL;
new_mst_state = kmemdup(mgr->state, sizeof(*new_mst_state), GFP_KERNEL);
if (new_mst_state)
new_mst_state->state = state;
return new_mst_state;
}
void drm_dp_mst_swap_state(void *obj, void **obj_state_ptr)
{
struct drm_dp_mst_topology_mgr *mgr = obj;
struct drm_dp_mst_topology_state **topology_state_ptr;
topology_state_ptr = (struct drm_dp_mst_topology_state **)obj_state_ptr;
mgr->state->state = (*topology_state_ptr)->state;
swap(*topology_state_ptr, mgr->state);
mgr->state->state = NULL;
}
void drm_dp_mst_destroy_state(void *obj_state)
{
kfree(obj_state);
}
static const struct drm_private_state_funcs mst_state_funcs = {
.duplicate_state = drm_dp_mst_duplicate_state,
.swap_state = drm_dp_mst_swap_state,
.destroy_state = drm_dp_mst_destroy_state,
};
/**
* drm_atomic_get_mst_topology_state: get MST topology state
*
* @state: global atomic state
* @mgr: MST topology manager, also the private object in this case
*
* This function wraps drm_atomic_get_priv_obj_state() passing in the MST atomic
* state vtable so that the private object state returned is that of a MST
* topology object. Also, drm_atomic_get_private_obj_state() expects the caller
* to care of the locking, so warn if don't hold the connection_mutex.
*
* RETURNS:
*
* The MST topology state or error pointer.
*/
struct drm_dp_mst_topology_state *drm_atomic_get_mst_topology_state(struct drm_atomic_state *state,
struct drm_dp_mst_topology_mgr *mgr)
{
struct drm_device *dev = mgr->dev;
WARN_ON(!drm_modeset_is_locked(&dev->mode_config.connection_mutex));
return drm_atomic_get_private_obj_state(state, mgr,
&mst_state_funcs);
}
EXPORT_SYMBOL(drm_atomic_get_mst_topology_state);
/** /**
* drm_dp_mst_topology_mgr_init - initialise a topology manager * drm_dp_mst_topology_mgr_init - initialise a topology manager
* @mgr: manager struct to initialise * @mgr: manager struct to initialise
...@@ -2980,6 +3118,15 @@ int drm_dp_mst_topology_mgr_init(struct drm_dp_mst_topology_mgr *mgr, ...@@ -2980,6 +3118,15 @@ int drm_dp_mst_topology_mgr_init(struct drm_dp_mst_topology_mgr *mgr,
if (test_calc_pbn_mode() < 0) if (test_calc_pbn_mode() < 0)
DRM_ERROR("MST PBN self-test failed\n"); DRM_ERROR("MST PBN self-test failed\n");
mgr->state = kzalloc(sizeof(*mgr->state), GFP_KERNEL);
if (mgr->state == NULL)
return -ENOMEM;
mgr->state->mgr = mgr;
/* max. time slots - one slot for MTP header */
mgr->state->avail_slots = 63;
mgr->funcs = &mst_state_funcs;
return 0; return 0;
} }
EXPORT_SYMBOL(drm_dp_mst_topology_mgr_init); EXPORT_SYMBOL(drm_dp_mst_topology_mgr_init);
...@@ -3000,6 +3147,9 @@ void drm_dp_mst_topology_mgr_destroy(struct drm_dp_mst_topology_mgr *mgr) ...@@ -3000,6 +3147,9 @@ void drm_dp_mst_topology_mgr_destroy(struct drm_dp_mst_topology_mgr *mgr)
mutex_unlock(&mgr->payload_lock); mutex_unlock(&mgr->payload_lock);
mgr->dev = NULL; mgr->dev = NULL;
mgr->aux = NULL; mgr->aux = NULL;
kfree(mgr->state);
mgr->state = NULL;
mgr->funcs = NULL;
} }
EXPORT_SYMBOL(drm_dp_mst_topology_mgr_destroy); EXPORT_SYMBOL(drm_dp_mst_topology_mgr_destroy);
......
...@@ -189,7 +189,7 @@ struct drm_framebuffer *drm_fb_cma_create_with_funcs(struct drm_device *dev, ...@@ -189,7 +189,7 @@ struct drm_framebuffer *drm_fb_cma_create_with_funcs(struct drm_device *dev,
obj = drm_gem_object_lookup(file_priv, mode_cmd->handles[i]); obj = drm_gem_object_lookup(file_priv, mode_cmd->handles[i]);
if (!obj) { if (!obj) {
dev_err(dev->dev, "Failed to lookup GEM object\n"); dev_err(dev->dev, "Failed to lookup GEM object\n");
ret = -ENXIO; ret = -ENOENT;
goto err_gem_object_put; goto err_gem_object_put;
} }
...@@ -259,6 +259,33 @@ struct drm_gem_cma_object *drm_fb_cma_get_gem_obj(struct drm_framebuffer *fb, ...@@ -259,6 +259,33 @@ struct drm_gem_cma_object *drm_fb_cma_get_gem_obj(struct drm_framebuffer *fb,
} }
EXPORT_SYMBOL_GPL(drm_fb_cma_get_gem_obj); EXPORT_SYMBOL_GPL(drm_fb_cma_get_gem_obj);
/**
* drm_fb_cma_get_gem_addr() - Get physical address for framebuffer
* @fb: The framebuffer
* @state: Which state of drm plane
* @plane: Which plane
* Return the CMA GEM address for given framebuffer.
*
* This function will usually be called from the PLANE callback functions.
*/
dma_addr_t drm_fb_cma_get_gem_addr(struct drm_framebuffer *fb,
struct drm_plane_state *state,
unsigned int plane)
{
struct drm_fb_cma *fb_cma = to_fb_cma(fb);
dma_addr_t paddr;
if (plane >= 4)
return 0;
paddr = fb_cma->obj[plane]->paddr + fb->offsets[plane];
paddr += fb->format->cpp[plane] * (state->src_x >> 16);
paddr += fb->pitches[plane] * (state->src_y >> 16);
return paddr;
}
EXPORT_SYMBOL_GPL(drm_fb_cma_get_gem_addr);
/** /**
* drm_fb_cma_prepare_fb() - Prepare CMA framebuffer * drm_fb_cma_prepare_fb() - Prepare CMA framebuffer
* @plane: Which plane * @plane: Which plane
......
...@@ -351,9 +351,8 @@ void drm_lastclose(struct drm_device * dev) ...@@ -351,9 +351,8 @@ void drm_lastclose(struct drm_device * dev)
* *
* This function must be used by drivers as their &file_operations.release * This function must be used by drivers as their &file_operations.release
* method. It frees any resources associated with the open file, and calls the * method. It frees any resources associated with the open file, and calls the
* &drm_driver.preclose and &drm_driver.lastclose driver callbacks. If this is * &drm_driver.postclose driver callback. If this is the last open file for the
* the last open file for the DRM device also proceeds to call the * DRM device also proceeds to call the &drm_driver.lastclose driver callback.
* &drm_driver.lastclose driver callback.
* *
* RETURNS: * RETURNS:
* *
...@@ -373,7 +372,8 @@ int drm_release(struct inode *inode, struct file *filp) ...@@ -373,7 +372,8 @@ int drm_release(struct inode *inode, struct file *filp)
list_del(&file_priv->lhead); list_del(&file_priv->lhead);
mutex_unlock(&dev->filelist_mutex); mutex_unlock(&dev->filelist_mutex);
if (dev->driver->preclose) if (drm_core_check_feature(dev, DRIVER_LEGACY) &&
dev->driver->preclose)
dev->driver->preclose(dev, file_priv); dev->driver->preclose(dev, file_priv);
/* ======================================================== /* ========================================================
......
...@@ -54,7 +54,7 @@ ...@@ -54,7 +54,7 @@
static bool static bool
drm_get_last_vbltimestamp(struct drm_device *dev, unsigned int pipe, drm_get_last_vbltimestamp(struct drm_device *dev, unsigned int pipe,
struct timeval *tvblank, unsigned flags); struct timeval *tvblank, bool in_vblank_irq);
static unsigned int drm_timestamp_precision = 20; /* Default to 20 usecs. */ static unsigned int drm_timestamp_precision = 20; /* Default to 20 usecs. */
...@@ -138,7 +138,7 @@ static void drm_reset_vblank_timestamp(struct drm_device *dev, unsigned int pipe ...@@ -138,7 +138,7 @@ static void drm_reset_vblank_timestamp(struct drm_device *dev, unsigned int pipe
*/ */
do { do {
cur_vblank = __get_vblank_counter(dev, pipe); cur_vblank = __get_vblank_counter(dev, pipe);
rc = drm_get_last_vbltimestamp(dev, pipe, &t_vblank, 0); rc = drm_get_last_vbltimestamp(dev, pipe, &t_vblank, false);
} while (cur_vblank != __get_vblank_counter(dev, pipe) && --count > 0); } while (cur_vblank != __get_vblank_counter(dev, pipe) && --count > 0);
/* /*
...@@ -171,7 +171,7 @@ static void drm_reset_vblank_timestamp(struct drm_device *dev, unsigned int pipe ...@@ -171,7 +171,7 @@ static void drm_reset_vblank_timestamp(struct drm_device *dev, unsigned int pipe
* device vblank fields. * device vblank fields.
*/ */
static void drm_update_vblank_count(struct drm_device *dev, unsigned int pipe, static void drm_update_vblank_count(struct drm_device *dev, unsigned int pipe,
unsigned long flags) bool in_vblank_irq)
{ {
struct drm_vblank_crtc *vblank = &dev->vblank[pipe]; struct drm_vblank_crtc *vblank = &dev->vblank[pipe];
u32 cur_vblank, diff; u32 cur_vblank, diff;
...@@ -194,7 +194,7 @@ static void drm_update_vblank_count(struct drm_device *dev, unsigned int pipe, ...@@ -194,7 +194,7 @@ static void drm_update_vblank_count(struct drm_device *dev, unsigned int pipe,
*/ */
do { do {
cur_vblank = __get_vblank_counter(dev, pipe); cur_vblank = __get_vblank_counter(dev, pipe);
rc = drm_get_last_vbltimestamp(dev, pipe, &t_vblank, flags); rc = drm_get_last_vbltimestamp(dev, pipe, &t_vblank, in_vblank_irq);
} while (cur_vblank != __get_vblank_counter(dev, pipe) && --count > 0); } while (cur_vblank != __get_vblank_counter(dev, pipe) && --count > 0);
if (dev->max_vblank_count != 0) { if (dev->max_vblank_count != 0) {
...@@ -214,13 +214,13 @@ static void drm_update_vblank_count(struct drm_device *dev, unsigned int pipe, ...@@ -214,13 +214,13 @@ static void drm_update_vblank_count(struct drm_device *dev, unsigned int pipe,
*/ */
diff = DIV_ROUND_CLOSEST_ULL(diff_ns, framedur_ns); diff = DIV_ROUND_CLOSEST_ULL(diff_ns, framedur_ns);
if (diff == 0 && flags & DRM_CALLED_FROM_VBLIRQ) if (diff == 0 && in_vblank_irq)
DRM_DEBUG_VBL("crtc %u: Redundant vblirq ignored." DRM_DEBUG_VBL("crtc %u: Redundant vblirq ignored."
" diff_ns = %lld, framedur_ns = %d)\n", " diff_ns = %lld, framedur_ns = %d)\n",
pipe, (long long) diff_ns, framedur_ns); pipe, (long long) diff_ns, framedur_ns);
} else { } else {
/* some kind of default for drivers w/o accurate vbl timestamping */ /* some kind of default for drivers w/o accurate vbl timestamping */
diff = (flags & DRM_CALLED_FROM_VBLIRQ) != 0; diff = in_vblank_irq ? 1 : 0;
} }
/* /*
...@@ -253,7 +253,7 @@ static void drm_update_vblank_count(struct drm_device *dev, unsigned int pipe, ...@@ -253,7 +253,7 @@ static void drm_update_vblank_count(struct drm_device *dev, unsigned int pipe,
* Otherwise reinitialize delayed at next vblank interrupt and assign 0 * Otherwise reinitialize delayed at next vblank interrupt and assign 0
* for now, to mark the vblanktimestamp as invalid. * for now, to mark the vblanktimestamp as invalid.
*/ */
if (!rc && (flags & DRM_CALLED_FROM_VBLIRQ) == 0) if (!rc && in_vblank_irq)
t_vblank = (struct timeval) {0, 0}; t_vblank = (struct timeval) {0, 0};
store_vblank(dev, pipe, diff, &t_vblank, cur_vblank); store_vblank(dev, pipe, diff, &t_vblank, cur_vblank);
...@@ -291,7 +291,7 @@ u32 drm_accurate_vblank_count(struct drm_crtc *crtc) ...@@ -291,7 +291,7 @@ u32 drm_accurate_vblank_count(struct drm_crtc *crtc)
spin_lock_irqsave(&dev->vblank_time_lock, flags); spin_lock_irqsave(&dev->vblank_time_lock, flags);
drm_update_vblank_count(dev, pipe, 0); drm_update_vblank_count(dev, pipe, false);
vblank = drm_vblank_count(dev, pipe); vblank = drm_vblank_count(dev, pipe);
spin_unlock_irqrestore(&dev->vblank_time_lock, flags); spin_unlock_irqrestore(&dev->vblank_time_lock, flags);
...@@ -349,7 +349,7 @@ static void vblank_disable_and_save(struct drm_device *dev, unsigned int pipe) ...@@ -349,7 +349,7 @@ static void vblank_disable_and_save(struct drm_device *dev, unsigned int pipe)
* this time. This makes the count account for the entire time * this time. This makes the count account for the entire time
* between drm_crtc_vblank_on() and drm_crtc_vblank_off(). * between drm_crtc_vblank_on() and drm_crtc_vblank_off().
*/ */
drm_update_vblank_count(dev, pipe, 0); drm_update_vblank_count(dev, pipe, false);
spin_unlock_irqrestore(&dev->vblank_time_lock, irqflags); spin_unlock_irqrestore(&dev->vblank_time_lock, irqflags);
} }
...@@ -684,6 +684,7 @@ void drm_calc_timestamping_constants(struct drm_crtc *crtc, ...@@ -684,6 +684,7 @@ void drm_calc_timestamping_constants(struct drm_crtc *crtc,
vblank->linedur_ns = linedur_ns; vblank->linedur_ns = linedur_ns;
vblank->framedur_ns = framedur_ns; vblank->framedur_ns = framedur_ns;
vblank->hwmode = *mode;
DRM_DEBUG("crtc %u: hwmode: htotal %d, vtotal %d, vdisplay %d\n", DRM_DEBUG("crtc %u: hwmode: htotal %d, vtotal %d, vdisplay %d\n",
crtc->base.id, mode->crtc_htotal, crtc->base.id, mode->crtc_htotal,
...@@ -700,10 +701,10 @@ EXPORT_SYMBOL(drm_calc_timestamping_constants); ...@@ -700,10 +701,10 @@ EXPORT_SYMBOL(drm_calc_timestamping_constants);
* @max_error: Desired maximum allowable error in timestamps (nanosecs) * @max_error: Desired maximum allowable error in timestamps (nanosecs)
* On return contains true maximum error of timestamp * On return contains true maximum error of timestamp
* @vblank_time: Pointer to struct timeval which should receive the timestamp * @vblank_time: Pointer to struct timeval which should receive the timestamp
* @flags: Flags to pass to driver: * @in_vblank_irq:
* 0 = Default, * True when called from drm_crtc_handle_vblank(). Some drivers
* DRM_CALLED_FROM_VBLIRQ = If function is called from vbl IRQ handler * need to apply some workarounds for gpu-specific vblank irq quirks
* @mode: mode which defines the scanout timings * if flag is set.
* *
* Implements calculation of exact vblank timestamps from given drm_display_mode * Implements calculation of exact vblank timestamps from given drm_display_mode
* timings and current video scanout position of a CRTC. This can be called from * timings and current video scanout position of a CRTC. This can be called from
...@@ -723,52 +724,62 @@ EXPORT_SYMBOL(drm_calc_timestamping_constants); ...@@ -723,52 +724,62 @@ EXPORT_SYMBOL(drm_calc_timestamping_constants);
* returns as no operation if a doublescan or interlaced video mode is * returns as no operation if a doublescan or interlaced video mode is
* active. Higher level code is expected to handle this. * active. Higher level code is expected to handle this.
* *
* Returns: * This function can be used to implement the &drm_driver.get_vblank_timestamp
* Negative value on error, failure or if not supported in current * directly, if the driver implements the &drm_driver.get_scanout_position hook.
* video mode:
*
* -EINVAL Invalid CRTC.
* -EAGAIN Temporary unavailable, e.g., called before initial modeset.
* -ENOTSUPP Function not supported in current display mode.
* -EIO Failed, e.g., due to failed scanout position query.
* *
* Returns or'ed positive status flags on success: * Note that atomic drivers must call drm_calc_timestamping_constants() before
* enabling a CRTC. The atomic helpers already take care of that in
* drm_atomic_helper_update_legacy_modeset_state().
* *
* DRM_VBLANKTIME_SCANOUTPOS_METHOD - Signal this method used for timestamping. * Returns:
* DRM_VBLANKTIME_INVBL - Timestamp taken while scanout was in vblank interval.
* *
* Returns true on success, and false on failure, i.e. when no accurate
* timestamp could be acquired.
*/ */
int drm_calc_vbltimestamp_from_scanoutpos(struct drm_device *dev, bool drm_calc_vbltimestamp_from_scanoutpos(struct drm_device *dev,
unsigned int pipe, unsigned int pipe,
int *max_error, int *max_error,
struct timeval *vblank_time, struct timeval *vblank_time,
unsigned flags, bool in_vblank_irq)
const struct drm_display_mode *mode)
{ {
struct timeval tv_etime; struct timeval tv_etime;
ktime_t stime, etime; ktime_t stime, etime;
unsigned int vbl_status; bool vbl_status;
int ret = DRM_VBLANKTIME_SCANOUTPOS_METHOD; struct drm_crtc *crtc;
const struct drm_display_mode *mode;
struct drm_vblank_crtc *vblank = &dev->vblank[pipe];
int vpos, hpos, i; int vpos, hpos, i;
int delta_ns, duration_ns; int delta_ns, duration_ns;
if (pipe >= dev->num_crtcs) { if (!drm_core_check_feature(dev, DRIVER_MODESET))
return false;
crtc = drm_crtc_from_index(dev, pipe);
if (pipe >= dev->num_crtcs || !crtc) {
DRM_ERROR("Invalid crtc %u\n", pipe); DRM_ERROR("Invalid crtc %u\n", pipe);
return -EINVAL; return false;
} }
/* Scanout position query not supported? Should not happen. */ /* Scanout position query not supported? Should not happen. */
if (!dev->driver->get_scanout_position) { if (!dev->driver->get_scanout_position) {
DRM_ERROR("Called from driver w/o get_scanout_position()!?\n"); DRM_ERROR("Called from driver w/o get_scanout_position()!?\n");
return -EIO; return false;
} }
if (drm_drv_uses_atomic_modeset(dev))
mode = &vblank->hwmode;
else
mode = &crtc->hwmode;
/* If mode timing undefined, just return as no-op: /* If mode timing undefined, just return as no-op:
* Happens during initial modesetting of a crtc. * Happens during initial modesetting of a crtc.
*/ */
if (mode->crtc_clock == 0) { if (mode->crtc_clock == 0) {
DRM_DEBUG("crtc %u: Noop due to uninitialized mode.\n", pipe); DRM_DEBUG("crtc %u: Noop due to uninitialized mode.\n", pipe);
return -EAGAIN; WARN_ON_ONCE(drm_drv_uses_atomic_modeset(dev));
return false;
} }
/* Get current scanout position with system timestamp. /* Get current scanout position with system timestamp.
...@@ -783,16 +794,17 @@ int drm_calc_vbltimestamp_from_scanoutpos(struct drm_device *dev, ...@@ -783,16 +794,17 @@ int drm_calc_vbltimestamp_from_scanoutpos(struct drm_device *dev,
* Get vertical and horizontal scanout position vpos, hpos, * Get vertical and horizontal scanout position vpos, hpos,
* and bounding timestamps stime, etime, pre/post query. * and bounding timestamps stime, etime, pre/post query.
*/ */
vbl_status = dev->driver->get_scanout_position(dev, pipe, flags, vbl_status = dev->driver->get_scanout_position(dev, pipe,
in_vblank_irq,
&vpos, &hpos, &vpos, &hpos,
&stime, &etime, &stime, &etime,
mode); mode);
/* Return as no-op if scanout query unsupported or failed. */ /* Return as no-op if scanout query unsupported or failed. */
if (!(vbl_status & DRM_SCANOUTPOS_VALID)) { if (!vbl_status) {
DRM_DEBUG("crtc %u : scanoutpos query failed [0x%x].\n", DRM_DEBUG("crtc %u : scanoutpos query failed.\n",
pipe, vbl_status); pipe);
return -EIO; return false;
} }
/* Compute uncertainty in timestamp of scanout position query. */ /* Compute uncertainty in timestamp of scanout position query. */
...@@ -830,13 +842,13 @@ int drm_calc_vbltimestamp_from_scanoutpos(struct drm_device *dev, ...@@ -830,13 +842,13 @@ int drm_calc_vbltimestamp_from_scanoutpos(struct drm_device *dev,
etime = ktime_sub_ns(etime, delta_ns); etime = ktime_sub_ns(etime, delta_ns);
*vblank_time = ktime_to_timeval(etime); *vblank_time = ktime_to_timeval(etime);
DRM_DEBUG_VBL("crtc %u : v 0x%x p(%d,%d)@ %ld.%ld -> %ld.%ld [e %d us, %d rep]\n", DRM_DEBUG_VBL("crtc %u : v p(%d,%d)@ %ld.%ld -> %ld.%ld [e %d us, %d rep]\n",
pipe, vbl_status, hpos, vpos, pipe, hpos, vpos,
(long)tv_etime.tv_sec, (long)tv_etime.tv_usec, (long)tv_etime.tv_sec, (long)tv_etime.tv_usec,
(long)vblank_time->tv_sec, (long)vblank_time->tv_usec, (long)vblank_time->tv_sec, (long)vblank_time->tv_usec,
duration_ns/1000, i); duration_ns/1000, i);
return ret; return true;
} }
EXPORT_SYMBOL(drm_calc_vbltimestamp_from_scanoutpos); EXPORT_SYMBOL(drm_calc_vbltimestamp_from_scanoutpos);
...@@ -854,9 +866,10 @@ static struct timeval get_drm_timestamp(void) ...@@ -854,9 +866,10 @@ static struct timeval get_drm_timestamp(void)
* @dev: DRM device * @dev: DRM device
* @pipe: index of CRTC whose vblank timestamp to retrieve * @pipe: index of CRTC whose vblank timestamp to retrieve
* @tvblank: Pointer to target struct timeval which should receive the timestamp * @tvblank: Pointer to target struct timeval which should receive the timestamp
* @flags: Flags to pass to driver: * @in_vblank_irq:
* 0 = Default, * True when called from drm_crtc_handle_vblank(). Some drivers
* DRM_CALLED_FROM_VBLIRQ = If function is called from vbl IRQ handler * need to apply some workarounds for gpu-specific vblank irq quirks
* if flag is set.
* *
* Fetches the system timestamp corresponding to the time of the most recent * Fetches the system timestamp corresponding to the time of the most recent
* vblank interval on specified CRTC. May call into kms-driver to * vblank interval on specified CRTC. May call into kms-driver to
...@@ -870,27 +883,25 @@ static struct timeval get_drm_timestamp(void) ...@@ -870,27 +883,25 @@ static struct timeval get_drm_timestamp(void)
*/ */
static bool static bool
drm_get_last_vbltimestamp(struct drm_device *dev, unsigned int pipe, drm_get_last_vbltimestamp(struct drm_device *dev, unsigned int pipe,
struct timeval *tvblank, unsigned flags) struct timeval *tvblank, bool in_vblank_irq)
{ {
int ret; bool ret = false;
/* Define requested maximum error on timestamps (nanoseconds). */ /* Define requested maximum error on timestamps (nanoseconds). */
int max_error = (int) drm_timestamp_precision * 1000; int max_error = (int) drm_timestamp_precision * 1000;
/* Query driver if possible and precision timestamping enabled. */ /* Query driver if possible and precision timestamping enabled. */
if (dev->driver->get_vblank_timestamp && (max_error > 0)) { if (dev->driver->get_vblank_timestamp && (max_error > 0))
ret = dev->driver->get_vblank_timestamp(dev, pipe, &max_error, ret = dev->driver->get_vblank_timestamp(dev, pipe, &max_error,
tvblank, flags); tvblank, in_vblank_irq);
if (ret > 0)
return true;
}
/* GPU high precision timestamp query unsupported or failed. /* GPU high precision timestamp query unsupported or failed.
* Return current monotonic/gettimeofday timestamp as best estimate. * Return current monotonic/gettimeofday timestamp as best estimate.
*/ */
*tvblank = get_drm_timestamp(); if (!ret)
*tvblank = get_drm_timestamp();
return false; return ret;
} }
/** /**
...@@ -1329,6 +1340,10 @@ void drm_crtc_vblank_off(struct drm_crtc *crtc) ...@@ -1329,6 +1340,10 @@ void drm_crtc_vblank_off(struct drm_crtc *crtc)
send_vblank_event(dev, e, seq, &now); send_vblank_event(dev, e, seq, &now);
} }
spin_unlock_irqrestore(&dev->event_lock, irqflags); spin_unlock_irqrestore(&dev->event_lock, irqflags);
/* Will be reset by the modeset helpers when re-enabling the crtc by
* calling drm_calc_timestamping_constants(). */
vblank->hwmode.crtc_clock = 0;
} }
EXPORT_SYMBOL(drm_crtc_vblank_off); EXPORT_SYMBOL(drm_crtc_vblank_off);
...@@ -1760,7 +1775,7 @@ bool drm_handle_vblank(struct drm_device *dev, unsigned int pipe) ...@@ -1760,7 +1775,7 @@ bool drm_handle_vblank(struct drm_device *dev, unsigned int pipe)
return false; return false;
} }
drm_update_vblank_count(dev, pipe, DRM_CALLED_FROM_VBLIRQ); drm_update_vblank_count(dev, pipe, true);
spin_unlock(&dev->vblank_time_lock); spin_unlock(&dev->vblank_time_lock);
......
...@@ -381,6 +381,7 @@ EXPORT_SYMBOL(drm_primary_helper_update); ...@@ -381,6 +381,7 @@ EXPORT_SYMBOL(drm_primary_helper_update);
/** /**
* drm_primary_helper_disable() - Helper for primary plane disable * drm_primary_helper_disable() - Helper for primary plane disable
* @plane: plane to disable * @plane: plane to disable
* @ctx: lock acquire context, not used here
* *
* Provides a default plane disable handler for primary planes. This is handler * Provides a default plane disable handler for primary planes. This is handler
* is called in response to a userspace SetPlane operation on the plane with a * is called in response to a userspace SetPlane operation on the plane with a
...@@ -510,12 +511,10 @@ int drm_plane_helper_commit(struct drm_plane *plane, ...@@ -510,12 +511,10 @@ int drm_plane_helper_commit(struct drm_plane *plane,
if (plane_funcs->cleanup_fb) if (plane_funcs->cleanup_fb)
plane_funcs->cleanup_fb(plane, plane_state); plane_funcs->cleanup_fb(plane, plane_state);
out: out:
if (plane_state) { if (plane->funcs->atomic_destroy_state)
if (plane->funcs->atomic_destroy_state) plane->funcs->atomic_destroy_state(plane, plane_state);
plane->funcs->atomic_destroy_state(plane, plane_state); else
else drm_atomic_helper_plane_destroy_state(plane, plane_state);
drm_atomic_helper_plane_destroy_state(plane, plane_state);
}
return ret; return ret;
} }
......
...@@ -595,15 +595,18 @@ int drm_gem_prime_handle_to_fd(struct drm_device *dev, ...@@ -595,15 +595,18 @@ int drm_gem_prime_handle_to_fd(struct drm_device *dev,
EXPORT_SYMBOL(drm_gem_prime_handle_to_fd); EXPORT_SYMBOL(drm_gem_prime_handle_to_fd);
/** /**
* drm_gem_prime_import - helper library implementation of the import callback * drm_gem_prime_import_dev - core implementation of the import callback
* @dev: drm_device to import into * @dev: drm_device to import into
* @dma_buf: dma-buf object to import * @dma_buf: dma-buf object to import
* @attach_dev: struct device to dma_buf attach
* *
* This is the implementation of the gem_prime_import functions for GEM drivers * This is the core of drm_gem_prime_import. It's designed to be called by
* using the PRIME helpers. * drivers who want to use a different device structure than dev->dev for
* attaching via dma_buf.
*/ */
struct drm_gem_object *drm_gem_prime_import(struct drm_device *dev, struct drm_gem_object *drm_gem_prime_import_dev(struct drm_device *dev,
struct dma_buf *dma_buf) struct dma_buf *dma_buf,
struct device *attach_dev)
{ {
struct dma_buf_attachment *attach; struct dma_buf_attachment *attach;
struct sg_table *sgt; struct sg_table *sgt;
...@@ -625,7 +628,7 @@ struct drm_gem_object *drm_gem_prime_import(struct drm_device *dev, ...@@ -625,7 +628,7 @@ struct drm_gem_object *drm_gem_prime_import(struct drm_device *dev,
if (!dev->driver->gem_prime_import_sg_table) if (!dev->driver->gem_prime_import_sg_table)
return ERR_PTR(-EINVAL); return ERR_PTR(-EINVAL);
attach = dma_buf_attach(dma_buf, dev->dev); attach = dma_buf_attach(dma_buf, attach_dev);
if (IS_ERR(attach)) if (IS_ERR(attach))
return ERR_CAST(attach); return ERR_CAST(attach);
...@@ -655,6 +658,21 @@ struct drm_gem_object *drm_gem_prime_import(struct drm_device *dev, ...@@ -655,6 +658,21 @@ struct drm_gem_object *drm_gem_prime_import(struct drm_device *dev,
return ERR_PTR(ret); return ERR_PTR(ret);
} }
EXPORT_SYMBOL(drm_gem_prime_import_dev);
/**
* drm_gem_prime_import - helper library implementation of the import callback
* @dev: drm_device to import into
* @dma_buf: dma-buf object to import
*
* This is the implementation of the gem_prime_import functions for GEM drivers
* using the PRIME helpers.
*/
struct drm_gem_object *drm_gem_prime_import(struct drm_device *dev,
struct dma_buf *dma_buf)
{
return drm_gem_prime_import_dev(dev, dma_buf, dev->dev);
}
EXPORT_SYMBOL(drm_gem_prime_import); EXPORT_SYMBOL(drm_gem_prime_import);
/** /**
......
...@@ -82,14 +82,9 @@ static int exynos_drm_open(struct drm_device *dev, struct drm_file *file) ...@@ -82,14 +82,9 @@ static int exynos_drm_open(struct drm_device *dev, struct drm_file *file)
return ret; return ret;
} }
static void exynos_drm_preclose(struct drm_device *dev,
struct drm_file *file)
{
exynos_drm_subdrv_close(dev, file);
}
static void exynos_drm_postclose(struct drm_device *dev, struct drm_file *file) static void exynos_drm_postclose(struct drm_device *dev, struct drm_file *file)
{ {
exynos_drm_subdrv_close(dev, file);
kfree(file->driver_priv); kfree(file->driver_priv);
file->driver_priv = NULL; file->driver_priv = NULL;
} }
...@@ -145,7 +140,6 @@ static struct drm_driver exynos_drm_driver = { ...@@ -145,7 +140,6 @@ static struct drm_driver exynos_drm_driver = {
.driver_features = DRIVER_MODESET | DRIVER_GEM | DRIVER_PRIME .driver_features = DRIVER_MODESET | DRIVER_GEM | DRIVER_PRIME
| DRIVER_ATOMIC | DRIVER_RENDER, | DRIVER_ATOMIC | DRIVER_RENDER,
.open = exynos_drm_open, .open = exynos_drm_open,
.preclose = exynos_drm_preclose,
.lastclose = exynos_drm_lastclose, .lastclose = exynos_drm_lastclose,
.postclose = exynos_drm_postclose, .postclose = exynos_drm_postclose,
.gem_free_object_unlocked = exynos_drm_gem_free_object, .gem_free_object_unlocked = exynos_drm_gem_free_object,
......
...@@ -32,53 +32,20 @@ static struct drm_display_mode *tpo_vid_get_config_mode(struct drm_device *dev) ...@@ -32,53 +32,20 @@ static struct drm_display_mode *tpo_vid_get_config_mode(struct drm_device *dev)
struct drm_display_mode *mode; struct drm_display_mode *mode;
struct drm_psb_private *dev_priv = dev->dev_private; struct drm_psb_private *dev_priv = dev->dev_private;
struct oaktrail_timing_info *ti = &dev_priv->gct_data.DTD; struct oaktrail_timing_info *ti = &dev_priv->gct_data.DTD;
bool use_gct = false;
mode = kzalloc(sizeof(*mode), GFP_KERNEL); mode = kzalloc(sizeof(*mode), GFP_KERNEL);
if (!mode) if (!mode)
return NULL; return NULL;
if (use_gct) { mode->hdisplay = 864;
mode->hdisplay = (ti->hactive_hi << 8) | ti->hactive_lo; mode->vdisplay = 480;
mode->vdisplay = (ti->vactive_hi << 8) | ti->vactive_lo; mode->hsync_start = 873;
mode->hsync_start = mode->hdisplay + mode->hsync_end = 876;
((ti->hsync_offset_hi << 8) | mode->htotal = 887;
ti->hsync_offset_lo); mode->vsync_start = 487;
mode->hsync_end = mode->hsync_start + mode->vsync_end = 490;
((ti->hsync_pulse_width_hi << 8) | mode->vtotal = 499;
ti->hsync_pulse_width_lo); mode->clock = 33264;
mode->htotal = mode->hdisplay + ((ti->hblank_hi << 8) |
ti->hblank_lo);
mode->vsync_start =
mode->vdisplay + ((ti->vsync_offset_hi << 8) |
ti->vsync_offset_lo);
mode->vsync_end =
mode->vsync_start + ((ti->vsync_pulse_width_hi << 8) |
ti->vsync_pulse_width_lo);
mode->vtotal = mode->vdisplay +
((ti->vblank_hi << 8) | ti->vblank_lo);
mode->clock = ti->pixel_clock * 10;
dev_dbg(dev->dev, "hdisplay is %d\n", mode->hdisplay);
dev_dbg(dev->dev, "vdisplay is %d\n", mode->vdisplay);
dev_dbg(dev->dev, "HSS is %d\n", mode->hsync_start);
dev_dbg(dev->dev, "HSE is %d\n", mode->hsync_end);
dev_dbg(dev->dev, "htotal is %d\n", mode->htotal);
dev_dbg(dev->dev, "VSS is %d\n", mode->vsync_start);
dev_dbg(dev->dev, "VSE is %d\n", mode->vsync_end);
dev_dbg(dev->dev, "vtotal is %d\n", mode->vtotal);
dev_dbg(dev->dev, "clock is %d\n", mode->clock);
} else {
mode->hdisplay = 864;
mode->vdisplay = 480;
mode->hsync_start = 873;
mode->hsync_end = 876;
mode->htotal = 887;
mode->vsync_start = 487;
mode->vsync_end = 490;
mode->vtotal = 499;
mode->clock = 33264;
}
drm_mode_set_name(mode); drm_mode_set_name(mode);
drm_mode_set_crtcinfo(mode, 0); drm_mode_set_crtcinfo(mode, 0);
......
...@@ -720,9 +720,7 @@ static u32 i915_get_vblank_counter(struct drm_device *dev, unsigned int pipe) ...@@ -720,9 +720,7 @@ static u32 i915_get_vblank_counter(struct drm_device *dev, unsigned int pipe)
struct drm_i915_private *dev_priv = to_i915(dev); struct drm_i915_private *dev_priv = to_i915(dev);
i915_reg_t high_frame, low_frame; i915_reg_t high_frame, low_frame;
u32 high1, high2, low, pixel, vbl_start, hsync_start, htotal; u32 high1, high2, low, pixel, vbl_start, hsync_start, htotal;
struct intel_crtc *intel_crtc = intel_get_crtc_for_pipe(dev_priv, const struct drm_display_mode *mode = &dev->vblank[pipe].hwmode;
pipe);
const struct drm_display_mode *mode = &intel_crtc->base.hwmode;
unsigned long irqflags; unsigned long irqflags;
htotal = mode->crtc_htotal; htotal = mode->crtc_htotal;
...@@ -779,13 +777,17 @@ static int __intel_get_crtc_scanline(struct intel_crtc *crtc) ...@@ -779,13 +777,17 @@ static int __intel_get_crtc_scanline(struct intel_crtc *crtc)
{ {
struct drm_device *dev = crtc->base.dev; struct drm_device *dev = crtc->base.dev;
struct drm_i915_private *dev_priv = to_i915(dev); struct drm_i915_private *dev_priv = to_i915(dev);
const struct drm_display_mode *mode = &crtc->base.hwmode; const struct drm_display_mode *mode;
struct drm_vblank_crtc *vblank;
enum pipe pipe = crtc->pipe; enum pipe pipe = crtc->pipe;
int position, vtotal; int position, vtotal;
if (!crtc->active) if (!crtc->active)
return -1; return -1;
vblank = &crtc->base.dev->vblank[drm_crtc_index(&crtc->base)];
mode = &vblank->hwmode;
vtotal = mode->crtc_vtotal; vtotal = mode->crtc_vtotal;
if (mode->flags & DRM_MODE_FLAG_INTERLACE) if (mode->flags & DRM_MODE_FLAG_INTERLACE)
vtotal /= 2; vtotal /= 2;
...@@ -827,10 +829,10 @@ static int __intel_get_crtc_scanline(struct intel_crtc *crtc) ...@@ -827,10 +829,10 @@ static int __intel_get_crtc_scanline(struct intel_crtc *crtc)
return (position + crtc->scanline_offset) % vtotal; return (position + crtc->scanline_offset) % vtotal;
} }
static int i915_get_crtc_scanoutpos(struct drm_device *dev, unsigned int pipe, static bool i915_get_crtc_scanoutpos(struct drm_device *dev, unsigned int pipe,
unsigned int flags, int *vpos, int *hpos, bool in_vblank_irq, int *vpos, int *hpos,
ktime_t *stime, ktime_t *etime, ktime_t *stime, ktime_t *etime,
const struct drm_display_mode *mode) const struct drm_display_mode *mode)
{ {
struct drm_i915_private *dev_priv = to_i915(dev); struct drm_i915_private *dev_priv = to_i915(dev);
struct intel_crtc *intel_crtc = intel_get_crtc_for_pipe(dev_priv, struct intel_crtc *intel_crtc = intel_get_crtc_for_pipe(dev_priv,
...@@ -838,13 +840,12 @@ static int i915_get_crtc_scanoutpos(struct drm_device *dev, unsigned int pipe, ...@@ -838,13 +840,12 @@ static int i915_get_crtc_scanoutpos(struct drm_device *dev, unsigned int pipe,
int position; int position;
int vbl_start, vbl_end, hsync_start, htotal, vtotal; int vbl_start, vbl_end, hsync_start, htotal, vtotal;
bool in_vbl = true; bool in_vbl = true;
int ret = 0;
unsigned long irqflags; unsigned long irqflags;
if (WARN_ON(!mode->crtc_clock)) { if (WARN_ON(!mode->crtc_clock)) {
DRM_DEBUG_DRIVER("trying to get scanoutpos for disabled " DRM_DEBUG_DRIVER("trying to get scanoutpos for disabled "
"pipe %c\n", pipe_name(pipe)); "pipe %c\n", pipe_name(pipe));
return 0; return false;
} }
htotal = mode->crtc_htotal; htotal = mode->crtc_htotal;
...@@ -859,8 +860,6 @@ static int i915_get_crtc_scanoutpos(struct drm_device *dev, unsigned int pipe, ...@@ -859,8 +860,6 @@ static int i915_get_crtc_scanoutpos(struct drm_device *dev, unsigned int pipe,
vtotal /= 2; vtotal /= 2;
} }
ret |= DRM_SCANOUTPOS_VALID | DRM_SCANOUTPOS_ACCURATE;
/* /*
* Lock uncore.lock, as we will do multiple timing critical raw * Lock uncore.lock, as we will do multiple timing critical raw
* register reads, potentially with preemption disabled, so the * register reads, potentially with preemption disabled, so the
...@@ -944,11 +943,7 @@ static int i915_get_crtc_scanoutpos(struct drm_device *dev, unsigned int pipe, ...@@ -944,11 +943,7 @@ static int i915_get_crtc_scanoutpos(struct drm_device *dev, unsigned int pipe,
*hpos = position - (*vpos * htotal); *hpos = position - (*vpos * htotal);
} }
/* In vblank? */ return true;
if (in_vbl)
ret |= DRM_SCANOUTPOS_IN_VBLANK;
return ret;
} }
int intel_get_crtc_scanline(struct intel_crtc *crtc) int intel_get_crtc_scanline(struct intel_crtc *crtc)
...@@ -964,37 +959,6 @@ int intel_get_crtc_scanline(struct intel_crtc *crtc) ...@@ -964,37 +959,6 @@ int intel_get_crtc_scanline(struct intel_crtc *crtc)
return position; return position;
} }
static int i915_get_vblank_timestamp(struct drm_device *dev, unsigned int pipe,
int *max_error,
struct timeval *vblank_time,
unsigned flags)
{
struct drm_i915_private *dev_priv = to_i915(dev);
struct intel_crtc *crtc;
if (pipe >= INTEL_INFO(dev_priv)->num_pipes) {
DRM_ERROR("Invalid crtc %u\n", pipe);
return -EINVAL;
}
/* Get drm_crtc to timestamp: */
crtc = intel_get_crtc_for_pipe(dev_priv, pipe);
if (crtc == NULL) {
DRM_ERROR("Invalid crtc %u\n", pipe);
return -EINVAL;
}
if (!crtc->base.hwmode.crtc_clock) {
DRM_DEBUG_KMS("crtc %u is disabled\n", pipe);
return -EBUSY;
}
/* Helper routine in DRM core does all the work: */
return drm_calc_vbltimestamp_from_scanoutpos(dev, pipe, max_error,
vblank_time, flags,
&crtc->base.hwmode);
}
static void ironlake_rps_change_irq_handler(struct drm_i915_private *dev_priv) static void ironlake_rps_change_irq_handler(struct drm_i915_private *dev_priv)
{ {
u32 busy_up, busy_down, max_avg, min_avg; u32 busy_up, busy_down, max_avg, min_avg;
...@@ -4294,7 +4258,7 @@ void intel_irq_init(struct drm_i915_private *dev_priv) ...@@ -4294,7 +4258,7 @@ void intel_irq_init(struct drm_i915_private *dev_priv)
dev_priv->hotplug.hpd_storm_threshold = HPD_STORM_DEFAULT_THRESHOLD; dev_priv->hotplug.hpd_storm_threshold = HPD_STORM_DEFAULT_THRESHOLD;
dev->driver->get_vblank_timestamp = i915_get_vblank_timestamp; dev->driver->get_vblank_timestamp = drm_calc_vbltimestamp_from_scanoutpos;
dev->driver->get_scanout_position = i915_get_crtc_scanoutpos; dev->driver->get_scanout_position = i915_get_crtc_scanoutpos;
if (IS_CHERRYVIEW(dev_priv)) { if (IS_CHERRYVIEW(dev_priv)) {
......
...@@ -11444,12 +11444,6 @@ intel_modeset_update_crtc_state(struct drm_atomic_state *state) ...@@ -11444,12 +11444,6 @@ intel_modeset_update_crtc_state(struct drm_atomic_state *state)
for_each_new_crtc_in_state(state, crtc, new_crtc_state, i) { for_each_new_crtc_in_state(state, crtc, new_crtc_state, i) {
to_intel_crtc(crtc)->config = to_intel_crtc_state(new_crtc_state); to_intel_crtc(crtc)->config = to_intel_crtc_state(new_crtc_state);
/* Update hwmode for vblank functions */
if (new_crtc_state->active)
crtc->hwmode = new_crtc_state->adjusted_mode;
else
crtc->hwmode.crtc_clock = 0;
/* /*
* Update legacy state to satisfy fbc code. This can * Update legacy state to satisfy fbc code. This can
* be removed when fbc uses the atomic state. * be removed when fbc uses the atomic state.
...@@ -15425,8 +15419,6 @@ static void intel_modeset_readout_hw_state(struct drm_device *dev) ...@@ -15425,8 +15419,6 @@ static void intel_modeset_readout_hw_state(struct drm_device *dev)
to_intel_crtc_state(crtc->base.state); to_intel_crtc_state(crtc->base.state);
int pixclk = 0; int pixclk = 0;
crtc->base.hwmode = crtc_state->base.adjusted_mode;
memset(&crtc->base.mode, 0, sizeof(crtc->base.mode)); memset(&crtc->base.mode, 0, sizeof(crtc->base.mode));
if (crtc_state->base.active) { if (crtc_state->base.active) {
intel_mode_from_pipe_config(&crtc->base.mode, crtc_state); intel_mode_from_pipe_config(&crtc->base.mode, crtc_state);
...@@ -15456,7 +15448,8 @@ static void intel_modeset_readout_hw_state(struct drm_device *dev) ...@@ -15456,7 +15448,8 @@ static void intel_modeset_readout_hw_state(struct drm_device *dev)
if (IS_BROADWELL(dev_priv) && crtc_state->ips_enabled) if (IS_BROADWELL(dev_priv) && crtc_state->ips_enabled)
pixclk = DIV_ROUND_UP(pixclk * 100, 95); pixclk = DIV_ROUND_UP(pixclk * 100, 95);
drm_calc_timestamping_constants(&crtc->base, &crtc->base.hwmode); drm_calc_timestamping_constants(&crtc->base,
&crtc_state->base.adjusted_mode);
update_scanline_offset(crtc); update_scanline_offset(crtc);
} }
......
...@@ -39,7 +39,7 @@ static bool intel_dp_mst_compute_config(struct intel_encoder *encoder, ...@@ -39,7 +39,7 @@ static bool intel_dp_mst_compute_config(struct intel_encoder *encoder,
struct intel_dp *intel_dp = &intel_dig_port->dp; struct intel_dp *intel_dp = &intel_dig_port->dp;
struct intel_connector *connector = struct intel_connector *connector =
to_intel_connector(conn_state->connector); to_intel_connector(conn_state->connector);
struct drm_atomic_state *state; struct drm_atomic_state *state = pipe_config->base.state;
int bpp; int bpp;
int lane_count, slots; int lane_count, slots;
const struct drm_display_mode *adjusted_mode = &pipe_config->base.adjusted_mode; const struct drm_display_mode *adjusted_mode = &pipe_config->base.adjusted_mode;
...@@ -57,20 +57,24 @@ static bool intel_dp_mst_compute_config(struct intel_encoder *encoder, ...@@ -57,20 +57,24 @@ static bool intel_dp_mst_compute_config(struct intel_encoder *encoder,
* seem to suggest we should do otherwise. * seem to suggest we should do otherwise.
*/ */
lane_count = drm_dp_max_lane_count(intel_dp->dpcd); lane_count = drm_dp_max_lane_count(intel_dp->dpcd);
pipe_config->lane_count = lane_count; pipe_config->lane_count = lane_count;
pipe_config->pipe_bpp = bpp; pipe_config->pipe_bpp = bpp;
pipe_config->port_clock = intel_dp_max_link_rate(intel_dp);
state = pipe_config->base.state; pipe_config->port_clock = intel_dp_max_link_rate(intel_dp);
if (drm_dp_mst_port_has_audio(&intel_dp->mst_mgr, connector->port)) if (drm_dp_mst_port_has_audio(&intel_dp->mst_mgr, connector->port))
pipe_config->has_audio = true; pipe_config->has_audio = true;
mst_pbn = drm_dp_calc_pbn_mode(adjusted_mode->crtc_clock, bpp);
mst_pbn = drm_dp_calc_pbn_mode(adjusted_mode->crtc_clock, bpp);
pipe_config->pbn = mst_pbn; pipe_config->pbn = mst_pbn;
slots = drm_dp_find_vcpi_slots(&intel_dp->mst_mgr, mst_pbn);
slots = drm_dp_atomic_find_vcpi_slots(state, &intel_dp->mst_mgr,
connector->port, mst_pbn);
if (slots < 0) {
DRM_DEBUG_KMS("failed finding vcpi slots:%d\n", slots);
return false;
}
intel_link_compute_m_n(bpp, lane_count, intel_link_compute_m_n(bpp, lane_count,
adjusted_mode->crtc_clock, adjusted_mode->crtc_clock,
...@@ -80,7 +84,38 @@ static bool intel_dp_mst_compute_config(struct intel_encoder *encoder, ...@@ -80,7 +84,38 @@ static bool intel_dp_mst_compute_config(struct intel_encoder *encoder,
pipe_config->dp_m_n.tu = slots; pipe_config->dp_m_n.tu = slots;
return true; return true;
}
static int intel_dp_mst_atomic_check(struct drm_connector *connector,
struct drm_connector_state *new_conn_state)
{
struct drm_atomic_state *state = new_conn_state->state;
struct drm_connector_state *old_conn_state;
struct drm_crtc *old_crtc;
struct drm_crtc_state *crtc_state;
int slots, ret = 0;
old_conn_state = drm_atomic_get_old_connector_state(state, connector);
old_crtc = old_conn_state->crtc;
if (!old_crtc)
return ret;
crtc_state = drm_atomic_get_new_crtc_state(state, old_crtc);
slots = to_intel_crtc_state(crtc_state)->dp_m_n.tu;
if (drm_atomic_crtc_needs_modeset(crtc_state) && slots > 0) {
struct drm_dp_mst_topology_mgr *mgr;
struct drm_encoder *old_encoder;
old_encoder = old_conn_state->best_encoder;
mgr = &enc_to_mst(old_encoder)->primary->dp.mst_mgr;
ret = drm_dp_atomic_release_vcpi_slots(state, mgr, slots);
if (ret)
DRM_DEBUG_KMS("failed releasing %d vcpi slots:%d\n", slots, ret);
else
to_intel_crtc_state(crtc_state)->dp_m_n.tu = 0;
}
return ret;
} }
static void intel_mst_disable_dp(struct intel_encoder *encoder, static void intel_mst_disable_dp(struct intel_encoder *encoder,
...@@ -387,6 +422,7 @@ static const struct drm_connector_helper_funcs intel_dp_mst_connector_helper_fun ...@@ -387,6 +422,7 @@ static const struct drm_connector_helper_funcs intel_dp_mst_connector_helper_fun
.mode_valid = intel_dp_mst_mode_valid, .mode_valid = intel_dp_mst_mode_valid,
.atomic_best_encoder = intel_mst_atomic_best_encoder, .atomic_best_encoder = intel_mst_atomic_best_encoder,
.best_encoder = intel_mst_best_encoder, .best_encoder = intel_mst_best_encoder,
.atomic_check = intel_dp_mst_atomic_check,
}; };
static void intel_dp_mst_encoder_destroy(struct drm_encoder *encoder) static void intel_dp_mst_encoder_destroy(struct drm_encoder *encoder)
......
...@@ -869,7 +869,6 @@ struct intel_hdmi { ...@@ -869,7 +869,6 @@ struct intel_hdmi {
bool has_audio; bool has_audio;
enum hdmi_force_audio force_audio; enum hdmi_force_audio force_audio;
bool rgb_quant_range_selectable; bool rgb_quant_range_selectable;
enum hdmi_picture_aspect aspect_ratio;
struct intel_connector *attached_connector; struct intel_connector *attached_connector;
void (*write_infoframe)(struct drm_encoder *encoder, void (*write_infoframe)(struct drm_encoder *encoder,
const struct intel_crtc_state *crtc_state, const struct intel_crtc_state *crtc_state,
......
...@@ -1403,7 +1403,7 @@ bool intel_hdmi_compute_config(struct intel_encoder *encoder, ...@@ -1403,7 +1403,7 @@ bool intel_hdmi_compute_config(struct intel_encoder *encoder,
} }
/* Set user selected PAR to incoming mode's member */ /* Set user selected PAR to incoming mode's member */
adjusted_mode->picture_aspect_ratio = intel_hdmi->aspect_ratio; adjusted_mode->picture_aspect_ratio = conn_state->picture_aspect_ratio;
pipe_config->lane_count = 4; pipe_config->lane_count = 4;
...@@ -1649,19 +1649,7 @@ intel_hdmi_set_property(struct drm_connector *connector, ...@@ -1649,19 +1649,7 @@ intel_hdmi_set_property(struct drm_connector *connector,
} }
if (property == connector->dev->mode_config.aspect_ratio_property) { if (property == connector->dev->mode_config.aspect_ratio_property) {
switch (val) { connector->state->picture_aspect_ratio = val;
case DRM_MODE_PICTURE_ASPECT_NONE:
intel_hdmi->aspect_ratio = HDMI_PICTURE_ASPECT_NONE;
break;
case DRM_MODE_PICTURE_ASPECT_4_3:
intel_hdmi->aspect_ratio = HDMI_PICTURE_ASPECT_4_3;
break;
case DRM_MODE_PICTURE_ASPECT_16_9:
intel_hdmi->aspect_ratio = HDMI_PICTURE_ASPECT_16_9;
break;
default:
return -EINVAL;
}
goto done; goto done;
} }
...@@ -1823,7 +1811,7 @@ intel_hdmi_add_properties(struct intel_hdmi *intel_hdmi, struct drm_connector *c ...@@ -1823,7 +1811,7 @@ intel_hdmi_add_properties(struct intel_hdmi *intel_hdmi, struct drm_connector *c
intel_attach_broadcast_rgb_property(connector); intel_attach_broadcast_rgb_property(connector);
intel_hdmi->color_range_auto = true; intel_hdmi->color_range_auto = true;
intel_attach_aspect_ratio_property(connector); intel_attach_aspect_ratio_property(connector);
intel_hdmi->aspect_ratio = HDMI_PICTURE_ASPECT_NONE; connector->state->picture_aspect_ratio = HDMI_PICTURE_ASPECT_NONE;
} }
/* /*
......
...@@ -106,11 +106,6 @@ struct intel_sdvo { ...@@ -106,11 +106,6 @@ struct intel_sdvo {
uint32_t color_range; uint32_t color_range;
bool color_range_auto; bool color_range_auto;
/**
* HDMI user specified aspect ratio
*/
enum hdmi_picture_aspect aspect_ratio;
/** /**
* This is set if we're going to treat the device as TV-out. * This is set if we're going to treat the device as TV-out.
* *
...@@ -1186,7 +1181,7 @@ static bool intel_sdvo_compute_config(struct intel_encoder *encoder, ...@@ -1186,7 +1181,7 @@ static bool intel_sdvo_compute_config(struct intel_encoder *encoder,
/* Set user selected PAR to incoming mode's member */ /* Set user selected PAR to incoming mode's member */
if (intel_sdvo->is_hdmi) if (intel_sdvo->is_hdmi)
adjusted_mode->picture_aspect_ratio = intel_sdvo->aspect_ratio; adjusted_mode->picture_aspect_ratio = conn_state->picture_aspect_ratio;
return true; return true;
} }
...@@ -2067,19 +2062,7 @@ intel_sdvo_set_property(struct drm_connector *connector, ...@@ -2067,19 +2062,7 @@ intel_sdvo_set_property(struct drm_connector *connector,
} }
if (property == connector->dev->mode_config.aspect_ratio_property) { if (property == connector->dev->mode_config.aspect_ratio_property) {
switch (val) { connector->state->picture_aspect_ratio = val;
case DRM_MODE_PICTURE_ASPECT_NONE:
intel_sdvo->aspect_ratio = HDMI_PICTURE_ASPECT_NONE;
break;
case DRM_MODE_PICTURE_ASPECT_4_3:
intel_sdvo->aspect_ratio = HDMI_PICTURE_ASPECT_4_3;
break;
case DRM_MODE_PICTURE_ASPECT_16_9:
intel_sdvo->aspect_ratio = HDMI_PICTURE_ASPECT_16_9;
break;
default:
return -EINVAL;
}
goto done; goto done;
} }
...@@ -2418,7 +2401,7 @@ intel_sdvo_add_hdmi_properties(struct intel_sdvo *intel_sdvo, ...@@ -2418,7 +2401,7 @@ intel_sdvo_add_hdmi_properties(struct intel_sdvo *intel_sdvo,
intel_sdvo->color_range_auto = true; intel_sdvo->color_range_auto = true;
} }
intel_attach_aspect_ratio_property(&connector->base.base); intel_attach_aspect_ratio_property(&connector->base.base);
intel_sdvo->aspect_ratio = HDMI_PICTURE_ASPECT_NONE; connector->base.base.state->picture_aspect_ratio = HDMI_PICTURE_ASPECT_NONE;
} }
static struct intel_sdvo_connector *intel_sdvo_connector_alloc(void) static struct intel_sdvo_connector *intel_sdvo_connector_alloc(void)
......
...@@ -527,31 +527,28 @@ static struct drm_encoder *get_encoder_from_crtc(struct drm_crtc *crtc) ...@@ -527,31 +527,28 @@ static struct drm_encoder *get_encoder_from_crtc(struct drm_crtc *crtc)
return NULL; return NULL;
} }
static int mdp5_get_scanoutpos(struct drm_device *dev, unsigned int pipe, static bool mdp5_get_scanoutpos(struct drm_device *dev, unsigned int pipe,
unsigned int flags, int *vpos, int *hpos, bool in_vblank_irq, int *vpos, int *hpos,
ktime_t *stime, ktime_t *etime, ktime_t *stime, ktime_t *etime,
const struct drm_display_mode *mode) const struct drm_display_mode *mode)
{ {
struct msm_drm_private *priv = dev->dev_private; struct msm_drm_private *priv = dev->dev_private;
struct drm_crtc *crtc; struct drm_crtc *crtc;
struct drm_encoder *encoder; struct drm_encoder *encoder;
int line, vsw, vbp, vactive_start, vactive_end, vfp_end; int line, vsw, vbp, vactive_start, vactive_end, vfp_end;
int ret = 0;
crtc = priv->crtcs[pipe]; crtc = priv->crtcs[pipe];
if (!crtc) { if (!crtc) {
DRM_ERROR("Invalid crtc %d\n", pipe); DRM_ERROR("Invalid crtc %d\n", pipe);
return 0; return false;
} }
encoder = get_encoder_from_crtc(crtc); encoder = get_encoder_from_crtc(crtc);
if (!encoder) { if (!encoder) {
DRM_ERROR("no encoder found for crtc %d\n", pipe); DRM_ERROR("no encoder found for crtc %d\n", pipe);
return 0; return false;
} }
ret |= DRM_SCANOUTPOS_VALID | DRM_SCANOUTPOS_ACCURATE;
vsw = mode->crtc_vsync_end - mode->crtc_vsync_start; vsw = mode->crtc_vsync_end - mode->crtc_vsync_start;
vbp = mode->crtc_vtotal - mode->crtc_vsync_end; vbp = mode->crtc_vtotal - mode->crtc_vsync_end;
...@@ -575,10 +572,8 @@ static int mdp5_get_scanoutpos(struct drm_device *dev, unsigned int pipe, ...@@ -575,10 +572,8 @@ static int mdp5_get_scanoutpos(struct drm_device *dev, unsigned int pipe,
if (line < vactive_start) { if (line < vactive_start) {
line -= vactive_start; line -= vactive_start;
ret |= DRM_SCANOUTPOS_IN_VBLANK;
} else if (line > vactive_end) { } else if (line > vactive_end) {
line = line - vfp_end - vactive_start; line = line - vfp_end - vactive_start;
ret |= DRM_SCANOUTPOS_IN_VBLANK;
} else { } else {
line -= vactive_start; line -= vactive_start;
} }
...@@ -589,31 +584,7 @@ static int mdp5_get_scanoutpos(struct drm_device *dev, unsigned int pipe, ...@@ -589,31 +584,7 @@ static int mdp5_get_scanoutpos(struct drm_device *dev, unsigned int pipe,
if (etime) if (etime)
*etime = ktime_get(); *etime = ktime_get();
return ret; return true;
}
static int mdp5_get_vblank_timestamp(struct drm_device *dev, unsigned int pipe,
int *max_error,
struct timeval *vblank_time,
unsigned flags)
{
struct msm_drm_private *priv = dev->dev_private;
struct drm_crtc *crtc;
if (pipe < 0 || pipe >= priv->num_crtcs) {
DRM_ERROR("Invalid crtc %d\n", pipe);
return -EINVAL;
}
crtc = priv->crtcs[pipe];
if (!crtc) {
DRM_ERROR("Invalid crtc %d\n", pipe);
return -EINVAL;
}
return drm_calc_vbltimestamp_from_scanoutpos(dev, pipe, max_error,
vblank_time, flags,
&crtc->mode);
} }
static u32 mdp5_get_vblank_counter(struct drm_device *dev, unsigned int pipe) static u32 mdp5_get_vblank_counter(struct drm_device *dev, unsigned int pipe)
...@@ -725,7 +696,7 @@ struct msm_kms *mdp5_kms_init(struct drm_device *dev) ...@@ -725,7 +696,7 @@ struct msm_kms *mdp5_kms_init(struct drm_device *dev)
dev->mode_config.max_width = 0xffff; dev->mode_config.max_width = 0xffff;
dev->mode_config.max_height = 0xffff; dev->mode_config.max_height = 0xffff;
dev->driver->get_vblank_timestamp = mdp5_get_vblank_timestamp; dev->driver->get_vblank_timestamp = drm_calc_vbltimestamp_from_scanoutpos;
dev->driver->get_scanout_position = mdp5_get_scanoutpos; dev->driver->get_scanout_position = mdp5_get_scanoutpos;
dev->driver->get_vblank_counter = mdp5_get_vblank_counter; dev->driver->get_vblank_counter = mdp5_get_vblank_counter;
dev->max_vblank_count = 0xffffffff; dev->max_vblank_count = 0xffffffff;
......
...@@ -98,7 +98,7 @@ calc(int blanks, int blanke, int total, int line) ...@@ -98,7 +98,7 @@ calc(int blanks, int blanke, int total, int line)
return line; return line;
} }
static int static bool
nouveau_display_scanoutpos_head(struct drm_crtc *crtc, int *vpos, int *hpos, nouveau_display_scanoutpos_head(struct drm_crtc *crtc, int *vpos, int *hpos,
ktime_t *stime, ktime_t *etime) ktime_t *stime, ktime_t *etime)
{ {
...@@ -111,16 +111,16 @@ nouveau_display_scanoutpos_head(struct drm_crtc *crtc, int *vpos, int *hpos, ...@@ -111,16 +111,16 @@ nouveau_display_scanoutpos_head(struct drm_crtc *crtc, int *vpos, int *hpos,
}; };
struct nouveau_display *disp = nouveau_display(crtc->dev); struct nouveau_display *disp = nouveau_display(crtc->dev);
struct drm_vblank_crtc *vblank = &crtc->dev->vblank[drm_crtc_index(crtc)]; struct drm_vblank_crtc *vblank = &crtc->dev->vblank[drm_crtc_index(crtc)];
int ret, retry = 20; int retry = 20;
bool ret = false;
do { do {
ret = nvif_mthd(&disp->disp, 0, &args, sizeof(args)); ret = nvif_mthd(&disp->disp, 0, &args, sizeof(args));
if (ret != 0) if (ret != 0)
return 0; return false;
if (args.scan.vline) { if (args.scan.vline) {
ret |= DRM_SCANOUTPOS_ACCURATE; ret = true;
ret |= DRM_SCANOUTPOS_VALID;
break; break;
} }
...@@ -133,14 +133,12 @@ nouveau_display_scanoutpos_head(struct drm_crtc *crtc, int *vpos, int *hpos, ...@@ -133,14 +133,12 @@ nouveau_display_scanoutpos_head(struct drm_crtc *crtc, int *vpos, int *hpos,
if (stime) *stime = ns_to_ktime(args.scan.time[0]); if (stime) *stime = ns_to_ktime(args.scan.time[0]);
if (etime) *etime = ns_to_ktime(args.scan.time[1]); if (etime) *etime = ns_to_ktime(args.scan.time[1]);
if (*vpos < 0)
ret |= DRM_SCANOUTPOS_IN_VBLANK;
return ret; return ret;
} }
int bool
nouveau_display_scanoutpos(struct drm_device *dev, unsigned int pipe, nouveau_display_scanoutpos(struct drm_device *dev, unsigned int pipe,
unsigned int flags, int *vpos, int *hpos, bool in_vblank_irq, int *vpos, int *hpos,
ktime_t *stime, ktime_t *etime, ktime_t *stime, ktime_t *etime,
const struct drm_display_mode *mode) const struct drm_display_mode *mode)
{ {
...@@ -153,28 +151,7 @@ nouveau_display_scanoutpos(struct drm_device *dev, unsigned int pipe, ...@@ -153,28 +151,7 @@ nouveau_display_scanoutpos(struct drm_device *dev, unsigned int pipe,
} }
} }
return 0; return false;
}
int
nouveau_display_vblstamp(struct drm_device *dev, unsigned int pipe,
int *max_error, struct timeval *time, unsigned flags)
{
struct drm_crtc *crtc;
list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) {
if (nouveau_crtc(crtc)->index == pipe) {
struct drm_display_mode *mode;
if (drm_drv_uses_atomic_modeset(dev))
mode = &crtc->state->adjusted_mode;
else
mode = &crtc->hwmode;
return drm_calc_vbltimestamp_from_scanoutpos(dev,
pipe, max_error, time, flags, mode);
}
}
return -EINVAL;
} }
static void static void
......
...@@ -68,11 +68,9 @@ int nouveau_display_suspend(struct drm_device *dev, bool runtime); ...@@ -68,11 +68,9 @@ int nouveau_display_suspend(struct drm_device *dev, bool runtime);
void nouveau_display_resume(struct drm_device *dev, bool runtime); void nouveau_display_resume(struct drm_device *dev, bool runtime);
int nouveau_display_vblank_enable(struct drm_device *, unsigned int); int nouveau_display_vblank_enable(struct drm_device *, unsigned int);
void nouveau_display_vblank_disable(struct drm_device *, unsigned int); void nouveau_display_vblank_disable(struct drm_device *, unsigned int);
int nouveau_display_scanoutpos(struct drm_device *, unsigned int, bool nouveau_display_scanoutpos(struct drm_device *, unsigned int,
unsigned int, int *, int *, ktime_t *, bool, int *, int *, ktime_t *,
ktime_t *, const struct drm_display_mode *); ktime_t *, const struct drm_display_mode *);
int nouveau_display_vblstamp(struct drm_device *, unsigned int, int *,
struct timeval *, unsigned);
int nouveau_crtc_page_flip(struct drm_crtc *crtc, struct drm_framebuffer *fb, int nouveau_crtc_page_flip(struct drm_crtc *crtc, struct drm_framebuffer *fb,
struct drm_pending_vblank_event *event, struct drm_pending_vblank_event *event,
......
...@@ -881,7 +881,7 @@ nouveau_drm_open(struct drm_device *dev, struct drm_file *fpriv) ...@@ -881,7 +881,7 @@ nouveau_drm_open(struct drm_device *dev, struct drm_file *fpriv)
} }
static void static void
nouveau_drm_preclose(struct drm_device *dev, struct drm_file *fpriv) nouveau_drm_postclose(struct drm_device *dev, struct drm_file *fpriv)
{ {
struct nouveau_cli *cli = nouveau_cli(fpriv); struct nouveau_cli *cli = nouveau_cli(fpriv);
struct nouveau_drm *drm = nouveau_drm(dev); struct nouveau_drm *drm = nouveau_drm(dev);
...@@ -897,12 +897,6 @@ nouveau_drm_preclose(struct drm_device *dev, struct drm_file *fpriv) ...@@ -897,12 +897,6 @@ nouveau_drm_preclose(struct drm_device *dev, struct drm_file *fpriv)
list_del(&cli->head); list_del(&cli->head);
mutex_unlock(&drm->client.mutex); mutex_unlock(&drm->client.mutex);
}
static void
nouveau_drm_postclose(struct drm_device *dev, struct drm_file *fpriv)
{
struct nouveau_cli *cli = nouveau_cli(fpriv);
nouveau_cli_fini(cli); nouveau_cli_fini(cli);
kfree(cli); kfree(cli);
pm_runtime_mark_last_busy(dev->dev); pm_runtime_mark_last_busy(dev->dev);
...@@ -974,7 +968,6 @@ driver_stub = { ...@@ -974,7 +968,6 @@ driver_stub = {
.load = nouveau_drm_load, .load = nouveau_drm_load,
.unload = nouveau_drm_unload, .unload = nouveau_drm_unload,
.open = nouveau_drm_open, .open = nouveau_drm_open,
.preclose = nouveau_drm_preclose,
.postclose = nouveau_drm_postclose, .postclose = nouveau_drm_postclose,
.lastclose = nouveau_vga_lastclose, .lastclose = nouveau_vga_lastclose,
...@@ -985,7 +978,7 @@ driver_stub = { ...@@ -985,7 +978,7 @@ driver_stub = {
.enable_vblank = nouveau_display_vblank_enable, .enable_vblank = nouveau_display_vblank_enable,
.disable_vblank = nouveau_display_vblank_disable, .disable_vblank = nouveau_display_vblank_disable,
.get_scanout_position = nouveau_display_scanoutpos, .get_scanout_position = nouveau_display_scanoutpos,
.get_vblank_timestamp = nouveau_display_vblstamp, .get_vblank_timestamp = drm_calc_vbltimestamp_from_scanoutpos,
.ioctls = nouveau_ioctls, .ioctls = nouveau_ioctls,
.num_ioctls = ARRAY_SIZE(nouveau_ioctls), .num_ioctls = ARRAY_SIZE(nouveau_ioctls),
......
config DRM_PL111
tristate "DRM Support for PL111 CLCD Controller"
depends on DRM
depends on ARM || ARM64 || COMPILE_TEST
select DRM_KMS_HELPER
select DRM_KMS_CMA_HELPER
select DRM_GEM_CMA_HELPER
select VT_HW_CONSOLE_BINDING if FRAMEBUFFER_CONSOLE
help
Choose this option for DRM support for the PL111 CLCD controller.
If M is selected the module will be called pl111_drm.
pl111_drm-y += pl111_connector.o \
pl111_display.o \
pl111_drv.o
obj-$(CONFIG_DRM_PL111) += pl111_drm.o
/*
* (C) COPYRIGHT 2012-2013 ARM Limited. All rights reserved.
*
* Parts of this file were based on sources as follows:
*
* Copyright (c) 2006-2008 Intel Corporation
* Copyright (c) 2007 Dave Airlie <airlied@linux.ie>
* Copyright (C) 2011 Texas Instruments
*
* This program is free software and is provided to you under the terms of the
* GNU General Public License version 2 as published by the Free Software
* Foundation, and any use by you of this program is subject to the terms of
* such GNU licence.
*
*/
/**
* pl111_drm_connector.c
* Implementation of the connector functions for PL111 DRM
*/
#include <linux/amba/clcd-regs.h>
#include <linux/version.h>
#include <linux/shmem_fs.h>
#include <linux/dma-buf.h>
#include <drm/drmP.h>
#include <drm/drm_atomic_helper.h>
#include <drm/drm_crtc_helper.h>
#include <drm/drm_of.h>
#include <drm/drm_panel.h>
#include "pl111_drm.h"
static void pl111_connector_destroy(struct drm_connector *connector)
{
struct pl111_drm_connector *pl111_connector =
to_pl111_connector(connector);
if (pl111_connector->panel)
drm_panel_detach(pl111_connector->panel);
drm_connector_unregister(connector);
drm_connector_cleanup(connector);
}
static enum drm_connector_status pl111_connector_detect(struct drm_connector
*connector, bool force)
{
struct pl111_drm_connector *pl111_connector =
to_pl111_connector(connector);
return (pl111_connector->panel ?
connector_status_connected :
connector_status_disconnected);
}
static int pl111_connector_helper_get_modes(struct drm_connector *connector)
{
struct pl111_drm_connector *pl111_connector =
to_pl111_connector(connector);
if (!pl111_connector->panel)
return 0;
return drm_panel_get_modes(pl111_connector->panel);
}
const struct drm_connector_funcs connector_funcs = {
.fill_modes = drm_helper_probe_single_connector_modes,
.destroy = pl111_connector_destroy,
.detect = pl111_connector_detect,
.dpms = drm_atomic_helper_connector_dpms,
.reset = drm_atomic_helper_connector_reset,
.atomic_duplicate_state = drm_atomic_helper_connector_duplicate_state,
.atomic_destroy_state = drm_atomic_helper_connector_destroy_state,
};
const struct drm_connector_helper_funcs connector_helper_funcs = {
.get_modes = pl111_connector_helper_get_modes,
};
/* Walks the OF graph to find the panel node and then asks DRM to look
* up the panel.
*/
static struct drm_panel *pl111_get_panel(struct device *dev)
{
struct device_node *endpoint, *panel_node;
struct device_node *np = dev->of_node;
struct drm_panel *panel;
endpoint = of_graph_get_next_endpoint(np, NULL);
if (!endpoint) {
dev_err(dev, "no endpoint to fetch panel\n");
return NULL;
}
/* don't proceed if we have an endpoint but no panel_node tied to it */
panel_node = of_graph_get_remote_port_parent(endpoint);
of_node_put(endpoint);
if (!panel_node) {
dev_err(dev, "no valid panel node\n");
return NULL;
}
panel = of_drm_find_panel(panel_node);
of_node_put(panel_node);
return panel;
}
int pl111_connector_init(struct drm_device *dev)
{
struct pl111_drm_dev_private *priv = dev->dev_private;
struct pl111_drm_connector *pl111_connector = &priv->connector;
struct drm_connector *connector = &pl111_connector->connector;
drm_connector_init(dev, connector, &connector_funcs,
DRM_MODE_CONNECTOR_DPI);
drm_connector_helper_add(connector, &connector_helper_funcs);
pl111_connector->panel = pl111_get_panel(dev->dev);
if (pl111_connector->panel)
drm_panel_attach(pl111_connector->panel, connector);
return 0;
}
/*
* (C) COPYRIGHT 2012-2013 ARM Limited. All rights reserved.
*
* Parts of this file were based on sources as follows:
*
* Copyright (c) 2006-2008 Intel Corporation
* Copyright (c) 2007 Dave Airlie <airlied@linux.ie>
* Copyright (C) 2011 Texas Instruments
*
* This program is free software and is provided to you under the terms of the
* GNU General Public License version 2 as published by the Free Software
* Foundation, and any use by you of this program is subject to the terms of
* such GNU licence.
*
*/
#include <linux/amba/clcd-regs.h>
#include <linux/clk.h>
#include <linux/version.h>
#include <linux/dma-buf.h>
#include <linux/of_graph.h>
#include <drm/drmP.h>
#include <drm/drm_panel.h>
#include <drm/drm_gem_cma_helper.h>
#include <drm/drm_fb_cma_helper.h>
#include "pl111_drm.h"
irqreturn_t pl111_irq(int irq, void *data)
{
struct pl111_drm_dev_private *priv = data;
u32 irq_stat;
irqreturn_t status = IRQ_NONE;
irq_stat = readl(priv->regs + CLCD_PL111_MIS);
if (!irq_stat)
return IRQ_NONE;
if (irq_stat & CLCD_IRQ_NEXTBASE_UPDATE) {
drm_crtc_handle_vblank(&priv->pipe.crtc);
status = IRQ_HANDLED;
}
/* Clear the interrupt once done */
writel(irq_stat, priv->regs + CLCD_PL111_ICR);
return status;
}
static u32 pl111_get_fb_offset(struct drm_plane_state *pstate)
{
struct drm_framebuffer *fb = pstate->fb;
struct drm_gem_cma_object *obj = drm_fb_cma_get_gem_obj(fb, 0);
return (obj->paddr +
fb->offsets[0] +
fb->format->cpp[0] * pstate->src_x +
fb->pitches[0] * pstate->src_y);
}
static int pl111_display_check(struct drm_simple_display_pipe *pipe,
struct drm_plane_state *pstate,
struct drm_crtc_state *cstate)
{
const struct drm_display_mode *mode = &cstate->mode;
struct drm_framebuffer *old_fb = pipe->plane.state->fb;
struct drm_framebuffer *fb = pstate->fb;
if (mode->hdisplay % 16)
return -EINVAL;
if (fb) {
u32 offset = pl111_get_fb_offset(pstate);
/* FB base address must be dword aligned. */
if (offset & 3)
return -EINVAL;
/* There's no pitch register -- the mode's hdisplay
* controls it.
*/
if (fb->pitches[0] != mode->hdisplay * fb->format->cpp[0])
return -EINVAL;
/* We can't change the FB format in a flicker-free
* manner (and only update it during CRTC enable).
*/
if (old_fb && old_fb->format != fb->format)
cstate->mode_changed = true;
}
return 0;
}
static void pl111_display_enable(struct drm_simple_display_pipe *pipe,
struct drm_crtc_state *cstate)
{
struct drm_crtc *crtc = &pipe->crtc;
struct drm_plane *plane = &pipe->plane;
struct drm_device *drm = crtc->dev;
struct pl111_drm_dev_private *priv = drm->dev_private;
const struct drm_display_mode *mode = &cstate->mode;
struct drm_framebuffer *fb = plane->state->fb;
struct drm_connector *connector = &priv->connector.connector;
u32 cntl;
u32 ppl, hsw, hfp, hbp;
u32 lpp, vsw, vfp, vbp;
u32 cpl;
int ret;
ret = clk_set_rate(priv->clk, mode->clock * 1000);
if (ret) {
dev_err(drm->dev,
"Failed to set pixel clock rate to %d: %d\n",
mode->clock * 1000, ret);
}
clk_prepare_enable(priv->clk);
ppl = (mode->hdisplay / 16) - 1;
hsw = mode->hsync_end - mode->hsync_start - 1;
hfp = mode->hsync_start - mode->hdisplay - 1;
hbp = mode->htotal - mode->hsync_end - 1;
lpp = mode->vdisplay - 1;
vsw = mode->vsync_end - mode->vsync_start - 1;
vfp = mode->vsync_start - mode->vdisplay;
vbp = mode->vtotal - mode->vsync_end;
cpl = mode->hdisplay - 1;
writel((ppl << 2) |
(hsw << 8) |
(hfp << 16) |
(hbp << 24),
priv->regs + CLCD_TIM0);
writel(lpp |
(vsw << 10) |
(vfp << 16) |
(vbp << 24),
priv->regs + CLCD_TIM1);
/* XXX: We currently always use CLCDCLK with no divisor. We
* could probably reduce power consumption by using HCLK
* (apb_pclk) with a divisor when it gets us near our target
* pixel clock.
*/
writel(((mode->flags & DRM_MODE_FLAG_NHSYNC) ? TIM2_IHS : 0) |
((mode->flags & DRM_MODE_FLAG_NVSYNC) ? TIM2_IVS : 0) |
((connector->display_info.bus_flags &
DRM_BUS_FLAG_DE_LOW) ? TIM2_IOE : 0) |
((connector->display_info.bus_flags &
DRM_BUS_FLAG_PIXDATA_NEGEDGE) ? TIM2_IPC : 0) |
TIM2_BCD |
(cpl << 16),
priv->regs + CLCD_TIM2);
writel(0, priv->regs + CLCD_TIM3);
drm_panel_prepare(priv->connector.panel);
/* Enable and Power Up */
cntl = CNTL_LCDEN | CNTL_LCDTFT | CNTL_LCDPWR | CNTL_LCDVCOMP(1);
/* Note that the the hardware's format reader takes 'r' from
* the low bit, while DRM formats list channels from high bit
* to low bit as you read left to right.
*/
switch (fb->format->format) {
case DRM_FORMAT_ABGR8888:
case DRM_FORMAT_XBGR8888:
cntl |= CNTL_LCDBPP24;
break;
case DRM_FORMAT_ARGB8888:
case DRM_FORMAT_XRGB8888:
cntl |= CNTL_LCDBPP24 | CNTL_BGR;
break;
case DRM_FORMAT_BGR565:
cntl |= CNTL_LCDBPP16_565;
break;
case DRM_FORMAT_RGB565:
cntl |= CNTL_LCDBPP16_565 | CNTL_BGR;
break;
case DRM_FORMAT_ABGR1555:
case DRM_FORMAT_XBGR1555:
cntl |= CNTL_LCDBPP16;
break;
case DRM_FORMAT_ARGB1555:
case DRM_FORMAT_XRGB1555:
cntl |= CNTL_LCDBPP16 | CNTL_BGR;
break;
case DRM_FORMAT_ABGR4444:
case DRM_FORMAT_XBGR4444:
cntl |= CNTL_LCDBPP16_444;
break;
case DRM_FORMAT_ARGB4444:
case DRM_FORMAT_XRGB4444:
cntl |= CNTL_LCDBPP16_444 | CNTL_BGR;
break;
default:
WARN_ONCE(true, "Unknown FB format 0x%08x\n",
fb->format->format);
break;
}
writel(cntl, priv->regs + CLCD_PL111_CNTL);
drm_panel_enable(priv->connector.panel);
drm_crtc_vblank_on(crtc);
}
void pl111_display_disable(struct drm_simple_display_pipe *pipe)
{
struct drm_crtc *crtc = &pipe->crtc;
struct drm_device *drm = crtc->dev;
struct pl111_drm_dev_private *priv = drm->dev_private;
drm_crtc_vblank_off(crtc);
drm_panel_disable(priv->connector.panel);
/* Disable and Power Down */
writel(0, priv->regs + CLCD_PL111_CNTL);
drm_panel_unprepare(priv->connector.panel);
clk_disable_unprepare(priv->clk);
}
static void pl111_display_update(struct drm_simple_display_pipe *pipe,
struct drm_plane_state *old_pstate)
{
struct drm_crtc *crtc = &pipe->crtc;
struct drm_device *drm = crtc->dev;
struct pl111_drm_dev_private *priv = drm->dev_private;
struct drm_pending_vblank_event *event = crtc->state->event;
struct drm_plane *plane = &pipe->plane;
struct drm_plane_state *pstate = plane->state;
struct drm_framebuffer *fb = pstate->fb;
if (fb) {
u32 addr = pl111_get_fb_offset(pstate);
writel(addr, priv->regs + CLCD_UBAS);
}
if (event) {
crtc->state->event = NULL;
spin_lock_irq(&crtc->dev->event_lock);
if (crtc->state->active && drm_crtc_vblank_get(crtc) == 0)
drm_crtc_arm_vblank_event(crtc, event);
else
drm_crtc_send_vblank_event(crtc, event);
spin_unlock_irq(&crtc->dev->event_lock);
}
}
int pl111_enable_vblank(struct drm_device *drm, unsigned int crtc)
{
struct pl111_drm_dev_private *priv = drm->dev_private;
writel(CLCD_IRQ_NEXTBASE_UPDATE, priv->regs + CLCD_PL111_IENB);
return 0;
}
void pl111_disable_vblank(struct drm_device *drm, unsigned int crtc)
{
struct pl111_drm_dev_private *priv = drm->dev_private;
writel(0, priv->regs + CLCD_PL111_IENB);
}
static int pl111_display_prepare_fb(struct drm_simple_display_pipe *pipe,
struct drm_plane_state *plane_state)
{
return drm_fb_cma_prepare_fb(&pipe->plane, plane_state);
}
const struct drm_simple_display_pipe_funcs pl111_display_funcs = {
.check = pl111_display_check,
.enable = pl111_display_enable,
.disable = pl111_display_disable,
.update = pl111_display_update,
.prepare_fb = pl111_display_prepare_fb,
};
int pl111_display_init(struct drm_device *drm)
{
struct pl111_drm_dev_private *priv = drm->dev_private;
struct device *dev = drm->dev;
struct device_node *endpoint;
u32 tft_r0b0g0[3];
int ret;
static const u32 formats[] = {
DRM_FORMAT_ABGR8888,
DRM_FORMAT_XBGR8888,
DRM_FORMAT_ARGB8888,
DRM_FORMAT_XRGB8888,
DRM_FORMAT_BGR565,
DRM_FORMAT_RGB565,
DRM_FORMAT_ABGR1555,
DRM_FORMAT_XBGR1555,
DRM_FORMAT_ARGB1555,
DRM_FORMAT_XRGB1555,
DRM_FORMAT_ABGR4444,
DRM_FORMAT_XBGR4444,
DRM_FORMAT_ARGB4444,
DRM_FORMAT_XRGB4444,
};
endpoint = of_graph_get_next_endpoint(dev->of_node, NULL);
if (!endpoint)
return -ENODEV;
if (of_property_read_u32_array(endpoint,
"arm,pl11x,tft-r0g0b0-pads",
tft_r0b0g0,
ARRAY_SIZE(tft_r0b0g0)) != 0) {
dev_err(dev, "arm,pl11x,tft-r0g0b0-pads should be 3 ints\n");
of_node_put(endpoint);
return -ENOENT;
}
of_node_put(endpoint);
if (tft_r0b0g0[0] != 0 ||
tft_r0b0g0[1] != 8 ||
tft_r0b0g0[2] != 16) {
dev_err(dev, "arm,pl11x,tft-r0g0b0-pads != [0,8,16] not yet supported\n");
return -EINVAL;
}
ret = drm_simple_display_pipe_init(drm, &priv->pipe,
&pl111_display_funcs,
formats, ARRAY_SIZE(formats),
&priv->connector.connector);
if (ret)
return ret;
return 0;
}
/*
*
* (C) COPYRIGHT 2012-2013 ARM Limited. All rights reserved.
*
*
* Parts of this file were based on sources as follows:
*
* Copyright (c) 2006-2008 Intel Corporation
* Copyright (c) 2007 Dave Airlie <airlied@linux.ie>
* Copyright (C) 2011 Texas Instruments
*
* This program is free software and is provided to you under the terms of the
* GNU General Public License version 2 as published by the Free Software
* Foundation, and any use by you of this program is subject to the terms of
* such GNU licence.
*
*/
#ifndef _PL111_DRM_H_
#define _PL111_DRM_H_
#include <drm/drm_gem.h>
#include <drm/drm_simple_kms_helper.h>
#define CLCD_IRQ_NEXTBASE_UPDATE BIT(2)
struct pl111_drm_connector {
struct drm_connector connector;
struct drm_panel *panel;
};
struct pl111_drm_dev_private {
struct drm_device *drm;
struct pl111_drm_connector connector;
struct drm_simple_display_pipe pipe;
struct drm_fbdev_cma *fbdev;
void *regs;
struct clk *clk;
};
#define to_pl111_connector(x) \
container_of(x, struct pl111_drm_connector, connector)
int pl111_display_init(struct drm_device *dev);
int pl111_enable_vblank(struct drm_device *drm, unsigned int crtc);
void pl111_disable_vblank(struct drm_device *drm, unsigned int crtc);
irqreturn_t pl111_irq(int irq, void *data);
int pl111_connector_init(struct drm_device *dev);
int pl111_encoder_init(struct drm_device *dev);
int pl111_dumb_create(struct drm_file *file_priv,
struct drm_device *dev,
struct drm_mode_create_dumb *args);
#endif /* _PL111_DRM_H_ */
/*
* (C) COPYRIGHT 2012-2013 ARM Limited. All rights reserved.
*
* Parts of this file were based on sources as follows:
*
* Copyright (c) 2006-2008 Intel Corporation
* Copyright (c) 2007 Dave Airlie <airlied@linux.ie>
* Copyright (C) 2011 Texas Instruments
*
* This program is free software and is provided to you under the terms of the
* GNU General Public License version 2 as published by the Free Software
* Foundation, and any use by you of this program is subject to the terms of
* such GNU licence.
*
*/
/**
* DOC: ARM PrimeCell PL111 CLCD Driver
*
* The PL111 is a simple LCD controller that can support TFT and STN
* displays. This driver exposes a standard KMS interface for them.
*
* This driver uses the same Device Tree binding as the fbdev CLCD
* driver. While the fbdev driver supports panels that may be
* connected to the CLCD internally to the CLCD driver, in DRM the
* panels get split out to drivers/gpu/drm/panels/. This means that,
* in converting from using fbdev to using DRM, you also need to write
* a panel driver (which may be as simple as an entry in
* panel-simple.c).
*
* The driver currently doesn't expose the cursor. The DRM API for
* cursors requires support for 64x64 ARGB8888 cursor images, while
* the hardware can only support 64x64 monochrome with masking
* cursors. While one could imagine trying to hack something together
* to look at the ARGB8888 and program reasonable in monochrome, we
* just don't expose the cursor at all instead, and leave cursor
* support to the X11 software cursor layer.
*
* TODO:
*
* - Fix race between setting plane base address and getting IRQ for
* vsync firing the pageflip completion.
*
* - Expose the correct set of formats we can support based on the
* "arm,pl11x,tft-r0g0b0-pads" DT property.
*
* - Use the "max-memory-bandwidth" DT property to filter the
* supported formats.
*
* - Read back hardware state at boot to skip reprogramming the
* hardware when doing a no-op modeset.
*
* - Use the internal clock divisor to reduce power consumption by
* using HCLK (apb_pclk) when appropriate.
*/
#include <linux/amba/bus.h>
#include <linux/amba/clcd-regs.h>
#include <linux/version.h>
#include <linux/shmem_fs.h>
#include <linux/dma-buf.h>
#include <linux/module.h>
#include <linux/slab.h>
#include <drm/drmP.h>
#include <drm/drm_atomic_helper.h>
#include <drm/drm_crtc_helper.h>
#include <drm/drm_gem_cma_helper.h>
#include <drm/drm_fb_cma_helper.h>
#include "pl111_drm.h"
#define DRIVER_DESC "DRM module for PL111"
struct drm_mode_config_funcs mode_config_funcs = {
.fb_create = drm_fb_cma_create,
.atomic_check = drm_atomic_helper_check,
.atomic_commit = drm_atomic_helper_commit,
};
static int pl111_modeset_init(struct drm_device *dev)
{
struct drm_mode_config *mode_config;
struct pl111_drm_dev_private *priv = dev->dev_private;
int ret = 0;
drm_mode_config_init(dev);
mode_config = &dev->mode_config;
mode_config->funcs = &mode_config_funcs;
mode_config->min_width = 1;
mode_config->max_width = 1024;
mode_config->min_height = 1;
mode_config->max_height = 768;
ret = pl111_connector_init(dev);
if (ret) {
dev_err(dev->dev, "Failed to create pl111_drm_connector\n");
goto out_config;
}
/* Don't actually attach if we didn't find a drm_panel
* attached to us. This will allow a kernel to include both
* the fbdev pl111 driver and this one, and choose between
* them based on which subsystem has support for the panel.
*/
if (!priv->connector.panel) {
dev_info(dev->dev,
"Disabling due to lack of DRM panel device.\n");
ret = -ENODEV;
goto out_config;
}
ret = pl111_display_init(dev);
if (ret != 0) {
dev_err(dev->dev, "Failed to init display\n");
goto out_config;
}
ret = drm_vblank_init(dev, 1);
if (ret != 0) {
dev_err(dev->dev, "Failed to init vblank\n");
goto out_config;
}
drm_mode_config_reset(dev);
priv->fbdev = drm_fbdev_cma_init(dev, 32,
dev->mode_config.num_connector);
drm_kms_helper_poll_init(dev);
goto finish;
out_config:
drm_mode_config_cleanup(dev);
finish:
return ret;
}
DEFINE_DRM_GEM_CMA_FOPS(drm_fops);
static void pl111_lastclose(struct drm_device *dev)
{
struct pl111_drm_dev_private *priv = dev->dev_private;
drm_fbdev_cma_restore_mode(priv->fbdev);
}
static struct drm_driver pl111_drm_driver = {
.driver_features =
DRIVER_MODESET | DRIVER_GEM | DRIVER_PRIME | DRIVER_ATOMIC,
.lastclose = pl111_lastclose,
.ioctls = NULL,
.fops = &drm_fops,
.name = "pl111",
.desc = DRIVER_DESC,
.date = "20170317",
.major = 1,
.minor = 0,
.patchlevel = 0,
.dumb_create = drm_gem_cma_dumb_create,
.dumb_destroy = drm_gem_dumb_destroy,
.dumb_map_offset = drm_gem_cma_dumb_map_offset,
.gem_free_object = drm_gem_cma_free_object,
.gem_vm_ops = &drm_gem_cma_vm_ops,
.enable_vblank = pl111_enable_vblank,
.disable_vblank = pl111_disable_vblank,
.prime_handle_to_fd = drm_gem_prime_handle_to_fd,
.prime_fd_to_handle = drm_gem_prime_fd_to_handle,
.gem_prime_import = drm_gem_prime_import,
.gem_prime_import_sg_table = drm_gem_cma_prime_import_sg_table,
.gem_prime_export = drm_gem_prime_export,
.gem_prime_get_sg_table = drm_gem_cma_prime_get_sg_table,
};
#ifdef CONFIG_ARM_AMBA
static int pl111_amba_probe(struct amba_device *amba_dev,
const struct amba_id *id)
{
struct device *dev = &amba_dev->dev;
struct pl111_drm_dev_private *priv;
struct drm_device *drm;
int ret;
priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
if (!priv)
return -ENOMEM;
drm = drm_dev_alloc(&pl111_drm_driver, dev);
if (IS_ERR(drm))
return PTR_ERR(drm);
amba_set_drvdata(amba_dev, drm);
priv->drm = drm;
drm->dev_private = priv;
priv->clk = devm_clk_get(dev, "clcdclk");
if (IS_ERR(priv->clk)) {
dev_err(dev, "CLCD: unable to get clk.\n");
ret = PTR_ERR(priv->clk);
goto dev_unref;
}
priv->regs = devm_ioremap_resource(dev, &amba_dev->res);
if (!priv->regs) {
dev_err(dev, "%s failed mmio\n", __func__);
return -EINVAL;
}
/* turn off interrupts before requesting the irq */
writel(0, priv->regs + CLCD_PL111_IENB);
ret = devm_request_irq(dev, amba_dev->irq[0], pl111_irq, 0,
"pl111", priv);
if (ret != 0) {
dev_err(dev, "%s failed irq %d\n", __func__, ret);
return ret;
}
ret = pl111_modeset_init(drm);
if (ret != 0)
goto dev_unref;
ret = drm_dev_register(drm, 0);
if (ret < 0)
goto dev_unref;
return 0;
dev_unref:
drm_dev_unref(drm);
return ret;
}
static int pl111_amba_remove(struct amba_device *amba_dev)
{
struct drm_device *drm = amba_get_drvdata(amba_dev);
struct pl111_drm_dev_private *priv = drm->dev_private;
drm_dev_unregister(drm);
if (priv->fbdev)
drm_fbdev_cma_fini(priv->fbdev);
drm_mode_config_cleanup(drm);
drm_dev_unref(drm);
return 0;
}
static struct amba_id pl111_id_table[] = {
{
.id = 0x00041111,
.mask = 0x000fffff,
},
{0, 0},
};
static struct amba_driver pl111_amba_driver = {
.drv = {
.name = "drm-clcd-pl111",
},
.probe = pl111_amba_probe,
.remove = pl111_amba_remove,
.id_table = pl111_id_table,
};
module_amba_driver(pl111_amba_driver);
#endif /* CONFIG_ARM_AMBA */
MODULE_DESCRIPTION(DRIVER_DESC);
MODULE_AUTHOR("ARM Ltd.");
MODULE_LICENSE("GPL");
...@@ -115,10 +115,6 @@ int radeon_resume_kms(struct drm_device *dev, bool resume, bool fbcon); ...@@ -115,10 +115,6 @@ int radeon_resume_kms(struct drm_device *dev, bool resume, bool fbcon);
u32 radeon_get_vblank_counter_kms(struct drm_device *dev, unsigned int pipe); u32 radeon_get_vblank_counter_kms(struct drm_device *dev, unsigned int pipe);
int radeon_enable_vblank_kms(struct drm_device *dev, unsigned int pipe); int radeon_enable_vblank_kms(struct drm_device *dev, unsigned int pipe);
void radeon_disable_vblank_kms(struct drm_device *dev, unsigned int pipe); void radeon_disable_vblank_kms(struct drm_device *dev, unsigned int pipe);
int radeon_get_vblank_timestamp_kms(struct drm_device *dev, unsigned int pipe,
int *max_error,
struct timeval *vblank_time,
unsigned flags);
void radeon_driver_irq_preinstall_kms(struct drm_device *dev); void radeon_driver_irq_preinstall_kms(struct drm_device *dev);
int radeon_driver_irq_postinstall_kms(struct drm_device *dev); int radeon_driver_irq_postinstall_kms(struct drm_device *dev);
void radeon_driver_irq_uninstall_kms(struct drm_device *dev); void radeon_driver_irq_uninstall_kms(struct drm_device *dev);
...@@ -530,6 +526,16 @@ static const struct file_operations radeon_driver_kms_fops = { ...@@ -530,6 +526,16 @@ static const struct file_operations radeon_driver_kms_fops = {
#endif #endif
}; };
static bool
radeon_get_crtc_scanout_position(struct drm_device *dev, unsigned int pipe,
bool in_vblank_irq, int *vpos, int *hpos,
ktime_t *stime, ktime_t *etime,
const struct drm_display_mode *mode)
{
return radeon_get_crtc_scanoutpos(dev, pipe, 0, vpos, hpos,
stime, etime, mode);
}
static struct drm_driver kms_driver = { static struct drm_driver kms_driver = {
.driver_features = .driver_features =
DRIVER_USE_AGP | DRIVER_USE_AGP |
...@@ -544,8 +550,8 @@ static struct drm_driver kms_driver = { ...@@ -544,8 +550,8 @@ static struct drm_driver kms_driver = {
.get_vblank_counter = radeon_get_vblank_counter_kms, .get_vblank_counter = radeon_get_vblank_counter_kms,
.enable_vblank = radeon_enable_vblank_kms, .enable_vblank = radeon_enable_vblank_kms,
.disable_vblank = radeon_disable_vblank_kms, .disable_vblank = radeon_disable_vblank_kms,
.get_vblank_timestamp = radeon_get_vblank_timestamp_kms, .get_vblank_timestamp = drm_calc_vbltimestamp_from_scanoutpos,
.get_scanout_position = radeon_get_crtc_scanoutpos, .get_scanout_position = radeon_get_crtc_scanout_position,
.irq_preinstall = radeon_driver_irq_preinstall_kms, .irq_preinstall = radeon_driver_irq_preinstall_kms,
.irq_postinstall = radeon_driver_irq_postinstall_kms, .irq_postinstall = radeon_driver_irq_postinstall_kms,
.irq_uninstall = radeon_driver_irq_uninstall_kms, .irq_uninstall = radeon_driver_irq_uninstall_kms,
......
...@@ -858,43 +858,6 @@ void radeon_disable_vblank_kms(struct drm_device *dev, int crtc) ...@@ -858,43 +858,6 @@ void radeon_disable_vblank_kms(struct drm_device *dev, int crtc)
spin_unlock_irqrestore(&rdev->irq.lock, irqflags); spin_unlock_irqrestore(&rdev->irq.lock, irqflags);
} }
/**
* radeon_get_vblank_timestamp_kms - get vblank timestamp
*
* @dev: drm dev pointer
* @crtc: crtc to get the timestamp for
* @max_error: max error
* @vblank_time: time value
* @flags: flags passed to the driver
*
* Gets the timestamp on the requested crtc based on the
* scanout position. (all asics).
* Returns postive status flags on success, negative error on failure.
*/
int radeon_get_vblank_timestamp_kms(struct drm_device *dev, int crtc,
int *max_error,
struct timeval *vblank_time,
unsigned flags)
{
struct drm_crtc *drmcrtc;
struct radeon_device *rdev = dev->dev_private;
if (crtc < 0 || crtc >= dev->num_crtcs) {
DRM_ERROR("Invalid crtc %d\n", crtc);
return -EINVAL;
}
/* Get associated drm_crtc: */
drmcrtc = &rdev->mode_info.crtcs[crtc]->base;
if (!drmcrtc)
return -EINVAL;
/* Helper routine in DRM core does all the work: */
return drm_calc_vbltimestamp_from_scanoutpos(dev, crtc, max_error,
vblank_time, flags,
&drmcrtc->hwmode);
}
const struct drm_ioctl_desc radeon_ioctls_kms[] = { const struct drm_ioctl_desc radeon_ioctls_kms[] = {
DRM_IOCTL_DEF_DRV(RADEON_CP_INIT, drm_invalid_op, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY), DRM_IOCTL_DEF_DRV(RADEON_CP_INIT, drm_invalid_op, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY),
DRM_IOCTL_DEF_DRV(RADEON_CP_START, drm_invalid_op, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY), DRM_IOCTL_DEF_DRV(RADEON_CP_START, drm_invalid_op, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY),
......
...@@ -691,6 +691,9 @@ struct atom_voltage_table ...@@ -691,6 +691,9 @@ struct atom_voltage_table
}; };
/* Driver internal use only flags of radeon_get_crtc_scanoutpos() */ /* Driver internal use only flags of radeon_get_crtc_scanoutpos() */
#define DRM_SCANOUTPOS_VALID (1 << 0)
#define DRM_SCANOUTPOS_IN_VBLANK (1 << 1)
#define DRM_SCANOUTPOS_ACCURATE (1 << 2)
#define USE_REAL_VBLANKSTART (1 << 30) #define USE_REAL_VBLANKSTART (1 << 30)
#define GET_DISTANCE_TO_VBLANKSTART (1 << 31) #define GET_DISTANCE_TO_VBLANKSTART (1 << 31)
......
...@@ -104,26 +104,18 @@ static void analogix_dp_psr_work(struct work_struct *work) ...@@ -104,26 +104,18 @@ static void analogix_dp_psr_work(struct work_struct *work)
{ {
struct rockchip_dp_device *dp = struct rockchip_dp_device *dp =
container_of(work, typeof(*dp), psr_work); container_of(work, typeof(*dp), psr_work);
struct drm_crtc *crtc = dp->encoder.crtc;
int psr_state = dp->psr_state;
int vact_end;
int ret; int ret;
unsigned long flags; unsigned long flags;
if (!crtc) ret = rockchip_drm_wait_vact_end(dp->encoder.crtc,
return; PSR_WAIT_LINE_FLAG_TIMEOUT_MS);
vact_end = crtc->mode.vtotal - crtc->mode.vsync_start + crtc->mode.vdisplay;
ret = rockchip_drm_wait_line_flag(dp->encoder.crtc, vact_end,
PSR_WAIT_LINE_FLAG_TIMEOUT_MS);
if (ret) { if (ret) {
dev_err(dp->dev, "line flag interrupt did not arrive\n"); dev_err(dp->dev, "line flag interrupt did not arrive\n");
return; return;
} }
spin_lock_irqsave(&dp->psr_lock, flags); spin_lock_irqsave(&dp->psr_lock, flags);
if (psr_state == EDP_VSC_PSR_STATE_ACTIVE) if (dp->psr_state == EDP_VSC_PSR_STATE_ACTIVE)
analogix_dp_enable_psr(dp->dev); analogix_dp_enable_psr(dp->dev);
else else
analogix_dp_disable_psr(dp->dev); analogix_dp_disable_psr(dp->dev);
......
...@@ -62,8 +62,7 @@ int rockchip_drm_dma_attach_device(struct drm_device *drm_dev, ...@@ -62,8 +62,7 @@ int rockchip_drm_dma_attach_device(struct drm_device *drm_dev,
struct device *dev); struct device *dev);
void rockchip_drm_dma_detach_device(struct drm_device *drm_dev, void rockchip_drm_dma_detach_device(struct drm_device *drm_dev,
struct device *dev); struct device *dev);
int rockchip_drm_wait_line_flag(struct drm_crtc *crtc, unsigned int line_num, int rockchip_drm_wait_vact_end(struct drm_crtc *crtc, unsigned int mstimeout);
unsigned int mstimeout);
extern struct platform_driver cdn_dp_driver; extern struct platform_driver cdn_dp_driver;
extern struct platform_driver dw_hdmi_rockchip_pltfm_driver; extern struct platform_driver dw_hdmi_rockchip_pltfm_driver;
......
...@@ -468,7 +468,7 @@ static bool vop_line_flag_irq_is_enabled(struct vop *vop) ...@@ -468,7 +468,7 @@ static bool vop_line_flag_irq_is_enabled(struct vop *vop)
return !!line_flag_irq; return !!line_flag_irq;
} }
static void vop_line_flag_irq_enable(struct vop *vop, int line_num) static void vop_line_flag_irq_enable(struct vop *vop)
{ {
unsigned long flags; unsigned long flags;
...@@ -477,7 +477,6 @@ static void vop_line_flag_irq_enable(struct vop *vop, int line_num) ...@@ -477,7 +477,6 @@ static void vop_line_flag_irq_enable(struct vop *vop, int line_num)
spin_lock_irqsave(&vop->irq_lock, flags); spin_lock_irqsave(&vop->irq_lock, flags);
VOP_CTRL_SET(vop, line_flag_num[0], line_num);
VOP_INTR_SET_TYPE(vop, clear, LINE_FLAG_INTR, 1); VOP_INTR_SET_TYPE(vop, clear, LINE_FLAG_INTR, 1);
VOP_INTR_SET_TYPE(vop, enable, LINE_FLAG_INTR, 1); VOP_INTR_SET_TYPE(vop, enable, LINE_FLAG_INTR, 1);
...@@ -981,6 +980,8 @@ static void vop_crtc_enable(struct drm_crtc *crtc) ...@@ -981,6 +980,8 @@ static void vop_crtc_enable(struct drm_crtc *crtc)
VOP_CTRL_SET(vop, vact_st_end, val); VOP_CTRL_SET(vop, vact_st_end, val);
VOP_CTRL_SET(vop, vpost_st_end, val); VOP_CTRL_SET(vop, vpost_st_end, val);
VOP_CTRL_SET(vop, line_flag_num[0], vact_end);
clk_set_rate(vop->dclk, adjusted_mode->clock * 1000); clk_set_rate(vop->dclk, adjusted_mode->clock * 1000);
VOP_CTRL_SET(vop, standby, 0); VOP_CTRL_SET(vop, standby, 0);
...@@ -1507,19 +1508,16 @@ static void vop_win_init(struct vop *vop) ...@@ -1507,19 +1508,16 @@ static void vop_win_init(struct vop *vop)
} }
/** /**
* rockchip_drm_wait_line_flag - acqiure the give line flag event * rockchip_drm_wait_vact_end
* @crtc: CRTC to enable line flag * @crtc: CRTC to enable line flag
* @line_num: interested line number
* @mstimeout: millisecond for timeout * @mstimeout: millisecond for timeout
* *
* Driver would hold here until the interested line flag interrupt have * Wait for vact_end line flag irq or timeout.
* happened or timeout to wait.
* *
* Returns: * Returns:
* Zero on success, negative errno on failure. * Zero on success, negative errno on failure.
*/ */
int rockchip_drm_wait_line_flag(struct drm_crtc *crtc, unsigned int line_num, int rockchip_drm_wait_vact_end(struct drm_crtc *crtc, unsigned int mstimeout)
unsigned int mstimeout)
{ {
struct vop *vop = to_vop(crtc); struct vop *vop = to_vop(crtc);
unsigned long jiffies_left; unsigned long jiffies_left;
...@@ -1527,14 +1525,14 @@ int rockchip_drm_wait_line_flag(struct drm_crtc *crtc, unsigned int line_num, ...@@ -1527,14 +1525,14 @@ int rockchip_drm_wait_line_flag(struct drm_crtc *crtc, unsigned int line_num,
if (!crtc || !vop->is_enabled) if (!crtc || !vop->is_enabled)
return -ENODEV; return -ENODEV;
if (line_num > crtc->mode.vtotal || mstimeout <= 0) if (mstimeout <= 0)
return -EINVAL; return -EINVAL;
if (vop_line_flag_irq_is_enabled(vop)) if (vop_line_flag_irq_is_enabled(vop))
return -EBUSY; return -EBUSY;
reinit_completion(&vop->line_flag_completion); reinit_completion(&vop->line_flag_completion);
vop_line_flag_irq_enable(vop, line_num); vop_line_flag_irq_enable(vop);
jiffies_left = wait_for_completion_timeout(&vop->line_flag_completion, jiffies_left = wait_for_completion_timeout(&vop->line_flag_completion,
msecs_to_jiffies(mstimeout)); msecs_to_jiffies(mstimeout));
...@@ -1547,7 +1545,7 @@ int rockchip_drm_wait_line_flag(struct drm_crtc *crtc, unsigned int line_num, ...@@ -1547,7 +1545,7 @@ int rockchip_drm_wait_line_flag(struct drm_crtc *crtc, unsigned int line_num,
return 0; return 0;
} }
EXPORT_SYMBOL(rockchip_drm_wait_line_flag); EXPORT_SYMBOL(rockchip_drm_wait_vact_end);
static int vop_bind(struct device *dev, struct device *master, void *data) static int vop_bind(struct device *dev, struct device *master, void *data)
{ {
......
...@@ -514,6 +514,8 @@ static int igt_reserve(void *ignored) ...@@ -514,6 +514,8 @@ static int igt_reserve(void *ignored)
ret = __igt_reserve(count, size + 1); ret = __igt_reserve(count, size + 1);
if (ret) if (ret)
return ret; return ret;
cond_resched();
} }
return 0; return 0;
...@@ -712,6 +714,10 @@ static int igt_insert(void *ignored) ...@@ -712,6 +714,10 @@ static int igt_insert(void *ignored)
return ret; return ret;
ret = __igt_insert(count, size + 1, false); ret = __igt_insert(count, size + 1, false);
if (ret)
return ret;
cond_resched();
} }
return 0; return 0;
...@@ -741,6 +747,10 @@ static int igt_replace(void *ignored) ...@@ -741,6 +747,10 @@ static int igt_replace(void *ignored)
return ret; return ret;
ret = __igt_insert(count, size + 1, true); ret = __igt_insert(count, size + 1, true);
if (ret)
return ret;
cond_resched();
} }
return 0; return 0;
...@@ -1011,6 +1021,8 @@ static int igt_insert_range(void *ignored) ...@@ -1011,6 +1021,8 @@ static int igt_insert_range(void *ignored)
ret = __igt_insert_range(count, size, max/4+1, 3*max/4-1); ret = __igt_insert_range(count, size, max/4+1, 3*max/4-1);
if (ret) if (ret)
return ret; return ret;
cond_resched();
} }
return 0; return 0;
...@@ -1056,6 +1068,7 @@ static int igt_align(void *ignored) ...@@ -1056,6 +1068,7 @@ static int igt_align(void *ignored)
drm_mm_for_each_node_safe(node, next, &mm) drm_mm_for_each_node_safe(node, next, &mm)
drm_mm_remove_node(node); drm_mm_remove_node(node);
DRM_MM_BUG_ON(!drm_mm_clean(&mm)); DRM_MM_BUG_ON(!drm_mm_clean(&mm));
cond_resched();
} }
ret = 0; ret = 0;
...@@ -1097,6 +1110,8 @@ static int igt_align_pot(int max) ...@@ -1097,6 +1110,8 @@ static int igt_align_pot(int max)
align, bit); align, bit);
goto out; goto out;
} }
cond_resched();
} }
ret = 0; ret = 0;
...@@ -1471,6 +1486,8 @@ static int igt_evict(void *ignored) ...@@ -1471,6 +1486,8 @@ static int igt_evict(void *ignored)
goto out; goto out;
} }
} }
cond_resched();
} }
ret = 0; ret = 0;
...@@ -1566,6 +1583,8 @@ static int igt_evict_range(void *ignored) ...@@ -1566,6 +1583,8 @@ static int igt_evict_range(void *ignored)
goto out; goto out;
} }
} }
cond_resched();
} }
ret = 0; ret = 0;
...@@ -1683,6 +1702,7 @@ static int igt_topdown(void *ignored) ...@@ -1683,6 +1702,7 @@ static int igt_topdown(void *ignored)
drm_mm_for_each_node_safe(node, next, &mm) drm_mm_for_each_node_safe(node, next, &mm)
drm_mm_remove_node(node); drm_mm_remove_node(node);
DRM_MM_BUG_ON(!drm_mm_clean(&mm)); DRM_MM_BUG_ON(!drm_mm_clean(&mm));
cond_resched();
} }
ret = 0; ret = 0;
...@@ -1783,6 +1803,7 @@ static int igt_bottomup(void *ignored) ...@@ -1783,6 +1803,7 @@ static int igt_bottomup(void *ignored)
drm_mm_for_each_node_safe(node, next, &mm) drm_mm_for_each_node_safe(node, next, &mm)
drm_mm_remove_node(node); drm_mm_remove_node(node);
DRM_MM_BUG_ON(!drm_mm_clean(&mm)); DRM_MM_BUG_ON(!drm_mm_clean(&mm));
cond_resched();
} }
ret = 0; ret = 0;
...@@ -1970,6 +1991,8 @@ static int igt_color(void *ignored) ...@@ -1970,6 +1991,8 @@ static int igt_color(void *ignored)
drm_mm_remove_node(node); drm_mm_remove_node(node);
kfree(node); kfree(node);
} }
cond_resched();
} }
ret = 0; ret = 0;
...@@ -2047,6 +2070,7 @@ static int evict_color(struct drm_mm *mm, ...@@ -2047,6 +2070,7 @@ static int evict_color(struct drm_mm *mm,
} }
} }
cond_resched();
return 0; return 0;
} }
...@@ -2132,6 +2156,8 @@ static int igt_color_evict(void *ignored) ...@@ -2132,6 +2156,8 @@ static int igt_color_evict(void *ignored)
goto out; goto out;
} }
} }
cond_resched();
} }
ret = 0; ret = 0;
...@@ -2231,6 +2257,8 @@ static int igt_color_evict_range(void *ignored) ...@@ -2231,6 +2257,8 @@ static int igt_color_evict_range(void *ignored)
goto out; goto out;
} }
} }
cond_resched();
} }
ret = 0; ret = 0;
......
...@@ -33,7 +33,7 @@ ...@@ -33,7 +33,7 @@
#define STI_CURS_MAX_SIZE 128 #define STI_CURS_MAX_SIZE 128
/* /*
* pixmap dma buffer stucture * pixmap dma buffer structure
* *
* @paddr: physical address * @paddr: physical address
* @size: buffer size * @size: buffer size
...@@ -121,8 +121,7 @@ static int cursor_dbg_show(struct seq_file *s, void *data) ...@@ -121,8 +121,7 @@ static int cursor_dbg_show(struct seq_file *s, void *data)
cursor_dbg_cml(s, cursor, readl(cursor->regs + CUR_CML)); cursor_dbg_cml(s, cursor, readl(cursor->regs + CUR_CML));
DBGFS_DUMP(CUR_AWS); DBGFS_DUMP(CUR_AWS);
DBGFS_DUMP(CUR_AWE); DBGFS_DUMP(CUR_AWE);
seq_puts(s, "\n"); seq_putc(s, '\n');
return 0; return 0;
} }
......
...@@ -186,8 +186,7 @@ static int dvo_dbg_show(struct seq_file *s, void *data) ...@@ -186,8 +186,7 @@ static int dvo_dbg_show(struct seq_file *s, void *data)
DBGFS_DUMP(DVO_LUT_PROG_MID); DBGFS_DUMP(DVO_LUT_PROG_MID);
DBGFS_DUMP(DVO_LUT_PROG_HIGH); DBGFS_DUMP(DVO_LUT_PROG_HIGH);
dvo_dbg_awg_microcode(s, dvo->regs + DVO_DIGSYNC_INSTR_I); dvo_dbg_awg_microcode(s, dvo->regs + DVO_DIGSYNC_INSTR_I);
seq_puts(s, "\n"); seq_putc(s, '\n');
return 0; return 0;
} }
......
...@@ -149,7 +149,7 @@ static void gdp_dbg_ctl(struct seq_file *s, int val) ...@@ -149,7 +149,7 @@ static void gdp_dbg_ctl(struct seq_file *s, int val)
seq_puts(s, "\tColor:"); seq_puts(s, "\tColor:");
for (i = 0; i < ARRAY_SIZE(gdp_format_to_str); i++) { for (i = 0; i < ARRAY_SIZE(gdp_format_to_str); i++) {
if (gdp_format_to_str[i].format == (val & 0x1F)) { if (gdp_format_to_str[i].format == (val & 0x1F)) {
seq_printf(s, gdp_format_to_str[i].name); seq_puts(s, gdp_format_to_str[i].name);
break; break;
} }
} }
...@@ -266,8 +266,7 @@ static void gdp_node_dump_node(struct seq_file *s, struct sti_gdp_node *node) ...@@ -266,8 +266,7 @@ static void gdp_node_dump_node(struct seq_file *s, struct sti_gdp_node *node)
seq_printf(s, "\n\tKEY2 0x%08X", node->gam_gdp_key2); seq_printf(s, "\n\tKEY2 0x%08X", node->gam_gdp_key2);
seq_printf(s, "\n\tPPT 0x%08X", node->gam_gdp_ppt); seq_printf(s, "\n\tPPT 0x%08X", node->gam_gdp_ppt);
gdp_dbg_ppt(s, node->gam_gdp_ppt); gdp_dbg_ppt(s, node->gam_gdp_ppt);
seq_printf(s, "\n\tCML 0x%08X", node->gam_gdp_cml); seq_printf(s, "\n\tCML 0x%08X\n", node->gam_gdp_cml);
seq_puts(s, "\n");
} }
static int gdp_node_dbg_show(struct seq_file *s, void *arg) static int gdp_node_dbg_show(struct seq_file *s, void *arg)
......
...@@ -320,8 +320,7 @@ static void hda_dbg_awg_microcode(struct seq_file *s, void __iomem *reg) ...@@ -320,8 +320,7 @@ static void hda_dbg_awg_microcode(struct seq_file *s, void __iomem *reg)
{ {
unsigned int i; unsigned int i;
seq_puts(s, "\n\n"); seq_puts(s, "\n\n HDA AWG microcode:");
seq_puts(s, " HDA AWG microcode:");
for (i = 0; i < AWG_MAX_INST; i++) { for (i = 0; i < AWG_MAX_INST; i++) {
if (i % 8 == 0) if (i % 8 == 0)
seq_printf(s, "\n %04X:", i); seq_printf(s, "\n %04X:", i);
...@@ -333,8 +332,7 @@ static void hda_dbg_video_dacs_ctrl(struct seq_file *s, void __iomem *reg) ...@@ -333,8 +332,7 @@ static void hda_dbg_video_dacs_ctrl(struct seq_file *s, void __iomem *reg)
{ {
u32 val = readl(reg); u32 val = readl(reg);
seq_puts(s, "\n"); seq_printf(s, "\n\n %-25s 0x%08X", "VIDEO_DACS_CONTROL", val);
seq_printf(s, "\n %-25s 0x%08X", "VIDEO_DACS_CONTROL", val);
seq_puts(s, "\tHD DACs "); seq_puts(s, "\tHD DACs ");
seq_puts(s, val & DAC_CFG_HD_HZUVW_OFF_MASK ? "disabled" : "enabled"); seq_puts(s, val & DAC_CFG_HD_HZUVW_OFF_MASK ? "disabled" : "enabled");
} }
...@@ -356,8 +354,7 @@ static int hda_dbg_show(struct seq_file *s, void *data) ...@@ -356,8 +354,7 @@ static int hda_dbg_show(struct seq_file *s, void *data)
hda_dbg_awg_microcode(s, hda->regs + HDA_SYNC_AWGI); hda_dbg_awg_microcode(s, hda->regs + HDA_SYNC_AWGI);
if (hda->video_dacs_ctrl) if (hda->video_dacs_ctrl)
hda_dbg_video_dacs_ctrl(s, hda->video_dacs_ctrl); hda_dbg_video_dacs_ctrl(s, hda->video_dacs_ctrl);
seq_puts(s, "\n"); seq_putc(s, '\n');
return 0; return 0;
} }
......
...@@ -592,7 +592,7 @@ static void hdmi_dbg_cfg(struct seq_file *s, int val) ...@@ -592,7 +592,7 @@ static void hdmi_dbg_cfg(struct seq_file *s, int val)
{ {
int tmp; int tmp;
seq_puts(s, "\t"); seq_putc(s, '\t');
tmp = val & HDMI_CFG_HDMI_NOT_DVI; tmp = val & HDMI_CFG_HDMI_NOT_DVI;
DBGFS_PRINT_STR("mode:", tmp ? "HDMI" : "DVI"); DBGFS_PRINT_STR("mode:", tmp ? "HDMI" : "DVI");
seq_puts(s, "\t\t\t\t\t"); seq_puts(s, "\t\t\t\t\t");
...@@ -616,7 +616,7 @@ static void hdmi_dbg_sta(struct seq_file *s, int val) ...@@ -616,7 +616,7 @@ static void hdmi_dbg_sta(struct seq_file *s, int val)
{ {
int tmp; int tmp;
seq_puts(s, "\t"); seq_putc(s, '\t');
tmp = (val & HDMI_STA_DLL_LCK); tmp = (val & HDMI_STA_DLL_LCK);
DBGFS_PRINT_STR("pll:", tmp ? "locked" : "not locked"); DBGFS_PRINT_STR("pll:", tmp ? "locked" : "not locked");
seq_puts(s, "\t\t\t\t\t"); seq_puts(s, "\t\t\t\t\t");
...@@ -632,7 +632,7 @@ static void hdmi_dbg_sw_di_cfg(struct seq_file *s, int val) ...@@ -632,7 +632,7 @@ static void hdmi_dbg_sw_di_cfg(struct seq_file *s, int val)
"once every field", "once every field",
"once every frame"}; "once every frame"};
seq_puts(s, "\t"); seq_putc(s, '\t');
tmp = (val & HDMI_IFRAME_CFG_DI_N(HDMI_IFRAME_MASK, 1)); tmp = (val & HDMI_IFRAME_CFG_DI_N(HDMI_IFRAME_MASK, 1));
DBGFS_PRINT_STR("Data island 1:", en_di[tmp]); DBGFS_PRINT_STR("Data island 1:", en_di[tmp]);
seq_puts(s, "\t\t\t\t\t"); seq_puts(s, "\t\t\t\t\t");
...@@ -664,16 +664,16 @@ static int hdmi_dbg_show(struct seq_file *s, void *data) ...@@ -664,16 +664,16 @@ static int hdmi_dbg_show(struct seq_file *s, void *data)
DBGFS_DUMP("\n", HDMI_STA); DBGFS_DUMP("\n", HDMI_STA);
hdmi_dbg_sta(s, hdmi_read(hdmi, HDMI_STA)); hdmi_dbg_sta(s, hdmi_read(hdmi, HDMI_STA));
DBGFS_DUMP("", HDMI_ACTIVE_VID_XMIN); DBGFS_DUMP("", HDMI_ACTIVE_VID_XMIN);
seq_puts(s, "\t"); seq_putc(s, '\t');
DBGFS_PRINT_INT("Xmin:", hdmi_read(hdmi, HDMI_ACTIVE_VID_XMIN)); DBGFS_PRINT_INT("Xmin:", hdmi_read(hdmi, HDMI_ACTIVE_VID_XMIN));
DBGFS_DUMP("", HDMI_ACTIVE_VID_XMAX); DBGFS_DUMP("", HDMI_ACTIVE_VID_XMAX);
seq_puts(s, "\t"); seq_putc(s, '\t');
DBGFS_PRINT_INT("Xmax:", hdmi_read(hdmi, HDMI_ACTIVE_VID_XMAX)); DBGFS_PRINT_INT("Xmax:", hdmi_read(hdmi, HDMI_ACTIVE_VID_XMAX));
DBGFS_DUMP("", HDMI_ACTIVE_VID_YMIN); DBGFS_DUMP("", HDMI_ACTIVE_VID_YMIN);
seq_puts(s, "\t"); seq_putc(s, '\t');
DBGFS_PRINT_INT("Ymin:", hdmi_read(hdmi, HDMI_ACTIVE_VID_YMIN)); DBGFS_PRINT_INT("Ymin:", hdmi_read(hdmi, HDMI_ACTIVE_VID_YMIN));
DBGFS_DUMP("", HDMI_ACTIVE_VID_YMAX); DBGFS_DUMP("", HDMI_ACTIVE_VID_YMAX);
seq_puts(s, "\t"); seq_putc(s, '\t');
DBGFS_PRINT_INT("Ymax:", hdmi_read(hdmi, HDMI_ACTIVE_VID_YMAX)); DBGFS_PRINT_INT("Ymax:", hdmi_read(hdmi, HDMI_ACTIVE_VID_YMAX));
DBGFS_DUMP("", HDMI_SW_DI_CFG); DBGFS_DUMP("", HDMI_SW_DI_CFG);
hdmi_dbg_sw_di_cfg(s, hdmi_read(hdmi, HDMI_SW_DI_CFG)); hdmi_dbg_sw_di_cfg(s, hdmi_read(hdmi, HDMI_SW_DI_CFG));
...@@ -692,8 +692,7 @@ static int hdmi_dbg_show(struct seq_file *s, void *data) ...@@ -692,8 +692,7 @@ static int hdmi_dbg_show(struct seq_file *s, void *data)
DBGFS_DUMP_DI(HDMI_SW_DI_N_PKT_WORD4, HDMI_IFRAME_SLOT_AVI); DBGFS_DUMP_DI(HDMI_SW_DI_N_PKT_WORD4, HDMI_IFRAME_SLOT_AVI);
DBGFS_DUMP_DI(HDMI_SW_DI_N_PKT_WORD5, HDMI_IFRAME_SLOT_AVI); DBGFS_DUMP_DI(HDMI_SW_DI_N_PKT_WORD5, HDMI_IFRAME_SLOT_AVI);
DBGFS_DUMP_DI(HDMI_SW_DI_N_PKT_WORD6, HDMI_IFRAME_SLOT_AVI); DBGFS_DUMP_DI(HDMI_SW_DI_N_PKT_WORD6, HDMI_IFRAME_SLOT_AVI);
seq_puts(s, "\n"); seq_printf(s, "\n\n AUDIO Infoframe (Data Island slot N=%d):",
seq_printf(s, "\n AUDIO Infoframe (Data Island slot N=%d):",
HDMI_IFRAME_SLOT_AUDIO); HDMI_IFRAME_SLOT_AUDIO);
DBGFS_DUMP_DI(HDMI_SW_DI_N_HEAD_WORD, HDMI_IFRAME_SLOT_AUDIO); DBGFS_DUMP_DI(HDMI_SW_DI_N_HEAD_WORD, HDMI_IFRAME_SLOT_AUDIO);
DBGFS_DUMP_DI(HDMI_SW_DI_N_PKT_WORD0, HDMI_IFRAME_SLOT_AUDIO); DBGFS_DUMP_DI(HDMI_SW_DI_N_PKT_WORD0, HDMI_IFRAME_SLOT_AUDIO);
...@@ -703,8 +702,7 @@ static int hdmi_dbg_show(struct seq_file *s, void *data) ...@@ -703,8 +702,7 @@ static int hdmi_dbg_show(struct seq_file *s, void *data)
DBGFS_DUMP_DI(HDMI_SW_DI_N_PKT_WORD4, HDMI_IFRAME_SLOT_AUDIO); DBGFS_DUMP_DI(HDMI_SW_DI_N_PKT_WORD4, HDMI_IFRAME_SLOT_AUDIO);
DBGFS_DUMP_DI(HDMI_SW_DI_N_PKT_WORD5, HDMI_IFRAME_SLOT_AUDIO); DBGFS_DUMP_DI(HDMI_SW_DI_N_PKT_WORD5, HDMI_IFRAME_SLOT_AUDIO);
DBGFS_DUMP_DI(HDMI_SW_DI_N_PKT_WORD6, HDMI_IFRAME_SLOT_AUDIO); DBGFS_DUMP_DI(HDMI_SW_DI_N_PKT_WORD6, HDMI_IFRAME_SLOT_AUDIO);
seq_puts(s, "\n"); seq_printf(s, "\n\n VENDOR SPECIFIC Infoframe (Data Island slot N=%d):",
seq_printf(s, "\n VENDOR SPECIFIC Infoframe (Data Island slot N=%d):",
HDMI_IFRAME_SLOT_VENDOR); HDMI_IFRAME_SLOT_VENDOR);
DBGFS_DUMP_DI(HDMI_SW_DI_N_HEAD_WORD, HDMI_IFRAME_SLOT_VENDOR); DBGFS_DUMP_DI(HDMI_SW_DI_N_HEAD_WORD, HDMI_IFRAME_SLOT_VENDOR);
DBGFS_DUMP_DI(HDMI_SW_DI_N_PKT_WORD0, HDMI_IFRAME_SLOT_VENDOR); DBGFS_DUMP_DI(HDMI_SW_DI_N_PKT_WORD0, HDMI_IFRAME_SLOT_VENDOR);
...@@ -714,8 +712,7 @@ static int hdmi_dbg_show(struct seq_file *s, void *data) ...@@ -714,8 +712,7 @@ static int hdmi_dbg_show(struct seq_file *s, void *data)
DBGFS_DUMP_DI(HDMI_SW_DI_N_PKT_WORD4, HDMI_IFRAME_SLOT_VENDOR); DBGFS_DUMP_DI(HDMI_SW_DI_N_PKT_WORD4, HDMI_IFRAME_SLOT_VENDOR);
DBGFS_DUMP_DI(HDMI_SW_DI_N_PKT_WORD5, HDMI_IFRAME_SLOT_VENDOR); DBGFS_DUMP_DI(HDMI_SW_DI_N_PKT_WORD5, HDMI_IFRAME_SLOT_VENDOR);
DBGFS_DUMP_DI(HDMI_SW_DI_N_PKT_WORD6, HDMI_IFRAME_SLOT_VENDOR); DBGFS_DUMP_DI(HDMI_SW_DI_N_PKT_WORD6, HDMI_IFRAME_SLOT_VENDOR);
seq_puts(s, "\n"); seq_putc(s, '\n');
return 0; return 0;
} }
......
...@@ -625,8 +625,7 @@ static int hqvdp_dbg_show(struct seq_file *s, void *data) ...@@ -625,8 +625,7 @@ static int hqvdp_dbg_show(struct seq_file *s, void *data)
hqvdp_dbg_dump_cmd(s, (struct sti_hqvdp_cmd *)virt); hqvdp_dbg_dump_cmd(s, (struct sti_hqvdp_cmd *)virt);
} }
seq_puts(s, "\n"); seq_putc(s, '\n');
return 0; return 0;
} }
...@@ -1357,12 +1356,12 @@ static int sti_hqvdp_probe(struct platform_device *pdev) ...@@ -1357,12 +1356,12 @@ static int sti_hqvdp_probe(struct platform_device *pdev)
/* Get Memory resources */ /* Get Memory resources */
res = platform_get_resource(pdev, IORESOURCE_MEM, 0); res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
if (res == NULL) { if (!res) {
DRM_ERROR("Get memory resource failed\n"); DRM_ERROR("Get memory resource failed\n");
return -ENXIO; return -ENXIO;
} }
hqvdp->regs = devm_ioremap(dev, res->start, resource_size(res)); hqvdp->regs = devm_ioremap(dev, res->start, resource_size(res));
if (hqvdp->regs == NULL) { if (!hqvdp->regs) {
DRM_ERROR("Register mapping failed\n"); DRM_ERROR("Register mapping failed\n");
return -ENXIO; return -ENXIO;
} }
......
...@@ -162,8 +162,7 @@ static int mixer_dbg_show(struct seq_file *s, void *arg) ...@@ -162,8 +162,7 @@ static int mixer_dbg_show(struct seq_file *s, void *arg)
DBGFS_DUMP(GAM_MIXER_MBP); DBGFS_DUMP(GAM_MIXER_MBP);
DBGFS_DUMP(GAM_MIXER_MX0); DBGFS_DUMP(GAM_MIXER_MX0);
mixer_dbg_mxn(s, mixer->regs + GAM_MIXER_MX0); mixer_dbg_mxn(s, mixer->regs + GAM_MIXER_MX0);
seq_puts(s, "\n"); seq_putc(s, '\n');
return 0; return 0;
} }
......
...@@ -459,7 +459,7 @@ static void tvout_dbg_vip(struct seq_file *s, int val) ...@@ -459,7 +459,7 @@ static void tvout_dbg_vip(struct seq_file *s, int val)
"Aux (color matrix by-passed)", "Aux (color matrix by-passed)",
"", "", "", "", "", "Force value"}; "", "", "", "", "", "Force value"};
seq_puts(s, "\t"); seq_putc(s, '\t');
mask = TVO_VIP_REORDER_MASK << TVO_VIP_REORDER_R_SHIFT; mask = TVO_VIP_REORDER_MASK << TVO_VIP_REORDER_R_SHIFT;
r = (val & mask) >> TVO_VIP_REORDER_R_SHIFT; r = (val & mask) >> TVO_VIP_REORDER_R_SHIFT;
mask = TVO_VIP_REORDER_MASK << TVO_VIP_REORDER_G_SHIFT; mask = TVO_VIP_REORDER_MASK << TVO_VIP_REORDER_G_SHIFT;
...@@ -558,8 +558,7 @@ static int tvout_dbg_show(struct seq_file *s, void *data) ...@@ -558,8 +558,7 @@ static int tvout_dbg_show(struct seq_file *s, void *data)
DBGFS_DUMP(TVO_CSC_AUX_M6); DBGFS_DUMP(TVO_CSC_AUX_M6);
DBGFS_DUMP(TVO_CSC_AUX_M7); DBGFS_DUMP(TVO_CSC_AUX_M7);
DBGFS_DUMP(TVO_AUX_IN_VID_FORMAT); DBGFS_DUMP(TVO_AUX_IN_VID_FORMAT);
seq_puts(s, "\n"); seq_putc(s, '\n');
return 0; return 0;
} }
...@@ -847,7 +846,7 @@ static int sti_tvout_probe(struct platform_device *pdev) ...@@ -847,7 +846,7 @@ static int sti_tvout_probe(struct platform_device *pdev)
tvout->dev = dev; tvout->dev = dev;
/* get Memory ressources */ /* get memory resources */
res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "tvout-reg"); res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "tvout-reg");
if (!res) { if (!res) {
DRM_ERROR("Invalid glue resource\n"); DRM_ERROR("Invalid glue resource\n");
......
...@@ -61,7 +61,7 @@ ...@@ -61,7 +61,7 @@
static void vid_dbg_ctl(struct seq_file *s, int val) static void vid_dbg_ctl(struct seq_file *s, int val)
{ {
val = val >> 30; val = val >> 30;
seq_puts(s, "\t"); seq_putc(s, '\t');
if (!(val & 1)) if (!(val & 1))
seq_puts(s, "NOT "); seq_puts(s, "NOT ");
...@@ -114,8 +114,7 @@ static int vid_dbg_show(struct seq_file *s, void *arg) ...@@ -114,8 +114,7 @@ static int vid_dbg_show(struct seq_file *s, void *arg)
DBGFS_DUMP(VID_BC); DBGFS_DUMP(VID_BC);
DBGFS_DUMP(VID_TINT); DBGFS_DUMP(VID_TINT);
DBGFS_DUMP(VID_CSAT); DBGFS_DUMP(VID_CSAT);
seq_puts(s, "\n"); seq_putc(s, '\n');
return 0; return 0;
} }
......
config DRM_STM
tristate "DRM Support for STMicroelectronics SoC Series"
depends on DRM && (ARCH_STM32 || ARCH_MULTIPLATFORM)
select DRM_KMS_HELPER
select DRM_GEM_CMA_HELPER
select DRM_KMS_CMA_HELPER
select DRM_PANEL
select VIDEOMODE_HELPERS
select FB_PROVIDE_GET_FB_UNMAPPED_AREA
default y
help
Enable support for the on-chip display controller on
STMicroelectronics STM32 MCUs.
To compile this driver as a module, choose M here: the module
will be called stm-drm.
ccflags-y := -Iinclude/drm
stm-drm-y := \
drv.o \
ltdc.o
obj-$(CONFIG_DRM_STM) += stm-drm.o
/*
* Copyright (C) STMicroelectronics SA 2017
*
* Authors: Philippe Cornu <philippe.cornu@st.com>
* Yannick Fertre <yannick.fertre@st.com>
* Fabien Dessenne <fabien.dessenne@st.com>
* Mickael Reulier <mickael.reulier@st.com>
*
* License terms: GNU General Public License (GPL), version 2
*/
#include <linux/component.h>
#include <linux/of_platform.h>
#include <drm/drm_atomic.h>
#include <drm/drm_atomic_helper.h>
#include <drm/drm_crtc_helper.h>
#include <drm/drm_fb_cma_helper.h>
#include <drm/drm_gem_cma_helper.h>
#include "ltdc.h"
#define DRIVER_NAME "stm"
#define DRIVER_DESC "STMicroelectronics SoC DRM"
#define DRIVER_DATE "20170330"
#define DRIVER_MAJOR 1
#define DRIVER_MINOR 0
#define DRIVER_PATCH_LEVEL 0
#define STM_MAX_FB_WIDTH 2048
#define STM_MAX_FB_HEIGHT 2048 /* same as width to handle orientation */
static void drv_output_poll_changed(struct drm_device *ddev)
{
struct ltdc_device *ldev = ddev->dev_private;
drm_fbdev_cma_hotplug_event(ldev->fbdev);
}
static const struct drm_mode_config_funcs drv_mode_config_funcs = {
.fb_create = drm_fb_cma_create,
.output_poll_changed = drv_output_poll_changed,
.atomic_check = drm_atomic_helper_check,
.atomic_commit = drm_atomic_helper_commit,
};
static void drv_lastclose(struct drm_device *ddev)
{
struct ltdc_device *ldev = ddev->dev_private;
DRM_DEBUG("%s\n", __func__);
drm_fbdev_cma_restore_mode(ldev->fbdev);
}
DEFINE_DRM_GEM_CMA_FOPS(drv_driver_fops);
static struct drm_driver drv_driver = {
.driver_features = DRIVER_MODESET | DRIVER_GEM | DRIVER_PRIME |
DRIVER_ATOMIC,
.lastclose = drv_lastclose,
.name = DRIVER_NAME,
.desc = DRIVER_DESC,
.date = DRIVER_DATE,
.major = DRIVER_MAJOR,
.minor = DRIVER_MINOR,
.patchlevel = DRIVER_PATCH_LEVEL,
.fops = &drv_driver_fops,
.dumb_create = drm_gem_cma_dumb_create,
.dumb_map_offset = drm_gem_cma_dumb_map_offset,
.dumb_destroy = drm_gem_dumb_destroy,
.prime_handle_to_fd = drm_gem_prime_handle_to_fd,
.prime_fd_to_handle = drm_gem_prime_fd_to_handle,
.gem_free_object_unlocked = drm_gem_cma_free_object,
.gem_vm_ops = &drm_gem_cma_vm_ops,
.gem_prime_export = drm_gem_prime_export,
.gem_prime_import = drm_gem_prime_import,
.gem_prime_get_sg_table = drm_gem_cma_prime_get_sg_table,
.gem_prime_import_sg_table = drm_gem_cma_prime_import_sg_table,
.gem_prime_vmap = drm_gem_cma_prime_vmap,
.gem_prime_vunmap = drm_gem_cma_prime_vunmap,
.gem_prime_mmap = drm_gem_cma_prime_mmap,
.enable_vblank = ltdc_crtc_enable_vblank,
.disable_vblank = ltdc_crtc_disable_vblank,
};
static int drv_load(struct drm_device *ddev)
{
struct platform_device *pdev = to_platform_device(ddev->dev);
struct drm_fbdev_cma *fbdev;
struct ltdc_device *ldev;
int ret;
DRM_DEBUG("%s\n", __func__);
ldev = devm_kzalloc(ddev->dev, sizeof(*ldev), GFP_KERNEL);
if (!ldev)
return -ENOMEM;
ddev->dev_private = (void *)ldev;
drm_mode_config_init(ddev);
/*
* set max width and height as default value.
* this value would be used to check framebuffer size limitation
* at drm_mode_addfb().
*/
ddev->mode_config.min_width = 0;
ddev->mode_config.min_height = 0;
ddev->mode_config.max_width = STM_MAX_FB_WIDTH;
ddev->mode_config.max_height = STM_MAX_FB_HEIGHT;
ddev->mode_config.funcs = &drv_mode_config_funcs;
ret = ltdc_load(ddev);
if (ret)
goto err;
drm_mode_config_reset(ddev);
drm_kms_helper_poll_init(ddev);
if (ddev->mode_config.num_connector) {
ldev = ddev->dev_private;
fbdev = drm_fbdev_cma_init(ddev, 16,
ddev->mode_config.num_connector);
if (IS_ERR(fbdev)) {
DRM_DEBUG("Warning: fails to create fbdev\n");
fbdev = NULL;
}
ldev->fbdev = fbdev;
}
platform_set_drvdata(pdev, ddev);
return 0;
err:
drm_mode_config_cleanup(ddev);
return ret;
}
static void drv_unload(struct drm_device *ddev)
{
struct ltdc_device *ldev = ddev->dev_private;
DRM_DEBUG("%s\n", __func__);
if (ldev->fbdev) {
drm_fbdev_cma_fini(ldev->fbdev);
ldev->fbdev = NULL;
}
drm_kms_helper_poll_fini(ddev);
ltdc_unload(ddev);
drm_mode_config_cleanup(ddev);
}
static int stm_drm_platform_probe(struct platform_device *pdev)
{
struct device *dev = &pdev->dev;
struct drm_device *ddev;
int ret;
DRM_DEBUG("%s\n", __func__);
dma_set_coherent_mask(dev, DMA_BIT_MASK(32));
ddev = drm_dev_alloc(&drv_driver, dev);
if (IS_ERR(ddev))
return PTR_ERR(ddev);
ret = drv_load(ddev);
if (ret)
goto err_unref;
ret = drm_dev_register(ddev, 0);
if (ret)
goto err_unref;
return 0;
err_unref:
drm_dev_unref(ddev);
return ret;
}
static int stm_drm_platform_remove(struct platform_device *pdev)
{
struct drm_device *ddev = platform_get_drvdata(pdev);
DRM_DEBUG("%s\n", __func__);
drm_dev_unregister(ddev);
drv_unload(ddev);
drm_dev_unref(ddev);
return 0;
}
static const struct of_device_id drv_dt_ids[] = {
{ .compatible = "st,stm32-ltdc"},
{ /* end node */ },
};
MODULE_DEVICE_TABLE(of, drv_dt_ids);
static struct platform_driver stm_drm_platform_driver = {
.probe = stm_drm_platform_probe,
.remove = stm_drm_platform_remove,
.driver = {
.name = DRIVER_NAME,
.of_match_table = drv_dt_ids,
},
};
module_platform_driver(stm_drm_platform_driver);
MODULE_AUTHOR("Philippe Cornu <philippe.cornu@st.com>");
MODULE_AUTHOR("Yannick Fertre <yannick.fertre@st.com>");
MODULE_AUTHOR("Fabien Dessenne <fabien.dessenne@st.com>");
MODULE_AUTHOR("Mickael Reulier <mickael.reulier@st.com>");
MODULE_DESCRIPTION("STMicroelectronics ST DRM LTDC driver");
MODULE_LICENSE("GPL v2");
此差异已折叠。
/*
* Copyright (C) STMicroelectronics SA 2017
*
* Authors: Philippe Cornu <philippe.cornu@st.com>
* Yannick Fertre <yannick.fertre@st.com>
* Fabien Dessenne <fabien.dessenne@st.com>
* Mickael Reulier <mickael.reulier@st.com>
*
* License terms: GNU General Public License (GPL), version 2
*/
#ifndef _LTDC_H_
#define _LTDC_H_
struct ltdc_caps {
u32 hw_version; /* hardware version */
u32 nb_layers; /* number of supported layers */
u32 reg_ofs; /* register offset for applicable regs */
u32 bus_width; /* bus width (32 or 64 bits) */
const u32 *pix_fmt_hw; /* supported pixel formats */
};
struct ltdc_device {
struct drm_fbdev_cma *fbdev;
void __iomem *regs;
struct clk *pixel_clk; /* lcd pixel clock */
struct drm_panel *panel;
struct mutex err_lock; /* protecting error_status */
struct ltdc_caps caps;
u32 clut[256]; /* color look up table */
u32 error_status;
u32 irq_status;
};
int ltdc_crtc_enable_vblank(struct drm_device *dev, unsigned int pipe);
void ltdc_crtc_disable_vblank(struct drm_device *dev, unsigned int pipe);
int ltdc_load(struct drm_device *ddev);
void ltdc_unload(struct drm_device *ddev);
#endif
...@@ -892,7 +892,7 @@ static int tegra_drm_context_cleanup(int id, void *p, void *data) ...@@ -892,7 +892,7 @@ static int tegra_drm_context_cleanup(int id, void *p, void *data)
return 0; return 0;
} }
static void tegra_drm_preclose(struct drm_device *drm, struct drm_file *file) static void tegra_drm_postclose(struct drm_device *drm, struct drm_file *file)
{ {
struct tegra_drm_file *fpriv = file->driver_priv; struct tegra_drm_file *fpriv = file->driver_priv;
...@@ -960,7 +960,7 @@ static struct drm_driver tegra_drm_driver = { ...@@ -960,7 +960,7 @@ static struct drm_driver tegra_drm_driver = {
.load = tegra_drm_load, .load = tegra_drm_load,
.unload = tegra_drm_unload, .unload = tegra_drm_unload,
.open = tegra_drm_open, .open = tegra_drm_open,
.preclose = tegra_drm_preclose, .postclose = tegra_drm_postclose,
.lastclose = tegra_drm_lastclose, .lastclose = tegra_drm_lastclose,
#if defined(CONFIG_DEBUG_FS) #if defined(CONFIG_DEBUG_FS)
......
...@@ -9,6 +9,7 @@ vc4-y := \ ...@@ -9,6 +9,7 @@ vc4-y := \
vc4_drv.o \ vc4_drv.o \
vc4_dpi.o \ vc4_dpi.o \
vc4_dsi.o \ vc4_dsi.o \
vc4_fence.o \
vc4_kms.o \ vc4_kms.o \
vc4_gem.o \ vc4_gem.o \
vc4_hdmi.o \ vc4_hdmi.o \
......
...@@ -19,6 +19,8 @@ ...@@ -19,6 +19,8 @@
* rendering can return quickly. * rendering can return quickly.
*/ */
#include <linux/dma-buf.h>
#include "vc4_drv.h" #include "vc4_drv.h"
#include "uapi/drm/vc4_drm.h" #include "uapi/drm/vc4_drm.h"
...@@ -88,6 +90,10 @@ static void vc4_bo_destroy(struct vc4_bo *bo) ...@@ -88,6 +90,10 @@ static void vc4_bo_destroy(struct vc4_bo *bo)
vc4->bo_stats.num_allocated--; vc4->bo_stats.num_allocated--;
vc4->bo_stats.size_allocated -= obj->size; vc4->bo_stats.size_allocated -= obj->size;
if (bo->resv == &bo->_resv)
reservation_object_fini(bo->resv);
drm_gem_cma_free_object(obj); drm_gem_cma_free_object(obj);
} }
...@@ -244,8 +250,12 @@ struct vc4_bo *vc4_bo_create(struct drm_device *dev, size_t unaligned_size, ...@@ -244,8 +250,12 @@ struct vc4_bo *vc4_bo_create(struct drm_device *dev, size_t unaligned_size,
return ERR_PTR(-ENOMEM); return ERR_PTR(-ENOMEM);
} }
} }
bo = to_vc4_bo(&cma_obj->base);
return to_vc4_bo(&cma_obj->base); bo->resv = &bo->_resv;
reservation_object_init(bo->resv);
return bo;
} }
int vc4_dumb_create(struct drm_file *file_priv, int vc4_dumb_create(struct drm_file *file_priv,
...@@ -369,6 +379,13 @@ static void vc4_bo_cache_time_timer(unsigned long data) ...@@ -369,6 +379,13 @@ static void vc4_bo_cache_time_timer(unsigned long data)
schedule_work(&vc4->bo_cache.time_work); schedule_work(&vc4->bo_cache.time_work);
} }
struct reservation_object *vc4_prime_res_obj(struct drm_gem_object *obj)
{
struct vc4_bo *bo = to_vc4_bo(obj);
return bo->resv;
}
struct dma_buf * struct dma_buf *
vc4_prime_export(struct drm_device *dev, struct drm_gem_object *obj, int flags) vc4_prime_export(struct drm_device *dev, struct drm_gem_object *obj, int flags)
{ {
...@@ -440,6 +457,24 @@ void *vc4_prime_vmap(struct drm_gem_object *obj) ...@@ -440,6 +457,24 @@ void *vc4_prime_vmap(struct drm_gem_object *obj)
return drm_gem_cma_prime_vmap(obj); return drm_gem_cma_prime_vmap(obj);
} }
struct drm_gem_object *
vc4_prime_import_sg_table(struct drm_device *dev,
struct dma_buf_attachment *attach,
struct sg_table *sgt)
{
struct drm_gem_object *obj;
struct vc4_bo *bo;
obj = drm_gem_cma_prime_import_sg_table(dev, attach, sgt);
if (IS_ERR(obj))
return obj;
bo = to_vc4_bo(obj);
bo->resv = attach->dmabuf->resv;
return obj;
}
int vc4_create_bo_ioctl(struct drm_device *dev, void *data, int vc4_create_bo_ioctl(struct drm_device *dev, void *data,
struct drm_file *file_priv) struct drm_file *file_priv)
{ {
......
...@@ -151,10 +151,10 @@ int vc4_crtc_debugfs_regs(struct seq_file *m, void *unused) ...@@ -151,10 +151,10 @@ int vc4_crtc_debugfs_regs(struct seq_file *m, void *unused)
} }
#endif #endif
int vc4_crtc_get_scanoutpos(struct drm_device *dev, unsigned int crtc_id, bool vc4_crtc_get_scanoutpos(struct drm_device *dev, unsigned int crtc_id,
unsigned int flags, int *vpos, int *hpos, bool in_vblank_irq, int *vpos, int *hpos,
ktime_t *stime, ktime_t *etime, ktime_t *stime, ktime_t *etime,
const struct drm_display_mode *mode) const struct drm_display_mode *mode)
{ {
struct vc4_dev *vc4 = to_vc4_dev(dev); struct vc4_dev *vc4 = to_vc4_dev(dev);
struct drm_crtc *crtc = drm_crtc_from_index(dev, crtc_id); struct drm_crtc *crtc = drm_crtc_from_index(dev, crtc_id);
...@@ -162,7 +162,7 @@ int vc4_crtc_get_scanoutpos(struct drm_device *dev, unsigned int crtc_id, ...@@ -162,7 +162,7 @@ int vc4_crtc_get_scanoutpos(struct drm_device *dev, unsigned int crtc_id,
u32 val; u32 val;
int fifo_lines; int fifo_lines;
int vblank_lines; int vblank_lines;
int ret = 0; bool ret = false;
/* preempt_disable_rt() should go right here in PREEMPT_RT patchset. */ /* preempt_disable_rt() should go right here in PREEMPT_RT patchset. */
...@@ -198,7 +198,7 @@ int vc4_crtc_get_scanoutpos(struct drm_device *dev, unsigned int crtc_id, ...@@ -198,7 +198,7 @@ int vc4_crtc_get_scanoutpos(struct drm_device *dev, unsigned int crtc_id,
fifo_lines = vc4_crtc->cob_size / mode->crtc_hdisplay; fifo_lines = vc4_crtc->cob_size / mode->crtc_hdisplay;
if (fifo_lines > 0) if (fifo_lines > 0)
ret |= DRM_SCANOUTPOS_VALID; ret = true;
/* HVS more than fifo_lines into frame for compositing? */ /* HVS more than fifo_lines into frame for compositing? */
if (*vpos > fifo_lines) { if (*vpos > fifo_lines) {
...@@ -216,7 +216,6 @@ int vc4_crtc_get_scanoutpos(struct drm_device *dev, unsigned int crtc_id, ...@@ -216,7 +216,6 @@ int vc4_crtc_get_scanoutpos(struct drm_device *dev, unsigned int crtc_id,
*/ */
*vpos -= fifo_lines + 1; *vpos -= fifo_lines + 1;
ret |= DRM_SCANOUTPOS_ACCURATE;
return ret; return ret;
} }
...@@ -229,10 +228,9 @@ int vc4_crtc_get_scanoutpos(struct drm_device *dev, unsigned int crtc_id, ...@@ -229,10 +228,9 @@ int vc4_crtc_get_scanoutpos(struct drm_device *dev, unsigned int crtc_id,
* We can't get meaningful readings wrt. scanline position of the PV * We can't get meaningful readings wrt. scanline position of the PV
* and need to make things up in a approximative but consistent way. * and need to make things up in a approximative but consistent way.
*/ */
ret |= DRM_SCANOUTPOS_IN_VBLANK;
vblank_lines = mode->vtotal - mode->vdisplay; vblank_lines = mode->vtotal - mode->vdisplay;
if (flags & DRM_CALLED_FROM_VBLIRQ) { if (in_vblank_irq) {
/* /*
* Assume the irq handler got called close to first * Assume the irq handler got called close to first
* line of vblank, so PV has about a full vblank * line of vblank, so PV has about a full vblank
...@@ -254,9 +252,10 @@ int vc4_crtc_get_scanoutpos(struct drm_device *dev, unsigned int crtc_id, ...@@ -254,9 +252,10 @@ int vc4_crtc_get_scanoutpos(struct drm_device *dev, unsigned int crtc_id,
* we are at the very beginning of vblank, as the hvs just * we are at the very beginning of vblank, as the hvs just
* started refilling, and the stime and etime timestamps * started refilling, and the stime and etime timestamps
* truly correspond to start of vblank. * truly correspond to start of vblank.
*
* Unfortunately there's no way to report this to upper levels
* and make it more useful.
*/ */
if ((val & SCALER_DISPSTATX_FULL) != SCALER_DISPSTATX_FULL)
ret |= DRM_SCANOUTPOS_ACCURATE;
} else { } else {
/* /*
* No clue where we are inside vblank. Return a vpos of zero, * No clue where we are inside vblank. Return a vpos of zero,
...@@ -270,19 +269,6 @@ int vc4_crtc_get_scanoutpos(struct drm_device *dev, unsigned int crtc_id, ...@@ -270,19 +269,6 @@ int vc4_crtc_get_scanoutpos(struct drm_device *dev, unsigned int crtc_id,
return ret; return ret;
} }
int vc4_crtc_get_vblank_timestamp(struct drm_device *dev, unsigned int crtc_id,
int *max_error, struct timeval *vblank_time,
unsigned flags)
{
struct drm_crtc *crtc = drm_crtc_from_index(dev, crtc_id);
struct drm_crtc_state *state = crtc->state;
/* Helper routine in DRM core does all the work: */
return drm_calc_vbltimestamp_from_scanoutpos(dev, crtc_id, max_error,
vblank_time, flags,
&state->adjusted_mode);
}
static void vc4_crtc_destroy(struct drm_crtc *crtc) static void vc4_crtc_destroy(struct drm_crtc *crtc)
{ {
drm_crtc_cleanup(crtc); drm_crtc_cleanup(crtc);
......
...@@ -154,7 +154,7 @@ static struct drm_driver vc4_drm_driver = { ...@@ -154,7 +154,7 @@ static struct drm_driver vc4_drm_driver = {
.irq_uninstall = vc4_irq_uninstall, .irq_uninstall = vc4_irq_uninstall,
.get_scanout_position = vc4_crtc_get_scanoutpos, .get_scanout_position = vc4_crtc_get_scanoutpos,
.get_vblank_timestamp = vc4_crtc_get_vblank_timestamp, .get_vblank_timestamp = drm_calc_vbltimestamp_from_scanoutpos,
#if defined(CONFIG_DEBUG_FS) #if defined(CONFIG_DEBUG_FS)
.debugfs_init = vc4_debugfs_init, .debugfs_init = vc4_debugfs_init,
...@@ -168,8 +168,9 @@ static struct drm_driver vc4_drm_driver = { ...@@ -168,8 +168,9 @@ static struct drm_driver vc4_drm_driver = {
.prime_fd_to_handle = drm_gem_prime_fd_to_handle, .prime_fd_to_handle = drm_gem_prime_fd_to_handle,
.gem_prime_import = drm_gem_prime_import, .gem_prime_import = drm_gem_prime_import,
.gem_prime_export = vc4_prime_export, .gem_prime_export = vc4_prime_export,
.gem_prime_res_obj = vc4_prime_res_obj,
.gem_prime_get_sg_table = drm_gem_cma_prime_get_sg_table, .gem_prime_get_sg_table = drm_gem_cma_prime_get_sg_table,
.gem_prime_import_sg_table = drm_gem_cma_prime_import_sg_table, .gem_prime_import_sg_table = vc4_prime_import_sg_table,
.gem_prime_vmap = vc4_prime_vmap, .gem_prime_vmap = vc4_prime_vmap,
.gem_prime_vunmap = drm_gem_cma_prime_vunmap, .gem_prime_vunmap = drm_gem_cma_prime_vunmap,
.gem_prime_mmap = vc4_prime_mmap, .gem_prime_mmap = vc4_prime_mmap,
...@@ -334,6 +335,7 @@ static int vc4_platform_drm_remove(struct platform_device *pdev) ...@@ -334,6 +335,7 @@ static int vc4_platform_drm_remove(struct platform_device *pdev)
static const struct of_device_id vc4_of_match[] = { static const struct of_device_id vc4_of_match[] = {
{ .compatible = "brcm,bcm2835-vc4", }, { .compatible = "brcm,bcm2835-vc4", },
{ .compatible = "brcm,cygnus-vc4", },
{}, {},
}; };
MODULE_DEVICE_TABLE(of, vc4_of_match); MODULE_DEVICE_TABLE(of, vc4_of_match);
......
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
...@@ -182,8 +182,7 @@ static void emit_tile(struct vc4_exec_info *exec, ...@@ -182,8 +182,7 @@ static void emit_tile(struct vc4_exec_info *exec,
if (has_bin) { if (has_bin) {
rcl_u8(setup, VC4_PACKET_BRANCH_TO_SUB_LIST); rcl_u8(setup, VC4_PACKET_BRANCH_TO_SUB_LIST);
rcl_u32(setup, (exec->tile_bo->paddr + rcl_u32(setup, (exec->tile_alloc_offset +
exec->tile_alloc_offset +
(y * exec->bin_tiles_x + x) * 32)); (y * exec->bin_tiles_x + x) * 32));
} }
......
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册