2010-11-24 03:52:43 +03:00
/*
* Copyright 2010 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
*/
2016-05-20 02:22:55 +03:00
# include "nouveau_drv.h"
2010-11-24 03:52:43 +03:00
# include "nouveau_dma.h"
# include "nouveau_fbcon.h"
int
nvc0_fbcon_fillrect ( struct fb_info * info , const struct fb_fillrect * rect )
{
struct nouveau_fbdev * nfbdev = info - > par ;
2016-11-04 10:20:35 +03:00
struct nouveau_drm * drm = nouveau_drm ( nfbdev - > helper . dev ) ;
2012-07-20 02:17:34 +04:00
struct nouveau_channel * chan = drm - > channel ;
2010-11-24 03:52:43 +03:00
int ret ;
ret = RING_SPACE ( chan , rect - > rop = = ROP_COPY ? 7 : 11 ) ;
if ( ret )
return ret ;
if ( rect - > rop ! = ROP_COPY ) {
2012-04-01 15:09:13 +04:00
BEGIN_NVC0 ( chan , NvSub2D , 0x02ac , 1 ) ;
2010-11-24 03:52:43 +03:00
OUT_RING ( chan , 1 ) ;
}
2012-04-01 15:09:13 +04:00
BEGIN_NVC0 ( chan , NvSub2D , 0x0588 , 1 ) ;
2010-11-24 03:52:43 +03: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 15:09:13 +04:00
BEGIN_NVC0 ( chan , NvSub2D , 0x0600 , 4 ) ;
2010-11-24 03:52:43 +03:00
OUT_RING ( chan , rect - > dx ) ;
OUT_RING ( chan , rect - > dy ) ;
OUT_RING ( chan , rect - > dx + rect - > width ) ;
OUT_RING ( chan , rect - > dy + rect - > height ) ;
if ( rect - > rop ! = ROP_COPY ) {
2012-04-01 15:09:13 +04:00
BEGIN_NVC0 ( chan , NvSub2D , 0x02ac , 1 ) ;
2010-11-24 03:52:43 +03:00
OUT_RING ( chan , 3 ) ;
}
FIRE_RING ( chan ) ;
return 0 ;
}
int
nvc0_fbcon_copyarea ( struct fb_info * info , const struct fb_copyarea * region )
{
struct nouveau_fbdev * nfbdev = info - > par ;
2016-11-04 10:20:35 +03:00
struct nouveau_drm * drm = nouveau_drm ( nfbdev - > helper . dev ) ;
2012-07-20 02:17:34 +04:00
struct nouveau_channel * chan = drm - > channel ;
2010-11-24 03:52:43 +03:00
int ret ;
ret = RING_SPACE ( chan , 12 ) ;
if ( ret )
return ret ;
2012-04-01 15:09:13 +04:00
BEGIN_NVC0 ( chan , NvSub2D , 0x0110 , 1 ) ;
2010-11-24 03:52:43 +03:00
OUT_RING ( chan , 0 ) ;
2012-04-01 15:09:13 +04:00
BEGIN_NVC0 ( chan , NvSub2D , 0x08b0 , 4 ) ;
2010-11-24 03:52:43 +03:00
OUT_RING ( chan , region - > dx ) ;
OUT_RING ( chan , region - > dy ) ;
OUT_RING ( chan , region - > width ) ;
OUT_RING ( chan , region - > height ) ;
2012-04-01 15:09:13 +04:00
BEGIN_NVC0 ( chan , NvSub2D , 0x08d0 , 4 ) ;
2010-11-24 03:52:43 +03:00
OUT_RING ( chan , 0 ) ;
OUT_RING ( chan , region - > sx ) ;
OUT_RING ( chan , 0 ) ;
OUT_RING ( chan , region - > sy ) ;
FIRE_RING ( chan ) ;
return 0 ;
}
int
nvc0_fbcon_imageblit ( struct fb_info * info , const struct fb_image * image )
{
struct nouveau_fbdev * nfbdev = info - > par ;
2016-11-04 10:20:35 +03:00
struct nouveau_drm * drm = nouveau_drm ( nfbdev - > helper . dev ) ;
2012-07-20 02:17:34 +04:00
struct nouveau_channel * chan = drm - > channel ;
2016-06-02 05:23:31 +03:00
uint32_t dwords , * data = ( uint32_t * ) image - > data ;
2010-11-24 03:52:43 +03:00
uint32_t mask = ~ ( ~ 0 > > ( 32 - info - > var . bits_per_pixel ) ) ;
uint32_t * palette = info - > pseudo_palette ;
int ret ;
if ( image - > depth ! = 1 )
return - ENODEV ;
ret = RING_SPACE ( chan , 11 ) ;
if ( ret )
return ret ;
2012-04-01 15:09:13 +04:00
BEGIN_NVC0 ( chan , NvSub2D , 0x0814 , 2 ) ;
2010-11-24 03:52:43 +03:00
if ( info - > fix . visual = = FB_VISUAL_TRUECOLOR | |
info - > fix . visual = = FB_VISUAL_DIRECTCOLOR ) {
OUT_RING ( chan , palette [ image - > bg_color ] | mask ) ;
OUT_RING ( chan , palette [ image - > fg_color ] | mask ) ;
} else {
OUT_RING ( chan , image - > bg_color ) ;
OUT_RING ( chan , image - > fg_color ) ;
}
2012-04-01 15:09:13 +04:00
BEGIN_NVC0 ( chan , NvSub2D , 0x0838 , 2 ) ;
2010-11-24 03:52:43 +03:00
OUT_RING ( chan , image - > width ) ;
OUT_RING ( chan , image - > height ) ;
2012-04-01 15:09:13 +04:00
BEGIN_NVC0 ( chan , NvSub2D , 0x0850 , 4 ) ;
2010-11-24 03:52:43 +03:00
OUT_RING ( chan , 0 ) ;
OUT_RING ( chan , image - > dx ) ;
OUT_RING ( chan , 0 ) ;
OUT_RING ( chan , image - > dy ) ;
2016-07-29 01:56:13 +03:00
dwords = ALIGN ( ALIGN ( image - > width , 8 ) * image - > height , 32 ) > > 5 ;
2010-11-24 03:52:43 +03:00
while ( dwords ) {
int push = dwords > 2047 ? 2047 : dwords ;
ret = RING_SPACE ( chan , push + 1 ) ;
if ( ret )
return ret ;
dwords - = push ;
2012-04-01 15:09:13 +04:00
BEGIN_NIC0 ( chan , NvSub2D , 0x0860 , push ) ;
2010-11-24 03:52:43 +03:00
OUT_RINGp ( chan , data , push ) ;
data + = push ;
}
FIRE_RING ( chan ) ;
return 0 ;
}
int
nvc0_fbcon_accel_init ( struct fb_info * info )
{
struct nouveau_fbdev * nfbdev = info - > par ;
2016-11-04 10:20:35 +03:00
struct drm_device * dev = nfbdev - > helper . dev ;
2011-06-07 07:12:44 +04:00
struct nouveau_framebuffer * fb = & nfbdev - > nouveau_fb ;
2012-07-31 10:16:21 +04:00
struct nouveau_drm * drm = nouveau_drm ( dev ) ;
2012-07-20 02:17:34 +04:00
struct nouveau_channel * chan = drm - > channel ;
2010-11-24 03:52:43 +03:00
int ret , format ;
2015-08-20 07:54:15 +03:00
ret = nvif_object_init ( & chan - > user , 0x902d , 0x902d , NULL , 0 ,
2014-08-09 22:10:22 +04:00
& nfbdev - > twod ) ;
2010-11-24 03:52:43 +03:00
if ( ret )
return ret ;
switch ( info - > var . bits_per_pixel ) {
case 8 :
format = 0xf3 ;
break ;
case 15 :
format = 0xf8 ;
break ;
case 16 :
format = 0xe8 ;
break ;
case 32 :
switch ( info - > var . transp . length ) {
case 0 : /* depth 24 */
case 8 : /* depth 32, just use 24.. */
format = 0xe6 ;
break ;
case 2 : /* depth 30 */
format = 0xd1 ;
break ;
default :
return - EINVAL ;
}
break ;
default :
return - EINVAL ;
}
2015-06-30 03:43:46 +03:00
ret = RING_SPACE ( chan , 58 ) ;
2010-11-24 03:52:43 +03:00
if ( ret ) {
WARN_ON ( 1 ) ;
nouveau_fbcon_gpu_lockup ( info ) ;
return ret ;
}
2012-04-01 15:09:13 +04:00
BEGIN_NVC0 ( chan , NvSub2D , 0x0000 , 1 ) ;
2014-08-09 22:10:23 +04:00
OUT_RING ( chan , nfbdev - > twod . handle ) ;
2012-04-01 15:09:13 +04:00
BEGIN_NVC0 ( chan , NvSub2D , 0x0290 , 1 ) ;
2010-11-24 03:52:43 +03:00
OUT_RING ( chan , 0 ) ;
2012-04-01 15:09:13 +04:00
BEGIN_NVC0 ( chan , NvSub2D , 0x0888 , 1 ) ;
2010-11-24 03:52:43 +03:00
OUT_RING ( chan , 1 ) ;
2012-04-01 15:09:13 +04:00
BEGIN_NVC0 ( chan , NvSub2D , 0x02ac , 1 ) ;
2010-11-24 03:52:43 +03:00
OUT_RING ( chan , 3 ) ;
2012-04-01 15:09:13 +04:00
BEGIN_NVC0 ( chan , NvSub2D , 0x02a0 , 1 ) ;
2010-11-24 03:52:43 +03:00
OUT_RING ( chan , 0x55 ) ;
2012-04-01 15:09:13 +04:00
BEGIN_NVC0 ( chan , NvSub2D , 0x08c0 , 4 ) ;
2010-11-24 03:52:43 +03:00
OUT_RING ( chan , 0 ) ;
OUT_RING ( chan , 1 ) ;
OUT_RING ( chan , 0 ) ;
OUT_RING ( chan , 1 ) ;
2012-04-01 15:09:13 +04:00
BEGIN_NVC0 ( chan , NvSub2D , 0x0580 , 2 ) ;
2010-11-24 03:52:43 +03:00
OUT_RING ( chan , 4 ) ;
OUT_RING ( chan , format ) ;
2012-04-01 15:09:13 +04:00
BEGIN_NVC0 ( chan , NvSub2D , 0x02e8 , 2 ) ;
2010-11-24 03:52:43 +03:00
OUT_RING ( chan , 2 ) ;
OUT_RING ( chan , 1 ) ;
2012-04-01 15:09:13 +04:00
BEGIN_NVC0 ( chan , NvSub2D , 0x0804 , 1 ) ;
2010-11-24 03:52:43 +03:00
OUT_RING ( chan , format ) ;
2012-04-01 15:09:13 +04:00
BEGIN_NVC0 ( chan , NvSub2D , 0x0800 , 1 ) ;
2010-11-24 03:52:43 +03:00
OUT_RING ( chan , 1 ) ;
2012-04-01 15:09:13 +04:00
BEGIN_NVC0 ( chan , NvSub2D , 0x0808 , 3 ) ;
2010-11-24 03:52:43 +03:00
OUT_RING ( chan , 0 ) ;
OUT_RING ( chan , 0 ) ;
OUT_RING ( chan , 1 ) ;
2012-04-01 15:09:13 +04:00
BEGIN_NVC0 ( chan , NvSub2D , 0x081c , 1 ) ;
2010-11-24 03:52:43 +03:00
OUT_RING ( chan , 1 ) ;
2012-04-01 15:09:13 +04:00
BEGIN_NVC0 ( chan , NvSub2D , 0x0840 , 4 ) ;
2010-11-24 03:52:43 +03:00
OUT_RING ( chan , 0 ) ;
OUT_RING ( chan , 1 ) ;
OUT_RING ( chan , 0 ) ;
OUT_RING ( chan , 1 ) ;
2012-04-01 15:09:13 +04:00
BEGIN_NVC0 ( chan , NvSub2D , 0x0200 , 10 ) ;
2010-11-24 03:52:43 +03:00
OUT_RING ( chan , format ) ;
OUT_RING ( chan , 1 ) ;
OUT_RING ( chan , 0 ) ;
OUT_RING ( chan , 1 ) ;
OUT_RING ( chan , 0 ) ;
OUT_RING ( chan , info - > fix . line_length ) ;
OUT_RING ( chan , info - > var . xres_virtual ) ;
OUT_RING ( chan , info - > var . yres_virtual ) ;
2011-06-07 07:12:44 +04:00
OUT_RING ( chan , upper_32_bits ( fb - > vma . offset ) ) ;
OUT_RING ( chan , lower_32_bits ( fb - > vma . offset ) ) ;
2012-04-01 15:09:13 +04:00
BEGIN_NVC0 ( chan , NvSub2D , 0x0230 , 10 ) ;
2010-11-24 03:52:43 +03:00
OUT_RING ( chan , format ) ;
OUT_RING ( chan , 1 ) ;
OUT_RING ( chan , 0 ) ;
OUT_RING ( chan , 1 ) ;
OUT_RING ( chan , 0 ) ;
OUT_RING ( chan , info - > fix . line_length ) ;
OUT_RING ( chan , info - > var . xres_virtual ) ;
OUT_RING ( chan , info - > var . yres_virtual ) ;
2011-06-07 07:12:44 +04:00
OUT_RING ( chan , upper_32_bits ( fb - > vma . offset ) ) ;
OUT_RING ( chan , lower_32_bits ( fb - > vma . offset ) ) ;
2010-11-24 03:52:43 +03:00
FIRE_RING ( chan ) ;
return 0 ;
}