2014-05-19 14:54:33 +10:00
/*
2011-07-04 16:25:18 +10:00
* Copyright 2011 Red Hat Inc .
*
* 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 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 COPYRIGHT HOLDER ( S ) OR AUTHOR ( S ) 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 : Ben Skeggs
*/
2011-07-05 10:33:08 +10:00
# include <linux/dma-mapping.h>
2011-07-05 13:08:40 +10:00
2012-10-02 18:01:07 +01:00
# include <drm/drmP.h>
# include <drm/drm_crtc_helper.h>
2014-10-29 10:03:57 +01:00
# include <drm/drm_plane_helper.h>
2014-05-31 01:48:06 +10:00
# include <drm/drm_dp_helper.h>
2015-12-04 09:45:43 +01:00
# include <drm/drm_fb_helper.h>
2011-07-04 16:25:18 +10:00
2014-08-10 04:10:23 +10:00
# include <nvif/class.h>
2015-11-08 12:16:40 +10:00
# include <nvif/cl0002.h>
2015-11-08 10:44:19 +10:00
# include <nvif/cl5070.h>
# include <nvif/cl507a.h>
# include <nvif/cl507b.h>
# include <nvif/cl507c.h>
# include <nvif/cl507d.h>
# include <nvif/cl507e.h>
2014-08-10 04:10:23 +10:00
2016-05-20 09:22:55 +10:00
# include "nouveau_drv.h"
2012-07-31 16:16:21 +10:00
# include "nouveau_dma.h"
# include "nouveau_gem.h"
2011-07-04 16:25:18 +10:00
# include "nouveau_connector.h"
# include "nouveau_encoder.h"
# include "nouveau_crtc.h"
2012-07-22 11:55:54 +10:00
# include "nouveau_fence.h"
2011-07-07 10:47:10 +10:00
# include "nv50_display.h"
2011-07-04 16:25:18 +10:00
2011-11-12 23:52:07 +10:00
# define EVO_DMA_NR 9
2011-11-12 01:30:24 +10:00
# define EVO_MASTER (0x00)
2011-11-16 15:22:34 +10:00
# define EVO_FLIP(c) (0x01 + (c))
2011-11-12 23:52:07 +10:00
# define EVO_OVLY(c) (0x05 + (c))
# define EVO_OIMM(c) (0x09 + (c))
2011-11-12 01:30:24 +10:00
# define EVO_CURS(c) (0x0d + (c))
2011-11-16 15:48:48 +10:00
/* offsets in shared sync bo of various structures */
# define EVO_SYNC(c, o) ((c) * 0x0100 + (o))
2013-03-02 13:21:31 +10:00
# define EVO_MAST_NTFY EVO_SYNC( 0, 0x00)
# define EVO_FLIP_SEM0(c) EVO_SYNC((c) + 1, 0x00)
# define EVO_FLIP_SEM1(c) EVO_SYNC((c) + 1, 0x10)
2011-11-16 15:48:48 +10:00
2012-10-16 14:18:32 +10:00
/******************************************************************************
* EVO channel
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2012-11-21 14:40:21 +10:00
struct nv50_chan {
2014-08-10 04:10:22 +10:00
struct nvif_object user ;
2015-08-20 14:54:15 +10:00
struct nvif_device * device ;
2012-10-16 14:18:32 +10:00
} ;
static int
2015-08-20 14:54:15 +10:00
nv50_chan_create ( struct nvif_device * device , struct nvif_object * disp ,
2015-08-20 14:54:16 +10:00
const s32 * oclass , u8 head , void * data , u32 size ,
2015-08-20 14:54:15 +10:00
struct nv50_chan * chan )
2012-10-16 14:18:32 +10:00
{
2015-08-20 14:54:16 +10:00
struct nvif_sclass * sclass ;
int ret , i , n ;
2014-11-03 15:01:33 +10:00
2015-08-20 14:54:15 +10:00
chan - > device = device ;
2015-08-20 14:54:16 +10:00
ret = n = nvif_object_sclass_get ( disp , & sclass ) ;
2014-11-03 15:01:33 +10:00
if ( ret < 0 )
return ret ;
2014-08-10 04:10:25 +10:00
while ( oclass [ 0 ] ) {
2015-08-20 14:54:16 +10:00
for ( i = 0 ; i < n ; i + + ) {
if ( sclass [ i ] . oclass = = oclass [ 0 ] ) {
2015-09-04 14:40:32 +10:00
ret = nvif_object_init ( disp , 0 , oclass [ 0 ] ,
2015-08-20 14:54:15 +10:00
data , size , & chan - > user ) ;
2014-11-03 15:01:33 +10:00
if ( ret = = 0 )
nvif_object_map ( & chan - > user ) ;
2015-08-20 14:54:16 +10:00
nvif_object_sclass_put ( & sclass ) ;
2014-11-03 15:01:33 +10:00
return ret ;
}
2014-08-10 04:10:28 +10:00
}
2014-11-03 15:01:33 +10:00
oclass + + ;
2014-08-10 04:10:25 +10:00
}
2014-11-03 15:01:33 +10:00
2015-08-20 14:54:16 +10:00
nvif_object_sclass_put ( & sclass ) ;
2014-08-10 04:10:25 +10:00
return - ENOSYS ;
2012-10-16 14:18:32 +10:00
}
static void
2014-08-10 04:10:22 +10:00
nv50_chan_destroy ( struct nv50_chan * chan )
2012-10-16 14:18:32 +10:00
{
2014-08-10 04:10:22 +10:00
nvif_object_fini ( & chan - > user ) ;
2012-10-16 14:18:32 +10:00
}
/******************************************************************************
* PIO EVO channel
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2012-11-21 14:40:21 +10:00
struct nv50_pioc {
struct nv50_chan base ;
2012-10-16 14:18:32 +10:00
} ;
static void
2014-08-10 04:10:22 +10:00
nv50_pioc_destroy ( struct nv50_pioc * pioc )
2012-10-16 14:18:32 +10:00
{
2014-08-10 04:10:22 +10:00
nv50_chan_destroy ( & pioc - > base ) ;
2012-10-16 14:18:32 +10:00
}
static int
2015-08-20 14:54:15 +10:00
nv50_pioc_create ( struct nvif_device * device , struct nvif_object * disp ,
2015-08-20 14:54:16 +10:00
const s32 * oclass , u8 head , void * data , u32 size ,
2015-08-20 14:54:15 +10:00
struct nv50_pioc * pioc )
2012-10-16 14:18:32 +10:00
{
2015-08-20 14:54:15 +10:00
return nv50_chan_create ( device , disp , oclass , head , data , size ,
& pioc - > base ) ;
2014-08-10 04:10:25 +10:00
}
/******************************************************************************
* Cursor Immediate
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
struct nv50_curs {
struct nv50_pioc base ;
} ;
static int
2015-08-20 14:54:15 +10:00
nv50_curs_create ( struct nvif_device * device , struct nvif_object * disp ,
int head , struct nv50_curs * curs )
2014-08-10 04:10:25 +10:00
{
2014-08-10 04:10:27 +10:00
struct nv50_disp_cursor_v0 args = {
2014-08-10 04:10:25 +10:00
. head = head ,
} ;
2015-08-20 14:54:16 +10:00
static const s32 oclass [ ] = {
2014-08-10 04:10:27 +10:00
GK104_DISP_CURSOR ,
GF110_DISP_CURSOR ,
GT214_DISP_CURSOR ,
G82_DISP_CURSOR ,
NV50_DISP_CURSOR ,
2014-08-10 04:10:25 +10:00
0
} ;
2015-08-20 14:54:15 +10:00
return nv50_pioc_create ( device , disp , oclass , head , & args , sizeof ( args ) ,
& curs - > base ) ;
2014-08-10 04:10:25 +10:00
}
/******************************************************************************
* Overlay Immediate
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
struct nv50_oimm {
struct nv50_pioc base ;
} ;
static int
2015-08-20 14:54:15 +10:00
nv50_oimm_create ( struct nvif_device * device , struct nvif_object * disp ,
int head , struct nv50_oimm * oimm )
2014-08-10 04:10:25 +10:00
{
2014-08-10 04:10:27 +10:00
struct nv50_disp_cursor_v0 args = {
2014-08-10 04:10:25 +10:00
. head = head ,
} ;
2015-08-20 14:54:16 +10:00
static const s32 oclass [ ] = {
2014-08-10 04:10:27 +10:00
GK104_DISP_OVERLAY ,
GF110_DISP_OVERLAY ,
GT214_DISP_OVERLAY ,
G82_DISP_OVERLAY ,
NV50_DISP_OVERLAY ,
2014-08-10 04:10:25 +10:00
0
} ;
2015-08-20 14:54:15 +10:00
return nv50_pioc_create ( device , disp , oclass , head , & args , sizeof ( args ) ,
& oimm - > base ) ;
2012-10-16 14:18:32 +10:00
}
/******************************************************************************
* DMA EVO channel
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2012-11-21 14:40:21 +10:00
struct nv50_dmac {
struct nv50_chan base ;
2011-11-12 14:28:12 +10:00
dma_addr_t handle ;
u32 * ptr ;
2012-12-02 14:49:44 +01:00
2014-08-10 04:10:22 +10:00
struct nvif_object sync ;
struct nvif_object vram ;
2012-12-02 14:49:44 +01:00
/* Protects against concurrent pushbuf access to this channel, lock is
* grabbed by evo_wait ( if the pushbuf reservation is successful ) and
* dropped again by evo_kick . */
struct mutex lock ;
2012-10-16 14:18:32 +10:00
} ;
static void
2014-08-10 04:10:22 +10:00
nv50_dmac_destroy ( struct nv50_dmac * dmac , struct nvif_object * disp )
2012-10-16 14:18:32 +10:00
{
2015-08-20 14:54:15 +10:00
struct nvif_device * device = dmac - > base . device ;
2014-08-10 04:10:22 +10:00
nvif_object_fini ( & dmac - > vram ) ;
nvif_object_fini ( & dmac - > sync ) ;
nv50_chan_destroy ( & dmac - > base ) ;
2012-10-16 14:18:32 +10:00
if ( dmac - > ptr ) {
2015-08-20 14:54:23 +10:00
struct device * dev = nvxx_device ( device ) - > dev ;
dma_free_coherent ( dev , PAGE_SIZE , dmac - > ptr , dmac - > handle ) ;
2012-10-16 14:18:32 +10:00
}
}
2012-11-16 13:58:48 +10:00
static int
2015-08-20 14:54:15 +10:00
nv50_dmac_create ( struct nvif_device * device , struct nvif_object * disp ,
2015-08-20 14:54:16 +10:00
const s32 * oclass , u8 head , void * data , u32 size , u64 syncbuf ,
2012-11-21 14:40:21 +10:00
struct nv50_dmac * dmac )
2012-11-16 13:58:48 +10:00
{
2014-08-10 04:10:27 +10:00
struct nv50_disp_core_channel_dma_v0 * args = data ;
2014-08-10 04:10:22 +10:00
struct nvif_object pushbuf ;
2012-11-16 13:58:48 +10:00
int ret ;
2012-12-02 14:49:44 +01:00
mutex_init ( & dmac - > lock ) ;
2015-08-20 14:54:23 +10:00
dmac - > ptr = dma_alloc_coherent ( nvxx_device ( device ) - > dev , PAGE_SIZE ,
& dmac - > handle , GFP_KERNEL ) ;
2012-11-16 13:58:48 +10:00
if ( ! dmac - > ptr )
return - ENOMEM ;
2015-09-04 14:40:32 +10:00
ret = nvif_object_init ( & device - > object , 0 , NV_DMA_FROM_MEMORY ,
& ( struct nv_dma_v0 ) {
2014-08-10 04:10:24 +10:00
. target = NV_DMA_V0_TARGET_PCI_US ,
. access = NV_DMA_V0_ACCESS_RD ,
2012-11-16 13:58:48 +10:00
. start = dmac - > handle + 0x0000 ,
. limit = dmac - > handle + 0x0fff ,
2014-08-10 04:10:24 +10:00
} , sizeof ( struct nv_dma_v0 ) , & pushbuf ) ;
2012-10-16 14:18:32 +10:00
if ( ret )
2012-11-16 13:58:48 +10:00
return ret ;
2012-10-16 14:18:32 +10:00
2015-08-20 14:54:16 +10:00
args - > pushbuf = nvif_handle ( & pushbuf ) ;
2015-08-20 14:54:15 +10:00
ret = nv50_chan_create ( device , disp , oclass , head , data , size ,
& dmac - > base ) ;
2014-08-10 04:10:22 +10:00
nvif_object_fini ( & pushbuf ) ;
2012-11-16 13:58:48 +10:00
if ( ret )
return ret ;
2015-08-20 14:54:15 +10:00
ret = nvif_object_init ( & dmac - > base . user , 0xf0000000 , NV_DMA_IN_MEMORY ,
2014-08-10 04:10:24 +10:00
& ( struct nv_dma_v0 ) {
. target = NV_DMA_V0_TARGET_VRAM ,
. access = NV_DMA_V0_ACCESS_RDWR ,
2012-11-16 13:58:48 +10:00
. start = syncbuf + 0x0000 ,
. limit = syncbuf + 0x0fff ,
2014-08-10 04:10:24 +10:00
} , sizeof ( struct nv_dma_v0 ) ,
2014-08-10 04:10:22 +10:00
& dmac - > sync ) ;
2012-11-16 13:58:48 +10:00
if ( ret )
return ret ;
2015-08-20 14:54:15 +10:00
ret = nvif_object_init ( & dmac - > base . user , 0xf0000001 , NV_DMA_IN_MEMORY ,
2014-08-10 04:10:24 +10:00
& ( struct nv_dma_v0 ) {
. target = NV_DMA_V0_TARGET_VRAM ,
. access = NV_DMA_V0_ACCESS_RDWR ,
2012-10-16 14:18:32 +10:00
. start = 0 ,
2014-08-10 04:10:28 +10:00
. limit = device - > info . ram_user - 1 ,
2014-08-10 04:10:24 +10:00
} , sizeof ( struct nv_dma_v0 ) ,
2014-08-10 04:10:22 +10:00
& dmac - > vram ) ;
2012-10-16 14:18:32 +10:00
if ( ret )
2012-11-16 13:58:48 +10:00
return ret ;
2012-10-16 14:18:32 +10:00
return ret ;
}
2014-08-10 04:10:25 +10:00
/******************************************************************************
* Core
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2012-11-21 14:40:21 +10:00
struct nv50_mast {
struct nv50_dmac base ;
2012-10-16 14:18:32 +10:00
} ;
2014-08-10 04:10:25 +10:00
static int
2015-08-20 14:54:15 +10:00
nv50_core_create ( struct nvif_device * device , struct nvif_object * disp ,
u64 syncbuf , struct nv50_mast * core )
2014-08-10 04:10:25 +10:00
{
2014-08-10 04:10:27 +10:00
struct nv50_disp_core_channel_dma_v0 args = {
. pushbuf = 0xb0007d00 ,
2014-08-10 04:10:25 +10:00
} ;
2015-08-20 14:54:16 +10:00
static const s32 oclass [ ] = {
2016-07-09 10:41:01 +10:00
GP104_DISP_CORE_CHANNEL_DMA ,
2016-07-09 10:41:01 +10:00
GP100_DISP_CORE_CHANNEL_DMA ,
2016-02-11 08:35:32 +10:00
GM200_DISP_CORE_CHANNEL_DMA ,
2014-08-10 04:10:27 +10:00
GM107_DISP_CORE_CHANNEL_DMA ,
GK110_DISP_CORE_CHANNEL_DMA ,
GK104_DISP_CORE_CHANNEL_DMA ,
GF110_DISP_CORE_CHANNEL_DMA ,
GT214_DISP_CORE_CHANNEL_DMA ,
GT206_DISP_CORE_CHANNEL_DMA ,
GT200_DISP_CORE_CHANNEL_DMA ,
G82_DISP_CORE_CHANNEL_DMA ,
NV50_DISP_CORE_CHANNEL_DMA ,
2014-08-10 04:10:25 +10:00
0
} ;
2015-08-20 14:54:15 +10:00
return nv50_dmac_create ( device , disp , oclass , 0 , & args , sizeof ( args ) ,
syncbuf , & core - > base ) ;
2014-08-10 04:10:25 +10:00
}
/******************************************************************************
* Base
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2012-10-16 14:18:32 +10:00
2012-11-21 14:40:21 +10:00
struct nv50_sync {
struct nv50_dmac base ;
2013-03-02 13:21:31 +10:00
u32 addr ;
u32 data ;
2011-11-12 14:28:12 +10:00
} ;
2014-08-10 04:10:25 +10:00
static int
2015-08-20 14:54:15 +10:00
nv50_base_create ( struct nvif_device * device , struct nvif_object * disp ,
int head , u64 syncbuf , struct nv50_sync * base )
2014-08-10 04:10:25 +10:00
{
2014-08-10 04:10:27 +10:00
struct nv50_disp_base_channel_dma_v0 args = {
. pushbuf = 0xb0007c00 | head ,
2014-08-10 04:10:25 +10:00
. head = head ,
} ;
2015-08-20 14:54:16 +10:00
static const s32 oclass [ ] = {
2014-08-10 04:10:27 +10:00
GK110_DISP_BASE_CHANNEL_DMA ,
GK104_DISP_BASE_CHANNEL_DMA ,
GF110_DISP_BASE_CHANNEL_DMA ,
GT214_DISP_BASE_CHANNEL_DMA ,
GT200_DISP_BASE_CHANNEL_DMA ,
G82_DISP_BASE_CHANNEL_DMA ,
NV50_DISP_BASE_CHANNEL_DMA ,
2014-08-10 04:10:25 +10:00
0
} ;
2015-08-20 14:54:15 +10:00
return nv50_dmac_create ( device , disp , oclass , head , & args , sizeof ( args ) ,
2014-08-10 04:10:25 +10:00
syncbuf , & base - > base ) ;
}
/******************************************************************************
* Overlay
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2012-11-21 14:40:21 +10:00
struct nv50_ovly {
struct nv50_dmac base ;
2012-10-16 14:18:32 +10:00
} ;
2011-07-08 13:17:01 +10:00
2014-08-10 04:10:25 +10:00
static int
2015-08-20 14:54:15 +10:00
nv50_ovly_create ( struct nvif_device * device , struct nvif_object * disp ,
int head , u64 syncbuf , struct nv50_ovly * ovly )
2014-08-10 04:10:25 +10:00
{
2014-08-10 04:10:27 +10:00
struct nv50_disp_overlay_channel_dma_v0 args = {
. pushbuf = 0xb0007e00 | head ,
2014-08-10 04:10:25 +10:00
. head = head ,
} ;
2015-08-20 14:54:16 +10:00
static const s32 oclass [ ] = {
2014-08-10 04:10:27 +10:00
GK104_DISP_OVERLAY_CONTROL_DMA ,
GF110_DISP_OVERLAY_CONTROL_DMA ,
GT214_DISP_OVERLAY_CHANNEL_DMA ,
GT200_DISP_OVERLAY_CHANNEL_DMA ,
G82_DISP_OVERLAY_CHANNEL_DMA ,
NV50_DISP_OVERLAY_CHANNEL_DMA ,
2014-08-10 04:10:25 +10:00
0
} ;
2015-08-20 14:54:15 +10:00
return nv50_dmac_create ( device , disp , oclass , head , & args , sizeof ( args ) ,
2014-08-10 04:10:25 +10:00
syncbuf , & ovly - > base ) ;
}
2011-07-04 16:25:18 +10:00
2012-11-21 14:40:21 +10:00
struct nv50_head {
2012-10-16 14:00:31 +10:00
struct nouveau_crtc base ;
2013-07-09 12:35:55 +10:00
struct nouveau_bo * image ;
2012-11-21 14:40:21 +10:00
struct nv50_curs curs ;
struct nv50_sync sync ;
struct nv50_ovly ovly ;
struct nv50_oimm oimm ;
2012-10-16 14:18:32 +10:00
} ;
2012-11-21 14:40:21 +10:00
# define nv50_head(c) ((struct nv50_head *)nouveau_crtc(c))
# define nv50_curs(c) (&nv50_head(c)->curs)
# define nv50_sync(c) (&nv50_head(c)->sync)
# define nv50_ovly(c) (&nv50_head(c)->ovly)
# define nv50_oimm(c) (&nv50_head(c)->oimm)
# define nv50_chan(c) (&(c)->base.base)
2014-08-10 04:10:22 +10:00
# define nv50_vers(c) nv50_chan(c)->user.oclass
struct nv50_fbdma {
struct list_head head ;
struct nvif_object core ;
struct nvif_object base [ 4 ] ;
} ;
2012-10-16 14:18:32 +10:00
2012-11-21 14:40:21 +10:00
struct nv50_disp {
2014-08-10 04:10:22 +10:00
struct nvif_object * disp ;
2012-11-21 14:40:21 +10:00
struct nv50_mast mast ;
2012-10-16 14:18:32 +10:00
2014-08-10 04:10:19 +10:00
struct list_head fbdma ;
2012-10-16 14:18:32 +10:00
struct nouveau_bo * sync ;
2012-10-16 14:00:31 +10:00
} ;
2012-11-21 14:40:21 +10:00
static struct nv50_disp *
nv50_disp ( struct drm_device * dev )
2011-07-04 16:25:18 +10:00
{
2012-07-31 16:16:21 +10:00
return nouveau_display ( dev ) - > priv ;
2011-07-04 16:25:18 +10:00
}
2012-11-21 14:40:21 +10:00
# define nv50_mast(d) (&nv50_disp(d)->mast)
2012-10-16 14:18:32 +10:00
2011-11-12 01:30:24 +10:00
static struct drm_crtc *
2012-11-21 14:40:21 +10:00
nv50_display_crtc_get ( struct drm_encoder * encoder )
2011-11-12 01:30:24 +10:00
{
return nouveau_encoder ( encoder ) - > crtc ;
}
/******************************************************************************
* EVO channel helpers
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2011-07-05 10:33:08 +10:00
static u32 *
2012-10-16 14:18:32 +10:00
evo_wait ( void * evoc , int nr )
2011-07-05 10:33:08 +10:00
{
2012-11-21 14:40:21 +10:00
struct nv50_dmac * dmac = evoc ;
2015-08-20 14:54:15 +10:00
struct nvif_device * device = dmac - > base . device ;
2014-08-10 04:10:22 +10:00
u32 put = nvif_rd32 ( & dmac - > base . user , 0x0000 ) / 4 ;
2011-07-05 10:33:08 +10:00
2012-12-02 14:49:44 +01:00
mutex_lock ( & dmac - > lock ) ;
2012-11-16 10:24:31 +10:00
if ( put + nr > = ( PAGE_SIZE / 4 ) - 8 ) {
2012-10-16 14:18:32 +10:00
dmac - > ptr [ put ] = 0x20000000 ;
2011-07-05 10:33:08 +10:00
2014-08-10 04:10:22 +10:00
nvif_wr32 ( & dmac - > base . user , 0x0000 , 0x00000000 ) ;
2015-08-20 14:54:11 +10:00
if ( nvif_msec ( device , 2000 ,
if ( ! nvif_rd32 ( & dmac - > base . user , 0x0004 ) )
break ;
) < 0 ) {
2012-12-02 14:49:44 +01:00
mutex_unlock ( & dmac - > lock ) ;
2015-08-20 14:54:13 +10:00
printk ( KERN_ERR " nouveau: evo channel stalled \n " ) ;
2011-07-05 10:33:08 +10:00
return NULL ;
}
put = 0 ;
}
2012-10-16 14:18:32 +10:00
return dmac - > ptr + put ;
2011-07-05 10:33:08 +10:00
}
static void
2012-10-16 14:18:32 +10:00
evo_kick ( u32 * push , void * evoc )
2011-07-05 10:33:08 +10:00
{
2012-11-21 14:40:21 +10:00
struct nv50_dmac * dmac = evoc ;
2014-08-10 04:10:22 +10:00
nvif_wr32 ( & dmac - > base . user , 0x0000 , ( push - dmac - > ptr ) < < 2 ) ;
2012-12-02 14:49:44 +01:00
mutex_unlock ( & dmac - > lock ) ;
2011-07-05 10:33:08 +10:00
}
2014-11-03 16:43:59 +10:00
# if 1
2011-07-05 10:33:08 +10:00
# define evo_mthd(p,m,s) *((p)++) = (((s) << 18) | (m))
# define evo_data(p,d) *((p)++) = (d)
2014-11-03 16:43:59 +10:00
# else
# define evo_mthd(p,m,s) do { \
const u32 _m = ( m ) , _s = ( s ) ; \
printk ( KERN_ERR " %04x %d %s \n " , _m , _s , __func__ ) ; \
* ( ( p ) + + ) = ( ( _s < < 18 ) | _m ) ; \
} while ( 0 )
# define evo_data(p,d) do { \
const u32 _d = ( d ) ; \
printk ( KERN_ERR " \t %08x \n " , _d ) ; \
* ( ( p ) + + ) = _d ; \
} while ( 0 )
# endif
2011-07-05 10:33:08 +10:00
2011-11-12 14:28:12 +10:00
static bool
evo_sync_wait ( void * data )
{
2013-02-18 17:50:51 -05:00
if ( nouveau_bo_rd32 ( data , EVO_MAST_NTFY ) ! = 0x00000000 )
return true ;
usleep_range ( 1 , 2 ) ;
return false ;
2011-11-12 14:28:12 +10:00
}
static int
2012-10-16 14:18:32 +10:00
evo_sync ( struct drm_device * dev )
2011-11-12 14:28:12 +10:00
{
2014-08-10 04:10:22 +10:00
struct nvif_device * device = & nouveau_drm ( dev ) - > device ;
2012-11-21 14:40:21 +10:00
struct nv50_disp * disp = nv50_disp ( dev ) ;
struct nv50_mast * mast = nv50_mast ( dev ) ;
2012-10-16 14:18:32 +10:00
u32 * push = evo_wait ( mast , 8 ) ;
2011-11-12 14:28:12 +10:00
if ( push ) {
2011-11-16 15:48:48 +10:00
nouveau_bo_wr32 ( disp - > sync , EVO_MAST_NTFY , 0x00000000 ) ;
2011-11-12 14:28:12 +10:00
evo_mthd ( push , 0x0084 , 1 ) ;
2011-11-16 15:48:48 +10:00
evo_data ( push , 0x80000000 | EVO_MAST_NTFY ) ;
2011-11-12 14:28:12 +10:00
evo_mthd ( push , 0x0080 , 2 ) ;
evo_data ( push , 0x00000000 ) ;
evo_data ( push , 0x00000000 ) ;
2012-10-16 14:18:32 +10:00
evo_kick ( push , mast ) ;
2015-08-20 14:54:11 +10:00
if ( nvif_msec ( device , 2000 ,
if ( evo_sync_wait ( disp - > sync ) )
break ;
) > = 0 )
2011-11-12 14:28:12 +10:00
return 0 ;
}
return - EBUSY ;
}
/******************************************************************************
2011-11-16 15:22:34 +10:00
* Page flipping channel
2011-11-12 14:28:12 +10:00
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
struct nouveau_bo *
2012-11-21 14:40:21 +10:00
nv50_display_crtc_sema ( struct drm_device * dev , int crtc )
2011-11-12 14:28:12 +10:00
{
2012-11-21 14:40:21 +10:00
return nv50_disp ( dev ) - > sync ;
2011-11-12 14:28:12 +10:00
}
2013-03-02 13:21:31 +10:00
struct nv50_display_flip {
struct nv50_disp * disp ;
struct nv50_sync * chan ;
} ;
static bool
nv50_display_flip_wait ( void * data )
{
struct nv50_display_flip * flip = data ;
if ( nouveau_bo_rd32 ( flip - > disp - > sync , flip - > chan - > addr / 4 ) = =
2013-04-07 21:01:19 -05:00
flip - > chan - > data )
2013-03-02 13:21:31 +10:00
return true ;
usleep_range ( 1 , 2 ) ;
return false ;
}
2011-11-12 14:28:12 +10:00
void
2012-11-21 14:40:21 +10:00
nv50_display_flip_stop ( struct drm_crtc * crtc )
2011-11-12 14:28:12 +10:00
{
2014-08-10 04:10:22 +10:00
struct nvif_device * device = & nouveau_drm ( crtc - > dev ) - > device ;
2013-03-02 13:21:31 +10:00
struct nv50_display_flip flip = {
. disp = nv50_disp ( crtc - > dev ) ,
. chan = nv50_sync ( crtc ) ,
} ;
2011-11-12 14:28:12 +10:00
u32 * push ;
2013-03-02 13:21:31 +10:00
push = evo_wait ( flip . chan , 8 ) ;
2011-11-12 14:28:12 +10:00
if ( push ) {
evo_mthd ( push , 0x0084 , 1 ) ;
evo_data ( push , 0x00000000 ) ;
evo_mthd ( push , 0x0094 , 1 ) ;
evo_data ( push , 0x00000000 ) ;
evo_mthd ( push , 0x00c0 , 1 ) ;
evo_data ( push , 0x00000000 ) ;
evo_mthd ( push , 0x0080 , 1 ) ;
evo_data ( push , 0x00000000 ) ;
2013-03-02 13:21:31 +10:00
evo_kick ( push , flip . chan ) ;
2011-11-12 14:28:12 +10:00
}
2013-03-02 13:21:31 +10:00
2015-08-20 14:54:11 +10:00
nvif_msec ( device , 2000 ,
if ( nv50_display_flip_wait ( & flip ) )
break ;
) ;
2011-11-12 14:28:12 +10:00
}
int
2012-11-21 14:40:21 +10:00
nv50_display_flip_next ( struct drm_crtc * crtc , struct drm_framebuffer * fb ,
2011-11-12 14:28:12 +10:00
struct nouveau_channel * chan , u32 swap_interval )
{
struct nouveau_framebuffer * nv_fb = nouveau_framebuffer ( fb ) ;
struct nouveau_crtc * nv_crtc = nouveau_crtc ( crtc ) ;
2013-07-09 12:35:55 +10:00
struct nv50_head * head = nv50_head ( crtc ) ;
2012-11-21 14:40:21 +10:00
struct nv50_sync * sync = nv50_sync ( crtc ) ;
2011-11-12 14:28:12 +10:00
u32 * push ;
2013-07-09 12:35:55 +10:00
int ret ;
2011-11-12 14:28:12 +10:00
2014-12-22 19:50:23 +10:00
if ( crtc - > primary - > fb - > width ! = fb - > width | |
crtc - > primary - > fb - > height ! = fb - > height )
return - EINVAL ;
2011-11-12 14:28:12 +10:00
swap_interval < < = 4 ;
if ( swap_interval = = 0 )
swap_interval | = 0x100 ;
2013-03-19 15:20:00 +10:00
if ( chan = = NULL )
evo_sync ( crtc - > dev ) ;
2011-11-12 14:28:12 +10:00
2012-10-16 14:18:32 +10:00
push = evo_wait ( sync , 128 ) ;
2011-11-12 14:28:12 +10:00
if ( unlikely ( push = = NULL ) )
return - EBUSY ;
2015-08-20 14:54:15 +10:00
if ( chan & & chan - > user . oclass < G82_CHANNEL_GPFIFO ) {
2013-03-02 13:21:31 +10:00
ret = RING_SPACE ( chan , 8 ) ;
if ( ret )
return ret ;
BEGIN_NV04 ( chan , 0 , NV11_SUBCHAN_DMA_SEMAPHORE , 2 ) ;
2013-07-09 12:35:55 +10:00
OUT_RING ( chan , NvEvoSema0 + nv_crtc - > index ) ;
2013-03-02 13:21:31 +10:00
OUT_RING ( chan , sync - > addr ^ 0x10 ) ;
BEGIN_NV04 ( chan , 0 , NV11_SUBCHAN_SEMAPHORE_RELEASE , 1 ) ;
OUT_RING ( chan , sync - > data + 1 ) ;
BEGIN_NV04 ( chan , 0 , NV11_SUBCHAN_SEMAPHORE_OFFSET , 2 ) ;
OUT_RING ( chan , sync - > addr ) ;
OUT_RING ( chan , sync - > data ) ;
} else
2015-08-20 14:54:15 +10:00
if ( chan & & chan - > user . oclass < FERMI_CHANNEL_GPFIFO ) {
2013-07-09 12:35:55 +10:00
u64 addr = nv84_fence_crtc ( chan , nv_crtc - > index ) + sync - > addr ;
2013-03-02 13:21:31 +10:00
ret = RING_SPACE ( chan , 12 ) ;
if ( ret )
return ret ;
BEGIN_NV04 ( chan , 0 , NV11_SUBCHAN_DMA_SEMAPHORE , 1 ) ;
2014-08-10 04:10:22 +10:00
OUT_RING ( chan , chan - > vram . handle ) ;
2013-03-02 13:21:31 +10:00
BEGIN_NV04 ( chan , 0 , NV84_SUBCHAN_SEMAPHORE_ADDRESS_HIGH , 4 ) ;
OUT_RING ( chan , upper_32_bits ( addr ^ 0x10 ) ) ;
OUT_RING ( chan , lower_32_bits ( addr ^ 0x10 ) ) ;
OUT_RING ( chan , sync - > data + 1 ) ;
OUT_RING ( chan , NV84_SUBCHAN_SEMAPHORE_TRIGGER_WRITE_LONG ) ;
BEGIN_NV04 ( chan , 0 , NV84_SUBCHAN_SEMAPHORE_ADDRESS_HIGH , 4 ) ;
OUT_RING ( chan , upper_32_bits ( addr ) ) ;
OUT_RING ( chan , lower_32_bits ( addr ) ) ;
OUT_RING ( chan , sync - > data ) ;
OUT_RING ( chan , NV84_SUBCHAN_SEMAPHORE_TRIGGER_ACQUIRE_EQUAL ) ;
} else
if ( chan ) {
2013-07-09 12:35:55 +10:00
u64 addr = nv84_fence_crtc ( chan , nv_crtc - > index ) + sync - > addr ;
2013-03-02 13:21:31 +10:00
ret = RING_SPACE ( chan , 10 ) ;
if ( ret )
return ret ;
BEGIN_NVC0 ( chan , 0 , NV84_SUBCHAN_SEMAPHORE_ADDRESS_HIGH , 4 ) ;
OUT_RING ( chan , upper_32_bits ( addr ^ 0x10 ) ) ;
OUT_RING ( chan , lower_32_bits ( addr ^ 0x10 ) ) ;
OUT_RING ( chan , sync - > data + 1 ) ;
OUT_RING ( chan , NV84_SUBCHAN_SEMAPHORE_TRIGGER_WRITE_LONG |
NVC0_SUBCHAN_SEMAPHORE_TRIGGER_YIELD ) ;
BEGIN_NVC0 ( chan , 0 , NV84_SUBCHAN_SEMAPHORE_ADDRESS_HIGH , 4 ) ;
OUT_RING ( chan , upper_32_bits ( addr ) ) ;
OUT_RING ( chan , lower_32_bits ( addr ) ) ;
OUT_RING ( chan , sync - > data ) ;
OUT_RING ( chan , NV84_SUBCHAN_SEMAPHORE_TRIGGER_ACQUIRE_EQUAL |
NVC0_SUBCHAN_SEMAPHORE_TRIGGER_YIELD ) ;
}
2012-04-30 11:34:10 -05:00
2013-03-02 13:21:31 +10:00
if ( chan ) {
sync - > addr ^ = 0x10 ;
sync - > data + + ;
2011-11-12 14:28:12 +10:00
FIRE_RING ( chan ) ;
}
/* queue the flip */
evo_mthd ( push , 0x0100 , 1 ) ;
evo_data ( push , 0xfffe0000 ) ;
evo_mthd ( push , 0x0084 , 1 ) ;
evo_data ( push , swap_interval ) ;
if ( ! ( swap_interval & 0x00000100 ) ) {
evo_mthd ( push , 0x00e0 , 1 ) ;
evo_data ( push , 0x40000000 ) ;
}
evo_mthd ( push , 0x0088 , 4 ) ;
2013-03-02 13:21:31 +10:00
evo_data ( push , sync - > addr ) ;
evo_data ( push , sync - > data + + ) ;
evo_data ( push , sync - > data ) ;
2014-08-10 04:10:23 +10:00
evo_data ( push , sync - > base . sync . handle ) ;
2011-11-12 14:28:12 +10:00
evo_mthd ( push , 0x00a0 , 2 ) ;
evo_data ( push , 0x00000000 ) ;
evo_data ( push , 0x00000000 ) ;
evo_mthd ( push , 0x00c0 , 1 ) ;
2014-08-10 04:10:19 +10:00
evo_data ( push , nv_fb - > r_handle ) ;
2011-11-12 14:28:12 +10:00
evo_mthd ( push , 0x0110 , 2 ) ;
evo_data ( push , 0x00000000 ) ;
evo_data ( push , 0x00000000 ) ;
2014-08-10 04:10:27 +10:00
if ( nv50_vers ( sync ) < GF110_DISP_BASE_CHANNEL_DMA ) {
2012-11-16 13:16:51 +10:00
evo_mthd ( push , 0x0800 , 5 ) ;
evo_data ( push , nv_fb - > nvbo - > bo . offset > > 8 ) ;
evo_data ( push , 0 ) ;
evo_data ( push , ( fb - > height < < 16 ) | fb - > width ) ;
evo_data ( push , nv_fb - > r_pitch ) ;
evo_data ( push , nv_fb - > r_format ) ;
} else {
evo_mthd ( push , 0x0400 , 5 ) ;
evo_data ( push , nv_fb - > nvbo - > bo . offset > > 8 ) ;
evo_data ( push , 0 ) ;
evo_data ( push , ( fb - > height < < 16 ) | fb - > width ) ;
evo_data ( push , nv_fb - > r_pitch ) ;
evo_data ( push , nv_fb - > r_format ) ;
}
2011-11-12 14:28:12 +10:00
evo_mthd ( push , 0x0080 , 1 ) ;
evo_data ( push , 0x00000000 ) ;
2012-10-16 14:18:32 +10:00
evo_kick ( push , sync ) ;
2013-07-09 12:35:55 +10:00
nouveau_bo_ref ( nv_fb - > nvbo , & head - > image ) ;
2011-11-12 14:28:12 +10:00
return 0 ;
}
2011-07-05 16:48:06 +10:00
/******************************************************************************
* CRTC
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
static int
2012-11-21 14:40:21 +10:00
nv50_crtc_set_dither ( struct nouveau_crtc * nv_crtc , bool update )
2011-07-05 16:48:06 +10:00
{
2012-11-21 14:40:21 +10:00
struct nv50_mast * mast = nv50_mast ( nv_crtc - > base . dev ) ;
2011-10-17 12:23:41 +10:00
struct nouveau_connector * nv_connector ;
struct drm_connector * connector ;
u32 * push , mode = 0x00 ;
2011-07-05 16:48:06 +10:00
2011-10-17 10:38:10 +10:00
nv_connector = nouveau_crtc_connector_get ( nv_crtc ) ;
2011-10-17 12:23:41 +10:00
connector = & nv_connector - > base ;
if ( nv_connector - > dithering_mode = = DITHERING_MODE_AUTO ) {
2014-04-01 15:22:40 -07:00
if ( nv_crtc - > base . primary - > fb - > depth > connector - > display_info . bpc * 3 )
2011-10-17 12:23:41 +10:00
mode = DITHERING_MODE_DYNAMIC2X2 ;
} else {
mode = nv_connector - > dithering_mode ;
}
if ( nv_connector - > dithering_depth = = DITHERING_DEPTH_AUTO ) {
if ( connector - > display_info . bpc > = 8 )
mode | = DITHERING_DEPTH_8BPC ;
} else {
mode | = nv_connector - > dithering_depth ;
2011-07-05 16:48:06 +10:00
}
2012-11-16 10:24:31 +10:00
push = evo_wait ( mast , 4 ) ;
2011-07-05 16:48:06 +10:00
if ( push ) {
2014-08-10 04:10:27 +10:00
if ( nv50_vers ( mast ) < GF110_DISP_CORE_CHANNEL_DMA ) {
2012-11-16 10:24:31 +10:00
evo_mthd ( push , 0x08a0 + ( nv_crtc - > index * 0x0400 ) , 1 ) ;
evo_data ( push , mode ) ;
} else
2014-08-10 04:10:27 +10:00
if ( nv50_vers ( mast ) < GK104_DISP_CORE_CHANNEL_DMA ) {
2012-11-16 10:24:31 +10:00
evo_mthd ( push , 0x0490 + ( nv_crtc - > index * 0x0300 ) , 1 ) ;
evo_data ( push , mode ) ;
} else {
evo_mthd ( push , 0x04a0 + ( nv_crtc - > index * 0x0300 ) , 1 ) ;
evo_data ( push , mode ) ;
}
2011-07-05 16:48:06 +10:00
if ( update ) {
evo_mthd ( push , 0x0080 , 1 ) ;
evo_data ( push , 0x00000000 ) ;
}
2012-11-16 10:24:31 +10:00
evo_kick ( push , mast ) ;
2011-07-05 16:48:06 +10:00
}
return 0 ;
}
static int
2012-11-21 14:40:21 +10:00
nv50_crtc_set_scale ( struct nouveau_crtc * nv_crtc , bool update )
2011-07-05 16:48:06 +10:00
{
2012-11-21 14:40:21 +10:00
struct nv50_mast * mast = nv50_mast ( nv_crtc - > base . dev ) ;
2011-11-11 23:49:06 +10:00
struct drm_display_mode * omode , * umode = & nv_crtc - > base . mode ;
2011-11-12 14:28:12 +10:00
struct drm_crtc * crtc = & nv_crtc - > base ;
2011-07-07 16:01:57 +10:00
struct nouveau_connector * nv_connector ;
2011-11-11 23:49:06 +10:00
int mode = DRM_MODE_SCALE_NONE ;
u32 oX , oY , * push ;
2011-07-07 16:01:57 +10:00
2011-11-11 23:49:06 +10:00
/* start off at the resolution we programmed the crtc for, this
* effectively handles NONE / FULL scaling
*/
2011-07-07 16:01:57 +10:00
nv_connector = nouveau_crtc_connector_get ( nv_crtc ) ;
2014-12-22 17:19:26 +10:00
if ( nv_connector & & nv_connector - > native_mode ) {
2011-11-11 23:49:06 +10:00
mode = nv_connector - > scaling_mode ;
2014-12-22 17:19:26 +10:00
if ( nv_connector - > scaling_full ) /* non-EDID LVDS/eDP mode */
mode = DRM_MODE_SCALE_FULLSCREEN ;
}
2011-11-11 23:49:06 +10:00
if ( mode ! = DRM_MODE_SCALE_NONE )
omode = nv_connector - > native_mode ;
else
omode = umode ;
oX = omode - > hdisplay ;
oY = omode - > vdisplay ;
if ( omode - > flags & DRM_MODE_FLAG_DBLSCAN )
oY * = 2 ;
/* add overscan compensation if necessary, will keep the aspect
* ratio the same as the backend mode unless overridden by the
* user setting both hborder and vborder properties .
*/
if ( nv_connector & & ( nv_connector - > underscan = = UNDERSCAN_ON | |
( nv_connector - > underscan = = UNDERSCAN_AUTO & &
drm_detect_hdmi_monitor ( nv_connector - > edid ) ) ) ) {
u32 bX = nv_connector - > underscan_hborder ;
u32 bY = nv_connector - > underscan_vborder ;
u32 aspect = ( oY < < 19 ) / oX ;
if ( bX ) {
oX - = ( bX * 2 ) ;
if ( bY ) oY - = ( bY * 2 ) ;
else oY = ( ( oX * aspect ) + ( aspect / 2 ) ) > > 19 ;
} else {
oX - = ( oX > > 4 ) + 32 ;
if ( bY ) oY - = ( bY * 2 ) ;
else oY = ( ( oX * aspect ) + ( aspect / 2 ) ) > > 19 ;
}
}
/* handle CENTER/ASPECT scaling, taking into account the areas
* removed already for overscan compensation
*/
switch ( mode ) {
case DRM_MODE_SCALE_CENTER :
oX = min ( ( u32 ) umode - > hdisplay , oX ) ;
oY = min ( ( u32 ) umode - > vdisplay , oY ) ;
/* fall-through */
case DRM_MODE_SCALE_ASPECT :
if ( oY < oX ) {
u32 aspect = ( umode - > hdisplay < < 19 ) / umode - > vdisplay ;
oX = ( ( oY * aspect ) + ( aspect / 2 ) ) > > 19 ;
} else {
u32 aspect = ( umode - > vdisplay < < 19 ) / umode - > hdisplay ;
oY = ( ( oX * aspect ) + ( aspect / 2 ) ) > > 19 ;
2011-07-07 16:01:57 +10:00
}
2011-11-11 23:49:06 +10:00
break ;
default :
break ;
2011-07-07 16:01:57 +10:00
}
2011-07-05 16:48:06 +10:00
2012-11-16 10:24:31 +10:00
push = evo_wait ( mast , 8 ) ;
2011-07-05 16:48:06 +10:00
if ( push ) {
2014-08-10 04:10:27 +10:00
if ( nv50_vers ( mast ) < GF110_DISP_CORE_CHANNEL_DMA ) {
2012-11-16 10:24:31 +10:00
/*XXX: SCALE_CTRL_ACTIVE??? */
evo_mthd ( push , 0x08d8 + ( nv_crtc - > index * 0x400 ) , 2 ) ;
evo_data ( push , ( oY < < 16 ) | oX ) ;
evo_data ( push , ( oY < < 16 ) | oX ) ;
evo_mthd ( push , 0x08a4 + ( nv_crtc - > index * 0x400 ) , 1 ) ;
evo_data ( push , 0x00000000 ) ;
evo_mthd ( push , 0x08c8 + ( nv_crtc - > index * 0x400 ) , 1 ) ;
evo_data ( push , umode - > vdisplay < < 16 | umode - > hdisplay ) ;
} else {
evo_mthd ( push , 0x04c0 + ( nv_crtc - > index * 0x300 ) , 3 ) ;
evo_data ( push , ( oY < < 16 ) | oX ) ;
evo_data ( push , ( oY < < 16 ) | oX ) ;
evo_data ( push , ( oY < < 16 ) | oX ) ;
evo_mthd ( push , 0x0494 + ( nv_crtc - > index * 0x300 ) , 1 ) ;
evo_data ( push , 0x00000000 ) ;
evo_mthd ( push , 0x04b8 + ( nv_crtc - > index * 0x300 ) , 1 ) ;
evo_data ( push , umode - > vdisplay < < 16 | umode - > hdisplay ) ;
}
evo_kick ( push , mast ) ;
2011-07-05 16:48:06 +10:00
if ( update ) {
2012-11-21 14:40:21 +10:00
nv50_display_flip_stop ( crtc ) ;
2014-04-01 15:22:40 -07:00
nv50_display_flip_next ( crtc , crtc - > primary - > fb ,
NULL , 1 ) ;
2011-07-05 16:48:06 +10:00
}
}
return 0 ;
}
2014-10-30 22:57:45 +01:00
static int
nv50_crtc_set_raster_vblank_dmi ( struct nouveau_crtc * nv_crtc , u32 usec )
{
struct nv50_mast * mast = nv50_mast ( nv_crtc - > base . dev ) ;
u32 * push ;
push = evo_wait ( mast , 8 ) ;
if ( ! push )
return - ENOMEM ;
evo_mthd ( push , 0x0828 + ( nv_crtc - > index * 0x400 ) , 1 ) ;
evo_data ( push , usec ) ;
evo_kick ( push , mast ) ;
return 0 ;
}
2012-11-21 13:03:42 +10:00
static int
2012-11-21 14:40:21 +10:00
nv50_crtc_set_color_vibrance ( struct nouveau_crtc * nv_crtc , bool update )
2012-11-21 13:03:42 +10:00
{
2012-11-21 14:40:21 +10:00
struct nv50_mast * mast = nv50_mast ( nv_crtc - > base . dev ) ;
2012-11-21 13:03:42 +10:00
u32 * push , hue , vib ;
int adj ;
adj = ( nv_crtc - > color_vibrance > 0 ) ? 50 : 0 ;
vib = ( ( nv_crtc - > color_vibrance * 2047 + adj ) / 100 ) & 0xfff ;
hue = ( ( nv_crtc - > vibrant_hue * 2047 ) / 100 ) & 0xfff ;
push = evo_wait ( mast , 16 ) ;
if ( push ) {
2014-08-10 04:10:27 +10:00
if ( nv50_vers ( mast ) < GF110_DISP_CORE_CHANNEL_DMA ) {
2012-11-21 13:03:42 +10:00
evo_mthd ( push , 0x08a8 + ( nv_crtc - > index * 0x400 ) , 1 ) ;
evo_data ( push , ( hue < < 20 ) | ( vib < < 8 ) ) ;
} else {
evo_mthd ( push , 0x0498 + ( nv_crtc - > index * 0x300 ) , 1 ) ;
evo_data ( push , ( hue < < 20 ) | ( vib < < 8 ) ) ;
}
if ( update ) {
evo_mthd ( push , 0x0080 , 1 ) ;
evo_data ( push , 0x00000000 ) ;
}
evo_kick ( push , mast ) ;
}
return 0 ;
}
2011-07-05 16:48:06 +10:00
static int
2012-11-21 14:40:21 +10:00
nv50_crtc_set_image ( struct nouveau_crtc * nv_crtc , struct drm_framebuffer * fb ,
2011-07-05 16:48:06 +10:00
int x , int y , bool update )
{
struct nouveau_framebuffer * nvfb = nouveau_framebuffer ( fb ) ;
2012-11-21 14:40:21 +10:00
struct nv50_mast * mast = nv50_mast ( nv_crtc - > base . dev ) ;
2011-07-05 16:48:06 +10:00
u32 * push ;
2012-11-16 10:24:31 +10:00
push = evo_wait ( mast , 16 ) ;
2011-07-05 16:48:06 +10:00
if ( push ) {
2014-08-10 04:10:27 +10:00
if ( nv50_vers ( mast ) < GF110_DISP_CORE_CHANNEL_DMA ) {
2012-11-16 10:24:31 +10:00
evo_mthd ( push , 0x0860 + ( nv_crtc - > index * 0x400 ) , 1 ) ;
evo_data ( push , nvfb - > nvbo - > bo . offset > > 8 ) ;
evo_mthd ( push , 0x0868 + ( nv_crtc - > index * 0x400 ) , 3 ) ;
evo_data ( push , ( fb - > height < < 16 ) | fb - > width ) ;
evo_data ( push , nvfb - > r_pitch ) ;
evo_data ( push , nvfb - > r_format ) ;
evo_mthd ( push , 0x08c0 + ( nv_crtc - > index * 0x400 ) , 1 ) ;
evo_data ( push , ( y < < 16 ) | x ) ;
2014-08-10 04:10:27 +10:00
if ( nv50_vers ( mast ) > NV50_DISP_CORE_CHANNEL_DMA ) {
2012-11-16 10:24:31 +10:00
evo_mthd ( push , 0x0874 + ( nv_crtc - > index * 0x400 ) , 1 ) ;
2014-08-10 04:10:19 +10:00
evo_data ( push , nvfb - > r_handle ) ;
2012-11-16 10:24:31 +10:00
}
} else {
evo_mthd ( push , 0x0460 + ( nv_crtc - > index * 0x300 ) , 1 ) ;
evo_data ( push , nvfb - > nvbo - > bo . offset > > 8 ) ;
evo_mthd ( push , 0x0468 + ( nv_crtc - > index * 0x300 ) , 4 ) ;
evo_data ( push , ( fb - > height < < 16 ) | fb - > width ) ;
evo_data ( push , nvfb - > r_pitch ) ;
evo_data ( push , nvfb - > r_format ) ;
2014-08-10 04:10:19 +10:00
evo_data ( push , nvfb - > r_handle ) ;
2012-11-16 10:24:31 +10:00
evo_mthd ( push , 0x04b0 + ( nv_crtc - > index * 0x300 ) , 1 ) ;
evo_data ( push , ( y < < 16 ) | x ) ;
}
2011-07-07 15:23:48 +10:00
if ( update ) {
evo_mthd ( push , 0x0080 , 1 ) ;
evo_data ( push , 0x00000000 ) ;
}
2012-11-16 10:24:31 +10:00
evo_kick ( push , mast ) ;
2011-07-05 16:48:06 +10:00
}
2014-08-10 04:10:19 +10:00
nv_crtc - > fb . handle = nvfb - > r_handle ;
2011-07-05 16:48:06 +10:00
return 0 ;
}
static void
2012-11-21 14:40:21 +10:00
nv50_crtc_cursor_show ( struct nouveau_crtc * nv_crtc )
2011-07-05 16:48:06 +10:00
{
2012-11-21 14:40:21 +10:00
struct nv50_mast * mast = nv50_mast ( nv_crtc - > base . dev ) ;
2012-11-16 10:24:31 +10:00
u32 * push = evo_wait ( mast , 16 ) ;
2011-07-05 16:48:06 +10:00
if ( push ) {
2014-08-10 04:10:27 +10:00
if ( nv50_vers ( mast ) < G82_DISP_CORE_CHANNEL_DMA ) {
2012-11-16 10:24:31 +10:00
evo_mthd ( push , 0x0880 + ( nv_crtc - > index * 0x400 ) , 2 ) ;
evo_data ( push , 0x85000000 ) ;
2015-01-13 09:18:49 +01:00
evo_data ( push , nv_crtc - > cursor . nvbo - > bo . offset > > 8 ) ;
2012-11-16 10:24:31 +10:00
} else
2014-08-10 04:10:27 +10:00
if ( nv50_vers ( mast ) < GF110_DISP_CORE_CHANNEL_DMA ) {
2012-11-16 10:24:31 +10:00
evo_mthd ( push , 0x0880 + ( nv_crtc - > index * 0x400 ) , 2 ) ;
evo_data ( push , 0x85000000 ) ;
2015-01-13 09:18:49 +01:00
evo_data ( push , nv_crtc - > cursor . nvbo - > bo . offset > > 8 ) ;
2012-11-16 10:24:31 +10:00
evo_mthd ( push , 0x089c + ( nv_crtc - > index * 0x400 ) , 1 ) ;
2014-08-10 04:10:23 +10:00
evo_data ( push , mast - > base . vram . handle ) ;
2012-11-16 10:24:31 +10:00
} else {
2011-07-05 16:48:06 +10:00
evo_mthd ( push , 0x0480 + ( nv_crtc - > index * 0x300 ) , 2 ) ;
evo_data ( push , 0x85000000 ) ;
2015-01-13 09:18:49 +01:00
evo_data ( push , nv_crtc - > cursor . nvbo - > bo . offset > > 8 ) ;
2011-07-05 16:48:06 +10:00
evo_mthd ( push , 0x048c + ( nv_crtc - > index * 0x300 ) , 1 ) ;
2014-08-10 04:10:23 +10:00
evo_data ( push , mast - > base . vram . handle ) ;
2012-11-16 10:24:31 +10:00
}
evo_kick ( push , mast ) ;
}
2015-01-13 09:18:49 +01:00
nv_crtc - > cursor . visible = true ;
2012-11-16 10:24:31 +10:00
}
static void
2012-11-21 14:40:21 +10:00
nv50_crtc_cursor_hide ( struct nouveau_crtc * nv_crtc )
2012-11-16 10:24:31 +10:00
{
2012-11-21 14:40:21 +10:00
struct nv50_mast * mast = nv50_mast ( nv_crtc - > base . dev ) ;
2012-11-16 10:24:31 +10:00
u32 * push = evo_wait ( mast , 16 ) ;
if ( push ) {
2014-08-10 04:10:27 +10:00
if ( nv50_vers ( mast ) < G82_DISP_CORE_CHANNEL_DMA ) {
2012-11-16 10:24:31 +10:00
evo_mthd ( push , 0x0880 + ( nv_crtc - > index * 0x400 ) , 1 ) ;
evo_data ( push , 0x05000000 ) ;
} else
2014-08-10 04:10:27 +10:00
if ( nv50_vers ( mast ) < GF110_DISP_CORE_CHANNEL_DMA ) {
2012-11-16 10:24:31 +10:00
evo_mthd ( push , 0x0880 + ( nv_crtc - > index * 0x400 ) , 1 ) ;
evo_data ( push , 0x05000000 ) ;
evo_mthd ( push , 0x089c + ( nv_crtc - > index * 0x400 ) , 1 ) ;
evo_data ( push , 0x00000000 ) ;
2011-07-05 16:48:06 +10:00
} else {
evo_mthd ( push , 0x0480 + ( nv_crtc - > index * 0x300 ) , 1 ) ;
evo_data ( push , 0x05000000 ) ;
evo_mthd ( push , 0x048c + ( nv_crtc - > index * 0x300 ) , 1 ) ;
evo_data ( push , 0x00000000 ) ;
}
2012-11-16 10:24:31 +10:00
evo_kick ( push , mast ) ;
}
2015-01-13 09:18:49 +01:00
nv_crtc - > cursor . visible = false ;
2012-11-16 10:24:31 +10:00
}
2011-07-05 16:48:06 +10:00
2012-11-16 10:24:31 +10:00
static void
2012-11-21 14:40:21 +10:00
nv50_crtc_cursor_show_hide ( struct nouveau_crtc * nv_crtc , bool show , bool update )
2012-11-16 10:24:31 +10:00
{
2012-11-21 14:40:21 +10:00
struct nv50_mast * mast = nv50_mast ( nv_crtc - > base . dev ) ;
2012-11-16 10:24:31 +10:00
2015-07-28 17:20:57 +10:00
if ( show & & nv_crtc - > cursor . nvbo & & nv_crtc - > base . enabled )
2012-11-21 14:40:21 +10:00
nv50_crtc_cursor_show ( nv_crtc ) ;
2012-11-16 10:24:31 +10:00
else
2012-11-21 14:40:21 +10:00
nv50_crtc_cursor_hide ( nv_crtc ) ;
2012-11-16 10:24:31 +10:00
if ( update ) {
u32 * push = evo_wait ( mast , 2 ) ;
if ( push ) {
2011-07-05 16:48:06 +10:00
evo_mthd ( push , 0x0080 , 1 ) ;
evo_data ( push , 0x00000000 ) ;
2012-11-16 10:24:31 +10:00
evo_kick ( push , mast ) ;
2011-07-05 16:48:06 +10:00
}
}
}
static void
2012-11-21 14:40:21 +10:00
nv50_crtc_dpms ( struct drm_crtc * crtc , int mode )
2011-07-05 16:48:06 +10:00
{
}
static void
2012-11-21 14:40:21 +10:00
nv50_crtc_prepare ( struct drm_crtc * crtc )
2011-07-05 16:48:06 +10:00
{
struct nouveau_crtc * nv_crtc = nouveau_crtc ( crtc ) ;
2012-11-21 14:40:21 +10:00
struct nv50_mast * mast = nv50_mast ( crtc - > dev ) ;
2011-07-05 16:48:06 +10:00
u32 * push ;
2012-11-21 14:40:21 +10:00
nv50_display_flip_stop ( crtc ) ;
2011-11-12 14:28:12 +10:00
2014-05-19 14:54:33 +10:00
push = evo_wait ( mast , 6 ) ;
2011-07-05 16:48:06 +10:00
if ( push ) {
2014-08-10 04:10:27 +10:00
if ( nv50_vers ( mast ) < G82_DISP_CORE_CHANNEL_DMA ) {
2012-11-16 10:24:31 +10:00
evo_mthd ( push , 0x0874 + ( nv_crtc - > index * 0x400 ) , 1 ) ;
evo_data ( push , 0x00000000 ) ;
evo_mthd ( push , 0x0840 + ( nv_crtc - > index * 0x400 ) , 1 ) ;
evo_data ( push , 0x40000000 ) ;
} else
2014-08-10 04:10:27 +10:00
if ( nv50_vers ( mast ) < GF110_DISP_CORE_CHANNEL_DMA ) {
2012-11-16 10:24:31 +10:00
evo_mthd ( push , 0x0874 + ( nv_crtc - > index * 0x400 ) , 1 ) ;
evo_data ( push , 0x00000000 ) ;
evo_mthd ( push , 0x0840 + ( nv_crtc - > index * 0x400 ) , 1 ) ;
evo_data ( push , 0x40000000 ) ;
evo_mthd ( push , 0x085c + ( nv_crtc - > index * 0x400 ) , 1 ) ;
evo_data ( push , 0x00000000 ) ;
} else {
evo_mthd ( push , 0x0474 + ( nv_crtc - > index * 0x300 ) , 1 ) ;
evo_data ( push , 0x00000000 ) ;
evo_mthd ( push , 0x0440 + ( nv_crtc - > index * 0x300 ) , 1 ) ;
evo_data ( push , 0x03000000 ) ;
evo_mthd ( push , 0x045c + ( nv_crtc - > index * 0x300 ) , 1 ) ;
evo_data ( push , 0x00000000 ) ;
}
evo_kick ( push , mast ) ;
2011-07-05 16:48:06 +10:00
}
2012-11-21 14:40:21 +10:00
nv50_crtc_cursor_show_hide ( nv_crtc , false , false ) ;
2011-07-05 16:48:06 +10:00
}
static void
2012-11-21 14:40:21 +10:00
nv50_crtc_commit ( struct drm_crtc * crtc )
2011-07-05 16:48:06 +10:00
{
struct nouveau_crtc * nv_crtc = nouveau_crtc ( crtc ) ;
2012-11-21 14:40:21 +10:00
struct nv50_mast * mast = nv50_mast ( crtc - > dev ) ;
2011-07-05 16:48:06 +10:00
u32 * push ;
2012-11-16 10:24:31 +10:00
push = evo_wait ( mast , 32 ) ;
2011-07-05 16:48:06 +10:00
if ( push ) {
2014-08-10 04:10:27 +10:00
if ( nv50_vers ( mast ) < G82_DISP_CORE_CHANNEL_DMA ) {
2012-11-16 10:24:31 +10:00
evo_mthd ( push , 0x0874 + ( nv_crtc - > index * 0x400 ) , 1 ) ;
2014-08-10 04:10:19 +10:00
evo_data ( push , nv_crtc - > fb . handle ) ;
2012-11-16 10:24:31 +10:00
evo_mthd ( push , 0x0840 + ( nv_crtc - > index * 0x400 ) , 2 ) ;
evo_data ( push , 0xc0000000 ) ;
evo_data ( push , nv_crtc - > lut . nvbo - > bo . offset > > 8 ) ;
} else
2014-08-10 04:10:27 +10:00
if ( nv50_vers ( mast ) < GF110_DISP_CORE_CHANNEL_DMA ) {
2012-11-16 10:24:31 +10:00
evo_mthd ( push , 0x0874 + ( nv_crtc - > index * 0x400 ) , 1 ) ;
2014-08-10 04:10:19 +10:00
evo_data ( push , nv_crtc - > fb . handle ) ;
2012-11-16 10:24:31 +10:00
evo_mthd ( push , 0x0840 + ( nv_crtc - > index * 0x400 ) , 2 ) ;
evo_data ( push , 0xc0000000 ) ;
evo_data ( push , nv_crtc - > lut . nvbo - > bo . offset > > 8 ) ;
evo_mthd ( push , 0x085c + ( nv_crtc - > index * 0x400 ) , 1 ) ;
2014-08-10 04:10:23 +10:00
evo_data ( push , mast - > base . vram . handle ) ;
2012-11-16 10:24:31 +10:00
} else {
evo_mthd ( push , 0x0474 + ( nv_crtc - > index * 0x300 ) , 1 ) ;
2014-08-10 04:10:19 +10:00
evo_data ( push , nv_crtc - > fb . handle ) ;
2012-11-16 10:24:31 +10:00
evo_mthd ( push , 0x0440 + ( nv_crtc - > index * 0x300 ) , 4 ) ;
evo_data ( push , 0x83000000 ) ;
evo_data ( push , nv_crtc - > lut . nvbo - > bo . offset > > 8 ) ;
evo_data ( push , 0x00000000 ) ;
evo_data ( push , 0x00000000 ) ;
evo_mthd ( push , 0x045c + ( nv_crtc - > index * 0x300 ) , 1 ) ;
2014-08-10 04:10:23 +10:00
evo_data ( push , mast - > base . vram . handle ) ;
2012-11-16 10:24:31 +10:00
evo_mthd ( push , 0x0430 + ( nv_crtc - > index * 0x300 ) , 1 ) ;
evo_data ( push , 0xffffff00 ) ;
}
evo_kick ( push , mast ) ;
2011-07-05 16:48:06 +10:00
}
2014-11-10 15:52:02 +10:00
nv50_crtc_cursor_show_hide ( nv_crtc , true , true ) ;
2014-04-01 15:22:40 -07:00
nv50_display_flip_next ( crtc , crtc - > primary - > fb , NULL , 1 ) ;
2011-07-05 16:48:06 +10:00
}
static bool
2012-11-21 14:40:21 +10:00
nv50_crtc_mode_fixup ( struct drm_crtc * crtc , const struct drm_display_mode * mode ,
2011-07-05 16:48:06 +10:00
struct drm_display_mode * adjusted_mode )
{
2014-01-24 10:13:23 +10:00
drm_mode_set_crtcinfo ( adjusted_mode , CRTC_INTERLACE_HALVE_V ) ;
2011-07-05 16:48:06 +10:00
return true ;
}
static int
2012-11-21 14:40:21 +10:00
nv50_crtc_swap_fbs ( struct drm_crtc * crtc , struct drm_framebuffer * old_fb )
2011-07-05 16:48:06 +10:00
{
2014-04-01 15:22:40 -07:00
struct nouveau_framebuffer * nvfb = nouveau_framebuffer ( crtc - > primary - > fb ) ;
2013-07-09 12:35:55 +10:00
struct nv50_head * head = nv50_head ( crtc ) ;
2011-07-05 16:48:06 +10:00
int ret ;
2014-11-10 12:35:06 +10:00
ret = nouveau_bo_pin ( nvfb - > nvbo , TTM_PL_FLAG_VRAM , true ) ;
2013-07-09 12:35:55 +10:00
if ( ret = = 0 ) {
if ( head - > image )
nouveau_bo_unpin ( head - > image ) ;
nouveau_bo_ref ( nvfb - > nvbo , & head - > image ) ;
2011-07-05 16:48:06 +10:00
}
2013-07-09 12:35:55 +10:00
return ret ;
2011-07-05 16:48:06 +10:00
}
static int
2012-11-21 14:40:21 +10:00
nv50_crtc_mode_set ( struct drm_crtc * crtc , struct drm_display_mode * umode ,
2011-07-05 16:48:06 +10:00
struct drm_display_mode * mode , int x , int y ,
struct drm_framebuffer * old_fb )
{
2012-11-21 14:40:21 +10:00
struct nv50_mast * mast = nv50_mast ( crtc - > dev ) ;
2011-07-05 16:48:06 +10:00
struct nouveau_crtc * nv_crtc = nouveau_crtc ( crtc ) ;
struct nouveau_connector * nv_connector ;
2011-11-11 23:39:22 +10:00
u32 ilace = ( mode - > flags & DRM_MODE_FLAG_INTERLACE ) ? 2 : 1 ;
u32 vscan = ( mode - > flags & DRM_MODE_FLAG_DBLSCAN ) ? 2 : 1 ;
u32 hactive , hsynce , hbackp , hfrontp , hblanke , hblanks ;
u32 vactive , vsynce , vbackp , vfrontp , vblanke , vblanks ;
2014-09-12 18:00:13 +02:00
u32 vblan2e = 0 , vblan2s = 1 , vblankus = 0 ;
2012-03-12 11:42:20 +10:00
u32 * push ;
2011-07-05 16:48:06 +10:00
int ret ;
2011-11-11 23:39:22 +10:00
hactive = mode - > htotal ;
hsynce = mode - > hsync_end - mode - > hsync_start - 1 ;
hbackp = mode - > htotal - mode - > hsync_end ;
hblanke = hsynce + hbackp ;
hfrontp = mode - > hsync_start - mode - > hdisplay ;
hblanks = mode - > htotal - hfrontp - 1 ;
vactive = mode - > vtotal * vscan / ilace ;
vsynce = ( ( mode - > vsync_end - mode - > vsync_start ) * vscan / ilace ) - 1 ;
vbackp = ( mode - > vtotal - mode - > vsync_end ) * vscan / ilace ;
vblanke = vsynce + vbackp ;
vfrontp = ( mode - > vsync_start - mode - > vdisplay ) * vscan / ilace ;
vblanks = vactive - vfrontp - 1 ;
2014-09-12 18:00:13 +02:00
/* XXX: Safe underestimate, even "0" works */
vblankus = ( vactive - mode - > vdisplay - 2 ) * hactive ;
vblankus * = 1000 ;
vblankus / = mode - > clock ;
2011-11-11 23:39:22 +10:00
if ( mode - > flags & DRM_MODE_FLAG_INTERLACE ) {
vblan2e = vactive + vsynce + vbackp ;
vblan2s = vblan2e + ( mode - > vdisplay * vscan / ilace ) ;
vactive = ( vactive * 2 ) + 1 ;
}
2012-11-21 14:40:21 +10:00
ret = nv50_crtc_swap_fbs ( crtc , old_fb ) ;
2011-07-05 16:48:06 +10:00
if ( ret )
return ret ;
2012-11-16 10:24:31 +10:00
push = evo_wait ( mast , 64 ) ;
2011-07-05 16:48:06 +10:00
if ( push ) {
2014-08-10 04:10:27 +10:00
if ( nv50_vers ( mast ) < GF110_DISP_CORE_CHANNEL_DMA ) {
2012-11-16 10:24:31 +10:00
evo_mthd ( push , 0x0804 + ( nv_crtc - > index * 0x400 ) , 2 ) ;
evo_data ( push , 0x00800000 | mode - > clock ) ;
evo_data ( push , ( ilace = = 2 ) ? 2 : 0 ) ;
2014-10-30 22:57:45 +01:00
evo_mthd ( push , 0x0810 + ( nv_crtc - > index * 0x400 ) , 6 ) ;
2012-11-16 10:24:31 +10:00
evo_data ( push , 0x00000000 ) ;
evo_data ( push , ( vactive < < 16 ) | hactive ) ;
evo_data ( push , ( vsynce < < 16 ) | hsynce ) ;
evo_data ( push , ( vblanke < < 16 ) | hblanke ) ;
evo_data ( push , ( vblanks < < 16 ) | hblanks ) ;
evo_data ( push , ( vblan2e < < 16 ) | vblan2s ) ;
2014-10-30 22:57:45 +01:00
evo_mthd ( push , 0x082c + ( nv_crtc - > index * 0x400 ) , 1 ) ;
2012-11-16 10:24:31 +10:00
evo_data ( push , 0x00000000 ) ;
evo_mthd ( push , 0x0900 + ( nv_crtc - > index * 0x400 ) , 2 ) ;
evo_data ( push , 0x00000311 ) ;
evo_data ( push , 0x00000100 ) ;
} else {
evo_mthd ( push , 0x0410 + ( nv_crtc - > index * 0x300 ) , 6 ) ;
evo_data ( push , 0x00000000 ) ;
evo_data ( push , ( vactive < < 16 ) | hactive ) ;
evo_data ( push , ( vsynce < < 16 ) | hsynce ) ;
evo_data ( push , ( vblanke < < 16 ) | hblanke ) ;
evo_data ( push , ( vblanks < < 16 ) | hblanks ) ;
evo_data ( push , ( vblan2e < < 16 ) | vblan2s ) ;
evo_mthd ( push , 0x042c + ( nv_crtc - > index * 0x300 ) , 1 ) ;
evo_data ( push , 0x00000000 ) ; /* ??? */
evo_mthd ( push , 0x0450 + ( nv_crtc - > index * 0x300 ) , 3 ) ;
evo_data ( push , mode - > clock * 1000 ) ;
evo_data ( push , 0x00200000 ) ; /* ??? */
evo_data ( push , mode - > clock * 1000 ) ;
evo_mthd ( push , 0x04d0 + ( nv_crtc - > index * 0x300 ) , 2 ) ;
evo_data ( push , 0x00000311 ) ;
evo_data ( push , 0x00000100 ) ;
}
evo_kick ( push , mast ) ;
2011-07-05 16:48:06 +10:00
}
nv_connector = nouveau_crtc_connector_get ( nv_crtc ) ;
2012-11-21 14:40:21 +10:00
nv50_crtc_set_dither ( nv_crtc , false ) ;
nv50_crtc_set_scale ( nv_crtc , false ) ;
2014-10-30 22:57:45 +01:00
/* G94 only accepts this after setting scale */
if ( nv50_vers ( mast ) < GF110_DISP_CORE_CHANNEL_DMA )
nv50_crtc_set_raster_vblank_dmi ( nv_crtc , vblankus ) ;
2012-11-21 14:40:21 +10:00
nv50_crtc_set_color_vibrance ( nv_crtc , false ) ;
2014-04-01 15:22:40 -07:00
nv50_crtc_set_image ( nv_crtc , crtc - > primary - > fb , x , y , false ) ;
2011-07-05 16:48:06 +10:00
return 0 ;
}
static int
2012-11-21 14:40:21 +10:00
nv50_crtc_mode_set_base ( struct drm_crtc * crtc , int x , int y ,
2011-07-05 16:48:06 +10:00
struct drm_framebuffer * old_fb )
{
2012-07-31 16:16:21 +10:00
struct nouveau_drm * drm = nouveau_drm ( crtc - > dev ) ;
2011-07-05 16:48:06 +10:00
struct nouveau_crtc * nv_crtc = nouveau_crtc ( crtc ) ;
int ret ;
2014-04-01 15:22:40 -07:00
if ( ! crtc - > primary - > fb ) {
2012-07-31 16:16:21 +10:00
NV_DEBUG ( drm , " No FB bound \n " ) ;
2011-08-26 09:40:39 +10:00
return 0 ;
}
2012-11-21 14:40:21 +10:00
ret = nv50_crtc_swap_fbs ( crtc , old_fb ) ;
2011-07-05 16:48:06 +10:00
if ( ret )
return ret ;
2012-11-21 14:40:21 +10:00
nv50_display_flip_stop ( crtc ) ;
2014-04-01 15:22:40 -07:00
nv50_crtc_set_image ( nv_crtc , crtc - > primary - > fb , x , y , true ) ;
nv50_display_flip_next ( crtc , crtc - > primary - > fb , NULL , 1 ) ;
2011-07-05 16:48:06 +10:00
return 0 ;
}
static int
2012-11-21 14:40:21 +10:00
nv50_crtc_mode_set_base_atomic ( struct drm_crtc * crtc ,
2011-07-05 16:48:06 +10:00
struct drm_framebuffer * fb , int x , int y ,
enum mode_set_atomic state )
{
struct nouveau_crtc * nv_crtc = nouveau_crtc ( crtc ) ;
2012-11-21 14:40:21 +10:00
nv50_display_flip_stop ( crtc ) ;
nv50_crtc_set_image ( nv_crtc , fb , x , y , true ) ;
2011-07-05 16:48:06 +10:00
return 0 ;
}
static void
2012-11-21 14:40:21 +10:00
nv50_crtc_lut_load ( struct drm_crtc * crtc )
2011-07-05 16:48:06 +10:00
{
2012-11-21 14:40:21 +10:00
struct nv50_disp * disp = nv50_disp ( crtc - > dev ) ;
2011-07-05 16:48:06 +10:00
struct nouveau_crtc * nv_crtc = nouveau_crtc ( crtc ) ;
void __iomem * lut = nvbo_kmap_obj_iovirtual ( nv_crtc - > lut . nvbo ) ;
int i ;
for ( i = 0 ; i < 256 ; i + + ) {
2012-11-16 10:24:31 +10:00
u16 r = nv_crtc - > lut . r [ i ] > > 2 ;
u16 g = nv_crtc - > lut . g [ i ] > > 2 ;
u16 b = nv_crtc - > lut . b [ i ] > > 2 ;
2014-08-10 04:10:27 +10:00
if ( disp - > disp - > oclass < GF110_DISP ) {
2012-11-16 10:24:31 +10:00
writew ( r + 0x0000 , lut + ( i * 0x08 ) + 0 ) ;
writew ( g + 0x0000 , lut + ( i * 0x08 ) + 2 ) ;
writew ( b + 0x0000 , lut + ( i * 0x08 ) + 4 ) ;
} else {
writew ( r + 0x6000 , lut + ( i * 0x20 ) + 0 ) ;
writew ( g + 0x6000 , lut + ( i * 0x20 ) + 2 ) ;
writew ( b + 0x6000 , lut + ( i * 0x20 ) + 4 ) ;
}
2011-07-05 16:48:06 +10:00
}
}
2013-07-09 12:35:55 +10:00
static void
nv50_crtc_disable ( struct drm_crtc * crtc )
{
struct nv50_head * head = nv50_head ( crtc ) ;
2014-06-05 12:56:35 +10:00
evo_sync ( crtc - > dev ) ;
2013-07-09 12:35:55 +10:00
if ( head - > image )
nouveau_bo_unpin ( head - > image ) ;
nouveau_bo_ref ( NULL , & head - > image ) ;
}
2011-07-05 16:48:06 +10:00
static int
2012-11-21 14:40:21 +10:00
nv50_crtc_cursor_set ( struct drm_crtc * crtc , struct drm_file * file_priv ,
2011-07-05 16:48:06 +10:00
uint32_t handle , uint32_t width , uint32_t height )
{
struct nouveau_crtc * nv_crtc = nouveau_crtc ( crtc ) ;
2014-11-10 15:52:02 +10:00
struct drm_gem_object * gem = NULL ;
struct nouveau_bo * nvbo = NULL ;
int ret = 0 ;
2011-07-05 16:48:06 +10:00
2014-11-10 15:52:02 +10:00
if ( handle ) {
2011-07-05 16:48:06 +10:00
if ( width ! = 64 | | height ! = 64 )
return - EINVAL ;
2016-05-09 11:04:54 +01:00
gem = drm_gem_object_lookup ( file_priv , handle ) ;
2011-07-05 16:48:06 +10:00
if ( unlikely ( ! gem ) )
return - ENOENT ;
nvbo = nouveau_gem_object ( gem ) ;
2014-11-10 15:52:02 +10:00
ret = nouveau_bo_pin ( nvbo , TTM_PL_FLAG_VRAM , true ) ;
2011-07-05 16:48:06 +10:00
}
2014-11-10 15:52:02 +10:00
if ( ret = = 0 ) {
2015-01-13 09:18:49 +01:00
if ( nv_crtc - > cursor . nvbo )
nouveau_bo_unpin ( nv_crtc - > cursor . nvbo ) ;
nouveau_bo_ref ( nvbo , & nv_crtc - > cursor . nvbo ) ;
2011-07-05 16:48:06 +10:00
}
2014-11-10 15:52:02 +10:00
drm_gem_object_unreference_unlocked ( gem ) ;
2011-07-05 16:48:06 +10:00
2014-11-10 15:52:02 +10:00
nv50_crtc_cursor_show_hide ( nv_crtc , true , true ) ;
2011-07-05 16:48:06 +10:00
return ret ;
}
static int
2012-11-21 14:40:21 +10:00
nv50_crtc_cursor_move ( struct drm_crtc * crtc , int x , int y )
2011-07-05 16:48:06 +10:00
{
2015-01-13 09:18:49 +01:00
struct nouveau_crtc * nv_crtc = nouveau_crtc ( crtc ) ;
2012-11-21 14:40:21 +10:00
struct nv50_curs * curs = nv50_curs ( crtc ) ;
struct nv50_chan * chan = nv50_chan ( curs ) ;
2014-08-10 04:10:22 +10:00
nvif_wr32 ( & chan - > user , 0x0084 , ( y < < 16 ) | ( x & 0xffff ) ) ;
nvif_wr32 ( & chan - > user , 0x0080 , 0x00000000 ) ;
2015-01-13 09:18:49 +01:00
nv_crtc - > cursor_saved_x = x ;
nv_crtc - > cursor_saved_y = y ;
2011-07-05 16:48:06 +10:00
return 0 ;
}
2016-06-07 12:49:30 +02:00
static int
2012-11-21 14:40:21 +10:00
nv50_crtc_gamma_set ( struct drm_crtc * crtc , u16 * r , u16 * g , u16 * b ,
2016-06-07 12:49:30 +02:00
uint32_t size )
2011-07-05 16:48:06 +10:00
{
struct nouveau_crtc * nv_crtc = nouveau_crtc ( crtc ) ;
u32 i ;
2016-06-07 12:49:30 +02:00
for ( i = 0 ; i < size ; i + + ) {
2011-07-05 16:48:06 +10:00
nv_crtc - > lut . r [ i ] = r [ i ] ;
nv_crtc - > lut . g [ i ] = g [ i ] ;
nv_crtc - > lut . b [ i ] = b [ i ] ;
}
2012-11-21 14:40:21 +10:00
nv50_crtc_lut_load ( crtc ) ;
2016-06-07 12:49:30 +02:00
return 0 ;
2011-07-05 16:48:06 +10:00
}
2015-01-13 09:18:49 +01:00
static void
nv50_crtc_cursor_restore ( struct nouveau_crtc * nv_crtc , int x , int y )
{
nv50_crtc_cursor_move ( & nv_crtc - > base , x , y ) ;
nv50_crtc_cursor_show_hide ( nv_crtc , true , true ) ;
}
2011-07-05 16:48:06 +10:00
static void
2012-11-21 14:40:21 +10:00
nv50_crtc_destroy ( struct drm_crtc * crtc )
2011-07-05 16:48:06 +10:00
{
struct nouveau_crtc * nv_crtc = nouveau_crtc ( crtc ) ;
2012-11-21 14:40:21 +10:00
struct nv50_disp * disp = nv50_disp ( crtc - > dev ) ;
struct nv50_head * head = nv50_head ( crtc ) ;
2014-08-10 04:10:22 +10:00
struct nv50_fbdma * fbdma ;
2013-07-09 12:35:55 +10:00
2014-08-10 04:10:22 +10:00
list_for_each_entry ( fbdma , & disp - > fbdma , head ) {
nvif_object_fini ( & fbdma - > base [ nv_crtc - > index ] ) ;
}
nv50_dmac_destroy ( & head - > ovly . base , disp - > disp ) ;
nv50_pioc_destroy ( & head - > oimm . base ) ;
nv50_dmac_destroy ( & head - > sync . base , disp - > disp ) ;
nv50_pioc_destroy ( & head - > curs . base ) ;
2013-07-09 12:35:55 +10:00
/*XXX: this shouldn't be necessary, but the core doesn't call
* disconnect ( ) during the cleanup paths
*/
if ( head - > image )
nouveau_bo_unpin ( head - > image ) ;
nouveau_bo_ref ( NULL , & head - > image ) ;
2014-11-10 15:52:02 +10:00
/*XXX: ditto */
2015-01-13 09:18:49 +01:00
if ( nv_crtc - > cursor . nvbo )
nouveau_bo_unpin ( nv_crtc - > cursor . nvbo ) ;
nouveau_bo_ref ( NULL , & nv_crtc - > cursor . nvbo ) ;
2013-07-09 12:35:55 +10:00
2011-07-05 16:48:06 +10:00
nouveau_bo_unmap ( nv_crtc - > lut . nvbo ) ;
2012-11-25 23:04:23 +01:00
if ( nv_crtc - > lut . nvbo )
nouveau_bo_unpin ( nv_crtc - > lut . nvbo ) ;
2011-07-05 16:48:06 +10:00
nouveau_bo_ref ( NULL , & nv_crtc - > lut . nvbo ) ;
2013-07-09 12:35:55 +10:00
2011-07-05 16:48:06 +10:00
drm_crtc_cleanup ( crtc ) ;
kfree ( crtc ) ;
}
2012-11-21 14:40:21 +10:00
static const struct drm_crtc_helper_funcs nv50_crtc_hfunc = {
. dpms = nv50_crtc_dpms ,
. prepare = nv50_crtc_prepare ,
. commit = nv50_crtc_commit ,
. mode_fixup = nv50_crtc_mode_fixup ,
. mode_set = nv50_crtc_mode_set ,
. mode_set_base = nv50_crtc_mode_set_base ,
. mode_set_base_atomic = nv50_crtc_mode_set_base_atomic ,
. load_lut = nv50_crtc_lut_load ,
2013-07-09 12:35:55 +10:00
. disable = nv50_crtc_disable ,
2011-07-05 16:48:06 +10:00
} ;
2012-11-21 14:40:21 +10:00
static const struct drm_crtc_funcs nv50_crtc_func = {
. cursor_set = nv50_crtc_cursor_set ,
. cursor_move = nv50_crtc_cursor_move ,
. gamma_set = nv50_crtc_gamma_set ,
2012-09-10 14:20:51 +10:00
. set_config = nouveau_crtc_set_config ,
2012-11-21 14:40:21 +10:00
. destroy = nv50_crtc_destroy ,
2011-11-12 14:28:12 +10:00
. page_flip = nouveau_crtc_page_flip ,
2011-07-05 16:48:06 +10:00
} ;
static int
2014-08-10 04:10:22 +10:00
nv50_crtc_create ( struct drm_device * dev , int index )
2011-07-05 16:48:06 +10:00
{
2015-08-20 14:54:15 +10:00
struct nouveau_drm * drm = nouveau_drm ( dev ) ;
struct nvif_device * device = & drm - > device ;
2012-11-21 14:40:21 +10:00
struct nv50_disp * disp = nv50_disp ( dev ) ;
struct nv50_head * head ;
2011-07-05 16:48:06 +10:00
struct drm_crtc * crtc ;
int ret , i ;
2012-10-16 14:00:31 +10:00
head = kzalloc ( sizeof ( * head ) , GFP_KERNEL ) ;
if ( ! head )
2011-07-05 16:48:06 +10:00
return - ENOMEM ;
2012-10-16 14:00:31 +10:00
head - > base . index = index ;
2012-11-21 13:03:42 +10:00
head - > base . color_vibrance = 50 ;
head - > base . vibrant_hue = 0 ;
2015-01-13 09:18:49 +01:00
head - > base . cursor . set_pos = nv50_crtc_cursor_restore ;
2011-07-05 16:48:06 +10:00
for ( i = 0 ; i < 256 ; i + + ) {
2012-10-16 14:00:31 +10:00
head - > base . lut . r [ i ] = i < < 8 ;
head - > base . lut . g [ i ] = i < < 8 ;
head - > base . lut . b [ i ] = i < < 8 ;
2011-07-05 16:48:06 +10:00
}
2012-10-16 14:00:31 +10:00
crtc = & head - > base . base ;
2012-11-21 14:40:21 +10:00
drm_crtc_init ( dev , crtc , & nv50_crtc_func ) ;
drm_crtc_helper_add ( crtc , & nv50_crtc_hfunc ) ;
2011-07-05 16:48:06 +10:00
drm_mode_crtc_set_gamma_size ( crtc , 256 ) ;
2012-10-16 14:18:32 +10:00
ret = nouveau_bo_new ( dev , 8192 , 0x100 , TTM_PL_FLAG_VRAM ,
2014-01-09 11:03:15 +01:00
0 , 0x0000 , NULL , NULL , & head - > base . lut . nvbo ) ;
2012-10-16 14:18:32 +10:00
if ( ! ret ) {
2014-11-10 12:35:06 +10:00
ret = nouveau_bo_pin ( head - > base . lut . nvbo , TTM_PL_FLAG_VRAM , true ) ;
2012-11-25 23:04:23 +01:00
if ( ! ret ) {
2012-10-16 14:18:32 +10:00
ret = nouveau_bo_map ( head - > base . lut . nvbo ) ;
2012-11-25 23:04:23 +01:00
if ( ret )
nouveau_bo_unpin ( head - > base . lut . nvbo ) ;
}
2012-10-16 14:18:32 +10:00
if ( ret )
nouveau_bo_ref ( NULL , & head - > base . lut . nvbo ) ;
}
if ( ret )
goto out ;
/* allocate cursor resources */
2015-08-20 14:54:15 +10:00
ret = nv50_curs_create ( device , disp - > disp , index , & head - > curs ) ;
2011-07-05 16:48:06 +10:00
if ( ret )
goto out ;
2012-10-16 14:18:32 +10:00
/* allocate page flip / sync resources */
2015-08-20 14:54:15 +10:00
ret = nv50_base_create ( device , disp - > disp , index , disp - > sync - > bo . offset ,
& head - > sync ) ;
2012-10-16 14:18:32 +10:00
if ( ret )
goto out ;
2013-03-02 13:21:31 +10:00
head - > sync . addr = EVO_FLIP_SEM0 ( index ) ;
head - > sync . data = 0x00000000 ;
2011-07-05 16:48:06 +10:00
2012-10-16 14:18:32 +10:00
/* allocate overlay resources */
2015-08-20 14:54:15 +10:00
ret = nv50_oimm_create ( device , disp - > disp , index , & head - > oimm ) ;
2011-07-05 16:48:06 +10:00
if ( ret )
goto out ;
2015-08-20 14:54:15 +10:00
ret = nv50_ovly_create ( device , disp - > disp , index , disp - > sync - > bo . offset ,
& head - > ovly ) ;
2012-10-16 14:18:32 +10:00
if ( ret )
goto out ;
2011-07-05 16:48:06 +10:00
out :
if ( ret )
2012-11-21 14:40:21 +10:00
nv50_crtc_destroy ( crtc ) ;
2011-07-05 16:48:06 +10:00
return ret ;
}
2014-12-22 16:30:13 +10:00
/******************************************************************************
* Encoder helpers
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
static bool
nv50_encoder_mode_fixup ( struct drm_encoder * encoder ,
const struct drm_display_mode * mode ,
struct drm_display_mode * adjusted_mode )
{
struct nouveau_encoder * nv_encoder = nouveau_encoder ( encoder ) ;
struct nouveau_connector * nv_connector ;
nv_connector = nouveau_encoder_connector_get ( nv_encoder ) ;
if ( nv_connector & & nv_connector - > native_mode ) {
2014-12-22 17:19:26 +10:00
nv_connector - > scaling_full = false ;
if ( nv_connector - > scaling_mode = = DRM_MODE_SCALE_NONE ) {
switch ( nv_connector - > type ) {
case DCB_CONNECTOR_LVDS :
case DCB_CONNECTOR_LVDS_SPWG :
case DCB_CONNECTOR_eDP :
/* force use of scaler for non-edid modes */
if ( adjusted_mode - > type & DRM_MODE_TYPE_DRIVER )
return true ;
nv_connector - > scaling_full = true ;
break ;
default :
return true ;
}
}
drm_mode_copy ( adjusted_mode , nv_connector - > native_mode ) ;
2014-12-22 16:30:13 +10:00
}
return true ;
}
2011-07-04 16:25:18 +10:00
/******************************************************************************
* DAC
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2011-07-06 15:25:47 +10:00
static void
2012-11-21 14:40:21 +10:00
nv50_dac_dpms ( struct drm_encoder * encoder , int mode )
2011-07-06 15:25:47 +10:00
{
struct nouveau_encoder * nv_encoder = nouveau_encoder ( encoder ) ;
2012-11-21 14:40:21 +10:00
struct nv50_disp * disp = nv50_disp ( encoder - > dev ) ;
2014-08-10 04:10:26 +10:00
struct {
struct nv50_disp_mthd_v1 base ;
struct nv50_disp_dac_pwr_v0 pwr ;
} args = {
. base . version = 1 ,
. base . method = NV50_DISP_MTHD_V1_DAC_PWR ,
. base . hasht = nv_encoder - > dcb - > hasht ,
. base . hashm = nv_encoder - > dcb - > hashm ,
. pwr . state = 1 ,
. pwr . data = 1 ,
. pwr . vsync = ( mode ! = DRM_MODE_DPMS_SUSPEND & &
mode ! = DRM_MODE_DPMS_OFF ) ,
. pwr . hsync = ( mode ! = DRM_MODE_DPMS_STANDBY & &
mode ! = DRM_MODE_DPMS_OFF ) ,
} ;
2011-07-06 15:25:47 +10:00
2014-08-10 04:10:26 +10:00
nvif_mthd ( disp - > disp , 0 , & args , sizeof ( args ) ) ;
2011-07-06 15:25:47 +10:00
}
static void
2012-11-21 14:40:21 +10:00
nv50_dac_commit ( struct drm_encoder * encoder )
2011-07-06 15:25:47 +10:00
{
}
static void
2012-11-21 14:40:21 +10:00
nv50_dac_mode_set ( struct drm_encoder * encoder , struct drm_display_mode * mode ,
2011-07-06 15:25:47 +10:00
struct drm_display_mode * adjusted_mode )
{
2012-11-21 14:40:21 +10:00
struct nv50_mast * mast = nv50_mast ( encoder - > dev ) ;
2011-07-06 15:25:47 +10:00
struct nouveau_encoder * nv_encoder = nouveau_encoder ( encoder ) ;
struct nouveau_crtc * nv_crtc = nouveau_crtc ( encoder - > crtc ) ;
2012-11-16 11:21:37 +10:00
u32 * push ;
2011-07-06 15:25:47 +10:00
2012-11-21 14:40:21 +10:00
nv50_dac_dpms ( encoder , DRM_MODE_DPMS_ON ) ;
2011-07-06 15:25:47 +10:00
2012-11-16 11:21:37 +10:00
push = evo_wait ( mast , 8 ) ;
2011-07-06 15:25:47 +10:00
if ( push ) {
2014-08-10 04:10:27 +10:00
if ( nv50_vers ( mast ) < GF110_DISP_CORE_CHANNEL_DMA ) {
2012-11-16 11:21:37 +10:00
u32 syncs = 0x00000000 ;
if ( mode - > flags & DRM_MODE_FLAG_NHSYNC )
syncs | = 0x00000001 ;
if ( mode - > flags & DRM_MODE_FLAG_NVSYNC )
syncs | = 0x00000002 ;
evo_mthd ( push , 0x0400 + ( nv_encoder - > or * 0x080 ) , 2 ) ;
evo_data ( push , 1 < < nv_crtc - > index ) ;
evo_data ( push , syncs ) ;
} else {
u32 magic = 0x31ec6000 | ( nv_crtc - > index < < 25 ) ;
u32 syncs = 0x00000001 ;
if ( mode - > flags & DRM_MODE_FLAG_NHSYNC )
syncs | = 0x00000008 ;
if ( mode - > flags & DRM_MODE_FLAG_NVSYNC )
syncs | = 0x00000010 ;
if ( mode - > flags & DRM_MODE_FLAG_INTERLACE )
magic | = 0x00000001 ;
evo_mthd ( push , 0x0404 + ( nv_crtc - > index * 0x300 ) , 2 ) ;
evo_data ( push , syncs ) ;
evo_data ( push , magic ) ;
evo_mthd ( push , 0x0180 + ( nv_encoder - > or * 0x020 ) , 1 ) ;
evo_data ( push , 1 < < nv_crtc - > index ) ;
}
evo_kick ( push , mast ) ;
2011-07-06 15:25:47 +10:00
}
nv_encoder - > crtc = encoder - > crtc ;
}
static void
2012-11-21 14:40:21 +10:00
nv50_dac_disconnect ( struct drm_encoder * encoder )
2011-07-06 15:25:47 +10:00
{
struct nouveau_encoder * nv_encoder = nouveau_encoder ( encoder ) ;
2012-11-21 14:40:21 +10:00
struct nv50_mast * mast = nv50_mast ( encoder - > dev ) ;
2012-11-16 11:21:37 +10:00
const int or = nv_encoder - > or ;
2011-07-06 15:25:47 +10:00
u32 * push ;
if ( nv_encoder - > crtc ) {
2012-11-21 14:40:21 +10:00
nv50_crtc_prepare ( nv_encoder - > crtc ) ;
2011-07-06 15:25:47 +10:00
2012-11-16 11:21:37 +10:00
push = evo_wait ( mast , 4 ) ;
2011-07-06 15:25:47 +10:00
if ( push ) {
2014-08-10 04:10:27 +10:00
if ( nv50_vers ( mast ) < GF110_DISP_CORE_CHANNEL_DMA ) {
2012-11-16 11:21:37 +10:00
evo_mthd ( push , 0x0400 + ( or * 0x080 ) , 1 ) ;
evo_data ( push , 0x00000000 ) ;
} else {
evo_mthd ( push , 0x0180 + ( or * 0x020 ) , 1 ) ;
evo_data ( push , 0x00000000 ) ;
}
evo_kick ( push , mast ) ;
2011-07-06 15:25:47 +10:00
}
}
2012-11-16 11:21:37 +10:00
nv_encoder - > crtc = NULL ;
2011-07-06 15:25:47 +10:00
}
2011-07-07 09:51:29 +10:00
static enum drm_connector_status
2012-11-21 14:40:21 +10:00
nv50_dac_detect ( struct drm_encoder * encoder , struct drm_connector * connector )
2011-07-07 09:51:29 +10:00
{
2014-08-10 04:10:26 +10:00
struct nouveau_encoder * nv_encoder = nouveau_encoder ( encoder ) ;
2012-11-21 14:40:21 +10:00
struct nv50_disp * disp = nv50_disp ( encoder - > dev ) ;
2014-08-10 04:10:26 +10:00
struct {
struct nv50_disp_mthd_v1 base ;
struct nv50_disp_dac_load_v0 load ;
} args = {
. base . version = 1 ,
. base . method = NV50_DISP_MTHD_V1_DAC_LOAD ,
. base . hasht = nv_encoder - > dcb - > hasht ,
. base . hashm = nv_encoder - > dcb - > hashm ,
} ;
int ret ;
args . load . data = nouveau_drm ( encoder - > dev ) - > vbios . dactestval ;
if ( args . load . data = = 0 )
args . load . data = 340 ;
2011-07-08 11:14:50 +10:00
2014-08-10 04:10:26 +10:00
ret = nvif_mthd ( disp - > disp , 0 , & args , sizeof ( args ) ) ;
if ( ret | | ! args . load . load )
2012-11-08 12:08:55 +10:00
return connector_status_disconnected ;
2011-07-08 11:14:50 +10:00
2012-11-08 12:08:55 +10:00
return connector_status_connected ;
2011-07-07 09:51:29 +10:00
}
2011-07-06 15:25:47 +10:00
static void
2012-11-21 14:40:21 +10:00
nv50_dac_destroy ( struct drm_encoder * encoder )
2011-07-06 15:25:47 +10:00
{
drm_encoder_cleanup ( encoder ) ;
kfree ( encoder ) ;
}
2012-11-21 14:40:21 +10:00
static const struct drm_encoder_helper_funcs nv50_dac_hfunc = {
. dpms = nv50_dac_dpms ,
2014-12-22 16:30:13 +10:00
. mode_fixup = nv50_encoder_mode_fixup ,
2012-11-21 14:40:21 +10:00
. prepare = nv50_dac_disconnect ,
. commit = nv50_dac_commit ,
. mode_set = nv50_dac_mode_set ,
. disable = nv50_dac_disconnect ,
. get_crtc = nv50_display_crtc_get ,
. detect = nv50_dac_detect
2011-07-06 15:25:47 +10:00
} ;
2012-11-21 14:40:21 +10:00
static const struct drm_encoder_funcs nv50_dac_func = {
. destroy = nv50_dac_destroy ,
2011-07-06 15:25:47 +10:00
} ;
static int
2012-11-21 14:40:21 +10:00
nv50_dac_create ( struct drm_connector * connector , struct dcb_output * dcbe )
2011-07-06 15:25:47 +10:00
{
2013-02-11 20:15:03 +10:00
struct nouveau_drm * drm = nouveau_drm ( connector - > dev ) ;
2015-01-14 15:36:34 +10:00
struct nvkm_i2c * i2c = nvxx_i2c ( & drm - > device ) ;
2015-08-20 14:54:15 +10:00
struct nvkm_i2c_bus * bus ;
2011-07-06 15:25:47 +10:00
struct nouveau_encoder * nv_encoder ;
struct drm_encoder * encoder ;
2013-02-11 20:15:03 +10:00
int type = DRM_MODE_ENCODER_DAC ;
2011-07-06 15:25:47 +10:00
nv_encoder = kzalloc ( sizeof ( * nv_encoder ) , GFP_KERNEL ) ;
if ( ! nv_encoder )
return - ENOMEM ;
nv_encoder - > dcb = dcbe ;
nv_encoder - > or = ffs ( dcbe - > or ) - 1 ;
2015-08-20 14:54:15 +10:00
bus = nvkm_i2c_bus_find ( i2c , dcbe - > i2c_index ) ;
if ( bus )
nv_encoder - > i2c = & bus - > i2c ;
2011-07-06 15:25:47 +10:00
encoder = to_drm_encoder ( nv_encoder ) ;
encoder - > possible_crtcs = dcbe - > heads ;
encoder - > possible_clones = 0 ;
drm: Pass 'name' to drm_encoder_init()
Done with coccinelle for the most part. However, it thinks '...' is
part of the semantic patch, so I put an 'int DOTDOTDOT' placeholder
in its place and got rid of it with sed afterwards.
@@
identifier dev, encoder, funcs;
@@
int drm_encoder_init(struct drm_device *dev,
struct drm_encoder *encoder,
const struct drm_encoder_funcs *funcs,
int encoder_type
+ ,const char *name, int DOTDOTDOT
)
{ ... }
@@
identifier dev, encoder, funcs;
@@
int drm_encoder_init(struct drm_device *dev,
struct drm_encoder *encoder,
const struct drm_encoder_funcs *funcs,
int encoder_type
+ ,const char *name, int DOTDOTDOT
);
@@
expression E1, E2, E3, E4;
@@
drm_encoder_init(E1, E2, E3, E4
+ ,NULL
)
v2: Add ', or NULL...' to @name kernel doc (Jani)
Annotate the function with __printf() attribute (Jani)
Signed-off-by: Ville Syrjälä <ville.syrjala@linux.intel.com>
Signed-off-by: Daniel Vetter <daniel.vetter@ffwll.ch>
Link: http://patchwork.freedesktop.org/patch/msgid/1449670818-2966-1-git-send-email-ville.syrjala@linux.intel.com
2015-12-09 16:20:18 +02:00
drm_encoder_init ( connector - > dev , encoder , & nv50_dac_func , type , NULL ) ;
2012-11-21 14:40:21 +10:00
drm_encoder_helper_add ( encoder , & nv50_dac_hfunc ) ;
2011-07-06 15:25:47 +10:00
drm_mode_connector_attach_encoder ( connector , encoder ) ;
return 0 ;
}
2011-07-04 16:25:18 +10:00
2011-11-11 18:13:13 +10:00
/******************************************************************************
* Audio
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
static void
2012-11-21 14:40:21 +10:00
nv50_audio_mode_set ( struct drm_encoder * encoder , struct drm_display_mode * mode )
2011-11-11 18:13:13 +10:00
{
struct nouveau_encoder * nv_encoder = nouveau_encoder ( encoder ) ;
2014-09-15 21:29:05 +10:00
struct nouveau_crtc * nv_crtc = nouveau_crtc ( encoder - > crtc ) ;
2011-11-11 18:13:13 +10:00
struct nouveau_connector * nv_connector ;
2012-11-21 14:40:21 +10:00
struct nv50_disp * disp = nv50_disp ( encoder - > dev ) ;
2014-09-15 21:11:51 +10:00
struct __packed {
struct {
struct nv50_disp_mthd_v1 mthd ;
struct nv50_disp_sor_hda_eld_v0 eld ;
} base ;
2014-08-10 04:10:26 +10:00
u8 data [ sizeof ( nv_connector - > base . eld ) ] ;
} args = {
2014-09-15 21:11:51 +10:00
. base . mthd . version = 1 ,
. base . mthd . method = NV50_DISP_MTHD_V1_SOR_HDA_ELD ,
. base . mthd . hasht = nv_encoder - > dcb - > hasht ,
2014-09-15 21:29:05 +10:00
. base . mthd . hashm = ( 0xf0ff & nv_encoder - > dcb - > hashm ) |
( 0x0100 < < nv_crtc - > index ) ,
2014-08-10 04:10:26 +10:00
} ;
2011-11-11 18:13:13 +10:00
nv_connector = nouveau_encoder_connector_get ( nv_encoder ) ;
if ( ! drm_detect_monitor_audio ( nv_connector - > edid ) )
return ;
drm_edid_to_eld ( & nv_connector - > base , nv_connector - > edid ) ;
2014-08-10 04:10:26 +10:00
memcpy ( args . data , nv_connector - > base . eld , sizeof ( args . data ) ) ;
2011-11-11 18:13:13 +10:00
2014-10-28 16:20:48 +02:00
nvif_mthd ( disp - > disp , 0 , & args ,
sizeof ( args . base ) + drm_eld_size ( args . data ) ) ;
2011-11-11 18:13:13 +10:00
}
static void
2014-09-15 21:29:05 +10:00
nv50_audio_disconnect ( struct drm_encoder * encoder , struct nouveau_crtc * nv_crtc )
2011-11-11 18:13:13 +10:00
{
struct nouveau_encoder * nv_encoder = nouveau_encoder ( encoder ) ;
2012-11-21 14:40:21 +10:00
struct nv50_disp * disp = nv50_disp ( encoder - > dev ) ;
2014-08-10 04:10:26 +10:00
struct {
struct nv50_disp_mthd_v1 base ;
struct nv50_disp_sor_hda_eld_v0 eld ;
} args = {
. base . version = 1 ,
. base . method = NV50_DISP_MTHD_V1_SOR_HDA_ELD ,
. base . hasht = nv_encoder - > dcb - > hasht ,
2014-09-15 21:29:05 +10:00
. base . hashm = ( 0xf0ff & nv_encoder - > dcb - > hashm ) |
( 0x0100 < < nv_crtc - > index ) ,
2014-08-10 04:10:26 +10:00
} ;
2011-11-11 18:13:13 +10:00
2014-08-10 04:10:26 +10:00
nvif_mthd ( disp - > disp , 0 , & args , sizeof ( args ) ) ;
2011-11-11 18:13:13 +10:00
}
/******************************************************************************
* HDMI
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
static void
2012-11-21 14:40:21 +10:00
nv50_hdmi_mode_set ( struct drm_encoder * encoder , struct drm_display_mode * mode )
2011-11-11 18:13:13 +10:00
{
2011-11-11 19:51:20 +10:00
struct nouveau_encoder * nv_encoder = nouveau_encoder ( encoder ) ;
struct nouveau_crtc * nv_crtc = nouveau_crtc ( encoder - > crtc ) ;
2012-11-21 14:40:21 +10:00
struct nv50_disp * disp = nv50_disp ( encoder - > dev ) ;
2014-08-10 04:10:26 +10:00
struct {
struct nv50_disp_mthd_v1 base ;
struct nv50_disp_sor_hdmi_pwr_v0 pwr ;
} args = {
. base . version = 1 ,
. base . method = NV50_DISP_MTHD_V1_SOR_HDMI_PWR ,
. base . hasht = nv_encoder - > dcb - > hasht ,
. base . hashm = ( 0xf0ff & nv_encoder - > dcb - > hashm ) |
( 0x0100 < < nv_crtc - > index ) ,
. pwr . state = 1 ,
. pwr . rekey = 56 , /* binary driver, and tegra, constant */
} ;
struct nouveau_connector * nv_connector ;
2011-11-11 19:51:20 +10:00
u32 max_ac_packet ;
nv_connector = nouveau_encoder_connector_get ( nv_encoder ) ;
if ( ! drm_detect_hdmi_monitor ( nv_connector - > edid ) )
return ;
max_ac_packet = mode - > htotal - mode - > hdisplay ;
2014-08-10 04:10:26 +10:00
max_ac_packet - = args . pwr . rekey ;
2011-11-11 19:51:20 +10:00
max_ac_packet - = 18 ; /* constant from tegra */
2014-08-10 04:10:26 +10:00
args . pwr . max_ac_packet = max_ac_packet / 32 ;
2011-11-11 20:46:00 +10:00
2014-08-10 04:10:26 +10:00
nvif_mthd ( disp - > disp , 0 , & args , sizeof ( args ) ) ;
2012-11-21 14:40:21 +10:00
nv50_audio_mode_set ( encoder , mode ) ;
2011-11-11 18:13:13 +10:00
}
static void
2014-06-05 10:59:55 +10:00
nv50_hdmi_disconnect ( struct drm_encoder * encoder , struct nouveau_crtc * nv_crtc )
2011-11-11 18:13:13 +10:00
{
2011-11-11 19:51:20 +10:00
struct nouveau_encoder * nv_encoder = nouveau_encoder ( encoder ) ;
2012-11-21 14:40:21 +10:00
struct nv50_disp * disp = nv50_disp ( encoder - > dev ) ;
2014-08-10 04:10:26 +10:00
struct {
struct nv50_disp_mthd_v1 base ;
struct nv50_disp_sor_hdmi_pwr_v0 pwr ;
} args = {
. base . version = 1 ,
. base . method = NV50_DISP_MTHD_V1_SOR_HDMI_PWR ,
. base . hasht = nv_encoder - > dcb - > hasht ,
. base . hashm = ( 0xf0ff & nv_encoder - > dcb - > hashm ) |
( 0x0100 < < nv_crtc - > index ) ,
} ;
2011-11-11 19:51:20 +10:00
2014-08-10 04:10:26 +10:00
nvif_mthd ( disp - > disp , 0 , & args , sizeof ( args ) ) ;
2011-11-11 18:13:13 +10:00
}
2011-07-04 16:25:18 +10:00
/******************************************************************************
* SOR
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2011-07-05 13:08:40 +10:00
static void
2012-11-21 14:40:21 +10:00
nv50_sor_dpms ( struct drm_encoder * encoder , int mode )
2011-07-05 13:08:40 +10:00
{
struct nouveau_encoder * nv_encoder = nouveau_encoder ( encoder ) ;
2014-08-10 04:10:26 +10:00
struct nv50_disp * disp = nv50_disp ( encoder - > dev ) ;
struct {
struct nv50_disp_mthd_v1 base ;
struct nv50_disp_sor_pwr_v0 pwr ;
} args = {
. base . version = 1 ,
. base . method = NV50_DISP_MTHD_V1_SOR_PWR ,
. base . hasht = nv_encoder - > dcb - > hasht ,
. base . hashm = nv_encoder - > dcb - > hashm ,
. pwr . state = mode = = DRM_MODE_DPMS_ON ,
} ;
2014-08-10 04:10:27 +10:00
struct {
struct nv50_disp_mthd_v1 base ;
struct nv50_disp_sor_dp_pwr_v0 pwr ;
} link = {
. base . version = 1 ,
. base . method = NV50_DISP_MTHD_V1_SOR_DP_PWR ,
. base . hasht = nv_encoder - > dcb - > hasht ,
. base . hashm = nv_encoder - > dcb - > hashm ,
. pwr . state = mode = = DRM_MODE_DPMS_ON ,
} ;
2011-07-05 13:08:40 +10:00
struct drm_device * dev = encoder - > dev ;
struct drm_encoder * partner ;
nv_encoder - > last_dpms = mode ;
list_for_each_entry ( partner , & dev - > mode_config . encoder_list , head ) {
struct nouveau_encoder * nv_partner = nouveau_encoder ( partner ) ;
if ( partner - > encoder_type ! = DRM_MODE_ENCODER_TMDS )
continue ;
if ( nv_partner ! = nv_encoder & &
2011-11-17 09:10:02 +10:00
nv_partner - > dcb - > or = = nv_encoder - > dcb - > or ) {
2011-07-05 13:08:40 +10:00
if ( nv_partner - > last_dpms = = DRM_MODE_DPMS_ON )
return ;
break ;
}
}
2014-05-31 01:48:06 +10:00
if ( nv_encoder - > dcb - > type = = DCB_OUTPUT_DP ) {
2014-08-10 04:10:26 +10:00
args . pwr . state = 1 ;
nvif_mthd ( disp - > disp , 0 , & args , sizeof ( args ) ) ;
2014-08-10 04:10:27 +10:00
nvif_mthd ( disp - > disp , 0 , & link , sizeof ( link ) ) ;
2014-05-31 01:48:06 +10:00
} else {
2014-08-10 04:10:26 +10:00
nvif_mthd ( disp - > disp , 0 , & args , sizeof ( args ) ) ;
2014-05-31 01:48:06 +10:00
}
2011-07-05 13:08:40 +10:00
}
2012-03-12 15:23:44 +10:00
static void
2014-06-05 10:59:55 +10:00
nv50_sor_ctrl ( struct nouveau_encoder * nv_encoder , u32 mask , u32 data )
2012-03-12 15:23:44 +10:00
{
2014-06-05 10:59:55 +10:00
struct nv50_mast * mast = nv50_mast ( nv_encoder - > base . base . dev ) ;
u32 temp = ( nv_encoder - > ctrl & ~ mask ) | ( data & mask ) , * push ;
if ( temp ! = nv_encoder - > ctrl & & ( push = evo_wait ( mast , 2 ) ) ) {
2014-08-10 04:10:27 +10:00
if ( nv50_vers ( mast ) < GF110_DISP_CORE_CHANNEL_DMA ) {
2014-06-05 10:59:55 +10:00
evo_mthd ( push , 0x0600 + ( nv_encoder - > or * 0x40 ) , 1 ) ;
evo_data ( push , ( nv_encoder - > ctrl = temp ) ) ;
} else {
evo_mthd ( push , 0x0200 + ( nv_encoder - > or * 0x20 ) , 1 ) ;
evo_data ( push , ( nv_encoder - > ctrl = temp ) ) ;
2012-03-12 15:23:44 +10:00
}
2014-06-05 10:59:55 +10:00
evo_kick ( push , mast ) ;
2012-03-12 15:23:44 +10:00
}
2014-06-05 10:59:55 +10:00
}
static void
nv50_sor_disconnect ( struct drm_encoder * encoder )
{
struct nouveau_encoder * nv_encoder = nouveau_encoder ( encoder ) ;
struct nouveau_crtc * nv_crtc = nouveau_crtc ( nv_encoder - > crtc ) ;
2012-11-16 11:40:34 +10:00
nv_encoder - > last_dpms = DRM_MODE_DPMS_OFF ;
nv_encoder - > crtc = NULL ;
2014-06-05 10:59:55 +10:00
if ( nv_crtc ) {
nv50_crtc_prepare ( & nv_crtc - > base ) ;
nv50_sor_ctrl ( nv_encoder , 1 < < nv_crtc - > index , 0 ) ;
2014-09-15 21:29:05 +10:00
nv50_audio_disconnect ( encoder , nv_crtc ) ;
2014-06-05 10:59:55 +10:00
nv50_hdmi_disconnect ( & nv_encoder - > base . base , nv_crtc ) ;
}
2012-03-12 15:23:44 +10:00
}
2011-07-05 13:08:40 +10:00
static void
2012-11-21 14:40:21 +10:00
nv50_sor_commit ( struct drm_encoder * encoder )
2011-07-05 13:08:40 +10:00
{
}
static void
2012-11-21 14:40:21 +10:00
nv50_sor_mode_set ( struct drm_encoder * encoder , struct drm_display_mode * umode ,
2011-07-08 12:52:14 +10:00
struct drm_display_mode * mode )
2011-07-05 13:08:40 +10:00
{
2014-08-10 04:10:27 +10:00
struct nouveau_encoder * nv_encoder = nouveau_encoder ( encoder ) ;
struct nouveau_crtc * nv_crtc = nouveau_crtc ( encoder - > crtc ) ;
struct {
struct nv50_disp_mthd_v1 base ;
struct nv50_disp_sor_lvds_script_v0 lvds ;
} lvds = {
. base . version = 1 ,
. base . method = NV50_DISP_MTHD_V1_SOR_LVDS_SCRIPT ,
. base . hasht = nv_encoder - > dcb - > hasht ,
. base . hashm = nv_encoder - > dcb - > hashm ,
} ;
2012-11-21 14:40:21 +10:00
struct nv50_disp * disp = nv50_disp ( encoder - > dev ) ;
struct nv50_mast * mast = nv50_mast ( encoder - > dev ) ;
2011-11-11 18:13:13 +10:00
struct drm_device * dev = encoder - > dev ;
2012-07-31 16:16:21 +10:00
struct nouveau_drm * drm = nouveau_drm ( dev ) ;
2011-07-08 12:52:14 +10:00
struct nouveau_connector * nv_connector ;
2012-07-31 16:16:21 +10:00
struct nvbios * bios = & drm - > vbios ;
2014-08-10 04:10:27 +10:00
u32 mask , ctrl ;
2012-11-16 11:40:34 +10:00
u8 owner = 1 < < nv_crtc - > index ;
u8 proto = 0xf ;
u8 depth = 0x0 ;
2011-07-05 13:08:40 +10:00
2011-07-08 12:52:14 +10:00
nv_connector = nouveau_encoder_connector_get ( nv_encoder ) ;
2014-06-05 10:59:55 +10:00
nv_encoder - > crtc = encoder - > crtc ;
2011-07-08 12:52:14 +10:00
switch ( nv_encoder - > dcb - > type ) {
2012-07-11 10:44:20 +10:00
case DCB_OUTPUT_TMDS :
2011-07-08 12:52:14 +10:00
if ( nv_encoder - > dcb - > sorconf . link & 1 ) {
2015-11-03 21:00:10 -05:00
proto = 0x1 ;
/* Only enable dual-link if:
* - Need to ( i . e . rate > 165 MHz )
* - DCB says we can
* - Not an HDMI monitor , since there ' s no dual - link
* on HDMI .
*/
if ( mode - > clock > = 165000 & &
nv_encoder - > dcb - > duallink_possible & &
! drm_detect_hdmi_monitor ( nv_connector - > edid ) )
proto | = 0x4 ;
2011-07-08 12:52:14 +10:00
} else {
2012-11-16 11:40:34 +10:00
proto = 0x2 ;
2011-07-08 12:52:14 +10:00
}
2014-06-05 10:59:55 +10:00
nv50_hdmi_mode_set ( & nv_encoder - > base . base , mode ) ;
2011-07-08 12:52:14 +10:00
break ;
2012-07-11 10:44:20 +10:00
case DCB_OUTPUT_LVDS :
2012-11-16 11:40:34 +10:00
proto = 0x0 ;
2011-07-08 12:52:14 +10:00
if ( bios - > fp_no_ddc ) {
if ( bios - > fp . dual_link )
2014-08-10 04:10:27 +10:00
lvds . lvds . script | = 0x0100 ;
2011-07-08 12:52:14 +10:00
if ( bios - > fp . if_is_24bit )
2014-08-10 04:10:27 +10:00
lvds . lvds . script | = 0x0200 ;
2011-07-08 12:52:14 +10:00
} else {
2011-11-18 10:23:59 +10:00
if ( nv_connector - > type = = DCB_CONNECTOR_LVDS_SPWG ) {
2011-07-08 12:52:14 +10:00
if ( ( ( u8 * ) nv_connector - > edid ) [ 121 ] = = 2 )
2014-08-10 04:10:27 +10:00
lvds . lvds . script | = 0x0100 ;
2011-07-08 12:52:14 +10:00
} else
if ( mode - > clock > = bios - > fp . duallink_transition_clk ) {
2014-08-10 04:10:27 +10:00
lvds . lvds . script | = 0x0100 ;
2011-07-08 12:52:14 +10:00
}
2011-07-05 13:08:40 +10:00
2014-08-10 04:10:27 +10:00
if ( lvds . lvds . script & 0x0100 ) {
2011-07-08 12:52:14 +10:00
if ( bios - > fp . strapless_is_24bit & 2 )
2014-08-10 04:10:27 +10:00
lvds . lvds . script | = 0x0200 ;
2011-07-08 12:52:14 +10:00
} else {
if ( bios - > fp . strapless_is_24bit & 1 )
2014-08-10 04:10:27 +10:00
lvds . lvds . script | = 0x0200 ;
2011-07-08 12:52:14 +10:00
}
if ( nv_connector - > base . display_info . bpc = = 8 )
2014-08-10 04:10:27 +10:00
lvds . lvds . script | = 0x0200 ;
2011-07-08 12:52:14 +10:00
}
2012-11-09 11:25:37 +10:00
2014-08-10 04:10:27 +10:00
nvif_mthd ( disp - > disp , 0 , & lvds , sizeof ( lvds ) ) ;
2011-07-08 12:52:14 +10:00
break ;
2012-07-11 10:44:20 +10:00
case DCB_OUTPUT_DP :
2012-03-12 11:42:20 +10:00
if ( nv_connector - > base . display_info . bpc = = 6 ) {
2012-03-11 01:28:48 +10:00
nv_encoder - > dp . datarate = mode - > clock * 18 / 8 ;
2012-11-16 11:40:34 +10:00
depth = 0x2 ;
2012-11-21 14:49:54 +10:00
} else
if ( nv_connector - > base . display_info . bpc = = 8 ) {
2012-03-11 01:28:48 +10:00
nv_encoder - > dp . datarate = mode - > clock * 24 / 8 ;
2012-11-16 11:40:34 +10:00
depth = 0x5 ;
2012-11-21 14:49:54 +10:00
} else {
nv_encoder - > dp . datarate = mode - > clock * 30 / 8 ;
depth = 0x6 ;
2012-03-12 11:42:20 +10:00
}
2012-03-11 01:28:48 +10:00
if ( nv_encoder - > dcb - > sorconf . link & 1 )
2012-11-16 11:40:34 +10:00
proto = 0x8 ;
2012-03-11 01:28:48 +10:00
else
2012-11-16 11:40:34 +10:00
proto = 0x9 ;
2014-09-15 15:20:47 +10:00
nv50_audio_mode_set ( encoder , mode ) ;
2012-03-11 01:28:48 +10:00
break ;
2011-07-08 12:52:14 +10:00
default :
BUG_ON ( 1 ) ;
break ;
}
2011-07-08 11:53:37 +10:00
2014-06-05 10:59:55 +10:00
nv50_sor_dpms ( & nv_encoder - > base . base , DRM_MODE_DPMS_ON ) ;
2011-07-05 13:08:40 +10:00
2014-08-10 04:10:27 +10:00
if ( nv50_vers ( mast ) > = GF110_DISP ) {
2014-06-05 10:59:55 +10:00
u32 * push = evo_wait ( mast , 3 ) ;
if ( push ) {
2012-11-16 11:40:34 +10:00
u32 magic = 0x31ec6000 | ( nv_crtc - > index < < 25 ) ;
u32 syncs = 0x00000001 ;
if ( mode - > flags & DRM_MODE_FLAG_NHSYNC )
syncs | = 0x00000008 ;
if ( mode - > flags & DRM_MODE_FLAG_NVSYNC )
syncs | = 0x00000010 ;
if ( mode - > flags & DRM_MODE_FLAG_INTERLACE )
magic | = 0x00000001 ;
evo_mthd ( push , 0x0404 + ( nv_crtc - > index * 0x300 ) , 2 ) ;
evo_data ( push , syncs | ( depth < < 6 ) ) ;
evo_data ( push , magic ) ;
2014-06-05 10:59:55 +10:00
evo_kick ( push , mast ) ;
2012-11-16 11:40:34 +10:00
}
2014-06-05 10:59:55 +10:00
ctrl = proto < < 8 ;
mask = 0x00000f00 ;
} else {
ctrl = ( depth < < 16 ) | ( proto < < 8 ) ;
if ( mode - > flags & DRM_MODE_FLAG_NHSYNC )
ctrl | = 0x00001000 ;
if ( mode - > flags & DRM_MODE_FLAG_NVSYNC )
ctrl | = 0x00002000 ;
mask = 0x000f3f00 ;
2011-07-05 13:08:40 +10:00
}
2014-06-05 10:59:55 +10:00
nv50_sor_ctrl ( nv_encoder , mask | owner , ctrl | owner ) ;
2011-07-05 13:08:40 +10:00
}
static void
2012-11-21 14:40:21 +10:00
nv50_sor_destroy ( struct drm_encoder * encoder )
2011-07-05 13:08:40 +10:00
{
drm_encoder_cleanup ( encoder ) ;
kfree ( encoder ) ;
}
2012-11-21 14:40:21 +10:00
static const struct drm_encoder_helper_funcs nv50_sor_hfunc = {
. dpms = nv50_sor_dpms ,
2014-12-22 16:30:13 +10:00
. mode_fixup = nv50_encoder_mode_fixup ,
2013-02-20 14:34:18 +10:00
. prepare = nv50_sor_disconnect ,
2012-11-21 14:40:21 +10:00
. commit = nv50_sor_commit ,
. mode_set = nv50_sor_mode_set ,
. disable = nv50_sor_disconnect ,
. get_crtc = nv50_display_crtc_get ,
2011-07-05 13:08:40 +10:00
} ;
2012-11-21 14:40:21 +10:00
static const struct drm_encoder_funcs nv50_sor_func = {
. destroy = nv50_sor_destroy ,
2011-07-05 13:08:40 +10:00
} ;
static int
2012-11-21 14:40:21 +10:00
nv50_sor_create ( struct drm_connector * connector , struct dcb_output * dcbe )
2011-07-05 13:08:40 +10:00
{
2013-02-11 20:15:03 +10:00
struct nouveau_drm * drm = nouveau_drm ( connector - > dev ) ;
2015-01-14 15:36:34 +10:00
struct nvkm_i2c * i2c = nvxx_i2c ( & drm - > device ) ;
2011-07-05 13:08:40 +10:00
struct nouveau_encoder * nv_encoder ;
struct drm_encoder * encoder ;
2013-02-11 20:15:03 +10:00
int type ;
switch ( dcbe - > type ) {
case DCB_OUTPUT_LVDS : type = DRM_MODE_ENCODER_LVDS ; break ;
case DCB_OUTPUT_TMDS :
case DCB_OUTPUT_DP :
default :
type = DRM_MODE_ENCODER_TMDS ;
break ;
}
2011-07-05 13:08:40 +10:00
nv_encoder = kzalloc ( sizeof ( * nv_encoder ) , GFP_KERNEL ) ;
if ( ! nv_encoder )
return - ENOMEM ;
nv_encoder - > dcb = dcbe ;
nv_encoder - > or = ffs ( dcbe - > or ) - 1 ;
nv_encoder - > last_dpms = DRM_MODE_DPMS_OFF ;
2015-08-20 14:54:15 +10:00
if ( dcbe - > type = = DCB_OUTPUT_DP ) {
struct nvkm_i2c_aux * aux =
nvkm_i2c_aux_find ( i2c , dcbe - > i2c_index ) ;
if ( aux ) {
nv_encoder - > i2c = & aux - > i2c ;
nv_encoder - > aux = aux ;
}
} else {
struct nvkm_i2c_bus * bus =
nvkm_i2c_bus_find ( i2c , dcbe - > i2c_index ) ;
if ( bus )
nv_encoder - > i2c = & bus - > i2c ;
}
2011-07-05 13:08:40 +10:00
encoder = to_drm_encoder ( nv_encoder ) ;
encoder - > possible_crtcs = dcbe - > heads ;
encoder - > possible_clones = 0 ;
drm: Pass 'name' to drm_encoder_init()
Done with coccinelle for the most part. However, it thinks '...' is
part of the semantic patch, so I put an 'int DOTDOTDOT' placeholder
in its place and got rid of it with sed afterwards.
@@
identifier dev, encoder, funcs;
@@
int drm_encoder_init(struct drm_device *dev,
struct drm_encoder *encoder,
const struct drm_encoder_funcs *funcs,
int encoder_type
+ ,const char *name, int DOTDOTDOT
)
{ ... }
@@
identifier dev, encoder, funcs;
@@
int drm_encoder_init(struct drm_device *dev,
struct drm_encoder *encoder,
const struct drm_encoder_funcs *funcs,
int encoder_type
+ ,const char *name, int DOTDOTDOT
);
@@
expression E1, E2, E3, E4;
@@
drm_encoder_init(E1, E2, E3, E4
+ ,NULL
)
v2: Add ', or NULL...' to @name kernel doc (Jani)
Annotate the function with __printf() attribute (Jani)
Signed-off-by: Ville Syrjälä <ville.syrjala@linux.intel.com>
Signed-off-by: Daniel Vetter <daniel.vetter@ffwll.ch>
Link: http://patchwork.freedesktop.org/patch/msgid/1449670818-2966-1-git-send-email-ville.syrjala@linux.intel.com
2015-12-09 16:20:18 +02:00
drm_encoder_init ( connector - > dev , encoder , & nv50_sor_func , type , NULL ) ;
2012-11-21 14:40:21 +10:00
drm_encoder_helper_add ( encoder , & nv50_sor_hfunc ) ;
2011-07-05 13:08:40 +10:00
drm_mode_connector_attach_encoder ( connector , encoder ) ;
return 0 ;
}
2011-07-04 16:25:18 +10:00
2013-02-11 09:52:58 +10:00
/******************************************************************************
* PIOR
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
static void
nv50_pior_dpms ( struct drm_encoder * encoder , int mode )
{
struct nouveau_encoder * nv_encoder = nouveau_encoder ( encoder ) ;
struct nv50_disp * disp = nv50_disp ( encoder - > dev ) ;
2014-08-10 04:10:27 +10:00
struct {
struct nv50_disp_mthd_v1 base ;
struct nv50_disp_pior_pwr_v0 pwr ;
} args = {
. base . version = 1 ,
. base . method = NV50_DISP_MTHD_V1_PIOR_PWR ,
. base . hasht = nv_encoder - > dcb - > hasht ,
. base . hashm = nv_encoder - > dcb - > hashm ,
. pwr . state = mode = = DRM_MODE_DPMS_ON ,
. pwr . type = nv_encoder - > dcb - > type ,
} ;
nvif_mthd ( disp - > disp , 0 , & args , sizeof ( args ) ) ;
2013-02-11 09:52:58 +10:00
}
static bool
nv50_pior_mode_fixup ( struct drm_encoder * encoder ,
const struct drm_display_mode * mode ,
struct drm_display_mode * adjusted_mode )
{
2014-12-22 16:30:13 +10:00
if ( ! nv50_encoder_mode_fixup ( encoder , mode , adjusted_mode ) )
return false ;
2013-02-11 09:52:58 +10:00
adjusted_mode - > clock * = 2 ;
return true ;
}
static void
nv50_pior_commit ( struct drm_encoder * encoder )
{
}
static void
nv50_pior_mode_set ( struct drm_encoder * encoder , struct drm_display_mode * mode ,
struct drm_display_mode * adjusted_mode )
{
struct nv50_mast * mast = nv50_mast ( encoder - > dev ) ;
struct nouveau_encoder * nv_encoder = nouveau_encoder ( encoder ) ;
struct nouveau_crtc * nv_crtc = nouveau_crtc ( encoder - > crtc ) ;
struct nouveau_connector * nv_connector ;
u8 owner = 1 < < nv_crtc - > index ;
u8 proto , depth ;
u32 * push ;
nv_connector = nouveau_encoder_connector_get ( nv_encoder ) ;
switch ( nv_connector - > base . display_info . bpc ) {
case 10 : depth = 0x6 ; break ;
case 8 : depth = 0x5 ; break ;
case 6 : depth = 0x2 ; break ;
default : depth = 0x0 ; break ;
}
switch ( nv_encoder - > dcb - > type ) {
case DCB_OUTPUT_TMDS :
case DCB_OUTPUT_DP :
proto = 0x0 ;
break ;
default :
BUG_ON ( 1 ) ;
break ;
}
nv50_pior_dpms ( encoder , DRM_MODE_DPMS_ON ) ;
push = evo_wait ( mast , 8 ) ;
if ( push ) {
2014-08-10 04:10:27 +10:00
if ( nv50_vers ( mast ) < GF110_DISP_CORE_CHANNEL_DMA ) {
2013-02-11 09:52:58 +10:00
u32 ctrl = ( depth < < 16 ) | ( proto < < 8 ) | owner ;
if ( mode - > flags & DRM_MODE_FLAG_NHSYNC )
ctrl | = 0x00001000 ;
if ( mode - > flags & DRM_MODE_FLAG_NVSYNC )
ctrl | = 0x00002000 ;
evo_mthd ( push , 0x0700 + ( nv_encoder - > or * 0x040 ) , 1 ) ;
evo_data ( push , ctrl ) ;
}
evo_kick ( push , mast ) ;
}
nv_encoder - > crtc = encoder - > crtc ;
}
static void
nv50_pior_disconnect ( struct drm_encoder * encoder )
{
struct nouveau_encoder * nv_encoder = nouveau_encoder ( encoder ) ;
struct nv50_mast * mast = nv50_mast ( encoder - > dev ) ;
const int or = nv_encoder - > or ;
u32 * push ;
if ( nv_encoder - > crtc ) {
nv50_crtc_prepare ( nv_encoder - > crtc ) ;
push = evo_wait ( mast , 4 ) ;
if ( push ) {
2014-08-10 04:10:27 +10:00
if ( nv50_vers ( mast ) < GF110_DISP_CORE_CHANNEL_DMA ) {
2013-02-11 09:52:58 +10:00
evo_mthd ( push , 0x0700 + ( or * 0x040 ) , 1 ) ;
evo_data ( push , 0x00000000 ) ;
}
evo_kick ( push , mast ) ;
}
}
nv_encoder - > crtc = NULL ;
}
static void
nv50_pior_destroy ( struct drm_encoder * encoder )
{
drm_encoder_cleanup ( encoder ) ;
kfree ( encoder ) ;
}
static const struct drm_encoder_helper_funcs nv50_pior_hfunc = {
. dpms = nv50_pior_dpms ,
. mode_fixup = nv50_pior_mode_fixup ,
. prepare = nv50_pior_disconnect ,
. commit = nv50_pior_commit ,
. mode_set = nv50_pior_mode_set ,
. disable = nv50_pior_disconnect ,
. get_crtc = nv50_display_crtc_get ,
} ;
static const struct drm_encoder_funcs nv50_pior_func = {
. destroy = nv50_pior_destroy ,
} ;
static int
nv50_pior_create ( struct drm_connector * connector , struct dcb_output * dcbe )
{
struct nouveau_drm * drm = nouveau_drm ( connector - > dev ) ;
2015-01-14 15:36:34 +10:00
struct nvkm_i2c * i2c = nvxx_i2c ( & drm - > device ) ;
2015-08-20 14:54:15 +10:00
struct nvkm_i2c_bus * bus = NULL ;
struct nvkm_i2c_aux * aux = NULL ;
struct i2c_adapter * ddc ;
2013-02-11 09:52:58 +10:00
struct nouveau_encoder * nv_encoder ;
struct drm_encoder * encoder ;
int type ;
switch ( dcbe - > type ) {
case DCB_OUTPUT_TMDS :
2015-08-20 14:54:15 +10:00
bus = nvkm_i2c_bus_find ( i2c , NVKM_I2C_BUS_EXT ( dcbe - > extdev ) ) ;
ddc = bus ? & bus - > i2c : NULL ;
2013-02-11 09:52:58 +10:00
type = DRM_MODE_ENCODER_TMDS ;
break ;
case DCB_OUTPUT_DP :
2015-08-20 14:54:15 +10:00
aux = nvkm_i2c_aux_find ( i2c , NVKM_I2C_AUX_EXT ( dcbe - > extdev ) ) ;
ddc = aux ? & aux - > i2c : NULL ;
2013-02-11 09:52:58 +10:00
type = DRM_MODE_ENCODER_TMDS ;
break ;
default :
return - ENODEV ;
}
nv_encoder = kzalloc ( sizeof ( * nv_encoder ) , GFP_KERNEL ) ;
if ( ! nv_encoder )
return - ENOMEM ;
nv_encoder - > dcb = dcbe ;
nv_encoder - > or = ffs ( dcbe - > or ) - 1 ;
nv_encoder - > i2c = ddc ;
2015-08-20 14:54:15 +10:00
nv_encoder - > aux = aux ;
2013-02-11 09:52:58 +10:00
encoder = to_drm_encoder ( nv_encoder ) ;
encoder - > possible_crtcs = dcbe - > heads ;
encoder - > possible_clones = 0 ;
drm: Pass 'name' to drm_encoder_init()
Done with coccinelle for the most part. However, it thinks '...' is
part of the semantic patch, so I put an 'int DOTDOTDOT' placeholder
in its place and got rid of it with sed afterwards.
@@
identifier dev, encoder, funcs;
@@
int drm_encoder_init(struct drm_device *dev,
struct drm_encoder *encoder,
const struct drm_encoder_funcs *funcs,
int encoder_type
+ ,const char *name, int DOTDOTDOT
)
{ ... }
@@
identifier dev, encoder, funcs;
@@
int drm_encoder_init(struct drm_device *dev,
struct drm_encoder *encoder,
const struct drm_encoder_funcs *funcs,
int encoder_type
+ ,const char *name, int DOTDOTDOT
);
@@
expression E1, E2, E3, E4;
@@
drm_encoder_init(E1, E2, E3, E4
+ ,NULL
)
v2: Add ', or NULL...' to @name kernel doc (Jani)
Annotate the function with __printf() attribute (Jani)
Signed-off-by: Ville Syrjälä <ville.syrjala@linux.intel.com>
Signed-off-by: Daniel Vetter <daniel.vetter@ffwll.ch>
Link: http://patchwork.freedesktop.org/patch/msgid/1449670818-2966-1-git-send-email-ville.syrjala@linux.intel.com
2015-12-09 16:20:18 +02:00
drm_encoder_init ( connector - > dev , encoder , & nv50_pior_func , type , NULL ) ;
2013-02-11 09:52:58 +10:00
drm_encoder_helper_add ( encoder , & nv50_pior_hfunc ) ;
drm_mode_connector_attach_encoder ( connector , encoder ) ;
return 0 ;
}
2014-08-10 04:10:19 +10:00
/******************************************************************************
* Framebuffer
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2014-08-10 04:10:19 +10:00
static void
2014-08-10 04:10:22 +10:00
nv50_fbdma_fini ( struct nv50_fbdma * fbdma )
2014-08-10 04:10:19 +10:00
{
2014-08-10 04:10:22 +10:00
int i ;
for ( i = 0 ; i < ARRAY_SIZE ( fbdma - > base ) ; i + + )
nvif_object_fini ( & fbdma - > base [ i ] ) ;
nvif_object_fini ( & fbdma - > core ) ;
2014-08-10 04:10:19 +10:00
list_del ( & fbdma - > head ) ;
kfree ( fbdma ) ;
}
static int
nv50_fbdma_init ( struct drm_device * dev , u32 name , u64 offset , u64 length , u8 kind )
{
struct nouveau_drm * drm = nouveau_drm ( dev ) ;
struct nv50_disp * disp = nv50_disp ( dev ) ;
struct nv50_mast * mast = nv50_mast ( dev ) ;
2014-08-10 04:10:24 +10:00
struct __attribute__ ( ( packed ) ) {
struct nv_dma_v0 base ;
union {
struct nv50_dma_v0 nv50 ;
struct gf100_dma_v0 gf100 ;
2015-08-20 14:54:21 +10:00
struct gf119_dma_v0 gf119 ;
2014-08-10 04:10:24 +10:00
} ;
} args = { } ;
2014-08-10 04:10:19 +10:00
struct nv50_fbdma * fbdma ;
struct drm_crtc * crtc ;
2014-08-10 04:10:24 +10:00
u32 size = sizeof ( args . base ) ;
2014-08-10 04:10:19 +10:00
int ret ;
list_for_each_entry ( fbdma , & disp - > fbdma , head ) {
2014-08-10 04:10:22 +10:00
if ( fbdma - > core . handle = = name )
2014-08-10 04:10:19 +10:00
return 0 ;
}
fbdma = kzalloc ( sizeof ( * fbdma ) , GFP_KERNEL ) ;
if ( ! fbdma )
return - ENOMEM ;
list_add ( & fbdma - > head , & disp - > fbdma ) ;
2014-08-10 04:10:24 +10:00
args . base . target = NV_DMA_V0_TARGET_VRAM ;
args . base . access = NV_DMA_V0_ACCESS_RDWR ;
args . base . start = offset ;
args . base . limit = offset + length - 1 ;
2014-08-10 04:10:19 +10:00
2014-08-10 04:10:22 +10:00
if ( drm - > device . info . chipset < 0x80 ) {
2014-08-10 04:10:24 +10:00
args . nv50 . part = NV50_DMA_V0_PART_256 ;
size + = sizeof ( args . nv50 ) ;
2014-08-10 04:10:19 +10:00
} else
2014-08-10 04:10:22 +10:00
if ( drm - > device . info . chipset < 0xc0 ) {
2014-08-10 04:10:24 +10:00
args . nv50 . part = NV50_DMA_V0_PART_256 ;
args . nv50 . kind = kind ;
size + = sizeof ( args . nv50 ) ;
2014-08-10 04:10:19 +10:00
} else
2014-08-10 04:10:22 +10:00
if ( drm - > device . info . chipset < 0xd0 ) {
2014-08-10 04:10:24 +10:00
args . gf100 . kind = kind ;
size + = sizeof ( args . gf100 ) ;
2014-08-10 04:10:19 +10:00
} else {
2015-08-20 14:54:21 +10:00
args . gf119 . page = GF119_DMA_V0_PAGE_LP ;
args . gf119 . kind = kind ;
size + = sizeof ( args . gf119 ) ;
2014-08-10 04:10:19 +10:00
}
list_for_each_entry ( crtc , & dev - > mode_config . crtc_list , head ) {
2014-08-10 04:10:22 +10:00
struct nv50_head * head = nv50_head ( crtc ) ;
2015-08-20 14:54:15 +10:00
int ret = nvif_object_init ( & head - > sync . base . base . user , name ,
NV_DMA_IN_MEMORY , & args , size ,
2014-08-10 04:10:22 +10:00
& fbdma - > base [ head - > base . index ] ) ;
2014-08-10 04:10:19 +10:00
if ( ret ) {
2014-08-10 04:10:22 +10:00
nv50_fbdma_fini ( fbdma ) ;
2014-08-10 04:10:19 +10:00
return ret ;
}
}
2015-08-20 14:54:15 +10:00
ret = nvif_object_init ( & mast - > base . base . user , name , NV_DMA_IN_MEMORY ,
& args , size , & fbdma - > core ) ;
2014-08-10 04:10:19 +10:00
if ( ret ) {
2014-08-10 04:10:22 +10:00
nv50_fbdma_fini ( fbdma ) ;
2014-08-10 04:10:19 +10:00
return ret ;
}
return 0 ;
}
2014-08-10 04:10:19 +10:00
static void
nv50_fb_dtor ( struct drm_framebuffer * fb )
{
}
static int
nv50_fb_ctor ( struct drm_framebuffer * fb )
{
struct nouveau_framebuffer * nv_fb = nouveau_framebuffer ( fb ) ;
struct nouveau_drm * drm = nouveau_drm ( fb - > dev ) ;
struct nouveau_bo * nvbo = nv_fb - > nvbo ;
2014-08-10 04:10:19 +10:00
struct nv50_disp * disp = nv50_disp ( fb - > dev ) ;
u8 kind = nouveau_bo_tile_layout ( nvbo ) > > 8 ;
u8 tile = nvbo - > tile_mode ;
2014-08-10 04:10:19 +10:00
2014-08-10 04:10:22 +10:00
if ( drm - > device . info . chipset > = 0xc0 )
2014-08-10 04:10:19 +10:00
tile > > = 4 ; /* yep.. */
2014-08-10 04:10:19 +10:00
switch ( fb - > depth ) {
case 8 : nv_fb - > r_format = 0x1e00 ; break ;
case 15 : nv_fb - > r_format = 0xe900 ; break ;
case 16 : nv_fb - > r_format = 0xe800 ; break ;
case 24 :
case 32 : nv_fb - > r_format = 0xcf00 ; break ;
case 30 : nv_fb - > r_format = 0xd100 ; break ;
default :
NV_ERROR ( drm , " unknown depth %d \n " , fb - > depth ) ;
return - EINVAL ;
}
2014-08-10 04:10:27 +10:00
if ( disp - > disp - > oclass < G82_DISP ) {
2014-08-10 04:10:19 +10:00
nv_fb - > r_pitch = kind ? ( ( ( fb - > pitches [ 0 ] / 4 ) < < 4 ) | tile ) :
( fb - > pitches [ 0 ] | 0x00100000 ) ;
nv_fb - > r_format | = kind < < 16 ;
} else
2014-08-10 04:10:27 +10:00
if ( disp - > disp - > oclass < GF110_DISP ) {
2014-08-10 04:10:19 +10:00
nv_fb - > r_pitch = kind ? ( ( ( fb - > pitches [ 0 ] / 4 ) < < 4 ) | tile ) :
( fb - > pitches [ 0 ] | 0x00100000 ) ;
2014-08-10 04:10:19 +10:00
} else {
2014-08-10 04:10:19 +10:00
nv_fb - > r_pitch = kind ? ( ( ( fb - > pitches [ 0 ] / 4 ) < < 4 ) | tile ) :
( fb - > pitches [ 0 ] | 0x01000000 ) ;
2014-08-10 04:10:19 +10:00
}
2014-08-10 04:10:19 +10:00
nv_fb - > r_handle = 0xffff0000 | kind ;
2014-08-10 04:10:19 +10:00
2014-08-10 04:10:28 +10:00
return nv50_fbdma_init ( fb - > dev , nv_fb - > r_handle , 0 ,
drm - > device . info . ram_user , kind ) ;
2014-08-10 04:10:19 +10:00
}
2011-07-04 16:25:18 +10:00
/******************************************************************************
* Init
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2014-08-10 04:10:19 +10:00
2011-11-09 11:36:33 +10:00
void
2012-11-21 14:40:21 +10:00
nv50_display_fini ( struct drm_device * dev )
2011-07-04 16:25:18 +10:00
{
}
int
2012-11-21 14:40:21 +10:00
nv50_display_init ( struct drm_device * dev )
2011-07-04 16:25:18 +10:00
{
2013-03-02 13:21:31 +10:00
struct nv50_disp * disp = nv50_disp ( dev ) ;
struct drm_crtc * crtc ;
u32 * push ;
push = evo_wait ( nv50_mast ( dev ) , 32 ) ;
if ( ! push )
return - EBUSY ;
list_for_each_entry ( crtc , & dev - > mode_config . crtc_list , head ) {
struct nv50_sync * sync = nv50_sync ( crtc ) ;
2015-01-13 09:18:49 +01:00
nv50_crtc_lut_load ( crtc ) ;
2013-03-02 13:21:31 +10:00
nouveau_bo_wr32 ( disp - > sync , sync - > addr / 4 , sync - > data ) ;
2011-11-12 01:30:24 +10:00
}
2011-07-05 11:58:58 +10:00
2013-03-02 13:21:31 +10:00
evo_mthd ( push , 0x0088 , 1 ) ;
2014-08-10 04:10:23 +10:00
evo_data ( push , nv50_mast ( dev ) - > base . sync . handle ) ;
2013-03-02 13:21:31 +10:00
evo_kick ( push , nv50_mast ( dev ) ) ;
return 0 ;
2011-07-04 16:25:18 +10:00
}
void
2012-11-21 14:40:21 +10:00
nv50_display_destroy ( struct drm_device * dev )
2011-07-04 16:25:18 +10:00
{
2012-11-21 14:40:21 +10:00
struct nv50_disp * disp = nv50_disp ( dev ) ;
2014-08-10 04:10:19 +10:00
struct nv50_fbdma * fbdma , * fbtmp ;
list_for_each_entry_safe ( fbdma , fbtmp , & disp - > fbdma , head ) {
2014-08-10 04:10:22 +10:00
nv50_fbdma_fini ( fbdma ) ;
2014-08-10 04:10:19 +10:00
}
2011-11-12 01:30:24 +10:00
2014-08-10 04:10:22 +10:00
nv50_dmac_destroy ( & disp - > mast . base , disp - > disp ) ;
2011-07-04 16:25:18 +10:00
2011-11-16 15:48:48 +10:00
nouveau_bo_unmap ( disp - > sync ) ;
2012-11-25 23:04:23 +01:00
if ( disp - > sync )
nouveau_bo_unpin ( disp - > sync ) ;
2011-11-16 15:48:48 +10:00
nouveau_bo_ref ( NULL , & disp - > sync ) ;
2011-07-05 10:33:08 +10:00
2012-07-31 16:16:21 +10:00
nouveau_display ( dev ) - > priv = NULL ;
2011-07-04 16:25:18 +10:00
kfree ( disp ) ;
}
int
2012-11-21 14:40:21 +10:00
nv50_display_create ( struct drm_device * dev )
2011-07-04 16:25:18 +10:00
{
2014-08-10 04:10:22 +10:00
struct nvif_device * device = & nouveau_drm ( dev ) - > device ;
2012-07-31 16:16:21 +10:00
struct nouveau_drm * drm = nouveau_drm ( dev ) ;
struct dcb_table * dcb = & drm - > vbios . dcb ;
2011-07-05 13:08:40 +10:00
struct drm_connector * connector , * tmp ;
2012-11-21 14:40:21 +10:00
struct nv50_disp * disp ;
2012-07-11 10:44:20 +10:00
struct dcb_output * dcbe ;
2012-03-04 16:25:59 +10:00
int crtcs , ret , i ;
2011-07-04 16:25:18 +10:00
disp = kzalloc ( sizeof ( * disp ) , GFP_KERNEL ) ;
if ( ! disp )
return - ENOMEM ;
2014-08-10 04:10:19 +10:00
INIT_LIST_HEAD ( & disp - > fbdma ) ;
2012-07-31 16:16:21 +10:00
nouveau_display ( dev ) - > priv = disp ;
2012-11-21 14:40:21 +10:00
nouveau_display ( dev ) - > dtor = nv50_display_destroy ;
nouveau_display ( dev ) - > init = nv50_display_init ;
nouveau_display ( dev ) - > fini = nv50_display_fini ;
2014-08-10 04:10:19 +10:00
nouveau_display ( dev ) - > fb_ctor = nv50_fb_ctor ;
nouveau_display ( dev ) - > fb_dtor = nv50_fb_dtor ;
2014-08-10 04:10:22 +10:00
disp - > disp = & nouveau_display ( dev ) - > disp ;
2011-07-04 16:25:18 +10:00
2012-10-16 14:18:32 +10:00
/* small shared memory area we use for notifiers and semaphores */
ret = nouveau_bo_new ( dev , 4096 , 0x1000 , TTM_PL_FLAG_VRAM ,
2014-01-09 11:03:15 +01:00
0 , 0x0000 , NULL , NULL , & disp - > sync ) ;
2012-10-16 14:18:32 +10:00
if ( ! ret ) {
2014-11-10 12:35:06 +10:00
ret = nouveau_bo_pin ( disp - > sync , TTM_PL_FLAG_VRAM , true ) ;
2012-11-25 23:04:23 +01:00
if ( ! ret ) {
2012-10-16 14:18:32 +10:00
ret = nouveau_bo_map ( disp - > sync ) ;
2012-11-25 23:04:23 +01:00
if ( ret )
nouveau_bo_unpin ( disp - > sync ) ;
}
2012-10-16 14:18:32 +10:00
if ( ret )
nouveau_bo_ref ( NULL , & disp - > sync ) ;
}
if ( ret )
goto out ;
/* allocate master evo channel */
2015-08-20 14:54:15 +10:00
ret = nv50_core_create ( device , disp - > disp , disp - > sync - > bo . offset ,
2014-08-10 04:10:25 +10:00
& disp - > mast ) ;
2012-10-16 14:18:32 +10:00
if ( ret )
goto out ;
2011-07-05 16:48:06 +10:00
/* create crtc objects to represent the hw heads */
2014-08-10 04:10:27 +10:00
if ( disp - > disp - > oclass > = GF110_DISP )
2015-08-20 14:54:15 +10:00
crtcs = nvif_rd32 ( & device - > object , 0x022448 ) ;
2012-11-16 11:44:14 +10:00
else
crtcs = 2 ;
2012-03-04 16:25:59 +10:00
for ( i = 0 ; i < crtcs ; i + + ) {
2014-08-10 04:10:22 +10:00
ret = nv50_crtc_create ( dev , i ) ;
2011-07-05 16:48:06 +10:00
if ( ret )
goto out ;
}
2011-07-05 13:08:40 +10:00
/* create encoder/connector objects based on VBIOS DCB table */
for ( i = 0 , dcbe = & dcb - > entry [ 0 ] ; i < dcb - > entries ; i + + , dcbe + + ) {
connector = nouveau_connector_create ( dev , dcbe - > connector ) ;
if ( IS_ERR ( connector ) )
continue ;
2013-02-11 09:52:58 +10:00
if ( dcbe - > location = = DCB_LOC_ON_CHIP ) {
switch ( dcbe - > type ) {
case DCB_OUTPUT_TMDS :
case DCB_OUTPUT_LVDS :
case DCB_OUTPUT_DP :
ret = nv50_sor_create ( connector , dcbe ) ;
break ;
case DCB_OUTPUT_ANALOG :
ret = nv50_dac_create ( connector , dcbe ) ;
break ;
default :
ret = - ENODEV ;
break ;
}
} else {
ret = nv50_pior_create ( connector , dcbe ) ;
2011-07-05 13:08:40 +10:00
}
2013-02-11 09:52:58 +10:00
if ( ret ) {
NV_WARN ( drm , " failed to create encoder %d/%d/%d: %d \n " ,
dcbe - > location , dcbe - > type ,
ffs ( dcbe - > or ) - 1 , ret ) ;
2013-03-05 22:26:06 +10:00
ret = 0 ;
2011-07-05 13:08:40 +10:00
}
}
/* cull any connectors we created that don't have an encoder */
list_for_each_entry_safe ( connector , tmp , & dev - > mode_config . connector_list , head ) {
if ( connector - > encoder_ids [ 0 ] )
continue ;
2012-07-31 16:16:21 +10:00
NV_WARN ( drm , " %s has no encoders, removing \n " ,
2014-06-03 14:56:18 +03:00
connector - > name ) ;
2011-07-05 13:08:40 +10:00
connector - > funcs - > destroy ( connector ) ;
}
2011-07-04 16:25:18 +10:00
out :
if ( ret )
2012-11-21 14:40:21 +10:00
nv50_display_destroy ( dev ) ;
2011-07-04 16:25:18 +10:00
return ret ;
}