2009-12-11 19:24:15 +10:00
/*
* Copyright ( C ) 2009 Red Hat < mjg @ redhat . com >
*
* 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 COPYRIGHT OWNER ( S ) AND / OR ITS SUPPLIERS 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 :
* Matthew Garrett < mjg @ redhat . com >
*
* Register locations derived from NVClock by Roderick Colenbrander
*/
# include <linux/backlight.h>
2012-07-26 09:12:47 +10:00
# include "nouveau_drm.h"
2009-12-11 19:24:15 +10:00
# include "nouveau_reg.h"
2011-08-02 19:29:37 +10:00
# include "nouveau_encoder.h"
2009-12-11 19:24:15 +10:00
2011-08-02 18:54:43 +10:00
static int
nv40_get_intensity ( struct backlight_device * bd )
2009-12-11 19:24:15 +10:00
{
2012-07-26 09:12:47 +10:00
struct nouveau_drm * drm = bl_get_data ( bd ) ;
2015-08-20 14:54:15 +10:00
struct nvif_object * device = & drm - > device . object ;
2014-08-10 04:10:22 +10:00
int val = ( nvif_rd32 ( device , NV40_PMC_BACKLIGHT ) &
2012-07-26 09:12:47 +10:00
NV40_PMC_BACKLIGHT_MASK ) > > 16 ;
2009-12-11 19:24:15 +10:00
return val ;
}
2011-08-02 18:54:43 +10:00
static int
nv40_set_intensity ( struct backlight_device * bd )
2009-12-11 19:24:15 +10:00
{
2012-07-26 09:12:47 +10:00
struct nouveau_drm * drm = bl_get_data ( bd ) ;
2015-08-20 14:54:15 +10:00
struct nvif_object * device = & drm - > device . object ;
2009-12-11 19:24:15 +10:00
int val = bd - > props . brightness ;
2014-08-10 04:10:22 +10:00
int reg = nvif_rd32 ( device , NV40_PMC_BACKLIGHT ) ;
2009-12-11 19:24:15 +10:00
2014-08-10 04:10:22 +10:00
nvif_wr32 ( device , NV40_PMC_BACKLIGHT ,
2009-12-11 19:24:15 +10:00
( val < < 16 ) | ( reg & ~ NV40_PMC_BACKLIGHT_MASK ) ) ;
return 0 ;
}
2010-11-16 14:14:02 +01:00
static const struct backlight_ops nv40_bl_ops = {
2009-12-11 19:24:15 +10:00
. options = BL_CORE_SUSPENDRESUME ,
. get_brightness = nv40_get_intensity ,
. update_status = nv40_set_intensity ,
} ;
2011-08-02 18:54:43 +10:00
static int
nv40_backlight_init ( struct drm_connector * connector )
2009-12-11 19:24:15 +10:00
{
2012-07-31 16:16:21 +10:00
struct nouveau_drm * drm = nouveau_drm ( connector - > dev ) ;
2015-08-20 14:54:15 +10:00
struct nvif_object * device = & drm - > device . object ;
2011-03-22 16:30:24 -07:00
struct backlight_properties props ;
2009-12-11 19:24:15 +10:00
struct backlight_device * bd ;
2014-08-10 04:10:22 +10:00
if ( ! ( nvif_rd32 ( device , NV40_PMC_BACKLIGHT ) & NV40_PMC_BACKLIGHT_MASK ) )
2009-12-11 19:24:15 +10:00
return 0 ;
2010-02-17 16:39:44 -05:00
memset ( & props , 0 , sizeof ( struct backlight_properties ) ) ;
2011-03-22 16:30:21 -07:00
props . type = BACKLIGHT_RAW ;
2010-02-17 16:39:44 -05:00
props . max_brightness = 31 ;
2013-10-11 14:07:25 +10:00
bd = backlight_device_register ( " nv_backlight " , connector - > kdev , drm ,
2010-02-17 16:39:44 -05:00
& nv40_bl_ops , & props ) ;
2013-01-27 17:13:52 +01:00
if ( IS_ERR ( bd ) )
return PTR_ERR ( bd ) ;
2012-07-26 09:12:47 +10:00
drm - > backlight = bd ;
2009-12-11 19:24:15 +10:00
bd - > props . brightness = nv40_get_intensity ( bd ) ;
backlight_update_status ( bd ) ;
return 0 ;
}
2011-08-02 18:54:43 +10:00
static int
nv50_get_intensity ( struct backlight_device * bd )
{
2011-08-02 19:29:37 +10:00
struct nouveau_encoder * nv_encoder = bl_get_data ( bd ) ;
2012-07-31 16:16:21 +10:00
struct nouveau_drm * drm = nouveau_drm ( nv_encoder - > base . base . dev ) ;
2015-08-20 14:54:15 +10:00
struct nvif_object * device = & drm - > device . object ;
2011-08-02 19:29:37 +10:00
int or = nv_encoder - > or ;
2011-08-02 20:45:35 +10:00
u32 div = 1025 ;
u32 val ;
2011-08-02 18:54:43 +10:00
2014-08-10 04:10:22 +10:00
val = nvif_rd32 ( device , NV50_PDISP_SOR_PWM_CTL ( or ) ) ;
2011-08-03 08:52:39 +10:00
val & = NV50_PDISP_SOR_PWM_CTL_VAL ;
2011-08-02 20:45:35 +10:00
return ( ( val * 100 ) + ( div / 2 ) ) / div ;
2011-08-02 18:54:43 +10:00
}
static int
nv50_set_intensity ( struct backlight_device * bd )
{
2011-08-02 19:29:37 +10:00
struct nouveau_encoder * nv_encoder = bl_get_data ( bd ) ;
2012-07-31 16:16:21 +10:00
struct nouveau_drm * drm = nouveau_drm ( nv_encoder - > base . base . dev ) ;
2015-08-20 14:54:15 +10:00
struct nvif_object * device = & drm - > device . object ;
2011-08-02 19:29:37 +10:00
int or = nv_encoder - > or ;
2011-08-02 20:45:35 +10:00
u32 div = 1025 ;
u32 val = ( bd - > props . brightness * div ) / 100 ;
2011-08-02 18:54:43 +10:00
2014-08-10 04:10:22 +10:00
nvif_wr32 ( device , NV50_PDISP_SOR_PWM_CTL ( or ) ,
2012-07-26 09:12:47 +10:00
NV50_PDISP_SOR_PWM_CTL_NEW | val ) ;
2011-08-02 18:54:43 +10:00
return 0 ;
}
static const struct backlight_ops nv50_bl_ops = {
. options = BL_CORE_SUSPENDRESUME ,
. get_brightness = nv50_get_intensity ,
. update_status = nv50_set_intensity ,
} ;
2011-08-03 08:52:39 +10:00
static int
nva3_get_intensity ( struct backlight_device * bd )
{
struct nouveau_encoder * nv_encoder = bl_get_data ( bd ) ;
2012-07-31 16:16:21 +10:00
struct nouveau_drm * drm = nouveau_drm ( nv_encoder - > base . base . dev ) ;
2015-08-20 14:54:15 +10:00
struct nvif_object * device = & drm - > device . object ;
2011-08-03 08:52:39 +10:00
int or = nv_encoder - > or ;
u32 div , val ;
2014-08-10 04:10:22 +10:00
div = nvif_rd32 ( device , NV50_PDISP_SOR_PWM_DIV ( or ) ) ;
val = nvif_rd32 ( device , NV50_PDISP_SOR_PWM_CTL ( or ) ) ;
2011-08-03 08:52:39 +10:00
val & = NVA3_PDISP_SOR_PWM_CTL_VAL ;
if ( div & & div > = val )
return ( ( val * 100 ) + ( div / 2 ) ) / div ;
return 100 ;
}
static int
nva3_set_intensity ( struct backlight_device * bd )
{
struct nouveau_encoder * nv_encoder = bl_get_data ( bd ) ;
2012-07-31 16:16:21 +10:00
struct nouveau_drm * drm = nouveau_drm ( nv_encoder - > base . base . dev ) ;
2015-08-20 14:54:15 +10:00
struct nvif_object * device = & drm - > device . object ;
2011-08-03 08:52:39 +10:00
int or = nv_encoder - > or ;
u32 div , val ;
2014-08-10 04:10:22 +10:00
div = nvif_rd32 ( device , NV50_PDISP_SOR_PWM_DIV ( or ) ) ;
2011-08-03 08:52:39 +10:00
val = ( bd - > props . brightness * div ) / 100 ;
if ( div ) {
2014-08-10 04:10:22 +10:00
nvif_wr32 ( device , NV50_PDISP_SOR_PWM_CTL ( or ) , val |
2012-07-26 09:12:47 +10:00
NV50_PDISP_SOR_PWM_CTL_NEW |
NVA3_PDISP_SOR_PWM_CTL_UNK ) ;
2011-08-03 08:52:39 +10:00
return 0 ;
}
return - EINVAL ;
}
static const struct backlight_ops nva3_bl_ops = {
. options = BL_CORE_SUSPENDRESUME ,
. get_brightness = nva3_get_intensity ,
. update_status = nva3_set_intensity ,
} ;
2011-08-02 18:54:43 +10:00
static int
nv50_backlight_init ( struct drm_connector * connector )
2009-12-11 19:24:15 +10:00
{
2012-07-31 16:16:21 +10:00
struct nouveau_drm * drm = nouveau_drm ( connector - > dev ) ;
2015-08-20 14:54:15 +10:00
struct nvif_object * device = & drm - > device . object ;
2011-08-02 19:29:37 +10:00
struct nouveau_encoder * nv_encoder ;
2011-03-22 16:30:24 -07:00
struct backlight_properties props ;
2009-12-11 19:24:15 +10:00
struct backlight_device * bd ;
2011-08-03 08:52:39 +10:00
const struct backlight_ops * ops ;
2011-08-02 19:29:37 +10:00
2012-07-11 10:44:20 +10:00
nv_encoder = find_encoder ( connector , DCB_OUTPUT_LVDS ) ;
2011-08-02 19:29:37 +10:00
if ( ! nv_encoder ) {
2012-07-11 10:44:20 +10:00
nv_encoder = find_encoder ( connector , DCB_OUTPUT_DP ) ;
2011-08-02 19:29:37 +10:00
if ( ! nv_encoder )
return - ENODEV ;
}
2014-08-10 04:10:22 +10:00
if ( ! nvif_rd32 ( device , NV50_PDISP_SOR_PWM_CTL ( nv_encoder - > or ) ) )
2009-12-11 19:24:15 +10:00
return 0 ;
2015-08-20 14:54:15 +10:00
if ( drm - > device . info . chipset < = 0xa0 | |
drm - > device . info . chipset = = 0xaa | |
drm - > device . info . chipset = = 0xac )
2011-08-03 08:52:39 +10:00
ops = & nv50_bl_ops ;
else
ops = & nva3_bl_ops ;
2010-02-17 16:39:44 -05:00
memset ( & props , 0 , sizeof ( struct backlight_properties ) ) ;
2011-03-22 16:30:21 -07:00
props . type = BACKLIGHT_RAW ;
2011-08-02 20:45:35 +10:00
props . max_brightness = 100 ;
2013-10-11 14:07:25 +10:00
bd = backlight_device_register ( " nv_backlight " , connector - > kdev ,
2011-08-03 08:52:39 +10:00
nv_encoder , ops , & props ) ;
2009-12-11 19:24:15 +10:00
if ( IS_ERR ( bd ) )
return PTR_ERR ( bd ) ;
2012-07-26 09:12:47 +10:00
drm - > backlight = bd ;
2011-08-03 08:52:39 +10:00
bd - > props . brightness = bd - > ops - > get_brightness ( bd ) ;
2009-12-11 19:24:15 +10:00
backlight_update_status ( bd ) ;
return 0 ;
}
2011-08-02 18:54:43 +10:00
int
2011-08-02 19:29:37 +10:00
nouveau_backlight_init ( struct drm_device * dev )
2009-12-11 19:24:15 +10:00
{
2012-07-31 16:16:21 +10:00
struct nouveau_drm * drm = nouveau_drm ( dev ) ;
2014-08-10 04:10:22 +10:00
struct nvif_device * device = & drm - > device ;
2011-08-02 19:29:37 +10:00
struct drm_connector * connector ;
2009-12-11 19:24:15 +10:00
2011-08-02 19:29:37 +10:00
list_for_each_entry ( connector , & dev - > mode_config . connector_list , head ) {
if ( connector - > connector_type ! = DRM_MODE_CONNECTOR_LVDS & &
connector - > connector_type ! = DRM_MODE_CONNECTOR_eDP )
continue ;
2014-08-10 04:10:22 +10:00
switch ( device - > info . family ) {
case NV_DEVICE_INFO_V0_CURIE :
2011-08-02 19:29:37 +10:00
return nv40_backlight_init ( connector ) ;
2014-08-10 04:10:22 +10:00
case NV_DEVICE_INFO_V0_TESLA :
case NV_DEVICE_INFO_V0_FERMI :
case NV_DEVICE_INFO_V0_KEPLER :
2011-08-02 19:29:37 +10:00
return nv50_backlight_init ( connector ) ;
default :
break ;
}
2009-12-11 19:24:15 +10:00
}
2011-08-02 19:29:37 +10:00
2009-12-11 19:24:15 +10:00
return 0 ;
}
2011-08-02 18:54:43 +10:00
void
2011-08-02 19:29:37 +10:00
nouveau_backlight_exit ( struct drm_device * dev )
2009-12-11 19:24:15 +10:00
{
2012-07-31 16:16:21 +10:00
struct nouveau_drm * drm = nouveau_drm ( dev ) ;
2009-12-11 19:24:15 +10:00
2012-07-26 09:12:47 +10:00
if ( drm - > backlight ) {
backlight_device_unregister ( drm - > backlight ) ;
drm - > backlight = NULL ;
2009-12-11 19:24:15 +10:00
}
}