Commit 67f33f30 authored by Dave Airlie's avatar Dave Airlie

Merge branch 'drm-fixes-3.17' of git://people.freedesktop.org/~agd5f/linux into drm-fixes

- fix a backlight regression resulting in dark screen
- add a PX quirk to avoid a hang with runtime pm
- fix an init issue on the CIK compute rings
- fix IH ring buffer overflows gracefully

* 'drm-fixes-3.17' of git://people.freedesktop.org/~agd5f/linux:
  drm/radeon/cik: use a separate counter for CP init timeout
  drm/radeon: add PX quirk for asus K53TK
  drm/radeon: add a backlight quirk for Amilo Xi 2550
  drm/radeon: add a module parameter for backlight control (v2)
  drm/radeon: Update IH_RB_RPTR register after each processed interrupt
  drm/radeon: Make IH ring overflow debugging output more useful
  drm/radeon: Clear RB_OVERFLOW bit earlier
parents 65e7e5d8 370ce45b
...@@ -4803,7 +4803,7 @@ struct bonaire_mqd ...@@ -4803,7 +4803,7 @@ struct bonaire_mqd
*/ */
static int cik_cp_compute_resume(struct radeon_device *rdev) static int cik_cp_compute_resume(struct radeon_device *rdev)
{ {
int r, i, idx; int r, i, j, idx;
u32 tmp; u32 tmp;
bool use_doorbell = true; bool use_doorbell = true;
u64 hqd_gpu_addr; u64 hqd_gpu_addr;
...@@ -4922,7 +4922,7 @@ static int cik_cp_compute_resume(struct radeon_device *rdev) ...@@ -4922,7 +4922,7 @@ static int cik_cp_compute_resume(struct radeon_device *rdev)
mqd->queue_state.cp_hqd_pq_wptr= 0; mqd->queue_state.cp_hqd_pq_wptr= 0;
if (RREG32(CP_HQD_ACTIVE) & 1) { if (RREG32(CP_HQD_ACTIVE) & 1) {
WREG32(CP_HQD_DEQUEUE_REQUEST, 1); WREG32(CP_HQD_DEQUEUE_REQUEST, 1);
for (i = 0; i < rdev->usec_timeout; i++) { for (j = 0; j < rdev->usec_timeout; j++) {
if (!(RREG32(CP_HQD_ACTIVE) & 1)) if (!(RREG32(CP_HQD_ACTIVE) & 1))
break; break;
udelay(1); udelay(1);
...@@ -7751,17 +7751,17 @@ static inline u32 cik_get_ih_wptr(struct radeon_device *rdev) ...@@ -7751,17 +7751,17 @@ static inline u32 cik_get_ih_wptr(struct radeon_device *rdev)
wptr = RREG32(IH_RB_WPTR); wptr = RREG32(IH_RB_WPTR);
if (wptr & RB_OVERFLOW) { if (wptr & RB_OVERFLOW) {
wptr &= ~RB_OVERFLOW;
/* When a ring buffer overflow happen start parsing interrupt /* When a ring buffer overflow happen start parsing interrupt
* from the last not overwritten vector (wptr + 16). Hopefully * from the last not overwritten vector (wptr + 16). Hopefully
* this should allow us to catchup. * this should allow us to catchup.
*/ */
dev_warn(rdev->dev, "IH ring buffer overflow (0x%08X, %d, %d)\n", dev_warn(rdev->dev, "IH ring buffer overflow (0x%08X, 0x%08X, 0x%08X)\n",
wptr, rdev->ih.rptr, (wptr + 16) + rdev->ih.ptr_mask); wptr, rdev->ih.rptr, (wptr + 16) & rdev->ih.ptr_mask);
rdev->ih.rptr = (wptr + 16) & rdev->ih.ptr_mask; rdev->ih.rptr = (wptr + 16) & rdev->ih.ptr_mask;
tmp = RREG32(IH_RB_CNTL); tmp = RREG32(IH_RB_CNTL);
tmp |= IH_WPTR_OVERFLOW_CLEAR; tmp |= IH_WPTR_OVERFLOW_CLEAR;
WREG32(IH_RB_CNTL, tmp); WREG32(IH_RB_CNTL, tmp);
wptr &= ~RB_OVERFLOW;
} }
return (wptr & rdev->ih.ptr_mask); return (wptr & rdev->ih.ptr_mask);
} }
...@@ -8251,6 +8251,7 @@ int cik_irq_process(struct radeon_device *rdev) ...@@ -8251,6 +8251,7 @@ int cik_irq_process(struct radeon_device *rdev)
/* wptr/rptr are in bytes! */ /* wptr/rptr are in bytes! */
rptr += 16; rptr += 16;
rptr &= rdev->ih.ptr_mask; rptr &= rdev->ih.ptr_mask;
WREG32(IH_RB_RPTR, rptr);
} }
if (queue_hotplug) if (queue_hotplug)
schedule_work(&rdev->hotplug_work); schedule_work(&rdev->hotplug_work);
...@@ -8259,7 +8260,6 @@ int cik_irq_process(struct radeon_device *rdev) ...@@ -8259,7 +8260,6 @@ int cik_irq_process(struct radeon_device *rdev)
if (queue_thermal) if (queue_thermal)
schedule_work(&rdev->pm.dpm.thermal.work); schedule_work(&rdev->pm.dpm.thermal.work);
rdev->ih.rptr = rptr; rdev->ih.rptr = rptr;
WREG32(IH_RB_RPTR, rdev->ih.rptr);
atomic_set(&rdev->ih.lock, 0); atomic_set(&rdev->ih.lock, 0);
/* make sure wptr hasn't changed while processing */ /* make sure wptr hasn't changed while processing */
......
...@@ -4749,17 +4749,17 @@ static u32 evergreen_get_ih_wptr(struct radeon_device *rdev) ...@@ -4749,17 +4749,17 @@ static u32 evergreen_get_ih_wptr(struct radeon_device *rdev)
wptr = RREG32(IH_RB_WPTR); wptr = RREG32(IH_RB_WPTR);
if (wptr & RB_OVERFLOW) { if (wptr & RB_OVERFLOW) {
wptr &= ~RB_OVERFLOW;
/* When a ring buffer overflow happen start parsing interrupt /* When a ring buffer overflow happen start parsing interrupt
* from the last not overwritten vector (wptr + 16). Hopefully * from the last not overwritten vector (wptr + 16). Hopefully
* this should allow us to catchup. * this should allow us to catchup.
*/ */
dev_warn(rdev->dev, "IH ring buffer overflow (0x%08X, %d, %d)\n", dev_warn(rdev->dev, "IH ring buffer overflow (0x%08X, 0x%08X, 0x%08X)\n",
wptr, rdev->ih.rptr, (wptr + 16) + rdev->ih.ptr_mask); wptr, rdev->ih.rptr, (wptr + 16) & rdev->ih.ptr_mask);
rdev->ih.rptr = (wptr + 16) & rdev->ih.ptr_mask; rdev->ih.rptr = (wptr + 16) & rdev->ih.ptr_mask;
tmp = RREG32(IH_RB_CNTL); tmp = RREG32(IH_RB_CNTL);
tmp |= IH_WPTR_OVERFLOW_CLEAR; tmp |= IH_WPTR_OVERFLOW_CLEAR;
WREG32(IH_RB_CNTL, tmp); WREG32(IH_RB_CNTL, tmp);
wptr &= ~RB_OVERFLOW;
} }
return (wptr & rdev->ih.ptr_mask); return (wptr & rdev->ih.ptr_mask);
} }
...@@ -5137,6 +5137,7 @@ int evergreen_irq_process(struct radeon_device *rdev) ...@@ -5137,6 +5137,7 @@ int evergreen_irq_process(struct radeon_device *rdev)
/* wptr/rptr are in bytes! */ /* wptr/rptr are in bytes! */
rptr += 16; rptr += 16;
rptr &= rdev->ih.ptr_mask; rptr &= rdev->ih.ptr_mask;
WREG32(IH_RB_RPTR, rptr);
} }
if (queue_hotplug) if (queue_hotplug)
schedule_work(&rdev->hotplug_work); schedule_work(&rdev->hotplug_work);
...@@ -5145,7 +5146,6 @@ int evergreen_irq_process(struct radeon_device *rdev) ...@@ -5145,7 +5146,6 @@ int evergreen_irq_process(struct radeon_device *rdev)
if (queue_thermal && rdev->pm.dpm_enabled) if (queue_thermal && rdev->pm.dpm_enabled)
schedule_work(&rdev->pm.dpm.thermal.work); schedule_work(&rdev->pm.dpm.thermal.work);
rdev->ih.rptr = rptr; rdev->ih.rptr = rptr;
WREG32(IH_RB_RPTR, rdev->ih.rptr);
atomic_set(&rdev->ih.lock, 0); atomic_set(&rdev->ih.lock, 0);
/* make sure wptr hasn't changed while processing */ /* make sure wptr hasn't changed while processing */
......
...@@ -3792,17 +3792,17 @@ static u32 r600_get_ih_wptr(struct radeon_device *rdev) ...@@ -3792,17 +3792,17 @@ static u32 r600_get_ih_wptr(struct radeon_device *rdev)
wptr = RREG32(IH_RB_WPTR); wptr = RREG32(IH_RB_WPTR);
if (wptr & RB_OVERFLOW) { if (wptr & RB_OVERFLOW) {
wptr &= ~RB_OVERFLOW;
/* When a ring buffer overflow happen start parsing interrupt /* When a ring buffer overflow happen start parsing interrupt
* from the last not overwritten vector (wptr + 16). Hopefully * from the last not overwritten vector (wptr + 16). Hopefully
* this should allow us to catchup. * this should allow us to catchup.
*/ */
dev_warn(rdev->dev, "IH ring buffer overflow (0x%08X, %d, %d)\n", dev_warn(rdev->dev, "IH ring buffer overflow (0x%08X, 0x%08X, 0x%08X)\n",
wptr, rdev->ih.rptr, (wptr + 16) + rdev->ih.ptr_mask); wptr, rdev->ih.rptr, (wptr + 16) & rdev->ih.ptr_mask);
rdev->ih.rptr = (wptr + 16) & rdev->ih.ptr_mask; rdev->ih.rptr = (wptr + 16) & rdev->ih.ptr_mask;
tmp = RREG32(IH_RB_CNTL); tmp = RREG32(IH_RB_CNTL);
tmp |= IH_WPTR_OVERFLOW_CLEAR; tmp |= IH_WPTR_OVERFLOW_CLEAR;
WREG32(IH_RB_CNTL, tmp); WREG32(IH_RB_CNTL, tmp);
wptr &= ~RB_OVERFLOW;
} }
return (wptr & rdev->ih.ptr_mask); return (wptr & rdev->ih.ptr_mask);
} }
...@@ -4048,6 +4048,7 @@ int r600_irq_process(struct radeon_device *rdev) ...@@ -4048,6 +4048,7 @@ int r600_irq_process(struct radeon_device *rdev)
/* wptr/rptr are in bytes! */ /* wptr/rptr are in bytes! */
rptr += 16; rptr += 16;
rptr &= rdev->ih.ptr_mask; rptr &= rdev->ih.ptr_mask;
WREG32(IH_RB_RPTR, rptr);
} }
if (queue_hotplug) if (queue_hotplug)
schedule_work(&rdev->hotplug_work); schedule_work(&rdev->hotplug_work);
...@@ -4056,7 +4057,6 @@ int r600_irq_process(struct radeon_device *rdev) ...@@ -4056,7 +4057,6 @@ int r600_irq_process(struct radeon_device *rdev)
if (queue_thermal && rdev->pm.dpm_enabled) if (queue_thermal && rdev->pm.dpm_enabled)
schedule_work(&rdev->pm.dpm.thermal.work); schedule_work(&rdev->pm.dpm.thermal.work);
rdev->ih.rptr = rptr; rdev->ih.rptr = rptr;
WREG32(IH_RB_RPTR, rdev->ih.rptr);
atomic_set(&rdev->ih.lock, 0); atomic_set(&rdev->ih.lock, 0);
/* make sure wptr hasn't changed while processing */ /* make sure wptr hasn't changed while processing */
......
...@@ -106,6 +106,7 @@ extern int radeon_vm_block_size; ...@@ -106,6 +106,7 @@ extern int radeon_vm_block_size;
extern int radeon_deep_color; extern int radeon_deep_color;
extern int radeon_use_pflipirq; extern int radeon_use_pflipirq;
extern int radeon_bapm; extern int radeon_bapm;
extern int radeon_backlight;
/* /*
* Copy from radeon_drv.h so we don't have to include both and have conflicting * Copy from radeon_drv.h so we don't have to include both and have conflicting
......
...@@ -123,6 +123,10 @@ static struct radeon_px_quirk radeon_px_quirk_list[] = { ...@@ -123,6 +123,10 @@ static struct radeon_px_quirk radeon_px_quirk_list[] = {
* https://bugzilla.kernel.org/show_bug.cgi?id=51381 * https://bugzilla.kernel.org/show_bug.cgi?id=51381
*/ */
{ PCI_VENDOR_ID_ATI, 0x6741, 0x1043, 0x108c, RADEON_PX_QUIRK_DISABLE_PX }, { PCI_VENDOR_ID_ATI, 0x6741, 0x1043, 0x108c, RADEON_PX_QUIRK_DISABLE_PX },
/* Asus K53TK laptop with AMD A6-3420M APU and Radeon 7670m GPU
* https://bugzilla.kernel.org/show_bug.cgi?id=51381
*/
{ PCI_VENDOR_ID_ATI, 0x6840, 0x1043, 0x2122, RADEON_PX_QUIRK_DISABLE_PX },
/* macbook pro 8.2 */ /* macbook pro 8.2 */
{ PCI_VENDOR_ID_ATI, 0x6741, PCI_VENDOR_ID_APPLE, 0x00e2, RADEON_PX_QUIRK_LONG_WAKEUP }, { PCI_VENDOR_ID_ATI, 0x6741, PCI_VENDOR_ID_APPLE, 0x00e2, RADEON_PX_QUIRK_LONG_WAKEUP },
{ 0, 0, 0, 0, 0 }, { 0, 0, 0, 0, 0 },
......
...@@ -181,6 +181,7 @@ int radeon_vm_block_size = -1; ...@@ -181,6 +181,7 @@ int radeon_vm_block_size = -1;
int radeon_deep_color = 0; int radeon_deep_color = 0;
int radeon_use_pflipirq = 2; int radeon_use_pflipirq = 2;
int radeon_bapm = -1; int radeon_bapm = -1;
int radeon_backlight = -1;
MODULE_PARM_DESC(no_wb, "Disable AGP writeback for scratch registers"); MODULE_PARM_DESC(no_wb, "Disable AGP writeback for scratch registers");
module_param_named(no_wb, radeon_no_wb, int, 0444); module_param_named(no_wb, radeon_no_wb, int, 0444);
...@@ -263,6 +264,9 @@ module_param_named(use_pflipirq, radeon_use_pflipirq, int, 0444); ...@@ -263,6 +264,9 @@ module_param_named(use_pflipirq, radeon_use_pflipirq, int, 0444);
MODULE_PARM_DESC(bapm, "BAPM support (1 = enable, 0 = disable, -1 = auto)"); MODULE_PARM_DESC(bapm, "BAPM support (1 = enable, 0 = disable, -1 = auto)");
module_param_named(bapm, radeon_bapm, int, 0444); module_param_named(bapm, radeon_bapm, int, 0444);
MODULE_PARM_DESC(backlight, "backlight support (1 = enable, 0 = disable, -1 = auto)");
module_param_named(backlight, radeon_backlight, int, 0444);
static struct pci_device_id pciidlist[] = { static struct pci_device_id pciidlist[] = {
radeon_PCI_IDS radeon_PCI_IDS
}; };
......
...@@ -158,10 +158,43 @@ radeon_get_encoder_enum(struct drm_device *dev, uint32_t supported_device, uint8 ...@@ -158,10 +158,43 @@ radeon_get_encoder_enum(struct drm_device *dev, uint32_t supported_device, uint8
return ret; return ret;
} }
static void radeon_encoder_add_backlight(struct radeon_encoder *radeon_encoder,
struct drm_connector *connector)
{
struct drm_device *dev = radeon_encoder->base.dev;
struct radeon_device *rdev = dev->dev_private;
bool use_bl = false;
if (!(radeon_encoder->devices & (ATOM_DEVICE_LCD_SUPPORT)))
return;
if (radeon_backlight == 0) {
return;
} else if (radeon_backlight == 1) {
use_bl = true;
} else if (radeon_backlight == -1) {
/* Quirks */
/* Amilo Xi 2550 only works with acpi bl */
if ((rdev->pdev->device == 0x9583) &&
(rdev->pdev->subsystem_vendor == 0x1734) &&
(rdev->pdev->subsystem_device == 0x1107))
use_bl = false;
else
use_bl = true;
}
if (use_bl) {
if (rdev->is_atom_bios)
radeon_atom_backlight_init(radeon_encoder, connector);
else
radeon_legacy_backlight_init(radeon_encoder, connector);
rdev->mode_info.bl_encoder = radeon_encoder;
}
}
void void
radeon_link_encoder_connector(struct drm_device *dev) radeon_link_encoder_connector(struct drm_device *dev)
{ {
struct radeon_device *rdev = dev->dev_private;
struct drm_connector *connector; struct drm_connector *connector;
struct radeon_connector *radeon_connector; struct radeon_connector *radeon_connector;
struct drm_encoder *encoder; struct drm_encoder *encoder;
...@@ -174,13 +207,8 @@ radeon_link_encoder_connector(struct drm_device *dev) ...@@ -174,13 +207,8 @@ radeon_link_encoder_connector(struct drm_device *dev)
radeon_encoder = to_radeon_encoder(encoder); radeon_encoder = to_radeon_encoder(encoder);
if (radeon_encoder->devices & radeon_connector->devices) { if (radeon_encoder->devices & radeon_connector->devices) {
drm_mode_connector_attach_encoder(connector, encoder); drm_mode_connector_attach_encoder(connector, encoder);
if (radeon_encoder->devices & (ATOM_DEVICE_LCD_SUPPORT)) { if (radeon_encoder->devices & (ATOM_DEVICE_LCD_SUPPORT))
if (rdev->is_atom_bios) radeon_encoder_add_backlight(radeon_encoder, connector);
radeon_atom_backlight_init(radeon_encoder, connector);
else
radeon_legacy_backlight_init(radeon_encoder, connector);
rdev->mode_info.bl_encoder = radeon_encoder;
}
} }
} }
} }
......
...@@ -6316,17 +6316,17 @@ static inline u32 si_get_ih_wptr(struct radeon_device *rdev) ...@@ -6316,17 +6316,17 @@ static inline u32 si_get_ih_wptr(struct radeon_device *rdev)
wptr = RREG32(IH_RB_WPTR); wptr = RREG32(IH_RB_WPTR);
if (wptr & RB_OVERFLOW) { if (wptr & RB_OVERFLOW) {
wptr &= ~RB_OVERFLOW;
/* When a ring buffer overflow happen start parsing interrupt /* When a ring buffer overflow happen start parsing interrupt
* from the last not overwritten vector (wptr + 16). Hopefully * from the last not overwritten vector (wptr + 16). Hopefully
* this should allow us to catchup. * this should allow us to catchup.
*/ */
dev_warn(rdev->dev, "IH ring buffer overflow (0x%08X, %d, %d)\n", dev_warn(rdev->dev, "IH ring buffer overflow (0x%08X, 0x%08X, 0x%08X)\n",
wptr, rdev->ih.rptr, (wptr + 16) + rdev->ih.ptr_mask); wptr, rdev->ih.rptr, (wptr + 16) & rdev->ih.ptr_mask);
rdev->ih.rptr = (wptr + 16) & rdev->ih.ptr_mask; rdev->ih.rptr = (wptr + 16) & rdev->ih.ptr_mask;
tmp = RREG32(IH_RB_CNTL); tmp = RREG32(IH_RB_CNTL);
tmp |= IH_WPTR_OVERFLOW_CLEAR; tmp |= IH_WPTR_OVERFLOW_CLEAR;
WREG32(IH_RB_CNTL, tmp); WREG32(IH_RB_CNTL, tmp);
wptr &= ~RB_OVERFLOW;
} }
return (wptr & rdev->ih.ptr_mask); return (wptr & rdev->ih.ptr_mask);
} }
...@@ -6664,13 +6664,13 @@ int si_irq_process(struct radeon_device *rdev) ...@@ -6664,13 +6664,13 @@ int si_irq_process(struct radeon_device *rdev)
/* wptr/rptr are in bytes! */ /* wptr/rptr are in bytes! */
rptr += 16; rptr += 16;
rptr &= rdev->ih.ptr_mask; rptr &= rdev->ih.ptr_mask;
WREG32(IH_RB_RPTR, rptr);
} }
if (queue_hotplug) if (queue_hotplug)
schedule_work(&rdev->hotplug_work); schedule_work(&rdev->hotplug_work);
if (queue_thermal && rdev->pm.dpm_enabled) if (queue_thermal && rdev->pm.dpm_enabled)
schedule_work(&rdev->pm.dpm.thermal.work); schedule_work(&rdev->pm.dpm.thermal.work);
rdev->ih.rptr = rptr; rdev->ih.rptr = rptr;
WREG32(IH_RB_RPTR, rdev->ih.rptr);
atomic_set(&rdev->ih.lock, 0); atomic_set(&rdev->ih.lock, 0);
/* make sure wptr hasn't changed while processing */ /* make sure wptr hasn't changed while processing */
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment