2009-12-11 19:24:15 +10:00
/*
* Copyright 2009 Ben Skeggs
* Copyright 2008 Stuart Bennett
*
* Permission is hereby granted , free of charge , to any person obtaining a
* copy of this software and associated documentation files ( the " Software " ) ,
* to deal in the Software without restriction , including without limitation
* the rights to use , copy , modify , merge , publish , distribute , sublicense ,
* and / or sell copies of the Software , and to permit persons to whom the
* Software is furnished to do so , subject to the following conditions :
*
* The above copyright notice and this permission notice ( including the next
* paragraph ) shall be included in all copies or substantial portions of the
* Software .
*
* THE SOFTWARE IS PROVIDED " AS IS " , WITHOUT WARRANTY OF ANY KIND , EXPRESS OR
* IMPLIED , INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY ,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT . IN NO EVENT SHALL
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM , DAMAGES OR OTHER
* LIABILITY , WHETHER IN AN ACTION OF CONTRACT , TORT OR OTHERWISE , ARISING
* FROM , OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
* DEALINGS IN THE SOFTWARE .
*/
2012-07-20 08:17:34 +10:00
# include "nouveau_drm.h"
2009-12-11 19:24:15 +10:00
# include "nouveau_dma.h"
# include "nouveau_fbcon.h"
2010-10-05 16:41:29 +10:00
int
2009-12-11 19:24:15 +10:00
nv04_fbcon_copyarea ( struct fb_info * info , const struct fb_copyarea * region )
{
2010-03-30 05:34:14 +00:00
struct nouveau_fbdev * nfbdev = info - > par ;
2012-07-31 16:16:21 +10:00
struct nouveau_drm * drm = nouveau_drm ( nfbdev - > dev ) ;
2012-07-20 08:17:34 +10:00
struct nouveau_channel * chan = drm - > channel ;
2010-10-05 16:41:29 +10:00
int ret ;
2009-12-11 19:24:15 +10:00
2010-10-05 16:41:29 +10:00
ret = RING_SPACE ( chan , 4 ) ;
if ( ret )
return ret ;
2009-12-11 19:24:15 +10:00
2012-04-01 21:09:13 +10:00
BEGIN_NV04 ( chan , NvSubImageBlit , 0x0300 , 3 ) ;
2009-12-11 19:24:15 +10:00
OUT_RING ( chan , ( region - > sy < < 16 ) | region - > sx ) ;
OUT_RING ( chan , ( region - > dy < < 16 ) | region - > dx ) ;
OUT_RING ( chan , ( region - > height < < 16 ) | region - > width ) ;
FIRE_RING ( chan ) ;
2010-10-05 16:41:29 +10:00
return 0 ;
2009-12-11 19:24:15 +10:00
}
2010-10-05 16:41:29 +10:00
int
2009-12-11 19:24:15 +10:00
nv04_fbcon_fillrect ( struct fb_info * info , const struct fb_fillrect * rect )
{
2010-03-30 05:34:14 +00:00
struct nouveau_fbdev * nfbdev = info - > par ;
2012-07-31 16:16:21 +10:00
struct nouveau_drm * drm = nouveau_drm ( nfbdev - > dev ) ;
2012-07-20 08:17:34 +10:00
struct nouveau_channel * chan = drm - > channel ;
2010-10-05 16:41:29 +10:00
int ret ;
2009-12-11 19:24:15 +10:00
2010-10-05 16:41:29 +10:00
ret = RING_SPACE ( chan , 7 ) ;
if ( ret )
return ret ;
2009-12-11 19:24:15 +10:00
2012-04-01 21:09:13 +10:00
BEGIN_NV04 ( chan , NvSubGdiRect , 0x02fc , 1 ) ;
2009-12-11 19:24:15 +10:00
OUT_RING ( chan , ( rect - > rop ! = ROP_COPY ) ? 1 : 3 ) ;
2012-04-01 21:09:13 +10:00
BEGIN_NV04 ( chan , NvSubGdiRect , 0x03fc , 1 ) ;
2010-01-04 09:10:55 +10:00
if ( info - > fix . visual = = FB_VISUAL_TRUECOLOR | |
info - > fix . visual = = FB_VISUAL_DIRECTCOLOR )
OUT_RING ( chan , ( ( uint32_t * ) info - > pseudo_palette ) [ rect - > color ] ) ;
else
OUT_RING ( chan , rect - > color ) ;
2012-04-01 21:09:13 +10:00
BEGIN_NV04 ( chan , NvSubGdiRect , 0x0400 , 2 ) ;
2009-12-11 19:24:15 +10:00
OUT_RING ( chan , ( rect - > dx < < 16 ) | rect - > dy ) ;
OUT_RING ( chan , ( rect - > width < < 16 ) | rect - > height ) ;
FIRE_RING ( chan ) ;
2010-10-05 16:41:29 +10:00
return 0 ;
2009-12-11 19:24:15 +10:00
}
2010-10-05 16:41:29 +10:00
int
2009-12-11 19:24:15 +10:00
nv04_fbcon_imageblit ( struct fb_info * info , const struct fb_image * image )
{
2010-03-30 05:34:14 +00:00
struct nouveau_fbdev * nfbdev = info - > par ;
2012-07-31 16:16:21 +10:00
struct nouveau_drm * drm = nouveau_drm ( nfbdev - > dev ) ;
2012-07-20 08:17:34 +10:00
struct nouveau_channel * chan = drm - > channel ;
2009-12-11 19:24:15 +10:00
uint32_t fg ;
uint32_t bg ;
uint32_t dsize ;
uint32_t width ;
uint32_t * data = ( uint32_t * ) image - > data ;
2010-10-05 16:41:29 +10:00
int ret ;
2009-12-11 19:24:15 +10:00
2010-10-05 16:41:29 +10:00
if ( image - > depth ! = 1 )
return - ENODEV ;
2009-12-11 19:24:15 +10:00
2010-10-05 16:41:29 +10:00
ret = RING_SPACE ( chan , 8 ) ;
if ( ret )
return ret ;
2009-12-11 19:24:15 +10:00
2010-02-27 18:13:35 +00:00
width = ALIGN ( image - > width , 8 ) ;
dsize = ALIGN ( width * image - > height , 32 ) > > 5 ;
2009-12-11 19:24:15 +10:00
if ( info - > fix . visual = = FB_VISUAL_TRUECOLOR | |
info - > fix . visual = = FB_VISUAL_DIRECTCOLOR ) {
fg = ( ( uint32_t * ) info - > pseudo_palette ) [ image - > fg_color ] ;
bg = ( ( uint32_t * ) info - > pseudo_palette ) [ image - > bg_color ] ;
} else {
fg = image - > fg_color ;
bg = image - > bg_color ;
}
2012-04-01 21:09:13 +10:00
BEGIN_NV04 ( chan , NvSubGdiRect , 0x0be4 , 7 ) ;
2009-12-11 19:24:15 +10:00
OUT_RING ( chan , ( image - > dy < < 16 ) | ( image - > dx & 0xffff ) ) ;
OUT_RING ( chan , ( ( image - > dy + image - > height ) < < 16 ) |
( ( image - > dx + image - > width ) & 0xffff ) ) ;
OUT_RING ( chan , bg ) ;
OUT_RING ( chan , fg ) ;
OUT_RING ( chan , ( image - > height < < 16 ) | width ) ;
2010-02-27 18:13:35 +00:00
OUT_RING ( chan , ( image - > height < < 16 ) | image - > width ) ;
2009-12-11 19:24:15 +10:00
OUT_RING ( chan , ( image - > dy < < 16 ) | ( image - > dx & 0xffff ) ) ;
while ( dsize ) {
int iter_len = dsize > 128 ? 128 : dsize ;
2010-10-05 16:41:29 +10:00
ret = RING_SPACE ( chan , iter_len + 1 ) ;
if ( ret )
return ret ;
2009-12-11 19:24:15 +10:00
2012-04-01 21:09:13 +10:00
BEGIN_NV04 ( chan , NvSubGdiRect , 0x0c00 , iter_len ) ;
2009-12-11 19:24:15 +10:00
OUT_RINGp ( chan , data , iter_len ) ;
data + = iter_len ;
dsize - = iter_len ;
}
FIRE_RING ( chan ) ;
2010-10-05 16:41:29 +10:00
return 0 ;
2009-12-11 19:24:15 +10:00
}
int
nv04_fbcon_accel_init ( struct fb_info * info )
{
2010-03-30 05:34:14 +00:00
struct nouveau_fbdev * nfbdev = info - > par ;
struct drm_device * dev = nfbdev - > dev ;
2012-07-31 16:16:21 +10:00
struct nouveau_drm * drm = nouveau_drm ( dev ) ;
2012-07-20 08:17:34 +10:00
struct nouveau_channel * chan = drm - > channel ;
2014-08-10 04:10:22 +10:00
struct nvif_device * device = & drm - > device ;
2009-12-11 19:24:15 +10:00
int surface_fmt , pattern_fmt , rect_fmt ;
int ret ;
switch ( info - > var . bits_per_pixel ) {
case 8 :
surface_fmt = 1 ;
pattern_fmt = 3 ;
rect_fmt = 3 ;
break ;
case 16 :
surface_fmt = 4 ;
pattern_fmt = 1 ;
rect_fmt = 1 ;
break ;
case 32 :
switch ( info - > var . transp . length ) {
case 0 : /* depth 24 */
case 8 : /* depth 32 */
break ;
default :
return - EINVAL ;
}
surface_fmt = 6 ;
pattern_fmt = 3 ;
rect_fmt = 3 ;
break ;
default :
return - EINVAL ;
}
2015-08-20 14:54:15 +10:00
ret = nvif_object_init ( & chan - > user , 0x0062 ,
2014-08-10 04:10:22 +10:00
device - > info . family > = NV_DEVICE_INFO_V0_CELSIUS ?
0x0062 : 0x0042 , NULL , 0 , & nfbdev - > surf2d ) ;
2009-12-11 19:24:15 +10:00
if ( ret )
return ret ;
2015-08-20 14:54:15 +10:00
ret = nvif_object_init ( & chan - > user , 0x0019 , 0x0019 , NULL , 0 ,
2014-08-10 04:10:22 +10:00
& nfbdev - > clip ) ;
2009-12-11 19:24:15 +10:00
if ( ret )
return ret ;
2015-08-20 14:54:15 +10:00
ret = nvif_object_init ( & chan - > user , 0x0043 , 0x0043 , NULL , 0 ,
2014-08-10 04:10:22 +10:00
& nfbdev - > rop ) ;
2009-12-11 19:24:15 +10:00
if ( ret )
return ret ;
2015-08-20 14:54:15 +10:00
ret = nvif_object_init ( & chan - > user , 0x0044 , 0x0044 , NULL , 0 ,
2014-08-10 04:10:22 +10:00
& nfbdev - > patt ) ;
2009-12-11 19:24:15 +10:00
if ( ret )
return ret ;
2015-08-20 14:54:15 +10:00
ret = nvif_object_init ( & chan - > user , 0x004a , 0x004a , NULL , 0 ,
2014-08-10 04:10:22 +10:00
& nfbdev - > gdi ) ;
2009-12-11 19:24:15 +10:00
if ( ret )
return ret ;
2015-08-20 14:54:15 +10:00
ret = nvif_object_init ( & chan - > user , 0x005f ,
2014-08-10 04:10:22 +10:00
device - > info . chipset > = 0x11 ? 0x009f : 0x005f ,
NULL , 0 , & nfbdev - > blit ) ;
2009-12-11 19:24:15 +10:00
if ( ret )
return ret ;
2015-06-29 04:07:20 -04:00
if ( RING_SPACE ( chan , 49 + ( device - > info . chipset > = 0x11 ? 4 : 0 ) ) ) {
2010-01-04 19:25:09 +01:00
nouveau_fbcon_gpu_lockup ( info ) ;
2009-12-11 19:24:15 +10:00
return 0 ;
}
2012-07-20 08:17:34 +10:00
BEGIN_NV04 ( chan , NvSubCtxSurf2D , 0x0000 , 1 ) ;
2014-08-10 04:10:23 +10:00
OUT_RING ( chan , nfbdev - > surf2d . handle ) ;
2012-07-20 08:17:34 +10:00
BEGIN_NV04 ( chan , NvSubCtxSurf2D , 0x0184 , 2 ) ;
2014-08-10 04:10:23 +10:00
OUT_RING ( chan , chan - > vram . handle ) ;
OUT_RING ( chan , chan - > vram . handle ) ;
2012-07-20 08:17:34 +10:00
BEGIN_NV04 ( chan , NvSubCtxSurf2D , 0x0300 , 4 ) ;
2009-12-11 19:24:15 +10:00
OUT_RING ( chan , surface_fmt ) ;
OUT_RING ( chan , info - > fix . line_length | ( info - > fix . line_length < < 16 ) ) ;
OUT_RING ( chan , info - > fix . smem_start - dev - > mode_config . fb_base ) ;
OUT_RING ( chan , info - > fix . smem_start - dev - > mode_config . fb_base ) ;
2012-07-20 08:17:34 +10:00
BEGIN_NV04 ( chan , NvSubCtxSurf2D , 0x0000 , 1 ) ;
2014-08-10 04:10:23 +10:00
OUT_RING ( chan , nfbdev - > rop . handle ) ;
2012-07-20 08:17:34 +10:00
BEGIN_NV04 ( chan , NvSubCtxSurf2D , 0x0300 , 1 ) ;
2009-12-11 19:24:15 +10:00
OUT_RING ( chan , 0x55 ) ;
2012-07-20 08:17:34 +10:00
BEGIN_NV04 ( chan , NvSubCtxSurf2D , 0x0000 , 1 ) ;
2014-08-10 04:10:23 +10:00
OUT_RING ( chan , nfbdev - > patt . handle ) ;
2012-07-20 08:17:34 +10:00
BEGIN_NV04 ( chan , NvSubCtxSurf2D , 0x0300 , 8 ) ;
2009-12-11 19:24:15 +10:00
OUT_RING ( chan , pattern_fmt ) ;
# ifdef __BIG_ENDIAN
OUT_RING ( chan , 2 ) ;
# else
OUT_RING ( chan , 1 ) ;
# endif
OUT_RING ( chan , 0 ) ;
OUT_RING ( chan , 1 ) ;
OUT_RING ( chan , ~ 0 ) ;
OUT_RING ( chan , ~ 0 ) ;
OUT_RING ( chan , ~ 0 ) ;
OUT_RING ( chan , ~ 0 ) ;
2012-07-20 08:17:34 +10:00
BEGIN_NV04 ( chan , NvSubCtxSurf2D , 0x0000 , 1 ) ;
2014-08-10 04:10:23 +10:00
OUT_RING ( chan , nfbdev - > clip . handle ) ;
2012-07-20 08:17:34 +10:00
BEGIN_NV04 ( chan , NvSubCtxSurf2D , 0x0300 , 2 ) ;
2009-12-11 19:24:15 +10:00
OUT_RING ( chan , 0 ) ;
OUT_RING ( chan , ( info - > var . yres_virtual < < 16 ) | info - > var . xres_virtual ) ;
2012-04-01 21:09:13 +10:00
BEGIN_NV04 ( chan , NvSubImageBlit , 0x0000 , 1 ) ;
2014-08-10 04:10:23 +10:00
OUT_RING ( chan , nfbdev - > blit . handle ) ;
2012-04-01 21:09:13 +10:00
BEGIN_NV04 ( chan , NvSubImageBlit , 0x019c , 1 ) ;
2014-08-10 04:10:23 +10:00
OUT_RING ( chan , nfbdev - > surf2d . handle ) ;
2012-04-01 21:09:13 +10:00
BEGIN_NV04 ( chan , NvSubImageBlit , 0x02fc , 1 ) ;
2009-12-11 19:24:15 +10:00
OUT_RING ( chan , 3 ) ;
2014-08-10 04:10:22 +10:00
if ( device - > info . chipset > = 0x11 /*XXX: oclass == 0x009f*/ ) {
2013-11-11 13:59:40 +10:00
BEGIN_NV04 ( chan , NvSubImageBlit , 0x0120 , 3 ) ;
OUT_RING ( chan , 0 ) ;
OUT_RING ( chan , 1 ) ;
OUT_RING ( chan , 2 ) ;
}
2009-12-11 19:24:15 +10:00
2012-04-01 21:09:13 +10:00
BEGIN_NV04 ( chan , NvSubGdiRect , 0x0000 , 1 ) ;
2014-08-10 04:10:23 +10:00
OUT_RING ( chan , nfbdev - > gdi . handle ) ;
2012-04-01 21:09:13 +10:00
BEGIN_NV04 ( chan , NvSubGdiRect , 0x0198 , 1 ) ;
2014-08-10 04:10:23 +10:00
OUT_RING ( chan , nfbdev - > surf2d . handle ) ;
2012-04-01 21:09:13 +10:00
BEGIN_NV04 ( chan , NvSubGdiRect , 0x0188 , 2 ) ;
2014-08-10 04:10:23 +10:00
OUT_RING ( chan , nfbdev - > patt . handle ) ;
OUT_RING ( chan , nfbdev - > rop . handle ) ;
2012-04-01 21:09:13 +10:00
BEGIN_NV04 ( chan , NvSubGdiRect , 0x0304 , 1 ) ;
2009-12-11 19:24:15 +10:00
OUT_RING ( chan , 1 ) ;
2012-04-01 21:09:13 +10:00
BEGIN_NV04 ( chan , NvSubGdiRect , 0x0300 , 1 ) ;
2009-12-11 19:24:15 +10:00
OUT_RING ( chan , rect_fmt ) ;
2012-04-01 21:09:13 +10:00
BEGIN_NV04 ( chan , NvSubGdiRect , 0x02fc , 1 ) ;
2009-12-11 19:24:15 +10:00
OUT_RING ( chan , 3 ) ;
FIRE_RING ( chan ) ;
return 0 ;
}