2009-09-15 22:57:34 +02:00
/*
* Copyright © 2009
*
* Permission is hereby granted , free of charge , to any person obtaining a
* copy of this software and associated documentation files ( the " Software " ) ,
* to deal in the Software without restriction , including without limitation
* the rights to use , copy , modify , merge , publish , distribute , sublicense ,
* and / or sell copies of the Software , and to permit persons to whom the
* Software is furnished to do so , subject to the following conditions :
*
* The above copyright notice and this permission notice ( including the next
* paragraph ) shall be included in all copies or substantial portions of the
* Software .
*
* THE SOFTWARE IS PROVIDED " AS IS " , WITHOUT WARRANTY OF ANY KIND , EXPRESS OR
* IMPLIED , INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY ,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT . IN NO EVENT SHALL
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM , DAMAGES OR OTHER
* LIABILITY , WHETHER IN AN ACTION OF CONTRACT , TORT OR OTHERWISE , ARISING FROM ,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE .
*
* Authors :
* Daniel Vetter < daniel @ ffwll . ch >
*
* Derived from Xorg ddx , xf86 - video - intel , src / i830_video . c
*/
2012-10-02 18:01:07 +01:00
# include <drm/drmP.h>
# include <drm/i915_drm.h>
2009-09-15 22:57:34 +02:00
# include "i915_drv.h"
# include "i915_reg.h"
# include "intel_drv.h"
2016-08-04 16:32:35 +01:00
# include "intel_frontbuffer.h"
2009-09-15 22:57:34 +02:00
/* Limits for overlay size. According to intel doc, the real limits are:
* Y width : 4095 , UV width ( planar ) : 2047 , Y height : 2047 ,
* UV width ( planar ) : * 1023. But the xorg thinks 2048 for height and width . Use
* the mininum of both . */
# define IMAGE_MAX_WIDTH 2048
# define IMAGE_MAX_HEIGHT 2046 /* 2 * 1023 */
/* on 830 and 845 these large limits result in the card hanging */
# define IMAGE_MAX_WIDTH_LEGACY 1024
# define IMAGE_MAX_HEIGHT_LEGACY 1088
/* overlay register definitions */
/* OCMD register */
# define OCMD_TILED_SURFACE (0x1<<19)
# define OCMD_MIRROR_MASK (0x3<<17)
# define OCMD_MIRROR_MODE (0x3<<17)
# define OCMD_MIRROR_HORIZONTAL (0x1<<17)
# define OCMD_MIRROR_VERTICAL (0x2<<17)
# define OCMD_MIRROR_BOTH (0x3<<17)
# define OCMD_BYTEORDER_MASK (0x3<<14) /* zero for YUYV or FOURCC YUY2 */
# define OCMD_UV_SWAP (0x1<<14) /* YVYU */
# define OCMD_Y_SWAP (0x2<<14) /* UYVY or FOURCC UYVY */
# define OCMD_Y_AND_UV_SWAP (0x3<<14) /* VYUY */
# define OCMD_SOURCE_FORMAT_MASK (0xf<<10)
# define OCMD_RGB_888 (0x1<<10) /* not in i965 Intel docs */
# define OCMD_RGB_555 (0x2<<10) /* not in i965 Intel docs */
# define OCMD_RGB_565 (0x3<<10) /* not in i965 Intel docs */
# define OCMD_YUV_422_PACKED (0x8<<10)
# define OCMD_YUV_411_PACKED (0x9<<10) /* not in i965 Intel docs */
# define OCMD_YUV_420_PLANAR (0xc<<10)
# define OCMD_YUV_422_PLANAR (0xd<<10)
# define OCMD_YUV_410_PLANAR (0xe<<10) /* also 411 */
# define OCMD_TVSYNCFLIP_PARITY (0x1<<9)
# define OCMD_TVSYNCFLIP_ENABLE (0x1<<7)
2010-07-13 13:52:17 +01:00
# define OCMD_BUF_TYPE_MASK (0x1<<5)
2009-09-15 22:57:34 +02:00
# define OCMD_BUF_TYPE_FRAME (0x0<<5)
# define OCMD_BUF_TYPE_FIELD (0x1<<5)
# define OCMD_TEST_MODE (0x1<<4)
# define OCMD_BUFFER_SELECT (0x3<<2)
# define OCMD_BUFFER0 (0x0<<2)
# define OCMD_BUFFER1 (0x1<<2)
# define OCMD_FIELD_SELECT (0x1<<2)
# define OCMD_FIELD0 (0x0<<1)
# define OCMD_FIELD1 (0x1<<1)
# define OCMD_ENABLE (0x1<<0)
/* OCONFIG register */
# define OCONF_PIPE_MASK (0x1<<18)
# define OCONF_PIPE_A (0x0<<18)
# define OCONF_PIPE_B (0x1<<18)
# define OCONF_GAMMA2_ENABLE (0x1<<16)
# define OCONF_CSC_MODE_BT601 (0x0<<5)
# define OCONF_CSC_MODE_BT709 (0x1<<5)
# define OCONF_CSC_BYPASS (0x1<<4)
# define OCONF_CC_OUT_8BIT (0x1<<3)
# define OCONF_TEST_MODE (0x1<<2)
# define OCONF_THREE_LINE_BUFFER (0x1<<0)
# define OCONF_TWO_LINE_BUFFER (0x0<<0)
/* DCLRKM (dst-key) register */
# define DST_KEY_ENABLE (0x1<<31)
# define CLK_RGB24_MASK 0x0
# define CLK_RGB16_MASK 0x070307
# define CLK_RGB15_MASK 0x070707
# define CLK_RGB8I_MASK 0xffffff
# define RGB16_TO_COLORKEY(c) \
( ( ( c & 0xF800 ) < < 8 ) | ( ( c & 0x07E0 ) < < 5 ) | ( ( c & 0x001F ) < < 3 ) )
# define RGB15_TO_COLORKEY(c) \
( ( ( c & 0x7c00 ) < < 9 ) | ( ( c & 0x03E0 ) < < 6 ) | ( ( c & 0x001F ) < < 3 ) )
/* overlay flip addr flag */
# define OFC_UPDATE 0x1
/* polyphase filter coefficients */
# define N_HORIZ_Y_TAPS 5
# define N_VERT_Y_TAPS 3
# define N_HORIZ_UV_TAPS 3
# define N_VERT_UV_TAPS 3
# define N_PHASES 17
# define MAX_TAPS 5
/* memory bufferd overlay registers */
struct overlay_registers {
2011-08-16 15:34:10 -04:00
u32 OBUF_0Y ;
u32 OBUF_1Y ;
u32 OBUF_0U ;
u32 OBUF_0V ;
u32 OBUF_1U ;
u32 OBUF_1V ;
u32 OSTRIDE ;
u32 YRGB_VPH ;
u32 UV_VPH ;
u32 HORZ_PH ;
u32 INIT_PHS ;
u32 DWINPOS ;
u32 DWINSZ ;
u32 SWIDTH ;
u32 SWIDTHSW ;
u32 SHEIGHT ;
u32 YRGBSCALE ;
u32 UVSCALE ;
u32 OCLRC0 ;
u32 OCLRC1 ;
u32 DCLRKV ;
u32 DCLRKM ;
u32 SCLRKVH ;
u32 SCLRKVL ;
u32 SCLRKEN ;
u32 OCONFIG ;
u32 OCMD ;
u32 RESERVED1 ; /* 0x6C */
u32 OSTART_0Y ;
u32 OSTART_1Y ;
u32 OSTART_0U ;
u32 OSTART_0V ;
u32 OSTART_1U ;
u32 OSTART_1V ;
u32 OTILEOFF_0Y ;
u32 OTILEOFF_1Y ;
u32 OTILEOFF_0U ;
u32 OTILEOFF_0V ;
u32 OTILEOFF_1U ;
u32 OTILEOFF_1V ;
u32 FASTHSCALE ; /* 0xA0 */
u32 UVSCALEV ; /* 0xA4 */
u32 RESERVEDC [ ( 0x200 - 0xA8 ) / 4 ] ; /* 0xA8 - 0x1FC */
u16 Y_VCOEFS [ N_VERT_Y_TAPS * N_PHASES ] ; /* 0x200 */
u16 RESERVEDD [ 0x100 / 2 - N_VERT_Y_TAPS * N_PHASES ] ;
u16 Y_HCOEFS [ N_HORIZ_Y_TAPS * N_PHASES ] ; /* 0x300 */
u16 RESERVEDE [ 0x200 / 2 - N_HORIZ_Y_TAPS * N_PHASES ] ;
u16 UV_VCOEFS [ N_VERT_UV_TAPS * N_PHASES ] ; /* 0x500 */
u16 RESERVEDF [ 0x100 / 2 - N_VERT_UV_TAPS * N_PHASES ] ;
u16 UV_HCOEFS [ N_HORIZ_UV_TAPS * N_PHASES ] ; /* 0x600 */
u16 RESERVEDG [ 0x100 / 2 - N_HORIZ_UV_TAPS * N_PHASES ] ;
2009-09-15 22:57:34 +02:00
} ;
2010-08-12 13:53:37 +01:00
struct intel_overlay {
2016-05-12 12:43:23 +01:00
struct drm_i915_private * i915 ;
2010-08-12 13:53:37 +01:00
struct intel_crtc * crtc ;
2016-08-15 10:49:01 +01:00
struct i915_vma * vma ;
struct i915_vma * old_vma ;
2015-03-31 10:37:23 +03:00
bool active ;
bool pfit_active ;
2010-08-12 13:53:37 +01:00
u32 pfit_vscale_ratio ; /* shifted-point number, (1<<12) == 1.0 */
2015-04-02 10:35:08 +01:00
u32 color_key : 24 ;
u32 color_key_enabled : 1 ;
2010-08-12 13:53:37 +01:00
u32 brightness , contrast , saturation ;
u32 old_xscale , old_yscale ;
/* register access */
u32 flip_addr ;
struct drm_i915_gem_object * reg_bo ;
/* flip handling */
2016-08-04 07:52:37 +01:00
struct i915_gem_active last_flip ;
2010-08-12 13:53:37 +01:00
} ;
2009-09-15 22:57:34 +02:00
2016-12-07 19:28:12 +02:00
static void i830_overlay_clock_gating ( struct drm_i915_private * dev_priv ,
bool enable )
{
struct pci_dev * pdev = dev_priv - > drm . pdev ;
u8 val ;
/* WA_OVERLAY_CLKGATE:alm */
if ( enable )
I915_WRITE ( DSPCLK_GATE_D , 0 ) ;
else
I915_WRITE ( DSPCLK_GATE_D , OVRUNIT_CLOCK_GATE_DISABLE ) ;
/* WA_DISABLE_L2CACHE_CLOCK_GATING:alm */
pci_bus_read_config_byte ( pdev - > bus ,
PCI_DEVFN ( 0 , 0 ) , I830_CLOCK_GATE , & val ) ;
if ( enable )
val & = ~ I830_L2_CACHE_CLOCK_GATE_DISABLE ;
else
val | = I830_L2_CACHE_CLOCK_GATE_DISABLE ;
pci_bus_write_config_byte ( pdev - > bus ,
PCI_DEVFN ( 0 , 0 ) , I830_CLOCK_GATE , val ) ;
}
2012-04-16 14:07:43 -07:00
static struct overlay_registers __iomem *
2010-08-12 10:35:26 +01:00
intel_overlay_map_regs ( struct intel_overlay * overlay )
2009-09-15 22:57:34 +02:00
{
2016-05-12 12:43:23 +01:00
struct drm_i915_private * dev_priv = overlay - > i915 ;
2012-04-16 14:07:43 -07:00
struct overlay_registers __iomem * regs ;
2009-09-15 22:57:34 +02:00
2016-05-12 12:43:23 +01:00
if ( OVERLAY_NEEDS_PHYSICAL ( dev_priv ) )
2014-05-21 12:42:56 +01:00
regs = ( struct overlay_registers __iomem * ) overlay - > reg_bo - > phys_handle - > vaddr ;
2010-08-12 12:02:11 +01:00
else
2016-08-19 16:54:27 +01:00
regs = io_mapping_map_wc ( & dev_priv - > ggtt . mappable ,
2016-04-28 09:56:37 +01:00
overlay - > flip_addr ,
PAGE_SIZE ) ;
2009-09-15 22:57:34 +02:00
2010-08-12 12:02:11 +01:00
return regs ;
2010-08-12 10:35:26 +01:00
}
2009-09-15 22:57:34 +02:00
2010-08-12 12:02:11 +01:00
static void intel_overlay_unmap_regs ( struct intel_overlay * overlay ,
2012-04-16 14:07:43 -07:00
struct overlay_registers __iomem * regs )
2010-08-12 10:35:26 +01:00
{
2016-05-12 12:43:23 +01:00
if ( ! OVERLAY_NEEDS_PHYSICAL ( overlay - > i915 ) )
2010-08-12 12:02:11 +01:00
io_mapping_unmap ( regs ) ;
2009-09-15 22:57:34 +02:00
}
2016-08-04 07:52:37 +01:00
static void intel_overlay_submit_request ( struct intel_overlay * overlay ,
2015-05-29 17:43:47 +01:00
struct drm_i915_gem_request * req ,
2016-08-04 07:52:37 +01:00
i915_gem_retire_fn retire )
2009-09-15 22:57:34 +02:00
{
2016-08-04 07:52:37 +01:00
GEM_BUG_ON ( i915_gem_active_peek ( & overlay - > last_flip ,
& overlay - > i915 - > drm . struct_mutex ) ) ;
2016-12-07 17:56:47 +00:00
i915_gem_active_set_retire_fn ( & overlay - > last_flip , retire ,
& overlay - > i915 - > drm . struct_mutex ) ;
2016-08-04 07:52:37 +01:00
i915_gem_active_set ( & overlay - > last_flip , req ) ;
2015-05-29 17:43:49 +01:00
i915_add_request ( req ) ;
2016-08-04 07:52:37 +01:00
}
2012-09-26 13:47:30 +01:00
2016-08-04 07:52:37 +01:00
static int intel_overlay_do_wait_request ( struct intel_overlay * overlay ,
struct drm_i915_gem_request * req ,
i915_gem_retire_fn retire )
{
intel_overlay_submit_request ( overlay , req , retire ) ;
return i915_gem_active_retire ( & overlay - > last_flip ,
& overlay - > i915 - > drm . struct_mutex ) ;
2009-09-15 22:57:34 +02:00
}
2016-08-02 22:50:26 +01:00
static struct drm_i915_gem_request * alloc_request ( struct intel_overlay * overlay )
{
struct drm_i915_private * dev_priv = overlay - > i915 ;
drm/i915: Allocate intel_engine_cs structure only for the enabled engines
With the possibility of addition of many more number of rings in future,
the drm_i915_private structure could bloat as an array, of type
intel_engine_cs, is embedded inside it.
struct intel_engine_cs engine[I915_NUM_ENGINES];
Though this is still fine as generally there is only a single instance of
drm_i915_private structure used, but not all of the possible rings would be
enabled or active on most of the platforms. Some memory can be saved by
allocating intel_engine_cs structure only for the enabled/active engines.
Currently the engine/ring ID is kept static and dev_priv->engine[] is simply
indexed using the enums defined in intel_engine_id.
To save memory and continue using the static engine/ring IDs, 'engine' is
defined as an array of pointers.
struct intel_engine_cs *engine[I915_NUM_ENGINES];
dev_priv->engine[engine_ID] will be NULL for disabled engine instances.
There is a text size reduction of 928 bytes, from 1028200 to 1027272, for
i915.o file (but for i915.ko file text size remain same as 1193131 bytes).
v2:
- Remove the engine iterator field added in drm_i915_private structure,
instead pass a local iterator variable to the for_each_engine**
macros. (Chris)
- Do away with intel_engine_initialized() and instead directly use the
NULL pointer check on engine pointer. (Chris)
v3:
- Remove for_each_engine_id() macro, as the updated macro for_each_engine()
can be used in place of it. (Chris)
- Protect the access to Render engine Fault register with a NULL check, as
engine specific init is done later in Driver load sequence.
v4:
- Use !!dev_priv->engine[VCS] style for the engine check in getparam. (Chris)
- Kill the superfluous init_engine_lists().
v5:
- Cleanup the intel_engines_init() & intel_engines_setup(), with respect to
allocation of intel_engine_cs structure. (Chris)
v6:
- Rebase.
v7:
- Optimize the for_each_engine_masked() macro. (Chris)
- Change the type of 'iter' local variable to enum intel_engine_id. (Chris)
- Rebase.
v8: Rebase.
v9: Rebase.
v10:
- For index calculation use engine ID instead of pointer based arithmetic in
intel_engine_sync_index() as engine pointers are not contiguous now (Chris)
- For appropriateness, rename local enum variable 'iter' to 'id'. (Joonas)
- Use for_each_engine macro for cleanup in intel_engines_init() and remove
check for NULL engine pointer in cleanup() routines. (Joonas)
v11: Rebase.
Cc: Chris Wilson <chris@chris-wilson.co.uk>
Signed-off-by: Akash Goel <akash.goel@intel.com>
Reviewed-by: Joonas Lahtinen <joonas.lahtinen@linux.intel.com>
Signed-off-by: Tvrtko Ursulin <tvrtko.ursulin@intel.com>
Link: http://patchwork.freedesktop.org/patch/msgid/1476378888-7372-1-git-send-email-akash.goel@intel.com
2016-10-13 22:44:48 +05:30
struct intel_engine_cs * engine = dev_priv - > engine [ RCS ] ;
2016-08-02 22:50:26 +01:00
return i915_gem_request_alloc ( engine , dev_priv - > kernel_context ) ;
}
2009-09-15 22:57:34 +02:00
/* overlay needs to be disable in OCMD reg */
static int intel_overlay_on ( struct intel_overlay * overlay )
{
2016-05-12 12:43:23 +01:00
struct drm_i915_private * dev_priv = overlay - > i915 ;
2015-05-29 17:43:47 +01:00
struct drm_i915_gem_request * req ;
2017-02-14 11:32:42 +00:00
u32 * cs ;
2009-09-15 22:57:34 +02:00
2015-03-31 10:37:22 +03:00
WARN_ON ( overlay - > active ) ;
2016-05-12 12:43:23 +01:00
WARN_ON ( IS_I830 ( dev_priv ) & & ! ( dev_priv - > quirks & QUIRK_PIPEA_FORCE ) ) ;
2010-07-16 17:13:01 +01:00
2016-08-02 22:50:26 +01:00
req = alloc_request ( overlay ) ;
drm/i915: simplify allocation of driver-internal requests
There are a number of places where the driver needs a request, but isn't
working on behalf of any specific user or in a specific context. At
present, we associate them with the per-engine default context. A future
patch will abolish those per-engine context pointers; but we can already
eliminate a lot of the references to them, just by making the allocator
allow NULL as a shorthand for "an appropriate context for this ring",
which will mean that the callers don't need to know anything about how
the "appropriate context" is found (e.g. per-ring vs per-device, etc).
So this patch renames the existing i915_gem_request_alloc(), and makes
it local (static inline), and replaces it with a wrapper that provides
a default if the context is NULL, and also has a nicer calling
convention (doesn't require a pointer to an output parameter). Then we
change all callers to use the new convention:
OLD:
err = i915_gem_request_alloc(ring, user_ctx, &req);
if (err) ...
NEW:
req = i915_gem_request_alloc(ring, user_ctx);
if (IS_ERR(req)) ...
OLD:
err = i915_gem_request_alloc(ring, ring->default_context, &req);
if (err) ...
NEW:
req = i915_gem_request_alloc(ring, NULL);
if (IS_ERR(req)) ...
v4: Rebased
Signed-off-by: Dave Gordon <david.s.gordon@intel.com>
Reviewed-by: Nick Hoath <nicholas.hoath@intel.com>
Link: http://patchwork.freedesktop.org/patch/msgid/1453230175-19330-2-git-send-email-david.s.gordon@intel.com
Signed-off-by: Daniel Vetter <daniel.vetter@ffwll.ch>
2016-01-19 19:02:53 +00:00
if ( IS_ERR ( req ) )
return PTR_ERR ( req ) ;
2010-10-27 12:45:26 +01:00
2017-02-14 11:32:42 +00:00
cs = intel_ring_begin ( req , 4 ) ;
if ( IS_ERR ( cs ) ) {
2017-03-17 11:47:09 +00:00
i915_add_request ( req ) ;
2017-02-14 11:32:42 +00:00
return PTR_ERR ( cs ) ;
2015-05-29 17:43:47 +01:00
}
2015-03-31 10:37:24 +03:00
overlay - > active = true ;
2016-12-07 19:28:12 +02:00
if ( IS_I830 ( dev_priv ) )
i830_overlay_clock_gating ( dev_priv , false ) ;
2017-02-14 11:32:42 +00:00
* cs + + = MI_OVERLAY_FLIP | MI_OVERLAY_ON ;
* cs + + = overlay - > flip_addr | OFC_UPDATE ;
* cs + + = MI_WAIT_FOR_EVENT | MI_WAIT_FOR_OVERLAY_FLIP ;
* cs + + = MI_NOOP ;
intel_ring_advance ( req , cs ) ;
2009-09-15 22:57:34 +02:00
2015-05-29 17:43:47 +01:00
return intel_overlay_do_wait_request ( overlay , req , NULL ) ;
2009-09-15 22:57:34 +02:00
}
2016-12-07 19:28:06 +02:00
static void intel_overlay_flip_prepare ( struct intel_overlay * overlay ,
struct i915_vma * vma )
{
enum pipe pipe = overlay - > crtc - > pipe ;
WARN_ON ( overlay - > old_vma ) ;
i915_gem_track_fb ( overlay - > vma ? overlay - > vma - > obj : NULL ,
vma ? vma - > obj : NULL ,
INTEL_FRONTBUFFER_OVERLAY ( pipe ) ) ;
intel_frontbuffer_flip_prepare ( overlay - > i915 ,
INTEL_FRONTBUFFER_OVERLAY ( pipe ) ) ;
overlay - > old_vma = overlay - > vma ;
if ( vma )
overlay - > vma = i915_vma_get ( vma ) ;
else
overlay - > vma = NULL ;
}
2009-09-15 22:57:34 +02:00
/* overlay needs to be enabled in OCMD reg */
2010-08-12 12:36:12 +01:00
static int intel_overlay_continue ( struct intel_overlay * overlay ,
2016-12-07 19:28:06 +02:00
struct i915_vma * vma ,
2010-08-12 12:36:12 +01:00
bool load_polyphase_filter )
2009-09-15 22:57:34 +02:00
{
2016-05-12 12:43:23 +01:00
struct drm_i915_private * dev_priv = overlay - > i915 ;
2015-05-29 17:43:47 +01:00
struct drm_i915_gem_request * req ;
2009-09-15 22:57:34 +02:00
u32 flip_addr = overlay - > flip_addr ;
2017-02-14 11:32:42 +00:00
u32 tmp , * cs ;
2009-09-15 22:57:34 +02:00
2015-03-31 10:37:22 +03:00
WARN_ON ( ! overlay - > active ) ;
2009-09-15 22:57:34 +02:00
if ( load_polyphase_filter )
flip_addr | = OFC_UPDATE ;
/* check for underruns */
tmp = I915_READ ( DOVSTA ) ;
if ( tmp & ( 1 < < 17 ) )
DRM_DEBUG ( " overlay underrun, DOVSTA: %x \n " , tmp ) ;
2016-08-02 22:50:26 +01:00
req = alloc_request ( overlay ) ;
drm/i915: simplify allocation of driver-internal requests
There are a number of places where the driver needs a request, but isn't
working on behalf of any specific user or in a specific context. At
present, we associate them with the per-engine default context. A future
patch will abolish those per-engine context pointers; but we can already
eliminate a lot of the references to them, just by making the allocator
allow NULL as a shorthand for "an appropriate context for this ring",
which will mean that the callers don't need to know anything about how
the "appropriate context" is found (e.g. per-ring vs per-device, etc).
So this patch renames the existing i915_gem_request_alloc(), and makes
it local (static inline), and replaces it with a wrapper that provides
a default if the context is NULL, and also has a nicer calling
convention (doesn't require a pointer to an output parameter). Then we
change all callers to use the new convention:
OLD:
err = i915_gem_request_alloc(ring, user_ctx, &req);
if (err) ...
NEW:
req = i915_gem_request_alloc(ring, user_ctx);
if (IS_ERR(req)) ...
OLD:
err = i915_gem_request_alloc(ring, ring->default_context, &req);
if (err) ...
NEW:
req = i915_gem_request_alloc(ring, NULL);
if (IS_ERR(req)) ...
v4: Rebased
Signed-off-by: Dave Gordon <david.s.gordon@intel.com>
Reviewed-by: Nick Hoath <nicholas.hoath@intel.com>
Link: http://patchwork.freedesktop.org/patch/msgid/1453230175-19330-2-git-send-email-david.s.gordon@intel.com
Signed-off-by: Daniel Vetter <daniel.vetter@ffwll.ch>
2016-01-19 19:02:53 +00:00
if ( IS_ERR ( req ) )
return PTR_ERR ( req ) ;
2012-09-26 13:47:30 +01:00
2017-02-14 11:32:42 +00:00
cs = intel_ring_begin ( req , 2 ) ;
if ( IS_ERR ( cs ) ) {
2017-03-17 11:47:09 +00:00
i915_add_request ( req ) ;
2017-02-14 11:32:42 +00:00
return PTR_ERR ( cs ) ;
2015-05-29 17:43:47 +01:00
}
2017-02-14 11:32:42 +00:00
* cs + + = MI_OVERLAY_FLIP | MI_OVERLAY_CONTINUE ;
* cs + + = flip_addr ;
intel_ring_advance ( req , cs ) ;
2009-09-15 22:57:36 +02:00
2016-12-07 19:28:06 +02:00
intel_overlay_flip_prepare ( overlay , vma ) ;
2016-08-04 07:52:37 +01:00
intel_overlay_submit_request ( overlay , req , NULL ) ;
2015-05-29 17:43:24 +01:00
return 0 ;
2009-09-15 22:57:36 +02:00
}
2016-12-07 19:28:06 +02:00
static void intel_overlay_release_old_vma ( struct intel_overlay * overlay )
2009-09-15 22:57:36 +02:00
{
2016-08-15 10:49:01 +01:00
struct i915_vma * vma ;
2009-09-15 22:57:36 +02:00
2016-08-15 10:49:01 +01:00
vma = fetch_and_zero ( & overlay - > old_vma ) ;
if ( WARN_ON ( ! vma ) )
return ;
2016-08-04 07:52:37 +01:00
2016-12-07 19:28:06 +02:00
intel_frontbuffer_flip_complete ( overlay - > i915 ,
INTEL_FRONTBUFFER_OVERLAY ( overlay - > crtc - > pipe ) ) ;
2009-09-15 22:57:36 +02:00
2016-08-15 10:49:06 +01:00
i915_gem_object_unpin_from_display_plane ( vma ) ;
2016-08-15 10:49:01 +01:00
i915_vma_put ( vma ) ;
2010-08-12 14:03:48 +01:00
}
2009-09-15 22:57:37 +02:00
2016-12-07 19:28:06 +02:00
static void intel_overlay_release_old_vid_tail ( struct i915_gem_active * active ,
struct drm_i915_gem_request * req )
{
struct intel_overlay * overlay =
container_of ( active , typeof ( * overlay ) , last_flip ) ;
intel_overlay_release_old_vma ( overlay ) ;
}
2016-08-04 07:52:37 +01:00
static void intel_overlay_off_tail ( struct i915_gem_active * active ,
struct drm_i915_gem_request * req )
2010-08-12 14:03:48 +01:00
{
2016-08-04 07:52:37 +01:00
struct intel_overlay * overlay =
container_of ( active , typeof ( * overlay ) , last_flip ) ;
2016-12-07 19:28:12 +02:00
struct drm_i915_private * dev_priv = overlay - > i915 ;
2009-09-15 22:57:34 +02:00
2016-12-07 19:28:06 +02:00
intel_overlay_release_old_vma ( overlay ) ;
2009-09-15 22:57:37 +02:00
2010-08-12 14:03:48 +01:00
overlay - > crtc - > overlay = NULL ;
overlay - > crtc = NULL ;
2015-03-31 10:37:23 +03:00
overlay - > active = false ;
2016-12-07 19:28:12 +02:00
if ( IS_I830 ( dev_priv ) )
i830_overlay_clock_gating ( dev_priv , true ) ;
2009-09-15 22:57:34 +02:00
}
/* overlay needs to be disabled in OCMD reg */
2011-02-21 14:43:56 +00:00
static int intel_overlay_off ( struct intel_overlay * overlay )
2009-09-15 22:57:34 +02:00
{
2015-05-29 17:43:47 +01:00
struct drm_i915_gem_request * req ;
2017-02-14 11:32:42 +00:00
u32 * cs , flip_addr = overlay - > flip_addr ;
2009-09-15 22:57:34 +02:00
2015-03-31 10:37:22 +03:00
WARN_ON ( ! overlay - > active ) ;
2009-09-15 22:57:34 +02:00
/* According to intel docs the overlay hw may hang (when switching
* off ) without loading the filter coeffs . It is however unclear whether
* this applies to the disabling of the overlay or to the switching off
* of the hw . Do it in both cases */
flip_addr | = OFC_UPDATE ;
2016-08-02 22:50:26 +01:00
req = alloc_request ( overlay ) ;
drm/i915: simplify allocation of driver-internal requests
There are a number of places where the driver needs a request, but isn't
working on behalf of any specific user or in a specific context. At
present, we associate them with the per-engine default context. A future
patch will abolish those per-engine context pointers; but we can already
eliminate a lot of the references to them, just by making the allocator
allow NULL as a shorthand for "an appropriate context for this ring",
which will mean that the callers don't need to know anything about how
the "appropriate context" is found (e.g. per-ring vs per-device, etc).
So this patch renames the existing i915_gem_request_alloc(), and makes
it local (static inline), and replaces it with a wrapper that provides
a default if the context is NULL, and also has a nicer calling
convention (doesn't require a pointer to an output parameter). Then we
change all callers to use the new convention:
OLD:
err = i915_gem_request_alloc(ring, user_ctx, &req);
if (err) ...
NEW:
req = i915_gem_request_alloc(ring, user_ctx);
if (IS_ERR(req)) ...
OLD:
err = i915_gem_request_alloc(ring, ring->default_context, &req);
if (err) ...
NEW:
req = i915_gem_request_alloc(ring, NULL);
if (IS_ERR(req)) ...
v4: Rebased
Signed-off-by: Dave Gordon <david.s.gordon@intel.com>
Reviewed-by: Nick Hoath <nicholas.hoath@intel.com>
Link: http://patchwork.freedesktop.org/patch/msgid/1453230175-19330-2-git-send-email-david.s.gordon@intel.com
Signed-off-by: Daniel Vetter <daniel.vetter@ffwll.ch>
2016-01-19 19:02:53 +00:00
if ( IS_ERR ( req ) )
return PTR_ERR ( req ) ;
2012-09-26 13:47:30 +01:00
2017-02-14 11:32:42 +00:00
cs = intel_ring_begin ( req , 6 ) ;
if ( IS_ERR ( cs ) ) {
2017-03-17 11:47:09 +00:00
i915_add_request ( req ) ;
2017-02-14 11:32:42 +00:00
return PTR_ERR ( cs ) ;
2015-05-29 17:43:47 +01:00
}
2009-09-15 22:57:34 +02:00
/* wait for overlay to go idle */
2017-02-14 11:32:42 +00:00
* cs + + = MI_OVERLAY_FLIP | MI_OVERLAY_CONTINUE ;
* cs + + = flip_addr ;
* cs + + = MI_WAIT_FOR_EVENT | MI_WAIT_FOR_OVERLAY_FLIP ;
2016-12-22 21:52:22 +02:00
2009-09-15 22:57:34 +02:00
/* turn overlay off */
2017-02-14 11:32:42 +00:00
* cs + + = MI_OVERLAY_FLIP | MI_OVERLAY_OFF ;
* cs + + = flip_addr ;
* cs + + = MI_WAIT_FOR_EVENT | MI_WAIT_FOR_OVERLAY_FLIP ;
2016-12-22 21:52:22 +02:00
2017-02-14 11:32:42 +00:00
intel_ring_advance ( req , cs ) ;
2009-09-15 22:57:34 +02:00
2016-12-07 19:28:06 +02:00
intel_overlay_flip_prepare ( overlay , NULL ) ;
2016-08-04 07:52:37 +01:00
return intel_overlay_do_wait_request ( overlay , req ,
intel_overlay_off_tail ) ;
2037-04-25 10:08:26 +02:00
}
2009-09-15 22:57:37 +02:00
/* recover from an interruption due to a signal
* We have to be careful not to repeat work forever an make forward progess . */
2011-02-21 14:43:56 +00:00
static int intel_overlay_recover_from_interrupt ( struct intel_overlay * overlay )
2009-09-15 22:57:37 +02:00
{
2016-08-04 07:52:37 +01:00
return i915_gem_active_retire ( & overlay - > last_flip ,
& overlay - > i915 - > drm . struct_mutex ) ;
2009-09-15 22:57:37 +02:00
}
2009-09-15 22:57:36 +02:00
/* Wait for pending overlay flip and release old frame.
* Needs to be called before the overlay register are changed
2010-08-12 10:35:26 +01:00
* via intel_overlay_ ( un ) map_regs
*/
2009-09-15 22:57:34 +02:00
static int intel_overlay_release_old_vid ( struct intel_overlay * overlay )
{
2016-05-12 12:43:23 +01:00
struct drm_i915_private * dev_priv = overlay - > i915 ;
2017-02-14 11:32:42 +00:00
u32 * cs ;
2009-09-15 22:57:34 +02:00
int ret ;
2016-07-05 10:40:23 +01:00
lockdep_assert_held ( & dev_priv - > drm . struct_mutex ) ;
2014-11-26 17:07:29 +02:00
2010-08-12 12:21:54 +01:00
/* Only wait if there is actually an old frame to release to
* guarantee forward progress .
*/
2016-08-15 10:49:01 +01:00
if ( ! overlay - > old_vma )
2009-09-15 22:57:37 +02:00
return 0 ;
2010-08-12 12:21:54 +01:00
if ( I915_READ ( ISR ) & I915_OVERLAY_PLANE_FLIP_PENDING_INTERRUPT ) {
/* synchronous slowpath */
2015-05-29 17:43:47 +01:00
struct drm_i915_gem_request * req ;
2016-08-02 22:50:26 +01:00
req = alloc_request ( overlay ) ;
drm/i915: simplify allocation of driver-internal requests
There are a number of places where the driver needs a request, but isn't
working on behalf of any specific user or in a specific context. At
present, we associate them with the per-engine default context. A future
patch will abolish those per-engine context pointers; but we can already
eliminate a lot of the references to them, just by making the allocator
allow NULL as a shorthand for "an appropriate context for this ring",
which will mean that the callers don't need to know anything about how
the "appropriate context" is found (e.g. per-ring vs per-device, etc).
So this patch renames the existing i915_gem_request_alloc(), and makes
it local (static inline), and replaces it with a wrapper that provides
a default if the context is NULL, and also has a nicer calling
convention (doesn't require a pointer to an output parameter). Then we
change all callers to use the new convention:
OLD:
err = i915_gem_request_alloc(ring, user_ctx, &req);
if (err) ...
NEW:
req = i915_gem_request_alloc(ring, user_ctx);
if (IS_ERR(req)) ...
OLD:
err = i915_gem_request_alloc(ring, ring->default_context, &req);
if (err) ...
NEW:
req = i915_gem_request_alloc(ring, NULL);
if (IS_ERR(req)) ...
v4: Rebased
Signed-off-by: Dave Gordon <david.s.gordon@intel.com>
Reviewed-by: Nick Hoath <nicholas.hoath@intel.com>
Link: http://patchwork.freedesktop.org/patch/msgid/1453230175-19330-2-git-send-email-david.s.gordon@intel.com
Signed-off-by: Daniel Vetter <daniel.vetter@ffwll.ch>
2016-01-19 19:02:53 +00:00
if ( IS_ERR ( req ) )
return PTR_ERR ( req ) ;
2010-10-27 12:45:26 +01:00
2017-02-14 11:32:42 +00:00
cs = intel_ring_begin ( req , 2 ) ;
if ( IS_ERR ( cs ) ) {
2017-03-17 11:47:09 +00:00
i915_add_request ( req ) ;
2017-02-14 11:32:42 +00:00
return PTR_ERR ( cs ) ;
2015-05-29 17:43:47 +01:00
}
2017-02-14 11:32:42 +00:00
* cs + + = MI_WAIT_FOR_EVENT | MI_WAIT_FOR_OVERLAY_FLIP ;
* cs + + = MI_NOOP ;
intel_ring_advance ( req , cs ) ;
2010-08-12 12:21:54 +01:00
2015-05-29 17:43:47 +01:00
ret = intel_overlay_do_wait_request ( overlay , req ,
2010-08-12 14:03:48 +01:00
intel_overlay_release_old_vid_tail ) ;
2010-08-12 12:21:54 +01:00
if ( ret )
return ret ;
2016-08-04 07:52:37 +01:00
} else
intel_overlay_release_old_vid_tail ( & overlay - > last_flip , NULL ) ;
2009-09-15 22:57:34 +02:00
return 0 ;
}
2014-11-26 17:07:29 +02:00
void intel_overlay_reset ( struct drm_i915_private * dev_priv )
{
struct intel_overlay * overlay = dev_priv - > overlay ;
if ( ! overlay )
return ;
intel_overlay_release_old_vid ( overlay ) ;
overlay - > old_xscale = 0 ;
overlay - > old_yscale = 0 ;
overlay - > crtc = NULL ;
overlay - > active = false ;
}
2009-09-15 22:57:34 +02:00
struct put_image_params {
int format ;
short dst_x ;
short dst_y ;
short dst_w ;
short dst_h ;
short src_w ;
short src_scan_h ;
short src_scan_w ;
short src_h ;
short stride_Y ;
short stride_UV ;
int offset_Y ;
int offset_U ;
int offset_V ;
} ;
static int packed_depth_bytes ( u32 format )
{
switch ( format & I915_OVERLAY_DEPTH_MASK ) {
2010-08-12 09:28:50 +01:00
case I915_OVERLAY_YUV422 :
return 4 ;
case I915_OVERLAY_YUV411 :
/* return 6; not implemented */
default :
return - EINVAL ;
2009-09-15 22:57:34 +02:00
}
}
static int packed_width_bytes ( u32 format , short width )
{
switch ( format & I915_OVERLAY_DEPTH_MASK ) {
2010-08-12 09:28:50 +01:00
case I915_OVERLAY_YUV422 :
return width < < 1 ;
default :
return - EINVAL ;
2009-09-15 22:57:34 +02:00
}
}
static int uv_hsubsampling ( u32 format )
{
switch ( format & I915_OVERLAY_DEPTH_MASK ) {
2010-08-12 09:28:50 +01:00
case I915_OVERLAY_YUV422 :
case I915_OVERLAY_YUV420 :
return 2 ;
case I915_OVERLAY_YUV411 :
case I915_OVERLAY_YUV410 :
return 4 ;
default :
return - EINVAL ;
2009-09-15 22:57:34 +02:00
}
}
static int uv_vsubsampling ( u32 format )
{
switch ( format & I915_OVERLAY_DEPTH_MASK ) {
2010-08-12 09:28:50 +01:00
case I915_OVERLAY_YUV420 :
case I915_OVERLAY_YUV410 :
return 2 ;
case I915_OVERLAY_YUV422 :
case I915_OVERLAY_YUV411 :
return 1 ;
default :
return - EINVAL ;
2009-09-15 22:57:34 +02:00
}
}
2016-05-12 12:43:23 +01:00
static u32 calc_swidthsw ( struct drm_i915_private * dev_priv , u32 offset , u32 width )
2009-09-15 22:57:34 +02:00
{
2016-12-07 19:28:09 +02:00
u32 sw ;
if ( IS_GEN2 ( dev_priv ) )
sw = ALIGN ( ( offset & 31 ) + width , 32 ) ;
else
sw = ALIGN ( ( offset & 63 ) + width , 64 ) ;
if ( sw = = 0 )
return 0 ;
return ( sw - 32 ) > > 3 ;
2009-09-15 22:57:34 +02:00
}
2016-12-07 19:28:10 +02:00
static const u16 y_static_hcoeffs [ N_PHASES ] [ N_HORIZ_Y_TAPS ] = {
[ 0 ] = { 0x3000 , 0xb4a0 , 0x1930 , 0x1920 , 0xb4a0 , } ,
[ 1 ] = { 0x3000 , 0xb500 , 0x19d0 , 0x1880 , 0xb440 , } ,
[ 2 ] = { 0x3000 , 0xb540 , 0x1a88 , 0x2f80 , 0xb3e0 , } ,
[ 3 ] = { 0x3000 , 0xb580 , 0x1b30 , 0x2e20 , 0xb380 , } ,
[ 4 ] = { 0x3000 , 0xb5c0 , 0x1bd8 , 0x2cc0 , 0xb320 , } ,
[ 5 ] = { 0x3020 , 0xb5e0 , 0x1c60 , 0x2b80 , 0xb2c0 , } ,
[ 6 ] = { 0x3020 , 0xb5e0 , 0x1cf8 , 0x2a20 , 0xb260 , } ,
[ 7 ] = { 0x3020 , 0xb5e0 , 0x1d80 , 0x28e0 , 0xb200 , } ,
[ 8 ] = { 0x3020 , 0xb5c0 , 0x1e08 , 0x3f40 , 0xb1c0 , } ,
[ 9 ] = { 0x3020 , 0xb580 , 0x1e78 , 0x3ce0 , 0xb160 , } ,
[ 10 ] = { 0x3040 , 0xb520 , 0x1ed8 , 0x3aa0 , 0xb120 , } ,
[ 11 ] = { 0x3040 , 0xb4a0 , 0x1f30 , 0x3880 , 0xb0e0 , } ,
[ 12 ] = { 0x3040 , 0xb400 , 0x1f78 , 0x3680 , 0xb0a0 , } ,
[ 13 ] = { 0x3020 , 0xb340 , 0x1fb8 , 0x34a0 , 0xb060 , } ,
[ 14 ] = { 0x3020 , 0xb240 , 0x1fe0 , 0x32e0 , 0xb040 , } ,
[ 15 ] = { 0x3020 , 0xb140 , 0x1ff8 , 0x3160 , 0xb020 , } ,
[ 16 ] = { 0xb000 , 0x3000 , 0x0800 , 0x3000 , 0xb000 , } ,
2010-08-12 09:28:50 +01:00
} ;
2016-12-07 19:28:10 +02:00
static const u16 uv_static_hcoeffs [ N_PHASES ] [ N_HORIZ_UV_TAPS ] = {
[ 0 ] = { 0x3000 , 0x1800 , 0x1800 , } ,
[ 1 ] = { 0xb000 , 0x18d0 , 0x2e60 , } ,
[ 2 ] = { 0xb000 , 0x1990 , 0x2ce0 , } ,
[ 3 ] = { 0xb020 , 0x1a68 , 0x2b40 , } ,
[ 4 ] = { 0xb040 , 0x1b20 , 0x29e0 , } ,
[ 5 ] = { 0xb060 , 0x1bd8 , 0x2880 , } ,
[ 6 ] = { 0xb080 , 0x1c88 , 0x3e60 , } ,
[ 7 ] = { 0xb0a0 , 0x1d28 , 0x3c00 , } ,
[ 8 ] = { 0xb0c0 , 0x1db8 , 0x39e0 , } ,
[ 9 ] = { 0xb0e0 , 0x1e40 , 0x37e0 , } ,
[ 10 ] = { 0xb100 , 0x1eb8 , 0x3620 , } ,
[ 11 ] = { 0xb100 , 0x1f18 , 0x34a0 , } ,
[ 12 ] = { 0xb100 , 0x1f68 , 0x3360 , } ,
[ 13 ] = { 0xb0e0 , 0x1fa8 , 0x3240 , } ,
[ 14 ] = { 0xb0c0 , 0x1fe0 , 0x3140 , } ,
[ 15 ] = { 0xb060 , 0x1ff0 , 0x30a0 , } ,
[ 16 ] = { 0x3000 , 0x0800 , 0x3000 , } ,
2010-08-12 09:28:50 +01:00
} ;
2009-09-15 22:57:34 +02:00
2012-04-16 14:07:43 -07:00
static void update_polyphase_filter ( struct overlay_registers __iomem * regs )
2009-09-15 22:57:34 +02:00
{
2012-04-16 14:07:43 -07:00
memcpy_toio ( regs - > Y_HCOEFS , y_static_hcoeffs , sizeof ( y_static_hcoeffs ) ) ;
memcpy_toio ( regs - > UV_HCOEFS , uv_static_hcoeffs ,
sizeof ( uv_static_hcoeffs ) ) ;
2009-09-15 22:57:34 +02:00
}
static bool update_scaling_factors ( struct intel_overlay * overlay ,
2012-04-16 14:07:43 -07:00
struct overlay_registers __iomem * regs ,
2009-09-15 22:57:34 +02:00
struct put_image_params * params )
{
/* fixed point with a 12 bit shift */
u32 xscale , yscale , xscale_UV , yscale_UV ;
# define FP_SHIFT 12
# define FRACT_MASK 0xfff
bool scale_changed = false ;
int uv_hscale = uv_hsubsampling ( params - > format ) ;
int uv_vscale = uv_vsubsampling ( params - > format ) ;
if ( params - > dst_w > 1 )
xscale = ( ( params - > src_scan_w - 1 ) < < FP_SHIFT )
/ ( params - > dst_w ) ;
else
xscale = 1 < < FP_SHIFT ;
if ( params - > dst_h > 1 )
yscale = ( ( params - > src_scan_h - 1 ) < < FP_SHIFT )
/ ( params - > dst_h ) ;
else
yscale = 1 < < FP_SHIFT ;
/*if (params->format & I915_OVERLAY_YUV_PLANAR) {*/
2010-08-12 09:28:50 +01:00
xscale_UV = xscale / uv_hscale ;
yscale_UV = yscale / uv_vscale ;
/* make the Y scale to UV scale ratio an exact multiply */
xscale = xscale_UV * uv_hscale ;
yscale = yscale_UV * uv_vscale ;
2009-09-15 22:57:34 +02:00
/*} else {
2010-08-12 09:28:50 +01:00
xscale_UV = 0 ;
yscale_UV = 0 ;
} */
2009-09-15 22:57:34 +02:00
if ( xscale ! = overlay - > old_xscale | | yscale ! = overlay - > old_yscale )
scale_changed = true ;
overlay - > old_xscale = xscale ;
overlay - > old_yscale = yscale ;
2012-04-16 14:07:43 -07:00
iowrite32 ( ( ( yscale & FRACT_MASK ) < < 20 ) |
( ( xscale > > FP_SHIFT ) < < 16 ) |
( ( xscale & FRACT_MASK ) < < 3 ) ,
& regs - > YRGBSCALE ) ;
2010-08-12 09:28:50 +01:00
2012-04-16 14:07:43 -07:00
iowrite32 ( ( ( yscale_UV & FRACT_MASK ) < < 20 ) |
( ( xscale_UV > > FP_SHIFT ) < < 16 ) |
( ( xscale_UV & FRACT_MASK ) < < 3 ) ,
& regs - > UVSCALE ) ;
2010-08-12 09:28:50 +01:00
2012-04-16 14:07:43 -07:00
iowrite32 ( ( ( ( yscale > > FP_SHIFT ) < < 16 ) |
( ( yscale_UV > > FP_SHIFT ) < < 0 ) ) ,
& regs - > UVSCALEV ) ;
2009-09-15 22:57:34 +02:00
if ( scale_changed )
update_polyphase_filter ( regs ) ;
return scale_changed ;
}
static void update_colorkey ( struct intel_overlay * overlay ,
2012-04-16 14:07:43 -07:00
struct overlay_registers __iomem * regs )
2009-09-15 22:57:34 +02:00
{
2016-12-07 19:28:11 +02:00
const struct intel_plane_state * state =
to_intel_plane_state ( overlay - > crtc - > base . primary - > state ) ;
2009-09-15 22:57:34 +02:00
u32 key = overlay - > color_key ;
2016-12-07 19:28:11 +02:00
u32 format = 0 ;
u32 flags = 0 ;
2015-04-02 10:35:08 +01:00
if ( overlay - > color_key_enabled )
flags | = DST_KEY_ENABLE ;
2010-08-12 09:30:58 +01:00
2016-12-07 19:28:11 +02:00
if ( state - > base . visible )
2017-01-04 11:41:10 +01:00
format = state - > base . fb - > format - > format ;
2016-12-07 19:28:11 +02:00
switch ( format ) {
case DRM_FORMAT_C8 :
2015-04-02 10:35:08 +01:00
key = 0 ;
flags | = CLK_RGB8I_MASK ;
2010-08-12 09:30:58 +01:00
break ;
2016-12-07 19:28:11 +02:00
case DRM_FORMAT_XRGB1555 :
key = RGB15_TO_COLORKEY ( key ) ;
flags | = CLK_RGB15_MASK ;
2010-08-12 09:30:58 +01:00
break ;
2016-12-07 19:28:11 +02:00
case DRM_FORMAT_RGB565 :
key = RGB16_TO_COLORKEY ( key ) ;
flags | = CLK_RGB16_MASK ;
break ;
default :
2015-04-02 10:35:08 +01:00
flags | = CLK_RGB24_MASK ;
2010-08-12 09:30:58 +01:00
break ;
2009-09-15 22:57:34 +02:00
}
2015-04-02 10:35:08 +01:00
iowrite32 ( key , & regs - > DCLRKV ) ;
iowrite32 ( flags , & regs - > DCLRKM ) ;
2009-09-15 22:57:34 +02:00
}
static u32 overlay_cmd_reg ( struct put_image_params * params )
{
u32 cmd = OCMD_ENABLE | OCMD_BUF_TYPE_FRAME | OCMD_BUFFER0 ;
if ( params - > format & I915_OVERLAY_YUV_PLANAR ) {
switch ( params - > format & I915_OVERLAY_DEPTH_MASK ) {
2010-08-12 09:28:50 +01:00
case I915_OVERLAY_YUV422 :
cmd | = OCMD_YUV_422_PLANAR ;
break ;
case I915_OVERLAY_YUV420 :
cmd | = OCMD_YUV_420_PLANAR ;
break ;
case I915_OVERLAY_YUV411 :
case I915_OVERLAY_YUV410 :
cmd | = OCMD_YUV_410_PLANAR ;
break ;
2009-09-15 22:57:34 +02:00
}
} else { /* YUV packed */
switch ( params - > format & I915_OVERLAY_DEPTH_MASK ) {
2010-08-12 09:28:50 +01:00
case I915_OVERLAY_YUV422 :
cmd | = OCMD_YUV_422_PACKED ;
break ;
case I915_OVERLAY_YUV411 :
cmd | = OCMD_YUV_411_PACKED ;
break ;
2009-09-15 22:57:34 +02:00
}
switch ( params - > format & I915_OVERLAY_SWAP_MASK ) {
2010-08-12 09:28:50 +01:00
case I915_OVERLAY_NO_SWAP :
break ;
case I915_OVERLAY_UV_SWAP :
cmd | = OCMD_UV_SWAP ;
break ;
case I915_OVERLAY_Y_SWAP :
cmd | = OCMD_Y_SWAP ;
break ;
case I915_OVERLAY_Y_AND_UV_SWAP :
cmd | = OCMD_Y_AND_UV_SWAP ;
break ;
2009-09-15 22:57:34 +02:00
}
}
return cmd ;
}
2010-08-12 12:38:21 +01:00
static int intel_overlay_do_put_image ( struct intel_overlay * overlay ,
2010-11-08 19:18:58 +00:00
struct drm_i915_gem_object * new_bo ,
2010-08-12 12:38:21 +01:00
struct put_image_params * params )
2009-09-15 22:57:34 +02:00
{
int ret , tmp_width ;
2012-04-16 14:07:43 -07:00
struct overlay_registers __iomem * regs ;
2009-09-15 22:57:34 +02:00
bool scale_changed = false ;
2016-05-12 12:43:23 +01:00
struct drm_i915_private * dev_priv = overlay - > i915 ;
2012-04-16 14:07:43 -07:00
u32 swidth , swidthsw , sheight , ostride ;
2014-06-18 23:28:09 +02:00
enum pipe pipe = overlay - > crtc - > pipe ;
2016-08-15 10:49:01 +01:00
struct i915_vma * vma ;
2009-09-15 22:57:34 +02:00
2016-07-05 10:40:23 +01:00
lockdep_assert_held ( & dev_priv - > drm . struct_mutex ) ;
WARN_ON ( ! drm_modeset_is_locked ( & dev_priv - > drm . mode_config . connection_mutex ) ) ;
2009-09-15 22:57:34 +02:00
ret = intel_overlay_release_old_vid ( overlay ) ;
if ( ret ! = 0 )
return ret ;
2017-01-14 00:28:27 +00:00
vma = i915_gem_object_pin_to_display_plane ( new_bo , 0 , NULL ) ;
2016-08-15 10:49:06 +01:00
if ( IS_ERR ( vma ) )
return PTR_ERR ( vma ) ;
2016-08-15 10:49:01 +01:00
2016-08-18 17:17:00 +01:00
ret = i915_vma_put_fence ( vma ) ;
2010-11-10 16:40:20 +00:00
if ( ret )
goto out_unpin ;
2009-09-15 22:57:34 +02:00
if ( ! overlay - > active ) {
2012-04-16 14:07:43 -07:00
u32 oconfig ;
2010-08-12 10:35:26 +01:00
regs = intel_overlay_map_regs ( overlay ) ;
2009-09-15 22:57:34 +02:00
if ( ! regs ) {
ret = - ENOMEM ;
goto out_unpin ;
}
2012-04-16 14:07:43 -07:00
oconfig = OCONF_CC_OUT_8BIT ;
2016-05-12 12:43:23 +01:00
if ( IS_GEN4 ( dev_priv ) )
2012-04-16 14:07:43 -07:00
oconfig | = OCONF_CSC_MODE_BT709 ;
2014-06-18 23:28:09 +02:00
oconfig | = pipe = = 0 ?
2009-09-15 22:57:34 +02:00
OCONF_PIPE_A : OCONF_PIPE_B ;
2012-04-16 14:07:43 -07:00
iowrite32 ( oconfig , & regs - > OCONFIG ) ;
2010-08-12 12:02:11 +01:00
intel_overlay_unmap_regs ( overlay , regs ) ;
2009-09-15 22:57:34 +02:00
ret = intel_overlay_on ( overlay ) ;
if ( ret ! = 0 )
goto out_unpin ;
}
2010-08-12 10:35:26 +01:00
regs = intel_overlay_map_regs ( overlay ) ;
2009-09-15 22:57:34 +02:00
if ( ! regs ) {
ret = - ENOMEM ;
goto out_unpin ;
}
2012-04-16 14:07:43 -07:00
iowrite32 ( ( params - > dst_y < < 16 ) | params - > dst_x , & regs - > DWINPOS ) ;
iowrite32 ( ( params - > dst_h < < 16 ) | params - > dst_w , & regs - > DWINSZ ) ;
2009-09-15 22:57:34 +02:00
if ( params - > format & I915_OVERLAY_YUV_PACKED )
tmp_width = packed_width_bytes ( params - > format , params - > src_w ) ;
else
tmp_width = params - > src_w ;
2012-04-16 14:07:43 -07:00
swidth = params - > src_w ;
2016-05-12 12:43:23 +01:00
swidthsw = calc_swidthsw ( dev_priv , params - > offset_Y , tmp_width ) ;
2012-04-16 14:07:43 -07:00
sheight = params - > src_h ;
2016-08-15 10:49:07 +01:00
iowrite32 ( i915_ggtt_offset ( vma ) + params - > offset_Y , & regs - > OBUF_0Y ) ;
2012-04-16 14:07:43 -07:00
ostride = params - > stride_Y ;
2009-09-15 22:57:34 +02:00
if ( params - > format & I915_OVERLAY_YUV_PLANAR ) {
int uv_hscale = uv_hsubsampling ( params - > format ) ;
int uv_vscale = uv_vsubsampling ( params - > format ) ;
u32 tmp_U , tmp_V ;
2012-04-16 14:07:43 -07:00
swidth | = ( params - > src_w / uv_hscale ) < < 16 ;
2016-05-12 12:43:23 +01:00
tmp_U = calc_swidthsw ( dev_priv , params - > offset_U ,
2010-08-12 09:28:50 +01:00
params - > src_w / uv_hscale ) ;
2016-05-12 12:43:23 +01:00
tmp_V = calc_swidthsw ( dev_priv , params - > offset_V ,
2010-08-12 09:28:50 +01:00
params - > src_w / uv_hscale ) ;
2012-04-16 14:07:43 -07:00
swidthsw | = max_t ( u32 , tmp_U , tmp_V ) < < 16 ;
sheight | = ( params - > src_h / uv_vscale ) < < 16 ;
2016-08-15 10:49:07 +01:00
iowrite32 ( i915_ggtt_offset ( vma ) + params - > offset_U ,
& regs - > OBUF_0U ) ;
iowrite32 ( i915_ggtt_offset ( vma ) + params - > offset_V ,
& regs - > OBUF_0V ) ;
2012-04-16 14:07:43 -07:00
ostride | = params - > stride_UV < < 16 ;
2009-09-15 22:57:34 +02:00
}
2012-04-16 14:07:43 -07:00
iowrite32 ( swidth , & regs - > SWIDTH ) ;
iowrite32 ( swidthsw , & regs - > SWIDTHSW ) ;
iowrite32 ( sheight , & regs - > SHEIGHT ) ;
iowrite32 ( ostride , & regs - > OSTRIDE ) ;
2009-09-15 22:57:34 +02:00
scale_changed = update_scaling_factors ( overlay , regs , params ) ;
update_colorkey ( overlay , regs ) ;
2012-04-16 14:07:43 -07:00
iowrite32 ( overlay_cmd_reg ( params ) , & regs - > OCMD ) ;
2009-09-15 22:57:34 +02:00
2010-08-12 12:02:11 +01:00
intel_overlay_unmap_regs ( overlay , regs ) ;
2009-09-15 22:57:34 +02:00
2016-12-07 19:28:06 +02:00
ret = intel_overlay_continue ( overlay , vma , scale_changed ) ;
2010-08-12 12:36:12 +01:00
if ( ret )
goto out_unpin ;
2009-09-15 22:57:34 +02:00
return 0 ;
out_unpin :
2016-08-15 10:49:06 +01:00
i915_gem_object_unpin_from_display_plane ( vma ) ;
2009-09-15 22:57:34 +02:00
return ret ;
}
2011-02-21 14:43:56 +00:00
int intel_overlay_switch_off ( struct intel_overlay * overlay )
2009-09-15 22:57:34 +02:00
{
2016-05-12 12:43:23 +01:00
struct drm_i915_private * dev_priv = overlay - > i915 ;
2012-04-16 14:07:43 -07:00
struct overlay_registers __iomem * regs ;
2010-08-12 13:50:28 +01:00
int ret ;
2009-09-15 22:57:34 +02:00
2016-07-05 10:40:23 +01:00
lockdep_assert_held ( & dev_priv - > drm . struct_mutex ) ;
WARN_ON ( ! drm_modeset_is_locked ( & dev_priv - > drm . mode_config . connection_mutex ) ) ;
2009-09-15 22:57:34 +02:00
2011-02-21 14:43:56 +00:00
ret = intel_overlay_recover_from_interrupt ( overlay ) ;
2010-08-12 14:03:48 +01:00
if ( ret ! = 0 )
return ret ;
2009-11-30 15:55:49 +01:00
2009-09-15 22:57:34 +02:00
if ( ! overlay - > active )
return 0 ;
ret = intel_overlay_release_old_vid ( overlay ) ;
if ( ret ! = 0 )
return ret ;
2010-08-12 10:35:26 +01:00
regs = intel_overlay_map_regs ( overlay ) ;
2012-04-16 14:07:43 -07:00
iowrite32 ( 0 , & regs - > OCMD ) ;
2010-08-12 12:02:11 +01:00
intel_overlay_unmap_regs ( overlay , regs ) ;
2009-09-15 22:57:34 +02:00
2016-08-04 07:52:37 +01:00
return intel_overlay_off ( overlay ) ;
2009-09-15 22:57:34 +02:00
}
static int check_overlay_possible_on_crtc ( struct intel_overlay * overlay ,
struct intel_crtc * crtc )
{
2010-09-13 14:19:16 +01:00
if ( ! crtc - > active )
2009-09-15 22:57:34 +02:00
return - EINVAL ;
/* can't use the overlay with double wide pipe */
2015-01-15 14:55:25 +02:00
if ( crtc - > config - > double_wide )
2009-09-15 22:57:34 +02:00
return - EINVAL ;
return 0 ;
}
static void update_pfit_vscale_ratio ( struct intel_overlay * overlay )
{
2016-05-12 12:43:23 +01:00
struct drm_i915_private * dev_priv = overlay - > i915 ;
2009-09-15 22:57:34 +02:00
u32 pfit_control = I915_READ ( PFIT_CONTROL ) ;
2010-08-12 11:15:58 +01:00
u32 ratio ;
2009-09-15 22:57:34 +02:00
/* XXX: This is not the same logic as in the xorg driver, but more in
2010-08-12 11:15:58 +01:00
* line with the intel documentation for the i965
*/
2016-05-12 12:43:23 +01:00
if ( INTEL_GEN ( dev_priv ) > = 4 ) {
2011-08-16 15:34:10 -04:00
/* on i965 use the PGM reg to read out the autoscaler values */
2010-09-17 00:32:17 +01:00
ratio = I915_READ ( PFIT_PGM_RATIOS ) > > PFIT_VERT_SCALE_SHIFT_965 ;
} else {
2010-08-12 11:15:58 +01:00
if ( pfit_control & VERT_AUTO_SCALE )
ratio = I915_READ ( PFIT_AUTO_RATIOS ) ;
2009-09-15 22:57:34 +02:00
else
2010-08-12 11:15:58 +01:00
ratio = I915_READ ( PFIT_PGM_RATIOS ) ;
ratio > > = PFIT_VERT_SCALE_SHIFT ;
2009-09-15 22:57:34 +02:00
}
overlay - > pfit_vscale_ratio = ratio ;
}
static int check_overlay_dst ( struct intel_overlay * overlay ,
struct drm_intel_overlay_put_image * rec )
{
2016-12-07 19:28:07 +02:00
const struct intel_crtc_state * pipe_config =
overlay - > crtc - > config ;
2009-09-15 22:57:34 +02:00
2016-12-07 19:28:07 +02:00
if ( rec - > dst_x < pipe_config - > pipe_src_w & &
rec - > dst_x + rec - > dst_width < = pipe_config - > pipe_src_w & &
rec - > dst_y < pipe_config - > pipe_src_h & &
rec - > dst_y + rec - > dst_height < = pipe_config - > pipe_src_h )
2009-09-15 22:57:34 +02:00
return 0 ;
else
return - EINVAL ;
}
static int check_overlay_scaling ( struct put_image_params * rec )
{
u32 tmp ;
/* downscaling limit is 8.0 */
tmp = ( ( rec - > src_scan_h < < 16 ) / rec - > dst_h ) > > 16 ;
if ( tmp > 7 )
return - EINVAL ;
tmp = ( ( rec - > src_scan_w < < 16 ) / rec - > dst_w ) > > 16 ;
if ( tmp > 7 )
return - EINVAL ;
return 0 ;
}
2016-05-12 12:43:23 +01:00
static int check_overlay_src ( struct drm_i915_private * dev_priv ,
2009-09-15 22:57:34 +02:00
struct drm_intel_overlay_put_image * rec ,
2010-11-08 19:18:58 +00:00
struct drm_i915_gem_object * new_bo )
2009-09-15 22:57:34 +02:00
{
int uv_hscale = uv_hsubsampling ( rec - > flags ) ;
int uv_vscale = uv_vsubsampling ( rec - > flags ) ;
2010-10-27 23:17:25 +02:00
u32 stride_mask ;
int depth ;
u32 tmp ;
2009-09-15 22:57:34 +02:00
/* check src dimensions */
2016-11-30 17:43:04 +02:00
if ( IS_I845G ( dev_priv ) | | IS_I830 ( dev_priv ) ) {
2010-08-12 09:28:50 +01:00
if ( rec - > src_height > IMAGE_MAX_HEIGHT_LEGACY | |
2010-08-12 11:29:34 +01:00
rec - > src_width > IMAGE_MAX_WIDTH_LEGACY )
2009-09-15 22:57:34 +02:00
return - EINVAL ;
} else {
2010-08-12 09:28:50 +01:00
if ( rec - > src_height > IMAGE_MAX_HEIGHT | |
2010-08-12 11:29:34 +01:00
rec - > src_width > IMAGE_MAX_WIDTH )
2009-09-15 22:57:34 +02:00
return - EINVAL ;
}
2010-08-12 11:29:34 +01:00
2009-09-15 22:57:34 +02:00
/* better safe than sorry, use 4 as the maximal subsampling ratio */
2010-08-12 09:28:50 +01:00
if ( rec - > src_height < N_VERT_Y_TAPS * 4 | |
2010-08-12 11:29:34 +01:00
rec - > src_width < N_HORIZ_Y_TAPS * 4 )
2009-09-15 22:57:34 +02:00
return - EINVAL ;
2010-07-12 19:35:38 +01:00
/* check alignment constraints */
2009-09-15 22:57:34 +02:00
switch ( rec - > flags & I915_OVERLAY_TYPE_MASK ) {
2010-08-12 09:28:50 +01:00
case I915_OVERLAY_RGB :
/* not implemented */
return - EINVAL ;
2010-08-12 11:29:34 +01:00
2010-08-12 09:28:50 +01:00
case I915_OVERLAY_YUV_PACKED :
if ( uv_vscale ! = 1 )
2009-09-15 22:57:34 +02:00
return - EINVAL ;
2010-08-12 11:29:34 +01:00
depth = packed_depth_bytes ( rec - > flags ) ;
2010-08-12 09:28:50 +01:00
if ( depth < 0 )
return depth ;
2010-08-12 11:29:34 +01:00
2010-08-12 09:28:50 +01:00
/* ignore UV planes */
rec - > stride_UV = 0 ;
rec - > offset_U = 0 ;
rec - > offset_V = 0 ;
/* check pixel alignment */
if ( rec - > offset_Y % depth )
return - EINVAL ;
break ;
2010-08-12 11:29:34 +01:00
2010-08-12 09:28:50 +01:00
case I915_OVERLAY_YUV_PLANAR :
if ( uv_vscale < 0 | | uv_hscale < 0 )
2009-09-15 22:57:34 +02:00
return - EINVAL ;
2010-08-12 09:28:50 +01:00
/* no offset restrictions for planar formats */
break ;
2010-08-12 11:29:34 +01:00
2010-08-12 09:28:50 +01:00
default :
return - EINVAL ;
2009-09-15 22:57:34 +02:00
}
if ( rec - > src_width % uv_hscale )
return - EINVAL ;
/* stride checking */
2016-11-30 17:43:04 +02:00
if ( IS_I830 ( dev_priv ) | | IS_I845G ( dev_priv ) )
2010-07-12 19:35:38 +01:00
stride_mask = 255 ;
else
stride_mask = 63 ;
2009-09-15 22:57:34 +02:00
if ( rec - > stride_Y & stride_mask | | rec - > stride_UV & stride_mask )
return - EINVAL ;
2016-05-12 12:43:23 +01:00
if ( IS_GEN4 ( dev_priv ) & & rec - > stride_Y < 512 )
2009-09-15 22:57:34 +02:00
return - EINVAL ;
tmp = ( rec - > flags & I915_OVERLAY_TYPE_MASK ) = = I915_OVERLAY_YUV_PLANAR ?
2010-08-12 11:29:34 +01:00
4096 : 8192 ;
if ( rec - > stride_Y > tmp | | rec - > stride_UV > 2 * 1024 )
2009-09-15 22:57:34 +02:00
return - EINVAL ;
/* check buffer dimensions */
switch ( rec - > flags & I915_OVERLAY_TYPE_MASK ) {
2010-08-12 09:28:50 +01:00
case I915_OVERLAY_RGB :
case I915_OVERLAY_YUV_PACKED :
/* always 4 Y values per depth pixels */
if ( packed_width_bytes ( rec - > flags , rec - > src_width ) > rec - > stride_Y )
return - EINVAL ;
tmp = rec - > stride_Y * rec - > src_height ;
2010-11-08 19:18:58 +00:00
if ( rec - > offset_Y + tmp > new_bo - > base . size )
2010-08-12 09:28:50 +01:00
return - EINVAL ;
break ;
case I915_OVERLAY_YUV_PLANAR :
if ( rec - > src_width > rec - > stride_Y )
return - EINVAL ;
if ( rec - > src_width / uv_hscale > rec - > stride_UV )
return - EINVAL ;
2010-08-12 11:29:34 +01:00
tmp = rec - > stride_Y * rec - > src_height ;
2010-11-08 19:18:58 +00:00
if ( rec - > offset_Y + tmp > new_bo - > base . size )
2010-08-12 09:28:50 +01:00
return - EINVAL ;
2010-08-12 11:29:34 +01:00
tmp = rec - > stride_UV * ( rec - > src_height / uv_vscale ) ;
2010-11-08 19:18:58 +00:00
if ( rec - > offset_U + tmp > new_bo - > base . size | |
rec - > offset_V + tmp > new_bo - > base . size )
2010-08-12 09:28:50 +01:00
return - EINVAL ;
break ;
2009-09-15 22:57:34 +02:00
}
return 0 ;
}
2016-05-12 12:43:23 +01:00
int intel_overlay_put_image_ioctl ( struct drm_device * dev , void * data ,
struct drm_file * file_priv )
2009-09-15 22:57:34 +02:00
{
struct drm_intel_overlay_put_image * put_image_rec = data ;
2016-07-04 11:34:36 +01:00
struct drm_i915_private * dev_priv = to_i915 ( dev ) ;
2009-09-15 22:57:34 +02:00
struct intel_overlay * overlay ;
2014-07-17 23:30:04 -04:00
struct drm_crtc * drmmode_crtc ;
2009-09-15 22:57:34 +02:00
struct intel_crtc * crtc ;
2010-11-08 19:18:58 +00:00
struct drm_i915_gem_object * new_bo ;
2009-09-15 22:57:34 +02:00
struct put_image_params * params ;
int ret ;
overlay = dev_priv - > overlay ;
if ( ! overlay ) {
DRM_DEBUG ( " userspace bug: no overlay \n " ) ;
return - ENODEV ;
}
if ( ! ( put_image_rec - > flags & I915_OVERLAY_ENABLE ) ) {
2012-12-02 01:05:46 +01:00
drm_modeset_lock_all ( dev ) ;
2009-09-15 22:57:34 +02:00
mutex_lock ( & dev - > struct_mutex ) ;
2011-02-21 14:43:56 +00:00
ret = intel_overlay_switch_off ( overlay ) ;
2009-09-15 22:57:34 +02:00
mutex_unlock ( & dev - > struct_mutex ) ;
2012-12-02 01:05:46 +01:00
drm_modeset_unlock_all ( dev ) ;
2009-09-15 22:57:34 +02:00
return ret ;
}
2013-09-19 12:18:32 +02:00
params = kmalloc ( sizeof ( * params ) , GFP_KERNEL ) ;
2009-09-15 22:57:34 +02:00
if ( ! params )
return - ENOMEM ;
2014-07-17 23:30:04 -04:00
drmmode_crtc = drm_crtc_find ( dev , put_image_rec - > crtc_id ) ;
if ( ! drmmode_crtc ) {
2010-03-06 14:05:39 +03:00
ret = - ENOENT ;
goto out_free ;
}
2014-07-17 23:30:04 -04:00
crtc = to_intel_crtc ( drmmode_crtc ) ;
2009-09-15 22:57:34 +02:00
2016-07-20 13:31:51 +01:00
new_bo = i915_gem_object_lookup ( file_priv , put_image_rec - > bo_handle ) ;
if ( ! new_bo ) {
2010-03-06 14:05:39 +03:00
ret = - ENOENT ;
goto out_free ;
}
2009-09-15 22:57:34 +02:00
2012-12-02 01:05:46 +01:00
drm_modeset_lock_all ( dev ) ;
2009-09-15 22:57:34 +02:00
mutex_lock ( & dev - > struct_mutex ) ;
2016-08-05 10:14:23 +01:00
if ( i915_gem_object_is_tiled ( new_bo ) ) {
2014-02-14 14:06:06 +01:00
DRM_DEBUG_KMS ( " buffer used for overlay image can not be tiled \n " ) ;
2010-11-10 16:40:20 +00:00
ret = - EINVAL ;
goto out_unlock ;
}
2011-02-21 14:43:56 +00:00
ret = intel_overlay_recover_from_interrupt ( overlay ) ;
2010-08-12 14:03:48 +01:00
if ( ret ! = 0 )
goto out_unlock ;
2009-09-15 22:57:37 +02:00
2009-09-15 22:57:34 +02:00
if ( overlay - > crtc ! = crtc ) {
2011-02-21 14:43:56 +00:00
ret = intel_overlay_switch_off ( overlay ) ;
2009-09-15 22:57:34 +02:00
if ( ret ! = 0 )
goto out_unlock ;
ret = check_overlay_possible_on_crtc ( overlay , crtc ) ;
if ( ret ! = 0 )
goto out_unlock ;
overlay - > crtc = crtc ;
crtc - > overlay = overlay ;
2010-09-13 01:16:10 +01:00
/* line too wide, i.e. one-line-mode */
2016-12-07 19:28:07 +02:00
if ( crtc - > config - > pipe_src_w > 1024 & &
2016-12-07 19:28:08 +02:00
crtc - > config - > gmch_pfit . control & PFIT_ENABLE ) {
2015-03-31 10:37:23 +03:00
overlay - > pfit_active = true ;
2009-09-15 22:57:34 +02:00
update_pfit_vscale_ratio ( overlay ) ;
} else
2015-03-31 10:37:23 +03:00
overlay - > pfit_active = false ;
2009-09-15 22:57:34 +02:00
}
ret = check_overlay_dst ( overlay , put_image_rec ) ;
if ( ret ! = 0 )
goto out_unlock ;
if ( overlay - > pfit_active ) {
params - > dst_y = ( ( ( ( u32 ) put_image_rec - > dst_y ) < < 12 ) /
2010-08-12 09:28:50 +01:00
overlay - > pfit_vscale_ratio ) ;
2009-09-15 22:57:34 +02:00
/* shifting right rounds downwards, so add 1 */
params - > dst_h = ( ( ( ( u32 ) put_image_rec - > dst_height ) < < 12 ) /
2010-08-12 09:28:50 +01:00
overlay - > pfit_vscale_ratio ) + 1 ;
2009-09-15 22:57:34 +02:00
} else {
params - > dst_y = put_image_rec - > dst_y ;
params - > dst_h = put_image_rec - > dst_height ;
}
params - > dst_x = put_image_rec - > dst_x ;
params - > dst_w = put_image_rec - > dst_width ;
params - > src_w = put_image_rec - > src_width ;
params - > src_h = put_image_rec - > src_height ;
params - > src_scan_w = put_image_rec - > src_scan_width ;
params - > src_scan_h = put_image_rec - > src_scan_height ;
2010-08-12 09:28:50 +01:00
if ( params - > src_scan_h > params - > src_h | |
params - > src_scan_w > params - > src_w ) {
2009-09-15 22:57:34 +02:00
ret = - EINVAL ;
goto out_unlock ;
}
2016-05-12 12:43:23 +01:00
ret = check_overlay_src ( dev_priv , put_image_rec , new_bo ) ;
2009-09-15 22:57:34 +02:00
if ( ret ! = 0 )
goto out_unlock ;
params - > format = put_image_rec - > flags & ~ I915_OVERLAY_FLAGS_MASK ;
params - > stride_Y = put_image_rec - > stride_Y ;
params - > stride_UV = put_image_rec - > stride_UV ;
params - > offset_Y = put_image_rec - > offset_Y ;
params - > offset_U = put_image_rec - > offset_U ;
params - > offset_V = put_image_rec - > offset_V ;
/* Check scaling after src size to prevent a divide-by-zero. */
ret = check_overlay_scaling ( params ) ;
if ( ret ! = 0 )
goto out_unlock ;
ret = intel_overlay_do_put_image ( overlay , new_bo , params ) ;
if ( ret ! = 0 )
goto out_unlock ;
mutex_unlock ( & dev - > struct_mutex ) ;
2012-12-02 01:05:46 +01:00
drm_modeset_unlock_all ( dev ) ;
2016-12-07 19:28:06 +02:00
i915_gem_object_put ( new_bo ) ;
2009-09-15 22:57:34 +02:00
kfree ( params ) ;
return 0 ;
out_unlock :
mutex_unlock ( & dev - > struct_mutex ) ;
2012-12-02 01:05:46 +01:00
drm_modeset_unlock_all ( dev ) ;
2016-10-28 13:58:43 +01:00
i915_gem_object_put ( new_bo ) ;
2010-03-06 14:05:39 +03:00
out_free :
2009-09-15 22:57:34 +02:00
kfree ( params ) ;
return ret ;
}
static void update_reg_attrs ( struct intel_overlay * overlay ,
2012-04-16 14:07:43 -07:00
struct overlay_registers __iomem * regs )
2009-09-15 22:57:34 +02:00
{
2012-04-16 14:07:43 -07:00
iowrite32 ( ( overlay - > contrast < < 18 ) | ( overlay - > brightness & 0xff ) ,
& regs - > OCLRC0 ) ;
iowrite32 ( overlay - > saturation , & regs - > OCLRC1 ) ;
2009-09-15 22:57:34 +02:00
}
static bool check_gamma_bounds ( u32 gamma1 , u32 gamma2 )
{
int i ;
if ( gamma1 & 0xff000000 | | gamma2 & 0xff000000 )
return false ;
for ( i = 0 ; i < 3 ; i + + ) {
2010-08-12 09:28:50 +01:00
if ( ( ( gamma1 > > i * 8 ) & 0xff ) > = ( ( gamma2 > > i * 8 ) & 0xff ) )
2009-09-15 22:57:34 +02:00
return false ;
}
return true ;
}
static bool check_gamma5_errata ( u32 gamma5 )
{
int i ;
for ( i = 0 ; i < 3 ; i + + ) {
if ( ( ( gamma5 > > i * 8 ) & 0xff ) = = 0x80 )
return false ;
}
return true ;
}
static int check_gamma ( struct drm_intel_overlay_attrs * attrs )
{
2010-08-12 09:28:50 +01:00
if ( ! check_gamma_bounds ( 0 , attrs - > gamma0 ) | |
! check_gamma_bounds ( attrs - > gamma0 , attrs - > gamma1 ) | |
! check_gamma_bounds ( attrs - > gamma1 , attrs - > gamma2 ) | |
! check_gamma_bounds ( attrs - > gamma2 , attrs - > gamma3 ) | |
! check_gamma_bounds ( attrs - > gamma3 , attrs - > gamma4 ) | |
! check_gamma_bounds ( attrs - > gamma4 , attrs - > gamma5 ) | |
! check_gamma_bounds ( attrs - > gamma5 , 0x00ffffff ) )
2009-09-15 22:57:34 +02:00
return - EINVAL ;
2010-08-12 09:28:50 +01:00
2009-09-15 22:57:34 +02:00
if ( ! check_gamma5_errata ( attrs - > gamma5 ) )
return - EINVAL ;
2010-08-12 09:28:50 +01:00
2009-09-15 22:57:34 +02:00
return 0 ;
}
2016-05-12 12:43:23 +01:00
int intel_overlay_attrs_ioctl ( struct drm_device * dev , void * data ,
struct drm_file * file_priv )
2009-09-15 22:57:34 +02:00
{
struct drm_intel_overlay_attrs * attrs = data ;
2016-07-04 11:34:36 +01:00
struct drm_i915_private * dev_priv = to_i915 ( dev ) ;
2009-09-15 22:57:34 +02:00
struct intel_overlay * overlay ;
2012-04-16 14:07:43 -07:00
struct overlay_registers __iomem * regs ;
2009-09-15 22:57:34 +02:00
int ret ;
overlay = dev_priv - > overlay ;
if ( ! overlay ) {
DRM_DEBUG ( " userspace bug: no overlay \n " ) ;
return - ENODEV ;
}
2012-12-02 01:05:46 +01:00
drm_modeset_lock_all ( dev ) ;
2009-09-15 22:57:34 +02:00
mutex_lock ( & dev - > struct_mutex ) ;
2010-08-12 10:44:45 +01:00
ret = - EINVAL ;
2009-09-15 22:57:34 +02:00
if ( ! ( attrs - > flags & I915_OVERLAY_UPDATE_ATTRS ) ) {
2010-08-12 10:44:45 +01:00
attrs - > color_key = overlay - > color_key ;
2009-09-15 22:57:34 +02:00
attrs - > brightness = overlay - > brightness ;
2010-08-12 10:44:45 +01:00
attrs - > contrast = overlay - > contrast ;
2009-09-15 22:57:34 +02:00
attrs - > saturation = overlay - > saturation ;
2016-05-12 12:43:23 +01:00
if ( ! IS_GEN2 ( dev_priv ) ) {
2009-09-15 22:57:34 +02:00
attrs - > gamma0 = I915_READ ( OGAMC0 ) ;
attrs - > gamma1 = I915_READ ( OGAMC1 ) ;
attrs - > gamma2 = I915_READ ( OGAMC2 ) ;
attrs - > gamma3 = I915_READ ( OGAMC3 ) ;
attrs - > gamma4 = I915_READ ( OGAMC4 ) ;
attrs - > gamma5 = I915_READ ( OGAMC5 ) ;
}
} else {
2010-08-12 10:44:45 +01:00
if ( attrs - > brightness < - 128 | | attrs - > brightness > 127 )
2009-09-15 22:57:34 +02:00
goto out_unlock ;
2010-08-12 10:44:45 +01:00
if ( attrs - > contrast > 255 )
2009-09-15 22:57:34 +02:00
goto out_unlock ;
2010-08-12 10:44:45 +01:00
if ( attrs - > saturation > 1023 )
2009-09-15 22:57:34 +02:00
goto out_unlock ;
2010-08-12 10:44:45 +01:00
overlay - > color_key = attrs - > color_key ;
overlay - > brightness = attrs - > brightness ;
overlay - > contrast = attrs - > contrast ;
overlay - > saturation = attrs - > saturation ;
2009-09-15 22:57:34 +02:00
2010-08-12 10:35:26 +01:00
regs = intel_overlay_map_regs ( overlay ) ;
2009-09-15 22:57:34 +02:00
if ( ! regs ) {
ret = - ENOMEM ;
goto out_unlock ;
}
update_reg_attrs ( overlay , regs ) ;
2010-08-12 12:02:11 +01:00
intel_overlay_unmap_regs ( overlay , regs ) ;
2009-09-15 22:57:34 +02:00
if ( attrs - > flags & I915_OVERLAY_UPDATE_GAMMA ) {
2016-05-12 12:43:23 +01:00
if ( IS_GEN2 ( dev_priv ) )
2009-09-15 22:57:34 +02:00
goto out_unlock ;
if ( overlay - > active ) {
ret = - EBUSY ;
goto out_unlock ;
}
ret = check_gamma ( attrs ) ;
2010-08-12 10:44:45 +01:00
if ( ret )
2009-09-15 22:57:34 +02:00
goto out_unlock ;
I915_WRITE ( OGAMC0 , attrs - > gamma0 ) ;
I915_WRITE ( OGAMC1 , attrs - > gamma1 ) ;
I915_WRITE ( OGAMC2 , attrs - > gamma2 ) ;
I915_WRITE ( OGAMC3 , attrs - > gamma3 ) ;
I915_WRITE ( OGAMC4 , attrs - > gamma4 ) ;
I915_WRITE ( OGAMC5 , attrs - > gamma5 ) ;
}
}
2015-04-02 10:35:08 +01:00
overlay - > color_key_enabled = ( attrs - > flags & I915_OVERLAY_DISABLE_DEST_COLORKEY ) = = 0 ;
2009-09-15 22:57:34 +02:00
2010-08-12 10:44:45 +01:00
ret = 0 ;
2009-09-15 22:57:34 +02:00
out_unlock :
mutex_unlock ( & dev - > struct_mutex ) ;
2012-12-02 01:05:46 +01:00
drm_modeset_unlock_all ( dev ) ;
2009-09-15 22:57:34 +02:00
return ret ;
}
2016-05-12 12:43:23 +01:00
void intel_setup_overlay ( struct drm_i915_private * dev_priv )
2009-09-15 22:57:34 +02:00
{
struct intel_overlay * overlay ;
2010-11-08 19:18:58 +00:00
struct drm_i915_gem_object * reg_bo ;
2012-04-16 14:07:43 -07:00
struct overlay_registers __iomem * regs ;
2016-08-15 10:49:06 +01:00
struct i915_vma * vma = NULL ;
2009-09-15 22:57:34 +02:00
int ret ;
2016-05-12 12:43:23 +01:00
if ( ! HAS_OVERLAY ( dev_priv ) )
2009-09-15 22:57:34 +02:00
return ;
2013-09-19 12:18:32 +02:00
overlay = kzalloc ( sizeof ( * overlay ) , GFP_KERNEL ) ;
2009-09-15 22:57:34 +02:00
if ( ! overlay )
return ;
2011-06-28 11:27:47 +01:00
2016-07-05 10:40:23 +01:00
mutex_lock ( & dev_priv - > drm . struct_mutex ) ;
2011-06-28 11:27:47 +01:00
if ( WARN_ON ( dev_priv - > overlay ) )
goto out_free ;
2016-05-12 12:43:23 +01:00
overlay - > i915 = dev_priv ;
2009-09-15 22:57:34 +02:00
2013-07-23 19:24:38 +02:00
reg_bo = NULL ;
2016-05-12 12:43:23 +01:00
if ( ! OVERLAY_NEEDS_PHYSICAL ( dev_priv ) )
2016-12-01 14:16:36 +00:00
reg_bo = i915_gem_object_create_stolen ( dev_priv , PAGE_SIZE ) ;
2012-11-15 11:32:29 +00:00
if ( reg_bo = = NULL )
2016-12-01 14:16:37 +00:00
reg_bo = i915_gem_object_create ( dev_priv , PAGE_SIZE ) ;
2016-04-25 13:32:13 +01:00
if ( IS_ERR ( reg_bo ) )
2009-09-15 22:57:34 +02:00
goto out_free ;
2010-11-08 19:18:58 +00:00
overlay - > reg_bo = reg_bo ;
2009-09-15 22:57:34 +02:00
2016-05-12 12:43:23 +01:00
if ( OVERLAY_NEEDS_PHYSICAL ( dev_priv ) ) {
2014-05-21 12:42:56 +01:00
ret = i915_gem_object_attach_phys ( reg_bo , PAGE_SIZE ) ;
2011-08-16 15:34:10 -04:00
if ( ret ) {
DRM_ERROR ( " failed to attach phys overlay regs \n " ) ;
goto out_free_bo ;
}
2014-05-21 12:42:56 +01:00
overlay - > flip_addr = reg_bo - > phys_handle - > busaddr ;
2010-08-12 09:42:51 +01:00
} else {
2016-08-15 10:49:06 +01:00
vma = i915_gem_object_ggtt_pin ( reg_bo , NULL ,
2016-08-04 16:32:34 +01:00
0 , PAGE_SIZE , PIN_MAPPABLE ) ;
2016-08-15 10:49:06 +01:00
if ( IS_ERR ( vma ) ) {
2011-08-16 15:34:10 -04:00
DRM_ERROR ( " failed to pin overlay register bo \n " ) ;
2016-08-15 10:49:06 +01:00
ret = PTR_ERR ( vma ) ;
2011-08-16 15:34:10 -04:00
goto out_free_bo ;
}
2016-08-15 10:49:07 +01:00
overlay - > flip_addr = i915_ggtt_offset ( vma ) ;
2010-08-12 09:35:00 +01:00
ret = i915_gem_object_set_to_gtt_domain ( reg_bo , true ) ;
if ( ret ) {
2011-08-16 15:34:10 -04:00
DRM_ERROR ( " failed to move overlay register bo into the GTT \n " ) ;
goto out_unpin_bo ;
}
2009-09-15 22:57:34 +02:00
}
/* init all values */
overlay - > color_key = 0x0101fe ;
2015-04-02 10:35:08 +01:00
overlay - > color_key_enabled = true ;
2009-09-15 22:57:34 +02:00
overlay - > brightness = - 19 ;
overlay - > contrast = 75 ;
overlay - > saturation = 146 ;
2016-12-21 16:45:47 +02:00
init_request_active ( & overlay - > last_flip , NULL ) ;
2010-08-12 10:35:26 +01:00
regs = intel_overlay_map_regs ( overlay ) ;
2009-09-15 22:57:34 +02:00
if ( ! regs )
2011-06-28 11:27:47 +01:00
goto out_unpin_bo ;
2009-09-15 22:57:34 +02:00
2012-04-16 14:07:43 -07:00
memset_io ( regs , 0 , sizeof ( struct overlay_registers ) ) ;
2009-09-15 22:57:34 +02:00
update_polyphase_filter ( regs ) ;
update_reg_attrs ( overlay , regs ) ;
2010-08-12 12:02:11 +01:00
intel_overlay_unmap_regs ( overlay , regs ) ;
2009-09-15 22:57:34 +02:00
dev_priv - > overlay = overlay ;
2016-07-05 10:40:23 +01:00
mutex_unlock ( & dev_priv - > drm . struct_mutex ) ;
2009-09-15 22:57:34 +02:00
DRM_INFO ( " initialized overlay support \n " ) ;
return ;
2010-08-12 09:35:00 +01:00
out_unpin_bo :
2016-08-15 10:49:06 +01:00
if ( vma )
i915_vma_unpin ( vma ) ;
2009-09-15 22:57:34 +02:00
out_free_bo :
2016-07-20 13:31:53 +01:00
i915_gem_object_put ( reg_bo ) ;
2009-09-15 22:57:34 +02:00
out_free :
2016-07-05 10:40:23 +01:00
mutex_unlock ( & dev_priv - > drm . struct_mutex ) ;
2009-09-15 22:57:34 +02:00
kfree ( overlay ) ;
return ;
}
2016-05-12 12:43:23 +01:00
void intel_cleanup_overlay ( struct drm_i915_private * dev_priv )
2009-09-15 22:57:34 +02:00
{
2010-08-12 10:50:36 +01:00
if ( ! dev_priv - > overlay )
return ;
2009-09-15 22:57:34 +02:00
2010-08-12 10:50:36 +01:00
/* The bo's should be free'd by the generic code already.
* Furthermore modesetting teardown happens beforehand so the
* hardware should be off already */
2015-03-31 10:37:22 +03:00
WARN_ON ( dev_priv - > overlay - > active ) ;
2010-08-12 10:50:36 +01:00
2016-10-28 13:58:43 +01:00
i915_gem_object_put ( dev_priv - > overlay - > reg_bo ) ;
2010-08-12 10:50:36 +01:00
kfree ( dev_priv - > overlay ) ;
2009-09-15 22:57:34 +02:00
}
2010-08-04 20:26:07 +01:00
2016-10-12 10:05:18 +01:00
# if IS_ENABLED(CONFIG_DRM_I915_CAPTURE_ERROR)
2010-08-04 20:26:07 +01:00
struct intel_overlay_error_state {
struct overlay_registers regs ;
unsigned long base ;
u32 dovsta ;
u32 isr ;
} ;
2012-04-16 14:07:43 -07:00
static struct overlay_registers __iomem *
2010-10-26 18:57:59 -07:00
intel_overlay_map_regs_atomic ( struct intel_overlay * overlay )
2010-08-19 08:19:30 +01:00
{
2016-05-12 12:43:23 +01:00
struct drm_i915_private * dev_priv = overlay - > i915 ;
2012-04-16 14:07:43 -07:00
struct overlay_registers __iomem * regs ;
2010-08-19 08:19:30 +01:00
2016-05-12 12:43:23 +01:00
if ( OVERLAY_NEEDS_PHYSICAL ( dev_priv ) )
2012-04-16 14:07:43 -07:00
/* Cast to make sparse happy, but it's wc memory anyway, so
* equivalent to the wc io mapping on X86 . */
regs = ( struct overlay_registers __iomem * )
2014-05-21 12:42:56 +01:00
overlay - > reg_bo - > phys_handle - > vaddr ;
2010-08-19 08:19:30 +01:00
else
2016-08-19 16:54:27 +01:00
regs = io_mapping_map_atomic_wc ( & dev_priv - > ggtt . mappable ,
2016-04-28 09:56:36 +01:00
overlay - > flip_addr ) ;
2010-08-19 08:19:30 +01:00
return regs ;
}
static void intel_overlay_unmap_regs_atomic ( struct intel_overlay * overlay ,
2012-04-16 14:07:43 -07:00
struct overlay_registers __iomem * regs )
2010-08-19 08:19:30 +01:00
{
2016-05-12 12:43:23 +01:00
if ( ! OVERLAY_NEEDS_PHYSICAL ( overlay - > i915 ) )
2010-10-26 18:57:59 -07:00
io_mapping_unmap_atomic ( regs ) ;
2010-08-19 08:19:30 +01:00
}
2010-08-04 20:26:07 +01:00
struct intel_overlay_error_state *
2016-05-06 15:40:21 +01:00
intel_overlay_capture_error_state ( struct drm_i915_private * dev_priv )
2010-08-04 20:26:07 +01:00
{
struct intel_overlay * overlay = dev_priv - > overlay ;
struct intel_overlay_error_state * error ;
struct overlay_registers __iomem * regs ;
if ( ! overlay | | ! overlay - > active )
return NULL ;
error = kmalloc ( sizeof ( * error ) , GFP_ATOMIC ) ;
if ( error = = NULL )
return NULL ;
error - > dovsta = I915_READ ( DOVSTA ) ;
error - > isr = I915_READ ( ISR ) ;
2016-04-28 09:56:36 +01:00
error - > base = overlay - > flip_addr ;
2010-08-04 20:26:07 +01:00
regs = intel_overlay_map_regs_atomic ( overlay ) ;
if ( ! regs )
goto err ;
memcpy_fromio ( & error - > regs , regs , sizeof ( struct overlay_registers ) ) ;
2010-10-26 18:57:59 -07:00
intel_overlay_unmap_regs_atomic ( overlay , regs ) ;
2010-08-04 20:26:07 +01:00
return error ;
err :
kfree ( error ) ;
return NULL ;
}
void
2013-05-23 13:55:35 +03:00
intel_overlay_print_error_state ( struct drm_i915_error_state_buf * m ,
struct intel_overlay_error_state * error )
2010-08-04 20:26:07 +01:00
{
2013-05-23 13:55:35 +03:00
i915_error_printf ( m , " Overlay, status: 0x%08x, interrupt: 0x%08x \n " ,
error - > dovsta , error - > isr ) ;
i915_error_printf ( m , " Register file at 0x%08lx: \n " ,
error - > base ) ;
2010-08-04 20:26:07 +01:00
2013-05-23 13:55:35 +03:00
# define P(x) i915_error_printf(m, " " #x ": 0x%08x\n", error->regs.x)
2010-08-04 20:26:07 +01:00
P ( OBUF_0Y ) ;
P ( OBUF_1Y ) ;
P ( OBUF_0U ) ;
P ( OBUF_0V ) ;
P ( OBUF_1U ) ;
P ( OBUF_1V ) ;
P ( OSTRIDE ) ;
P ( YRGB_VPH ) ;
P ( UV_VPH ) ;
P ( HORZ_PH ) ;
P ( INIT_PHS ) ;
P ( DWINPOS ) ;
P ( DWINSZ ) ;
P ( SWIDTH ) ;
P ( SWIDTHSW ) ;
P ( SHEIGHT ) ;
P ( YRGBSCALE ) ;
P ( UVSCALE ) ;
P ( OCLRC0 ) ;
P ( OCLRC1 ) ;
P ( DCLRKV ) ;
P ( DCLRKM ) ;
P ( SCLRKVH ) ;
P ( SCLRKVL ) ;
P ( SCLRKEN ) ;
P ( OCONFIG ) ;
P ( OCMD ) ;
P ( OSTART_0Y ) ;
P ( OSTART_1Y ) ;
P ( OSTART_0U ) ;
P ( OSTART_0V ) ;
P ( OSTART_1U ) ;
P ( OSTART_1V ) ;
P ( OTILEOFF_0Y ) ;
P ( OTILEOFF_1Y ) ;
P ( OTILEOFF_0U ) ;
P ( OTILEOFF_0V ) ;
P ( OTILEOFF_1U ) ;
P ( OTILEOFF_1V ) ;
P ( FASTHSCALE ) ;
P ( UVSCALEV ) ;
# undef P
}
2016-10-12 10:05:18 +01:00
# endif