Skip to content
Snippets Groups Projects
Commit 28c20cc7 authored by Linus Torvalds's avatar Linus Torvalds
Browse files

Merge tag 'drm-fixes-2018-07-20' of git://anongit.freedesktop.org/drm/drm

Pull drm fixes from Dave Airlie:
 "Just two sets of driver fixes this week to follow up on the set from
  earlier in the week and hopefully get me realigned schedule wise.

  amdgpu:
   - ACP fix for boards with multiple I2S instances
   - DP fix for CZ, vega
   - hybrid laptop fixes
   - Resume regression fix

  nouveau:
   - large memory systems and Pascal fix
   - MST race fixes
   - runtime PM fix"

* tag 'drm-fixes-2018-07-20' of git://anongit.freedesktop.org/drm/drm:
  drm/nouveau/fb/gp100-: disable address remapper
  drm/amd/amdgpu: creating two I2S instances for stoney/cz (v2)
  drm/amdgpu: add another ATPX quirk for TOPAZ
  drm/amd/display: Fix DP HBR2 Eye Diagram Pattern on Carrizo
  drm/amdgpu: Make sure IB tests flushed after IP resume
  drm/nouveau: Set DRIVER_ATOMIC cap earlier to fix debugfs
  drm/nouveau: Remove bogus crtc check in pmops_runtime_idle
  drm/nouveau/drm/nouveau: Fix runtime PM leak in nv50_disp_atomic_commit()
  drm/nouveau: Avoid looping through fake MST connectors
  drm/nouveau: Use drm_connector_list_iter_* for iterating connectors
  drm/nouveau/gem: off by one bugs in nouveau_gem_pushbuf_reloc_apply()
  drm/nouveau/kms/nv50-: ensure window updates are submitted when flushing mst disables
parents fb7d1bcf 02e546ea
No related branches found
No related tags found
No related merge requests found
Showing
with 152 additions and 64 deletions
...@@ -57,6 +57,10 @@ ...@@ -57,6 +57,10 @@
#define ACP_I2S_COMP2_CAP_REG_OFFSET 0xa8 #define ACP_I2S_COMP2_CAP_REG_OFFSET 0xa8
#define ACP_I2S_COMP1_PLAY_REG_OFFSET 0x6c #define ACP_I2S_COMP1_PLAY_REG_OFFSET 0x6c
#define ACP_I2S_COMP2_PLAY_REG_OFFSET 0x68 #define ACP_I2S_COMP2_PLAY_REG_OFFSET 0x68
#define ACP_BT_PLAY_REGS_START 0x14970
#define ACP_BT_PLAY_REGS_END 0x14a24
#define ACP_BT_COMP1_REG_OFFSET 0xac
#define ACP_BT_COMP2_REG_OFFSET 0xa8
#define mmACP_PGFSM_RETAIN_REG 0x51c9 #define mmACP_PGFSM_RETAIN_REG 0x51c9
#define mmACP_PGFSM_CONFIG_REG 0x51ca #define mmACP_PGFSM_CONFIG_REG 0x51ca
...@@ -77,7 +81,7 @@ ...@@ -77,7 +81,7 @@
#define ACP_SOFT_RESET_DONE_TIME_OUT_VALUE 0x000000FF #define ACP_SOFT_RESET_DONE_TIME_OUT_VALUE 0x000000FF
#define ACP_TIMEOUT_LOOP 0x000000FF #define ACP_TIMEOUT_LOOP 0x000000FF
#define ACP_DEVS 3 #define ACP_DEVS 4
#define ACP_SRC_ID 162 #define ACP_SRC_ID 162
enum { enum {
...@@ -316,14 +320,13 @@ static int acp_hw_init(void *handle) ...@@ -316,14 +320,13 @@ static int acp_hw_init(void *handle)
if (adev->acp.acp_cell == NULL) if (adev->acp.acp_cell == NULL)
return -ENOMEM; return -ENOMEM;
adev->acp.acp_res = kcalloc(4, sizeof(struct resource), GFP_KERNEL); adev->acp.acp_res = kcalloc(5, sizeof(struct resource), GFP_KERNEL);
if (adev->acp.acp_res == NULL) { if (adev->acp.acp_res == NULL) {
kfree(adev->acp.acp_cell); kfree(adev->acp.acp_cell);
return -ENOMEM; return -ENOMEM;
} }
i2s_pdata = kcalloc(2, sizeof(struct i2s_platform_data), GFP_KERNEL); i2s_pdata = kcalloc(3, sizeof(struct i2s_platform_data), GFP_KERNEL);
if (i2s_pdata == NULL) { if (i2s_pdata == NULL) {
kfree(adev->acp.acp_res); kfree(adev->acp.acp_res);
kfree(adev->acp.acp_cell); kfree(adev->acp.acp_cell);
...@@ -358,6 +361,20 @@ static int acp_hw_init(void *handle) ...@@ -358,6 +361,20 @@ static int acp_hw_init(void *handle)
i2s_pdata[1].i2s_reg_comp1 = ACP_I2S_COMP1_CAP_REG_OFFSET; i2s_pdata[1].i2s_reg_comp1 = ACP_I2S_COMP1_CAP_REG_OFFSET;
i2s_pdata[1].i2s_reg_comp2 = ACP_I2S_COMP2_CAP_REG_OFFSET; i2s_pdata[1].i2s_reg_comp2 = ACP_I2S_COMP2_CAP_REG_OFFSET;
i2s_pdata[2].quirks = DW_I2S_QUIRK_COMP_REG_OFFSET;
switch (adev->asic_type) {
case CHIP_STONEY:
i2s_pdata[2].quirks |= DW_I2S_QUIRK_16BIT_IDX_OVERRIDE;
break;
default:
break;
}
i2s_pdata[2].cap = DWC_I2S_PLAY | DWC_I2S_RECORD;
i2s_pdata[2].snd_rates = SNDRV_PCM_RATE_8000_96000;
i2s_pdata[2].i2s_reg_comp1 = ACP_BT_COMP1_REG_OFFSET;
i2s_pdata[2].i2s_reg_comp2 = ACP_BT_COMP2_REG_OFFSET;
adev->acp.acp_res[0].name = "acp2x_dma"; adev->acp.acp_res[0].name = "acp2x_dma";
adev->acp.acp_res[0].flags = IORESOURCE_MEM; adev->acp.acp_res[0].flags = IORESOURCE_MEM;
adev->acp.acp_res[0].start = acp_base; adev->acp.acp_res[0].start = acp_base;
...@@ -373,13 +390,18 @@ static int acp_hw_init(void *handle) ...@@ -373,13 +390,18 @@ static int acp_hw_init(void *handle)
adev->acp.acp_res[2].start = acp_base + ACP_I2S_CAP_REGS_START; adev->acp.acp_res[2].start = acp_base + ACP_I2S_CAP_REGS_START;
adev->acp.acp_res[2].end = acp_base + ACP_I2S_CAP_REGS_END; adev->acp.acp_res[2].end = acp_base + ACP_I2S_CAP_REGS_END;
adev->acp.acp_res[3].name = "acp2x_dma_irq"; adev->acp.acp_res[3].name = "acp2x_dw_bt_i2s_play_cap";
adev->acp.acp_res[3].flags = IORESOURCE_IRQ; adev->acp.acp_res[3].flags = IORESOURCE_MEM;
adev->acp.acp_res[3].start = amdgpu_irq_create_mapping(adev, 162); adev->acp.acp_res[3].start = acp_base + ACP_BT_PLAY_REGS_START;
adev->acp.acp_res[3].end = adev->acp.acp_res[3].start; adev->acp.acp_res[3].end = acp_base + ACP_BT_PLAY_REGS_END;
adev->acp.acp_res[4].name = "acp2x_dma_irq";
adev->acp.acp_res[4].flags = IORESOURCE_IRQ;
adev->acp.acp_res[4].start = amdgpu_irq_create_mapping(adev, 162);
adev->acp.acp_res[4].end = adev->acp.acp_res[4].start;
adev->acp.acp_cell[0].name = "acp_audio_dma"; adev->acp.acp_cell[0].name = "acp_audio_dma";
adev->acp.acp_cell[0].num_resources = 4; adev->acp.acp_cell[0].num_resources = 5;
adev->acp.acp_cell[0].resources = &adev->acp.acp_res[0]; adev->acp.acp_cell[0].resources = &adev->acp.acp_res[0];
adev->acp.acp_cell[0].platform_data = &adev->asic_type; adev->acp.acp_cell[0].platform_data = &adev->asic_type;
adev->acp.acp_cell[0].pdata_size = sizeof(adev->asic_type); adev->acp.acp_cell[0].pdata_size = sizeof(adev->asic_type);
...@@ -396,6 +418,12 @@ static int acp_hw_init(void *handle) ...@@ -396,6 +418,12 @@ static int acp_hw_init(void *handle)
adev->acp.acp_cell[2].platform_data = &i2s_pdata[1]; adev->acp.acp_cell[2].platform_data = &i2s_pdata[1];
adev->acp.acp_cell[2].pdata_size = sizeof(struct i2s_platform_data); adev->acp.acp_cell[2].pdata_size = sizeof(struct i2s_platform_data);
adev->acp.acp_cell[3].name = "designware-i2s";
adev->acp.acp_cell[3].num_resources = 1;
adev->acp.acp_cell[3].resources = &adev->acp.acp_res[3];
adev->acp.acp_cell[3].platform_data = &i2s_pdata[2];
adev->acp.acp_cell[3].pdata_size = sizeof(struct i2s_platform_data);
r = mfd_add_hotplug_devices(adev->acp.parent, adev->acp.acp_cell, r = mfd_add_hotplug_devices(adev->acp.parent, adev->acp.acp_cell,
ACP_DEVS); ACP_DEVS);
if (r) if (r)
...@@ -451,7 +479,6 @@ static int acp_hw_init(void *handle) ...@@ -451,7 +479,6 @@ static int acp_hw_init(void *handle)
val = cgs_read_register(adev->acp.cgs_device, mmACP_SOFT_RESET); val = cgs_read_register(adev->acp.cgs_device, mmACP_SOFT_RESET);
val &= ~ACP_SOFT_RESET__SoftResetAud_MASK; val &= ~ACP_SOFT_RESET__SoftResetAud_MASK;
cgs_write_register(adev->acp.cgs_device, mmACP_SOFT_RESET, val); cgs_write_register(adev->acp.cgs_device, mmACP_SOFT_RESET, val);
return 0; return 0;
} }
......
...@@ -575,6 +575,7 @@ static const struct amdgpu_px_quirk amdgpu_px_quirk_list[] = { ...@@ -575,6 +575,7 @@ static const struct amdgpu_px_quirk amdgpu_px_quirk_list[] = {
{ 0x1002, 0x6900, 0x1002, 0x0124, AMDGPU_PX_QUIRK_FORCE_ATPX }, { 0x1002, 0x6900, 0x1002, 0x0124, AMDGPU_PX_QUIRK_FORCE_ATPX },
{ 0x1002, 0x6900, 0x1028, 0x0812, AMDGPU_PX_QUIRK_FORCE_ATPX }, { 0x1002, 0x6900, 0x1028, 0x0812, AMDGPU_PX_QUIRK_FORCE_ATPX },
{ 0x1002, 0x6900, 0x1028, 0x0813, AMDGPU_PX_QUIRK_FORCE_ATPX }, { 0x1002, 0x6900, 0x1028, 0x0813, AMDGPU_PX_QUIRK_FORCE_ATPX },
{ 0x1002, 0x6900, 0x1025, 0x125A, AMDGPU_PX_QUIRK_FORCE_ATPX },
{ 0, 0, 0, 0, 0 }, { 0, 0, 0, 0, 0 },
}; };
......
...@@ -2747,6 +2747,9 @@ int amdgpu_device_resume(struct drm_device *dev, bool resume, bool fbcon) ...@@ -2747,6 +2747,9 @@ int amdgpu_device_resume(struct drm_device *dev, bool resume, bool fbcon)
if (r) if (r)
return r; return r;
/* Make sure IB tests flushed */
flush_delayed_work(&adev->late_init_work);
/* blat the mode back in */ /* blat the mode back in */
if (fbcon) { if (fbcon) {
if (!amdgpu_device_has_dc_support(adev)) { if (!amdgpu_device_has_dc_support(adev)) {
......
...@@ -1767,12 +1767,10 @@ static void dp_test_send_link_training(struct dc_link *link) ...@@ -1767,12 +1767,10 @@ static void dp_test_send_link_training(struct dc_link *link)
dp_retrain_link_dp_test(link, &link_settings, false); dp_retrain_link_dp_test(link, &link_settings, false);
} }
/* TODO hbr2 compliance eye output is unstable /* TODO Raven hbr2 compliance eye output is unstable
* (toggling on and off) with debugger break * (toggling on and off) with debugger break
* This caueses intermittent PHY automation failure * This caueses intermittent PHY automation failure
* Need to look into the root cause */ * Need to look into the root cause */
static uint8_t force_tps4_for_cp2520 = 1;
static void dp_test_send_phy_test_pattern(struct dc_link *link) static void dp_test_send_phy_test_pattern(struct dc_link *link)
{ {
union phy_test_pattern dpcd_test_pattern; union phy_test_pattern dpcd_test_pattern;
...@@ -1832,13 +1830,13 @@ static void dp_test_send_phy_test_pattern(struct dc_link *link) ...@@ -1832,13 +1830,13 @@ static void dp_test_send_phy_test_pattern(struct dc_link *link)
break; break;
case PHY_TEST_PATTERN_CP2520_1: case PHY_TEST_PATTERN_CP2520_1:
/* CP2520 pattern is unstable, temporarily use TPS4 instead */ /* CP2520 pattern is unstable, temporarily use TPS4 instead */
test_pattern = (force_tps4_for_cp2520 == 1) ? test_pattern = (link->dc->caps.force_dp_tps4_for_cp2520 == 1) ?
DP_TEST_PATTERN_TRAINING_PATTERN4 : DP_TEST_PATTERN_TRAINING_PATTERN4 :
DP_TEST_PATTERN_HBR2_COMPLIANCE_EYE; DP_TEST_PATTERN_HBR2_COMPLIANCE_EYE;
break; break;
case PHY_TEST_PATTERN_CP2520_2: case PHY_TEST_PATTERN_CP2520_2:
/* CP2520 pattern is unstable, temporarily use TPS4 instead */ /* CP2520 pattern is unstable, temporarily use TPS4 instead */
test_pattern = (force_tps4_for_cp2520 == 1) ? test_pattern = (link->dc->caps.force_dp_tps4_for_cp2520 == 1) ?
DP_TEST_PATTERN_TRAINING_PATTERN4 : DP_TEST_PATTERN_TRAINING_PATTERN4 :
DP_TEST_PATTERN_HBR2_COMPLIANCE_EYE; DP_TEST_PATTERN_HBR2_COMPLIANCE_EYE;
break; break;
......
...@@ -76,6 +76,7 @@ struct dc_caps { ...@@ -76,6 +76,7 @@ struct dc_caps {
bool is_apu; bool is_apu;
bool dual_link_dvi; bool dual_link_dvi;
bool post_blend_color_processing; bool post_blend_color_processing;
bool force_dp_tps4_for_cp2520;
}; };
struct dc_dcc_surface_param { struct dc_dcc_surface_param {
......
...@@ -1027,6 +1027,8 @@ static bool construct( ...@@ -1027,6 +1027,8 @@ static bool construct(
dc->caps.max_slave_planes = 1; dc->caps.max_slave_planes = 1;
dc->caps.is_apu = true; dc->caps.is_apu = true;
dc->caps.post_blend_color_processing = false; dc->caps.post_blend_color_processing = false;
/* Raven DP PHY HBR2 eye diagram pattern is not stable. Use TP4 */
dc->caps.force_dp_tps4_for_cp2520 = true;
if (dc->ctx->dce_environment == DCE_ENV_PRODUCTION_DRV) if (dc->ctx->dce_environment == DCE_ENV_PRODUCTION_DRV)
dc->debug = debug_defaults_drv; dc->debug = debug_defaults_drv;
......
...@@ -55,6 +55,9 @@ nv04_display_create(struct drm_device *dev) ...@@ -55,6 +55,9 @@ nv04_display_create(struct drm_device *dev)
nouveau_display(dev)->init = nv04_display_init; nouveau_display(dev)->init = nv04_display_init;
nouveau_display(dev)->fini = nv04_display_fini; nouveau_display(dev)->fini = nv04_display_fini;
/* Pre-nv50 doesn't support atomic, so don't expose the ioctls */
dev->driver->driver_features &= ~DRIVER_ATOMIC;
nouveau_hw_save_vga_fonts(dev, 1); nouveau_hw_save_vga_fonts(dev, 1);
nv04_crtc_create(dev, 0); nv04_crtc_create(dev, 0);
......
...@@ -1585,8 +1585,9 @@ nv50_pior_create(struct drm_connector *connector, struct dcb_output *dcbe) ...@@ -1585,8 +1585,9 @@ nv50_pior_create(struct drm_connector *connector, struct dcb_output *dcbe)
*****************************************************************************/ *****************************************************************************/
static void static void
nv50_disp_atomic_commit_core(struct nouveau_drm *drm, u32 *interlock) nv50_disp_atomic_commit_core(struct drm_atomic_state *state, u32 *interlock)
{ {
struct nouveau_drm *drm = nouveau_drm(state->dev);
struct nv50_disp *disp = nv50_disp(drm->dev); struct nv50_disp *disp = nv50_disp(drm->dev);
struct nv50_core *core = disp->core; struct nv50_core *core = disp->core;
struct nv50_mstm *mstm; struct nv50_mstm *mstm;
...@@ -1617,6 +1618,22 @@ nv50_disp_atomic_commit_core(struct nouveau_drm *drm, u32 *interlock) ...@@ -1617,6 +1618,22 @@ nv50_disp_atomic_commit_core(struct nouveau_drm *drm, u32 *interlock)
} }
} }
static void
nv50_disp_atomic_commit_wndw(struct drm_atomic_state *state, u32 *interlock)
{
struct drm_plane_state *new_plane_state;
struct drm_plane *plane;
int i;
for_each_new_plane_in_state(state, plane, new_plane_state, i) {
struct nv50_wndw *wndw = nv50_wndw(plane);
if (interlock[wndw->interlock.type] & wndw->interlock.data) {
if (wndw->func->update)
wndw->func->update(wndw, interlock);
}
}
}
static void static void
nv50_disp_atomic_commit_tail(struct drm_atomic_state *state) nv50_disp_atomic_commit_tail(struct drm_atomic_state *state)
{ {
...@@ -1684,7 +1701,8 @@ nv50_disp_atomic_commit_tail(struct drm_atomic_state *state) ...@@ -1684,7 +1701,8 @@ nv50_disp_atomic_commit_tail(struct drm_atomic_state *state)
help->disable(encoder); help->disable(encoder);
interlock[NV50_DISP_INTERLOCK_CORE] |= 1; interlock[NV50_DISP_INTERLOCK_CORE] |= 1;
if (outp->flush_disable) { if (outp->flush_disable) {
nv50_disp_atomic_commit_core(drm, interlock); nv50_disp_atomic_commit_wndw(state, interlock);
nv50_disp_atomic_commit_core(state, interlock);
memset(interlock, 0x00, sizeof(interlock)); memset(interlock, 0x00, sizeof(interlock));
} }
} }
...@@ -1693,15 +1711,8 @@ nv50_disp_atomic_commit_tail(struct drm_atomic_state *state) ...@@ -1693,15 +1711,8 @@ nv50_disp_atomic_commit_tail(struct drm_atomic_state *state)
/* Flush disable. */ /* Flush disable. */
if (interlock[NV50_DISP_INTERLOCK_CORE]) { if (interlock[NV50_DISP_INTERLOCK_CORE]) {
if (atom->flush_disable) { if (atom->flush_disable) {
for_each_new_plane_in_state(state, plane, new_plane_state, i) { nv50_disp_atomic_commit_wndw(state, interlock);
struct nv50_wndw *wndw = nv50_wndw(plane); nv50_disp_atomic_commit_core(state, interlock);
if (interlock[wndw->interlock.type] & wndw->interlock.data) {
if (wndw->func->update)
wndw->func->update(wndw, interlock);
}
}
nv50_disp_atomic_commit_core(drm, interlock);
memset(interlock, 0x00, sizeof(interlock)); memset(interlock, 0x00, sizeof(interlock));
} }
} }
...@@ -1762,18 +1773,14 @@ nv50_disp_atomic_commit_tail(struct drm_atomic_state *state) ...@@ -1762,18 +1773,14 @@ nv50_disp_atomic_commit_tail(struct drm_atomic_state *state)
} }
/* Flush update. */ /* Flush update. */
for_each_new_plane_in_state(state, plane, new_plane_state, i) { nv50_disp_atomic_commit_wndw(state, interlock);
struct nv50_wndw *wndw = nv50_wndw(plane);
if (interlock[wndw->interlock.type] & wndw->interlock.data) {
if (wndw->func->update)
wndw->func->update(wndw, interlock);
}
}
if (interlock[NV50_DISP_INTERLOCK_CORE]) { if (interlock[NV50_DISP_INTERLOCK_CORE]) {
if (interlock[NV50_DISP_INTERLOCK_BASE] || if (interlock[NV50_DISP_INTERLOCK_BASE] ||
interlock[NV50_DISP_INTERLOCK_OVLY] ||
interlock[NV50_DISP_INTERLOCK_WNDW] ||
!atom->state.legacy_cursor_update) !atom->state.legacy_cursor_update)
nv50_disp_atomic_commit_core(drm, interlock); nv50_disp_atomic_commit_core(state, interlock);
else else
disp->core->func->update(disp->core, interlock, false); disp->core->func->update(disp->core, interlock, false);
} }
...@@ -1871,7 +1878,7 @@ nv50_disp_atomic_commit(struct drm_device *dev, ...@@ -1871,7 +1878,7 @@ nv50_disp_atomic_commit(struct drm_device *dev,
nv50_disp_atomic_commit_tail(state); nv50_disp_atomic_commit_tail(state);
drm_for_each_crtc(crtc, dev) { drm_for_each_crtc(crtc, dev) {
if (crtc->state->enable) { if (crtc->state->active) {
if (!drm->have_disp_power_ref) { if (!drm->have_disp_power_ref) {
drm->have_disp_power_ref = true; drm->have_disp_power_ref = true;
return 0; return 0;
...@@ -2119,10 +2126,6 @@ nv50_display_destroy(struct drm_device *dev) ...@@ -2119,10 +2126,6 @@ nv50_display_destroy(struct drm_device *dev)
kfree(disp); kfree(disp);
} }
MODULE_PARM_DESC(atomic, "Expose atomic ioctl (default: disabled)");
static int nouveau_atomic = 0;
module_param_named(atomic, nouveau_atomic, int, 0400);
int int
nv50_display_create(struct drm_device *dev) nv50_display_create(struct drm_device *dev)
{ {
...@@ -2147,8 +2150,6 @@ nv50_display_create(struct drm_device *dev) ...@@ -2147,8 +2150,6 @@ nv50_display_create(struct drm_device *dev)
disp->disp = &nouveau_display(dev)->disp; disp->disp = &nouveau_display(dev)->disp;
dev->mode_config.funcs = &nv50_disp_func; dev->mode_config.funcs = &nv50_disp_func;
dev->driver->driver_features |= DRIVER_PREFER_XBGR_30BPP; dev->driver->driver_features |= DRIVER_PREFER_XBGR_30BPP;
if (nouveau_atomic)
dev->driver->driver_features |= DRIVER_ATOMIC;
/* small shared memory area we use for notifiers and semaphores */ /* small shared memory area we use for notifiers and semaphores */
ret = nouveau_bo_new(&drm->client, 4096, 0x1000, TTM_PL_FLAG_VRAM, ret = nouveau_bo_new(&drm->client, 4096, 0x1000, TTM_PL_FLAG_VRAM,
......
...@@ -267,6 +267,7 @@ nouveau_backlight_init(struct drm_device *dev) ...@@ -267,6 +267,7 @@ nouveau_backlight_init(struct drm_device *dev)
struct nouveau_drm *drm = nouveau_drm(dev); struct nouveau_drm *drm = nouveau_drm(dev);
struct nvif_device *device = &drm->client.device; struct nvif_device *device = &drm->client.device;
struct drm_connector *connector; struct drm_connector *connector;
struct drm_connector_list_iter conn_iter;
INIT_LIST_HEAD(&drm->bl_connectors); INIT_LIST_HEAD(&drm->bl_connectors);
...@@ -275,7 +276,8 @@ nouveau_backlight_init(struct drm_device *dev) ...@@ -275,7 +276,8 @@ nouveau_backlight_init(struct drm_device *dev)
return 0; return 0;
} }
list_for_each_entry(connector, &dev->mode_config.connector_list, head) { drm_connector_list_iter_begin(dev, &conn_iter);
drm_for_each_connector_iter(connector, &conn_iter) {
if (connector->connector_type != DRM_MODE_CONNECTOR_LVDS && if (connector->connector_type != DRM_MODE_CONNECTOR_LVDS &&
connector->connector_type != DRM_MODE_CONNECTOR_eDP) connector->connector_type != DRM_MODE_CONNECTOR_eDP)
continue; continue;
...@@ -292,7 +294,7 @@ nouveau_backlight_init(struct drm_device *dev) ...@@ -292,7 +294,7 @@ nouveau_backlight_init(struct drm_device *dev)
break; break;
} }
} }
drm_connector_list_iter_end(&conn_iter);
return 0; return 0;
} }
......
...@@ -1208,14 +1208,19 @@ nouveau_connector_create(struct drm_device *dev, int index) ...@@ -1208,14 +1208,19 @@ nouveau_connector_create(struct drm_device *dev, int index)
struct nouveau_display *disp = nouveau_display(dev); struct nouveau_display *disp = nouveau_display(dev);
struct nouveau_connector *nv_connector = NULL; struct nouveau_connector *nv_connector = NULL;
struct drm_connector *connector; struct drm_connector *connector;
struct drm_connector_list_iter conn_iter;
int type, ret = 0; int type, ret = 0;
bool dummy; bool dummy;
list_for_each_entry(connector, &dev->mode_config.connector_list, head) { drm_connector_list_iter_begin(dev, &conn_iter);
nouveau_for_each_non_mst_connector_iter(connector, &conn_iter) {
nv_connector = nouveau_connector(connector); nv_connector = nouveau_connector(connector);
if (nv_connector->index == index) if (nv_connector->index == index) {
drm_connector_list_iter_end(&conn_iter);
return connector; return connector;
}
} }
drm_connector_list_iter_end(&conn_iter);
nv_connector = kzalloc(sizeof(*nv_connector), GFP_KERNEL); nv_connector = kzalloc(sizeof(*nv_connector), GFP_KERNEL);
if (!nv_connector) if (!nv_connector)
......
...@@ -33,6 +33,7 @@ ...@@ -33,6 +33,7 @@
#include <drm/drm_encoder.h> #include <drm/drm_encoder.h>
#include <drm/drm_dp_helper.h> #include <drm/drm_dp_helper.h>
#include "nouveau_crtc.h" #include "nouveau_crtc.h"
#include "nouveau_encoder.h"
struct nvkm_i2c_port; struct nvkm_i2c_port;
...@@ -60,19 +61,46 @@ static inline struct nouveau_connector *nouveau_connector( ...@@ -60,19 +61,46 @@ static inline struct nouveau_connector *nouveau_connector(
return container_of(con, struct nouveau_connector, base); return container_of(con, struct nouveau_connector, base);
} }
static inline bool
nouveau_connector_is_mst(struct drm_connector *connector)
{
const struct nouveau_encoder *nv_encoder;
const struct drm_encoder *encoder;
if (connector->connector_type != DRM_MODE_CONNECTOR_DisplayPort)
return false;
nv_encoder = find_encoder(connector, DCB_OUTPUT_ANY);
if (!nv_encoder)
return false;
encoder = &nv_encoder->base.base;
return encoder->encoder_type == DRM_MODE_ENCODER_DPMST;
}
#define nouveau_for_each_non_mst_connector_iter(connector, iter) \
drm_for_each_connector_iter(connector, iter) \
for_each_if(!nouveau_connector_is_mst(connector))
static inline struct nouveau_connector * static inline struct nouveau_connector *
nouveau_crtc_connector_get(struct nouveau_crtc *nv_crtc) nouveau_crtc_connector_get(struct nouveau_crtc *nv_crtc)
{ {
struct drm_device *dev = nv_crtc->base.dev; struct drm_device *dev = nv_crtc->base.dev;
struct drm_connector *connector; struct drm_connector *connector;
struct drm_connector_list_iter conn_iter;
struct nouveau_connector *nv_connector = NULL;
struct drm_crtc *crtc = to_drm_crtc(nv_crtc); struct drm_crtc *crtc = to_drm_crtc(nv_crtc);
list_for_each_entry(connector, &dev->mode_config.connector_list, head) { drm_connector_list_iter_begin(dev, &conn_iter);
if (connector->encoder && connector->encoder->crtc == crtc) nouveau_for_each_non_mst_connector_iter(connector, &conn_iter) {
return nouveau_connector(connector); if (connector->encoder && connector->encoder->crtc == crtc) {
nv_connector = nouveau_connector(connector);
break;
}
} }
drm_connector_list_iter_end(&conn_iter);
return NULL; return nv_connector;
} }
struct drm_connector * struct drm_connector *
......
...@@ -404,6 +404,7 @@ nouveau_display_init(struct drm_device *dev) ...@@ -404,6 +404,7 @@ nouveau_display_init(struct drm_device *dev)
struct nouveau_display *disp = nouveau_display(dev); struct nouveau_display *disp = nouveau_display(dev);
struct nouveau_drm *drm = nouveau_drm(dev); struct nouveau_drm *drm = nouveau_drm(dev);
struct drm_connector *connector; struct drm_connector *connector;
struct drm_connector_list_iter conn_iter;
int ret; int ret;
ret = disp->init(dev); ret = disp->init(dev);
...@@ -411,10 +412,12 @@ nouveau_display_init(struct drm_device *dev) ...@@ -411,10 +412,12 @@ nouveau_display_init(struct drm_device *dev)
return ret; return ret;
/* enable hotplug interrupts */ /* enable hotplug interrupts */
list_for_each_entry(connector, &dev->mode_config.connector_list, head) { drm_connector_list_iter_begin(dev, &conn_iter);
nouveau_for_each_non_mst_connector_iter(connector, &conn_iter) {
struct nouveau_connector *conn = nouveau_connector(connector); struct nouveau_connector *conn = nouveau_connector(connector);
nvif_notify_get(&conn->hpd); nvif_notify_get(&conn->hpd);
} }
drm_connector_list_iter_end(&conn_iter);
/* enable flip completion events */ /* enable flip completion events */
nvif_notify_get(&drm->flip); nvif_notify_get(&drm->flip);
...@@ -427,6 +430,7 @@ nouveau_display_fini(struct drm_device *dev, bool suspend) ...@@ -427,6 +430,7 @@ nouveau_display_fini(struct drm_device *dev, bool suspend)
struct nouveau_display *disp = nouveau_display(dev); struct nouveau_display *disp = nouveau_display(dev);
struct nouveau_drm *drm = nouveau_drm(dev); struct nouveau_drm *drm = nouveau_drm(dev);
struct drm_connector *connector; struct drm_connector *connector;
struct drm_connector_list_iter conn_iter;
if (!suspend) { if (!suspend) {
if (drm_drv_uses_atomic_modeset(dev)) if (drm_drv_uses_atomic_modeset(dev))
...@@ -439,10 +443,12 @@ nouveau_display_fini(struct drm_device *dev, bool suspend) ...@@ -439,10 +443,12 @@ nouveau_display_fini(struct drm_device *dev, bool suspend)
nvif_notify_put(&drm->flip); nvif_notify_put(&drm->flip);
/* disable hotplug interrupts */ /* disable hotplug interrupts */
list_for_each_entry(connector, &dev->mode_config.connector_list, head) { drm_connector_list_iter_begin(dev, &conn_iter);
nouveau_for_each_non_mst_connector_iter(connector, &conn_iter) {
struct nouveau_connector *conn = nouveau_connector(connector); struct nouveau_connector *conn = nouveau_connector(connector);
nvif_notify_put(&conn->hpd); nvif_notify_put(&conn->hpd);
} }
drm_connector_list_iter_end(&conn_iter);
drm_kms_helper_poll_disable(dev); drm_kms_helper_poll_disable(dev);
disp->fini(dev); disp->fini(dev);
......
...@@ -81,6 +81,10 @@ MODULE_PARM_DESC(modeset, "enable driver (default: auto, " ...@@ -81,6 +81,10 @@ MODULE_PARM_DESC(modeset, "enable driver (default: auto, "
int nouveau_modeset = -1; int nouveau_modeset = -1;
module_param_named(modeset, nouveau_modeset, int, 0400); module_param_named(modeset, nouveau_modeset, int, 0400);
MODULE_PARM_DESC(atomic, "Expose atomic ioctl (default: disabled)");
static int nouveau_atomic = 0;
module_param_named(atomic, nouveau_atomic, int, 0400);
MODULE_PARM_DESC(runpm, "disable (0), force enable (1), optimus only default (-1)"); MODULE_PARM_DESC(runpm, "disable (0), force enable (1), optimus only default (-1)");
static int nouveau_runtime_pm = -1; static int nouveau_runtime_pm = -1;
module_param_named(runpm, nouveau_runtime_pm, int, 0400); module_param_named(runpm, nouveau_runtime_pm, int, 0400);
...@@ -509,6 +513,9 @@ static int nouveau_drm_probe(struct pci_dev *pdev, ...@@ -509,6 +513,9 @@ static int nouveau_drm_probe(struct pci_dev *pdev,
pci_set_master(pdev); pci_set_master(pdev);
if (nouveau_atomic)
driver_pci.driver_features |= DRIVER_ATOMIC;
ret = drm_get_pci_dev(pdev, pent, &driver_pci); ret = drm_get_pci_dev(pdev, pent, &driver_pci);
if (ret) { if (ret) {
nvkm_device_del(&device); nvkm_device_del(&device);
...@@ -874,22 +881,11 @@ nouveau_pmops_runtime_resume(struct device *dev) ...@@ -874,22 +881,11 @@ nouveau_pmops_runtime_resume(struct device *dev)
static int static int
nouveau_pmops_runtime_idle(struct device *dev) nouveau_pmops_runtime_idle(struct device *dev)
{ {
struct pci_dev *pdev = to_pci_dev(dev);
struct drm_device *drm_dev = pci_get_drvdata(pdev);
struct nouveau_drm *drm = nouveau_drm(drm_dev);
struct drm_crtc *crtc;
if (!nouveau_pmops_runtime()) { if (!nouveau_pmops_runtime()) {
pm_runtime_forbid(dev); pm_runtime_forbid(dev);
return -EBUSY; return -EBUSY;
} }
list_for_each_entry(crtc, &drm->dev->mode_config.crtc_list, head) {
if (crtc->enabled) {
DRM_DEBUG_DRIVER("failing to power off - crtc active\n");
return -EBUSY;
}
}
pm_runtime_mark_last_busy(dev); pm_runtime_mark_last_busy(dev);
pm_runtime_autosuspend(dev); pm_runtime_autosuspend(dev);
/* we don't want the main rpm_idle to call suspend - we want to autosuspend */ /* we don't want the main rpm_idle to call suspend - we want to autosuspend */
......
...@@ -616,7 +616,7 @@ nouveau_gem_pushbuf_reloc_apply(struct nouveau_cli *cli, ...@@ -616,7 +616,7 @@ nouveau_gem_pushbuf_reloc_apply(struct nouveau_cli *cli,
struct nouveau_bo *nvbo; struct nouveau_bo *nvbo;
uint32_t data; uint32_t data;
if (unlikely(r->bo_index > req->nr_buffers)) { if (unlikely(r->bo_index >= req->nr_buffers)) {
NV_PRINTK(err, cli, "reloc bo index invalid\n"); NV_PRINTK(err, cli, "reloc bo index invalid\n");
ret = -EINVAL; ret = -EINVAL;
break; break;
...@@ -626,7 +626,7 @@ nouveau_gem_pushbuf_reloc_apply(struct nouveau_cli *cli, ...@@ -626,7 +626,7 @@ nouveau_gem_pushbuf_reloc_apply(struct nouveau_cli *cli,
if (b->presumed.valid) if (b->presumed.valid)
continue; continue;
if (unlikely(r->reloc_bo_index > req->nr_buffers)) { if (unlikely(r->reloc_bo_index >= req->nr_buffers)) {
NV_PRINTK(err, cli, "reloc container bo index invalid\n"); NV_PRINTK(err, cli, "reloc container bo index invalid\n");
ret = -EINVAL; ret = -EINVAL;
break; break;
......
...@@ -140,6 +140,9 @@ nvkm_fb_init(struct nvkm_subdev *subdev) ...@@ -140,6 +140,9 @@ nvkm_fb_init(struct nvkm_subdev *subdev)
if (fb->func->init) if (fb->func->init)
fb->func->init(fb); fb->func->init(fb);
if (fb->func->init_remapper)
fb->func->init_remapper(fb);
if (fb->func->init_page) { if (fb->func->init_page) {
ret = fb->func->init_page(fb); ret = fb->func->init_page(fb);
if (WARN_ON(ret)) if (WARN_ON(ret))
......
...@@ -36,6 +36,14 @@ gp100_fb_init_unkn(struct nvkm_fb *base) ...@@ -36,6 +36,14 @@ gp100_fb_init_unkn(struct nvkm_fb *base)
nvkm_wr32(device, 0x1faccc, nvkm_rd32(device, 0x100ccc)); nvkm_wr32(device, 0x1faccc, nvkm_rd32(device, 0x100ccc));
} }
void
gp100_fb_init_remapper(struct nvkm_fb *fb)
{
struct nvkm_device *device = fb->subdev.device;
/* Disable address remapper. */
nvkm_mask(device, 0x100c14, 0x00040000, 0x00000000);
}
void void
gp100_fb_init(struct nvkm_fb *base) gp100_fb_init(struct nvkm_fb *base)
{ {
...@@ -56,6 +64,7 @@ gp100_fb = { ...@@ -56,6 +64,7 @@ gp100_fb = {
.dtor = gf100_fb_dtor, .dtor = gf100_fb_dtor,
.oneinit = gf100_fb_oneinit, .oneinit = gf100_fb_oneinit,
.init = gp100_fb_init, .init = gp100_fb_init,
.init_remapper = gp100_fb_init_remapper,
.init_page = gm200_fb_init_page, .init_page = gm200_fb_init_page,
.init_unkn = gp100_fb_init_unkn, .init_unkn = gp100_fb_init_unkn,
.ram_new = gp100_ram_new, .ram_new = gp100_ram_new,
......
...@@ -31,6 +31,7 @@ gp102_fb = { ...@@ -31,6 +31,7 @@ gp102_fb = {
.dtor = gf100_fb_dtor, .dtor = gf100_fb_dtor,
.oneinit = gf100_fb_oneinit, .oneinit = gf100_fb_oneinit,
.init = gp100_fb_init, .init = gp100_fb_init,
.init_remapper = gp100_fb_init_remapper,
.init_page = gm200_fb_init_page, .init_page = gm200_fb_init_page,
.ram_new = gp100_ram_new, .ram_new = gp100_ram_new,
}; };
......
...@@ -11,6 +11,7 @@ struct nvkm_fb_func { ...@@ -11,6 +11,7 @@ struct nvkm_fb_func {
u32 (*tags)(struct nvkm_fb *); u32 (*tags)(struct nvkm_fb *);
int (*oneinit)(struct nvkm_fb *); int (*oneinit)(struct nvkm_fb *);
void (*init)(struct nvkm_fb *); void (*init)(struct nvkm_fb *);
void (*init_remapper)(struct nvkm_fb *);
int (*init_page)(struct nvkm_fb *); int (*init_page)(struct nvkm_fb *);
void (*init_unkn)(struct nvkm_fb *); void (*init_unkn)(struct nvkm_fb *);
void (*intr)(struct nvkm_fb *); void (*intr)(struct nvkm_fb *);
...@@ -69,5 +70,6 @@ int gf100_fb_init_page(struct nvkm_fb *); ...@@ -69,5 +70,6 @@ int gf100_fb_init_page(struct nvkm_fb *);
int gm200_fb_init_page(struct nvkm_fb *); int gm200_fb_init_page(struct nvkm_fb *);
void gp100_fb_init_remapper(struct nvkm_fb *);
void gp100_fb_init_unkn(struct nvkm_fb *); void gp100_fb_init_unkn(struct nvkm_fb *);
#endif #endif
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment