2009-06-05 16:42:42 +04:00
/*
* Copyright 2008 Advanced Micro Devices , Inc .
* Copyright 2008 Red Hat Inc .
* Copyright 2009 Jerome Glisse .
*
* 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 : Dave Airlie
* Alex Deucher
* Jerome Glisse
*/
# include "drmP.h"
2010-05-07 10:42:51 +04:00
# include "drm_crtc_helper.h"
2009-06-05 16:42:42 +04:00
# include "radeon_drm.h"
# include "radeon_reg.h"
# include "radeon.h"
# include "atom.h"
irqreturn_t radeon_driver_irq_handler_kms ( DRM_IRQ_ARGS )
{
struct drm_device * dev = ( struct drm_device * ) arg ;
struct radeon_device * rdev = dev - > dev_private ;
return radeon_irq_process ( rdev ) ;
}
2009-12-05 00:56:37 +03:00
/*
* Handle hotplug events outside the interrupt handler proper .
*/
static void radeon_hotplug_work_func ( struct work_struct * work )
{
struct radeon_device * rdev = container_of ( work , struct radeon_device ,
hotplug_work ) ;
struct drm_device * dev = rdev - > ddev ;
struct drm_mode_config * mode_config = & dev - > mode_config ;
struct drm_connector * connector ;
if ( mode_config - > num_connector ) {
list_for_each_entry ( connector , & mode_config - > connector_list , head )
radeon_connector_hotplug ( connector ) ;
}
/* Just fire off a uevent and let userspace tell us what to do */
2010-05-07 10:42:51 +04:00
drm_helper_hpd_irq_event ( dev ) ;
2009-12-05 00:56:37 +03:00
}
2009-06-05 16:42:42 +04:00
void radeon_driver_irq_preinstall_kms ( struct drm_device * dev )
{
struct radeon_device * rdev = dev - > dev_private ;
unsigned i ;
2009-12-05 00:56:37 +03:00
INIT_WORK ( & rdev - > hotplug_work , radeon_hotplug_work_func ) ;
2009-06-05 16:42:42 +04:00
/* Disable *all* interrupts */
rdev - > irq . sw_int = false ;
2010-04-22 20:52:11 +04:00
rdev - > irq . gui_idle = false ;
2010-03-17 00:08:06 +03:00
for ( i = 0 ; i < rdev - > num_crtc ; i + + )
2009-06-05 16:42:42 +04:00
rdev - > irq . crtc_vblank_int [ i ] = false ;
2010-03-17 00:08:06 +03:00
for ( i = 0 ; i < 6 ; i + + )
rdev - > irq . hpd [ i ] = false ;
2009-06-05 16:42:42 +04:00
radeon_irq_set ( rdev ) ;
/* Clear bits */
radeon_irq_process ( rdev ) ;
}
int radeon_driver_irq_postinstall_kms ( struct drm_device * dev )
{
struct radeon_device * rdev = dev - > dev_private ;
dev - > max_vblank_count = 0x001fffff ;
rdev - > irq . sw_int = true ;
radeon_irq_set ( rdev ) ;
return 0 ;
}
void radeon_driver_irq_uninstall_kms ( struct drm_device * dev )
{
struct radeon_device * rdev = dev - > dev_private ;
unsigned i ;
if ( rdev = = NULL ) {
return ;
}
/* Disable *all* interrupts */
rdev - > irq . sw_int = false ;
2010-04-22 20:52:11 +04:00
rdev - > irq . gui_idle = false ;
2010-03-17 00:08:06 +03:00
for ( i = 0 ; i < rdev - > num_crtc ; i + + )
2009-06-05 16:42:42 +04:00
rdev - > irq . crtc_vblank_int [ i ] = false ;
2010-03-17 00:08:06 +03:00
for ( i = 0 ; i < 6 ; i + + )
2010-01-07 17:39:14 +03:00
rdev - > irq . hpd [ i ] = false ;
2009-06-05 16:42:42 +04:00
radeon_irq_set ( rdev ) ;
}
int radeon_irq_kms_init ( struct radeon_device * rdev )
{
int r = 0 ;
2009-12-01 09:04:56 +03:00
spin_lock_init ( & rdev - > irq . sw_lock ) ;
2010-03-17 00:08:06 +03:00
r = drm_vblank_init ( rdev - > ddev , rdev - > num_crtc ) ;
2009-06-05 16:42:42 +04:00
if ( r ) {
return r ;
}
2009-10-16 20:21:24 +04:00
/* enable msi */
rdev - > msi_enabled = 0 ;
2010-03-31 01:22:32 +04:00
/* MSIs don't seem to work reliably on all IGP
* chips . Disable MSI on them for now .
2009-12-01 21:43:46 +03:00
*/
if ( ( rdev - > family > = CHIP_RV380 ) & &
2010-03-31 01:22:32 +04:00
( ! ( rdev - > flags & RADEON_IS_IGP ) ) ) {
2009-10-16 20:21:24 +04:00
int ret = pci_enable_msi ( rdev - > pdev ) ;
2009-12-01 21:43:46 +03:00
if ( ! ret ) {
2009-10-16 20:21:24 +04:00
rdev - > msi_enabled = 1 ;
2009-12-01 21:43:46 +03:00
DRM_INFO ( " radeon: using MSI. \n " ) ;
}
2009-10-16 20:21:24 +04:00
}
2009-06-05 16:42:42 +04:00
rdev - > irq . installed = true ;
2010-01-07 17:39:14 +03:00
r = drm_irq_install ( rdev - > ddev ) ;
if ( r ) {
rdev - > irq . installed = false ;
return r ;
}
2009-06-05 16:42:42 +04:00
DRM_INFO ( " radeon: irq initialized. \n " ) ;
return 0 ;
}
void radeon_irq_kms_fini ( struct radeon_device * rdev )
{
2010-01-07 17:39:14 +03:00
drm_vblank_cleanup ( rdev - > ddev ) ;
2009-06-05 16:42:42 +04:00
if ( rdev - > irq . installed ) {
drm_irq_uninstall ( rdev - > ddev ) ;
2010-01-07 17:39:14 +03:00
rdev - > irq . installed = false ;
2009-10-16 20:21:24 +04:00
if ( rdev - > msi_enabled )
pci_disable_msi ( rdev - > pdev ) ;
2009-06-05 16:42:42 +04:00
}
}
2009-12-01 09:04:56 +03:00
void radeon_irq_kms_sw_irq_get ( struct radeon_device * rdev )
{
unsigned long irqflags ;
spin_lock_irqsave ( & rdev - > irq . sw_lock , irqflags ) ;
if ( rdev - > ddev - > irq_enabled & & ( + + rdev - > irq . sw_refcount = = 1 ) ) {
rdev - > irq . sw_int = true ;
radeon_irq_set ( rdev ) ;
}
spin_unlock_irqrestore ( & rdev - > irq . sw_lock , irqflags ) ;
}
void radeon_irq_kms_sw_irq_put ( struct radeon_device * rdev )
{
unsigned long irqflags ;
spin_lock_irqsave ( & rdev - > irq . sw_lock , irqflags ) ;
BUG_ON ( rdev - > ddev - > irq_enabled & & rdev - > irq . sw_refcount < = 0 ) ;
if ( rdev - > ddev - > irq_enabled & & ( - - rdev - > irq . sw_refcount = = 0 ) ) {
rdev - > irq . sw_int = false ;
radeon_irq_set ( rdev ) ;
}
spin_unlock_irqrestore ( & rdev - > irq . sw_lock , irqflags ) ;
}