From f77f13e22df4a40d237697df496152c8c37f3f2b Mon Sep 17 00:00:00 2001 From: Gilles Espinasse Date: Mon, 29 Mar 2010 15:41:47 +0200 Subject: Fix comment and Kconfig typos for 'require' and 'fragment' Signed-off-by: Gilles Espinasse Signed-off-by: Jiri Kosina --- drivers/gpu/drm/radeon/atombios.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers/gpu/drm/radeon') diff --git a/drivers/gpu/drm/radeon/atombios.h b/drivers/gpu/drm/radeon/atombios.h index 6732b5dd8ff4..e91a815861f4 100644 --- a/drivers/gpu/drm/radeon/atombios.h +++ b/drivers/gpu/drm/radeon/atombios.h @@ -3780,7 +3780,7 @@ typedef struct _ATOM_ASIC_SS_ASSIGNMENT UCHAR ucReserved[2]; }ATOM_ASIC_SS_ASSIGNMENT; -//Define ucClockIndication, SW uses the IDs below to search if the SS is requried/enabled on a clock branch/signal type. +//Define ucClockIndication, SW uses the IDs below to search if the SS is required/enabled on a clock branch/signal type. //SS is not required or enabled if a match is not found. #define ASIC_INTERNAL_MEMORY_SS 1 #define ASIC_INTERNAL_ENGINE_SS 2 @@ -5895,7 +5895,7 @@ typedef struct _ATOM_PPLIB_RS780_CLOCK_INFO UCHAR ucPadding; // For proper alignment and size. USHORT usVDDC; // For the 780, use: None, Low, High, Variable UCHAR ucMaxHTLinkWidth; // From SBIOS - {2, 4, 8, 16} - UCHAR ucMinHTLinkWidth; // From SBIOS - {2, 4, 8, 16}. Effective only if CDLW enabled. Minimum down stream width could be bigger as display BW requriement. + UCHAR ucMinHTLinkWidth; // From SBIOS - {2, 4, 8, 16}. Effective only if CDLW enabled. Minimum down stream width could be bigger as display BW requirement. USHORT usHTLinkFreq; // See definition ATOM_PPLIB_RS780_HTLINKFREQ_xxx or in MHz(>=200). ULONG ulFlags; } ATOM_PPLIB_RS780_CLOCK_INFO; -- cgit v1.2.3 From 7466f4cc508878a8328dff1c328a2b4108888d2e Mon Sep 17 00:00:00 2001 From: Adam Jackson Date: Mon, 29 Mar 2010 21:43:23 +0000 Subject: drm/edid: Remove arbitrary EDID extension limit Signed-off-by: Adam Jackson Signed-off-by: Dave Airlie --- drivers/gpu/drm/drm_crtc.c | 7 +++++-- drivers/gpu/drm/drm_edid.c | 19 +++++-------------- drivers/gpu/drm/drm_sysfs.c | 2 +- drivers/gpu/drm/radeon/radeon_combios.c | 8 ++++---- include/drm/drm_edid.h | 3 --- 5 files changed, 15 insertions(+), 24 deletions(-) (limited to 'drivers/gpu/drm/radeon') diff --git a/drivers/gpu/drm/drm_crtc.c b/drivers/gpu/drm/drm_crtc.c index d91fb8c0b7b3..aa24f2f9dc0a 100644 --- a/drivers/gpu/drm/drm_crtc.c +++ b/drivers/gpu/drm/drm_crtc.c @@ -33,6 +33,7 @@ #include "drm.h" #include "drmP.h" #include "drm_crtc.h" +#include "drm_edid.h" struct drm_prop_enum_list { int type; @@ -2349,7 +2350,7 @@ int drm_mode_connector_update_edid_property(struct drm_connector *connector, struct edid *edid) { struct drm_device *dev = connector->dev; - int ret = 0; + int ret = 0, size; if (connector->edid_blob_ptr) drm_property_destroy_blob(dev, connector->edid_blob_ptr); @@ -2361,7 +2362,9 @@ int drm_mode_connector_update_edid_property(struct drm_connector *connector, return ret; } - connector->edid_blob_ptr = drm_property_create_blob(connector->dev, 128, edid); + size = EDID_LENGTH * (1 + edid->extensions); + connector->edid_blob_ptr = drm_property_create_blob(connector->dev, + size, edid); ret = drm_connector_property_set_value(connector, dev->mode_config.edid_property, diff --git a/drivers/gpu/drm/drm_edid.c b/drivers/gpu/drm/drm_edid.c index 58b67932f04a..cf24ecab6a4a 100644 --- a/drivers/gpu/drm/drm_edid.c +++ b/drivers/gpu/drm/drm_edid.c @@ -1325,7 +1325,6 @@ static int add_detailed_info_eedid(struct drm_connector *connector, int i, modes = 0; char *edid_ext = NULL; struct detailed_timing *timing; - int edid_ext_num; int start_offset, end_offset; int timing_level; @@ -1342,19 +1341,15 @@ static int add_detailed_info_eedid(struct drm_connector *connector, return 0; } - /* Chose real EDID extension number */ - edid_ext_num = edid->extensions > DRM_MAX_EDID_EXT_NUM ? - DRM_MAX_EDID_EXT_NUM : edid->extensions; - /* Find CEA extension */ - for (i = 0; i < edid_ext_num; i++) { + for (i = 0; i < edid->extensions; i++) { edid_ext = (char *)edid + EDID_LENGTH * (i + 1); /* This block is CEA extension */ if (edid_ext[0] == 0x02) break; } - if (i == edid_ext_num) { + if (i == edid->extensions) { /* if there is no additional timing EDID block, return */ return 0; } @@ -1393,7 +1388,7 @@ static int add_detailed_info_eedid(struct drm_connector *connector, bool drm_detect_hdmi_monitor(struct edid *edid) { char *edid_ext = NULL; - int i, hdmi_id, edid_ext_num; + int i, hdmi_id; int start_offset, end_offset; bool is_hdmi = false; @@ -1401,19 +1396,15 @@ bool drm_detect_hdmi_monitor(struct edid *edid) if (edid == NULL || edid->extensions == 0) goto end; - /* Chose real EDID extension number */ - edid_ext_num = edid->extensions > DRM_MAX_EDID_EXT_NUM ? - DRM_MAX_EDID_EXT_NUM : edid->extensions; - /* Find CEA extension */ - for (i = 0; i < edid_ext_num; i++) { + for (i = 0; i < edid->extensions; i++) { edid_ext = (char *)edid + EDID_LENGTH * (i + 1); /* This block is CEA extension */ if (edid_ext[0] == 0x02) break; } - if (i == edid_ext_num) + if (i == edid->extensions) goto end; /* Data block offset in CEA extension block */ diff --git a/drivers/gpu/drm/drm_sysfs.c b/drivers/gpu/drm/drm_sysfs.c index 014ce24761b9..7b7c83f6041a 100644 --- a/drivers/gpu/drm/drm_sysfs.c +++ b/drivers/gpu/drm/drm_sysfs.c @@ -332,7 +332,7 @@ static struct device_attribute connector_attrs_opt1[] = { static struct bin_attribute edid_attr = { .attr.name = "edid", .attr.mode = 0444, - .size = 128, + .size = 0, .read = edid_show, }; diff --git a/drivers/gpu/drm/radeon/radeon_combios.c b/drivers/gpu/drm/radeon/radeon_combios.c index 2becdeda68a3..20f38b85c70a 100644 --- a/drivers/gpu/drm/radeon/radeon_combios.c +++ b/drivers/gpu/drm/radeon/radeon_combios.c @@ -450,17 +450,17 @@ bool radeon_combios_check_hardcoded_edid(struct radeon_device *rdev) { int edid_info; struct edid *edid; + unsigned char *raw; edid_info = combios_get_table_offset(rdev->ddev, COMBIOS_HARDCODED_EDID_TABLE); if (!edid_info) return false; - edid = kmalloc(EDID_LENGTH * (DRM_MAX_EDID_EXT_NUM + 1), - GFP_KERNEL); + raw = rdev->bios + edid_info; + edid = kmalloc(EDID_LENGTH * (raw[0x7e] + 1), GFP_KERNEL); if (edid == NULL) return false; - memcpy((unsigned char *)edid, - (unsigned char *)(rdev->bios + edid_info), EDID_LENGTH); + memcpy((unsigned char *)edid, raw, EDID_LENGTH * (raw[0x7e] + 1)); if (!drm_edid_is_valid(edid)) { kfree(edid); diff --git a/include/drm/drm_edid.h b/include/drm/drm_edid.h index b4209898f115..d33c3e038606 100644 --- a/include/drm/drm_edid.h +++ b/include/drm/drm_edid.h @@ -201,7 +201,4 @@ struct edid { #define EDID_PRODUCT_ID(e) ((e)->prod_code[0] | ((e)->prod_code[1] << 8)) -/* define the number of Extension EDID block */ -#define DRM_MAX_EDID_EXT_NUM 4 - #endif /* __DRM_EDID_H__ */ -- cgit v1.2.3 From 225758d8ba4fdcc1e8c9cf617fd89529bd4a9596 Mon Sep 17 00:00:00 2001 From: Jerome Glisse Date: Tue, 9 Mar 2010 14:45:10 +0000 Subject: drm/radeon/kms: fence cleanup + more reliable GPU lockup detection V4 This patch cleanup the fence code, it drops the timeout field of fence as the time to complete each IB is unpredictable and shouldn't be bound. The fence cleanup lead to GPU lockup detection improvement, this patch introduce a callback, allowing to do asic specific test for lockup detection. In this patch the CP is use as a first indicator of GPU lockup. If CP doesn't make progress during 1second we assume we are facing a GPU lockup. To avoid overhead of testing GPU lockup frequently due to fence taking time to be signaled we query the lockup callback every 500msec. There is plenty code comment explaining the design & choise inside the code. This have been tested mostly on R3XX/R5XX hw, in normal running destkop (compiz firefox, quake3 running) the lockup callback wasn't call once (1 hour session). Also tested with forcing GPU lockup and lockup was reported after the 1s CP activity timeout. V2 switch to 500ms timeout so GPU lockup get call at least 2 times in less than 2sec. V3 store last jiffies in fence struct so on ERESTART, EBUSY we keep track of how long we already wait for a given fence V4 make sure we got up to date cp read pointer so we don't have false positive Signed-off-by: Jerome Glisse Signed-off-by: Dave Airlie --- drivers/gpu/drm/radeon/evergreen.c | 6 ++ drivers/gpu/drm/radeon/r100.c | 86 ++++++++++++++++++++++++++++ drivers/gpu/drm/radeon/r300.c | 28 ++++++++- drivers/gpu/drm/radeon/r600.c | 34 +++++++++-- drivers/gpu/drm/radeon/radeon.h | 104 +++++++++++++++++++--------------- drivers/gpu/drm/radeon/radeon_asic.c | 15 ++++- drivers/gpu/drm/radeon/radeon_asic.h | 7 ++- drivers/gpu/drm/radeon/radeon_fence.c | 102 ++++++++++++++++++--------------- drivers/gpu/drm/radeon/rv770.c | 6 -- 9 files changed, 281 insertions(+), 107 deletions(-) (limited to 'drivers/gpu/drm/radeon') diff --git a/drivers/gpu/drm/radeon/evergreen.c b/drivers/gpu/drm/radeon/evergreen.c index 647a0efdc353..3070e5994120 100644 --- a/drivers/gpu/drm/radeon/evergreen.c +++ b/drivers/gpu/drm/radeon/evergreen.c @@ -486,6 +486,12 @@ int evergreen_mc_init(struct radeon_device *rdev) return 0; } +bool evergreen_gpu_is_lockup(struct radeon_device *rdev) +{ + /* FIXME: implement for evergreen */ + return false; +} + int evergreen_gpu_reset(struct radeon_device *rdev) { /* FIXME: implement for evergreen */ diff --git a/drivers/gpu/drm/radeon/r100.c b/drivers/gpu/drm/radeon/r100.c index 3ae51ada1abf..845c8f3063fe 100644 --- a/drivers/gpu/drm/radeon/r100.c +++ b/drivers/gpu/drm/radeon/r100.c @@ -1777,6 +1777,92 @@ int r100_rb2d_reset(struct radeon_device *rdev) return -1; } +void r100_gpu_lockup_update(struct r100_gpu_lockup *lockup, struct radeon_cp *cp) +{ + lockup->last_cp_rptr = cp->rptr; + lockup->last_jiffies = jiffies; +} + +/** + * r100_gpu_cp_is_lockup() - check if CP is lockup by recording information + * @rdev: radeon device structure + * @lockup: r100_gpu_lockup structure holding CP lockup tracking informations + * @cp: radeon_cp structure holding CP information + * + * We don't need to initialize the lockup tracking information as we will either + * have CP rptr to a different value of jiffies wrap around which will force + * initialization of the lockup tracking informations. + * + * A possible false positivie is if we get call after while and last_cp_rptr == + * the current CP rptr, even if it's unlikely it might happen. To avoid this + * if the elapsed time since last call is bigger than 2 second than we return + * false and update the tracking information. Due to this the caller must call + * r100_gpu_cp_is_lockup several time in less than 2sec for lockup to be reported + * the fencing code should be cautious about that. + * + * Caller should write to the ring to force CP to do something so we don't get + * false positive when CP is just gived nothing to do. + * + **/ +bool r100_gpu_cp_is_lockup(struct radeon_device *rdev, struct r100_gpu_lockup *lockup, struct radeon_cp *cp) +{ + unsigned long cjiffies, elapsed; + + cjiffies = jiffies; + if (!time_after(cjiffies, lockup->last_jiffies)) { + /* likely a wrap around */ + lockup->last_cp_rptr = cp->rptr; + lockup->last_jiffies = jiffies; + return false; + } + if (cp->rptr != lockup->last_cp_rptr) { + /* CP is still working no lockup */ + lockup->last_cp_rptr = cp->rptr; + lockup->last_jiffies = jiffies; + return false; + } + elapsed = jiffies_to_msecs(cjiffies - lockup->last_jiffies); + if (elapsed >= 3000) { + /* very likely the improbable case where current + * rptr is equal to last recorded, a while ago, rptr + * this is more likely a false positive update tracking + * information which should force us to be recall at + * latter point + */ + lockup->last_cp_rptr = cp->rptr; + lockup->last_jiffies = jiffies; + return false; + } + if (elapsed >= 1000) { + dev_err(rdev->dev, "GPU lockup CP stall for more than %lumsec\n", elapsed); + return true; + } + /* give a chance to the GPU ... */ + return false; +} + +bool r100_gpu_is_lockup(struct radeon_device *rdev) +{ + u32 rbbm_status; + int r; + + rbbm_status = RREG32(R_000E40_RBBM_STATUS); + if (!G_000E40_GUI_ACTIVE(rbbm_status)) { + r100_gpu_lockup_update(&rdev->config.r100.lockup, &rdev->cp); + return false; + } + /* force CP activities */ + r = radeon_ring_lock(rdev, 2); + if (!r) { + /* PACKET2 NOP */ + radeon_ring_write(rdev, 0x80000000); + radeon_ring_write(rdev, 0x80000000); + radeon_ring_unlock_commit(rdev); + } + rdev->cp.rptr = RREG32(RADEON_CP_RB_RPTR); + return r100_gpu_cp_is_lockup(rdev, &rdev->config.r100.lockup, &rdev->cp); +} + int r100_gpu_reset(struct radeon_device *rdev) { uint32_t status; diff --git a/drivers/gpu/drm/radeon/r300.c b/drivers/gpu/drm/radeon/r300.c index 0e9eb761a90f..9825fb19331f 100644 --- a/drivers/gpu/drm/radeon/r300.c +++ b/drivers/gpu/drm/radeon/r300.c @@ -26,8 +26,9 @@ * Jerome Glisse */ #include -#include "drmP.h" -#include "drm.h" +#include +#include +#include #include "radeon_reg.h" #include "radeon.h" #include "radeon_asic.h" @@ -426,12 +427,35 @@ int r300_ga_reset(struct radeon_device *rdev) return -1; } +bool r300_gpu_is_lockup(struct radeon_device *rdev) +{ + u32 rbbm_status; + int r; + + rbbm_status = RREG32(R_000E40_RBBM_STATUS); + if (!G_000E40_GUI_ACTIVE(rbbm_status)) { + r100_gpu_lockup_update(&rdev->config.r300.lockup, &rdev->cp); + return false; + } + /* force CP activities */ + r = radeon_ring_lock(rdev, 2); + if (!r) { + /* PACKET2 NOP */ + radeon_ring_write(rdev, 0x80000000); + radeon_ring_write(rdev, 0x80000000); + radeon_ring_unlock_commit(rdev); + } + rdev->cp.rptr = RREG32(RADEON_CP_RB_RPTR); + return r100_gpu_cp_is_lockup(rdev, &rdev->config.r300.lockup, &rdev->cp); +} + int r300_gpu_reset(struct radeon_device *rdev) { uint32_t status; /* reset order likely matter */ status = RREG32(RADEON_RBBM_STATUS); + dev_info(rdev->dev, "(%s:%d) RBBM_STATUS=0x%08X\n", __func__, __LINE__, status); /* reset HDP */ r100_hdp_reset(rdev); /* reset rb2d */ diff --git a/drivers/gpu/drm/radeon/r600.c b/drivers/gpu/drm/radeon/r600.c index 5509354c7c89..a09c062df4db 100644 --- a/drivers/gpu/drm/radeon/r600.c +++ b/drivers/gpu/drm/radeon/r600.c @@ -784,7 +784,7 @@ int r600_gpu_soft_reset(struct radeon_device *rdev) dev_info(rdev->dev, " R_008020_GRBM_SOFT_RESET=0x%08X\n", tmp); WREG32(R_008020_GRBM_SOFT_RESET, tmp); (void)RREG32(R_008020_GRBM_SOFT_RESET); - udelay(50); + mdelay(1); WREG32(R_008020_GRBM_SOFT_RESET, 0); (void)RREG32(R_008020_GRBM_SOFT_RESET); } @@ -824,16 +824,16 @@ int r600_gpu_soft_reset(struct radeon_device *rdev) dev_info(rdev->dev, " R_000E60_SRBM_SOFT_RESET=0x%08X\n", srbm_reset); WREG32(R_000E60_SRBM_SOFT_RESET, srbm_reset); (void)RREG32(R_000E60_SRBM_SOFT_RESET); - udelay(50); + mdelay(1); WREG32(R_000E60_SRBM_SOFT_RESET, 0); (void)RREG32(R_000E60_SRBM_SOFT_RESET); WREG32(R_000E60_SRBM_SOFT_RESET, srbm_reset); (void)RREG32(R_000E60_SRBM_SOFT_RESET); - udelay(50); + mdelay(1); WREG32(R_000E60_SRBM_SOFT_RESET, 0); (void)RREG32(R_000E60_SRBM_SOFT_RESET); /* Wait a little for things to settle down */ - udelay(50); + mdelay(1); dev_info(rdev->dev, " R_008010_GRBM_STATUS=0x%08X\n", RREG32(R_008010_GRBM_STATUS)); dev_info(rdev->dev, " R_008014_GRBM_STATUS2=0x%08X\n", @@ -848,6 +848,32 @@ int r600_gpu_soft_reset(struct radeon_device *rdev) return 0; } +bool r600_gpu_is_lockup(struct radeon_device *rdev) +{ + u32 srbm_status; + u32 grbm_status; + u32 grbm_status2; + int r; + + srbm_status = RREG32(R_000E50_SRBM_STATUS); + grbm_status = RREG32(R_008010_GRBM_STATUS); + grbm_status2 = RREG32(R_008014_GRBM_STATUS2); + if (!G_008010_GUI_ACTIVE(grbm_status)) { + r100_gpu_lockup_update(&rdev->config.r300.lockup, &rdev->cp); + return false; + } + /* force CP activities */ + r = radeon_ring_lock(rdev, 2); + if (!r) { + /* PACKET2 NOP */ + radeon_ring_write(rdev, 0x80000000); + radeon_ring_write(rdev, 0x80000000); + radeon_ring_unlock_commit(rdev); + } + rdev->cp.rptr = RREG32(R600_CP_RB_RPTR); + return r100_gpu_cp_is_lockup(rdev, &rdev->config.r300.lockup, &rdev->cp); +} + int r600_gpu_reset(struct radeon_device *rdev) { return r600_gpu_soft_reset(rdev); diff --git a/drivers/gpu/drm/radeon/radeon.h b/drivers/gpu/drm/radeon/radeon.h index 034218c3dbbb..a3d13c367176 100644 --- a/drivers/gpu/drm/radeon/radeon.h +++ b/drivers/gpu/drm/radeon/radeon.h @@ -99,6 +99,7 @@ extern int radeon_hw_i2c; * symbol; */ #define RADEON_MAX_USEC_TIMEOUT 100000 /* 100 ms */ +#define RADEON_FENCE_JIFFIES_TIMEOUT (HZ / 2) /* RADEON_IB_POOL_SIZE must be a power of 2 */ #define RADEON_IB_POOL_SIZE 16 #define RADEON_DEBUGFS_MAX_NUM_FILES 32 @@ -182,7 +183,8 @@ struct radeon_fence_driver { uint32_t scratch_reg; atomic_t seq; uint32_t last_seq; - unsigned long count_timeout; + unsigned long last_jiffies; + unsigned long last_timeout; wait_queue_head_t queue; rwlock_t lock; struct list_head created; @@ -197,7 +199,6 @@ struct radeon_fence { struct list_head list; /* protected by radeon_fence.lock */ uint32_t seq; - unsigned long timeout; bool emited; bool signaled; }; @@ -746,6 +747,7 @@ struct radeon_asic { int (*resume)(struct radeon_device *rdev); int (*suspend)(struct radeon_device *rdev); void (*vga_set_state)(struct radeon_device *rdev, bool state); + bool (*gpu_is_lockup)(struct radeon_device *rdev); int (*gpu_reset)(struct radeon_device *rdev); void (*gart_tlb_flush)(struct radeon_device *rdev); int (*gart_set_page)(struct radeon_device *rdev, int i, uint64_t addr); @@ -804,59 +806,68 @@ struct radeon_asic { /* * Asic structures */ +struct r100_gpu_lockup { + unsigned long last_jiffies; + u32 last_cp_rptr; +}; + struct r100_asic { - const unsigned *reg_safe_bm; - unsigned reg_safe_bm_size; - u32 hdp_cntl; + const unsigned *reg_safe_bm; + unsigned reg_safe_bm_size; + u32 hdp_cntl; + struct r100_gpu_lockup lockup; }; struct r300_asic { - const unsigned *reg_safe_bm; - unsigned reg_safe_bm_size; - u32 resync_scratch; - u32 hdp_cntl; + const unsigned *reg_safe_bm; + unsigned reg_safe_bm_size; + u32 resync_scratch; + u32 hdp_cntl; + struct r100_gpu_lockup lockup; }; struct r600_asic { - unsigned max_pipes; - unsigned max_tile_pipes; - unsigned max_simds; - unsigned max_backends; - unsigned max_gprs; - unsigned max_threads; - unsigned max_stack_entries; - unsigned max_hw_contexts; - unsigned max_gs_threads; - unsigned sx_max_export_size; - unsigned sx_max_export_pos_size; - unsigned sx_max_export_smx_size; - unsigned sq_num_cf_insts; - unsigned tiling_nbanks; - unsigned tiling_npipes; - unsigned tiling_group_size; + unsigned max_pipes; + unsigned max_tile_pipes; + unsigned max_simds; + unsigned max_backends; + unsigned max_gprs; + unsigned max_threads; + unsigned max_stack_entries; + unsigned max_hw_contexts; + unsigned max_gs_threads; + unsigned sx_max_export_size; + unsigned sx_max_export_pos_size; + unsigned sx_max_export_smx_size; + unsigned sq_num_cf_insts; + unsigned tiling_nbanks; + unsigned tiling_npipes; + unsigned tiling_group_size; + struct r100_gpu_lockup lockup; }; struct rv770_asic { - unsigned max_pipes; - unsigned max_tile_pipes; - unsigned max_simds; - unsigned max_backends; - unsigned max_gprs; - unsigned max_threads; - unsigned max_stack_entries; - unsigned max_hw_contexts; - unsigned max_gs_threads; - unsigned sx_max_export_size; - unsigned sx_max_export_pos_size; - unsigned sx_max_export_smx_size; - unsigned sq_num_cf_insts; - unsigned sx_num_of_sets; - unsigned sc_prim_fifo_size; - unsigned sc_hiz_tile_fifo_size; - unsigned sc_earlyz_tile_fifo_fize; - unsigned tiling_nbanks; - unsigned tiling_npipes; - unsigned tiling_group_size; + unsigned max_pipes; + unsigned max_tile_pipes; + unsigned max_simds; + unsigned max_backends; + unsigned max_gprs; + unsigned max_threads; + unsigned max_stack_entries; + unsigned max_hw_contexts; + unsigned max_gs_threads; + unsigned sx_max_export_size; + unsigned sx_max_export_pos_size; + unsigned sx_max_export_smx_size; + unsigned sq_num_cf_insts; + unsigned sx_num_of_sets; + unsigned sc_prim_fifo_size; + unsigned sc_hiz_tile_fifo_size; + unsigned sc_earlyz_tile_fifo_fize; + unsigned tiling_nbanks; + unsigned tiling_npipes; + unsigned tiling_group_size; + struct r100_gpu_lockup lockup; }; union radeon_asic_config { @@ -1145,6 +1156,7 @@ static inline void radeon_ring_write(struct radeon_device *rdev, uint32_t v) #define radeon_suspend(rdev) (rdev)->asic->suspend((rdev)) #define radeon_cs_parse(p) rdev->asic->cs_parse((p)) #define radeon_vga_set_state(rdev, state) (rdev)->asic->vga_set_state((rdev), (state)) +#define radeon_gpu_is_lockup(rdev) (rdev)->asic->gpu_is_lockup((rdev)) #define radeon_gpu_reset(rdev) (rdev)->asic->gpu_reset((rdev)) #define radeon_gart_tlb_flush(rdev) (rdev)->asic->gart_tlb_flush((rdev)) #define radeon_gart_set_page(rdev, i, p) (rdev)->asic->gart_set_page((rdev), (i), (p)) @@ -1200,6 +1212,8 @@ extern int radeon_resume_kms(struct drm_device *dev); extern int radeon_suspend_kms(struct drm_device *dev, pm_message_t state); /* r100,rv100,rs100,rv200,rs200,r200,rv250,rs300,rv280 */ +extern void r100_gpu_lockup_update(struct r100_gpu_lockup *lockup, struct radeon_cp *cp); +extern bool r100_gpu_cp_is_lockup(struct radeon_device *rdev, struct r100_gpu_lockup *lockup, struct radeon_cp *cp); /* rv200,rv250,rv280 */ extern void r200_set_safe_registers(struct radeon_device *rdev); diff --git a/drivers/gpu/drm/radeon/radeon_asic.c b/drivers/gpu/drm/radeon/radeon_asic.c index a4b4bc9fa322..7e21985139f7 100644 --- a/drivers/gpu/drm/radeon/radeon_asic.c +++ b/drivers/gpu/drm/radeon/radeon_asic.c @@ -134,6 +134,7 @@ static struct radeon_asic r100_asic = { .suspend = &r100_suspend, .resume = &r100_resume, .vga_set_state = &r100_vga_set_state, + .gpu_is_lockup = &r100_gpu_is_lockup, .gpu_reset = &r100_gpu_reset, .gart_tlb_flush = &r100_pci_gart_tlb_flush, .gart_set_page = &r100_pci_gart_set_page, @@ -172,6 +173,7 @@ static struct radeon_asic r200_asic = { .suspend = &r100_suspend, .resume = &r100_resume, .vga_set_state = &r100_vga_set_state, + .gpu_is_lockup = &r100_gpu_is_lockup, .gpu_reset = &r100_gpu_reset, .gart_tlb_flush = &r100_pci_gart_tlb_flush, .gart_set_page = &r100_pci_gart_set_page, @@ -209,6 +211,7 @@ static struct radeon_asic r300_asic = { .suspend = &r300_suspend, .resume = &r300_resume, .vga_set_state = &r100_vga_set_state, + .gpu_is_lockup = &r300_gpu_is_lockup, .gpu_reset = &r300_gpu_reset, .gart_tlb_flush = &r100_pci_gart_tlb_flush, .gart_set_page = &r100_pci_gart_set_page, @@ -247,6 +250,7 @@ static struct radeon_asic r300_asic_pcie = { .suspend = &r300_suspend, .resume = &r300_resume, .vga_set_state = &r100_vga_set_state, + .gpu_is_lockup = &r300_gpu_is_lockup, .gpu_reset = &r300_gpu_reset, .gart_tlb_flush = &rv370_pcie_gart_tlb_flush, .gart_set_page = &rv370_pcie_gart_set_page, @@ -284,6 +288,7 @@ static struct radeon_asic r420_asic = { .suspend = &r420_suspend, .resume = &r420_resume, .vga_set_state = &r100_vga_set_state, + .gpu_is_lockup = &r300_gpu_is_lockup, .gpu_reset = &r300_gpu_reset, .gart_tlb_flush = &rv370_pcie_gart_tlb_flush, .gart_set_page = &rv370_pcie_gart_set_page, @@ -322,6 +327,7 @@ static struct radeon_asic rs400_asic = { .suspend = &rs400_suspend, .resume = &rs400_resume, .vga_set_state = &r100_vga_set_state, + .gpu_is_lockup = &r300_gpu_is_lockup, .gpu_reset = &r300_gpu_reset, .gart_tlb_flush = &rs400_gart_tlb_flush, .gart_set_page = &rs400_gart_set_page, @@ -360,6 +366,7 @@ static struct radeon_asic rs600_asic = { .suspend = &rs600_suspend, .resume = &rs600_resume, .vga_set_state = &r100_vga_set_state, + .gpu_is_lockup = &r300_gpu_is_lockup, .gpu_reset = &r300_gpu_reset, .gart_tlb_flush = &rs600_gart_tlb_flush, .gart_set_page = &rs600_gart_set_page, @@ -398,6 +405,7 @@ static struct radeon_asic rs690_asic = { .suspend = &rs690_suspend, .resume = &rs690_resume, .vga_set_state = &r100_vga_set_state, + .gpu_is_lockup = &r300_gpu_is_lockup, .gpu_reset = &r300_gpu_reset, .gart_tlb_flush = &rs400_gart_tlb_flush, .gart_set_page = &rs400_gart_set_page, @@ -436,6 +444,7 @@ static struct radeon_asic rv515_asic = { .suspend = &rv515_suspend, .resume = &rv515_resume, .vga_set_state = &r100_vga_set_state, + .gpu_is_lockup = &r300_gpu_is_lockup, .gpu_reset = &rv515_gpu_reset, .gart_tlb_flush = &rv370_pcie_gart_tlb_flush, .gart_set_page = &rv370_pcie_gart_set_page, @@ -474,6 +483,7 @@ static struct radeon_asic r520_asic = { .suspend = &rv515_suspend, .resume = &r520_resume, .vga_set_state = &r100_vga_set_state, + .gpu_is_lockup = &r300_gpu_is_lockup, .gpu_reset = &rv515_gpu_reset, .gart_tlb_flush = &rv370_pcie_gart_tlb_flush, .gart_set_page = &rv370_pcie_gart_set_page, @@ -513,6 +523,7 @@ static struct radeon_asic r600_asic = { .resume = &r600_resume, .cp_commit = &r600_cp_commit, .vga_set_state = &r600_vga_set_state, + .gpu_is_lockup = &r600_gpu_is_lockup, .gpu_reset = &r600_gpu_reset, .gart_tlb_flush = &r600_pcie_gart_tlb_flush, .gart_set_page = &rs600_gart_set_page, @@ -586,7 +597,8 @@ static struct radeon_asic rv770_asic = { .suspend = &rv770_suspend, .resume = &rv770_resume, .cp_commit = &r600_cp_commit, - .gpu_reset = &rv770_gpu_reset, + .gpu_reset = &r600_gpu_reset, + .gpu_is_lockup = &r600_gpu_is_lockup, .vga_set_state = &r600_vga_set_state, .gart_tlb_flush = &r600_pcie_gart_tlb_flush, .gart_set_page = &rs600_gart_set_page, @@ -623,6 +635,7 @@ static struct radeon_asic evergreen_asic = { .suspend = &evergreen_suspend, .resume = &evergreen_resume, .cp_commit = NULL, + .gpu_is_lockup = &evergreen_gpu_is_lockup, .gpu_reset = &evergreen_gpu_reset, .vga_set_state = &r600_vga_set_state, .gart_tlb_flush = &r600_pcie_gart_tlb_flush, diff --git a/drivers/gpu/drm/radeon/radeon_asic.h b/drivers/gpu/drm/radeon/radeon_asic.h index a0b8280663d1..ce2f3e4f0814 100644 --- a/drivers/gpu/drm/radeon/radeon_asic.h +++ b/drivers/gpu/drm/radeon/radeon_asic.h @@ -60,6 +60,7 @@ int r100_resume(struct radeon_device *rdev); uint32_t r100_mm_rreg(struct radeon_device *rdev, uint32_t reg); void r100_mm_wreg(struct radeon_device *rdev, uint32_t reg, uint32_t v); void r100_vga_set_state(struct radeon_device *rdev, bool state); +bool r100_gpu_is_lockup(struct radeon_device *rdev); int r100_gpu_reset(struct radeon_device *rdev); u32 r100_get_vblank_counter(struct radeon_device *rdev, int crtc); void r100_pci_gart_tlb_flush(struct radeon_device *rdev); @@ -134,7 +135,7 @@ extern int r200_copy_dma(struct radeon_device *rdev, uint64_t src_offset, uint64_t dst_offset, unsigned num_pages, - struct radeon_fence *fence); + struct radeon_fence *fence); /* * r300,r350,rv350,rv380 @@ -143,6 +144,7 @@ extern int r300_init(struct radeon_device *rdev); extern void r300_fini(struct radeon_device *rdev); extern int r300_suspend(struct radeon_device *rdev); extern int r300_resume(struct radeon_device *rdev); +extern bool r300_gpu_is_lockup(struct radeon_device *rdev); extern int r300_gpu_reset(struct radeon_device *rdev); extern void r300_ring_start(struct radeon_device *rdev); extern void r300_fence_ring_emit(struct radeon_device *rdev, @@ -252,6 +254,7 @@ int r600_copy_dma(struct radeon_device *rdev, struct radeon_fence *fence); int r600_irq_process(struct radeon_device *rdev); int r600_irq_set(struct radeon_device *rdev); +bool r600_gpu_is_lockup(struct radeon_device *rdev); int r600_gpu_reset(struct radeon_device *rdev); int r600_set_surface_reg(struct radeon_device *rdev, int reg, uint32_t tiling_flags, uint32_t pitch, @@ -276,7 +279,6 @@ int rv770_init(struct radeon_device *rdev); void rv770_fini(struct radeon_device *rdev); int rv770_suspend(struct radeon_device *rdev); int rv770_resume(struct radeon_device *rdev); -int rv770_gpu_reset(struct radeon_device *rdev); /* * evergreen @@ -285,6 +287,7 @@ int evergreen_init(struct radeon_device *rdev); void evergreen_fini(struct radeon_device *rdev); int evergreen_suspend(struct radeon_device *rdev); int evergreen_resume(struct radeon_device *rdev); +bool evergreen_gpu_is_lockup(struct radeon_device *rdev); int evergreen_gpu_reset(struct radeon_device *rdev); void evergreen_bandwidth_update(struct radeon_device *rdev); void evergreen_hpd_init(struct radeon_device *rdev); diff --git a/drivers/gpu/drm/radeon/radeon_fence.c b/drivers/gpu/drm/radeon/radeon_fence.c index 8495d4e32e18..393154268dea 100644 --- a/drivers/gpu/drm/radeon/radeon_fence.c +++ b/drivers/gpu/drm/radeon/radeon_fence.c @@ -57,7 +57,6 @@ int radeon_fence_emit(struct radeon_device *rdev, struct radeon_fence *fence) radeon_fence_ring_emit(rdev, fence); fence->emited = true; - fence->timeout = jiffies + ((2000 * HZ) / 1000); list_del(&fence->list); list_add_tail(&fence->list, &rdev->fence_drv.emited); write_unlock_irqrestore(&rdev->fence_drv.lock, irq_flags); @@ -70,15 +69,34 @@ static bool radeon_fence_poll_locked(struct radeon_device *rdev) struct list_head *i, *n; uint32_t seq; bool wake = false; + unsigned long cjiffies; - if (rdev == NULL) { - return true; - } - if (rdev->shutdown) { - return true; - } seq = RREG32(rdev->fence_drv.scratch_reg); - rdev->fence_drv.last_seq = seq; + if (seq != rdev->fence_drv.last_seq) { + rdev->fence_drv.last_seq = seq; + rdev->fence_drv.last_jiffies = jiffies; + rdev->fence_drv.last_timeout = RADEON_FENCE_JIFFIES_TIMEOUT; + } else { + cjiffies = jiffies; + if (time_after(cjiffies, rdev->fence_drv.last_jiffies)) { + cjiffies -= rdev->fence_drv.last_jiffies; + if (time_after(rdev->fence_drv.last_timeout, cjiffies)) { + /* update the timeout */ + rdev->fence_drv.last_timeout -= cjiffies; + } else { + /* the 500ms timeout is elapsed we should test + * for GPU lockup + */ + rdev->fence_drv.last_timeout = 1; + } + } else { + /* wrap around update last jiffies, we will just wait + * a little longer + */ + rdev->fence_drv.last_jiffies = cjiffies; + } + return false; + } n = NULL; list_for_each(i, &rdev->fence_drv.emited) { fence = list_entry(i, struct radeon_fence, list); @@ -170,9 +188,8 @@ bool radeon_fence_signaled(struct radeon_fence *fence) int radeon_fence_wait(struct radeon_fence *fence, bool intr) { struct radeon_device *rdev; - unsigned long cur_jiffies; - unsigned long timeout; - bool expired = false; + unsigned long irq_flags, timeout; + u32 seq; int r; if (fence == NULL) { @@ -183,14 +200,10 @@ int radeon_fence_wait(struct radeon_fence *fence, bool intr) if (radeon_fence_signaled(fence)) { return 0; } - + timeout = rdev->fence_drv.last_timeout; retry: - cur_jiffies = jiffies; - timeout = HZ / 100; - if (time_after(fence->timeout, cur_jiffies)) { - timeout = fence->timeout - cur_jiffies; - } - + /* save current sequence used to check for GPU lockup */ + seq = rdev->fence_drv.last_seq; if (intr) { radeon_irq_kms_sw_irq_get(rdev); r = wait_event_interruptible_timeout(rdev->fence_drv.queue, @@ -205,38 +218,34 @@ retry: radeon_irq_kms_sw_irq_put(rdev); } if (unlikely(!radeon_fence_signaled(fence))) { - if (unlikely(r == 0)) { - expired = true; + /* we were interrupted for some reason and fence isn't + * isn't signaled yet, resume wait + */ + if (r) { + timeout = r; + goto retry; } - if (unlikely(expired)) { - timeout = 1; - if (time_after(cur_jiffies, fence->timeout)) { - timeout = cur_jiffies - fence->timeout; - } - timeout = jiffies_to_msecs(timeout); - if (timeout > 500) { - DRM_ERROR("fence(%p:0x%08X) %lums timeout " - "going to reset GPU\n", - fence, fence->seq, timeout); - radeon_gpu_reset(rdev); - WREG32(rdev->fence_drv.scratch_reg, fence->seq); - } + /* don't protect read access to rdev->fence_drv.last_seq + * if we experiencing a lockup the value doesn't change + */ + if (seq == rdev->fence_drv.last_seq && radeon_gpu_is_lockup(rdev)) { + /* good news we believe it's a lockup */ + dev_warn(rdev->dev, "GPU lockup (last fence id 0x%08X)\n", seq); + r = radeon_gpu_reset(rdev); + if (r) + return r; + /* FIXME: what should we do ? marking everyone + * as signaled for now + */ + WREG32(rdev->fence_drv.scratch_reg, fence->seq); } + timeout = RADEON_FENCE_JIFFIES_TIMEOUT; + write_lock_irqsave(&rdev->fence_drv.lock, irq_flags); + rdev->fence_drv.last_timeout = RADEON_FENCE_JIFFIES_TIMEOUT; + rdev->fence_drv.last_jiffies = jiffies; + write_unlock_irqrestore(&rdev->fence_drv.lock, irq_flags); goto retry; } - if (unlikely(expired)) { - rdev->fence_drv.count_timeout++; - cur_jiffies = jiffies; - timeout = 1; - if (time_after(cur_jiffies, fence->timeout)) { - timeout = cur_jiffies - fence->timeout; - } - timeout = jiffies_to_msecs(timeout); - DRM_ERROR("fence(%p:0x%08X) %lums timeout\n", - fence, fence->seq, timeout); - DRM_ERROR("last signaled fence(0x%08X)\n", - rdev->fence_drv.last_seq); - } return 0; } @@ -332,7 +341,6 @@ int radeon_fence_driver_init(struct radeon_device *rdev) INIT_LIST_HEAD(&rdev->fence_drv.created); INIT_LIST_HEAD(&rdev->fence_drv.emited); INIT_LIST_HEAD(&rdev->fence_drv.signaled); - rdev->fence_drv.count_timeout = 0; init_waitqueue_head(&rdev->fence_drv.queue); rdev->fence_drv.initialized = true; write_unlock_irqrestore(&rdev->fence_drv.lock, irq_flags); diff --git a/drivers/gpu/drm/radeon/rv770.c b/drivers/gpu/drm/radeon/rv770.c index 9f37d2efb0a9..2b8a4e170654 100644 --- a/drivers/gpu/drm/radeon/rv770.c +++ b/drivers/gpu/drm/radeon/rv770.c @@ -916,12 +916,6 @@ int rv770_mc_init(struct radeon_device *rdev) return 0; } -int rv770_gpu_reset(struct radeon_device *rdev) -{ - /* FIXME: implement any rv770 specific bits */ - return r600_gpu_reset(rdev); -} - static int rv770_startup(struct radeon_device *rdev) { int r; -- cgit v1.2.3 From a2d07b7438f015a0349bc9af3c96a8164549bbc5 Mon Sep 17 00:00:00 2001 From: Jerome Glisse Date: Tue, 9 Mar 2010 14:45:11 +0000 Subject: drm/radeon/kms: rename gpu_reset to asic_reset Patch rename gpu_reset to asic_reset in prevision of having gpu_reset doing more stuff than just basic asic reset. Signed-off-by: Jerome Glisse Signed-off-by: Dave Airlie --- drivers/gpu/drm/radeon/evergreen.c | 2 +- drivers/gpu/drm/radeon/r100.c | 6 +++--- drivers/gpu/drm/radeon/r300.c | 6 +++--- drivers/gpu/drm/radeon/r420.c | 4 ++-- drivers/gpu/drm/radeon/r520.c | 4 ++-- drivers/gpu/drm/radeon/r600.c | 2 +- drivers/gpu/drm/radeon/radeon.h | 6 +++--- drivers/gpu/drm/radeon/radeon_asic.c | 28 ++++++++++++++-------------- drivers/gpu/drm/radeon/radeon_asic.h | 10 +++++----- drivers/gpu/drm/radeon/radeon_device.c | 2 +- drivers/gpu/drm/radeon/radeon_fence.c | 2 +- drivers/gpu/drm/radeon/rs400.c | 4 ++-- drivers/gpu/drm/radeon/rs600.c | 4 ++-- drivers/gpu/drm/radeon/rs690.c | 4 ++-- drivers/gpu/drm/radeon/rv515.c | 8 ++++---- 15 files changed, 46 insertions(+), 46 deletions(-) (limited to 'drivers/gpu/drm/radeon') diff --git a/drivers/gpu/drm/radeon/evergreen.c b/drivers/gpu/drm/radeon/evergreen.c index 3070e5994120..7672f11ed995 100644 --- a/drivers/gpu/drm/radeon/evergreen.c +++ b/drivers/gpu/drm/radeon/evergreen.c @@ -492,7 +492,7 @@ bool evergreen_gpu_is_lockup(struct radeon_device *rdev) return false; } -int evergreen_gpu_reset(struct radeon_device *rdev) +int evergreen_asic_reset(struct radeon_device *rdev) { /* FIXME: implement for evergreen */ return 0; diff --git a/drivers/gpu/drm/radeon/r100.c b/drivers/gpu/drm/radeon/r100.c index 845c8f3063fe..8bb91092bffc 100644 --- a/drivers/gpu/drm/radeon/r100.c +++ b/drivers/gpu/drm/radeon/r100.c @@ -1863,7 +1863,7 @@ bool r100_gpu_is_lockup(struct radeon_device *rdev) return r100_gpu_cp_is_lockup(rdev, &rdev->config.r100.lockup, &rdev->cp); } -int r100_gpu_reset(struct radeon_device *rdev) +int r100_asic_reset(struct radeon_device *rdev) { uint32_t status; @@ -3512,7 +3512,7 @@ int r100_resume(struct radeon_device *rdev) /* Resume clock before doing reset */ r100_clock_startup(rdev); /* Reset gpu before posting otherwise ATOM will enter infinite loop */ - if (radeon_gpu_reset(rdev)) { + if (radeon_asic_reset(rdev)) { dev_warn(rdev->dev, "GPU reset failed ! (0xE40=0x%08X, 0x7C0=0x%08X)\n", RREG32(R_000E40_RBBM_STATUS), RREG32(R_0007C0_CP_STAT)); @@ -3581,7 +3581,7 @@ int r100_init(struct radeon_device *rdev) return r; } /* Reset gpu before posting otherwise ATOM will enter infinite loop */ - if (radeon_gpu_reset(rdev)) { + if (radeon_asic_reset(rdev)) { dev_warn(rdev->dev, "GPU reset failed ! (0xE40=0x%08X, 0x7C0=0x%08X)\n", RREG32(R_000E40_RBBM_STATUS), diff --git a/drivers/gpu/drm/radeon/r300.c b/drivers/gpu/drm/radeon/r300.c index 9825fb19331f..7d5de5dbde23 100644 --- a/drivers/gpu/drm/radeon/r300.c +++ b/drivers/gpu/drm/radeon/r300.c @@ -449,7 +449,7 @@ bool r300_gpu_is_lockup(struct radeon_device *rdev) return r100_gpu_cp_is_lockup(rdev, &rdev->config.r300.lockup, &rdev->cp); } -int r300_gpu_reset(struct radeon_device *rdev) +int r300_asic_reset(struct radeon_device *rdev) { uint32_t status; @@ -1333,7 +1333,7 @@ int r300_resume(struct radeon_device *rdev) /* Resume clock before doing reset */ r300_clock_startup(rdev); /* Reset gpu before posting otherwise ATOM will enter infinite loop */ - if (radeon_gpu_reset(rdev)) { + if (radeon_asic_reset(rdev)) { dev_warn(rdev->dev, "GPU reset failed ! (0xE40=0x%08X, 0x7C0=0x%08X)\n", RREG32(R_000E40_RBBM_STATUS), RREG32(R_0007C0_CP_STAT)); @@ -1404,7 +1404,7 @@ int r300_init(struct radeon_device *rdev) return r; } /* Reset gpu before posting otherwise ATOM will enter infinite loop */ - if (radeon_gpu_reset(rdev)) { + if (radeon_asic_reset(rdev)) { dev_warn(rdev->dev, "GPU reset failed ! (0xE40=0x%08X, 0x7C0=0x%08X)\n", RREG32(R_000E40_RBBM_STATUS), diff --git a/drivers/gpu/drm/radeon/r420.c b/drivers/gpu/drm/radeon/r420.c index 0b8603ca6974..061553aa7a0c 100644 --- a/drivers/gpu/drm/radeon/r420.c +++ b/drivers/gpu/drm/radeon/r420.c @@ -234,7 +234,7 @@ int r420_resume(struct radeon_device *rdev) /* Resume clock before doing reset */ r420_clock_resume(rdev); /* Reset gpu before posting otherwise ATOM will enter infinite loop */ - if (radeon_gpu_reset(rdev)) { + if (radeon_asic_reset(rdev)) { dev_warn(rdev->dev, "GPU reset failed ! (0xE40=0x%08X, 0x7C0=0x%08X)\n", RREG32(R_000E40_RBBM_STATUS), RREG32(R_0007C0_CP_STAT)); @@ -315,7 +315,7 @@ int r420_init(struct radeon_device *rdev) } } /* Reset gpu before posting otherwise ATOM will enter infinite loop */ - if (radeon_gpu_reset(rdev)) { + if (radeon_asic_reset(rdev)) { dev_warn(rdev->dev, "GPU reset failed ! (0xE40=0x%08X, 0x7C0=0x%08X)\n", RREG32(R_000E40_RBBM_STATUS), diff --git a/drivers/gpu/drm/radeon/r520.c b/drivers/gpu/drm/radeon/r520.c index 3c44b8d39318..3ade473e69ba 100644 --- a/drivers/gpu/drm/radeon/r520.c +++ b/drivers/gpu/drm/radeon/r520.c @@ -209,7 +209,7 @@ int r520_resume(struct radeon_device *rdev) /* Resume clock before doing reset */ rv515_clock_startup(rdev); /* Reset gpu before posting otherwise ATOM will enter infinite loop */ - if (radeon_gpu_reset(rdev)) { + if (radeon_asic_reset(rdev)) { dev_warn(rdev->dev, "GPU reset failed ! (0xE40=0x%08X, 0x7C0=0x%08X)\n", RREG32(R_000E40_RBBM_STATUS), RREG32(R_0007C0_CP_STAT)); @@ -246,7 +246,7 @@ int r520_init(struct radeon_device *rdev) return -EINVAL; } /* Reset gpu before posting otherwise ATOM will enter infinite loop */ - if (radeon_gpu_reset(rdev)) { + if (radeon_asic_reset(rdev)) { dev_warn(rdev->dev, "GPU reset failed ! (0xE40=0x%08X, 0x7C0=0x%08X)\n", RREG32(R_000E40_RBBM_STATUS), diff --git a/drivers/gpu/drm/radeon/r600.c b/drivers/gpu/drm/radeon/r600.c index a09c062df4db..24fd5459fb42 100644 --- a/drivers/gpu/drm/radeon/r600.c +++ b/drivers/gpu/drm/radeon/r600.c @@ -874,7 +874,7 @@ bool r600_gpu_is_lockup(struct radeon_device *rdev) return r100_gpu_cp_is_lockup(rdev, &rdev->config.r300.lockup, &rdev->cp); } -int r600_gpu_reset(struct radeon_device *rdev) +int r600_asic_reset(struct radeon_device *rdev) { return r600_gpu_soft_reset(rdev); } diff --git a/drivers/gpu/drm/radeon/radeon.h b/drivers/gpu/drm/radeon/radeon.h index a3d13c367176..3cc5820b0e1b 100644 --- a/drivers/gpu/drm/radeon/radeon.h +++ b/drivers/gpu/drm/radeon/radeon.h @@ -748,7 +748,7 @@ struct radeon_asic { int (*suspend)(struct radeon_device *rdev); void (*vga_set_state)(struct radeon_device *rdev, bool state); bool (*gpu_is_lockup)(struct radeon_device *rdev); - int (*gpu_reset)(struct radeon_device *rdev); + int (*asic_reset)(struct radeon_device *rdev); void (*gart_tlb_flush)(struct radeon_device *rdev); int (*gart_set_page)(struct radeon_device *rdev, int i, uint64_t addr); int (*cp_init)(struct radeon_device *rdev, unsigned ring_size); @@ -1157,7 +1157,7 @@ static inline void radeon_ring_write(struct radeon_device *rdev, uint32_t v) #define radeon_cs_parse(p) rdev->asic->cs_parse((p)) #define radeon_vga_set_state(rdev, state) (rdev)->asic->vga_set_state((rdev), (state)) #define radeon_gpu_is_lockup(rdev) (rdev)->asic->gpu_is_lockup((rdev)) -#define radeon_gpu_reset(rdev) (rdev)->asic->gpu_reset((rdev)) +#define radeon_asic_reset(rdev) (rdev)->asic->asic_reset((rdev)) #define radeon_gart_tlb_flush(rdev) (rdev)->asic->gart_tlb_flush((rdev)) #define radeon_gart_set_page(rdev, i, p) (rdev)->asic->gart_set_page((rdev), (i), (p)) #define radeon_cp_commit(rdev) (rdev)->asic->cp_commit((rdev)) @@ -1290,7 +1290,7 @@ extern void r600_scratch_init(struct radeon_device *rdev); extern int r600_blit_init(struct radeon_device *rdev); extern void r600_blit_fini(struct radeon_device *rdev); extern int r600_init_microcode(struct radeon_device *rdev); -extern int r600_gpu_reset(struct radeon_device *rdev); +extern int r600_asic_reset(struct radeon_device *rdev); /* r600 irq */ extern int r600_irq_init(struct radeon_device *rdev); extern void r600_irq_fini(struct radeon_device *rdev); diff --git a/drivers/gpu/drm/radeon/radeon_asic.c b/drivers/gpu/drm/radeon/radeon_asic.c index 7e21985139f7..011ac6d86581 100644 --- a/drivers/gpu/drm/radeon/radeon_asic.c +++ b/drivers/gpu/drm/radeon/radeon_asic.c @@ -135,7 +135,7 @@ static struct radeon_asic r100_asic = { .resume = &r100_resume, .vga_set_state = &r100_vga_set_state, .gpu_is_lockup = &r100_gpu_is_lockup, - .gpu_reset = &r100_gpu_reset, + .asic_reset = &r100_asic_reset, .gart_tlb_flush = &r100_pci_gart_tlb_flush, .gart_set_page = &r100_pci_gart_set_page, .cp_commit = &r100_cp_commit, @@ -174,7 +174,7 @@ static struct radeon_asic r200_asic = { .resume = &r100_resume, .vga_set_state = &r100_vga_set_state, .gpu_is_lockup = &r100_gpu_is_lockup, - .gpu_reset = &r100_gpu_reset, + .asic_reset = &r100_asic_reset, .gart_tlb_flush = &r100_pci_gart_tlb_flush, .gart_set_page = &r100_pci_gart_set_page, .cp_commit = &r100_cp_commit, @@ -212,7 +212,7 @@ static struct radeon_asic r300_asic = { .resume = &r300_resume, .vga_set_state = &r100_vga_set_state, .gpu_is_lockup = &r300_gpu_is_lockup, - .gpu_reset = &r300_gpu_reset, + .asic_reset = &r300_asic_reset, .gart_tlb_flush = &r100_pci_gart_tlb_flush, .gart_set_page = &r100_pci_gart_set_page, .cp_commit = &r100_cp_commit, @@ -251,7 +251,7 @@ static struct radeon_asic r300_asic_pcie = { .resume = &r300_resume, .vga_set_state = &r100_vga_set_state, .gpu_is_lockup = &r300_gpu_is_lockup, - .gpu_reset = &r300_gpu_reset, + .asic_reset = &r300_asic_reset, .gart_tlb_flush = &rv370_pcie_gart_tlb_flush, .gart_set_page = &rv370_pcie_gart_set_page, .cp_commit = &r100_cp_commit, @@ -289,7 +289,7 @@ static struct radeon_asic r420_asic = { .resume = &r420_resume, .vga_set_state = &r100_vga_set_state, .gpu_is_lockup = &r300_gpu_is_lockup, - .gpu_reset = &r300_gpu_reset, + .asic_reset = &r300_asic_reset, .gart_tlb_flush = &rv370_pcie_gart_tlb_flush, .gart_set_page = &rv370_pcie_gart_set_page, .cp_commit = &r100_cp_commit, @@ -328,7 +328,7 @@ static struct radeon_asic rs400_asic = { .resume = &rs400_resume, .vga_set_state = &r100_vga_set_state, .gpu_is_lockup = &r300_gpu_is_lockup, - .gpu_reset = &r300_gpu_reset, + .asic_reset = &r300_asic_reset, .gart_tlb_flush = &rs400_gart_tlb_flush, .gart_set_page = &rs400_gart_set_page, .cp_commit = &r100_cp_commit, @@ -367,7 +367,7 @@ static struct radeon_asic rs600_asic = { .resume = &rs600_resume, .vga_set_state = &r100_vga_set_state, .gpu_is_lockup = &r300_gpu_is_lockup, - .gpu_reset = &r300_gpu_reset, + .asic_reset = &r300_asic_reset, .gart_tlb_flush = &rs600_gart_tlb_flush, .gart_set_page = &rs600_gart_set_page, .cp_commit = &r100_cp_commit, @@ -406,7 +406,7 @@ static struct radeon_asic rs690_asic = { .resume = &rs690_resume, .vga_set_state = &r100_vga_set_state, .gpu_is_lockup = &r300_gpu_is_lockup, - .gpu_reset = &r300_gpu_reset, + .asic_reset = &r300_asic_reset, .gart_tlb_flush = &rs400_gart_tlb_flush, .gart_set_page = &rs400_gart_set_page, .cp_commit = &r100_cp_commit, @@ -445,7 +445,7 @@ static struct radeon_asic rv515_asic = { .resume = &rv515_resume, .vga_set_state = &r100_vga_set_state, .gpu_is_lockup = &r300_gpu_is_lockup, - .gpu_reset = &rv515_gpu_reset, + .asic_reset = &rv515_asic_reset, .gart_tlb_flush = &rv370_pcie_gart_tlb_flush, .gart_set_page = &rv370_pcie_gart_set_page, .cp_commit = &r100_cp_commit, @@ -484,7 +484,7 @@ static struct radeon_asic r520_asic = { .resume = &r520_resume, .vga_set_state = &r100_vga_set_state, .gpu_is_lockup = &r300_gpu_is_lockup, - .gpu_reset = &rv515_gpu_reset, + .asic_reset = &rv515_asic_reset, .gart_tlb_flush = &rv370_pcie_gart_tlb_flush, .gart_set_page = &rv370_pcie_gart_set_page, .cp_commit = &r100_cp_commit, @@ -524,7 +524,7 @@ static struct radeon_asic r600_asic = { .cp_commit = &r600_cp_commit, .vga_set_state = &r600_vga_set_state, .gpu_is_lockup = &r600_gpu_is_lockup, - .gpu_reset = &r600_gpu_reset, + .asic_reset = &r600_asic_reset, .gart_tlb_flush = &r600_pcie_gart_tlb_flush, .gart_set_page = &rs600_gart_set_page, .ring_test = &r600_ring_test, @@ -561,7 +561,7 @@ static struct radeon_asic rs780_asic = { .resume = &r600_resume, .cp_commit = &r600_cp_commit, .vga_set_state = &r600_vga_set_state, - .gpu_reset = &r600_gpu_reset, + .asic_reset = &r600_asic_reset, .gart_tlb_flush = &r600_pcie_gart_tlb_flush, .gart_set_page = &rs600_gart_set_page, .ring_test = &r600_ring_test, @@ -597,7 +597,7 @@ static struct radeon_asic rv770_asic = { .suspend = &rv770_suspend, .resume = &rv770_resume, .cp_commit = &r600_cp_commit, - .gpu_reset = &r600_gpu_reset, + .asic_reset = &r600_asic_reset, .gpu_is_lockup = &r600_gpu_is_lockup, .vga_set_state = &r600_vga_set_state, .gart_tlb_flush = &r600_pcie_gart_tlb_flush, @@ -636,7 +636,7 @@ static struct radeon_asic evergreen_asic = { .resume = &evergreen_resume, .cp_commit = NULL, .gpu_is_lockup = &evergreen_gpu_is_lockup, - .gpu_reset = &evergreen_gpu_reset, + .asic_reset = &evergreen_asic_reset, .vga_set_state = &r600_vga_set_state, .gart_tlb_flush = &r600_pcie_gart_tlb_flush, .gart_set_page = &rs600_gart_set_page, diff --git a/drivers/gpu/drm/radeon/radeon_asic.h b/drivers/gpu/drm/radeon/radeon_asic.h index ce2f3e4f0814..53ebcacbd0e0 100644 --- a/drivers/gpu/drm/radeon/radeon_asic.h +++ b/drivers/gpu/drm/radeon/radeon_asic.h @@ -61,7 +61,7 @@ uint32_t r100_mm_rreg(struct radeon_device *rdev, uint32_t reg); void r100_mm_wreg(struct radeon_device *rdev, uint32_t reg, uint32_t v); void r100_vga_set_state(struct radeon_device *rdev, bool state); bool r100_gpu_is_lockup(struct radeon_device *rdev); -int r100_gpu_reset(struct radeon_device *rdev); +int r100_asic_reset(struct radeon_device *rdev); u32 r100_get_vblank_counter(struct radeon_device *rdev, int crtc); void r100_pci_gart_tlb_flush(struct radeon_device *rdev); int r100_pci_gart_set_page(struct radeon_device *rdev, int i, uint64_t addr); @@ -145,7 +145,7 @@ extern void r300_fini(struct radeon_device *rdev); extern int r300_suspend(struct radeon_device *rdev); extern int r300_resume(struct radeon_device *rdev); extern bool r300_gpu_is_lockup(struct radeon_device *rdev); -extern int r300_gpu_reset(struct radeon_device *rdev); +extern int r300_asic_reset(struct radeon_device *rdev); extern void r300_ring_start(struct radeon_device *rdev); extern void r300_fence_ring_emit(struct radeon_device *rdev, struct radeon_fence *fence); @@ -214,7 +214,7 @@ void rs690_bandwidth_update(struct radeon_device *rdev); */ int rv515_init(struct radeon_device *rdev); void rv515_fini(struct radeon_device *rdev); -int rv515_gpu_reset(struct radeon_device *rdev); +int rv515_asic_reset(struct radeon_device *rdev); uint32_t rv515_mc_rreg(struct radeon_device *rdev, uint32_t reg); void rv515_mc_wreg(struct radeon_device *rdev, uint32_t reg, uint32_t v); void rv515_ring_start(struct radeon_device *rdev); @@ -255,7 +255,7 @@ int r600_copy_dma(struct radeon_device *rdev, int r600_irq_process(struct radeon_device *rdev); int r600_irq_set(struct radeon_device *rdev); bool r600_gpu_is_lockup(struct radeon_device *rdev); -int r600_gpu_reset(struct radeon_device *rdev); +int r600_asic_reset(struct radeon_device *rdev); int r600_set_surface_reg(struct radeon_device *rdev, int reg, uint32_t tiling_flags, uint32_t pitch, uint32_t offset, uint32_t obj_size); @@ -288,7 +288,7 @@ void evergreen_fini(struct radeon_device *rdev); int evergreen_suspend(struct radeon_device *rdev); int evergreen_resume(struct radeon_device *rdev); bool evergreen_gpu_is_lockup(struct radeon_device *rdev); -int evergreen_gpu_reset(struct radeon_device *rdev); +int evergreen_asic_reset(struct radeon_device *rdev); void evergreen_bandwidth_update(struct radeon_device *rdev); void evergreen_hpd_init(struct radeon_device *rdev); void evergreen_hpd_fini(struct radeon_device *rdev); diff --git a/drivers/gpu/drm/radeon/radeon_device.c b/drivers/gpu/drm/radeon/radeon_device.c index 60ec47b71642..232a30768499 100644 --- a/drivers/gpu/drm/radeon/radeon_device.c +++ b/drivers/gpu/drm/radeon/radeon_device.c @@ -619,7 +619,7 @@ int radeon_device_init(struct radeon_device *rdev, /* Acceleration not working on AGP card try again * with fallback to PCI or PCIE GART */ - radeon_gpu_reset(rdev); + radeon_asic_reset(rdev); radeon_fini(rdev); radeon_agp_disable(rdev); r = radeon_init(rdev); diff --git a/drivers/gpu/drm/radeon/radeon_fence.c b/drivers/gpu/drm/radeon/radeon_fence.c index 393154268dea..2560740ff922 100644 --- a/drivers/gpu/drm/radeon/radeon_fence.c +++ b/drivers/gpu/drm/radeon/radeon_fence.c @@ -231,7 +231,7 @@ retry: if (seq == rdev->fence_drv.last_seq && radeon_gpu_is_lockup(rdev)) { /* good news we believe it's a lockup */ dev_warn(rdev->dev, "GPU lockup (last fence id 0x%08X)\n", seq); - r = radeon_gpu_reset(rdev); + r = radeon_asic_reset(rdev); if (r) return r; /* FIXME: what should we do ? marking everyone diff --git a/drivers/gpu/drm/radeon/rs400.c b/drivers/gpu/drm/radeon/rs400.c index 626aaf082b1a..3deec2185083 100644 --- a/drivers/gpu/drm/radeon/rs400.c +++ b/drivers/gpu/drm/radeon/rs400.c @@ -432,7 +432,7 @@ int rs400_resume(struct radeon_device *rdev) /* setup MC before calling post tables */ rs400_mc_program(rdev); /* Reset gpu before posting otherwise ATOM will enter infinite loop */ - if (radeon_gpu_reset(rdev)) { + if (radeon_asic_reset(rdev)) { dev_warn(rdev->dev, "GPU reset failed ! (0xE40=0x%08X, 0x7C0=0x%08X)\n", RREG32(R_000E40_RBBM_STATUS), RREG32(R_0007C0_CP_STAT)); @@ -496,7 +496,7 @@ int rs400_init(struct radeon_device *rdev) return r; } /* Reset gpu before posting otherwise ATOM will enter infinite loop */ - if (radeon_gpu_reset(rdev)) { + if (radeon_asic_reset(rdev)) { dev_warn(rdev->dev, "GPU reset failed ! (0xE40=0x%08X, 0x7C0=0x%08X)\n", RREG32(R_000E40_RBBM_STATUS), diff --git a/drivers/gpu/drm/radeon/rs600.c b/drivers/gpu/drm/radeon/rs600.c index abf824c2123d..c1be20afd429 100644 --- a/drivers/gpu/drm/radeon/rs600.c +++ b/drivers/gpu/drm/radeon/rs600.c @@ -601,7 +601,7 @@ int rs600_resume(struct radeon_device *rdev) /* Resume clock before doing reset */ rv515_clock_startup(rdev); /* Reset gpu before posting otherwise ATOM will enter infinite loop */ - if (radeon_gpu_reset(rdev)) { + if (radeon_asic_reset(rdev)) { dev_warn(rdev->dev, "GPU reset failed ! (0xE40=0x%08X, 0x7C0=0x%08X)\n", RREG32(R_000E40_RBBM_STATUS), RREG32(R_0007C0_CP_STAT)); @@ -664,7 +664,7 @@ int rs600_init(struct radeon_device *rdev) return -EINVAL; } /* Reset gpu before posting otherwise ATOM will enter infinite loop */ - if (radeon_gpu_reset(rdev)) { + if (radeon_asic_reset(rdev)) { dev_warn(rdev->dev, "GPU reset failed ! (0xE40=0x%08X, 0x7C0=0x%08X)\n", RREG32(R_000E40_RBBM_STATUS), diff --git a/drivers/gpu/drm/radeon/rs690.c b/drivers/gpu/drm/radeon/rs690.c index bbf3da790fd5..ef35e0468f13 100644 --- a/drivers/gpu/drm/radeon/rs690.c +++ b/drivers/gpu/drm/radeon/rs690.c @@ -653,7 +653,7 @@ int rs690_resume(struct radeon_device *rdev) /* Resume clock before doing reset */ rv515_clock_startup(rdev); /* Reset gpu before posting otherwise ATOM will enter infinite loop */ - if (radeon_gpu_reset(rdev)) { + if (radeon_asic_reset(rdev)) { dev_warn(rdev->dev, "GPU reset failed ! (0xE40=0x%08X, 0x7C0=0x%08X)\n", RREG32(R_000E40_RBBM_STATUS), RREG32(R_0007C0_CP_STAT)); @@ -717,7 +717,7 @@ int rs690_init(struct radeon_device *rdev) return -EINVAL; } /* Reset gpu before posting otherwise ATOM will enter infinite loop */ - if (radeon_gpu_reset(rdev)) { + if (radeon_asic_reset(rdev)) { dev_warn(rdev->dev, "GPU reset failed ! (0xE40=0x%08X, 0x7C0=0x%08X)\n", RREG32(R_000E40_RBBM_STATUS), diff --git a/drivers/gpu/drm/radeon/rv515.c b/drivers/gpu/drm/radeon/rv515.c index 1cf233f7e516..2a4c01f5cf12 100644 --- a/drivers/gpu/drm/radeon/rv515.c +++ b/drivers/gpu/drm/radeon/rv515.c @@ -227,7 +227,7 @@ int rv515_ga_reset(struct radeon_device *rdev) return -1; } -int rv515_gpu_reset(struct radeon_device *rdev) +int rv515_asic_reset(struct radeon_device *rdev) { uint32_t status; @@ -334,7 +334,7 @@ static int rv515_debugfs_ga_info(struct seq_file *m, void *data) tmp = RREG32(0x2140); seq_printf(m, "VAP_CNTL_STATUS 0x%08x\n", tmp); - radeon_gpu_reset(rdev); + radeon_asic_reset(rdev); tmp = RREG32(0x425C); seq_printf(m, "GA_IDLE 0x%08x\n", tmp); return 0; @@ -502,7 +502,7 @@ int rv515_resume(struct radeon_device *rdev) /* Resume clock before doing reset */ rv515_clock_startup(rdev); /* Reset gpu before posting otherwise ATOM will enter infinite loop */ - if (radeon_gpu_reset(rdev)) { + if (radeon_asic_reset(rdev)) { dev_warn(rdev->dev, "GPU reset failed ! (0xE40=0x%08X, 0x7C0=0x%08X)\n", RREG32(R_000E40_RBBM_STATUS), RREG32(R_0007C0_CP_STAT)); @@ -572,7 +572,7 @@ int rv515_init(struct radeon_device *rdev) return -EINVAL; } /* Reset gpu before posting otherwise ATOM will enter infinite loop */ - if (radeon_gpu_reset(rdev)) { + if (radeon_asic_reset(rdev)) { dev_warn(rdev->dev, "GPU reset failed ! (0xE40=0x%08X, 0x7C0=0x%08X)\n", RREG32(R_000E40_RBBM_STATUS), -- cgit v1.2.3 From 90aca4d2740255bd130ea71a91530b9920c70abe Mon Sep 17 00:00:00 2001 From: Jerome Glisse Date: Tue, 9 Mar 2010 14:45:12 +0000 Subject: drm/radeon/kms: simplify & improve GPU reset V2 This simplify and improve GPU reset for R1XX-R6XX hw, it's not 100% reliable here are result: - R1XX/R2XX works bunch of time in a row, sometimes it seems it can work indifinitly - R3XX/R3XX the most unreliable one, sometimes you will be able to reset few times, sometimes not even once - R5XX more reliable than previous hw, seems to work most of the times but once in a while it fails for no obvious reasons (same status than previous reset just no same happy ending) - R6XX/R7XX are lot more reliable with this patch, still it seems that it can fail after a bunch (reset every 2sec for 3hour bring down the GPU & computer) This have been tested on various hw, for some odd reasons i wasn't able to lockup RS480/RS690 (while they use to love locking up). Note that on R1XX-R5XX the cursor will disapear after lockup haven't checked why, switch to console and back to X will restore cursor. Next step is to record the bogus command that leaded to the lockup. V2 Fix r6xx resume path to avoid reinitializing blit module, use the gpu_lockup boolean to avoid entering inifinite waiting loop on fence while reiniting the GPU Signed-off-by: Jerome Glisse Signed-off-by: Dave Airlie --- drivers/gpu/drm/radeon/r100.c | 180 ++++++++++++--------------------- drivers/gpu/drm/radeon/r100d.h | 128 +++++++++++++++++++++++ drivers/gpu/drm/radeon/r300.c | 134 +++++++++++------------- drivers/gpu/drm/radeon/r300d.h | 47 ++++++++- drivers/gpu/drm/radeon/r520.c | 1 - drivers/gpu/drm/radeon/r600.c | 53 +--------- drivers/gpu/drm/radeon/r600_blit_kms.c | 3 + drivers/gpu/drm/radeon/radeon.h | 1 + drivers/gpu/drm/radeon/radeon_asic.c | 9 +- drivers/gpu/drm/radeon/radeon_asic.h | 6 +- drivers/gpu/drm/radeon/radeon_cs.c | 4 - drivers/gpu/drm/radeon/radeon_device.c | 22 ++++ drivers/gpu/drm/radeon/radeon_fence.c | 13 ++- drivers/gpu/drm/radeon/radeon_gart.c | 2 +- drivers/gpu/drm/radeon/rs400.c | 2 - drivers/gpu/drm/radeon/rs600.c | 73 ++++++++++++- drivers/gpu/drm/radeon/rs600d.h | 46 +++++++++ drivers/gpu/drm/radeon/rs690.c | 2 - drivers/gpu/drm/radeon/rv515.c | 90 ----------------- drivers/gpu/drm/radeon/rv515d.h | 46 +++++++++ 20 files changed, 508 insertions(+), 354 deletions(-) (limited to 'drivers/gpu/drm/radeon') diff --git a/drivers/gpu/drm/radeon/r100.c b/drivers/gpu/drm/radeon/r100.c index 8bb91092bffc..7a4a4fc276b3 100644 --- a/drivers/gpu/drm/radeon/r100.c +++ b/drivers/gpu/drm/radeon/r100.c @@ -662,26 +662,6 @@ int r100_cp_init(struct radeon_device *rdev, unsigned ring_size) if (r100_debugfs_cp_init(rdev)) { DRM_ERROR("Failed to register debugfs file for CP !\n"); } - /* Reset CP */ - tmp = RREG32(RADEON_CP_CSQ_STAT); - if ((tmp & (1 << 31))) { - DRM_INFO("radeon: cp busy (0x%08X) resetting\n", tmp); - WREG32(RADEON_CP_CSQ_MODE, 0); - WREG32(RADEON_CP_CSQ_CNTL, 0); - WREG32(RADEON_RBBM_SOFT_RESET, RADEON_SOFT_RESET_CP); - tmp = RREG32(RADEON_RBBM_SOFT_RESET); - mdelay(2); - WREG32(RADEON_RBBM_SOFT_RESET, 0); - tmp = RREG32(RADEON_RBBM_SOFT_RESET); - mdelay(2); - tmp = RREG32(RADEON_CP_CSQ_STAT); - if ((tmp & (1 << 31))) { - DRM_INFO("radeon: cp reset failed (0x%08X)\n", tmp); - } - } else { - DRM_INFO("radeon: cp idle (0x%08X)\n", tmp); - } - if (!rdev->me_fw) { r = r100_cp_init_microcode(rdev); if (r) { @@ -786,39 +766,6 @@ void r100_cp_disable(struct radeon_device *rdev) } } -int r100_cp_reset(struct radeon_device *rdev) -{ - uint32_t tmp; - bool reinit_cp; - int i; - - reinit_cp = rdev->cp.ready; - rdev->cp.ready = false; - WREG32(RADEON_CP_CSQ_MODE, 0); - WREG32(RADEON_CP_CSQ_CNTL, 0); - WREG32(RADEON_RBBM_SOFT_RESET, RADEON_SOFT_RESET_CP); - (void)RREG32(RADEON_RBBM_SOFT_RESET); - udelay(200); - WREG32(RADEON_RBBM_SOFT_RESET, 0); - /* Wait to prevent race in RBBM_STATUS */ - mdelay(1); - for (i = 0; i < rdev->usec_timeout; i++) { - tmp = RREG32(RADEON_RBBM_STATUS); - if (!(tmp & (1 << 16))) { - DRM_INFO("CP reset succeed (RBBM_STATUS=0x%08X)\n", - tmp); - if (reinit_cp) { - return r100_cp_init(rdev, rdev->cp.ring_size); - } - return 0; - } - DRM_UDELAY(1); - } - tmp = RREG32(RADEON_RBBM_STATUS); - DRM_ERROR("Failed to reset CP (RBBM_STATUS=0x%08X)!\n", tmp); - return -1; -} - void r100_cp_commit(struct radeon_device *rdev) { WREG32(RADEON_CP_RB_WPTR, rdev->cp.wptr); @@ -1732,51 +1679,6 @@ int r100_mc_wait_for_idle(struct radeon_device *rdev) return -1; } -void r100_gpu_init(struct radeon_device *rdev) -{ - /* TODO: anythings to do here ? pipes ? */ - r100_hdp_reset(rdev); -} - -void r100_hdp_reset(struct radeon_device *rdev) -{ - uint32_t tmp; - - tmp = RREG32(RADEON_HOST_PATH_CNTL) & RADEON_HDP_APER_CNTL; - tmp |= (7 << 28); - WREG32(RADEON_HOST_PATH_CNTL, tmp | RADEON_HDP_SOFT_RESET | RADEON_HDP_READ_BUFFER_INVALIDATE); - (void)RREG32(RADEON_HOST_PATH_CNTL); - udelay(200); - WREG32(RADEON_RBBM_SOFT_RESET, 0); - WREG32(RADEON_HOST_PATH_CNTL, tmp); - (void)RREG32(RADEON_HOST_PATH_CNTL); -} - -int r100_rb2d_reset(struct radeon_device *rdev) -{ - uint32_t tmp; - int i; - - WREG32(RADEON_RBBM_SOFT_RESET, RADEON_SOFT_RESET_E2); - (void)RREG32(RADEON_RBBM_SOFT_RESET); - udelay(200); - WREG32(RADEON_RBBM_SOFT_RESET, 0); - /* Wait to prevent race in RBBM_STATUS */ - mdelay(1); - for (i = 0; i < rdev->usec_timeout; i++) { - tmp = RREG32(RADEON_RBBM_STATUS); - if (!(tmp & (1 << 26))) { - DRM_INFO("RB2D reset succeed (RBBM_STATUS=0x%08X)\n", - tmp); - return 0; - } - DRM_UDELAY(1); - } - tmp = RREG32(RADEON_RBBM_STATUS); - DRM_ERROR("Failed to reset RB2D (RBBM_STATUS=0x%08X)!\n", tmp); - return -1; -} - void r100_gpu_lockup_update(struct r100_gpu_lockup *lockup, struct radeon_cp *cp) { lockup->last_cp_rptr = cp->rptr; @@ -1863,31 +1765,77 @@ bool r100_gpu_is_lockup(struct radeon_device *rdev) return r100_gpu_cp_is_lockup(rdev, &rdev->config.r100.lockup, &rdev->cp); } +void r100_bm_disable(struct radeon_device *rdev) +{ + u32 tmp; + + /* disable bus mastering */ + tmp = RREG32(R_000030_BUS_CNTL); + WREG32(R_000030_BUS_CNTL, (tmp & 0xFFFFFFFF) | 0x00000044); + mdelay(1); + WREG32(R_000030_BUS_CNTL, (tmp & 0xFFFFFFFF) | 0x00000042); + mdelay(1); + WREG32(R_000030_BUS_CNTL, (tmp & 0xFFFFFFFF) | 0x00000040); + tmp = RREG32(RADEON_BUS_CNTL); + mdelay(1); + pci_read_config_word(rdev->pdev, 0x4, (u16*)&tmp); + pci_write_config_word(rdev->pdev, 0x4, tmp & 0xFFFB); + mdelay(1); +} + int r100_asic_reset(struct radeon_device *rdev) { - uint32_t status; + struct r100_mc_save save; + u32 status, tmp; - /* reset order likely matter */ - status = RREG32(RADEON_RBBM_STATUS); - /* reset HDP */ - r100_hdp_reset(rdev); - /* reset rb2d */ - if (status & ((1 << 17) | (1 << 18) | (1 << 27))) { - r100_rb2d_reset(rdev); + r100_mc_stop(rdev, &save); + status = RREG32(R_000E40_RBBM_STATUS); + if (!G_000E40_GUI_ACTIVE(status)) { + return 0; } - /* TODO: reset 3D engine */ + status = RREG32(R_000E40_RBBM_STATUS); + dev_info(rdev->dev, "(%s:%d) RBBM_STATUS=0x%08X\n", __func__, __LINE__, status); + /* stop CP */ + WREG32(RADEON_CP_CSQ_CNTL, 0); + tmp = RREG32(RADEON_CP_RB_CNTL); + WREG32(RADEON_CP_RB_CNTL, tmp | RADEON_RB_RPTR_WR_ENA); + WREG32(RADEON_CP_RB_RPTR_WR, 0); + WREG32(RADEON_CP_RB_WPTR, 0); + WREG32(RADEON_CP_RB_CNTL, tmp); + /* save PCI state */ + pci_save_state(rdev->pdev); + /* disable bus mastering */ + r100_bm_disable(rdev); + WREG32(R_0000F0_RBBM_SOFT_RESET, S_0000F0_SOFT_RESET_SE(1) | + S_0000F0_SOFT_RESET_RE(1) | + S_0000F0_SOFT_RESET_PP(1) | + S_0000F0_SOFT_RESET_RB(1)); + RREG32(R_0000F0_RBBM_SOFT_RESET); + mdelay(500); + WREG32(R_0000F0_RBBM_SOFT_RESET, 0); + mdelay(1); + status = RREG32(R_000E40_RBBM_STATUS); + dev_info(rdev->dev, "(%s:%d) RBBM_STATUS=0x%08X\n", __func__, __LINE__, status); /* reset CP */ - status = RREG32(RADEON_RBBM_STATUS); - if (status & (1 << 16)) { - r100_cp_reset(rdev); - } + WREG32(R_0000F0_RBBM_SOFT_RESET, S_0000F0_SOFT_RESET_CP(1)); + RREG32(R_0000F0_RBBM_SOFT_RESET); + mdelay(500); + WREG32(R_0000F0_RBBM_SOFT_RESET, 0); + mdelay(1); + status = RREG32(R_000E40_RBBM_STATUS); + dev_info(rdev->dev, "(%s:%d) RBBM_STATUS=0x%08X\n", __func__, __LINE__, status); + /* restore PCI & busmastering */ + pci_restore_state(rdev->pdev); + r100_enable_bm(rdev); /* Check if GPU is idle */ - status = RREG32(RADEON_RBBM_STATUS); - if (status & RADEON_RBBM_ACTIVE) { - DRM_ERROR("Failed to reset GPU (RBBM_STATUS=0x%08X)\n", status); + if (G_000E40_SE_BUSY(status) || G_000E40_RE_BUSY(status) || + G_000E40_TAM_BUSY(status) || G_000E40_PB_BUSY(status)) { + dev_err(rdev->dev, "failed to reset GPU\n"); + rdev->gpu_lockup = true; return -1; } - DRM_INFO("GPU reset succeed (RBBM_STATUS=0x%08X)\n", status); + r100_mc_resume(rdev, &save); + dev_info(rdev->dev, "GPU reset succeed\n"); return 0; } @@ -3475,7 +3423,7 @@ static int r100_startup(struct radeon_device *rdev) /* Resume clock */ r100_clock_startup(rdev); /* Initialize GPU configuration (# pipes, ...) */ - r100_gpu_init(rdev); +// r100_gpu_init(rdev); /* Initialize GART (initialize after TTM so we can allocate * memory through TTM but finalize after TTM) */ r100_enable_bm(rdev); diff --git a/drivers/gpu/drm/radeon/r100d.h b/drivers/gpu/drm/radeon/r100d.h index df29a630c466..de8abd104ab7 100644 --- a/drivers/gpu/drm/radeon/r100d.h +++ b/drivers/gpu/drm/radeon/r100d.h @@ -74,6 +74,134 @@ #define CP_PACKET3_GET_OPCODE(h) (((h) >> 8) & 0xFF) /* Registers */ +#define R_0000F0_RBBM_SOFT_RESET 0x0000F0 +#define S_0000F0_SOFT_RESET_CP(x) (((x) & 0x1) << 0) +#define G_0000F0_SOFT_RESET_CP(x) (((x) >> 0) & 0x1) +#define C_0000F0_SOFT_RESET_CP 0xFFFFFFFE +#define S_0000F0_SOFT_RESET_HI(x) (((x) & 0x1) << 1) +#define G_0000F0_SOFT_RESET_HI(x) (((x) >> 1) & 0x1) +#define C_0000F0_SOFT_RESET_HI 0xFFFFFFFD +#define S_0000F0_SOFT_RESET_SE(x) (((x) & 0x1) << 2) +#define G_0000F0_SOFT_RESET_SE(x) (((x) >> 2) & 0x1) +#define C_0000F0_SOFT_RESET_SE 0xFFFFFFFB +#define S_0000F0_SOFT_RESET_RE(x) (((x) & 0x1) << 3) +#define G_0000F0_SOFT_RESET_RE(x) (((x) >> 3) & 0x1) +#define C_0000F0_SOFT_RESET_RE 0xFFFFFFF7 +#define S_0000F0_SOFT_RESET_PP(x) (((x) & 0x1) << 4) +#define G_0000F0_SOFT_RESET_PP(x) (((x) >> 4) & 0x1) +#define C_0000F0_SOFT_RESET_PP 0xFFFFFFEF +#define S_0000F0_SOFT_RESET_E2(x) (((x) & 0x1) << 5) +#define G_0000F0_SOFT_RESET_E2(x) (((x) >> 5) & 0x1) +#define C_0000F0_SOFT_RESET_E2 0xFFFFFFDF +#define S_0000F0_SOFT_RESET_RB(x) (((x) & 0x1) << 6) +#define G_0000F0_SOFT_RESET_RB(x) (((x) >> 6) & 0x1) +#define C_0000F0_SOFT_RESET_RB 0xFFFFFFBF +#define S_0000F0_SOFT_RESET_HDP(x) (((x) & 0x1) << 7) +#define G_0000F0_SOFT_RESET_HDP(x) (((x) >> 7) & 0x1) +#define C_0000F0_SOFT_RESET_HDP 0xFFFFFF7F +#define S_0000F0_SOFT_RESET_MC(x) (((x) & 0x1) << 8) +#define G_0000F0_SOFT_RESET_MC(x) (((x) >> 8) & 0x1) +#define C_0000F0_SOFT_RESET_MC 0xFFFFFEFF +#define S_0000F0_SOFT_RESET_AIC(x) (((x) & 0x1) << 9) +#define G_0000F0_SOFT_RESET_AIC(x) (((x) >> 9) & 0x1) +#define C_0000F0_SOFT_RESET_AIC 0xFFFFFDFF +#define S_0000F0_SOFT_RESET_VIP(x) (((x) & 0x1) << 10) +#define G_0000F0_SOFT_RESET_VIP(x) (((x) >> 10) & 0x1) +#define C_0000F0_SOFT_RESET_VIP 0xFFFFFBFF +#define S_0000F0_SOFT_RESET_DISP(x) (((x) & 0x1) << 11) +#define G_0000F0_SOFT_RESET_DISP(x) (((x) >> 11) & 0x1) +#define C_0000F0_SOFT_RESET_DISP 0xFFFFF7FF +#define S_0000F0_SOFT_RESET_CG(x) (((x) & 0x1) << 12) +#define G_0000F0_SOFT_RESET_CG(x) (((x) >> 12) & 0x1) +#define C_0000F0_SOFT_RESET_CG 0xFFFFEFFF +#define R_000030_BUS_CNTL 0x000030 +#define S_000030_BUS_DBL_RESYNC(x) (((x) & 0x1) << 0) +#define G_000030_BUS_DBL_RESYNC(x) (((x) >> 0) & 0x1) +#define C_000030_BUS_DBL_RESYNC 0xFFFFFFFE +#define S_000030_BUS_MSTR_RESET(x) (((x) & 0x1) << 1) +#define G_000030_BUS_MSTR_RESET(x) (((x) >> 1) & 0x1) +#define C_000030_BUS_MSTR_RESET 0xFFFFFFFD +#define S_000030_BUS_FLUSH_BUF(x) (((x) & 0x1) << 2) +#define G_000030_BUS_FLUSH_BUF(x) (((x) >> 2) & 0x1) +#define C_000030_BUS_FLUSH_BUF 0xFFFFFFFB +#define S_000030_BUS_STOP_REQ_DIS(x) (((x) & 0x1) << 3) +#define G_000030_BUS_STOP_REQ_DIS(x) (((x) >> 3) & 0x1) +#define C_000030_BUS_STOP_REQ_DIS 0xFFFFFFF7 +#define S_000030_BUS_PM4_READ_COMBINE_EN(x) (((x) & 0x1) << 4) +#define G_000030_BUS_PM4_READ_COMBINE_EN(x) (((x) >> 4) & 0x1) +#define C_000030_BUS_PM4_READ_COMBINE_EN 0xFFFFFFEF +#define S_000030_BUS_WRT_COMBINE_EN(x) (((x) & 0x1) << 5) +#define G_000030_BUS_WRT_COMBINE_EN(x) (((x) >> 5) & 0x1) +#define C_000030_BUS_WRT_COMBINE_EN 0xFFFFFFDF +#define S_000030_BUS_MASTER_DIS(x) (((x) & 0x1) << 6) +#define G_000030_BUS_MASTER_DIS(x) (((x) >> 6) & 0x1) +#define C_000030_BUS_MASTER_DIS 0xFFFFFFBF +#define S_000030_BIOS_ROM_WRT_EN(x) (((x) & 0x1) << 7) +#define G_000030_BIOS_ROM_WRT_EN(x) (((x) >> 7) & 0x1) +#define C_000030_BIOS_ROM_WRT_EN 0xFFFFFF7F +#define S_000030_BM_DAC_CRIPPLE(x) (((x) & 0x1) << 8) +#define G_000030_BM_DAC_CRIPPLE(x) (((x) >> 8) & 0x1) +#define C_000030_BM_DAC_CRIPPLE 0xFFFFFEFF +#define S_000030_BUS_NON_PM4_READ_COMBINE_EN(x) (((x) & 0x1) << 9) +#define G_000030_BUS_NON_PM4_READ_COMBINE_EN(x) (((x) >> 9) & 0x1) +#define C_000030_BUS_NON_PM4_READ_COMBINE_EN 0xFFFFFDFF +#define S_000030_BUS_XFERD_DISCARD_EN(x) (((x) & 0x1) << 10) +#define G_000030_BUS_XFERD_DISCARD_EN(x) (((x) >> 10) & 0x1) +#define C_000030_BUS_XFERD_DISCARD_EN 0xFFFFFBFF +#define S_000030_BUS_SGL_READ_DISABLE(x) (((x) & 0x1) << 11) +#define G_000030_BUS_SGL_READ_DISABLE(x) (((x) >> 11) & 0x1) +#define C_000030_BUS_SGL_READ_DISABLE 0xFFFFF7FF +#define S_000030_BIOS_DIS_ROM(x) (((x) & 0x1) << 12) +#define G_000030_BIOS_DIS_ROM(x) (((x) >> 12) & 0x1) +#define C_000030_BIOS_DIS_ROM 0xFFFFEFFF +#define S_000030_BUS_PCI_READ_RETRY_EN(x) (((x) & 0x1) << 13) +#define G_000030_BUS_PCI_READ_RETRY_EN(x) (((x) >> 13) & 0x1) +#define C_000030_BUS_PCI_READ_RETRY_EN 0xFFFFDFFF +#define S_000030_BUS_AGP_AD_STEPPING_EN(x) (((x) & 0x1) << 14) +#define G_000030_BUS_AGP_AD_STEPPING_EN(x) (((x) >> 14) & 0x1) +#define C_000030_BUS_AGP_AD_STEPPING_EN 0xFFFFBFFF +#define S_000030_BUS_PCI_WRT_RETRY_EN(x) (((x) & 0x1) << 15) +#define G_000030_BUS_PCI_WRT_RETRY_EN(x) (((x) >> 15) & 0x1) +#define C_000030_BUS_PCI_WRT_RETRY_EN 0xFFFF7FFF +#define S_000030_BUS_RETRY_WS(x) (((x) & 0xF) << 16) +#define G_000030_BUS_RETRY_WS(x) (((x) >> 16) & 0xF) +#define C_000030_BUS_RETRY_WS 0xFFF0FFFF +#define S_000030_BUS_MSTR_RD_MULT(x) (((x) & 0x1) << 20) +#define G_000030_BUS_MSTR_RD_MULT(x) (((x) >> 20) & 0x1) +#define C_000030_BUS_MSTR_RD_MULT 0xFFEFFFFF +#define S_000030_BUS_MSTR_RD_LINE(x) (((x) & 0x1) << 21) +#define G_000030_BUS_MSTR_RD_LINE(x) (((x) >> 21) & 0x1) +#define C_000030_BUS_MSTR_RD_LINE 0xFFDFFFFF +#define S_000030_BUS_SUSPEND(x) (((x) & 0x1) << 22) +#define G_000030_BUS_SUSPEND(x) (((x) >> 22) & 0x1) +#define C_000030_BUS_SUSPEND 0xFFBFFFFF +#define S_000030_LAT_16X(x) (((x) & 0x1) << 23) +#define G_000030_LAT_16X(x) (((x) >> 23) & 0x1) +#define C_000030_LAT_16X 0xFF7FFFFF +#define S_000030_BUS_RD_DISCARD_EN(x) (((x) & 0x1) << 24) +#define G_000030_BUS_RD_DISCARD_EN(x) (((x) >> 24) & 0x1) +#define C_000030_BUS_RD_DISCARD_EN 0xFEFFFFFF +#define S_000030_ENFRCWRDY(x) (((x) & 0x1) << 25) +#define G_000030_ENFRCWRDY(x) (((x) >> 25) & 0x1) +#define C_000030_ENFRCWRDY 0xFDFFFFFF +#define S_000030_BUS_MSTR_WS(x) (((x) & 0x1) << 26) +#define G_000030_BUS_MSTR_WS(x) (((x) >> 26) & 0x1) +#define C_000030_BUS_MSTR_WS 0xFBFFFFFF +#define S_000030_BUS_PARKING_DIS(x) (((x) & 0x1) << 27) +#define G_000030_BUS_PARKING_DIS(x) (((x) >> 27) & 0x1) +#define C_000030_BUS_PARKING_DIS 0xF7FFFFFF +#define S_000030_BUS_MSTR_DISCONNECT_EN(x) (((x) & 0x1) << 28) +#define G_000030_BUS_MSTR_DISCONNECT_EN(x) (((x) >> 28) & 0x1) +#define C_000030_BUS_MSTR_DISCONNECT_EN 0xEFFFFFFF +#define S_000030_SERR_EN(x) (((x) & 0x1) << 29) +#define G_000030_SERR_EN(x) (((x) >> 29) & 0x1) +#define C_000030_SERR_EN 0xDFFFFFFF +#define S_000030_BUS_READ_BURST(x) (((x) & 0x1) << 30) +#define G_000030_BUS_READ_BURST(x) (((x) >> 30) & 0x1) +#define C_000030_BUS_READ_BURST 0xBFFFFFFF +#define S_000030_BUS_RDY_READ_DLY(x) (((x) & 0x1) << 31) +#define G_000030_BUS_RDY_READ_DLY(x) (((x) >> 31) & 0x1) +#define C_000030_BUS_RDY_READ_DLY 0x7FFFFFFF #define R_000040_GEN_INT_CNTL 0x000040 #define S_000040_CRTC_VBLANK(x) (((x) & 0x1) << 0) #define G_000040_CRTC_VBLANK(x) (((x) >> 0) & 0x1) diff --git a/drivers/gpu/drm/radeon/r300.c b/drivers/gpu/drm/radeon/r300.c index 7d5de5dbde23..199110ef8df2 100644 --- a/drivers/gpu/drm/radeon/r300.c +++ b/drivers/gpu/drm/radeon/r300.c @@ -151,6 +151,10 @@ void rv370_pcie_gart_disable(struct radeon_device *rdev) u32 tmp; int r; + WREG32_PCIE(RADEON_PCIE_TX_GART_START_LO, 0); + WREG32_PCIE(RADEON_PCIE_TX_GART_END_LO, 0); + WREG32_PCIE(RADEON_PCIE_TX_GART_START_HI, 0); + WREG32_PCIE(RADEON_PCIE_TX_GART_END_HI, 0); tmp = RREG32_PCIE(RADEON_PCIE_TX_GART_CNTL); tmp |= RADEON_PCIE_TX_GART_UNMAPPED_ACCESS_DISCARD; WREG32_PCIE(RADEON_PCIE_TX_GART_CNTL, tmp & ~RADEON_PCIE_TX_GART_EN); @@ -323,7 +327,6 @@ void r300_gpu_init(struct radeon_device *rdev) { uint32_t gb_tile_config, tmp; - r100_hdp_reset(rdev); /* FIXME: rv380 one pipes ? */ if ((rdev->family == CHIP_R300 && rdev->pdev->device != 0x4144) || (rdev->family == CHIP_R350)) { @@ -376,57 +379,6 @@ void r300_gpu_init(struct radeon_device *rdev) rdev->num_gb_pipes, rdev->num_z_pipes); } -int r300_ga_reset(struct radeon_device *rdev) -{ - uint32_t tmp; - bool reinit_cp; - int i; - - reinit_cp = rdev->cp.ready; - rdev->cp.ready = false; - for (i = 0; i < rdev->usec_timeout; i++) { - WREG32(RADEON_CP_CSQ_MODE, 0); - WREG32(RADEON_CP_CSQ_CNTL, 0); - WREG32(RADEON_RBBM_SOFT_RESET, 0x32005); - (void)RREG32(RADEON_RBBM_SOFT_RESET); - udelay(200); - WREG32(RADEON_RBBM_SOFT_RESET, 0); - /* Wait to prevent race in RBBM_STATUS */ - mdelay(1); - tmp = RREG32(RADEON_RBBM_STATUS); - if (tmp & ((1 << 20) | (1 << 26))) { - DRM_ERROR("VAP & CP still busy (RBBM_STATUS=0x%08X)", tmp); - /* GA still busy soft reset it */ - WREG32(0x429C, 0x200); - WREG32(R300_VAP_PVS_STATE_FLUSH_REG, 0); - WREG32(R300_RE_SCISSORS_TL, 0); - WREG32(R300_RE_SCISSORS_BR, 0); - WREG32(0x24AC, 0); - } - /* Wait to prevent race in RBBM_STATUS */ - mdelay(1); - tmp = RREG32(RADEON_RBBM_STATUS); - if (!(tmp & ((1 << 20) | (1 << 26)))) { - break; - } - } - for (i = 0; i < rdev->usec_timeout; i++) { - tmp = RREG32(RADEON_RBBM_STATUS); - if (!(tmp & ((1 << 20) | (1 << 26)))) { - DRM_INFO("GA reset succeed (RBBM_STATUS=0x%08X)\n", - tmp); - if (reinit_cp) { - return r100_cp_init(rdev, rdev->cp.ring_size); - } - return 0; - } - DRM_UDELAY(1); - } - tmp = RREG32(RADEON_RBBM_STATUS); - DRM_ERROR("Failed to reset GA ! (RBBM_STATUS=0x%08X)\n", tmp); - return -1; -} - bool r300_gpu_is_lockup(struct radeon_device *rdev) { u32 rbbm_status; @@ -451,37 +403,69 @@ bool r300_gpu_is_lockup(struct radeon_device *rdev) int r300_asic_reset(struct radeon_device *rdev) { - uint32_t status; + struct r100_mc_save save; + u32 status, tmp; - /* reset order likely matter */ - status = RREG32(RADEON_RBBM_STATUS); - dev_info(rdev->dev, "(%s:%d) RBBM_STATUS=0x%08X\n", __func__, __LINE__, status); - /* reset HDP */ - r100_hdp_reset(rdev); - /* reset rb2d */ - if (status & ((1 << 17) | (1 << 18) | (1 << 27))) { - r100_rb2d_reset(rdev); - } - /* reset GA */ - if (status & ((1 << 20) | (1 << 26))) { - r300_ga_reset(rdev); - } - /* reset CP */ - status = RREG32(RADEON_RBBM_STATUS); - if (status & (1 << 16)) { - r100_cp_reset(rdev); + r100_mc_stop(rdev, &save); + status = RREG32(R_000E40_RBBM_STATUS); + if (!G_000E40_GUI_ACTIVE(status)) { + return 0; } + status = RREG32(R_000E40_RBBM_STATUS); + dev_info(rdev->dev, "(%s:%d) RBBM_STATUS=0x%08X\n", __func__, __LINE__, status); + /* stop CP */ + WREG32(RADEON_CP_CSQ_CNTL, 0); + tmp = RREG32(RADEON_CP_RB_CNTL); + WREG32(RADEON_CP_RB_CNTL, tmp | RADEON_RB_RPTR_WR_ENA); + WREG32(RADEON_CP_RB_RPTR_WR, 0); + WREG32(RADEON_CP_RB_WPTR, 0); + WREG32(RADEON_CP_RB_CNTL, tmp); + /* save PCI state */ + pci_save_state(rdev->pdev); + /* disable bus mastering */ + r100_bm_disable(rdev); + WREG32(R_0000F0_RBBM_SOFT_RESET, S_0000F0_SOFT_RESET_VAP(1) | + S_0000F0_SOFT_RESET_GA(1)); + RREG32(R_0000F0_RBBM_SOFT_RESET); + mdelay(500); + WREG32(R_0000F0_RBBM_SOFT_RESET, 0); + mdelay(1); + status = RREG32(R_000E40_RBBM_STATUS); + dev_info(rdev->dev, "(%s:%d) RBBM_STATUS=0x%08X\n", __func__, __LINE__, status); + /* resetting the CP seems to be problematic sometimes it end up + * hard locking the computer, but it's necessary for successfull + * reset more test & playing is needed on R3XX/R4XX to find a + * reliable (if any solution) + */ + WREG32(R_0000F0_RBBM_SOFT_RESET, S_0000F0_SOFT_RESET_CP(1)); + RREG32(R_0000F0_RBBM_SOFT_RESET); + mdelay(500); + WREG32(R_0000F0_RBBM_SOFT_RESET, 0); + mdelay(1); + status = RREG32(R_000E40_RBBM_STATUS); + dev_info(rdev->dev, "(%s:%d) RBBM_STATUS=0x%08X\n", __func__, __LINE__, status); + /* reset MC */ + WREG32(R_0000F0_RBBM_SOFT_RESET, S_0000F0_SOFT_RESET_MC(1)); + RREG32(R_0000F0_RBBM_SOFT_RESET); + mdelay(500); + WREG32(R_0000F0_RBBM_SOFT_RESET, 0); + mdelay(1); + status = RREG32(R_000E40_RBBM_STATUS); + dev_info(rdev->dev, "(%s:%d) RBBM_STATUS=0x%08X\n", __func__, __LINE__, status); + /* restore PCI & busmastering */ + pci_restore_state(rdev->pdev); + r100_enable_bm(rdev); /* Check if GPU is idle */ - status = RREG32(RADEON_RBBM_STATUS); - if (status & RADEON_RBBM_ACTIVE) { - DRM_ERROR("Failed to reset GPU (RBBM_STATUS=0x%08X)\n", status); + if (G_000E40_GA_BUSY(status) || G_000E40_VAP_BUSY(status)) { + dev_err(rdev->dev, "failed to reset GPU\n"); + rdev->gpu_lockup = true; return -1; } - DRM_INFO("GPU reset succeed (RBBM_STATUS=0x%08X)\n", status); + r100_mc_resume(rdev, &save); + dev_info(rdev->dev, "GPU reset succeed\n"); return 0; } - /* * r300,r350,rv350,rv380 VRAM info */ diff --git a/drivers/gpu/drm/radeon/r300d.h b/drivers/gpu/drm/radeon/r300d.h index 4c73114f0de9..968a33317fbf 100644 --- a/drivers/gpu/drm/radeon/r300d.h +++ b/drivers/gpu/drm/radeon/r300d.h @@ -209,7 +209,52 @@ #define S_000E40_GUI_ACTIVE(x) (((x) & 0x1) << 31) #define G_000E40_GUI_ACTIVE(x) (((x) >> 31) & 0x1) #define C_000E40_GUI_ACTIVE 0x7FFFFFFF - +#define R_0000F0_RBBM_SOFT_RESET 0x0000F0 +#define S_0000F0_SOFT_RESET_CP(x) (((x) & 0x1) << 0) +#define G_0000F0_SOFT_RESET_CP(x) (((x) >> 0) & 0x1) +#define C_0000F0_SOFT_RESET_CP 0xFFFFFFFE +#define S_0000F0_SOFT_RESET_HI(x) (((x) & 0x1) << 1) +#define G_0000F0_SOFT_RESET_HI(x) (((x) >> 1) & 0x1) +#define C_0000F0_SOFT_RESET_HI 0xFFFFFFFD +#define S_0000F0_SOFT_RESET_VAP(x) (((x) & 0x1) << 2) +#define G_0000F0_SOFT_RESET_VAP(x) (((x) >> 2) & 0x1) +#define C_0000F0_SOFT_RESET_VAP 0xFFFFFFFB +#define S_0000F0_SOFT_RESET_RE(x) (((x) & 0x1) << 3) +#define G_0000F0_SOFT_RESET_RE(x) (((x) >> 3) & 0x1) +#define C_0000F0_SOFT_RESET_RE 0xFFFFFFF7 +#define S_0000F0_SOFT_RESET_PP(x) (((x) & 0x1) << 4) +#define G_0000F0_SOFT_RESET_PP(x) (((x) >> 4) & 0x1) +#define C_0000F0_SOFT_RESET_PP 0xFFFFFFEF +#define S_0000F0_SOFT_RESET_E2(x) (((x) & 0x1) << 5) +#define G_0000F0_SOFT_RESET_E2(x) (((x) >> 5) & 0x1) +#define C_0000F0_SOFT_RESET_E2 0xFFFFFFDF +#define S_0000F0_SOFT_RESET_RB(x) (((x) & 0x1) << 6) +#define G_0000F0_SOFT_RESET_RB(x) (((x) >> 6) & 0x1) +#define C_0000F0_SOFT_RESET_RB 0xFFFFFFBF +#define S_0000F0_SOFT_RESET_HDP(x) (((x) & 0x1) << 7) +#define G_0000F0_SOFT_RESET_HDP(x) (((x) >> 7) & 0x1) +#define C_0000F0_SOFT_RESET_HDP 0xFFFFFF7F +#define S_0000F0_SOFT_RESET_MC(x) (((x) & 0x1) << 8) +#define G_0000F0_SOFT_RESET_MC(x) (((x) >> 8) & 0x1) +#define C_0000F0_SOFT_RESET_MC 0xFFFFFEFF +#define S_0000F0_SOFT_RESET_AIC(x) (((x) & 0x1) << 9) +#define G_0000F0_SOFT_RESET_AIC(x) (((x) >> 9) & 0x1) +#define C_0000F0_SOFT_RESET_AIC 0xFFFFFDFF +#define S_0000F0_SOFT_RESET_VIP(x) (((x) & 0x1) << 10) +#define G_0000F0_SOFT_RESET_VIP(x) (((x) >> 10) & 0x1) +#define C_0000F0_SOFT_RESET_VIP 0xFFFFFBFF +#define S_0000F0_SOFT_RESET_DISP(x) (((x) & 0x1) << 11) +#define G_0000F0_SOFT_RESET_DISP(x) (((x) >> 11) & 0x1) +#define C_0000F0_SOFT_RESET_DISP 0xFFFFF7FF +#define S_0000F0_SOFT_RESET_CG(x) (((x) & 0x1) << 12) +#define G_0000F0_SOFT_RESET_CG(x) (((x) >> 12) & 0x1) +#define C_0000F0_SOFT_RESET_CG 0xFFFFEFFF +#define S_0000F0_SOFT_RESET_GA(x) (((x) & 0x1) << 13) +#define G_0000F0_SOFT_RESET_GA(x) (((x) >> 13) & 0x1) +#define C_0000F0_SOFT_RESET_GA 0xFFFFDFFF +#define S_0000F0_SOFT_RESET_IDCT(x) (((x) & 0x1) << 14) +#define G_0000F0_SOFT_RESET_IDCT(x) (((x) >> 14) & 0x1) +#define C_0000F0_SOFT_RESET_IDCT 0xFFFFBFFF #define R_00000D_SCLK_CNTL 0x00000D #define S_00000D_SCLK_SRC_SEL(x) (((x) & 0x7) << 0) diff --git a/drivers/gpu/drm/radeon/r520.c b/drivers/gpu/drm/radeon/r520.c index 3ade473e69ba..870111e26bd1 100644 --- a/drivers/gpu/drm/radeon/r520.c +++ b/drivers/gpu/drm/radeon/r520.c @@ -53,7 +53,6 @@ static void r520_gpu_init(struct radeon_device *rdev) { unsigned pipe_select_current, gb_pipe_select, tmp; - r100_hdp_reset(rdev); rv515_vga_render_disable(rdev); /* * DST_PIPE_CONFIG 0x170C diff --git a/drivers/gpu/drm/radeon/r600.c b/drivers/gpu/drm/radeon/r600.c index 24fd5459fb42..13c9cc34231d 100644 --- a/drivers/gpu/drm/radeon/r600.c +++ b/drivers/gpu/drm/radeon/r600.c @@ -749,7 +749,6 @@ int r600_gpu_soft_reset(struct radeon_device *rdev) S_008014_DB2_BUSY(1) | S_008014_DB3_BUSY(1) | S_008014_CB0_BUSY(1) | S_008014_CB1_BUSY(1) | S_008014_CB2_BUSY(1) | S_008014_CB3_BUSY(1); - u32 srbm_reset = 0; u32 tmp; dev_info(rdev->dev, "GPU softreset \n"); @@ -764,7 +763,7 @@ int r600_gpu_soft_reset(struct radeon_device *rdev) dev_warn(rdev->dev, "Wait for MC idle timedout !\n"); } /* Disable CP parsing/prefetching */ - WREG32(R_0086D8_CP_ME_CNTL, S_0086D8_CP_ME_HALT(0xff)); + WREG32(R_0086D8_CP_ME_CNTL, S_0086D8_CP_ME_HALT(1)); /* Check if any of the rendering block is busy and reset it */ if ((RREG32(R_008010_GRBM_STATUS) & grbm_busy_mask) || (RREG32(R_008014_GRBM_STATUS2) & grbm2_busy_mask)) { @@ -783,55 +782,17 @@ int r600_gpu_soft_reset(struct radeon_device *rdev) S_008020_SOFT_RESET_VGT(1); dev_info(rdev->dev, " R_008020_GRBM_SOFT_RESET=0x%08X\n", tmp); WREG32(R_008020_GRBM_SOFT_RESET, tmp); - (void)RREG32(R_008020_GRBM_SOFT_RESET); - mdelay(1); + RREG32(R_008020_GRBM_SOFT_RESET); + mdelay(15); WREG32(R_008020_GRBM_SOFT_RESET, 0); - (void)RREG32(R_008020_GRBM_SOFT_RESET); } /* Reset CP (we always reset CP) */ tmp = S_008020_SOFT_RESET_CP(1); dev_info(rdev->dev, "R_008020_GRBM_SOFT_RESET=0x%08X\n", tmp); WREG32(R_008020_GRBM_SOFT_RESET, tmp); - (void)RREG32(R_008020_GRBM_SOFT_RESET); - udelay(50); + RREG32(R_008020_GRBM_SOFT_RESET); + mdelay(15); WREG32(R_008020_GRBM_SOFT_RESET, 0); - (void)RREG32(R_008020_GRBM_SOFT_RESET); - /* Reset others GPU block if necessary */ - if (G_000E50_RLC_BUSY(RREG32(R_000E50_SRBM_STATUS))) - srbm_reset |= S_000E60_SOFT_RESET_RLC(1); - if (G_000E50_GRBM_RQ_PENDING(RREG32(R_000E50_SRBM_STATUS))) - srbm_reset |= S_000E60_SOFT_RESET_GRBM(1); - if (G_000E50_HI_RQ_PENDING(RREG32(R_000E50_SRBM_STATUS))) - srbm_reset |= S_000E60_SOFT_RESET_IH(1); - if (G_000E50_VMC_BUSY(RREG32(R_000E50_SRBM_STATUS))) - srbm_reset |= S_000E60_SOFT_RESET_VMC(1); - if (G_000E50_MCB_BUSY(RREG32(R_000E50_SRBM_STATUS))) - srbm_reset |= S_000E60_SOFT_RESET_MC(1); - if (G_000E50_MCDZ_BUSY(RREG32(R_000E50_SRBM_STATUS))) - srbm_reset |= S_000E60_SOFT_RESET_MC(1); - if (G_000E50_MCDY_BUSY(RREG32(R_000E50_SRBM_STATUS))) - srbm_reset |= S_000E60_SOFT_RESET_MC(1); - if (G_000E50_MCDX_BUSY(RREG32(R_000E50_SRBM_STATUS))) - srbm_reset |= S_000E60_SOFT_RESET_MC(1); - if (G_000E50_MCDW_BUSY(RREG32(R_000E50_SRBM_STATUS))) - srbm_reset |= S_000E60_SOFT_RESET_MC(1); - if (G_000E50_RLC_BUSY(RREG32(R_000E50_SRBM_STATUS))) - srbm_reset |= S_000E60_SOFT_RESET_RLC(1); - if (G_000E50_SEM_BUSY(RREG32(R_000E50_SRBM_STATUS))) - srbm_reset |= S_000E60_SOFT_RESET_SEM(1); - if (G_000E50_BIF_BUSY(RREG32(R_000E50_SRBM_STATUS))) - srbm_reset |= S_000E60_SOFT_RESET_BIF(1); - dev_info(rdev->dev, " R_000E60_SRBM_SOFT_RESET=0x%08X\n", srbm_reset); - WREG32(R_000E60_SRBM_SOFT_RESET, srbm_reset); - (void)RREG32(R_000E60_SRBM_SOFT_RESET); - mdelay(1); - WREG32(R_000E60_SRBM_SOFT_RESET, 0); - (void)RREG32(R_000E60_SRBM_SOFT_RESET); - WREG32(R_000E60_SRBM_SOFT_RESET, srbm_reset); - (void)RREG32(R_000E60_SRBM_SOFT_RESET); - mdelay(1); - WREG32(R_000E60_SRBM_SOFT_RESET, 0); - (void)RREG32(R_000E60_SRBM_SOFT_RESET); /* Wait a little for things to settle down */ mdelay(1); dev_info(rdev->dev, " R_008010_GRBM_STATUS=0x%08X\n", @@ -840,10 +801,6 @@ int r600_gpu_soft_reset(struct radeon_device *rdev) RREG32(R_008014_GRBM_STATUS2)); dev_info(rdev->dev, " R_000E50_SRBM_STATUS=0x%08X\n", RREG32(R_000E50_SRBM_STATUS)); - /* After reset we need to reinit the asic as GPU often endup in an - * incoherent state. - */ - atom_asic_init(rdev->mode_info.atom_context); rv515_mc_resume(rdev, &save); return 0; } diff --git a/drivers/gpu/drm/radeon/r600_blit_kms.c b/drivers/gpu/drm/radeon/r600_blit_kms.c index f6c6c77db7e0..d13622ae74e9 100644 --- a/drivers/gpu/drm/radeon/r600_blit_kms.c +++ b/drivers/gpu/drm/radeon/r600_blit_kms.c @@ -447,6 +447,9 @@ int r600_blit_init(struct radeon_device *rdev) u32 packet2s[16]; int num_packet2s = 0; + /* don't reinitialize blit */ + if (rdev->r600_blit.shader_obj) + return 0; mutex_init(&rdev->r600_blit.mutex); rdev->r600_blit.state_offset = 0; diff --git a/drivers/gpu/drm/radeon/radeon.h b/drivers/gpu/drm/radeon/radeon.h index 3cc5820b0e1b..4ac97ab28947 100644 --- a/drivers/gpu/drm/radeon/radeon.h +++ b/drivers/gpu/drm/radeon/radeon.h @@ -1188,6 +1188,7 @@ static inline void radeon_ring_write(struct radeon_device *rdev, uint32_t v) /* Common functions */ /* AGP */ +extern int radeon_gpu_reset(struct radeon_device *rdev); extern void radeon_agp_disable(struct radeon_device *rdev); extern int radeon_gart_table_vram_pin(struct radeon_device *rdev); extern void radeon_gart_restore(struct radeon_device *rdev); diff --git a/drivers/gpu/drm/radeon/radeon_asic.c b/drivers/gpu/drm/radeon/radeon_asic.c index 011ac6d86581..0d7664b8e489 100644 --- a/drivers/gpu/drm/radeon/radeon_asic.c +++ b/drivers/gpu/drm/radeon/radeon_asic.c @@ -367,7 +367,7 @@ static struct radeon_asic rs600_asic = { .resume = &rs600_resume, .vga_set_state = &r100_vga_set_state, .gpu_is_lockup = &r300_gpu_is_lockup, - .asic_reset = &r300_asic_reset, + .asic_reset = &rs600_asic_reset, .gart_tlb_flush = &rs600_gart_tlb_flush, .gart_set_page = &rs600_gart_set_page, .cp_commit = &r100_cp_commit, @@ -406,7 +406,7 @@ static struct radeon_asic rs690_asic = { .resume = &rs690_resume, .vga_set_state = &r100_vga_set_state, .gpu_is_lockup = &r300_gpu_is_lockup, - .asic_reset = &r300_asic_reset, + .asic_reset = &rs600_asic_reset, .gart_tlb_flush = &rs400_gart_tlb_flush, .gart_set_page = &rs400_gart_set_page, .cp_commit = &r100_cp_commit, @@ -445,7 +445,7 @@ static struct radeon_asic rv515_asic = { .resume = &rv515_resume, .vga_set_state = &r100_vga_set_state, .gpu_is_lockup = &r300_gpu_is_lockup, - .asic_reset = &rv515_asic_reset, + .asic_reset = &rs600_asic_reset, .gart_tlb_flush = &rv370_pcie_gart_tlb_flush, .gart_set_page = &rv370_pcie_gart_set_page, .cp_commit = &r100_cp_commit, @@ -484,7 +484,7 @@ static struct radeon_asic r520_asic = { .resume = &r520_resume, .vga_set_state = &r100_vga_set_state, .gpu_is_lockup = &r300_gpu_is_lockup, - .asic_reset = &rv515_asic_reset, + .asic_reset = &rs600_asic_reset, .gart_tlb_flush = &rv370_pcie_gart_tlb_flush, .gart_set_page = &rv370_pcie_gart_set_page, .cp_commit = &r100_cp_commit, @@ -560,6 +560,7 @@ static struct radeon_asic rs780_asic = { .suspend = &r600_suspend, .resume = &r600_resume, .cp_commit = &r600_cp_commit, + .gpu_is_lockup = &r600_gpu_is_lockup, .vga_set_state = &r600_vga_set_state, .asic_reset = &r600_asic_reset, .gart_tlb_flush = &r600_pcie_gart_tlb_flush, diff --git a/drivers/gpu/drm/radeon/radeon_asic.h b/drivers/gpu/drm/radeon/radeon_asic.h index 53ebcacbd0e0..77d48ba4a29a 100644 --- a/drivers/gpu/drm/radeon/radeon_asic.h +++ b/drivers/gpu/drm/radeon/radeon_asic.h @@ -111,8 +111,6 @@ void r100_vram_init_sizes(struct radeon_device *rdev); void r100_wb_disable(struct radeon_device *rdev); void r100_wb_fini(struct radeon_device *rdev); int r100_wb_init(struct radeon_device *rdev); -void r100_hdp_reset(struct radeon_device *rdev); -int r100_rb2d_reset(struct radeon_device *rdev); int r100_cp_reset(struct radeon_device *rdev); void r100_vga_render_disable(struct radeon_device *rdev); int r100_cs_track_check_pkt3_indx_buffer(struct radeon_cs_parser *p, @@ -127,7 +125,7 @@ int r100_cs_packet_parse(struct radeon_cs_parser *p, unsigned idx); void r100_enable_bm(struct radeon_device *rdev); void r100_set_common_regs(struct radeon_device *rdev); - +void r100_bm_disable(struct radeon_device *rdev); /* * r200,rv250,rs300,rv280 */ @@ -180,6 +178,7 @@ void rs400_mc_wreg(struct radeon_device *rdev, uint32_t reg, uint32_t v); /* * rs600. */ +extern int rs600_asic_reset(struct radeon_device *rdev); extern int rs600_init(struct radeon_device *rdev); extern void rs600_fini(struct radeon_device *rdev); extern int rs600_suspend(struct radeon_device *rdev); @@ -214,7 +213,6 @@ void rs690_bandwidth_update(struct radeon_device *rdev); */ int rv515_init(struct radeon_device *rdev); void rv515_fini(struct radeon_device *rdev); -int rv515_asic_reset(struct radeon_device *rdev); uint32_t rv515_mc_rreg(struct radeon_device *rdev, uint32_t reg); void rv515_mc_wreg(struct radeon_device *rdev, uint32_t reg, uint32_t v); void rv515_ring_start(struct radeon_device *rdev); diff --git a/drivers/gpu/drm/radeon/radeon_cs.c b/drivers/gpu/drm/radeon/radeon_cs.c index f9b0fe002c0a..ae0fb7356e62 100644 --- a/drivers/gpu/drm/radeon/radeon_cs.c +++ b/drivers/gpu/drm/radeon/radeon_cs.c @@ -220,10 +220,6 @@ int radeon_cs_ioctl(struct drm_device *dev, void *data, struct drm_file *filp) int r; mutex_lock(&rdev->cs_mutex); - if (rdev->gpu_lockup) { - mutex_unlock(&rdev->cs_mutex); - return -EINVAL; - } /* initialize parser */ memset(&parser, 0, sizeof(struct radeon_cs_parser)); parser.filp = filp; diff --git a/drivers/gpu/drm/radeon/radeon_device.c b/drivers/gpu/drm/radeon/radeon_device.c index 232a30768499..d4ff5a6d3496 100644 --- a/drivers/gpu/drm/radeon/radeon_device.c +++ b/drivers/gpu/drm/radeon/radeon_device.c @@ -639,6 +639,8 @@ void radeon_device_fini(struct radeon_device *rdev) { DRM_INFO("radeon: finishing device.\n"); rdev->shutdown = true; + /* evict vram memory */ + radeon_bo_evict_vram(rdev); radeon_fini(rdev); destroy_workqueue(rdev->wq); vga_switcheroo_unregister_client(rdev->pdev); @@ -737,6 +739,26 @@ int radeon_resume_kms(struct drm_device *dev) return 0; } +int radeon_gpu_reset(struct radeon_device *rdev) +{ + int r; + + radeon_save_bios_scratch_regs(rdev); + radeon_suspend(rdev); + + r = radeon_asic_reset(rdev); + if (!r) { + dev_info(rdev->dev, "GPU reset succeed\n"); + radeon_resume(rdev); + radeon_restore_bios_scratch_regs(rdev); + drm_helper_resume_force_mode(rdev->ddev); + return 0; + } + /* bad news, how to tell it to userspace ? */ + dev_info(rdev->dev, "GPU reset failed\n"); + return r; +} + /* * Debugfs diff --git a/drivers/gpu/drm/radeon/radeon_fence.c b/drivers/gpu/drm/radeon/radeon_fence.c index 2560740ff922..fcd7802d8a71 100644 --- a/drivers/gpu/drm/radeon/radeon_fence.c +++ b/drivers/gpu/drm/radeon/radeon_fence.c @@ -209,8 +209,9 @@ retry: r = wait_event_interruptible_timeout(rdev->fence_drv.queue, radeon_fence_signaled(fence), timeout); radeon_irq_kms_sw_irq_put(rdev); - if (unlikely(r < 0)) + if (unlikely(r < 0)) { return r; + } } else { radeon_irq_kms_sw_irq_get(rdev); r = wait_event_timeout(rdev->fence_drv.queue, @@ -230,14 +231,16 @@ retry: */ if (seq == rdev->fence_drv.last_seq && radeon_gpu_is_lockup(rdev)) { /* good news we believe it's a lockup */ - dev_warn(rdev->dev, "GPU lockup (last fence id 0x%08X)\n", seq); - r = radeon_asic_reset(rdev); - if (r) - return r; + WARN(1, "GPU lockup (waiting for 0x%08X last fence id 0x%08X)\n", fence->seq, seq); /* FIXME: what should we do ? marking everyone * as signaled for now */ + rdev->gpu_lockup = true; WREG32(rdev->fence_drv.scratch_reg, fence->seq); + r = radeon_gpu_reset(rdev); + if (r) + return r; + rdev->gpu_lockup = false; } timeout = RADEON_FENCE_JIFFIES_TIMEOUT; write_lock_irqsave(&rdev->fence_drv.lock, irq_flags); diff --git a/drivers/gpu/drm/radeon/radeon_gart.c b/drivers/gpu/drm/radeon/radeon_gart.c index 1770d3c07fd0..e65b90317fab 100644 --- a/drivers/gpu/drm/radeon/radeon_gart.c +++ b/drivers/gpu/drm/radeon/radeon_gart.c @@ -173,7 +173,7 @@ int radeon_gart_bind(struct radeon_device *rdev, unsigned offset, int i, j; if (!rdev->gart.ready) { - DRM_ERROR("trying to bind memory to unitialized GART !\n"); + WARN(1, "trying to bind memory to unitialized GART !\n"); return -EINVAL; } t = offset / RADEON_GPU_PAGE_SIZE; diff --git a/drivers/gpu/drm/radeon/rs400.c b/drivers/gpu/drm/radeon/rs400.c index 3deec2185083..9420c20dc142 100644 --- a/drivers/gpu/drm/radeon/rs400.c +++ b/drivers/gpu/drm/radeon/rs400.c @@ -242,8 +242,6 @@ int rs400_mc_wait_for_idle(struct radeon_device *rdev) void rs400_gpu_init(struct radeon_device *rdev) { - /* FIXME: HDP same place on rs400 ? */ - r100_hdp_reset(rdev); /* FIXME: is this correct ? */ r420_pipes_init(rdev); if (rs400_mc_wait_for_idle(rdev)) { diff --git a/drivers/gpu/drm/radeon/rs600.c b/drivers/gpu/drm/radeon/rs600.c index c1be20afd429..a16d9d79f36f 100644 --- a/drivers/gpu/drm/radeon/rs600.c +++ b/drivers/gpu/drm/radeon/rs600.c @@ -147,6 +147,78 @@ void rs600_hpd_fini(struct radeon_device *rdev) } } +void rs600_bm_disable(struct radeon_device *rdev) +{ + u32 tmp; + + /* disable bus mastering */ + pci_read_config_word(rdev->pdev, 0x4, (u16*)&tmp); + pci_write_config_word(rdev->pdev, 0x4, tmp & 0xFFFB); + mdelay(1); +} + +int rs600_asic_reset(struct radeon_device *rdev) +{ + u32 status, tmp; + + struct rv515_mc_save save; + + /* Stops all mc clients */ + rv515_mc_stop(rdev, &save); + status = RREG32(R_000E40_RBBM_STATUS); + if (!G_000E40_GUI_ACTIVE(status)) { + return 0; + } + status = RREG32(R_000E40_RBBM_STATUS); + dev_info(rdev->dev, "(%s:%d) RBBM_STATUS=0x%08X\n", __func__, __LINE__, status); + /* stop CP */ + WREG32(RADEON_CP_CSQ_CNTL, 0); + tmp = RREG32(RADEON_CP_RB_CNTL); + WREG32(RADEON_CP_RB_CNTL, tmp | RADEON_RB_RPTR_WR_ENA); + WREG32(RADEON_CP_RB_RPTR_WR, 0); + WREG32(RADEON_CP_RB_WPTR, 0); + WREG32(RADEON_CP_RB_CNTL, tmp); + pci_save_state(rdev->pdev); + /* disable bus mastering */ + rs600_bm_disable(rdev); + /* reset GA+VAP */ + WREG32(R_0000F0_RBBM_SOFT_RESET, S_0000F0_SOFT_RESET_VAP(1) | + S_0000F0_SOFT_RESET_GA(1)); + RREG32(R_0000F0_RBBM_SOFT_RESET); + mdelay(500); + WREG32(R_0000F0_RBBM_SOFT_RESET, 0); + mdelay(1); + status = RREG32(R_000E40_RBBM_STATUS); + dev_info(rdev->dev, "(%s:%d) RBBM_STATUS=0x%08X\n", __func__, __LINE__, status); + /* reset CP */ + WREG32(R_0000F0_RBBM_SOFT_RESET, S_0000F0_SOFT_RESET_CP(1)); + RREG32(R_0000F0_RBBM_SOFT_RESET); + mdelay(500); + WREG32(R_0000F0_RBBM_SOFT_RESET, 0); + mdelay(1); + status = RREG32(R_000E40_RBBM_STATUS); + dev_info(rdev->dev, "(%s:%d) RBBM_STATUS=0x%08X\n", __func__, __LINE__, status); + /* reset MC */ + WREG32(R_0000F0_RBBM_SOFT_RESET, S_0000F0_SOFT_RESET_MC(1)); + RREG32(R_0000F0_RBBM_SOFT_RESET); + mdelay(500); + WREG32(R_0000F0_RBBM_SOFT_RESET, 0); + mdelay(1); + status = RREG32(R_000E40_RBBM_STATUS); + dev_info(rdev->dev, "(%s:%d) RBBM_STATUS=0x%08X\n", __func__, __LINE__, status); + /* restore PCI & busmastering */ + pci_restore_state(rdev->pdev); + /* Check if GPU is idle */ + if (G_000E40_GA_BUSY(status) || G_000E40_VAP_BUSY(status)) { + dev_err(rdev->dev, "failed to reset GPU\n"); + rdev->gpu_lockup = true; + return -1; + } + rv515_mc_resume(rdev, &save); + dev_info(rdev->dev, "GPU reset succeed\n"); + return 0; +} + /* * GART. */ @@ -454,7 +526,6 @@ int rs600_mc_wait_for_idle(struct radeon_device *rdev) void rs600_gpu_init(struct radeon_device *rdev) { - r100_hdp_reset(rdev); r420_pipes_init(rdev); /* Wait for mc idle */ if (rs600_mc_wait_for_idle(rdev)) diff --git a/drivers/gpu/drm/radeon/rs600d.h b/drivers/gpu/drm/radeon/rs600d.h index e52d2695510b..08c4bebd3011 100644 --- a/drivers/gpu/drm/radeon/rs600d.h +++ b/drivers/gpu/drm/radeon/rs600d.h @@ -178,6 +178,52 @@ #define S_000074_MC_IND_DATA(x) (((x) & 0xFFFFFFFF) << 0) #define G_000074_MC_IND_DATA(x) (((x) >> 0) & 0xFFFFFFFF) #define C_000074_MC_IND_DATA 0x00000000 +#define R_0000F0_RBBM_SOFT_RESET 0x0000F0 +#define S_0000F0_SOFT_RESET_CP(x) (((x) & 0x1) << 0) +#define G_0000F0_SOFT_RESET_CP(x) (((x) >> 0) & 0x1) +#define C_0000F0_SOFT_RESET_CP 0xFFFFFFFE +#define S_0000F0_SOFT_RESET_HI(x) (((x) & 0x1) << 1) +#define G_0000F0_SOFT_RESET_HI(x) (((x) >> 1) & 0x1) +#define C_0000F0_SOFT_RESET_HI 0xFFFFFFFD +#define S_0000F0_SOFT_RESET_VAP(x) (((x) & 0x1) << 2) +#define G_0000F0_SOFT_RESET_VAP(x) (((x) >> 2) & 0x1) +#define C_0000F0_SOFT_RESET_VAP 0xFFFFFFFB +#define S_0000F0_SOFT_RESET_RE(x) (((x) & 0x1) << 3) +#define G_0000F0_SOFT_RESET_RE(x) (((x) >> 3) & 0x1) +#define C_0000F0_SOFT_RESET_RE 0xFFFFFFF7 +#define S_0000F0_SOFT_RESET_PP(x) (((x) & 0x1) << 4) +#define G_0000F0_SOFT_RESET_PP(x) (((x) >> 4) & 0x1) +#define C_0000F0_SOFT_RESET_PP 0xFFFFFFEF +#define S_0000F0_SOFT_RESET_E2(x) (((x) & 0x1) << 5) +#define G_0000F0_SOFT_RESET_E2(x) (((x) >> 5) & 0x1) +#define C_0000F0_SOFT_RESET_E2 0xFFFFFFDF +#define S_0000F0_SOFT_RESET_RB(x) (((x) & 0x1) << 6) +#define G_0000F0_SOFT_RESET_RB(x) (((x) >> 6) & 0x1) +#define C_0000F0_SOFT_RESET_RB 0xFFFFFFBF +#define S_0000F0_SOFT_RESET_HDP(x) (((x) & 0x1) << 7) +#define G_0000F0_SOFT_RESET_HDP(x) (((x) >> 7) & 0x1) +#define C_0000F0_SOFT_RESET_HDP 0xFFFFFF7F +#define S_0000F0_SOFT_RESET_MC(x) (((x) & 0x1) << 8) +#define G_0000F0_SOFT_RESET_MC(x) (((x) >> 8) & 0x1) +#define C_0000F0_SOFT_RESET_MC 0xFFFFFEFF +#define S_0000F0_SOFT_RESET_AIC(x) (((x) & 0x1) << 9) +#define G_0000F0_SOFT_RESET_AIC(x) (((x) >> 9) & 0x1) +#define C_0000F0_SOFT_RESET_AIC 0xFFFFFDFF +#define S_0000F0_SOFT_RESET_VIP(x) (((x) & 0x1) << 10) +#define G_0000F0_SOFT_RESET_VIP(x) (((x) >> 10) & 0x1) +#define C_0000F0_SOFT_RESET_VIP 0xFFFFFBFF +#define S_0000F0_SOFT_RESET_DISP(x) (((x) & 0x1) << 11) +#define G_0000F0_SOFT_RESET_DISP(x) (((x) >> 11) & 0x1) +#define C_0000F0_SOFT_RESET_DISP 0xFFFFF7FF +#define S_0000F0_SOFT_RESET_CG(x) (((x) & 0x1) << 12) +#define G_0000F0_SOFT_RESET_CG(x) (((x) >> 12) & 0x1) +#define C_0000F0_SOFT_RESET_CG 0xFFFFEFFF +#define S_0000F0_SOFT_RESET_GA(x) (((x) & 0x1) << 13) +#define G_0000F0_SOFT_RESET_GA(x) (((x) >> 13) & 0x1) +#define C_0000F0_SOFT_RESET_GA 0xFFFFDFFF +#define S_0000F0_SOFT_RESET_IDCT(x) (((x) & 0x1) << 14) +#define G_0000F0_SOFT_RESET_IDCT(x) (((x) >> 14) & 0x1) +#define C_0000F0_SOFT_RESET_IDCT 0xFFFFBFFF #define R_000134_HDP_FB_LOCATION 0x000134 #define S_000134_HDP_FB_START(x) (((x) & 0xFFFF) << 0) #define G_000134_HDP_FB_START(x) (((x) >> 0) & 0xFFFF) diff --git a/drivers/gpu/drm/radeon/rs690.c b/drivers/gpu/drm/radeon/rs690.c index ef35e0468f13..56a0aec84af2 100644 --- a/drivers/gpu/drm/radeon/rs690.c +++ b/drivers/gpu/drm/radeon/rs690.c @@ -48,8 +48,6 @@ static int rs690_mc_wait_for_idle(struct radeon_device *rdev) static void rs690_gpu_init(struct radeon_device *rdev) { - /* FIXME: HDP same place on rs690 ? */ - r100_hdp_reset(rdev); /* FIXME: is this correct ? */ r420_pipes_init(rdev); if (rs690_mc_wait_for_idle(rdev)) { diff --git a/drivers/gpu/drm/radeon/rv515.c b/drivers/gpu/drm/radeon/rv515.c index 2a4c01f5cf12..b42f8d90a0f6 100644 --- a/drivers/gpu/drm/radeon/rv515.c +++ b/drivers/gpu/drm/radeon/rv515.c @@ -146,16 +146,11 @@ void rv515_gpu_init(struct radeon_device *rdev) { unsigned pipe_select_current, gb_pipe_select, tmp; - r100_hdp_reset(rdev); - r100_rb2d_reset(rdev); - if (r100_gui_wait_for_idle(rdev)) { printk(KERN_WARNING "Failed to wait GUI idle while " "reseting GPU. Bad things might happen.\n"); } - rv515_vga_render_disable(rdev); - r420_pipes_init(rdev); gb_pipe_select = RREG32(0x402C); tmp = RREG32(0x170C); @@ -173,91 +168,6 @@ void rv515_gpu_init(struct radeon_device *rdev) } } -int rv515_ga_reset(struct radeon_device *rdev) -{ - uint32_t tmp; - bool reinit_cp; - int i; - - reinit_cp = rdev->cp.ready; - rdev->cp.ready = false; - for (i = 0; i < rdev->usec_timeout; i++) { - WREG32(CP_CSQ_MODE, 0); - WREG32(CP_CSQ_CNTL, 0); - WREG32(RBBM_SOFT_RESET, 0x32005); - (void)RREG32(RBBM_SOFT_RESET); - udelay(200); - WREG32(RBBM_SOFT_RESET, 0); - /* Wait to prevent race in RBBM_STATUS */ - mdelay(1); - tmp = RREG32(RBBM_STATUS); - if (tmp & ((1 << 20) | (1 << 26))) { - DRM_ERROR("VAP & CP still busy (RBBM_STATUS=0x%08X)\n", tmp); - /* GA still busy soft reset it */ - WREG32(0x429C, 0x200); - WREG32(VAP_PVS_STATE_FLUSH_REG, 0); - WREG32(0x43E0, 0); - WREG32(0x43E4, 0); - WREG32(0x24AC, 0); - } - /* Wait to prevent race in RBBM_STATUS */ - mdelay(1); - tmp = RREG32(RBBM_STATUS); - if (!(tmp & ((1 << 20) | (1 << 26)))) { - break; - } - } - for (i = 0; i < rdev->usec_timeout; i++) { - tmp = RREG32(RBBM_STATUS); - if (!(tmp & ((1 << 20) | (1 << 26)))) { - DRM_INFO("GA reset succeed (RBBM_STATUS=0x%08X)\n", - tmp); - DRM_INFO("GA_IDLE=0x%08X\n", RREG32(0x425C)); - DRM_INFO("RB3D_RESET_STATUS=0x%08X\n", RREG32(0x46f0)); - DRM_INFO("ISYNC_CNTL=0x%08X\n", RREG32(0x1724)); - if (reinit_cp) { - return r100_cp_init(rdev, rdev->cp.ring_size); - } - return 0; - } - DRM_UDELAY(1); - } - tmp = RREG32(RBBM_STATUS); - DRM_ERROR("Failed to reset GA ! (RBBM_STATUS=0x%08X)\n", tmp); - return -1; -} - -int rv515_asic_reset(struct radeon_device *rdev) -{ - uint32_t status; - - /* reset order likely matter */ - status = RREG32(RBBM_STATUS); - /* reset HDP */ - r100_hdp_reset(rdev); - /* reset rb2d */ - if (status & ((1 << 17) | (1 << 18) | (1 << 27))) { - r100_rb2d_reset(rdev); - } - /* reset GA */ - if (status & ((1 << 20) | (1 << 26))) { - rv515_ga_reset(rdev); - } - /* reset CP */ - status = RREG32(RBBM_STATUS); - if (status & (1 << 16)) { - r100_cp_reset(rdev); - } - /* Check if GPU is idle */ - status = RREG32(RBBM_STATUS); - if (status & (1 << 31)) { - DRM_ERROR("Failed to reset GPU (RBBM_STATUS=0x%08X)\n", status); - return -1; - } - DRM_INFO("GPU reset succeed (RBBM_STATUS=0x%08X)\n", status); - return 0; -} - static void rv515_vram_get_type(struct radeon_device *rdev) { uint32_t tmp; diff --git a/drivers/gpu/drm/radeon/rv515d.h b/drivers/gpu/drm/radeon/rv515d.h index fc216e49384d..590309a710b1 100644 --- a/drivers/gpu/drm/radeon/rv515d.h +++ b/drivers/gpu/drm/radeon/rv515d.h @@ -217,6 +217,52 @@ #define CP_PACKET3_GET_OPCODE(h) (((h) >> 8) & 0xFF) /* Registers */ +#define R_0000F0_RBBM_SOFT_RESET 0x0000F0 +#define S_0000F0_SOFT_RESET_CP(x) (((x) & 0x1) << 0) +#define G_0000F0_SOFT_RESET_CP(x) (((x) >> 0) & 0x1) +#define C_0000F0_SOFT_RESET_CP 0xFFFFFFFE +#define S_0000F0_SOFT_RESET_HI(x) (((x) & 0x1) << 1) +#define G_0000F0_SOFT_RESET_HI(x) (((x) >> 1) & 0x1) +#define C_0000F0_SOFT_RESET_HI 0xFFFFFFFD +#define S_0000F0_SOFT_RESET_VAP(x) (((x) & 0x1) << 2) +#define G_0000F0_SOFT_RESET_VAP(x) (((x) >> 2) & 0x1) +#define C_0000F0_SOFT_RESET_VAP 0xFFFFFFFB +#define S_0000F0_SOFT_RESET_RE(x) (((x) & 0x1) << 3) +#define G_0000F0_SOFT_RESET_RE(x) (((x) >> 3) & 0x1) +#define C_0000F0_SOFT_RESET_RE 0xFFFFFFF7 +#define S_0000F0_SOFT_RESET_PP(x) (((x) & 0x1) << 4) +#define G_0000F0_SOFT_RESET_PP(x) (((x) >> 4) & 0x1) +#define C_0000F0_SOFT_RESET_PP 0xFFFFFFEF +#define S_0000F0_SOFT_RESET_E2(x) (((x) & 0x1) << 5) +#define G_0000F0_SOFT_RESET_E2(x) (((x) >> 5) & 0x1) +#define C_0000F0_SOFT_RESET_E2 0xFFFFFFDF +#define S_0000F0_SOFT_RESET_RB(x) (((x) & 0x1) << 6) +#define G_0000F0_SOFT_RESET_RB(x) (((x) >> 6) & 0x1) +#define C_0000F0_SOFT_RESET_RB 0xFFFFFFBF +#define S_0000F0_SOFT_RESET_HDP(x) (((x) & 0x1) << 7) +#define G_0000F0_SOFT_RESET_HDP(x) (((x) >> 7) & 0x1) +#define C_0000F0_SOFT_RESET_HDP 0xFFFFFF7F +#define S_0000F0_SOFT_RESET_MC(x) (((x) & 0x1) << 8) +#define G_0000F0_SOFT_RESET_MC(x) (((x) >> 8) & 0x1) +#define C_0000F0_SOFT_RESET_MC 0xFFFFFEFF +#define S_0000F0_SOFT_RESET_AIC(x) (((x) & 0x1) << 9) +#define G_0000F0_SOFT_RESET_AIC(x) (((x) >> 9) & 0x1) +#define C_0000F0_SOFT_RESET_AIC 0xFFFFFDFF +#define S_0000F0_SOFT_RESET_VIP(x) (((x) & 0x1) << 10) +#define G_0000F0_SOFT_RESET_VIP(x) (((x) >> 10) & 0x1) +#define C_0000F0_SOFT_RESET_VIP 0xFFFFFBFF +#define S_0000F0_SOFT_RESET_DISP(x) (((x) & 0x1) << 11) +#define G_0000F0_SOFT_RESET_DISP(x) (((x) >> 11) & 0x1) +#define C_0000F0_SOFT_RESET_DISP 0xFFFFF7FF +#define S_0000F0_SOFT_RESET_CG(x) (((x) & 0x1) << 12) +#define G_0000F0_SOFT_RESET_CG(x) (((x) >> 12) & 0x1) +#define C_0000F0_SOFT_RESET_CG 0xFFFFEFFF +#define S_0000F0_SOFT_RESET_GA(x) (((x) & 0x1) << 13) +#define G_0000F0_SOFT_RESET_GA(x) (((x) >> 13) & 0x1) +#define C_0000F0_SOFT_RESET_GA 0xFFFFDFFF +#define S_0000F0_SOFT_RESET_IDCT(x) (((x) & 0x1) << 14) +#define G_0000F0_SOFT_RESET_IDCT(x) (((x) >> 14) & 0x1) +#define C_0000F0_SOFT_RESET_IDCT 0xFFFFBFFF #define R_0000F8_CONFIG_MEMSIZE 0x0000F8 #define S_0000F8_CONFIG_MEMSIZE(x) (((x) & 0xFFFFFFFF) << 0) #define G_0000F8_CONFIG_MEMSIZE(x) (((x) >> 0) & 0xFFFFFFFF) -- cgit v1.2.3 From 8d7cddcd7f9e847cec44851ca53fd3e81e846c49 Mon Sep 17 00:00:00 2001 From: Pauli Nieminen Date: Thu, 1 Apr 2010 12:44:59 +0000 Subject: drm/radeon/kms: Add ttm page pool debugfs file. ttm_page_pool file is hooked ttm_page_alloc_debugfs for pool allocator state. Signed-off-by: Pauli Nieminen Signed-off-by: Dave Airlie --- drivers/gpu/drm/radeon/radeon_ttm.c | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) (limited to 'drivers/gpu/drm/radeon') diff --git a/drivers/gpu/drm/radeon/radeon_ttm.c b/drivers/gpu/drm/radeon/radeon_ttm.c index 43c5ab34b634..fc787e8fa730 100644 --- a/drivers/gpu/drm/radeon/radeon_ttm.c +++ b/drivers/gpu/drm/radeon/radeon_ttm.c @@ -33,6 +33,7 @@ #include #include #include +#include #include #include #include @@ -744,8 +745,8 @@ static int radeon_mm_dump_table(struct seq_file *m, void *data) static int radeon_ttm_debugfs_init(struct radeon_device *rdev) { #if defined(CONFIG_DEBUG_FS) - static struct drm_info_list radeon_mem_types_list[RADEON_DEBUGFS_MEM_TYPES]; - static char radeon_mem_types_names[RADEON_DEBUGFS_MEM_TYPES][32]; + static struct drm_info_list radeon_mem_types_list[RADEON_DEBUGFS_MEM_TYPES+1]; + static char radeon_mem_types_names[RADEON_DEBUGFS_MEM_TYPES+1][32]; unsigned i; for (i = 0; i < RADEON_DEBUGFS_MEM_TYPES; i++) { @@ -762,7 +763,13 @@ static int radeon_ttm_debugfs_init(struct radeon_device *rdev) radeon_mem_types_list[i].data = &rdev->mman.bdev.man[TTM_PL_TT].manager; } - return radeon_debugfs_add_files(rdev, radeon_mem_types_list, RADEON_DEBUGFS_MEM_TYPES); + /* Add ttm page pool to debugfs */ + sprintf(radeon_mem_types_names[i], "ttm_page_pool"); + radeon_mem_types_list[i].name = radeon_mem_types_names[i]; + radeon_mem_types_list[i].show = &ttm_page_alloc_debugfs; + radeon_mem_types_list[i].driver_features = 0; + radeon_mem_types_list[i].data = NULL; + return radeon_debugfs_add_files(rdev, radeon_mem_types_list, RADEON_DEBUGFS_MEM_TYPES+1); #endif return 0; -- cgit v1.2.3 From 386516744ba45d50f42c6999151cc210cb4f96e4 Mon Sep 17 00:00:00 2001 From: Dave Airlie Date: Tue, 30 Mar 2010 05:34:13 +0000 Subject: drm/fb: fix fbdev object model + cleanup properly. The fbdev layer in the kms code should act like a consumer of the kms services and avoid having relying on information being store in the kms core structures in order for it to work. This patch a) removes the info pointer/psuedo palette from the core drm_framebuffer structure and moves it to the fbdev helper layer, it also removes the core drm keeping a list of kernel kms fbdevs. b) migrated all the fb helper functions out of the crtc helper file into the fb helper file. c) pushed the fb probing/hotplug control into the driver d) makes the surface sizes into a structure for ease of passing This changes the intel/radeon/nouveau drivers to use the new helper. Signed-off-by: Dave Airlie --- drivers/gpu/drm/drm_crtc.c | 1 - drivers/gpu/drm/drm_crtc_helper.c | 391 +------------------------ drivers/gpu/drm/drm_fb_helper.c | 469 ++++++++++++++++++++++++++---- drivers/gpu/drm/i915/i915_dma.c | 2 +- drivers/gpu/drm/i915/i915_drv.h | 4 + drivers/gpu/drm/i915/intel_display.c | 37 +-- drivers/gpu/drm/i915/intel_drv.h | 13 +- drivers/gpu/drm/i915/intel_fb.c | 175 ++++++----- drivers/gpu/drm/nouveau/nouveau_display.c | 41 ++- drivers/gpu/drm/nouveau/nouveau_drv.c | 19 +- drivers/gpu/drm/nouveau/nouveau_drv.h | 4 +- drivers/gpu/drm/nouveau/nouveau_fb.h | 6 +- drivers/gpu/drm/nouveau/nouveau_fbcon.c | 149 +++++++--- drivers/gpu/drm/nouveau/nouveau_fbcon.h | 15 +- drivers/gpu/drm/nouveau/nouveau_irq.c | 10 +- drivers/gpu/drm/nouveau/nouveau_state.c | 5 +- drivers/gpu/drm/radeon/radeon.h | 3 - drivers/gpu/drm/radeon/radeon_device.c | 9 +- drivers/gpu/drm/radeon/radeon_display.c | 42 +-- drivers/gpu/drm/radeon/radeon_fb.c | 220 +++++++------- drivers/gpu/drm/radeon/radeon_gem.c | 3 +- drivers/gpu/drm/radeon/radeon_irq_kms.c | 2 + drivers/gpu/drm/radeon/radeon_mode.h | 23 +- drivers/gpu/drm/vmwgfx/vmwgfx_kms.c | 6 - include/drm/drm_crtc.h | 12 - include/drm/drm_crtc_helper.h | 1 - include/drm/drm_fb_helper.h | 24 +- 27 files changed, 850 insertions(+), 836 deletions(-) (limited to 'drivers/gpu/drm/radeon') diff --git a/drivers/gpu/drm/drm_crtc.c b/drivers/gpu/drm/drm_crtc.c index d91fb8c0b7b3..6a472d534522 100644 --- a/drivers/gpu/drm/drm_crtc.c +++ b/drivers/gpu/drm/drm_crtc.c @@ -857,7 +857,6 @@ void drm_mode_config_init(struct drm_device *dev) mutex_init(&dev->mode_config.mutex); mutex_init(&dev->mode_config.idr_mutex); INIT_LIST_HEAD(&dev->mode_config.fb_list); - INIT_LIST_HEAD(&dev->mode_config.fb_kernel_list); INIT_LIST_HEAD(&dev->mode_config.crtc_list); INIT_LIST_HEAD(&dev->mode_config.connector_list); INIT_LIST_HEAD(&dev->mode_config.encoder_list); diff --git a/drivers/gpu/drm/drm_crtc_helper.c b/drivers/gpu/drm/drm_crtc_helper.c index 51103aa469f8..9d23f54673d3 100644 --- a/drivers/gpu/drm/drm_crtc_helper.c +++ b/drivers/gpu/drm/drm_crtc_helper.c @@ -55,7 +55,7 @@ static void drm_mode_validate_flag(struct drm_connector *connector, } /** - * drm_helper_probe_connector_modes - get complete set of display modes + * drm_helper_probe_single_connector_modes - get complete set of display modes * @dev: DRM device * @maxX: max width for modes * @maxY: max height for modes @@ -154,21 +154,6 @@ prune: } EXPORT_SYMBOL(drm_helper_probe_single_connector_modes); -int drm_helper_probe_connector_modes(struct drm_device *dev, uint32_t maxX, - uint32_t maxY) -{ - struct drm_connector *connector; - int count = 0; - - list_for_each_entry(connector, &dev->mode_config.connector_list, head) { - count += drm_helper_probe_single_connector_modes(connector, - maxX, maxY); - } - - return count; -} -EXPORT_SYMBOL(drm_helper_probe_connector_modes); - /** * drm_helper_encoder_in_use - check if a given encoder is in use * @encoder: encoder to check @@ -263,302 +248,6 @@ void drm_helper_disable_unused_functions(struct drm_device *dev) } EXPORT_SYMBOL(drm_helper_disable_unused_functions); -static struct drm_display_mode *drm_has_preferred_mode(struct drm_connector *connector, int width, int height) -{ - struct drm_display_mode *mode; - - list_for_each_entry(mode, &connector->modes, head) { - if (drm_mode_width(mode) > width || - drm_mode_height(mode) > height) - continue; - if (mode->type & DRM_MODE_TYPE_PREFERRED) - return mode; - } - return NULL; -} - -static bool drm_has_cmdline_mode(struct drm_connector *connector) -{ - struct drm_fb_helper_connector *fb_help_conn = connector->fb_helper_private; - struct drm_fb_helper_cmdline_mode *cmdline_mode; - - if (!fb_help_conn) - return false; - - cmdline_mode = &fb_help_conn->cmdline_mode; - return cmdline_mode->specified; -} - -static struct drm_display_mode *drm_pick_cmdline_mode(struct drm_connector *connector, int width, int height) -{ - struct drm_fb_helper_connector *fb_help_conn = connector->fb_helper_private; - struct drm_fb_helper_cmdline_mode *cmdline_mode; - struct drm_display_mode *mode = NULL; - - if (!fb_help_conn) - return mode; - - cmdline_mode = &fb_help_conn->cmdline_mode; - if (cmdline_mode->specified == false) - return mode; - - /* attempt to find a matching mode in the list of modes - * we have gotten so far, if not add a CVT mode that conforms - */ - if (cmdline_mode->rb || cmdline_mode->margins) - goto create_mode; - - list_for_each_entry(mode, &connector->modes, head) { - /* check width/height */ - if (mode->hdisplay != cmdline_mode->xres || - mode->vdisplay != cmdline_mode->yres) - continue; - - if (cmdline_mode->refresh_specified) { - if (mode->vrefresh != cmdline_mode->refresh) - continue; - } - - if (cmdline_mode->interlace) { - if (!(mode->flags & DRM_MODE_FLAG_INTERLACE)) - continue; - } - return mode; - } - -create_mode: - mode = drm_cvt_mode(connector->dev, cmdline_mode->xres, - cmdline_mode->yres, - cmdline_mode->refresh_specified ? cmdline_mode->refresh : 60, - cmdline_mode->rb, cmdline_mode->interlace, - cmdline_mode->margins); - drm_mode_set_crtcinfo(mode, CRTC_INTERLACE_HALVE_V); - list_add(&mode->head, &connector->modes); - return mode; -} - -static bool drm_connector_enabled(struct drm_connector *connector, bool strict) -{ - bool enable; - - if (strict) { - enable = connector->status == connector_status_connected; - } else { - enable = connector->status != connector_status_disconnected; - } - return enable; -} - -static void drm_enable_connectors(struct drm_device *dev, bool *enabled) -{ - bool any_enabled = false; - struct drm_connector *connector; - int i = 0; - - list_for_each_entry(connector, &dev->mode_config.connector_list, head) { - enabled[i] = drm_connector_enabled(connector, true); - DRM_DEBUG_KMS("connector %d enabled? %s\n", connector->base.id, - enabled[i] ? "yes" : "no"); - any_enabled |= enabled[i]; - i++; - } - - if (any_enabled) - return; - - i = 0; - list_for_each_entry(connector, &dev->mode_config.connector_list, head) { - enabled[i] = drm_connector_enabled(connector, false); - i++; - } -} - -static bool drm_target_preferred(struct drm_device *dev, - struct drm_display_mode **modes, - bool *enabled, int width, int height) -{ - struct drm_connector *connector; - int i = 0; - - list_for_each_entry(connector, &dev->mode_config.connector_list, head) { - - if (enabled[i] == false) { - i++; - continue; - } - - DRM_DEBUG_KMS("looking for cmdline mode on connector %d\n", - connector->base.id); - - /* got for command line mode first */ - modes[i] = drm_pick_cmdline_mode(connector, width, height); - if (!modes[i]) { - DRM_DEBUG_KMS("looking for preferred mode on connector %d\n", - connector->base.id); - modes[i] = drm_has_preferred_mode(connector, width, height); - } - /* No preferred modes, pick one off the list */ - if (!modes[i] && !list_empty(&connector->modes)) { - list_for_each_entry(modes[i], &connector->modes, head) - break; - } - DRM_DEBUG_KMS("found mode %s\n", modes[i] ? modes[i]->name : - "none"); - i++; - } - return true; -} - -static int drm_pick_crtcs(struct drm_device *dev, - struct drm_crtc **best_crtcs, - struct drm_display_mode **modes, - int n, int width, int height) -{ - int c, o; - struct drm_connector *connector; - struct drm_connector_helper_funcs *connector_funcs; - struct drm_encoder *encoder; - struct drm_crtc *best_crtc; - int my_score, best_score, score; - struct drm_crtc **crtcs, *crtc; - - if (n == dev->mode_config.num_connector) - return 0; - c = 0; - list_for_each_entry(connector, &dev->mode_config.connector_list, head) { - if (c == n) - break; - c++; - } - - best_crtcs[n] = NULL; - best_crtc = NULL; - best_score = drm_pick_crtcs(dev, best_crtcs, modes, n+1, width, height); - if (modes[n] == NULL) - return best_score; - - crtcs = kmalloc(dev->mode_config.num_connector * - sizeof(struct drm_crtc *), GFP_KERNEL); - if (!crtcs) - return best_score; - - my_score = 1; - if (connector->status == connector_status_connected) - my_score++; - if (drm_has_cmdline_mode(connector)) - my_score++; - if (drm_has_preferred_mode(connector, width, height)) - my_score++; - - connector_funcs = connector->helper_private; - encoder = connector_funcs->best_encoder(connector); - if (!encoder) - goto out; - - connector->encoder = encoder; - - /* select a crtc for this connector and then attempt to configure - remaining connectors */ - c = 0; - list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) { - - if ((encoder->possible_crtcs & (1 << c)) == 0) { - c++; - continue; - } - - for (o = 0; o < n; o++) - if (best_crtcs[o] == crtc) - break; - - if (o < n) { - /* ignore cloning for now */ - c++; - continue; - } - - crtcs[n] = crtc; - memcpy(crtcs, best_crtcs, n * sizeof(struct drm_crtc *)); - score = my_score + drm_pick_crtcs(dev, crtcs, modes, n + 1, - width, height); - if (score > best_score) { - best_crtc = crtc; - best_score = score; - memcpy(best_crtcs, crtcs, - dev->mode_config.num_connector * - sizeof(struct drm_crtc *)); - } - c++; - } -out: - kfree(crtcs); - return best_score; -} - -static void drm_setup_crtcs(struct drm_device *dev) -{ - struct drm_crtc **crtcs; - struct drm_display_mode **modes; - struct drm_encoder *encoder; - struct drm_connector *connector; - bool *enabled; - int width, height; - int i, ret; - - DRM_DEBUG_KMS("\n"); - - width = dev->mode_config.max_width; - height = dev->mode_config.max_height; - - /* clean out all the encoder/crtc combos */ - list_for_each_entry(encoder, &dev->mode_config.encoder_list, head) { - encoder->crtc = NULL; - } - - crtcs = kcalloc(dev->mode_config.num_connector, - sizeof(struct drm_crtc *), GFP_KERNEL); - modes = kcalloc(dev->mode_config.num_connector, - sizeof(struct drm_display_mode *), GFP_KERNEL); - enabled = kcalloc(dev->mode_config.num_connector, - sizeof(bool), GFP_KERNEL); - - drm_enable_connectors(dev, enabled); - - ret = drm_target_preferred(dev, modes, enabled, width, height); - if (!ret) - DRM_ERROR("Unable to find initial modes\n"); - - DRM_DEBUG_KMS("picking CRTCs for %dx%d config\n", width, height); - - drm_pick_crtcs(dev, crtcs, modes, 0, width, height); - - i = 0; - list_for_each_entry(connector, &dev->mode_config.connector_list, head) { - struct drm_display_mode *mode = modes[i]; - struct drm_crtc *crtc = crtcs[i]; - - if (connector->encoder == NULL) { - i++; - continue; - } - - if (mode && crtc) { - DRM_DEBUG_KMS("desired mode %s set on crtc %d\n", - mode->name, crtc->base.id); - crtc->desired_mode = mode; - connector->encoder->crtc = crtc; - } else { - connector->encoder->crtc = NULL; - connector->encoder = NULL; - } - i++; - } - - kfree(crtcs); - kfree(modes); - kfree(enabled); -} - /** * drm_encoder_crtc_ok - can a given crtc drive a given encoder? * @encoder: encoder to test @@ -984,63 +673,6 @@ fail: } EXPORT_SYMBOL(drm_crtc_helper_set_config); -bool drm_helper_plugged_event(struct drm_device *dev) -{ - DRM_DEBUG_KMS("\n"); - - drm_helper_probe_connector_modes(dev, dev->mode_config.max_width, - dev->mode_config.max_height); - - drm_setup_crtcs(dev); - - /* alert the driver fb layer */ - dev->mode_config.funcs->fb_changed(dev); - - /* FIXME: send hotplug event */ - return true; -} -/** - * drm_initial_config - setup a sane initial connector configuration - * @dev: DRM device - * - * LOCKING: - * Called at init time, must take mode config lock. - * - * Scan the CRTCs and connectors and try to put together an initial setup. - * At the moment, this is a cloned configuration across all heads with - * a new framebuffer object as the backing store. - * - * RETURNS: - * Zero if everything went ok, nonzero otherwise. - */ -bool drm_helper_initial_config(struct drm_device *dev) -{ - int count = 0; - - /* disable all the possible outputs/crtcs before entering KMS mode */ - drm_helper_disable_unused_functions(dev); - - drm_fb_helper_parse_command_line(dev); - - count = drm_helper_probe_connector_modes(dev, - dev->mode_config.max_width, - dev->mode_config.max_height); - - /* - * we shouldn't end up with no modes here. - */ - if (count == 0) - printk(KERN_INFO "No connectors reported connected with modes\n"); - - drm_setup_crtcs(dev); - - /* alert the driver fb layer */ - dev->mode_config.funcs->fb_changed(dev); - - return 0; -} -EXPORT_SYMBOL(drm_helper_initial_config); - static int drm_helper_choose_encoder_dpms(struct drm_encoder *encoder) { int dpms = DRM_MODE_DPMS_OFF; @@ -1123,27 +755,6 @@ void drm_helper_connector_dpms(struct drm_connector *connector, int mode) } EXPORT_SYMBOL(drm_helper_connector_dpms); -/** - * drm_hotplug_stage_two - * @dev DRM device - * @connector hotpluged connector - * - * LOCKING. - * Caller must hold mode config lock, function might grab struct lock. - * - * Stage two of a hotplug. - * - * RETURNS: - * Zero on success, errno on failure. - */ -int drm_helper_hotplug_stage_two(struct drm_device *dev) -{ - drm_helper_plugged_event(dev); - - return 0; -} -EXPORT_SYMBOL(drm_helper_hotplug_stage_two); - int drm_helper_mode_fill_fb_struct(struct drm_framebuffer *fb, struct drm_mode_fb_cmd *mode_cmd) { diff --git a/drivers/gpu/drm/drm_fb_helper.c b/drivers/gpu/drm/drm_fb_helper.c index 99487237111d..055b5be78877 100644 --- a/drivers/gpu/drm/drm_fb_helper.c +++ b/drivers/gpu/drm/drm_fb_helper.c @@ -747,32 +747,30 @@ EXPORT_SYMBOL(drm_fb_helper_pan_display); int drm_fb_helper_single_fb_probe(struct drm_device *dev, int preferred_bpp, - int (*fb_create)(struct drm_device *dev, - uint32_t fb_width, - uint32_t fb_height, - uint32_t surface_width, - uint32_t surface_height, - uint32_t surface_depth, - uint32_t surface_bpp, - struct drm_framebuffer **fb_ptr)) + int (*fb_find_or_create)(struct drm_device *dev, + struct drm_fb_helper_surface_size *sizes, + struct drm_fb_helper **fb_ptr)) { struct drm_crtc *crtc; struct drm_connector *connector; - unsigned int fb_width = (unsigned)-1, fb_height = (unsigned)-1; - unsigned int surface_width = 0, surface_height = 0; int new_fb = 0; int crtc_count = 0; int ret, i, conn_count = 0; struct fb_info *info; - struct drm_framebuffer *fb; struct drm_mode_set *modeset = NULL; struct drm_fb_helper *fb_helper; - uint32_t surface_depth = 24, surface_bpp = 32; + struct drm_fb_helper_surface_size sizes; + + memset(&sizes, 0, sizeof(struct drm_fb_helper_surface_size)); + sizes.surface_depth = 24; + sizes.surface_bpp = 32; + sizes.fb_width = (unsigned)-1; + sizes.fb_height = (unsigned)-1; /* if driver picks 8 or 16 by default use that for both depth/bpp */ - if (preferred_bpp != surface_bpp) { - surface_depth = surface_bpp = preferred_bpp; + if (preferred_bpp != sizes.surface_bpp) { + sizes.surface_depth = sizes.surface_bpp = preferred_bpp; } /* first up get a count of crtcs now in use and new min/maxes width/heights */ list_for_each_entry(connector, &dev->mode_config.connector_list, head) { @@ -788,21 +786,21 @@ int drm_fb_helper_single_fb_probe(struct drm_device *dev, if (cmdline_mode->bpp_specified) { switch (cmdline_mode->bpp) { case 8: - surface_depth = surface_bpp = 8; + sizes.surface_depth = sizes.surface_bpp = 8; break; case 15: - surface_depth = 15; - surface_bpp = 16; + sizes.surface_depth = 15; + sizes.surface_bpp = 16; break; case 16: - surface_depth = surface_bpp = 16; + sizes.surface_depth = sizes.surface_bpp = 16; break; case 24: - surface_depth = surface_bpp = 24; + sizes.surface_depth = sizes.surface_bpp = 24; break; case 32: - surface_depth = 24; - surface_bpp = 32; + sizes.surface_depth = 24; + sizes.surface_bpp = 32; break; } break; @@ -812,59 +810,41 @@ int drm_fb_helper_single_fb_probe(struct drm_device *dev, list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) { if (drm_helper_crtc_in_use(crtc)) { if (crtc->desired_mode) { - if (crtc->desired_mode->hdisplay < fb_width) - fb_width = crtc->desired_mode->hdisplay; + if (crtc->desired_mode->hdisplay < sizes.fb_width) + sizes.fb_width = crtc->desired_mode->hdisplay; - if (crtc->desired_mode->vdisplay < fb_height) - fb_height = crtc->desired_mode->vdisplay; + if (crtc->desired_mode->vdisplay < sizes.fb_height) + sizes.fb_height = crtc->desired_mode->vdisplay; - if (crtc->desired_mode->hdisplay > surface_width) - surface_width = crtc->desired_mode->hdisplay; + if (crtc->desired_mode->hdisplay > sizes.surface_width) + sizes.surface_width = crtc->desired_mode->hdisplay; - if (crtc->desired_mode->vdisplay > surface_height) - surface_height = crtc->desired_mode->vdisplay; + if (crtc->desired_mode->vdisplay > sizes.surface_height) + sizes.surface_height = crtc->desired_mode->vdisplay; } crtc_count++; } } - if (crtc_count == 0 || fb_width == -1 || fb_height == -1) { + if (crtc_count == 0 || sizes.fb_width == -1 || sizes.fb_height == -1) { /* hmm everyone went away - assume VGA cable just fell out and will come back later. */ return 0; } - /* do we have an fb already? */ - if (list_empty(&dev->mode_config.fb_kernel_list)) { - ret = (*fb_create)(dev, fb_width, fb_height, surface_width, - surface_height, surface_depth, surface_bpp, - &fb); - if (ret) - return -EINVAL; - new_fb = 1; - } else { - fb = list_first_entry(&dev->mode_config.fb_kernel_list, - struct drm_framebuffer, filp_head); - - /* if someone hotplugs something bigger than we have already allocated, we are pwned. - As really we can't resize an fbdev that is in the wild currently due to fbdev - not really being designed for the lower layers moving stuff around under it. - - so in the grand style of things - punt. */ - if ((fb->width < surface_width) || - (fb->height < surface_height)) { - DRM_ERROR("Framebuffer not large enough to scale console onto.\n"); - return -EINVAL; - } - } + /* push down into drivers */ + new_fb = (*fb_find_or_create)(dev, &sizes, + &fb_helper); + if (new_fb < 0) + return new_fb; - info = fb->fbdev; - fb_helper = info->par; + info = fb_helper->fbdev; crtc_count = 0; /* okay we need to setup new connector sets in the crtcs */ list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) { modeset = &fb_helper->crtc_info[crtc_count].mode_set; - modeset->fb = fb; + modeset->fb = fb_helper->fb; conn_count = 0; list_for_each_entry(connector, &dev->mode_config.connector_list, head) { if (connector->encoder) @@ -891,7 +871,6 @@ int drm_fb_helper_single_fb_probe(struct drm_device *dev, } } fb_helper->crtc_count = crtc_count; - fb_helper->fb = fb; if (new_fb) { info->var.pixclock = 0; @@ -902,11 +881,13 @@ int drm_fb_helper_single_fb_probe(struct drm_device *dev, fb_dealloc_cmap(&info->cmap); return -EINVAL; } + + printk(KERN_INFO "fb%d: %s frame buffer device\n", info->node, + info->fix.id); + } else { drm_fb_helper_set_par(info); } - printk(KERN_INFO "fb%d: %s frame buffer device\n", info->node, - info->fix.id); /* Switch back to kernel console on panic */ /* multi card linked list maybe */ @@ -916,7 +897,9 @@ int drm_fb_helper_single_fb_probe(struct drm_device *dev, &paniced); register_sysrq_key('v', &sysrq_drm_fb_helper_restore_op); } - list_add(&fb_helper->kernel_fb_list, &kernel_fb_helper_list); + if (new_fb) + list_add(&fb_helper->kernel_fb_list, &kernel_fb_helper_list); + return 0; } EXPORT_SYMBOL(drm_fb_helper_single_fb_probe); @@ -931,7 +914,7 @@ void drm_fb_helper_free(struct drm_fb_helper *helper) unregister_sysrq_key('v', &sysrq_drm_fb_helper_restore_op); } drm_fb_helper_crtc_free(helper); - fb_dealloc_cmap(&helper->fb->fbdev->cmap); + fb_dealloc_cmap(&helper->fbdev->cmap); } EXPORT_SYMBOL(drm_fb_helper_free); @@ -953,10 +936,11 @@ void drm_fb_helper_fill_fix(struct fb_info *info, uint32_t pitch, } EXPORT_SYMBOL(drm_fb_helper_fill_fix); -void drm_fb_helper_fill_var(struct fb_info *info, struct drm_framebuffer *fb, +void drm_fb_helper_fill_var(struct fb_info *info, struct drm_fb_helper *fb_helper, uint32_t fb_width, uint32_t fb_height) { - info->pseudo_palette = fb->pseudo_palette; + struct drm_framebuffer *fb = fb_helper->fb; + info->pseudo_palette = fb_helper->pseudo_palette; info->var.xres_virtual = fb->width; info->var.yres_virtual = fb->height; info->var.bits_per_pixel = fb->bits_per_pixel; @@ -1024,3 +1008,364 @@ void drm_fb_helper_fill_var(struct fb_info *info, struct drm_framebuffer *fb, info->var.yres = fb_height; } EXPORT_SYMBOL(drm_fb_helper_fill_var); + +static int drm_helper_probe_connector_modes(struct drm_device *dev, uint32_t maxX, + uint32_t maxY) +{ + struct drm_connector *connector; + int count = 0; + + list_for_each_entry(connector, &dev->mode_config.connector_list, head) { + count += connector->funcs->fill_modes(connector, maxX, maxY); + } + + return count; +} + +static struct drm_display_mode *drm_has_preferred_mode(struct drm_connector *connector, int width, int height) +{ + struct drm_display_mode *mode; + + list_for_each_entry(mode, &connector->modes, head) { + if (drm_mode_width(mode) > width || + drm_mode_height(mode) > height) + continue; + if (mode->type & DRM_MODE_TYPE_PREFERRED) + return mode; + } + return NULL; +} + +static bool drm_has_cmdline_mode(struct drm_connector *connector) +{ + struct drm_fb_helper_connector *fb_help_conn = connector->fb_helper_private; + struct drm_fb_helper_cmdline_mode *cmdline_mode; + + if (!fb_help_conn) + return false; + + cmdline_mode = &fb_help_conn->cmdline_mode; + return cmdline_mode->specified; +} + +static struct drm_display_mode *drm_pick_cmdline_mode(struct drm_connector *connector, int width, int height) +{ + struct drm_fb_helper_connector *fb_help_conn = connector->fb_helper_private; + struct drm_fb_helper_cmdline_mode *cmdline_mode; + struct drm_display_mode *mode = NULL; + + if (!fb_help_conn) + return mode; + + cmdline_mode = &fb_help_conn->cmdline_mode; + if (cmdline_mode->specified == false) + return mode; + + /* attempt to find a matching mode in the list of modes + * we have gotten so far, if not add a CVT mode that conforms + */ + if (cmdline_mode->rb || cmdline_mode->margins) + goto create_mode; + + list_for_each_entry(mode, &connector->modes, head) { + /* check width/height */ + if (mode->hdisplay != cmdline_mode->xres || + mode->vdisplay != cmdline_mode->yres) + continue; + + if (cmdline_mode->refresh_specified) { + if (mode->vrefresh != cmdline_mode->refresh) + continue; + } + + if (cmdline_mode->interlace) { + if (!(mode->flags & DRM_MODE_FLAG_INTERLACE)) + continue; + } + return mode; + } + +create_mode: + mode = drm_cvt_mode(connector->dev, cmdline_mode->xres, + cmdline_mode->yres, + cmdline_mode->refresh_specified ? cmdline_mode->refresh : 60, + cmdline_mode->rb, cmdline_mode->interlace, + cmdline_mode->margins); + drm_mode_set_crtcinfo(mode, CRTC_INTERLACE_HALVE_V); + list_add(&mode->head, &connector->modes); + return mode; +} + +static bool drm_connector_enabled(struct drm_connector *connector, bool strict) +{ + bool enable; + + if (strict) { + enable = connector->status == connector_status_connected; + } else { + enable = connector->status != connector_status_disconnected; + } + return enable; +} + +static void drm_enable_connectors(struct drm_device *dev, bool *enabled) +{ + bool any_enabled = false; + struct drm_connector *connector; + int i = 0; + + list_for_each_entry(connector, &dev->mode_config.connector_list, head) { + enabled[i] = drm_connector_enabled(connector, true); + DRM_DEBUG_KMS("connector %d enabled? %s\n", connector->base.id, + enabled[i] ? "yes" : "no"); + any_enabled |= enabled[i]; + i++; + } + + if (any_enabled) + return; + + i = 0; + list_for_each_entry(connector, &dev->mode_config.connector_list, head) { + enabled[i] = drm_connector_enabled(connector, false); + i++; + } +} + +static bool drm_target_preferred(struct drm_device *dev, + struct drm_display_mode **modes, + bool *enabled, int width, int height) +{ + struct drm_connector *connector; + int i = 0; + + list_for_each_entry(connector, &dev->mode_config.connector_list, head) { + + if (enabled[i] == false) { + i++; + continue; + } + + DRM_DEBUG_KMS("looking for cmdline mode on connector %d\n", + connector->base.id); + + /* got for command line mode first */ + modes[i] = drm_pick_cmdline_mode(connector, width, height); + if (!modes[i]) { + DRM_DEBUG_KMS("looking for preferred mode on connector %d\n", + connector->base.id); + modes[i] = drm_has_preferred_mode(connector, width, height); + } + /* No preferred modes, pick one off the list */ + if (!modes[i] && !list_empty(&connector->modes)) { + list_for_each_entry(modes[i], &connector->modes, head) + break; + } + DRM_DEBUG_KMS("found mode %s\n", modes[i] ? modes[i]->name : + "none"); + i++; + } + return true; +} + +static int drm_pick_crtcs(struct drm_device *dev, + struct drm_crtc **best_crtcs, + struct drm_display_mode **modes, + int n, int width, int height) +{ + int c, o; + struct drm_connector *connector; + struct drm_connector_helper_funcs *connector_funcs; + struct drm_encoder *encoder; + struct drm_crtc *best_crtc; + int my_score, best_score, score; + struct drm_crtc **crtcs, *crtc; + + if (n == dev->mode_config.num_connector) + return 0; + c = 0; + list_for_each_entry(connector, &dev->mode_config.connector_list, head) { + if (c == n) + break; + c++; + } + + best_crtcs[n] = NULL; + best_crtc = NULL; + best_score = drm_pick_crtcs(dev, best_crtcs, modes, n+1, width, height); + if (modes[n] == NULL) + return best_score; + + crtcs = kmalloc(dev->mode_config.num_connector * + sizeof(struct drm_crtc *), GFP_KERNEL); + if (!crtcs) + return best_score; + + my_score = 1; + if (connector->status == connector_status_connected) + my_score++; + if (drm_has_cmdline_mode(connector)) + my_score++; + if (drm_has_preferred_mode(connector, width, height)) + my_score++; + + connector_funcs = connector->helper_private; + encoder = connector_funcs->best_encoder(connector); + if (!encoder) + goto out; + + connector->encoder = encoder; + + /* select a crtc for this connector and then attempt to configure + remaining connectors */ + c = 0; + list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) { + + if ((encoder->possible_crtcs & (1 << c)) == 0) { + c++; + continue; + } + + for (o = 0; o < n; o++) + if (best_crtcs[o] == crtc) + break; + + if (o < n) { + /* ignore cloning for now */ + c++; + continue; + } + + crtcs[n] = crtc; + memcpy(crtcs, best_crtcs, n * sizeof(struct drm_crtc *)); + score = my_score + drm_pick_crtcs(dev, crtcs, modes, n + 1, + width, height); + if (score > best_score) { + best_crtc = crtc; + best_score = score; + memcpy(best_crtcs, crtcs, + dev->mode_config.num_connector * + sizeof(struct drm_crtc *)); + } + c++; + } +out: + kfree(crtcs); + return best_score; +} + +static void drm_setup_crtcs(struct drm_device *dev) +{ + struct drm_crtc **crtcs; + struct drm_display_mode **modes; + struct drm_encoder *encoder; + struct drm_connector *connector; + bool *enabled; + int width, height; + int i, ret; + + DRM_DEBUG_KMS("\n"); + + width = dev->mode_config.max_width; + height = dev->mode_config.max_height; + + /* clean out all the encoder/crtc combos */ + list_for_each_entry(encoder, &dev->mode_config.encoder_list, head) { + encoder->crtc = NULL; + } + + crtcs = kcalloc(dev->mode_config.num_connector, + sizeof(struct drm_crtc *), GFP_KERNEL); + modes = kcalloc(dev->mode_config.num_connector, + sizeof(struct drm_display_mode *), GFP_KERNEL); + enabled = kcalloc(dev->mode_config.num_connector, + sizeof(bool), GFP_KERNEL); + + drm_enable_connectors(dev, enabled); + + ret = drm_target_preferred(dev, modes, enabled, width, height); + if (!ret) + DRM_ERROR("Unable to find initial modes\n"); + + DRM_DEBUG_KMS("picking CRTCs for %dx%d config\n", width, height); + + drm_pick_crtcs(dev, crtcs, modes, 0, width, height); + + i = 0; + list_for_each_entry(connector, &dev->mode_config.connector_list, head) { + struct drm_display_mode *mode = modes[i]; + struct drm_crtc *crtc = crtcs[i]; + + if (connector->encoder == NULL) { + i++; + continue; + } + + if (mode && crtc) { + DRM_DEBUG_KMS("desired mode %s set on crtc %d\n", + mode->name, crtc->base.id); + crtc->desired_mode = mode; + connector->encoder->crtc = crtc; + } else { + connector->encoder->crtc = NULL; + connector->encoder = NULL; + } + i++; + } + + kfree(crtcs); + kfree(modes); + kfree(enabled); +} + +/** + * drm_helper_initial_config - setup a sane initial connector configuration + * @dev: DRM device + * + * LOCKING: + * Called at init time, must take mode config lock. + * + * Scan the CRTCs and connectors and try to put together an initial setup. + * At the moment, this is a cloned configuration across all heads with + * a new framebuffer object as the backing store. + * + * RETURNS: + * Zero if everything went ok, nonzero otherwise. + */ +bool drm_helper_initial_config(struct drm_device *dev) +{ + int count = 0; + + /* disable all the possible outputs/crtcs before entering KMS mode */ + drm_helper_disable_unused_functions(dev); + + drm_fb_helper_parse_command_line(dev); + + count = drm_helper_probe_connector_modes(dev, + dev->mode_config.max_width, + dev->mode_config.max_height); + + /* + * we shouldn't end up with no modes here. + */ + if (count == 0) + printk(KERN_INFO "No connectors reported connected with modes\n"); + + drm_setup_crtcs(dev); + + return 0; +} +EXPORT_SYMBOL(drm_helper_initial_config); + +bool drm_helper_fb_hotplug_event(struct drm_device *dev) +{ + DRM_DEBUG_KMS("\n"); + + drm_helper_probe_connector_modes(dev, dev->mode_config.max_width, + dev->mode_config.max_height); + + drm_setup_crtcs(dev); + + return true; +} +EXPORT_SYMBOL(drm_helper_fb_hotplug_event); diff --git a/drivers/gpu/drm/i915/i915_dma.c b/drivers/gpu/drm/i915/i915_dma.c index 8bfc0bbf13e6..7c7d229ddde0 100644 --- a/drivers/gpu/drm/i915/i915_dma.c +++ b/drivers/gpu/drm/i915/i915_dma.c @@ -1491,7 +1491,7 @@ static int i915_load_modeset_init(struct drm_device *dev, I915_WRITE(INSTPM, (1 << 5) | (1 << 21)); - drm_helper_initial_config(dev); + intel_fbdev_init(dev); return 0; diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index 979439cfb827..601f354e467e 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h @@ -220,6 +220,8 @@ enum no_fbc_reason { FBC_NOT_TILED, /* buffer not tiled */ }; +struct intel_kernel_fbdev; + typedef struct drm_i915_private { struct drm_device *dev; @@ -627,6 +629,8 @@ typedef struct drm_i915_private { u8 max_delay; enum no_fbc_reason no_fbc_reason; + + struct intel_kernel_fbdev *fbdev; } drm_i915_private_t; /** driver private structure attached to each drm_gem_object */ diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index 9cd6de5f9906..80577b8a368b 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -4506,10 +4506,6 @@ static void intel_setup_outputs(struct drm_device *dev) static void intel_user_framebuffer_destroy(struct drm_framebuffer *fb) { struct intel_framebuffer *intel_fb = to_intel_framebuffer(fb); - struct drm_device *dev = fb->dev; - - if (fb->fbdev) - intelfb_remove(dev, fb); drm_framebuffer_cleanup(fb); drm_gem_object_unreference_unlocked(intel_fb->obj); @@ -4532,18 +4528,13 @@ static const struct drm_framebuffer_funcs intel_fb_funcs = { .create_handle = intel_user_framebuffer_create_handle, }; -int intel_framebuffer_create(struct drm_device *dev, - struct drm_mode_fb_cmd *mode_cmd, - struct drm_framebuffer **fb, - struct drm_gem_object *obj) +int intel_framebuffer_init(struct drm_device *dev, + struct intel_framebuffer *intel_fb, + struct drm_mode_fb_cmd *mode_cmd, + struct drm_gem_object *obj) { - struct intel_framebuffer *intel_fb; int ret; - intel_fb = kzalloc(sizeof(*intel_fb), GFP_KERNEL); - if (!intel_fb) - return -ENOMEM; - ret = drm_framebuffer_init(dev, &intel_fb->base, &intel_fb_funcs); if (ret) { DRM_ERROR("framebuffer init failed %d\n", ret); @@ -4551,40 +4542,40 @@ int intel_framebuffer_create(struct drm_device *dev, } drm_helper_mode_fill_fb_struct(&intel_fb->base, mode_cmd); - intel_fb->obj = obj; - - *fb = &intel_fb->base; - return 0; } - static struct drm_framebuffer * intel_user_framebuffer_create(struct drm_device *dev, struct drm_file *filp, struct drm_mode_fb_cmd *mode_cmd) { struct drm_gem_object *obj; - struct drm_framebuffer *fb; + struct intel_framebuffer *intel_fb; int ret; obj = drm_gem_object_lookup(dev, filp, mode_cmd->handle); if (!obj) return NULL; - ret = intel_framebuffer_create(dev, mode_cmd, &fb, obj); + intel_fb = kzalloc(sizeof(*intel_fb), GFP_KERNEL); + if (!intel_fb) + return NULL; + + ret = intel_framebuffer_init(dev, intel_fb, + mode_cmd, obj); if (ret) { drm_gem_object_unreference_unlocked(obj); + kfree(intel_fb); return NULL; } - return fb; + return &intel_fb->base; } static const struct drm_mode_config_funcs intel_mode_funcs = { .fb_create = intel_user_framebuffer_create, - .fb_changed = intelfb_probe, }; static struct drm_gem_object * @@ -4924,6 +4915,8 @@ void intel_modeset_cleanup(struct drm_device *dev) mutex_lock(&dev->struct_mutex); + intel_fbdev_fini(dev); + list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) { /* Skip inactive CRTCs */ if (!crtc->fb) diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h index 3a467ca57857..9ffb9f2c9abd 100644 --- a/drivers/gpu/drm/i915/intel_drv.h +++ b/drivers/gpu/drm/i915/intel_drv.h @@ -200,9 +200,6 @@ extern void intel_release_load_detect_pipe(struct intel_output *intel_output, extern struct drm_connector* intel_sdvo_find(struct drm_device *dev, int sdvoB); extern int intel_sdvo_supports_hotplug(struct drm_connector *connector); extern void intel_sdvo_set_hotplug(struct drm_connector *connector, int enable); -extern int intelfb_probe(struct drm_device *dev); -extern int intelfb_remove(struct drm_device *dev, struct drm_framebuffer *fb); -extern int intelfb_resize(struct drm_device *dev, struct drm_crtc *crtc); extern void intelfb_restore(void); extern void intel_crtc_fb_gamma_set(struct drm_crtc *crtc, u16 red, u16 green, u16 blue, int regno); @@ -212,10 +209,12 @@ extern void intel_init_clock_gating(struct drm_device *dev); extern void ironlake_enable_drps(struct drm_device *dev); extern void ironlake_disable_drps(struct drm_device *dev); -extern int intel_framebuffer_create(struct drm_device *dev, - struct drm_mode_fb_cmd *mode_cmd, - struct drm_framebuffer **fb, - struct drm_gem_object *obj); +extern int intel_framebuffer_init(struct drm_device *dev, + struct intel_framebuffer *ifb, + struct drm_mode_fb_cmd *mode_cmd, + struct drm_gem_object *obj); +extern int intel_fbdev_init(struct drm_device *dev); +extern void intel_fbdev_fini(struct drm_device *dev); extern void intel_prepare_page_flip(struct drm_device *dev, int plane); extern void intel_finish_page_flip(struct drm_device *dev, int pipe); diff --git a/drivers/gpu/drm/i915/intel_fb.c b/drivers/gpu/drm/i915/intel_fb.c index 8cd791dc5b29..b0de9bbde34a 100644 --- a/drivers/gpu/drm/i915/intel_fb.c +++ b/drivers/gpu/drm/i915/intel_fb.c @@ -45,9 +45,10 @@ #include "i915_drm.h" #include "i915_drv.h" -struct intelfb_par { +struct intel_kernel_fbdev { struct drm_fb_helper helper; - struct intel_framebuffer *intel_fb; + struct intel_framebuffer ifb; + struct list_head fbdev_list; struct drm_display_mode *our_mode; }; @@ -70,54 +71,12 @@ static struct drm_fb_helper_funcs intel_fb_helper_funcs = { }; -/** - * Currently it is assumed that the old framebuffer is reused. - * - * LOCKING - * caller should hold the mode config lock. - * - */ -int intelfb_resize(struct drm_device *dev, struct drm_crtc *crtc) +static int intelfb_create(struct drm_device *dev, + struct drm_fb_helper_surface_size *sizes, + struct intel_kernel_fbdev **ifbdev_p) { struct fb_info *info; - struct drm_framebuffer *fb; - struct drm_display_mode *mode = crtc->desired_mode; - - fb = crtc->fb; - if (!fb) - return 1; - - info = fb->fbdev; - if (!info) - return 1; - - if (!mode) - return 1; - - info->var.xres = mode->hdisplay; - info->var.right_margin = mode->hsync_start - mode->hdisplay; - info->var.hsync_len = mode->hsync_end - mode->hsync_start; - info->var.left_margin = mode->htotal - mode->hsync_end; - info->var.yres = mode->vdisplay; - info->var.lower_margin = mode->vsync_start - mode->vdisplay; - info->var.vsync_len = mode->vsync_end - mode->vsync_start; - info->var.upper_margin = mode->vtotal - mode->vsync_end; - info->var.pixclock = 10000000 / mode->htotal * 1000 / mode->vtotal * 100; - /* avoid overflow */ - info->var.pixclock = info->var.pixclock * 1000 / mode->vrefresh; - - return 0; -} -EXPORT_SYMBOL(intelfb_resize); - -static int intelfb_create(struct drm_device *dev, uint32_t fb_width, - uint32_t fb_height, uint32_t surface_width, - uint32_t surface_height, - uint32_t surface_depth, uint32_t surface_bpp, - struct drm_framebuffer **fb_p) -{ - struct fb_info *info; - struct intelfb_par *par; + struct intel_kernel_fbdev *ifbdev; struct drm_framebuffer *fb; struct intel_framebuffer *intel_fb; struct drm_mode_fb_cmd mode_cmd; @@ -127,15 +86,15 @@ static int intelfb_create(struct drm_device *dev, uint32_t fb_width, int size, ret, mmio_bar = IS_I9XX(dev) ? 0 : 1; /* we don't do packed 24bpp */ - if (surface_bpp == 24) - surface_bpp = 32; + if (sizes->surface_bpp == 24) + sizes->surface_bpp = 32; - mode_cmd.width = surface_width; - mode_cmd.height = surface_height; + mode_cmd.width = sizes->surface_width; + mode_cmd.height = sizes->surface_height; - mode_cmd.bpp = surface_bpp; + mode_cmd.bpp = sizes->surface_bpp; mode_cmd.pitch = ALIGN(mode_cmd.width * ((mode_cmd.bpp + 1) / 8), 64); - mode_cmd.depth = surface_depth; + mode_cmd.depth = sizes->surface_depth; size = mode_cmd.pitch * mode_cmd.height; size = ALIGN(size, PAGE_SIZE); @@ -158,28 +117,25 @@ static int intelfb_create(struct drm_device *dev, uint32_t fb_width, /* Flush everything out, we'll be doing GTT only from now on */ i915_gem_object_set_to_gtt_domain(fbo, 1); - ret = intel_framebuffer_create(dev, &mode_cmd, &fb, fbo); - if (ret) { - DRM_ERROR("failed to allocate fb.\n"); + info = framebuffer_alloc(sizeof(struct intel_kernel_fbdev), device); + if (!info) { + ret = -ENOMEM; goto out_unpin; } - list_add(&fb->filp_head, &dev->mode_config.fb_kernel_list); + ifbdev = info->par; + intel_framebuffer_init(dev, &ifbdev->ifb, &mode_cmd, fbo); - intel_fb = to_intel_framebuffer(fb); - *fb_p = fb; + fb = &ifbdev->ifb.base; - info = framebuffer_alloc(sizeof(struct intelfb_par), device); - if (!info) { - ret = -ENOMEM; - goto out_unpin; - } + ifbdev->helper.fb = fb; + ifbdev->helper.fbdev = info; + ifbdev->helper.funcs = &intel_fb_helper_funcs; + ifbdev->helper.dev = dev; - par = info->par; + *ifbdev_p = ifbdev; - par->helper.funcs = &intel_fb_helper_funcs; - par->helper.dev = dev; - ret = drm_fb_helper_init_crtc_count(&par->helper, 2, + ret = drm_fb_helper_init_crtc_count(&ifbdev->helper, 2, INTELFB_CONN_LIMIT); if (ret) goto out_unref; @@ -214,7 +170,7 @@ static int intelfb_create(struct drm_device *dev, uint32_t fb_width, // memset(info->screen_base, 0, size); drm_fb_helper_fill_fix(info, fb->pitch, fb->depth); - drm_fb_helper_fill_var(info, fb, fb_width, fb_height); + drm_fb_helper_fill_var(info, &ifbdev->helper, sizes->fb_width, sizes->fb_height); /* FIXME: we really shouldn't expose mmio space at all */ info->fix.mmio_start = pci_resource_start(dev->pdev, mmio_bar); @@ -226,15 +182,11 @@ static int intelfb_create(struct drm_device *dev, uint32_t fb_width, info->pixmap.flags = FB_PIXMAP_SYSTEM; info->pixmap.scan_align = 1; - fb->fbdev = info; - - par->intel_fb = intel_fb; - - /* To allow resizeing without swapping buffers */ DRM_DEBUG_KMS("allocated %dx%d fb: 0x%08x, bo %p\n", intel_fb->base.width, intel_fb->base.height, obj_priv->gtt_offset, fbo); + mutex_unlock(&dev->struct_mutex); vga_switcheroo_client_fb_set(dev->pdev, info); return 0; @@ -248,35 +200,76 @@ out: return ret; } -int intelfb_probe(struct drm_device *dev) +static int intel_fb_find_or_create_single(struct drm_device *dev, + struct drm_fb_helper_surface_size *sizes, + struct drm_fb_helper **fb_ptr) +{ + drm_i915_private_t *dev_priv = dev->dev_private; + struct intel_kernel_fbdev *ifbdev = NULL; + int new_fb = 0; + int ret; + + if (!dev_priv->fbdev) { + ret = intelfb_create(dev, sizes, + &ifbdev); + if (ret) + return ret; + + dev_priv->fbdev = ifbdev; + new_fb = 1; + } else { + ifbdev = dev_priv->fbdev; + if (ifbdev->ifb.base.width < sizes->surface_width || + ifbdev->ifb.base.height < sizes->surface_height) { + DRM_ERROR("Framebuffer not large enough to scale console onto.\n"); + return -EINVAL; + } + } + + *fb_ptr = &ifbdev->helper; + return new_fb; +} + +static int intelfb_probe(struct drm_device *dev) { int ret; DRM_DEBUG_KMS("\n"); - ret = drm_fb_helper_single_fb_probe(dev, 32, intelfb_create); + ret = drm_fb_helper_single_fb_probe(dev, 32, intel_fb_find_or_create_single); return ret; } -EXPORT_SYMBOL(intelfb_probe); -int intelfb_remove(struct drm_device *dev, struct drm_framebuffer *fb) +int intel_fbdev_destroy(struct drm_device *dev, + struct intel_kernel_fbdev *ifbdev) { struct fb_info *info; + struct intel_framebuffer *ifb = &ifbdev->ifb; - if (!fb) - return -EINVAL; + info = ifbdev->helper.fbdev; - info = fb->fbdev; + unregister_framebuffer(info); + iounmap(info->screen_base); + drm_fb_helper_free(&ifbdev->helper); - if (info) { - struct intelfb_par *par = info->par; - unregister_framebuffer(info); - iounmap(info->screen_base); - if (info->par) - drm_fb_helper_free(&par->helper); - framebuffer_release(info); - } + drm_framebuffer_cleanup(&ifb->base); + drm_gem_object_unreference_unlocked(ifb->obj); + + framebuffer_release(info); return 0; } -EXPORT_SYMBOL(intelfb_remove); + +int intel_fbdev_init(struct drm_device *dev) +{ + drm_helper_initial_config(dev); + intelfb_probe(dev); + return 0; +} + +void intel_fbdev_fini(struct drm_device *dev) +{ + drm_i915_private_t *dev_priv = dev->dev_private; + intel_fbdev_destroy(dev, dev_priv->fbdev); + dev_priv->fbdev = NULL; +} MODULE_LICENSE("GPL and additional rights"); diff --git a/drivers/gpu/drm/nouveau/nouveau_display.c b/drivers/gpu/drm/nouveau/nouveau_display.c index cf1c5c0a0abe..9d7928f40fdf 100644 --- a/drivers/gpu/drm/nouveau/nouveau_display.c +++ b/drivers/gpu/drm/nouveau/nouveau_display.c @@ -34,10 +34,6 @@ static void nouveau_user_framebuffer_destroy(struct drm_framebuffer *drm_fb) { struct nouveau_framebuffer *fb = nouveau_framebuffer(drm_fb); - struct drm_device *dev = drm_fb->dev; - - if (drm_fb->fbdev) - nouveau_fbcon_remove(dev, drm_fb); if (fb->nvbo) drm_gem_object_unreference_unlocked(fb->nvbo->gem); @@ -61,27 +57,20 @@ static const struct drm_framebuffer_funcs nouveau_framebuffer_funcs = { .create_handle = nouveau_user_framebuffer_create_handle, }; -struct drm_framebuffer * -nouveau_framebuffer_create(struct drm_device *dev, struct nouveau_bo *nvbo, - struct drm_mode_fb_cmd *mode_cmd) +int +nouveau_framebuffer_init(struct drm_device *dev, struct nouveau_framebuffer *nouveau_fb, + struct drm_mode_fb_cmd *mode_cmd, struct nouveau_bo *nvbo) { - struct nouveau_framebuffer *fb; int ret; - fb = kzalloc(sizeof(struct nouveau_framebuffer), GFP_KERNEL); - if (!fb) - return NULL; - - ret = drm_framebuffer_init(dev, &fb->base, &nouveau_framebuffer_funcs); + ret = drm_framebuffer_init(dev, &nouveau_fb->base, &nouveau_framebuffer_funcs); if (ret) { - kfree(fb); - return NULL; + return ret; } - drm_helper_mode_fill_fb_struct(&fb->base, mode_cmd); - - fb->nvbo = nvbo; - return &fb->base; + drm_helper_mode_fill_fb_struct(&nouveau_fb->base, mode_cmd); + nouveau_fb->nvbo = nvbo; + return 0; } static struct drm_framebuffer * @@ -89,24 +78,28 @@ nouveau_user_framebuffer_create(struct drm_device *dev, struct drm_file *file_priv, struct drm_mode_fb_cmd *mode_cmd) { - struct drm_framebuffer *fb; + struct nouveau_framebuffer *nouveau_fb; struct drm_gem_object *gem; + int ret; gem = drm_gem_object_lookup(dev, file_priv, mode_cmd->handle); if (!gem) return NULL; - fb = nouveau_framebuffer_create(dev, nouveau_gem_object(gem), mode_cmd); - if (!fb) { + nouveau_fb = kzalloc(sizeof(struct nouveau_framebuffer), GFP_KERNEL); + if (!nouveau_fb) + return NULL; + + ret = nouveau_framebuffer_init(dev, nouveau_fb, mode_cmd, nouveau_gem_object(gem)); + if (ret) { drm_gem_object_unreference(gem); return NULL; } - return fb; + return &nouveau_fb->base; } const struct drm_mode_config_funcs nouveau_mode_config_funcs = { .fb_create = nouveau_user_framebuffer_create, - .fb_changed = nouveau_fbcon_probe, }; diff --git a/drivers/gpu/drm/nouveau/nouveau_drv.c b/drivers/gpu/drm/nouveau/nouveau_drv.c index 1de974acbc65..c6079e36669d 100644 --- a/drivers/gpu/drm/nouveau/nouveau_drv.c +++ b/drivers/gpu/drm/nouveau/nouveau_drv.c @@ -153,7 +153,6 @@ nouveau_pci_suspend(struct pci_dev *pdev, pm_message_t pm_state) struct nouveau_fifo_engine *pfifo = &dev_priv->engine.fifo; struct nouveau_channel *chan; struct drm_crtc *crtc; - uint32_t fbdev_flags; int ret, i; if (!drm_core_check_feature(dev, DRIVER_MODESET)) @@ -163,8 +162,7 @@ nouveau_pci_suspend(struct pci_dev *pdev, pm_message_t pm_state) return 0; NV_INFO(dev, "Disabling fbcon acceleration...\n"); - fbdev_flags = dev_priv->fbdev_info->flags; - dev_priv->fbdev_info->flags |= FBINFO_HWACCEL_DISABLED; + nouveau_fbcon_save_disable_accel(dev); NV_INFO(dev, "Unpinning framebuffer(s)...\n"); list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) { @@ -230,9 +228,9 @@ nouveau_pci_suspend(struct pci_dev *pdev, pm_message_t pm_state) } acquire_console_sem(); - fb_set_suspend(dev_priv->fbdev_info, 1); + nouveau_fbcon_set_suspend(dev, 1); release_console_sem(); - dev_priv->fbdev_info->flags = fbdev_flags; + nouveau_fbcon_restore_accel(dev); return 0; out_abort: @@ -250,14 +248,12 @@ nouveau_pci_resume(struct pci_dev *pdev) struct drm_nouveau_private *dev_priv = dev->dev_private; struct nouveau_engine *engine = &dev_priv->engine; struct drm_crtc *crtc; - uint32_t fbdev_flags; int ret, i; if (!drm_core_check_feature(dev, DRIVER_MODESET)) return -ENODEV; - fbdev_flags = dev_priv->fbdev_info->flags; - dev_priv->fbdev_info->flags |= FBINFO_HWACCEL_DISABLED; + nouveau_fbcon_save_disable_accel(dev); NV_INFO(dev, "We're back, enabling device...\n"); pci_set_power_state(pdev, PCI_D0); @@ -332,13 +328,14 @@ nouveau_pci_resume(struct pci_dev *pdev) } acquire_console_sem(); - fb_set_suspend(dev_priv->fbdev_info, 0); + nouveau_fbcon_set_suspend(dev, 0); release_console_sem(); - nouveau_fbcon_zfill(dev); + nouveau_fbcon_zfill_all(dev); drm_helper_resume_force_mode(dev); - dev_priv->fbdev_info->flags = fbdev_flags; + + nouveau_fbcon_restore_accel(dev); return 0; } diff --git a/drivers/gpu/drm/nouveau/nouveau_drv.h b/drivers/gpu/drm/nouveau/nouveau_drv.h index d8b559011777..93459e07e829 100644 --- a/drivers/gpu/drm/nouveau/nouveau_drv.h +++ b/drivers/gpu/drm/nouveau/nouveau_drv.h @@ -531,8 +531,6 @@ struct drm_nouveau_private { atomic_t validate_sequence; } ttm; - struct fb_info *fbdev_info; - int fifo_alloc_count; struct nouveau_channel *fifos[NOUVEAU_MAX_CHANNEL_NR]; @@ -628,6 +626,8 @@ struct drm_nouveau_private { struct { struct dentry *channel_root; } debugfs; + + struct nouveau_fbcon_par *nfbdev; }; static inline struct drm_nouveau_private * diff --git a/drivers/gpu/drm/nouveau/nouveau_fb.h b/drivers/gpu/drm/nouveau/nouveau_fb.h index 4a3f31aa1949..d432134b71e0 100644 --- a/drivers/gpu/drm/nouveau/nouveau_fb.h +++ b/drivers/gpu/drm/nouveau/nouveau_fb.h @@ -40,8 +40,6 @@ nouveau_framebuffer(struct drm_framebuffer *fb) extern const struct drm_mode_config_funcs nouveau_mode_config_funcs; -struct drm_framebuffer * -nouveau_framebuffer_create(struct drm_device *, struct nouveau_bo *, - struct drm_mode_fb_cmd *); - +int nouveau_framebuffer_init(struct drm_device *dev, struct nouveau_framebuffer *nouveau_fb, + struct drm_mode_fb_cmd *mode_cmd, struct nouveau_bo *nvbo); #endif /* __NOUVEAU_FB_H__ */ diff --git a/drivers/gpu/drm/nouveau/nouveau_fbcon.c b/drivers/gpu/drm/nouveau/nouveau_fbcon.c index 68cedd9194fe..712ee42e3cf8 100644 --- a/drivers/gpu/drm/nouveau/nouveau_fbcon.c +++ b/drivers/gpu/drm/nouveau/nouveau_fbcon.c @@ -199,11 +199,10 @@ not_fb: } #endif -void -nouveau_fbcon_zfill(struct drm_device *dev) +static void +nouveau_fbcon_zfill(struct drm_device *dev, struct nouveau_fbcon_par *fbpar) { - struct drm_nouveau_private *dev_priv = dev->dev_private; - struct fb_info *info = dev_priv->fbdev_info; + struct fb_info *info = fbpar->helper.fbdev; struct fb_fillrect rect; /* Clear the entire fbcon. The drm will program every connector @@ -219,10 +218,9 @@ nouveau_fbcon_zfill(struct drm_device *dev) } static int -nouveau_fbcon_create(struct drm_device *dev, uint32_t fb_width, - uint32_t fb_height, uint32_t surface_width, - uint32_t surface_height, uint32_t surface_depth, - uint32_t surface_bpp, struct drm_framebuffer **pfb) +nouveau_fbcon_create(struct drm_device *dev, + struct drm_fb_helper_surface_size *sizes, + struct nouveau_fbcon_par **fbpar_p) { struct drm_nouveau_private *dev_priv = dev->dev_private; struct fb_info *info; @@ -234,13 +232,13 @@ nouveau_fbcon_create(struct drm_device *dev, uint32_t fb_width, struct device *device = &dev->pdev->dev; int size, ret; - mode_cmd.width = surface_width; - mode_cmd.height = surface_height; + mode_cmd.width = sizes->surface_width; + mode_cmd.height = sizes->surface_height; - mode_cmd.bpp = surface_bpp; + mode_cmd.bpp = sizes->surface_bpp; mode_cmd.pitch = mode_cmd.width * (mode_cmd.bpp >> 3); mode_cmd.pitch = roundup(mode_cmd.pitch, 256); - mode_cmd.depth = surface_depth; + mode_cmd.depth = sizes->surface_depth; size = mode_cmd.pitch * mode_cmd.height; size = roundup(size, PAGE_SIZE); @@ -269,18 +267,6 @@ nouveau_fbcon_create(struct drm_device *dev, uint32_t fb_width, mutex_lock(&dev->struct_mutex); - fb = nouveau_framebuffer_create(dev, nvbo, &mode_cmd); - if (!fb) { - ret = -ENOMEM; - NV_ERROR(dev, "failed to allocate fb.\n"); - goto out_unref; - } - - list_add(&fb->filp_head, &dev->mode_config.fb_kernel_list); - - nouveau_fb = nouveau_framebuffer(fb); - *pfb = fb; - info = framebuffer_alloc(sizeof(struct nouveau_fbcon_par), device); if (!info) { ret = -ENOMEM; @@ -288,12 +274,20 @@ nouveau_fbcon_create(struct drm_device *dev, uint32_t fb_width, } par = info->par; + nouveau_framebuffer_init(dev, &par->nouveau_fb, &mode_cmd, nvbo); + + fb = &par->nouveau_fb.base; + /* setup helper */ + par->helper.fb = fb; + par->helper.fbdev = info; par->helper.funcs = &nouveau_fbcon_helper_funcs; par->helper.dev = dev; + + *fbpar_p = par; + ret = drm_fb_helper_init_crtc_count(&par->helper, 2, 4); if (ret) goto out_unref; - dev_priv->fbdev_info = info; strcpy(info->fix.id, "nouveaufb"); if (nouveau_nofbaccel) @@ -311,7 +305,7 @@ nouveau_fbcon_create(struct drm_device *dev, uint32_t fb_width, info->screen_size = size; drm_fb_helper_fill_fix(info, fb->pitch, fb->depth); - drm_fb_helper_fill_var(info, fb, fb_width, fb_height); + drm_fb_helper_fill_var(info, &par->helper, sizes->fb_width, sizes->fb_height); /* FIXME: we really shouldn't expose mmio space at all */ info->fix.mmio_start = pci_resource_start(dev->pdev, 1); @@ -344,9 +338,6 @@ nouveau_fbcon_create(struct drm_device *dev, uint32_t fb_width, info->pixmap.flags = FB_PIXMAP_SYSTEM; info->pixmap.scan_align = 1; - fb->fbdev = info; - - par->nouveau_fb = nouveau_fb; par->dev = dev; if (dev_priv->channel && !nouveau_nofbaccel) { @@ -362,7 +353,7 @@ nouveau_fbcon_create(struct drm_device *dev, uint32_t fb_width, }; } - nouveau_fbcon_zfill(dev); + nouveau_fbcon_zfill(dev, par); /* To allow resizeing without swapping buffers */ NV_INFO(dev, "allocated %dx%d fb: 0x%lx, bo %p\n", @@ -380,35 +371,59 @@ out: return ret; } -int +static int +nouveau_fbcon_find_or_create_single(struct drm_device *dev, + struct drm_fb_helper_surface_size *sizes, + struct drm_fb_helper **fb_ptr) +{ + struct drm_nouveau_private *dev_priv = dev->dev_private; + struct nouveau_fbcon_par *fbpar; + int new_fb = 0; + int ret; + + if (!dev_priv->nfbdev) { + ret = nouveau_fbcon_create(dev, sizes, + &fbpar); + if (ret) + return ret; + dev_priv->nfbdev = fbpar; + new_fb = 1; + } else { + fbpar = dev_priv->nfbdev; + if (fbpar->nouveau_fb.base.width < sizes->surface_width || + fbpar->nouveau_fb.base.height < sizes->surface_height) { + DRM_ERROR("Framebuffer not large enough to scale console onto.\n"); + return -EINVAL; + } + } + *fb_ptr = &fbpar->helper; + return new_fb; +} + +static int nouveau_fbcon_probe(struct drm_device *dev) { NV_DEBUG_KMS(dev, "\n"); - return drm_fb_helper_single_fb_probe(dev, 32, nouveau_fbcon_create); + return drm_fb_helper_single_fb_probe(dev, 32, nouveau_fbcon_find_or_create_single); } int -nouveau_fbcon_remove(struct drm_device *dev, struct drm_framebuffer *fb) +nouveau_fbcon_destroy(struct drm_device *dev, struct nouveau_fbcon_par *fbpar) { - struct nouveau_framebuffer *nouveau_fb = nouveau_framebuffer(fb); + struct nouveau_framebuffer *nouveau_fb = &fbpar->nouveau_fb; struct fb_info *info; - if (!fb) - return -EINVAL; + info = fbpar->helper.fbdev; - info = fb->fbdev; - if (info) { - struct nouveau_fbcon_par *par = info->par; + unregister_framebuffer(info); + nouveau_bo_unmap(nouveau_fb->nvbo); + drm_gem_object_unreference_unlocked(nouveau_fb->nvbo->gem); + nouveau_fb->nvbo = NULL; + drm_fb_helper_free(&fbpar->helper); - unregister_framebuffer(info); - nouveau_bo_unmap(nouveau_fb->nvbo); - drm_gem_object_unreference_unlocked(nouveau_fb->nvbo->gem); - nouveau_fb->nvbo = NULL; - if (par) - drm_fb_helper_free(&par->helper); - framebuffer_release(info); - } + drm_framebuffer_cleanup(&nouveau_fb->base); + framebuffer_release(info); return 0; } @@ -421,3 +436,43 @@ void nouveau_fbcon_gpu_lockup(struct fb_info *info) NV_ERROR(dev, "GPU lockup - switching to software fbcon\n"); info->flags |= FBINFO_HWACCEL_DISABLED; } + +int nouveau_fbcon_init(struct drm_device *dev) +{ + drm_helper_initial_config(dev); + nouveau_fbcon_probe(dev); + return 0; +} + +void nouveau_fbcon_fini(struct drm_device *dev) +{ + struct drm_nouveau_private *dev_priv = dev->dev_private; + nouveau_fbcon_destroy(dev, dev_priv->nfbdev); + dev_priv->nfbdev = NULL; +} + +void nouveau_fbcon_save_disable_accel(struct drm_device *dev) +{ + struct drm_nouveau_private *dev_priv = dev->dev_private; + + dev_priv->nfbdev->saved_flags = dev_priv->nfbdev->helper.fbdev->flags; + dev_priv->nfbdev->helper.fbdev->flags |= FBINFO_HWACCEL_DISABLED; +} + +void nouveau_fbcon_restore_accel(struct drm_device *dev) +{ + struct drm_nouveau_private *dev_priv = dev->dev_private; + dev_priv->nfbdev->helper.fbdev->flags = dev_priv->nfbdev->saved_flags; +} + +void nouveau_fbcon_set_suspend(struct drm_device *dev, int state) +{ + struct drm_nouveau_private *dev_priv = dev->dev_private; + fb_set_suspend(dev_priv->nfbdev->helper.fbdev, state); +} + +void nouveau_fbcon_zfill_all(struct drm_device *dev) +{ + struct drm_nouveau_private *dev_priv = dev->dev_private; + nouveau_fbcon_zfill(dev, dev_priv->nfbdev); +} diff --git a/drivers/gpu/drm/nouveau/nouveau_fbcon.h b/drivers/gpu/drm/nouveau/nouveau_fbcon.h index f9c34e1a8c11..fa66cb9fa4d4 100644 --- a/drivers/gpu/drm/nouveau/nouveau_fbcon.h +++ b/drivers/gpu/drm/nouveau/nouveau_fbcon.h @@ -29,16 +29,16 @@ #include "drm_fb_helper.h" +#include "nouveau_fb.h" struct nouveau_fbcon_par { struct drm_fb_helper helper; + struct nouveau_framebuffer nouveau_fb; + struct list_head fbdev_list; struct drm_device *dev; - struct nouveau_framebuffer *nouveau_fb; + unsigned int saved_flags; }; -int nouveau_fbcon_probe(struct drm_device *dev); -int nouveau_fbcon_remove(struct drm_device *dev, struct drm_framebuffer *fb); void nouveau_fbcon_restore(void); -void nouveau_fbcon_zfill(struct drm_device *dev); void nv04_fbcon_copyarea(struct fb_info *info, const struct fb_copyarea *region); void nv04_fbcon_fillrect(struct fb_info *info, const struct fb_fillrect *rect); @@ -50,5 +50,12 @@ void nv50_fbcon_imageblit(struct fb_info *info, const struct fb_image *image); int nv50_fbcon_accel_init(struct fb_info *info); void nouveau_fbcon_gpu_lockup(struct fb_info *info); + +int nouveau_fbcon_init(struct drm_device *dev); +void nouveau_fbcon_fini(struct drm_device *dev); +void nouveau_fbcon_set_suspend(struct drm_device *dev, int state); +void nouveau_fbcon_zfill_all(struct drm_device *dev); +void nouveau_fbcon_save_disable_accel(struct drm_device *dev); +void nouveau_fbcon_restore_accel(struct drm_device *dev); #endif /* __NV50_FBCON_H__ */ diff --git a/drivers/gpu/drm/nouveau/nouveau_irq.c b/drivers/gpu/drm/nouveau/nouveau_irq.c index 2bd59a92fee5..0aa08b3be375 100644 --- a/drivers/gpu/drm/nouveau/nouveau_irq.c +++ b/drivers/gpu/drm/nouveau/nouveau_irq.c @@ -1203,7 +1203,7 @@ nouveau_irq_handler(DRM_IRQ_ARGS) { struct drm_device *dev = (struct drm_device *)arg; struct drm_nouveau_private *dev_priv = dev->dev_private; - uint32_t status, fbdev_flags = 0; + uint32_t status; unsigned long flags; status = nv_rd32(dev, NV03_PMC_INTR_0); @@ -1212,11 +1212,6 @@ nouveau_irq_handler(DRM_IRQ_ARGS) spin_lock_irqsave(&dev_priv->context_switch_lock, flags); - if (dev_priv->fbdev_info) { - fbdev_flags = dev_priv->fbdev_info->flags; - dev_priv->fbdev_info->flags |= FBINFO_HWACCEL_DISABLED; - } - if (status & NV_PMC_INTR_0_PFIFO_PENDING) { nouveau_fifo_irq_handler(dev); status &= ~NV_PMC_INTR_0_PFIFO_PENDING; @@ -1246,9 +1241,6 @@ nouveau_irq_handler(DRM_IRQ_ARGS) if (status) NV_ERROR(dev, "Unhandled PMC INTR status bits 0x%08x\n", status); - if (dev_priv->fbdev_info) - dev_priv->fbdev_info->flags = fbdev_flags; - spin_unlock_irqrestore(&dev_priv->context_switch_lock, flags); return IRQ_HANDLED; diff --git a/drivers/gpu/drm/nouveau/nouveau_state.c b/drivers/gpu/drm/nouveau/nouveau_state.c index 58b46807de23..23e67bf0898c 100644 --- a/drivers/gpu/drm/nouveau/nouveau_state.c +++ b/drivers/gpu/drm/nouveau/nouveau_state.c @@ -33,6 +33,7 @@ #include "nouveau_drv.h" #include "nouveau_drm.h" +#include "nouveau_fbcon.h" #include "nv50_display.h" static void nouveau_stub_takedown(struct drm_device *dev) {} @@ -511,7 +512,7 @@ nouveau_card_init(struct drm_device *dev) dev_priv->init_state = NOUVEAU_CARD_INIT_DONE; if (drm_core_check_feature(dev, DRIVER_MODESET)) - drm_helper_initial_config(dev); + nouveau_fbcon_init(dev); return 0; @@ -552,6 +553,7 @@ static void nouveau_card_takedown(struct drm_device *dev) NV_DEBUG(dev, "prev state = %d\n", dev_priv->init_state); if (dev_priv->init_state != NOUVEAU_CARD_INIT_DOWN) { + nouveau_backlight_exit(dev); if (dev_priv->channel) { @@ -783,6 +785,7 @@ int nouveau_unload(struct drm_device *dev) struct drm_nouveau_private *dev_priv = dev->dev_private; if (drm_core_check_feature(dev, DRIVER_MODESET)) { + nouveau_fbcon_fini(dev); if (dev_priv->card_type >= NV_50) nv50_display_destroy(dev); else diff --git a/drivers/gpu/drm/radeon/radeon.h b/drivers/gpu/drm/radeon/radeon.h index 034218c3dbbb..4f50807ae0a5 100644 --- a/drivers/gpu/drm/radeon/radeon.h +++ b/drivers/gpu/drm/radeon/radeon.h @@ -927,9 +927,6 @@ struct radeon_device { bool is_atom_bios; uint16_t bios_header_start; struct radeon_bo *stollen_vga_memory; - struct fb_info *fbdev_info; - struct radeon_bo *fbdev_rbo; - struct radeon_framebuffer *fbdev_rfb; /* Register mmio */ resource_size_t rmmio_base; resource_size_t rmmio_size; diff --git a/drivers/gpu/drm/radeon/radeon_device.c b/drivers/gpu/drm/radeon/radeon_device.c index 60ec47b71642..90e8883494ad 100644 --- a/drivers/gpu/drm/radeon/radeon_device.c +++ b/drivers/gpu/drm/radeon/radeon_device.c @@ -676,9 +676,10 @@ int radeon_suspend_kms(struct drm_device *dev, pm_message_t state) continue; } robj = rfb->obj->driver_private; - if (robj != rdev->fbdev_rbo) { + /* don't unpin kernel fb objects */ + if (!radeon_fbdev_robj_is_fb(rdev, robj)) { r = radeon_bo_reserve(robj, false); - if (unlikely(r == 0)) { + if (r == 0) { radeon_bo_unpin(robj); radeon_bo_unreserve(robj); } @@ -703,7 +704,7 @@ int radeon_suspend_kms(struct drm_device *dev, pm_message_t state) pci_set_power_state(dev->pdev, PCI_D3hot); } acquire_console_sem(); - fb_set_suspend(rdev->fbdev_info, 1); + radeon_fbdev_set_suspend(rdev, 1); release_console_sem(); return 0; } @@ -727,7 +728,7 @@ int radeon_resume_kms(struct drm_device *dev) radeon_agp_resume(rdev); radeon_resume(rdev); radeon_restore_bios_scratch_regs(rdev); - fb_set_suspend(rdev->fbdev_info, 0); + radeon_fbdev_set_suspend(rdev, 0); release_console_sem(); /* reset hpd state */ diff --git a/drivers/gpu/drm/radeon/radeon_display.c b/drivers/gpu/drm/radeon/radeon_display.c index b8d672828246..243c1c4bc836 100644 --- a/drivers/gpu/drm/radeon/radeon_display.c +++ b/drivers/gpu/drm/radeon/radeon_display.c @@ -831,10 +831,6 @@ void radeon_compute_pll(struct radeon_pll *pll, static void radeon_user_framebuffer_destroy(struct drm_framebuffer *fb) { struct radeon_framebuffer *radeon_fb = to_radeon_framebuffer(fb); - struct drm_device *dev = fb->dev; - - if (fb->fbdev) - radeonfb_remove(dev, fb); if (radeon_fb->obj) drm_gem_object_unreference_unlocked(radeon_fb->obj); @@ -856,21 +852,15 @@ static const struct drm_framebuffer_funcs radeon_fb_funcs = { .create_handle = radeon_user_framebuffer_create_handle, }; -struct drm_framebuffer * -radeon_framebuffer_create(struct drm_device *dev, - struct drm_mode_fb_cmd *mode_cmd, - struct drm_gem_object *obj) +void +radeon_framebuffer_init(struct drm_device *dev, + struct radeon_framebuffer *rfb, + struct drm_mode_fb_cmd *mode_cmd, + struct drm_gem_object *obj) { - struct radeon_framebuffer *radeon_fb; - - radeon_fb = kzalloc(sizeof(*radeon_fb), GFP_KERNEL); - if (radeon_fb == NULL) { - return NULL; - } - drm_framebuffer_init(dev, &radeon_fb->base, &radeon_fb_funcs); - drm_helper_mode_fill_fb_struct(&radeon_fb->base, mode_cmd); - radeon_fb->obj = obj; - return &radeon_fb->base; + rfb->obj = obj; + drm_framebuffer_init(dev, &rfb->base, &radeon_fb_funcs); + drm_helper_mode_fill_fb_struct(&rfb->base, mode_cmd); } static struct drm_framebuffer * @@ -879,6 +869,7 @@ radeon_user_framebuffer_create(struct drm_device *dev, struct drm_mode_fb_cmd *mode_cmd) { struct drm_gem_object *obj; + struct radeon_framebuffer *radeon_fb; obj = drm_gem_object_lookup(dev, file_priv, mode_cmd->handle); if (obj == NULL) { @@ -886,12 +877,19 @@ radeon_user_framebuffer_create(struct drm_device *dev, "can't create framebuffer\n", mode_cmd->handle); return NULL; } - return radeon_framebuffer_create(dev, mode_cmd, obj); + + radeon_fb = kzalloc(sizeof(*radeon_fb), GFP_KERNEL); + if (radeon_fb == NULL) { + return NULL; + } + + radeon_framebuffer_init(dev, radeon_fb, mode_cmd, obj); + + return &radeon_fb->base; } static const struct drm_mode_config_funcs radeon_mode_funcs = { .fb_create = radeon_user_framebuffer_create, - .fb_changed = radeonfb_probe, }; struct drm_prop_enum_list { @@ -1031,12 +1029,14 @@ int radeon_modeset_init(struct radeon_device *rdev) } /* initialize hpd */ radeon_hpd_init(rdev); - drm_helper_initial_config(rdev->ddev); + + radeon_fbdev_init(rdev); return 0; } void radeon_modeset_fini(struct radeon_device *rdev) { + radeon_fbdev_fini(rdev); kfree(rdev->mode_info.bios_hardcoded_edid); if (rdev->mode_info.mode_config_initialized) { diff --git a/drivers/gpu/drm/radeon/radeon_fb.c b/drivers/gpu/drm/radeon/radeon_fb.c index 8fccbf29235e..a7e4c2a89ee0 100644 --- a/drivers/gpu/drm/radeon/radeon_fb.c +++ b/drivers/gpu/drm/radeon/radeon_fb.c @@ -41,10 +41,15 @@ #include -struct radeon_fb_device { +/* object hierarchy - + this contains a helper + a radeon fb + the helper contains a pointer to radeon framebuffer baseclass. +*/ +struct radeon_kernel_fbdev { struct drm_fb_helper helper; - struct radeon_framebuffer *rfb; - struct radeon_device *rdev; + struct radeon_framebuffer rfb; + struct list_head fbdev_list; + struct radeon_device *rdev; }; static struct fb_ops radeonfb_ops = { @@ -60,45 +65,6 @@ static struct fb_ops radeonfb_ops = { .fb_setcmap = drm_fb_helper_setcmap, }; -/** - * Currently it is assumed that the old framebuffer is reused. - * - * LOCKING - * caller should hold the mode config lock. - * - */ -int radeonfb_resize(struct drm_device *dev, struct drm_crtc *crtc) -{ - struct fb_info *info; - struct drm_framebuffer *fb; - struct drm_display_mode *mode = crtc->desired_mode; - - fb = crtc->fb; - if (fb == NULL) { - return 1; - } - info = fb->fbdev; - if (info == NULL) { - return 1; - } - if (mode == NULL) { - return 1; - } - info->var.xres = mode->hdisplay; - info->var.right_margin = mode->hsync_start - mode->hdisplay; - info->var.hsync_len = mode->hsync_end - mode->hsync_start; - info->var.left_margin = mode->htotal - mode->hsync_end; - info->var.yres = mode->vdisplay; - info->var.lower_margin = mode->vsync_start - mode->vdisplay; - info->var.vsync_len = mode->vsync_end - mode->vsync_start; - info->var.upper_margin = mode->vtotal - mode->vsync_end; - info->var.pixclock = 10000000 / mode->htotal * 1000 / mode->vtotal * 100; - /* avoid overflow */ - info->var.pixclock = info->var.pixclock * 1000 / mode->vrefresh; - - return 0; -} -EXPORT_SYMBOL(radeonfb_resize); static int radeon_align_pitch(struct radeon_device *rdev, int width, int bpp, bool tiled) { @@ -129,17 +95,14 @@ static struct drm_fb_helper_funcs radeon_fb_helper_funcs = { .gamma_get = radeon_crtc_fb_gamma_get, }; -int radeonfb_create(struct drm_device *dev, - uint32_t fb_width, uint32_t fb_height, - uint32_t surface_width, uint32_t surface_height, - uint32_t surface_depth, uint32_t surface_bpp, - struct drm_framebuffer **fb_p) +static int radeonfb_create(struct drm_device *dev, + struct drm_fb_helper_surface_size *sizes, + struct radeon_kernel_fbdev **rfbdev_p) { struct radeon_device *rdev = dev->dev_private; struct fb_info *info; - struct radeon_fb_device *rfbdev; + struct radeon_kernel_fbdev *rfbdev; struct drm_framebuffer *fb = NULL; - struct radeon_framebuffer *rfb; struct drm_mode_fb_cmd mode_cmd; struct drm_gem_object *gobj = NULL; struct radeon_bo *rbo = NULL; @@ -151,17 +114,17 @@ int radeonfb_create(struct drm_device *dev, bool fb_tiled = false; /* useful for testing */ u32 tiling_flags = 0; - mode_cmd.width = surface_width; - mode_cmd.height = surface_height; + mode_cmd.width = sizes->surface_width; + mode_cmd.height = sizes->surface_height; /* avivo can't scanout real 24bpp */ - if ((surface_bpp == 24) && ASIC_IS_AVIVO(rdev)) - surface_bpp = 32; + if ((sizes->surface_bpp == 24) && ASIC_IS_AVIVO(rdev)) + sizes->surface_bpp = 32; - mode_cmd.bpp = surface_bpp; + mode_cmd.bpp = sizes->surface_bpp; /* need to align pitch with crtc limits */ mode_cmd.pitch = radeon_align_pitch(rdev, mode_cmd.width, mode_cmd.bpp, fb_tiled) * ((mode_cmd.bpp + 1) / 8); - mode_cmd.depth = surface_depth; + mode_cmd.depth = sizes->surface_depth; size = mode_cmd.pitch * mode_cmd.height; aligned_size = ALIGN(size, PAGE_SIZE); @@ -172,7 +135,7 @@ int radeonfb_create(struct drm_device *dev, &gobj); if (ret) { printk(KERN_ERR "failed to allocate framebuffer (%d %d)\n", - surface_width, surface_height); + sizes->surface_width, sizes->surface_height); ret = -ENOMEM; goto out; } @@ -201,12 +164,7 @@ int radeonfb_create(struct drm_device *dev, dev_err(rdev->dev, "FB failed to set tiling flags\n"); } mutex_lock(&rdev->ddev->struct_mutex); - fb = radeon_framebuffer_create(rdev->ddev, &mode_cmd, gobj); - if (fb == NULL) { - DRM_ERROR("failed to allocate fb.\n"); - ret = -ENOMEM; - goto out_unref; - } + ret = radeon_bo_reserve(rbo, false); if (unlikely(ret != 0)) goto out_unref; @@ -223,23 +181,25 @@ int radeonfb_create(struct drm_device *dev, goto out_unref; } - list_add(&fb->filp_head, &rdev->ddev->mode_config.fb_kernel_list); - - *fb_p = fb; - rfb = to_radeon_framebuffer(fb); - rdev->fbdev_rfb = rfb; - rdev->fbdev_rbo = rbo; - - info = framebuffer_alloc(sizeof(struct radeon_fb_device), device); + info = framebuffer_alloc(sizeof(struct radeon_kernel_fbdev), device); if (info == NULL) { ret = -ENOMEM; goto out_unref; } - rdev->fbdev_info = info; rfbdev = info->par; + rfbdev->rdev = rdev; + radeon_framebuffer_init(dev, &rfbdev->rfb, &mode_cmd, gobj); + fb = &rfbdev->rfb.base; + + /* setup helper */ + rfbdev->helper.fb = fb; + rfbdev->helper.fbdev = info; rfbdev->helper.funcs = &radeon_fb_helper_funcs; rfbdev->helper.dev = dev; + + *rfbdev_p = rfbdev; + ret = drm_fb_helper_init_crtc_count(&rfbdev->helper, rdev->num_crtc, RADEONFB_CONN_LIMIT); if (ret) @@ -260,7 +220,7 @@ int radeonfb_create(struct drm_device *dev, info->screen_base = fbptr; info->screen_size = size; - drm_fb_helper_fill_var(info, fb, fb_width, fb_height); + drm_fb_helper_fill_var(info, &rfbdev->helper, sizes->fb_width, sizes->fb_height); /* setup aperture base/size for vesafb takeover */ info->aperture_base = rdev->ddev->mode_config.fb_base; @@ -283,9 +243,6 @@ int radeonfb_create(struct drm_device *dev, DRM_INFO("fb depth is %d\n", fb->depth); DRM_INFO(" pitch is %d\n", fb->pitch); - fb->fbdev = info; - rfbdev->rfb = rfb; - rfbdev->rdev = rdev; mutex_unlock(&rdev->ddev->struct_mutex); vga_switcheroo_client_fb_set(rdev->ddev->pdev, info); @@ -300,7 +257,6 @@ out_unref: } } if (fb && ret) { - list_del(&fb->filp_head); drm_gem_object_unreference(gobj); drm_framebuffer_cleanup(fb); kfree(fb); @@ -311,6 +267,35 @@ out: return ret; } +static int radeon_fb_find_or_create_single(struct drm_device *dev, + struct drm_fb_helper_surface_size *sizes, + struct drm_fb_helper **fb_ptr) +{ + struct radeon_device *rdev = dev->dev_private; + struct radeon_kernel_fbdev *rfbdev = NULL; + int new_fb = 0; + int ret; + + if (!rdev->mode_info.rfbdev) { + ret = radeonfb_create(dev, sizes, + &rfbdev); + if (ret) + return ret; + rdev->mode_info.rfbdev = rfbdev; + new_fb = 1; + } else { + rfbdev = rdev->mode_info.rfbdev; + if (rfbdev->rfb.base.width < sizes->surface_width || + rfbdev->rfb.base.height < sizes->surface_height) { + DRM_ERROR("Framebuffer not large enough to scale console onto.\n"); + return -EINVAL; + } + } + + *fb_ptr = &rfbdev->helper; + return new_fb; +} + static char *mode_option; int radeon_parse_options(char *options) { @@ -327,7 +312,7 @@ int radeon_parse_options(char *options) return 0; } -int radeonfb_probe(struct drm_device *dev) +static int radeonfb_probe(struct drm_device *dev) { struct radeon_device *rdev = dev->dev_private; int bpp_sel = 32; @@ -336,37 +321,76 @@ int radeonfb_probe(struct drm_device *dev) if (ASIC_IS_RN50(rdev) || rdev->mc.real_vram_size <= (32*1024*1024)) bpp_sel = 8; - return drm_fb_helper_single_fb_probe(dev, bpp_sel, &radeonfb_create); + return drm_fb_helper_single_fb_probe(dev, bpp_sel, &radeon_fb_find_or_create_single); +} + +void radeonfb_hotplug(struct drm_device *dev) +{ + drm_helper_fb_hotplug_event(dev); + + radeonfb_probe(dev); } -int radeonfb_remove(struct drm_device *dev, struct drm_framebuffer *fb) +static int radeon_fbdev_destroy(struct drm_device *dev, struct radeon_kernel_fbdev *rfbdev) { struct fb_info *info; - struct radeon_framebuffer *rfb = to_radeon_framebuffer(fb); + struct radeon_framebuffer *rfb = &rfbdev->rfb; struct radeon_bo *rbo; int r; - if (!fb) { - return -EINVAL; - } - info = fb->fbdev; - if (info) { - struct radeon_fb_device *rfbdev = info->par; - rbo = rfb->obj->driver_private; - unregister_framebuffer(info); - r = radeon_bo_reserve(rbo, false); - if (likely(r == 0)) { - radeon_bo_kunmap(rbo); - radeon_bo_unpin(rbo); - radeon_bo_unreserve(rbo); - } - drm_fb_helper_free(&rfbdev->helper); - framebuffer_release(info); + rbo = rfb->obj->driver_private; + info = rfbdev->helper.fbdev; + unregister_framebuffer(info); + r = radeon_bo_reserve(rbo, false); + if (likely(r == 0)) { + radeon_bo_kunmap(rbo); + radeon_bo_unpin(rbo); + radeon_bo_unreserve(rbo); } - printk(KERN_INFO "unregistered panic notifier\n"); + drm_fb_helper_free(&rfbdev->helper); + drm_framebuffer_cleanup(&rfb->base); + if (rfb->obj) + drm_gem_object_unreference_unlocked(rfb->obj); + + framebuffer_release(info); return 0; } -EXPORT_SYMBOL(radeonfb_remove); MODULE_LICENSE("GPL"); + +int radeon_fbdev_init(struct radeon_device *rdev) +{ + drm_helper_initial_config(rdev->ddev); + radeonfb_probe(rdev->ddev); + return 0; +} + +void radeon_fbdev_fini(struct radeon_device *rdev) +{ + radeon_fbdev_destroy(rdev->ddev, rdev->mode_info.rfbdev); + rdev->mode_info.rfbdev = NULL; +} + +void radeon_fbdev_set_suspend(struct radeon_device *rdev, int state) +{ + fb_set_suspend(rdev->mode_info.rfbdev->helper.fbdev, state); +} + +int radeon_fbdev_total_size(struct radeon_device *rdev) +{ + struct radeon_bo *robj; + int size = 0; + + robj = rdev->mode_info.rfbdev->rfb.obj->driver_private; + size += radeon_bo_size(robj); + return size; +} + +bool radeon_fbdev_robj_is_fb(struct radeon_device *rdev, struct radeon_bo *robj) +{ + if (robj == rdev->mode_info.rfbdev->rfb.obj->driver_private) + return true; + return false; +} + diff --git a/drivers/gpu/drm/radeon/radeon_gem.c b/drivers/gpu/drm/radeon/radeon_gem.c index ef92d147d8f0..28dd3e1b9c3a 100644 --- a/drivers/gpu/drm/radeon/radeon_gem.c +++ b/drivers/gpu/drm/radeon/radeon_gem.c @@ -158,8 +158,7 @@ int radeon_gem_info_ioctl(struct drm_device *dev, void *data, args->vram_visible = rdev->mc.real_vram_size; if (rdev->stollen_vga_memory) args->vram_visible -= radeon_bo_size(rdev->stollen_vga_memory); - if (rdev->fbdev_rbo) - args->vram_visible -= radeon_bo_size(rdev->fbdev_rbo); + args->vram_visible -= radeon_fbdev_total_size(rdev); args->gart_size = rdev->mc.gtt_size - rdev->cp.ring_size - 4096 - RADEON_IB_POOL_SIZE*64*1024; return 0; diff --git a/drivers/gpu/drm/radeon/radeon_irq_kms.c b/drivers/gpu/drm/radeon/radeon_irq_kms.c index a212041e8b0b..e7afd80a3d69 100644 --- a/drivers/gpu/drm/radeon/radeon_irq_kms.c +++ b/drivers/gpu/drm/radeon/radeon_irq_kms.c @@ -55,6 +55,8 @@ static void radeon_hotplug_work_func(struct work_struct *work) radeon_connector_hotplug(connector); } /* Just fire off a uevent and let userspace tell us what to do */ + radeonfb_hotplug(dev); + drm_sysfs_hotplug_event(dev); } diff --git a/drivers/gpu/drm/radeon/radeon_mode.h b/drivers/gpu/drm/radeon/radeon_mode.h index 0b8e32776b10..1e9138bf5592 100644 --- a/drivers/gpu/drm/radeon/radeon_mode.h +++ b/drivers/gpu/drm/radeon/radeon_mode.h @@ -39,6 +39,7 @@ #include #include "radeon_fixed.h" +struct radeon_bo; struct radeon_device; #define to_radeon_crtc(x) container_of(x, struct radeon_crtc, base) @@ -202,6 +203,8 @@ enum radeon_dvo_chip { DVO_SIL1178, }; +struct radeon_kernel_fbdev; + struct radeon_mode_info { struct atom_context *atom_context; struct card_info *atom_card_info; @@ -218,6 +221,9 @@ struct radeon_mode_info { struct drm_property *tmds_pll_property; /* hardcoded DFP edid from BIOS */ struct edid *bios_hardcoded_edid; + + /* pointer to fbdev info structure */ + struct radeon_kernel_fbdev *rfbdev; }; #define MAX_H_CODE_TIMING_LEN 32 @@ -532,11 +538,10 @@ extern void radeon_crtc_fb_gamma_set(struct drm_crtc *crtc, u16 red, u16 green, u16 blue, int regno); extern void radeon_crtc_fb_gamma_get(struct drm_crtc *crtc, u16 *red, u16 *green, u16 *blue, int regno); -struct drm_framebuffer *radeon_framebuffer_create(struct drm_device *dev, - struct drm_mode_fb_cmd *mode_cmd, - struct drm_gem_object *obj); - -int radeonfb_probe(struct drm_device *dev); +void radeon_framebuffer_init(struct drm_device *dev, + struct radeon_framebuffer *rfb, + struct drm_mode_fb_cmd *mode_cmd, + struct drm_gem_object *obj); int radeonfb_remove(struct drm_device *dev, struct drm_framebuffer *fb); bool radeon_get_legacy_connector_info_from_bios(struct drm_device *dev); @@ -573,4 +578,12 @@ void radeon_legacy_tv_adjust_pll2(struct drm_encoder *encoder, void radeon_legacy_tv_mode_set(struct drm_encoder *encoder, struct drm_display_mode *mode, struct drm_display_mode *adjusted_mode); + +/* fbdev layer */ +int radeon_fbdev_init(struct radeon_device *rdev); +void radeon_fbdev_fini(struct radeon_device *rdev); +void radeon_fbdev_set_suspend(struct radeon_device *rdev, int state); +int radeon_fbdev_total_size(struct radeon_device *rdev); +bool radeon_fbdev_robj_is_fb(struct radeon_device *rdev, struct radeon_bo *robj); +void radeonfb_hotplug(struct drm_device *dev); #endif diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_kms.c b/drivers/gpu/drm/vmwgfx/vmwgfx_kms.c index 31f9afed0a63..bbc7c4c30bc7 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_kms.c +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_kms.c @@ -752,14 +752,8 @@ err_not_scanout: return NULL; } -static int vmw_kms_fb_changed(struct drm_device *dev) -{ - return 0; -} - static struct drm_mode_config_funcs vmw_kms_funcs = { .fb_create = vmw_kms_fb_create, - .fb_changed = vmw_kms_fb_changed, }; int vmw_kms_init(struct vmw_private *dev_priv) diff --git a/include/drm/drm_crtc.h b/include/drm/drm_crtc.h index 1347524a8e30..c70814b184e8 100644 --- a/include/drm/drm_crtc.h +++ b/include/drm/drm_crtc.h @@ -271,8 +271,6 @@ struct drm_framebuffer { unsigned int depth; int bits_per_pixel; int flags; - struct fb_info *fbdev; - u32 pseudo_palette[17]; struct list_head filp_head; /* if you are using the helper */ void *helper_private; @@ -548,16 +546,9 @@ struct drm_mode_set { /** * struct drm_mode_config_funcs - configure CRTCs for a given screen layout - * @resize: adjust CRTCs as necessary for the proposed layout - * - * Currently only a resize hook is available. DRM will call back into the - * driver with a new screen width and height. If the driver can't support - * the proposed size, it can return false. Otherwise it should adjust - * the CRTC<->connector mappings as needed and update its view of the screen. */ struct drm_mode_config_funcs { struct drm_framebuffer *(*fb_create)(struct drm_device *dev, struct drm_file *file_priv, struct drm_mode_fb_cmd *mode_cmd); - int (*fb_changed)(struct drm_device *dev); }; struct drm_mode_group { @@ -590,9 +581,6 @@ struct drm_mode_config { struct list_head property_list; - /* in-kernel framebuffers - hung of filp_head in drm_framebuffer */ - struct list_head fb_kernel_list; - int min_width, min_height; int max_width, max_height; struct drm_mode_config_funcs *funcs; diff --git a/include/drm/drm_crtc_helper.h b/include/drm/drm_crtc_helper.h index b29e20168b5f..ce7aab77f7dc 100644 --- a/include/drm/drm_crtc_helper.h +++ b/include/drm/drm_crtc_helper.h @@ -97,7 +97,6 @@ struct drm_connector_helper_funcs { extern int drm_helper_probe_single_connector_modes(struct drm_connector *connector, uint32_t maxX, uint32_t maxY); extern void drm_helper_disable_unused_functions(struct drm_device *dev); extern int drm_helper_hotplug_stage_two(struct drm_device *dev); -extern bool drm_helper_initial_config(struct drm_device *dev); extern int drm_crtc_helper_set_config(struct drm_mode_set *set); extern bool drm_crtc_helper_set_mode(struct drm_crtc *crtc, struct drm_display_mode *mode, diff --git a/include/drm/drm_fb_helper.h b/include/drm/drm_fb_helper.h index 58c892a2cbfa..38ab0daffd1f 100644 --- a/include/drm/drm_fb_helper.h +++ b/include/drm/drm_fb_helper.h @@ -57,6 +57,15 @@ struct drm_fb_helper_cmdline_mode { bool margins; }; +struct drm_fb_helper_surface_size { + u32 fb_width; + u32 fb_height; + u32 surface_width; + u32 surface_height; + u32 surface_bpp; + u32 surface_depth; +}; + struct drm_fb_helper_connector { struct drm_fb_helper_cmdline_mode cmdline_mode; }; @@ -69,19 +78,16 @@ struct drm_fb_helper { struct drm_fb_helper_crtc *crtc_info; struct drm_fb_helper_funcs *funcs; int conn_limit; + struct fb_info *fbdev; + u32 pseudo_palette[17]; struct list_head kernel_fb_list; }; int drm_fb_helper_single_fb_probe(struct drm_device *dev, int preferred_bpp, int (*fb_create)(struct drm_device *dev, - uint32_t fb_width, - uint32_t fb_height, - uint32_t surface_width, - uint32_t surface_height, - uint32_t surface_depth, - uint32_t surface_bpp, - struct drm_framebuffer **fb_ptr)); + struct drm_fb_helper_surface_size *sizes, + struct drm_fb_helper **fb_ptr)); int drm_fb_helper_init_crtc_count(struct drm_fb_helper *helper, int crtc_count, int max_conn); void drm_fb_helper_free(struct drm_fb_helper *helper); @@ -99,7 +105,7 @@ int drm_fb_helper_setcolreg(unsigned regno, struct fb_info *info); void drm_fb_helper_restore(void); -void drm_fb_helper_fill_var(struct fb_info *info, struct drm_framebuffer *fb, +void drm_fb_helper_fill_var(struct fb_info *info, struct drm_fb_helper *fb_helper, uint32_t fb_width, uint32_t fb_height); void drm_fb_helper_fill_fix(struct fb_info *info, uint32_t pitch, uint32_t depth); @@ -108,4 +114,6 @@ int drm_fb_helper_add_connector(struct drm_connector *connector); int drm_fb_helper_parse_command_line(struct drm_device *dev); int drm_fb_helper_setcmap(struct fb_cmap *cmap, struct fb_info *info); +bool drm_helper_fb_hotplug_event(struct drm_device *dev); +bool drm_helper_initial_config(struct drm_device *dev); #endif -- cgit v1.2.3 From 8be48d924c307e72e3797ab5bde81b07a1ccc52d Mon Sep 17 00:00:00 2001 From: Dave Airlie Date: Tue, 30 Mar 2010 05:34:14 +0000 Subject: drm/kms/fb: move to using fb helper crtc grouping instead of core crtc list This move to using the list of crtcs in the fb helper and cleans up the whole picking code, now we store the crtc/connectors we want directly into the modeset and we use the modeset directly to set the mode. Fixes from James Simmons and Ben Skeggs. Signed-off-by: Dave Airlie --- drivers/gpu/drm/drm_crtc_helper.c | 4 - drivers/gpu/drm/drm_fb_helper.c | 329 ++++++++++++++------------------ drivers/gpu/drm/i915/i915_drv.h | 5 +- drivers/gpu/drm/i915/intel_fb.c | 93 +++++---- drivers/gpu/drm/nouveau/nouveau_drv.h | 2 +- drivers/gpu/drm/nouveau/nouveau_fbcon.c | 121 ++++++------ drivers/gpu/drm/nouveau/nouveau_fbcon.h | 2 +- drivers/gpu/drm/nouveau/nv04_fbcon.c | 16 +- drivers/gpu/drm/nouveau/nv50_fbcon.c | 16 +- drivers/gpu/drm/radeon/radeon_fb.c | 240 ++++++++++++----------- drivers/gpu/drm/radeon/radeon_mode.h | 4 +- include/drm/drm_crtc.h | 5 - include/drm/drm_fb_helper.h | 21 +- 13 files changed, 411 insertions(+), 447 deletions(-) (limited to 'drivers/gpu/drm/radeon') diff --git a/drivers/gpu/drm/drm_crtc_helper.c b/drivers/gpu/drm/drm_crtc_helper.c index 9d23f54673d3..b142ac260d97 100644 --- a/drivers/gpu/drm/drm_crtc_helper.c +++ b/drivers/gpu/drm/drm_crtc_helper.c @@ -625,10 +625,6 @@ int drm_crtc_helper_set_config(struct drm_mode_set *set) ret = -EINVAL; goto fail; } - /* TODO are these needed? */ - set->crtc->desired_x = set->x; - set->crtc->desired_y = set->y; - set->crtc->desired_mode = set->mode; } drm_helper_disable_unused_functions(dev); } else if (fb_changed) { diff --git a/drivers/gpu/drm/drm_fb_helper.c b/drivers/gpu/drm/drm_fb_helper.c index 055b5be78877..2515563063ce 100644 --- a/drivers/gpu/drm/drm_fb_helper.c +++ b/drivers/gpu/drm/drm_fb_helper.c @@ -292,6 +292,7 @@ static void drm_fb_helper_on(struct fb_info *info) struct drm_fb_helper *fb_helper = info->par; struct drm_device *dev = fb_helper->dev; struct drm_crtc *crtc; + struct drm_crtc_helper_funcs *crtc_funcs; struct drm_encoder *encoder; int i; @@ -299,33 +300,28 @@ static void drm_fb_helper_on(struct fb_info *info) * For each CRTC in this fb, turn the crtc on then, * find all associated encoders and turn them on. */ + mutex_lock(&dev->mode_config.mutex); for (i = 0; i < fb_helper->crtc_count; i++) { - list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) { - struct drm_crtc_helper_funcs *crtc_funcs = - crtc->helper_private; + crtc = fb_helper->crtc_info[i].mode_set.crtc; + crtc_funcs = crtc->helper_private; - /* Only mess with CRTCs in this fb */ - if (crtc->base.id != fb_helper->crtc_info[i].crtc_id || - !crtc->enabled) - continue; + if (!crtc->enabled) + continue; + + crtc_funcs->dpms(crtc, DRM_MODE_DPMS_ON); - mutex_lock(&dev->mode_config.mutex); - crtc_funcs->dpms(crtc, DRM_MODE_DPMS_ON); - mutex_unlock(&dev->mode_config.mutex); - /* Found a CRTC on this fb, now find encoders */ - list_for_each_entry(encoder, &dev->mode_config.encoder_list, head) { - if (encoder->crtc == crtc) { - struct drm_encoder_helper_funcs *encoder_funcs; + /* Found a CRTC on this fb, now find encoders */ + list_for_each_entry(encoder, &dev->mode_config.encoder_list, head) { + if (encoder->crtc == crtc) { + struct drm_encoder_helper_funcs *encoder_funcs; - encoder_funcs = encoder->helper_private; - mutex_lock(&dev->mode_config.mutex); - encoder_funcs->dpms(encoder, DRM_MODE_DPMS_ON); - mutex_unlock(&dev->mode_config.mutex); - } + encoder_funcs = encoder->helper_private; + encoder_funcs->dpms(encoder, DRM_MODE_DPMS_ON); } } } + mutex_unlock(&dev->mode_config.mutex); } static void drm_fb_helper_off(struct fb_info *info, int dpms_mode) @@ -333,6 +329,7 @@ static void drm_fb_helper_off(struct fb_info *info, int dpms_mode) struct drm_fb_helper *fb_helper = info->par; struct drm_device *dev = fb_helper->dev; struct drm_crtc *crtc; + struct drm_crtc_helper_funcs *crtc_funcs; struct drm_encoder *encoder; int i; @@ -340,32 +337,26 @@ static void drm_fb_helper_off(struct fb_info *info, int dpms_mode) * For each CRTC in this fb, find all associated encoders * and turn them off, then turn off the CRTC. */ + mutex_lock(&dev->mode_config.mutex); for (i = 0; i < fb_helper->crtc_count; i++) { - list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) { - struct drm_crtc_helper_funcs *crtc_funcs = - crtc->helper_private; + crtc = fb_helper->crtc_info[i].mode_set.crtc; + crtc_funcs = crtc->helper_private; - /* Only mess with CRTCs in this fb */ - if (crtc->base.id != fb_helper->crtc_info[i].crtc_id || - !crtc->enabled) - continue; + if (!crtc->enabled) + continue; - /* Found a CRTC on this fb, now find encoders */ - list_for_each_entry(encoder, &dev->mode_config.encoder_list, head) { - if (encoder->crtc == crtc) { - struct drm_encoder_helper_funcs *encoder_funcs; + /* Found a CRTC on this fb, now find encoders */ + list_for_each_entry(encoder, &dev->mode_config.encoder_list, head) { + if (encoder->crtc == crtc) { + struct drm_encoder_helper_funcs *encoder_funcs; - encoder_funcs = encoder->helper_private; - mutex_lock(&dev->mode_config.mutex); - encoder_funcs->dpms(encoder, dpms_mode); - mutex_unlock(&dev->mode_config.mutex); - } + encoder_funcs = encoder->helper_private; + encoder_funcs->dpms(encoder, dpms_mode); } - mutex_lock(&dev->mode_config.mutex); - crtc_funcs->dpms(crtc, DRM_MODE_DPMS_OFF); - mutex_unlock(&dev->mode_config.mutex); } + crtc_funcs->dpms(crtc, DRM_MODE_DPMS_OFF); } + mutex_unlock(&dev->mode_config.mutex); } int drm_fb_helper_blank(int blank, struct fb_info *info) @@ -405,17 +396,19 @@ static void drm_fb_helper_crtc_free(struct drm_fb_helper *helper) kfree(helper->crtc_info); } -int drm_fb_helper_init_crtc_count(struct drm_fb_helper *helper, int crtc_count, int max_conn_count) +int drm_fb_helper_init_crtc_count(struct drm_device *dev, + struct drm_fb_helper *helper, + int crtc_count, int max_conn_count) { - struct drm_device *dev = helper->dev; struct drm_crtc *crtc; int ret = 0; int i; + INIT_LIST_HEAD(&helper->kernel_fb_list); + helper->dev = dev; helper->crtc_info = kcalloc(crtc_count, sizeof(struct drm_fb_helper_crtc), GFP_KERNEL); if (!helper->crtc_info) return -ENOMEM; - helper->crtc_count = crtc_count; for (i = 0; i < crtc_count; i++) { @@ -507,20 +500,15 @@ static int setcolreg(struct drm_crtc *crtc, u16 red, u16 green, int drm_fb_helper_setcmap(struct fb_cmap *cmap, struct fb_info *info) { struct drm_fb_helper *fb_helper = info->par; - struct drm_device *dev = fb_helper->dev; + struct drm_crtc_helper_funcs *crtc_funcs; u16 *red, *green, *blue, *transp; struct drm_crtc *crtc; int i, rc = 0; int start; - list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) { - struct drm_crtc_helper_funcs *crtc_funcs = crtc->helper_private; - for (i = 0; i < fb_helper->crtc_count; i++) { - if (crtc->base.id == fb_helper->crtc_info[i].crtc_id) - break; - } - if (i == fb_helper->crtc_count) - continue; + for (i = 0; i < fb_helper->crtc_count; i++) { + crtc = fb_helper->crtc_info[i].mode_set.crtc; + crtc_funcs = crtc->helper_private; red = cmap->red; green = cmap->green; @@ -556,22 +544,17 @@ int drm_fb_helper_setcolreg(unsigned regno, struct fb_info *info) { struct drm_fb_helper *fb_helper = info->par; - struct drm_device *dev = fb_helper->dev; struct drm_crtc *crtc; + struct drm_crtc_helper_funcs *crtc_funcs; int i; int ret; if (regno > 255) return 1; - list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) { - struct drm_crtc_helper_funcs *crtc_funcs = crtc->helper_private; - for (i = 0; i < fb_helper->crtc_count; i++) { - if (crtc->base.id == fb_helper->crtc_info[i].crtc_id) - break; - } - if (i == fb_helper->crtc_count) - continue; + for (i = 0; i < fb_helper->crtc_count; i++) { + crtc = fb_helper->crtc_info[i].mode_set.crtc; + crtc_funcs = crtc->helper_private; ret = setcolreg(crtc, red, green, blue, regno, info); if (ret) @@ -686,23 +669,20 @@ int drm_fb_helper_set_par(struct fb_info *info) return -EINVAL; } - list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) { - - for (i = 0; i < fb_helper->crtc_count; i++) { - if (crtc->base.id == fb_helper->crtc_info[i].crtc_id) - break; - } - if (i == fb_helper->crtc_count) - continue; + mutex_lock(&dev->mode_config.mutex); + for (i = 0; i < fb_helper->crtc_count; i++) { + crtc = fb_helper->crtc_info[i].mode_set.crtc; - if (crtc->fb == fb_helper->crtc_info[i].mode_set.fb) { - mutex_lock(&dev->mode_config.mutex); + if (crtc->fb != fb_helper->crtc_info[i].mode_set.fb) { ret = crtc->funcs->set_config(&fb_helper->crtc_info[i].mode_set); - mutex_unlock(&dev->mode_config.mutex); - if (ret) + + if (ret) { + mutex_unlock(&dev->mode_config.mutex); return ret; + } } } + mutex_unlock(&dev->mode_config.mutex); return 0; } EXPORT_SYMBOL(drm_fb_helper_set_par); @@ -717,14 +697,9 @@ int drm_fb_helper_pan_display(struct fb_var_screeninfo *var, int ret = 0; int i; - list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) { - for (i = 0; i < fb_helper->crtc_count; i++) { - if (crtc->base.id == fb_helper->crtc_info[i].crtc_id) - break; - } - - if (i == fb_helper->crtc_count) - continue; + mutex_lock(&dev->mode_config.mutex); + for (i = 0; i < fb_helper->crtc_count; i++) { + crtc = fb_helper->crtc_info[i].mode_set.crtc; modeset = &fb_helper->crtc_info[i].mode_set; @@ -732,34 +707,29 @@ int drm_fb_helper_pan_display(struct fb_var_screeninfo *var, modeset->y = var->yoffset; if (modeset->num_connectors) { - mutex_lock(&dev->mode_config.mutex); ret = crtc->funcs->set_config(modeset); - mutex_unlock(&dev->mode_config.mutex); if (!ret) { info->var.xoffset = var->xoffset; info->var.yoffset = var->yoffset; } } } + mutex_unlock(&dev->mode_config.mutex); return ret; } EXPORT_SYMBOL(drm_fb_helper_pan_display); -int drm_fb_helper_single_fb_probe(struct drm_device *dev, - int preferred_bpp, - int (*fb_find_or_create)(struct drm_device *dev, - struct drm_fb_helper_surface_size *sizes, - struct drm_fb_helper **fb_ptr)) +int drm_fb_helper_single_fb_probe(struct drm_fb_helper *fb_helper, + int preferred_bpp) { - struct drm_crtc *crtc; + struct drm_device *dev = fb_helper->dev; struct drm_connector *connector; int new_fb = 0; int crtc_count = 0; - int ret, i, conn_count = 0; + int ret, i; struct fb_info *info; - struct drm_mode_set *modeset = NULL; - struct drm_fb_helper *fb_helper; struct drm_fb_helper_surface_size sizes; + int gamma_size = 0; memset(&sizes, 0, sizeof(struct drm_fb_helper_surface_size)); sizes.surface_depth = 24; @@ -775,7 +745,6 @@ int drm_fb_helper_single_fb_probe(struct drm_device *dev, /* first up get a count of crtcs now in use and new min/maxes width/heights */ list_for_each_entry(connector, &dev->mode_config.connector_list, head) { struct drm_fb_helper_connector *fb_help_conn = connector->fb_helper_private; - struct drm_fb_helper_cmdline_mode *cmdline_mode; if (!fb_help_conn) @@ -807,21 +776,22 @@ int drm_fb_helper_single_fb_probe(struct drm_device *dev, } } - list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) { - if (drm_helper_crtc_in_use(crtc)) { - if (crtc->desired_mode) { - if (crtc->desired_mode->hdisplay < sizes.fb_width) - sizes.fb_width = crtc->desired_mode->hdisplay; - - if (crtc->desired_mode->vdisplay < sizes.fb_height) - sizes.fb_height = crtc->desired_mode->vdisplay; - - if (crtc->desired_mode->hdisplay > sizes.surface_width) - sizes.surface_width = crtc->desired_mode->hdisplay; - - if (crtc->desired_mode->vdisplay > sizes.surface_height) - sizes.surface_height = crtc->desired_mode->vdisplay; - } + crtc_count = 0; + for (i = 0; i < fb_helper->crtc_count; i++) { + struct drm_display_mode *desired_mode; + desired_mode = fb_helper->crtc_info[i].desired_mode; + + if (desired_mode) { + if (gamma_size == 0) + gamma_size = fb_helper->crtc_info[i].mode_set.crtc->gamma_size; + if (desired_mode->hdisplay < sizes.fb_width) + sizes.fb_width = desired_mode->hdisplay; + if (desired_mode->vdisplay < sizes.fb_height) + sizes.fb_height = desired_mode->vdisplay; + if (desired_mode->hdisplay > sizes.surface_width) + sizes.surface_width = desired_mode->hdisplay; + if (desired_mode->vdisplay > sizes.surface_height) + sizes.surface_height = desired_mode->vdisplay; crtc_count++; } } @@ -833,48 +803,20 @@ int drm_fb_helper_single_fb_probe(struct drm_device *dev, } /* push down into drivers */ - new_fb = (*fb_find_or_create)(dev, &sizes, - &fb_helper); + new_fb = (*fb_helper->fb_probe)(fb_helper, &sizes); if (new_fb < 0) return new_fb; info = fb_helper->fbdev; - crtc_count = 0; - /* okay we need to setup new connector sets in the crtcs */ - list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) { - modeset = &fb_helper->crtc_info[crtc_count].mode_set; - modeset->fb = fb_helper->fb; - conn_count = 0; - list_for_each_entry(connector, &dev->mode_config.connector_list, head) { - if (connector->encoder) - if (connector->encoder->crtc == modeset->crtc) { - modeset->connectors[conn_count] = connector; - conn_count++; - if (conn_count > fb_helper->conn_limit) - BUG(); - } - } - - for (i = conn_count; i < fb_helper->conn_limit; i++) - modeset->connectors[i] = NULL; - - modeset->crtc = crtc; - crtc_count++; - - modeset->num_connectors = conn_count; - if (modeset->crtc->desired_mode) { - if (modeset->mode) - drm_mode_destroy(dev, modeset->mode); - modeset->mode = drm_mode_duplicate(dev, - modeset->crtc->desired_mode); - } + /* set the fb pointer */ + for (i = 0; i < fb_helper->crtc_count; i++) { + fb_helper->crtc_info[i].mode_set.fb = fb_helper->fb; } - fb_helper->crtc_count = crtc_count; if (new_fb) { info->var.pixclock = 0; - ret = fb_alloc_cmap(&info->cmap, modeset->crtc->gamma_size, 0); + ret = fb_alloc_cmap(&info->cmap, gamma_size, 0); if (ret) return ret; if (register_framebuffer(info) < 0) { @@ -906,15 +848,18 @@ EXPORT_SYMBOL(drm_fb_helper_single_fb_probe); void drm_fb_helper_free(struct drm_fb_helper *helper) { - list_del(&helper->kernel_fb_list); - if (list_empty(&kernel_fb_helper_list)) { - printk(KERN_INFO "unregistered panic notifier\n"); - atomic_notifier_chain_unregister(&panic_notifier_list, - &paniced); - unregister_sysrq_key('v', &sysrq_drm_fb_helper_restore_op); + if (!list_empty(&helper->kernel_fb_list)) { + list_del(&helper->kernel_fb_list); + if (list_empty(&kernel_fb_helper_list)) { + printk(KERN_INFO "unregistered panic notifier\n"); + atomic_notifier_chain_unregister(&panic_notifier_list, + &paniced); + unregister_sysrq_key('v', &sysrq_drm_fb_helper_restore_op); + } } drm_fb_helper_crtc_free(helper); - fb_dealloc_cmap(&helper->fbdev->cmap); + if (helper->fbdev->cmap.len) + fb_dealloc_cmap(&helper->fbdev->cmap); } EXPORT_SYMBOL(drm_fb_helper_free); @@ -1168,20 +1113,21 @@ static bool drm_target_preferred(struct drm_device *dev, return true; } -static int drm_pick_crtcs(struct drm_device *dev, - struct drm_crtc **best_crtcs, +static int drm_pick_crtcs(struct drm_fb_helper *fb_helper, + struct drm_fb_helper_crtc **best_crtcs, struct drm_display_mode **modes, int n, int width, int height) { int c, o; + struct drm_device *dev = fb_helper->dev; struct drm_connector *connector; struct drm_connector_helper_funcs *connector_funcs; struct drm_encoder *encoder; - struct drm_crtc *best_crtc; + struct drm_fb_helper_crtc *best_crtc; int my_score, best_score, score; - struct drm_crtc **crtcs, *crtc; + struct drm_fb_helper_crtc **crtcs, *crtc; - if (n == dev->mode_config.num_connector) + if (n == fb_helper->dev->mode_config.num_connector) return 0; c = 0; list_for_each_entry(connector, &dev->mode_config.connector_list, head) { @@ -1192,12 +1138,12 @@ static int drm_pick_crtcs(struct drm_device *dev, best_crtcs[n] = NULL; best_crtc = NULL; - best_score = drm_pick_crtcs(dev, best_crtcs, modes, n+1, width, height); + best_score = drm_pick_crtcs(fb_helper, best_crtcs, modes, n+1, width, height); if (modes[n] == NULL) return best_score; - crtcs = kmalloc(dev->mode_config.num_connector * - sizeof(struct drm_crtc *), GFP_KERNEL); + crtcs = kzalloc(dev->mode_config.num_connector * + sizeof(struct drm_fb_helper_crtc *), GFP_KERNEL); if (!crtcs) return best_score; @@ -1214,15 +1160,12 @@ static int drm_pick_crtcs(struct drm_device *dev, if (!encoder) goto out; - connector->encoder = encoder; - /* select a crtc for this connector and then attempt to configure remaining connectors */ - c = 0; - list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) { + for (c = 0; c < fb_helper->crtc_count; c++) { + crtc = &fb_helper->crtc_info[c]; if ((encoder->possible_crtcs & (1 << c)) == 0) { - c++; continue; } @@ -1232,34 +1175,34 @@ static int drm_pick_crtcs(struct drm_device *dev, if (o < n) { /* ignore cloning for now */ - c++; continue; } crtcs[n] = crtc; - memcpy(crtcs, best_crtcs, n * sizeof(struct drm_crtc *)); - score = my_score + drm_pick_crtcs(dev, crtcs, modes, n + 1, + memcpy(crtcs, best_crtcs, n * sizeof(struct drm_fb_helper_crtc *)); + score = my_score + drm_pick_crtcs(fb_helper, crtcs, modes, n + 1, width, height); if (score > best_score) { best_crtc = crtc; best_score = score; memcpy(best_crtcs, crtcs, dev->mode_config.num_connector * - sizeof(struct drm_crtc *)); + sizeof(struct drm_fb_helper_crtc *)); } - c++; } out: kfree(crtcs); return best_score; } -static void drm_setup_crtcs(struct drm_device *dev) +static void drm_setup_crtcs(struct drm_fb_helper *fb_helper) { - struct drm_crtc **crtcs; + struct drm_device *dev = fb_helper->dev; + struct drm_fb_helper_crtc **crtcs; struct drm_display_mode **modes; struct drm_encoder *encoder; struct drm_connector *connector; + struct drm_mode_set *modeset; bool *enabled; int width, height; int i, ret; @@ -1275,7 +1218,7 @@ static void drm_setup_crtcs(struct drm_device *dev) } crtcs = kcalloc(dev->mode_config.num_connector, - sizeof(struct drm_crtc *), GFP_KERNEL); + sizeof(struct drm_fb_helper_crtc *), GFP_KERNEL); modes = kcalloc(dev->mode_config.num_connector, sizeof(struct drm_display_mode *), GFP_KERNEL); enabled = kcalloc(dev->mode_config.num_connector, @@ -1289,26 +1232,30 @@ static void drm_setup_crtcs(struct drm_device *dev) DRM_DEBUG_KMS("picking CRTCs for %dx%d config\n", width, height); - drm_pick_crtcs(dev, crtcs, modes, 0, width, height); + drm_pick_crtcs(fb_helper, crtcs, modes, 0, width, height); + + /* need to set the modesets up here for use later */ + /* fill out the connector<->crtc mappings into the modesets */ + for (i = 0; i < fb_helper->crtc_count; i++) { + modeset = &fb_helper->crtc_info[i].mode_set; + modeset->num_connectors = 0; + } i = 0; list_for_each_entry(connector, &dev->mode_config.connector_list, head) { struct drm_display_mode *mode = modes[i]; - struct drm_crtc *crtc = crtcs[i]; - - if (connector->encoder == NULL) { - i++; - continue; - } + struct drm_fb_helper_crtc *fb_crtc = crtcs[i]; + modeset = &fb_crtc->mode_set; - if (mode && crtc) { + if (mode && fb_crtc) { DRM_DEBUG_KMS("desired mode %s set on crtc %d\n", - mode->name, crtc->base.id); - crtc->desired_mode = mode; - connector->encoder->crtc = crtc; - } else { - connector->encoder->crtc = NULL; - connector->encoder = NULL; + mode->name, fb_crtc->mode_set.crtc->base.id); + fb_crtc->desired_mode = mode; + if (modeset->mode) + drm_mode_destroy(dev, modeset->mode); + modeset->mode = drm_mode_duplicate(dev, + fb_crtc->desired_mode); + modeset->connectors[modeset->num_connectors++] = connector; } i++; } @@ -1332,14 +1279,15 @@ static void drm_setup_crtcs(struct drm_device *dev) * RETURNS: * Zero if everything went ok, nonzero otherwise. */ -bool drm_helper_initial_config(struct drm_device *dev) +bool drm_fb_helper_initial_config(struct drm_fb_helper *fb_helper) { + struct drm_device *dev = fb_helper->dev; int count = 0; /* disable all the possible outputs/crtcs before entering KMS mode */ - drm_helper_disable_unused_functions(dev); + drm_helper_disable_unused_functions(fb_helper->dev); - drm_fb_helper_parse_command_line(dev); + drm_fb_helper_parse_command_line(fb_helper->dev); count = drm_helper_probe_connector_modes(dev, dev->mode_config.max_width, @@ -1351,20 +1299,21 @@ bool drm_helper_initial_config(struct drm_device *dev) if (count == 0) printk(KERN_INFO "No connectors reported connected with modes\n"); - drm_setup_crtcs(dev); + drm_setup_crtcs(fb_helper); return 0; } -EXPORT_SYMBOL(drm_helper_initial_config); +EXPORT_SYMBOL(drm_fb_helper_initial_config); -bool drm_helper_fb_hotplug_event(struct drm_device *dev) +bool drm_helper_fb_hotplug_event(struct drm_fb_helper *fb_helper, + u32 max_width, u32 max_height) { DRM_DEBUG_KMS("\n"); - drm_helper_probe_connector_modes(dev, dev->mode_config.max_width, - dev->mode_config.max_height); + drm_helper_probe_connector_modes(fb_helper->dev, max_width, + max_height); - drm_setup_crtcs(dev); + drm_setup_crtcs(fb_helper); return true; } diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index 601f354e467e..0405a7460594 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h @@ -220,7 +220,7 @@ enum no_fbc_reason { FBC_NOT_TILED, /* buffer not tiled */ }; -struct intel_kernel_fbdev; +struct intel_fbdev; typedef struct drm_i915_private { struct drm_device *dev; @@ -630,7 +630,8 @@ typedef struct drm_i915_private { enum no_fbc_reason no_fbc_reason; - struct intel_kernel_fbdev *fbdev; + /* list of fbdev register on this device */ + struct intel_fbdev *fbdev; } drm_i915_private_t; /** driver private structure attached to each drm_gem_object */ diff --git a/drivers/gpu/drm/i915/intel_fb.c b/drivers/gpu/drm/i915/intel_fb.c index b0de9bbde34a..ff6912edf0c6 100644 --- a/drivers/gpu/drm/i915/intel_fb.c +++ b/drivers/gpu/drm/i915/intel_fb.c @@ -45,7 +45,7 @@ #include "i915_drm.h" #include "i915_drv.h" -struct intel_kernel_fbdev { +struct intel_fbdev { struct drm_fb_helper helper; struct intel_framebuffer ifb; struct list_head fbdev_list; @@ -71,14 +71,12 @@ static struct drm_fb_helper_funcs intel_fb_helper_funcs = { }; -static int intelfb_create(struct drm_device *dev, - struct drm_fb_helper_surface_size *sizes, - struct intel_kernel_fbdev **ifbdev_p) +static int intelfb_create(struct intel_fbdev *ifbdev, + struct drm_fb_helper_surface_size *sizes) { + struct drm_device *dev = ifbdev->helper.dev; struct fb_info *info; - struct intel_kernel_fbdev *ifbdev; struct drm_framebuffer *fb; - struct intel_framebuffer *intel_fb; struct drm_mode_fb_cmd mode_cmd; struct drm_gem_object *fbo = NULL; struct drm_i915_gem_object *obj_priv; @@ -117,13 +115,14 @@ static int intelfb_create(struct drm_device *dev, /* Flush everything out, we'll be doing GTT only from now on */ i915_gem_object_set_to_gtt_domain(fbo, 1); - info = framebuffer_alloc(sizeof(struct intel_kernel_fbdev), device); + info = framebuffer_alloc(0, device); if (!info) { ret = -ENOMEM; goto out_unpin; } - ifbdev = info->par; + info->par = ifbdev; + intel_framebuffer_init(dev, &ifbdev->ifb, &mode_cmd, fbo); fb = &ifbdev->ifb.base; @@ -131,22 +130,12 @@ static int intelfb_create(struct drm_device *dev, ifbdev->helper.fb = fb; ifbdev->helper.fbdev = info; ifbdev->helper.funcs = &intel_fb_helper_funcs; - ifbdev->helper.dev = dev; - - *ifbdev_p = ifbdev; - - ret = drm_fb_helper_init_crtc_count(&ifbdev->helper, 2, - INTELFB_CONN_LIMIT); - if (ret) - goto out_unref; strcpy(info->fix.id, "inteldrmfb"); info->flags = FBINFO_DEFAULT; - info->fbops = &intelfb_ops; - /* setup aperture base/size for vesafb takeover */ info->aperture_base = dev->mode_config.fb_base; if (IS_I9XX(dev)) @@ -183,8 +172,8 @@ static int intelfb_create(struct drm_device *dev, info->pixmap.scan_align = 1; DRM_DEBUG_KMS("allocated %dx%d fb: 0x%08x, bo %p\n", - intel_fb->base.width, intel_fb->base.height, - obj_priv->gtt_offset, fbo); + fb->width, fb->height, + obj_priv->gtt_offset, fbo); mutex_unlock(&dev->struct_mutex); @@ -200,76 +189,80 @@ out: return ret; } -static int intel_fb_find_or_create_single(struct drm_device *dev, - struct drm_fb_helper_surface_size *sizes, - struct drm_fb_helper **fb_ptr) +static int intel_fb_find_or_create_single(struct drm_fb_helper *helper, + struct drm_fb_helper_surface_size *sizes) { - drm_i915_private_t *dev_priv = dev->dev_private; - struct intel_kernel_fbdev *ifbdev = NULL; + struct intel_fbdev *ifbdev = (struct intel_fbdev *)helper; int new_fb = 0; int ret; - if (!dev_priv->fbdev) { - ret = intelfb_create(dev, sizes, - &ifbdev); + if (!helper->fb) { + ret = intelfb_create(ifbdev, sizes); if (ret) return ret; - - dev_priv->fbdev = ifbdev; new_fb = 1; - } else { - ifbdev = dev_priv->fbdev; - if (ifbdev->ifb.base.width < sizes->surface_width || - ifbdev->ifb.base.height < sizes->surface_height) { - DRM_ERROR("Framebuffer not large enough to scale console onto.\n"); - return -EINVAL; - } } - - *fb_ptr = &ifbdev->helper; return new_fb; } -static int intelfb_probe(struct drm_device *dev) +static int intelfb_probe(struct intel_fbdev *ifbdev) { int ret; DRM_DEBUG_KMS("\n"); - ret = drm_fb_helper_single_fb_probe(dev, 32, intel_fb_find_or_create_single); + ret = drm_fb_helper_single_fb_probe(&ifbdev->helper, 32); return ret; } int intel_fbdev_destroy(struct drm_device *dev, - struct intel_kernel_fbdev *ifbdev) + struct intel_fbdev *ifbdev) { struct fb_info *info; struct intel_framebuffer *ifb = &ifbdev->ifb; - info = ifbdev->helper.fbdev; + if (ifbdev->helper.fbdev) { + info = ifbdev->helper.fbdev; + unregister_framebuffer(info); + iounmap(info->screen_base); + framebuffer_release(info); + } - unregister_framebuffer(info); - iounmap(info->screen_base); drm_fb_helper_free(&ifbdev->helper); drm_framebuffer_cleanup(&ifb->base); - drm_gem_object_unreference_unlocked(ifb->obj); - - framebuffer_release(info); + if (ifb->obj) + drm_gem_object_unreference_unlocked(ifb->obj); return 0; } int intel_fbdev_init(struct drm_device *dev) { - drm_helper_initial_config(dev); - intelfb_probe(dev); + struct intel_fbdev *ifbdev; + drm_i915_private_t *dev_priv = dev->dev_private; + + ifbdev = kzalloc(sizeof(struct intel_fbdev), GFP_KERNEL); + if (!ifbdev) + return -ENOMEM; + + dev_priv->fbdev = ifbdev; + + drm_fb_helper_init_crtc_count(dev, &ifbdev->helper, 2, + INTELFB_CONN_LIMIT); + ifbdev->helper.fb_probe = intel_fb_find_or_create_single; + drm_fb_helper_initial_config(&ifbdev->helper); + intelfb_probe(ifbdev); return 0; } void intel_fbdev_fini(struct drm_device *dev) { drm_i915_private_t *dev_priv = dev->dev_private; + if (!dev_priv->fbdev) + return; + intel_fbdev_destroy(dev, dev_priv->fbdev); + kfree(dev_priv->fbdev); dev_priv->fbdev = NULL; } MODULE_LICENSE("GPL and additional rights"); diff --git a/drivers/gpu/drm/nouveau/nouveau_drv.h b/drivers/gpu/drm/nouveau/nouveau_drv.h index 93459e07e829..941339cb8d8b 100644 --- a/drivers/gpu/drm/nouveau/nouveau_drv.h +++ b/drivers/gpu/drm/nouveau/nouveau_drv.h @@ -627,7 +627,7 @@ struct drm_nouveau_private { struct dentry *channel_root; } debugfs; - struct nouveau_fbcon_par *nfbdev; + struct nouveau_fbdev *nfbdev; }; static inline struct drm_nouveau_private * diff --git a/drivers/gpu/drm/nouveau/nouveau_fbcon.c b/drivers/gpu/drm/nouveau/nouveau_fbcon.c index 712ee42e3cf8..90843b62d9b1 100644 --- a/drivers/gpu/drm/nouveau/nouveau_fbcon.c +++ b/drivers/gpu/drm/nouveau/nouveau_fbcon.c @@ -53,8 +53,8 @@ static int nouveau_fbcon_sync(struct fb_info *info) { - struct nouveau_fbcon_par *par = info->par; - struct drm_device *dev = par->dev; + struct nouveau_fbdev *nfbdev = info->par; + struct drm_device *dev = nfbdev->dev; struct drm_nouveau_private *dev_priv = dev->dev_private; struct nouveau_channel *chan = dev_priv->channel; int ret, i; @@ -200,9 +200,9 @@ not_fb: #endif static void -nouveau_fbcon_zfill(struct drm_device *dev, struct nouveau_fbcon_par *fbpar) +nouveau_fbcon_zfill(struct drm_device *dev, struct nouveau_fbdev *nfbdev) { - struct fb_info *info = fbpar->helper.fbdev; + struct fb_info *info = nfbdev->helper.fbdev; struct fb_fillrect rect; /* Clear the entire fbcon. The drm will program every connector @@ -218,13 +218,12 @@ nouveau_fbcon_zfill(struct drm_device *dev, struct nouveau_fbcon_par *fbpar) } static int -nouveau_fbcon_create(struct drm_device *dev, - struct drm_fb_helper_surface_size *sizes, - struct nouveau_fbcon_par **fbpar_p) +nouveau_fbcon_create(struct nouveau_fbdev *nfbdev, + struct drm_fb_helper_surface_size *sizes) { + struct drm_device *dev = nfbdev->dev; struct drm_nouveau_private *dev_priv = dev->dev_private; struct fb_info *info; - struct nouveau_fbcon_par *par; struct drm_framebuffer *fb; struct nouveau_framebuffer *nouveau_fb; struct nouveau_bo *nvbo; @@ -267,27 +266,23 @@ nouveau_fbcon_create(struct drm_device *dev, mutex_lock(&dev->struct_mutex); - info = framebuffer_alloc(sizeof(struct nouveau_fbcon_par), device); + info = framebuffer_alloc(0, device); if (!info) { ret = -ENOMEM; goto out_unref; } - par = info->par; - nouveau_framebuffer_init(dev, &par->nouveau_fb, &mode_cmd, nvbo); + info->par = nfbdev; - fb = &par->nouveau_fb.base; - /* setup helper */ - par->helper.fb = fb; - par->helper.fbdev = info; - par->helper.funcs = &nouveau_fbcon_helper_funcs; - par->helper.dev = dev; + nouveau_framebuffer_init(dev, &nfbdev->nouveau_fb, &mode_cmd, nvbo); - *fbpar_p = par; + nouveau_fb = &nfbdev->nouveau_fb; + fb = &nouveau_fb->base; - ret = drm_fb_helper_init_crtc_count(&par->helper, 2, 4); - if (ret) - goto out_unref; + /* setup helper */ + nfbdev->helper.fb = fb; + nfbdev->helper.fbdev = info; + nfbdev->helper.funcs = &nouveau_fbcon_helper_funcs; strcpy(info->fix.id, "nouveaufb"); if (nouveau_nofbaccel) @@ -305,7 +300,7 @@ nouveau_fbcon_create(struct drm_device *dev, info->screen_size = size; drm_fb_helper_fill_fix(info, fb->pitch, fb->depth); - drm_fb_helper_fill_var(info, &par->helper, sizes->fb_width, sizes->fb_height); + drm_fb_helper_fill_var(info, &nfbdev->helper, sizes->fb_width, sizes->fb_height); /* FIXME: we really shouldn't expose mmio space at all */ info->fix.mmio_start = pci_resource_start(dev->pdev, 1); @@ -338,8 +333,6 @@ nouveau_fbcon_create(struct drm_device *dev, info->pixmap.flags = FB_PIXMAP_SYSTEM; info->pixmap.scan_align = 1; - par->dev = dev; - if (dev_priv->channel && !nouveau_nofbaccel) { switch (dev_priv->card_type) { case NV_50: @@ -353,7 +346,7 @@ nouveau_fbcon_create(struct drm_device *dev, }; } - nouveau_fbcon_zfill(dev, par); + nouveau_fbcon_zfill(dev, nfbdev); /* To allow resizeing without swapping buffers */ NV_INFO(dev, "allocated %dx%d fb: 0x%lx, bo %p\n", @@ -372,66 +365,56 @@ out: } static int -nouveau_fbcon_find_or_create_single(struct drm_device *dev, - struct drm_fb_helper_surface_size *sizes, - struct drm_fb_helper **fb_ptr) +nouveau_fbcon_find_or_create_single(struct drm_fb_helper *helper, + struct drm_fb_helper_surface_size *sizes) { - struct drm_nouveau_private *dev_priv = dev->dev_private; - struct nouveau_fbcon_par *fbpar; + struct nouveau_fbdev *nfbdev = (struct nouveau_fbdev *)helper; int new_fb = 0; int ret; - if (!dev_priv->nfbdev) { - ret = nouveau_fbcon_create(dev, sizes, - &fbpar); + if (!helper->fb) { + ret = nouveau_fbcon_create(nfbdev, sizes); if (ret) return ret; - dev_priv->nfbdev = fbpar; new_fb = 1; - } else { - fbpar = dev_priv->nfbdev; - if (fbpar->nouveau_fb.base.width < sizes->surface_width || - fbpar->nouveau_fb.base.height < sizes->surface_height) { - DRM_ERROR("Framebuffer not large enough to scale console onto.\n"); - return -EINVAL; - } } - *fb_ptr = &fbpar->helper; return new_fb; } static int -nouveau_fbcon_probe(struct drm_device *dev) +nouveau_fbcon_probe(struct nouveau_fbdev *nfbdev) { - NV_DEBUG_KMS(dev, "\n"); + NV_DEBUG_KMS(nfbdev->dev, "\n"); - return drm_fb_helper_single_fb_probe(dev, 32, nouveau_fbcon_find_or_create_single); + return drm_fb_helper_single_fb_probe(&nfbdev->helper, 32); } int -nouveau_fbcon_destroy(struct drm_device *dev, struct nouveau_fbcon_par *fbpar) +nouveau_fbcon_destroy(struct drm_device *dev, struct nouveau_fbdev *nfbdev) { - struct nouveau_framebuffer *nouveau_fb = &fbpar->nouveau_fb; + struct nouveau_framebuffer *nouveau_fb = &nfbdev->nouveau_fb; struct fb_info *info; - info = fbpar->helper.fbdev; - - unregister_framebuffer(info); - nouveau_bo_unmap(nouveau_fb->nvbo); - drm_gem_object_unreference_unlocked(nouveau_fb->nvbo->gem); - nouveau_fb->nvbo = NULL; - drm_fb_helper_free(&fbpar->helper); + if (nfbdev->helper.fbdev) { + info = nfbdev->helper.fbdev; + unregister_framebuffer(info); + framebuffer_release(info); + } + if (nouveau_fb->nvbo) { + nouveau_bo_unmap(nouveau_fb->nvbo); + drm_gem_object_unreference_unlocked(nouveau_fb->nvbo->gem); + nouveau_fb->nvbo = NULL; + } + drm_fb_helper_free(&nfbdev->helper); drm_framebuffer_cleanup(&nouveau_fb->base); - framebuffer_release(info); - return 0; } void nouveau_fbcon_gpu_lockup(struct fb_info *info) { - struct nouveau_fbcon_par *par = info->par; - struct drm_device *dev = par->dev; + struct nouveau_fbdev *nfbdev = info->par; + struct drm_device *dev = nfbdev->dev; NV_ERROR(dev, "GPU lockup - switching to software fbcon\n"); info->flags |= FBINFO_HWACCEL_DISABLED; @@ -439,15 +422,33 @@ void nouveau_fbcon_gpu_lockup(struct fb_info *info) int nouveau_fbcon_init(struct drm_device *dev) { - drm_helper_initial_config(dev); - nouveau_fbcon_probe(dev); + struct drm_nouveau_private *dev_priv = dev->dev_private; + struct nouveau_fbdev *nfbdev; + + nfbdev = kzalloc(sizeof(struct nouveau_fbdev), GFP_KERNEL); + if (!nfbdev) + return -ENOMEM; + + nfbdev->dev = dev; + dev_priv->nfbdev = nfbdev; + + drm_fb_helper_init_crtc_count(dev, &nfbdev->helper, + 2, 4); + nfbdev->helper.fb_probe = nouveau_fbcon_find_or_create_single; + drm_fb_helper_initial_config(&nfbdev->helper); + nouveau_fbcon_probe(nfbdev); return 0; } void nouveau_fbcon_fini(struct drm_device *dev) { struct drm_nouveau_private *dev_priv = dev->dev_private; + + if (!dev_priv->nfbdev) + return; + nouveau_fbcon_destroy(dev, dev_priv->nfbdev); + kfree(dev_priv->nfbdev); dev_priv->nfbdev = NULL; } diff --git a/drivers/gpu/drm/nouveau/nouveau_fbcon.h b/drivers/gpu/drm/nouveau/nouveau_fbcon.h index fa66cb9fa4d4..7835b5685555 100644 --- a/drivers/gpu/drm/nouveau/nouveau_fbcon.h +++ b/drivers/gpu/drm/nouveau/nouveau_fbcon.h @@ -30,7 +30,7 @@ #include "drm_fb_helper.h" #include "nouveau_fb.h" -struct nouveau_fbcon_par { +struct nouveau_fbdev { struct drm_fb_helper helper; struct nouveau_framebuffer nouveau_fb; struct list_head fbdev_list; diff --git a/drivers/gpu/drm/nouveau/nv04_fbcon.c b/drivers/gpu/drm/nouveau/nv04_fbcon.c index 813b25cec726..603090ee6ac7 100644 --- a/drivers/gpu/drm/nouveau/nv04_fbcon.c +++ b/drivers/gpu/drm/nouveau/nv04_fbcon.c @@ -30,8 +30,8 @@ void nv04_fbcon_copyarea(struct fb_info *info, const struct fb_copyarea *region) { - struct nouveau_fbcon_par *par = info->par; - struct drm_device *dev = par->dev; + struct nouveau_fbdev *nfbdev = info->par; + struct drm_device *dev = nfbdev->dev; struct drm_nouveau_private *dev_priv = dev->dev_private; struct nouveau_channel *chan = dev_priv->channel; @@ -57,8 +57,8 @@ nv04_fbcon_copyarea(struct fb_info *info, const struct fb_copyarea *region) void nv04_fbcon_fillrect(struct fb_info *info, const struct fb_fillrect *rect) { - struct nouveau_fbcon_par *par = info->par; - struct drm_device *dev = par->dev; + struct nouveau_fbdev *nfbdev = info->par; + struct drm_device *dev = nfbdev->dev; struct drm_nouveau_private *dev_priv = dev->dev_private; struct nouveau_channel *chan = dev_priv->channel; @@ -91,8 +91,8 @@ nv04_fbcon_fillrect(struct fb_info *info, const struct fb_fillrect *rect) void nv04_fbcon_imageblit(struct fb_info *info, const struct fb_image *image) { - struct nouveau_fbcon_par *par = info->par; - struct drm_device *dev = par->dev; + struct nouveau_fbdev *nfbdev = info->par; + struct drm_device *dev = nfbdev->dev; struct drm_nouveau_private *dev_priv = dev->dev_private; struct nouveau_channel *chan = dev_priv->channel; uint32_t fg; @@ -179,8 +179,8 @@ nv04_fbcon_grobj_new(struct drm_device *dev, int class, uint32_t handle) int nv04_fbcon_accel_init(struct fb_info *info) { - struct nouveau_fbcon_par *par = info->par; - struct drm_device *dev = par->dev; + struct nouveau_fbdev *nfbdev = info->par; + struct drm_device *dev = nfbdev->dev; struct drm_nouveau_private *dev_priv = dev->dev_private; struct nouveau_channel *chan = dev_priv->channel; const int sub = NvSubCtxSurf2D; diff --git a/drivers/gpu/drm/nouveau/nv50_fbcon.c b/drivers/gpu/drm/nouveau/nv50_fbcon.c index 25a3cd8794f9..f2410489cd35 100644 --- a/drivers/gpu/drm/nouveau/nv50_fbcon.c +++ b/drivers/gpu/drm/nouveau/nv50_fbcon.c @@ -6,8 +6,8 @@ void nv50_fbcon_fillrect(struct fb_info *info, const struct fb_fillrect *rect) { - struct nouveau_fbcon_par *par = info->par; - struct drm_device *dev = par->dev; + struct nouveau_fbdev *nfbdev = info->par; + struct drm_device *dev = nfbdev->dev; struct drm_nouveau_private *dev_priv = dev->dev_private; struct nouveau_channel *chan = dev_priv->channel; @@ -49,8 +49,8 @@ nv50_fbcon_fillrect(struct fb_info *info, const struct fb_fillrect *rect) void nv50_fbcon_copyarea(struct fb_info *info, const struct fb_copyarea *region) { - struct nouveau_fbcon_par *par = info->par; - struct drm_device *dev = par->dev; + struct nouveau_fbdev *nfbdev = info->par; + struct drm_device *dev = nfbdev->dev; struct drm_nouveau_private *dev_priv = dev->dev_private; struct nouveau_channel *chan = dev_priv->channel; @@ -84,8 +84,8 @@ nv50_fbcon_copyarea(struct fb_info *info, const struct fb_copyarea *region) void nv50_fbcon_imageblit(struct fb_info *info, const struct fb_image *image) { - struct nouveau_fbcon_par *par = info->par; - struct drm_device *dev = par->dev; + struct nouveau_fbdev *nfbdev = info->par; + struct drm_device *dev = nfbdev->dev; struct drm_nouveau_private *dev_priv = dev->dev_private; struct nouveau_channel *chan = dev_priv->channel; uint32_t width, dwords, *data = (uint32_t *)image->data; @@ -152,8 +152,8 @@ nv50_fbcon_imageblit(struct fb_info *info, const struct fb_image *image) int nv50_fbcon_accel_init(struct fb_info *info) { - struct nouveau_fbcon_par *par = info->par; - struct drm_device *dev = par->dev; + struct nouveau_fbdev *nfbdev = info->par; + struct drm_device *dev = nfbdev->dev; struct drm_nouveau_private *dev_priv = dev->dev_private; struct nouveau_channel *chan = dev_priv->channel; struct nouveau_gpuobj *eng2d = NULL; diff --git a/drivers/gpu/drm/radeon/radeon_fb.c b/drivers/gpu/drm/radeon/radeon_fb.c index a7e4c2a89ee0..705425defba0 100644 --- a/drivers/gpu/drm/radeon/radeon_fb.c +++ b/drivers/gpu/drm/radeon/radeon_fb.c @@ -23,10 +23,6 @@ * Authors: * David Airlie */ - /* - * Modularization - */ - #include #include @@ -45,7 +41,7 @@ this contains a helper + a radeon fb the helper contains a pointer to radeon framebuffer baseclass. */ -struct radeon_kernel_fbdev { +struct radeon_fbdev { struct drm_fb_helper helper; struct radeon_framebuffer rfb; struct list_head fbdev_list; @@ -95,49 +91,44 @@ static struct drm_fb_helper_funcs radeon_fb_helper_funcs = { .gamma_get = radeon_crtc_fb_gamma_get, }; -static int radeonfb_create(struct drm_device *dev, - struct drm_fb_helper_surface_size *sizes, - struct radeon_kernel_fbdev **rfbdev_p) +static void radeonfb_destroy_pinned_object(struct drm_gem_object *gobj) { - struct radeon_device *rdev = dev->dev_private; - struct fb_info *info; - struct radeon_kernel_fbdev *rfbdev; - struct drm_framebuffer *fb = NULL; - struct drm_mode_fb_cmd mode_cmd; + struct radeon_bo *rbo = gobj->driver_private; + int ret; + + ret = radeon_bo_reserve(rbo, false); + if (likely(ret == 0)) { + radeon_bo_kunmap(rbo); + radeon_bo_unreserve(rbo); + } + drm_gem_object_unreference_unlocked(gobj); +} + +static int radeonfb_create_pinned_object(struct radeon_fbdev *rfbdev, + struct drm_mode_fb_cmd *mode_cmd, + struct drm_gem_object **gobj_p) +{ + struct radeon_device *rdev = rfbdev->rdev; struct drm_gem_object *gobj = NULL; struct radeon_bo *rbo = NULL; - struct device *device = &rdev->pdev->dev; - int size, aligned_size, ret; - u64 fb_gpuaddr; - void *fbptr = NULL; - unsigned long tmp; bool fb_tiled = false; /* useful for testing */ u32 tiling_flags = 0; + int ret; + int aligned_size, size; - mode_cmd.width = sizes->surface_width; - mode_cmd.height = sizes->surface_height; - - /* avivo can't scanout real 24bpp */ - if ((sizes->surface_bpp == 24) && ASIC_IS_AVIVO(rdev)) - sizes->surface_bpp = 32; - - mode_cmd.bpp = sizes->surface_bpp; /* need to align pitch with crtc limits */ - mode_cmd.pitch = radeon_align_pitch(rdev, mode_cmd.width, mode_cmd.bpp, fb_tiled) * ((mode_cmd.bpp + 1) / 8); - mode_cmd.depth = sizes->surface_depth; + mode_cmd->pitch = radeon_align_pitch(rdev, mode_cmd->width, mode_cmd->bpp, fb_tiled) * ((mode_cmd->bpp + 1) / 8); - size = mode_cmd.pitch * mode_cmd.height; + size = mode_cmd->pitch * mode_cmd->height; aligned_size = ALIGN(size, PAGE_SIZE); - ret = radeon_gem_object_create(rdev, aligned_size, 0, - RADEON_GEM_DOMAIN_VRAM, - false, ttm_bo_type_kernel, - &gobj); + RADEON_GEM_DOMAIN_VRAM, + false, ttm_bo_type_kernel, + &gobj); if (ret) { - printk(KERN_ERR "failed to allocate framebuffer (%d %d)\n", - sizes->surface_width, sizes->surface_height); - ret = -ENOMEM; - goto out; + printk(KERN_ERR "failed to allocate framebuffer (%d)\n", + aligned_size); + return -ENOMEM; } rbo = gobj->driver_private; @@ -145,7 +136,7 @@ static int radeonfb_create(struct drm_device *dev, tiling_flags = RADEON_TILING_MACRO; #ifdef __BIG_ENDIAN - switch (mode_cmd.bpp) { + switch (mode_cmd->bpp) { case 32: tiling_flags |= RADEON_TILING_SWAP_32BIT; break; @@ -158,54 +149,82 @@ static int radeonfb_create(struct drm_device *dev, if (tiling_flags) { ret = radeon_bo_set_tiling_flags(rbo, - tiling_flags | RADEON_TILING_SURFACE, - mode_cmd.pitch); + tiling_flags | RADEON_TILING_SURFACE, + mode_cmd->pitch); if (ret) dev_err(rdev->dev, "FB failed to set tiling flags\n"); } - mutex_lock(&rdev->ddev->struct_mutex); + ret = radeon_bo_reserve(rbo, false); if (unlikely(ret != 0)) goto out_unref; - ret = radeon_bo_pin(rbo, RADEON_GEM_DOMAIN_VRAM, &fb_gpuaddr); + ret = radeon_bo_pin(rbo, RADEON_GEM_DOMAIN_VRAM, NULL); if (ret) { radeon_bo_unreserve(rbo); goto out_unref; } if (fb_tiled) radeon_bo_check_tiling(rbo, 0, 0); - ret = radeon_bo_kmap(rbo, &fbptr); + ret = radeon_bo_kmap(rbo, NULL); radeon_bo_unreserve(rbo); if (ret) { goto out_unref; } - info = framebuffer_alloc(sizeof(struct radeon_kernel_fbdev), device); + *gobj_p = gobj; + return 0; +out_unref: + radeonfb_destroy_pinned_object(gobj); + *gobj_p = NULL; + return ret; +} + +static int radeonfb_create(struct radeon_fbdev *rfbdev, + struct drm_fb_helper_surface_size *sizes) +{ + struct radeon_device *rdev = rfbdev->rdev; + struct fb_info *info; + struct drm_framebuffer *fb = NULL; + struct drm_mode_fb_cmd mode_cmd; + struct drm_gem_object *gobj = NULL; + struct radeon_bo *rbo = NULL; + struct device *device = &rdev->pdev->dev; + int ret; + unsigned long tmp; + + mode_cmd.width = sizes->surface_width; + mode_cmd.height = sizes->surface_height; + + /* avivo can't scanout real 24bpp */ + if ((sizes->surface_bpp == 24) && ASIC_IS_AVIVO(rdev)) + sizes->surface_bpp = 32; + + mode_cmd.bpp = sizes->surface_bpp; + mode_cmd.depth = sizes->surface_depth; + + ret = radeonfb_create_pinned_object(rfbdev, &mode_cmd, &gobj); + rbo = gobj->driver_private; + + /* okay we have an object now allocate the framebuffer */ + info = framebuffer_alloc(0, device); if (info == NULL) { ret = -ENOMEM; goto out_unref; } - rfbdev = info->par; - rfbdev->rdev = rdev; - radeon_framebuffer_init(dev, &rfbdev->rfb, &mode_cmd, gobj); + info->par = rfbdev; + + radeon_framebuffer_init(rdev->ddev, &rfbdev->rfb, &mode_cmd, gobj); + fb = &rfbdev->rfb.base; /* setup helper */ rfbdev->helper.fb = fb; rfbdev->helper.fbdev = info; rfbdev->helper.funcs = &radeon_fb_helper_funcs; - rfbdev->helper.dev = dev; - - *rfbdev_p = rfbdev; - ret = drm_fb_helper_init_crtc_count(&rfbdev->helper, rdev->num_crtc, - RADEONFB_CONN_LIMIT); - if (ret) - goto out_unref; - - memset_io(fbptr, 0x0, aligned_size); + memset_io(rbo->kptr, 0x0, radeon_bo_size(rbo)); strcpy(info->fix.id, "radeondrmfb"); @@ -214,11 +233,11 @@ static int radeonfb_create(struct drm_device *dev, info->flags = FBINFO_DEFAULT; info->fbops = &radeonfb_ops; - tmp = fb_gpuaddr - rdev->mc.vram_start; + tmp = radeon_bo_gpu_offset(rbo) - rdev->mc.vram_start; info->fix.smem_start = rdev->mc.aper_base + tmp; - info->fix.smem_len = size; - info->screen_base = fbptr; - info->screen_size = size; + info->fix.smem_len = radeon_bo_size(rbo); + info->screen_base = rbo->kptr; + info->screen_size = radeon_bo_size(rbo); drm_fb_helper_fill_var(info, &rfbdev->helper, sizes->fb_width, sizes->fb_height); @@ -239,60 +258,40 @@ static int radeonfb_create(struct drm_device *dev, } DRM_INFO("fb mappable at 0x%lX\n", info->fix.smem_start); DRM_INFO("vram apper at 0x%lX\n", (unsigned long)rdev->mc.aper_base); - DRM_INFO("size %lu\n", (unsigned long)size); + DRM_INFO("size %lu\n", (unsigned long)radeon_bo_size(rbo)); DRM_INFO("fb depth is %d\n", fb->depth); DRM_INFO(" pitch is %d\n", fb->pitch); - - mutex_unlock(&rdev->ddev->struct_mutex); vga_switcheroo_client_fb_set(rdev->ddev->pdev, info); return 0; out_unref: if (rbo) { - ret = radeon_bo_reserve(rbo, false); - if (likely(ret == 0)) { - radeon_bo_kunmap(rbo); - radeon_bo_unreserve(rbo); - } + } if (fb && ret) { drm_gem_object_unreference(gobj); drm_framebuffer_cleanup(fb); kfree(fb); } - drm_gem_object_unreference(gobj); - mutex_unlock(&rdev->ddev->struct_mutex); + out: return ret; } -static int radeon_fb_find_or_create_single(struct drm_device *dev, - struct drm_fb_helper_surface_size *sizes, - struct drm_fb_helper **fb_ptr) +static int radeon_fb_find_or_create_single(struct drm_fb_helper *helper, + struct drm_fb_helper_surface_size *sizes) { - struct radeon_device *rdev = dev->dev_private; - struct radeon_kernel_fbdev *rfbdev = NULL; + struct radeon_fbdev *rfbdev = (struct radeon_fbdev *)helper; int new_fb = 0; int ret; - if (!rdev->mode_info.rfbdev) { - ret = radeonfb_create(dev, sizes, - &rfbdev); + if (!helper->fb) { + ret = radeonfb_create(rfbdev, sizes); if (ret) return ret; - rdev->mode_info.rfbdev = rfbdev; new_fb = 1; - } else { - rfbdev = rdev->mode_info.rfbdev; - if (rfbdev->rfb.base.width < sizes->surface_width || - rfbdev->rfb.base.height < sizes->surface_height) { - DRM_ERROR("Framebuffer not large enough to scale console onto.\n"); - return -EINVAL; - } } - - *fb_ptr = &rfbdev->helper; return new_fb; } @@ -312,48 +311,55 @@ int radeon_parse_options(char *options) return 0; } -static int radeonfb_probe(struct drm_device *dev) +static int radeonfb_probe(struct radeon_fbdev *rfbdev) { - struct radeon_device *rdev = dev->dev_private; + struct radeon_device *rdev = rfbdev->rdev; int bpp_sel = 32; /* select 8 bpp console on RN50 or 16MB cards */ if (ASIC_IS_RN50(rdev) || rdev->mc.real_vram_size <= (32*1024*1024)) bpp_sel = 8; - return drm_fb_helper_single_fb_probe(dev, bpp_sel, &radeon_fb_find_or_create_single); + return drm_fb_helper_single_fb_probe(&rfbdev->helper, bpp_sel); } void radeonfb_hotplug(struct drm_device *dev) { - drm_helper_fb_hotplug_event(dev); + struct radeon_device *rdev = dev->dev_private; + int max_width, max_height; + + max_width = rdev->mode_info.rfbdev->rfb.base.width; + max_height = rdev->mode_info.rfbdev->rfb.base.height; + drm_helper_fb_hotplug_event(&rdev->mode_info.rfbdev->helper, max_width, max_height); - radeonfb_probe(dev); + radeonfb_probe(rdev->mode_info.rfbdev); } -static int radeon_fbdev_destroy(struct drm_device *dev, struct radeon_kernel_fbdev *rfbdev) +static int radeon_fbdev_destroy(struct drm_device *dev, struct radeon_fbdev *rfbdev) { struct fb_info *info; struct radeon_framebuffer *rfb = &rfbdev->rfb; struct radeon_bo *rbo; int r; - rbo = rfb->obj->driver_private; - info = rfbdev->helper.fbdev; - unregister_framebuffer(info); - r = radeon_bo_reserve(rbo, false); - if (likely(r == 0)) { - radeon_bo_kunmap(rbo); - radeon_bo_unpin(rbo); - radeon_bo_unreserve(rbo); + if (rfbdev->helper.fbdev) { + info = rfbdev->helper.fbdev; + unregister_framebuffer(info); + framebuffer_release(info); } + if (rfb->obj) { + rbo = rfb->obj->driver_private; + r = radeon_bo_reserve(rbo, false); + if (likely(r == 0)) { + radeon_bo_kunmap(rbo); + radeon_bo_unpin(rbo); + radeon_bo_unreserve(rbo); + } + drm_gem_object_unreference_unlocked(rfb->obj); + } drm_fb_helper_free(&rfbdev->helper); drm_framebuffer_cleanup(&rfb->base); - if (rfb->obj) - drm_gem_object_unreference_unlocked(rfb->obj); - - framebuffer_release(info); return 0; } @@ -361,14 +367,32 @@ MODULE_LICENSE("GPL"); int radeon_fbdev_init(struct radeon_device *rdev) { - drm_helper_initial_config(rdev->ddev); - radeonfb_probe(rdev->ddev); + struct radeon_fbdev *rfbdev; + + rfbdev = kzalloc(sizeof(struct radeon_fbdev), GFP_KERNEL); + if (!rfbdev) + return -ENOMEM; + + rfbdev->rdev = rdev; + rdev->mode_info.rfbdev = rfbdev; + + drm_fb_helper_init_crtc_count(rdev->ddev, &rfbdev->helper, + rdev->num_crtc, + RADEONFB_CONN_LIMIT); + rfbdev->helper.fb_probe = radeon_fb_find_or_create_single; + drm_fb_helper_initial_config(&rfbdev->helper); + radeonfb_probe(rfbdev); return 0; + } void radeon_fbdev_fini(struct radeon_device *rdev) { + if (!rdev->mode_info.rfbdev) + return; + radeon_fbdev_destroy(rdev->ddev, rdev->mode_info.rfbdev); + kfree(rdev->mode_info.rfbdev); rdev->mode_info.rfbdev = NULL; } diff --git a/drivers/gpu/drm/radeon/radeon_mode.h b/drivers/gpu/drm/radeon/radeon_mode.h index 1e9138bf5592..165f6025a3bc 100644 --- a/drivers/gpu/drm/radeon/radeon_mode.h +++ b/drivers/gpu/drm/radeon/radeon_mode.h @@ -203,7 +203,7 @@ enum radeon_dvo_chip { DVO_SIL1178, }; -struct radeon_kernel_fbdev; +struct radeon_fbdev; struct radeon_mode_info { struct atom_context *atom_context; @@ -223,7 +223,7 @@ struct radeon_mode_info { struct edid *bios_hardcoded_edid; /* pointer to fbdev info structure */ - struct radeon_kernel_fbdev *rfbdev; + struct radeon_fbdev *rfbdev; }; #define MAX_H_CODE_TIMING_LEN 32 diff --git a/include/drm/drm_crtc.h b/include/drm/drm_crtc.h index c70814b184e8..e4e34bae22cd 100644 --- a/include/drm/drm_crtc.h +++ b/include/drm/drm_crtc.h @@ -367,9 +367,6 @@ struct drm_crtc_funcs { * @enabled: is this CRTC enabled? * @x: x position on screen * @y: y position on screen - * @desired_mode: new desired mode - * @desired_x: desired x for desired_mode - * @desired_y: desired y for desired_mode * @funcs: CRTC control functions * * Each CRTC may have one or more connectors associated with it. This structure @@ -389,8 +386,6 @@ struct drm_crtc { struct drm_display_mode mode; int x, y; - struct drm_display_mode *desired_mode; - int desired_x, desired_y; const struct drm_crtc_funcs *funcs; /* CRTC gamma size for reporting to userspace */ diff --git a/include/drm/drm_fb_helper.h b/include/drm/drm_fb_helper.h index 38ab0daffd1f..b1ea66f11ded 100644 --- a/include/drm/drm_fb_helper.h +++ b/include/drm/drm_fb_helper.h @@ -33,6 +33,7 @@ struct drm_fb_helper_crtc { uint32_t crtc_id; struct drm_mode_set mode_set; + struct drm_display_mode *desired_mode; }; @@ -81,14 +82,16 @@ struct drm_fb_helper { struct fb_info *fbdev; u32 pseudo_palette[17]; struct list_head kernel_fb_list; + + int (*fb_probe)(struct drm_fb_helper *helper, + struct drm_fb_helper_surface_size *sizes); }; -int drm_fb_helper_single_fb_probe(struct drm_device *dev, - int preferred_bpp, - int (*fb_create)(struct drm_device *dev, - struct drm_fb_helper_surface_size *sizes, - struct drm_fb_helper **fb_ptr)); -int drm_fb_helper_init_crtc_count(struct drm_fb_helper *helper, int crtc_count, +int drm_fb_helper_single_fb_probe(struct drm_fb_helper *helper, + int preferred_bpp); + +int drm_fb_helper_init_crtc_count(struct drm_device *dev, + struct drm_fb_helper *helper, int crtc_count, int max_conn); void drm_fb_helper_free(struct drm_fb_helper *helper); int drm_fb_helper_blank(int blank, struct fb_info *info); @@ -114,6 +117,8 @@ int drm_fb_helper_add_connector(struct drm_connector *connector); int drm_fb_helper_parse_command_line(struct drm_device *dev); int drm_fb_helper_setcmap(struct fb_cmap *cmap, struct fb_info *info); -bool drm_helper_fb_hotplug_event(struct drm_device *dev); -bool drm_helper_initial_config(struct drm_device *dev); +bool drm_helper_fb_hotplug_event(struct drm_fb_helper *fb_helper, u32 max_width, + u32 max_height); +bool drm_fb_helper_initial_config(struct drm_fb_helper *fb_helper); + #endif -- cgit v1.2.3 From 0b4c0f3f0eceacb691e2b5570d9b16d751ce1b48 Mon Sep 17 00:00:00 2001 From: Dave Airlie Date: Tue, 30 Mar 2010 05:34:15 +0000 Subject: drm/kms/fb: separate fbdev connector list from core drm connectors This breaks the connection between the core drm connector list and the fbdev connector usage, and allows them to become disjoint in the future. It also removes the untype void* that was in the connector struct to support this. All connectors are added to the fbdev now but this could be changed in the future. Signed-off-by: Dave Airlie --- drivers/gpu/drm/drm_crtc.c | 1 - drivers/gpu/drm/drm_fb_helper.c | 196 +++++++++++++++-------------- drivers/gpu/drm/i915/intel_fb.c | 1 + drivers/gpu/drm/nouveau/nouveau_fbcon.c | 2 + drivers/gpu/drm/radeon/radeon_connectors.c | 50 ++------ drivers/gpu/drm/radeon/radeon_fb.c | 5 +- include/drm/drm_crtc.h | 1 - include/drm/drm_crtc_helper.h | 5 +- include/drm/drm_fb_helper.h | 6 +- 9 files changed, 126 insertions(+), 141 deletions(-) (limited to 'drivers/gpu/drm/radeon') diff --git a/drivers/gpu/drm/drm_crtc.c b/drivers/gpu/drm/drm_crtc.c index 6a472d534522..e8cd6832f08e 100644 --- a/drivers/gpu/drm/drm_crtc.c +++ b/drivers/gpu/drm/drm_crtc.c @@ -493,7 +493,6 @@ void drm_connector_cleanup(struct drm_connector *connector) list_for_each_entry_safe(mode, t, &connector->user_modes, head) drm_mode_remove(connector, mode); - kfree(connector->fb_helper_private); mutex_lock(&dev->mode_config.mutex); drm_mode_object_put(dev, &connector->base); list_del(&connector->head); diff --git a/drivers/gpu/drm/drm_fb_helper.c b/drivers/gpu/drm/drm_fb_helper.c index 2515563063ce..9808f6e37a9d 100644 --- a/drivers/gpu/drm/drm_fb_helper.c +++ b/drivers/gpu/drm/drm_fb_helper.c @@ -41,15 +41,33 @@ MODULE_LICENSE("GPL and additional rights"); static LIST_HEAD(kernel_fb_helper_list); -int drm_fb_helper_add_connector(struct drm_connector *connector) +/* simple single crtc case helper function */ +int drm_fb_helper_single_add_all_connectors(struct drm_fb_helper *fb_helper) { - connector->fb_helper_private = kzalloc(sizeof(struct drm_fb_helper_connector), GFP_KERNEL); - if (!connector->fb_helper_private) - return -ENOMEM; + struct drm_device *dev = fb_helper->dev; + struct drm_connector *connector; + int i; + + list_for_each_entry(connector, &dev->mode_config.connector_list, head) { + struct drm_fb_helper_connector *fb_helper_connector; + + fb_helper_connector = kzalloc(sizeof(struct drm_fb_helper_connector), GFP_KERNEL); + if (!fb_helper_connector) + goto fail; + fb_helper_connector->connector = connector; + fb_helper->connector_info[fb_helper->connector_count++] = fb_helper_connector; + } return 0; +fail: + for (i = 0; i < fb_helper->connector_count; i++) { + kfree(fb_helper->connector_info[i]); + fb_helper->connector_info[i] = NULL; + } + fb_helper->connector_count = 0; + return -ENOMEM; } -EXPORT_SYMBOL(drm_fb_helper_add_connector); +EXPORT_SYMBOL(drm_fb_helper_single_add_all_connectors); /** * drm_fb_helper_connector_parse_command_line - parse command line for connector @@ -64,7 +82,7 @@ EXPORT_SYMBOL(drm_fb_helper_add_connector); * * enable/enable Digital/disable bit at the end */ -static bool drm_fb_helper_connector_parse_command_line(struct drm_connector *connector, +static bool drm_fb_helper_connector_parse_command_line(struct drm_fb_helper_connector *fb_helper_conn, const char *mode_option) { const char *name; @@ -74,13 +92,13 @@ static bool drm_fb_helper_connector_parse_command_line(struct drm_connector *con int yres_specified = 0, cvt = 0, rb = 0, interlace = 0, margins = 0; int i; enum drm_connector_force force = DRM_FORCE_UNSPECIFIED; - struct drm_fb_helper_connector *fb_help_conn = connector->fb_helper_private; struct drm_fb_helper_cmdline_mode *cmdline_mode; + struct drm_connector *connector = fb_helper_conn->connector; - if (!fb_help_conn) + if (!fb_helper_conn) return false; - cmdline_mode = &fb_help_conn->cmdline_mode; + cmdline_mode = &fb_helper_conn->cmdline_mode; if (!mode_option) mode_option = fb_mode_option; @@ -203,18 +221,21 @@ done: return true; } -int drm_fb_helper_parse_command_line(struct drm_device *dev) +static int drm_fb_helper_parse_command_line(struct drm_fb_helper *fb_helper) { - struct drm_connector *connector; + struct drm_fb_helper_connector *fb_helper_conn; + int i; - list_for_each_entry(connector, &dev->mode_config.connector_list, head) { + for (i = 0; i < fb_helper->connector_count; i++) { char *option = NULL; + fb_helper_conn = fb_helper->connector_info[i]; + /* do something on return - turn off connector maybe */ - if (fb_get_options(drm_get_connector_name(connector), &option)) + if (fb_get_options(drm_get_connector_name(fb_helper_conn->connector), &option)) continue; - drm_fb_helper_connector_parse_command_line(connector, option); + drm_fb_helper_connector_parse_command_line(fb_helper_conn, option); } return 0; } @@ -391,6 +412,9 @@ static void drm_fb_helper_crtc_free(struct drm_fb_helper *helper) { int i; + for (i = 0; i < helper->connector_count; i++) + kfree(helper->connector_info[i]); + kfree(helper->connector_info); for (i = 0; i < helper->crtc_count; i++) kfree(helper->crtc_info[i].mode_set.connectors); kfree(helper->crtc_info); @@ -411,6 +435,13 @@ int drm_fb_helper_init_crtc_count(struct drm_device *dev, return -ENOMEM; helper->crtc_count = crtc_count; + helper->connector_info = kcalloc(dev->mode_config.num_connector, sizeof(struct drm_fb_helper_connector *), GFP_KERNEL); + if (!helper->connector_info) { + kfree(helper->crtc_info); + return -ENOMEM; + } + helper->connector_count = 0; + for (i = 0; i < crtc_count; i++) { helper->crtc_info[i].mode_set.connectors = kcalloc(max_conn_count, @@ -672,14 +703,10 @@ int drm_fb_helper_set_par(struct fb_info *info) mutex_lock(&dev->mode_config.mutex); for (i = 0; i < fb_helper->crtc_count; i++) { crtc = fb_helper->crtc_info[i].mode_set.crtc; - - if (crtc->fb != fb_helper->crtc_info[i].mode_set.fb) { - ret = crtc->funcs->set_config(&fb_helper->crtc_info[i].mode_set); - - if (ret) { - mutex_unlock(&dev->mode_config.mutex); - return ret; - } + ret = crtc->funcs->set_config(&fb_helper->crtc_info[i].mode_set); + if (ret) { + mutex_unlock(&dev->mode_config.mutex); + return ret; } } mutex_unlock(&dev->mode_config.mutex); @@ -722,8 +749,6 @@ EXPORT_SYMBOL(drm_fb_helper_pan_display); int drm_fb_helper_single_fb_probe(struct drm_fb_helper *fb_helper, int preferred_bpp) { - struct drm_device *dev = fb_helper->dev; - struct drm_connector *connector; int new_fb = 0; int crtc_count = 0; int ret, i; @@ -743,14 +768,11 @@ int drm_fb_helper_single_fb_probe(struct drm_fb_helper *fb_helper, sizes.surface_depth = sizes.surface_bpp = preferred_bpp; } /* first up get a count of crtcs now in use and new min/maxes width/heights */ - list_for_each_entry(connector, &dev->mode_config.connector_list, head) { - struct drm_fb_helper_connector *fb_help_conn = connector->fb_helper_private; + for (i = 0; i < fb_helper->connector_count; i++) { + struct drm_fb_helper_connector *fb_helper_conn = fb_helper->connector_info[i]; struct drm_fb_helper_cmdline_mode *cmdline_mode; - if (!fb_help_conn) - continue; - - cmdline_mode = &fb_help_conn->cmdline_mode; + cmdline_mode = &fb_helper_conn->cmdline_mode; if (cmdline_mode->bpp_specified) { switch (cmdline_mode->bpp) { @@ -954,24 +976,27 @@ void drm_fb_helper_fill_var(struct fb_info *info, struct drm_fb_helper *fb_helpe } EXPORT_SYMBOL(drm_fb_helper_fill_var); -static int drm_helper_probe_connector_modes(struct drm_device *dev, uint32_t maxX, - uint32_t maxY) +static int drm_fb_helper_probe_connector_modes(struct drm_fb_helper *fb_helper, + uint32_t maxX, + uint32_t maxY) { struct drm_connector *connector; int count = 0; + int i; - list_for_each_entry(connector, &dev->mode_config.connector_list, head) { + for (i = 0; i < fb_helper->connector_count; i++) { + connector = fb_helper->connector_info[i]->connector; count += connector->funcs->fill_modes(connector, maxX, maxY); } return count; } -static struct drm_display_mode *drm_has_preferred_mode(struct drm_connector *connector, int width, int height) +static struct drm_display_mode *drm_has_preferred_mode(struct drm_fb_helper_connector *fb_connector, int width, int height) { struct drm_display_mode *mode; - list_for_each_entry(mode, &connector->modes, head) { + list_for_each_entry(mode, &fb_connector->connector->modes, head) { if (drm_mode_width(mode) > width || drm_mode_height(mode) > height) continue; @@ -981,28 +1006,20 @@ static struct drm_display_mode *drm_has_preferred_mode(struct drm_connector *con return NULL; } -static bool drm_has_cmdline_mode(struct drm_connector *connector) +static bool drm_has_cmdline_mode(struct drm_fb_helper_connector *fb_connector) { - struct drm_fb_helper_connector *fb_help_conn = connector->fb_helper_private; struct drm_fb_helper_cmdline_mode *cmdline_mode; - - if (!fb_help_conn) - return false; - - cmdline_mode = &fb_help_conn->cmdline_mode; + cmdline_mode = &fb_connector->cmdline_mode; return cmdline_mode->specified; } -static struct drm_display_mode *drm_pick_cmdline_mode(struct drm_connector *connector, int width, int height) +static struct drm_display_mode *drm_pick_cmdline_mode(struct drm_fb_helper_connector *fb_helper_conn, + int width, int height) { - struct drm_fb_helper_connector *fb_help_conn = connector->fb_helper_private; struct drm_fb_helper_cmdline_mode *cmdline_mode; struct drm_display_mode *mode = NULL; - if (!fb_help_conn) - return mode; - - cmdline_mode = &fb_help_conn->cmdline_mode; + cmdline_mode = &fb_helper_conn->cmdline_mode; if (cmdline_mode->specified == false) return mode; @@ -1012,7 +1029,7 @@ static struct drm_display_mode *drm_pick_cmdline_mode(struct drm_connector *conn if (cmdline_mode->rb || cmdline_mode->margins) goto create_mode; - list_for_each_entry(mode, &connector->modes, head) { + list_for_each_entry(mode, &fb_helper_conn->connector->modes, head) { /* check width/height */ if (mode->hdisplay != cmdline_mode->xres || mode->vdisplay != cmdline_mode->yres) @@ -1031,13 +1048,13 @@ static struct drm_display_mode *drm_pick_cmdline_mode(struct drm_connector *conn } create_mode: - mode = drm_cvt_mode(connector->dev, cmdline_mode->xres, + mode = drm_cvt_mode(fb_helper_conn->connector->dev, cmdline_mode->xres, cmdline_mode->yres, cmdline_mode->refresh_specified ? cmdline_mode->refresh : 60, cmdline_mode->rb, cmdline_mode->interlace, cmdline_mode->margins); drm_mode_set_crtcinfo(mode, CRTC_INTERLACE_HALVE_V); - list_add(&mode->head, &connector->modes); + list_add(&mode->head, &fb_helper_conn->connector->modes); return mode; } @@ -1053,62 +1070,60 @@ static bool drm_connector_enabled(struct drm_connector *connector, bool strict) return enable; } -static void drm_enable_connectors(struct drm_device *dev, bool *enabled) +static void drm_enable_connectors(struct drm_fb_helper *fb_helper, + bool *enabled) { bool any_enabled = false; struct drm_connector *connector; int i = 0; - list_for_each_entry(connector, &dev->mode_config.connector_list, head) { + for (i = 0; i < fb_helper->connector_count; i++) { + connector = fb_helper->connector_info[i]->connector; enabled[i] = drm_connector_enabled(connector, true); DRM_DEBUG_KMS("connector %d enabled? %s\n", connector->base.id, enabled[i] ? "yes" : "no"); any_enabled |= enabled[i]; - i++; } if (any_enabled) return; - i = 0; - list_for_each_entry(connector, &dev->mode_config.connector_list, head) { + for (i = 0; i < fb_helper->connector_count; i++) { + connector = fb_helper->connector_info[i]->connector; enabled[i] = drm_connector_enabled(connector, false); - i++; } } -static bool drm_target_preferred(struct drm_device *dev, +static bool drm_target_preferred(struct drm_fb_helper *fb_helper, struct drm_display_mode **modes, bool *enabled, int width, int height) { - struct drm_connector *connector; - int i = 0; + struct drm_fb_helper_connector *fb_helper_conn; + int i; - list_for_each_entry(connector, &dev->mode_config.connector_list, head) { + for (i = 0; i < fb_helper->connector_count; i++) { + fb_helper_conn = fb_helper->connector_info[i]; - if (enabled[i] == false) { - i++; + if (enabled[i] == false) continue; - } DRM_DEBUG_KMS("looking for cmdline mode on connector %d\n", - connector->base.id); + fb_helper_conn->connector->base.id); /* got for command line mode first */ - modes[i] = drm_pick_cmdline_mode(connector, width, height); + modes[i] = drm_pick_cmdline_mode(fb_helper_conn, width, height); if (!modes[i]) { DRM_DEBUG_KMS("looking for preferred mode on connector %d\n", - connector->base.id); - modes[i] = drm_has_preferred_mode(connector, width, height); + fb_helper_conn->connector->base.id); + modes[i] = drm_has_preferred_mode(fb_helper_conn, width, height); } /* No preferred modes, pick one off the list */ - if (!modes[i] && !list_empty(&connector->modes)) { - list_for_each_entry(modes[i], &connector->modes, head) + if (!modes[i] && !list_empty(&fb_helper_conn->connector->modes)) { + list_for_each_entry(modes[i], &fb_helper_conn->connector->modes, head) break; } DRM_DEBUG_KMS("found mode %s\n", modes[i] ? modes[i]->name : "none"); - i++; } return true; } @@ -1126,15 +1141,13 @@ static int drm_pick_crtcs(struct drm_fb_helper *fb_helper, struct drm_fb_helper_crtc *best_crtc; int my_score, best_score, score; struct drm_fb_helper_crtc **crtcs, *crtc; + struct drm_fb_helper_connector *fb_helper_conn; - if (n == fb_helper->dev->mode_config.num_connector) + if (n == fb_helper->connector_count) return 0; - c = 0; - list_for_each_entry(connector, &dev->mode_config.connector_list, head) { - if (c == n) - break; - c++; - } + + fb_helper_conn = fb_helper->connector_info[n]; + connector = fb_helper_conn->connector; best_crtcs[n] = NULL; best_crtc = NULL; @@ -1150,9 +1163,9 @@ static int drm_pick_crtcs(struct drm_fb_helper *fb_helper, my_score = 1; if (connector->status == connector_status_connected) my_score++; - if (drm_has_cmdline_mode(connector)) + if (drm_has_cmdline_mode(fb_helper_conn)) my_score++; - if (drm_has_preferred_mode(connector, width, height)) + if (drm_has_preferred_mode(fb_helper_conn, width, height)) my_score++; connector_funcs = connector->helper_private; @@ -1201,7 +1214,6 @@ static void drm_setup_crtcs(struct drm_fb_helper *fb_helper) struct drm_fb_helper_crtc **crtcs; struct drm_display_mode **modes; struct drm_encoder *encoder; - struct drm_connector *connector; struct drm_mode_set *modeset; bool *enabled; int width, height; @@ -1224,9 +1236,9 @@ static void drm_setup_crtcs(struct drm_fb_helper *fb_helper) enabled = kcalloc(dev->mode_config.num_connector, sizeof(bool), GFP_KERNEL); - drm_enable_connectors(dev, enabled); + drm_enable_connectors(fb_helper, enabled); - ret = drm_target_preferred(dev, modes, enabled, width, height); + ret = drm_target_preferred(fb_helper, modes, enabled, width, height); if (!ret) DRM_ERROR("Unable to find initial modes\n"); @@ -1241,8 +1253,7 @@ static void drm_setup_crtcs(struct drm_fb_helper *fb_helper) modeset->num_connectors = 0; } - i = 0; - list_for_each_entry(connector, &dev->mode_config.connector_list, head) { + for (i = 0; i < fb_helper->connector_count; i++) { struct drm_display_mode *mode = modes[i]; struct drm_fb_helper_crtc *fb_crtc = crtcs[i]; modeset = &fb_crtc->mode_set; @@ -1255,9 +1266,8 @@ static void drm_setup_crtcs(struct drm_fb_helper *fb_helper) drm_mode_destroy(dev, modeset->mode); modeset->mode = drm_mode_duplicate(dev, fb_crtc->desired_mode); - modeset->connectors[modeset->num_connectors++] = connector; + modeset->connectors[modeset->num_connectors++] = fb_helper->connector_info[i]->connector; } - i++; } kfree(crtcs); @@ -1287,11 +1297,11 @@ bool drm_fb_helper_initial_config(struct drm_fb_helper *fb_helper) /* disable all the possible outputs/crtcs before entering KMS mode */ drm_helper_disable_unused_functions(fb_helper->dev); - drm_fb_helper_parse_command_line(fb_helper->dev); + drm_fb_helper_parse_command_line(fb_helper); - count = drm_helper_probe_connector_modes(dev, - dev->mode_config.max_width, - dev->mode_config.max_height); + count = drm_fb_helper_probe_connector_modes(fb_helper, + dev->mode_config.max_width, + dev->mode_config.max_height); /* * we shouldn't end up with no modes here. @@ -1310,8 +1320,8 @@ bool drm_helper_fb_hotplug_event(struct drm_fb_helper *fb_helper, { DRM_DEBUG_KMS("\n"); - drm_helper_probe_connector_modes(fb_helper->dev, max_width, - max_height); + drm_fb_helper_probe_connector_modes(fb_helper, max_width, + max_height); drm_setup_crtcs(fb_helper); diff --git a/drivers/gpu/drm/i915/intel_fb.c b/drivers/gpu/drm/i915/intel_fb.c index ff6912edf0c6..8f7a7c476098 100644 --- a/drivers/gpu/drm/i915/intel_fb.c +++ b/drivers/gpu/drm/i915/intel_fb.c @@ -249,6 +249,7 @@ int intel_fbdev_init(struct drm_device *dev) drm_fb_helper_init_crtc_count(dev, &ifbdev->helper, 2, INTELFB_CONN_LIMIT); + drm_fb_helper_single_add_all_connectors(&ifbdev->helper); ifbdev->helper.fb_probe = intel_fb_find_or_create_single; drm_fb_helper_initial_config(&ifbdev->helper); intelfb_probe(ifbdev); diff --git a/drivers/gpu/drm/nouveau/nouveau_fbcon.c b/drivers/gpu/drm/nouveau/nouveau_fbcon.c index 90843b62d9b1..fd5d3cde0a07 100644 --- a/drivers/gpu/drm/nouveau/nouveau_fbcon.c +++ b/drivers/gpu/drm/nouveau/nouveau_fbcon.c @@ -435,6 +435,8 @@ int nouveau_fbcon_init(struct drm_device *dev) drm_fb_helper_init_crtc_count(dev, &nfbdev->helper, 2, 4); nfbdev->helper.fb_probe = nouveau_fbcon_find_or_create_single; + drm_fb_helper_single_add_all_connectors(&nfbdev->helper); + drm_fb_helper_initial_config(&nfbdev->helper); nouveau_fbcon_probe(nfbdev); return 0; diff --git a/drivers/gpu/drm/radeon/radeon_connectors.c b/drivers/gpu/drm/radeon/radeon_connectors.c index 3fba50540f72..47bd98521bec 100644 --- a/drivers/gpu/drm/radeon/radeon_connectors.c +++ b/drivers/gpu/drm/radeon/radeon_connectors.c @@ -1032,7 +1032,6 @@ radeon_add_atom_connector(struct drm_device *dev, struct radeon_connector_atom_dig *radeon_dig_connector; uint32_t subpixel_order = SubPixelNone; bool shared_ddc = false; - int ret; /* fixme - tv/cv/din */ if (connector_type == DRM_MODE_CONNECTOR_Unknown) @@ -1067,9 +1066,7 @@ radeon_add_atom_connector(struct drm_device *dev, switch (connector_type) { case DRM_MODE_CONNECTOR_VGA: drm_connector_init(dev, &radeon_connector->base, &radeon_vga_connector_funcs, connector_type); - ret = drm_connector_helper_add(&radeon_connector->base, &radeon_vga_connector_helper_funcs); - if (ret) - goto failed; + drm_connector_helper_add(&radeon_connector->base, &radeon_vga_connector_helper_funcs); if (i2c_bus->valid) { radeon_connector->ddc_bus = radeon_i2c_create(dev, i2c_bus, "VGA"); if (!radeon_connector->ddc_bus) @@ -1082,9 +1079,7 @@ radeon_add_atom_connector(struct drm_device *dev, break; case DRM_MODE_CONNECTOR_DVIA: drm_connector_init(dev, &radeon_connector->base, &radeon_vga_connector_funcs, connector_type); - ret = drm_connector_helper_add(&radeon_connector->base, &radeon_vga_connector_helper_funcs); - if (ret) - goto failed; + drm_connector_helper_add(&radeon_connector->base, &radeon_vga_connector_helper_funcs); if (i2c_bus->valid) { radeon_connector->ddc_bus = radeon_i2c_create(dev, i2c_bus, "DVI"); if (!radeon_connector->ddc_bus) @@ -1104,9 +1099,7 @@ radeon_add_atom_connector(struct drm_device *dev, radeon_dig_connector->igp_lane_info = igp_lane_info; radeon_connector->con_priv = radeon_dig_connector; drm_connector_init(dev, &radeon_connector->base, &radeon_dvi_connector_funcs, connector_type); - ret = drm_connector_helper_add(&radeon_connector->base, &radeon_dvi_connector_helper_funcs); - if (ret) - goto failed; + drm_connector_helper_add(&radeon_connector->base, &radeon_dvi_connector_helper_funcs); if (i2c_bus->valid) { radeon_connector->ddc_bus = radeon_i2c_create(dev, i2c_bus, "DVI"); if (!radeon_connector->ddc_bus) @@ -1132,9 +1125,7 @@ radeon_add_atom_connector(struct drm_device *dev, radeon_dig_connector->igp_lane_info = igp_lane_info; radeon_connector->con_priv = radeon_dig_connector; drm_connector_init(dev, &radeon_connector->base, &radeon_dvi_connector_funcs, connector_type); - ret = drm_connector_helper_add(&radeon_connector->base, &radeon_dvi_connector_helper_funcs); - if (ret) - goto failed; + drm_connector_helper_add(&radeon_connector->base, &radeon_dvi_connector_helper_funcs); if (i2c_bus->valid) { radeon_connector->ddc_bus = radeon_i2c_create(dev, i2c_bus, "HDMI"); if (!radeon_connector->ddc_bus) @@ -1154,9 +1145,7 @@ radeon_add_atom_connector(struct drm_device *dev, radeon_dig_connector->igp_lane_info = igp_lane_info; radeon_connector->con_priv = radeon_dig_connector; drm_connector_init(dev, &radeon_connector->base, &radeon_dp_connector_funcs, connector_type); - ret = drm_connector_helper_add(&radeon_connector->base, &radeon_dp_connector_helper_funcs); - if (ret) - goto failed; + drm_connector_helper_add(&radeon_connector->base, &radeon_dp_connector_helper_funcs); if (i2c_bus->valid) { /* add DP i2c bus */ if (connector_type == DRM_MODE_CONNECTOR_eDP) @@ -1182,9 +1171,7 @@ radeon_add_atom_connector(struct drm_device *dev, case DRM_MODE_CONNECTOR_9PinDIN: if (radeon_tv == 1) { drm_connector_init(dev, &radeon_connector->base, &radeon_tv_connector_funcs, connector_type); - ret = drm_connector_helper_add(&radeon_connector->base, &radeon_tv_connector_helper_funcs); - if (ret) - goto failed; + drm_connector_helper_add(&radeon_connector->base, &radeon_tv_connector_helper_funcs); radeon_connector->dac_load_detect = true; drm_connector_attach_property(&radeon_connector->base, rdev->mode_info.load_detect_property, @@ -1202,9 +1189,7 @@ radeon_add_atom_connector(struct drm_device *dev, radeon_dig_connector->igp_lane_info = igp_lane_info; radeon_connector->con_priv = radeon_dig_connector; drm_connector_init(dev, &radeon_connector->base, &radeon_lvds_connector_funcs, connector_type); - ret = drm_connector_helper_add(&radeon_connector->base, &radeon_lvds_connector_helper_funcs); - if (ret) - goto failed; + drm_connector_helper_add(&radeon_connector->base, &radeon_lvds_connector_helper_funcs); if (i2c_bus->valid) { radeon_connector->ddc_bus = radeon_i2c_create(dev, i2c_bus, "LVDS"); if (!radeon_connector->ddc_bus) @@ -1241,7 +1226,6 @@ radeon_add_legacy_connector(struct drm_device *dev, struct drm_connector *connector; struct radeon_connector *radeon_connector; uint32_t subpixel_order = SubPixelNone; - int ret; /* fixme - tv/cv/din */ if (connector_type == DRM_MODE_CONNECTOR_Unknown) @@ -1269,9 +1253,7 @@ radeon_add_legacy_connector(struct drm_device *dev, switch (connector_type) { case DRM_MODE_CONNECTOR_VGA: drm_connector_init(dev, &radeon_connector->base, &radeon_vga_connector_funcs, connector_type); - ret = drm_connector_helper_add(&radeon_connector->base, &radeon_vga_connector_helper_funcs); - if (ret) - goto failed; + drm_connector_helper_add(&radeon_connector->base, &radeon_vga_connector_helper_funcs); if (i2c_bus->valid) { radeon_connector->ddc_bus = radeon_i2c_create(dev, i2c_bus, "VGA"); if (!radeon_connector->ddc_bus) @@ -1284,9 +1266,7 @@ radeon_add_legacy_connector(struct drm_device *dev, break; case DRM_MODE_CONNECTOR_DVIA: drm_connector_init(dev, &radeon_connector->base, &radeon_vga_connector_funcs, connector_type); - ret = drm_connector_helper_add(&radeon_connector->base, &radeon_vga_connector_helper_funcs); - if (ret) - goto failed; + drm_connector_helper_add(&radeon_connector->base, &radeon_vga_connector_helper_funcs); if (i2c_bus->valid) { radeon_connector->ddc_bus = radeon_i2c_create(dev, i2c_bus, "DVI"); if (!radeon_connector->ddc_bus) @@ -1300,9 +1280,7 @@ radeon_add_legacy_connector(struct drm_device *dev, case DRM_MODE_CONNECTOR_DVII: case DRM_MODE_CONNECTOR_DVID: drm_connector_init(dev, &radeon_connector->base, &radeon_dvi_connector_funcs, connector_type); - ret = drm_connector_helper_add(&radeon_connector->base, &radeon_dvi_connector_helper_funcs); - if (ret) - goto failed; + drm_connector_helper_add(&radeon_connector->base, &radeon_dvi_connector_helper_funcs); if (i2c_bus->valid) { radeon_connector->ddc_bus = radeon_i2c_create(dev, i2c_bus, "DVI"); if (!radeon_connector->ddc_bus) @@ -1319,9 +1297,7 @@ radeon_add_legacy_connector(struct drm_device *dev, case DRM_MODE_CONNECTOR_9PinDIN: if (radeon_tv == 1) { drm_connector_init(dev, &radeon_connector->base, &radeon_tv_connector_funcs, connector_type); - ret = drm_connector_helper_add(&radeon_connector->base, &radeon_tv_connector_helper_funcs); - if (ret) - goto failed; + drm_connector_helper_add(&radeon_connector->base, &radeon_tv_connector_helper_funcs); radeon_connector->dac_load_detect = true; /* RS400,RC410,RS480 chipset seems to report a lot * of false positive on load detect, we haven't yet @@ -1340,9 +1316,7 @@ radeon_add_legacy_connector(struct drm_device *dev, break; case DRM_MODE_CONNECTOR_LVDS: drm_connector_init(dev, &radeon_connector->base, &radeon_lvds_connector_funcs, connector_type); - ret = drm_connector_helper_add(&radeon_connector->base, &radeon_lvds_connector_helper_funcs); - if (ret) - goto failed; + drm_connector_helper_add(&radeon_connector->base, &radeon_lvds_connector_helper_funcs); if (i2c_bus->valid) { radeon_connector->ddc_bus = radeon_i2c_create(dev, i2c_bus, "LVDS"); if (!radeon_connector->ddc_bus) diff --git a/drivers/gpu/drm/radeon/radeon_fb.c b/drivers/gpu/drm/radeon/radeon_fb.c index 705425defba0..7275b2e09444 100644 --- a/drivers/gpu/drm/radeon/radeon_fb.c +++ b/drivers/gpu/drm/radeon/radeon_fb.c @@ -274,8 +274,6 @@ out_unref: drm_framebuffer_cleanup(fb); kfree(fb); } - -out: return ret; } @@ -380,6 +378,9 @@ int radeon_fbdev_init(struct radeon_device *rdev) rdev->num_crtc, RADEONFB_CONN_LIMIT); rfbdev->helper.fb_probe = radeon_fb_find_or_create_single; + + drm_fb_helper_single_add_all_connectors(&rfbdev->helper); + drm_fb_helper_initial_config(&rfbdev->helper); radeonfb_probe(rfbdev); return 0; diff --git a/include/drm/drm_crtc.h b/include/drm/drm_crtc.h index e4e34bae22cd..fce2042ad0a5 100644 --- a/include/drm/drm_crtc.h +++ b/include/drm/drm_crtc.h @@ -514,7 +514,6 @@ struct drm_connector { uint32_t encoder_ids[DRM_CONNECTOR_MAX_ENCODER]; uint32_t force_encoder_id; struct drm_encoder *encoder; /* currently active encoder */ - void *fb_helper_private; }; /** diff --git a/include/drm/drm_crtc_helper.h b/include/drm/drm_crtc_helper.h index ce7aab77f7dc..b1fa0f8cfa60 100644 --- a/include/drm/drm_crtc_helper.h +++ b/include/drm/drm_crtc_helper.h @@ -39,7 +39,6 @@ #include -#include "drm_fb_helper.h" struct drm_crtc_helper_funcs { /* * Control power levels on the CRTC. If the mode passed in is @@ -96,7 +95,6 @@ struct drm_connector_helper_funcs { extern int drm_helper_probe_single_connector_modes(struct drm_connector *connector, uint32_t maxX, uint32_t maxY); extern void drm_helper_disable_unused_functions(struct drm_device *dev); -extern int drm_helper_hotplug_stage_two(struct drm_device *dev); extern int drm_crtc_helper_set_config(struct drm_mode_set *set); extern bool drm_crtc_helper_set_mode(struct drm_crtc *crtc, struct drm_display_mode *mode, @@ -122,11 +120,10 @@ static inline void drm_encoder_helper_add(struct drm_encoder *encoder, encoder->helper_private = (void *)funcs; } -static inline int drm_connector_helper_add(struct drm_connector *connector, +static inline void drm_connector_helper_add(struct drm_connector *connector, const struct drm_connector_helper_funcs *funcs) { connector->helper_private = (void *)funcs; - return drm_fb_helper_add_connector(connector); } extern int drm_helper_resume_force_mode(struct drm_device *dev); diff --git a/include/drm/drm_fb_helper.h b/include/drm/drm_fb_helper.h index b1ea66f11ded..50094f94d4ca 100644 --- a/include/drm/drm_fb_helper.h +++ b/include/drm/drm_fb_helper.h @@ -69,6 +69,7 @@ struct drm_fb_helper_surface_size { struct drm_fb_helper_connector { struct drm_fb_helper_cmdline_mode cmdline_mode; + struct drm_connector *connector; }; struct drm_fb_helper { @@ -77,6 +78,8 @@ struct drm_fb_helper { struct drm_display_mode *mode; int crtc_count; struct drm_fb_helper_crtc *crtc_info; + int connector_count; + struct drm_fb_helper_connector **connector_info; struct drm_fb_helper_funcs *funcs; int conn_limit; struct fb_info *fbdev; @@ -113,12 +116,11 @@ void drm_fb_helper_fill_var(struct fb_info *info, struct drm_fb_helper *fb_helpe void drm_fb_helper_fill_fix(struct fb_info *info, uint32_t pitch, uint32_t depth); -int drm_fb_helper_add_connector(struct drm_connector *connector); -int drm_fb_helper_parse_command_line(struct drm_device *dev); int drm_fb_helper_setcmap(struct fb_cmap *cmap, struct fb_info *info); bool drm_helper_fb_hotplug_event(struct drm_fb_helper *fb_helper, u32 max_width, u32 max_height); bool drm_fb_helper_initial_config(struct drm_fb_helper *fb_helper); +int drm_fb_helper_single_add_all_connectors(struct drm_fb_helper *fb_helper); #endif -- cgit v1.2.3 From 5c4426a782bc9509573fc7958a786ebd14fafdf3 Mon Sep 17 00:00:00 2001 From: Dave Airlie Date: Tue, 30 Mar 2010 05:34:17 +0000 Subject: drm/kms/fb: add polling support for when nothing is connected. When we are running in a headless environment we have no idea what output the user might plug in later, we only have hotplug detect from the digital outputs. So if we detect no connected outputs at initialisation, start a slow work operation to poll every 5 seconds for an output. this is only hooked up for radeon so far, on hw where we have full hotplug detection there is no need for this. Signed-off-by: Dave Airlie --- drivers/gpu/drm/Kconfig | 1 + drivers/gpu/drm/drm_fb_helper.c | 82 ++++++++++++++++++++++++++++++--- drivers/gpu/drm/radeon/radeon_fb.c | 14 +++++- drivers/gpu/drm/radeon/radeon_irq_kms.c | 2 +- drivers/gpu/drm/radeon/radeon_mode.h | 2 +- include/drm/drm_fb_helper.h | 12 ++++- 6 files changed, 101 insertions(+), 12 deletions(-) (limited to 'drivers/gpu/drm/radeon') diff --git a/drivers/gpu/drm/Kconfig b/drivers/gpu/drm/Kconfig index 305c59003963..be5aa7d5206b 100644 --- a/drivers/gpu/drm/Kconfig +++ b/drivers/gpu/drm/Kconfig @@ -23,6 +23,7 @@ config DRM_KMS_HELPER depends on DRM select FB select FRAMEBUFFER_CONSOLE if !EMBEDDED + select SLOW_WORK help FB and CRTC helpers for KMS drivers. diff --git a/drivers/gpu/drm/drm_fb_helper.c b/drivers/gpu/drm/drm_fb_helper.c index 6374e9b75d45..3312092f2c7e 100644 --- a/drivers/gpu/drm/drm_fb_helper.c +++ b/drivers/gpu/drm/drm_fb_helper.c @@ -1308,9 +1308,14 @@ bool drm_fb_helper_initial_config(struct drm_fb_helper *fb_helper) /* * we shouldn't end up with no modes here. */ - if (count == 0) - printk(KERN_INFO "No connectors reported connected with modes\n"); - + if (count == 0) { + if (fb_helper->poll_enabled) { + delayed_slow_work_enqueue(&fb_helper->output_poll_slow_work, + 5*HZ); + printk(KERN_INFO "No connectors reported connected with modes - started polling\n"); + } else + printk(KERN_INFO "No connectors reported connected with modes\n"); + } drm_setup_crtcs(fb_helper); return 0; @@ -1318,15 +1323,80 @@ bool drm_fb_helper_initial_config(struct drm_fb_helper *fb_helper) EXPORT_SYMBOL(drm_fb_helper_initial_config); bool drm_helper_fb_hotplug_event(struct drm_fb_helper *fb_helper, - u32 max_width, u32 max_height) + u32 max_width, u32 max_height, bool polled) { + int count = 0; + int ret; DRM_DEBUG_KMS("\n"); - drm_fb_helper_probe_connector_modes(fb_helper, max_width, + count = drm_fb_helper_probe_connector_modes(fb_helper, max_width, max_height); - + if (fb_helper->poll_enabled && !polled) { + if (count) { + delayed_slow_work_cancel(&fb_helper->output_poll_slow_work); + } else { + ret = delayed_slow_work_enqueue(&fb_helper->output_poll_slow_work, 5*HZ); + } + } drm_setup_crtcs(fb_helper); return true; } EXPORT_SYMBOL(drm_helper_fb_hotplug_event); + +static void output_poll_execute(struct slow_work *work) +{ + struct delayed_slow_work *delayed_work = container_of(work, struct delayed_slow_work, work); + struct drm_fb_helper *fb_helper = container_of(delayed_work, struct drm_fb_helper, output_poll_slow_work); + struct drm_device *dev = fb_helper->dev; + struct drm_connector *connector; + enum drm_connector_status old_status, status; + bool repoll = true, changed = false; + int ret; + + list_for_each_entry(connector, &dev->mode_config.connector_list, head) { + old_status = connector->status; + status = connector->funcs->detect(connector); + if (old_status != status) { + changed = true; + /* something changed */ + } + if (status == connector_status_connected) { + DRM_DEBUG("%s is connected - stop polling\n", drm_get_connector_name(connector)); + repoll = false; + } + } + + if (repoll) { + ret = delayed_slow_work_enqueue(delayed_work, 5*HZ); + if (ret) + DRM_ERROR("delayed enqueue failed %d\n", ret); + } + + if (changed) { + if (fb_helper->fb_poll_changed) + fb_helper->fb_poll_changed(fb_helper); + } +} + +struct slow_work_ops output_poll_ops = { + .execute = output_poll_execute, +}; + +void drm_fb_helper_poll_init(struct drm_fb_helper *fb_helper) +{ + int ret; + + ret = slow_work_register_user(THIS_MODULE); + + delayed_slow_work_init(&fb_helper->output_poll_slow_work, &output_poll_ops); + fb_helper->poll_enabled = true; +} +EXPORT_SYMBOL(drm_fb_helper_poll_init); + +void drm_fb_helper_poll_fini(struct drm_fb_helper *fb_helper) +{ + delayed_slow_work_cancel(&fb_helper->output_poll_slow_work); + slow_work_unregister_user(THIS_MODULE); +} +EXPORT_SYMBOL(drm_fb_helper_poll_fini); diff --git a/drivers/gpu/drm/radeon/radeon_fb.c b/drivers/gpu/drm/radeon/radeon_fb.c index 7275b2e09444..7913e50fe501 100644 --- a/drivers/gpu/drm/radeon/radeon_fb.c +++ b/drivers/gpu/drm/radeon/radeon_fb.c @@ -321,18 +321,23 @@ static int radeonfb_probe(struct radeon_fbdev *rfbdev) return drm_fb_helper_single_fb_probe(&rfbdev->helper, bpp_sel); } -void radeonfb_hotplug(struct drm_device *dev) +void radeonfb_hotplug(struct drm_device *dev, bool polled) { struct radeon_device *rdev = dev->dev_private; int max_width, max_height; max_width = rdev->mode_info.rfbdev->rfb.base.width; max_height = rdev->mode_info.rfbdev->rfb.base.height; - drm_helper_fb_hotplug_event(&rdev->mode_info.rfbdev->helper, max_width, max_height); + drm_helper_fb_hotplug_event(&rdev->mode_info.rfbdev->helper, max_width, max_height, polled); radeonfb_probe(rdev->mode_info.rfbdev); } +static void radeon_fb_poll_changed(struct drm_fb_helper *fb_helper) +{ + radeonfb_hotplug(fb_helper->dev, true); +} + static int radeon_fbdev_destroy(struct drm_device *dev, struct radeon_fbdev *rfbdev) { struct fb_info *info; @@ -381,8 +386,12 @@ int radeon_fbdev_init(struct radeon_device *rdev) drm_fb_helper_single_add_all_connectors(&rfbdev->helper); + rfbdev->helper.fb_poll_changed = radeon_fb_poll_changed; + drm_fb_helper_poll_init(&rfbdev->helper); + drm_fb_helper_initial_config(&rfbdev->helper); radeonfb_probe(rfbdev); + return 0; } @@ -392,6 +401,7 @@ void radeon_fbdev_fini(struct radeon_device *rdev) if (!rdev->mode_info.rfbdev) return; + drm_fb_helper_poll_fini(&rdev->mode_info.rfbdev->helper); radeon_fbdev_destroy(rdev->ddev, rdev->mode_info.rfbdev); kfree(rdev->mode_info.rfbdev); rdev->mode_info.rfbdev = NULL; diff --git a/drivers/gpu/drm/radeon/radeon_irq_kms.c b/drivers/gpu/drm/radeon/radeon_irq_kms.c index e7afd80a3d69..a95907aa7eae 100644 --- a/drivers/gpu/drm/radeon/radeon_irq_kms.c +++ b/drivers/gpu/drm/radeon/radeon_irq_kms.c @@ -55,7 +55,7 @@ static void radeon_hotplug_work_func(struct work_struct *work) radeon_connector_hotplug(connector); } /* Just fire off a uevent and let userspace tell us what to do */ - radeonfb_hotplug(dev); + radeonfb_hotplug(dev, false); drm_sysfs_hotplug_event(dev); } diff --git a/drivers/gpu/drm/radeon/radeon_mode.h b/drivers/gpu/drm/radeon/radeon_mode.h index 165f6025a3bc..4a086c09e117 100644 --- a/drivers/gpu/drm/radeon/radeon_mode.h +++ b/drivers/gpu/drm/radeon/radeon_mode.h @@ -585,5 +585,5 @@ void radeon_fbdev_fini(struct radeon_device *rdev); void radeon_fbdev_set_suspend(struct radeon_device *rdev, int state); int radeon_fbdev_total_size(struct radeon_device *rdev); bool radeon_fbdev_robj_is_fb(struct radeon_device *rdev, struct radeon_bo *robj); -void radeonfb_hotplug(struct drm_device *dev); +void radeonfb_hotplug(struct drm_device *dev, bool polled); #endif diff --git a/include/drm/drm_fb_helper.h b/include/drm/drm_fb_helper.h index 50094f94d4ca..a073d73c195e 100644 --- a/include/drm/drm_fb_helper.h +++ b/include/drm/drm_fb_helper.h @@ -30,6 +30,8 @@ #ifndef DRM_FB_HELPER_H #define DRM_FB_HELPER_H +#include + struct drm_fb_helper_crtc { uint32_t crtc_id; struct drm_mode_set mode_set; @@ -86,8 +88,12 @@ struct drm_fb_helper { u32 pseudo_palette[17]; struct list_head kernel_fb_list; + struct delayed_slow_work output_poll_slow_work; + bool poll_enabled; int (*fb_probe)(struct drm_fb_helper *helper, struct drm_fb_helper_surface_size *sizes); + + void (*fb_poll_changed)(struct drm_fb_helper *helper); }; int drm_fb_helper_single_fb_probe(struct drm_fb_helper *helper, @@ -118,9 +124,11 @@ void drm_fb_helper_fill_fix(struct fb_info *info, uint32_t pitch, int drm_fb_helper_setcmap(struct fb_cmap *cmap, struct fb_info *info); -bool drm_helper_fb_hotplug_event(struct drm_fb_helper *fb_helper, u32 max_width, - u32 max_height); +bool drm_helper_fb_hotplug_event(struct drm_fb_helper *fb_helper, + u32 max_width, u32 max_height, bool polled); bool drm_fb_helper_initial_config(struct drm_fb_helper *fb_helper); int drm_fb_helper_single_add_all_connectors(struct drm_fb_helper *fb_helper); +void drm_fb_helper_poll_init(struct drm_fb_helper *fb_helper); +void drm_fb_helper_poll_fini(struct drm_fb_helper *fb_helper); #endif -- cgit v1.2.3 From 4abe35204af82a018ca3ce6db4102aa09719698e Mon Sep 17 00:00:00 2001 From: Dave Airlie Date: Tue, 30 Mar 2010 05:34:18 +0000 Subject: drm/kms/fb: use slow work mechanism for normal hotplug also. a) slow work is always used now for any fbcon hotplug, as its not a fast task and is more suited to being ran under slow work. b) attempt to not do any fbdev changes when X is running as we'll just mess it up. This hooks set_par to hopefully do the changes once X hands control to fbdev. This also adds the nouveau/intel hotplug support. Signed-off-by: Dave Airlie --- drivers/gpu/drm/drm_fb_helper.c | 207 +++++++++++++++++++------------- drivers/gpu/drm/i915/i915_irq.c | 1 + drivers/gpu/drm/i915/intel_drv.h | 2 + drivers/gpu/drm/i915/intel_fb.c | 42 ++++--- drivers/gpu/drm/nouveau/nouveau_fbcon.c | 45 ++++--- drivers/gpu/drm/nouveau/nouveau_fbcon.h | 2 + drivers/gpu/drm/nouveau/nv50_display.c | 3 + drivers/gpu/drm/radeon/radeon_fb.c | 74 +++++------- include/drm/drm_fb_helper.h | 47 ++++---- 9 files changed, 241 insertions(+), 182 deletions(-) (limited to 'drivers/gpu/drm/radeon') diff --git a/drivers/gpu/drm/drm_fb_helper.c b/drivers/gpu/drm/drm_fb_helper.c index 3312092f2c7e..b889eb0aaf5f 100644 --- a/drivers/gpu/drm/drm_fb_helper.c +++ b/drivers/gpu/drm/drm_fb_helper.c @@ -41,6 +41,8 @@ MODULE_LICENSE("GPL and additional rights"); static LIST_HEAD(kernel_fb_helper_list); +static struct slow_work_ops output_status_change_ops; + /* simple single crtc case helper function */ int drm_fb_helper_single_add_all_connectors(struct drm_fb_helper *fb_helper) { @@ -420,54 +422,81 @@ static void drm_fb_helper_crtc_free(struct drm_fb_helper *helper) kfree(helper->crtc_info); } -int drm_fb_helper_init_crtc_count(struct drm_device *dev, - struct drm_fb_helper *helper, - int crtc_count, int max_conn_count) +int drm_fb_helper_init(struct drm_device *dev, + struct drm_fb_helper *fb_helper, + int crtc_count, int max_conn_count, + bool polled) { struct drm_crtc *crtc; int ret = 0; int i; - INIT_LIST_HEAD(&helper->kernel_fb_list); - helper->dev = dev; - helper->crtc_info = kcalloc(crtc_count, sizeof(struct drm_fb_helper_crtc), GFP_KERNEL); - if (!helper->crtc_info) + fb_helper->dev = dev; + fb_helper->poll_enabled = polled; + + slow_work_register_user(THIS_MODULE); + delayed_slow_work_init(&fb_helper->output_status_change_slow_work, + &output_status_change_ops); + + INIT_LIST_HEAD(&fb_helper->kernel_fb_list); + + fb_helper->crtc_info = kcalloc(crtc_count, sizeof(struct drm_fb_helper_crtc), GFP_KERNEL); + if (!fb_helper->crtc_info) return -ENOMEM; - helper->crtc_count = crtc_count; - helper->connector_info = kcalloc(dev->mode_config.num_connector, sizeof(struct drm_fb_helper_connector *), GFP_KERNEL); - if (!helper->connector_info) { - kfree(helper->crtc_info); + fb_helper->crtc_count = crtc_count; + fb_helper->connector_info = kcalloc(dev->mode_config.num_connector, sizeof(struct drm_fb_helper_connector *), GFP_KERNEL); + if (!fb_helper->connector_info) { + kfree(fb_helper->crtc_info); return -ENOMEM; } - helper->connector_count = 0; + fb_helper->connector_count = 0; for (i = 0; i < crtc_count; i++) { - helper->crtc_info[i].mode_set.connectors = + fb_helper->crtc_info[i].mode_set.connectors = kcalloc(max_conn_count, sizeof(struct drm_connector *), GFP_KERNEL); - if (!helper->crtc_info[i].mode_set.connectors) { + if (!fb_helper->crtc_info[i].mode_set.connectors) { ret = -ENOMEM; goto out_free; } - helper->crtc_info[i].mode_set.num_connectors = 0; + fb_helper->crtc_info[i].mode_set.num_connectors = 0; } i = 0; list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) { - helper->crtc_info[i].crtc_id = crtc->base.id; - helper->crtc_info[i].mode_set.crtc = crtc; + fb_helper->crtc_info[i].crtc_id = crtc->base.id; + fb_helper->crtc_info[i].mode_set.crtc = crtc; i++; } - helper->conn_limit = max_conn_count; + fb_helper->conn_limit = max_conn_count; return 0; out_free: - drm_fb_helper_crtc_free(helper); + drm_fb_helper_crtc_free(fb_helper); return -ENOMEM; } -EXPORT_SYMBOL(drm_fb_helper_init_crtc_count); +EXPORT_SYMBOL(drm_fb_helper_init); + +void drm_fb_helper_fini(struct drm_fb_helper *fb_helper) +{ + if (!list_empty(&fb_helper->kernel_fb_list)) { + list_del(&fb_helper->kernel_fb_list); + if (list_empty(&kernel_fb_helper_list)) { + printk(KERN_INFO "unregistered panic notifier\n"); + atomic_notifier_chain_unregister(&panic_notifier_list, + &paniced); + unregister_sysrq_key('v', &sysrq_drm_fb_helper_restore_op); + } + } + + drm_fb_helper_crtc_free(fb_helper); + + delayed_slow_work_cancel(&fb_helper->output_status_change_slow_work); + slow_work_unregister_user(THIS_MODULE); +} +EXPORT_SYMBOL(drm_fb_helper_fini); static int setcolreg(struct drm_crtc *crtc, u16 red, u16 green, u16 blue, u16 regno, struct fb_info *info) @@ -710,6 +739,11 @@ int drm_fb_helper_set_par(struct fb_info *info) } } mutex_unlock(&dev->mode_config.mutex); + + if (fb_helper->delayed_hotplug) { + fb_helper->delayed_hotplug = false; + delayed_slow_work_enqueue(&fb_helper->output_status_change_slow_work, 0); + } return 0; } EXPORT_SYMBOL(drm_fb_helper_set_par); @@ -751,7 +785,7 @@ int drm_fb_helper_single_fb_probe(struct drm_fb_helper *fb_helper, { int new_fb = 0; int crtc_count = 0; - int ret, i; + int i; struct fb_info *info; struct drm_fb_helper_surface_size sizes; int gamma_size = 0; @@ -827,7 +861,7 @@ int drm_fb_helper_single_fb_probe(struct drm_fb_helper *fb_helper, } /* push down into drivers */ - new_fb = (*fb_helper->fb_probe)(fb_helper, &sizes); + new_fb = (*fb_helper->funcs->fb_probe)(fb_helper, &sizes); if (new_fb < 0) return new_fb; @@ -840,11 +874,7 @@ int drm_fb_helper_single_fb_probe(struct drm_fb_helper *fb_helper, if (new_fb) { info->var.pixclock = 0; - ret = fb_alloc_cmap(&info->cmap, gamma_size, 0); - if (ret) - return ret; if (register_framebuffer(info) < 0) { - fb_dealloc_cmap(&info->cmap); return -EINVAL; } @@ -870,23 +900,6 @@ int drm_fb_helper_single_fb_probe(struct drm_fb_helper *fb_helper, } EXPORT_SYMBOL(drm_fb_helper_single_fb_probe); -void drm_fb_helper_free(struct drm_fb_helper *helper) -{ - if (!list_empty(&helper->kernel_fb_list)) { - list_del(&helper->kernel_fb_list); - if (list_empty(&kernel_fb_helper_list)) { - printk(KERN_INFO "unregistered panic notifier\n"); - atomic_notifier_chain_unregister(&panic_notifier_list, - &paniced); - unregister_sysrq_key('v', &sysrq_drm_fb_helper_restore_op); - } - } - drm_fb_helper_crtc_free(helper); - if (helper->fbdev->cmap.len) - fb_dealloc_cmap(&helper->fbdev->cmap); -} -EXPORT_SYMBOL(drm_fb_helper_free); - void drm_fb_helper_fill_fix(struct fb_info *info, uint32_t pitch, uint32_t depth) { @@ -1291,7 +1304,7 @@ static void drm_setup_crtcs(struct drm_fb_helper *fb_helper) * RETURNS: * Zero if everything went ok, nonzero otherwise. */ -bool drm_fb_helper_initial_config(struct drm_fb_helper *fb_helper) +bool drm_fb_helper_initial_config(struct drm_fb_helper *fb_helper, int bpp_sel) { struct drm_device *dev = fb_helper->dev; int count = 0; @@ -1304,13 +1317,12 @@ bool drm_fb_helper_initial_config(struct drm_fb_helper *fb_helper) count = drm_fb_helper_probe_connector_modes(fb_helper, dev->mode_config.max_width, dev->mode_config.max_height); - /* * we shouldn't end up with no modes here. */ if (count == 0) { if (fb_helper->poll_enabled) { - delayed_slow_work_enqueue(&fb_helper->output_poll_slow_work, + delayed_slow_work_enqueue(&fb_helper->output_status_change_slow_work, 5*HZ); printk(KERN_INFO "No connectors reported connected with modes - started polling\n"); } else @@ -1318,85 +1330,114 @@ bool drm_fb_helper_initial_config(struct drm_fb_helper *fb_helper) } drm_setup_crtcs(fb_helper); - return 0; + return drm_fb_helper_single_fb_probe(fb_helper, bpp_sel); } EXPORT_SYMBOL(drm_fb_helper_initial_config); -bool drm_helper_fb_hotplug_event(struct drm_fb_helper *fb_helper, - u32 max_width, u32 max_height, bool polled) +/* we got a hotplug irq - need to update fbcon */ +void drm_helper_fb_hpd_irq_event(struct drm_fb_helper *fb_helper) +{ + /* if we don't have the fbdev registered yet do nothing */ + if (!fb_helper->fbdev) + return; + + /* schedule a slow work asap */ + delayed_slow_work_enqueue(&fb_helper->output_status_change_slow_work, 0); +} +EXPORT_SYMBOL(drm_helper_fb_hpd_irq_event); + +bool drm_helper_fb_hotplug_event(struct drm_fb_helper *fb_helper, bool polled) { int count = 0; int ret; + u32 max_width, max_height, bpp_sel; + + if (!fb_helper->fb) + return false; DRM_DEBUG_KMS("\n"); + max_width = fb_helper->fb->width; + max_height = fb_helper->fb->height; + bpp_sel = fb_helper->fb->bits_per_pixel; + count = drm_fb_helper_probe_connector_modes(fb_helper, max_width, max_height); if (fb_helper->poll_enabled && !polled) { if (count) { - delayed_slow_work_cancel(&fb_helper->output_poll_slow_work); + delayed_slow_work_cancel(&fb_helper->output_status_change_slow_work); } else { - ret = delayed_slow_work_enqueue(&fb_helper->output_poll_slow_work, 5*HZ); + ret = delayed_slow_work_enqueue(&fb_helper->output_status_change_slow_work, 5*HZ); } } drm_setup_crtcs(fb_helper); - return true; + return drm_fb_helper_single_fb_probe(fb_helper, bpp_sel); } EXPORT_SYMBOL(drm_helper_fb_hotplug_event); -static void output_poll_execute(struct slow_work *work) +/* + * delayed work queue execution function + * - check if fbdev is actually in use on the gpu + * - if not set delayed flag and repoll if necessary + * - check for connector status change + * - repoll if 0 modes found + *- call driver output status changed notifier + */ +static void output_status_change_execute(struct slow_work *work) { struct delayed_slow_work *delayed_work = container_of(work, struct delayed_slow_work, work); - struct drm_fb_helper *fb_helper = container_of(delayed_work, struct drm_fb_helper, output_poll_slow_work); - struct drm_device *dev = fb_helper->dev; + struct drm_fb_helper *fb_helper = container_of(delayed_work, struct drm_fb_helper, output_status_change_slow_work); struct drm_connector *connector; enum drm_connector_status old_status, status; - bool repoll = true, changed = false; + bool repoll, changed = false; int ret; + int i; + bool bound = false, crtcs_bound = false; + struct drm_crtc *crtc; - list_for_each_entry(connector, &dev->mode_config.connector_list, head) { + repoll = fb_helper->poll_enabled; + + /* first of all check the fbcon framebuffer is actually bound to any crtc */ + /* take into account that no crtc at all maybe bound */ + list_for_each_entry(crtc, &fb_helper->dev->mode_config.crtc_list, head) { + if (crtc->fb) + crtcs_bound = true; + if (crtc->fb == fb_helper->fb) + bound = true; + } + + if (bound == false && crtcs_bound) { + fb_helper->delayed_hotplug = true; + goto requeue; + } + + for (i = 0; i < fb_helper->connector_count; i++) { + connector = fb_helper->connector_info[i]->connector; old_status = connector->status; status = connector->funcs->detect(connector); if (old_status != status) { changed = true; - /* something changed */ } - if (status == connector_status_connected) { + if (status == connector_status_connected && repoll) { DRM_DEBUG("%s is connected - stop polling\n", drm_get_connector_name(connector)); repoll = false; } } + if (changed) { + if (fb_helper->funcs->fb_output_status_changed) + fb_helper->funcs->fb_output_status_changed(fb_helper); + } + +requeue: if (repoll) { ret = delayed_slow_work_enqueue(delayed_work, 5*HZ); if (ret) DRM_ERROR("delayed enqueue failed %d\n", ret); } - - if (changed) { - if (fb_helper->fb_poll_changed) - fb_helper->fb_poll_changed(fb_helper); - } } -struct slow_work_ops output_poll_ops = { - .execute = output_poll_execute, +static struct slow_work_ops output_status_change_ops = { + .execute = output_status_change_execute, }; -void drm_fb_helper_poll_init(struct drm_fb_helper *fb_helper) -{ - int ret; - - ret = slow_work_register_user(THIS_MODULE); - - delayed_slow_work_init(&fb_helper->output_poll_slow_work, &output_poll_ops); - fb_helper->poll_enabled = true; -} -EXPORT_SYMBOL(drm_fb_helper_poll_init); - -void drm_fb_helper_poll_fini(struct drm_fb_helper *fb_helper) -{ - delayed_slow_work_cancel(&fb_helper->output_poll_slow_work); - slow_work_unregister_user(THIS_MODULE); -} -EXPORT_SYMBOL(drm_fb_helper_poll_fini); diff --git a/drivers/gpu/drm/i915/i915_irq.c b/drivers/gpu/drm/i915/i915_irq.c index 5388354da0d1..fdf08f222901 100644 --- a/drivers/gpu/drm/i915/i915_irq.c +++ b/drivers/gpu/drm/i915/i915_irq.c @@ -266,6 +266,7 @@ static void i915_hotplug_work_func(struct work_struct *work) } } /* Just fire off a uevent and let userspace tell us what to do */ + intelfb_hotplug(dev, false); drm_sysfs_hotplug_event(dev); } diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h index 9ffb9f2c9abd..11fce595882d 100644 --- a/drivers/gpu/drm/i915/intel_drv.h +++ b/drivers/gpu/drm/i915/intel_drv.h @@ -228,4 +228,6 @@ extern int intel_overlay_put_image(struct drm_device *dev, void *data, struct drm_file *file_priv); extern int intel_overlay_attrs(struct drm_device *dev, void *data, struct drm_file *file_priv); + +void intelfb_hotplug(struct drm_device *dev, bool polled); #endif /* __INTEL_DRV_H__ */ diff --git a/drivers/gpu/drm/i915/intel_fb.c b/drivers/gpu/drm/i915/intel_fb.c index 8f7a7c476098..cc726ff0a02d 100644 --- a/drivers/gpu/drm/i915/intel_fb.c +++ b/drivers/gpu/drm/i915/intel_fb.c @@ -65,12 +65,6 @@ static struct fb_ops intelfb_ops = { .fb_setcmap = drm_fb_helper_setcmap, }; -static struct drm_fb_helper_funcs intel_fb_helper_funcs = { - .gamma_set = intel_crtc_fb_gamma_set, - .gamma_get = intel_crtc_fb_gamma_get, -}; - - static int intelfb_create(struct intel_fbdev *ifbdev, struct drm_fb_helper_surface_size *sizes) { @@ -129,7 +123,6 @@ static int intelfb_create(struct intel_fbdev *ifbdev, ifbdev->helper.fb = fb; ifbdev->helper.fbdev = info; - ifbdev->helper.funcs = &intel_fb_helper_funcs; strcpy(info->fix.id, "inteldrmfb"); @@ -154,6 +147,12 @@ static int intelfb_create(struct intel_fbdev *ifbdev, ret = -ENOSPC; goto out_unpin; } + + ret = fb_alloc_cmap(&info->cmap, 256, 0); + if (ret) { + ret = -ENOMEM; + goto out_unpin; + } info->screen_size = size; // memset(info->screen_base, 0, size); @@ -205,15 +204,18 @@ static int intel_fb_find_or_create_single(struct drm_fb_helper *helper, return new_fb; } -static int intelfb_probe(struct intel_fbdev *ifbdev) +void intelfb_hotplug(struct drm_device *dev, bool polled) { - int ret; - - DRM_DEBUG_KMS("\n"); - ret = drm_fb_helper_single_fb_probe(&ifbdev->helper, 32); - return ret; + drm_i915_private_t *dev_priv = dev->dev_private; + drm_helper_fb_hpd_irq_event(&dev_priv->fbdev->helper); } +static struct drm_fb_helper_funcs intel_fb_helper_funcs = { + .gamma_set = intel_crtc_fb_gamma_set, + .gamma_get = intel_crtc_fb_gamma_get, + .fb_probe = intel_fb_find_or_create_single, +}; + int intel_fbdev_destroy(struct drm_device *dev, struct intel_fbdev *ifbdev) { @@ -224,10 +226,12 @@ int intel_fbdev_destroy(struct drm_device *dev, info = ifbdev->helper.fbdev; unregister_framebuffer(info); iounmap(info->screen_base); + if (info->cmap.len) + fb_dealloc_cmap(&info->cmap); framebuffer_release(info); } - drm_fb_helper_free(&ifbdev->helper); + drm_fb_helper_fini(&ifbdev->helper); drm_framebuffer_cleanup(&ifb->base); if (ifb->obj) @@ -246,13 +250,13 @@ int intel_fbdev_init(struct drm_device *dev) return -ENOMEM; dev_priv->fbdev = ifbdev; + ifbdev->helper.funcs = &intel_fb_helper_funcs; + + drm_fb_helper_init(dev, &ifbdev->helper, 2, + INTELFB_CONN_LIMIT, false); - drm_fb_helper_init_crtc_count(dev, &ifbdev->helper, 2, - INTELFB_CONN_LIMIT); drm_fb_helper_single_add_all_connectors(&ifbdev->helper); - ifbdev->helper.fb_probe = intel_fb_find_or_create_single; - drm_fb_helper_initial_config(&ifbdev->helper); - intelfb_probe(ifbdev); + drm_fb_helper_initial_config(&ifbdev->helper, 32); return 0; } diff --git a/drivers/gpu/drm/nouveau/nouveau_fbcon.c b/drivers/gpu/drm/nouveau/nouveau_fbcon.c index fd5d3cde0a07..bc81ec7dc131 100644 --- a/drivers/gpu/drm/nouveau/nouveau_fbcon.c +++ b/drivers/gpu/drm/nouveau/nouveau_fbcon.c @@ -156,11 +156,6 @@ static void nouveau_fbcon_gamma_get(struct drm_crtc *crtc, u16 *red, u16 *green, *blue = nv_crtc->lut.b[regno]; } -static struct drm_fb_helper_funcs nouveau_fbcon_helper_funcs = { - .gamma_set = nouveau_fbcon_gamma_set, - .gamma_get = nouveau_fbcon_gamma_get -}; - #if defined(__i386__) || defined(__x86_64__) static bool nouveau_fbcon_has_vesafb_or_efifb(struct drm_device *dev) @@ -272,6 +267,12 @@ nouveau_fbcon_create(struct nouveau_fbdev *nfbdev, goto out_unref; } + ret = fb_alloc_cmap(&info->cmap, 256, 0); + if (ret) { + ret = -ENOMEM; + goto out_unref; + } + info->par = nfbdev; nouveau_framebuffer_init(dev, &nfbdev->nouveau_fb, &mode_cmd, nvbo); @@ -282,7 +283,6 @@ nouveau_fbcon_create(struct nouveau_fbdev *nfbdev, /* setup helper */ nfbdev->helper.fb = fb; nfbdev->helper.fbdev = info; - nfbdev->helper.funcs = &nouveau_fbcon_helper_funcs; strcpy(info->fix.id, "nouveaufb"); if (nouveau_nofbaccel) @@ -381,12 +381,15 @@ nouveau_fbcon_find_or_create_single(struct drm_fb_helper *helper, return new_fb; } -static int -nouveau_fbcon_probe(struct nouveau_fbdev *nfbdev) +void nouveau_fbcon_hotplug(struct drm_device *dev) { - NV_DEBUG_KMS(nfbdev->dev, "\n"); + struct drm_nouveau_private *dev_priv = dev->dev_private; + drm_helper_fb_hpd_irq_event(&dev_priv->nfbdev->helper); +} - return drm_fb_helper_single_fb_probe(&nfbdev->helper, 32); +static void nouveau_fbcon_output_status_changed(struct drm_fb_helper *fb_helper) +{ + drm_helper_fb_hotplug_event(fb_helper, true); } int @@ -398,6 +401,8 @@ nouveau_fbcon_destroy(struct drm_device *dev, struct nouveau_fbdev *nfbdev) if (nfbdev->helper.fbdev) { info = nfbdev->helper.fbdev; unregister_framebuffer(info); + if (info->cmap.len) + fb_dealloc_cmap(&info->cmap); framebuffer_release(info); } @@ -406,7 +411,7 @@ nouveau_fbcon_destroy(struct drm_device *dev, struct nouveau_fbdev *nfbdev) drm_gem_object_unreference_unlocked(nouveau_fb->nvbo->gem); nouveau_fb->nvbo = NULL; } - drm_fb_helper_free(&nfbdev->helper); + drm_fb_helper_fini(&nfbdev->helper); drm_framebuffer_cleanup(&nouveau_fb->base); return 0; } @@ -420,6 +425,14 @@ void nouveau_fbcon_gpu_lockup(struct fb_info *info) info->flags |= FBINFO_HWACCEL_DISABLED; } +static struct drm_fb_helper_funcs nouveau_fbcon_helper_funcs = { + .gamma_set = nouveau_fbcon_gamma_set, + .gamma_get = nouveau_fbcon_gamma_get, + .fb_probe = nouveau_fbcon_find_or_create_single, + .fb_output_status_changed = nouveau_fbcon_output_status_changed, +}; + + int nouveau_fbcon_init(struct drm_device *dev) { struct drm_nouveau_private *dev_priv = dev->dev_private; @@ -431,14 +444,12 @@ int nouveau_fbcon_init(struct drm_device *dev) nfbdev->dev = dev; dev_priv->nfbdev = nfbdev; + nfbdev->helper.funcs = &nouveau_fbcon_helper_funcs; - drm_fb_helper_init_crtc_count(dev, &nfbdev->helper, - 2, 4); - nfbdev->helper.fb_probe = nouveau_fbcon_find_or_create_single; + drm_fb_helper_init(dev, &nfbdev->helper, + 2, 4, true); drm_fb_helper_single_add_all_connectors(&nfbdev->helper); - - drm_fb_helper_initial_config(&nfbdev->helper); - nouveau_fbcon_probe(nfbdev); + drm_fb_helper_initial_config(&nfbdev->helper, 32); return 0; } diff --git a/drivers/gpu/drm/nouveau/nouveau_fbcon.h b/drivers/gpu/drm/nouveau/nouveau_fbcon.h index 7835b5685555..bf8e00d4de65 100644 --- a/drivers/gpu/drm/nouveau/nouveau_fbcon.h +++ b/drivers/gpu/drm/nouveau/nouveau_fbcon.h @@ -57,5 +57,7 @@ void nouveau_fbcon_set_suspend(struct drm_device *dev, int state); void nouveau_fbcon_zfill_all(struct drm_device *dev); void nouveau_fbcon_save_disable_accel(struct drm_device *dev); void nouveau_fbcon_restore_accel(struct drm_device *dev); + +void nouveau_fbcon_hotplug(struct drm_device *dev); #endif /* __NV50_FBCON_H__ */ diff --git a/drivers/gpu/drm/nouveau/nv50_display.c b/drivers/gpu/drm/nouveau/nv50_display.c index fac6c88a2b1f..d4f06c2a61e6 100644 --- a/drivers/gpu/drm/nouveau/nv50_display.c +++ b/drivers/gpu/drm/nouveau/nv50_display.c @@ -29,6 +29,7 @@ #include "nouveau_encoder.h" #include "nouveau_connector.h" #include "nouveau_fb.h" +#include "nouveau_fbcon.h" #include "drm_crtc_helper.h" static void @@ -941,6 +942,8 @@ nv50_display_irq_hotplug(struct drm_device *dev) nv_wr32(dev, 0xe054, nv_rd32(dev, 0xe054)); if (dev_priv->chipset >= 0x90) nv_wr32(dev, 0xe074, nv_rd32(dev, 0xe074)); + + nouveau_fbcon_hotplug(dev); } void diff --git a/drivers/gpu/drm/radeon/radeon_fb.c b/drivers/gpu/drm/radeon/radeon_fb.c index 7913e50fe501..93cc54fac330 100644 --- a/drivers/gpu/drm/radeon/radeon_fb.c +++ b/drivers/gpu/drm/radeon/radeon_fb.c @@ -86,11 +86,6 @@ static int radeon_align_pitch(struct radeon_device *rdev, int width, int bpp, bo return aligned; } -static struct drm_fb_helper_funcs radeon_fb_helper_funcs = { - .gamma_set = radeon_crtc_fb_gamma_set, - .gamma_get = radeon_crtc_fb_gamma_get, -}; - static void radeonfb_destroy_pinned_object(struct drm_gem_object *gobj) { struct radeon_bo *rbo = gobj->driver_private; @@ -222,7 +217,6 @@ static int radeonfb_create(struct radeon_fbdev *rfbdev, /* setup helper */ rfbdev->helper.fb = fb; rfbdev->helper.fbdev = info; - rfbdev->helper.funcs = &radeon_fb_helper_funcs; memset_io(rbo->kptr, 0x0, radeon_bo_size(rbo)); @@ -252,10 +246,18 @@ static int radeonfb_create(struct radeon_fbdev *rfbdev, info->pixmap.access_align = 32; info->pixmap.flags = FB_PIXMAP_SYSTEM; info->pixmap.scan_align = 1; + if (info->screen_base == NULL) { ret = -ENOSPC; goto out_unref; } + + ret = fb_alloc_cmap(&info->cmap, 256, 0); + if (ret) { + ret = -ENOMEM; + goto out_unref; + } + DRM_INFO("fb mappable at 0x%lX\n", info->fix.smem_start); DRM_INFO("vram apper at 0x%lX\n", (unsigned long)rdev->mc.aper_base); DRM_INFO("size %lu\n", (unsigned long)radeon_bo_size(rbo)); @@ -309,33 +311,16 @@ int radeon_parse_options(char *options) return 0; } -static int radeonfb_probe(struct radeon_fbdev *rfbdev) -{ - struct radeon_device *rdev = rfbdev->rdev; - int bpp_sel = 32; - - /* select 8 bpp console on RN50 or 16MB cards */ - if (ASIC_IS_RN50(rdev) || rdev->mc.real_vram_size <= (32*1024*1024)) - bpp_sel = 8; - - return drm_fb_helper_single_fb_probe(&rfbdev->helper, bpp_sel); -} - void radeonfb_hotplug(struct drm_device *dev, bool polled) { struct radeon_device *rdev = dev->dev_private; - int max_width, max_height; - - max_width = rdev->mode_info.rfbdev->rfb.base.width; - max_height = rdev->mode_info.rfbdev->rfb.base.height; - drm_helper_fb_hotplug_event(&rdev->mode_info.rfbdev->helper, max_width, max_height, polled); - radeonfb_probe(rdev->mode_info.rfbdev); + drm_helper_fb_hpd_irq_event(&rdev->mode_info.rfbdev->helper); } -static void radeon_fb_poll_changed(struct drm_fb_helper *fb_helper) +static void radeon_fb_output_status_changed(struct drm_fb_helper *fb_helper) { - radeonfb_hotplug(fb_helper->dev, true); + drm_helper_fb_hotplug_event(fb_helper, true); } static int radeon_fbdev_destroy(struct drm_device *dev, struct radeon_fbdev *rfbdev) @@ -347,7 +332,10 @@ static int radeon_fbdev_destroy(struct drm_device *dev, struct radeon_fbdev *rfb if (rfbdev->helper.fbdev) { info = rfbdev->helper.fbdev; + unregister_framebuffer(info); + if (info->cmap.len) + fb_dealloc_cmap(&info->cmap); framebuffer_release(info); } @@ -361,16 +349,27 @@ static int radeon_fbdev_destroy(struct drm_device *dev, struct radeon_fbdev *rfb } drm_gem_object_unreference_unlocked(rfb->obj); } - drm_fb_helper_free(&rfbdev->helper); + drm_fb_helper_fini(&rfbdev->helper); drm_framebuffer_cleanup(&rfb->base); return 0; } -MODULE_LICENSE("GPL"); + +static struct drm_fb_helper_funcs radeon_fb_helper_funcs = { + .gamma_set = radeon_crtc_fb_gamma_set, + .gamma_get = radeon_crtc_fb_gamma_get, + .fb_probe = radeon_fb_find_or_create_single, + .fb_output_status_changed = radeon_fb_output_status_changed, +}; int radeon_fbdev_init(struct radeon_device *rdev) { struct radeon_fbdev *rfbdev; + int bpp_sel = 32; + + /* select 8 bpp console on RN50 or 16MB cards */ + if (ASIC_IS_RN50(rdev) || rdev->mc.real_vram_size <= (32*1024*1024)) + bpp_sel = 8; rfbdev = kzalloc(sizeof(struct radeon_fbdev), GFP_KERNEL); if (!rfbdev) @@ -378,20 +377,13 @@ int radeon_fbdev_init(struct radeon_device *rdev) rfbdev->rdev = rdev; rdev->mode_info.rfbdev = rfbdev; + rfbdev->helper.funcs = &radeon_fb_helper_funcs; - drm_fb_helper_init_crtc_count(rdev->ddev, &rfbdev->helper, - rdev->num_crtc, - RADEONFB_CONN_LIMIT); - rfbdev->helper.fb_probe = radeon_fb_find_or_create_single; - + drm_fb_helper_init(rdev->ddev, &rfbdev->helper, + rdev->num_crtc, + RADEONFB_CONN_LIMIT, true); drm_fb_helper_single_add_all_connectors(&rfbdev->helper); - - rfbdev->helper.fb_poll_changed = radeon_fb_poll_changed; - drm_fb_helper_poll_init(&rfbdev->helper); - - drm_fb_helper_initial_config(&rfbdev->helper); - radeonfb_probe(rfbdev); - + drm_fb_helper_initial_config(&rfbdev->helper, bpp_sel); return 0; } @@ -401,7 +393,6 @@ void radeon_fbdev_fini(struct radeon_device *rdev) if (!rdev->mode_info.rfbdev) return; - drm_fb_helper_poll_fini(&rdev->mode_info.rfbdev->helper); radeon_fbdev_destroy(rdev->ddev, rdev->mode_info.rfbdev); kfree(rdev->mode_info.rfbdev); rdev->mode_info.rfbdev = NULL; @@ -428,4 +419,3 @@ bool radeon_fbdev_robj_is_fb(struct radeon_device *rdev, struct radeon_bo *robj) return true; return false; } - diff --git a/include/drm/drm_fb_helper.h b/include/drm/drm_fb_helper.h index a073d73c195e..9b55a94feada 100644 --- a/include/drm/drm_fb_helper.h +++ b/include/drm/drm_fb_helper.h @@ -32,20 +32,14 @@ #include +struct drm_fb_helper; + struct drm_fb_helper_crtc { uint32_t crtc_id; struct drm_mode_set mode_set; struct drm_display_mode *desired_mode; }; - -struct drm_fb_helper_funcs { - void (*gamma_set)(struct drm_crtc *crtc, u16 red, u16 green, - u16 blue, int regno); - void (*gamma_get)(struct drm_crtc *crtc, u16 *red, u16 *green, - u16 *blue, int regno); -}; - /* mode specified on the command line */ struct drm_fb_helper_cmdline_mode { bool specified; @@ -69,6 +63,19 @@ struct drm_fb_helper_surface_size { u32 surface_depth; }; +struct drm_fb_helper_funcs { + void (*gamma_set)(struct drm_crtc *crtc, u16 red, u16 green, + u16 blue, int regno); + void (*gamma_get)(struct drm_crtc *crtc, u16 *red, u16 *green, + u16 *blue, int regno); + + int (*fb_probe)(struct drm_fb_helper *helper, + struct drm_fb_helper_surface_size *sizes); + + void (*fb_output_status_changed)(struct drm_fb_helper *helper); + +}; + struct drm_fb_helper_connector { struct drm_fb_helper_cmdline_mode cmdline_mode; struct drm_connector *connector; @@ -88,21 +95,20 @@ struct drm_fb_helper { u32 pseudo_palette[17]; struct list_head kernel_fb_list; - struct delayed_slow_work output_poll_slow_work; + struct delayed_slow_work output_status_change_slow_work; bool poll_enabled; - int (*fb_probe)(struct drm_fb_helper *helper, - struct drm_fb_helper_surface_size *sizes); - - void (*fb_poll_changed)(struct drm_fb_helper *helper); + /* we got a hotplug but fbdev wasn't running the console + delay until next set_par */ + bool delayed_hotplug; }; int drm_fb_helper_single_fb_probe(struct drm_fb_helper *helper, int preferred_bpp); -int drm_fb_helper_init_crtc_count(struct drm_device *dev, - struct drm_fb_helper *helper, int crtc_count, - int max_conn); -void drm_fb_helper_free(struct drm_fb_helper *helper); +int drm_fb_helper_init(struct drm_device *dev, + struct drm_fb_helper *helper, int crtc_count, + int max_conn, bool polled); +void drm_fb_helper_fini(struct drm_fb_helper *helper); int drm_fb_helper_blank(int blank, struct fb_info *info); int drm_fb_helper_pan_display(struct fb_var_screeninfo *var, struct fb_info *info); @@ -125,10 +131,9 @@ void drm_fb_helper_fill_fix(struct fb_info *info, uint32_t pitch, int drm_fb_helper_setcmap(struct fb_cmap *cmap, struct fb_info *info); bool drm_helper_fb_hotplug_event(struct drm_fb_helper *fb_helper, - u32 max_width, u32 max_height, bool polled); -bool drm_fb_helper_initial_config(struct drm_fb_helper *fb_helper); + bool polled); +bool drm_fb_helper_initial_config(struct drm_fb_helper *fb_helper, int bpp_sel); int drm_fb_helper_single_add_all_connectors(struct drm_fb_helper *fb_helper); -void drm_fb_helper_poll_init(struct drm_fb_helper *fb_helper); -void drm_fb_helper_poll_fini(struct drm_fb_helper *fb_helper); +void drm_helper_fb_hpd_irq_event(struct drm_fb_helper *fb_helper); #endif -- cgit v1.2.3 From b1f201980eb4a7a59277a13cf18acdbb46167ad5 Mon Sep 17 00:00:00 2001 From: James Simmons Date: Wed, 7 Apr 2010 15:06:21 +0000 Subject: drm/fb: remove drm_fb_helper_setcolreg This patch is against the drm-fbdevfix1 branch. It removes the drm_fb_helper_setcolreg function. The reason is that fb_setcolreg is only used in the case where fb_setcmap is called and no fb_ops->fb_setcmap is used. In the drm case we always need a fb_setcmap hook to handle multiple crtcs so we don't need a fb_setcolreg hook. Please apply. Signed-off-by: James Simmons Signed-off-by: Dave Airlie --- drivers/gpu/drm/drm_fb_helper.c | 30 ------------------------------ drivers/gpu/drm/i915/intel_fb.c | 1 - drivers/gpu/drm/nouveau/nouveau_fbcon.c | 3 --- drivers/gpu/drm/radeon/radeon_fb.c | 1 - 4 files changed, 35 deletions(-) (limited to 'drivers/gpu/drm/radeon') diff --git a/drivers/gpu/drm/drm_fb_helper.c b/drivers/gpu/drm/drm_fb_helper.c index b889eb0aaf5f..6929f5b21d2c 100644 --- a/drivers/gpu/drm/drm_fb_helper.c +++ b/drivers/gpu/drm/drm_fb_helper.c @@ -596,36 +596,6 @@ int drm_fb_helper_setcmap(struct fb_cmap *cmap, struct fb_info *info) } EXPORT_SYMBOL(drm_fb_helper_setcmap); -int drm_fb_helper_setcolreg(unsigned regno, - unsigned red, - unsigned green, - unsigned blue, - unsigned transp, - struct fb_info *info) -{ - struct drm_fb_helper *fb_helper = info->par; - struct drm_crtc *crtc; - struct drm_crtc_helper_funcs *crtc_funcs; - int i; - int ret; - - if (regno > 255) - return 1; - - for (i = 0; i < fb_helper->crtc_count; i++) { - crtc = fb_helper->crtc_info[i].mode_set.crtc; - crtc_funcs = crtc->helper_private; - - ret = setcolreg(crtc, red, green, blue, regno, info); - if (ret) - return ret; - - crtc_funcs->load_lut(crtc); - } - return 0; -} -EXPORT_SYMBOL(drm_fb_helper_setcolreg); - int drm_fb_helper_check_var(struct fb_var_screeninfo *var, struct fb_info *info) { diff --git a/drivers/gpu/drm/i915/intel_fb.c b/drivers/gpu/drm/i915/intel_fb.c index cc726ff0a02d..cbb8cb7144c6 100644 --- a/drivers/gpu/drm/i915/intel_fb.c +++ b/drivers/gpu/drm/i915/intel_fb.c @@ -56,7 +56,6 @@ static struct fb_ops intelfb_ops = { .owner = THIS_MODULE, .fb_check_var = drm_fb_helper_check_var, .fb_set_par = drm_fb_helper_set_par, - .fb_setcolreg = drm_fb_helper_setcolreg, .fb_fillrect = cfb_fillrect, .fb_copyarea = cfb_copyarea, .fb_imageblit = cfb_imageblit, diff --git a/drivers/gpu/drm/nouveau/nouveau_fbcon.c b/drivers/gpu/drm/nouveau/nouveau_fbcon.c index bc81ec7dc131..bea9f780d2c7 100644 --- a/drivers/gpu/drm/nouveau/nouveau_fbcon.c +++ b/drivers/gpu/drm/nouveau/nouveau_fbcon.c @@ -98,7 +98,6 @@ static struct fb_ops nouveau_fbcon_ops = { .owner = THIS_MODULE, .fb_check_var = drm_fb_helper_check_var, .fb_set_par = drm_fb_helper_set_par, - .fb_setcolreg = drm_fb_helper_setcolreg, .fb_fillrect = cfb_fillrect, .fb_copyarea = cfb_copyarea, .fb_imageblit = cfb_imageblit, @@ -112,7 +111,6 @@ static struct fb_ops nv04_fbcon_ops = { .owner = THIS_MODULE, .fb_check_var = drm_fb_helper_check_var, .fb_set_par = drm_fb_helper_set_par, - .fb_setcolreg = drm_fb_helper_setcolreg, .fb_fillrect = nv04_fbcon_fillrect, .fb_copyarea = nv04_fbcon_copyarea, .fb_imageblit = nv04_fbcon_imageblit, @@ -126,7 +124,6 @@ static struct fb_ops nv50_fbcon_ops = { .owner = THIS_MODULE, .fb_check_var = drm_fb_helper_check_var, .fb_set_par = drm_fb_helper_set_par, - .fb_setcolreg = drm_fb_helper_setcolreg, .fb_fillrect = nv50_fbcon_fillrect, .fb_copyarea = nv50_fbcon_copyarea, .fb_imageblit = nv50_fbcon_imageblit, diff --git a/drivers/gpu/drm/radeon/radeon_fb.c b/drivers/gpu/drm/radeon/radeon_fb.c index 93cc54fac330..d3ed4afdbdee 100644 --- a/drivers/gpu/drm/radeon/radeon_fb.c +++ b/drivers/gpu/drm/radeon/radeon_fb.c @@ -52,7 +52,6 @@ static struct fb_ops radeonfb_ops = { .owner = THIS_MODULE, .fb_check_var = drm_fb_helper_check_var, .fb_set_par = drm_fb_helper_set_par, - .fb_setcolreg = drm_fb_helper_setcolreg, .fb_fillrect = cfb_fillrect, .fb_copyarea = cfb_copyarea, .fb_imageblit = cfb_imageblit, -- cgit v1.2.3 From 9d87fa2138d06ff400551800d67d522625033e35 Mon Sep 17 00:00:00 2001 From: Jerome Glisse Date: Wed, 7 Apr 2010 10:21:19 +0000 Subject: drm/ttm: split no_wait argument in 2 GPU or reserve wait There is case where we want to be able to wait only for the GPU while not waiting for other buffer to be unreserved. This patch split the no_wait argument all the way down in the whole ttm path so that upper level can decide on what to wait on or not. [airlied: squashed these 4 for bisectability reasons.] drm/radeon/kms: update to TTM no_wait splitted argument drm/nouveau: update to TTM no_wait splitted argument drm/vmwgfx: update to TTM no_wait splitted argument [vmwgfx patch: Reviewed-by: Thomas Hellstrom ] Signed-off-by: Jerome Glisse Acked-by: Thomas Hellstrom Signed-off-by: Dave Airlie --- drivers/gpu/drm/nouveau/nouveau_bo.c | 45 ++++++++++++++------------ drivers/gpu/drm/nouveau/nouveau_gem.c | 2 +- drivers/gpu/drm/radeon/radeon_object.c | 6 ++-- drivers/gpu/drm/radeon/radeon_ttm.c | 39 +++++++++++----------- drivers/gpu/drm/ttm/ttm_bo.c | 57 ++++++++++++++++++--------------- drivers/gpu/drm/ttm/ttm_bo_util.c | 9 ++++-- drivers/gpu/drm/vmwgfx/vmwgfx_execbuf.c | 4 +-- drivers/gpu/drm/vmwgfx/vmwgfx_fb.c | 4 +-- drivers/gpu/drm/vmwgfx/vmwgfx_overlay.c | 2 +- include/drm/ttm/ttm_bo_api.h | 6 ++-- include/drm/ttm/ttm_bo_driver.h | 29 ++++++++++------- 11 files changed, 115 insertions(+), 88 deletions(-) (limited to 'drivers/gpu/drm/radeon') diff --git a/drivers/gpu/drm/nouveau/nouveau_bo.c b/drivers/gpu/drm/nouveau/nouveau_bo.c index 026612471c92..5a167de895c6 100644 --- a/drivers/gpu/drm/nouveau/nouveau_bo.c +++ b/drivers/gpu/drm/nouveau/nouveau_bo.c @@ -219,7 +219,7 @@ nouveau_bo_pin(struct nouveau_bo *nvbo, uint32_t memtype) for (i = 0; i < nvbo->placement.num_placement; i++) nvbo->placements[i] |= TTM_PL_FLAG_NO_EVICT; - ret = ttm_bo_validate(bo, &nvbo->placement, false, false); + ret = ttm_bo_validate(bo, &nvbo->placement, false, false, false); if (ret == 0) { switch (bo->mem.mem_type) { case TTM_PL_VRAM: @@ -256,7 +256,7 @@ nouveau_bo_unpin(struct nouveau_bo *nvbo) for (i = 0; i < nvbo->placement.num_placement; i++) nvbo->placements[i] &= ~TTM_PL_FLAG_NO_EVICT; - ret = ttm_bo_validate(bo, &nvbo->placement, false, false); + ret = ttm_bo_validate(bo, &nvbo->placement, false, false, false); if (ret == 0) { switch (bo->mem.mem_type) { case TTM_PL_VRAM: @@ -456,7 +456,8 @@ nouveau_bo_evict_flags(struct ttm_buffer_object *bo, struct ttm_placement *pl) static int nouveau_bo_move_accel_cleanup(struct nouveau_channel *chan, - struct nouveau_bo *nvbo, bool evict, bool no_wait, + struct nouveau_bo *nvbo, bool evict, + bool no_wait_reserve, bool no_wait_gpu, struct ttm_mem_reg *new_mem) { struct nouveau_fence *fence = NULL; @@ -467,7 +468,7 @@ nouveau_bo_move_accel_cleanup(struct nouveau_channel *chan, return ret; ret = ttm_bo_move_accel_cleanup(&nvbo->bo, fence, NULL, - evict, no_wait, new_mem); + evict, no_wait_reserve, no_wait_gpu, new_mem); if (nvbo->channel && nvbo->channel != chan) ret = nouveau_fence_wait(fence, NULL, false, false); nouveau_fence_unref((void *)&fence); @@ -491,7 +492,8 @@ nouveau_bo_mem_ctxdma(struct nouveau_bo *nvbo, struct nouveau_channel *chan, static int nouveau_bo_move_m2mf(struct ttm_buffer_object *bo, int evict, bool intr, - int no_wait, struct ttm_mem_reg *new_mem) + bool no_wait_reserve, bool no_wait_gpu, + struct ttm_mem_reg *new_mem) { struct nouveau_bo *nvbo = nouveau_bo(bo); struct drm_nouveau_private *dev_priv = nouveau_bdev(bo->bdev); @@ -569,12 +571,13 @@ nouveau_bo_move_m2mf(struct ttm_buffer_object *bo, int evict, bool intr, dst_offset += (PAGE_SIZE * line_count); } - return nouveau_bo_move_accel_cleanup(chan, nvbo, evict, no_wait, new_mem); + return nouveau_bo_move_accel_cleanup(chan, nvbo, evict, no_wait_reserve, no_wait_gpu, new_mem); } static int nouveau_bo_move_flipd(struct ttm_buffer_object *bo, bool evict, bool intr, - bool no_wait, struct ttm_mem_reg *new_mem) + bool no_wait_reserve, bool no_wait_gpu, + struct ttm_mem_reg *new_mem) { u32 placement_memtype = TTM_PL_FLAG_TT | TTM_PL_MASK_CACHING; struct ttm_placement placement; @@ -587,7 +590,7 @@ nouveau_bo_move_flipd(struct ttm_buffer_object *bo, bool evict, bool intr, tmp_mem = *new_mem; tmp_mem.mm_node = NULL; - ret = ttm_bo_mem_space(bo, &placement, &tmp_mem, intr, no_wait); + ret = ttm_bo_mem_space(bo, &placement, &tmp_mem, intr, no_wait_reserve, no_wait_gpu); if (ret) return ret; @@ -595,11 +598,11 @@ nouveau_bo_move_flipd(struct ttm_buffer_object *bo, bool evict, bool intr, if (ret) goto out; - ret = nouveau_bo_move_m2mf(bo, true, intr, no_wait, &tmp_mem); + ret = nouveau_bo_move_m2mf(bo, true, intr, no_wait_reserve, no_wait_gpu, &tmp_mem); if (ret) goto out; - ret = ttm_bo_move_ttm(bo, evict, no_wait, new_mem); + ret = ttm_bo_move_ttm(bo, evict, no_wait_reserve, no_wait_gpu, new_mem); out: if (tmp_mem.mm_node) { spin_lock(&bo->bdev->glob->lru_lock); @@ -612,7 +615,8 @@ out: static int nouveau_bo_move_flips(struct ttm_buffer_object *bo, bool evict, bool intr, - bool no_wait, struct ttm_mem_reg *new_mem) + bool no_wait_reserve, bool no_wait_gpu, + struct ttm_mem_reg *new_mem) { u32 placement_memtype = TTM_PL_FLAG_TT | TTM_PL_MASK_CACHING; struct ttm_placement placement; @@ -625,15 +629,15 @@ nouveau_bo_move_flips(struct ttm_buffer_object *bo, bool evict, bool intr, tmp_mem = *new_mem; tmp_mem.mm_node = NULL; - ret = ttm_bo_mem_space(bo, &placement, &tmp_mem, intr, no_wait); + ret = ttm_bo_mem_space(bo, &placement, &tmp_mem, intr, no_wait_reserve, no_wait_gpu); if (ret) return ret; - ret = ttm_bo_move_ttm(bo, evict, no_wait, &tmp_mem); + ret = ttm_bo_move_ttm(bo, evict, no_wait_reserve, no_wait_gpu, &tmp_mem); if (ret) goto out; - ret = nouveau_bo_move_m2mf(bo, evict, intr, no_wait, new_mem); + ret = nouveau_bo_move_m2mf(bo, evict, intr, no_wait_reserve, no_wait_gpu, new_mem); if (ret) goto out; @@ -700,7 +704,8 @@ nouveau_bo_vm_cleanup(struct ttm_buffer_object *bo, static int nouveau_bo_move(struct ttm_buffer_object *bo, bool evict, bool intr, - bool no_wait, struct ttm_mem_reg *new_mem) + bool no_wait_reserve, bool no_wait_gpu, + struct ttm_mem_reg *new_mem) { struct drm_nouveau_private *dev_priv = nouveau_bdev(bo->bdev); struct nouveau_bo *nvbo = nouveau_bo(bo); @@ -715,7 +720,7 @@ nouveau_bo_move(struct ttm_buffer_object *bo, bool evict, bool intr, /* Software copy if the card isn't up and running yet. */ if (dev_priv->init_state != NOUVEAU_CARD_INIT_DONE || !dev_priv->channel) { - ret = ttm_bo_move_memcpy(bo, evict, no_wait, new_mem); + ret = ttm_bo_move_memcpy(bo, evict, no_wait_reserve, no_wait_gpu, new_mem); goto out; } @@ -729,17 +734,17 @@ nouveau_bo_move(struct ttm_buffer_object *bo, bool evict, bool intr, /* Hardware assisted copy. */ if (new_mem->mem_type == TTM_PL_SYSTEM) - ret = nouveau_bo_move_flipd(bo, evict, intr, no_wait, new_mem); + ret = nouveau_bo_move_flipd(bo, evict, intr, no_wait_reserve, no_wait_gpu, new_mem); else if (old_mem->mem_type == TTM_PL_SYSTEM) - ret = nouveau_bo_move_flips(bo, evict, intr, no_wait, new_mem); + ret = nouveau_bo_move_flips(bo, evict, intr, no_wait_reserve, no_wait_gpu, new_mem); else - ret = nouveau_bo_move_m2mf(bo, evict, intr, no_wait, new_mem); + ret = nouveau_bo_move_m2mf(bo, evict, intr, no_wait_reserve, no_wait_gpu, new_mem); if (!ret) goto out; /* Fallback to software copy. */ - ret = ttm_bo_move_memcpy(bo, evict, no_wait, new_mem); + ret = ttm_bo_move_memcpy(bo, evict, no_wait_reserve, no_wait_gpu, new_mem); out: if (ret) diff --git a/drivers/gpu/drm/nouveau/nouveau_gem.c b/drivers/gpu/drm/nouveau/nouveau_gem.c index 0d22f66f1c79..1f5040363b90 100644 --- a/drivers/gpu/drm/nouveau/nouveau_gem.c +++ b/drivers/gpu/drm/nouveau/nouveau_gem.c @@ -387,7 +387,7 @@ validate_list(struct nouveau_channel *chan, struct list_head *list, nvbo->channel = chan; ret = ttm_bo_validate(&nvbo->bo, &nvbo->placement, - false, false); + false, false, false); nvbo->channel = NULL; if (unlikely(ret)) { NV_ERROR(dev, "fail ttm_validate\n"); diff --git a/drivers/gpu/drm/radeon/radeon_object.c b/drivers/gpu/drm/radeon/radeon_object.c index dc7e3f449138..4b441f87f47a 100644 --- a/drivers/gpu/drm/radeon/radeon_object.c +++ b/drivers/gpu/drm/radeon/radeon_object.c @@ -191,7 +191,7 @@ int radeon_bo_pin(struct radeon_bo *bo, u32 domain, u64 *gpu_addr) } for (i = 0; i < bo->placement.num_placement; i++) bo->placements[i] |= TTM_PL_FLAG_NO_EVICT; - r = ttm_bo_validate(&bo->tbo, &bo->placement, false, false); + r = ttm_bo_validate(&bo->tbo, &bo->placement, false, false, false); if (likely(r == 0)) { bo->pin_count = 1; if (gpu_addr != NULL) @@ -215,7 +215,7 @@ int radeon_bo_unpin(struct radeon_bo *bo) return 0; for (i = 0; i < bo->placement.num_placement; i++) bo->placements[i] &= ~TTM_PL_FLAG_NO_EVICT; - r = ttm_bo_validate(&bo->tbo, &bo->placement, false, false); + r = ttm_bo_validate(&bo->tbo, &bo->placement, false, false, false); if (unlikely(r != 0)) dev_err(bo->rdev->dev, "%p validate failed for unpin\n", bo); return r; @@ -330,7 +330,7 @@ int radeon_bo_list_validate(struct list_head *head) lobj->rdomain); } r = ttm_bo_validate(&bo->tbo, &bo->placement, - true, false); + true, false, false); if (unlikely(r)) return r; } diff --git a/drivers/gpu/drm/radeon/radeon_ttm.c b/drivers/gpu/drm/radeon/radeon_ttm.c index 43c5ab34b634..ba4724c38ac0 100644 --- a/drivers/gpu/drm/radeon/radeon_ttm.c +++ b/drivers/gpu/drm/radeon/radeon_ttm.c @@ -243,9 +243,9 @@ static void radeon_move_null(struct ttm_buffer_object *bo, } static int radeon_move_blit(struct ttm_buffer_object *bo, - bool evict, int no_wait, - struct ttm_mem_reg *new_mem, - struct ttm_mem_reg *old_mem) + bool evict, int no_wait_reserve, bool no_wait_gpu, + struct ttm_mem_reg *new_mem, + struct ttm_mem_reg *old_mem) { struct radeon_device *rdev; uint64_t old_start, new_start; @@ -289,13 +289,14 @@ static int radeon_move_blit(struct ttm_buffer_object *bo, r = radeon_copy(rdev, old_start, new_start, new_mem->num_pages, fence); /* FIXME: handle copy error */ r = ttm_bo_move_accel_cleanup(bo, (void *)fence, NULL, - evict, no_wait, new_mem); + evict, no_wait_reserve, no_wait_gpu, new_mem); radeon_fence_unref(&fence); return r; } static int radeon_move_vram_ram(struct ttm_buffer_object *bo, - bool evict, bool interruptible, bool no_wait, + bool evict, bool interruptible, + bool no_wait_reserve, bool no_wait_gpu, struct ttm_mem_reg *new_mem) { struct radeon_device *rdev; @@ -316,7 +317,7 @@ static int radeon_move_vram_ram(struct ttm_buffer_object *bo, placement.busy_placement = &placements; placements = TTM_PL_MASK_CACHING | TTM_PL_FLAG_TT; r = ttm_bo_mem_space(bo, &placement, &tmp_mem, - interruptible, no_wait); + interruptible, no_wait_reserve, no_wait_gpu); if (unlikely(r)) { return r; } @@ -330,11 +331,11 @@ static int radeon_move_vram_ram(struct ttm_buffer_object *bo, if (unlikely(r)) { goto out_cleanup; } - r = radeon_move_blit(bo, true, no_wait, &tmp_mem, old_mem); + r = radeon_move_blit(bo, true, no_wait_reserve, no_wait_gpu, &tmp_mem, old_mem); if (unlikely(r)) { goto out_cleanup; } - r = ttm_bo_move_ttm(bo, true, no_wait, new_mem); + r = ttm_bo_move_ttm(bo, true, no_wait_reserve, no_wait_gpu, new_mem); out_cleanup: if (tmp_mem.mm_node) { struct ttm_bo_global *glob = rdev->mman.bdev.glob; @@ -348,7 +349,8 @@ out_cleanup: } static int radeon_move_ram_vram(struct ttm_buffer_object *bo, - bool evict, bool interruptible, bool no_wait, + bool evict, bool interruptible, + bool no_wait_reserve, bool no_wait_gpu, struct ttm_mem_reg *new_mem) { struct radeon_device *rdev; @@ -368,15 +370,15 @@ static int radeon_move_ram_vram(struct ttm_buffer_object *bo, placement.num_busy_placement = 1; placement.busy_placement = &placements; placements = TTM_PL_MASK_CACHING | TTM_PL_FLAG_TT; - r = ttm_bo_mem_space(bo, &placement, &tmp_mem, interruptible, no_wait); + r = ttm_bo_mem_space(bo, &placement, &tmp_mem, interruptible, no_wait_reserve, no_wait_gpu); if (unlikely(r)) { return r; } - r = ttm_bo_move_ttm(bo, true, no_wait, &tmp_mem); + r = ttm_bo_move_ttm(bo, true, no_wait_reserve, no_wait_gpu, &tmp_mem); if (unlikely(r)) { goto out_cleanup; } - r = radeon_move_blit(bo, true, no_wait, new_mem, old_mem); + r = radeon_move_blit(bo, true, no_wait_reserve, no_wait_gpu, new_mem, old_mem); if (unlikely(r)) { goto out_cleanup; } @@ -393,8 +395,9 @@ out_cleanup: } static int radeon_bo_move(struct ttm_buffer_object *bo, - bool evict, bool interruptible, bool no_wait, - struct ttm_mem_reg *new_mem) + bool evict, bool interruptible, + bool no_wait_reserve, bool no_wait_gpu, + struct ttm_mem_reg *new_mem) { struct radeon_device *rdev; struct ttm_mem_reg *old_mem = &bo->mem; @@ -421,18 +424,18 @@ static int radeon_bo_move(struct ttm_buffer_object *bo, if (old_mem->mem_type == TTM_PL_VRAM && new_mem->mem_type == TTM_PL_SYSTEM) { r = radeon_move_vram_ram(bo, evict, interruptible, - no_wait, new_mem); + no_wait_reserve, no_wait_gpu, new_mem); } else if (old_mem->mem_type == TTM_PL_SYSTEM && new_mem->mem_type == TTM_PL_VRAM) { r = radeon_move_ram_vram(bo, evict, interruptible, - no_wait, new_mem); + no_wait_reserve, no_wait_gpu, new_mem); } else { - r = radeon_move_blit(bo, evict, no_wait, new_mem, old_mem); + r = radeon_move_blit(bo, evict, no_wait_reserve, no_wait_gpu, new_mem, old_mem); } if (r) { memcpy: - r = ttm_bo_move_memcpy(bo, evict, no_wait, new_mem); + r = ttm_bo_move_memcpy(bo, evict, no_wait_reserve, no_wait_gpu, new_mem); } return r; diff --git a/drivers/gpu/drm/ttm/ttm_bo.c b/drivers/gpu/drm/ttm/ttm_bo.c index dd47b2a9a791..40631e2866f8 100644 --- a/drivers/gpu/drm/ttm/ttm_bo.c +++ b/drivers/gpu/drm/ttm/ttm_bo.c @@ -357,7 +357,8 @@ static int ttm_bo_add_ttm(struct ttm_buffer_object *bo, bool zero_alloc) static int ttm_bo_handle_move_mem(struct ttm_buffer_object *bo, struct ttm_mem_reg *mem, - bool evict, bool interruptible, bool no_wait) + bool evict, bool interruptible, + bool no_wait_reserve, bool no_wait_gpu) { struct ttm_bo_device *bdev = bo->bdev; bool old_is_pci = ttm_mem_reg_is_pci(bdev, &bo->mem); @@ -402,12 +403,12 @@ static int ttm_bo_handle_move_mem(struct ttm_buffer_object *bo, if (!(old_man->flags & TTM_MEMTYPE_FLAG_FIXED) && !(new_man->flags & TTM_MEMTYPE_FLAG_FIXED)) - ret = ttm_bo_move_ttm(bo, evict, no_wait, mem); + ret = ttm_bo_move_ttm(bo, evict, no_wait_reserve, no_wait_gpu, mem); else if (bdev->driver->move) ret = bdev->driver->move(bo, evict, interruptible, - no_wait, mem); + no_wait_reserve, no_wait_gpu, mem); else - ret = ttm_bo_move_memcpy(bo, evict, no_wait, mem); + ret = ttm_bo_move_memcpy(bo, evict, no_wait_reserve, no_wait_gpu, mem); if (ret) goto out_err; @@ -606,7 +607,7 @@ void ttm_bo_unref(struct ttm_buffer_object **p_bo) EXPORT_SYMBOL(ttm_bo_unref); static int ttm_bo_evict(struct ttm_buffer_object *bo, bool interruptible, - bool no_wait) + bool no_wait_reserve, bool no_wait_gpu) { struct ttm_bo_device *bdev = bo->bdev; struct ttm_bo_global *glob = bo->glob; @@ -615,7 +616,7 @@ static int ttm_bo_evict(struct ttm_buffer_object *bo, bool interruptible, int ret = 0; spin_lock(&bo->lock); - ret = ttm_bo_wait(bo, false, interruptible, no_wait); + ret = ttm_bo_wait(bo, false, interruptible, no_wait_gpu); spin_unlock(&bo->lock); if (unlikely(ret != 0)) { @@ -638,7 +639,7 @@ static int ttm_bo_evict(struct ttm_buffer_object *bo, bool interruptible, placement.num_busy_placement = 0; bdev->driver->evict_flags(bo, &placement); ret = ttm_bo_mem_space(bo, &placement, &evict_mem, interruptible, - no_wait); + no_wait_reserve, no_wait_gpu); if (ret) { if (ret != -ERESTARTSYS) { printk(KERN_ERR TTM_PFX @@ -650,7 +651,7 @@ static int ttm_bo_evict(struct ttm_buffer_object *bo, bool interruptible, } ret = ttm_bo_handle_move_mem(bo, &evict_mem, true, interruptible, - no_wait); + no_wait_reserve, no_wait_gpu); if (ret) { if (ret != -ERESTARTSYS) printk(KERN_ERR TTM_PFX "Buffer eviction failed\n"); @@ -670,7 +671,8 @@ out: static int ttm_mem_evict_first(struct ttm_bo_device *bdev, uint32_t mem_type, - bool interruptible, bool no_wait) + bool interruptible, bool no_wait_reserve, + bool no_wait_gpu) { struct ttm_bo_global *glob = bdev->glob; struct ttm_mem_type_manager *man = &bdev->man[mem_type]; @@ -687,11 +689,11 @@ retry: bo = list_first_entry(&man->lru, struct ttm_buffer_object, lru); kref_get(&bo->list_kref); - ret = ttm_bo_reserve_locked(bo, false, true, false, 0); + ret = ttm_bo_reserve_locked(bo, false, no_wait_reserve, false, 0); if (unlikely(ret == -EBUSY)) { spin_unlock(&glob->lru_lock); - if (likely(!no_wait)) + if (likely(!no_wait_gpu)) ret = ttm_bo_wait_unreserved(bo, interruptible); kref_put(&bo->list_kref, ttm_bo_release_list); @@ -713,7 +715,7 @@ retry: while (put_count--) kref_put(&bo->list_kref, ttm_bo_ref_bug); - ret = ttm_bo_evict(bo, interruptible, no_wait); + ret = ttm_bo_evict(bo, interruptible, no_wait_reserve, no_wait_gpu); ttm_bo_unreserve(bo); kref_put(&bo->list_kref, ttm_bo_release_list); @@ -764,7 +766,9 @@ static int ttm_bo_mem_force_space(struct ttm_buffer_object *bo, uint32_t mem_type, struct ttm_placement *placement, struct ttm_mem_reg *mem, - bool interruptible, bool no_wait) + bool interruptible, + bool no_wait_reserve, + bool no_wait_gpu) { struct ttm_bo_device *bdev = bo->bdev; struct ttm_bo_global *glob = bdev->glob; @@ -785,7 +789,7 @@ static int ttm_bo_mem_force_space(struct ttm_buffer_object *bo, } spin_unlock(&glob->lru_lock); ret = ttm_mem_evict_first(bdev, mem_type, interruptible, - no_wait); + no_wait_reserve, no_wait_gpu); if (unlikely(ret != 0)) return ret; } while (1); @@ -855,7 +859,8 @@ static bool ttm_bo_mt_compatible(struct ttm_mem_type_manager *man, int ttm_bo_mem_space(struct ttm_buffer_object *bo, struct ttm_placement *placement, struct ttm_mem_reg *mem, - bool interruptible, bool no_wait) + bool interruptible, bool no_wait_reserve, + bool no_wait_gpu) { struct ttm_bo_device *bdev = bo->bdev; struct ttm_mem_type_manager *man; @@ -952,7 +957,7 @@ int ttm_bo_mem_space(struct ttm_buffer_object *bo, } ret = ttm_bo_mem_force_space(bo, mem_type, placement, mem, - interruptible, no_wait); + interruptible, no_wait_reserve, no_wait_gpu); if (ret == 0 && mem->mm_node) { mem->placement = cur_flags; mem->mm_node->private = bo; @@ -978,7 +983,8 @@ EXPORT_SYMBOL(ttm_bo_wait_cpu); int ttm_bo_move_buffer(struct ttm_buffer_object *bo, struct ttm_placement *placement, - bool interruptible, bool no_wait) + bool interruptible, bool no_wait_reserve, + bool no_wait_gpu) { struct ttm_bo_global *glob = bo->glob; int ret = 0; @@ -992,7 +998,7 @@ int ttm_bo_move_buffer(struct ttm_buffer_object *bo, * instead of doing it here. */ spin_lock(&bo->lock); - ret = ttm_bo_wait(bo, false, interruptible, no_wait); + ret = ttm_bo_wait(bo, false, interruptible, no_wait_gpu); spin_unlock(&bo->lock); if (ret) return ret; @@ -1002,10 +1008,10 @@ int ttm_bo_move_buffer(struct ttm_buffer_object *bo, /* * Determine where to move the buffer. */ - ret = ttm_bo_mem_space(bo, placement, &mem, interruptible, no_wait); + ret = ttm_bo_mem_space(bo, placement, &mem, interruptible, no_wait_reserve, no_wait_gpu); if (ret) goto out_unlock; - ret = ttm_bo_handle_move_mem(bo, &mem, false, interruptible, no_wait); + ret = ttm_bo_handle_move_mem(bo, &mem, false, interruptible, no_wait_reserve, no_wait_gpu); out_unlock: if (ret && mem.mm_node) { spin_lock(&glob->lru_lock); @@ -1039,7 +1045,8 @@ static int ttm_bo_mem_compat(struct ttm_placement *placement, int ttm_bo_validate(struct ttm_buffer_object *bo, struct ttm_placement *placement, - bool interruptible, bool no_wait) + bool interruptible, bool no_wait_reserve, + bool no_wait_gpu) { int ret; @@ -1054,7 +1061,7 @@ int ttm_bo_validate(struct ttm_buffer_object *bo, */ ret = ttm_bo_mem_compat(placement, &bo->mem); if (ret < 0) { - ret = ttm_bo_move_buffer(bo, placement, interruptible, no_wait); + ret = ttm_bo_move_buffer(bo, placement, interruptible, no_wait_reserve, no_wait_gpu); if (ret) return ret; } else { @@ -1175,7 +1182,7 @@ int ttm_bo_init(struct ttm_bo_device *bdev, goto out_err; } - ret = ttm_bo_validate(bo, placement, interruptible, false); + ret = ttm_bo_validate(bo, placement, interruptible, false, false); if (ret) goto out_err; @@ -1249,7 +1256,7 @@ static int ttm_bo_force_list_clean(struct ttm_bo_device *bdev, spin_lock(&glob->lru_lock); while (!list_empty(&man->lru)) { spin_unlock(&glob->lru_lock); - ret = ttm_mem_evict_first(bdev, mem_type, false, false); + ret = ttm_mem_evict_first(bdev, mem_type, false, false, false); if (ret) { if (allow_errors) { return ret; @@ -1839,7 +1846,7 @@ static int ttm_bo_swapout(struct ttm_mem_shrink *shrink) evict_mem.mem_type = TTM_PL_SYSTEM; ret = ttm_bo_handle_move_mem(bo, &evict_mem, true, - false, false); + false, false, false); if (unlikely(ret != 0)) goto out; } diff --git a/drivers/gpu/drm/ttm/ttm_bo_util.c b/drivers/gpu/drm/ttm/ttm_bo_util.c index 5ca37a58a98c..865b2a826e13 100644 --- a/drivers/gpu/drm/ttm/ttm_bo_util.c +++ b/drivers/gpu/drm/ttm/ttm_bo_util.c @@ -49,7 +49,8 @@ void ttm_bo_free_old_node(struct ttm_buffer_object *bo) } int ttm_bo_move_ttm(struct ttm_buffer_object *bo, - bool evict, bool no_wait, struct ttm_mem_reg *new_mem) + bool evict, bool no_wait_reserve, + bool no_wait_gpu, struct ttm_mem_reg *new_mem) { struct ttm_tt *ttm = bo->ttm; struct ttm_mem_reg *old_mem = &bo->mem; @@ -207,7 +208,8 @@ static int ttm_copy_ttm_io_page(struct ttm_tt *ttm, void *dst, } int ttm_bo_move_memcpy(struct ttm_buffer_object *bo, - bool evict, bool no_wait, struct ttm_mem_reg *new_mem) + bool evict, bool no_wait_reserve, bool no_wait_gpu, + struct ttm_mem_reg *new_mem) { struct ttm_bo_device *bdev = bo->bdev; struct ttm_mem_type_manager *man = &bdev->man[new_mem->mem_type]; @@ -525,7 +527,8 @@ int ttm_bo_pfn_prot(struct ttm_buffer_object *bo, int ttm_bo_move_accel_cleanup(struct ttm_buffer_object *bo, void *sync_obj, void *sync_obj_arg, - bool evict, bool no_wait, + bool evict, bool no_wait_reserve, + bool no_wait_gpu, struct ttm_mem_reg *new_mem) { struct ttm_bo_device *bdev = bo->bdev; diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_execbuf.c b/drivers/gpu/drm/vmwgfx/vmwgfx_execbuf.c index 0897359b3e4e..dbd36b8910cf 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_execbuf.c +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_execbuf.c @@ -570,7 +570,7 @@ static int vmw_validate_single_buffer(struct vmw_private *dev_priv, * Put BO in VRAM, only if there is space. */ - ret = ttm_bo_validate(bo, &vmw_vram_sys_placement, true, false); + ret = ttm_bo_validate(bo, &vmw_vram_sys_placement, true, false, false); if (unlikely(ret == -ERESTARTSYS)) return ret; @@ -590,7 +590,7 @@ static int vmw_validate_single_buffer(struct vmw_private *dev_priv, * previous contents. */ - ret = ttm_bo_validate(bo, &vmw_vram_placement, true, false); + ret = ttm_bo_validate(bo, &vmw_vram_placement, true, false, false); return ret; } diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_fb.c b/drivers/gpu/drm/vmwgfx/vmwgfx_fb.c index a93367041cdc..80125ffc4e28 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_fb.c +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_fb.c @@ -628,7 +628,7 @@ int vmw_dmabuf_from_vram(struct vmw_private *vmw_priv, if (unlikely(ret != 0)) return ret; - ret = ttm_bo_validate(bo, &vmw_sys_placement, false, false); + ret = ttm_bo_validate(bo, &vmw_sys_placement, false, false, false); ttm_bo_unreserve(bo); return ret; @@ -652,7 +652,7 @@ int vmw_dmabuf_to_start_of_vram(struct vmw_private *vmw_priv, if (unlikely(ret != 0)) goto err_unlock; - ret = ttm_bo_validate(bo, &ne_placement, false, false); + ret = ttm_bo_validate(bo, &ne_placement, false, false, false); ttm_bo_unreserve(bo); err_unlock: ttm_write_unlock(&vmw_priv->active_master->lock); diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_overlay.c b/drivers/gpu/drm/vmwgfx/vmwgfx_overlay.c index 5b6eabeb7f51..ad566c85b075 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_overlay.c +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_overlay.c @@ -118,7 +118,7 @@ static int vmw_dmabuf_pin_in_vram(struct vmw_private *dev_priv, if (pin) overlay_placement = &vmw_vram_ne_placement; - ret = ttm_bo_validate(bo, overlay_placement, interruptible, false); + ret = ttm_bo_validate(bo, overlay_placement, interruptible, false, false); ttm_bo_unreserve(bo); diff --git a/include/drm/ttm/ttm_bo_api.h b/include/drm/ttm/ttm_bo_api.h index 81eb9f45883c..8c8005ec4eaf 100644 --- a/include/drm/ttm/ttm_bo_api.h +++ b/include/drm/ttm/ttm_bo_api.h @@ -313,7 +313,8 @@ extern int ttm_bo_wait(struct ttm_buffer_object *bo, bool lazy, * @bo: The buffer object. * @placement: Proposed placement for the buffer object. * @interruptible: Sleep interruptible if sleeping. - * @no_wait: Return immediately if the buffer is busy. + * @no_wait_reserve: Return immediately if other buffers are busy. + * @no_wait_gpu: Return immediately if the GPU is busy. * * Changes placement and caching policy of the buffer object * according proposed placement. @@ -325,7 +326,8 @@ extern int ttm_bo_wait(struct ttm_buffer_object *bo, bool lazy, */ extern int ttm_bo_validate(struct ttm_buffer_object *bo, struct ttm_placement *placement, - bool interruptible, bool no_wait); + bool interruptible, bool no_wait_reserve, + bool no_wait_gpu); /** * ttm_bo_unref diff --git a/include/drm/ttm/ttm_bo_driver.h b/include/drm/ttm/ttm_bo_driver.h index e929c27ede22..69f70e418c2c 100644 --- a/include/drm/ttm/ttm_bo_driver.h +++ b/include/drm/ttm/ttm_bo_driver.h @@ -311,7 +311,8 @@ struct ttm_bo_driver { */ int (*move) (struct ttm_buffer_object *bo, bool evict, bool interruptible, - bool no_wait, struct ttm_mem_reg *new_mem); + bool no_wait_reserve, bool no_wait_gpu, + struct ttm_mem_reg *new_mem); /** * struct ttm_bo_driver_member verify_access @@ -633,7 +634,8 @@ extern bool ttm_mem_reg_is_pci(struct ttm_bo_device *bdev, * @proposed_placement: Proposed new placement for the buffer object. * @mem: A struct ttm_mem_reg. * @interruptible: Sleep interruptible when sliping. - * @no_wait: Don't sleep waiting for space to become available. + * @no_wait_reserve: Return immediately if other buffers are busy. + * @no_wait_gpu: Return immediately if the GPU is busy. * * Allocate memory space for the buffer object pointed to by @bo, using * the placement flags in @mem, potentially evicting other idle buffer objects. @@ -647,7 +649,8 @@ extern bool ttm_mem_reg_is_pci(struct ttm_bo_device *bdev, extern int ttm_bo_mem_space(struct ttm_buffer_object *bo, struct ttm_placement *placement, struct ttm_mem_reg *mem, - bool interruptible, bool no_wait); + bool interruptible, + bool no_wait_reserve, bool no_wait_gpu); /** * ttm_bo_wait_for_cpu * @@ -826,7 +829,8 @@ extern void ttm_bo_unblock_reservation(struct ttm_buffer_object *bo); * * @bo: A pointer to a struct ttm_buffer_object. * @evict: 1: This is an eviction. Don't try to pipeline. - * @no_wait: Never sleep, but rather return with -EBUSY. + * @no_wait_reserve: Return immediately if other buffers are busy. + * @no_wait_gpu: Return immediately if the GPU is busy. * @new_mem: struct ttm_mem_reg indicating where to move. * * Optimized move function for a buffer object with both old and @@ -840,15 +844,16 @@ extern void ttm_bo_unblock_reservation(struct ttm_buffer_object *bo); */ extern int ttm_bo_move_ttm(struct ttm_buffer_object *bo, - bool evict, bool no_wait, - struct ttm_mem_reg *new_mem); + bool evict, bool no_wait_reserve, + bool no_wait_gpu, struct ttm_mem_reg *new_mem); /** * ttm_bo_move_memcpy * * @bo: A pointer to a struct ttm_buffer_object. * @evict: 1: This is an eviction. Don't try to pipeline. - * @no_wait: Never sleep, but rather return with -EBUSY. + * @no_wait_reserve: Return immediately if other buffers are busy. + * @no_wait_gpu: Return immediately if the GPU is busy. * @new_mem: struct ttm_mem_reg indicating where to move. * * Fallback move function for a mappable buffer object in mappable memory. @@ -862,8 +867,8 @@ extern int ttm_bo_move_ttm(struct ttm_buffer_object *bo, */ extern int ttm_bo_move_memcpy(struct ttm_buffer_object *bo, - bool evict, - bool no_wait, struct ttm_mem_reg *new_mem); + bool evict, bool no_wait_reserve, + bool no_wait_gpu, struct ttm_mem_reg *new_mem); /** * ttm_bo_free_old_node @@ -882,7 +887,8 @@ extern void ttm_bo_free_old_node(struct ttm_buffer_object *bo); * @sync_obj_arg: An argument to pass to the sync object idle / wait * functions. * @evict: This is an evict move. Don't return until the buffer is idle. - * @no_wait: Never sleep, but rather return with -EBUSY. + * @no_wait_reserve: Return immediately if other buffers are busy. + * @no_wait_gpu: Return immediately if the GPU is busy. * @new_mem: struct ttm_mem_reg indicating where to move. * * Accelerated move function to be called when an accelerated move @@ -896,7 +902,8 @@ extern void ttm_bo_free_old_node(struct ttm_buffer_object *bo); extern int ttm_bo_move_accel_cleanup(struct ttm_buffer_object *bo, void *sync_obj, void *sync_obj_arg, - bool evict, bool no_wait, + bool evict, bool no_wait_reserve, + bool no_wait_gpu, struct ttm_mem_reg *new_mem); /** * ttm_io_prot -- cgit v1.2.3 From 08c5c51507614ffd6fee8f3517c33ac5e1576e82 Mon Sep 17 00:00:00 2001 From: Alex Deucher Date: Wed, 10 Feb 2010 17:30:05 -0500 Subject: drm/radeon/kms: update atombios.h power tables for evergreen Signed-off-by: Alex Deucher Signed-off-by: Dave Airlie --- drivers/gpu/drm/radeon/atombios.h | 76 +++++++++++++++++++++++++++++++++++++-- 1 file changed, 74 insertions(+), 2 deletions(-) (limited to 'drivers/gpu/drm/radeon') diff --git a/drivers/gpu/drm/radeon/atombios.h b/drivers/gpu/drm/radeon/atombios.h index 6732b5dd8ff4..26986c8e1f45 100644 --- a/drivers/gpu/drm/radeon/atombios.h +++ b/drivers/gpu/drm/radeon/atombios.h @@ -5742,6 +5742,9 @@ typedef struct _ATOM_PPLIB_THERMALCONTROLLER #define ATOM_PP_THERMALCONTROLLER_RV6xx 7 #define ATOM_PP_THERMALCONTROLLER_RV770 8 #define ATOM_PP_THERMALCONTROLLER_ADT7473 9 +#define ATOM_PP_THERMALCONTROLLER_EXTERNAL_GPIO 11 +#define ATOM_PP_THERMALCONTROLLER_EVERGREEN 12 +#define ATOM_PP_THERMALCONTROLLER_ADT7473_WITH_INTERNAL 0x89 // ADT7473 Fan Control + Internal Thermal Controller typedef struct _ATOM_PPLIB_STATE { @@ -5749,6 +5752,26 @@ typedef struct _ATOM_PPLIB_STATE UCHAR ucClockStateIndices[1]; // variable-sized } ATOM_PPLIB_STATE; +typedef struct _ATOM_PPLIB_FANTABLE +{ + UCHAR ucFanTableFormat; // Change this if the table format changes or version changes so that the other fields are not the same. + UCHAR ucTHyst; // Temperature hysteresis. Integer. + USHORT usTMin; // The temperature, in 0.01 centigrades, below which we just run at a minimal PWM. + USHORT usTMed; // The middle temperature where we change slopes. + USHORT usTHigh; // The high point above TMed for adjusting the second slope. + USHORT usPWMMin; // The minimum PWM value in percent (0.01% increments). + USHORT usPWMMed; // The PWM value (in percent) at TMed. + USHORT usPWMHigh; // The PWM value at THigh. +} ATOM_PPLIB_FANTABLE; + +typedef struct _ATOM_PPLIB_EXTENDEDHEADER +{ + USHORT usSize; + ULONG ulMaxEngineClock; // For Overdrive. + ULONG ulMaxMemoryClock; // For Overdrive. + // Add extra system parameters here, always adjust size to include all fields. +} ATOM_PPLIB_EXTENDEDHEADER; + //// ATOM_PPLIB_POWERPLAYTABLE::ulPlatformCaps #define ATOM_PP_PLATFORM_CAP_BACKBIAS 1 #define ATOM_PP_PLATFORM_CAP_POWERPLAY 2 @@ -5762,6 +5785,12 @@ typedef struct _ATOM_PPLIB_STATE #define ATOM_PP_PLATFORM_CAP_SIDEPORTCONTROL 512 #define ATOM_PP_PLATFORM_CAP_TURNOFFPLL_ASPML1 1024 #define ATOM_PP_PLATFORM_CAP_HTLINKCONTROL 2048 +#define ATOM_PP_PLATFORM_CAP_MVDDCONTROL 4096 +#define ATOM_PP_PLATFORM_CAP_GOTO_BOOT_ON_ALERT 0x2000 // Go to boot state on alerts, e.g. on an AC->DC transition. +#define ATOM_PP_PLATFORM_CAP_DONT_WAIT_FOR_VBLANK_ON_ALERT 0x4000 // Do NOT wait for VBLANK during an alert (e.g. AC->DC transition). +#define ATOM_PP_PLATFORM_CAP_VDDCI_CONTROL 0x8000 // Does the driver control VDDCI independently from VDDC. +#define ATOM_PP_PLATFORM_CAP_REGULATOR_HOT 0x00010000 // Enable the 'regulator hot' feature. +#define ATOM_PP_PLATFORM_CAP_BACO 0x00020000 // Does the driver supports BACO state. typedef struct _ATOM_PPLIB_POWERPLAYTABLE { @@ -5797,6 +5826,21 @@ typedef struct _ATOM_PPLIB_POWERPLAYTABLE } ATOM_PPLIB_POWERPLAYTABLE; +typedef struct _ATOM_PPLIB_POWERPLAYTABLE2 +{ + ATOM_PPLIB_POWERPLAYTABLE basicTable; + UCHAR ucNumCustomThermalPolicy; + USHORT usCustomThermalPolicyArrayOffset; +}ATOM_PPLIB_POWERPLAYTABLE2, *LPATOM_PPLIB_POWERPLAYTABLE2; + +typedef struct _ATOM_PPLIB_POWERPLAYTABLE3 +{ + ATOM_PPLIB_POWERPLAYTABLE2 basicTable2; + USHORT usFormatID; // To be used ONLY by PPGen. + USHORT usFanTableOffset; + USHORT usExtendendedHeaderOffset; +} ATOM_PPLIB_POWERPLAYTABLE3, *LPATOM_PPLIB_POWERPLAYTABLE3; + //// ATOM_PPLIB_NONCLOCK_INFO::usClassification #define ATOM_PPLIB_CLASSIFICATION_UI_MASK 0x0007 #define ATOM_PPLIB_CLASSIFICATION_UI_SHIFT 0 @@ -5816,7 +5860,9 @@ typedef struct _ATOM_PPLIB_POWERPLAYTABLE #define ATOM_PPLIB_CLASSIFICATION_UVDSTATE 0x0400 #define ATOM_PPLIB_CLASSIFICATION_3DLOW 0x0800 #define ATOM_PPLIB_CLASSIFICATION_ACPI 0x1000 -// remaining 3 bits are reserved +#define ATOM_PPLIB_CLASSIFICATION_HD2STATE 0x2000 +#define ATOM_PPLIB_CLASSIFICATION_HDSTATE 0x4000 +#define ATOM_PPLIB_CLASSIFICATION_SDSTATE 0x8000 //// ATOM_PPLIB_NONCLOCK_INFO::ulCapsAndSettings #define ATOM_PPLIB_SINGLE_DISPLAY_ONLY 0x00000001 @@ -5840,9 +5886,15 @@ typedef struct _ATOM_PPLIB_POWERPLAYTABLE #define ATOM_PPLIB_SOFTWARE_DISABLE_LOADBALANCING 0x00001000 #define ATOM_PPLIB_SOFTWARE_ENABLE_SLEEP_FOR_TIMESTAMPS 0x00002000 +#define ATOM_PPLIB_DISALLOW_ON_DC 0x00004000 #define ATOM_PPLIB_ENABLE_VARIBRIGHT 0x00008000 -#define ATOM_PPLIB_DISALLOW_ON_DC 0x00004000 +//memory related flags +#define ATOM_PPLIB_SWSTATE_MEMORY_DLL_OFF 0x000010000 + +//M3 Arb //2bits, current 3 sets of parameters in total +#define ATOM_PPLIB_M3ARB_MASK 0x00060000 +#define ATOM_PPLIB_M3ARB_SHIFT 17 // Contained in an array starting at the offset // in ATOM_PPLIB_POWERPLAYTABLE::usNonClockInfoArrayOffset. @@ -5860,6 +5912,9 @@ typedef struct _ATOM_PPLIB_NONCLOCK_INFO // Contained in an array starting at the offset // in ATOM_PPLIB_POWERPLAYTABLE::usClockInfoArrayOffset. // referenced from ATOM_PPLIB_STATE::ucClockStateIndices +#define ATOM_PPLIB_NONCLOCKINFO_VER1 12 +#define ATOM_PPLIB_NONCLOCKINFO_VER2 24 + typedef struct _ATOM_PPLIB_R600_CLOCK_INFO { USHORT usEngineClockLow; @@ -5882,6 +5937,23 @@ typedef struct _ATOM_PPLIB_R600_CLOCK_INFO #define ATOM_PPLIB_R600_FLAGS_BACKBIASENABLE 4 #define ATOM_PPLIB_R600_FLAGS_MEMORY_ODT_OFF 8 #define ATOM_PPLIB_R600_FLAGS_MEMORY_DLL_OFF 16 +#define ATOM_PPLIB_R600_FLAGS_LOWPOWER 32 // On the RV770 use 'low power' setting (sequencer S0). + +typedef struct _ATOM_PPLIB_EVERGREEN_CLOCK_INFO +{ + USHORT usEngineClockLow; + UCHAR ucEngineClockHigh; + + USHORT usMemoryClockLow; + UCHAR ucMemoryClockHigh; + + USHORT usVDDC; + USHORT usVDDCI; + USHORT usUnused; + + ULONG ulFlags; // ATOM_PPLIB_R600_FLAGS_* + +} ATOM_PPLIB_EVERGREEN_CLOCK_INFO; typedef struct _ATOM_PPLIB_RS780_CLOCK_INFO -- cgit v1.2.3 From 49f6598277635af13d60e7d2601963356bc48bd8 Mon Sep 17 00:00:00 2001 From: Alex Deucher Date: Wed, 24 Mar 2010 16:39:45 -0400 Subject: drm/radeon/kms: add support for evergreen power tables Signed-off-by: Alex Deucher Signed-off-by: Dave Airlie --- drivers/gpu/drm/radeon/radeon_atombios.c | 44 ++++++++++++++++++++++++++++++-- 1 file changed, 42 insertions(+), 2 deletions(-) (limited to 'drivers/gpu/drm/radeon') diff --git a/drivers/gpu/drm/radeon/radeon_atombios.c b/drivers/gpu/drm/radeon/radeon_atombios.c index 5673665ff216..273019925e0b 100644 --- a/drivers/gpu/drm/radeon/radeon_atombios.c +++ b/drivers/gpu/drm/radeon/radeon_atombios.c @@ -1462,6 +1462,10 @@ static const char *pp_lib_thermal_controller_names[] = { "RV6xx", "RV770", "ADT7473", + "External GPIO", + "Evergreen", + "ADT7473 with internal", + }; union power_info { @@ -1707,15 +1711,21 @@ void radeon_atombios_get_power_modes(struct radeon_device *rdev) break; } } - } else if (frev == 4) { + } else { /* add the i2c bus for thermal/fan chip */ /* no support for internal controller yet */ if (power_info->info_4.sThermalController.ucType > 0) { if ((power_info->info_4.sThermalController.ucType == ATOM_PP_THERMALCONTROLLER_RV6xx) || - (power_info->info_4.sThermalController.ucType == ATOM_PP_THERMALCONTROLLER_RV770)) { + (power_info->info_4.sThermalController.ucType == ATOM_PP_THERMALCONTROLLER_RV770) || + (power_info->info_4.sThermalController.ucType == ATOM_PP_THERMALCONTROLLER_EVERGREEN)) { DRM_INFO("Internal thermal controller %s fan control\n", (power_info->info_4.sThermalController.ucFanParameters & ATOM_PP_FANPARAMETERS_NOFAN) ? "without" : "with"); + } else if ((power_info->info_4.sThermalController.ucType == + ATOM_PP_THERMALCONTROLLER_EXTERNAL_GPIO) || + (power_info->info_4.sThermalController.ucType == + ATOM_PP_THERMALCONTROLLER_ADT7473_WITH_INTERNAL)) { + DRM_INFO("Special thermal controller config\n"); } else { DRM_INFO("Possible %s thermal controller at 0x%02x %s fan control\n", pp_lib_thermal_controller_names[power_info->info_4.sThermalController.ucType], @@ -1763,6 +1773,36 @@ void radeon_atombios_get_power_modes(struct radeon_device *rdev) rdev->pm.power_state[state_index].clock_info[mode_index].voltage.voltage = clock_info->usVDDC; mode_index++; + } else if (ASIC_IS_DCE4(rdev)) { + struct _ATOM_PPLIB_EVERGREEN_CLOCK_INFO *clock_info = + (struct _ATOM_PPLIB_EVERGREEN_CLOCK_INFO *) + (mode_info->atom_context->bios + + data_offset + + le16_to_cpu(power_info->info_4.usClockInfoArrayOffset) + + (power_state->ucClockStateIndices[j] * + power_info->info_4.ucClockInfoSize)); + sclk = le16_to_cpu(clock_info->usEngineClockLow); + sclk |= clock_info->ucEngineClockHigh << 16; + mclk = le16_to_cpu(clock_info->usMemoryClockLow); + mclk |= clock_info->ucMemoryClockHigh << 16; + rdev->pm.power_state[state_index].clock_info[mode_index].mclk = mclk; + rdev->pm.power_state[state_index].clock_info[mode_index].sclk = sclk; + /* skip invalid modes */ + if ((rdev->pm.power_state[state_index].clock_info[mode_index].mclk == 0) || + (rdev->pm.power_state[state_index].clock_info[mode_index].sclk == 0)) + continue; + /* skip overclock modes for now */ + if ((rdev->pm.power_state[state_index].clock_info[mode_index].mclk > + rdev->clock.default_mclk + RADEON_MODE_OVERCLOCK_MARGIN) || + (rdev->pm.power_state[state_index].clock_info[mode_index].sclk > + rdev->clock.default_sclk + RADEON_MODE_OVERCLOCK_MARGIN)) + continue; + rdev->pm.power_state[state_index].clock_info[mode_index].voltage.type = + VOLTAGE_SW; + rdev->pm.power_state[state_index].clock_info[mode_index].voltage.voltage = + clock_info->usVDDC; + /* XXX usVDDCI */ + mode_index++; } else { struct _ATOM_PPLIB_R600_CLOCK_INFO *clock_info = (struct _ATOM_PPLIB_R600_CLOCK_INFO *) -- cgit v1.2.3 From 0fcdb61e78050f8f0b31029eeafa5ae013ce0f35 Mon Sep 17 00:00:00 2001 From: Alex Deucher Date: Wed, 24 Mar 2010 13:20:41 -0400 Subject: drm/radeon/kms/evergreen: add gart support Gart setup is more or less like r7xx. Copy rv770d.h to evergreend.h and fix up changes. Signed-off-by: Alex Deucher Signed-off-by: Dave Airlie --- drivers/gpu/drm/radeon/evergreen.c | 58 +++++--- drivers/gpu/drm/radeon/evergreend.h | 270 +++++++++++++++++++++++++++++++++++ drivers/gpu/drm/radeon/radeon_asic.c | 2 +- drivers/gpu/drm/radeon/radeon_asic.h | 1 + 4 files changed, 311 insertions(+), 20 deletions(-) create mode 100644 drivers/gpu/drm/radeon/evergreend.h (limited to 'drivers/gpu/drm/radeon') diff --git a/drivers/gpu/drm/radeon/evergreen.c b/drivers/gpu/drm/radeon/evergreen.c index 7672f11ed995..afcff06ef291 100644 --- a/drivers/gpu/drm/radeon/evergreen.c +++ b/drivers/gpu/drm/radeon/evergreen.c @@ -27,7 +27,7 @@ #include "radeon.h" #include "radeon_asic.h" #include "radeon_drm.h" -#include "rv770d.h" +#include "evergreend.h" #include "atom.h" #include "avivod.h" #include "evergreen_reg.h" @@ -82,10 +82,31 @@ static int evergreen_mc_wait_for_idle(struct radeon_device *rdev) /* * GART */ +void evergreen_pcie_gart_tlb_flush(struct radeon_device *rdev) +{ + unsigned i; + u32 tmp; + + WREG32(VM_CONTEXT0_REQUEST_RESPONSE, REQUEST_TYPE(1)); + for (i = 0; i < rdev->usec_timeout; i++) { + /* read MC_STATUS */ + tmp = RREG32(VM_CONTEXT0_REQUEST_RESPONSE); + tmp = (tmp & RESPONSE_TYPE_MASK) >> RESPONSE_TYPE_SHIFT; + if (tmp == 2) { + printk(KERN_WARNING "[drm] r600 flush TLB failed\n"); + return; + } + if (tmp) { + return; + } + udelay(1); + } +} + int evergreen_pcie_gart_enable(struct radeon_device *rdev) { u32 tmp; - int r, i; + int r; if (rdev->gart.table.vram.robj == NULL) { dev_err(rdev->dev, "No VRAM object for PCIE GART.\n"); @@ -120,10 +141,9 @@ int evergreen_pcie_gart_enable(struct radeon_device *rdev) RANGE_PROTECTION_FAULT_ENABLE_DEFAULT); WREG32(VM_CONTEXT0_PROTECTION_FAULT_DEFAULT_ADDR, (u32)(rdev->dummy_page.addr >> 12)); - for (i = 1; i < 7; i++) - WREG32(VM_CONTEXT0_CNTL + (i * 4), 0); + WREG32(VM_CONTEXT1_CNTL, 0); - r600_pcie_gart_tlb_flush(rdev); + evergreen_pcie_gart_tlb_flush(rdev); rdev->gart.ready = true; return 0; } @@ -131,11 +151,11 @@ int evergreen_pcie_gart_enable(struct radeon_device *rdev) void evergreen_pcie_gart_disable(struct radeon_device *rdev) { u32 tmp; - int i, r; + int r; /* Disable all tables */ - for (i = 0; i < 7; i++) - WREG32(VM_CONTEXT0_CNTL + (i * 4), 0); + WREG32(VM_CONTEXT0_CNTL, 0); + WREG32(VM_CONTEXT1_CNTL, 0); /* Setup L2 cache */ WREG32(VM_L2_CNTL, ENABLE_L2_FRAGMENT_PROCESSING | @@ -172,7 +192,6 @@ void evergreen_pcie_gart_fini(struct radeon_device *rdev) void evergreen_agp_enable(struct radeon_device *rdev) { u32 tmp; - int i; /* Setup L2 cache */ WREG32(VM_L2_CNTL, ENABLE_L2_CACHE | ENABLE_L2_FRAGMENT_PROCESSING | @@ -192,8 +211,8 @@ void evergreen_agp_enable(struct radeon_device *rdev) WREG32(MC_VM_MB_L1_TLB1_CNTL, tmp); WREG32(MC_VM_MB_L1_TLB2_CNTL, tmp); WREG32(MC_VM_MB_L1_TLB3_CNTL, tmp); - for (i = 0; i < 7; i++) - WREG32(VM_CONTEXT0_CNTL + (i * 4), 0); + WREG32(VM_CONTEXT0_CNTL, 0); + WREG32(VM_CONTEXT1_CNTL, 0); } static void evergreen_mc_stop(struct radeon_device *rdev, struct evergreen_mc_save *save) @@ -500,9 +519,9 @@ int evergreen_asic_reset(struct radeon_device *rdev) static int evergreen_startup(struct radeon_device *rdev) { -#if 0 int r; +#if 0 if (!rdev->me_fw || !rdev->pfp_fw || !rdev->rlc_fw) { r = r600_init_microcode(rdev); if (r) { @@ -512,15 +531,13 @@ static int evergreen_startup(struct radeon_device *rdev) } #endif evergreen_mc_program(rdev); -#if 0 if (rdev->flags & RADEON_IS_AGP) { - evergreem_agp_enable(rdev); + evergreen_agp_enable(rdev); } else { r = evergreen_pcie_gart_enable(rdev); if (r) return r; } -#endif evergreen_gpu_init(rdev); #if 0 if (!rdev->r600_blit.shader_obj) { @@ -607,7 +624,10 @@ int evergreen_suspend(struct radeon_device *rdev) r700_cp_stop(rdev); rdev->cp.ready = false; r600_wb_disable(rdev); +#endif + evergreen_pcie_gart_disable(rdev); +#if 0 /* unpin shaders bo */ r = radeon_bo_reserve(rdev->r600_blit.shader_obj, false); if (likely(r == 0)) { @@ -717,18 +737,18 @@ int evergreen_init(struct radeon_device *rdev) rdev->ih.ring_obj = NULL; r600_ih_ring_init(rdev, 64 * 1024); - +#endif r = r600_pcie_gart_init(rdev); if (r) return r; -#endif + rdev->accel_working = false; r = evergreen_startup(rdev); if (r) { evergreen_suspend(rdev); /*r600_wb_fini(rdev);*/ /*radeon_ring_fini(rdev);*/ - /*evergreen_pcie_gart_fini(rdev);*/ + evergreen_pcie_gart_fini(rdev); rdev->accel_working = false; } if (rdev->accel_working) { @@ -756,8 +776,8 @@ void evergreen_fini(struct radeon_device *rdev) radeon_irq_kms_fini(rdev); radeon_ring_fini(rdev); r600_wb_fini(rdev); - evergreen_pcie_gart_fini(rdev); #endif + evergreen_pcie_gart_fini(rdev); radeon_gem_fini(rdev); radeon_fence_driver_fini(rdev); radeon_clocks_fini(rdev); diff --git a/drivers/gpu/drm/radeon/evergreend.h b/drivers/gpu/drm/radeon/evergreend.h new file mode 100644 index 000000000000..5cf707a54562 --- /dev/null +++ b/drivers/gpu/drm/radeon/evergreend.h @@ -0,0 +1,270 @@ +/* + * Copyright 2010 Advanced Micro Devices, 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: Alex Deucher + */ +#ifndef EVERGREEND_H +#define EVERGREEND_H + +/* Registers */ + +#define CC_GC_SHADER_PIPE_CONFIG 0x8950 +#define CC_RB_BACKEND_DISABLE 0x98F4 +#define BACKEND_DISABLE(x) ((x) << 16) +#define CC_SYS_RB_BACKEND_DISABLE 0x3F88 + +#define CGTS_SYS_TCC_DISABLE 0x3F90 +#define CGTS_TCC_DISABLE 0x9148 +#define CGTS_USER_SYS_TCC_DISABLE 0x3F94 +#define CGTS_USER_TCC_DISABLE 0x914C + +#define CONFIG_MEMSIZE 0x5428 + +#define CP_ME_CNTL 0x86D8 +#define CP_ME_HALT (1<<28) +#define CP_PFP_HALT (1<<26) +#define CP_ME_RAM_DATA 0xC160 +#define CP_ME_RAM_RADDR 0xC158 +#define CP_ME_RAM_WADDR 0xC15C +#define CP_MEQ_THRESHOLDS 0x8764 +#define STQ_SPLIT(x) ((x) << 0) +#define CP_PERFMON_CNTL 0x87FC +#define CP_PFP_UCODE_ADDR 0xC150 +#define CP_PFP_UCODE_DATA 0xC154 +#define CP_QUEUE_THRESHOLDS 0x8760 +#define ROQ_IB1_START(x) ((x) << 0) +#define ROQ_IB2_START(x) ((x) << 8) +#define CP_RB_CNTL 0xC104 +#define RB_BUFSZ(x) ((x)<<0) +#define RB_BLKSZ(x) ((x)<<8) +#define RB_NO_UPDATE (1<<27) +#define RB_RPTR_WR_ENA (1<<31) +#define BUF_SWAP_32BIT (2 << 16) +#define CP_RB_RPTR 0x8700 +#define CP_RB_RPTR_ADDR 0xC10C +#define CP_RB_RPTR_ADDR_HI 0xC110 +#define CP_RB_RPTR_WR 0xC108 +#define CP_RB_WPTR 0xC114 +#define CP_RB_WPTR_ADDR 0xC118 +#define CP_RB_WPTR_ADDR_HI 0xC11C +#define CP_RB_WPTR_DELAY 0x8704 +#define CP_SEM_WAIT_TIMER 0x85BC + + +#define GC_USER_SHADER_PIPE_CONFIG 0x8954 +#define INACTIVE_QD_PIPES(x) ((x) << 8) +#define INACTIVE_QD_PIPES_MASK 0x0000FF00 +#define INACTIVE_SIMDS(x) ((x) << 16) +#define INACTIVE_SIMDS_MASK 0x00FF0000 + +#define GRBM_CNTL 0x8000 +#define GRBM_READ_TIMEOUT(x) ((x) << 0) +#define GRBM_SOFT_RESET 0x8020 +#define SOFT_RESET_CP (1<<0) +#define GRBM_STATUS 0x8010 +#define CMDFIFO_AVAIL_MASK 0x0000000F +#define GUI_ACTIVE (1<<31) + +#define HDP_HOST_PATH_CNTL 0x2C00 +#define HDP_NONSURFACE_BASE 0x2C04 +#define HDP_NONSURFACE_INFO 0x2C08 +#define HDP_NONSURFACE_SIZE 0x2C0C +#define HDP_REG_COHERENCY_FLUSH_CNTL 0x54A0 +#define HDP_TILING_CONFIG 0x2F3C + +#define MC_SHARED_CHMAP 0x2004 +#define NOOFCHAN_SHIFT 12 +#define NOOFCHAN_MASK 0x00003000 + +#define MC_ARB_RAMCFG 0x2760 +#define NOOFBANK_SHIFT 0 +#define NOOFBANK_MASK 0x00000003 +#define NOOFRANK_SHIFT 2 +#define NOOFRANK_MASK 0x00000004 +#define NOOFROWS_SHIFT 3 +#define NOOFROWS_MASK 0x00000038 +#define NOOFCOLS_SHIFT 6 +#define NOOFCOLS_MASK 0x000000C0 +#define CHANSIZE_SHIFT 8 +#define CHANSIZE_MASK 0x00000100 +#define BURSTLENGTH_SHIFT 9 +#define BURSTLENGTH_MASK 0x00000200 +#define CHANSIZE_OVERRIDE (1 << 11) +#define MC_VM_AGP_TOP 0x2028 +#define MC_VM_AGP_BOT 0x202C +#define MC_VM_AGP_BASE 0x2030 +#define MC_VM_FB_LOCATION 0x2024 +#define MC_VM_MB_L1_TLB0_CNTL 0x2234 +#define MC_VM_MB_L1_TLB1_CNTL 0x2238 +#define MC_VM_MB_L1_TLB2_CNTL 0x223C +#define MC_VM_MB_L1_TLB3_CNTL 0x2240 +#define ENABLE_L1_TLB (1 << 0) +#define ENABLE_L1_FRAGMENT_PROCESSING (1 << 1) +#define SYSTEM_ACCESS_MODE_PA_ONLY (0 << 3) +#define SYSTEM_ACCESS_MODE_USE_SYS_MAP (1 << 3) +#define SYSTEM_ACCESS_MODE_IN_SYS (2 << 3) +#define SYSTEM_ACCESS_MODE_NOT_IN_SYS (3 << 3) +#define SYSTEM_APERTURE_UNMAPPED_ACCESS_PASS_THRU (0 << 5) +#define EFFECTIVE_L1_TLB_SIZE(x) ((x)<<15) +#define EFFECTIVE_L1_QUEUE_SIZE(x) ((x)<<18) +#define MC_VM_MD_L1_TLB0_CNTL 0x2654 +#define MC_VM_MD_L1_TLB1_CNTL 0x2658 +#define MC_VM_MD_L1_TLB2_CNTL 0x265C +#define MC_VM_SYSTEM_APERTURE_DEFAULT_ADDR 0x203C +#define MC_VM_SYSTEM_APERTURE_HIGH_ADDR 0x2038 +#define MC_VM_SYSTEM_APERTURE_LOW_ADDR 0x2034 + +#define PA_CL_ENHANCE 0x8A14 +#define CLIP_VTX_REORDER_ENA (1 << 0) +#define NUM_CLIP_SEQ(x) ((x) << 1) +#define PA_SC_AA_CONFIG 0x28C04 +#define PA_SC_CLIPRECT_RULE 0x2820C +#define PA_SC_EDGERULE 0x28230 +#define PA_SC_FIFO_SIZE 0x8BCC +#define SC_PRIM_FIFO_SIZE(x) ((x) << 0) +#define SC_HIZ_TILE_FIFO_SIZE(x) ((x) << 12) +#define PA_SC_FORCE_EOV_MAX_CNTS 0x8B24 +#define FORCE_EOV_MAX_CLK_CNT(x) ((x)<<0) +#define FORCE_EOV_MAX_REZ_CNT(x) ((x)<<16) +#define PA_SC_LINE_STIPPLE 0x28A0C +#define PA_SC_LINE_STIPPLE_STATE 0x8B10 + +#define SCRATCH_REG0 0x8500 +#define SCRATCH_REG1 0x8504 +#define SCRATCH_REG2 0x8508 +#define SCRATCH_REG3 0x850C +#define SCRATCH_REG4 0x8510 +#define SCRATCH_REG5 0x8514 +#define SCRATCH_REG6 0x8518 +#define SCRATCH_REG7 0x851C +#define SCRATCH_UMSK 0x8540 +#define SCRATCH_ADDR 0x8544 + +#define SMX_DC_CTL0 0xA020 +#define USE_HASH_FUNCTION (1 << 0) +#define CACHE_DEPTH(x) ((x) << 1) +#define FLUSH_ALL_ON_EVENT (1 << 10) +#define STALL_ON_EVENT (1 << 11) +#define SMX_EVENT_CTL 0xA02C +#define ES_FLUSH_CTL(x) ((x) << 0) +#define GS_FLUSH_CTL(x) ((x) << 3) +#define ACK_FLUSH_CTL(x) ((x) << 6) +#define SYNC_FLUSH_CTL (1 << 8) + +#define SPI_CONFIG_CNTL 0x9100 +#define GPR_WRITE_PRIORITY(x) ((x) << 0) +#define SPI_CONFIG_CNTL_1 0x913C +#define VTX_DONE_DELAY(x) ((x) << 0) +#define INTERP_ONE_PRIM_PER_ROW (1 << 4) +#define SPI_INPUT_Z 0x286D8 +#define SPI_PS_IN_CONTROL_0 0x286CC +#define NUM_INTERP(x) ((x)<<0) +#define POSITION_ENA (1<<8) +#define POSITION_CENTROID (1<<9) +#define POSITION_ADDR(x) ((x)<<10) +#define PARAM_GEN(x) ((x)<<15) +#define PARAM_GEN_ADDR(x) ((x)<<19) +#define BARYC_SAMPLE_CNTL(x) ((x)<<26) +#define PERSP_GRADIENT_ENA (1<<28) +#define LINEAR_GRADIENT_ENA (1<<29) +#define POSITION_SAMPLE (1<<30) +#define BARYC_AT_SAMPLE_ENA (1<<31) + +#define SQ_CONFIG 0x8C00 +#define VC_ENABLE (1 << 0) +#define EXPORT_SRC_C (1 << 1) +#define SQ_GPR_RESOURCE_MGMT_1 0x8C04 +#define NUM_PS_GPRS(x) ((x) << 0) +#define NUM_VS_GPRS(x) ((x) << 16) +#define NUM_CLAUSE_TEMP_GPRS(x) ((x) << 28) +#define SQ_GPR_RESOURCE_MGMT_2 0x8C08 +#define NUM_GS_GPRS(x) ((x) << 0) +#define NUM_ES_GPRS(x) ((x) << 16) +#define SQ_MS_FIFO_SIZES 0x8CF0 +#define CACHE_FIFO_SIZE(x) ((x) << 0) +#define FETCH_FIFO_HIWATER(x) ((x) << 8) +#define DONE_FIFO_HIWATER(x) ((x) << 16) +#define ALU_UPDATE_FIFO_HIWATER(x) ((x) << 24) + +#define SX_DEBUG_1 0x9058 +#define ENABLE_NEW_SMX_ADDRESS (1 << 16) +#define SX_EXPORT_BUFFER_SIZES 0x900C +#define COLOR_BUFFER_SIZE(x) ((x) << 0) +#define POSITION_BUFFER_SIZE(x) ((x) << 8) +#define SMX_BUFFER_SIZE(x) ((x) << 16) +#define SX_MISC 0x28350 + +#define TA_CNTL_AUX 0x9508 +#define DISABLE_CUBE_WRAP (1 << 0) +#define DISABLE_CUBE_ANISO (1 << 1) +#define SYNC_GRADIENT (1 << 24) +#define SYNC_WALKER (1 << 25) +#define SYNC_ALIGNER (1 << 26) + +#define VGT_CACHE_INVALIDATION 0x88C4 +#define CACHE_INVALIDATION(x) ((x)<<0) +#define VC_ONLY 0 +#define TC_ONLY 1 +#define VC_AND_TC 2 +#define AUTO_INVLD_EN(x) ((x) << 6) +#define NO_AUTO 0 +#define ES_AUTO 1 +#define GS_AUTO 2 +#define ES_AND_GS_AUTO 3 +#define VGT_GS_VERTEX_REUSE 0x88D4 +#define VGT_NUM_INSTANCES 0x8974 +#define VGT_OUT_DEALLOC_CNTL 0x28C5C +#define DEALLOC_DIST_MASK 0x0000007F +#define VGT_VERTEX_REUSE_BLOCK_CNTL 0x28C58 +#define VTX_REUSE_DEPTH_MASK 0x000000FF + +#define VM_CONTEXT0_CNTL 0x1410 +#define ENABLE_CONTEXT (1 << 0) +#define PAGE_TABLE_DEPTH(x) (((x) & 3) << 1) +#define RANGE_PROTECTION_FAULT_ENABLE_DEFAULT (1 << 4) +#define VM_CONTEXT1_CNTL 0x1414 +#define VM_CONTEXT0_PAGE_TABLE_BASE_ADDR 0x153C +#define VM_CONTEXT0_PAGE_TABLE_END_ADDR 0x157C +#define VM_CONTEXT0_PAGE_TABLE_START_ADDR 0x155C +#define VM_CONTEXT0_PROTECTION_FAULT_DEFAULT_ADDR 0x1518 +#define VM_CONTEXT0_REQUEST_RESPONSE 0x1470 +#define REQUEST_TYPE(x) (((x) & 0xf) << 0) +#define RESPONSE_TYPE_MASK 0x000000F0 +#define RESPONSE_TYPE_SHIFT 4 +#define VM_L2_CNTL 0x1400 +#define ENABLE_L2_CACHE (1 << 0) +#define ENABLE_L2_FRAGMENT_PROCESSING (1 << 1) +#define ENABLE_L2_PTE_CACHE_LRU_UPDATE_BY_WRITE (1 << 9) +#define EFFECTIVE_L2_QUEUE_SIZE(x) (((x) & 7) << 14) +#define VM_L2_CNTL2 0x1404 +#define INVALIDATE_ALL_L1_TLBS (1 << 0) +#define INVALIDATE_L2_CACHE (1 << 1) +#define VM_L2_CNTL3 0x1408 +#define BANK_SELECT(x) ((x) << 0) +#define CACHE_UPDATE_MODE(x) ((x) << 6) +#define VM_L2_STATUS 0x140C +#define L2_BUSY (1 << 0) + +#define WAIT_UNTIL 0x8040 + +#define SRBM_STATUS 0x0E50 + +#endif diff --git a/drivers/gpu/drm/radeon/radeon_asic.c b/drivers/gpu/drm/radeon/radeon_asic.c index 0d7664b8e489..d923e4b234d2 100644 --- a/drivers/gpu/drm/radeon/radeon_asic.c +++ b/drivers/gpu/drm/radeon/radeon_asic.c @@ -639,7 +639,7 @@ static struct radeon_asic evergreen_asic = { .gpu_is_lockup = &evergreen_gpu_is_lockup, .asic_reset = &evergreen_asic_reset, .vga_set_state = &r600_vga_set_state, - .gart_tlb_flush = &r600_pcie_gart_tlb_flush, + .gart_tlb_flush = &evergreen_pcie_gart_tlb_flush, .gart_set_page = &rs600_gart_set_page, .ring_test = NULL, .ring_ib_execute = NULL, diff --git a/drivers/gpu/drm/radeon/radeon_asic.h b/drivers/gpu/drm/radeon/radeon_asic.h index 77d48ba4a29a..1d451ff03676 100644 --- a/drivers/gpu/drm/radeon/radeon_asic.h +++ b/drivers/gpu/drm/radeon/radeon_asic.h @@ -281,6 +281,7 @@ int rv770_resume(struct radeon_device *rdev); /* * evergreen */ +void evergreen_pcie_gart_tlb_flush(struct radeon_device *rdev); int evergreen_init(struct radeon_device *rdev); void evergreen_fini(struct radeon_device *rdev); int evergreen_suspend(struct radeon_device *rdev); -- cgit v1.2.3 From 747943ea187e5acceb7ffc762ff2c84cb3449745 Mon Sep 17 00:00:00 2001 From: Alex Deucher Date: Wed, 24 Mar 2010 13:26:36 -0400 Subject: drm/radeon/kms/evergreen: add soft reset function Works pretty similarly to r6xx/r7xx. Signed-off-by: Alex Deucher Signed-off-by: Dave Airlie --- drivers/gpu/drm/radeon/evergreen.c | 73 ++++++++++++++++++++++++++++++++++++- drivers/gpu/drm/radeon/evergreend.h | 63 +++++++++++++++++++++++++++++++- 2 files changed, 132 insertions(+), 4 deletions(-) (limited to 'drivers/gpu/drm/radeon') diff --git a/drivers/gpu/drm/radeon/evergreen.c b/drivers/gpu/drm/radeon/evergreen.c index afcff06ef291..a6130a494c56 100644 --- a/drivers/gpu/drm/radeon/evergreen.c +++ b/drivers/gpu/drm/radeon/evergreen.c @@ -511,12 +511,81 @@ bool evergreen_gpu_is_lockup(struct radeon_device *rdev) return false; } -int evergreen_asic_reset(struct radeon_device *rdev) +static int evergreen_gpu_soft_reset(struct radeon_device *rdev) { - /* FIXME: implement for evergreen */ + struct evergreen_mc_save save; + u32 srbm_reset = 0; + u32 grbm_reset = 0; + + dev_info(rdev->dev, "GPU softreset \n"); + dev_info(rdev->dev, " GRBM_STATUS=0x%08X\n", + RREG32(GRBM_STATUS)); + dev_info(rdev->dev, " GRBM_STATUS_SE0=0x%08X\n", + RREG32(GRBM_STATUS_SE0)); + dev_info(rdev->dev, " GRBM_STATUS_SE1=0x%08X\n", + RREG32(GRBM_STATUS_SE1)); + dev_info(rdev->dev, " SRBM_STATUS=0x%08X\n", + RREG32(SRBM_STATUS)); + evergreen_mc_stop(rdev, &save); + if (evergreen_mc_wait_for_idle(rdev)) { + dev_warn(rdev->dev, "Wait for MC idle timedout !\n"); + } + /* Disable CP parsing/prefetching */ + WREG32(CP_ME_CNTL, CP_ME_HALT | CP_PFP_HALT); + + /* reset all the gfx blocks */ + grbm_reset = (SOFT_RESET_CP | + SOFT_RESET_CB | + SOFT_RESET_DB | + SOFT_RESET_PA | + SOFT_RESET_SC | + SOFT_RESET_SPI | + SOFT_RESET_SH | + SOFT_RESET_SX | + SOFT_RESET_TC | + SOFT_RESET_TA | + SOFT_RESET_VC | + SOFT_RESET_VGT); + + dev_info(rdev->dev, " GRBM_SOFT_RESET=0x%08X\n", grbm_reset); + WREG32(GRBM_SOFT_RESET, grbm_reset); + (void)RREG32(GRBM_SOFT_RESET); + udelay(50); + WREG32(GRBM_SOFT_RESET, 0); + (void)RREG32(GRBM_SOFT_RESET); + + /* reset all the system blocks */ + srbm_reset = SRBM_SOFT_RESET_ALL_MASK; + + dev_info(rdev->dev, " SRBM_SOFT_RESET=0x%08X\n", srbm_reset); + WREG32(SRBM_SOFT_RESET, srbm_reset); + (void)RREG32(SRBM_SOFT_RESET); + udelay(50); + WREG32(SRBM_SOFT_RESET, 0); + (void)RREG32(SRBM_SOFT_RESET); + /* Wait a little for things to settle down */ + udelay(50); + dev_info(rdev->dev, " GRBM_STATUS=0x%08X\n", + RREG32(GRBM_STATUS)); + dev_info(rdev->dev, " GRBM_STATUS_SE0=0x%08X\n", + RREG32(GRBM_STATUS_SE0)); + dev_info(rdev->dev, " GRBM_STATUS_SE1=0x%08X\n", + RREG32(GRBM_STATUS_SE1)); + dev_info(rdev->dev, " SRBM_STATUS=0x%08X\n", + RREG32(SRBM_STATUS)); + /* After reset we need to reinit the asic as GPU often endup in an + * incoherent state. + */ + atom_asic_init(rdev->mode_info.atom_context); + evergreen_mc_resume(rdev, &save); return 0; } +int evergreen_asic_reset(struct radeon_device *rdev) +{ + return evergreen_gpu_soft_reset(rdev); +} + static int evergreen_startup(struct radeon_device *rdev) { int r; diff --git a/drivers/gpu/drm/radeon/evergreend.h b/drivers/gpu/drm/radeon/evergreend.h index 5cf707a54562..7c290a6dd0e3 100644 --- a/drivers/gpu/drm/radeon/evergreend.h +++ b/drivers/gpu/drm/radeon/evergreend.h @@ -78,10 +78,53 @@ #define GRBM_CNTL 0x8000 #define GRBM_READ_TIMEOUT(x) ((x) << 0) #define GRBM_SOFT_RESET 0x8020 -#define SOFT_RESET_CP (1<<0) +#define SOFT_RESET_CP (1 << 0) +#define SOFT_RESET_CB (1 << 1) +#define SOFT_RESET_DB (1 << 3) +#define SOFT_RESET_PA (1 << 5) +#define SOFT_RESET_SC (1 << 6) +#define SOFT_RESET_SPI (1 << 8) +#define SOFT_RESET_SH (1 << 9) +#define SOFT_RESET_SX (1 << 10) +#define SOFT_RESET_TC (1 << 11) +#define SOFT_RESET_TA (1 << 12) +#define SOFT_RESET_VC (1 << 13) +#define SOFT_RESET_VGT (1 << 14) + #define GRBM_STATUS 0x8010 #define CMDFIFO_AVAIL_MASK 0x0000000F -#define GUI_ACTIVE (1<<31) +#define SRBM_RQ_PENDING (1 << 5) +#define CF_RQ_PENDING (1 << 7) +#define PF_RQ_PENDING (1 << 8) +#define GRBM_EE_BUSY (1 << 10) +#define SX_CLEAN (1 << 11) +#define DB_CLEAN (1 << 12) +#define CB_CLEAN (1 << 13) +#define TA_BUSY (1 << 14) +#define VGT_BUSY_NO_DMA (1 << 16) +#define VGT_BUSY (1 << 17) +#define SX_BUSY (1 << 20) +#define SH_BUSY (1 << 21) +#define SPI_BUSY (1 << 22) +#define SC_BUSY (1 << 24) +#define PA_BUSY (1 << 25) +#define DB_BUSY (1 << 26) +#define CP_COHERENCY_BUSY (1 << 28) +#define CP_BUSY (1 << 29) +#define CB_BUSY (1 << 30) +#define GUI_ACTIVE (1 << 31) +#define GRBM_STATUS_SE0 0x8014 +#define GRBM_STATUS_SE1 0x8018 +#define SE_SX_CLEAN (1 << 0) +#define SE_DB_CLEAN (1 << 1) +#define SE_CB_CLEAN (1 << 2) +#define SE_TA_BUSY (1 << 25) +#define SE_SX_BUSY (1 << 26) +#define SE_SPI_BUSY (1 << 27) +#define SE_SH_BUSY (1 << 28) +#define SE_SC_BUSY (1 << 29) +#define SE_DB_BUSY (1 << 30) +#define SE_CB_BUSY (1 << 31) #define HDP_HOST_PATH_CNTL 0x2C00 #define HDP_NONSURFACE_BASE 0x2C04 @@ -266,5 +309,21 @@ #define WAIT_UNTIL 0x8040 #define SRBM_STATUS 0x0E50 +#define SRBM_SOFT_RESET 0x0E60 +#define SRBM_SOFT_RESET_ALL_MASK 0x00FEEFA6 +#define SOFT_RESET_BIF (1 << 1) +#define SOFT_RESET_CG (1 << 2) +#define SOFT_RESET_DC (1 << 5) +#define SOFT_RESET_GRBM (1 << 8) +#define SOFT_RESET_HDP (1 << 9) +#define SOFT_RESET_IH (1 << 10) +#define SOFT_RESET_MC (1 << 11) +#define SOFT_RESET_RLC (1 << 13) +#define SOFT_RESET_ROM (1 << 14) +#define SOFT_RESET_SEM (1 << 15) +#define SOFT_RESET_VMC (1 << 17) +#define SOFT_RESET_TST (1 << 21) +#define SOFT_RESET_REGBB (1 << 22) +#define SOFT_RESET_ORB (1 << 23) #endif -- cgit v1.2.3 From 32fcdbf4084544c3d8fa413004d57e5dc6f2eefe Mon Sep 17 00:00:00 2001 From: Alex Deucher Date: Wed, 24 Mar 2010 13:33:47 -0400 Subject: drm/radeon/kms/evergreen: implement gfx init This initializes the gfx engine so accel can eventually be used. Signed-off-by: Alex Deucher Signed-off-by: Dave Airlie --- drivers/gpu/drm/radeon/evergreen.c | 556 +++++++++++++++++++++++++++++++++++- drivers/gpu/drm/radeon/evergreend.h | 105 ++++++- drivers/gpu/drm/radeon/radeon.h | 25 ++ 3 files changed, 668 insertions(+), 18 deletions(-) (limited to 'drivers/gpu/drm/radeon') diff --git a/drivers/gpu/drm/radeon/evergreen.c b/drivers/gpu/drm/radeon/evergreen.c index a6130a494c56..26b219bb1388 100644 --- a/drivers/gpu/drm/radeon/evergreen.c +++ b/drivers/gpu/drm/radeon/evergreen.c @@ -434,24 +434,572 @@ static int evergreen_cp_load_microcode(struct radeon_device *rdev) return 0; } - +#endif /* * Core functions */ -static u32 evergreen_get_tile_pipe_to_backend_map(u32 num_tile_pipes, +static u32 evergreen_get_tile_pipe_to_backend_map(struct radeon_device *rdev, + u32 num_tile_pipes, u32 num_backends, u32 backend_disable_mask) { u32 backend_map = 0; + u32 enabled_backends_mask = 0; + u32 enabled_backends_count = 0; + u32 cur_pipe; + u32 swizzle_pipe[EVERGREEN_MAX_PIPES]; + u32 cur_backend = 0; + u32 i; + bool force_no_swizzle; + + if (num_tile_pipes > EVERGREEN_MAX_PIPES) + num_tile_pipes = EVERGREEN_MAX_PIPES; + if (num_tile_pipes < 1) + num_tile_pipes = 1; + if (num_backends > EVERGREEN_MAX_BACKENDS) + num_backends = EVERGREEN_MAX_BACKENDS; + if (num_backends < 1) + num_backends = 1; + + for (i = 0; i < EVERGREEN_MAX_BACKENDS; ++i) { + if (((backend_disable_mask >> i) & 1) == 0) { + enabled_backends_mask |= (1 << i); + ++enabled_backends_count; + } + if (enabled_backends_count == num_backends) + break; + } + + if (enabled_backends_count == 0) { + enabled_backends_mask = 1; + enabled_backends_count = 1; + } + + if (enabled_backends_count != num_backends) + num_backends = enabled_backends_count; + + memset((uint8_t *)&swizzle_pipe[0], 0, sizeof(u32) * EVERGREEN_MAX_PIPES); + switch (rdev->family) { + case CHIP_CEDAR: + case CHIP_REDWOOD: + force_no_swizzle = false; + break; + case CHIP_CYPRESS: + case CHIP_HEMLOCK: + case CHIP_JUNIPER: + default: + force_no_swizzle = true; + break; + } + if (force_no_swizzle) { + bool last_backend_enabled = false; + + force_no_swizzle = false; + for (i = 0; i < EVERGREEN_MAX_BACKENDS; ++i) { + if (((enabled_backends_mask >> i) & 1) == 1) { + if (last_backend_enabled) + force_no_swizzle = true; + last_backend_enabled = true; + } else + last_backend_enabled = false; + } + } + + switch (num_tile_pipes) { + case 1: + case 3: + case 5: + case 7: + DRM_ERROR("odd number of pipes!\n"); + break; + case 2: + swizzle_pipe[0] = 0; + swizzle_pipe[1] = 1; + break; + case 4: + if (force_no_swizzle) { + swizzle_pipe[0] = 0; + swizzle_pipe[1] = 1; + swizzle_pipe[2] = 2; + swizzle_pipe[3] = 3; + } else { + swizzle_pipe[0] = 0; + swizzle_pipe[1] = 2; + swizzle_pipe[2] = 1; + swizzle_pipe[3] = 3; + } + break; + case 6: + if (force_no_swizzle) { + swizzle_pipe[0] = 0; + swizzle_pipe[1] = 1; + swizzle_pipe[2] = 2; + swizzle_pipe[3] = 3; + swizzle_pipe[4] = 4; + swizzle_pipe[5] = 5; + } else { + swizzle_pipe[0] = 0; + swizzle_pipe[1] = 2; + swizzle_pipe[2] = 4; + swizzle_pipe[3] = 1; + swizzle_pipe[4] = 3; + swizzle_pipe[5] = 5; + } + break; + case 8: + if (force_no_swizzle) { + swizzle_pipe[0] = 0; + swizzle_pipe[1] = 1; + swizzle_pipe[2] = 2; + swizzle_pipe[3] = 3; + swizzle_pipe[4] = 4; + swizzle_pipe[5] = 5; + swizzle_pipe[6] = 6; + swizzle_pipe[7] = 7; + } else { + swizzle_pipe[0] = 0; + swizzle_pipe[1] = 2; + swizzle_pipe[2] = 4; + swizzle_pipe[3] = 6; + swizzle_pipe[4] = 1; + swizzle_pipe[5] = 3; + swizzle_pipe[6] = 5; + swizzle_pipe[7] = 7; + } + break; + } + + for (cur_pipe = 0; cur_pipe < num_tile_pipes; ++cur_pipe) { + while (((1 << cur_backend) & enabled_backends_mask) == 0) + cur_backend = (cur_backend + 1) % EVERGREEN_MAX_BACKENDS; + + backend_map |= (((cur_backend & 0xf) << (swizzle_pipe[cur_pipe] * 4))); + + cur_backend = (cur_backend + 1) % EVERGREEN_MAX_BACKENDS; + } return backend_map; } -#endif static void evergreen_gpu_init(struct radeon_device *rdev) { - /* XXX */ + u32 cc_rb_backend_disable = 0; + u32 cc_gc_shader_pipe_config; + u32 gb_addr_config = 0; + u32 mc_shared_chmap, mc_arb_ramcfg; + u32 gb_backend_map; + u32 grbm_gfx_index; + u32 sx_debug_1; + u32 smx_dc_ctl0; + u32 sq_config; + u32 sq_lds_resource_mgmt; + u32 sq_gpr_resource_mgmt_1; + u32 sq_gpr_resource_mgmt_2; + u32 sq_gpr_resource_mgmt_3; + u32 sq_thread_resource_mgmt; + u32 sq_thread_resource_mgmt_2; + u32 sq_stack_resource_mgmt_1; + u32 sq_stack_resource_mgmt_2; + u32 sq_stack_resource_mgmt_3; + u32 vgt_cache_invalidation; + u32 hdp_host_path_cntl; + int i, j, num_shader_engines, ps_thread_count; + + switch (rdev->family) { + case CHIP_CYPRESS: + case CHIP_HEMLOCK: + rdev->config.evergreen.num_ses = 2; + rdev->config.evergreen.max_pipes = 4; + rdev->config.evergreen.max_tile_pipes = 8; + rdev->config.evergreen.max_simds = 10; + rdev->config.evergreen.max_backends = 4 * rdev->config.evergreen.num_ses; + rdev->config.evergreen.max_gprs = 256; + rdev->config.evergreen.max_threads = 248; + rdev->config.evergreen.max_gs_threads = 32; + rdev->config.evergreen.max_stack_entries = 512; + rdev->config.evergreen.sx_num_of_sets = 4; + rdev->config.evergreen.sx_max_export_size = 256; + rdev->config.evergreen.sx_max_export_pos_size = 64; + rdev->config.evergreen.sx_max_export_smx_size = 192; + rdev->config.evergreen.max_hw_contexts = 8; + rdev->config.evergreen.sq_num_cf_insts = 2; + + rdev->config.evergreen.sc_prim_fifo_size = 0x100; + rdev->config.evergreen.sc_hiz_tile_fifo_size = 0x30; + rdev->config.evergreen.sc_earlyz_tile_fifo_size = 0x130; + break; + case CHIP_JUNIPER: + rdev->config.evergreen.num_ses = 1; + rdev->config.evergreen.max_pipes = 4; + rdev->config.evergreen.max_tile_pipes = 4; + rdev->config.evergreen.max_simds = 10; + rdev->config.evergreen.max_backends = 4 * rdev->config.evergreen.num_ses; + rdev->config.evergreen.max_gprs = 256; + rdev->config.evergreen.max_threads = 248; + rdev->config.evergreen.max_gs_threads = 32; + rdev->config.evergreen.max_stack_entries = 512; + rdev->config.evergreen.sx_num_of_sets = 4; + rdev->config.evergreen.sx_max_export_size = 256; + rdev->config.evergreen.sx_max_export_pos_size = 64; + rdev->config.evergreen.sx_max_export_smx_size = 192; + rdev->config.evergreen.max_hw_contexts = 8; + rdev->config.evergreen.sq_num_cf_insts = 2; + + rdev->config.evergreen.sc_prim_fifo_size = 0x100; + rdev->config.evergreen.sc_hiz_tile_fifo_size = 0x30; + rdev->config.evergreen.sc_earlyz_tile_fifo_size = 0x130; + break; + case CHIP_REDWOOD: + rdev->config.evergreen.num_ses = 1; + rdev->config.evergreen.max_pipes = 4; + rdev->config.evergreen.max_tile_pipes = 4; + rdev->config.evergreen.max_simds = 5; + rdev->config.evergreen.max_backends = 2 * rdev->config.evergreen.num_ses; + rdev->config.evergreen.max_gprs = 256; + rdev->config.evergreen.max_threads = 248; + rdev->config.evergreen.max_gs_threads = 32; + rdev->config.evergreen.max_stack_entries = 256; + rdev->config.evergreen.sx_num_of_sets = 4; + rdev->config.evergreen.sx_max_export_size = 256; + rdev->config.evergreen.sx_max_export_pos_size = 64; + rdev->config.evergreen.sx_max_export_smx_size = 192; + rdev->config.evergreen.max_hw_contexts = 8; + rdev->config.evergreen.sq_num_cf_insts = 2; + + rdev->config.evergreen.sc_prim_fifo_size = 0x100; + rdev->config.evergreen.sc_hiz_tile_fifo_size = 0x30; + rdev->config.evergreen.sc_earlyz_tile_fifo_size = 0x130; + break; + case CHIP_CEDAR: + default: + rdev->config.evergreen.num_ses = 1; + rdev->config.evergreen.max_pipes = 2; + rdev->config.evergreen.max_tile_pipes = 2; + rdev->config.evergreen.max_simds = 2; + rdev->config.evergreen.max_backends = 1 * rdev->config.evergreen.num_ses; + rdev->config.evergreen.max_gprs = 256; + rdev->config.evergreen.max_threads = 192; + rdev->config.evergreen.max_gs_threads = 16; + rdev->config.evergreen.max_stack_entries = 256; + rdev->config.evergreen.sx_num_of_sets = 4; + rdev->config.evergreen.sx_max_export_size = 128; + rdev->config.evergreen.sx_max_export_pos_size = 32; + rdev->config.evergreen.sx_max_export_smx_size = 96; + rdev->config.evergreen.max_hw_contexts = 4; + rdev->config.evergreen.sq_num_cf_insts = 1; + + rdev->config.evergreen.sc_prim_fifo_size = 0x40; + rdev->config.evergreen.sc_hiz_tile_fifo_size = 0x30; + rdev->config.evergreen.sc_earlyz_tile_fifo_size = 0x130; + break; + } + + /* Initialize HDP */ + for (i = 0, j = 0; i < 32; i++, j += 0x18) { + WREG32((0x2c14 + j), 0x00000000); + WREG32((0x2c18 + j), 0x00000000); + WREG32((0x2c1c + j), 0x00000000); + WREG32((0x2c20 + j), 0x00000000); + WREG32((0x2c24 + j), 0x00000000); + } + + WREG32(GRBM_CNTL, GRBM_READ_TIMEOUT(0xff)); + + cc_gc_shader_pipe_config = RREG32(CC_GC_SHADER_PIPE_CONFIG) & ~2; + + cc_gc_shader_pipe_config |= + INACTIVE_QD_PIPES((EVERGREEN_MAX_PIPES_MASK << rdev->config.evergreen.max_pipes) + & EVERGREEN_MAX_PIPES_MASK); + cc_gc_shader_pipe_config |= + INACTIVE_SIMDS((EVERGREEN_MAX_SIMDS_MASK << rdev->config.evergreen.max_simds) + & EVERGREEN_MAX_SIMDS_MASK); + + cc_rb_backend_disable = + BACKEND_DISABLE((EVERGREEN_MAX_BACKENDS_MASK << rdev->config.evergreen.max_backends) + & EVERGREEN_MAX_BACKENDS_MASK); + + + mc_shared_chmap = RREG32(MC_SHARED_CHMAP); + mc_arb_ramcfg = RREG32(MC_ARB_RAMCFG); + + switch (rdev->config.evergreen.max_tile_pipes) { + case 1: + default: + gb_addr_config |= NUM_PIPES(0); + break; + case 2: + gb_addr_config |= NUM_PIPES(1); + break; + case 4: + gb_addr_config |= NUM_PIPES(2); + break; + case 8: + gb_addr_config |= NUM_PIPES(3); + break; + } + + gb_addr_config |= PIPE_INTERLEAVE_SIZE((mc_arb_ramcfg & BURSTLENGTH_MASK) >> BURSTLENGTH_SHIFT); + gb_addr_config |= BANK_INTERLEAVE_SIZE(0); + gb_addr_config |= NUM_SHADER_ENGINES(rdev->config.evergreen.num_ses - 1); + gb_addr_config |= SHADER_ENGINE_TILE_SIZE(1); + gb_addr_config |= NUM_GPUS(0); /* Hemlock? */ + gb_addr_config |= MULTI_GPU_TILE_SIZE(2); + + if (((mc_arb_ramcfg & NOOFCOLS_MASK) >> NOOFCOLS_SHIFT) > 2) + gb_addr_config |= ROW_SIZE(2); + else + gb_addr_config |= ROW_SIZE((mc_arb_ramcfg & NOOFCOLS_MASK) >> NOOFCOLS_SHIFT); + + if (rdev->ddev->pdev->device == 0x689e) { + u32 efuse_straps_4; + u32 efuse_straps_3; + u8 efuse_box_bit_131_124; + + WREG32(RCU_IND_INDEX, 0x204); + efuse_straps_4 = RREG32(RCU_IND_DATA); + WREG32(RCU_IND_INDEX, 0x203); + efuse_straps_3 = RREG32(RCU_IND_DATA); + efuse_box_bit_131_124 = (u8)(((efuse_straps_4 & 0xf) << 4) | ((efuse_straps_3 & 0xf0000000) >> 28)); + + switch(efuse_box_bit_131_124) { + case 0x00: + gb_backend_map = 0x76543210; + break; + case 0x55: + gb_backend_map = 0x77553311; + break; + case 0x56: + gb_backend_map = 0x77553300; + break; + case 0x59: + gb_backend_map = 0x77552211; + break; + case 0x66: + gb_backend_map = 0x77443300; + break; + case 0x99: + gb_backend_map = 0x66552211; + break; + case 0x5a: + gb_backend_map = 0x77552200; + break; + case 0xaa: + gb_backend_map = 0x66442200; + break; + case 0x95: + gb_backend_map = 0x66553311; + break; + default: + DRM_ERROR("bad backend map, using default\n"); + gb_backend_map = + evergreen_get_tile_pipe_to_backend_map(rdev, + rdev->config.evergreen.max_tile_pipes, + rdev->config.evergreen.max_backends, + ((EVERGREEN_MAX_BACKENDS_MASK << + rdev->config.evergreen.max_backends) & + EVERGREEN_MAX_BACKENDS_MASK)); + break; + } + } else if (rdev->ddev->pdev->device == 0x68b9) { + u32 efuse_straps_3; + u8 efuse_box_bit_127_124; + + WREG32(RCU_IND_INDEX, 0x203); + efuse_straps_3 = RREG32(RCU_IND_DATA); + efuse_box_bit_127_124 = (u8)(efuse_straps_3 & 0xF0000000) >> 28; + + switch(efuse_box_bit_127_124) { + case 0x0: + gb_backend_map = 0x00003210; + break; + case 0x5: + case 0x6: + case 0x9: + case 0xa: + gb_backend_map = 0x00003311; + break; + default: + DRM_ERROR("bad backend map, using default\n"); + gb_backend_map = + evergreen_get_tile_pipe_to_backend_map(rdev, + rdev->config.evergreen.max_tile_pipes, + rdev->config.evergreen.max_backends, + ((EVERGREEN_MAX_BACKENDS_MASK << + rdev->config.evergreen.max_backends) & + EVERGREEN_MAX_BACKENDS_MASK)); + break; + } + } else + gb_backend_map = + evergreen_get_tile_pipe_to_backend_map(rdev, + rdev->config.evergreen.max_tile_pipes, + rdev->config.evergreen.max_backends, + ((EVERGREEN_MAX_BACKENDS_MASK << + rdev->config.evergreen.max_backends) & + EVERGREEN_MAX_BACKENDS_MASK)); + + WREG32(GB_BACKEND_MAP, gb_backend_map); + WREG32(GB_ADDR_CONFIG, gb_addr_config); + WREG32(DMIF_ADDR_CONFIG, gb_addr_config); + WREG32(HDP_ADDR_CONFIG, gb_addr_config); + + num_shader_engines = ((RREG32(GB_ADDR_CONFIG) & NUM_SHADER_ENGINES(3)) >> 12) + 1; + grbm_gfx_index = INSTANCE_BROADCAST_WRITES; + + for (i = 0; i < rdev->config.evergreen.num_ses; i++) { + u32 rb = cc_rb_backend_disable | (0xf0 << 16); + u32 sp = cc_gc_shader_pipe_config; + u32 gfx = grbm_gfx_index | SE_INDEX(i); + + if (i == num_shader_engines) { + rb |= BACKEND_DISABLE(EVERGREEN_MAX_BACKENDS_MASK); + sp |= INACTIVE_SIMDS(EVERGREEN_MAX_SIMDS_MASK); + } + + WREG32(GRBM_GFX_INDEX, gfx); + WREG32(RLC_GFX_INDEX, gfx); + + WREG32(CC_RB_BACKEND_DISABLE, rb); + WREG32(CC_SYS_RB_BACKEND_DISABLE, rb); + WREG32(GC_USER_RB_BACKEND_DISABLE, rb); + WREG32(CC_GC_SHADER_PIPE_CONFIG, sp); + } + + grbm_gfx_index |= SE_BROADCAST_WRITES; + WREG32(GRBM_GFX_INDEX, grbm_gfx_index); + WREG32(RLC_GFX_INDEX, grbm_gfx_index); + + WREG32(CGTS_SYS_TCC_DISABLE, 0); + WREG32(CGTS_TCC_DISABLE, 0); + WREG32(CGTS_USER_SYS_TCC_DISABLE, 0); + WREG32(CGTS_USER_TCC_DISABLE, 0); + + /* set HW defaults for 3D engine */ + WREG32(CP_QUEUE_THRESHOLDS, (ROQ_IB1_START(0x16) | + ROQ_IB2_START(0x2b))); + + WREG32(CP_MEQ_THRESHOLDS, STQ_SPLIT(0x30)); + + WREG32(TA_CNTL_AUX, (DISABLE_CUBE_ANISO | + SYNC_GRADIENT | + SYNC_WALKER | + SYNC_ALIGNER)); + + sx_debug_1 = RREG32(SX_DEBUG_1); + sx_debug_1 |= ENABLE_NEW_SMX_ADDRESS; + WREG32(SX_DEBUG_1, sx_debug_1); + + + smx_dc_ctl0 = RREG32(SMX_DC_CTL0); + smx_dc_ctl0 &= ~NUMBER_OF_SETS(0x1ff); + smx_dc_ctl0 |= NUMBER_OF_SETS(rdev->config.evergreen.sx_num_of_sets); + WREG32(SMX_DC_CTL0, smx_dc_ctl0); + + WREG32(SX_EXPORT_BUFFER_SIZES, (COLOR_BUFFER_SIZE((rdev->config.evergreen.sx_max_export_size / 4) - 1) | + POSITION_BUFFER_SIZE((rdev->config.evergreen.sx_max_export_pos_size / 4) - 1) | + SMX_BUFFER_SIZE((rdev->config.evergreen.sx_max_export_smx_size / 4) - 1))); + + WREG32(PA_SC_FIFO_SIZE, (SC_PRIM_FIFO_SIZE(rdev->config.evergreen.sc_prim_fifo_size) | + SC_HIZ_TILE_FIFO_SIZE(rdev->config.evergreen.sc_hiz_tile_fifo_size) | + SC_EARLYZ_TILE_FIFO_SIZE(rdev->config.evergreen.sc_earlyz_tile_fifo_size))); + + WREG32(VGT_NUM_INSTANCES, 1); + WREG32(SPI_CONFIG_CNTL, 0); + WREG32(SPI_CONFIG_CNTL_1, VTX_DONE_DELAY(4)); + WREG32(CP_PERFMON_CNTL, 0); + + WREG32(SQ_MS_FIFO_SIZES, (CACHE_FIFO_SIZE(16 * rdev->config.evergreen.sq_num_cf_insts) | + FETCH_FIFO_HIWATER(0x4) | + DONE_FIFO_HIWATER(0xe0) | + ALU_UPDATE_FIFO_HIWATER(0x8))); + + sq_config = RREG32(SQ_CONFIG); + sq_config &= ~(PS_PRIO(3) | + VS_PRIO(3) | + GS_PRIO(3) | + ES_PRIO(3)); + sq_config |= (VC_ENABLE | + EXPORT_SRC_C | + PS_PRIO(0) | + VS_PRIO(1) | + GS_PRIO(2) | + ES_PRIO(3)); + + if (rdev->family == CHIP_CEDAR) + /* no vertex cache */ + sq_config &= ~VC_ENABLE; + + sq_lds_resource_mgmt = RREG32(SQ_LDS_RESOURCE_MGMT); + + sq_gpr_resource_mgmt_1 = NUM_PS_GPRS((rdev->config.evergreen.max_gprs - (4 * 2))* 12 / 32); + sq_gpr_resource_mgmt_1 |= NUM_VS_GPRS((rdev->config.evergreen.max_gprs - (4 * 2)) * 6 / 32); + sq_gpr_resource_mgmt_1 |= NUM_CLAUSE_TEMP_GPRS(4); + sq_gpr_resource_mgmt_2 = NUM_GS_GPRS((rdev->config.evergreen.max_gprs - (4 * 2)) * 4 / 32); + sq_gpr_resource_mgmt_2 |= NUM_ES_GPRS((rdev->config.evergreen.max_gprs - (4 * 2)) * 4 / 32); + sq_gpr_resource_mgmt_3 = NUM_HS_GPRS((rdev->config.evergreen.max_gprs - (4 * 2)) * 3 / 32); + sq_gpr_resource_mgmt_3 |= NUM_LS_GPRS((rdev->config.evergreen.max_gprs - (4 * 2)) * 3 / 32); + + if (rdev->family == CHIP_CEDAR) + ps_thread_count = 96; + else + ps_thread_count = 128; + + sq_thread_resource_mgmt = NUM_PS_THREADS(ps_thread_count); + sq_thread_resource_mgmt |= NUM_VS_THREADS(((rdev->config.evergreen.max_threads - ps_thread_count) / 6) / 8) * 8; + sq_thread_resource_mgmt |= NUM_GS_THREADS(((rdev->config.evergreen.max_threads - ps_thread_count) / 6) / 8) * 8; + sq_thread_resource_mgmt |= NUM_ES_THREADS(((rdev->config.evergreen.max_threads - ps_thread_count) / 6) / 8) * 8; + sq_thread_resource_mgmt_2 = NUM_HS_THREADS(((rdev->config.evergreen.max_threads - ps_thread_count) / 6) / 8) * 8; + sq_thread_resource_mgmt_2 |= NUM_LS_THREADS(((rdev->config.evergreen.max_threads - ps_thread_count) / 6) / 8) * 8; + + sq_stack_resource_mgmt_1 = NUM_PS_STACK_ENTRIES((rdev->config.evergreen.max_stack_entries * 1) / 6); + sq_stack_resource_mgmt_1 |= NUM_VS_STACK_ENTRIES((rdev->config.evergreen.max_stack_entries * 1) / 6); + sq_stack_resource_mgmt_2 = NUM_GS_STACK_ENTRIES((rdev->config.evergreen.max_stack_entries * 1) / 6); + sq_stack_resource_mgmt_2 |= NUM_ES_STACK_ENTRIES((rdev->config.evergreen.max_stack_entries * 1) / 6); + sq_stack_resource_mgmt_3 = NUM_HS_STACK_ENTRIES((rdev->config.evergreen.max_stack_entries * 1) / 6); + sq_stack_resource_mgmt_3 |= NUM_LS_STACK_ENTRIES((rdev->config.evergreen.max_stack_entries * 1) / 6); + + WREG32(SQ_CONFIG, sq_config); + WREG32(SQ_GPR_RESOURCE_MGMT_1, sq_gpr_resource_mgmt_1); + WREG32(SQ_GPR_RESOURCE_MGMT_2, sq_gpr_resource_mgmt_2); + WREG32(SQ_GPR_RESOURCE_MGMT_3, sq_gpr_resource_mgmt_3); + WREG32(SQ_THREAD_RESOURCE_MGMT, sq_thread_resource_mgmt); + WREG32(SQ_THREAD_RESOURCE_MGMT_2, sq_thread_resource_mgmt_2); + WREG32(SQ_STACK_RESOURCE_MGMT_1, sq_stack_resource_mgmt_1); + WREG32(SQ_STACK_RESOURCE_MGMT_2, sq_stack_resource_mgmt_2); + WREG32(SQ_STACK_RESOURCE_MGMT_3, sq_stack_resource_mgmt_3); + WREG32(SQ_DYN_GPR_CNTL_PS_FLUSH_REQ, 0); + WREG32(SQ_LDS_RESOURCE_MGMT, sq_lds_resource_mgmt); + + WREG32(PA_SC_FORCE_EOV_MAX_CNTS, (FORCE_EOV_MAX_CLK_CNT(4095) | + FORCE_EOV_MAX_REZ_CNT(255))); + + if (rdev->family == CHIP_CEDAR) + vgt_cache_invalidation = CACHE_INVALIDATION(TC_ONLY); + else + vgt_cache_invalidation = CACHE_INVALIDATION(VC_AND_TC); + vgt_cache_invalidation |= AUTO_INVLD_EN(ES_AND_GS_AUTO); + WREG32(VGT_CACHE_INVALIDATION, vgt_cache_invalidation); + + WREG32(VGT_GS_VERTEX_REUSE, 16); + WREG32(PA_SC_LINE_STIPPLE_STATE, 0); + + WREG32(CB_PERF_CTR0_SEL_0, 0); + WREG32(CB_PERF_CTR0_SEL_1, 0); + WREG32(CB_PERF_CTR1_SEL_0, 0); + WREG32(CB_PERF_CTR1_SEL_1, 0); + WREG32(CB_PERF_CTR2_SEL_0, 0); + WREG32(CB_PERF_CTR2_SEL_1, 0); + WREG32(CB_PERF_CTR3_SEL_0, 0); + WREG32(CB_PERF_CTR3_SEL_1, 0); + + hdp_host_path_cntl = RREG32(HDP_HOST_PATH_CNTL); + WREG32(HDP_HOST_PATH_CNTL, hdp_host_path_cntl); + + WREG32(PA_CL_ENHANCE, CLIP_VTX_REORDER_ENA | NUM_CLIP_SEQ(3)); + + udelay(50); + } int evergreen_mc_init(struct radeon_device *rdev) diff --git a/drivers/gpu/drm/radeon/evergreend.h b/drivers/gpu/drm/radeon/evergreend.h index 7c290a6dd0e3..effe335356c7 100644 --- a/drivers/gpu/drm/radeon/evergreend.h +++ b/drivers/gpu/drm/radeon/evergreend.h @@ -24,12 +24,49 @@ #ifndef EVERGREEND_H #define EVERGREEND_H +#define EVERGREEN_MAX_SH_GPRS 256 +#define EVERGREEN_MAX_TEMP_GPRS 16 +#define EVERGREEN_MAX_SH_THREADS 256 +#define EVERGREEN_MAX_SH_STACK_ENTRIES 4096 +#define EVERGREEN_MAX_FRC_EOV_CNT 16384 +#define EVERGREEN_MAX_BACKENDS 8 +#define EVERGREEN_MAX_BACKENDS_MASK 0xFF +#define EVERGREEN_MAX_SIMDS 16 +#define EVERGREEN_MAX_SIMDS_MASK 0xFFFF +#define EVERGREEN_MAX_PIPES 8 +#define EVERGREEN_MAX_PIPES_MASK 0xFF +#define EVERGREEN_MAX_LDS_NUM 0xFFFF + /* Registers */ -#define CC_GC_SHADER_PIPE_CONFIG 0x8950 -#define CC_RB_BACKEND_DISABLE 0x98F4 -#define BACKEND_DISABLE(x) ((x) << 16) +#define RCU_IND_INDEX 0x100 +#define RCU_IND_DATA 0x104 + +#define GRBM_GFX_INDEX 0x802C +#define INSTANCE_INDEX(x) ((x) << 0) +#define SE_INDEX(x) ((x) << 16) +#define INSTANCE_BROADCAST_WRITES (1 << 30) +#define SE_BROADCAST_WRITES (1 << 31) +#define RLC_GFX_INDEX 0x3fC4 +#define CC_GC_SHADER_PIPE_CONFIG 0x8950 +#define WRITE_DIS (1 << 0) +#define CC_RB_BACKEND_DISABLE 0x98F4 +#define BACKEND_DISABLE(x) ((x) << 16) +#define GB_ADDR_CONFIG 0x98F8 +#define NUM_PIPES(x) ((x) << 0) +#define PIPE_INTERLEAVE_SIZE(x) ((x) << 4) +#define BANK_INTERLEAVE_SIZE(x) ((x) << 8) +#define NUM_SHADER_ENGINES(x) ((x) << 12) +#define SHADER_ENGINE_TILE_SIZE(x) ((x) << 16) +#define NUM_GPUS(x) ((x) << 20) +#define MULTI_GPU_TILE_SIZE(x) ((x) << 24) +#define ROW_SIZE(x) ((x) << 28) +#define GB_BACKEND_MAP 0x98FC +#define DMIF_ADDR_CONFIG 0xBD4 +#define HDP_ADDR_CONFIG 0x2F48 + #define CC_SYS_RB_BACKEND_DISABLE 0x3F88 +#define GC_USER_RB_BACKEND_DISABLE 0x9B7C #define CGTS_SYS_TCC_DISABLE 0x3F90 #define CGTS_TCC_DISABLE 0x9148 @@ -38,9 +75,9 @@ #define CONFIG_MEMSIZE 0x5428 -#define CP_ME_CNTL 0x86D8 -#define CP_ME_HALT (1<<28) -#define CP_PFP_HALT (1<<26) +#define CP_ME_CNTL 0x86D8 +#define CP_ME_HALT (1 << 28) +#define CP_PFP_HALT (1 << 26) #define CP_ME_RAM_DATA 0xC160 #define CP_ME_RAM_RADDR 0xC158 #define CP_ME_RAM_WADDR 0xC15C @@ -53,10 +90,10 @@ #define ROQ_IB1_START(x) ((x) << 0) #define ROQ_IB2_START(x) ((x) << 8) #define CP_RB_CNTL 0xC104 -#define RB_BUFSZ(x) ((x)<<0) -#define RB_BLKSZ(x) ((x)<<8) -#define RB_NO_UPDATE (1<<27) -#define RB_RPTR_WR_ENA (1<<31) +#define RB_BUFSZ(x) ((x) << 0) +#define RB_BLKSZ(x) ((x) << 8) +#define RB_NO_UPDATE (1 << 27) +#define RB_RPTR_WR_ENA (1 << 31) #define BUF_SWAP_32BIT (2 << 16) #define CP_RB_RPTR 0x8700 #define CP_RB_RPTR_ADDR 0xC10C @@ -184,9 +221,10 @@ #define PA_SC_FIFO_SIZE 0x8BCC #define SC_PRIM_FIFO_SIZE(x) ((x) << 0) #define SC_HIZ_TILE_FIFO_SIZE(x) ((x) << 12) +#define SC_EARLYZ_TILE_FIFO_SIZE(x) ((x) << 20) #define PA_SC_FORCE_EOV_MAX_CNTS 0x8B24 -#define FORCE_EOV_MAX_CLK_CNT(x) ((x)<<0) -#define FORCE_EOV_MAX_REZ_CNT(x) ((x)<<16) +#define FORCE_EOV_MAX_CLK_CNT(x) ((x) << 0) +#define FORCE_EOV_MAX_REZ_CNT(x) ((x) << 16) #define PA_SC_LINE_STIPPLE 0x28A0C #define PA_SC_LINE_STIPPLE_STATE 0x8B10 @@ -203,7 +241,7 @@ #define SMX_DC_CTL0 0xA020 #define USE_HASH_FUNCTION (1 << 0) -#define CACHE_DEPTH(x) ((x) << 1) +#define NUMBER_OF_SETS(x) ((x) << 1) #define FLUSH_ALL_ON_EVENT (1 << 10) #define STALL_ON_EVENT (1 << 11) #define SMX_EVENT_CTL 0xA02C @@ -234,6 +272,13 @@ #define SQ_CONFIG 0x8C00 #define VC_ENABLE (1 << 0) #define EXPORT_SRC_C (1 << 1) +#define CS_PRIO(x) ((x) << 18) +#define LS_PRIO(x) ((x) << 20) +#define HS_PRIO(x) ((x) << 22) +#define PS_PRIO(x) ((x) << 24) +#define VS_PRIO(x) ((x) << 26) +#define GS_PRIO(x) ((x) << 28) +#define ES_PRIO(x) ((x) << 30) #define SQ_GPR_RESOURCE_MGMT_1 0x8C04 #define NUM_PS_GPRS(x) ((x) << 0) #define NUM_VS_GPRS(x) ((x) << 16) @@ -241,6 +286,29 @@ #define SQ_GPR_RESOURCE_MGMT_2 0x8C08 #define NUM_GS_GPRS(x) ((x) << 0) #define NUM_ES_GPRS(x) ((x) << 16) +#define SQ_GPR_RESOURCE_MGMT_3 0x8C0C +#define NUM_HS_GPRS(x) ((x) << 0) +#define NUM_LS_GPRS(x) ((x) << 16) +#define SQ_THREAD_RESOURCE_MGMT 0x8C18 +#define NUM_PS_THREADS(x) ((x) << 0) +#define NUM_VS_THREADS(x) ((x) << 8) +#define NUM_GS_THREADS(x) ((x) << 16) +#define NUM_ES_THREADS(x) ((x) << 24) +#define SQ_THREAD_RESOURCE_MGMT_2 0x8C1C +#define NUM_HS_THREADS(x) ((x) << 0) +#define NUM_LS_THREADS(x) ((x) << 8) +#define SQ_STACK_RESOURCE_MGMT_1 0x8C20 +#define NUM_PS_STACK_ENTRIES(x) ((x) << 0) +#define NUM_VS_STACK_ENTRIES(x) ((x) << 16) +#define SQ_STACK_RESOURCE_MGMT_2 0x8C24 +#define NUM_GS_STACK_ENTRIES(x) ((x) << 0) +#define NUM_ES_STACK_ENTRIES(x) ((x) << 16) +#define SQ_STACK_RESOURCE_MGMT_3 0x8C28 +#define NUM_HS_STACK_ENTRIES(x) ((x) << 0) +#define NUM_LS_STACK_ENTRIES(x) ((x) << 16) +#define SQ_DYN_GPR_CNTL_PS_FLUSH_REQ 0x8D8C +#define SQ_LDS_RESOURCE_MGMT 0x8E2C + #define SQ_MS_FIFO_SIZES 0x8CF0 #define CACHE_FIFO_SIZE(x) ((x) << 0) #define FETCH_FIFO_HIWATER(x) ((x) << 8) @@ -255,6 +323,15 @@ #define SMX_BUFFER_SIZE(x) ((x) << 16) #define SX_MISC 0x28350 +#define CB_PERF_CTR0_SEL_0 0x9A20 +#define CB_PERF_CTR0_SEL_1 0x9A24 +#define CB_PERF_CTR1_SEL_0 0x9A28 +#define CB_PERF_CTR1_SEL_1 0x9A2C +#define CB_PERF_CTR2_SEL_0 0x9A30 +#define CB_PERF_CTR2_SEL_1 0x9A34 +#define CB_PERF_CTR3_SEL_0 0x9A38 +#define CB_PERF_CTR3_SEL_1 0x9A3C + #define TA_CNTL_AUX 0x9508 #define DISABLE_CUBE_WRAP (1 << 0) #define DISABLE_CUBE_ANISO (1 << 1) @@ -263,7 +340,7 @@ #define SYNC_ALIGNER (1 << 26) #define VGT_CACHE_INVALIDATION 0x88C4 -#define CACHE_INVALIDATION(x) ((x)<<0) +#define CACHE_INVALIDATION(x) ((x) << 0) #define VC_ONLY 0 #define TC_ONLY 1 #define VC_AND_TC 2 diff --git a/drivers/gpu/drm/radeon/radeon.h b/drivers/gpu/drm/radeon/radeon.h index 4ac97ab28947..a77a86203996 100644 --- a/drivers/gpu/drm/radeon/radeon.h +++ b/drivers/gpu/drm/radeon/radeon.h @@ -870,11 +870,36 @@ struct rv770_asic { struct r100_gpu_lockup lockup; }; +struct evergreen_asic { + unsigned num_ses; + unsigned max_pipes; + unsigned max_tile_pipes; + unsigned max_simds; + unsigned max_backends; + unsigned max_gprs; + unsigned max_threads; + unsigned max_stack_entries; + unsigned max_hw_contexts; + unsigned max_gs_threads; + unsigned sx_max_export_size; + unsigned sx_max_export_pos_size; + unsigned sx_max_export_smx_size; + unsigned sq_num_cf_insts; + unsigned sx_num_of_sets; + unsigned sc_prim_fifo_size; + unsigned sc_hiz_tile_fifo_size; + unsigned sc_earlyz_tile_fifo_size; + unsigned tiling_nbanks; + unsigned tiling_npipes; + unsigned tiling_group_size; +}; + union radeon_asic_config { struct r300_asic r300; struct r100_asic r100; struct r600_asic r600; struct rv770_asic rv770; + struct evergreen_asic evergreen; }; /* -- cgit v1.2.3 From fe251e2fffa1ebc17c8e6e895b0374ae4e732fa5 Mon Sep 17 00:00:00 2001 From: Alex Deucher Date: Wed, 24 Mar 2010 13:36:43 -0400 Subject: drm/radeon/kms/evergreen: setup and enable the CP The command processor (CP) fetches command buffers and feeds the GPU. This patch requires the evergreen family me and pfp ucode files. Signed-off-by: Alex Deucher Signed-off-by: Dave Airlie --- drivers/gpu/drm/radeon/evergreen.c | 117 ++++++++++++++++++++++++++++------- drivers/gpu/drm/radeon/evergreend.h | 2 + drivers/gpu/drm/radeon/r600.c | 47 ++++++++++++-- drivers/gpu/drm/radeon/radeon.h | 4 ++ drivers/gpu/drm/radeon/radeon_asic.c | 6 +- drivers/gpu/drm/radeon/rv770.c | 10 ++- 6 files changed, 154 insertions(+), 32 deletions(-) (limited to 'drivers/gpu/drm/radeon') diff --git a/drivers/gpu/drm/radeon/evergreen.c b/drivers/gpu/drm/radeon/evergreen.c index 26b219bb1388..57fe569682df 100644 --- a/drivers/gpu/drm/radeon/evergreen.c +++ b/drivers/gpu/drm/radeon/evergreen.c @@ -32,6 +32,9 @@ #include "avivod.h" #include "evergreen_reg.h" +#define EVERGREEN_PFP_UCODE_SIZE 1120 +#define EVERGREEN_PM4_UCODE_SIZE 1376 + static void evergreen_gpu_init(struct radeon_device *rdev); void evergreen_fini(struct radeon_device *rdev); @@ -418,23 +421,91 @@ static void evergreen_mc_program(struct radeon_device *rdev) rv515_vga_render_disable(rdev); } -#if 0 /* * CP. */ -static void evergreen_cp_stop(struct radeon_device *rdev) -{ - /* XXX */ -} - static int evergreen_cp_load_microcode(struct radeon_device *rdev) { - /* XXX */ + const __be32 *fw_data; + int i; + + if (!rdev->me_fw || !rdev->pfp_fw) + return -EINVAL; + r700_cp_stop(rdev); + WREG32(CP_RB_CNTL, RB_NO_UPDATE | (15 << 8) | (3 << 0)); + + fw_data = (const __be32 *)rdev->pfp_fw->data; + WREG32(CP_PFP_UCODE_ADDR, 0); + for (i = 0; i < EVERGREEN_PFP_UCODE_SIZE; i++) + WREG32(CP_PFP_UCODE_DATA, be32_to_cpup(fw_data++)); + WREG32(CP_PFP_UCODE_ADDR, 0); + + fw_data = (const __be32 *)rdev->me_fw->data; + WREG32(CP_ME_RAM_WADDR, 0); + for (i = 0; i < EVERGREEN_PM4_UCODE_SIZE; i++) + WREG32(CP_ME_RAM_DATA, be32_to_cpup(fw_data++)); + + WREG32(CP_PFP_UCODE_ADDR, 0); + WREG32(CP_ME_RAM_WADDR, 0); + WREG32(CP_ME_RAM_RADDR, 0); return 0; } + +int evergreen_cp_resume(struct radeon_device *rdev) +{ + u32 tmp; + u32 rb_bufsz; + int r; + + /* Reset cp; if cp is reset, then PA, SH, VGT also need to be reset */ + WREG32(GRBM_SOFT_RESET, (SOFT_RESET_CP | + SOFT_RESET_PA | + SOFT_RESET_SH | + SOFT_RESET_VGT | + SOFT_RESET_SX)); + RREG32(GRBM_SOFT_RESET); + mdelay(15); + WREG32(GRBM_SOFT_RESET, 0); + RREG32(GRBM_SOFT_RESET); + + /* Set ring buffer size */ + rb_bufsz = drm_order(rdev->cp.ring_size / 8); + tmp = RB_NO_UPDATE | (drm_order(RADEON_GPU_PAGE_SIZE/8) << 8) | rb_bufsz; +#ifdef __BIG_ENDIAN + tmp |= BUF_SWAP_32BIT; #endif + WREG32(CP_RB_CNTL, tmp); + WREG32(CP_SEM_WAIT_TIMER, 0x4); + + /* Set the write pointer delay */ + WREG32(CP_RB_WPTR_DELAY, 0); + + /* Initialize the ring buffer's read and write pointers */ + WREG32(CP_RB_CNTL, tmp | RB_RPTR_WR_ENA); + WREG32(CP_RB_RPTR_WR, 0); + WREG32(CP_RB_WPTR, 0); + WREG32(CP_RB_RPTR_ADDR, rdev->cp.gpu_addr & 0xFFFFFFFF); + WREG32(CP_RB_RPTR_ADDR_HI, upper_32_bits(rdev->cp.gpu_addr)); + mdelay(1); + WREG32(CP_RB_CNTL, tmp); + + WREG32(CP_RB_BASE, rdev->cp.gpu_addr >> 8); + WREG32(CP_DEBUG, (1 << 27) | (1 << 28)); + + rdev->cp.rptr = RREG32(CP_RB_RPTR); + rdev->cp.wptr = RREG32(CP_RB_WPTR); + + r600_cp_start(rdev); + rdev->cp.ready = true; + r = radeon_ring_test(rdev); + if (r) { + rdev->cp.ready = false; + return r; + } + return 0; +} /* * Core functions @@ -1138,15 +1209,15 @@ static int evergreen_startup(struct radeon_device *rdev) { int r; -#if 0 - if (!rdev->me_fw || !rdev->pfp_fw || !rdev->rlc_fw) { + /* XXX until interrupts are supported */ + if (!rdev->me_fw || !rdev->pfp_fw /*|| !rdev->rlc_fw*/) { r = r600_init_microcode(rdev); if (r) { DRM_ERROR("Failed to load firmware!\n"); return r; } } -#endif + evergreen_mc_program(rdev); if (rdev->flags & RADEON_IS_AGP) { evergreen_agp_enable(rdev); @@ -1184,6 +1255,7 @@ static int evergreen_startup(struct radeon_device *rdev) return r; } r600_irq_set(rdev); +#endif r = radeon_ring_init(rdev, rdev->cp.ring_size); if (r) @@ -1191,12 +1263,12 @@ static int evergreen_startup(struct radeon_device *rdev) r = evergreen_cp_load_microcode(rdev); if (r) return r; - r = r600_cp_resume(rdev); + r = evergreen_cp_resume(rdev); if (r) return r; /* write back buffer are not vital so don't worry about failure */ r600_wb_enable(rdev); -#endif + return 0; } @@ -1221,13 +1293,13 @@ int evergreen_resume(struct radeon_device *rdev) DRM_ERROR("r600 startup failed on resume\n"); return r; } -#if 0 + r = r600_ib_test(rdev); if (r) { DRM_ERROR("radeon: failled testing IB (%d).\n", r); return r; } -#endif + return r; } @@ -1236,12 +1308,11 @@ int evergreen_suspend(struct radeon_device *rdev) { #if 0 int r; - +#endif /* FIXME: we should wait for ring to be empty */ r700_cp_stop(rdev); rdev->cp.ready = false; r600_wb_disable(rdev); -#endif evergreen_pcie_gart_disable(rdev); #if 0 @@ -1348,10 +1419,10 @@ int evergreen_init(struct radeon_device *rdev) r = radeon_irq_kms_init(rdev); if (r) return r; - +#endif rdev->cp.ring_obj = NULL; r600_ring_init(rdev, 1024 * 1024); - +#if 0 rdev->ih.ring_obj = NULL; r600_ih_ring_init(rdev, 64 * 1024); #endif @@ -1362,9 +1433,13 @@ int evergreen_init(struct radeon_device *rdev) rdev->accel_working = false; r = evergreen_startup(rdev); if (r) { - evergreen_suspend(rdev); - /*r600_wb_fini(rdev);*/ - /*radeon_ring_fini(rdev);*/ + dev_err(rdev->dev, "disabling GPU acceleration\n"); + r700_cp_fini(rdev); + r600_wb_fini(rdev); +#if 0 + r600_irq_fini(rdev); + radeon_irq_kms_fini(rdev); +#endif evergreen_pcie_gart_fini(rdev); rdev->accel_working = false; } diff --git a/drivers/gpu/drm/radeon/evergreend.h b/drivers/gpu/drm/radeon/evergreend.h index effe335356c7..10e9768534da 100644 --- a/drivers/gpu/drm/radeon/evergreend.h +++ b/drivers/gpu/drm/radeon/evergreend.h @@ -89,6 +89,7 @@ #define CP_QUEUE_THRESHOLDS 0x8760 #define ROQ_IB1_START(x) ((x) << 0) #define ROQ_IB2_START(x) ((x) << 8) +#define CP_RB_BASE 0xC100 #define CP_RB_CNTL 0xC104 #define RB_BUFSZ(x) ((x) << 0) #define RB_BLKSZ(x) ((x) << 8) @@ -104,6 +105,7 @@ #define CP_RB_WPTR_ADDR_HI 0xC11C #define CP_RB_WPTR_DELAY 0x8704 #define CP_SEM_WAIT_TIMER 0x85BC +#define CP_DEBUG 0xC1FC #define GC_USER_SHADER_PIPE_CONFIG 0x8954 diff --git a/drivers/gpu/drm/radeon/r600.c b/drivers/gpu/drm/radeon/r600.c index 13c9cc34231d..4b0225715b93 100644 --- a/drivers/gpu/drm/radeon/r600.c +++ b/drivers/gpu/drm/radeon/r600.c @@ -43,6 +43,8 @@ #define R700_PFP_UCODE_SIZE 848 #define R700_PM4_UCODE_SIZE 1360 #define R700_RLC_UCODE_SIZE 1024 +#define EVERGREEN_PFP_UCODE_SIZE 1120 +#define EVERGREEN_PM4_UCODE_SIZE 1376 /* Firmware Names */ MODULE_FIRMWARE("radeon/R600_pfp.bin"); @@ -67,6 +69,14 @@ MODULE_FIRMWARE("radeon/RV710_pfp.bin"); MODULE_FIRMWARE("radeon/RV710_me.bin"); MODULE_FIRMWARE("radeon/R600_rlc.bin"); MODULE_FIRMWARE("radeon/R700_rlc.bin"); +MODULE_FIRMWARE("radeon/CEDAR_pfp.bin"); +MODULE_FIRMWARE("radeon/CEDAR_me.bin"); +MODULE_FIRMWARE("radeon/REDWOOD_pfp.bin"); +MODULE_FIRMWARE("radeon/REDWOOD_me.bin"); +MODULE_FIRMWARE("radeon/JUNIPER_pfp.bin"); +MODULE_FIRMWARE("radeon/JUNIPER_me.bin"); +MODULE_FIRMWARE("radeon/CYRPESS_pfp.bin"); +MODULE_FIRMWARE("radeon/CYPRESS_me.bin"); int r600_debugfs_mc_info_init(struct radeon_device *rdev); @@ -1449,10 +1459,31 @@ int r600_init_microcode(struct radeon_device *rdev) chip_name = "RV710"; rlc_chip_name = "R700"; break; + case CHIP_CEDAR: + chip_name = "CEDAR"; + rlc_chip_name = ""; + break; + case CHIP_REDWOOD: + chip_name = "REDWOOD"; + rlc_chip_name = ""; + break; + case CHIP_JUNIPER: + chip_name = "JUNIPER"; + rlc_chip_name = ""; + break; + case CHIP_CYPRESS: + case CHIP_HEMLOCK: + chip_name = "CYPRESS"; + rlc_chip_name = ""; + break; default: BUG(); } - if (rdev->family >= CHIP_RV770) { + if (rdev->family >= CHIP_CEDAR) { + pfp_req_size = EVERGREEN_PFP_UCODE_SIZE * 4; + me_req_size = EVERGREEN_PM4_UCODE_SIZE * 4; + rlc_req_size = 0; + } else if (rdev->family >= CHIP_RV770) { pfp_req_size = R700_PFP_UCODE_SIZE * 4; me_req_size = R700_PM4_UCODE_SIZE * 4; rlc_req_size = R700_RLC_UCODE_SIZE * 4; @@ -1487,6 +1518,8 @@ int r600_init_microcode(struct radeon_device *rdev) err = -EINVAL; } + /* XXX until evergreen interrupts are supported */ + if (rdev->family < CHIP_CEDAR) { snprintf(fw_name, sizeof(fw_name), "radeon/%s_rlc.bin", rlc_chip_name); err = request_firmware(&rdev->rlc_fw, fw_name, &pdev->dev); if (err) @@ -1497,6 +1530,7 @@ int r600_init_microcode(struct radeon_device *rdev) rdev->rlc_fw->size, fw_name); err = -EINVAL; } + } out: platform_device_unregister(pdev); @@ -1566,12 +1600,15 @@ int r600_cp_start(struct radeon_device *rdev) } radeon_ring_write(rdev, PACKET3(PACKET3_ME_INITIALIZE, 5)); radeon_ring_write(rdev, 0x1); - if (rdev->family < CHIP_RV770) { - radeon_ring_write(rdev, 0x3); - radeon_ring_write(rdev, rdev->config.r600.max_hw_contexts - 1); - } else { + if (rdev->family >= CHIP_CEDAR) { + radeon_ring_write(rdev, 0x0); + radeon_ring_write(rdev, rdev->config.evergreen.max_hw_contexts - 1); + } else if (rdev->family >= CHIP_RV770) { radeon_ring_write(rdev, 0x0); radeon_ring_write(rdev, rdev->config.rv770.max_hw_contexts - 1); + } else { + radeon_ring_write(rdev, 0x3); + radeon_ring_write(rdev, rdev->config.r600.max_hw_contexts - 1); } radeon_ring_write(rdev, PACKET3_ME_INITIALIZE_DEVICE_ID(1)); radeon_ring_write(rdev, 0); diff --git a/drivers/gpu/drm/radeon/radeon.h b/drivers/gpu/drm/radeon/radeon.h index a77a86203996..acf21d7e3cb2 100644 --- a/drivers/gpu/drm/radeon/radeon.h +++ b/drivers/gpu/drm/radeon/radeon.h @@ -1300,6 +1300,7 @@ extern void rs690_line_buffer_adjust(struct radeon_device *rdev, extern void r600_vram_gtt_location(struct radeon_device *rdev, struct radeon_mc *mc); extern bool r600_card_posted(struct radeon_device *rdev); extern void r600_cp_stop(struct radeon_device *rdev); +extern int r600_cp_start(struct radeon_device *rdev); extern void r600_ring_init(struct radeon_device *rdev, unsigned ring_size); extern int r600_cp_resume(struct radeon_device *rdev); extern void r600_cp_fini(struct radeon_device *rdev); @@ -1340,6 +1341,9 @@ extern void r600_hdmi_update_audio_settings(struct drm_encoder *encoder, uint8_t status_bits, uint8_t category_code); +extern void r700_cp_stop(struct radeon_device *rdev); +extern void r700_cp_fini(struct radeon_device *rdev); + /* evergreen */ struct evergreen_mc_save { u32 vga_control[6]; diff --git a/drivers/gpu/drm/radeon/radeon_asic.c b/drivers/gpu/drm/radeon/radeon_asic.c index d923e4b234d2..3a576ab805cf 100644 --- a/drivers/gpu/drm/radeon/radeon_asic.c +++ b/drivers/gpu/drm/radeon/radeon_asic.c @@ -635,14 +635,14 @@ static struct radeon_asic evergreen_asic = { .fini = &evergreen_fini, .suspend = &evergreen_suspend, .resume = &evergreen_resume, - .cp_commit = NULL, + .cp_commit = &r600_cp_commit, .gpu_is_lockup = &evergreen_gpu_is_lockup, .asic_reset = &evergreen_asic_reset, .vga_set_state = &r600_vga_set_state, .gart_tlb_flush = &evergreen_pcie_gart_tlb_flush, .gart_set_page = &rs600_gart_set_page, - .ring_test = NULL, - .ring_ib_execute = NULL, + .ring_test = &r600_ring_test, + .ring_ib_execute = &r600_ring_ib_execute, .irq_set = NULL, .irq_process = NULL, .get_vblank_counter = NULL, diff --git a/drivers/gpu/drm/radeon/rv770.c b/drivers/gpu/drm/radeon/rv770.c index 2b8a4e170654..2642d2642641 100644 --- a/drivers/gpu/drm/radeon/rv770.c +++ b/drivers/gpu/drm/radeon/rv770.c @@ -236,7 +236,6 @@ void r700_cp_stop(struct radeon_device *rdev) WREG32(CP_ME_CNTL, (CP_ME_HALT | CP_PFP_HALT)); } - static int rv770_cp_load_microcode(struct radeon_device *rdev) { const __be32 *fw_data; @@ -271,6 +270,11 @@ static int rv770_cp_load_microcode(struct radeon_device *rdev) return 0; } +void r700_cp_fini(struct radeon_device *rdev) +{ + r700_cp_stop(rdev); + radeon_ring_fini(rdev); +} /* * Core functions @@ -1125,7 +1129,7 @@ int rv770_init(struct radeon_device *rdev) r = rv770_startup(rdev); if (r) { dev_err(rdev->dev, "disabling GPU acceleration\n"); - r600_cp_fini(rdev); + r700_cp_fini(rdev); r600_wb_fini(rdev); r600_irq_fini(rdev); radeon_irq_kms_fini(rdev); @@ -1159,7 +1163,7 @@ void rv770_fini(struct radeon_device *rdev) { radeon_pm_fini(rdev); r600_blit_fini(rdev); - r600_cp_fini(rdev); + r700_cp_fini(rdev); r600_wb_fini(rdev); r600_irq_fini(rdev); radeon_irq_kms_fini(rdev); -- cgit v1.2.3 From 45f9a39bedc3afab3fc85567792efc0103f34a55 Mon Sep 17 00:00:00 2001 From: Alex Deucher Date: Wed, 24 Mar 2010 13:55:51 -0400 Subject: drm/radeon/kms/evergreen: implement irq support Signed-off-by: Alex Deucher Signed-off-by: Dave Airlie --- drivers/gpu/drm/radeon/atombios_crtc.c | 8 +- drivers/gpu/drm/radeon/evergreen.c | 549 ++++++++++++++++++++++++++++++++- drivers/gpu/drm/radeon/evergreend.h | 148 +++++++++ drivers/gpu/drm/radeon/r600.c | 40 ++- drivers/gpu/drm/radeon/radeon.h | 5 +- drivers/gpu/drm/radeon/radeon_asic.c | 6 +- drivers/gpu/drm/radeon/radeon_asic.h | 4 + 7 files changed, 719 insertions(+), 41 deletions(-) (limited to 'drivers/gpu/drm/radeon') diff --git a/drivers/gpu/drm/radeon/atombios_crtc.c b/drivers/gpu/drm/radeon/atombios_crtc.c index fd4ef6d18849..6300675dd488 100644 --- a/drivers/gpu/drm/radeon/atombios_crtc.c +++ b/drivers/gpu/drm/radeon/atombios_crtc.c @@ -249,17 +249,13 @@ void atombios_crtc_dpms(struct drm_crtc *crtc, int mode) if (ASIC_IS_DCE3(rdev)) atombios_enable_crtc_memreq(crtc, ATOM_ENABLE); atombios_blank_crtc(crtc, ATOM_DISABLE); - /* XXX re-enable when interrupt support is added */ - if (!ASIC_IS_DCE4(rdev)) - drm_vblank_post_modeset(dev, radeon_crtc->crtc_id); + drm_vblank_post_modeset(dev, radeon_crtc->crtc_id); radeon_crtc_load_lut(crtc); break; case DRM_MODE_DPMS_STANDBY: case DRM_MODE_DPMS_SUSPEND: case DRM_MODE_DPMS_OFF: - /* XXX re-enable when interrupt support is added */ - if (!ASIC_IS_DCE4(rdev)) - drm_vblank_pre_modeset(dev, radeon_crtc->crtc_id); + drm_vblank_pre_modeset(dev, radeon_crtc->crtc_id); atombios_blank_crtc(crtc, ATOM_ENABLE); if (ASIC_IS_DCE3(rdev)) atombios_enable_crtc_memreq(crtc, ATOM_DISABLE); diff --git a/drivers/gpu/drm/radeon/evergreen.c b/drivers/gpu/drm/radeon/evergreen.c index 57fe569682df..5c34349058c1 100644 --- a/drivers/gpu/drm/radeon/evergreen.c +++ b/drivers/gpu/drm/radeon/evergreen.c @@ -1205,12 +1205,532 @@ int evergreen_asic_reset(struct radeon_device *rdev) return evergreen_gpu_soft_reset(rdev); } +/* Interrupts */ + +u32 evergreen_get_vblank_counter(struct radeon_device *rdev, int crtc) +{ + switch (crtc) { + case 0: + return RREG32(CRTC_STATUS_FRAME_COUNT + EVERGREEN_CRTC0_REGISTER_OFFSET); + case 1: + return RREG32(CRTC_STATUS_FRAME_COUNT + EVERGREEN_CRTC1_REGISTER_OFFSET); + case 2: + return RREG32(CRTC_STATUS_FRAME_COUNT + EVERGREEN_CRTC2_REGISTER_OFFSET); + case 3: + return RREG32(CRTC_STATUS_FRAME_COUNT + EVERGREEN_CRTC3_REGISTER_OFFSET); + case 4: + return RREG32(CRTC_STATUS_FRAME_COUNT + EVERGREEN_CRTC4_REGISTER_OFFSET); + case 5: + return RREG32(CRTC_STATUS_FRAME_COUNT + EVERGREEN_CRTC5_REGISTER_OFFSET); + default: + return 0; + } +} + +void evergreen_disable_interrupt_state(struct radeon_device *rdev) +{ + u32 tmp; + + WREG32(CP_INT_CNTL, 0); + WREG32(GRBM_INT_CNTL, 0); + WREG32(INT_MASK + EVERGREEN_CRTC0_REGISTER_OFFSET, 0); + WREG32(INT_MASK + EVERGREEN_CRTC1_REGISTER_OFFSET, 0); + WREG32(INT_MASK + EVERGREEN_CRTC2_REGISTER_OFFSET, 0); + WREG32(INT_MASK + EVERGREEN_CRTC3_REGISTER_OFFSET, 0); + WREG32(INT_MASK + EVERGREEN_CRTC4_REGISTER_OFFSET, 0); + WREG32(INT_MASK + EVERGREEN_CRTC5_REGISTER_OFFSET, 0); + + WREG32(GRPH_INT_CONTROL + EVERGREEN_CRTC0_REGISTER_OFFSET, 0); + WREG32(GRPH_INT_CONTROL + EVERGREEN_CRTC1_REGISTER_OFFSET, 0); + WREG32(GRPH_INT_CONTROL + EVERGREEN_CRTC2_REGISTER_OFFSET, 0); + WREG32(GRPH_INT_CONTROL + EVERGREEN_CRTC3_REGISTER_OFFSET, 0); + WREG32(GRPH_INT_CONTROL + EVERGREEN_CRTC4_REGISTER_OFFSET, 0); + WREG32(GRPH_INT_CONTROL + EVERGREEN_CRTC5_REGISTER_OFFSET, 0); + + WREG32(DACA_AUTODETECT_INT_CONTROL, 0); + WREG32(DACB_AUTODETECT_INT_CONTROL, 0); + + tmp = RREG32(DC_HPD1_INT_CONTROL) & DC_HPDx_INT_POLARITY; + WREG32(DC_HPD1_INT_CONTROL, tmp); + tmp = RREG32(DC_HPD2_INT_CONTROL) & DC_HPDx_INT_POLARITY; + WREG32(DC_HPD2_INT_CONTROL, tmp); + tmp = RREG32(DC_HPD3_INT_CONTROL) & DC_HPDx_INT_POLARITY; + WREG32(DC_HPD3_INT_CONTROL, tmp); + tmp = RREG32(DC_HPD4_INT_CONTROL) & DC_HPDx_INT_POLARITY; + WREG32(DC_HPD4_INT_CONTROL, tmp); + tmp = RREG32(DC_HPD5_INT_CONTROL) & DC_HPDx_INT_POLARITY; + WREG32(DC_HPD5_INT_CONTROL, tmp); + tmp = RREG32(DC_HPD6_INT_CONTROL) & DC_HPDx_INT_POLARITY; + WREG32(DC_HPD6_INT_CONTROL, tmp); + +} + +int evergreen_irq_set(struct radeon_device *rdev) +{ + u32 cp_int_cntl = CNTX_BUSY_INT_ENABLE | CNTX_EMPTY_INT_ENABLE; + u32 crtc1 = 0, crtc2 = 0, crtc3 = 0, crtc4 = 0, crtc5 = 0, crtc6 = 0; + u32 hpd1, hpd2, hpd3, hpd4, hpd5, hpd6; + + if (!rdev->irq.installed) { + WARN(1, "Can't enable IRQ/MSI because no handler is installed.\n"); + return -EINVAL; + } + /* don't enable anything if the ih is disabled */ + if (!rdev->ih.enabled) { + r600_disable_interrupts(rdev); + /* force the active interrupt state to all disabled */ + evergreen_disable_interrupt_state(rdev); + return 0; + } + + hpd1 = RREG32(DC_HPD1_INT_CONTROL) & ~DC_HPDx_INT_EN; + hpd2 = RREG32(DC_HPD2_INT_CONTROL) & ~DC_HPDx_INT_EN; + hpd3 = RREG32(DC_HPD3_INT_CONTROL) & ~DC_HPDx_INT_EN; + hpd4 = RREG32(DC_HPD4_INT_CONTROL) & ~DC_HPDx_INT_EN; + hpd5 = RREG32(DC_HPD5_INT_CONTROL) & ~DC_HPDx_INT_EN; + hpd6 = RREG32(DC_HPD6_INT_CONTROL) & ~DC_HPDx_INT_EN; + + if (rdev->irq.sw_int) { + DRM_DEBUG("evergreen_irq_set: sw int\n"); + cp_int_cntl |= RB_INT_ENABLE; + } + if (rdev->irq.crtc_vblank_int[0]) { + DRM_DEBUG("evergreen_irq_set: vblank 0\n"); + crtc1 |= VBLANK_INT_MASK; + } + if (rdev->irq.crtc_vblank_int[1]) { + DRM_DEBUG("evergreen_irq_set: vblank 1\n"); + crtc2 |= VBLANK_INT_MASK; + } + if (rdev->irq.crtc_vblank_int[2]) { + DRM_DEBUG("evergreen_irq_set: vblank 2\n"); + crtc3 |= VBLANK_INT_MASK; + } + if (rdev->irq.crtc_vblank_int[3]) { + DRM_DEBUG("evergreen_irq_set: vblank 3\n"); + crtc4 |= VBLANK_INT_MASK; + } + if (rdev->irq.crtc_vblank_int[4]) { + DRM_DEBUG("evergreen_irq_set: vblank 4\n"); + crtc5 |= VBLANK_INT_MASK; + } + if (rdev->irq.crtc_vblank_int[5]) { + DRM_DEBUG("evergreen_irq_set: vblank 5\n"); + crtc6 |= VBLANK_INT_MASK; + } + if (rdev->irq.hpd[0]) { + DRM_DEBUG("evergreen_irq_set: hpd 1\n"); + hpd1 |= DC_HPDx_INT_EN; + } + if (rdev->irq.hpd[1]) { + DRM_DEBUG("evergreen_irq_set: hpd 2\n"); + hpd2 |= DC_HPDx_INT_EN; + } + if (rdev->irq.hpd[2]) { + DRM_DEBUG("evergreen_irq_set: hpd 3\n"); + hpd3 |= DC_HPDx_INT_EN; + } + if (rdev->irq.hpd[3]) { + DRM_DEBUG("evergreen_irq_set: hpd 4\n"); + hpd4 |= DC_HPDx_INT_EN; + } + if (rdev->irq.hpd[4]) { + DRM_DEBUG("evergreen_irq_set: hpd 5\n"); + hpd5 |= DC_HPDx_INT_EN; + } + if (rdev->irq.hpd[5]) { + DRM_DEBUG("evergreen_irq_set: hpd 6\n"); + hpd6 |= DC_HPDx_INT_EN; + } + + WREG32(CP_INT_CNTL, cp_int_cntl); + + WREG32(INT_MASK + EVERGREEN_CRTC0_REGISTER_OFFSET, crtc1); + WREG32(INT_MASK + EVERGREEN_CRTC1_REGISTER_OFFSET, crtc2); + WREG32(INT_MASK + EVERGREEN_CRTC2_REGISTER_OFFSET, crtc3); + WREG32(INT_MASK + EVERGREEN_CRTC3_REGISTER_OFFSET, crtc4); + WREG32(INT_MASK + EVERGREEN_CRTC4_REGISTER_OFFSET, crtc5); + WREG32(INT_MASK + EVERGREEN_CRTC5_REGISTER_OFFSET, crtc6); + + WREG32(DC_HPD1_INT_CONTROL, hpd1); + WREG32(DC_HPD2_INT_CONTROL, hpd2); + WREG32(DC_HPD3_INT_CONTROL, hpd3); + WREG32(DC_HPD4_INT_CONTROL, hpd4); + WREG32(DC_HPD5_INT_CONTROL, hpd5); + WREG32(DC_HPD6_INT_CONTROL, hpd6); + + return 0; +} + +static inline void evergreen_irq_ack(struct radeon_device *rdev, + u32 *disp_int, + u32 *disp_int_cont, + u32 *disp_int_cont2, + u32 *disp_int_cont3, + u32 *disp_int_cont4, + u32 *disp_int_cont5) +{ + u32 tmp; + + *disp_int = RREG32(DISP_INTERRUPT_STATUS); + *disp_int_cont = RREG32(DISP_INTERRUPT_STATUS_CONTINUE); + *disp_int_cont2 = RREG32(DISP_INTERRUPT_STATUS_CONTINUE2); + *disp_int_cont3 = RREG32(DISP_INTERRUPT_STATUS_CONTINUE3); + *disp_int_cont4 = RREG32(DISP_INTERRUPT_STATUS_CONTINUE4); + *disp_int_cont5 = RREG32(DISP_INTERRUPT_STATUS_CONTINUE5); + + if (*disp_int & LB_D1_VBLANK_INTERRUPT) + WREG32(VBLANK_STATUS + EVERGREEN_CRTC0_REGISTER_OFFSET, VBLANK_ACK); + if (*disp_int & LB_D1_VLINE_INTERRUPT) + WREG32(VLINE_STATUS + EVERGREEN_CRTC0_REGISTER_OFFSET, VLINE_ACK); + + if (*disp_int_cont & LB_D2_VBLANK_INTERRUPT) + WREG32(VBLANK_STATUS + EVERGREEN_CRTC1_REGISTER_OFFSET, VBLANK_ACK); + if (*disp_int_cont & LB_D2_VLINE_INTERRUPT) + WREG32(VLINE_STATUS + EVERGREEN_CRTC1_REGISTER_OFFSET, VLINE_ACK); + + if (*disp_int_cont2 & LB_D3_VBLANK_INTERRUPT) + WREG32(VBLANK_STATUS + EVERGREEN_CRTC2_REGISTER_OFFSET, VBLANK_ACK); + if (*disp_int_cont2 & LB_D3_VLINE_INTERRUPT) + WREG32(VLINE_STATUS + EVERGREEN_CRTC2_REGISTER_OFFSET, VLINE_ACK); + + if (*disp_int_cont3 & LB_D4_VBLANK_INTERRUPT) + WREG32(VBLANK_STATUS + EVERGREEN_CRTC3_REGISTER_OFFSET, VBLANK_ACK); + if (*disp_int_cont3 & LB_D4_VLINE_INTERRUPT) + WREG32(VLINE_STATUS + EVERGREEN_CRTC3_REGISTER_OFFSET, VLINE_ACK); + + if (*disp_int_cont4 & LB_D5_VBLANK_INTERRUPT) + WREG32(VBLANK_STATUS + EVERGREEN_CRTC4_REGISTER_OFFSET, VBLANK_ACK); + if (*disp_int_cont4 & LB_D5_VLINE_INTERRUPT) + WREG32(VLINE_STATUS + EVERGREEN_CRTC4_REGISTER_OFFSET, VLINE_ACK); + + if (*disp_int_cont5 & LB_D6_VBLANK_INTERRUPT) + WREG32(VBLANK_STATUS + EVERGREEN_CRTC5_REGISTER_OFFSET, VBLANK_ACK); + if (*disp_int_cont5 & LB_D6_VLINE_INTERRUPT) + WREG32(VLINE_STATUS + EVERGREEN_CRTC5_REGISTER_OFFSET, VLINE_ACK); + + if (*disp_int & DC_HPD1_INTERRUPT) { + tmp = RREG32(DC_HPD1_INT_CONTROL); + tmp |= DC_HPDx_INT_ACK; + WREG32(DC_HPD1_INT_CONTROL, tmp); + } + if (*disp_int_cont & DC_HPD2_INTERRUPT) { + tmp = RREG32(DC_HPD2_INT_CONTROL); + tmp |= DC_HPDx_INT_ACK; + WREG32(DC_HPD2_INT_CONTROL, tmp); + } + if (*disp_int_cont2 & DC_HPD3_INTERRUPT) { + tmp = RREG32(DC_HPD3_INT_CONTROL); + tmp |= DC_HPDx_INT_ACK; + WREG32(DC_HPD3_INT_CONTROL, tmp); + } + if (*disp_int_cont3 & DC_HPD4_INTERRUPT) { + tmp = RREG32(DC_HPD4_INT_CONTROL); + tmp |= DC_HPDx_INT_ACK; + WREG32(DC_HPD4_INT_CONTROL, tmp); + } + if (*disp_int_cont4 & DC_HPD5_INTERRUPT) { + tmp = RREG32(DC_HPD5_INT_CONTROL); + tmp |= DC_HPDx_INT_ACK; + WREG32(DC_HPD5_INT_CONTROL, tmp); + } + if (*disp_int_cont5 & DC_HPD6_INTERRUPT) { + tmp = RREG32(DC_HPD5_INT_CONTROL); + tmp |= DC_HPDx_INT_ACK; + WREG32(DC_HPD6_INT_CONTROL, tmp); + } +} + +void evergreen_irq_disable(struct radeon_device *rdev) +{ + u32 disp_int, disp_int_cont, disp_int_cont2; + u32 disp_int_cont3, disp_int_cont4, disp_int_cont5; + + r600_disable_interrupts(rdev); + /* Wait and acknowledge irq */ + mdelay(1); + evergreen_irq_ack(rdev, &disp_int, &disp_int_cont, &disp_int_cont2, + &disp_int_cont3, &disp_int_cont4, &disp_int_cont5); + evergreen_disable_interrupt_state(rdev); +} + +static void evergreen_irq_suspend(struct radeon_device *rdev) +{ + evergreen_irq_disable(rdev); + r600_rlc_stop(rdev); +} + +static inline u32 evergreen_get_ih_wptr(struct radeon_device *rdev) +{ + u32 wptr, tmp; + + /* XXX use writeback */ + wptr = RREG32(IH_RB_WPTR); + + if (wptr & RB_OVERFLOW) { + /* When a ring buffer overflow happen start parsing interrupt + * from the last not overwritten vector (wptr + 16). Hopefully + * this should allow us to catchup. + */ + dev_warn(rdev->dev, "IH ring buffer overflow (0x%08X, %d, %d)\n", + wptr, rdev->ih.rptr, (wptr + 16) + rdev->ih.ptr_mask); + rdev->ih.rptr = (wptr + 16) & rdev->ih.ptr_mask; + tmp = RREG32(IH_RB_CNTL); + tmp |= IH_WPTR_OVERFLOW_CLEAR; + WREG32(IH_RB_CNTL, tmp); + } + return (wptr & rdev->ih.ptr_mask); +} + +int evergreen_irq_process(struct radeon_device *rdev) +{ + u32 wptr = evergreen_get_ih_wptr(rdev); + u32 rptr = rdev->ih.rptr; + u32 src_id, src_data; + u32 ring_index; + u32 disp_int, disp_int_cont, disp_int_cont2; + u32 disp_int_cont3, disp_int_cont4, disp_int_cont5; + unsigned long flags; + bool queue_hotplug = false; + + DRM_DEBUG("r600_irq_process start: rptr %d, wptr %d\n", rptr, wptr); + if (!rdev->ih.enabled) + return IRQ_NONE; + + spin_lock_irqsave(&rdev->ih.lock, flags); + + if (rptr == wptr) { + spin_unlock_irqrestore(&rdev->ih.lock, flags); + return IRQ_NONE; + } + if (rdev->shutdown) { + spin_unlock_irqrestore(&rdev->ih.lock, flags); + return IRQ_NONE; + } + +restart_ih: + /* display interrupts */ + evergreen_irq_ack(rdev, &disp_int, &disp_int_cont, &disp_int_cont2, + &disp_int_cont3, &disp_int_cont4, &disp_int_cont5); + + rdev->ih.wptr = wptr; + while (rptr != wptr) { + /* wptr/rptr are in bytes! */ + ring_index = rptr / 4; + src_id = rdev->ih.ring[ring_index] & 0xff; + src_data = rdev->ih.ring[ring_index + 1] & 0xfffffff; + + switch (src_id) { + case 1: /* D1 vblank/vline */ + switch (src_data) { + case 0: /* D1 vblank */ + if (disp_int & LB_D1_VBLANK_INTERRUPT) { + drm_handle_vblank(rdev->ddev, 0); + wake_up(&rdev->irq.vblank_queue); + disp_int &= ~LB_D1_VBLANK_INTERRUPT; + DRM_DEBUG("IH: D1 vblank\n"); + } + break; + case 1: /* D1 vline */ + if (disp_int & LB_D1_VLINE_INTERRUPT) { + disp_int &= ~LB_D1_VLINE_INTERRUPT; + DRM_DEBUG("IH: D1 vline\n"); + } + break; + default: + DRM_DEBUG("Unhandled interrupt: %d %d\n", src_id, src_data); + break; + } + break; + case 2: /* D2 vblank/vline */ + switch (src_data) { + case 0: /* D2 vblank */ + if (disp_int_cont & LB_D2_VBLANK_INTERRUPT) { + drm_handle_vblank(rdev->ddev, 1); + wake_up(&rdev->irq.vblank_queue); + disp_int_cont &= ~LB_D2_VBLANK_INTERRUPT; + DRM_DEBUG("IH: D2 vblank\n"); + } + break; + case 1: /* D2 vline */ + if (disp_int_cont & LB_D2_VLINE_INTERRUPT) { + disp_int_cont &= ~LB_D2_VLINE_INTERRUPT; + DRM_DEBUG("IH: D2 vline\n"); + } + break; + default: + DRM_DEBUG("Unhandled interrupt: %d %d\n", src_id, src_data); + break; + } + break; + case 3: /* D3 vblank/vline */ + switch (src_data) { + case 0: /* D3 vblank */ + if (disp_int_cont2 & LB_D3_VBLANK_INTERRUPT) { + drm_handle_vblank(rdev->ddev, 2); + wake_up(&rdev->irq.vblank_queue); + disp_int_cont2 &= ~LB_D3_VBLANK_INTERRUPT; + DRM_DEBUG("IH: D3 vblank\n"); + } + break; + case 1: /* D3 vline */ + if (disp_int_cont2 & LB_D3_VLINE_INTERRUPT) { + disp_int_cont2 &= ~LB_D3_VLINE_INTERRUPT; + DRM_DEBUG("IH: D3 vline\n"); + } + break; + default: + DRM_DEBUG("Unhandled interrupt: %d %d\n", src_id, src_data); + break; + } + break; + case 4: /* D4 vblank/vline */ + switch (src_data) { + case 0: /* D4 vblank */ + if (disp_int_cont3 & LB_D4_VBLANK_INTERRUPT) { + drm_handle_vblank(rdev->ddev, 3); + wake_up(&rdev->irq.vblank_queue); + disp_int_cont3 &= ~LB_D4_VBLANK_INTERRUPT; + DRM_DEBUG("IH: D4 vblank\n"); + } + break; + case 1: /* D4 vline */ + if (disp_int_cont3 & LB_D4_VLINE_INTERRUPT) { + disp_int_cont3 &= ~LB_D4_VLINE_INTERRUPT; + DRM_DEBUG("IH: D4 vline\n"); + } + break; + default: + DRM_DEBUG("Unhandled interrupt: %d %d\n", src_id, src_data); + break; + } + break; + case 5: /* D5 vblank/vline */ + switch (src_data) { + case 0: /* D5 vblank */ + if (disp_int_cont4 & LB_D5_VBLANK_INTERRUPT) { + drm_handle_vblank(rdev->ddev, 4); + wake_up(&rdev->irq.vblank_queue); + disp_int_cont4 &= ~LB_D5_VBLANK_INTERRUPT; + DRM_DEBUG("IH: D5 vblank\n"); + } + break; + case 1: /* D5 vline */ + if (disp_int_cont4 & LB_D5_VLINE_INTERRUPT) { + disp_int_cont4 &= ~LB_D5_VLINE_INTERRUPT; + DRM_DEBUG("IH: D5 vline\n"); + } + break; + default: + DRM_DEBUG("Unhandled interrupt: %d %d\n", src_id, src_data); + break; + } + break; + case 6: /* D6 vblank/vline */ + switch (src_data) { + case 0: /* D6 vblank */ + if (disp_int_cont5 & LB_D6_VBLANK_INTERRUPT) { + drm_handle_vblank(rdev->ddev, 5); + wake_up(&rdev->irq.vblank_queue); + disp_int_cont5 &= ~LB_D6_VBLANK_INTERRUPT; + DRM_DEBUG("IH: D6 vblank\n"); + } + break; + case 1: /* D6 vline */ + if (disp_int_cont5 & LB_D6_VLINE_INTERRUPT) { + disp_int_cont5 &= ~LB_D6_VLINE_INTERRUPT; + DRM_DEBUG("IH: D6 vline\n"); + } + break; + default: + DRM_DEBUG("Unhandled interrupt: %d %d\n", src_id, src_data); + break; + } + break; + case 42: /* HPD hotplug */ + switch (src_data) { + case 0: + if (disp_int & DC_HPD1_INTERRUPT) { + disp_int &= ~DC_HPD1_INTERRUPT; + queue_hotplug = true; + DRM_DEBUG("IH: HPD1\n"); + } + break; + case 1: + if (disp_int_cont & DC_HPD2_INTERRUPT) { + disp_int_cont &= ~DC_HPD2_INTERRUPT; + queue_hotplug = true; + DRM_DEBUG("IH: HPD2\n"); + } + break; + case 2: + if (disp_int_cont2 & DC_HPD3_INTERRUPT) { + disp_int_cont2 &= ~DC_HPD3_INTERRUPT; + queue_hotplug = true; + DRM_DEBUG("IH: HPD3\n"); + } + break; + case 3: + if (disp_int_cont3 & DC_HPD4_INTERRUPT) { + disp_int_cont3 &= ~DC_HPD4_INTERRUPT; + queue_hotplug = true; + DRM_DEBUG("IH: HPD4\n"); + } + break; + case 4: + if (disp_int_cont4 & DC_HPD5_INTERRUPT) { + disp_int_cont4 &= ~DC_HPD5_INTERRUPT; + queue_hotplug = true; + DRM_DEBUG("IH: HPD5\n"); + } + break; + case 5: + if (disp_int_cont5 & DC_HPD6_INTERRUPT) { + disp_int_cont5 &= ~DC_HPD6_INTERRUPT; + queue_hotplug = true; + DRM_DEBUG("IH: HPD6\n"); + } + break; + default: + DRM_DEBUG("Unhandled interrupt: %d %d\n", src_id, src_data); + break; + } + break; + case 176: /* CP_INT in ring buffer */ + case 177: /* CP_INT in IB1 */ + case 178: /* CP_INT in IB2 */ + DRM_DEBUG("IH: CP int: 0x%08x\n", src_data); + radeon_fence_process(rdev); + break; + case 181: /* CP EOP event */ + DRM_DEBUG("IH: CP EOP\n"); + break; + default: + DRM_DEBUG("Unhandled interrupt: %d %d\n", src_id, src_data); + break; + } + + /* wptr/rptr are in bytes! */ + rptr += 16; + rptr &= rdev->ih.ptr_mask; + } + /* make sure wptr hasn't changed while processing */ + wptr = evergreen_get_ih_wptr(rdev); + if (wptr != rdev->ih.wptr) + goto restart_ih; + if (queue_hotplug) + queue_work(rdev->wq, &rdev->hotplug_work); + rdev->ih.rptr = rptr; + WREG32(IH_RB_RPTR, rdev->ih.rptr); + spin_unlock_irqrestore(&rdev->ih.lock, flags); + return IRQ_HANDLED; +} + static int evergreen_startup(struct radeon_device *rdev) { int r; - /* XXX until interrupts are supported */ - if (!rdev->me_fw || !rdev->pfp_fw /*|| !rdev->rlc_fw*/) { + if (!rdev->me_fw || !rdev->pfp_fw || !rdev->rlc_fw) { r = r600_init_microcode(rdev); if (r) { DRM_ERROR("Failed to load firmware!\n"); @@ -1246,6 +1766,7 @@ static int evergreen_startup(struct radeon_device *rdev) DRM_ERROR("failed to pin blit object %d\n", r); return r; } +#endif /* Enable IRQ */ r = r600_irq_init(rdev); @@ -1254,8 +1775,7 @@ static int evergreen_startup(struct radeon_device *rdev) radeon_irq_kms_fini(rdev); return r; } - r600_irq_set(rdev); -#endif + evergreen_irq_set(rdev); r = radeon_ring_init(rdev, rdev->cp.ring_size); if (r) @@ -1312,8 +1832,8 @@ int evergreen_suspend(struct radeon_device *rdev) /* FIXME: we should wait for ring to be empty */ r700_cp_stop(rdev); rdev->cp.ready = false; + evergreen_irq_suspend(rdev); r600_wb_disable(rdev); - evergreen_pcie_gart_disable(rdev); #if 0 /* unpin shaders bo */ @@ -1415,17 +1935,17 @@ int evergreen_init(struct radeon_device *rdev) r = radeon_bo_init(rdev); if (r) return r; -#if 0 + r = radeon_irq_kms_init(rdev); if (r) return r; -#endif + rdev->cp.ring_obj = NULL; r600_ring_init(rdev, 1024 * 1024); -#if 0 + rdev->ih.ring_obj = NULL; r600_ih_ring_init(rdev, 64 * 1024); -#endif + r = r600_pcie_gart_init(rdev); if (r) return r; @@ -1436,10 +1956,8 @@ int evergreen_init(struct radeon_device *rdev) dev_err(rdev->dev, "disabling GPU acceleration\n"); r700_cp_fini(rdev); r600_wb_fini(rdev); -#if 0 r600_irq_fini(rdev); radeon_irq_kms_fini(rdev); -#endif evergreen_pcie_gart_fini(rdev); rdev->accel_working = false; } @@ -1461,14 +1979,11 @@ int evergreen_init(struct radeon_device *rdev) void evergreen_fini(struct radeon_device *rdev) { radeon_pm_fini(rdev); - evergreen_suspend(rdev); -#if 0 - r600_blit_fini(rdev); + /*r600_blit_fini(rdev);*/ + r700_cp_fini(rdev); + r600_wb_fini(rdev); r600_irq_fini(rdev); radeon_irq_kms_fini(rdev); - radeon_ring_fini(rdev); - r600_wb_fini(rdev); -#endif evergreen_pcie_gart_fini(rdev); radeon_gem_fini(rdev); radeon_fence_driver_fini(rdev); diff --git a/drivers/gpu/drm/radeon/evergreend.h b/drivers/gpu/drm/radeon/evergreend.h index 10e9768534da..93e9e17ad54a 100644 --- a/drivers/gpu/drm/radeon/evergreend.h +++ b/drivers/gpu/drm/radeon/evergreend.h @@ -405,4 +405,152 @@ #define SOFT_RESET_REGBB (1 << 22) #define SOFT_RESET_ORB (1 << 23) +#define IH_RB_CNTL 0x3e00 +# define IH_RB_ENABLE (1 << 0) +# define IH_IB_SIZE(x) ((x) << 1) /* log2 */ +# define IH_RB_FULL_DRAIN_ENABLE (1 << 6) +# define IH_WPTR_WRITEBACK_ENABLE (1 << 8) +# define IH_WPTR_WRITEBACK_TIMER(x) ((x) << 9) /* log2 */ +# define IH_WPTR_OVERFLOW_ENABLE (1 << 16) +# define IH_WPTR_OVERFLOW_CLEAR (1 << 31) +#define IH_RB_BASE 0x3e04 +#define IH_RB_RPTR 0x3e08 +#define IH_RB_WPTR 0x3e0c +# define RB_OVERFLOW (1 << 0) +# define WPTR_OFFSET_MASK 0x3fffc +#define IH_RB_WPTR_ADDR_HI 0x3e10 +#define IH_RB_WPTR_ADDR_LO 0x3e14 +#define IH_CNTL 0x3e18 +# define ENABLE_INTR (1 << 0) +# define IH_MC_SWAP(x) ((x) << 2) +# define IH_MC_SWAP_NONE 0 +# define IH_MC_SWAP_16BIT 1 +# define IH_MC_SWAP_32BIT 2 +# define IH_MC_SWAP_64BIT 3 +# define RPTR_REARM (1 << 4) +# define MC_WRREQ_CREDIT(x) ((x) << 15) +# define MC_WR_CLEAN_CNT(x) ((x) << 20) + +#define CP_INT_CNTL 0xc124 +# define CNTX_BUSY_INT_ENABLE (1 << 19) +# define CNTX_EMPTY_INT_ENABLE (1 << 20) +# define SCRATCH_INT_ENABLE (1 << 25) +# define TIME_STAMP_INT_ENABLE (1 << 26) +# define IB2_INT_ENABLE (1 << 29) +# define IB1_INT_ENABLE (1 << 30) +# define RB_INT_ENABLE (1 << 31) +#define CP_INT_STATUS 0xc128 +# define SCRATCH_INT_STAT (1 << 25) +# define TIME_STAMP_INT_STAT (1 << 26) +# define IB2_INT_STAT (1 << 29) +# define IB1_INT_STAT (1 << 30) +# define RB_INT_STAT (1 << 31) + +#define GRBM_INT_CNTL 0x8060 +# define RDERR_INT_ENABLE (1 << 0) +# define GUI_IDLE_INT_ENABLE (1 << 19) + +/* 0x6e98, 0x7a98, 0x10698, 0x11298, 0x11e98, 0x12a98 */ +#define CRTC_STATUS_FRAME_COUNT 0x6e98 + +/* 0x6bb8, 0x77b8, 0x103b8, 0x10fb8, 0x11bb8, 0x127b8 */ +#define VLINE_STATUS 0x6bb8 +# define VLINE_OCCURRED (1 << 0) +# define VLINE_ACK (1 << 4) +# define VLINE_STAT (1 << 12) +# define VLINE_INTERRUPT (1 << 16) +# define VLINE_INTERRUPT_TYPE (1 << 17) +/* 0x6bbc, 0x77bc, 0x103bc, 0x10fbc, 0x11bbc, 0x127bc */ +#define VBLANK_STATUS 0x6bbc +# define VBLANK_OCCURRED (1 << 0) +# define VBLANK_ACK (1 << 4) +# define VBLANK_STAT (1 << 12) +# define VBLANK_INTERRUPT (1 << 16) +# define VBLANK_INTERRUPT_TYPE (1 << 17) + +/* 0x6b40, 0x7740, 0x10340, 0x10f40, 0x11b40, 0x12740 */ +#define INT_MASK 0x6b40 +# define VBLANK_INT_MASK (1 << 0) +# define VLINE_INT_MASK (1 << 4) + +#define DISP_INTERRUPT_STATUS 0x60f4 +# define LB_D1_VLINE_INTERRUPT (1 << 2) +# define LB_D1_VBLANK_INTERRUPT (1 << 3) +# define DC_HPD1_INTERRUPT (1 << 17) +# define DC_HPD1_RX_INTERRUPT (1 << 18) +# define DACA_AUTODETECT_INTERRUPT (1 << 22) +# define DACB_AUTODETECT_INTERRUPT (1 << 23) +# define DC_I2C_SW_DONE_INTERRUPT (1 << 24) +# define DC_I2C_HW_DONE_INTERRUPT (1 << 25) +#define DISP_INTERRUPT_STATUS_CONTINUE 0x60f8 +# define LB_D2_VLINE_INTERRUPT (1 << 2) +# define LB_D2_VBLANK_INTERRUPT (1 << 3) +# define DC_HPD2_INTERRUPT (1 << 17) +# define DC_HPD2_RX_INTERRUPT (1 << 18) +# define DISP_TIMER_INTERRUPT (1 << 24) +#define DISP_INTERRUPT_STATUS_CONTINUE2 0x60fc +# define LB_D3_VLINE_INTERRUPT (1 << 2) +# define LB_D3_VBLANK_INTERRUPT (1 << 3) +# define DC_HPD3_INTERRUPT (1 << 17) +# define DC_HPD3_RX_INTERRUPT (1 << 18) +#define DISP_INTERRUPT_STATUS_CONTINUE3 0x6100 +# define LB_D4_VLINE_INTERRUPT (1 << 2) +# define LB_D4_VBLANK_INTERRUPT (1 << 3) +# define DC_HPD4_INTERRUPT (1 << 17) +# define DC_HPD4_RX_INTERRUPT (1 << 18) +#define DISP_INTERRUPT_STATUS_CONTINUE4 0x614c +# define LB_D5_VLINE_INTERRUPT (1 << 2) +# define LB_D5_VBLANK_INTERRUPT (1 << 3) +# define DC_HPD5_INTERRUPT (1 << 17) +# define DC_HPD5_RX_INTERRUPT (1 << 18) +#define DISP_INTERRUPT_STATUS_CONTINUE5 0x6050 +# define LB_D6_VLINE_INTERRUPT (1 << 2) +# define LB_D6_VBLANK_INTERRUPT (1 << 3) +# define DC_HPD6_INTERRUPT (1 << 17) +# define DC_HPD6_RX_INTERRUPT (1 << 18) + +/* 0x6858, 0x7458, 0x10058, 0x10c58, 0x11858, 0x12458 */ +#define GRPH_INT_STATUS 0x6858 +# define GRPH_PFLIP_INT_OCCURRED (1 << 0) +# define GRPH_PFLIP_INT_CLEAR (1 << 8) +/* 0x685c, 0x745c, 0x1005c, 0x10c5c, 0x1185c, 0x1245c */ +#define GRPH_INT_CONTROL 0x685c +# define GRPH_PFLIP_INT_MASK (1 << 0) +# define GRPH_PFLIP_INT_TYPE (1 << 8) + +#define DACA_AUTODETECT_INT_CONTROL 0x66c8 +#define DACB_AUTODETECT_INT_CONTROL 0x67c8 + +#define DC_HPD1_INT_STATUS 0x601c +#define DC_HPD2_INT_STATUS 0x6028 +#define DC_HPD3_INT_STATUS 0x6034 +#define DC_HPD4_INT_STATUS 0x6040 +#define DC_HPD5_INT_STATUS 0x604c +#define DC_HPD6_INT_STATUS 0x6058 +# define DC_HPDx_INT_STATUS (1 << 0) +# define DC_HPDx_SENSE (1 << 1) +# define DC_HPDx_RX_INT_STATUS (1 << 8) + +#define DC_HPD1_INT_CONTROL 0x6020 +#define DC_HPD2_INT_CONTROL 0x602c +#define DC_HPD3_INT_CONTROL 0x6038 +#define DC_HPD4_INT_CONTROL 0x6044 +#define DC_HPD5_INT_CONTROL 0x6050 +#define DC_HPD6_INT_CONTROL 0x605c +# define DC_HPDx_INT_ACK (1 << 0) +# define DC_HPDx_INT_POLARITY (1 << 8) +# define DC_HPDx_INT_EN (1 << 16) +# define DC_HPDx_RX_INT_ACK (1 << 20) +# define DC_HPDx_RX_INT_EN (1 << 24) + +#define DC_HPD1_CONTROL 0x6024 +#define DC_HPD2_CONTROL 0x6030 +#define DC_HPD3_CONTROL 0x603c +#define DC_HPD4_CONTROL 0x6048 +#define DC_HPD5_CONTROL 0x6054 +#define DC_HPD6_CONTROL 0x6060 +# define DC_HPDx_CONNECTION_TIMER(x) ((x) << 0) +# define DC_HPDx_RX_INT_TIMER(x) ((x) << 16) +# define DC_HPDx_EN (1 << 28) + #endif diff --git a/drivers/gpu/drm/radeon/r600.c b/drivers/gpu/drm/radeon/r600.c index 4b0225715b93..d178fa826eec 100644 --- a/drivers/gpu/drm/radeon/r600.c +++ b/drivers/gpu/drm/radeon/r600.c @@ -45,6 +45,7 @@ #define R700_RLC_UCODE_SIZE 1024 #define EVERGREEN_PFP_UCODE_SIZE 1120 #define EVERGREEN_PM4_UCODE_SIZE 1376 +#define EVERGREEN_RLC_UCODE_SIZE 768 /* Firmware Names */ MODULE_FIRMWARE("radeon/R600_pfp.bin"); @@ -71,12 +72,16 @@ MODULE_FIRMWARE("radeon/R600_rlc.bin"); MODULE_FIRMWARE("radeon/R700_rlc.bin"); MODULE_FIRMWARE("radeon/CEDAR_pfp.bin"); MODULE_FIRMWARE("radeon/CEDAR_me.bin"); +MODULE_FIRMWARE("radeon/CEDAR_rlc.bin"); MODULE_FIRMWARE("radeon/REDWOOD_pfp.bin"); MODULE_FIRMWARE("radeon/REDWOOD_me.bin"); +MODULE_FIRMWARE("radeon/REDWOOD_rlc.bin"); MODULE_FIRMWARE("radeon/JUNIPER_pfp.bin"); MODULE_FIRMWARE("radeon/JUNIPER_me.bin"); +MODULE_FIRMWARE("radeon/JUNIPER_rlc.bin"); MODULE_FIRMWARE("radeon/CYRPESS_pfp.bin"); MODULE_FIRMWARE("radeon/CYPRESS_me.bin"); +MODULE_FIRMWARE("radeon/CYPRESS_rlc.bin"); int r600_debugfs_mc_info_init(struct radeon_device *rdev); @@ -84,6 +89,7 @@ int r600_debugfs_mc_info_init(struct radeon_device *rdev); int r600_mc_wait_for_idle(struct radeon_device *rdev); void r600_gpu_init(struct radeon_device *rdev); void r600_fini(struct radeon_device *rdev); +void r600_irq_disable(struct radeon_device *rdev); /* hpd for digital panel detect/disconnect */ bool r600_hpd_sense(struct radeon_device *rdev, enum radeon_hpd_id hpd) @@ -1461,20 +1467,20 @@ int r600_init_microcode(struct radeon_device *rdev) break; case CHIP_CEDAR: chip_name = "CEDAR"; - rlc_chip_name = ""; + rlc_chip_name = "CEDAR"; break; case CHIP_REDWOOD: chip_name = "REDWOOD"; - rlc_chip_name = ""; + rlc_chip_name = "REDWOOD"; break; case CHIP_JUNIPER: chip_name = "JUNIPER"; - rlc_chip_name = ""; + rlc_chip_name = "JUNIPER"; break; case CHIP_CYPRESS: case CHIP_HEMLOCK: chip_name = "CYPRESS"; - rlc_chip_name = ""; + rlc_chip_name = "CYPRESS"; break; default: BUG(); } @@ -1482,7 +1488,7 @@ int r600_init_microcode(struct radeon_device *rdev) if (rdev->family >= CHIP_CEDAR) { pfp_req_size = EVERGREEN_PFP_UCODE_SIZE * 4; me_req_size = EVERGREEN_PM4_UCODE_SIZE * 4; - rlc_req_size = 0; + rlc_req_size = EVERGREEN_RLC_UCODE_SIZE * 4; } else if (rdev->family >= CHIP_RV770) { pfp_req_size = R700_PFP_UCODE_SIZE * 4; me_req_size = R700_PM4_UCODE_SIZE * 4; @@ -1518,8 +1524,6 @@ int r600_init_microcode(struct radeon_device *rdev) err = -EINVAL; } - /* XXX until evergreen interrupts are supported */ - if (rdev->family < CHIP_CEDAR) { snprintf(fw_name, sizeof(fw_name), "radeon/%s_rlc.bin", rlc_chip_name); err = request_firmware(&rdev->rlc_fw, fw_name, &pdev->dev); if (err) @@ -1530,7 +1534,6 @@ int r600_init_microcode(struct radeon_device *rdev) rdev->rlc_fw->size, fw_name); err = -EINVAL; } - } out: platform_device_unregister(pdev); @@ -2309,10 +2312,11 @@ static void r600_ih_ring_fini(struct radeon_device *rdev) } } -static void r600_rlc_stop(struct radeon_device *rdev) +void r600_rlc_stop(struct radeon_device *rdev) { - if (rdev->family >= CHIP_RV770) { + if ((rdev->family >= CHIP_RV770) && + (rdev->family <= CHIP_RV740)) { /* r7xx asics need to soft reset RLC before halting */ WREG32(SRBM_SOFT_RESET, SOFT_RESET_RLC); RREG32(SRBM_SOFT_RESET); @@ -2349,7 +2353,12 @@ static int r600_rlc_init(struct radeon_device *rdev) WREG32(RLC_UCODE_CNTL, 0); fw_data = (const __be32 *)rdev->rlc_fw->data; - if (rdev->family >= CHIP_RV770) { + if (rdev->family >= CHIP_CEDAR) { + for (i = 0; i < EVERGREEN_RLC_UCODE_SIZE; i++) { + WREG32(RLC_UCODE_ADDR, i); + WREG32(RLC_UCODE_DATA, be32_to_cpup(fw_data++)); + } + } else if (rdev->family >= CHIP_RV770) { for (i = 0; i < R700_RLC_UCODE_SIZE; i++) { WREG32(RLC_UCODE_ADDR, i); WREG32(RLC_UCODE_DATA, be32_to_cpup(fw_data++)); @@ -2379,7 +2388,7 @@ static void r600_enable_interrupts(struct radeon_device *rdev) rdev->ih.enabled = true; } -static void r600_disable_interrupts(struct radeon_device *rdev) +void r600_disable_interrupts(struct radeon_device *rdev) { u32 ih_rb_cntl = RREG32(IH_RB_CNTL); u32 ih_cntl = RREG32(IH_CNTL); @@ -2494,7 +2503,10 @@ int r600_irq_init(struct radeon_device *rdev) WREG32(IH_CNTL, ih_cntl); /* force the active interrupt state to all disabled */ - r600_disable_interrupt_state(rdev); + if (rdev->family >= CHIP_CEDAR) + evergreen_disable_interrupt_state(rdev); + else + r600_disable_interrupt_state(rdev); /* enable irqs */ r600_enable_interrupts(rdev); @@ -2504,7 +2516,7 @@ int r600_irq_init(struct radeon_device *rdev) void r600_irq_suspend(struct radeon_device *rdev) { - r600_disable_interrupts(rdev); + r600_irq_disable(rdev); r600_rlc_stop(rdev); } diff --git a/drivers/gpu/drm/radeon/radeon.h b/drivers/gpu/drm/radeon/radeon.h index acf21d7e3cb2..e0132ef093b4 100644 --- a/drivers/gpu/drm/radeon/radeon.h +++ b/drivers/gpu/drm/radeon/radeon.h @@ -372,7 +372,7 @@ struct radeon_irq { bool installed; bool sw_int; /* FIXME: use a define max crtc rather than hardcode it */ - bool crtc_vblank_int[2]; + bool crtc_vblank_int[6]; wait_queue_head_t vblank_queue; /* FIXME: use defines for max hpd/dacs */ bool hpd[6]; @@ -1324,6 +1324,8 @@ extern void r600_irq_fini(struct radeon_device *rdev); extern void r600_ih_ring_init(struct radeon_device *rdev, unsigned ring_size); extern int r600_irq_set(struct radeon_device *rdev); extern void r600_irq_suspend(struct radeon_device *rdev); +extern void r600_disable_interrupts(struct radeon_device *rdev); +extern void r600_rlc_stop(struct radeon_device *rdev); /* r600 audio */ extern int r600_audio_init(struct radeon_device *rdev); extern int r600_audio_tmds_index(struct drm_encoder *encoder); @@ -1343,6 +1345,7 @@ extern void r600_hdmi_update_audio_settings(struct drm_encoder *encoder, extern void r700_cp_stop(struct radeon_device *rdev); extern void r700_cp_fini(struct radeon_device *rdev); +void evergreen_disable_interrupt_state(struct radeon_device *rdev); /* evergreen */ struct evergreen_mc_save { diff --git a/drivers/gpu/drm/radeon/radeon_asic.c b/drivers/gpu/drm/radeon/radeon_asic.c index 3a576ab805cf..f835333c1b69 100644 --- a/drivers/gpu/drm/radeon/radeon_asic.c +++ b/drivers/gpu/drm/radeon/radeon_asic.c @@ -643,9 +643,9 @@ static struct radeon_asic evergreen_asic = { .gart_set_page = &rs600_gart_set_page, .ring_test = &r600_ring_test, .ring_ib_execute = &r600_ring_ib_execute, - .irq_set = NULL, - .irq_process = NULL, - .get_vblank_counter = NULL, + .irq_set = &evergreen_irq_set, + .irq_process = &evergreen_irq_process, + .get_vblank_counter = &evergreen_get_vblank_counter, .fence_ring_emit = NULL, .cs_parse = NULL, .copy_blit = NULL, diff --git a/drivers/gpu/drm/radeon/radeon_asic.h b/drivers/gpu/drm/radeon/radeon_asic.h index 1d451ff03676..ef2c7ba1bdc9 100644 --- a/drivers/gpu/drm/radeon/radeon_asic.h +++ b/drivers/gpu/drm/radeon/radeon_asic.h @@ -294,4 +294,8 @@ void evergreen_hpd_fini(struct radeon_device *rdev); bool evergreen_hpd_sense(struct radeon_device *rdev, enum radeon_hpd_id hpd); void evergreen_hpd_set_polarity(struct radeon_device *rdev, enum radeon_hpd_id hpd); +u32 evergreen_get_vblank_counter(struct radeon_device *rdev, int crtc); +int evergreen_irq_set(struct radeon_device *rdev); +int evergreen_irq_process(struct radeon_device *rdev); + #endif -- cgit v1.2.3 From 0ca2ab52d451c25764e53d3d289e1be357c977d7 Mon Sep 17 00:00:00 2001 From: Alex Deucher Date: Fri, 26 Feb 2010 13:57:45 -0500 Subject: drm/radeon/kms/evergreen: add hpd support Hot plug detect (hpd) for digital monitors Signed-off-by: Alex Deucher Signed-off-by: Dave Airlie --- drivers/gpu/drm/radeon/evergreen.c | 166 +++++++++++++++++++++++++++++++++++-- drivers/gpu/drm/radeon/radeon.h | 3 +- 2 files changed, 161 insertions(+), 8 deletions(-) (limited to 'drivers/gpu/drm/radeon') diff --git a/drivers/gpu/drm/radeon/evergreen.c b/drivers/gpu/drm/radeon/evergreen.c index 5c34349058c1..fcf65d9d6196 100644 --- a/drivers/gpu/drm/radeon/evergreen.c +++ b/drivers/gpu/drm/radeon/evergreen.c @@ -41,28 +41,180 @@ void evergreen_fini(struct radeon_device *rdev); bool evergreen_hpd_sense(struct radeon_device *rdev, enum radeon_hpd_id hpd) { bool connected = false; - /* XXX */ + + switch (hpd) { + case RADEON_HPD_1: + if (RREG32(DC_HPD1_INT_STATUS) & DC_HPDx_SENSE) + connected = true; + break; + case RADEON_HPD_2: + if (RREG32(DC_HPD2_INT_STATUS) & DC_HPDx_SENSE) + connected = true; + break; + case RADEON_HPD_3: + if (RREG32(DC_HPD3_INT_STATUS) & DC_HPDx_SENSE) + connected = true; + break; + case RADEON_HPD_4: + if (RREG32(DC_HPD4_INT_STATUS) & DC_HPDx_SENSE) + connected = true; + break; + case RADEON_HPD_5: + if (RREG32(DC_HPD5_INT_STATUS) & DC_HPDx_SENSE) + connected = true; + break; + case RADEON_HPD_6: + if (RREG32(DC_HPD6_INT_STATUS) & DC_HPDx_SENSE) + connected = true; + break; + default: + break; + } + return connected; } void evergreen_hpd_set_polarity(struct radeon_device *rdev, enum radeon_hpd_id hpd) { - /* XXX */ + u32 tmp; + bool connected = evergreen_hpd_sense(rdev, hpd); + + switch (hpd) { + case RADEON_HPD_1: + tmp = RREG32(DC_HPD1_INT_CONTROL); + if (connected) + tmp &= ~DC_HPDx_INT_POLARITY; + else + tmp |= DC_HPDx_INT_POLARITY; + WREG32(DC_HPD1_INT_CONTROL, tmp); + break; + case RADEON_HPD_2: + tmp = RREG32(DC_HPD2_INT_CONTROL); + if (connected) + tmp &= ~DC_HPDx_INT_POLARITY; + else + tmp |= DC_HPDx_INT_POLARITY; + WREG32(DC_HPD2_INT_CONTROL, tmp); + break; + case RADEON_HPD_3: + tmp = RREG32(DC_HPD3_INT_CONTROL); + if (connected) + tmp &= ~DC_HPDx_INT_POLARITY; + else + tmp |= DC_HPDx_INT_POLARITY; + WREG32(DC_HPD3_INT_CONTROL, tmp); + break; + case RADEON_HPD_4: + tmp = RREG32(DC_HPD4_INT_CONTROL); + if (connected) + tmp &= ~DC_HPDx_INT_POLARITY; + else + tmp |= DC_HPDx_INT_POLARITY; + WREG32(DC_HPD4_INT_CONTROL, tmp); + break; + case RADEON_HPD_5: + tmp = RREG32(DC_HPD5_INT_CONTROL); + if (connected) + tmp &= ~DC_HPDx_INT_POLARITY; + else + tmp |= DC_HPDx_INT_POLARITY; + WREG32(DC_HPD5_INT_CONTROL, tmp); + break; + case RADEON_HPD_6: + tmp = RREG32(DC_HPD6_INT_CONTROL); + if (connected) + tmp &= ~DC_HPDx_INT_POLARITY; + else + tmp |= DC_HPDx_INT_POLARITY; + WREG32(DC_HPD6_INT_CONTROL, tmp); + break; + default: + break; + } } void evergreen_hpd_init(struct radeon_device *rdev) { - /* XXX */ + struct drm_device *dev = rdev->ddev; + struct drm_connector *connector; + u32 tmp = DC_HPDx_CONNECTION_TIMER(0x9c4) | + DC_HPDx_RX_INT_TIMER(0xfa) | DC_HPDx_EN; + + list_for_each_entry(connector, &dev->mode_config.connector_list, head) { + struct radeon_connector *radeon_connector = to_radeon_connector(connector); + switch (radeon_connector->hpd.hpd) { + case RADEON_HPD_1: + WREG32(DC_HPD1_CONTROL, tmp); + rdev->irq.hpd[0] = true; + break; + case RADEON_HPD_2: + WREG32(DC_HPD2_CONTROL, tmp); + rdev->irq.hpd[1] = true; + break; + case RADEON_HPD_3: + WREG32(DC_HPD3_CONTROL, tmp); + rdev->irq.hpd[2] = true; + break; + case RADEON_HPD_4: + WREG32(DC_HPD4_CONTROL, tmp); + rdev->irq.hpd[3] = true; + break; + case RADEON_HPD_5: + WREG32(DC_HPD5_CONTROL, tmp); + rdev->irq.hpd[4] = true; + break; + case RADEON_HPD_6: + WREG32(DC_HPD6_CONTROL, tmp); + rdev->irq.hpd[5] = true; + break; + default: + break; + } + } + if (rdev->irq.installed) + evergreen_irq_set(rdev); } - -void evergreen_bandwidth_update(struct radeon_device *rdev) +void evergreen_hpd_fini(struct radeon_device *rdev) { - /* XXX */ + struct drm_device *dev = rdev->ddev; + struct drm_connector *connector; + + list_for_each_entry(connector, &dev->mode_config.connector_list, head) { + struct radeon_connector *radeon_connector = to_radeon_connector(connector); + switch (radeon_connector->hpd.hpd) { + case RADEON_HPD_1: + WREG32(DC_HPD1_CONTROL, 0); + rdev->irq.hpd[0] = false; + break; + case RADEON_HPD_2: + WREG32(DC_HPD2_CONTROL, 0); + rdev->irq.hpd[1] = false; + break; + case RADEON_HPD_3: + WREG32(DC_HPD3_CONTROL, 0); + rdev->irq.hpd[2] = false; + break; + case RADEON_HPD_4: + WREG32(DC_HPD4_CONTROL, 0); + rdev->irq.hpd[3] = false; + break; + case RADEON_HPD_5: + WREG32(DC_HPD5_CONTROL, 0); + rdev->irq.hpd[4] = false; + break; + case RADEON_HPD_6: + WREG32(DC_HPD6_CONTROL, 0); + rdev->irq.hpd[5] = false; + break; + default: + break; + } + } } -void evergreen_hpd_fini(struct radeon_device *rdev) +void evergreen_bandwidth_update(struct radeon_device *rdev) { /* XXX */ } diff --git a/drivers/gpu/drm/radeon/radeon.h b/drivers/gpu/drm/radeon/radeon.h index e0132ef093b4..815df347c08e 100644 --- a/drivers/gpu/drm/radeon/radeon.h +++ b/drivers/gpu/drm/radeon/radeon.h @@ -1345,7 +1345,8 @@ extern void r600_hdmi_update_audio_settings(struct drm_encoder *encoder, extern void r700_cp_stop(struct radeon_device *rdev); extern void r700_cp_fini(struct radeon_device *rdev); -void evergreen_disable_interrupt_state(struct radeon_device *rdev); +extern void evergreen_disable_interrupt_state(struct radeon_device *rdev); +extern int evergreen_irq_set(struct radeon_device *rdev); /* evergreen */ struct evergreen_mc_save { -- cgit v1.2.3 From a7433742d62c6e0e1173bd144a4aef7724b48d60 Mon Sep 17 00:00:00 2001 From: Dave Airlie Date: Fri, 9 Apr 2010 15:31:09 +1000 Subject: drm/radeon: fix cypress firmware typo. Pointed out by Dave Witbrodt. Signed-off-by: Dave Airlie --- drivers/gpu/drm/radeon/r600.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/gpu/drm/radeon') diff --git a/drivers/gpu/drm/radeon/r600.c b/drivers/gpu/drm/radeon/r600.c index d178fa826eec..25aa2f808935 100644 --- a/drivers/gpu/drm/radeon/r600.c +++ b/drivers/gpu/drm/radeon/r600.c @@ -79,7 +79,7 @@ MODULE_FIRMWARE("radeon/REDWOOD_rlc.bin"); MODULE_FIRMWARE("radeon/JUNIPER_pfp.bin"); MODULE_FIRMWARE("radeon/JUNIPER_me.bin"); MODULE_FIRMWARE("radeon/JUNIPER_rlc.bin"); -MODULE_FIRMWARE("radeon/CYRPESS_pfp.bin"); +MODULE_FIRMWARE("radeon/CYPRESS_pfp.bin"); MODULE_FIRMWARE("radeon/CYPRESS_me.bin"); MODULE_FIRMWARE("radeon/CYPRESS_rlc.bin"); -- cgit v1.2.3 From fd632aa34c8592fb1d37fc83cbffa827bc7dd42c Mon Sep 17 00:00:00 2001 From: Daniel Vetter Date: Fri, 9 Apr 2010 19:05:05 +0000 Subject: drm: free core gem object from driver callbacks When drivers embed the core gem object into their own structures, they'll have to do this. Temporarily this results in an ugly kfree(gem_obj); in every gem driver. Signed-off-by: Daniel Vetter Acked-by: Eric Anholt Signed-off-by: Dave Airlie --- drivers/gpu/drm/drm_gem.c | 10 +++------- drivers/gpu/drm/i915/i915_gem.c | 3 +++ drivers/gpu/drm/nouveau/nouveau_gem.c | 3 +++ drivers/gpu/drm/radeon/radeon_gem.c | 3 +++ include/drm/drmP.h | 1 + 5 files changed, 13 insertions(+), 7 deletions(-) (limited to 'drivers/gpu/drm/radeon') diff --git a/drivers/gpu/drm/drm_gem.c b/drivers/gpu/drm/drm_gem.c index 3b64d0ef1998..33dad3fa6043 100644 --- a/drivers/gpu/drm/drm_gem.c +++ b/drivers/gpu/drm/drm_gem.c @@ -422,15 +422,15 @@ drm_gem_release(struct drm_device *dev, struct drm_file *file_private) idr_destroy(&file_private->object_idr); } -static void -drm_gem_object_free_common(struct drm_gem_object *obj) +void +drm_gem_object_release(struct drm_gem_object *obj) { struct drm_device *dev = obj->dev; fput(obj->filp); atomic_dec(&dev->object_count); atomic_sub(obj->size, &dev->object_memory); - kfree(obj); } +EXPORT_SYMBOL(drm_gem_object_release); /** * Called after the last reference to the object has been lost. @@ -448,8 +448,6 @@ drm_gem_object_free(struct kref *kref) if (dev->driver->gem_free_object != NULL) dev->driver->gem_free_object(obj); - - drm_gem_object_free_common(obj); } EXPORT_SYMBOL(drm_gem_object_free); @@ -472,8 +470,6 @@ drm_gem_object_free_unlocked(struct kref *kref) dev->driver->gem_free_object(obj); mutex_unlock(&dev->struct_mutex); } - - drm_gem_object_free_common(obj); } EXPORT_SYMBOL(drm_gem_object_free_unlocked); diff --git a/drivers/gpu/drm/i915/i915_gem.c b/drivers/gpu/drm/i915/i915_gem.c index 80871c62a571..d4ea90999f67 100644 --- a/drivers/gpu/drm/i915/i915_gem.c +++ b/drivers/gpu/drm/i915/i915_gem.c @@ -4474,6 +4474,9 @@ void i915_gem_free_object(struct drm_gem_object *obj) kfree(obj_priv->page_cpu_valid); kfree(obj_priv->bit_17); kfree(obj->driver_private); + + drm_gem_object_release(obj); + kfree(obj); } /** Unbinds all inactive objects. */ diff --git a/drivers/gpu/drm/nouveau/nouveau_gem.c b/drivers/gpu/drm/nouveau/nouveau_gem.c index 1bc0b38a5167..6d1aa89ec870 100644 --- a/drivers/gpu/drm/nouveau/nouveau_gem.c +++ b/drivers/gpu/drm/nouveau/nouveau_gem.c @@ -57,6 +57,9 @@ nouveau_gem_object_del(struct drm_gem_object *gem) } ttm_bo_unref(&bo); + + drm_gem_object_release(gem); + kfree(gem); } int diff --git a/drivers/gpu/drm/radeon/radeon_gem.c b/drivers/gpu/drm/radeon/radeon_gem.c index 28dd3e1b9c3a..a72a3ee5d69b 100644 --- a/drivers/gpu/drm/radeon/radeon_gem.c +++ b/drivers/gpu/drm/radeon/radeon_gem.c @@ -44,6 +44,9 @@ void radeon_gem_object_free(struct drm_gem_object *gobj) if (robj) { radeon_bo_unref(&robj); } + + drm_gem_object_release(gobj); + kfree(gobj); } int radeon_gem_object_create(struct radeon_device *rdev, int size, diff --git a/include/drm/drmP.h b/include/drm/drmP.h index b3b57b561b92..c1b987158dfa 100644 --- a/include/drm/drmP.h +++ b/include/drm/drmP.h @@ -1428,6 +1428,7 @@ extern void drm_sysfs_connector_remove(struct drm_connector *connector); /* Graphics Execution Manager library functions (drm_gem.c) */ int drm_gem_init(struct drm_device *dev); void drm_gem_destroy(struct drm_device *dev); +void drm_gem_object_release(struct drm_gem_object *obj); void drm_gem_object_free(struct kref *kref); void drm_gem_object_free_unlocked(struct kref *kref); struct drm_gem_object *drm_gem_object_alloc(struct drm_device *dev, -- cgit v1.2.3 From 0a2d50e3a8faaf36cde36920431586090411ea15 Mon Sep 17 00:00:00 2001 From: Jerome Glisse Date: Fri, 9 Apr 2010 14:39:24 +0200 Subject: drm/radeon/kms: add support for new fault callback V7 This add the support for the new fault callback and also the infrastructure for supporting unmappable VRAM. V2 validate BO with no_wait = true V3 don't derefence bo->mem.mm_node as it's not NULL only for VRAM or GTT V4 update to splitted no_wait ttm change V5 update to new balanced io_mem_reserve/free change V6 callback is responsible for iomapping memory V7 move back iomapping to ttm Signed-off-by: Jerome Glisse Signed-off-by: Dave Airlie --- drivers/gpu/drm/radeon/radeon_object.c | 26 +++++++++++++++-- drivers/gpu/drm/radeon/radeon_object.h | 2 +- drivers/gpu/drm/radeon/radeon_ttm.c | 51 +++++++++++++++++++++++++++++++--- 3 files changed, 72 insertions(+), 7 deletions(-) (limited to 'drivers/gpu/drm/radeon') diff --git a/drivers/gpu/drm/radeon/radeon_object.c b/drivers/gpu/drm/radeon/radeon_object.c index 4b441f87f47a..57b3f95c0efa 100644 --- a/drivers/gpu/drm/radeon/radeon_object.c +++ b/drivers/gpu/drm/radeon/radeon_object.c @@ -498,11 +498,33 @@ void radeon_bo_move_notify(struct ttm_buffer_object *bo, radeon_bo_check_tiling(rbo, 0, 1); } -void radeon_bo_fault_reserve_notify(struct ttm_buffer_object *bo) +int radeon_bo_fault_reserve_notify(struct ttm_buffer_object *bo) { + struct radeon_device *rdev; struct radeon_bo *rbo; + unsigned long offset, size; + int r; + if (!radeon_ttm_bo_is_radeon_bo(bo)) - return; + return 0; rbo = container_of(bo, struct radeon_bo, tbo); radeon_bo_check_tiling(rbo, 0, 0); + rdev = rbo->rdev; + if (bo->mem.mem_type == TTM_PL_VRAM) { + size = bo->mem.num_pages << PAGE_SHIFT; + offset = bo->mem.mm_node->start << PAGE_SHIFT; + if ((offset + size) > rdev->mc.visible_vram_size) { + /* hurrah the memory is not visible ! */ + radeon_ttm_placement_from_domain(rbo, RADEON_GEM_DOMAIN_VRAM); + rbo->placement.lpfn = rdev->mc.visible_vram_size >> PAGE_SHIFT; + r = ttm_bo_validate(bo, &rbo->placement, false, true, false); + if (unlikely(r != 0)) + return r; + offset = bo->mem.mm_node->start << PAGE_SHIFT; + /* this should not happen */ + if ((offset + size) > rdev->mc.visible_vram_size) + return -EINVAL; + } + } + return 0; } diff --git a/drivers/gpu/drm/radeon/radeon_object.h b/drivers/gpu/drm/radeon/radeon_object.h index 7ab43de1e244..353998dc2c03 100644 --- a/drivers/gpu/drm/radeon/radeon_object.h +++ b/drivers/gpu/drm/radeon/radeon_object.h @@ -168,6 +168,6 @@ extern int radeon_bo_check_tiling(struct radeon_bo *bo, bool has_moved, bool force_drop); extern void radeon_bo_move_notify(struct ttm_buffer_object *bo, struct ttm_mem_reg *mem); -extern void radeon_bo_fault_reserve_notify(struct ttm_buffer_object *bo); +extern int radeon_bo_fault_reserve_notify(struct ttm_buffer_object *bo); extern int radeon_bo_get_surface_reg(struct radeon_bo *bo); #endif diff --git a/drivers/gpu/drm/radeon/radeon_ttm.c b/drivers/gpu/drm/radeon/radeon_ttm.c index ba4724c38ac0..62b4b800e0a3 100644 --- a/drivers/gpu/drm/radeon/radeon_ttm.c +++ b/drivers/gpu/drm/radeon/radeon_ttm.c @@ -165,8 +165,7 @@ static int radeon_init_mem_type(struct ttm_bo_device *bdev, uint32_t type, man->io_size = rdev->mc.gtt_size; man->io_addr = NULL; if (!rdev->ddev->agp->cant_use_aperture) - man->flags = TTM_MEMTYPE_FLAG_NEEDS_IOREMAP | - TTM_MEMTYPE_FLAG_MAPPABLE; + man->flags = TTM_MEMTYPE_FLAG_MAPPABLE; man->available_caching = TTM_PL_FLAG_UNCACHED | TTM_PL_FLAG_WC; man->default_caching = TTM_PL_FLAG_WC; @@ -182,7 +181,6 @@ static int radeon_init_mem_type(struct ttm_bo_device *bdev, uint32_t type, /* "On-card" video ram */ man->gpu_offset = rdev->mc.vram_start; man->flags = TTM_MEMTYPE_FLAG_FIXED | - TTM_MEMTYPE_FLAG_NEEDS_IOREMAP | TTM_MEMTYPE_FLAG_MAPPABLE; man->available_caching = TTM_PL_FLAG_UNCACHED | TTM_PL_FLAG_WC; man->default_caching = TTM_PL_FLAG_WC; @@ -437,10 +435,53 @@ static int radeon_bo_move(struct ttm_buffer_object *bo, memcpy: r = ttm_bo_move_memcpy(bo, evict, no_wait_reserve, no_wait_gpu, new_mem); } - return r; } +static int radeon_ttm_io_mem_reserve(struct ttm_bo_device *bdev, struct ttm_mem_reg *mem) +{ + struct ttm_mem_type_manager *man = &bdev->man[mem->mem_type]; + struct radeon_device *rdev = radeon_get_rdev(bdev); + + mem->bus.addr = NULL; + mem->bus.offset = 0; + mem->bus.size = mem->num_pages << PAGE_SHIFT; + mem->bus.base = 0; + mem->bus.is_iomem = false; + if (!(man->flags & TTM_MEMTYPE_FLAG_MAPPABLE)) + return -EINVAL; + switch (mem->mem_type) { + case TTM_PL_SYSTEM: + /* system memory */ + return 0; + case TTM_PL_TT: +#if __OS_HAS_AGP + if (rdev->flags & RADEON_IS_AGP) { + /* RADEON_IS_AGP is set only if AGP is active */ + mem->bus.offset = mem->mm_node->start << PAGE_SHIFT; + mem->bus.base = rdev->mc.agp_base; + mem->bus.is_iomem = true; + } +#endif + break; + case TTM_PL_VRAM: + mem->bus.offset = mem->mm_node->start << PAGE_SHIFT; + /* check if it's visible */ + if ((mem->bus.offset + mem->bus.size) > rdev->mc.visible_vram_size) + return -EINVAL; + mem->bus.base = rdev->mc.aper_base; + mem->bus.is_iomem = true; + break; + default: + return -EINVAL; + } + return 0; +} + +static void radeon_ttm_io_mem_free(struct ttm_bo_device *bdev, struct ttm_mem_reg *mem) +{ +} + static int radeon_sync_obj_wait(void *sync_obj, void *sync_arg, bool lazy, bool interruptible) { @@ -481,6 +522,8 @@ static struct ttm_bo_driver radeon_bo_driver = { .sync_obj_ref = &radeon_sync_obj_ref, .move_notify = &radeon_bo_move_notify, .fault_reserve_notify = &radeon_bo_fault_reserve_notify, + .io_mem_reserve = &radeon_ttm_io_mem_reserve, + .io_mem_free = &radeon_ttm_io_mem_free, }; int radeon_ttm_init(struct radeon_device *rdev) -- cgit v1.2.3 From 0c321c79627189204d7d0bf65ab19f5ac419abed Mon Sep 17 00:00:00 2001 From: Jerome Glisse Date: Wed, 7 Apr 2010 10:21:27 +0000 Subject: drm/ttm: remove io_ field from TTM V6 All TTM driver have been converted to new io_mem_reserve/free interface which allow driver to choose and return proper io base, offset to core TTM for ioremapping if necessary. This patch remove what is now deadcode. V2 adapt to match with change in first patch of the patchset V3 update after io_mem_reserve/io_mem_free callback balancing V4 adjust to minor cleanup V5 remove the needs ioremap flag V6 keep the ioremapping facility in TTM [airlied- squashed driver removals in here also] Signed-off-by: Jerome Glisse Reviewed-by: Thomas Hellstrom Signed-off-by: Dave Airlie --- drivers/gpu/drm/nouveau/nouveau_bo.c | 11 ----------- drivers/gpu/drm/radeon/radeon_ttm.c | 13 +------------ drivers/gpu/drm/ttm/ttm_bo.c | 22 ---------------------- drivers/gpu/drm/ttm/ttm_bo_util.c | 19 ++++--------------- drivers/gpu/drm/vmwgfx/vmwgfx_buffer.c | 6 ------ include/drm/ttm/ttm_bo_driver.h | 12 ------------ 6 files changed, 5 insertions(+), 78 deletions(-) (limited to 'drivers/gpu/drm/radeon') diff --git a/drivers/gpu/drm/nouveau/nouveau_bo.c b/drivers/gpu/drm/nouveau/nouveau_bo.c index 288c2ecd937a..34be1924218f 100644 --- a/drivers/gpu/drm/nouveau/nouveau_bo.c +++ b/drivers/gpu/drm/nouveau/nouveau_bo.c @@ -390,13 +390,6 @@ nouveau_bo_init_mem_type(struct ttm_bo_device *bdev, uint32_t type, man->available_caching = TTM_PL_FLAG_UNCACHED | TTM_PL_FLAG_WC; man->default_caching = TTM_PL_FLAG_WC; - - man->io_addr = NULL; - man->io_offset = drm_get_resource_start(dev, 1); - man->io_size = drm_get_resource_len(dev, 1); - if (man->io_size > nouveau_mem_fb_amount(dev)) - man->io_size = nouveau_mem_fb_amount(dev); - man->gpu_offset = dev_priv->vm_vram_base; break; case TTM_PL_TT: @@ -417,10 +410,6 @@ nouveau_bo_init_mem_type(struct ttm_bo_device *bdev, uint32_t type, dev_priv->gart_info.type); return -EINVAL; } - - man->io_offset = dev_priv->gart_info.aper_base; - man->io_size = dev_priv->gart_info.aper_size; - man->io_addr = NULL; man->gpu_offset = dev_priv->vm_gart_base; break; default: diff --git a/drivers/gpu/drm/radeon/radeon_ttm.c b/drivers/gpu/drm/radeon/radeon_ttm.c index 62b4b800e0a3..91030eab22b0 100644 --- a/drivers/gpu/drm/radeon/radeon_ttm.c +++ b/drivers/gpu/drm/radeon/radeon_ttm.c @@ -161,21 +161,13 @@ static int radeon_init_mem_type(struct ttm_bo_device *bdev, uint32_t type, (unsigned)type); return -EINVAL; } - man->io_offset = rdev->mc.agp_base; - man->io_size = rdev->mc.gtt_size; - man->io_addr = NULL; if (!rdev->ddev->agp->cant_use_aperture) man->flags = TTM_MEMTYPE_FLAG_MAPPABLE; man->available_caching = TTM_PL_FLAG_UNCACHED | TTM_PL_FLAG_WC; man->default_caching = TTM_PL_FLAG_WC; - } else -#endif - { - man->io_offset = 0; - man->io_size = 0; - man->io_addr = NULL; } +#endif break; case TTM_PL_VRAM: /* "On-card" video ram */ @@ -184,9 +176,6 @@ static int radeon_init_mem_type(struct ttm_bo_device *bdev, uint32_t type, TTM_MEMTYPE_FLAG_MAPPABLE; man->available_caching = TTM_PL_FLAG_UNCACHED | TTM_PL_FLAG_WC; man->default_caching = TTM_PL_FLAG_WC; - man->io_addr = NULL; - man->io_offset = rdev->mc.aper_base; - man->io_size = rdev->mc.aper_size; break; default: DRM_ERROR("Unsupported memory type %u\n", (unsigned)type); diff --git a/drivers/gpu/drm/ttm/ttm_bo.c b/drivers/gpu/drm/ttm/ttm_bo.c index b42e3fae1bd5..3b5b094b1397 100644 --- a/drivers/gpu/drm/ttm/ttm_bo.c +++ b/drivers/gpu/drm/ttm/ttm_bo.c @@ -79,8 +79,6 @@ static void ttm_mem_type_debug(struct ttm_bo_device *bdev, int mem_type) printk(KERN_ERR TTM_PFX " use_type: %d\n", man->use_type); printk(KERN_ERR TTM_PFX " flags: 0x%08X\n", man->flags); printk(KERN_ERR TTM_PFX " gpu_offset: 0x%08lX\n", man->gpu_offset); - printk(KERN_ERR TTM_PFX " io_offset: 0x%08lX\n", man->io_offset); - printk(KERN_ERR TTM_PFX " io_size: %ld\n", man->io_size); printk(KERN_ERR TTM_PFX " size: %llu\n", man->size); printk(KERN_ERR TTM_PFX " available_caching: 0x%08X\n", man->available_caching); @@ -1563,26 +1561,6 @@ bool ttm_mem_reg_is_pci(struct ttm_bo_device *bdev, struct ttm_mem_reg *mem) return true; } -int ttm_bo_pci_offset(struct ttm_bo_device *bdev, - struct ttm_mem_reg *mem, - unsigned long *bus_base, - unsigned long *bus_offset, unsigned long *bus_size) -{ - struct ttm_mem_type_manager *man = &bdev->man[mem->mem_type]; - - *bus_size = 0; - if (!(man->flags & TTM_MEMTYPE_FLAG_MAPPABLE)) - return -EINVAL; - - if (ttm_mem_reg_is_pci(bdev, mem)) { - *bus_offset = mem->mm_node->start << PAGE_SHIFT; - *bus_size = mem->num_pages << PAGE_SHIFT; - *bus_base = man->io_offset + (uintptr_t)man->io_addr; - } - - return 0; -} - void ttm_bo_unmap_virtual(struct ttm_buffer_object *bo) { struct ttm_bo_device *bdev = bo->bdev; diff --git a/drivers/gpu/drm/ttm/ttm_bo_util.c b/drivers/gpu/drm/ttm/ttm_bo_util.c index d58eeb5ed22b..333b401ca4c9 100644 --- a/drivers/gpu/drm/ttm/ttm_bo_util.c +++ b/drivers/gpu/drm/ttm/ttm_bo_util.c @@ -83,24 +83,13 @@ EXPORT_SYMBOL(ttm_bo_move_ttm); int ttm_mem_io_reserve(struct ttm_bo_device *bdev, struct ttm_mem_reg *mem) { - struct ttm_mem_type_manager *man = &bdev->man[mem->mem_type]; int ret; - if (bdev->driver->io_mem_reserve) { - if (!mem->bus.io_reserved) { - mem->bus.io_reserved = true; - ret = bdev->driver->io_mem_reserve(bdev, mem); - if (unlikely(ret != 0)) - return ret; - } - } else { - ret = ttm_bo_pci_offset(bdev, mem, &mem->bus.base, &mem->bus.offset, &mem->bus.size); + if (!mem->bus.io_reserved) { + mem->bus.io_reserved = true; + ret = bdev->driver->io_mem_reserve(bdev, mem); if (unlikely(ret != 0)) return ret; - mem->bus.addr = NULL; - if (!(man->flags & TTM_MEMTYPE_FLAG_NEEDS_IOREMAP)) - mem->bus.addr = (void *)(((u8 *)man->io_addr) + mem->bus.offset); - mem->bus.is_iomem = (mem->bus.size > 0) ? 1 : 0; } return 0; } @@ -149,7 +138,7 @@ void ttm_mem_reg_iounmap(struct ttm_bo_device *bdev, struct ttm_mem_reg *mem, man = &bdev->man[mem->mem_type]; - if (virtual && (man->flags & TTM_MEMTYPE_FLAG_NEEDS_IOREMAP || mem->bus.addr == NULL)) + if (virtual && mem->bus.addr == NULL) iounmap(virtual); ttm_mem_io_free(bdev, mem); } diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_buffer.c b/drivers/gpu/drm/vmwgfx/vmwgfx_buffer.c index f3558968fdff..c4f5114aee7c 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_buffer.c +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_buffer.c @@ -137,9 +137,6 @@ int vmw_invalidate_caches(struct ttm_bo_device *bdev, uint32_t flags) int vmw_init_mem_type(struct ttm_bo_device *bdev, uint32_t type, struct ttm_mem_type_manager *man) { - struct vmw_private *dev_priv = - container_of(bdev, struct vmw_private, bdev); - switch (type) { case TTM_PL_SYSTEM: /* System memory */ @@ -151,10 +148,7 @@ int vmw_init_mem_type(struct ttm_bo_device *bdev, uint32_t type, case TTM_PL_VRAM: /* "On-card" video ram */ man->gpu_offset = 0; - man->io_offset = dev_priv->vram_start; - man->io_size = dev_priv->vram_size; man->flags = TTM_MEMTYPE_FLAG_FIXED | TTM_MEMTYPE_FLAG_MAPPABLE; - man->io_addr = NULL; man->available_caching = TTM_PL_MASK_CACHING; man->default_caching = TTM_PL_FLAG_WC; break; diff --git a/include/drm/ttm/ttm_bo_driver.h b/include/drm/ttm/ttm_bo_driver.h index da39865d67d8..7720b1787e23 100644 --- a/include/drm/ttm/ttm_bo_driver.h +++ b/include/drm/ttm/ttm_bo_driver.h @@ -176,8 +176,6 @@ struct ttm_tt { #define TTM_MEMTYPE_FLAG_FIXED (1 << 0) /* Fixed (on-card) PCI memory */ #define TTM_MEMTYPE_FLAG_MAPPABLE (1 << 1) /* Memory mappable */ -#define TTM_MEMTYPE_FLAG_NEEDS_IOREMAP (1 << 2) /* Fixed memory needs ioremap - before kernel access. */ #define TTM_MEMTYPE_FLAG_CMA (1 << 3) /* Can't map aperture */ /** @@ -189,13 +187,6 @@ struct ttm_tt { * managed by this memory type. * @gpu_offset: If used, the GPU offset of the first managed page of * fixed memory or the first managed location in an aperture. - * @io_offset: The io_offset of the first managed page of IO memory or - * the first managed location in an aperture. For TTM_MEMTYPE_FLAG_CMA - * memory, this should be set to NULL. - * @io_size: The size of a managed IO region (fixed memory or aperture). - * @io_addr: Virtual kernel address if the io region is pre-mapped. For - * TTM_MEMTYPE_FLAG_NEEDS_IOREMAP there is no pre-mapped io map and - * @io_addr should be set to NULL. * @size: Size of the managed region. * @available_caching: A mask of available caching types, TTM_PL_FLAG_XX, * as defined in ttm_placement_common.h @@ -221,9 +212,6 @@ struct ttm_mem_type_manager { bool use_type; uint32_t flags; unsigned long gpu_offset; - unsigned long io_offset; - unsigned long io_size; - void *io_addr; uint64_t size; uint32_t available_caching; uint32_t default_caching; -- cgit v1.2.3 From 6b8b1786a8c29ce6e32298b93ac8d4a18a2b11c4 Mon Sep 17 00:00:00 2001 From: Jerome Glisse Date: Wed, 7 Apr 2010 10:21:31 +0000 Subject: drm/radeon/kms: enable use of unmappable VRAM V2 This patch enable the use of unmappable VRAM thanks to previous TTM infrastructure change. V2 update after io_mem_reserve/io_mem_free callback balancing Signed-off-by: Jerome Glisse Signed-off-by: Dave Airlie --- drivers/gpu/drm/radeon/evergreen.c | 5 ----- drivers/gpu/drm/radeon/r100.c | 5 ----- drivers/gpu/drm/radeon/r600.c | 5 ----- drivers/gpu/drm/radeon/rv770.c | 5 ----- 4 files changed, 20 deletions(-) (limited to 'drivers/gpu/drm/radeon') diff --git a/drivers/gpu/drm/radeon/evergreen.c b/drivers/gpu/drm/radeon/evergreen.c index 647a0efdc353..5c7c5c399302 100644 --- a/drivers/gpu/drm/radeon/evergreen.c +++ b/drivers/gpu/drm/radeon/evergreen.c @@ -475,11 +475,6 @@ int evergreen_mc_init(struct radeon_device *rdev) rdev->mc.mc_vram_size = RREG32(CONFIG_MEMSIZE) * 1024 * 1024; rdev->mc.real_vram_size = RREG32(CONFIG_MEMSIZE) * 1024 * 1024; rdev->mc.visible_vram_size = rdev->mc.aper_size; - /* FIXME remove this once we support unmappable VRAM */ - if (rdev->mc.mc_vram_size > rdev->mc.aper_size) { - rdev->mc.mc_vram_size = rdev->mc.aper_size; - rdev->mc.real_vram_size = rdev->mc.aper_size; - } r600_vram_gtt_location(rdev, &rdev->mc); radeon_update_bandwidth_info(rdev); diff --git a/drivers/gpu/drm/radeon/r100.c b/drivers/gpu/drm/radeon/r100.c index 3ae51ada1abf..3ce549706c2a 100644 --- a/drivers/gpu/drm/radeon/r100.c +++ b/drivers/gpu/drm/radeon/r100.c @@ -2001,11 +2001,6 @@ void r100_vram_init_sizes(struct radeon_device *rdev) else rdev->mc.mc_vram_size = rdev->mc.real_vram_size; } - /* FIXME remove this once we support unmappable VRAM */ - if (rdev->mc.mc_vram_size > rdev->mc.aper_size) { - rdev->mc.mc_vram_size = rdev->mc.aper_size; - rdev->mc.real_vram_size = rdev->mc.aper_size; - } } void r100_vga_set_state(struct radeon_device *rdev, bool state) diff --git a/drivers/gpu/drm/radeon/r600.c b/drivers/gpu/drm/radeon/r600.c index 5509354c7c89..dce41b167f85 100644 --- a/drivers/gpu/drm/radeon/r600.c +++ b/drivers/gpu/drm/radeon/r600.c @@ -713,11 +713,6 @@ int r600_mc_init(struct radeon_device *rdev) rdev->mc.mc_vram_size = RREG32(CONFIG_MEMSIZE); rdev->mc.real_vram_size = RREG32(CONFIG_MEMSIZE); rdev->mc.visible_vram_size = rdev->mc.aper_size; - /* FIXME remove this once we support unmappable VRAM */ - if (rdev->mc.mc_vram_size > rdev->mc.aper_size) { - rdev->mc.mc_vram_size = rdev->mc.aper_size; - rdev->mc.real_vram_size = rdev->mc.aper_size; - } r600_vram_gtt_location(rdev, &rdev->mc); if (rdev->flags & RADEON_IS_IGP) diff --git a/drivers/gpu/drm/radeon/rv770.c b/drivers/gpu/drm/radeon/rv770.c index 9f37d2efb0a9..e2089faa9593 100644 --- a/drivers/gpu/drm/radeon/rv770.c +++ b/drivers/gpu/drm/radeon/rv770.c @@ -905,11 +905,6 @@ int rv770_mc_init(struct radeon_device *rdev) rdev->mc.mc_vram_size = RREG32(CONFIG_MEMSIZE); rdev->mc.real_vram_size = RREG32(CONFIG_MEMSIZE); rdev->mc.visible_vram_size = rdev->mc.aper_size; - /* FIXME remove this once we support unmappable VRAM */ - if (rdev->mc.mc_vram_size > rdev->mc.aper_size) { - rdev->mc.mc_vram_size = rdev->mc.aper_size; - rdev->mc.real_vram_size = rdev->mc.aper_size; - } r600_vram_gtt_location(rdev, &rdev->mc); radeon_update_bandwidth_info(rdev); -- cgit v1.2.3 From 58bd086313ea0eda037f65b9bda2b3decb959a31 Mon Sep 17 00:00:00 2001 From: Christian König Date: Mon, 5 Apr 2010 22:14:55 +0200 Subject: drm/radeon/kms: rework audio polling timer MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Rework HDMI audio polling timer, only enable it when at least one HDMI encoder needs it. Preparation for replacing it with irq support. Signed-off-by: Christian König Signed-off-by: Dave Airlie --- drivers/gpu/drm/radeon/r600_audio.c | 55 +++++++++++++++++++++++++++--------- drivers/gpu/drm/radeon/r600_hdmi.c | 17 +++++++---- drivers/gpu/drm/radeon/radeon.h | 14 +++++---- drivers/gpu/drm/radeon/radeon_mode.h | 1 + 4 files changed, 61 insertions(+), 26 deletions(-) (limited to 'drivers/gpu/drm/radeon') diff --git a/drivers/gpu/drm/radeon/r600_audio.c b/drivers/gpu/drm/radeon/r600_audio.c index 1d898051c631..ed8d3989f172 100644 --- a/drivers/gpu/drm/radeon/r600_audio.c +++ b/drivers/gpu/drm/radeon/r600_audio.c @@ -44,7 +44,7 @@ static int r600_audio_chipset_supported(struct radeon_device *rdev) /* * current number of channels */ -static int r600_audio_channels(struct radeon_device *rdev) +int r600_audio_channels(struct radeon_device *rdev) { return (RREG32(R600_AUDIO_RATE_BPS_CHANNEL) & 0x7) + 1; } @@ -52,7 +52,7 @@ static int r600_audio_channels(struct radeon_device *rdev) /* * current bits per sample */ -static int r600_audio_bits_per_sample(struct radeon_device *rdev) +int r600_audio_bits_per_sample(struct radeon_device *rdev) { uint32_t value = (RREG32(R600_AUDIO_RATE_BPS_CHANNEL) & 0xF0) >> 4; switch (value) { @@ -71,7 +71,7 @@ static int r600_audio_bits_per_sample(struct radeon_device *rdev) /* * current sampling rate in HZ */ -static int r600_audio_rate(struct radeon_device *rdev) +int r600_audio_rate(struct radeon_device *rdev) { uint32_t value = RREG32(R600_AUDIO_RATE_BPS_CHANNEL); uint32_t result; @@ -90,7 +90,7 @@ static int r600_audio_rate(struct radeon_device *rdev) /* * iec 60958 status bits */ -static uint8_t r600_audio_status_bits(struct radeon_device *rdev) +uint8_t r600_audio_status_bits(struct radeon_device *rdev) { return RREG32(R600_AUDIO_STATUS_BITS) & 0xff; } @@ -98,7 +98,7 @@ static uint8_t r600_audio_status_bits(struct radeon_device *rdev) /* * iec 60958 category code */ -static uint8_t r600_audio_category_code(struct radeon_device *rdev) +uint8_t r600_audio_category_code(struct radeon_device *rdev) { return (RREG32(R600_AUDIO_STATUS_BITS) >> 8) & 0xff; } @@ -118,7 +118,7 @@ static void r600_audio_update_hdmi(unsigned long param) uint8_t category_code = r600_audio_category_code(rdev); struct drm_encoder *encoder; - int changes = 0; + int changes = 0, still_going = 0; changes |= channels != rdev->audio_channels; changes |= rate != rdev->audio_rate; @@ -135,15 +135,17 @@ static void r600_audio_update_hdmi(unsigned long param) } list_for_each_entry(encoder, &dev->mode_config.encoder_list, head) { - if (changes || r600_hdmi_buffer_status_changed(encoder)) - r600_hdmi_update_audio_settings( - encoder, channels, - rate, bps, status_bits, - category_code); + struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder); + if (radeon_encoder->audio_polling_active) { + still_going = 1; + if (changes || r600_hdmi_buffer_status_changed(encoder)) + r600_hdmi_update_audio_settings(encoder); + } } - mod_timer(&rdev->audio_timer, - jiffies + msecs_to_jiffies(AUDIO_TIMER_INTERVALL)); + if(still_going) + mod_timer(&rdev->audio_timer, + jiffies + msecs_to_jiffies(AUDIO_TIMER_INTERVALL)); } /* @@ -176,9 +178,34 @@ int r600_audio_init(struct radeon_device *rdev) r600_audio_update_hdmi, (unsigned long)rdev); + return 0; +} + +/* + * enable the polling timer, to check for status changes + */ +void r600_audio_enable_polling(struct drm_encoder *encoder) +{ + struct drm_device *dev = encoder->dev; + struct radeon_device *rdev = dev->dev_private; + struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder); + + DRM_DEBUG("r600_audio_enable_polling: %d", radeon_encoder->audio_polling_active); + if (radeon_encoder->audio_polling_active) + return; + + radeon_encoder->audio_polling_active = 1; mod_timer(&rdev->audio_timer, jiffies + 1); +} - return 0; +/* + * disable the polling timer, so we get no more status updates + */ +void r600_audio_disable_polling(struct drm_encoder *encoder) +{ + struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder); + DRM_DEBUG("r600_audio_disable_polling: %d", radeon_encoder->audio_polling_active); + radeon_encoder->audio_polling_active = 0; } /* diff --git a/drivers/gpu/drm/radeon/r600_hdmi.c b/drivers/gpu/drm/radeon/r600_hdmi.c index 2616b822ba68..d014472d0d3f 100644 --- a/drivers/gpu/drm/radeon/r600_hdmi.c +++ b/drivers/gpu/drm/radeon/r600_hdmi.c @@ -353,17 +353,18 @@ void r600_hdmi_setmode(struct drm_encoder *encoder, struct drm_display_mode *mod /* * update settings with current parameters from audio engine */ -void r600_hdmi_update_audio_settings(struct drm_encoder *encoder, - int channels, - int rate, - int bps, - uint8_t status_bits, - uint8_t category_code) +void r600_hdmi_update_audio_settings(struct drm_encoder *encoder) { struct drm_device *dev = encoder->dev; struct radeon_device *rdev = dev->dev_private; uint32_t offset = to_radeon_encoder(encoder)->hdmi_offset; + int channels = r600_audio_channels(rdev); + int rate = r600_audio_rate(rdev); + int bps = r600_audio_bits_per_sample(rdev); + uint8_t status_bits = r600_audio_status_bits(rdev); + uint8_t category_code = r600_audio_category_code(rdev); + uint32_t iec; if (!offset) @@ -518,6 +519,8 @@ void r600_hdmi_enable(struct drm_encoder *encoder) } } + r600_audio_enable_polling(encoder); + DRM_DEBUG("Enabling HDMI interface @ 0x%04X for encoder 0x%x\n", radeon_encoder->hdmi_offset, radeon_encoder->encoder_id); } @@ -539,6 +542,8 @@ void r600_hdmi_disable(struct drm_encoder *encoder) return; } + r600_audio_disable_polling(encoder); + DRM_DEBUG("Disabling HDMI interface @ 0x%04X for encoder 0x%x\n", radeon_encoder->hdmi_offset, radeon_encoder->encoder_id); diff --git a/drivers/gpu/drm/radeon/radeon.h b/drivers/gpu/drm/radeon/radeon.h index e9120985a652..42217af58145 100644 --- a/drivers/gpu/drm/radeon/radeon.h +++ b/drivers/gpu/drm/radeon/radeon.h @@ -1327,18 +1327,20 @@ extern void r600_rlc_stop(struct radeon_device *rdev); extern int r600_audio_init(struct radeon_device *rdev); extern int r600_audio_tmds_index(struct drm_encoder *encoder); extern void r600_audio_set_clock(struct drm_encoder *encoder, int clock); +extern int r600_audio_channels(struct radeon_device *rdev); +extern int r600_audio_bits_per_sample(struct radeon_device *rdev); +extern int r600_audio_rate(struct radeon_device *rdev); +extern uint8_t r600_audio_status_bits(struct radeon_device *rdev); +extern uint8_t r600_audio_category_code(struct radeon_device *rdev); +extern void r600_audio_enable_polling(struct drm_encoder *encoder); +extern void r600_audio_disable_polling(struct drm_encoder *encoder); extern void r600_audio_fini(struct radeon_device *rdev); extern void r600_hdmi_init(struct drm_encoder *encoder); extern void r600_hdmi_enable(struct drm_encoder *encoder); extern void r600_hdmi_disable(struct drm_encoder *encoder); extern void r600_hdmi_setmode(struct drm_encoder *encoder, struct drm_display_mode *mode); extern int r600_hdmi_buffer_status_changed(struct drm_encoder *encoder); -extern void r600_hdmi_update_audio_settings(struct drm_encoder *encoder, - int channels, - int rate, - int bps, - uint8_t status_bits, - uint8_t category_code); +extern void r600_hdmi_update_audio_settings(struct drm_encoder *encoder); extern void r700_cp_stop(struct radeon_device *rdev); extern void r700_cp_fini(struct radeon_device *rdev); diff --git a/drivers/gpu/drm/radeon/radeon_mode.h b/drivers/gpu/drm/radeon/radeon_mode.h index 4a086c09e117..dd451c55c533 100644 --- a/drivers/gpu/drm/radeon/radeon_mode.h +++ b/drivers/gpu/drm/radeon/radeon_mode.h @@ -345,6 +345,7 @@ struct radeon_encoder { enum radeon_rmx_type rmx_type; struct drm_display_mode native_mode; void *enc_priv; + int audio_polling_active; int hdmi_offset; int hdmi_config_offset; int hdmi_audio_workaround; -- cgit v1.2.3 From f2594933df9719bd2b0aaaa8ea9b2b850d6e1c42 Mon Sep 17 00:00:00 2001 From: Christian Koenig Date: Sat, 10 Apr 2010 03:13:16 +0200 Subject: drm/radeon/kms: HDMI irq support MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Implements irq support for HDMI audio output. Now the polling timer is only enabled if irq support isn't available. Signed-off-by: Christian König Signed-off-by: Dave Airlie --- drivers/gpu/drm/radeon/r600.c | 33 +++++++++++++++++++++ drivers/gpu/drm/radeon/r600_audio.c | 21 ++++++++------ drivers/gpu/drm/radeon/r600_hdmi.c | 54 +++++++++++++++++++++-------------- drivers/gpu/drm/radeon/r600_reg.h | 57 +++++++++++++++++++------------------ drivers/gpu/drm/radeon/radeon.h | 3 ++ 5 files changed, 112 insertions(+), 56 deletions(-) (limited to 'drivers/gpu/drm/radeon') diff --git a/drivers/gpu/drm/radeon/r600.c b/drivers/gpu/drm/radeon/r600.c index c325cb121059..2ec423c3f3f8 100644 --- a/drivers/gpu/drm/radeon/r600.c +++ b/drivers/gpu/drm/radeon/r600.c @@ -2527,6 +2527,7 @@ int r600_irq_set(struct radeon_device *rdev) u32 cp_int_cntl = CNTX_BUSY_INT_ENABLE | CNTX_EMPTY_INT_ENABLE; u32 mode_int = 0; u32 hpd1, hpd2, hpd3, hpd4 = 0, hpd5 = 0, hpd6 = 0; + u32 hdmi1, hdmi2; if (!rdev->irq.installed) { WARN(1, "Can't enable IRQ/MSI because no handler is installed.\n"); @@ -2540,7 +2541,9 @@ int r600_irq_set(struct radeon_device *rdev) return 0; } + hdmi1 = RREG32(R600_HDMI_BLOCK1 + R600_HDMI_CNTL) & ~R600_HDMI_INT_EN; if (ASIC_IS_DCE3(rdev)) { + hdmi2 = RREG32(R600_HDMI_BLOCK3 + R600_HDMI_CNTL) & ~R600_HDMI_INT_EN; hpd1 = RREG32(DC_HPD1_INT_CONTROL) & ~DC_HPDx_INT_EN; hpd2 = RREG32(DC_HPD2_INT_CONTROL) & ~DC_HPDx_INT_EN; hpd3 = RREG32(DC_HPD3_INT_CONTROL) & ~DC_HPDx_INT_EN; @@ -2550,6 +2553,7 @@ int r600_irq_set(struct radeon_device *rdev) hpd6 = RREG32(DC_HPD6_INT_CONTROL) & ~DC_HPDx_INT_EN; } } else { + hdmi2 = RREG32(R600_HDMI_BLOCK2 + R600_HDMI_CNTL) & ~R600_HDMI_INT_EN; hpd1 = RREG32(DC_HOT_PLUG_DETECT1_INT_CONTROL) & ~DC_HPDx_INT_EN; hpd2 = RREG32(DC_HOT_PLUG_DETECT2_INT_CONTROL) & ~DC_HPDx_INT_EN; hpd3 = RREG32(DC_HOT_PLUG_DETECT3_INT_CONTROL) & ~DC_HPDx_INT_EN; @@ -2591,10 +2595,20 @@ int r600_irq_set(struct radeon_device *rdev) DRM_DEBUG("r600_irq_set: hpd 6\n"); hpd6 |= DC_HPDx_INT_EN; } + if (rdev->irq.hdmi[0]) { + DRM_DEBUG("r600_irq_set: hdmi 1\n"); + hdmi1 |= R600_HDMI_INT_EN; + } + if (rdev->irq.hdmi[1]) { + DRM_DEBUG("r600_irq_set: hdmi 2\n"); + hdmi2 |= R600_HDMI_INT_EN; + } WREG32(CP_INT_CNTL, cp_int_cntl); WREG32(DxMODE_INT_MASK, mode_int); + WREG32(R600_HDMI_BLOCK1 + R600_HDMI_CNTL, hdmi1); if (ASIC_IS_DCE3(rdev)) { + WREG32(R600_HDMI_BLOCK3 + R600_HDMI_CNTL, hdmi2); WREG32(DC_HPD1_INT_CONTROL, hpd1); WREG32(DC_HPD2_INT_CONTROL, hpd2); WREG32(DC_HPD3_INT_CONTROL, hpd3); @@ -2604,6 +2618,7 @@ int r600_irq_set(struct radeon_device *rdev) WREG32(DC_HPD6_INT_CONTROL, hpd6); } } else { + WREG32(R600_HDMI_BLOCK2 + R600_HDMI_CNTL, hdmi2); WREG32(DC_HOT_PLUG_DETECT1_INT_CONTROL, hpd1); WREG32(DC_HOT_PLUG_DETECT2_INT_CONTROL, hpd2); WREG32(DC_HOT_PLUG_DETECT3_INT_CONTROL, hpd3); @@ -2687,6 +2702,18 @@ static inline void r600_irq_ack(struct radeon_device *rdev, WREG32(DC_HPD6_INT_CONTROL, tmp); } } + if (RREG32(R600_HDMI_BLOCK1 + R600_HDMI_STATUS) & R600_HDMI_INT_PENDING) { + WREG32_P(R600_HDMI_BLOCK1 + R600_HDMI_CNTL, R600_HDMI_INT_ACK, ~R600_HDMI_INT_ACK); + } + if (ASIC_IS_DCE3(rdev)) { + if (RREG32(R600_HDMI_BLOCK3 + R600_HDMI_STATUS) & R600_HDMI_INT_PENDING) { + WREG32_P(R600_HDMI_BLOCK3 + R600_HDMI_CNTL, R600_HDMI_INT_ACK, ~R600_HDMI_INT_ACK); + } + } else { + if (RREG32(R600_HDMI_BLOCK2 + R600_HDMI_STATUS) & R600_HDMI_INT_PENDING) { + WREG32_P(R600_HDMI_BLOCK2 + R600_HDMI_CNTL, R600_HDMI_INT_ACK, ~R600_HDMI_INT_ACK); + } + } } void r600_irq_disable(struct radeon_device *rdev) @@ -2740,6 +2767,8 @@ static inline u32 r600_get_ih_wptr(struct radeon_device *rdev) * 19 1 FP Hot plug detection B * 19 2 DAC A auto-detection * 19 3 DAC B auto-detection + * 21 4 HDMI block A + * 21 5 HDMI block B * 176 - CP_INT RB * 177 - CP_INT IB1 * 178 - CP_INT IB2 @@ -2879,6 +2908,10 @@ restart_ih: break; } break; + case 21: /* HDMI */ + DRM_DEBUG("IH: HDMI: 0x%x\n", src_data); + r600_audio_schedule_polling(rdev); + break; case 176: /* CP_INT in ring buffer */ case 177: /* CP_INT in IB1 */ case 178: /* CP_INT in IB2 */ diff --git a/drivers/gpu/drm/radeon/r600_audio.c b/drivers/gpu/drm/radeon/r600_audio.c index ed8d3989f172..2b26553c352c 100644 --- a/drivers/gpu/drm/radeon/r600_audio.c +++ b/drivers/gpu/drm/radeon/r600_audio.c @@ -103,6 +103,15 @@ uint8_t r600_audio_category_code(struct radeon_device *rdev) return (RREG32(R600_AUDIO_STATUS_BITS) >> 8) & 0xff; } +/* + * schedule next audio update event + */ +void r600_audio_schedule_polling(struct radeon_device *rdev) +{ + mod_timer(&rdev->audio_timer, + jiffies + msecs_to_jiffies(AUDIO_TIMER_INTERVALL)); +} + /* * update all hdmi interfaces with current audio parameters */ @@ -136,16 +145,12 @@ static void r600_audio_update_hdmi(unsigned long param) list_for_each_entry(encoder, &dev->mode_config.encoder_list, head) { struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder); - if (radeon_encoder->audio_polling_active) { - still_going = 1; - if (changes || r600_hdmi_buffer_status_changed(encoder)) - r600_hdmi_update_audio_settings(encoder); - } + still_going |= radeon_encoder->audio_polling_active; + if (changes || r600_hdmi_buffer_status_changed(encoder)) + r600_hdmi_update_audio_settings(encoder); } - if(still_going) - mod_timer(&rdev->audio_timer, - jiffies + msecs_to_jiffies(AUDIO_TIMER_INTERVALL)); + if(still_going) r600_audio_schedule_polling(rdev); } /* diff --git a/drivers/gpu/drm/radeon/r600_hdmi.c b/drivers/gpu/drm/radeon/r600_hdmi.c index d014472d0d3f..40b1aca6d1f4 100644 --- a/drivers/gpu/drm/radeon/r600_hdmi.c +++ b/drivers/gpu/drm/radeon/r600_hdmi.c @@ -290,17 +290,15 @@ void r600_hdmi_audio_workaround(struct drm_encoder *encoder) if (!offset) return; - if (r600_hdmi_is_audio_buffer_filled(encoder)) { - /* disable audio workaround and start delivering of audio frames */ - WREG32_P(offset+R600_HDMI_CNTL, 0x00000001, ~0x00001001); + if (!radeon_encoder->hdmi_audio_workaround || + r600_hdmi_is_audio_buffer_filled(encoder)) { - } else if (radeon_encoder->hdmi_audio_workaround) { - /* enable audio workaround and start delivering of audio frames */ - WREG32_P(offset+R600_HDMI_CNTL, 0x00001001, ~0x00001001); + /* disable audio workaround */ + WREG32_P(offset+R600_HDMI_CNTL, 0x00000001, ~0x00001001); } else { - /* disable audio workaround and stop delivering of audio frames */ - WREG32_P(offset+R600_HDMI_CNTL, 0x00000000, ~0x00001001); + /* enable audio workaround */ + WREG32_P(offset+R600_HDMI_CNTL, 0x00001001, ~0x00001001); } } @@ -345,9 +343,6 @@ void r600_hdmi_setmode(struct drm_encoder *encoder, struct drm_display_mode *mod /* audio packets per line, does anyone know how to calc this ? */ WREG32_P(offset+R600_HDMI_CNTL, 0x00040000, ~0x001F0000); - - /* update? reset? don't realy know */ - WREG32_P(offset+R600_HDMI_CNTL, 0x14000000, ~0x14000000); } /* @@ -416,9 +411,6 @@ void r600_hdmi_update_audio_settings(struct drm_encoder *encoder) r600_hdmi_audioinfoframe(encoder, channels-1, 0, 0, 0, 0, 0, 0, 0); r600_hdmi_audio_workaround(encoder); - - /* update? reset? don't realy know */ - WREG32_P(offset+R600_HDMI_CNTL, 0x04000000, ~0x04000000); } static int r600_hdmi_find_free_block(struct drm_device *dev) @@ -487,6 +479,7 @@ void r600_hdmi_enable(struct drm_encoder *encoder) struct drm_device *dev = encoder->dev; struct radeon_device *rdev = dev->dev_private; struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder); + uint32_t offset; if (ASIC_IS_DCE4(rdev)) return; @@ -500,10 +493,10 @@ void r600_hdmi_enable(struct drm_encoder *encoder) } } + offset = radeon_encoder->hdmi_offset; if (ASIC_IS_DCE32(rdev) && !ASIC_IS_DCE4(rdev)) { WREG32_P(radeon_encoder->hdmi_config_offset + 0x4, 0x1, ~0x1); } else if (rdev->family >= CHIP_R600 && !ASIC_IS_DCE3(rdev)) { - int offset = radeon_encoder->hdmi_offset; switch (radeon_encoder->encoder_id) { case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_TMDS1: WREG32_P(AVIVO_TMDSA_CNTL, 0x4, ~0x4); @@ -519,7 +512,20 @@ void r600_hdmi_enable(struct drm_encoder *encoder) } } - r600_audio_enable_polling(encoder); + if (rdev->irq.installed + && rdev->family != CHIP_RS600 + && rdev->family != CHIP_RS690 + && rdev->family != CHIP_RS740) { + + /* if irq is available use it */ + rdev->irq.hdmi[offset == R600_HDMI_BLOCK1 ? 0 : 1] = true; + radeon_irq_set(rdev); + + r600_audio_disable_polling(encoder); + } else { + /* if not fallback to polling */ + r600_audio_enable_polling(encoder); + } DRM_DEBUG("Enabling HDMI interface @ 0x%04X for encoder 0x%x\n", radeon_encoder->hdmi_offset, radeon_encoder->encoder_id); @@ -533,24 +539,30 @@ void r600_hdmi_disable(struct drm_encoder *encoder) struct drm_device *dev = encoder->dev; struct radeon_device *rdev = dev->dev_private; struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder); + uint8_t offset; if (ASIC_IS_DCE4(rdev)) return; - if (!radeon_encoder->hdmi_offset) { + offset = radeon_encoder->hdmi_offset; + if (!offset) { dev_err(rdev->dev, "Disabling not enabled HDMI\n"); return; } - r600_audio_disable_polling(encoder); - DRM_DEBUG("Disabling HDMI interface @ 0x%04X for encoder 0x%x\n", - radeon_encoder->hdmi_offset, radeon_encoder->encoder_id); + offset, radeon_encoder->encoder_id); + + /* disable irq */ + rdev->irq.hdmi[offset == R600_HDMI_BLOCK1 ? 0 : 1] = false; + radeon_irq_set(rdev); + + /* disable polling */ + r600_audio_disable_polling(encoder); if (ASIC_IS_DCE32(rdev) && !ASIC_IS_DCE4(rdev)) { WREG32_P(radeon_encoder->hdmi_config_offset + 0x4, 0, ~0x1); } else if (rdev->family >= CHIP_R600 && !ASIC_IS_DCE3(rdev)) { - int offset = radeon_encoder->hdmi_offset; switch (radeon_encoder->encoder_id) { case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_TMDS1: WREG32_P(AVIVO_TMDSA_CNTL, 0, ~0x4); diff --git a/drivers/gpu/drm/radeon/r600_reg.h b/drivers/gpu/drm/radeon/r600_reg.h index 7b1d22370f6e..d84612ae47e0 100644 --- a/drivers/gpu/drm/radeon/r600_reg.h +++ b/drivers/gpu/drm/radeon/r600_reg.h @@ -157,33 +157,36 @@ #define R600_HDMI_BLOCK3 0x7800 /* HDMI registers */ -#define R600_HDMI_ENABLE 0x00 -#define R600_HDMI_STATUS 0x04 -#define R600_HDMI_CNTL 0x08 -#define R600_HDMI_UNKNOWN_0 0x0C -#define R600_HDMI_AUDIOCNTL 0x10 -#define R600_HDMI_VIDEOCNTL 0x14 -#define R600_HDMI_VERSION 0x18 -#define R600_HDMI_UNKNOWN_1 0x28 -#define R600_HDMI_VIDEOINFOFRAME_0 0x54 -#define R600_HDMI_VIDEOINFOFRAME_1 0x58 -#define R600_HDMI_VIDEOINFOFRAME_2 0x5c -#define R600_HDMI_VIDEOINFOFRAME_3 0x60 -#define R600_HDMI_32kHz_CTS 0xac -#define R600_HDMI_32kHz_N 0xb0 -#define R600_HDMI_44_1kHz_CTS 0xb4 -#define R600_HDMI_44_1kHz_N 0xb8 -#define R600_HDMI_48kHz_CTS 0xbc -#define R600_HDMI_48kHz_N 0xc0 -#define R600_HDMI_AUDIOINFOFRAME_0 0xcc -#define R600_HDMI_AUDIOINFOFRAME_1 0xd0 -#define R600_HDMI_IEC60958_1 0xd4 -#define R600_HDMI_IEC60958_2 0xd8 -#define R600_HDMI_UNKNOWN_2 0xdc -#define R600_HDMI_AUDIO_DEBUG_0 0xe0 -#define R600_HDMI_AUDIO_DEBUG_1 0xe4 -#define R600_HDMI_AUDIO_DEBUG_2 0xe8 -#define R600_HDMI_AUDIO_DEBUG_3 0xec +#define R600_HDMI_ENABLE 0x00 +#define R600_HDMI_STATUS 0x04 +# define R600_HDMI_INT_PENDING (1 << 29) +#define R600_HDMI_CNTL 0x08 +# define R600_HDMI_INT_EN (1 << 28) +# define R600_HDMI_INT_ACK (1 << 29) +#define R600_HDMI_UNKNOWN_0 0x0C +#define R600_HDMI_AUDIOCNTL 0x10 +#define R600_HDMI_VIDEOCNTL 0x14 +#define R600_HDMI_VERSION 0x18 +#define R600_HDMI_UNKNOWN_1 0x28 +#define R600_HDMI_VIDEOINFOFRAME_0 0x54 +#define R600_HDMI_VIDEOINFOFRAME_1 0x58 +#define R600_HDMI_VIDEOINFOFRAME_2 0x5c +#define R600_HDMI_VIDEOINFOFRAME_3 0x60 +#define R600_HDMI_32kHz_CTS 0xac +#define R600_HDMI_32kHz_N 0xb0 +#define R600_HDMI_44_1kHz_CTS 0xb4 +#define R600_HDMI_44_1kHz_N 0xb8 +#define R600_HDMI_48kHz_CTS 0xbc +#define R600_HDMI_48kHz_N 0xc0 +#define R600_HDMI_AUDIOINFOFRAME_0 0xcc +#define R600_HDMI_AUDIOINFOFRAME_1 0xd0 +#define R600_HDMI_IEC60958_1 0xd4 +#define R600_HDMI_IEC60958_2 0xd8 +#define R600_HDMI_UNKNOWN_2 0xdc +#define R600_HDMI_AUDIO_DEBUG_0 0xe0 +#define R600_HDMI_AUDIO_DEBUG_1 0xe4 +#define R600_HDMI_AUDIO_DEBUG_2 0xe8 +#define R600_HDMI_AUDIO_DEBUG_3 0xec /* HDMI additional config base register addresses */ #define R600_HDMI_CONFIG1 0x7600 diff --git a/drivers/gpu/drm/radeon/radeon.h b/drivers/gpu/drm/radeon/radeon.h index 42217af58145..ab29d972a167 100644 --- a/drivers/gpu/drm/radeon/radeon.h +++ b/drivers/gpu/drm/radeon/radeon.h @@ -376,6 +376,8 @@ struct radeon_irq { wait_queue_head_t vblank_queue; /* FIXME: use defines for max hpd/dacs */ bool hpd[6]; + /* FIXME: use defines for max HDMI blocks */ + bool hdmi[2]; spinlock_t sw_lock; int sw_refcount; }; @@ -1332,6 +1334,7 @@ extern int r600_audio_bits_per_sample(struct radeon_device *rdev); extern int r600_audio_rate(struct radeon_device *rdev); extern uint8_t r600_audio_status_bits(struct radeon_device *rdev); extern uint8_t r600_audio_category_code(struct radeon_device *rdev); +extern void r600_audio_schedule_polling(struct radeon_device *rdev); extern void r600_audio_enable_polling(struct drm_encoder *encoder); extern void r600_audio_disable_polling(struct drm_encoder *encoder); extern void r600_audio_fini(struct radeon_device *rdev); -- cgit v1.2.3 From a1e9ada3e148dc300fdd25705bd3ac024897dc68 Mon Sep 17 00:00:00 2001 From: Jerome Glisse Date: Mon, 26 Apr 2010 22:23:42 +0200 Subject: drm/radeon/kms: R3XX-R4XX fix GPU reset code Previous reset code leaded to computer hard lockup (need to unplug the power too reboot the computer) on various configuration. This patch change the reset code to avoid hard lockup. The GPU reset is failing most of the time but at least user can log in remotely or properly shutdown the computer. Two issues were leading to hard lockup : - Writting to the scratch register lead to hard lockup most likely because the write back mecanism is in fuzy state after GPU lockup. - Resetting the GPU memory controller and not reinitializing it after leaded to hard lockup. We did only reinitialize in case of successfull reset thus unsuccessfull reset quickly leaded to hard lockup. Signed-off-by: Jerome Glisse Signed-off-by: Dave Airlie --- drivers/gpu/drm/radeon/r300.c | 8 -------- drivers/gpu/drm/radeon/radeon_fence.c | 2 +- 2 files changed, 1 insertion(+), 9 deletions(-) (limited to 'drivers/gpu/drm/radeon') diff --git a/drivers/gpu/drm/radeon/r300.c b/drivers/gpu/drm/radeon/r300.c index bb005bff4b08..5d622cb39b33 100644 --- a/drivers/gpu/drm/radeon/r300.c +++ b/drivers/gpu/drm/radeon/r300.c @@ -445,14 +445,6 @@ int r300_asic_reset(struct radeon_device *rdev) mdelay(1); status = RREG32(R_000E40_RBBM_STATUS); dev_info(rdev->dev, "(%s:%d) RBBM_STATUS=0x%08X\n", __func__, __LINE__, status); - /* reset MC */ - WREG32(R_0000F0_RBBM_SOFT_RESET, S_0000F0_SOFT_RESET_MC(1)); - RREG32(R_0000F0_RBBM_SOFT_RESET); - mdelay(500); - WREG32(R_0000F0_RBBM_SOFT_RESET, 0); - mdelay(1); - status = RREG32(R_000E40_RBBM_STATUS); - dev_info(rdev->dev, "(%s:%d) RBBM_STATUS=0x%08X\n", __func__, __LINE__, status); /* restore PCI & busmastering */ pci_restore_state(rdev->pdev); r100_enable_bm(rdev); diff --git a/drivers/gpu/drm/radeon/radeon_fence.c b/drivers/gpu/drm/radeon/radeon_fence.c index 1b8b9cc271f2..b1f9a81b5d1d 100644 --- a/drivers/gpu/drm/radeon/radeon_fence.c +++ b/drivers/gpu/drm/radeon/radeon_fence.c @@ -237,10 +237,10 @@ retry: * as signaled for now */ rdev->gpu_lockup = true; - WREG32(rdev->fence_drv.scratch_reg, fence->seq); r = radeon_gpu_reset(rdev); if (r) return r; + WREG32(rdev->fence_drv.scratch_reg, fence->seq); rdev->gpu_lockup = false; } timeout = RADEON_FENCE_JIFFIES_TIMEOUT; -- cgit v1.2.3 From aa9613916a461027fdade8661177660db0975806 Mon Sep 17 00:00:00 2001 From: Alex Deucher Date: Fri, 7 May 2010 17:05:22 -0400 Subject: drm/radeon/kms/atom: disable the encoders in encoder_disable Previously we just set them to dpms off. This should save additional power. Signed-off-by: Alex Deucher Signed-off-by: Dave Airlie --- drivers/gpu/drm/radeon/radeon_encoders.c | 39 ++++++++++++++++++++++++++++++++ 1 file changed, 39 insertions(+) (limited to 'drivers/gpu/drm/radeon') diff --git a/drivers/gpu/drm/radeon/radeon_encoders.c b/drivers/gpu/drm/radeon/radeon_encoders.c index 30293bec0801..63b805693905 100644 --- a/drivers/gpu/drm/radeon/radeon_encoders.c +++ b/drivers/gpu/drm/radeon/radeon_encoders.c @@ -1509,10 +1509,49 @@ static void radeon_atom_encoder_commit(struct drm_encoder *encoder) static void radeon_atom_encoder_disable(struct drm_encoder *encoder) { + struct drm_device *dev = encoder->dev; + struct radeon_device *rdev = dev->dev_private; struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder); struct radeon_encoder_atom_dig *dig; radeon_atom_encoder_dpms(encoder, DRM_MODE_DPMS_OFF); + switch (radeon_encoder->encoder_id) { + case ENCODER_OBJECT_ID_INTERNAL_TMDS1: + case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_TMDS1: + case ENCODER_OBJECT_ID_INTERNAL_LVDS: + case ENCODER_OBJECT_ID_INTERNAL_LVTM1: + atombios_digital_setup(encoder, PANEL_ENCODER_ACTION_DISABLE); + break; + case ENCODER_OBJECT_ID_INTERNAL_UNIPHY: + case ENCODER_OBJECT_ID_INTERNAL_UNIPHY1: + case ENCODER_OBJECT_ID_INTERNAL_UNIPHY2: + case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_LVTMA: + if (ASIC_IS_DCE4(rdev)) + /* disable the transmitter */ + atombios_dig_transmitter_setup(encoder, ATOM_TRANSMITTER_ACTION_DISABLE, 0, 0); + else { + /* disable the encoder and transmitter */ + atombios_dig_transmitter_setup(encoder, ATOM_TRANSMITTER_ACTION_DISABLE, 0, 0); + atombios_dig_encoder_setup(encoder, ATOM_DISABLE); + } + break; + case ENCODER_OBJECT_ID_INTERNAL_DDI: + atombios_ddia_setup(encoder, ATOM_DISABLE); + break; + case ENCODER_OBJECT_ID_INTERNAL_DVO1: + case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_DVO1: + atombios_external_tmds_setup(encoder, ATOM_DISABLE); + break; + case ENCODER_OBJECT_ID_INTERNAL_DAC1: + case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_DAC1: + case ENCODER_OBJECT_ID_INTERNAL_DAC2: + case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_DAC2: + atombios_dac_setup(encoder, ATOM_DISABLE); + if (radeon_encoder->active_device & (ATOM_DEVICE_TV_SUPPORT | ATOM_DEVICE_CV_SUPPORT)) + atombios_tv_setup(encoder, ATOM_DISABLE); + break; + } + if (radeon_encoder_is_digital(encoder)) { if (atombios_get_encoder_mode(encoder) == ATOM_ENCODER_MODE_HDMI) r600_hdmi_disable(encoder); -- cgit v1.2.3 From 8bf3aae6214792a5f758fb6f82cf25a98ac8e5a0 Mon Sep 17 00:00:00 2001 From: Alex Deucher Date: Fri, 7 May 2010 23:17:20 -0400 Subject: drm/radeon/kms: fix copy pasto in disable encoders patch Signed-off-by: Alex Deucher Signed-off-by: Dave Airlie --- drivers/gpu/drm/radeon/radeon_encoders.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/gpu/drm/radeon') diff --git a/drivers/gpu/drm/radeon/radeon_encoders.c b/drivers/gpu/drm/radeon/radeon_encoders.c index 63b805693905..1ec292ef11b0 100644 --- a/drivers/gpu/drm/radeon/radeon_encoders.c +++ b/drivers/gpu/drm/radeon/radeon_encoders.c @@ -1547,7 +1547,7 @@ static void radeon_atom_encoder_disable(struct drm_encoder *encoder) case ENCODER_OBJECT_ID_INTERNAL_DAC2: case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_DAC2: atombios_dac_setup(encoder, ATOM_DISABLE); - if (radeon_encoder->active_device & (ATOM_DEVICE_TV_SUPPORT | ATOM_DEVICE_CV_SUPPORT)) + if (radeon_encoder->devices & (ATOM_DEVICE_TV_SUPPORT | ATOM_DEVICE_CV_SUPPORT)) atombios_tv_setup(encoder, ATOM_DISABLE); break; } -- cgit v1.2.3 From 1ff26a3604d0292988d4cade0e49ba9918dbfd46 Mon Sep 17 00:00:00 2001 From: Alex Deucher Date: Tue, 18 May 2010 00:23:15 -0400 Subject: drm/radeon/kms/atom: fix typo in LVDS panel info parsing Fixes LVDS issues on some laptops; notably laptops with 2048x1536 panels. Signed-off-by: Alex Deucher Cc: stable@kernel.org Signed-off-by: Dave Airlie --- drivers/gpu/drm/radeon/radeon_atombios.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/gpu/drm/radeon') diff --git a/drivers/gpu/drm/radeon/radeon_atombios.c b/drivers/gpu/drm/radeon/radeon_atombios.c index 273019925e0b..031a96ceb0f5 100644 --- a/drivers/gpu/drm/radeon/radeon_atombios.c +++ b/drivers/gpu/drm/radeon/radeon_atombios.c @@ -1174,7 +1174,7 @@ struct radeon_encoder_atom_dig *radeon_atombios_get_lvds_info(struct lvds->native_mode.vtotal = lvds->native_mode.vdisplay + le16_to_cpu(lvds_info->info.sLCDTiming.usVBlanking_Time); lvds->native_mode.vsync_start = lvds->native_mode.vdisplay + - le16_to_cpu(lvds_info->info.sLCDTiming.usVSyncWidth); + le16_to_cpu(lvds_info->info.sLCDTiming.usVSyncOffset); lvds->native_mode.vsync_end = lvds->native_mode.vsync_start + le16_to_cpu(lvds_info->info.sLCDTiming.usVSyncWidth); lvds->panel_pwr_delay = -- cgit v1.2.3 From 68b61a7fd21be9df23577d48643ba9e364758200 Mon Sep 17 00:00:00 2001 From: Alex Deucher Date: Tue, 18 May 2010 00:30:05 -0400 Subject: drm/radeon/kms/combios: match lvds panel info parsing to ddx Should work better on some panels. Signed-off-by: Alex Deucher Signed-off-by: Dave Airlie --- drivers/gpu/drm/radeon/radeon_combios.c | 26 ++++++++++++++------------ 1 file changed, 14 insertions(+), 12 deletions(-) (limited to 'drivers/gpu/drm/radeon') diff --git a/drivers/gpu/drm/radeon/radeon_combios.c b/drivers/gpu/drm/radeon/radeon_combios.c index 0f1fd9254e30..44198581ba9e 100644 --- a/drivers/gpu/drm/radeon/radeon_combios.c +++ b/drivers/gpu/drm/radeon/radeon_combios.c @@ -1113,18 +1113,20 @@ struct radeon_encoder_lvds *radeon_combios_get_lvds_info(struct radeon_encoder break; if ((RBIOS16(tmp) == lvds->native_mode.hdisplay) && - (RBIOS16(tmp + 2) == - lvds->native_mode.vdisplay)) { - lvds->native_mode.htotal = RBIOS16(tmp + 17) * 8; - lvds->native_mode.hsync_start = RBIOS16(tmp + 21) * 8; - lvds->native_mode.hsync_end = (RBIOS8(tmp + 23) + - RBIOS16(tmp + 21)) * 8; - - lvds->native_mode.vtotal = RBIOS16(tmp + 24); - lvds->native_mode.vsync_start = RBIOS16(tmp + 28) & 0x7ff; - lvds->native_mode.vsync_end = - ((RBIOS16(tmp + 28) & 0xf800) >> 11) + - (RBIOS16(tmp + 28) & 0x7ff); + (RBIOS16(tmp + 2) == lvds->native_mode.vdisplay)) { + lvds->native_mode.htotal = lvds->native_mode.hdisplay + + (RBIOS16(tmp + 17) - RBIOS16(tmp + 19)) * 8; + lvds->native_mode.hsync_start = lvds->native_mode.hdisplay + + (RBIOS16(tmp + 21) - RBIOS16(tmp + 19) - 1) * 8; + lvds->native_mode.hsync_end = lvds->native_mode.hsync_start + + (RBIOS8(tmp + 23) * 8); + + lvds->native_mode.vtotal = lvds->native_mode.vdisplay + + (RBIOS16(tmp + 24) - RBIOS16(tmp + 26)); + lvds->native_mode.vsync_start = lvds->native_mode.vdisplay + + ((RBIOS16(tmp + 28) & 0x7ff) - RBIOS16(tmp + 26)); + lvds->native_mode.vsync_end = lvds->native_mode.vsync_start + + ((RBIOS16(tmp + 28) & 0xf800) >> 11); lvds->native_mode.clock = RBIOS16(tmp + 9) * 10; lvds->native_mode.flags = 0; -- cgit v1.2.3 From f405a1ab2bf316b1969fc5355891e5dff4e1a54c Mon Sep 17 00:00:00 2001 From: Julia Lawall Date: Sat, 15 May 2010 23:17:40 +0200 Subject: drivers/gpu/drm: Use kmemdup Use kmemdup when some other buffer is immediately copied into the allocated region. A simplified version of the semantic patch that makes this change is as follows: (http://coccinelle.lip6.fr/) // @@ expression from,to,size,flag; statement S; @@ - to = \(kmalloc\|kzalloc\)(size,flag); + to = kmemdup(from,size,flag); if (to==NULL || ...) S - memcpy(to, from, size); // Signed-off-by: Julia Lawall Signed-off-by: Dave Airlie --- drivers/gpu/drm/nouveau/nouveau_grctx.c | 6 ++---- drivers/gpu/drm/radeon/radeon_bios.c | 3 +-- 2 files changed, 3 insertions(+), 6 deletions(-) (limited to 'drivers/gpu/drm/radeon') diff --git a/drivers/gpu/drm/nouveau/nouveau_grctx.c b/drivers/gpu/drm/nouveau/nouveau_grctx.c index 32f0e495464c..f731c5f60536 100644 --- a/drivers/gpu/drm/nouveau/nouveau_grctx.c +++ b/drivers/gpu/drm/nouveau/nouveau_grctx.c @@ -68,13 +68,12 @@ nouveau_grctx_prog_load(struct drm_device *dev) return ret; } - pgraph->ctxprog = kmalloc(fw->size, GFP_KERNEL); + pgraph->ctxprog = kmemdup(fw->data, fw->size, GFP_KERNEL); if (!pgraph->ctxprog) { NV_ERROR(dev, "OOM copying ctxprog\n"); release_firmware(fw); return -ENOMEM; } - memcpy(pgraph->ctxprog, fw->data, fw->size); cp = pgraph->ctxprog; if (le32_to_cpu(cp->signature) != 0x5043564e || @@ -97,14 +96,13 @@ nouveau_grctx_prog_load(struct drm_device *dev) return ret; } - pgraph->ctxvals = kmalloc(fw->size, GFP_KERNEL); + pgraph->ctxvals = kmemdup(fw->data, fw->size, GFP_KERNEL); if (!pgraph->ctxvals) { NV_ERROR(dev, "OOM copying ctxvals\n"); release_firmware(fw); nouveau_grctx_fini(dev); return -ENOMEM; } - memcpy(pgraph->ctxvals, fw->data, fw->size); cv = (void *)pgraph->ctxvals; if (le32_to_cpu(cv->signature) != 0x5643564e || diff --git a/drivers/gpu/drm/radeon/radeon_bios.c b/drivers/gpu/drm/radeon/radeon_bios.c index 8ad71f701316..fbba938f8048 100644 --- a/drivers/gpu/drm/radeon/radeon_bios.c +++ b/drivers/gpu/drm/radeon/radeon_bios.c @@ -85,12 +85,11 @@ static bool radeon_read_bios(struct radeon_device *rdev) pci_unmap_rom(rdev->pdev, bios); return false; } - rdev->bios = kmalloc(size, GFP_KERNEL); + rdev->bios = kmemdup(bios, size, GFP_KERNEL); if (rdev->bios == NULL) { pci_unmap_rom(rdev->pdev, bios); return false; } - memcpy(rdev->bios, bios, size); pci_unmap_rom(rdev->pdev, bios); return true; } -- cgit v1.2.3 From bc35afdb182d4c48c889fe27ba7a5d7ea0c8194d Mon Sep 17 00:00:00 2001 From: Jerome Glisse Date: Wed, 12 May 2010 18:01:13 +0200 Subject: drm/radeon/kms: add query for crtc hw id from crtc id to get info V2 Userspace need to know the hw crtc id (0, 1, 2, ...) from the drm crtc id. Bump the minor version so userspace can enable conditionaly features depend on this. V2 use num_crtc and avoid DRM_ERROR Signed-off-by: Jerome Glisse Signed-off-by: Dave Airlie --- drivers/gpu/drm/radeon/radeon_drv.c | 3 ++- drivers/gpu/drm/radeon/radeon_kms.c | 18 ++++++++++++++++++ include/drm/radeon_drm.h | 1 + 3 files changed, 21 insertions(+), 1 deletion(-) (limited to 'drivers/gpu/drm/radeon') diff --git a/drivers/gpu/drm/radeon/radeon_drv.c b/drivers/gpu/drm/radeon/radeon_drv.c index 4b05563d99e1..6e22815f7f07 100644 --- a/drivers/gpu/drm/radeon/radeon_drv.c +++ b/drivers/gpu/drm/radeon/radeon_drv.c @@ -44,9 +44,10 @@ * - 2.1.0 - add square tiling interface * - 2.2.0 - add r6xx/r7xx const buffer support * - 2.3.0 - add MSPOS + 3D texture + r500 VAP regs + * - 2.4.0 - add crtc id query */ #define KMS_DRIVER_MAJOR 2 -#define KMS_DRIVER_MINOR 3 +#define KMS_DRIVER_MINOR 4 #define KMS_DRIVER_PATCHLEVEL 0 int radeon_driver_load_kms(struct drm_device *dev, unsigned long flags); int radeon_driver_unload_kms(struct drm_device *dev); diff --git a/drivers/gpu/drm/radeon/radeon_kms.c b/drivers/gpu/drm/radeon/radeon_kms.c index d3657dcfdd26..021572a3dd9c 100644 --- a/drivers/gpu/drm/radeon/radeon_kms.c +++ b/drivers/gpu/drm/radeon/radeon_kms.c @@ -98,11 +98,15 @@ int radeon_info_ioctl(struct drm_device *dev, void *data, struct drm_file *filp) { struct radeon_device *rdev = dev->dev_private; struct drm_radeon_info *info; + struct radeon_mode_info *minfo = &rdev->mode_info; uint32_t *value_ptr; uint32_t value; + struct drm_crtc *crtc; + int i, found; info = data; value_ptr = (uint32_t *)((unsigned long)info->value); + value = *value_ptr; switch (info->request) { case RADEON_INFO_DEVICE_ID: value = dev->pci_device; @@ -116,6 +120,20 @@ int radeon_info_ioctl(struct drm_device *dev, void *data, struct drm_file *filp) case RADEON_INFO_ACCEL_WORKING: value = rdev->accel_working; break; + case RADEON_INFO_CRTC_FROM_ID: + for (i = 0, found = 0; i < rdev->num_crtc; i++) { + crtc = (struct drm_crtc *)minfo->crtcs[i]; + if (crtc && crtc->base.id == value) { + value = i; + found = 1; + break; + } + } + if (!found) { + DRM_DEBUG("unknown crtc id %d\n", value); + return -EINVAL; + } + break; default: DRM_DEBUG("Invalid request %d\n", info->request); return -EINVAL; diff --git a/include/drm/radeon_drm.h b/include/drm/radeon_drm.h index 81e614bf2dc3..3ff9fc071dfe 100644 --- a/include/drm/radeon_drm.h +++ b/include/drm/radeon_drm.h @@ -902,6 +902,7 @@ struct drm_radeon_cs { #define RADEON_INFO_NUM_GB_PIPES 0x01 #define RADEON_INFO_NUM_Z_PIPES 0x02 #define RADEON_INFO_ACCEL_WORKING 0x03 +#define RADEON_INFO_CRTC_FROM_ID 0x04 struct drm_radeon_info { uint32_t request; -- cgit v1.2.3 From 1471ca9aa71cd37b6a7476bb6f06a3a8622ea1bd Mon Sep 17 00:00:00 2001 From: Marcin Slusarz Date: Sun, 16 May 2010 17:27:03 +0200 Subject: fbdev: allow passing more than one aperture for handoff It removes a hack from nouveau code which had to detect which region to pass to kick vesafb/efifb. Signed-off-by: Marcin Slusarz Cc: Eric Anholt Cc: Ben Skeggs Cc: Thomas Hellstrom Cc: Dave Airlie Cc: Peter Jones Cc: Benjamin Herrenschmidt Signed-off-by: Dave Airlie --- drivers/gpu/drm/i915/intel_fb.c | 11 +++-- drivers/gpu/drm/nouveau/nouveau_fbcon.c | 84 ++++++++++----------------------- drivers/gpu/drm/radeon/radeon_fb.c | 9 +++- drivers/gpu/drm/vmwgfx/vmwgfx_fb.c | 10 +++- drivers/video/efifb.c | 11 +++-- drivers/video/fbmem.c | 29 ++++++++++-- drivers/video/fbsysfs.c | 1 + drivers/video/offb.c | 28 ++++++----- drivers/video/vesafb.c | 11 +++-- include/linux/fb.h | 17 ++++++- 10 files changed, 123 insertions(+), 88 deletions(-) (limited to 'drivers/gpu/drm/radeon') diff --git a/drivers/gpu/drm/i915/intel_fb.c b/drivers/gpu/drm/i915/intel_fb.c index b04e0a86bf9a..7f1eabbaa2bb 100644 --- a/drivers/gpu/drm/i915/intel_fb.c +++ b/drivers/gpu/drm/i915/intel_fb.c @@ -128,11 +128,16 @@ static int intelfb_create(struct intel_fbdev *ifbdev, info->fbops = &intelfb_ops; /* setup aperture base/size for vesafb takeover */ - info->aperture_base = dev->mode_config.fb_base; + info->apertures = alloc_apertures(1); + if (!info->apertures) { + ret = -ENOMEM; + goto out_unpin; + } + info->apertures->ranges[0].base = dev->mode_config.fb_base; if (IS_I9XX(dev)) - info->aperture_size = pci_resource_len(dev->pdev, 2); + info->apertures->ranges[0].size = pci_resource_len(dev->pdev, 2); else - info->aperture_size = pci_resource_len(dev->pdev, 0); + info->apertures->ranges[0].size = pci_resource_len(dev->pdev, 0); info->fix.smem_start = dev->mode_config.fb_base + obj_priv->gtt_offset; info->fix.smem_len = size; diff --git a/drivers/gpu/drm/nouveau/nouveau_fbcon.c b/drivers/gpu/drm/nouveau/nouveau_fbcon.c index f29fa8c117ce..292c7ff95105 100644 --- a/drivers/gpu/drm/nouveau/nouveau_fbcon.c +++ b/drivers/gpu/drm/nouveau/nouveau_fbcon.c @@ -152,44 +152,6 @@ static void nouveau_fbcon_gamma_get(struct drm_crtc *crtc, u16 *red, u16 *green, *blue = nv_crtc->lut.b[regno]; } -#if defined(__i386__) || defined(__x86_64__) -static bool -nouveau_fbcon_has_vesafb_or_efifb(struct drm_device *dev) -{ - struct pci_dev *pdev = dev->pdev; - int ramin; - - if (screen_info.orig_video_isVGA != VIDEO_TYPE_VLFB && - screen_info.orig_video_isVGA != VIDEO_TYPE_EFI) - return false; - - if (screen_info.lfb_base < pci_resource_start(pdev, 1)) - goto not_fb; - - if (screen_info.lfb_base + screen_info.lfb_size >= - pci_resource_start(pdev, 1) + pci_resource_len(pdev, 1)) - goto not_fb; - - return true; -not_fb: - ramin = 2; - if (pci_resource_len(pdev, ramin) == 0) { - ramin = 3; - if (pci_resource_len(pdev, ramin) == 0) - return false; - } - - if (screen_info.lfb_base < pci_resource_start(pdev, ramin)) - return false; - - if (screen_info.lfb_base + screen_info.lfb_size >= - pci_resource_start(pdev, ramin) + pci_resource_len(pdev, ramin)) - return false; - - return true; -} -#endif - static void nouveau_fbcon_zfill(struct drm_device *dev, struct nouveau_fbdev *nfbdev) { @@ -219,7 +181,9 @@ nouveau_fbcon_create(struct nouveau_fbdev *nfbdev, struct nouveau_framebuffer *nouveau_fb; struct nouveau_bo *nvbo; struct drm_mode_fb_cmd mode_cmd; - struct device *device = &dev->pdev->dev; + struct pci_dev *pdev = dev->pdev; + struct device *device = &pdev->dev; + struct apertures_struct *aper; int size, ret; mode_cmd.width = sizes->surface_width; @@ -299,28 +263,30 @@ nouveau_fbcon_create(struct nouveau_fbdev *nfbdev, drm_fb_helper_fill_var(info, &nfbdev->helper, sizes->fb_width, sizes->fb_height); /* FIXME: we really shouldn't expose mmio space at all */ - info->fix.mmio_start = pci_resource_start(dev->pdev, 1); - info->fix.mmio_len = pci_resource_len(dev->pdev, 1); + info->fix.mmio_start = pci_resource_start(pdev, 1); + info->fix.mmio_len = pci_resource_len(pdev, 1); /* Set aperture base/size for vesafb takeover */ -#if defined(__i386__) || defined(__x86_64__) - if (nouveau_fbcon_has_vesafb_or_efifb(dev)) { - /* Some NVIDIA VBIOS' are stupid and decide to put the - * framebuffer in the middle of the PRAMIN BAR for - * whatever reason. We need to know the exact lfb_base - * to get vesafb kicked off, and the only reliable way - * we have left is to find out lfb_base the same way - * vesafb did. - */ - info->aperture_base = screen_info.lfb_base; - info->aperture_size = screen_info.lfb_size; - if (screen_info.orig_video_isVGA == VIDEO_TYPE_VLFB) - info->aperture_size *= 65536; - } else -#endif - { - info->aperture_base = info->fix.mmio_start; - info->aperture_size = info->fix.mmio_len; + aper = info->apertures = alloc_apertures(3); + if (!info->apertures) { + ret = -ENOMEM; + goto out_unref; + } + + aper->ranges[0].base = pci_resource_start(pdev, 1); + aper->ranges[0].size = pci_resource_len(pdev, 1); + aper->count = 1; + + if (pci_resource_len(pdev, 2)) { + aper->ranges[aper->count].base = pci_resource_start(pdev, 2); + aper->ranges[aper->count].size = pci_resource_len(pdev, 2); + aper->count++; + } + + if (pci_resource_len(pdev, 3)) { + aper->ranges[aper->count].base = pci_resource_start(pdev, 3); + aper->ranges[aper->count].size = pci_resource_len(pdev, 3); + aper->count++; } info->pixmap.size = 64*1024; diff --git a/drivers/gpu/drm/radeon/radeon_fb.c b/drivers/gpu/drm/radeon/radeon_fb.c index fcb5b52727b0..b4948021e345 100644 --- a/drivers/gpu/drm/radeon/radeon_fb.c +++ b/drivers/gpu/drm/radeon/radeon_fb.c @@ -236,8 +236,13 @@ static int radeonfb_create(struct radeon_fbdev *rfbdev, drm_fb_helper_fill_var(info, &rfbdev->helper, sizes->fb_width, sizes->fb_height); /* setup aperture base/size for vesafb takeover */ - info->aperture_base = rdev->ddev->mode_config.fb_base; - info->aperture_size = rdev->mc.real_vram_size; + info->apertures = alloc_apertures(1); + if (!info->apertures) { + ret = -ENOMEM; + goto out_unref; + } + info->apertures->ranges[0].base = rdev->ddev->mode_config.fb_base; + info->apertures->ranges[0].size = rdev->mc.real_vram_size; info->fix.mmio_start = 0; info->fix.mmio_len = 0; diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_fb.c b/drivers/gpu/drm/vmwgfx/vmwgfx_fb.c index 80125ffc4e28..7421aaad8d09 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_fb.c +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_fb.c @@ -559,8 +559,13 @@ int vmw_fb_init(struct vmw_private *vmw_priv) info->pixmap.scan_align = 1; #endif - info->aperture_base = vmw_priv->vram_start; - info->aperture_size = vmw_priv->vram_size; + info->apertures = alloc_apertures(1); + if (!info->apertures) { + ret = -ENOMEM; + goto err_aper; + } + info->apertures->ranges[0].base = vmw_priv->vram_start; + info->apertures->ranges[0].size = vmw_priv->vram_size; /* * Dirty & Deferred IO @@ -580,6 +585,7 @@ int vmw_fb_init(struct vmw_private *vmw_priv) err_defio: fb_deferred_io_cleanup(info); +err_aper: ttm_bo_kunmap(&par->map); err_unref: ttm_bo_unref((struct ttm_buffer_object **)&par->vmw_bo); diff --git a/drivers/video/efifb.c b/drivers/video/efifb.c index 581d2dbf675a..3b986567111a 100644 --- a/drivers/video/efifb.c +++ b/drivers/video/efifb.c @@ -165,7 +165,7 @@ static void efifb_destroy(struct fb_info *info) { if (info->screen_base) iounmap(info->screen_base); - release_mem_region(info->aperture_base, info->aperture_size); + release_mem_region(info->apertures->ranges[0].base, info->apertures->ranges[0].size); framebuffer_release(info); } @@ -289,8 +289,13 @@ static int __devinit efifb_probe(struct platform_device *dev) info->pseudo_palette = info->par; info->par = NULL; - info->aperture_base = efifb_fix.smem_start; - info->aperture_size = size_remap; + info->apertures = alloc_apertures(1); + if (!info->apertures) { + err = -ENOMEM; + goto err_release_fb; + } + info->apertures->ranges[0].base = efifb_fix.smem_start; + info->apertures->ranges[0].size = size_remap; info->screen_base = ioremap(efifb_fix.smem_start, efifb_fix.smem_len); if (!info->screen_base) { diff --git a/drivers/video/fbmem.c b/drivers/video/fbmem.c index a15b44e9c003..03f2dc2470b5 100644 --- a/drivers/video/fbmem.c +++ b/drivers/video/fbmem.c @@ -1468,16 +1468,39 @@ static int fb_check_foreignness(struct fb_info *fi) return 0; } -static bool fb_do_apertures_overlap(struct fb_info *gen, struct fb_info *hw) +static bool apertures_overlap(struct aperture *gen, struct aperture *hw) { /* is the generic aperture base the same as the HW one */ - if (gen->aperture_base == hw->aperture_base) + if (gen->base == hw->base) return true; /* is the generic aperture base inside the hw base->hw base+size */ - if (gen->aperture_base > hw->aperture_base && gen->aperture_base <= hw->aperture_base + hw->aperture_size) + if (gen->base > hw->base && gen->base <= hw->base + hw->size) return true; return false; } + +static bool fb_do_apertures_overlap(struct fb_info *gen, struct fb_info *hw) +{ + int i, j; + struct apertures_struct *hwa = hw->apertures; + struct apertures_struct *gena = gen->apertures; + if (!hwa || !gena) + return false; + + for (i = 0; i < hwa->count; ++i) { + struct aperture *h = &hwa->ranges[i]; + for (j = 0; j < gena->count; ++j) { + struct aperture *g = &gena->ranges[j]; + printk(KERN_DEBUG "checking generic (%llx %llx) vs hw (%llx %llx)\n", + g->base, g->size, h->base, h->size); + if (apertures_overlap(g, h)) + return true; + } + } + + return false; +} + /** * register_framebuffer - registers a frame buffer device * @fb_info: frame buffer info structure diff --git a/drivers/video/fbsysfs.c b/drivers/video/fbsysfs.c index 81aa3129c17d..0a08f1341227 100644 --- a/drivers/video/fbsysfs.c +++ b/drivers/video/fbsysfs.c @@ -80,6 +80,7 @@ EXPORT_SYMBOL(framebuffer_alloc); */ void framebuffer_release(struct fb_info *info) { + kfree(info->apertures); kfree(info); } EXPORT_SYMBOL(framebuffer_release); diff --git a/drivers/video/offb.c b/drivers/video/offb.c index 61f8b8f919b0..46dda7d8aaee 100644 --- a/drivers/video/offb.c +++ b/drivers/video/offb.c @@ -285,7 +285,7 @@ static void offb_destroy(struct fb_info *info) { if (info->screen_base) iounmap(info->screen_base); - release_mem_region(info->aperture_base, info->aperture_size); + release_mem_region(info->apertures->ranges[0].base, info->apertures->ranges[0].size); framebuffer_release(info); } @@ -491,8 +491,11 @@ static void __init offb_init_fb(const char *name, const char *full_name, var->vmode = FB_VMODE_NONINTERLACED; /* set offb aperture size for generic probing */ - info->aperture_base = address; - info->aperture_size = fix->smem_len; + info->apertures = alloc_apertures(1); + if (!info->apertures) + goto out_aper; + info->apertures->ranges[0].base = address; + info->apertures->ranges[0].size = fix->smem_len; info->fbops = &offb_ops; info->screen_base = ioremap(address, fix->smem_len); @@ -501,17 +504,20 @@ static void __init offb_init_fb(const char *name, const char *full_name, fb_alloc_cmap(&info->cmap, 256, 0); - if (register_framebuffer(info) < 0) { - iounmap(par->cmap_adr); - par->cmap_adr = NULL; - iounmap(info->screen_base); - framebuffer_release(info); - release_mem_region(res_start, res_size); - return; - } + if (register_framebuffer(info) < 0) + goto out_err; printk(KERN_INFO "fb%d: Open Firmware frame buffer device on %s\n", info->node, full_name); + return; + +out_err: + iounmap(info->screen_base); +out_aper: + iounmap(par->cmap_adr); + par->cmap_adr = NULL; + framebuffer_release(info); + release_mem_region(res_start, res_size); } diff --git a/drivers/video/vesafb.c b/drivers/video/vesafb.c index 0cadf7aee27e..090aa1a9be6e 100644 --- a/drivers/video/vesafb.c +++ b/drivers/video/vesafb.c @@ -177,7 +177,7 @@ static void vesafb_destroy(struct fb_info *info) { if (info->screen_base) iounmap(info->screen_base); - release_mem_region(info->aperture_base, info->aperture_size); + release_mem_region(info->apertures->ranges[0].base, info->apertures->ranges[0].size); framebuffer_release(info); } @@ -295,8 +295,13 @@ static int __init vesafb_probe(struct platform_device *dev) info->par = NULL; /* set vesafb aperture size for generic probing */ - info->aperture_base = screen_info.lfb_base; - info->aperture_size = size_total; + info->apertures = alloc_apertures(1); + if (!info->apertures) { + err = -ENOMEM; + goto err; + } + info->apertures->ranges[0].base = screen_info.lfb_base; + info->apertures->ranges[0].size = size_total; info->screen_base = ioremap(vesafb_fix.smem_start, vesafb_fix.smem_len); if (!info->screen_base) { diff --git a/include/linux/fb.h b/include/linux/fb.h index c10163b4c40e..de5ff5fa8380 100644 --- a/include/linux/fb.h +++ b/include/linux/fb.h @@ -403,6 +403,7 @@ struct fb_cursor { #include #include #include +#include #include struct vm_area_struct; @@ -862,10 +863,22 @@ struct fb_info { /* we need the PCI or similiar aperture base/size not smem_start/size as smem_start may just be an object allocated inside the aperture so may not actually overlap */ - resource_size_t aperture_base; - resource_size_t aperture_size; + struct apertures_struct { + unsigned int count; + struct aperture { + resource_size_t base; + resource_size_t size; + } ranges[0]; + } *apertures; }; +static inline struct apertures_struct *alloc_apertures(unsigned int max_num) { + struct apertures_struct *a = kzalloc(sizeof(struct apertures_struct) + + max_num * sizeof(struct aperture), GFP_KERNEL); + a->count = max_num; + return a; +} + #ifdef MODULE #define FBINFO_DEFAULT FBINFO_MODULE #else -- cgit v1.2.3 From eb1f8e4f3be898df808e2dfc131099f5831d491d Mon Sep 17 00:00:00 2001 From: Dave Airlie Date: Fri, 7 May 2010 06:42:51 +0000 Subject: drm/fbdev: rework output polling to be back in the core. (v4) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit After thinking it over a lot it made more sense for the core to deal with the output polling especially so it can notify X. v2: drop plans for fake connector - per Michel's comments - fix X patch sent to xorg-devel, add intel polled/hpd setting, add initial nouveau polled/hpd settings. v3: add config lock take inside polling, add intel/nouveau poll init/fini calls v4: config lock was a bit agressive, only needed around connector list reading. otherwise it could re-enter. glisse: discard drm_helper_hpd_irq_event v3: Reviewed-by: Michel Dänzer Signed-off-by: Dave Airlie --- drivers/gpu/drm/Kconfig | 2 +- drivers/gpu/drm/drm_crtc_helper.c | 95 +++++++++++++++++++++ drivers/gpu/drm/drm_fb_helper.c | 123 ++++------------------------ drivers/gpu/drm/i915/i915_dma.c | 2 +- drivers/gpu/drm/i915/i915_irq.c | 3 +- drivers/gpu/drm/i915/intel_crt.c | 5 ++ drivers/gpu/drm/i915/intel_display.c | 2 + drivers/gpu/drm/i915/intel_dp.c | 2 + drivers/gpu/drm/i915/intel_drv.h | 2 +- drivers/gpu/drm/i915/intel_fb.c | 14 ++-- drivers/gpu/drm/i915/intel_hdmi.c | 1 + drivers/gpu/drm/i915/intel_sdvo.c | 2 + drivers/gpu/drm/nouveau/nouveau_connector.c | 12 +++ drivers/gpu/drm/nouveau/nouveau_display.c | 1 + drivers/gpu/drm/nouveau/nouveau_fbcon.c | 14 +--- drivers/gpu/drm/nouveau/nouveau_fbcon.h | 2 +- drivers/gpu/drm/nouveau/nouveau_state.c | 5 +- drivers/gpu/drm/nouveau/nv50_display.c | 2 +- drivers/gpu/drm/radeon/radeon_connectors.c | 13 +++ drivers/gpu/drm/radeon/radeon_display.c | 10 +++ drivers/gpu/drm/radeon/radeon_fb.c | 15 +--- drivers/gpu/drm/radeon/radeon_irq_kms.c | 5 +- drivers/gpu/drm/radeon/radeon_mode.h | 3 +- include/drm/drm_crtc.h | 17 ++++ include/drm/drm_crtc_helper.h | 3 + include/drm/drm_fb_helper.h | 13 +-- 26 files changed, 211 insertions(+), 157 deletions(-) (limited to 'drivers/gpu/drm/radeon') diff --git a/drivers/gpu/drm/Kconfig b/drivers/gpu/drm/Kconfig index be5aa7d5206b..2583ddfcc33e 100644 --- a/drivers/gpu/drm/Kconfig +++ b/drivers/gpu/drm/Kconfig @@ -9,6 +9,7 @@ menuconfig DRM depends on (AGP || AGP=n) && PCI && !EMULATED_CMPXCHG && MMU select I2C select I2C_ALGOBIT + select SLOW_WORK help Kernel-level support for the Direct Rendering Infrastructure (DRI) introduced in XFree86 4.0. If you say Y here, you need to select @@ -23,7 +24,6 @@ config DRM_KMS_HELPER depends on DRM select FB select FRAMEBUFFER_CONSOLE if !EMBEDDED - select SLOW_WORK help FB and CRTC helpers for KMS drivers. diff --git a/drivers/gpu/drm/drm_crtc_helper.c b/drivers/gpu/drm/drm_crtc_helper.c index b142ac260d97..764401951041 100644 --- a/drivers/gpu/drm/drm_crtc_helper.c +++ b/drivers/gpu/drm/drm_crtc_helper.c @@ -807,3 +807,98 @@ int drm_helper_resume_force_mode(struct drm_device *dev) return 0; } EXPORT_SYMBOL(drm_helper_resume_force_mode); + +static struct slow_work_ops output_poll_ops; + +#define DRM_OUTPUT_POLL_PERIOD (10*HZ) +static void output_poll_execute(struct slow_work *work) +{ + struct delayed_slow_work *delayed_work = container_of(work, struct delayed_slow_work, work); + struct drm_device *dev = container_of(delayed_work, struct drm_device, mode_config.output_poll_slow_work); + struct drm_connector *connector; + enum drm_connector_status old_status, status; + bool repoll = false, changed = false; + int ret; + + mutex_lock(&dev->mode_config.mutex); + list_for_each_entry(connector, &dev->mode_config.connector_list, head) { + + /* if this is HPD or polled don't check it - + TV out for instance */ + if (!connector->polled) + continue; + + else if (connector->polled & (DRM_CONNECTOR_POLL_CONNECT | DRM_CONNECTOR_POLL_DISCONNECT)) + repoll = true; + + old_status = connector->status; + /* if we are connected and don't want to poll for disconnect + skip it */ + if (old_status == connector_status_connected && + !(connector->polled & DRM_CONNECTOR_POLL_DISCONNECT) && + !(connector->polled & DRM_CONNECTOR_POLL_HPD)) + continue; + + status = connector->funcs->detect(connector); + if (old_status != status) + changed = true; + } + + mutex_unlock(&dev->mode_config.mutex); + + if (changed) { + /* send a uevent + call fbdev */ + drm_sysfs_hotplug_event(dev); + if (dev->mode_config.funcs->output_poll_changed) + dev->mode_config.funcs->output_poll_changed(dev); + } + + if (repoll) { + ret = delayed_slow_work_enqueue(delayed_work, DRM_OUTPUT_POLL_PERIOD); + if (ret) + DRM_ERROR("delayed enqueue failed %d\n", ret); + } +} + +void drm_kms_helper_poll_init(struct drm_device *dev) +{ + struct drm_connector *connector; + bool poll = false; + int ret; + + list_for_each_entry(connector, &dev->mode_config.connector_list, head) { + if (connector->polled) + poll = true; + } + slow_work_register_user(THIS_MODULE); + delayed_slow_work_init(&dev->mode_config.output_poll_slow_work, + &output_poll_ops); + + if (poll) { + ret = delayed_slow_work_enqueue(&dev->mode_config.output_poll_slow_work, DRM_OUTPUT_POLL_PERIOD); + if (ret) + DRM_ERROR("delayed enqueue failed %d\n", ret); + } +} +EXPORT_SYMBOL(drm_kms_helper_poll_init); + +void drm_kms_helper_poll_fini(struct drm_device *dev) +{ + delayed_slow_work_cancel(&dev->mode_config.output_poll_slow_work); + slow_work_unregister_user(THIS_MODULE); +} +EXPORT_SYMBOL(drm_kms_helper_poll_fini); + +void drm_helper_hpd_irq_event(struct drm_device *dev) +{ + if (!dev->mode_config.poll_enabled) + return; + delayed_slow_work_cancel(&dev->mode_config.output_poll_slow_work); + /* schedule a slow work asap */ + delayed_slow_work_enqueue(&dev->mode_config.output_poll_slow_work, 0); +} +EXPORT_SYMBOL(drm_helper_hpd_irq_event); + +static struct slow_work_ops output_poll_ops = { + .execute = output_poll_execute, +}; diff --git a/drivers/gpu/drm/drm_fb_helper.c b/drivers/gpu/drm/drm_fb_helper.c index 5db4f47a0085..f7b8fca4bbbc 100644 --- a/drivers/gpu/drm/drm_fb_helper.c +++ b/drivers/gpu/drm/drm_fb_helper.c @@ -42,8 +42,6 @@ MODULE_LICENSE("GPL and additional rights"); static LIST_HEAD(kernel_fb_helper_list); -static struct slow_work_ops output_status_change_ops; - /* simple single crtc case helper function */ int drm_fb_helper_single_add_all_connectors(struct drm_fb_helper *fb_helper) { @@ -425,19 +423,13 @@ static void drm_fb_helper_crtc_free(struct drm_fb_helper *helper) int drm_fb_helper_init(struct drm_device *dev, struct drm_fb_helper *fb_helper, - int crtc_count, int max_conn_count, - bool polled) + int crtc_count, int max_conn_count) { struct drm_crtc *crtc; int ret = 0; int i; fb_helper->dev = dev; - fb_helper->poll_enabled = polled; - - slow_work_register_user(THIS_MODULE); - delayed_slow_work_init(&fb_helper->output_status_change_slow_work, - &output_status_change_ops); INIT_LIST_HEAD(&fb_helper->kernel_fb_list); @@ -494,8 +486,6 @@ void drm_fb_helper_fini(struct drm_fb_helper *fb_helper) drm_fb_helper_crtc_free(fb_helper); - delayed_slow_work_cancel(&fb_helper->output_status_change_slow_work); - slow_work_unregister_user(THIS_MODULE); } EXPORT_SYMBOL(drm_fb_helper_fini); @@ -713,7 +703,7 @@ int drm_fb_helper_set_par(struct fb_info *info) if (fb_helper->delayed_hotplug) { fb_helper->delayed_hotplug = false; - delayed_slow_work_enqueue(&fb_helper->output_status_change_slow_work, 0); + drm_fb_helper_hotplug_event(fb_helper); } return 0; } @@ -826,7 +816,7 @@ int drm_fb_helper_single_fb_probe(struct drm_fb_helper *fb_helper, if (crtc_count == 0 || sizes.fb_width == -1 || sizes.fb_height == -1) { /* hmm everyone went away - assume VGA cable just fell out and will come back later. */ - DRM_ERROR("Cannot find any crtc or sizes - going 1024x768\n"); + DRM_INFO("Cannot find any crtc or sizes - going 1024x768\n"); sizes.fb_width = sizes.surface_width = 1024; sizes.fb_height = sizes.surface_height = 768; } @@ -1292,12 +1282,7 @@ bool drm_fb_helper_initial_config(struct drm_fb_helper *fb_helper, int bpp_sel) * we shouldn't end up with no modes here. */ if (count == 0) { - if (fb_helper->poll_enabled) { - delayed_slow_work_enqueue(&fb_helper->output_status_change_slow_work, - 5*HZ); - printk(KERN_INFO "No connectors reported connected with modes - started polling\n"); - } else - printk(KERN_INFO "No connectors reported connected with modes\n"); + printk(KERN_INFO "No connectors reported connected with modes\n"); } drm_setup_crtcs(fb_helper); @@ -1305,71 +1290,16 @@ bool drm_fb_helper_initial_config(struct drm_fb_helper *fb_helper, int bpp_sel) } EXPORT_SYMBOL(drm_fb_helper_initial_config); -/* we got a hotplug irq - need to update fbcon */ -void drm_helper_fb_hpd_irq_event(struct drm_fb_helper *fb_helper) -{ - /* if we don't have the fbdev registered yet do nothing */ - if (!fb_helper->fbdev) - return; - - /* schedule a slow work asap */ - delayed_slow_work_enqueue(&fb_helper->output_status_change_slow_work, 0); -} -EXPORT_SYMBOL(drm_helper_fb_hpd_irq_event); - -bool drm_helper_fb_hotplug_event(struct drm_fb_helper *fb_helper, bool polled) +bool drm_fb_helper_hotplug_event(struct drm_fb_helper *fb_helper) { int count = 0; - int ret; u32 max_width, max_height, bpp_sel; - - if (!fb_helper->fb) - return false; - DRM_DEBUG_KMS("\n"); - - max_width = fb_helper->fb->width; - max_height = fb_helper->fb->height; - bpp_sel = fb_helper->fb->bits_per_pixel; - - count = drm_fb_helper_probe_connector_modes(fb_helper, max_width, - max_height); - if (fb_helper->poll_enabled && !polled) { - if (count) { - delayed_slow_work_cancel(&fb_helper->output_status_change_slow_work); - } else { - ret = delayed_slow_work_enqueue(&fb_helper->output_status_change_slow_work, 5*HZ); - } - } - drm_setup_crtcs(fb_helper); - - return drm_fb_helper_single_fb_probe(fb_helper, bpp_sel); -} -EXPORT_SYMBOL(drm_helper_fb_hotplug_event); - -/* - * delayed work queue execution function - * - check if fbdev is actually in use on the gpu - * - if not set delayed flag and repoll if necessary - * - check for connector status change - * - repoll if 0 modes found - *- call driver output status changed notifier - */ -static void output_status_change_execute(struct slow_work *work) -{ - struct delayed_slow_work *delayed_work = container_of(work, struct delayed_slow_work, work); - struct drm_fb_helper *fb_helper = container_of(delayed_work, struct drm_fb_helper, output_status_change_slow_work); - struct drm_connector *connector; - enum drm_connector_status old_status, status; - bool repoll, changed = false; - int ret; - int i; bool bound = false, crtcs_bound = false; struct drm_crtc *crtc; - repoll = fb_helper->poll_enabled; + if (!fb_helper->fb) + return false; - /* first of all check the fbcon framebuffer is actually bound to any crtc */ - /* take into account that no crtc at all maybe bound */ list_for_each_entry(crtc, &fb_helper->dev->mode_config.crtc_list, head) { if (crtc->fb) crtcs_bound = true; @@ -1377,38 +1307,21 @@ static void output_status_change_execute(struct slow_work *work) bound = true; } - if (bound == false && crtcs_bound) { + if (!bound && crtcs_bound) { fb_helper->delayed_hotplug = true; - goto requeue; + return false; } + DRM_DEBUG_KMS("\n"); - for (i = 0; i < fb_helper->connector_count; i++) { - connector = fb_helper->connector_info[i]->connector; - old_status = connector->status; - status = connector->funcs->detect(connector); - if (old_status != status) { - changed = true; - } - if (status == connector_status_connected && repoll) { - DRM_DEBUG("%s is connected - stop polling\n", drm_get_connector_name(connector)); - repoll = false; - } - } + max_width = fb_helper->fb->width; + max_height = fb_helper->fb->height; + bpp_sel = fb_helper->fb->bits_per_pixel; - if (changed) { - if (fb_helper->funcs->fb_output_status_changed) - fb_helper->funcs->fb_output_status_changed(fb_helper); - } + count = drm_fb_helper_probe_connector_modes(fb_helper, max_width, + max_height); + drm_setup_crtcs(fb_helper); -requeue: - if (repoll) { - ret = delayed_slow_work_enqueue(delayed_work, 5*HZ); - if (ret) - DRM_ERROR("delayed enqueue failed %d\n", ret); - } + return drm_fb_helper_single_fb_probe(fb_helper, bpp_sel); } - -static struct slow_work_ops output_status_change_ops = { - .execute = output_status_change_execute, -}; +EXPORT_SYMBOL(drm_fb_helper_hotplug_event); diff --git a/drivers/gpu/drm/i915/i915_dma.c b/drivers/gpu/drm/i915/i915_dma.c index 52e468bbd5e4..8fe66ac4e1a5 100644 --- a/drivers/gpu/drm/i915/i915_dma.c +++ b/drivers/gpu/drm/i915/i915_dma.c @@ -1493,7 +1493,7 @@ static int i915_load_modeset_init(struct drm_device *dev, I915_WRITE(INSTPM, (1 << 5) | (1 << 21)); intel_fbdev_init(dev); - + drm_kms_helper_poll_init(dev); return 0; destroy_ringbuffer: diff --git a/drivers/gpu/drm/i915/i915_irq.c b/drivers/gpu/drm/i915/i915_irq.c index ed26b7b7376a..b034ea36731c 100644 --- a/drivers/gpu/drm/i915/i915_irq.c +++ b/drivers/gpu/drm/i915/i915_irq.c @@ -271,8 +271,7 @@ static void i915_hotplug_work_func(struct work_struct *work) } } /* Just fire off a uevent and let userspace tell us what to do */ - intelfb_hotplug(dev, false); - drm_sysfs_hotplug_event(dev); + drm_helper_hpd_irq_event(dev); } static void i915_handle_rps_change(struct drm_device *dev) diff --git a/drivers/gpu/drm/i915/intel_crt.c b/drivers/gpu/drm/i915/intel_crt.c index 26756cd34e3c..e16ac5a28c3c 100644 --- a/drivers/gpu/drm/i915/intel_crt.c +++ b/drivers/gpu/drm/i915/intel_crt.c @@ -577,5 +577,10 @@ void intel_crt_init(struct drm_device *dev) drm_sysfs_connector_add(connector); + if (I915_HAS_HOTPLUG(dev)) + connector->polled = DRM_CONNECTOR_POLL_HPD; + else + connector->polled = DRM_CONNECTOR_POLL_CONNECT; + dev_priv->hotplug_supported_mask |= CRT_HOTPLUG_INT_STATUS; } diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index 3836f56e842c..4d739a1b13ca 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -4959,6 +4959,7 @@ intel_user_framebuffer_create(struct drm_device *dev, static const struct drm_mode_config_funcs intel_mode_funcs = { .fb_create = intel_user_framebuffer_create, + .output_poll_changed = intel_fb_output_poll_changed, }; static struct drm_gem_object * @@ -5346,6 +5347,7 @@ void intel_modeset_cleanup(struct drm_device *dev) mutex_lock(&dev->struct_mutex); + drm_kms_helper_poll_fini(dev); intel_fbdev_fini(dev); list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) { diff --git a/drivers/gpu/drm/i915/intel_dp.c b/drivers/gpu/drm/i915/intel_dp.c index f6299bb788e5..6b1c9a27c27a 100644 --- a/drivers/gpu/drm/i915/intel_dp.c +++ b/drivers/gpu/drm/i915/intel_dp.c @@ -1392,6 +1392,8 @@ intel_dp_init(struct drm_device *dev, int output_reg) DRM_MODE_CONNECTOR_DisplayPort); drm_connector_helper_add(connector, &intel_dp_connector_helper_funcs); + connector->polled = DRM_CONNECTOR_POLL_HPD; + if (output_reg == DP_A) intel_encoder->type = INTEL_OUTPUT_EDP; else diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h index 3230e8d2ea43..df931f787665 100644 --- a/drivers/gpu/drm/i915/intel_drv.h +++ b/drivers/gpu/drm/i915/intel_drv.h @@ -235,5 +235,5 @@ extern int intel_overlay_put_image(struct drm_device *dev, void *data, extern int intel_overlay_attrs(struct drm_device *dev, void *data, struct drm_file *file_priv); -void intelfb_hotplug(struct drm_device *dev, bool polled); +extern void intel_fb_output_poll_changed(struct drm_device *dev); #endif /* __INTEL_DRV_H__ */ diff --git a/drivers/gpu/drm/i915/intel_fb.c b/drivers/gpu/drm/i915/intel_fb.c index 7f1eabbaa2bb..6f53cf7fbc50 100644 --- a/drivers/gpu/drm/i915/intel_fb.c +++ b/drivers/gpu/drm/i915/intel_fb.c @@ -207,12 +207,6 @@ static int intel_fb_find_or_create_single(struct drm_fb_helper *helper, return new_fb; } -void intelfb_hotplug(struct drm_device *dev, bool polled) -{ - drm_i915_private_t *dev_priv = dev->dev_private; - drm_helper_fb_hpd_irq_event(&dev_priv->fbdev->helper); -} - static struct drm_fb_helper_funcs intel_fb_helper_funcs = { .gamma_set = intel_crtc_fb_gamma_set, .gamma_get = intel_crtc_fb_gamma_get, @@ -256,7 +250,7 @@ int intel_fbdev_init(struct drm_device *dev) ifbdev->helper.funcs = &intel_fb_helper_funcs; drm_fb_helper_init(dev, &ifbdev->helper, 2, - INTELFB_CONN_LIMIT, false); + INTELFB_CONN_LIMIT); drm_fb_helper_single_add_all_connectors(&ifbdev->helper); drm_fb_helper_initial_config(&ifbdev->helper, 32); @@ -274,3 +268,9 @@ void intel_fbdev_fini(struct drm_device *dev) dev_priv->fbdev = NULL; } MODULE_LICENSE("GPL and additional rights"); + +void intel_fb_output_poll_changed(struct drm_device *dev) +{ + drm_i915_private_t *dev_priv = dev->dev_private; + drm_fb_helper_hotplug_event(&dev_priv->fbdev->helper); +} diff --git a/drivers/gpu/drm/i915/intel_hdmi.c b/drivers/gpu/drm/i915/intel_hdmi.c index 8a1c4eddc030..65727f0a79a3 100644 --- a/drivers/gpu/drm/i915/intel_hdmi.c +++ b/drivers/gpu/drm/i915/intel_hdmi.c @@ -237,6 +237,7 @@ void intel_hdmi_init(struct drm_device *dev, int sdvox_reg) intel_encoder->type = INTEL_OUTPUT_HDMI; + connector->polled = DRM_CONNECTOR_POLL_HPD; connector->interlace_allowed = 0; connector->doublescan_allowed = 0; intel_encoder->crtc_mask = (1 << 0) | (1 << 1); diff --git a/drivers/gpu/drm/i915/intel_sdvo.c b/drivers/gpu/drm/i915/intel_sdvo.c index 42ceb15da689..ca372abc36cd 100644 --- a/drivers/gpu/drm/i915/intel_sdvo.c +++ b/drivers/gpu/drm/i915/intel_sdvo.c @@ -2244,6 +2244,7 @@ intel_sdvo_dvi_init(struct intel_encoder *intel_encoder, int device) } connector = &intel_connector->base; + connector->polled = DRM_CONNECTOR_POLL_CONNECT | DRM_CONNECTOR_POLL_DISCONNECT; encoder->encoder_type = DRM_MODE_ENCODER_TMDS; connector->connector_type = DRM_MODE_CONNECTOR_DVID; @@ -2310,6 +2311,7 @@ intel_sdvo_analog_init(struct intel_encoder *intel_encoder, int device) return false; connector = &intel_connector->base; + connector->polled = DRM_CONNECTOR_POLL_CONNECT; encoder->encoder_type = DRM_MODE_ENCODER_DAC; connector->connector_type = DRM_MODE_CONNECTOR_VGA; sdvo_connector = intel_connector->dev_priv; diff --git a/drivers/gpu/drm/nouveau/nouveau_connector.c b/drivers/gpu/drm/nouveau/nouveau_connector.c index 14afe1e47e57..7e663a79829f 100644 --- a/drivers/gpu/drm/nouveau/nouveau_connector.c +++ b/drivers/gpu/drm/nouveau/nouveau_connector.c @@ -843,6 +843,7 @@ nouveau_connector_create(struct drm_device *dev, switch (dcb->type) { case DCB_CONNECTOR_VGA: + connector->polled = DRM_CONNECTOR_POLL_CONNECT; if (dev_priv->card_type >= NV_50) { drm_connector_attach_property(connector, dev->mode_config.scaling_mode_property, @@ -854,6 +855,17 @@ nouveau_connector_create(struct drm_device *dev, case DCB_CONNECTOR_TV_3: nv_connector->scaling_mode = DRM_MODE_SCALE_NONE; break; + case DCB_CONNECTOR_DP: + case DCB_CONNECTOR_eDP: + case DCB_CONNECTOR_HDMI_0: + case DCB_CONNECTOR_HDMI_1: + case DCB_CONNECTOR_DVI_I: + case DCB_CONNECTOR_DVI_D: + if (dev_priv->card_type >= NV_50) + connector->polled = DRM_CONNECTOR_POLL_HPD; + else + connector->polled = DRM_CONNECTOR_POLL_CONNECT; + /* fall-through */ default: nv_connector->scaling_mode = DRM_MODE_SCALE_FULLSCREEN; diff --git a/drivers/gpu/drm/nouveau/nouveau_display.c b/drivers/gpu/drm/nouveau/nouveau_display.c index 9d7928f40fdf..74e6b4ed12c0 100644 --- a/drivers/gpu/drm/nouveau/nouveau_display.c +++ b/drivers/gpu/drm/nouveau/nouveau_display.c @@ -101,5 +101,6 @@ nouveau_user_framebuffer_create(struct drm_device *dev, const struct drm_mode_config_funcs nouveau_mode_config_funcs = { .fb_create = nouveau_user_framebuffer_create, + .output_poll_changed = nouveau_fbcon_output_poll_changed, }; diff --git a/drivers/gpu/drm/nouveau/nouveau_fbcon.c b/drivers/gpu/drm/nouveau/nouveau_fbcon.c index 2c2199329cc1..fd4a2df715e9 100644 --- a/drivers/gpu/drm/nouveau/nouveau_fbcon.c +++ b/drivers/gpu/drm/nouveau/nouveau_fbcon.c @@ -326,15 +326,11 @@ nouveau_fbcon_find_or_create_single(struct drm_fb_helper *helper, return new_fb; } -void nouveau_fbcon_hotplug(struct drm_device *dev) +void +nouveau_fbcon_output_poll_changed(struct drm_device *dev) { struct drm_nouveau_private *dev_priv = dev->dev_private; - drm_helper_fb_hpd_irq_event(&dev_priv->nfbdev->helper); -} - -static void nouveau_fbcon_output_status_changed(struct drm_fb_helper *fb_helper) -{ - drm_helper_fb_hotplug_event(fb_helper, true); + drm_fb_helper_hotplug_event(&dev_priv->nfbdev->helper); } int @@ -374,7 +370,6 @@ static struct drm_fb_helper_funcs nouveau_fbcon_helper_funcs = { .gamma_set = nouveau_fbcon_gamma_set, .gamma_get = nouveau_fbcon_gamma_get, .fb_probe = nouveau_fbcon_find_or_create_single, - .fb_output_status_changed = nouveau_fbcon_output_status_changed, }; @@ -391,8 +386,7 @@ int nouveau_fbcon_init(struct drm_device *dev) dev_priv->nfbdev = nfbdev; nfbdev->helper.funcs = &nouveau_fbcon_helper_funcs; - drm_fb_helper_init(dev, &nfbdev->helper, - 2, 4, true); + drm_fb_helper_init(dev, &nfbdev->helper, 2, 4); drm_fb_helper_single_add_all_connectors(&nfbdev->helper); drm_fb_helper_initial_config(&nfbdev->helper, 32); return 0; diff --git a/drivers/gpu/drm/nouveau/nouveau_fbcon.h b/drivers/gpu/drm/nouveau/nouveau_fbcon.h index bf8e00d4de65..e7e12684c37e 100644 --- a/drivers/gpu/drm/nouveau/nouveau_fbcon.h +++ b/drivers/gpu/drm/nouveau/nouveau_fbcon.h @@ -58,6 +58,6 @@ void nouveau_fbcon_zfill_all(struct drm_device *dev); void nouveau_fbcon_save_disable_accel(struct drm_device *dev); void nouveau_fbcon_restore_accel(struct drm_device *dev); -void nouveau_fbcon_hotplug(struct drm_device *dev); +void nouveau_fbcon_output_poll_changed(struct drm_device *dev); #endif /* __NV50_FBCON_H__ */ diff --git a/drivers/gpu/drm/nouveau/nouveau_state.c b/drivers/gpu/drm/nouveau/nouveau_state.c index c667a1138c33..e632339c323e 100644 --- a/drivers/gpu/drm/nouveau/nouveau_state.c +++ b/drivers/gpu/drm/nouveau/nouveau_state.c @@ -516,8 +516,10 @@ nouveau_card_init(struct drm_device *dev) dev_priv->init_state = NOUVEAU_CARD_INIT_DONE; - if (drm_core_check_feature(dev, DRIVER_MODESET)) + if (drm_core_check_feature(dev, DRIVER_MODESET)) { nouveau_fbcon_init(dev); + drm_kms_helper_poll_init(dev); + } return 0; @@ -844,6 +846,7 @@ int nouveau_unload(struct drm_device *dev) struct drm_nouveau_private *dev_priv = dev->dev_private; if (drm_core_check_feature(dev, DRIVER_MODESET)) { + drm_kms_helper_poll_fini(dev); nouveau_fbcon_fini(dev); if (dev_priv->card_type >= NV_50) nv50_display_destroy(dev); diff --git a/drivers/gpu/drm/nouveau/nv50_display.c b/drivers/gpu/drm/nouveau/nv50_display.c index f9b304866e66..34156b69594f 100644 --- a/drivers/gpu/drm/nouveau/nv50_display.c +++ b/drivers/gpu/drm/nouveau/nv50_display.c @@ -947,7 +947,7 @@ nv50_display_irq_hotplug_bh(struct work_struct *work) if (dev_priv->chipset >= 0x90) nv_wr32(dev, 0xe074, nv_rd32(dev, 0xe074)); - nouveau_fbcon_hotplug(dev); + drm_helper_hpd_irq_event(dev); } void diff --git a/drivers/gpu/drm/radeon/radeon_connectors.c b/drivers/gpu/drm/radeon/radeon_connectors.c index c48934677adf..765854ed33c2 100644 --- a/drivers/gpu/drm/radeon/radeon_connectors.c +++ b/drivers/gpu/drm/radeon/radeon_connectors.c @@ -1085,6 +1085,7 @@ radeon_add_atom_connector(struct drm_device *dev, drm_connector_attach_property(&radeon_connector->base, rdev->mode_info.load_detect_property, 1); + connector->polled = DRM_CONNECTOR_POLL_CONNECT; break; case DRM_MODE_CONNECTOR_DVIA: drm_connector_init(dev, &radeon_connector->base, &radeon_vga_connector_funcs, connector_type); @@ -1211,6 +1212,12 @@ radeon_add_atom_connector(struct drm_device *dev, break; } + if (hpd->hpd == RADEON_HPD_NONE) { + if (i2c_bus->valid) + connector->polled = DRM_CONNECTOR_POLL_CONNECT; + } else + connector->polled = DRM_CONNECTOR_POLL_HPD; + connector->display_info.subpixel_order = subpixel_order; drm_sysfs_connector_add(connector); return; @@ -1272,6 +1279,7 @@ radeon_add_legacy_connector(struct drm_device *dev, drm_connector_attach_property(&radeon_connector->base, rdev->mode_info.load_detect_property, 1); + connector->polled = DRM_CONNECTOR_POLL_CONNECT; break; case DRM_MODE_CONNECTOR_DVIA: drm_connector_init(dev, &radeon_connector->base, &radeon_vga_connector_funcs, connector_type); @@ -1338,6 +1346,11 @@ radeon_add_legacy_connector(struct drm_device *dev, break; } + if (hpd->hpd == RADEON_HPD_NONE) { + if (i2c_bus->valid) + connector->polled = DRM_CONNECTOR_POLL_CONNECT; + } else + connector->polled = DRM_CONNECTOR_POLL_HPD; connector->display_info.subpixel_order = subpixel_order; drm_sysfs_connector_add(connector); return; diff --git a/drivers/gpu/drm/radeon/radeon_display.c b/drivers/gpu/drm/radeon/radeon_display.c index 243c1c4bc836..bc9cc9211e67 100644 --- a/drivers/gpu/drm/radeon/radeon_display.c +++ b/drivers/gpu/drm/radeon/radeon_display.c @@ -888,8 +888,15 @@ radeon_user_framebuffer_create(struct drm_device *dev, return &radeon_fb->base; } +static void radeon_output_poll_changed(struct drm_device *dev) +{ + struct radeon_device *rdev = dev->dev_private; + radeon_fb_output_poll_changed(rdev); +} + static const struct drm_mode_config_funcs radeon_mode_funcs = { .fb_create = radeon_user_framebuffer_create, + .output_poll_changed = radeon_output_poll_changed }; struct drm_prop_enum_list { @@ -1031,6 +1038,8 @@ int radeon_modeset_init(struct radeon_device *rdev) radeon_hpd_init(rdev); radeon_fbdev_init(rdev); + drm_kms_helper_poll_init(rdev->ddev); + return 0; } @@ -1040,6 +1049,7 @@ void radeon_modeset_fini(struct radeon_device *rdev) kfree(rdev->mode_info.bios_hardcoded_edid); if (rdev->mode_info.mode_config_initialized) { + drm_kms_helper_poll_fini(rdev->ddev); radeon_hpd_fini(rdev); drm_mode_config_cleanup(rdev->ddev); rdev->mode_info.mode_config_initialized = false; diff --git a/drivers/gpu/drm/radeon/radeon_fb.c b/drivers/gpu/drm/radeon/radeon_fb.c index b4948021e345..e192acfbf0cd 100644 --- a/drivers/gpu/drm/radeon/radeon_fb.c +++ b/drivers/gpu/drm/radeon/radeon_fb.c @@ -316,16 +316,9 @@ int radeon_parse_options(char *options) return 0; } -void radeonfb_hotplug(struct drm_device *dev, bool polled) +void radeon_fb_output_poll_changed(struct radeon_device *rdev) { - struct radeon_device *rdev = dev->dev_private; - - drm_helper_fb_hpd_irq_event(&rdev->mode_info.rfbdev->helper); -} - -static void radeon_fb_output_status_changed(struct drm_fb_helper *fb_helper) -{ - drm_helper_fb_hotplug_event(fb_helper, true); + drm_fb_helper_hotplug_event(&rdev->mode_info.rfbdev->helper); } static int radeon_fbdev_destroy(struct drm_device *dev, struct radeon_fbdev *rfbdev) @@ -364,7 +357,6 @@ static struct drm_fb_helper_funcs radeon_fb_helper_funcs = { .gamma_set = radeon_crtc_fb_gamma_set, .gamma_get = radeon_crtc_fb_gamma_get, .fb_probe = radeon_fb_find_or_create_single, - .fb_output_status_changed = radeon_fb_output_status_changed, }; int radeon_fbdev_init(struct radeon_device *rdev) @@ -386,11 +378,10 @@ int radeon_fbdev_init(struct radeon_device *rdev) drm_fb_helper_init(rdev->ddev, &rfbdev->helper, rdev->num_crtc, - RADEONFB_CONN_LIMIT, true); + RADEONFB_CONN_LIMIT); drm_fb_helper_single_add_all_connectors(&rfbdev->helper); drm_fb_helper_initial_config(&rfbdev->helper, bpp_sel); return 0; - } void radeon_fbdev_fini(struct radeon_device *rdev) diff --git a/drivers/gpu/drm/radeon/radeon_irq_kms.c b/drivers/gpu/drm/radeon/radeon_irq_kms.c index a95907aa7eae..8fa40ed397ec 100644 --- a/drivers/gpu/drm/radeon/radeon_irq_kms.c +++ b/drivers/gpu/drm/radeon/radeon_irq_kms.c @@ -26,6 +26,7 @@ * Jerome Glisse */ #include "drmP.h" +#include "drm_crtc_helper.h" #include "radeon_drm.h" #include "radeon_reg.h" #include "radeon.h" @@ -55,9 +56,7 @@ static void radeon_hotplug_work_func(struct work_struct *work) radeon_connector_hotplug(connector); } /* Just fire off a uevent and let userspace tell us what to do */ - radeonfb_hotplug(dev, false); - - drm_sysfs_hotplug_event(dev); + drm_helper_hpd_irq_event(dev); } void radeon_driver_irq_preinstall_kms(struct drm_device *dev) diff --git a/drivers/gpu/drm/radeon/radeon_mode.h b/drivers/gpu/drm/radeon/radeon_mode.h index dd451c55c533..061a2a6801cc 100644 --- a/drivers/gpu/drm/radeon/radeon_mode.h +++ b/drivers/gpu/drm/radeon/radeon_mode.h @@ -586,5 +586,6 @@ void radeon_fbdev_fini(struct radeon_device *rdev); void radeon_fbdev_set_suspend(struct radeon_device *rdev, int state); int radeon_fbdev_total_size(struct radeon_device *rdev); bool radeon_fbdev_robj_is_fb(struct radeon_device *rdev, struct radeon_bo *robj); -void radeonfb_hotplug(struct drm_device *dev, bool polled); + +void radeon_fb_output_poll_changed(struct radeon_device *rdev); #endif diff --git a/include/drm/drm_crtc.h b/include/drm/drm_crtc.h index c560364663a5..2e4bf92faa85 100644 --- a/include/drm/drm_crtc.h +++ b/include/drm/drm_crtc.h @@ -31,6 +31,7 @@ #include #include +#include struct drm_device; struct drm_mode_set; @@ -460,6 +461,15 @@ enum drm_connector_force { DRM_FORCE_ON_DIGITAL, /* for DVI-I use digital connector */ }; +/* should we poll this connector for connects and disconnects */ +/* hot plug detectable */ +#define DRM_CONNECTOR_POLL_HPD (1 << 0) +/* poll for connections */ +#define DRM_CONNECTOR_POLL_CONNECT (1 << 1) +/* can cleanly poll for disconnections without flickering the screen */ +/* DACs should rarely do this without a lot of testing */ +#define DRM_CONNECTOR_POLL_DISCONNECT (1 << 2) + /** * drm_connector - central DRM connector control structure * @crtc: CRTC this connector is currently connected to, NULL if none @@ -504,6 +514,8 @@ struct drm_connector { u32 property_ids[DRM_CONNECTOR_MAX_PROPERTY]; uint64_t property_values[DRM_CONNECTOR_MAX_PROPERTY]; + uint8_t polled; /* DRM_CONNECTOR_POLL_* */ + /* requested DPMS state */ int dpms; @@ -543,6 +555,7 @@ struct drm_mode_set { */ struct drm_mode_config_funcs { struct drm_framebuffer *(*fb_create)(struct drm_device *dev, struct drm_file *file_priv, struct drm_mode_fb_cmd *mode_cmd); + void (*output_poll_changed)(struct drm_device *dev); }; struct drm_mode_group { @@ -580,6 +593,10 @@ struct drm_mode_config { struct drm_mode_config_funcs *funcs; resource_size_t fb_base; + /* output poll support */ + bool poll_enabled; + struct delayed_slow_work output_poll_slow_work; + /* pointers to standard properties */ struct list_head property_blob_list; struct drm_property *edid_property; diff --git a/include/drm/drm_crtc_helper.h b/include/drm/drm_crtc_helper.h index b1fa0f8cfa60..dc5873c21e45 100644 --- a/include/drm/drm_crtc_helper.h +++ b/include/drm/drm_crtc_helper.h @@ -127,4 +127,7 @@ static inline void drm_connector_helper_add(struct drm_connector *connector, } extern int drm_helper_resume_force_mode(struct drm_device *dev); +extern void drm_kms_helper_poll_init(struct drm_device *dev); +extern void drm_kms_helper_poll_fini(struct drm_device *dev); +extern void drm_helper_hpd_irq_event(struct drm_device *dev); #endif diff --git a/include/drm/drm_fb_helper.h b/include/drm/drm_fb_helper.h index 9b55a94feada..f0a6afc47e76 100644 --- a/include/drm/drm_fb_helper.h +++ b/include/drm/drm_fb_helper.h @@ -30,8 +30,6 @@ #ifndef DRM_FB_HELPER_H #define DRM_FB_HELPER_H -#include - struct drm_fb_helper; struct drm_fb_helper_crtc { @@ -71,9 +69,6 @@ struct drm_fb_helper_funcs { int (*fb_probe)(struct drm_fb_helper *helper, struct drm_fb_helper_surface_size *sizes); - - void (*fb_output_status_changed)(struct drm_fb_helper *helper); - }; struct drm_fb_helper_connector { @@ -95,8 +90,6 @@ struct drm_fb_helper { u32 pseudo_palette[17]; struct list_head kernel_fb_list; - struct delayed_slow_work output_status_change_slow_work; - bool poll_enabled; /* we got a hotplug but fbdev wasn't running the console delay until next set_par */ bool delayed_hotplug; @@ -107,7 +100,7 @@ int drm_fb_helper_single_fb_probe(struct drm_fb_helper *helper, int drm_fb_helper_init(struct drm_device *dev, struct drm_fb_helper *helper, int crtc_count, - int max_conn, bool polled); + int max_conn); void drm_fb_helper_fini(struct drm_fb_helper *helper); int drm_fb_helper_blank(int blank, struct fb_info *info); int drm_fb_helper_pan_display(struct fb_var_screeninfo *var, @@ -130,10 +123,8 @@ void drm_fb_helper_fill_fix(struct fb_info *info, uint32_t pitch, int drm_fb_helper_setcmap(struct fb_cmap *cmap, struct fb_info *info); -bool drm_helper_fb_hotplug_event(struct drm_fb_helper *fb_helper, - bool polled); +bool drm_fb_helper_hotplug_event(struct drm_fb_helper *fb_helper); bool drm_fb_helper_initial_config(struct drm_fb_helper *fb_helper, int bpp_sel); int drm_fb_helper_single_add_all_connectors(struct drm_fb_helper *fb_helper); -void drm_helper_fb_hpd_irq_event(struct drm_fb_helper *fb_helper); #endif -- cgit v1.2.3 From def9ba9cf6a8266ee1ffd72556db002c3a2663db Mon Sep 17 00:00:00 2001 From: Alex Deucher Date: Thu, 22 Apr 2010 12:39:58 -0400 Subject: drm/radeon/kms: add gui_idle callback Check to see if the GUI engine and related blocks (2D, 3D, CP, etc) are idle or not. There are a number of cases when we need to know if the drawing engine is busy. Signed-off-by: Alex Deucher Signed-off-by: Dave Airlie --- drivers/gpu/drm/radeon/r100.c | 8 ++++++++ drivers/gpu/drm/radeon/r600.c | 8 ++++++++ drivers/gpu/drm/radeon/radeon.h | 2 ++ drivers/gpu/drm/radeon/radeon_asic.c | 14 ++++++++++++++ drivers/gpu/drm/radeon/radeon_asic.h | 2 ++ 5 files changed, 34 insertions(+) (limited to 'drivers/gpu/drm/radeon') diff --git a/drivers/gpu/drm/radeon/r100.c b/drivers/gpu/drm/radeon/r100.c index 9bdccb964999..e62116e222a0 100644 --- a/drivers/gpu/drm/radeon/r100.c +++ b/drivers/gpu/drm/radeon/r100.c @@ -67,6 +67,14 @@ MODULE_FIRMWARE(FIRMWARE_R520); * r100,rv100,rs100,rv200,rs200,r200,rv250,rs300,rv280 */ +bool r100_gui_idle(struct radeon_device *rdev) +{ + if (RREG32(RADEON_RBBM_STATUS) & RADEON_RBBM_ACTIVE) + return false; + else + return true; +} + /* hpd for digital panel detect/disconnect */ bool r100_hpd_sense(struct radeon_device *rdev, enum radeon_hpd_id hpd) { diff --git a/drivers/gpu/drm/radeon/r600.c b/drivers/gpu/drm/radeon/r600.c index 2ec423c3f3f8..1c85dcb168a1 100644 --- a/drivers/gpu/drm/radeon/r600.c +++ b/drivers/gpu/drm/radeon/r600.c @@ -92,6 +92,14 @@ void r600_gpu_init(struct radeon_device *rdev); void r600_fini(struct radeon_device *rdev); void r600_irq_disable(struct radeon_device *rdev); +bool r600_gui_idle(struct radeon_device *rdev) +{ + if (RREG32(GRBM_STATUS) & GUI_ACTIVE) + return false; + else + return true; +} + /* hpd for digital panel detect/disconnect */ bool r600_hpd_sense(struct radeon_device *rdev, enum radeon_hpd_id hpd) { diff --git a/drivers/gpu/drm/radeon/radeon.h b/drivers/gpu/drm/radeon/radeon.h index ab29d972a167..bb4a2a66f070 100644 --- a/drivers/gpu/drm/radeon/radeon.h +++ b/drivers/gpu/drm/radeon/radeon.h @@ -803,6 +803,7 @@ struct radeon_asic { * through ring. */ void (*ioctl_wait_idle)(struct radeon_device *rdev, struct radeon_bo *bo); + bool (*gui_idle)(struct radeon_device *rdev); }; /* @@ -1209,6 +1210,7 @@ static inline void radeon_ring_write(struct radeon_device *rdev, uint32_t v) #define radeon_hpd_fini(rdev) (rdev)->asic->hpd_fini((rdev)) #define radeon_hpd_sense(rdev, hpd) (rdev)->asic->hpd_sense((rdev), (hpd)) #define radeon_hpd_set_polarity(rdev, hpd) (rdev)->asic->hpd_set_polarity((rdev), (hpd)) +#define radeon_gui_idle(rdev) (rdev)->asic->gui_idle((rdev)) /* Common functions */ /* AGP */ diff --git a/drivers/gpu/drm/radeon/radeon_asic.c b/drivers/gpu/drm/radeon/radeon_asic.c index f835333c1b69..42708462fd4b 100644 --- a/drivers/gpu/drm/radeon/radeon_asic.c +++ b/drivers/gpu/drm/radeon/radeon_asic.c @@ -165,6 +165,7 @@ static struct radeon_asic r100_asic = { .hpd_sense = &r100_hpd_sense, .hpd_set_polarity = &r100_hpd_set_polarity, .ioctl_wait_idle = NULL, + .gui_idle = &r100_gui_idle, }; static struct radeon_asic r200_asic = { @@ -203,6 +204,7 @@ static struct radeon_asic r200_asic = { .hpd_sense = &r100_hpd_sense, .hpd_set_polarity = &r100_hpd_set_polarity, .ioctl_wait_idle = NULL, + .gui_idle = &r100_gui_idle, }; static struct radeon_asic r300_asic = { @@ -242,6 +244,7 @@ static struct radeon_asic r300_asic = { .hpd_sense = &r100_hpd_sense, .hpd_set_polarity = &r100_hpd_set_polarity, .ioctl_wait_idle = NULL, + .gui_idle = &r100_gui_idle, }; static struct radeon_asic r300_asic_pcie = { @@ -280,6 +283,7 @@ static struct radeon_asic r300_asic_pcie = { .hpd_sense = &r100_hpd_sense, .hpd_set_polarity = &r100_hpd_set_polarity, .ioctl_wait_idle = NULL, + .gui_idle = &r100_gui_idle, }; static struct radeon_asic r420_asic = { @@ -319,6 +323,7 @@ static struct radeon_asic r420_asic = { .hpd_sense = &r100_hpd_sense, .hpd_set_polarity = &r100_hpd_set_polarity, .ioctl_wait_idle = NULL, + .gui_idle = &r100_gui_idle, }; static struct radeon_asic rs400_asic = { @@ -358,6 +363,7 @@ static struct radeon_asic rs400_asic = { .hpd_sense = &r100_hpd_sense, .hpd_set_polarity = &r100_hpd_set_polarity, .ioctl_wait_idle = NULL, + .gui_idle = &r100_gui_idle, }; static struct radeon_asic rs600_asic = { @@ -397,6 +403,7 @@ static struct radeon_asic rs600_asic = { .hpd_sense = &rs600_hpd_sense, .hpd_set_polarity = &rs600_hpd_set_polarity, .ioctl_wait_idle = NULL, + .gui_idle = &r100_gui_idle, }; static struct radeon_asic rs690_asic = { @@ -436,6 +443,7 @@ static struct radeon_asic rs690_asic = { .hpd_sense = &rs600_hpd_sense, .hpd_set_polarity = &rs600_hpd_set_polarity, .ioctl_wait_idle = NULL, + .gui_idle = &r100_gui_idle, }; static struct radeon_asic rv515_asic = { @@ -475,6 +483,7 @@ static struct radeon_asic rv515_asic = { .hpd_sense = &rs600_hpd_sense, .hpd_set_polarity = &rs600_hpd_set_polarity, .ioctl_wait_idle = NULL, + .gui_idle = &r100_gui_idle, }; static struct radeon_asic r520_asic = { @@ -514,6 +523,7 @@ static struct radeon_asic r520_asic = { .hpd_sense = &rs600_hpd_sense, .hpd_set_polarity = &rs600_hpd_set_polarity, .ioctl_wait_idle = NULL, + .gui_idle = &r100_gui_idle, }; static struct radeon_asic r600_asic = { @@ -552,6 +562,7 @@ static struct radeon_asic r600_asic = { .hpd_sense = &r600_hpd_sense, .hpd_set_polarity = &r600_hpd_set_polarity, .ioctl_wait_idle = r600_ioctl_wait_idle, + .gui_idle = &r600_gui_idle, }; static struct radeon_asic rs780_asic = { @@ -590,6 +601,7 @@ static struct radeon_asic rs780_asic = { .hpd_sense = &r600_hpd_sense, .hpd_set_polarity = &r600_hpd_set_polarity, .ioctl_wait_idle = r600_ioctl_wait_idle, + .gui_idle = &r600_gui_idle, }; static struct radeon_asic rv770_asic = { @@ -628,6 +640,7 @@ static struct radeon_asic rv770_asic = { .hpd_sense = &r600_hpd_sense, .hpd_set_polarity = &r600_hpd_set_polarity, .ioctl_wait_idle = r600_ioctl_wait_idle, + .gui_idle = &r600_gui_idle, }; static struct radeon_asic evergreen_asic = { @@ -664,6 +677,7 @@ static struct radeon_asic evergreen_asic = { .hpd_fini = &evergreen_hpd_fini, .hpd_sense = &evergreen_hpd_sense, .hpd_set_polarity = &evergreen_hpd_set_polarity, + .gui_idle = &r600_gui_idle, }; int radeon_asic_init(struct radeon_device *rdev) diff --git a/drivers/gpu/drm/radeon/radeon_asic.h b/drivers/gpu/drm/radeon/radeon_asic.h index ef2c7ba1bdc9..c74bf9bd26c2 100644 --- a/drivers/gpu/drm/radeon/radeon_asic.h +++ b/drivers/gpu/drm/radeon/radeon_asic.h @@ -126,6 +126,7 @@ int r100_cs_packet_parse(struct radeon_cs_parser *p, void r100_enable_bm(struct radeon_device *rdev); void r100_set_common_regs(struct radeon_device *rdev); void r100_bm_disable(struct radeon_device *rdev); +extern bool r100_gui_idle(struct radeon_device *rdev); /* * r200,rv250,rs300,rv280 */ @@ -269,6 +270,7 @@ bool r600_hpd_sense(struct radeon_device *rdev, enum radeon_hpd_id hpd); void r600_hpd_set_polarity(struct radeon_device *rdev, enum radeon_hpd_id hpd); extern void r600_ioctl_wait_idle(struct radeon_device *rdev, struct radeon_bo *bo); +extern bool r600_gui_idle(struct radeon_device *rdev); /* * rv770,rv730,rv710,rv740 -- cgit v1.2.3 From 2031f77ca9c17133869b265210418959a909d259 Mon Sep 17 00:00:00 2001 From: Alex Deucher Date: Thu, 22 Apr 2010 12:52:11 -0400 Subject: drm/radeon/kms: add support for gui idle interrupts (v4) Useful for certain power management operations. You need to wait for the GUI engine (2D, 3D, CP, etc.) to be idle before changing clocks or adjusting engine parameters. (v2) Fix gui idle enable on pre-r6xx asics (v3) The gui idle interrrupt status bit is permanently asserted on pre-r6xx chips, but the interrrupt is still generated. workaround it in the driver. (v4) Add support for evergreen Signed-off-by: Alex Deucher Signed-off-by: Dave Airlie --- drivers/gpu/drm/radeon/evergreen.c | 11 +++++++++++ drivers/gpu/drm/radeon/r100.c | 20 ++++++++++++++++++++ drivers/gpu/drm/radeon/r600.c | 11 +++++++++++ drivers/gpu/drm/radeon/radeon.h | 4 ++++ drivers/gpu/drm/radeon/radeon_device.c | 1 + drivers/gpu/drm/radeon/radeon_irq_kms.c | 2 ++ drivers/gpu/drm/radeon/radeon_pm.c | 1 + drivers/gpu/drm/radeon/radeon_reg.h | 3 +++ drivers/gpu/drm/radeon/rs600.c | 22 +++++++++++++++++++++- 9 files changed, 74 insertions(+), 1 deletion(-) (limited to 'drivers/gpu/drm/radeon') diff --git a/drivers/gpu/drm/radeon/evergreen.c b/drivers/gpu/drm/radeon/evergreen.c index b3d168fb89e5..0137a4cd90f5 100644 --- a/drivers/gpu/drm/radeon/evergreen.c +++ b/drivers/gpu/drm/radeon/evergreen.c @@ -1418,6 +1418,7 @@ int evergreen_irq_set(struct radeon_device *rdev) u32 cp_int_cntl = CNTX_BUSY_INT_ENABLE | CNTX_EMPTY_INT_ENABLE; u32 crtc1 = 0, crtc2 = 0, crtc3 = 0, crtc4 = 0, crtc5 = 0, crtc6 = 0; u32 hpd1, hpd2, hpd3, hpd4, hpd5, hpd6; + u32 grbm_int_cntl = 0; if (!rdev->irq.installed) { WARN(1, "Can't enable IRQ/MSI because no handler is installed.\n"); @@ -1490,8 +1491,13 @@ int evergreen_irq_set(struct radeon_device *rdev) DRM_DEBUG("evergreen_irq_set: hpd 6\n"); hpd6 |= DC_HPDx_INT_EN; } + if (rdev->irq.gui_idle) { + DRM_DEBUG("gui idle\n"); + grbm_int_cntl |= GUI_IDLE_INT_ENABLE; + } WREG32(CP_INT_CNTL, cp_int_cntl); + WREG32(GRBM_INT_CNTL, grbm_int_cntl); WREG32(INT_MASK + EVERGREEN_CRTC0_REGISTER_OFFSET, crtc1); WREG32(INT_MASK + EVERGREEN_CRTC1_REGISTER_OFFSET, crtc2); @@ -1853,6 +1859,11 @@ restart_ih: case 181: /* CP EOP event */ DRM_DEBUG("IH: CP EOP\n"); break; + case 233: /* GUI IDLE */ + DRM_DEBUG("IH: CP EOP\n"); + rdev->pm.gui_idle = true; + wake_up(&rdev->irq.idle_queue); + break; default: DRM_DEBUG("Unhandled interrupt: %d %d\n", src_id, src_data); break; diff --git a/drivers/gpu/drm/radeon/r100.c b/drivers/gpu/drm/radeon/r100.c index e62116e222a0..d35298684f30 100644 --- a/drivers/gpu/drm/radeon/r100.c +++ b/drivers/gpu/drm/radeon/r100.c @@ -262,6 +262,9 @@ int r100_irq_set(struct radeon_device *rdev) if (rdev->irq.sw_int) { tmp |= RADEON_SW_INT_ENABLE; } + if (rdev->irq.gui_idle) { + tmp |= RADEON_GUI_IDLE_MASK; + } if (rdev->irq.crtc_vblank_int[0]) { tmp |= RADEON_CRTC_VBLANK_MASK; } @@ -296,6 +299,12 @@ static inline uint32_t r100_irq_ack(struct radeon_device *rdev) RADEON_CRTC_VBLANK_STAT | RADEON_CRTC2_VBLANK_STAT | RADEON_FP_DETECT_STAT | RADEON_FP2_DETECT_STAT; + /* the interrupt works, but the status bit is permanently asserted */ + if (rdev->irq.gui_idle && radeon_gui_idle(rdev)) { + if (!rdev->irq.gui_idle_acked) + irq_mask |= RADEON_GUI_IDLE_STAT; + } + if (irqs) { WREG32(RADEON_GEN_INT_STATUS, irqs); } @@ -307,6 +316,9 @@ int r100_irq_process(struct radeon_device *rdev) uint32_t status, msi_rearm; bool queue_hotplug = false; + /* reset gui idle ack. the status bit is broken */ + rdev->irq.gui_idle_acked = false; + status = r100_irq_ack(rdev); if (!status) { return IRQ_NONE; @@ -319,6 +331,12 @@ int r100_irq_process(struct radeon_device *rdev) if (status & RADEON_SW_INT_TEST) { radeon_fence_process(rdev); } + /* gui idle interrupt */ + if (status & RADEON_GUI_IDLE_STAT) { + rdev->irq.gui_idle_acked = true; + rdev->pm.gui_idle = true; + wake_up(&rdev->irq.idle_queue); + } /* Vertical blank interrupts */ if (status & RADEON_CRTC_VBLANK_STAT) { drm_handle_vblank(rdev->ddev, 0); @@ -340,6 +358,8 @@ int r100_irq_process(struct radeon_device *rdev) } status = r100_irq_ack(rdev); } + /* reset gui idle ack. the status bit is broken */ + rdev->irq.gui_idle_acked = false; if (queue_hotplug) queue_work(rdev->wq, &rdev->hotplug_work); if (rdev->msi_enabled) { diff --git a/drivers/gpu/drm/radeon/r600.c b/drivers/gpu/drm/radeon/r600.c index 1c85dcb168a1..094c29dd96e3 100644 --- a/drivers/gpu/drm/radeon/r600.c +++ b/drivers/gpu/drm/radeon/r600.c @@ -2535,6 +2535,7 @@ int r600_irq_set(struct radeon_device *rdev) u32 cp_int_cntl = CNTX_BUSY_INT_ENABLE | CNTX_EMPTY_INT_ENABLE; u32 mode_int = 0; u32 hpd1, hpd2, hpd3, hpd4 = 0, hpd5 = 0, hpd6 = 0; + u32 grbm_int_cntl = 0; u32 hdmi1, hdmi2; if (!rdev->irq.installed) { @@ -2611,9 +2612,14 @@ int r600_irq_set(struct radeon_device *rdev) DRM_DEBUG("r600_irq_set: hdmi 2\n"); hdmi2 |= R600_HDMI_INT_EN; } + if (rdev->irq.gui_idle) { + DRM_DEBUG("gui idle\n"); + grbm_int_cntl |= GUI_IDLE_INT_ENABLE; + } WREG32(CP_INT_CNTL, cp_int_cntl); WREG32(DxMODE_INT_MASK, mode_int); + WREG32(GRBM_INT_CNTL, grbm_int_cntl); WREG32(R600_HDMI_BLOCK1 + R600_HDMI_CNTL, hdmi1); if (ASIC_IS_DCE3(rdev)) { WREG32(R600_HDMI_BLOCK3 + R600_HDMI_CNTL, hdmi2); @@ -2929,6 +2935,11 @@ restart_ih: case 181: /* CP EOP event */ DRM_DEBUG("IH: CP EOP\n"); break; + case 233: /* GUI IDLE */ + DRM_DEBUG("IH: CP EOP\n"); + rdev->pm.gui_idle = true; + wake_up(&rdev->irq.idle_queue); + break; default: DRM_DEBUG("Unhandled interrupt: %d %d\n", src_id, src_data); break; diff --git a/drivers/gpu/drm/radeon/radeon.h b/drivers/gpu/drm/radeon/radeon.h index bb4a2a66f070..433937109afc 100644 --- a/drivers/gpu/drm/radeon/radeon.h +++ b/drivers/gpu/drm/radeon/radeon.h @@ -376,6 +376,9 @@ struct radeon_irq { wait_queue_head_t vblank_queue; /* FIXME: use defines for max hpd/dacs */ bool hpd[6]; + bool gui_idle; + bool gui_idle_acked; + wait_queue_head_t idle_queue; /* FIXME: use defines for max HDMI blocks */ bool hdmi[2]; spinlock_t sw_lock; @@ -694,6 +697,7 @@ struct radeon_pm { int active_crtcs; int req_vblank; bool vblank_sync; + bool gui_idle; fixed20_12 max_bandwidth; fixed20_12 igp_sideport_mclk; fixed20_12 igp_system_mclk; diff --git a/drivers/gpu/drm/radeon/radeon_device.c b/drivers/gpu/drm/radeon/radeon_device.c index 26217ffe0355..53a2c27dd8fa 100644 --- a/drivers/gpu/drm/radeon/radeon_device.c +++ b/drivers/gpu/drm/radeon/radeon_device.c @@ -602,6 +602,7 @@ int radeon_device_init(struct radeon_device *rdev, rwlock_init(&rdev->fence_drv.lock); INIT_LIST_HEAD(&rdev->gem.objects); init_waitqueue_head(&rdev->irq.vblank_queue); + init_waitqueue_head(&rdev->irq.idle_queue); /* setup workqueue */ rdev->wq = create_workqueue("radeon"); diff --git a/drivers/gpu/drm/radeon/radeon_irq_kms.c b/drivers/gpu/drm/radeon/radeon_irq_kms.c index 8fa40ed397ec..059bfa4098d7 100644 --- a/drivers/gpu/drm/radeon/radeon_irq_kms.c +++ b/drivers/gpu/drm/radeon/radeon_irq_kms.c @@ -68,6 +68,7 @@ void radeon_driver_irq_preinstall_kms(struct drm_device *dev) /* Disable *all* interrupts */ rdev->irq.sw_int = false; + rdev->irq.gui_idle = false; for (i = 0; i < rdev->num_crtc; i++) rdev->irq.crtc_vblank_int[i] = false; for (i = 0; i < 6; i++) @@ -97,6 +98,7 @@ void radeon_driver_irq_uninstall_kms(struct drm_device *dev) } /* Disable *all* interrupts */ rdev->irq.sw_int = false; + rdev->irq.gui_idle = false; for (i = 0; i < rdev->num_crtc; i++) rdev->irq.crtc_vblank_int[i] = false; for (i = 0; i < 6; i++) diff --git a/drivers/gpu/drm/radeon/radeon_pm.c b/drivers/gpu/drm/radeon/radeon_pm.c index a4b57493aa78..6dfeb9cf16ba 100644 --- a/drivers/gpu/drm/radeon/radeon_pm.c +++ b/drivers/gpu/drm/radeon/radeon_pm.c @@ -27,6 +27,7 @@ #define RADEON_IDLE_LOOP_MS 100 #define RADEON_RECLOCK_DELAY_MS 200 #define RADEON_WAIT_VBLANK_TIMEOUT 200 +#define RADEON_WAIT_IDLE_TIMEOUT 200 static bool radeon_pm_debug_check_in_vbl(struct radeon_device *rdev, bool finish); static void radeon_pm_set_clocks_locked(struct radeon_device *rdev); diff --git a/drivers/gpu/drm/radeon/radeon_reg.h b/drivers/gpu/drm/radeon/radeon_reg.h index eabbc9cf30a7..74d1cbfa23a1 100644 --- a/drivers/gpu/drm/radeon/radeon_reg.h +++ b/drivers/gpu/drm/radeon/radeon_reg.h @@ -995,6 +995,7 @@ # define RADEON_FP_DETECT_MASK (1 << 4) # define RADEON_CRTC2_VBLANK_MASK (1 << 9) # define RADEON_FP2_DETECT_MASK (1 << 10) +# define RADEON_GUI_IDLE_MASK (1 << 19) # define RADEON_SW_INT_ENABLE (1 << 25) #define RADEON_GEN_INT_STATUS 0x0044 # define AVIVO_DISPLAY_INT_STATUS (1 << 0) @@ -1006,6 +1007,8 @@ # define RADEON_CRTC2_VBLANK_STAT_ACK (1 << 9) # define RADEON_FP2_DETECT_STAT (1 << 10) # define RADEON_FP2_DETECT_STAT_ACK (1 << 10) +# define RADEON_GUI_IDLE_STAT (1 << 19) +# define RADEON_GUI_IDLE_STAT_ACK (1 << 19) # define RADEON_SW_INT_FIRE (1 << 26) # define RADEON_SW_INT_TEST (1 << 25) # define RADEON_SW_INT_TEST_ACK (1 << 25) diff --git a/drivers/gpu/drm/radeon/rs600.c b/drivers/gpu/drm/radeon/rs600.c index 5e3f21861f45..b312b72d76ce 100644 --- a/drivers/gpu/drm/radeon/rs600.c +++ b/drivers/gpu/drm/radeon/rs600.c @@ -382,6 +382,9 @@ int rs600_irq_set(struct radeon_device *rdev) if (rdev->irq.sw_int) { tmp |= S_000040_SW_INT_EN(1); } + if (rdev->irq.gui_idle) { + tmp |= S_000040_GUI_IDLE(1); + } if (rdev->irq.crtc_vblank_int[0]) { mode_int |= S_006540_D1MODE_VBLANK_INT_MASK(1); } @@ -404,9 +407,15 @@ int rs600_irq_set(struct radeon_device *rdev) static inline uint32_t rs600_irq_ack(struct radeon_device *rdev, u32 *r500_disp_int) { uint32_t irqs = RREG32(R_000044_GEN_INT_STATUS); - uint32_t irq_mask = ~C_000044_SW_INT; + uint32_t irq_mask = S_000044_SW_INT(1); u32 tmp; + /* the interrupt works, but the status bit is permanently asserted */ + if (rdev->irq.gui_idle && radeon_gui_idle(rdev)) { + if (!rdev->irq.gui_idle_acked) + irq_mask |= S_000044_GUI_IDLE_STAT(1); + } + if (G_000044_DISPLAY_INT_STAT(irqs)) { *r500_disp_int = RREG32(R_007EDC_DISP_INTERRUPT_STATUS); if (G_007EDC_LB_D1_VBLANK_INTERRUPT(*r500_disp_int)) { @@ -454,6 +463,9 @@ int rs600_irq_process(struct radeon_device *rdev) uint32_t r500_disp_int; bool queue_hotplug = false; + /* reset gui idle ack. the status bit is broken */ + rdev->irq.gui_idle_acked = false; + status = rs600_irq_ack(rdev, &r500_disp_int); if (!status && !r500_disp_int) { return IRQ_NONE; @@ -462,6 +474,12 @@ int rs600_irq_process(struct radeon_device *rdev) /* SW interrupt */ if (G_000044_SW_INT(status)) radeon_fence_process(rdev); + /* GUI idle */ + if (G_000040_GUI_IDLE(status)) { + rdev->irq.gui_idle_acked = true; + rdev->pm.gui_idle = true; + wake_up(&rdev->irq.idle_queue); + } /* Vertical blank interrupts */ if (G_007EDC_LB_D1_VBLANK_INTERRUPT(r500_disp_int)) { drm_handle_vblank(rdev->ddev, 0); @@ -483,6 +501,8 @@ int rs600_irq_process(struct radeon_device *rdev) } status = rs600_irq_ack(rdev, &r500_disp_int); } + /* reset gui idle ack. the status bit is broken */ + rdev->irq.gui_idle_acked = false; if (queue_hotplug) queue_work(rdev->wq, &rdev->hotplug_work); if (rdev->msi_enabled) { -- cgit v1.2.3 From ef6e6cf56aca91c0b0db8de6e79e0874595fd260 Mon Sep 17 00:00:00 2001 From: Alex Deucher Date: Wed, 17 Mar 2010 14:29:15 -0400 Subject: drm/radeon/kms: wait for gpu idle before changing power mode MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit set proper wait condition as noted by Rafał Miłecki. Signed-off-by: Alex Deucher Signed-off-by: Dave Airlie --- drivers/gpu/drm/radeon/radeon_pm.c | 10 ++++++++++ 1 file changed, 10 insertions(+) (limited to 'drivers/gpu/drm/radeon') diff --git a/drivers/gpu/drm/radeon/radeon_pm.c b/drivers/gpu/drm/radeon/radeon_pm.c index 6dfeb9cf16ba..4ece89aa26f8 100644 --- a/drivers/gpu/drm/radeon/radeon_pm.c +++ b/drivers/gpu/drm/radeon/radeon_pm.c @@ -378,6 +378,16 @@ static void radeon_pm_set_clocks(struct radeon_device *rdev) radeon_get_power_state(rdev, rdev->pm.planned_action); mutex_lock(&rdev->cp.mutex); + /* wait for GPU idle */ + rdev->pm.gui_idle = false; + rdev->irq.gui_idle = true; + radeon_irq_set(rdev); + wait_event_interruptible_timeout( + rdev->irq.idle_queue, rdev->pm.gui_idle, + msecs_to_jiffies(RADEON_WAIT_IDLE_TIMEOUT)); + rdev->irq.gui_idle = false; + radeon_irq_set(rdev); + if (rdev->pm.active_crtcs & (1 << 0)) { rdev->pm.req_vblank |= (1 << 0); drm_vblank_get(rdev->ddev, 0); -- cgit v1.2.3 From 02b17cc05372ab58e9638008d0206f1c1ee0cf5c Mon Sep 17 00:00:00 2001 From: Alex Deucher Date: Thu, 22 Apr 2010 13:25:06 -0400 Subject: drm/radeon/kms/atom/pm: rework power mode parsing On pre-r6xx, the power mode array is usually ordered: low ... high default On r6xx+: default low ... high Signed-off-by: Alex Deucher Signed-off-by: Dave Airlie --- drivers/gpu/drm/radeon/radeon_atombios.c | 23 +++++++++++++++++++---- 1 file changed, 19 insertions(+), 4 deletions(-) (limited to 'drivers/gpu/drm/radeon') diff --git a/drivers/gpu/drm/radeon/radeon_atombios.c b/drivers/gpu/drm/radeon/radeon_atombios.c index 031a96ceb0f5..aa0a973a8af2 100644 --- a/drivers/gpu/drm/radeon/radeon_atombios.c +++ b/drivers/gpu/drm/radeon/radeon_atombios.c @@ -1506,6 +1506,7 @@ void radeon_atombios_get_power_modes(struct radeon_device *rdev) num_modes = power_info->info.ucNumOfPowerModeEntries; if (num_modes > ATOM_MAX_NUMBEROF_POWER_BLOCK) num_modes = ATOM_MAX_NUMBEROF_POWER_BLOCK; + /* last mode is usually default, array is low to high */ for (i = 0; i < num_modes; i++) { rdev->pm.power_state[state_index].clock_info[0].voltage.type = VOLTAGE_NONE; switch (frev) { @@ -1711,6 +1712,14 @@ void radeon_atombios_get_power_modes(struct radeon_device *rdev) break; } } + /* last mode is usually default */ + if (!rdev->pm.default_power_state) { + rdev->pm.power_state[state_index - 1].type = + POWER_STATE_TYPE_DEFAULT; + rdev->pm.default_power_state = &rdev->pm.power_state[state_index - 1]; + rdev->pm.power_state[state_index - 1].default_clock_mode = + &rdev->pm.power_state[state_index - 1].clock_info[0]; + } } else { /* add the i2c bus for thermal/fan chip */ /* no support for internal controller yet */ @@ -1736,6 +1745,7 @@ void radeon_atombios_get_power_modes(struct radeon_device *rdev) rdev->pm.i2c_bus = radeon_i2c_create(rdev->ddev, &i2c_bus, "Thermal"); } } + /* first mode is usually default, followed by low to high */ for (i = 0; i < power_info->info_4.ucNumStates; i++) { mode_index = 0; power_state = (struct _ATOM_PPLIB_STATE *) @@ -1865,12 +1875,16 @@ void radeon_atombios_get_power_modes(struct radeon_device *rdev) state_index++; } } + /* first mode is usually default */ + if (!rdev->pm.default_power_state) { + rdev->pm.power_state[0].type = + POWER_STATE_TYPE_DEFAULT; + rdev->pm.default_power_state = &rdev->pm.power_state[0]; + rdev->pm.power_state[0].default_clock_mode = + &rdev->pm.power_state[0].clock_info[0]; + } } } else { - /* XXX figure out some good default low power mode for cards w/out power tables */ - } - - if (rdev->pm.default_power_state == NULL) { /* add the default mode */ rdev->pm.power_state[state_index].type = POWER_STATE_TYPE_DEFAULT; @@ -1887,6 +1901,7 @@ void radeon_atombios_get_power_modes(struct radeon_device *rdev) rdev->pm.default_power_state = &rdev->pm.power_state[state_index]; state_index++; } + rdev->pm.num_power_states = state_index; rdev->pm.current_power_state = rdev->pm.default_power_state; -- cgit v1.2.3 From 8a56df632e524a1c444c56bb7ce9fe8d94e639e0 Mon Sep 17 00:00:00 2001 From: Alex Deucher Date: Mon, 15 Mar 2010 17:09:05 -0400 Subject: drm/radeon/kms/pm: interate across crtcs for vblank Signed-off-by: Alex Deucher Signed-off-by: Dave Airlie --- drivers/gpu/drm/radeon/radeon_pm.c | 26 ++++++++++++-------------- 1 file changed, 12 insertions(+), 14 deletions(-) (limited to 'drivers/gpu/drm/radeon') diff --git a/drivers/gpu/drm/radeon/radeon_pm.c b/drivers/gpu/drm/radeon/radeon_pm.c index 4ece89aa26f8..ff3abd8c8966 100644 --- a/drivers/gpu/drm/radeon/radeon_pm.c +++ b/drivers/gpu/drm/radeon/radeon_pm.c @@ -375,6 +375,8 @@ static void radeon_pm_set_clocks_locked(struct radeon_device *rdev) static void radeon_pm_set_clocks(struct radeon_device *rdev) { + int i; + radeon_get_power_state(rdev, rdev->pm.planned_action); mutex_lock(&rdev->cp.mutex); @@ -388,22 +390,18 @@ static void radeon_pm_set_clocks(struct radeon_device *rdev) rdev->irq.gui_idle = false; radeon_irq_set(rdev); - if (rdev->pm.active_crtcs & (1 << 0)) { - rdev->pm.req_vblank |= (1 << 0); - drm_vblank_get(rdev->ddev, 0); - } - if (rdev->pm.active_crtcs & (1 << 1)) { - rdev->pm.req_vblank |= (1 << 1); - drm_vblank_get(rdev->ddev, 1); + for (i = 0; i < rdev->num_crtc; i++) { + if (rdev->pm.active_crtcs & (1 << i)) { + rdev->pm.req_vblank |= (1 << i); + drm_vblank_get(rdev->ddev, i); + } } radeon_pm_set_clocks_locked(rdev); - if (rdev->pm.req_vblank & (1 << 0)) { - rdev->pm.req_vblank &= ~(1 << 0); - drm_vblank_put(rdev->ddev, 0); - } - if (rdev->pm.req_vblank & (1 << 1)) { - rdev->pm.req_vblank &= ~(1 << 1); - drm_vblank_put(rdev->ddev, 1); + for (i = 0; i < rdev->num_crtc; i++) { + if (rdev->pm.req_vblank & (1 << i)) { + rdev->pm.req_vblank &= ~(1 << i); + drm_vblank_put(rdev->ddev, i); + } } mutex_unlock(&rdev->cp.mutex); -- cgit v1.2.3 From 03214bd5c6e59c83703238227254deef8810513d Mon Sep 17 00:00:00 2001 From: Alex Deucher Date: Tue, 16 Mar 2010 17:42:46 -0400 Subject: drm/radeon/kms/pm: move pm state update to crtc functions crtcs are what we ultimately care about wrt to pm. Signed-off-by: Alex Deucher Signed-off-by: Dave Airlie --- drivers/gpu/drm/radeon/atombios_crtc.c | 9 +++++++++ drivers/gpu/drm/radeon/radeon_encoders.c | 5 ----- drivers/gpu/drm/radeon/radeon_legacy_crtc.c | 9 +++++++++ drivers/gpu/drm/radeon/radeon_legacy_encoders.c | 15 --------------- 4 files changed, 18 insertions(+), 20 deletions(-) (limited to 'drivers/gpu/drm/radeon') diff --git a/drivers/gpu/drm/radeon/atombios_crtc.c b/drivers/gpu/drm/radeon/atombios_crtc.c index 3feca6aec4c4..12fb12a2bbac 100644 --- a/drivers/gpu/drm/radeon/atombios_crtc.c +++ b/drivers/gpu/drm/radeon/atombios_crtc.c @@ -262,6 +262,9 @@ void atombios_crtc_dpms(struct drm_crtc *crtc, int mode) atombios_enable_crtc(crtc, ATOM_DISABLE); break; } + + /* adjust pm to dpms change */ + radeon_pm_compute_clocks(rdev); } static void @@ -1156,6 +1159,12 @@ static bool atombios_crtc_mode_fixup(struct drm_crtc *crtc, struct drm_display_mode *mode, struct drm_display_mode *adjusted_mode) { + struct drm_device *dev = crtc->dev; + struct radeon_device *rdev = dev->dev_private; + + /* adjust pm to upcoming mode change */ + radeon_pm_compute_clocks(rdev); + if (!radeon_crtc_scaling_mode_fixup(crtc, mode, adjusted_mode)) return false; return true; diff --git a/drivers/gpu/drm/radeon/radeon_encoders.c b/drivers/gpu/drm/radeon/radeon_encoders.c index 1ec292ef11b0..b5dff14ea8c6 100644 --- a/drivers/gpu/drm/radeon/radeon_encoders.c +++ b/drivers/gpu/drm/radeon/radeon_encoders.c @@ -262,9 +262,6 @@ static bool radeon_atom_mode_fixup(struct drm_encoder *encoder, struct drm_device *dev = encoder->dev; struct radeon_device *rdev = dev->dev_private; - /* adjust pm to upcoming mode change */ - radeon_pm_compute_clocks(rdev); - /* set the active encoder to connector routing */ radeon_encoder_set_active_device(encoder); drm_mode_set_crtcinfo(adjusted_mode, 0); @@ -1074,8 +1071,6 @@ radeon_atom_encoder_dpms(struct drm_encoder *encoder, int mode) } radeon_atombios_encoder_dpms_scratch_regs(encoder, (mode == DRM_MODE_DPMS_ON) ? true : false); - /* adjust pm to dpms change */ - radeon_pm_compute_clocks(rdev); } union crtc_source_param { diff --git a/drivers/gpu/drm/radeon/radeon_legacy_crtc.c b/drivers/gpu/drm/radeon/radeon_legacy_crtc.c index 88865e38fe30..60c0dcb8e11e 100644 --- a/drivers/gpu/drm/radeon/radeon_legacy_crtc.c +++ b/drivers/gpu/drm/radeon/radeon_legacy_crtc.c @@ -337,6 +337,9 @@ void radeon_crtc_dpms(struct drm_crtc *crtc, int mode) } break; } + + /* adjust pm to dpms change */ + radeon_pm_compute_clocks(rdev); } int radeon_crtc_set_base(struct drm_crtc *crtc, int x, int y, @@ -966,6 +969,12 @@ static bool radeon_crtc_mode_fixup(struct drm_crtc *crtc, struct drm_display_mode *mode, struct drm_display_mode *adjusted_mode) { + struct drm_device *dev = crtc->dev; + struct radeon_device *rdev = dev->dev_private; + + /* adjust pm to upcoming mode change */ + radeon_pm_compute_clocks(rdev); + if (!radeon_crtc_scaling_mode_fixup(crtc, mode, adjusted_mode)) return false; return true; diff --git a/drivers/gpu/drm/radeon/radeon_legacy_encoders.c b/drivers/gpu/drm/radeon/radeon_legacy_encoders.c index 2441cca7d775..341df86a253b 100644 --- a/drivers/gpu/drm/radeon/radeon_legacy_encoders.c +++ b/drivers/gpu/drm/radeon/radeon_legacy_encoders.c @@ -116,8 +116,6 @@ static void radeon_legacy_lvds_dpms(struct drm_encoder *encoder, int mode) else radeon_combios_encoder_dpms_scratch_regs(encoder, (mode == DRM_MODE_DPMS_ON) ? true : false); - /* adjust pm to dpms change */ - radeon_pm_compute_clocks(rdev); } static void radeon_legacy_lvds_prepare(struct drm_encoder *encoder) @@ -217,11 +215,6 @@ static bool radeon_legacy_mode_fixup(struct drm_encoder *encoder, struct drm_display_mode *adjusted_mode) { struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder); - struct drm_device *dev = encoder->dev; - struct radeon_device *rdev = dev->dev_private; - - /* adjust pm to upcoming mode change */ - radeon_pm_compute_clocks(rdev); /* set the active encoder to connector routing */ radeon_encoder_set_active_device(encoder); @@ -294,8 +287,6 @@ static void radeon_legacy_primary_dac_dpms(struct drm_encoder *encoder, int mode else radeon_combios_encoder_dpms_scratch_regs(encoder, (mode == DRM_MODE_DPMS_ON) ? true : false); - /* adjust pm to dpms change */ - radeon_pm_compute_clocks(rdev); } static void radeon_legacy_primary_dac_prepare(struct drm_encoder *encoder) @@ -482,8 +473,6 @@ static void radeon_legacy_tmds_int_dpms(struct drm_encoder *encoder, int mode) else radeon_combios_encoder_dpms_scratch_regs(encoder, (mode == DRM_MODE_DPMS_ON) ? true : false); - /* adjust pm to dpms change */ - radeon_pm_compute_clocks(rdev); } static void radeon_legacy_tmds_int_prepare(struct drm_encoder *encoder) @@ -650,8 +639,6 @@ static void radeon_legacy_tmds_ext_dpms(struct drm_encoder *encoder, int mode) else radeon_combios_encoder_dpms_scratch_regs(encoder, (mode == DRM_MODE_DPMS_ON) ? true : false); - /* adjust pm to dpms change */ - radeon_pm_compute_clocks(rdev); } static void radeon_legacy_tmds_ext_prepare(struct drm_encoder *encoder) @@ -860,8 +847,6 @@ static void radeon_legacy_tv_dac_dpms(struct drm_encoder *encoder, int mode) else radeon_combios_encoder_dpms_scratch_regs(encoder, (mode == DRM_MODE_DPMS_ON) ? true : false); - /* adjust pm to dpms change */ - radeon_pm_compute_clocks(rdev); } static void radeon_legacy_tv_dac_prepare(struct drm_encoder *encoder) -- cgit v1.2.3 From bae6b5627387a950a8faf366d6027bd0a7a93078 Mon Sep 17 00:00:00 2001 From: Alex Deucher Date: Thu, 22 Apr 2010 13:38:05 -0400 Subject: drm/radeon/kms/pm: add asic specific callbacks for setting power state (v2) (v2) Add evergreen vbl checks Signed-off-by: Alex Deucher Signed-off-by: Dave Airlie --- drivers/gpu/drm/radeon/evergreen_reg.h | 1 + drivers/gpu/drm/radeon/r100.c | 37 ++++++++++++ drivers/gpu/drm/radeon/r600.c | 37 ++++++++++++ drivers/gpu/drm/radeon/radeon.h | 4 ++ drivers/gpu/drm/radeon/radeon_asic.c | 14 +++++ drivers/gpu/drm/radeon/radeon_asic.h | 3 + drivers/gpu/drm/radeon/radeon_pm.c | 100 +++++++++++++++++---------------- drivers/gpu/drm/radeon/radeon_reg.h | 1 - 8 files changed, 148 insertions(+), 49 deletions(-) (limited to 'drivers/gpu/drm/radeon') diff --git a/drivers/gpu/drm/radeon/evergreen_reg.h b/drivers/gpu/drm/radeon/evergreen_reg.h index f7c7c9643433..9dba6d97d9b7 100644 --- a/drivers/gpu/drm/radeon/evergreen_reg.h +++ b/drivers/gpu/drm/radeon/evergreen_reg.h @@ -166,6 +166,7 @@ /* CRTC blocks at 0x6df0, 0x79f0, 0x105f0, 0x111f0, 0x11df0, 0x129f0 */ #define EVERGREEN_CRTC_CONTROL 0x6e70 # define EVERGREEN_CRTC_MASTER_EN (1 << 0) +#define EVERGREEN_CRTC_STATUS 0x6e8c #define EVERGREEN_CRTC_UPDATE_LOCK 0x6ed4 #define EVERGREEN_DC_GPIO_HPD_MASK 0x64b0 diff --git a/drivers/gpu/drm/radeon/r100.c b/drivers/gpu/drm/radeon/r100.c index d35298684f30..b076b96f8b6c 100644 --- a/drivers/gpu/drm/radeon/r100.c +++ b/drivers/gpu/drm/radeon/r100.c @@ -67,6 +67,43 @@ MODULE_FIRMWARE(FIRMWARE_R520); * r100,rv100,rs100,rv200,rs200,r200,rv250,rs300,rv280 */ +void r100_set_power_state(struct radeon_device *rdev) +{ + /* if *_clock_mode are the same, *_power_state are as well */ + if (rdev->pm.requested_clock_mode == rdev->pm.current_clock_mode) + return; + + DRM_INFO("Setting: e: %d m: %d p: %d\n", + rdev->pm.requested_clock_mode->sclk, + rdev->pm.requested_clock_mode->mclk, + rdev->pm.requested_power_state->non_clock_info.pcie_lanes); + + /* set pcie lanes */ + /* TODO */ + + /* set voltage */ + /* TODO */ + + /* set engine clock */ + radeon_sync_with_vblank(rdev); + radeon_pm_debug_check_in_vbl(rdev, false); + radeon_set_engine_clock(rdev, rdev->pm.requested_clock_mode->sclk); + radeon_pm_debug_check_in_vbl(rdev, true); + +#if 0 + /* set memory clock */ + if (rdev->asic->set_memory_clock) { + radeon_sync_with_vblank(rdev); + radeon_pm_debug_check_in_vbl(rdev, false); + radeon_set_memory_clock(rdev, rdev->pm.requested_clock_mode->mclk); + radeon_pm_debug_check_in_vbl(rdev, true); + } +#endif + + rdev->pm.current_power_state = rdev->pm.requested_power_state; + rdev->pm.current_clock_mode = rdev->pm.requested_clock_mode; +} + bool r100_gui_idle(struct radeon_device *rdev) { if (RREG32(RADEON_RBBM_STATUS) & RADEON_RBBM_ACTIVE) diff --git a/drivers/gpu/drm/radeon/r600.c b/drivers/gpu/drm/radeon/r600.c index 094c29dd96e3..c2d1946535ab 100644 --- a/drivers/gpu/drm/radeon/r600.c +++ b/drivers/gpu/drm/radeon/r600.c @@ -92,6 +92,43 @@ void r600_gpu_init(struct radeon_device *rdev); void r600_fini(struct radeon_device *rdev); void r600_irq_disable(struct radeon_device *rdev); +void r600_set_power_state(struct radeon_device *rdev) +{ + /* if *_clock_mode are the same, *_power_state are as well */ + if (rdev->pm.requested_clock_mode == rdev->pm.current_clock_mode) + return; + + DRM_INFO("Setting: e: %d m: %d p: %d\n", + rdev->pm.requested_clock_mode->sclk, + rdev->pm.requested_clock_mode->mclk, + rdev->pm.requested_power_state->non_clock_info.pcie_lanes); + + /* set pcie lanes */ + /* TODO */ + + /* set voltage */ + /* TODO */ + + /* set engine clock */ + radeon_sync_with_vblank(rdev); + radeon_pm_debug_check_in_vbl(rdev, false); + radeon_set_engine_clock(rdev, rdev->pm.requested_clock_mode->sclk); + radeon_pm_debug_check_in_vbl(rdev, true); + +#if 0 + /* set memory clock */ + if (rdev->asic->set_memory_clock) { + radeon_sync_with_vblank(rdev); + radeon_pm_debug_check_in_vbl(rdev, false); + radeon_set_memory_clock(rdev, rdev->pm.requested_clock_mode->mclk); + radeon_pm_debug_check_in_vbl(rdev, true); + } +#endif + + rdev->pm.current_power_state = rdev->pm.requested_power_state; + rdev->pm.current_clock_mode = rdev->pm.requested_clock_mode; +} + bool r600_gui_idle(struct radeon_device *rdev) { if (RREG32(GRBM_STATUS) & GUI_ACTIVE) diff --git a/drivers/gpu/drm/radeon/radeon.h b/drivers/gpu/drm/radeon/radeon.h index 433937109afc..11fe1d1444c2 100644 --- a/drivers/gpu/drm/radeon/radeon.h +++ b/drivers/gpu/drm/radeon/radeon.h @@ -175,6 +175,8 @@ void radeon_pm_fini(struct radeon_device *rdev); void radeon_pm_compute_clocks(struct radeon_device *rdev); void radeon_combios_get_power_modes(struct radeon_device *rdev); void radeon_atombios_get_power_modes(struct radeon_device *rdev); +bool radeon_pm_debug_check_in_vbl(struct radeon_device *rdev, bool finish); +void radeon_sync_with_vblank(struct radeon_device *rdev); /* * Fences. @@ -808,6 +810,7 @@ struct radeon_asic { */ void (*ioctl_wait_idle)(struct radeon_device *rdev, struct radeon_bo *bo); bool (*gui_idle)(struct radeon_device *rdev); + void (*set_power_state)(struct radeon_device *rdev); }; /* @@ -1215,6 +1218,7 @@ static inline void radeon_ring_write(struct radeon_device *rdev, uint32_t v) #define radeon_hpd_sense(rdev, hpd) (rdev)->asic->hpd_sense((rdev), (hpd)) #define radeon_hpd_set_polarity(rdev, hpd) (rdev)->asic->hpd_set_polarity((rdev), (hpd)) #define radeon_gui_idle(rdev) (rdev)->asic->gui_idle((rdev)) +#define radeon_set_power_state(rdev) (rdev)->asic->set_power_state((rdev)) /* Common functions */ /* AGP */ diff --git a/drivers/gpu/drm/radeon/radeon_asic.c b/drivers/gpu/drm/radeon/radeon_asic.c index 42708462fd4b..48893fbb6582 100644 --- a/drivers/gpu/drm/radeon/radeon_asic.c +++ b/drivers/gpu/drm/radeon/radeon_asic.c @@ -166,6 +166,7 @@ static struct radeon_asic r100_asic = { .hpd_set_polarity = &r100_hpd_set_polarity, .ioctl_wait_idle = NULL, .gui_idle = &r100_gui_idle, + .set_power_state = &r100_set_power_state, }; static struct radeon_asic r200_asic = { @@ -205,6 +206,7 @@ static struct radeon_asic r200_asic = { .hpd_set_polarity = &r100_hpd_set_polarity, .ioctl_wait_idle = NULL, .gui_idle = &r100_gui_idle, + .set_power_state = &r100_set_power_state, }; static struct radeon_asic r300_asic = { @@ -245,6 +247,7 @@ static struct radeon_asic r300_asic = { .hpd_set_polarity = &r100_hpd_set_polarity, .ioctl_wait_idle = NULL, .gui_idle = &r100_gui_idle, + .set_power_state = &r100_set_power_state, }; static struct radeon_asic r300_asic_pcie = { @@ -284,6 +287,7 @@ static struct radeon_asic r300_asic_pcie = { .hpd_set_polarity = &r100_hpd_set_polarity, .ioctl_wait_idle = NULL, .gui_idle = &r100_gui_idle, + .set_power_state = &r100_set_power_state, }; static struct radeon_asic r420_asic = { @@ -324,6 +328,7 @@ static struct radeon_asic r420_asic = { .hpd_set_polarity = &r100_hpd_set_polarity, .ioctl_wait_idle = NULL, .gui_idle = &r100_gui_idle, + .set_power_state = &r100_set_power_state, }; static struct radeon_asic rs400_asic = { @@ -364,6 +369,7 @@ static struct radeon_asic rs400_asic = { .hpd_set_polarity = &r100_hpd_set_polarity, .ioctl_wait_idle = NULL, .gui_idle = &r100_gui_idle, + .set_power_state = &r100_set_power_state, }; static struct radeon_asic rs600_asic = { @@ -404,6 +410,7 @@ static struct radeon_asic rs600_asic = { .hpd_set_polarity = &rs600_hpd_set_polarity, .ioctl_wait_idle = NULL, .gui_idle = &r100_gui_idle, + .set_power_state = &r100_set_power_state, }; static struct radeon_asic rs690_asic = { @@ -444,6 +451,7 @@ static struct radeon_asic rs690_asic = { .hpd_set_polarity = &rs600_hpd_set_polarity, .ioctl_wait_idle = NULL, .gui_idle = &r100_gui_idle, + .set_power_state = &r100_set_power_state, }; static struct radeon_asic rv515_asic = { @@ -484,6 +492,7 @@ static struct radeon_asic rv515_asic = { .hpd_set_polarity = &rs600_hpd_set_polarity, .ioctl_wait_idle = NULL, .gui_idle = &r100_gui_idle, + .set_power_state = &r100_set_power_state, }; static struct radeon_asic r520_asic = { @@ -524,6 +533,7 @@ static struct radeon_asic r520_asic = { .hpd_set_polarity = &rs600_hpd_set_polarity, .ioctl_wait_idle = NULL, .gui_idle = &r100_gui_idle, + .set_power_state = &r100_set_power_state, }; static struct radeon_asic r600_asic = { @@ -563,6 +573,7 @@ static struct radeon_asic r600_asic = { .hpd_set_polarity = &r600_hpd_set_polarity, .ioctl_wait_idle = r600_ioctl_wait_idle, .gui_idle = &r600_gui_idle, + .set_power_state = &r600_set_power_state, }; static struct radeon_asic rs780_asic = { @@ -602,6 +613,7 @@ static struct radeon_asic rs780_asic = { .hpd_set_polarity = &r600_hpd_set_polarity, .ioctl_wait_idle = r600_ioctl_wait_idle, .gui_idle = &r600_gui_idle, + .set_power_state = &r600_set_power_state, }; static struct radeon_asic rv770_asic = { @@ -641,6 +653,7 @@ static struct radeon_asic rv770_asic = { .hpd_set_polarity = &r600_hpd_set_polarity, .ioctl_wait_idle = r600_ioctl_wait_idle, .gui_idle = &r600_gui_idle, + .set_power_state = &r600_set_power_state, }; static struct radeon_asic evergreen_asic = { @@ -678,6 +691,7 @@ static struct radeon_asic evergreen_asic = { .hpd_sense = &evergreen_hpd_sense, .hpd_set_polarity = &evergreen_hpd_set_polarity, .gui_idle = &r600_gui_idle, + .set_power_state = &r600_set_power_state, }; int radeon_asic_init(struct radeon_device *rdev) diff --git a/drivers/gpu/drm/radeon/radeon_asic.h b/drivers/gpu/drm/radeon/radeon_asic.h index c74bf9bd26c2..90d8e6dee52c 100644 --- a/drivers/gpu/drm/radeon/radeon_asic.h +++ b/drivers/gpu/drm/radeon/radeon_asic.h @@ -127,6 +127,8 @@ void r100_enable_bm(struct radeon_device *rdev); void r100_set_common_regs(struct radeon_device *rdev); void r100_bm_disable(struct radeon_device *rdev); extern bool r100_gui_idle(struct radeon_device *rdev); +extern void r100_set_power_state(struct radeon_device *rdev); + /* * r200,rv250,rs300,rv280 */ @@ -271,6 +273,7 @@ void r600_hpd_set_polarity(struct radeon_device *rdev, enum radeon_hpd_id hpd); extern void r600_ioctl_wait_idle(struct radeon_device *rdev, struct radeon_bo *bo); extern bool r600_gui_idle(struct radeon_device *rdev); +extern void r600_set_power_state(struct radeon_device *rdev); /* * rv770,rv730,rv710,rv740 diff --git a/drivers/gpu/drm/radeon/radeon_pm.c b/drivers/gpu/drm/radeon/radeon_pm.c index ff3abd8c8966..129956d003a4 100644 --- a/drivers/gpu/drm/radeon/radeon_pm.c +++ b/drivers/gpu/drm/radeon/radeon_pm.c @@ -29,7 +29,6 @@ #define RADEON_WAIT_VBLANK_TIMEOUT 200 #define RADEON_WAIT_IDLE_TIMEOUT 200 -static bool radeon_pm_debug_check_in_vbl(struct radeon_device *rdev, bool finish); static void radeon_pm_set_clocks_locked(struct radeon_device *rdev); static void radeon_pm_set_clocks(struct radeon_device *rdev); static void radeon_pm_idle_work_handler(struct work_struct *work); @@ -181,7 +180,7 @@ static void radeon_get_power_state(struct radeon_device *rdev, rdev->pm.requested_power_state->non_clock_info.pcie_lanes); } -static inline void radeon_sync_with_vblank(struct radeon_device *rdev) +void radeon_sync_with_vblank(struct radeon_device *rdev) { if (rdev->pm.active_crtcs) { rdev->pm.vblank_sync = false; @@ -191,43 +190,6 @@ static inline void radeon_sync_with_vblank(struct radeon_device *rdev) } } -static void radeon_set_power_state(struct radeon_device *rdev) -{ - /* if *_clock_mode are the same, *_power_state are as well */ - if (rdev->pm.requested_clock_mode == rdev->pm.current_clock_mode) - return; - - DRM_INFO("Setting: e: %d m: %d p: %d\n", - rdev->pm.requested_clock_mode->sclk, - rdev->pm.requested_clock_mode->mclk, - rdev->pm.requested_power_state->non_clock_info.pcie_lanes); - - /* set pcie lanes */ - /* TODO */ - - /* set voltage */ - /* TODO */ - - /* set engine clock */ - radeon_sync_with_vblank(rdev); - radeon_pm_debug_check_in_vbl(rdev, false); - radeon_set_engine_clock(rdev, rdev->pm.requested_clock_mode->sclk); - radeon_pm_debug_check_in_vbl(rdev, true); - -#if 0 - /* set memory clock */ - if (rdev->asic->set_memory_clock) { - radeon_sync_with_vblank(rdev); - radeon_pm_debug_check_in_vbl(rdev, false); - radeon_set_memory_clock(rdev, rdev->pm.requested_clock_mode->mclk); - radeon_pm_debug_check_in_vbl(rdev, true); - } -#endif - - rdev->pm.current_power_state = rdev->pm.requested_power_state; - rdev->pm.current_clock_mode = rdev->pm.requested_clock_mode; -} - int radeon_pm_init(struct radeon_device *rdev) { rdev->pm.state = PM_STATE_DISABLED; @@ -330,26 +292,68 @@ void radeon_pm_compute_clocks(struct radeon_device *rdev) mutex_unlock(&rdev->pm.mutex); } -static bool radeon_pm_debug_check_in_vbl(struct radeon_device *rdev, bool finish) +bool radeon_pm_debug_check_in_vbl(struct radeon_device *rdev, bool finish) { - u32 stat_crtc1 = 0, stat_crtc2 = 0; + u32 stat_crtc = 0; bool in_vbl = true; - if (ASIC_IS_AVIVO(rdev)) { + if (ASIC_IS_DCE4(rdev)) { + if (rdev->pm.active_crtcs & (1 << 0)) { + stat_crtc = RREG32(EVERGREEN_CRTC_STATUS + EVERGREEN_CRTC0_REGISTER_OFFSET); + if (!(stat_crtc & 1)) + in_vbl = false; + } + if (rdev->pm.active_crtcs & (1 << 1)) { + stat_crtc = RREG32(EVERGREEN_CRTC_STATUS + EVERGREEN_CRTC1_REGISTER_OFFSET); + if (!(stat_crtc & 1)) + in_vbl = false; + } + if (rdev->pm.active_crtcs & (1 << 2)) { + stat_crtc = RREG32(EVERGREEN_CRTC_STATUS + EVERGREEN_CRTC2_REGISTER_OFFSET); + if (!(stat_crtc & 1)) + in_vbl = false; + } + if (rdev->pm.active_crtcs & (1 << 3)) { + stat_crtc = RREG32(EVERGREEN_CRTC_STATUS + EVERGREEN_CRTC3_REGISTER_OFFSET); + if (!(stat_crtc & 1)) + in_vbl = false; + } + if (rdev->pm.active_crtcs & (1 << 4)) { + stat_crtc = RREG32(EVERGREEN_CRTC_STATUS + EVERGREEN_CRTC4_REGISTER_OFFSET); + if (!(stat_crtc & 1)) + in_vbl = false; + } + if (rdev->pm.active_crtcs & (1 << 5)) { + stat_crtc = RREG32(EVERGREEN_CRTC_STATUS + EVERGREEN_CRTC5_REGISTER_OFFSET); + if (!(stat_crtc & 1)) + in_vbl = false; + } + } else if (ASIC_IS_AVIVO(rdev)) { + if (rdev->pm.active_crtcs & (1 << 0)) { + stat_crtc = RREG32(D1CRTC_STATUS); + if (!(stat_crtc & 1)) + in_vbl = false; + } + if (rdev->pm.active_crtcs & (1 << 1)) { + stat_crtc = RREG32(D2CRTC_STATUS); + if (!(stat_crtc & 1)) + in_vbl = false; + } + } else { if (rdev->pm.active_crtcs & (1 << 0)) { - stat_crtc1 = RREG32(D1CRTC_STATUS); - if (!(stat_crtc1 & 1)) + stat_crtc = RREG32(RADEON_CRTC_STATUS); + if (!(stat_crtc & 1)) in_vbl = false; } if (rdev->pm.active_crtcs & (1 << 1)) { - stat_crtc2 = RREG32(D2CRTC_STATUS); - if (!(stat_crtc2 & 1)) + stat_crtc = RREG32(RADEON_CRTC2_STATUS); + if (!(stat_crtc & 1)) in_vbl = false; } } if (in_vbl == false) - DRM_INFO("not in vbl for pm change %08x %08x at %s\n", stat_crtc1, - stat_crtc2, finish ? "exit" : "entry"); + DRM_INFO("not in vbl for pm change %08x at %s\n", stat_crtc, + finish ? "exit" : "entry"); return in_vbl; } static void radeon_pm_set_clocks_locked(struct radeon_device *rdev) diff --git a/drivers/gpu/drm/radeon/radeon_reg.h b/drivers/gpu/drm/radeon/radeon_reg.h index 74d1cbfa23a1..c332f46340d5 100644 --- a/drivers/gpu/drm/radeon/radeon_reg.h +++ b/drivers/gpu/drm/radeon/radeon_reg.h @@ -553,7 +553,6 @@ # define RADEON_CRTC_CRNT_VLINE_MASK (0x7ff << 16) #define RADEON_CRTC2_CRNT_FRAME 0x0314 #define RADEON_CRTC2_GUI_TRIG_VLINE 0x0318 -#define RADEON_CRTC2_STATUS 0x03fc #define RADEON_CRTC2_VLINE_CRNT_VLINE 0x0310 #define RADEON_CRTC8_DATA 0x03d5 /* VGA, 0x3b5 */ #define RADEON_CRTC8_IDX 0x03d4 /* VGA, 0x3b4 */ -- cgit v1.2.3 From a48b9b4edb8bb87deb13b9f088a595cf71457b69 Mon Sep 17 00:00:00 2001 From: Alex Deucher Date: Thu, 22 Apr 2010 14:03:55 -0400 Subject: drm/radeon/kms/pm: add asic specific callbacks for getting power state (v2) This also simplifies the code and enables reclocking with multiple heads active by tracking whether the power states are single or multi-head capable. Eventually, we will want to select a power state based on external factors (AC/DC state, user selection, etc.). (v2) Update for evergreen Signed-off-by: Alex Deucher Signed-off-by: Dave Airlie --- drivers/gpu/drm/radeon/atombios_crtc.c | 2 + drivers/gpu/drm/radeon/r100.c | 140 +++++++++++++++--- drivers/gpu/drm/radeon/r600.c | 217 ++++++++++++++++++++++++---- drivers/gpu/drm/radeon/radeon.h | 25 +++- drivers/gpu/drm/radeon/radeon_asic.c | 14 ++ drivers/gpu/drm/radeon/radeon_asic.h | 4 + drivers/gpu/drm/radeon/radeon_atombios.c | 91 ++++++------ drivers/gpu/drm/radeon/radeon_combios.c | 11 +- drivers/gpu/drm/radeon/radeon_legacy_crtc.c | 2 + drivers/gpu/drm/radeon/radeon_pm.c | 153 +++----------------- 10 files changed, 413 insertions(+), 246 deletions(-) (limited to 'drivers/gpu/drm/radeon') diff --git a/drivers/gpu/drm/radeon/atombios_crtc.c b/drivers/gpu/drm/radeon/atombios_crtc.c index 12fb12a2bbac..b11aa37ed6d5 100644 --- a/drivers/gpu/drm/radeon/atombios_crtc.c +++ b/drivers/gpu/drm/radeon/atombios_crtc.c @@ -251,6 +251,7 @@ void atombios_crtc_dpms(struct drm_crtc *crtc, int mode) atombios_blank_crtc(crtc, ATOM_DISABLE); drm_vblank_post_modeset(dev, radeon_crtc->crtc_id); radeon_crtc_load_lut(crtc); + radeon_crtc->enabled = true; break; case DRM_MODE_DPMS_STANDBY: case DRM_MODE_DPMS_SUSPEND: @@ -260,6 +261,7 @@ void atombios_crtc_dpms(struct drm_crtc *crtc, int mode) if (ASIC_IS_DCE3(rdev)) atombios_enable_crtc_memreq(crtc, ATOM_DISABLE); atombios_enable_crtc(crtc, ATOM_DISABLE); + radeon_crtc->enabled = false; break; } diff --git a/drivers/gpu/drm/radeon/r100.c b/drivers/gpu/drm/radeon/r100.c index b076b96f8b6c..a6b2aca36b47 100644 --- a/drivers/gpu/drm/radeon/r100.c +++ b/drivers/gpu/drm/radeon/r100.c @@ -67,41 +67,133 @@ MODULE_FIRMWARE(FIRMWARE_R520); * r100,rv100,rs100,rv200,rs200,r200,rv250,rs300,rv280 */ +void r100_get_power_state(struct radeon_device *rdev, + enum radeon_pm_action action) +{ + int i; + rdev->pm.can_upclock = true; + rdev->pm.can_downclock = true; + + switch (action) { + case PM_ACTION_MINIMUM: + rdev->pm.requested_power_state_index = 0; + rdev->pm.can_downclock = false; + break; + case PM_ACTION_DOWNCLOCK: + if (rdev->pm.current_power_state_index == 0) { + rdev->pm.requested_power_state_index = rdev->pm.current_power_state_index; + rdev->pm.can_downclock = false; + } else { + if (rdev->pm.active_crtc_count > 1) { + for (i = 0; i < rdev->pm.num_power_states; i++) { + if (rdev->pm.power_state[i].flags & RADEON_PM_SINGLE_DISPLAY_ONLY) + continue; + else if (i >= rdev->pm.current_power_state_index) { + rdev->pm.requested_power_state_index = rdev->pm.current_power_state_index; + break; + } else { + rdev->pm.requested_power_state_index = i; + break; + } + } + } else + rdev->pm.requested_power_state_index = + rdev->pm.current_power_state_index - 1; + } + break; + case PM_ACTION_UPCLOCK: + if (rdev->pm.current_power_state_index == (rdev->pm.num_power_states - 1)) { + rdev->pm.requested_power_state_index = rdev->pm.current_power_state_index; + rdev->pm.can_upclock = false; + } else { + if (rdev->pm.active_crtc_count > 1) { + for (i = (rdev->pm.num_power_states - 1); i >= 0; i--) { + if (rdev->pm.power_state[i].flags & RADEON_PM_SINGLE_DISPLAY_ONLY) + continue; + else if (i <= rdev->pm.current_power_state_index) { + rdev->pm.requested_power_state_index = rdev->pm.current_power_state_index; + break; + } else { + rdev->pm.requested_power_state_index = i; + break; + } + } + } else + rdev->pm.requested_power_state_index = + rdev->pm.current_power_state_index + 1; + } + break; + case PM_ACTION_NONE: + default: + DRM_ERROR("Requested mode for not defined action\n"); + return; + } + /* only one clock mode per power state */ + rdev->pm.requested_clock_mode_index = 0; + + DRM_INFO("Requested: e: %d m: %d p: %d\n", + rdev->pm.power_state[rdev->pm.requested_power_state_index]. + clock_info[rdev->pm.requested_clock_mode_index].sclk, + rdev->pm.power_state[rdev->pm.requested_power_state_index]. + clock_info[rdev->pm.requested_clock_mode_index].mclk, + rdev->pm.power_state[rdev->pm.requested_power_state_index]. + non_clock_info.pcie_lanes); +} + void r100_set_power_state(struct radeon_device *rdev) { - /* if *_clock_mode are the same, *_power_state are as well */ - if (rdev->pm.requested_clock_mode == rdev->pm.current_clock_mode) + u32 sclk, mclk; + + if (rdev->pm.current_power_state_index == rdev->pm.requested_power_state_index) return; - DRM_INFO("Setting: e: %d m: %d p: %d\n", - rdev->pm.requested_clock_mode->sclk, - rdev->pm.requested_clock_mode->mclk, - rdev->pm.requested_power_state->non_clock_info.pcie_lanes); + if (radeon_gui_idle(rdev)) { - /* set pcie lanes */ - /* TODO */ + sclk = rdev->pm.power_state[rdev->pm.requested_power_state_index]. + clock_info[rdev->pm.requested_clock_mode_index].sclk; + if (sclk > rdev->clock.default_sclk) + sclk = rdev->clock.default_sclk; - /* set voltage */ - /* TODO */ + mclk = rdev->pm.power_state[rdev->pm.requested_power_state_index]. + clock_info[rdev->pm.requested_clock_mode_index].mclk; + if (mclk > rdev->clock.default_mclk) + mclk = rdev->clock.default_mclk; + /* don't change the mclk with multiple crtcs */ + if (rdev->pm.active_crtc_count > 1) + mclk = rdev->clock.default_mclk; - /* set engine clock */ - radeon_sync_with_vblank(rdev); - radeon_pm_debug_check_in_vbl(rdev, false); - radeon_set_engine_clock(rdev, rdev->pm.requested_clock_mode->sclk); - radeon_pm_debug_check_in_vbl(rdev, true); + /* set pcie lanes */ + /* TODO */ + + /* set voltage */ + /* TODO */ + + /* set engine clock */ + if (sclk != rdev->pm.current_sclk) { + radeon_sync_with_vblank(rdev); + radeon_pm_debug_check_in_vbl(rdev, false); + radeon_set_engine_clock(rdev, sclk); + radeon_pm_debug_check_in_vbl(rdev, true); + rdev->pm.current_sclk = sclk; + DRM_INFO("Setting: e: %d\n", sclk); + } #if 0 - /* set memory clock */ - if (rdev->asic->set_memory_clock) { - radeon_sync_with_vblank(rdev); - radeon_pm_debug_check_in_vbl(rdev, false); - radeon_set_memory_clock(rdev, rdev->pm.requested_clock_mode->mclk); - radeon_pm_debug_check_in_vbl(rdev, true); - } + /* set memory clock */ + if (rdev->asic->set_memory_clock && (mclk != rdev->pm.current_mclk)) { + radeon_sync_with_vblank(rdev); + radeon_pm_debug_check_in_vbl(rdev, false); + radeon_set_memory_clock(rdev, mclk); + radeon_pm_debug_check_in_vbl(rdev, true); + rdev->pm.current_mclk = mclk; + DRM_INFO("Setting: m: %d\n", mclk); + } #endif - rdev->pm.current_power_state = rdev->pm.requested_power_state; - rdev->pm.current_clock_mode = rdev->pm.requested_clock_mode; + rdev->pm.current_power_state_index = rdev->pm.requested_power_state_index; + rdev->pm.current_clock_mode_index = rdev->pm.requested_clock_mode_index; + } else + DRM_INFO("GUI not idle!!!\n"); } bool r100_gui_idle(struct radeon_device *rdev) diff --git a/drivers/gpu/drm/radeon/r600.c b/drivers/gpu/drm/radeon/r600.c index c2d1946535ab..cc2797949ee5 100644 --- a/drivers/gpu/drm/radeon/r600.c +++ b/drivers/gpu/drm/radeon/r600.c @@ -92,41 +92,206 @@ void r600_gpu_init(struct radeon_device *rdev); void r600_fini(struct radeon_device *rdev); void r600_irq_disable(struct radeon_device *rdev); -void r600_set_power_state(struct radeon_device *rdev) +void r600_get_power_state(struct radeon_device *rdev, + enum radeon_pm_action action) { - /* if *_clock_mode are the same, *_power_state are as well */ - if (rdev->pm.requested_clock_mode == rdev->pm.current_clock_mode) - return; + int i; + + rdev->pm.can_upclock = true; + rdev->pm.can_downclock = true; + + /* power state array is low to high, default is first */ + if ((rdev->flags & RADEON_IS_IGP) || (rdev->family == CHIP_R600)) { + int min_power_state_index = 0; + + if (rdev->pm.num_power_states > 2) + min_power_state_index = 1; + + switch (action) { + case PM_ACTION_MINIMUM: + rdev->pm.requested_power_state_index = min_power_state_index; + rdev->pm.requested_clock_mode_index = 0; + rdev->pm.can_downclock = false; + break; + case PM_ACTION_DOWNCLOCK: + if (rdev->pm.current_power_state_index == min_power_state_index) { + rdev->pm.requested_power_state_index = rdev->pm.current_power_state_index; + rdev->pm.can_downclock = false; + } else { + if (rdev->pm.active_crtc_count > 1) { + for (i = 0; i < rdev->pm.num_power_states; i++) { + if (rdev->pm.power_state[i].flags & RADEON_PM_SINGLE_DISPLAY_ONLY) + continue; + else if (i >= rdev->pm.current_power_state_index) { + rdev->pm.requested_power_state_index = + rdev->pm.current_power_state_index; + break; + } else { + rdev->pm.requested_power_state_index = i; + break; + } + } + } else + rdev->pm.requested_power_state_index = + rdev->pm.current_power_state_index - 1; + } + rdev->pm.requested_clock_mode_index = 0; + break; + case PM_ACTION_UPCLOCK: + if (rdev->pm.current_power_state_index == (rdev->pm.num_power_states - 1)) { + rdev->pm.requested_power_state_index = rdev->pm.current_power_state_index; + rdev->pm.can_upclock = false; + } else { + if (rdev->pm.active_crtc_count > 1) { + for (i = (rdev->pm.num_power_states - 1); i >= 0; i--) { + if (rdev->pm.power_state[i].flags & RADEON_PM_SINGLE_DISPLAY_ONLY) + continue; + else if (i <= rdev->pm.current_power_state_index) { + rdev->pm.requested_power_state_index = + rdev->pm.current_power_state_index; + break; + } else { + rdev->pm.requested_power_state_index = i; + break; + } + } + } else + rdev->pm.requested_power_state_index = + rdev->pm.current_power_state_index + 1; + } + rdev->pm.requested_clock_mode_index = 0; + break; + case PM_ACTION_NONE: + default: + DRM_ERROR("Requested mode for not defined action\n"); + return; + } + } else { + /* XXX select a power state based on AC/DC, single/dualhead, etc. */ + /* for now just select the first power state and switch between clock modes */ + /* power state array is low to high, default is first (0) */ + if (rdev->pm.active_crtc_count > 1) { + rdev->pm.requested_power_state_index = -1; + /* start at 1 as we don't want the default mode */ + for (i = 1; i < rdev->pm.num_power_states; i++) { + if (rdev->pm.power_state[i].flags & RADEON_PM_SINGLE_DISPLAY_ONLY) + continue; + else if ((rdev->pm.power_state[i].type == POWER_STATE_TYPE_PERFORMANCE) || + (rdev->pm.power_state[i].type == POWER_STATE_TYPE_BATTERY)) { + rdev->pm.requested_power_state_index = i; + break; + } + } + /* if nothing selected, grab the default state. */ + if (rdev->pm.requested_power_state_index == -1) + rdev->pm.requested_power_state_index = 0; + } else + rdev->pm.requested_power_state_index = 1; + + switch (action) { + case PM_ACTION_MINIMUM: + rdev->pm.requested_clock_mode_index = 0; + rdev->pm.can_downclock = false; + break; + case PM_ACTION_DOWNCLOCK: + if (rdev->pm.requested_power_state_index == rdev->pm.current_power_state_index) { + if (rdev->pm.current_clock_mode_index == 0) { + rdev->pm.requested_clock_mode_index = 0; + rdev->pm.can_downclock = false; + } else + rdev->pm.requested_clock_mode_index = + rdev->pm.current_clock_mode_index - 1; + } else { + rdev->pm.requested_clock_mode_index = 0; + rdev->pm.can_downclock = false; + } + break; + case PM_ACTION_UPCLOCK: + if (rdev->pm.requested_power_state_index == rdev->pm.current_power_state_index) { + if (rdev->pm.current_clock_mode_index == + (rdev->pm.power_state[rdev->pm.requested_power_state_index].num_clock_modes - 1)) { + rdev->pm.requested_clock_mode_index = rdev->pm.current_clock_mode_index; + rdev->pm.can_upclock = false; + } else + rdev->pm.requested_clock_mode_index = + rdev->pm.current_clock_mode_index + 1; + } else { + rdev->pm.requested_clock_mode_index = + rdev->pm.power_state[rdev->pm.requested_power_state_index].num_clock_modes - 1; + rdev->pm.can_upclock = false; + } + break; + case PM_ACTION_NONE: + default: + DRM_ERROR("Requested mode for not defined action\n"); + return; + } + } - DRM_INFO("Setting: e: %d m: %d p: %d\n", - rdev->pm.requested_clock_mode->sclk, - rdev->pm.requested_clock_mode->mclk, - rdev->pm.requested_power_state->non_clock_info.pcie_lanes); + DRM_INFO("Requested: e: %d m: %d p: %d\n", + rdev->pm.power_state[rdev->pm.requested_power_state_index]. + clock_info[rdev->pm.requested_clock_mode_index].sclk, + rdev->pm.power_state[rdev->pm.requested_power_state_index]. + clock_info[rdev->pm.requested_clock_mode_index].mclk, + rdev->pm.power_state[rdev->pm.requested_power_state_index]. + non_clock_info.pcie_lanes); +} - /* set pcie lanes */ - /* TODO */ +void r600_set_power_state(struct radeon_device *rdev) +{ + u32 sclk, mclk; - /* set voltage */ - /* TODO */ + if ((rdev->pm.requested_clock_mode_index == rdev->pm.current_clock_mode_index) && + (rdev->pm.requested_power_state_index == rdev->pm.current_power_state_index)) + return; - /* set engine clock */ - radeon_sync_with_vblank(rdev); - radeon_pm_debug_check_in_vbl(rdev, false); - radeon_set_engine_clock(rdev, rdev->pm.requested_clock_mode->sclk); - radeon_pm_debug_check_in_vbl(rdev, true); + if (radeon_gui_idle(rdev)) { + + sclk = rdev->pm.power_state[rdev->pm.requested_power_state_index]. + clock_info[rdev->pm.requested_clock_mode_index].sclk; + if (sclk > rdev->clock.default_sclk) + sclk = rdev->clock.default_sclk; + + mclk = rdev->pm.power_state[rdev->pm.requested_power_state_index]. + clock_info[rdev->pm.requested_clock_mode_index].mclk; + if (mclk > rdev->clock.default_mclk) + mclk = rdev->clock.default_mclk; + /* don't change the mclk with multiple crtcs */ + if (rdev->pm.active_crtc_count > 1) + mclk = rdev->clock.default_mclk; + + /* set pcie lanes */ + /* TODO */ + + /* set voltage */ + /* TODO */ + + /* set engine clock */ + if (sclk != rdev->pm.current_sclk) { + radeon_sync_with_vblank(rdev); + radeon_pm_debug_check_in_vbl(rdev, false); + radeon_set_engine_clock(rdev, sclk); + radeon_pm_debug_check_in_vbl(rdev, true); + rdev->pm.current_sclk = sclk; + DRM_INFO("Setting: e: %d\n", sclk); + } #if 0 - /* set memory clock */ - if (rdev->asic->set_memory_clock) { - radeon_sync_with_vblank(rdev); - radeon_pm_debug_check_in_vbl(rdev, false); - radeon_set_memory_clock(rdev, rdev->pm.requested_clock_mode->mclk); - radeon_pm_debug_check_in_vbl(rdev, true); - } + /* set memory clock */ + if (rdev->asic->set_memory_clock && (mclk != rdev->pm.current_mclk)) { + radeon_sync_with_vblank(rdev); + radeon_pm_debug_check_in_vbl(rdev, false); + radeon_set_memory_clock(rdev, mclk); + radeon_pm_debug_check_in_vbl(rdev, true); + rdev->pm.current_mclk = mclk; + DRM_INFO("Setting: m: %d\n", mclk); + } #endif - rdev->pm.current_power_state = rdev->pm.requested_power_state; - rdev->pm.current_clock_mode = rdev->pm.requested_clock_mode; + rdev->pm.current_power_state_index = rdev->pm.requested_power_state_index; + rdev->pm.current_clock_mode_index = rdev->pm.requested_clock_mode_index; + } else + DRM_INFO("GUI not idle!!!\n"); } bool r600_gui_idle(struct radeon_device *rdev) diff --git a/drivers/gpu/drm/radeon/radeon.h b/drivers/gpu/drm/radeon/radeon.h index 11fe1d1444c2..b5eccc4094e8 100644 --- a/drivers/gpu/drm/radeon/radeon.h +++ b/drivers/gpu/drm/radeon/radeon.h @@ -672,6 +672,9 @@ struct radeon_pm_clock_info { u32 flags; }; +/* state flags */ +#define RADEON_PM_SINGLE_DISPLAY_ONLY (1 << 0) + struct radeon_power_state { enum radeon_pm_state_type type; /* XXX: use a define for num clock modes */ @@ -682,6 +685,8 @@ struct radeon_power_state { /* non clock info about this state */ struct radeon_pm_non_clock_info non_clock_info; bool voltage_drop_active; + /* standardized state flags */ + u32 flags; }; /* @@ -695,8 +700,10 @@ struct radeon_pm { enum radeon_pm_state state; enum radeon_pm_action planned_action; unsigned long action_timeout; - bool downclocked; - int active_crtcs; + bool can_upclock; + bool can_downclock; + u32 active_crtcs; + int active_crtc_count; int req_vblank; bool vblank_sync; bool gui_idle; @@ -716,11 +723,13 @@ struct radeon_pm { struct radeon_power_state power_state[8]; /* number of valid power states */ int num_power_states; - struct radeon_power_state *current_power_state; - struct radeon_pm_clock_info *current_clock_mode; - struct radeon_power_state *requested_power_state; - struct radeon_pm_clock_info *requested_clock_mode; - struct radeon_power_state *default_power_state; + int current_power_state_index; + int current_clock_mode_index; + int requested_power_state_index; + int requested_clock_mode_index; + int default_power_state_index; + u32 current_sclk; + u32 current_mclk; struct radeon_i2c_chan *i2c_bus; }; @@ -810,6 +819,7 @@ struct radeon_asic { */ void (*ioctl_wait_idle)(struct radeon_device *rdev, struct radeon_bo *bo); bool (*gui_idle)(struct radeon_device *rdev); + void (*get_power_state)(struct radeon_device *rdev, enum radeon_pm_action action); void (*set_power_state)(struct radeon_device *rdev); }; @@ -1218,6 +1228,7 @@ static inline void radeon_ring_write(struct radeon_device *rdev, uint32_t v) #define radeon_hpd_sense(rdev, hpd) (rdev)->asic->hpd_sense((rdev), (hpd)) #define radeon_hpd_set_polarity(rdev, hpd) (rdev)->asic->hpd_set_polarity((rdev), (hpd)) #define radeon_gui_idle(rdev) (rdev)->asic->gui_idle((rdev)) +#define radeon_get_power_state(rdev, a) (rdev)->asic->get_power_state((rdev), (a)) #define radeon_set_power_state(rdev) (rdev)->asic->set_power_state((rdev)) /* Common functions */ diff --git a/drivers/gpu/drm/radeon/radeon_asic.c b/drivers/gpu/drm/radeon/radeon_asic.c index 48893fbb6582..1053115ba652 100644 --- a/drivers/gpu/drm/radeon/radeon_asic.c +++ b/drivers/gpu/drm/radeon/radeon_asic.c @@ -166,6 +166,7 @@ static struct radeon_asic r100_asic = { .hpd_set_polarity = &r100_hpd_set_polarity, .ioctl_wait_idle = NULL, .gui_idle = &r100_gui_idle, + .get_power_state = &r100_get_power_state, .set_power_state = &r100_set_power_state, }; @@ -206,6 +207,7 @@ static struct radeon_asic r200_asic = { .hpd_set_polarity = &r100_hpd_set_polarity, .ioctl_wait_idle = NULL, .gui_idle = &r100_gui_idle, + .get_power_state = &r100_get_power_state, .set_power_state = &r100_set_power_state, }; @@ -247,6 +249,7 @@ static struct radeon_asic r300_asic = { .hpd_set_polarity = &r100_hpd_set_polarity, .ioctl_wait_idle = NULL, .gui_idle = &r100_gui_idle, + .get_power_state = &r100_get_power_state, .set_power_state = &r100_set_power_state, }; @@ -287,6 +290,7 @@ static struct radeon_asic r300_asic_pcie = { .hpd_set_polarity = &r100_hpd_set_polarity, .ioctl_wait_idle = NULL, .gui_idle = &r100_gui_idle, + .get_power_state = &r100_get_power_state, .set_power_state = &r100_set_power_state, }; @@ -328,6 +332,7 @@ static struct radeon_asic r420_asic = { .hpd_set_polarity = &r100_hpd_set_polarity, .ioctl_wait_idle = NULL, .gui_idle = &r100_gui_idle, + .get_power_state = &r100_get_power_state, .set_power_state = &r100_set_power_state, }; @@ -369,6 +374,7 @@ static struct radeon_asic rs400_asic = { .hpd_set_polarity = &r100_hpd_set_polarity, .ioctl_wait_idle = NULL, .gui_idle = &r100_gui_idle, + .get_power_state = &r100_get_power_state, .set_power_state = &r100_set_power_state, }; @@ -410,6 +416,7 @@ static struct radeon_asic rs600_asic = { .hpd_set_polarity = &rs600_hpd_set_polarity, .ioctl_wait_idle = NULL, .gui_idle = &r100_gui_idle, + .get_power_state = &r100_get_power_state, .set_power_state = &r100_set_power_state, }; @@ -451,6 +458,7 @@ static struct radeon_asic rs690_asic = { .hpd_set_polarity = &rs600_hpd_set_polarity, .ioctl_wait_idle = NULL, .gui_idle = &r100_gui_idle, + .get_power_state = &r100_get_power_state, .set_power_state = &r100_set_power_state, }; @@ -492,6 +500,7 @@ static struct radeon_asic rv515_asic = { .hpd_set_polarity = &rs600_hpd_set_polarity, .ioctl_wait_idle = NULL, .gui_idle = &r100_gui_idle, + .get_power_state = &r100_get_power_state, .set_power_state = &r100_set_power_state, }; @@ -533,6 +542,7 @@ static struct radeon_asic r520_asic = { .hpd_set_polarity = &rs600_hpd_set_polarity, .ioctl_wait_idle = NULL, .gui_idle = &r100_gui_idle, + .get_power_state = &r100_get_power_state, .set_power_state = &r100_set_power_state, }; @@ -573,6 +583,7 @@ static struct radeon_asic r600_asic = { .hpd_set_polarity = &r600_hpd_set_polarity, .ioctl_wait_idle = r600_ioctl_wait_idle, .gui_idle = &r600_gui_idle, + .get_power_state = &r600_get_power_state, .set_power_state = &r600_set_power_state, }; @@ -613,6 +624,7 @@ static struct radeon_asic rs780_asic = { .hpd_set_polarity = &r600_hpd_set_polarity, .ioctl_wait_idle = r600_ioctl_wait_idle, .gui_idle = &r600_gui_idle, + .get_power_state = &r600_get_power_state, .set_power_state = &r600_set_power_state, }; @@ -653,6 +665,7 @@ static struct radeon_asic rv770_asic = { .hpd_set_polarity = &r600_hpd_set_polarity, .ioctl_wait_idle = r600_ioctl_wait_idle, .gui_idle = &r600_gui_idle, + .get_power_state = &r600_get_power_state, .set_power_state = &r600_set_power_state, }; @@ -691,6 +704,7 @@ static struct radeon_asic evergreen_asic = { .hpd_sense = &evergreen_hpd_sense, .hpd_set_polarity = &evergreen_hpd_set_polarity, .gui_idle = &r600_gui_idle, + .get_power_state = &r600_get_power_state, .set_power_state = &r600_set_power_state, }; diff --git a/drivers/gpu/drm/radeon/radeon_asic.h b/drivers/gpu/drm/radeon/radeon_asic.h index 90d8e6dee52c..71b21bb4e5f3 100644 --- a/drivers/gpu/drm/radeon/radeon_asic.h +++ b/drivers/gpu/drm/radeon/radeon_asic.h @@ -128,6 +128,8 @@ void r100_set_common_regs(struct radeon_device *rdev); void r100_bm_disable(struct radeon_device *rdev); extern bool r100_gui_idle(struct radeon_device *rdev); extern void r100_set_power_state(struct radeon_device *rdev); +extern void r100_get_power_state(struct radeon_device *rdev, + enum radeon_pm_action action); /* * r200,rv250,rs300,rv280 @@ -274,6 +276,8 @@ void r600_hpd_set_polarity(struct radeon_device *rdev, extern void r600_ioctl_wait_idle(struct radeon_device *rdev, struct radeon_bo *bo); extern bool r600_gui_idle(struct radeon_device *rdev); extern void r600_set_power_state(struct radeon_device *rdev); +extern void r600_get_power_state(struct radeon_device *rdev, + enum radeon_pm_action action); /* * rv770,rv730,rv710,rv740 diff --git a/drivers/gpu/drm/radeon/radeon_atombios.c b/drivers/gpu/drm/radeon/radeon_atombios.c index aa0a973a8af2..dbfb837d224c 100644 --- a/drivers/gpu/drm/radeon/radeon_atombios.c +++ b/drivers/gpu/drm/radeon/radeon_atombios.c @@ -1489,7 +1489,7 @@ void radeon_atombios_get_power_modes(struct radeon_device *rdev) int state_index = 0, mode_index = 0; struct radeon_i2c_bus_rec i2c_bus; - rdev->pm.default_power_state = NULL; + rdev->pm.default_power_state_index = -1; if (atom_parse_data_header(mode_info->atom_context, index, NULL, &frev, &crev, &data_offset)) { @@ -1520,12 +1520,6 @@ void radeon_atombios_get_power_modes(struct radeon_device *rdev) if ((rdev->pm.power_state[state_index].clock_info[0].mclk == 0) || (rdev->pm.power_state[state_index].clock_info[0].sclk == 0)) continue; - /* skip overclock modes for now */ - if ((rdev->pm.power_state[state_index].clock_info[0].mclk > - rdev->clock.default_mclk + RADEON_MODE_OVERCLOCK_MARGIN) || - (rdev->pm.power_state[state_index].clock_info[0].sclk > - rdev->clock.default_sclk + RADEON_MODE_OVERCLOCK_MARGIN)) - continue; rdev->pm.power_state[state_index].non_clock_info.pcie_lanes = power_info->info.asPowerPlayInfo[i].ucNumPciELanes; misc = le32_to_cpu(power_info->info.asPowerPlayInfo[i].ulMiscInfo); @@ -1547,6 +1541,7 @@ void radeon_atombios_get_power_modes(struct radeon_device *rdev) rdev->pm.power_state[state_index].clock_info[0].voltage.vddc_id = power_info->info.asPowerPlayInfo[i].ucVoltageDropIndex; } + rdev->pm.power_state[state_index].flags = RADEON_PM_SINGLE_DISPLAY_ONLY; /* order matters! */ if (misc & ATOM_PM_MISCINFO_POWER_SAVING_MODE) rdev->pm.power_state[state_index].type = @@ -1560,15 +1555,20 @@ void radeon_atombios_get_power_modes(struct radeon_device *rdev) if (misc & ATOM_PM_MISCINFO_LOAD_BALANCE_EN) rdev->pm.power_state[state_index].type = POWER_STATE_TYPE_BALANCED; - if (misc & ATOM_PM_MISCINFO_3D_ACCELERATION_EN) + if (misc & ATOM_PM_MISCINFO_3D_ACCELERATION_EN) { rdev->pm.power_state[state_index].type = POWER_STATE_TYPE_PERFORMANCE; + rdev->pm.power_state[state_index].flags &= + ~RADEON_PM_SINGLE_DISPLAY_ONLY; + } if (misc & ATOM_PM_MISCINFO_DRIVER_DEFAULT_MODE) { rdev->pm.power_state[state_index].type = POWER_STATE_TYPE_DEFAULT; - rdev->pm.default_power_state = &rdev->pm.power_state[state_index]; + rdev->pm.default_power_state_index = state_index; rdev->pm.power_state[state_index].default_clock_mode = &rdev->pm.power_state[state_index].clock_info[0]; + rdev->pm.power_state[state_index].flags &= + ~RADEON_PM_SINGLE_DISPLAY_ONLY; } state_index++; break; @@ -1582,12 +1582,6 @@ void radeon_atombios_get_power_modes(struct radeon_device *rdev) if ((rdev->pm.power_state[state_index].clock_info[0].mclk == 0) || (rdev->pm.power_state[state_index].clock_info[0].sclk == 0)) continue; - /* skip overclock modes for now */ - if ((rdev->pm.power_state[state_index].clock_info[0].mclk > - rdev->clock.default_mclk + RADEON_MODE_OVERCLOCK_MARGIN) || - (rdev->pm.power_state[state_index].clock_info[0].sclk > - rdev->clock.default_sclk + RADEON_MODE_OVERCLOCK_MARGIN)) - continue; rdev->pm.power_state[state_index].non_clock_info.pcie_lanes = power_info->info_2.asPowerPlayInfo[i].ucNumPciELanes; misc = le32_to_cpu(power_info->info_2.asPowerPlayInfo[i].ulMiscInfo); @@ -1610,6 +1604,7 @@ void radeon_atombios_get_power_modes(struct radeon_device *rdev) rdev->pm.power_state[state_index].clock_info[0].voltage.vddc_id = power_info->info_2.asPowerPlayInfo[i].ucVoltageDropIndex; } + rdev->pm.power_state[state_index].flags = RADEON_PM_SINGLE_DISPLAY_ONLY; /* order matters! */ if (misc & ATOM_PM_MISCINFO_POWER_SAVING_MODE) rdev->pm.power_state[state_index].type = @@ -1623,18 +1618,26 @@ void radeon_atombios_get_power_modes(struct radeon_device *rdev) if (misc & ATOM_PM_MISCINFO_LOAD_BALANCE_EN) rdev->pm.power_state[state_index].type = POWER_STATE_TYPE_BALANCED; - if (misc & ATOM_PM_MISCINFO_3D_ACCELERATION_EN) + if (misc & ATOM_PM_MISCINFO_3D_ACCELERATION_EN) { rdev->pm.power_state[state_index].type = POWER_STATE_TYPE_PERFORMANCE; + rdev->pm.power_state[state_index].flags &= + ~RADEON_PM_SINGLE_DISPLAY_ONLY; + } if (misc2 & ATOM_PM_MISCINFO2_SYSTEM_AC_LITE_MODE) rdev->pm.power_state[state_index].type = POWER_STATE_TYPE_BALANCED; + if (misc2 & ATOM_PM_MISCINFO2_MULTI_DISPLAY_SUPPORT) + rdev->pm.power_state[state_index].flags &= + ~RADEON_PM_SINGLE_DISPLAY_ONLY; if (misc & ATOM_PM_MISCINFO_DRIVER_DEFAULT_MODE) { rdev->pm.power_state[state_index].type = POWER_STATE_TYPE_DEFAULT; - rdev->pm.default_power_state = &rdev->pm.power_state[state_index]; + rdev->pm.default_power_state_index = state_index; rdev->pm.power_state[state_index].default_clock_mode = &rdev->pm.power_state[state_index].clock_info[0]; + rdev->pm.power_state[state_index].flags &= + ~RADEON_PM_SINGLE_DISPLAY_ONLY; } state_index++; break; @@ -1648,12 +1651,6 @@ void radeon_atombios_get_power_modes(struct radeon_device *rdev) if ((rdev->pm.power_state[state_index].clock_info[0].mclk == 0) || (rdev->pm.power_state[state_index].clock_info[0].sclk == 0)) continue; - /* skip overclock modes for now */ - if ((rdev->pm.power_state[state_index].clock_info[0].mclk > - rdev->clock.default_mclk + RADEON_MODE_OVERCLOCK_MARGIN) || - (rdev->pm.power_state[state_index].clock_info[0].sclk > - rdev->clock.default_sclk + RADEON_MODE_OVERCLOCK_MARGIN)) - continue; rdev->pm.power_state[state_index].non_clock_info.pcie_lanes = power_info->info_3.asPowerPlayInfo[i].ucNumPciELanes; misc = le32_to_cpu(power_info->info_3.asPowerPlayInfo[i].ulMiscInfo); @@ -1682,6 +1679,7 @@ void radeon_atombios_get_power_modes(struct radeon_device *rdev) power_info->info_3.asPowerPlayInfo[i].ucVDDCI_VoltageDropIndex; } } + rdev->pm.power_state[state_index].flags = RADEON_PM_SINGLE_DISPLAY_ONLY; /* order matters! */ if (misc & ATOM_PM_MISCINFO_POWER_SAVING_MODE) rdev->pm.power_state[state_index].type = @@ -1695,16 +1693,19 @@ void radeon_atombios_get_power_modes(struct radeon_device *rdev) if (misc & ATOM_PM_MISCINFO_LOAD_BALANCE_EN) rdev->pm.power_state[state_index].type = POWER_STATE_TYPE_BALANCED; - if (misc & ATOM_PM_MISCINFO_3D_ACCELERATION_EN) + if (misc & ATOM_PM_MISCINFO_3D_ACCELERATION_EN) { rdev->pm.power_state[state_index].type = POWER_STATE_TYPE_PERFORMANCE; + rdev->pm.power_state[state_index].flags &= + ~RADEON_PM_SINGLE_DISPLAY_ONLY; + } if (misc2 & ATOM_PM_MISCINFO2_SYSTEM_AC_LITE_MODE) rdev->pm.power_state[state_index].type = POWER_STATE_TYPE_BALANCED; if (misc & ATOM_PM_MISCINFO_DRIVER_DEFAULT_MODE) { rdev->pm.power_state[state_index].type = POWER_STATE_TYPE_DEFAULT; - rdev->pm.default_power_state = &rdev->pm.power_state[state_index]; + rdev->pm.default_power_state_index = state_index; rdev->pm.power_state[state_index].default_clock_mode = &rdev->pm.power_state[state_index].clock_info[0]; } @@ -1713,12 +1714,14 @@ void radeon_atombios_get_power_modes(struct radeon_device *rdev) } } /* last mode is usually default */ - if (!rdev->pm.default_power_state) { + if (rdev->pm.default_power_state_index == -1) { rdev->pm.power_state[state_index - 1].type = POWER_STATE_TYPE_DEFAULT; - rdev->pm.default_power_state = &rdev->pm.power_state[state_index - 1]; + rdev->pm.default_power_state_index = state_index - 1; rdev->pm.power_state[state_index - 1].default_clock_mode = &rdev->pm.power_state[state_index - 1].clock_info[0]; + rdev->pm.power_state[state_index].flags &= + ~RADEON_PM_SINGLE_DISPLAY_ONLY; } } else { /* add the i2c bus for thermal/fan chip */ @@ -1774,10 +1777,6 @@ void radeon_atombios_get_power_modes(struct radeon_device *rdev) /* skip invalid modes */ if (rdev->pm.power_state[state_index].clock_info[mode_index].sclk == 0) continue; - /* skip overclock modes for now */ - if (rdev->pm.power_state[state_index].clock_info[mode_index].sclk > - rdev->clock.default_sclk + RADEON_MODE_OVERCLOCK_MARGIN) - continue; rdev->pm.power_state[state_index].clock_info[mode_index].voltage.type = VOLTAGE_SW; rdev->pm.power_state[state_index].clock_info[mode_index].voltage.voltage = @@ -1801,12 +1800,6 @@ void radeon_atombios_get_power_modes(struct radeon_device *rdev) if ((rdev->pm.power_state[state_index].clock_info[mode_index].mclk == 0) || (rdev->pm.power_state[state_index].clock_info[mode_index].sclk == 0)) continue; - /* skip overclock modes for now */ - if ((rdev->pm.power_state[state_index].clock_info[mode_index].mclk > - rdev->clock.default_mclk + RADEON_MODE_OVERCLOCK_MARGIN) || - (rdev->pm.power_state[state_index].clock_info[mode_index].sclk > - rdev->clock.default_sclk + RADEON_MODE_OVERCLOCK_MARGIN)) - continue; rdev->pm.power_state[state_index].clock_info[mode_index].voltage.type = VOLTAGE_SW; rdev->pm.power_state[state_index].clock_info[mode_index].voltage.voltage = @@ -1831,12 +1824,6 @@ void radeon_atombios_get_power_modes(struct radeon_device *rdev) if ((rdev->pm.power_state[state_index].clock_info[mode_index].mclk == 0) || (rdev->pm.power_state[state_index].clock_info[mode_index].sclk == 0)) continue; - /* skip overclock modes for now */ - if ((rdev->pm.power_state[state_index].clock_info[mode_index].mclk > - rdev->clock.default_mclk + RADEON_MODE_OVERCLOCK_MARGIN) || - (rdev->pm.power_state[state_index].clock_info[mode_index].sclk > - rdev->clock.default_sclk + RADEON_MODE_OVERCLOCK_MARGIN)) - continue; rdev->pm.power_state[state_index].clock_info[mode_index].voltage.type = VOLTAGE_SW; rdev->pm.power_state[state_index].clock_info[mode_index].voltage.voltage = @@ -1865,10 +1852,14 @@ void radeon_atombios_get_power_modes(struct radeon_device *rdev) POWER_STATE_TYPE_PERFORMANCE; break; } + rdev->pm.power_state[state_index].flags = 0; + if (misc & ATOM_PPLIB_SINGLE_DISPLAY_ONLY) + rdev->pm.power_state[state_index].flags |= + RADEON_PM_SINGLE_DISPLAY_ONLY; if (misc2 & ATOM_PPLIB_CLASSIFICATION_BOOT) { rdev->pm.power_state[state_index].type = POWER_STATE_TYPE_DEFAULT; - rdev->pm.default_power_state = &rdev->pm.power_state[state_index]; + rdev->pm.default_power_state_index = state_index; rdev->pm.power_state[state_index].default_clock_mode = &rdev->pm.power_state[state_index].clock_info[mode_index - 1]; } @@ -1876,10 +1867,10 @@ void radeon_atombios_get_power_modes(struct radeon_device *rdev) } } /* first mode is usually default */ - if (!rdev->pm.default_power_state) { + if (rdev->pm.default_power_state_index == -1) { rdev->pm.power_state[0].type = POWER_STATE_TYPE_DEFAULT; - rdev->pm.default_power_state = &rdev->pm.power_state[0]; + rdev->pm.default_power_state_index = 0; rdev->pm.power_state[0].default_clock_mode = &rdev->pm.power_state[0].clock_info[0]; } @@ -1898,15 +1889,15 @@ void radeon_atombios_get_power_modes(struct radeon_device *rdev) rdev->pm.power_state[state_index].non_clock_info.pcie_lanes = radeon_get_pcie_lanes(rdev); else rdev->pm.power_state[state_index].non_clock_info.pcie_lanes = 16; - rdev->pm.default_power_state = &rdev->pm.power_state[state_index]; + rdev->pm.default_power_state_index = state_index; + rdev->pm.power_state[state_index].flags = 0; state_index++; } rdev->pm.num_power_states = state_index; - rdev->pm.current_power_state = rdev->pm.default_power_state; - rdev->pm.current_clock_mode = - rdev->pm.default_power_state->default_clock_mode; + rdev->pm.current_power_state_index = rdev->pm.default_power_state_index; + rdev->pm.current_clock_mode_index = 0; } void radeon_atom_set_clock_gating(struct radeon_device *rdev, int enable) diff --git a/drivers/gpu/drm/radeon/radeon_combios.c b/drivers/gpu/drm/radeon/radeon_combios.c index 44198581ba9e..6a9ec8511261 100644 --- a/drivers/gpu/drm/radeon/radeon_combios.c +++ b/drivers/gpu/drm/radeon/radeon_combios.c @@ -2368,7 +2368,7 @@ void radeon_combios_get_power_modes(struct radeon_device *rdev) u8 rev, blocks, tmp; int state_index = 0; - rdev->pm.default_power_state = NULL; + rdev->pm.default_power_state_index = -1; if (rdev->flags & RADEON_IS_MOBILITY) { offset = combios_get_table_offset(dev, COMBIOS_POWERPLAY_INFO_TABLE); @@ -2441,6 +2441,7 @@ void radeon_combios_get_power_modes(struct radeon_device *rdev) if (rev > 6) rdev->pm.power_state[state_index].non_clock_info.pcie_lanes = RBIOS8(offset + 0x5 + 0x10); + rdev->pm.power_state[state_index].flags = RADEON_PM_SINGLE_DISPLAY_ONLY; state_index++; } else { /* XXX figure out some good default low power mode for mobility cards w/out power tables */ @@ -2462,12 +2463,12 @@ default_mode: rdev->pm.power_state[state_index].non_clock_info.pcie_lanes = radeon_get_pcie_lanes(rdev); else rdev->pm.power_state[state_index].non_clock_info.pcie_lanes = 16; - rdev->pm.default_power_state = &rdev->pm.power_state[state_index]; + rdev->pm.power_state[state_index].flags = 0; + rdev->pm.default_power_state_index = state_index; rdev->pm.num_power_states = state_index + 1; - rdev->pm.current_power_state = rdev->pm.default_power_state; - rdev->pm.current_clock_mode = - rdev->pm.default_power_state->default_clock_mode; + rdev->pm.current_power_state_index = rdev->pm.default_power_state_index; + rdev->pm.current_clock_mode_index = 0; } void radeon_external_tmds_setup(struct drm_encoder *encoder) diff --git a/drivers/gpu/drm/radeon/radeon_legacy_crtc.c b/drivers/gpu/drm/radeon/radeon_legacy_crtc.c index 60c0dcb8e11e..f4f9cb297e36 100644 --- a/drivers/gpu/drm/radeon/radeon_legacy_crtc.c +++ b/drivers/gpu/drm/radeon/radeon_legacy_crtc.c @@ -323,6 +323,7 @@ void radeon_crtc_dpms(struct drm_crtc *crtc, int mode) } drm_vblank_post_modeset(dev, radeon_crtc->crtc_id); radeon_crtc_load_lut(crtc); + radeon_crtc->enabled = true; break; case DRM_MODE_DPMS_STANDBY: case DRM_MODE_DPMS_SUSPEND: @@ -335,6 +336,7 @@ void radeon_crtc_dpms(struct drm_crtc *crtc, int mode) RADEON_CRTC_DISP_REQ_EN_B)); WREG32_P(RADEON_CRTC_EXT_CNTL, mask, ~mask); } + radeon_crtc->enabled = false; break; } diff --git a/drivers/gpu/drm/radeon/radeon_pm.c b/drivers/gpu/drm/radeon/radeon_pm.c index 129956d003a4..10ef8924799d 100644 --- a/drivers/gpu/drm/radeon/radeon_pm.c +++ b/drivers/gpu/drm/radeon/radeon_pm.c @@ -56,7 +56,7 @@ static void radeon_print_power_mode_info(struct radeon_device *rdev) DRM_INFO("%d Power State(s)\n", rdev->pm.num_power_states); for (i = 0; i < rdev->pm.num_power_states; i++) { - if (rdev->pm.default_power_state == &rdev->pm.power_state[i]) + if (rdev->pm.default_power_state_index == i) is_default = true; else is_default = false; @@ -65,6 +65,8 @@ static void radeon_print_power_mode_info(struct radeon_device *rdev) is_default ? "(default)" : ""); if ((rdev->flags & RADEON_IS_PCIE) && !(rdev->flags & RADEON_IS_IGP)) DRM_INFO("\t%d PCIE Lanes\n", rdev->pm.power_state[i].non_clock_info.pcie_lanes); + if (rdev->pm.power_state[i].flags & RADEON_PM_SINGLE_DISPLAY_ONLY) + DRM_INFO("\tSingle display only\n"); DRM_INFO("\t%d Clock Mode(s)\n", rdev->pm.power_state[i].num_clock_modes); for (j = 0; j < rdev->pm.power_state[i].num_clock_modes; j++) { if (rdev->flags & RADEON_IS_IGP) @@ -80,106 +82,6 @@ static void radeon_print_power_mode_info(struct radeon_device *rdev) } } -static struct radeon_power_state * radeon_pick_power_state(struct radeon_device *rdev, - enum radeon_pm_state_type type) -{ - int i, j; - enum radeon_pm_state_type wanted_types[2]; - int wanted_count; - - switch (type) { - case POWER_STATE_TYPE_DEFAULT: - default: - return rdev->pm.default_power_state; - case POWER_STATE_TYPE_POWERSAVE: - if (rdev->flags & RADEON_IS_MOBILITY) { - wanted_types[0] = POWER_STATE_TYPE_POWERSAVE; - wanted_types[1] = POWER_STATE_TYPE_BATTERY; - wanted_count = 2; - } else { - wanted_types[0] = POWER_STATE_TYPE_PERFORMANCE; - wanted_count = 1; - } - break; - case POWER_STATE_TYPE_BATTERY: - if (rdev->flags & RADEON_IS_MOBILITY) { - wanted_types[0] = POWER_STATE_TYPE_BATTERY; - wanted_types[1] = POWER_STATE_TYPE_POWERSAVE; - wanted_count = 2; - } else { - wanted_types[0] = POWER_STATE_TYPE_PERFORMANCE; - wanted_count = 1; - } - break; - case POWER_STATE_TYPE_BALANCED: - case POWER_STATE_TYPE_PERFORMANCE: - wanted_types[0] = type; - wanted_count = 1; - break; - } - - for (i = 0; i < wanted_count; i++) { - for (j = 0; j < rdev->pm.num_power_states; j++) { - if (rdev->pm.power_state[j].type == wanted_types[i]) - return &rdev->pm.power_state[j]; - } - } - - return rdev->pm.default_power_state; -} - -static struct radeon_pm_clock_info * radeon_pick_clock_mode(struct radeon_device *rdev, - struct radeon_power_state *power_state, - enum radeon_pm_clock_mode_type type) -{ - switch (type) { - case POWER_MODE_TYPE_DEFAULT: - default: - return power_state->default_clock_mode; - case POWER_MODE_TYPE_LOW: - return &power_state->clock_info[0]; - case POWER_MODE_TYPE_MID: - if (power_state->num_clock_modes > 2) - return &power_state->clock_info[1]; - else - return &power_state->clock_info[0]; - break; - case POWER_MODE_TYPE_HIGH: - return &power_state->clock_info[power_state->num_clock_modes - 1]; - } - -} - -static void radeon_get_power_state(struct radeon_device *rdev, - enum radeon_pm_action action) -{ - switch (action) { - case PM_ACTION_MINIMUM: - rdev->pm.requested_power_state = radeon_pick_power_state(rdev, POWER_STATE_TYPE_BATTERY); - rdev->pm.requested_clock_mode = - radeon_pick_clock_mode(rdev, rdev->pm.requested_power_state, POWER_MODE_TYPE_LOW); - break; - case PM_ACTION_DOWNCLOCK: - rdev->pm.requested_power_state = radeon_pick_power_state(rdev, POWER_STATE_TYPE_POWERSAVE); - rdev->pm.requested_clock_mode = - radeon_pick_clock_mode(rdev, rdev->pm.requested_power_state, POWER_MODE_TYPE_MID); - break; - case PM_ACTION_UPCLOCK: - rdev->pm.requested_power_state = radeon_pick_power_state(rdev, POWER_STATE_TYPE_DEFAULT); - rdev->pm.requested_clock_mode = - radeon_pick_clock_mode(rdev, rdev->pm.requested_power_state, POWER_MODE_TYPE_HIGH); - break; - case PM_ACTION_NONE: - default: - DRM_ERROR("Requested mode for not defined action\n"); - return; - } - DRM_INFO("Requested: e: %d m: %d p: %d\n", - rdev->pm.requested_clock_mode->sclk, - rdev->pm.requested_clock_mode->mclk, - rdev->pm.requested_power_state->non_clock_info.pcie_lanes); -} - void radeon_sync_with_vblank(struct radeon_device *rdev) { if (rdev->pm.active_crtcs) { @@ -194,7 +96,8 @@ int radeon_pm_init(struct radeon_device *rdev) { rdev->pm.state = PM_STATE_DISABLED; rdev->pm.planned_action = PM_ACTION_NONE; - rdev->pm.downclocked = false; + rdev->pm.can_upclock = true; + rdev->pm.can_downclock = true; if (rdev->bios) { if (rdev->is_atom_bios) @@ -229,9 +132,8 @@ void radeon_pm_fini(struct radeon_device *rdev) void radeon_pm_compute_clocks(struct radeon_device *rdev) { struct drm_device *ddev = rdev->ddev; - struct drm_connector *connector; + struct drm_crtc *crtc; struct radeon_crtc *radeon_crtc; - int count = 0; if (rdev->pm.state == PM_STATE_DISABLED) return; @@ -239,29 +141,27 @@ void radeon_pm_compute_clocks(struct radeon_device *rdev) mutex_lock(&rdev->pm.mutex); rdev->pm.active_crtcs = 0; - list_for_each_entry(connector, - &ddev->mode_config.connector_list, head) { - if (connector->encoder && - connector->encoder->crtc && - connector->dpms != DRM_MODE_DPMS_OFF) { - radeon_crtc = to_radeon_crtc(connector->encoder->crtc); + rdev->pm.active_crtc_count = 0; + list_for_each_entry(crtc, + &ddev->mode_config.crtc_list, head) { + radeon_crtc = to_radeon_crtc(crtc); + if (radeon_crtc->enabled) { rdev->pm.active_crtcs |= (1 << radeon_crtc->crtc_id); - ++count; + rdev->pm.active_crtc_count++; } } - if (count > 1) { + if (rdev->pm.active_crtc_count > 1) { if (rdev->pm.state == PM_STATE_ACTIVE) { cancel_delayed_work(&rdev->pm.idle_work); rdev->pm.state = PM_STATE_PAUSED; rdev->pm.planned_action = PM_ACTION_UPCLOCK; - if (rdev->pm.downclocked) - radeon_pm_set_clocks(rdev); + radeon_pm_set_clocks(rdev); DRM_DEBUG("radeon: dynamic power management deactivated\n"); } - } else if (count == 1) { + } else if (rdev->pm.active_crtc_count == 1) { /* TODO: Increase clocks if needed for current mode */ if (rdev->pm.state == PM_STATE_MINIMUM) { @@ -271,15 +171,13 @@ void radeon_pm_compute_clocks(struct radeon_device *rdev) queue_delayed_work(rdev->wq, &rdev->pm.idle_work, msecs_to_jiffies(RADEON_IDLE_LOOP_MS)); - } - else if (rdev->pm.state == PM_STATE_PAUSED) { + } else if (rdev->pm.state == PM_STATE_PAUSED) { rdev->pm.state = PM_STATE_ACTIVE; queue_delayed_work(rdev->wq, &rdev->pm.idle_work, msecs_to_jiffies(RADEON_IDLE_LOOP_MS)); DRM_DEBUG("radeon: dynamic power management activated\n"); } - } - else { /* count == 0 */ + } else { /* count == 0 */ if (rdev->pm.state != PM_STATE_MINIMUM) { cancel_delayed_work(&rdev->pm.idle_work); @@ -359,19 +257,6 @@ bool radeon_pm_debug_check_in_vbl(struct radeon_device *rdev, bool finish) static void radeon_pm_set_clocks_locked(struct radeon_device *rdev) { /*radeon_fence_wait_last(rdev);*/ - switch (rdev->pm.planned_action) { - case PM_ACTION_UPCLOCK: - rdev->pm.downclocked = false; - break; - case PM_ACTION_DOWNCLOCK: - rdev->pm.downclocked = true; - break; - case PM_ACTION_MINIMUM: - break; - case PM_ACTION_NONE: - DRM_ERROR("%s: PM_ACTION_NONE\n", __func__); - break; - } radeon_set_power_state(rdev); rdev->pm.planned_action = PM_ACTION_NONE; @@ -437,7 +322,7 @@ static void radeon_pm_idle_work_handler(struct work_struct *work) if (rdev->pm.planned_action == PM_ACTION_DOWNCLOCK) { rdev->pm.planned_action = PM_ACTION_NONE; } else if (rdev->pm.planned_action == PM_ACTION_NONE && - rdev->pm.downclocked) { + rdev->pm.can_upclock) { rdev->pm.planned_action = PM_ACTION_UPCLOCK; rdev->pm.action_timeout = jiffies + @@ -447,7 +332,7 @@ static void radeon_pm_idle_work_handler(struct work_struct *work) if (rdev->pm.planned_action == PM_ACTION_UPCLOCK) { rdev->pm.planned_action = PM_ACTION_NONE; } else if (rdev->pm.planned_action == PM_ACTION_NONE && - !rdev->pm.downclocked) { + rdev->pm.can_downclock) { rdev->pm.planned_action = PM_ACTION_DOWNCLOCK; rdev->pm.action_timeout = jiffies + -- cgit v1.2.3 From c00f53be5ec70038d7a34f64872df51dabfc5a5b Mon Sep 17 00:00:00 2001 From: Alex Deucher Date: Mon, 22 Mar 2010 13:34:22 -0400 Subject: drm/radeon/kms/pm: update display watermarks with power state changes Signed-off-by: Alex Deucher Signed-off-by: Dave Airlie --- drivers/gpu/drm/radeon/radeon_pm.c | 5 +++++ 1 file changed, 5 insertions(+) (limited to 'drivers/gpu/drm/radeon') diff --git a/drivers/gpu/drm/radeon/radeon_pm.c b/drivers/gpu/drm/radeon/radeon_pm.c index 10ef8924799d..a137ee2f722c 100644 --- a/drivers/gpu/drm/radeon/radeon_pm.c +++ b/drivers/gpu/drm/radeon/radeon_pm.c @@ -293,6 +293,11 @@ static void radeon_pm_set_clocks(struct radeon_device *rdev) } } + /* update display watermarks based on new power state */ + radeon_update_bandwidth_info(rdev); + if (rdev->pm.active_crtc_count) + radeon_bandwidth_update(rdev); + mutex_unlock(&rdev->cp.mutex); } -- cgit v1.2.3 From 678e7dfa9e1bb0d1ad31b7cddce58fc3b67cfb27 Mon Sep 17 00:00:00 2001 From: Alex Deucher Date: Thu, 22 Apr 2010 14:17:56 -0400 Subject: drm/radeon/kms/atom: load hwmon drivers Hook the atom table parsing up to module loading, so we can automatically load the appropriate hwmon drivers. Based on initial patch for r6xx from Matthew Garrett Signed-off-by: Alex Deucher Signed-off-by: Dave Airlie --- drivers/gpu/drm/radeon/radeon_atombios.c | 69 ++++++++++++++++++++------------ 1 file changed, 43 insertions(+), 26 deletions(-) (limited to 'drivers/gpu/drm/radeon') diff --git a/drivers/gpu/drm/radeon/radeon_atombios.c b/drivers/gpu/drm/radeon/radeon_atombios.c index dbfb837d224c..a0a99b66af82 100644 --- a/drivers/gpu/drm/radeon/radeon_atombios.c +++ b/drivers/gpu/drm/radeon/radeon_atombios.c @@ -1442,29 +1442,29 @@ radeon_atombios_get_tv_dac_info(struct radeon_encoder *encoder) static const char *thermal_controller_names[] = { "NONE", - "LM63", - "ADM1032", - "ADM1030", - "MUA6649", - "LM64", - "F75375", - "ASC7512", + "lm63", + "adm1032", + "adm1030", + "max6649", + "lm64", + "f75375", + "asc7xxx", }; static const char *pp_lib_thermal_controller_names[] = { "NONE", - "LM63", - "ADM1032", - "ADM1030", - "MUA6649", - "LM64", - "F75375", + "lm63", + "adm1032", + "adm1030", + "max6649", + "lm64", + "f75375", "RV6xx", "RV770", - "ADT7473", + "adt7473", "External GPIO", "Evergreen", - "ADT7473 with internal", + "adt7473 with internal", }; @@ -1502,6 +1502,14 @@ void radeon_atombios_get_power_modes(struct radeon_device *rdev) power_info->info.ucOverdriveControllerAddress >> 1); i2c_bus = radeon_lookup_i2c_gpio(rdev, power_info->info.ucOverdriveI2cLine); rdev->pm.i2c_bus = radeon_i2c_create(rdev->ddev, &i2c_bus, "Thermal"); + if (rdev->pm.i2c_bus) { + struct i2c_board_info info = { }; + const char *name = thermal_controller_names[power_info->info. + ucOverdriveThermalController]; + info.addr = power_info->info.ucOverdriveControllerAddress >> 1; + strlcpy(info.type, name, sizeof(info.type)); + i2c_new_device(&rdev->pm.i2c_bus->adapter, &info); + } } num_modes = power_info->info.ucNumOfPowerModeEntries; if (num_modes > ATOM_MAX_NUMBEROF_POWER_BLOCK) @@ -1726,26 +1734,35 @@ void radeon_atombios_get_power_modes(struct radeon_device *rdev) } else { /* add the i2c bus for thermal/fan chip */ /* no support for internal controller yet */ - if (power_info->info_4.sThermalController.ucType > 0) { - if ((power_info->info_4.sThermalController.ucType == ATOM_PP_THERMALCONTROLLER_RV6xx) || - (power_info->info_4.sThermalController.ucType == ATOM_PP_THERMALCONTROLLER_RV770) || - (power_info->info_4.sThermalController.ucType == ATOM_PP_THERMALCONTROLLER_EVERGREEN)) { + ATOM_PPLIB_THERMALCONTROLLER *controller = &power_info->info_4.sThermalController; + if (controller->ucType > 0) { + if ((controller->ucType == ATOM_PP_THERMALCONTROLLER_RV6xx) || + (controller->ucType == ATOM_PP_THERMALCONTROLLER_RV770) || + (controller->ucType == ATOM_PP_THERMALCONTROLLER_EVERGREEN)) { DRM_INFO("Internal thermal controller %s fan control\n", - (power_info->info_4.sThermalController.ucFanParameters & + (controller->ucFanParameters & ATOM_PP_FANPARAMETERS_NOFAN) ? "without" : "with"); - } else if ((power_info->info_4.sThermalController.ucType == + } else if ((controller->ucType == ATOM_PP_THERMALCONTROLLER_EXTERNAL_GPIO) || - (power_info->info_4.sThermalController.ucType == + (controller->ucType == ATOM_PP_THERMALCONTROLLER_ADT7473_WITH_INTERNAL)) { DRM_INFO("Special thermal controller config\n"); } else { DRM_INFO("Possible %s thermal controller at 0x%02x %s fan control\n", - pp_lib_thermal_controller_names[power_info->info_4.sThermalController.ucType], - power_info->info_4.sThermalController.ucI2cAddress >> 1, - (power_info->info_4.sThermalController.ucFanParameters & + pp_lib_thermal_controller_names[controller->ucType], + controller->ucI2cAddress >> 1, + (controller->ucFanParameters & ATOM_PP_FANPARAMETERS_NOFAN) ? "without" : "with"); - i2c_bus = radeon_lookup_i2c_gpio(rdev, power_info->info_4.sThermalController.ucI2cLine); + i2c_bus = radeon_lookup_i2c_gpio(rdev, controller->ucI2cLine); rdev->pm.i2c_bus = radeon_i2c_create(rdev->ddev, &i2c_bus, "Thermal"); + if (rdev->pm.i2c_bus) { + struct i2c_board_info info = { }; + const char *name = pp_lib_thermal_controller_names[controller->ucType]; + info.addr = controller->ucI2cAddress >> 1; + strlcpy(info.type, name, sizeof(info.type)); + i2c_new_device(&rdev->pm.i2c_bus->adapter, &info); + } + } } /* first mode is usually default, followed by low to high */ -- cgit v1.2.3 From 90c3905950021a9b37ac1a4dd78225881f4c61e4 Mon Sep 17 00:00:00 2001 From: Alex Deucher Date: Wed, 24 Mar 2010 11:32:29 -0400 Subject: drm/radeon/kms/pm: don't enable pm if there is only on power state Just adds overhead when the power state will never change. Signed-off-by: Alex Deucher Signed-off-by: Dave Airlie --- drivers/gpu/drm/radeon/radeon_pm.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/gpu/drm/radeon') diff --git a/drivers/gpu/drm/radeon/radeon_pm.c b/drivers/gpu/drm/radeon/radeon_pm.c index a137ee2f722c..811126464a7b 100644 --- a/drivers/gpu/drm/radeon/radeon_pm.c +++ b/drivers/gpu/drm/radeon/radeon_pm.c @@ -113,7 +113,7 @@ int radeon_pm_init(struct radeon_device *rdev) INIT_DELAYED_WORK(&rdev->pm.idle_work, radeon_pm_idle_work_handler); - if (radeon_dynpm != -1 && radeon_dynpm) { + if ((radeon_dynpm != -1 && radeon_dynpm) && (rdev->pm.num_power_states > 1)) { rdev->pm.state = PM_STATE_PAUSED; DRM_INFO("radeon: dynamic power management enabled\n"); } -- cgit v1.2.3 From d91eeb7862a4a5f7c5c92b953fa69d2f1430e840 Mon Sep 17 00:00:00 2001 From: Alex Deucher Date: Mon, 5 Apr 2010 15:26:43 -0400 Subject: drm/radeon/kms/pm: clean power state printing Signed-off-by: Alex Deucher Signed-off-by: Dave Airlie --- drivers/gpu/drm/radeon/radeon_pm.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/gpu/drm/radeon') diff --git a/drivers/gpu/drm/radeon/radeon_pm.c b/drivers/gpu/drm/radeon/radeon_pm.c index 811126464a7b..1febb62bdd95 100644 --- a/drivers/gpu/drm/radeon/radeon_pm.c +++ b/drivers/gpu/drm/radeon/radeon_pm.c @@ -42,7 +42,7 @@ static const char *pm_state_names[4] = { }; static const char *pm_state_types[5] = { - "Default", + "", "Powersave", "Battery", "Balanced", -- cgit v1.2.3 From 79daedc942813c0417ff5e277da6f7f35705cde5 Mon Sep 17 00:00:00 2001 From: Alex Deucher Date: Thu, 22 Apr 2010 14:25:19 -0400 Subject: drm/radeon/kms: minor pm cleanups - remove non_clock_info struct - track power state misc flags Signed-off-by: Alex Deucher Signed-off-by: Dave Airlie --- drivers/gpu/drm/radeon/r100.c | 2 +- drivers/gpu/drm/radeon/r600.c | 2 +- drivers/gpu/drm/radeon/radeon.h | 13 +++---------- drivers/gpu/drm/radeon/radeon_atombios.c | 22 ++++++++++++++-------- drivers/gpu/drm/radeon/radeon_combios.c | 15 ++++----------- drivers/gpu/drm/radeon/radeon_pm.c | 2 +- 6 files changed, 24 insertions(+), 32 deletions(-) (limited to 'drivers/gpu/drm/radeon') diff --git a/drivers/gpu/drm/radeon/r100.c b/drivers/gpu/drm/radeon/r100.c index a6b2aca36b47..f10b747024f1 100644 --- a/drivers/gpu/drm/radeon/r100.c +++ b/drivers/gpu/drm/radeon/r100.c @@ -137,7 +137,7 @@ void r100_get_power_state(struct radeon_device *rdev, rdev->pm.power_state[rdev->pm.requested_power_state_index]. clock_info[rdev->pm.requested_clock_mode_index].mclk, rdev->pm.power_state[rdev->pm.requested_power_state_index]. - non_clock_info.pcie_lanes); + pcie_lanes); } void r100_set_power_state(struct radeon_device *rdev) diff --git a/drivers/gpu/drm/radeon/r600.c b/drivers/gpu/drm/radeon/r600.c index cc2797949ee5..35a5d4856f46 100644 --- a/drivers/gpu/drm/radeon/r600.c +++ b/drivers/gpu/drm/radeon/r600.c @@ -234,7 +234,7 @@ void r600_get_power_state(struct radeon_device *rdev, rdev->pm.power_state[rdev->pm.requested_power_state_index]. clock_info[rdev->pm.requested_clock_mode_index].mclk, rdev->pm.power_state[rdev->pm.requested_power_state_index]. - non_clock_info.pcie_lanes); + pcie_lanes); } void r600_set_power_state(struct radeon_device *rdev) diff --git a/drivers/gpu/drm/radeon/radeon.h b/drivers/gpu/drm/radeon/radeon.h index b5eccc4094e8..b9ad976cfb9c 100644 --- a/drivers/gpu/drm/radeon/radeon.h +++ b/drivers/gpu/drm/radeon/radeon.h @@ -654,13 +654,6 @@ struct radeon_voltage { u32 voltage; }; -struct radeon_pm_non_clock_info { - /* pcie lanes */ - int pcie_lanes; - /* standardized non-clock flags */ - u32 flags; -}; - struct radeon_pm_clock_info { /* memory clock */ u32 mclk; @@ -682,11 +675,11 @@ struct radeon_power_state { /* number of valid clock modes in this power state */ int num_clock_modes; struct radeon_pm_clock_info *default_clock_mode; - /* non clock info about this state */ - struct radeon_pm_non_clock_info non_clock_info; - bool voltage_drop_active; /* standardized state flags */ u32 flags; + u32 misc; /* vbios specific flags */ + u32 misc2; /* vbios specific flags */ + int pcie_lanes; /* pcie lanes */ }; /* diff --git a/drivers/gpu/drm/radeon/radeon_atombios.c b/drivers/gpu/drm/radeon/radeon_atombios.c index a0a99b66af82..c29ac74a1d20 100644 --- a/drivers/gpu/drm/radeon/radeon_atombios.c +++ b/drivers/gpu/drm/radeon/radeon_atombios.c @@ -1528,7 +1528,7 @@ void radeon_atombios_get_power_modes(struct radeon_device *rdev) if ((rdev->pm.power_state[state_index].clock_info[0].mclk == 0) || (rdev->pm.power_state[state_index].clock_info[0].sclk == 0)) continue; - rdev->pm.power_state[state_index].non_clock_info.pcie_lanes = + rdev->pm.power_state[state_index].pcie_lanes = power_info->info.asPowerPlayInfo[i].ucNumPciELanes; misc = le32_to_cpu(power_info->info.asPowerPlayInfo[i].ulMiscInfo); if (misc & ATOM_PM_MISCINFO_VOLTAGE_DROP_SUPPORT) { @@ -1550,6 +1550,7 @@ void radeon_atombios_get_power_modes(struct radeon_device *rdev) power_info->info.asPowerPlayInfo[i].ucVoltageDropIndex; } rdev->pm.power_state[state_index].flags = RADEON_PM_SINGLE_DISPLAY_ONLY; + rdev->pm.power_state[state_index].misc = misc; /* order matters! */ if (misc & ATOM_PM_MISCINFO_POWER_SAVING_MODE) rdev->pm.power_state[state_index].type = @@ -1590,7 +1591,7 @@ void radeon_atombios_get_power_modes(struct radeon_device *rdev) if ((rdev->pm.power_state[state_index].clock_info[0].mclk == 0) || (rdev->pm.power_state[state_index].clock_info[0].sclk == 0)) continue; - rdev->pm.power_state[state_index].non_clock_info.pcie_lanes = + rdev->pm.power_state[state_index].pcie_lanes = power_info->info_2.asPowerPlayInfo[i].ucNumPciELanes; misc = le32_to_cpu(power_info->info_2.asPowerPlayInfo[i].ulMiscInfo); misc2 = le32_to_cpu(power_info->info_2.asPowerPlayInfo[i].ulMiscInfo2); @@ -1613,6 +1614,8 @@ void radeon_atombios_get_power_modes(struct radeon_device *rdev) power_info->info_2.asPowerPlayInfo[i].ucVoltageDropIndex; } rdev->pm.power_state[state_index].flags = RADEON_PM_SINGLE_DISPLAY_ONLY; + rdev->pm.power_state[state_index].misc = misc; + rdev->pm.power_state[state_index].misc2 = misc2; /* order matters! */ if (misc & ATOM_PM_MISCINFO_POWER_SAVING_MODE) rdev->pm.power_state[state_index].type = @@ -1659,7 +1662,7 @@ void radeon_atombios_get_power_modes(struct radeon_device *rdev) if ((rdev->pm.power_state[state_index].clock_info[0].mclk == 0) || (rdev->pm.power_state[state_index].clock_info[0].sclk == 0)) continue; - rdev->pm.power_state[state_index].non_clock_info.pcie_lanes = + rdev->pm.power_state[state_index].pcie_lanes = power_info->info_3.asPowerPlayInfo[i].ucNumPciELanes; misc = le32_to_cpu(power_info->info_3.asPowerPlayInfo[i].ulMiscInfo); misc2 = le32_to_cpu(power_info->info_3.asPowerPlayInfo[i].ulMiscInfo2); @@ -1688,6 +1691,8 @@ void radeon_atombios_get_power_modes(struct radeon_device *rdev) } } rdev->pm.power_state[state_index].flags = RADEON_PM_SINGLE_DISPLAY_ONLY; + rdev->pm.power_state[state_index].misc = misc; + rdev->pm.power_state[state_index].misc2 = misc2; /* order matters! */ if (misc & ATOM_PM_MISCINFO_POWER_SAVING_MODE) rdev->pm.power_state[state_index].type = @@ -1730,6 +1735,8 @@ void radeon_atombios_get_power_modes(struct radeon_device *rdev) &rdev->pm.power_state[state_index - 1].clock_info[0]; rdev->pm.power_state[state_index].flags &= ~RADEON_PM_SINGLE_DISPLAY_ONLY; + rdev->pm.power_state[state_index].misc = 0; + rdev->pm.power_state[state_index].misc2 = 0; } } else { /* add the i2c bus for thermal/fan chip */ @@ -1852,7 +1859,9 @@ void radeon_atombios_get_power_modes(struct radeon_device *rdev) if (mode_index) { misc = le32_to_cpu(non_clock_info->ulCapsAndSettings); misc2 = le16_to_cpu(non_clock_info->usClassification); - rdev->pm.power_state[state_index].non_clock_info.pcie_lanes = + rdev->pm.power_state[state_index].misc = misc; + rdev->pm.power_state[state_index].misc2 = misc2; + rdev->pm.power_state[state_index].pcie_lanes = ((misc & ATOM_PPLIB_PCIE_LINK_WIDTH_MASK) >> ATOM_PPLIB_PCIE_LINK_WIDTH_SHIFT) + 1; switch (misc2 & ATOM_PPLIB_CLASSIFICATION_UI_MASK) { @@ -1902,10 +1911,7 @@ void radeon_atombios_get_power_modes(struct radeon_device *rdev) rdev->pm.power_state[state_index].default_clock_mode = &rdev->pm.power_state[state_index].clock_info[0]; rdev->pm.power_state[state_index].clock_info[0].voltage.type = VOLTAGE_NONE; - if (rdev->asic->get_pcie_lanes) - rdev->pm.power_state[state_index].non_clock_info.pcie_lanes = radeon_get_pcie_lanes(rdev); - else - rdev->pm.power_state[state_index].non_clock_info.pcie_lanes = 16; + rdev->pm.power_state[state_index].pcie_lanes = 16; rdev->pm.default_power_state_index = state_index; rdev->pm.power_state[state_index].flags = 0; state_index++; diff --git a/drivers/gpu/drm/radeon/radeon_combios.c b/drivers/gpu/drm/radeon/radeon_combios.c index 6a9ec8511261..c22344b7fc58 100644 --- a/drivers/gpu/drm/radeon/radeon_combios.c +++ b/drivers/gpu/drm/radeon/radeon_combios.c @@ -2382,17 +2382,13 @@ void radeon_combios_get_power_modes(struct radeon_device *rdev) if ((rdev->pm.power_state[state_index].clock_info[0].mclk == 0) || (rdev->pm.power_state[state_index].clock_info[0].sclk == 0)) goto default_mode; - /* skip overclock modes for now */ - if ((rdev->pm.power_state[state_index].clock_info[0].mclk > - rdev->clock.default_mclk + RADEON_MODE_OVERCLOCK_MARGIN) || - (rdev->pm.power_state[state_index].clock_info[0].sclk > - rdev->clock.default_sclk + RADEON_MODE_OVERCLOCK_MARGIN)) - goto default_mode; rdev->pm.power_state[state_index].type = POWER_STATE_TYPE_BATTERY; misc = RBIOS16(offset + 0x5 + 0x0); if (rev > 4) misc2 = RBIOS16(offset + 0x5 + 0xe); + rdev->pm.power_state[state_index].misc = misc; + rdev->pm.power_state[state_index].misc2 = misc2; if (misc & 0x4) { rdev->pm.power_state[state_index].clock_info[0].voltage.type = VOLTAGE_GPIO; if (misc & 0x8) @@ -2439,7 +2435,7 @@ void radeon_combios_get_power_modes(struct radeon_device *rdev) } else rdev->pm.power_state[state_index].clock_info[0].voltage.type = VOLTAGE_NONE; if (rev > 6) - rdev->pm.power_state[state_index].non_clock_info.pcie_lanes = + rdev->pm.power_state[state_index].pcie_lanes = RBIOS8(offset + 0x5 + 0x10); rdev->pm.power_state[state_index].flags = RADEON_PM_SINGLE_DISPLAY_ONLY; state_index++; @@ -2459,10 +2455,7 @@ default_mode: rdev->pm.power_state[state_index].clock_info[0].sclk = rdev->clock.default_sclk; rdev->pm.power_state[state_index].default_clock_mode = &rdev->pm.power_state[state_index].clock_info[0]; rdev->pm.power_state[state_index].clock_info[0].voltage.type = VOLTAGE_NONE; - if (rdev->asic->get_pcie_lanes) - rdev->pm.power_state[state_index].non_clock_info.pcie_lanes = radeon_get_pcie_lanes(rdev); - else - rdev->pm.power_state[state_index].non_clock_info.pcie_lanes = 16; + rdev->pm.power_state[state_index].pcie_lanes = 16; rdev->pm.power_state[state_index].flags = 0; rdev->pm.default_power_state_index = state_index; rdev->pm.num_power_states = state_index + 1; diff --git a/drivers/gpu/drm/radeon/radeon_pm.c b/drivers/gpu/drm/radeon/radeon_pm.c index 1febb62bdd95..87814eb8a1b4 100644 --- a/drivers/gpu/drm/radeon/radeon_pm.c +++ b/drivers/gpu/drm/radeon/radeon_pm.c @@ -64,7 +64,7 @@ static void radeon_print_power_mode_info(struct radeon_device *rdev) pm_state_types[rdev->pm.power_state[i].type], is_default ? "(default)" : ""); if ((rdev->flags & RADEON_IS_PCIE) && !(rdev->flags & RADEON_IS_IGP)) - DRM_INFO("\t%d PCIE Lanes\n", rdev->pm.power_state[i].non_clock_info.pcie_lanes); + DRM_INFO("\t%d PCIE Lanes\n", rdev->pm.power_state[i].pcie_lanes); if (rdev->pm.power_state[i].flags & RADEON_PM_SINGLE_DISPLAY_ONLY) DRM_INFO("\tSingle display only\n"); DRM_INFO("\t%d Clock Mode(s)\n", rdev->pm.power_state[i].num_clock_modes); -- cgit v1.2.3 From 58e21dff53b9063563e7bb5f5a795ab2d8f61dda Mon Sep 17 00:00:00 2001 From: Alex Deucher Date: Mon, 22 Mar 2010 13:31:08 -0400 Subject: drm/radeon/kms/pm: restore default power state on exit Signed-off-by: Alex Deucher Signed-off-by: Dave Airlie --- drivers/gpu/drm/radeon/r100.c | 4 ++++ drivers/gpu/drm/radeon/r600.c | 10 ++++++++++ drivers/gpu/drm/radeon/radeon.h | 3 ++- drivers/gpu/drm/radeon/radeon_pm.c | 9 +++++++++ 4 files changed, 25 insertions(+), 1 deletion(-) (limited to 'drivers/gpu/drm/radeon') diff --git a/drivers/gpu/drm/radeon/r100.c b/drivers/gpu/drm/radeon/r100.c index f10b747024f1..6443d9ea6c11 100644 --- a/drivers/gpu/drm/radeon/r100.c +++ b/drivers/gpu/drm/radeon/r100.c @@ -123,6 +123,10 @@ void r100_get_power_state(struct radeon_device *rdev, rdev->pm.current_power_state_index + 1; } break; + case PM_ACTION_DEFAULT: + rdev->pm.requested_power_state_index = rdev->pm.default_power_state_index; + rdev->pm.can_upclock = false; + break; case PM_ACTION_NONE: default: DRM_ERROR("Requested mode for not defined action\n"); diff --git a/drivers/gpu/drm/radeon/r600.c b/drivers/gpu/drm/radeon/r600.c index 35a5d4856f46..4f7f318b5437 100644 --- a/drivers/gpu/drm/radeon/r600.c +++ b/drivers/gpu/drm/radeon/r600.c @@ -161,6 +161,11 @@ void r600_get_power_state(struct radeon_device *rdev, } rdev->pm.requested_clock_mode_index = 0; break; + case PM_ACTION_DEFAULT: + rdev->pm.requested_power_state_index = rdev->pm.default_power_state_index; + rdev->pm.requested_clock_mode_index = 0; + rdev->pm.can_upclock = false; + break; case PM_ACTION_NONE: default: DRM_ERROR("Requested mode for not defined action\n"); @@ -221,6 +226,11 @@ void r600_get_power_state(struct radeon_device *rdev, rdev->pm.can_upclock = false; } break; + case PM_ACTION_DEFAULT: + rdev->pm.requested_power_state_index = rdev->pm.default_power_state_index; + rdev->pm.requested_clock_mode_index = 0; + rdev->pm.can_upclock = false; + break; case PM_ACTION_NONE: default: DRM_ERROR("Requested mode for not defined action\n"); diff --git a/drivers/gpu/drm/radeon/radeon.h b/drivers/gpu/drm/radeon/radeon.h index b9ad976cfb9c..5ffb29597af7 100644 --- a/drivers/gpu/drm/radeon/radeon.h +++ b/drivers/gpu/drm/radeon/radeon.h @@ -615,7 +615,8 @@ enum radeon_pm_action { PM_ACTION_NONE, PM_ACTION_MINIMUM, PM_ACTION_DOWNCLOCK, - PM_ACTION_UPCLOCK + PM_ACTION_UPCLOCK, + PM_ACTION_DEFAULT }; enum radeon_voltage_type { diff --git a/drivers/gpu/drm/radeon/radeon_pm.c b/drivers/gpu/drm/radeon/radeon_pm.c index 87814eb8a1b4..23b79ebce6c1 100644 --- a/drivers/gpu/drm/radeon/radeon_pm.c +++ b/drivers/gpu/drm/radeon/radeon_pm.c @@ -125,6 +125,15 @@ int radeon_pm_init(struct radeon_device *rdev) void radeon_pm_fini(struct radeon_device *rdev) { + if (rdev->pm.state != PM_STATE_DISABLED) { + /* cancel work */ + cancel_delayed_work_sync(&rdev->pm.idle_work); + /* reset default clocks */ + rdev->pm.state = PM_STATE_DISABLED; + rdev->pm.planned_action = PM_ACTION_DEFAULT; + radeon_pm_set_clocks(rdev); + } + if (rdev->pm.i2c_bus) radeon_i2c_destroy(rdev->pm.i2c_bus); } -- cgit v1.2.3 From 49e02b7306cb7e01965fe5f41ba0f80085142f6e Mon Sep 17 00:00:00 2001 From: Alex Deucher Date: Fri, 23 Apr 2010 17:57:27 -0400 Subject: drm/radeon/kms/pm: add additional asic callbacks - pm_misc() - handles voltage, pcie lanes, and other non clock related power mode settings. Currently disabled. Needs further debugging - pm_prepare() - disables crtc mem requests right now. All memory clients need to be disabled when changing memory clocks. This function can be expanded to include disabling fb access as well. - pm_finish() - enable active memory clients. Signed-off-by: Alex Deucher Signed-off-by: Dave Airlie --- drivers/gpu/drm/radeon/evergreen.c | 41 ++++++++++ drivers/gpu/drm/radeon/evergreen_reg.h | 1 + drivers/gpu/drm/radeon/r100.c | 142 +++++++++++++++++++++++++++++++++ drivers/gpu/drm/radeon/r100d.h | 36 +++++++++ drivers/gpu/drm/radeon/r500_reg.h | 1 + drivers/gpu/drm/radeon/r600.c | 5 ++ drivers/gpu/drm/radeon/radeon.h | 3 + drivers/gpu/drm/radeon/radeon_asic.c | 42 ++++++++++ drivers/gpu/drm/radeon/radeon_asic.h | 11 +++ drivers/gpu/drm/radeon/rs600.c | 123 ++++++++++++++++++++++++++++ drivers/gpu/drm/radeon/rs600d.h | 32 ++++++++ drivers/gpu/drm/radeon/rv770.c | 4 + 12 files changed, 441 insertions(+) (limited to 'drivers/gpu/drm/radeon') diff --git a/drivers/gpu/drm/radeon/evergreen.c b/drivers/gpu/drm/radeon/evergreen.c index 0137a4cd90f5..8d86d0568d97 100644 --- a/drivers/gpu/drm/radeon/evergreen.c +++ b/drivers/gpu/drm/radeon/evergreen.c @@ -39,6 +39,47 @@ static void evergreen_gpu_init(struct radeon_device *rdev); void evergreen_fini(struct radeon_device *rdev); +void evergreen_pm_misc(struct radeon_device *rdev) +{ + +} + +void evergreen_pm_prepare(struct radeon_device *rdev) +{ + struct drm_device *ddev = rdev->ddev; + struct drm_crtc *crtc; + struct radeon_crtc *radeon_crtc; + u32 tmp; + + /* disable any active CRTCs */ + list_for_each_entry(crtc, &ddev->mode_config.crtc_list, head) { + radeon_crtc = to_radeon_crtc(crtc); + if (radeon_crtc->enabled) { + tmp = RREG32(EVERGREEN_CRTC_CONTROL + radeon_crtc->crtc_offset); + tmp |= EVERGREEN_CRTC_DISP_READ_REQUEST_DISABLE; + WREG32(EVERGREEN_CRTC_CONTROL + radeon_crtc->crtc_offset, tmp); + } + } +} + +void evergreen_pm_finish(struct radeon_device *rdev) +{ + struct drm_device *ddev = rdev->ddev; + struct drm_crtc *crtc; + struct radeon_crtc *radeon_crtc; + u32 tmp; + + /* enable any active CRTCs */ + list_for_each_entry(crtc, &ddev->mode_config.crtc_list, head) { + radeon_crtc = to_radeon_crtc(crtc); + if (radeon_crtc->enabled) { + tmp = RREG32(EVERGREEN_CRTC_CONTROL + radeon_crtc->crtc_offset); + tmp &= ~EVERGREEN_CRTC_DISP_READ_REQUEST_DISABLE; + WREG32(EVERGREEN_CRTC_CONTROL + radeon_crtc->crtc_offset, tmp); + } + } +} + bool evergreen_hpd_sense(struct radeon_device *rdev, enum radeon_hpd_id hpd) { bool connected = false; diff --git a/drivers/gpu/drm/radeon/evergreen_reg.h b/drivers/gpu/drm/radeon/evergreen_reg.h index 9dba6d97d9b7..93aab2ebd9d0 100644 --- a/drivers/gpu/drm/radeon/evergreen_reg.h +++ b/drivers/gpu/drm/radeon/evergreen_reg.h @@ -166,6 +166,7 @@ /* CRTC blocks at 0x6df0, 0x79f0, 0x105f0, 0x111f0, 0x11df0, 0x129f0 */ #define EVERGREEN_CRTC_CONTROL 0x6e70 # define EVERGREEN_CRTC_MASTER_EN (1 << 0) +# define EVERGREEN_CRTC_DISP_READ_REQUEST_DISABLE (1 << 24) #define EVERGREEN_CRTC_STATUS 0x6e8c #define EVERGREEN_CRTC_UPDATE_LOCK 0x6ed4 diff --git a/drivers/gpu/drm/radeon/r100.c b/drivers/gpu/drm/radeon/r100.c index 6443d9ea6c11..2106ac66eb32 100644 --- a/drivers/gpu/drm/radeon/r100.c +++ b/drivers/gpu/drm/radeon/r100.c @@ -37,6 +37,7 @@ #include "rs100d.h" #include "rv200d.h" #include "rv250d.h" +#include "atom.h" #include #include @@ -200,6 +201,147 @@ void r100_set_power_state(struct radeon_device *rdev) DRM_INFO("GUI not idle!!!\n"); } +void r100_pm_misc(struct radeon_device *rdev) +{ +#if 0 + int requested_index = rdev->pm.requested_power_state_index; + struct radeon_power_state *ps = &rdev->pm.power_state[requested_index]; + struct radeon_voltage *voltage = &ps->clock_info[0].voltage; + u32 tmp, sclk_cntl, sclk_cntl2, sclk_more_cntl; + + if ((voltage->type == VOLTAGE_GPIO) && (voltage->gpio.valid)) { + if (ps->misc & ATOM_PM_MISCINFO_VOLTAGE_DROP_SUPPORT) { + tmp = RREG32(voltage->gpio.reg); + if (voltage->active_high) + tmp |= voltage->gpio.mask; + else + tmp &= ~(voltage->gpio.mask); + WREG32(voltage->gpio.reg, tmp); + if (voltage->delay) + udelay(voltage->delay); + } else { + tmp = RREG32(voltage->gpio.reg); + if (voltage->active_high) + tmp &= ~voltage->gpio.mask; + else + tmp |= voltage->gpio.mask; + WREG32(voltage->gpio.reg, tmp); + if (voltage->delay) + udelay(voltage->delay); + } + } + + sclk_cntl = RREG32_PLL(SCLK_CNTL); + sclk_cntl2 = RREG32_PLL(SCLK_CNTL2); + sclk_cntl2 &= ~REDUCED_SPEED_SCLK_SEL(3); + sclk_more_cntl = RREG32_PLL(SCLK_MORE_CNTL); + sclk_more_cntl &= ~VOLTAGE_DELAY_SEL(3); + if (ps->misc & ATOM_PM_MISCINFO_ASIC_REDUCED_SPEED_SCLK_EN) { + sclk_more_cntl |= REDUCED_SPEED_SCLK_EN; + if (ps->misc & ATOM_PM_MISCINFO_DYN_CLK_3D_IDLE) + sclk_cntl2 |= REDUCED_SPEED_SCLK_MODE; + else + sclk_cntl2 &= ~REDUCED_SPEED_SCLK_MODE; + if (ps->misc & ATOM_PM_MISCINFO_DYNAMIC_CLOCK_DIVIDER_BY_2) + sclk_cntl2 |= REDUCED_SPEED_SCLK_SEL(0); + else if (ps->misc & ATOM_PM_MISCINFO_DYNAMIC_CLOCK_DIVIDER_BY_4) + sclk_cntl2 |= REDUCED_SPEED_SCLK_SEL(2); + } else + sclk_more_cntl &= ~REDUCED_SPEED_SCLK_EN; + + if (ps->misc & ATOM_PM_MISCINFO_ASIC_DYNAMIC_VOLTAGE_EN) { + sclk_more_cntl |= IO_CG_VOLTAGE_DROP; + if (voltage->delay) { + sclk_more_cntl |= VOLTAGE_DROP_SYNC; + switch (voltage->delay) { + case 33: + sclk_more_cntl |= VOLTAGE_DELAY_SEL(0); + break; + case 66: + sclk_more_cntl |= VOLTAGE_DELAY_SEL(1); + break; + case 99: + sclk_more_cntl |= VOLTAGE_DELAY_SEL(2); + break; + case 132: + sclk_more_cntl |= VOLTAGE_DELAY_SEL(3); + break; + } + } else + sclk_more_cntl &= ~VOLTAGE_DROP_SYNC; + } else + sclk_more_cntl &= ~IO_CG_VOLTAGE_DROP; + + if (ps->misc & ATOM_PM_MISCINFO_DYNAMIC_HDP_BLOCK_EN) + sclk_cntl &= ~FORCE_HDP; + else + sclk_cntl |= FORCE_HDP; + + WREG32_PLL(SCLK_CNTL, sclk_cntl); + WREG32_PLL(SCLK_CNTL2, sclk_cntl2); + WREG32_PLL(SCLK_MORE_CNTL, sclk_more_cntl); + + /* set pcie lanes */ + if ((rdev->flags & RADEON_IS_PCIE) && + !(rdev->flags & RADEON_IS_IGP) && + rdev->asic->set_pcie_lanes && + (ps->pcie_lanes != + rdev->pm.power_state[rdev->pm.current_power_state_index].pcie_lanes)) { + radeon_set_pcie_lanes(rdev, + ps->pcie_lanes); + DRM_INFO("Setting: p: %d\n", ps->pcie_lanes); + } +#endif +} + +void r100_pm_prepare(struct radeon_device *rdev) +{ + struct drm_device *ddev = rdev->ddev; + struct drm_crtc *crtc; + struct radeon_crtc *radeon_crtc; + u32 tmp; + + /* disable any active CRTCs */ + list_for_each_entry(crtc, &ddev->mode_config.crtc_list, head) { + radeon_crtc = to_radeon_crtc(crtc); + if (radeon_crtc->enabled) { + if (radeon_crtc->crtc_id) { + tmp = RREG32(RADEON_CRTC2_GEN_CNTL); + tmp |= RADEON_CRTC2_DISP_REQ_EN_B; + WREG32(RADEON_CRTC2_GEN_CNTL, tmp); + } else { + tmp = RREG32(RADEON_CRTC_GEN_CNTL); + tmp |= RADEON_CRTC_DISP_REQ_EN_B; + WREG32(RADEON_CRTC_GEN_CNTL, tmp); + } + } + } +} + +void r100_pm_finish(struct radeon_device *rdev) +{ + struct drm_device *ddev = rdev->ddev; + struct drm_crtc *crtc; + struct radeon_crtc *radeon_crtc; + u32 tmp; + + /* enable any active CRTCs */ + list_for_each_entry(crtc, &ddev->mode_config.crtc_list, head) { + radeon_crtc = to_radeon_crtc(crtc); + if (radeon_crtc->enabled) { + if (radeon_crtc->crtc_id) { + tmp = RREG32(RADEON_CRTC2_GEN_CNTL); + tmp &= ~RADEON_CRTC2_DISP_REQ_EN_B; + WREG32(RADEON_CRTC2_GEN_CNTL, tmp); + } else { + tmp = RREG32(RADEON_CRTC_GEN_CNTL); + tmp &= ~RADEON_CRTC_DISP_REQ_EN_B; + WREG32(RADEON_CRTC_GEN_CNTL, tmp); + } + } + } +} + bool r100_gui_idle(struct radeon_device *rdev) { if (RREG32(RADEON_RBBM_STATUS) & RADEON_RBBM_ACTIVE) diff --git a/drivers/gpu/drm/radeon/r100d.h b/drivers/gpu/drm/radeon/r100d.h index de8abd104ab7..d016b16fa116 100644 --- a/drivers/gpu/drm/radeon/r100d.h +++ b/drivers/gpu/drm/radeon/r100d.h @@ -838,5 +838,41 @@ #define G_00000D_FORCE_RB(x) (((x) >> 28) & 0x1) #define C_00000D_FORCE_RB 0xEFFFFFFF +/* PLL regs */ +#define SCLK_CNTL 0xd +#define FORCE_HDP (1 << 17) +#define CLK_PWRMGT_CNTL 0x14 +#define GLOBAL_PMAN_EN (1 << 10) +#define DISP_PM (1 << 20) +#define PLL_PWRMGT_CNTL 0x15 +#define MPLL_TURNOFF (1 << 0) +#define SPLL_TURNOFF (1 << 1) +#define PPLL_TURNOFF (1 << 2) +#define P2PLL_TURNOFF (1 << 3) +#define TVPLL_TURNOFF (1 << 4) +#define MOBILE_SU (1 << 16) +#define SU_SCLK_USE_BCLK (1 << 17) +#define SCLK_CNTL2 0x1e +#define REDUCED_SPEED_SCLK_MODE (1 << 16) +#define REDUCED_SPEED_SCLK_SEL(x) ((x) << 17) +#define MCLK_MISC 0x1f +#define EN_MCLK_TRISTATE_IN_SUSPEND (1 << 18) +#define SCLK_MORE_CNTL 0x35 +#define REDUCED_SPEED_SCLK_EN (1 << 16) +#define IO_CG_VOLTAGE_DROP (1 << 17) +#define VOLTAGE_DELAY_SEL(x) ((x) << 20) +#define VOLTAGE_DROP_SYNC (1 << 19) + +/* mmreg */ +#define DISP_PWR_MAN 0xd08 +#define DISP_D3_GRPH_RST (1 << 18) +#define DISP_D3_SUBPIC_RST (1 << 19) +#define DISP_D3_OV0_RST (1 << 20) +#define DISP_D1D2_GRPH_RST (1 << 21) +#define DISP_D1D2_SUBPIC_RST (1 << 22) +#define DISP_D1D2_OV0_RST (1 << 23) +#define DISP_DVO_ENABLE_RST (1 << 24) +#define TV_ENABLE_RST (1 << 25) +#define AUTO_PWRUP_EN (1 << 26) #endif diff --git a/drivers/gpu/drm/radeon/r500_reg.h b/drivers/gpu/drm/radeon/r500_reg.h index 0cf2ad2a5585..f5adf42a9d15 100644 --- a/drivers/gpu/drm/radeon/r500_reg.h +++ b/drivers/gpu/drm/radeon/r500_reg.h @@ -347,6 +347,7 @@ #define AVIVO_D1CRTC_CONTROL 0x6080 # define AVIVO_CRTC_EN (1 << 0) +# define AVIVO_CRTC_DISP_READ_REQUEST_DISABLE (1 << 24) #define AVIVO_D1CRTC_BLANK_CONTROL 0x6084 #define AVIVO_D1CRTC_INTERLACE_CONTROL 0x6088 #define AVIVO_D1CRTC_INTERLACE_STATUS 0x608c diff --git a/drivers/gpu/drm/radeon/r600.c b/drivers/gpu/drm/radeon/r600.c index 4f7f318b5437..38f75f54019b 100644 --- a/drivers/gpu/drm/radeon/r600.c +++ b/drivers/gpu/drm/radeon/r600.c @@ -304,6 +304,11 @@ void r600_set_power_state(struct radeon_device *rdev) DRM_INFO("GUI not idle!!!\n"); } +void r600_pm_misc(struct radeon_device *rdev) +{ + +} + bool r600_gui_idle(struct radeon_device *rdev) { if (RREG32(GRBM_STATUS) & GUI_ACTIVE) diff --git a/drivers/gpu/drm/radeon/radeon.h b/drivers/gpu/drm/radeon/radeon.h index 5ffb29597af7..16f0ea78ea9d 100644 --- a/drivers/gpu/drm/radeon/radeon.h +++ b/drivers/gpu/drm/radeon/radeon.h @@ -815,6 +815,9 @@ struct radeon_asic { bool (*gui_idle)(struct radeon_device *rdev); void (*get_power_state)(struct radeon_device *rdev, enum radeon_pm_action action); void (*set_power_state)(struct radeon_device *rdev); + void (*pm_misc)(struct radeon_device *rdev); + void (*pm_prepare)(struct radeon_device *rdev); + void (*pm_finish)(struct radeon_device *rdev); }; /* diff --git a/drivers/gpu/drm/radeon/radeon_asic.c b/drivers/gpu/drm/radeon/radeon_asic.c index 1053115ba652..1e6f17bf54fd 100644 --- a/drivers/gpu/drm/radeon/radeon_asic.c +++ b/drivers/gpu/drm/radeon/radeon_asic.c @@ -168,6 +168,9 @@ static struct radeon_asic r100_asic = { .gui_idle = &r100_gui_idle, .get_power_state = &r100_get_power_state, .set_power_state = &r100_set_power_state, + .pm_misc = &r100_pm_misc, + .pm_prepare = &r100_pm_prepare, + .pm_finish = &r100_pm_finish, }; static struct radeon_asic r200_asic = { @@ -209,6 +212,9 @@ static struct radeon_asic r200_asic = { .gui_idle = &r100_gui_idle, .get_power_state = &r100_get_power_state, .set_power_state = &r100_set_power_state, + .pm_misc = &r100_pm_misc, + .pm_prepare = &r100_pm_prepare, + .pm_finish = &r100_pm_finish, }; static struct radeon_asic r300_asic = { @@ -251,6 +257,9 @@ static struct radeon_asic r300_asic = { .gui_idle = &r100_gui_idle, .get_power_state = &r100_get_power_state, .set_power_state = &r100_set_power_state, + .pm_misc = &r100_pm_misc, + .pm_prepare = &r100_pm_prepare, + .pm_finish = &r100_pm_finish, }; static struct radeon_asic r300_asic_pcie = { @@ -292,6 +301,9 @@ static struct radeon_asic r300_asic_pcie = { .gui_idle = &r100_gui_idle, .get_power_state = &r100_get_power_state, .set_power_state = &r100_set_power_state, + .pm_misc = &r100_pm_misc, + .pm_prepare = &r100_pm_prepare, + .pm_finish = &r100_pm_finish, }; static struct radeon_asic r420_asic = { @@ -334,6 +346,9 @@ static struct radeon_asic r420_asic = { .gui_idle = &r100_gui_idle, .get_power_state = &r100_get_power_state, .set_power_state = &r100_set_power_state, + .pm_misc = &r100_pm_misc, + .pm_prepare = &r100_pm_prepare, + .pm_finish = &r100_pm_finish, }; static struct radeon_asic rs400_asic = { @@ -376,6 +391,9 @@ static struct radeon_asic rs400_asic = { .gui_idle = &r100_gui_idle, .get_power_state = &r100_get_power_state, .set_power_state = &r100_set_power_state, + .pm_misc = &r100_pm_misc, + .pm_prepare = &r100_pm_prepare, + .pm_finish = &r100_pm_finish, }; static struct radeon_asic rs600_asic = { @@ -418,6 +436,9 @@ static struct radeon_asic rs600_asic = { .gui_idle = &r100_gui_idle, .get_power_state = &r100_get_power_state, .set_power_state = &r100_set_power_state, + .pm_misc = &rs600_pm_misc, + .pm_prepare = &rs600_pm_prepare, + .pm_finish = &rs600_pm_finish, }; static struct radeon_asic rs690_asic = { @@ -460,6 +481,9 @@ static struct radeon_asic rs690_asic = { .gui_idle = &r100_gui_idle, .get_power_state = &r100_get_power_state, .set_power_state = &r100_set_power_state, + .pm_misc = &rs600_pm_misc, + .pm_prepare = &rs600_pm_prepare, + .pm_finish = &rs600_pm_finish, }; static struct radeon_asic rv515_asic = { @@ -502,6 +526,9 @@ static struct radeon_asic rv515_asic = { .gui_idle = &r100_gui_idle, .get_power_state = &r100_get_power_state, .set_power_state = &r100_set_power_state, + .pm_misc = &rs600_pm_misc, + .pm_prepare = &rs600_pm_prepare, + .pm_finish = &rs600_pm_finish, }; static struct radeon_asic r520_asic = { @@ -544,6 +571,9 @@ static struct radeon_asic r520_asic = { .gui_idle = &r100_gui_idle, .get_power_state = &r100_get_power_state, .set_power_state = &r100_set_power_state, + .pm_misc = &rs600_pm_misc, + .pm_prepare = &rs600_pm_prepare, + .pm_finish = &rs600_pm_finish, }; static struct radeon_asic r600_asic = { @@ -585,6 +615,9 @@ static struct radeon_asic r600_asic = { .gui_idle = &r600_gui_idle, .get_power_state = &r600_get_power_state, .set_power_state = &r600_set_power_state, + .pm_misc = &r600_pm_misc, + .pm_prepare = &rs600_pm_prepare, + .pm_finish = &rs600_pm_finish, }; static struct radeon_asic rs780_asic = { @@ -626,6 +659,9 @@ static struct radeon_asic rs780_asic = { .gui_idle = &r600_gui_idle, .get_power_state = &r600_get_power_state, .set_power_state = &r600_set_power_state, + .pm_misc = &r600_pm_misc, + .pm_prepare = &rs600_pm_prepare, + .pm_finish = &rs600_pm_finish, }; static struct radeon_asic rv770_asic = { @@ -667,6 +703,9 @@ static struct radeon_asic rv770_asic = { .gui_idle = &r600_gui_idle, .get_power_state = &r600_get_power_state, .set_power_state = &r600_set_power_state, + .pm_misc = &rv770_pm_misc, + .pm_prepare = &rs600_pm_prepare, + .pm_finish = &rs600_pm_finish, }; static struct radeon_asic evergreen_asic = { @@ -706,6 +745,9 @@ static struct radeon_asic evergreen_asic = { .gui_idle = &r600_gui_idle, .get_power_state = &r600_get_power_state, .set_power_state = &r600_set_power_state, + .pm_misc = &evergreen_pm_misc, + .pm_prepare = &evergreen_pm_prepare, + .pm_finish = &evergreen_pm_finish, }; int radeon_asic_init(struct radeon_device *rdev) diff --git a/drivers/gpu/drm/radeon/radeon_asic.h b/drivers/gpu/drm/radeon/radeon_asic.h index 71b21bb4e5f3..378db67ba2d8 100644 --- a/drivers/gpu/drm/radeon/radeon_asic.h +++ b/drivers/gpu/drm/radeon/radeon_asic.h @@ -130,6 +130,9 @@ extern bool r100_gui_idle(struct radeon_device *rdev); extern void r100_set_power_state(struct radeon_device *rdev); extern void r100_get_power_state(struct radeon_device *rdev, enum radeon_pm_action action); +extern void r100_pm_misc(struct radeon_device *rdev); +extern void r100_pm_prepare(struct radeon_device *rdev); +extern void r100_pm_finish(struct radeon_device *rdev); /* * r200,rv250,rs300,rv280 @@ -201,6 +204,9 @@ void rs600_hpd_fini(struct radeon_device *rdev); bool rs600_hpd_sense(struct radeon_device *rdev, enum radeon_hpd_id hpd); void rs600_hpd_set_polarity(struct radeon_device *rdev, enum radeon_hpd_id hpd); +extern void rs600_pm_misc(struct radeon_device *rdev); +extern void rs600_pm_prepare(struct radeon_device *rdev); +extern void rs600_pm_finish(struct radeon_device *rdev); /* * rs690,rs740 @@ -278,6 +284,7 @@ extern bool r600_gui_idle(struct radeon_device *rdev); extern void r600_set_power_state(struct radeon_device *rdev); extern void r600_get_power_state(struct radeon_device *rdev, enum radeon_pm_action action); +extern void r600_pm_misc(struct radeon_device *rdev); /* * rv770,rv730,rv710,rv740 @@ -286,6 +293,7 @@ int rv770_init(struct radeon_device *rdev); void rv770_fini(struct radeon_device *rdev); int rv770_suspend(struct radeon_device *rdev); int rv770_resume(struct radeon_device *rdev); +extern void rv770_pm_misc(struct radeon_device *rdev); /* * evergreen @@ -306,5 +314,8 @@ void evergreen_hpd_set_polarity(struct radeon_device *rdev, u32 evergreen_get_vblank_counter(struct radeon_device *rdev, int crtc); int evergreen_irq_set(struct radeon_device *rdev); int evergreen_irq_process(struct radeon_device *rdev); +extern void evergreen_pm_misc(struct radeon_device *rdev); +extern void evergreen_pm_prepare(struct radeon_device *rdev); +extern void evergreen_pm_finish(struct radeon_device *rdev); #endif diff --git a/drivers/gpu/drm/radeon/rs600.c b/drivers/gpu/drm/radeon/rs600.c index b312b72d76ce..c3890b76a1c0 100644 --- a/drivers/gpu/drm/radeon/rs600.c +++ b/drivers/gpu/drm/radeon/rs600.c @@ -46,6 +46,129 @@ void rs600_gpu_init(struct radeon_device *rdev); int rs600_mc_wait_for_idle(struct radeon_device *rdev); +void rs600_pm_misc(struct radeon_device *rdev) +{ +#if 0 + int requested_index = rdev->pm.requested_power_state_index; + struct radeon_power_state *ps = &rdev->pm.power_state[requested_index]; + struct radeon_voltage *voltage = &ps->clock_info[0].voltage; + u32 tmp, dyn_pwrmgt_sclk_length, dyn_sclk_vol_cntl; + u32 hdp_dyn_cntl, mc_host_dyn_cntl; + + if ((voltage->type == VOLTAGE_GPIO) && (voltage->gpio.valid)) { + if (ps->misc & ATOM_PM_MISCINFO_VOLTAGE_DROP_SUPPORT) { + tmp = RREG32(voltage->gpio.reg); + if (voltage->active_high) + tmp |= voltage->gpio.mask; + else + tmp &= ~(voltage->gpio.mask); + WREG32(voltage->gpio.reg, tmp); + if (voltage->delay) + udelay(voltage->delay); + } else { + tmp = RREG32(voltage->gpio.reg); + if (voltage->active_high) + tmp &= ~voltage->gpio.mask; + else + tmp |= voltage->gpio.mask; + WREG32(voltage->gpio.reg, tmp); + if (voltage->delay) + udelay(voltage->delay); + } + } + + dyn_pwrmgt_sclk_length = RREG32_PLL(DYN_PWRMGT_SCLK_LENGTH); + dyn_pwrmgt_sclk_length &= ~REDUCED_POWER_SCLK_HILEN(0xf); + dyn_pwrmgt_sclk_length &= ~REDUCED_POWER_SCLK_LOLEN(0xf); + if (ps->misc & ATOM_PM_MISCINFO_ASIC_REDUCED_SPEED_SCLK_EN) { + if (ps->misc & ATOM_PM_MISCINFO_DYNAMIC_CLOCK_DIVIDER_BY_2) { + dyn_pwrmgt_sclk_length |= REDUCED_POWER_SCLK_HILEN(2); + dyn_pwrmgt_sclk_length |= REDUCED_POWER_SCLK_LOLEN(2); + } else if (ps->misc & ATOM_PM_MISCINFO_DYNAMIC_CLOCK_DIVIDER_BY_4) { + dyn_pwrmgt_sclk_length |= REDUCED_POWER_SCLK_HILEN(4); + dyn_pwrmgt_sclk_length |= REDUCED_POWER_SCLK_LOLEN(4); + } + } else { + dyn_pwrmgt_sclk_length |= REDUCED_POWER_SCLK_HILEN(1); + dyn_pwrmgt_sclk_length |= REDUCED_POWER_SCLK_LOLEN(1); + } + WREG32_PLL(DYN_PWRMGT_SCLK_LENGTH, dyn_pwrmgt_sclk_length); + + dyn_sclk_vol_cntl = RREG32_PLL(DYN_SCLK_VOL_CNTL); + if (ps->misc & ATOM_PM_MISCINFO_ASIC_DYNAMIC_VOLTAGE_EN) { + dyn_sclk_vol_cntl |= IO_CG_VOLTAGE_DROP; + if (voltage->delay) { + dyn_sclk_vol_cntl |= VOLTAGE_DROP_SYNC; + dyn_sclk_vol_cntl |= VOLTAGE_DELAY_SEL(voltage->delay); + } else + dyn_sclk_vol_cntl &= ~VOLTAGE_DROP_SYNC; + } else + dyn_sclk_vol_cntl &= ~IO_CG_VOLTAGE_DROP; + WREG32_PLL(DYN_SCLK_VOL_CNTL, dyn_sclk_vol_cntl); + + hdp_dyn_cntl = RREG32_PLL(HDP_DYN_CNTL); + if (ps->misc & ATOM_PM_MISCINFO_DYNAMIC_HDP_BLOCK_EN) + hdp_dyn_cntl &= ~HDP_FORCEON; + else + hdp_dyn_cntl |= HDP_FORCEON; + WREG32_PLL(HDP_DYN_CNTL, hdp_dyn_cntl); + + mc_host_dyn_cntl = RREG32_PLL(MC_HOST_DYN_CNTL); + if (ps->misc & ATOM_PM_MISCINFO_DYNAMIC_MC_HOST_BLOCK_EN) + mc_host_dyn_cntl &= ~MC_HOST_FORCEON; + else + mc_host_dyn_cntl |= MC_HOST_FORCEON; + WREG32_PLL(MC_HOST_DYN_CNTL, mc_host_dyn_cntl); + + /* set pcie lanes */ + if ((rdev->flags & RADEON_IS_PCIE) && + !(rdev->flags & RADEON_IS_IGP) && + rdev->asic->set_pcie_lanes && + (ps->pcie_lanes != + rdev->pm.power_state[rdev->pm.current_power_state_index].pcie_lanes)) { + radeon_set_pcie_lanes(rdev, + ps->pcie_lanes); + DRM_INFO("Setting: p: %d\n", ps->pcie_lanes); + } +#endif +} + +void rs600_pm_prepare(struct radeon_device *rdev) +{ + struct drm_device *ddev = rdev->ddev; + struct drm_crtc *crtc; + struct radeon_crtc *radeon_crtc; + u32 tmp; + + /* disable any active CRTCs */ + list_for_each_entry(crtc, &ddev->mode_config.crtc_list, head) { + radeon_crtc = to_radeon_crtc(crtc); + if (radeon_crtc->enabled) { + tmp = RREG32(AVIVO_D1CRTC_CONTROL + radeon_crtc->crtc_offset); + tmp |= AVIVO_CRTC_DISP_READ_REQUEST_DISABLE; + WREG32(AVIVO_D1CRTC_CONTROL + radeon_crtc->crtc_offset, tmp); + } + } +} + +void rs600_pm_finish(struct radeon_device *rdev) +{ + struct drm_device *ddev = rdev->ddev; + struct drm_crtc *crtc; + struct radeon_crtc *radeon_crtc; + u32 tmp; + + /* enable any active CRTCs */ + list_for_each_entry(crtc, &ddev->mode_config.crtc_list, head) { + radeon_crtc = to_radeon_crtc(crtc); + if (radeon_crtc->enabled) { + tmp = RREG32(AVIVO_D1CRTC_CONTROL + radeon_crtc->crtc_offset); + tmp &= ~AVIVO_CRTC_DISP_READ_REQUEST_DISABLE; + WREG32(AVIVO_D1CRTC_CONTROL + radeon_crtc->crtc_offset, tmp); + } + } +} + /* hpd for digital panel detect/disconnect */ bool rs600_hpd_sense(struct radeon_device *rdev, enum radeon_hpd_id hpd) { diff --git a/drivers/gpu/drm/radeon/rs600d.h b/drivers/gpu/drm/radeon/rs600d.h index 08c4bebd3011..8f624342927a 100644 --- a/drivers/gpu/drm/radeon/rs600d.h +++ b/drivers/gpu/drm/radeon/rs600d.h @@ -634,4 +634,36 @@ #define G_006D4C_D2MODE_PRIORITY_B_FORCE_MASK(x) (((x) >> 24) & 0x1) #define C_006D4C_D2MODE_PRIORITY_B_FORCE_MASK 0xFEFFFFFF +/* PLL regs */ +#define GENERAL_PWRMGT 0x8 +#define GLOBAL_PWRMGT_EN (1 << 0) +#define MOBILE_SU (1 << 2) +#define DYN_PWRMGT_SCLK_LENGTH 0xc +#define NORMAL_POWER_SCLK_HILEN(x) ((x) << 0) +#define NORMAL_POWER_SCLK_LOLEN(x) ((x) << 4) +#define REDUCED_POWER_SCLK_HILEN(x) ((x) << 8) +#define REDUCED_POWER_SCLK_LOLEN(x) ((x) << 12) +#define POWER_D1_SCLK_HILEN(x) ((x) << 16) +#define POWER_D1_SCLK_LOLEN(x) ((x) << 20) +#define STATIC_SCREEN_HILEN(x) ((x) << 24) +#define STATIC_SCREEN_LOLEN(x) ((x) << 28) +#define DYN_SCLK_VOL_CNTL 0xe +#define IO_CG_VOLTAGE_DROP (1 << 0) +#define VOLTAGE_DROP_SYNC (1 << 2) +#define VOLTAGE_DELAY_SEL(x) ((x) << 3) +#define HDP_DYN_CNTL 0x10 +#define HDP_FORCEON (1 << 0) +#define MC_HOST_DYN_CNTL 0x1e +#define MC_HOST_FORCEON (1 << 0) + +/* mmreg */ +#define DOUT_POWER_MANAGEMENT_CNTL 0x7ee0 +#define PWRDN_WAIT_BUSY_OFF (1 << 0) +#define PWRDN_WAIT_PWRSEQ_OFF (1 << 4) +#define PWRDN_WAIT_PPLL_OFF (1 << 8) +#define PWRUP_WAIT_PPLL_ON (1 << 12) +#define PWRUP_WAIT_MEM_INIT_DONE (1 << 16) +#define PM_ASSERT_RESET (1 << 20) +#define PM_PWRDN_PPLL (1 << 24) + #endif diff --git a/drivers/gpu/drm/radeon/rv770.c b/drivers/gpu/drm/radeon/rv770.c index a74683e18612..7c55182a9dd7 100644 --- a/drivers/gpu/drm/radeon/rv770.c +++ b/drivers/gpu/drm/radeon/rv770.c @@ -42,6 +42,10 @@ static void rv770_gpu_init(struct radeon_device *rdev); void rv770_fini(struct radeon_device *rdev); +void rv770_pm_misc(struct radeon_device *rdev) +{ + +} /* * GART -- cgit v1.2.3 From a424816fb37f894a37585cf86dfdd6b8b1dc681f Mon Sep 17 00:00:00 2001 From: Alex Deucher Date: Sat, 24 Apr 2010 14:50:23 -0400 Subject: drm/radeon/kms/pm: rework power management Add two new sysfs attributes: - dynpm - power_state Echoing 0/1 to dynpm disables/enables dynamic power management. The driver scales the sclk dynamically based on the number of queued fences. dynpm only scales sclk dynamically in single head mode. Echoing x.y to power_state selects a static power state (x) and clock mode (y). This allows you to statically select a power state and clock mode. Selecting a static clock mode will disable dynpm. Signed-off-by: Alex Deucher Signed-off-by: Dave Airlie --- drivers/gpu/drm/radeon/r100.c | 66 +++++++++++------ drivers/gpu/drm/radeon/r600.c | 69 ++++++++++------- drivers/gpu/drm/radeon/radeon.h | 7 +- drivers/gpu/drm/radeon/radeon_asic.h | 4 +- drivers/gpu/drm/radeon/radeon_pm.c | 139 ++++++++++++++++++++++++++++++++++- 5 files changed, 229 insertions(+), 56 deletions(-) (limited to 'drivers/gpu/drm/radeon') diff --git a/drivers/gpu/drm/radeon/r100.c b/drivers/gpu/drm/radeon/r100.c index 2106ac66eb32..7675827c3a8d 100644 --- a/drivers/gpu/drm/radeon/r100.c +++ b/drivers/gpu/drm/radeon/r100.c @@ -145,7 +145,7 @@ void r100_get_power_state(struct radeon_device *rdev, pcie_lanes); } -void r100_set_power_state(struct radeon_device *rdev) +void r100_set_power_state(struct radeon_device *rdev, bool static_switch) { u32 sclk, mclk; @@ -167,33 +167,51 @@ void r100_set_power_state(struct radeon_device *rdev) if (rdev->pm.active_crtc_count > 1) mclk = rdev->clock.default_mclk; - /* set pcie lanes */ - /* TODO */ + /* voltage, pcie lanes, etc.*/ + radeon_pm_misc(rdev); - /* set voltage */ - /* TODO */ - - /* set engine clock */ - if (sclk != rdev->pm.current_sclk) { - radeon_sync_with_vblank(rdev); - radeon_pm_debug_check_in_vbl(rdev, false); - radeon_set_engine_clock(rdev, sclk); - radeon_pm_debug_check_in_vbl(rdev, true); - rdev->pm.current_sclk = sclk; - DRM_INFO("Setting: e: %d\n", sclk); - } + if (static_switch) { + radeon_pm_prepare(rdev); + /* set engine clock */ + if (sclk != rdev->pm.current_sclk) { + radeon_set_engine_clock(rdev, sclk); + rdev->pm.current_sclk = sclk; + DRM_INFO("Setting: e: %d\n", sclk); + } +#if 0 + /* set memory clock */ + if (rdev->asic->set_memory_clock && (mclk != rdev->pm.current_mclk)) { + radeon_set_memory_clock(rdev, mclk); + rdev->pm.current_mclk = mclk; + DRM_INFO("Setting: m: %d\n", mclk); + } +#endif + radeon_pm_finish(rdev); + } else { + /* set engine clock */ + if (sclk != rdev->pm.current_sclk) { + radeon_sync_with_vblank(rdev); + radeon_pm_debug_check_in_vbl(rdev, false); + radeon_set_engine_clock(rdev, sclk); + radeon_pm_debug_check_in_vbl(rdev, true); + rdev->pm.current_sclk = sclk; + DRM_INFO("Setting: e: %d\n", sclk); + } #if 0 - /* set memory clock */ - if (rdev->asic->set_memory_clock && (mclk != rdev->pm.current_mclk)) { - radeon_sync_with_vblank(rdev); - radeon_pm_debug_check_in_vbl(rdev, false); - radeon_set_memory_clock(rdev, mclk); - radeon_pm_debug_check_in_vbl(rdev, true); - rdev->pm.current_mclk = mclk; - DRM_INFO("Setting: m: %d\n", mclk); - } + /* set memory clock */ + if (rdev->asic->set_memory_clock && (mclk != rdev->pm.current_mclk)) { + radeon_sync_with_vblank(rdev); + radeon_pm_debug_check_in_vbl(rdev, false); + radeon_pm_prepare(rdev); + radeon_set_memory_clock(rdev, mclk); + radeon_pm_finish(rdev); + radeon_pm_debug_check_in_vbl(rdev, true); + rdev->pm.current_mclk = mclk; + DRM_INFO("Setting: m: %d\n", mclk); + } #endif + } rdev->pm.current_power_state_index = rdev->pm.requested_power_state_index; rdev->pm.current_clock_mode_index = rdev->pm.requested_clock_mode_index; diff --git a/drivers/gpu/drm/radeon/r600.c b/drivers/gpu/drm/radeon/r600.c index 38f75f54019b..469130994064 100644 --- a/drivers/gpu/drm/radeon/r600.c +++ b/drivers/gpu/drm/radeon/r600.c @@ -247,7 +247,7 @@ void r600_get_power_state(struct radeon_device *rdev, pcie_lanes); } -void r600_set_power_state(struct radeon_device *rdev) +void r600_set_power_state(struct radeon_device *rdev, bool static_switch) { u32 sclk, mclk; @@ -266,37 +266,52 @@ void r600_set_power_state(struct radeon_device *rdev) clock_info[rdev->pm.requested_clock_mode_index].mclk; if (mclk > rdev->clock.default_mclk) mclk = rdev->clock.default_mclk; - /* don't change the mclk with multiple crtcs */ - if (rdev->pm.active_crtc_count > 1) - mclk = rdev->clock.default_mclk; - - /* set pcie lanes */ - /* TODO */ - /* set voltage */ - /* TODO */ + /* voltage, pcie lanes, etc.*/ + radeon_pm_misc(rdev); - /* set engine clock */ - if (sclk != rdev->pm.current_sclk) { - radeon_sync_with_vblank(rdev); - radeon_pm_debug_check_in_vbl(rdev, false); - radeon_set_engine_clock(rdev, sclk); - radeon_pm_debug_check_in_vbl(rdev, true); - rdev->pm.current_sclk = sclk; - DRM_INFO("Setting: e: %d\n", sclk); - } + if (static_switch) { + radeon_pm_prepare(rdev); + /* set engine clock */ + if (sclk != rdev->pm.current_sclk) { + radeon_set_engine_clock(rdev, sclk); + rdev->pm.current_sclk = sclk; + DRM_INFO("Setting: e: %d\n", sclk); + } +#if 0 + /* set memory clock */ + if (rdev->asic->set_memory_clock && (mclk != rdev->pm.current_mclk)) { + radeon_set_memory_clock(rdev, mclk); + rdev->pm.current_mclk = mclk; + DRM_INFO("Setting: m: %d\n", mclk); + } +#endif + radeon_pm_finish(rdev); + } else { + /* set engine clock */ + if (sclk != rdev->pm.current_sclk) { + radeon_sync_with_vblank(rdev); + radeon_pm_debug_check_in_vbl(rdev, false); + radeon_set_engine_clock(rdev, sclk); + radeon_pm_debug_check_in_vbl(rdev, true); + rdev->pm.current_sclk = sclk; + DRM_INFO("Setting: e: %d\n", sclk); + } #if 0 - /* set memory clock */ - if (rdev->asic->set_memory_clock && (mclk != rdev->pm.current_mclk)) { - radeon_sync_with_vblank(rdev); - radeon_pm_debug_check_in_vbl(rdev, false); - radeon_set_memory_clock(rdev, mclk); - radeon_pm_debug_check_in_vbl(rdev, true); - rdev->pm.current_mclk = mclk; - DRM_INFO("Setting: m: %d\n", mclk); - } + /* set memory clock */ + if (rdev->asic->set_memory_clock && (mclk != rdev->pm.current_mclk)) { + radeon_sync_with_vblank(rdev); + radeon_pm_debug_check_in_vbl(rdev, false); + radeon_pm_prepare(rdev); + radeon_set_memory_clock(rdev, mclk); + radeon_pm_finish(rdev); + radeon_pm_debug_check_in_vbl(rdev, true); + rdev->pm.current_mclk = mclk; + DRM_INFO("Setting: m: %d\n", mclk); + } #endif + } rdev->pm.current_power_state_index = rdev->pm.requested_power_state_index; rdev->pm.current_clock_mode_index = rdev->pm.requested_clock_mode_index; diff --git a/drivers/gpu/drm/radeon/radeon.h b/drivers/gpu/drm/radeon/radeon.h index 16f0ea78ea9d..cdcf5eaf6714 100644 --- a/drivers/gpu/drm/radeon/radeon.h +++ b/drivers/gpu/drm/radeon/radeon.h @@ -814,7 +814,7 @@ struct radeon_asic { void (*ioctl_wait_idle)(struct radeon_device *rdev, struct radeon_bo *bo); bool (*gui_idle)(struct radeon_device *rdev); void (*get_power_state)(struct radeon_device *rdev, enum radeon_pm_action action); - void (*set_power_state)(struct radeon_device *rdev); + void (*set_power_state)(struct radeon_device *rdev, bool static_switch); void (*pm_misc)(struct radeon_device *rdev); void (*pm_prepare)(struct radeon_device *rdev); void (*pm_finish)(struct radeon_device *rdev); @@ -1226,7 +1226,10 @@ static inline void radeon_ring_write(struct radeon_device *rdev, uint32_t v) #define radeon_hpd_set_polarity(rdev, hpd) (rdev)->asic->hpd_set_polarity((rdev), (hpd)) #define radeon_gui_idle(rdev) (rdev)->asic->gui_idle((rdev)) #define radeon_get_power_state(rdev, a) (rdev)->asic->get_power_state((rdev), (a)) -#define radeon_set_power_state(rdev) (rdev)->asic->set_power_state((rdev)) +#define radeon_set_power_state(rdev, s) (rdev)->asic->set_power_state((rdev), (s)) +#define radeon_pm_misc(rdev) (rdev)->asic->pm_misc((rdev)) +#define radeon_pm_prepare(rdev) (rdev)->asic->pm_prepare((rdev)) +#define radeon_pm_finish(rdev) (rdev)->asic->pm_finish((rdev)) /* Common functions */ /* AGP */ diff --git a/drivers/gpu/drm/radeon/radeon_asic.h b/drivers/gpu/drm/radeon/radeon_asic.h index 378db67ba2d8..8a1278629994 100644 --- a/drivers/gpu/drm/radeon/radeon_asic.h +++ b/drivers/gpu/drm/radeon/radeon_asic.h @@ -127,7 +127,7 @@ void r100_enable_bm(struct radeon_device *rdev); void r100_set_common_regs(struct radeon_device *rdev); void r100_bm_disable(struct radeon_device *rdev); extern bool r100_gui_idle(struct radeon_device *rdev); -extern void r100_set_power_state(struct radeon_device *rdev); +extern void r100_set_power_state(struct radeon_device *rdev, bool static_switch); extern void r100_get_power_state(struct radeon_device *rdev, enum radeon_pm_action action); extern void r100_pm_misc(struct radeon_device *rdev); @@ -281,7 +281,7 @@ void r600_hpd_set_polarity(struct radeon_device *rdev, enum radeon_hpd_id hpd); extern void r600_ioctl_wait_idle(struct radeon_device *rdev, struct radeon_bo *bo); extern bool r600_gui_idle(struct radeon_device *rdev); -extern void r600_set_power_state(struct radeon_device *rdev); +extern void r600_set_power_state(struct radeon_device *rdev, bool static_switch); extern void r600_get_power_state(struct radeon_device *rdev, enum radeon_pm_action action); extern void r600_pm_misc(struct radeon_device *rdev); diff --git a/drivers/gpu/drm/radeon/radeon_pm.c b/drivers/gpu/drm/radeon/radeon_pm.c index 23b79ebce6c1..c703ae326bc3 100644 --- a/drivers/gpu/drm/radeon/radeon_pm.c +++ b/drivers/gpu/drm/radeon/radeon_pm.c @@ -34,6 +34,128 @@ static void radeon_pm_set_clocks(struct radeon_device *rdev); static void radeon_pm_idle_work_handler(struct work_struct *work); static int radeon_debugfs_pm_init(struct radeon_device *rdev); +static void radeon_pm_set_power_mode_static_locked(struct radeon_device *rdev) +{ + mutex_lock(&rdev->cp.mutex); + + /* wait for GPU idle */ + rdev->pm.gui_idle = false; + rdev->irq.gui_idle = true; + radeon_irq_set(rdev); + wait_event_interruptible_timeout( + rdev->irq.idle_queue, rdev->pm.gui_idle, + msecs_to_jiffies(RADEON_WAIT_IDLE_TIMEOUT)); + rdev->irq.gui_idle = false; + radeon_irq_set(rdev); + + radeon_set_power_state(rdev, true); + + /* update display watermarks based on new power state */ + radeon_update_bandwidth_info(rdev); + if (rdev->pm.active_crtc_count) + radeon_bandwidth_update(rdev); + + mutex_unlock(&rdev->cp.mutex); +} + +static ssize_t radeon_get_power_state_static(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct drm_device *ddev = pci_get_drvdata(to_pci_dev(dev)); + struct radeon_device *rdev = ddev->dev_private; + + return snprintf(buf, PAGE_SIZE, "%d.%d\n", rdev->pm.current_power_state_index, + rdev->pm.current_clock_mode_index); +} + +static ssize_t radeon_set_power_state_static(struct device *dev, + struct device_attribute *attr, + const char *buf, + size_t count) +{ + struct drm_device *ddev = pci_get_drvdata(to_pci_dev(dev)); + struct radeon_device *rdev = ddev->dev_private; + int ps, cm; + + if (sscanf(buf, "%u.%u", &ps, &cm) != 2) { + DRM_ERROR("Invalid power state!\n"); + return count; + } + + mutex_lock(&rdev->pm.mutex); + if ((ps >= 0) && (ps < rdev->pm.num_power_states) && + (cm >= 0) && (cm < rdev->pm.power_state[ps].num_clock_modes)) { + if ((rdev->pm.active_crtc_count > 1) && + (rdev->pm.power_state[ps].flags & RADEON_PM_SINGLE_DISPLAY_ONLY)) { + DRM_ERROR("Invalid power state for multi-head: %d.%d\n", ps, cm); + } else { + /* disable dynpm */ + rdev->pm.state = PM_STATE_DISABLED; + rdev->pm.planned_action = PM_ACTION_NONE; + rdev->pm.requested_power_state_index = ps; + rdev->pm.requested_clock_mode_index = cm; + radeon_pm_set_power_mode_static_locked(rdev); + } + } else + DRM_ERROR("Invalid power state: %d.%d\n\n", ps, cm); + mutex_unlock(&rdev->pm.mutex); + + return count; +} + +static ssize_t radeon_get_dynpm(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct drm_device *ddev = pci_get_drvdata(to_pci_dev(dev)); + struct radeon_device *rdev = ddev->dev_private; + + return snprintf(buf, PAGE_SIZE, "%s\n", + (rdev->pm.state == PM_STATE_DISABLED) ? "disabled" : "enabled"); +} + +static ssize_t radeon_set_dynpm(struct device *dev, + struct device_attribute *attr, + const char *buf, + size_t count) +{ + struct drm_device *ddev = pci_get_drvdata(to_pci_dev(dev)); + struct radeon_device *rdev = ddev->dev_private; + int tmp = simple_strtoul(buf, NULL, 10); + + if (tmp == 0) { + /* update power mode info */ + radeon_pm_compute_clocks(rdev); + /* disable dynpm */ + mutex_lock(&rdev->pm.mutex); + rdev->pm.state = PM_STATE_DISABLED; + rdev->pm.planned_action = PM_ACTION_NONE; + mutex_unlock(&rdev->pm.mutex); + DRM_INFO("radeon: dynamic power management disabled\n"); + } else if (tmp == 1) { + if (rdev->pm.num_power_states > 1) { + /* enable dynpm */ + mutex_lock(&rdev->pm.mutex); + rdev->pm.state = PM_STATE_PAUSED; + rdev->pm.planned_action = PM_ACTION_DEFAULT; + radeon_get_power_state(rdev, rdev->pm.planned_action); + mutex_unlock(&rdev->pm.mutex); + /* update power mode info */ + radeon_pm_compute_clocks(rdev); + DRM_INFO("radeon: dynamic power management enabled\n"); + } else + DRM_ERROR("dynpm not valid on this system\n"); + } else + DRM_ERROR("Invalid setting: %d\n", tmp); + + return count; +} + +static DEVICE_ATTR(power_state, S_IRUGO | S_IWUSR, radeon_get_power_state_static, radeon_set_power_state_static); +static DEVICE_ATTR(dynpm, S_IRUGO | S_IWUSR, radeon_get_dynpm, radeon_set_dynpm); + + static const char *pm_state_names[4] = { "PM_STATE_DISABLED", "PM_STATE_MINIMUM", @@ -111,6 +233,10 @@ int radeon_pm_init(struct radeon_device *rdev) DRM_ERROR("Failed to register debugfs file for PM!\n"); } + /* where's the best place to put this? */ + device_create_file(rdev->dev, &dev_attr_power_state); + device_create_file(rdev->dev, &dev_attr_dynpm); + INIT_DELAYED_WORK(&rdev->pm.idle_work, radeon_pm_idle_work_handler); if ((radeon_dynpm != -1 && radeon_dynpm) && (rdev->pm.num_power_states > 1)) { @@ -132,8 +258,19 @@ void radeon_pm_fini(struct radeon_device *rdev) rdev->pm.state = PM_STATE_DISABLED; rdev->pm.planned_action = PM_ACTION_DEFAULT; radeon_pm_set_clocks(rdev); + } else if ((rdev->pm.current_power_state_index != + rdev->pm.default_power_state_index) || + (rdev->pm.current_clock_mode_index != 0)) { + rdev->pm.requested_power_state_index = rdev->pm.default_power_state_index; + rdev->pm.requested_clock_mode_index = 0; + mutex_lock(&rdev->pm.mutex); + radeon_pm_set_power_mode_static_locked(rdev); + mutex_unlock(&rdev->pm.mutex); } + device_remove_file(rdev->dev, &dev_attr_power_state); + device_remove_file(rdev->dev, &dev_attr_dynpm); + if (rdev->pm.i2c_bus) radeon_i2c_destroy(rdev->pm.i2c_bus); } @@ -267,7 +404,7 @@ static void radeon_pm_set_clocks_locked(struct radeon_device *rdev) { /*radeon_fence_wait_last(rdev);*/ - radeon_set_power_state(rdev); + radeon_set_power_state(rdev, false); rdev->pm.planned_action = PM_ACTION_NONE; } -- cgit v1.2.3 From 2aba631c008e7d82e3ec45dd32bec1ea63a963cf Mon Sep 17 00:00:00 2001 From: Matthew Garrett Date: Mon, 26 Apr 2010 15:45:23 -0400 Subject: radeon: Unify PM entry paths There's a moderate amount of effort involved in setting the card up for clock transitions, so unify the codepaths to make it easier to implement. Signed-off-by: Matthew Garrett Signed-off-by: Dave Airlie --- drivers/gpu/drm/radeon/radeon_pm.c | 90 ++++++++++++++------------------------ 1 file changed, 32 insertions(+), 58 deletions(-) (limited to 'drivers/gpu/drm/radeon') diff --git a/drivers/gpu/drm/radeon/radeon_pm.c b/drivers/gpu/drm/radeon/radeon_pm.c index c703ae326bc3..a61de1f9ff64 100644 --- a/drivers/gpu/drm/radeon/radeon_pm.c +++ b/drivers/gpu/drm/radeon/radeon_pm.c @@ -29,13 +29,13 @@ #define RADEON_WAIT_VBLANK_TIMEOUT 200 #define RADEON_WAIT_IDLE_TIMEOUT 200 -static void radeon_pm_set_clocks_locked(struct radeon_device *rdev); -static void radeon_pm_set_clocks(struct radeon_device *rdev); static void radeon_pm_idle_work_handler(struct work_struct *work); static int radeon_debugfs_pm_init(struct radeon_device *rdev); -static void radeon_pm_set_power_mode_static_locked(struct radeon_device *rdev) +static void radeon_pm_set_clocks(struct radeon_device *rdev, int static_switch) { + int i; + mutex_lock(&rdev->cp.mutex); /* wait for GPU idle */ @@ -48,13 +48,33 @@ static void radeon_pm_set_power_mode_static_locked(struct radeon_device *rdev) rdev->irq.gui_idle = false; radeon_irq_set(rdev); - radeon_set_power_state(rdev, true); - + if (!static_switch) { + for (i = 0; i < rdev->num_crtc; i++) { + if (rdev->pm.active_crtcs & (1 << i)) { + rdev->pm.req_vblank |= (1 << i); + drm_vblank_get(rdev->ddev, i); + } + } + } + + radeon_set_power_state(rdev, static_switch); + + if (!static_switch) { + for (i = 0; i < rdev->num_crtc; i++) { + if (rdev->pm.req_vblank & (1 << i)) { + rdev->pm.req_vblank &= ~(1 << i); + drm_vblank_put(rdev->ddev, i); + } + } + } + /* update display watermarks based on new power state */ radeon_update_bandwidth_info(rdev); if (rdev->pm.active_crtc_count) radeon_bandwidth_update(rdev); + rdev->pm.planned_action = PM_ACTION_NONE; + mutex_unlock(&rdev->cp.mutex); } @@ -95,7 +115,7 @@ static ssize_t radeon_set_power_state_static(struct device *dev, rdev->pm.planned_action = PM_ACTION_NONE; rdev->pm.requested_power_state_index = ps; rdev->pm.requested_clock_mode_index = cm; - radeon_pm_set_power_mode_static_locked(rdev); + radeon_pm_set_clocks(rdev, true); } } else DRM_ERROR("Invalid power state: %d.%d\n\n", ps, cm); @@ -257,14 +277,14 @@ void radeon_pm_fini(struct radeon_device *rdev) /* reset default clocks */ rdev->pm.state = PM_STATE_DISABLED; rdev->pm.planned_action = PM_ACTION_DEFAULT; - radeon_pm_set_clocks(rdev); + radeon_pm_set_clocks(rdev, false); } else if ((rdev->pm.current_power_state_index != rdev->pm.default_power_state_index) || (rdev->pm.current_clock_mode_index != 0)) { rdev->pm.requested_power_state_index = rdev->pm.default_power_state_index; rdev->pm.requested_clock_mode_index = 0; mutex_lock(&rdev->pm.mutex); - radeon_pm_set_power_mode_static_locked(rdev); + radeon_pm_set_clocks(rdev, true); mutex_unlock(&rdev->pm.mutex); } @@ -303,7 +323,7 @@ void radeon_pm_compute_clocks(struct radeon_device *rdev) rdev->pm.state = PM_STATE_PAUSED; rdev->pm.planned_action = PM_ACTION_UPCLOCK; - radeon_pm_set_clocks(rdev); + radeon_pm_set_clocks(rdev, false); DRM_DEBUG("radeon: dynamic power management deactivated\n"); } @@ -313,7 +333,7 @@ void radeon_pm_compute_clocks(struct radeon_device *rdev) if (rdev->pm.state == PM_STATE_MINIMUM) { rdev->pm.state = PM_STATE_ACTIVE; rdev->pm.planned_action = PM_ACTION_UPCLOCK; - radeon_pm_set_clocks(rdev); + radeon_pm_set_clocks(rdev, false); queue_delayed_work(rdev->wq, &rdev->pm.idle_work, msecs_to_jiffies(RADEON_IDLE_LOOP_MS)); @@ -329,7 +349,7 @@ void radeon_pm_compute_clocks(struct radeon_device *rdev) rdev->pm.state = PM_STATE_MINIMUM; rdev->pm.planned_action = PM_ACTION_MINIMUM; - radeon_pm_set_clocks(rdev); + radeon_pm_set_clocks(rdev, false); } } @@ -400,52 +420,6 @@ bool radeon_pm_debug_check_in_vbl(struct radeon_device *rdev, bool finish) finish ? "exit" : "entry"); return in_vbl; } -static void radeon_pm_set_clocks_locked(struct radeon_device *rdev) -{ - /*radeon_fence_wait_last(rdev);*/ - - radeon_set_power_state(rdev, false); - rdev->pm.planned_action = PM_ACTION_NONE; -} - -static void radeon_pm_set_clocks(struct radeon_device *rdev) -{ - int i; - - radeon_get_power_state(rdev, rdev->pm.planned_action); - mutex_lock(&rdev->cp.mutex); - - /* wait for GPU idle */ - rdev->pm.gui_idle = false; - rdev->irq.gui_idle = true; - radeon_irq_set(rdev); - wait_event_interruptible_timeout( - rdev->irq.idle_queue, rdev->pm.gui_idle, - msecs_to_jiffies(RADEON_WAIT_IDLE_TIMEOUT)); - rdev->irq.gui_idle = false; - radeon_irq_set(rdev); - - for (i = 0; i < rdev->num_crtc; i++) { - if (rdev->pm.active_crtcs & (1 << i)) { - rdev->pm.req_vblank |= (1 << i); - drm_vblank_get(rdev->ddev, i); - } - } - radeon_pm_set_clocks_locked(rdev); - for (i = 0; i < rdev->num_crtc; i++) { - if (rdev->pm.req_vblank & (1 << i)) { - rdev->pm.req_vblank &= ~(1 << i); - drm_vblank_put(rdev->ddev, i); - } - } - - /* update display watermarks based on new power state */ - radeon_update_bandwidth_info(rdev); - if (rdev->pm.active_crtc_count) - radeon_bandwidth_update(rdev); - - mutex_unlock(&rdev->cp.mutex); -} static void radeon_pm_idle_work_handler(struct work_struct *work) { @@ -493,7 +467,7 @@ static void radeon_pm_idle_work_handler(struct work_struct *work) if (rdev->pm.planned_action != PM_ACTION_NONE && jiffies > rdev->pm.action_timeout) { - radeon_pm_set_clocks(rdev); + radeon_pm_set_clocks(rdev, false); } } mutex_unlock(&rdev->pm.mutex); -- cgit v1.2.3 From 5876dd249e8e47c730cac090bf6edd88e5f04327 Mon Sep 17 00:00:00 2001 From: Matthew Garrett Date: Mon, 26 Apr 2010 15:52:20 -0400 Subject: radeon: Unmap vram pages when reclocking Touching vram while the card is reclocking can lead to lockups. Unmap any pages that could be touched by the CPU and block any accesses to vram until the reclocking is complete. Signed-off-by: Matthew Garrett Signed-off-by: Dave Airlie --- drivers/gpu/drm/radeon/radeon.h | 1 + drivers/gpu/drm/radeon/radeon_device.c | 1 + drivers/gpu/drm/radeon/radeon_object.c | 4 ++++ drivers/gpu/drm/radeon/radeon_pm.c | 28 ++++++++++++++++++++++++++++ drivers/gpu/drm/radeon/radeon_ttm.c | 6 +++++- 5 files changed, 39 insertions(+), 1 deletion(-) (limited to 'drivers/gpu/drm/radeon') diff --git a/drivers/gpu/drm/radeon/radeon.h b/drivers/gpu/drm/radeon/radeon.h index cdcf5eaf6714..bed84b316bba 100644 --- a/drivers/gpu/drm/radeon/radeon.h +++ b/drivers/gpu/drm/radeon/radeon.h @@ -1024,6 +1024,7 @@ struct radeon_device { struct work_struct hotplug_work; int num_crtc; /* number of crtcs */ struct mutex dc_hw_i2c_mutex; /* display controller hw i2c mutex */ + struct mutex vram_mutex; /* audio stuff */ struct timer_list audio_timer; diff --git a/drivers/gpu/drm/radeon/radeon_device.c b/drivers/gpu/drm/radeon/radeon_device.c index 53a2c27dd8fa..0372ec96020f 100644 --- a/drivers/gpu/drm/radeon/radeon_device.c +++ b/drivers/gpu/drm/radeon/radeon_device.c @@ -599,6 +599,7 @@ int radeon_device_init(struct radeon_device *rdev, spin_lock_init(&rdev->ih.lock); mutex_init(&rdev->gem.mutex); mutex_init(&rdev->pm.mutex); + mutex_init(&rdev->vram_mutex); rwlock_init(&rdev->fence_drv.lock); INIT_LIST_HEAD(&rdev->gem.objects); init_waitqueue_head(&rdev->irq.vblank_queue); diff --git a/drivers/gpu/drm/radeon/radeon_object.c b/drivers/gpu/drm/radeon/radeon_object.c index 6a8617bac142..06def708b014 100644 --- a/drivers/gpu/drm/radeon/radeon_object.c +++ b/drivers/gpu/drm/radeon/radeon_object.c @@ -112,9 +112,11 @@ int radeon_bo_create(struct radeon_device *rdev, struct drm_gem_object *gobj, radeon_ttm_placement_from_domain(bo, domain); /* Kernel allocation are uninterruptible */ + mutex_lock(&rdev->vram_mutex); r = ttm_bo_init(&rdev->mman.bdev, &bo->tbo, size, type, &bo->placement, 0, 0, !kernel, NULL, size, &radeon_ttm_bo_destroy); + mutex_unlock(&rdev->vram_mutex); if (unlikely(r != 0)) { if (r != -ERESTARTSYS) dev_err(rdev->dev, @@ -170,7 +172,9 @@ void radeon_bo_unref(struct radeon_bo **bo) if ((*bo) == NULL) return; tbo = &((*bo)->tbo); + mutex_lock(&(*bo)->rdev->vram_mutex); ttm_bo_unref(&tbo); + mutex_unlock(&(*bo)->rdev->vram_mutex); if (tbo == NULL) *bo = NULL; } diff --git a/drivers/gpu/drm/radeon/radeon_pm.c b/drivers/gpu/drm/radeon/radeon_pm.c index a61de1f9ff64..da35bd7f38dc 100644 --- a/drivers/gpu/drm/radeon/radeon_pm.c +++ b/drivers/gpu/drm/radeon/radeon_pm.c @@ -32,6 +32,28 @@ static void radeon_pm_idle_work_handler(struct work_struct *work); static int radeon_debugfs_pm_init(struct radeon_device *rdev); +static void radeon_unmap_vram_bos(struct radeon_device *rdev) +{ + struct radeon_bo *bo, *n; + + if (list_empty(&rdev->gem.objects)) + return; + + list_for_each_entry_safe(bo, n, &rdev->gem.objects, list) { + if (bo->tbo.mem.mem_type == TTM_PL_VRAM) + ttm_bo_unmap_virtual(&bo->tbo); + } + + if (rdev->gart.table.vram.robj) + ttm_bo_unmap_virtual(&rdev->gart.table.vram.robj->tbo); + + if (rdev->stollen_vga_memory) + ttm_bo_unmap_virtual(&rdev->stollen_vga_memory->tbo); + + if (rdev->r600_blit.shader_obj) + ttm_bo_unmap_virtual(&rdev->r600_blit.shader_obj->tbo); +} + static void radeon_pm_set_clocks(struct radeon_device *rdev, int static_switch) { int i; @@ -48,6 +70,10 @@ static void radeon_pm_set_clocks(struct radeon_device *rdev, int static_switch) rdev->irq.gui_idle = false; radeon_irq_set(rdev); + mutex_lock(&rdev->vram_mutex); + + radeon_unmap_vram_bos(rdev); + if (!static_switch) { for (i = 0; i < rdev->num_crtc; i++) { if (rdev->pm.active_crtcs & (1 << i)) { @@ -67,6 +93,8 @@ static void radeon_pm_set_clocks(struct radeon_device *rdev, int static_switch) } } } + + mutex_unlock(&rdev->vram_mutex); /* update display watermarks based on new power state */ radeon_update_bandwidth_info(rdev); diff --git a/drivers/gpu/drm/radeon/radeon_ttm.c b/drivers/gpu/drm/radeon/radeon_ttm.c index af98f45954b3..3aa3a65800ab 100644 --- a/drivers/gpu/drm/radeon/radeon_ttm.c +++ b/drivers/gpu/drm/radeon/radeon_ttm.c @@ -607,13 +607,17 @@ static const struct vm_operations_struct *ttm_vm_ops = NULL; static int radeon_ttm_fault(struct vm_area_struct *vma, struct vm_fault *vmf) { struct ttm_buffer_object *bo; + struct radeon_device *rdev; int r; - bo = (struct ttm_buffer_object *)vma->vm_private_data; + bo = (struct ttm_buffer_object *)vma->vm_private_data; if (bo == NULL) { return VM_FAULT_NOPAGE; } + rdev = radeon_get_rdev(bo->bdev); + mutex_lock(&rdev->vram_mutex); r = ttm_vm_ops->fault(vma, vmf); + mutex_unlock(&rdev->vram_mutex); return r; } -- cgit v1.2.3 From 8f5b5e632cd55d9acf10ba498b858fd996bd1a39 Mon Sep 17 00:00:00 2001 From: Matthew Garrett Date: Mon, 26 Apr 2010 15:57:01 -0400 Subject: radeon: Take drm struct_mutex over reclocking We need to block the drm core from doing anything that may touch our vram during reclock, so take the drm mutex for the duration. Signed-off-by: Matthew Garrett Signed-off-by: Dave Airlie --- drivers/gpu/drm/radeon/radeon_pm.c | 10 ++++++++++ 1 file changed, 10 insertions(+) (limited to 'drivers/gpu/drm/radeon') diff --git a/drivers/gpu/drm/radeon/radeon_pm.c b/drivers/gpu/drm/radeon/radeon_pm.c index da35bd7f38dc..c9390ea56f96 100644 --- a/drivers/gpu/drm/radeon/radeon_pm.c +++ b/drivers/gpu/drm/radeon/radeon_pm.c @@ -131,6 +131,7 @@ static ssize_t radeon_set_power_state_static(struct device *dev, return count; } + mutex_lock(&rdev->ddev->struct_mutex); mutex_lock(&rdev->pm.mutex); if ((ps >= 0) && (ps < rdev->pm.num_power_states) && (cm >= 0) && (cm < rdev->pm.power_state[ps].num_clock_modes)) { @@ -148,6 +149,7 @@ static ssize_t radeon_set_power_state_static(struct device *dev, } else DRM_ERROR("Invalid power state: %d.%d\n\n", ps, cm); mutex_unlock(&rdev->pm.mutex); + mutex_unlock(&rdev->ddev->struct_mutex); return count; } @@ -184,11 +186,13 @@ static ssize_t radeon_set_dynpm(struct device *dev, } else if (tmp == 1) { if (rdev->pm.num_power_states > 1) { /* enable dynpm */ + mutex_lock(&rdev->ddev->struct_mutex); mutex_lock(&rdev->pm.mutex); rdev->pm.state = PM_STATE_PAUSED; rdev->pm.planned_action = PM_ACTION_DEFAULT; radeon_get_power_state(rdev, rdev->pm.planned_action); mutex_unlock(&rdev->pm.mutex); + mutex_unlock(&rdev->ddev->struct_mutex); /* update power mode info */ radeon_pm_compute_clocks(rdev); DRM_INFO("radeon: dynamic power management enabled\n"); @@ -311,9 +315,11 @@ void radeon_pm_fini(struct radeon_device *rdev) (rdev->pm.current_clock_mode_index != 0)) { rdev->pm.requested_power_state_index = rdev->pm.default_power_state_index; rdev->pm.requested_clock_mode_index = 0; + mutex_lock(&rdev->ddev->struct_mutex); mutex_lock(&rdev->pm.mutex); radeon_pm_set_clocks(rdev, true); mutex_unlock(&rdev->pm.mutex); + mutex_unlock(&rdev->ddev->struct_mutex); } device_remove_file(rdev->dev, &dev_attr_power_state); @@ -332,6 +338,7 @@ void radeon_pm_compute_clocks(struct radeon_device *rdev) if (rdev->pm.state == PM_STATE_DISABLED) return; + mutex_lock(&rdev->ddev->struct_mutex); mutex_lock(&rdev->pm.mutex); rdev->pm.active_crtcs = 0; @@ -382,6 +389,7 @@ void radeon_pm_compute_clocks(struct radeon_device *rdev) } mutex_unlock(&rdev->pm.mutex); + mutex_unlock(&rdev->ddev->struct_mutex); } bool radeon_pm_debug_check_in_vbl(struct radeon_device *rdev, bool finish) @@ -455,6 +463,7 @@ static void radeon_pm_idle_work_handler(struct work_struct *work) rdev = container_of(work, struct radeon_device, pm.idle_work.work); + mutex_lock(&rdev->ddev->struct_mutex); mutex_lock(&rdev->pm.mutex); if (rdev->pm.state == PM_STATE_ACTIVE) { unsigned long irq_flags; @@ -499,6 +508,7 @@ static void radeon_pm_idle_work_handler(struct work_struct *work) } } mutex_unlock(&rdev->pm.mutex); + mutex_unlock(&rdev->ddev->struct_mutex); queue_delayed_work(rdev->wq, &rdev->pm.idle_work, msecs_to_jiffies(RADEON_IDLE_LOOP_MS)); -- cgit v1.2.3 From d9932a3241cc6a9629d6586ec362583cb77d7a29 Mon Sep 17 00:00:00 2001 From: Matthew Garrett Date: Mon, 26 Apr 2010 16:02:26 -0400 Subject: radeon: Stop the ttm workqueue while reclocking The ttm bo workqueue may touch objects while we're reclocking, so make sure it's blocked until we're done. Signed-off-by: Matthew Garrett Signed-off-by: Dave Airlie --- drivers/gpu/drm/radeon/radeon_pm.c | 3 +++ 1 file changed, 3 insertions(+) (limited to 'drivers/gpu/drm/radeon') diff --git a/drivers/gpu/drm/radeon/radeon_pm.c b/drivers/gpu/drm/radeon/radeon_pm.c index c9390ea56f96..79d3336eede5 100644 --- a/drivers/gpu/drm/radeon/radeon_pm.c +++ b/drivers/gpu/drm/radeon/radeon_pm.c @@ -460,9 +460,11 @@ bool radeon_pm_debug_check_in_vbl(struct radeon_device *rdev, bool finish) static void radeon_pm_idle_work_handler(struct work_struct *work) { struct radeon_device *rdev; + int resched; rdev = container_of(work, struct radeon_device, pm.idle_work.work); + resched = ttm_bo_lock_delayed_workqueue(&rdev->mman.bdev); mutex_lock(&rdev->ddev->struct_mutex); mutex_lock(&rdev->pm.mutex); if (rdev->pm.state == PM_STATE_ACTIVE) { @@ -509,6 +511,7 @@ static void radeon_pm_idle_work_handler(struct work_struct *work) } mutex_unlock(&rdev->pm.mutex); mutex_unlock(&rdev->ddev->struct_mutex); + ttm_bo_unlock_delayed_workqueue(&rdev->mman.bdev, resched); queue_delayed_work(rdev->wq, &rdev->pm.idle_work, msecs_to_jiffies(RADEON_IDLE_LOOP_MS)); -- cgit v1.2.3 From 956ac86d9277b7142f0ad3f24f7fbd4beed0777d Mon Sep 17 00:00:00 2001 From: Matthew Garrett Date: Mon, 26 Apr 2010 17:01:16 -0400 Subject: radeon: Enable memory reclockong on r600 With luck, dynamic memory reclocking on r600 should be stable with the previous patches. Enable it. Signed-off-by: Matthew Garrett Signed-off-by: Dave Airlie --- drivers/gpu/drm/radeon/r600.c | 16 +++++++--------- 1 file changed, 7 insertions(+), 9 deletions(-) (limited to 'drivers/gpu/drm/radeon') diff --git a/drivers/gpu/drm/radeon/r600.c b/drivers/gpu/drm/radeon/r600.c index 469130994064..1696cc277d8b 100644 --- a/drivers/gpu/drm/radeon/r600.c +++ b/drivers/gpu/drm/radeon/r600.c @@ -271,26 +271,27 @@ void r600_set_power_state(struct radeon_device *rdev, bool static_switch) radeon_pm_misc(rdev); if (static_switch) { - radeon_pm_prepare(rdev); + /* set engine clock */ if (sclk != rdev->pm.current_sclk) { radeon_set_engine_clock(rdev, sclk); rdev->pm.current_sclk = sclk; DRM_INFO("Setting: e: %d\n", sclk); } -#if 0 + /* set memory clock */ if (rdev->asic->set_memory_clock && (mclk != rdev->pm.current_mclk)) { + radeon_pm_prepare(rdev); radeon_set_memory_clock(rdev, mclk); + radeon_pm_finish(rdev); rdev->pm.current_mclk = mclk; DRM_INFO("Setting: m: %d\n", mclk); } -#endif - radeon_pm_finish(rdev); + } else { - /* set engine clock */ + radeon_sync_with_vblank(rdev); + if (sclk != rdev->pm.current_sclk) { - radeon_sync_with_vblank(rdev); radeon_pm_debug_check_in_vbl(rdev, false); radeon_set_engine_clock(rdev, sclk); radeon_pm_debug_check_in_vbl(rdev, true); @@ -298,10 +299,8 @@ void r600_set_power_state(struct radeon_device *rdev, bool static_switch) DRM_INFO("Setting: e: %d\n", sclk); } -#if 0 /* set memory clock */ if (rdev->asic->set_memory_clock && (mclk != rdev->pm.current_mclk)) { - radeon_sync_with_vblank(rdev); radeon_pm_debug_check_in_vbl(rdev, false); radeon_pm_prepare(rdev); radeon_set_memory_clock(rdev, mclk); @@ -310,7 +309,6 @@ void r600_set_power_state(struct radeon_device *rdev, bool static_switch) rdev->pm.current_mclk = mclk; DRM_INFO("Setting: m: %d\n", mclk); } -#endif } rdev->pm.current_power_state_index = rdev->pm.requested_power_state_index; -- cgit v1.2.3 From c37d230af450472183e70947f8e2aa8101a96603 Mon Sep 17 00:00:00 2001 From: Matthew Garrett Date: Tue, 27 Apr 2010 13:58:46 -0400 Subject: radeon: Make sure that we determine the correct PM state before transition We need to choose the correct PM state to transition into before starting the actual change. Call radeon_get_power_state() at the top of the clock setting to do so. Signed-off-by: Matthew Garrett Signed-off-by: Dave Airlie --- drivers/gpu/drm/radeon/radeon_pm.c | 3 +++ 1 file changed, 3 insertions(+) (limited to 'drivers/gpu/drm/radeon') diff --git a/drivers/gpu/drm/radeon/radeon_pm.c b/drivers/gpu/drm/radeon/radeon_pm.c index 79d3336eede5..7cc54c804cb0 100644 --- a/drivers/gpu/drm/radeon/radeon_pm.c +++ b/drivers/gpu/drm/radeon/radeon_pm.c @@ -58,6 +58,9 @@ static void radeon_pm_set_clocks(struct radeon_device *rdev, int static_switch) { int i; + if (!static_switch) + radeon_get_power_state(rdev, rdev->pm.planned_action); + mutex_lock(&rdev->cp.mutex); /* wait for GPU idle */ -- cgit v1.2.3 From 612e06ce9c78840c3a1a207dfbe489a059d87c28 Mon Sep 17 00:00:00 2001 From: Matthew Garrett Date: Tue, 27 Apr 2010 17:16:58 -0400 Subject: radeon: Fix locking in power management paths The ttm code could take vram_mutex followed by cp_mutex, while the reclocking code would do the reverse. Hilarity could ensue. Signed-off-by: Matthew Garrett Signed-off-by: Dave Airlie --- drivers/gpu/drm/radeon/radeon_pm.c | 18 ++++-------------- 1 file changed, 4 insertions(+), 14 deletions(-) (limited to 'drivers/gpu/drm/radeon') diff --git a/drivers/gpu/drm/radeon/radeon_pm.c b/drivers/gpu/drm/radeon/radeon_pm.c index 7cc54c804cb0..134b19537d11 100644 --- a/drivers/gpu/drm/radeon/radeon_pm.c +++ b/drivers/gpu/drm/radeon/radeon_pm.c @@ -61,6 +61,8 @@ static void radeon_pm_set_clocks(struct radeon_device *rdev, int static_switch) if (!static_switch) radeon_get_power_state(rdev, rdev->pm.planned_action); + mutex_lock(&rdev->ddev->struct_mutex); + mutex_lock(&rdev->vram_mutex); mutex_lock(&rdev->cp.mutex); /* wait for GPU idle */ @@ -73,8 +75,6 @@ static void radeon_pm_set_clocks(struct radeon_device *rdev, int static_switch) rdev->irq.gui_idle = false; radeon_irq_set(rdev); - mutex_lock(&rdev->vram_mutex); - radeon_unmap_vram_bos(rdev); if (!static_switch) { @@ -97,8 +97,6 @@ static void radeon_pm_set_clocks(struct radeon_device *rdev, int static_switch) } } - mutex_unlock(&rdev->vram_mutex); - /* update display watermarks based on new power state */ radeon_update_bandwidth_info(rdev); if (rdev->pm.active_crtc_count) @@ -107,6 +105,8 @@ static void radeon_pm_set_clocks(struct radeon_device *rdev, int static_switch) rdev->pm.planned_action = PM_ACTION_NONE; mutex_unlock(&rdev->cp.mutex); + mutex_unlock(&rdev->vram_mutex); + mutex_unlock(&rdev->ddev->struct_mutex); } static ssize_t radeon_get_power_state_static(struct device *dev, @@ -134,7 +134,6 @@ static ssize_t radeon_set_power_state_static(struct device *dev, return count; } - mutex_lock(&rdev->ddev->struct_mutex); mutex_lock(&rdev->pm.mutex); if ((ps >= 0) && (ps < rdev->pm.num_power_states) && (cm >= 0) && (cm < rdev->pm.power_state[ps].num_clock_modes)) { @@ -152,7 +151,6 @@ static ssize_t radeon_set_power_state_static(struct device *dev, } else DRM_ERROR("Invalid power state: %d.%d\n\n", ps, cm); mutex_unlock(&rdev->pm.mutex); - mutex_unlock(&rdev->ddev->struct_mutex); return count; } @@ -189,13 +187,11 @@ static ssize_t radeon_set_dynpm(struct device *dev, } else if (tmp == 1) { if (rdev->pm.num_power_states > 1) { /* enable dynpm */ - mutex_lock(&rdev->ddev->struct_mutex); mutex_lock(&rdev->pm.mutex); rdev->pm.state = PM_STATE_PAUSED; rdev->pm.planned_action = PM_ACTION_DEFAULT; radeon_get_power_state(rdev, rdev->pm.planned_action); mutex_unlock(&rdev->pm.mutex); - mutex_unlock(&rdev->ddev->struct_mutex); /* update power mode info */ radeon_pm_compute_clocks(rdev); DRM_INFO("radeon: dynamic power management enabled\n"); @@ -318,11 +314,9 @@ void radeon_pm_fini(struct radeon_device *rdev) (rdev->pm.current_clock_mode_index != 0)) { rdev->pm.requested_power_state_index = rdev->pm.default_power_state_index; rdev->pm.requested_clock_mode_index = 0; - mutex_lock(&rdev->ddev->struct_mutex); mutex_lock(&rdev->pm.mutex); radeon_pm_set_clocks(rdev, true); mutex_unlock(&rdev->pm.mutex); - mutex_unlock(&rdev->ddev->struct_mutex); } device_remove_file(rdev->dev, &dev_attr_power_state); @@ -341,7 +335,6 @@ void radeon_pm_compute_clocks(struct radeon_device *rdev) if (rdev->pm.state == PM_STATE_DISABLED) return; - mutex_lock(&rdev->ddev->struct_mutex); mutex_lock(&rdev->pm.mutex); rdev->pm.active_crtcs = 0; @@ -392,7 +385,6 @@ void radeon_pm_compute_clocks(struct radeon_device *rdev) } mutex_unlock(&rdev->pm.mutex); - mutex_unlock(&rdev->ddev->struct_mutex); } bool radeon_pm_debug_check_in_vbl(struct radeon_device *rdev, bool finish) @@ -468,7 +460,6 @@ static void radeon_pm_idle_work_handler(struct work_struct *work) pm.idle_work.work); resched = ttm_bo_lock_delayed_workqueue(&rdev->mman.bdev); - mutex_lock(&rdev->ddev->struct_mutex); mutex_lock(&rdev->pm.mutex); if (rdev->pm.state == PM_STATE_ACTIVE) { unsigned long irq_flags; @@ -513,7 +504,6 @@ static void radeon_pm_idle_work_handler(struct work_struct *work) } } mutex_unlock(&rdev->pm.mutex); - mutex_unlock(&rdev->ddev->struct_mutex); ttm_bo_unlock_delayed_workqueue(&rdev->mman.bdev, resched); queue_delayed_work(rdev->wq, &rdev->pm.idle_work, -- cgit v1.2.3 From f81f202402640c27b38e1452dcb4d3e447043f48 Mon Sep 17 00:00:00 2001 From: Matthew Garrett Date: Wed, 28 Apr 2010 12:13:06 -0400 Subject: radeon: Try harder to ensure we reclock in vblank The vblank interrupt on r600 doesn't seem to be especially reliable, so perform some sanity checks before the actual reclock. Signed-off-by: Matthew Garrett Signed-off-by: Dave Airlie --- drivers/gpu/drm/radeon/r500_reg.h | 2 ++ drivers/gpu/drm/radeon/r600.c | 26 ++++++++++++++++++++++++++ drivers/gpu/drm/radeon/radeon.h | 1 + drivers/gpu/drm/radeon/radeon_pm.c | 11 ++++++++++- 4 files changed, 39 insertions(+), 1 deletion(-) (limited to 'drivers/gpu/drm/radeon') diff --git a/drivers/gpu/drm/radeon/r500_reg.h b/drivers/gpu/drm/radeon/r500_reg.h index f5adf42a9d15..93c9a2bbccf8 100644 --- a/drivers/gpu/drm/radeon/r500_reg.h +++ b/drivers/gpu/drm/radeon/r500_reg.h @@ -351,6 +351,7 @@ #define AVIVO_D1CRTC_BLANK_CONTROL 0x6084 #define AVIVO_D1CRTC_INTERLACE_CONTROL 0x6088 #define AVIVO_D1CRTC_INTERLACE_STATUS 0x608c +#define AVIVO_D1CRTC_STATUS_POSITION 0x60a0 #define AVIVO_D1CRTC_FRAME_COUNT 0x60a4 #define AVIVO_D1CRTC_STEREO_CONTROL 0x60c4 @@ -489,6 +490,7 @@ #define AVIVO_D2CRTC_BLANK_CONTROL 0x6884 #define AVIVO_D2CRTC_INTERLACE_CONTROL 0x6888 #define AVIVO_D2CRTC_INTERLACE_STATUS 0x688c +#define AVIVO_D2CRTC_STATUS_POSITION 0x68a0 #define AVIVO_D2CRTC_FRAME_COUNT 0x68a4 #define AVIVO_D2CRTC_STEREO_CONTROL 0x68c4 diff --git a/drivers/gpu/drm/radeon/r600.c b/drivers/gpu/drm/radeon/r600.c index 1696cc277d8b..d3a79e0a9125 100644 --- a/drivers/gpu/drm/radeon/r600.c +++ b/drivers/gpu/drm/radeon/r600.c @@ -289,8 +289,34 @@ void r600_set_power_state(struct radeon_device *rdev, bool static_switch) } } else { + u32 position; + u32 vbl; + radeon_sync_with_vblank(rdev); + if (!radeon_pm_in_vbl(rdev)) + return; + + if (rdev->pm.active_crtcs & (1 << 0)) { + vbl = RREG32(AVIVO_D1CRTC_V_BLANK_START_END); + position = RREG32(AVIVO_D1CRTC_STATUS_POSITION); + position &= 0xfff; + vbl &= 0xfff; + + if (position < vbl && position > 1) + return; + } + + if (rdev->pm.active_crtcs & (1 << 1)) { + vbl = RREG32(AVIVO_D2CRTC_V_BLANK_START_END); + position = RREG32(AVIVO_D2CRTC_STATUS_POSITION); + position &= 0xfff; + vbl &= 0xfff; + + if (position < vbl && position > 1) + return; + } + if (sclk != rdev->pm.current_sclk) { radeon_pm_debug_check_in_vbl(rdev, false); radeon_set_engine_clock(rdev, sclk); diff --git a/drivers/gpu/drm/radeon/radeon.h b/drivers/gpu/drm/radeon/radeon.h index bed84b316bba..93ac88eb6b3a 100644 --- a/drivers/gpu/drm/radeon/radeon.h +++ b/drivers/gpu/drm/radeon/radeon.h @@ -175,6 +175,7 @@ void radeon_pm_fini(struct radeon_device *rdev); void radeon_pm_compute_clocks(struct radeon_device *rdev); void radeon_combios_get_power_modes(struct radeon_device *rdev); void radeon_atombios_get_power_modes(struct radeon_device *rdev); +bool radeon_pm_in_vbl(struct radeon_device *rdev); bool radeon_pm_debug_check_in_vbl(struct radeon_device *rdev, bool finish); void radeon_sync_with_vblank(struct radeon_device *rdev); diff --git a/drivers/gpu/drm/radeon/radeon_pm.c b/drivers/gpu/drm/radeon/radeon_pm.c index 134b19537d11..88163e043fcf 100644 --- a/drivers/gpu/drm/radeon/radeon_pm.c +++ b/drivers/gpu/drm/radeon/radeon_pm.c @@ -387,7 +387,7 @@ void radeon_pm_compute_clocks(struct radeon_device *rdev) mutex_unlock(&rdev->pm.mutex); } -bool radeon_pm_debug_check_in_vbl(struct radeon_device *rdev, bool finish) +bool radeon_pm_in_vbl(struct radeon_device *rdev) { u32 stat_crtc = 0; bool in_vbl = true; @@ -446,6 +446,15 @@ bool radeon_pm_debug_check_in_vbl(struct radeon_device *rdev, bool finish) in_vbl = false; } } + + return in_vbl; +} + +bool radeon_pm_debug_check_in_vbl(struct radeon_device *rdev, bool finish) +{ + u32 stat_crtc = 0; + bool in_vbl = radeon_pm_in_vbl(rdev); + if (in_vbl == false) DRM_INFO("not in vbl for pm change %08x at %s\n", stat_crtc, finish ? "exit" : "entry"); -- cgit v1.2.3 From 15a7df8db84e7a9d9915d879199ac4a870836c54 Mon Sep 17 00:00:00 2001 From: Matthew Garrett Date: Wed, 28 Apr 2010 14:45:05 -0400 Subject: radeon: Enable memory reclocking on r100-500 This seems to be relatively stable now, so enable it for these chipsets too. Signed-off-by: Matthew Garrett Signed-off-by: Dave Airlie --- drivers/gpu/drm/radeon/r100.c | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) (limited to 'drivers/gpu/drm/radeon') diff --git a/drivers/gpu/drm/radeon/r100.c b/drivers/gpu/drm/radeon/r100.c index 7675827c3a8d..87c4ffaf545e 100644 --- a/drivers/gpu/drm/radeon/r100.c +++ b/drivers/gpu/drm/radeon/r100.c @@ -188,9 +188,13 @@ void r100_set_power_state(struct radeon_device *rdev, bool static_switch) #endif radeon_pm_finish(rdev); } else { + radeon_sync_with_vblank(rdev); + + if (!radeon_pm_in_vbl(rdev)) + return; + /* set engine clock */ if (sclk != rdev->pm.current_sclk) { - radeon_sync_with_vblank(rdev); radeon_pm_debug_check_in_vbl(rdev, false); radeon_set_engine_clock(rdev, sclk); radeon_pm_debug_check_in_vbl(rdev, true); @@ -198,10 +202,8 @@ void r100_set_power_state(struct radeon_device *rdev, bool static_switch) DRM_INFO("Setting: e: %d\n", sclk); } -#if 0 /* set memory clock */ if (rdev->asic->set_memory_clock && (mclk != rdev->pm.current_mclk)) { - radeon_sync_with_vblank(rdev); radeon_pm_debug_check_in_vbl(rdev, false); radeon_pm_prepare(rdev); radeon_set_memory_clock(rdev, mclk); @@ -210,7 +212,6 @@ void r100_set_power_state(struct radeon_device *rdev, bool static_switch) rdev->pm.current_mclk = mclk; DRM_INFO("Setting: m: %d\n", mclk); } -#endif } rdev->pm.current_power_state_index = rdev->pm.requested_power_state_index; -- cgit v1.2.3 From 68adac5e49436992e9c999fbae879d9ac5b72d4e Mon Sep 17 00:00:00 2001 From: Ben Skeggs Date: Wed, 28 Apr 2010 11:46:42 +1000 Subject: drm: move radeon_fixed.h to shared drm_fixed.h header Will be used by nouveau driver also in the near future. Signed-off-by: Ben Skeggs Signed-off-by: Dave Airlie --- drivers/gpu/drm/radeon/atombios_crtc.c | 2 +- drivers/gpu/drm/radeon/r100.c | 194 +++++++++---------- drivers/gpu/drm/radeon/radeon_device.c | 24 +-- drivers/gpu/drm/radeon/radeon_display.c | 68 +++---- drivers/gpu/drm/radeon/radeon_fixed.h | 67 ------- drivers/gpu/drm/radeon/radeon_legacy_crtc.c | 2 +- drivers/gpu/drm/radeon/radeon_mode.h | 2 +- drivers/gpu/drm/radeon/rs690.c | 280 ++++++++++++++-------------- drivers/gpu/drm/radeon/rv515.c | 188 +++++++++---------- include/drm/drm_fixed.h | 67 +++++++ 10 files changed, 447 insertions(+), 447 deletions(-) delete mode 100644 drivers/gpu/drm/radeon/radeon_fixed.h create mode 100644 include/drm/drm_fixed.h (limited to 'drivers/gpu/drm/radeon') diff --git a/drivers/gpu/drm/radeon/atombios_crtc.c b/drivers/gpu/drm/radeon/atombios_crtc.c index b11aa37ed6d5..4151ad8affed 100644 --- a/drivers/gpu/drm/radeon/atombios_crtc.c +++ b/drivers/gpu/drm/radeon/atombios_crtc.c @@ -26,7 +26,7 @@ #include #include #include -#include "radeon_fixed.h" +#include #include "radeon.h" #include "atom.h" #include "atom-bits.h" diff --git a/drivers/gpu/drm/radeon/r100.c b/drivers/gpu/drm/radeon/r100.c index 87c4ffaf545e..a5f11c300f6a 100644 --- a/drivers/gpu/drm/radeon/r100.c +++ b/drivers/gpu/drm/radeon/r100.c @@ -2686,53 +2686,53 @@ void r100_bandwidth_update(struct radeon_device *rdev) fixed20_12 peak_disp_bw, mem_bw, pix_clk, pix_clk2, temp_ff, crit_point_ff; uint32_t temp, data, mem_trcd, mem_trp, mem_tras; fixed20_12 memtcas_ff[8] = { - fixed_init(1), - fixed_init(2), - fixed_init(3), - fixed_init(0), - fixed_init_half(1), - fixed_init_half(2), - fixed_init(0), + dfixed_init(1), + dfixed_init(2), + dfixed_init(3), + dfixed_init(0), + dfixed_init_half(1), + dfixed_init_half(2), + dfixed_init(0), }; fixed20_12 memtcas_rs480_ff[8] = { - fixed_init(0), - fixed_init(1), - fixed_init(2), - fixed_init(3), - fixed_init(0), - fixed_init_half(1), - fixed_init_half(2), - fixed_init_half(3), + dfixed_init(0), + dfixed_init(1), + dfixed_init(2), + dfixed_init(3), + dfixed_init(0), + dfixed_init_half(1), + dfixed_init_half(2), + dfixed_init_half(3), }; fixed20_12 memtcas2_ff[8] = { - fixed_init(0), - fixed_init(1), - fixed_init(2), - fixed_init(3), - fixed_init(4), - fixed_init(5), - fixed_init(6), - fixed_init(7), + dfixed_init(0), + dfixed_init(1), + dfixed_init(2), + dfixed_init(3), + dfixed_init(4), + dfixed_init(5), + dfixed_init(6), + dfixed_init(7), }; fixed20_12 memtrbs[8] = { - fixed_init(1), - fixed_init_half(1), - fixed_init(2), - fixed_init_half(2), - fixed_init(3), - fixed_init_half(3), - fixed_init(4), - fixed_init_half(4) + dfixed_init(1), + dfixed_init_half(1), + dfixed_init(2), + dfixed_init_half(2), + dfixed_init(3), + dfixed_init_half(3), + dfixed_init(4), + dfixed_init_half(4) }; fixed20_12 memtrbs_r4xx[8] = { - fixed_init(4), - fixed_init(5), - fixed_init(6), - fixed_init(7), - fixed_init(8), - fixed_init(9), - fixed_init(10), - fixed_init(11) + dfixed_init(4), + dfixed_init(5), + dfixed_init(6), + dfixed_init(7), + dfixed_init(8), + dfixed_init(9), + dfixed_init(10), + dfixed_init(11) }; fixed20_12 min_mem_eff; fixed20_12 mc_latency_sclk, mc_latency_mclk, k1; @@ -2763,7 +2763,7 @@ void r100_bandwidth_update(struct radeon_device *rdev) } } - min_mem_eff.full = rfixed_const_8(0); + min_mem_eff.full = dfixed_const_8(0); /* get modes */ if ((rdev->disp_priority == 2) && ASIC_IS_R300(rdev)) { uint32_t mc_init_misc_lat_timer = RREG32(R300_MC_INIT_MISC_LAT_TIMER); @@ -2784,28 +2784,28 @@ void r100_bandwidth_update(struct radeon_device *rdev) mclk_ff = rdev->pm.mclk; temp = (rdev->mc.vram_width / 8) * (rdev->mc.vram_is_ddr ? 2 : 1); - temp_ff.full = rfixed_const(temp); - mem_bw.full = rfixed_mul(mclk_ff, temp_ff); + temp_ff.full = dfixed_const(temp); + mem_bw.full = dfixed_mul(mclk_ff, temp_ff); pix_clk.full = 0; pix_clk2.full = 0; peak_disp_bw.full = 0; if (mode1) { - temp_ff.full = rfixed_const(1000); - pix_clk.full = rfixed_const(mode1->clock); /* convert to fixed point */ - pix_clk.full = rfixed_div(pix_clk, temp_ff); - temp_ff.full = rfixed_const(pixel_bytes1); - peak_disp_bw.full += rfixed_mul(pix_clk, temp_ff); + temp_ff.full = dfixed_const(1000); + pix_clk.full = dfixed_const(mode1->clock); /* convert to fixed point */ + pix_clk.full = dfixed_div(pix_clk, temp_ff); + temp_ff.full = dfixed_const(pixel_bytes1); + peak_disp_bw.full += dfixed_mul(pix_clk, temp_ff); } if (mode2) { - temp_ff.full = rfixed_const(1000); - pix_clk2.full = rfixed_const(mode2->clock); /* convert to fixed point */ - pix_clk2.full = rfixed_div(pix_clk2, temp_ff); - temp_ff.full = rfixed_const(pixel_bytes2); - peak_disp_bw.full += rfixed_mul(pix_clk2, temp_ff); + temp_ff.full = dfixed_const(1000); + pix_clk2.full = dfixed_const(mode2->clock); /* convert to fixed point */ + pix_clk2.full = dfixed_div(pix_clk2, temp_ff); + temp_ff.full = dfixed_const(pixel_bytes2); + peak_disp_bw.full += dfixed_mul(pix_clk2, temp_ff); } - mem_bw.full = rfixed_mul(mem_bw, min_mem_eff); + mem_bw.full = dfixed_mul(mem_bw, min_mem_eff); if (peak_disp_bw.full >= mem_bw.full) { DRM_ERROR("You may not have enough display bandwidth for current mode\n" "If you have flickering problem, try to lower resolution, refresh rate, or color depth\n"); @@ -2847,9 +2847,9 @@ void r100_bandwidth_update(struct radeon_device *rdev) mem_tras = ((temp >> 12) & 0xf) + 4; } /* convert to FF */ - trcd_ff.full = rfixed_const(mem_trcd); - trp_ff.full = rfixed_const(mem_trp); - tras_ff.full = rfixed_const(mem_tras); + trcd_ff.full = dfixed_const(mem_trcd); + trp_ff.full = dfixed_const(mem_trp); + tras_ff.full = dfixed_const(mem_tras); /* Get values from the MEM_SDRAM_MODE_REG register...converting its */ temp = RREG32(RADEON_MEM_SDRAM_MODE_REG); @@ -2867,7 +2867,7 @@ void r100_bandwidth_update(struct radeon_device *rdev) /* extra cas latency stored in bits 23-25 0-4 clocks */ data = (temp >> 23) & 0x7; if (data < 5) - tcas_ff.full += rfixed_const(data); + tcas_ff.full += dfixed_const(data); } if (ASIC_IS_R300(rdev) && !(rdev->flags & RADEON_IS_IGP)) { @@ -2904,72 +2904,72 @@ void r100_bandwidth_update(struct radeon_device *rdev) if (rdev->flags & RADEON_IS_AGP) { fixed20_12 agpmode_ff; - agpmode_ff.full = rfixed_const(radeon_agpmode); - temp_ff.full = rfixed_const_666(16); - sclk_eff_ff.full -= rfixed_mul(agpmode_ff, temp_ff); + agpmode_ff.full = dfixed_const(radeon_agpmode); + temp_ff.full = dfixed_const_666(16); + sclk_eff_ff.full -= dfixed_mul(agpmode_ff, temp_ff); } /* TODO PCIE lanes may affect this - agpmode == 16?? */ if (ASIC_IS_R300(rdev)) { - sclk_delay_ff.full = rfixed_const(250); + sclk_delay_ff.full = dfixed_const(250); } else { if ((rdev->family == CHIP_RV100) || rdev->flags & RADEON_IS_IGP) { if (rdev->mc.vram_is_ddr) - sclk_delay_ff.full = rfixed_const(41); + sclk_delay_ff.full = dfixed_const(41); else - sclk_delay_ff.full = rfixed_const(33); + sclk_delay_ff.full = dfixed_const(33); } else { if (rdev->mc.vram_width == 128) - sclk_delay_ff.full = rfixed_const(57); + sclk_delay_ff.full = dfixed_const(57); else - sclk_delay_ff.full = rfixed_const(41); + sclk_delay_ff.full = dfixed_const(41); } } - mc_latency_sclk.full = rfixed_div(sclk_delay_ff, sclk_eff_ff); + mc_latency_sclk.full = dfixed_div(sclk_delay_ff, sclk_eff_ff); if (rdev->mc.vram_is_ddr) { if (rdev->mc.vram_width == 32) { - k1.full = rfixed_const(40); + k1.full = dfixed_const(40); c = 3; } else { - k1.full = rfixed_const(20); + k1.full = dfixed_const(20); c = 1; } } else { - k1.full = rfixed_const(40); + k1.full = dfixed_const(40); c = 3; } - temp_ff.full = rfixed_const(2); - mc_latency_mclk.full = rfixed_mul(trcd_ff, temp_ff); - temp_ff.full = rfixed_const(c); - mc_latency_mclk.full += rfixed_mul(tcas_ff, temp_ff); - temp_ff.full = rfixed_const(4); - mc_latency_mclk.full += rfixed_mul(tras_ff, temp_ff); - mc_latency_mclk.full += rfixed_mul(trp_ff, temp_ff); + temp_ff.full = dfixed_const(2); + mc_latency_mclk.full = dfixed_mul(trcd_ff, temp_ff); + temp_ff.full = dfixed_const(c); + mc_latency_mclk.full += dfixed_mul(tcas_ff, temp_ff); + temp_ff.full = dfixed_const(4); + mc_latency_mclk.full += dfixed_mul(tras_ff, temp_ff); + mc_latency_mclk.full += dfixed_mul(trp_ff, temp_ff); mc_latency_mclk.full += k1.full; - mc_latency_mclk.full = rfixed_div(mc_latency_mclk, mclk_ff); - mc_latency_mclk.full += rfixed_div(temp_ff, sclk_eff_ff); + mc_latency_mclk.full = dfixed_div(mc_latency_mclk, mclk_ff); + mc_latency_mclk.full += dfixed_div(temp_ff, sclk_eff_ff); /* HW cursor time assuming worst case of full size colour cursor. */ - temp_ff.full = rfixed_const((2 * (cur_size - (rdev->mc.vram_is_ddr + 1)))); + temp_ff.full = dfixed_const((2 * (cur_size - (rdev->mc.vram_is_ddr + 1)))); temp_ff.full += trcd_ff.full; if (temp_ff.full < tras_ff.full) temp_ff.full = tras_ff.full; - cur_latency_mclk.full = rfixed_div(temp_ff, mclk_ff); + cur_latency_mclk.full = dfixed_div(temp_ff, mclk_ff); - temp_ff.full = rfixed_const(cur_size); - cur_latency_sclk.full = rfixed_div(temp_ff, sclk_eff_ff); + temp_ff.full = dfixed_const(cur_size); + cur_latency_sclk.full = dfixed_div(temp_ff, sclk_eff_ff); /* Find the total latency for the display data. */ - disp_latency_overhead.full = rfixed_const(8); - disp_latency_overhead.full = rfixed_div(disp_latency_overhead, sclk_ff); + disp_latency_overhead.full = dfixed_const(8); + disp_latency_overhead.full = dfixed_div(disp_latency_overhead, sclk_ff); mc_latency_mclk.full += disp_latency_overhead.full + cur_latency_mclk.full; mc_latency_sclk.full += disp_latency_overhead.full + cur_latency_sclk.full; @@ -2997,16 +2997,16 @@ void r100_bandwidth_update(struct radeon_device *rdev) /* Find the drain rate of the display buffer. */ - temp_ff.full = rfixed_const((16/pixel_bytes1)); - disp_drain_rate.full = rfixed_div(pix_clk, temp_ff); + temp_ff.full = dfixed_const((16/pixel_bytes1)); + disp_drain_rate.full = dfixed_div(pix_clk, temp_ff); /* Find the critical point of the display buffer. */ - crit_point_ff.full = rfixed_mul(disp_drain_rate, disp_latency); - crit_point_ff.full += rfixed_const_half(0); + crit_point_ff.full = dfixed_mul(disp_drain_rate, disp_latency); + crit_point_ff.full += dfixed_const_half(0); - critical_point = rfixed_trunc(crit_point_ff); + critical_point = dfixed_trunc(crit_point_ff); if (rdev->disp_priority == 2) { critical_point = 0; @@ -3077,8 +3077,8 @@ void r100_bandwidth_update(struct radeon_device *rdev) /* Find the drain rate of the display buffer. */ - temp_ff.full = rfixed_const((16/pixel_bytes2)); - disp_drain_rate2.full = rfixed_div(pix_clk2, temp_ff); + temp_ff.full = dfixed_const((16/pixel_bytes2)); + disp_drain_rate2.full = dfixed_div(pix_clk2, temp_ff); grph2_cntl = RREG32(RADEON_GRPH2_BUFFER_CNTL); grph2_cntl &= ~(RADEON_GRPH_STOP_REQ_MASK); @@ -3099,8 +3099,8 @@ void r100_bandwidth_update(struct radeon_device *rdev) critical_point2 = 0; else { temp = (rdev->mc.vram_width * rdev->mc.vram_is_ddr + 1)/128; - temp_ff.full = rfixed_const(temp); - temp_ff.full = rfixed_mul(mclk_ff, temp_ff); + temp_ff.full = dfixed_const(temp); + temp_ff.full = dfixed_mul(mclk_ff, temp_ff); if (sclk_ff.full < temp_ff.full) temp_ff.full = sclk_ff.full; @@ -3108,15 +3108,15 @@ void r100_bandwidth_update(struct radeon_device *rdev) if (mode1) { temp_ff.full = read_return_rate.full - disp_drain_rate.full; - time_disp1_drop_priority.full = rfixed_div(crit_point_ff, temp_ff); + time_disp1_drop_priority.full = dfixed_div(crit_point_ff, temp_ff); } else { time_disp1_drop_priority.full = 0; } crit_point_ff.full = disp_latency.full + time_disp1_drop_priority.full + disp_latency.full; - crit_point_ff.full = rfixed_mul(crit_point_ff, disp_drain_rate2); - crit_point_ff.full += rfixed_const_half(0); + crit_point_ff.full = dfixed_mul(crit_point_ff, disp_drain_rate2); + crit_point_ff.full += dfixed_const_half(0); - critical_point2 = rfixed_trunc(crit_point_ff); + critical_point2 = dfixed_trunc(crit_point_ff); if (rdev->disp_priority == 2) { critical_point2 = 0; diff --git a/drivers/gpu/drm/radeon/radeon_device.c b/drivers/gpu/drm/radeon/radeon_device.c index 0372ec96020f..e249da81dbfc 100644 --- a/drivers/gpu/drm/radeon/radeon_device.c +++ b/drivers/gpu/drm/radeon/radeon_device.c @@ -299,24 +299,24 @@ void radeon_update_bandwidth_info(struct radeon_device *rdev) sclk = radeon_get_engine_clock(rdev); mclk = rdev->clock.default_mclk; - a.full = rfixed_const(100); - rdev->pm.sclk.full = rfixed_const(sclk); - rdev->pm.sclk.full = rfixed_div(rdev->pm.sclk, a); - rdev->pm.mclk.full = rfixed_const(mclk); - rdev->pm.mclk.full = rfixed_div(rdev->pm.mclk, a); + a.full = dfixed_const(100); + rdev->pm.sclk.full = dfixed_const(sclk); + rdev->pm.sclk.full = dfixed_div(rdev->pm.sclk, a); + rdev->pm.mclk.full = dfixed_const(mclk); + rdev->pm.mclk.full = dfixed_div(rdev->pm.mclk, a); - a.full = rfixed_const(16); + a.full = dfixed_const(16); /* core_bandwidth = sclk(Mhz) * 16 */ - rdev->pm.core_bandwidth.full = rfixed_div(rdev->pm.sclk, a); + rdev->pm.core_bandwidth.full = dfixed_div(rdev->pm.sclk, a); } else { sclk = radeon_get_engine_clock(rdev); mclk = radeon_get_memory_clock(rdev); - a.full = rfixed_const(100); - rdev->pm.sclk.full = rfixed_const(sclk); - rdev->pm.sclk.full = rfixed_div(rdev->pm.sclk, a); - rdev->pm.mclk.full = rfixed_const(mclk); - rdev->pm.mclk.full = rfixed_div(rdev->pm.mclk, a); + a.full = dfixed_const(100); + rdev->pm.sclk.full = dfixed_const(sclk); + rdev->pm.sclk.full = dfixed_div(rdev->pm.sclk, a); + rdev->pm.mclk.full = dfixed_const(mclk); + rdev->pm.mclk.full = dfixed_div(rdev->pm.mclk, a); } } diff --git a/drivers/gpu/drm/radeon/radeon_display.c b/drivers/gpu/drm/radeon/radeon_display.c index bc9cc9211e67..10d70540fc50 100644 --- a/drivers/gpu/drm/radeon/radeon_display.c +++ b/drivers/gpu/drm/radeon/radeon_display.c @@ -633,37 +633,37 @@ calc_fb_div(struct radeon_pll *pll, vco_freq = freq * post_div; /* feedback_divider = vco_freq * ref_div / pll->reference_freq; */ - a.full = rfixed_const(pll->reference_freq); - feedback_divider.full = rfixed_const(vco_freq); - feedback_divider.full = rfixed_div(feedback_divider, a); - a.full = rfixed_const(ref_div); - feedback_divider.full = rfixed_mul(feedback_divider, a); + a.full = dfixed_const(pll->reference_freq); + feedback_divider.full = dfixed_const(vco_freq); + feedback_divider.full = dfixed_div(feedback_divider, a); + a.full = dfixed_const(ref_div); + feedback_divider.full = dfixed_mul(feedback_divider, a); if (pll->flags & RADEON_PLL_USE_FRAC_FB_DIV) { /* feedback_divider = floor((feedback_divider * 10.0) + 0.5) * 0.1; */ - a.full = rfixed_const(10); - feedback_divider.full = rfixed_mul(feedback_divider, a); - feedback_divider.full += rfixed_const_half(0); - feedback_divider.full = rfixed_floor(feedback_divider); - feedback_divider.full = rfixed_div(feedback_divider, a); + a.full = dfixed_const(10); + feedback_divider.full = dfixed_mul(feedback_divider, a); + feedback_divider.full += dfixed_const_half(0); + feedback_divider.full = dfixed_floor(feedback_divider); + feedback_divider.full = dfixed_div(feedback_divider, a); /* *fb_div = floor(feedback_divider); */ - a.full = rfixed_floor(feedback_divider); - *fb_div = rfixed_trunc(a); + a.full = dfixed_floor(feedback_divider); + *fb_div = dfixed_trunc(a); /* *fb_div_frac = fmod(feedback_divider, 1.0) * 10.0; */ - a.full = rfixed_const(10); - b.full = rfixed_mul(feedback_divider, a); + a.full = dfixed_const(10); + b.full = dfixed_mul(feedback_divider, a); - feedback_divider.full = rfixed_floor(feedback_divider); - feedback_divider.full = rfixed_mul(feedback_divider, a); + feedback_divider.full = dfixed_floor(feedback_divider); + feedback_divider.full = dfixed_mul(feedback_divider, a); feedback_divider.full = b.full - feedback_divider.full; - *fb_div_frac = rfixed_trunc(feedback_divider); + *fb_div_frac = dfixed_trunc(feedback_divider); } else { /* *fb_div = floor(feedback_divider + 0.5); */ - feedback_divider.full += rfixed_const_half(0); - feedback_divider.full = rfixed_floor(feedback_divider); + feedback_divider.full += dfixed_const_half(0); + feedback_divider.full = dfixed_floor(feedback_divider); - *fb_div = rfixed_trunc(feedback_divider); + *fb_div = dfixed_trunc(feedback_divider); *fb_div_frac = 0; } @@ -693,10 +693,10 @@ calc_fb_ref_div(struct radeon_pll *pll, pll_out_max = pll->pll_out_max; } - ffreq.full = rfixed_const(freq); + ffreq.full = dfixed_const(freq); /* max_error = ffreq * 0.0025; */ - a.full = rfixed_const(400); - max_error.full = rfixed_div(ffreq, a); + a.full = dfixed_const(400); + max_error.full = dfixed_div(ffreq, a); for ((*ref_div) = pll->min_ref_div; (*ref_div) < pll->max_ref_div; ++(*ref_div)) { if (calc_fb_div(pll, freq, post_div, (*ref_div), fb_div, fb_div_frac)) { @@ -707,9 +707,9 @@ calc_fb_ref_div(struct radeon_pll *pll, continue; /* pll_out = vco / post_div; */ - a.full = rfixed_const(post_div); - pll_out.full = rfixed_const(vco); - pll_out.full = rfixed_div(pll_out, a); + a.full = dfixed_const(post_div); + pll_out.full = dfixed_const(vco); + pll_out.full = dfixed_div(pll_out, a); if (pll_out.full >= ffreq.full) { error.full = pll_out.full - ffreq.full; @@ -1099,15 +1099,15 @@ bool radeon_crtc_scaling_mode_fixup(struct drm_crtc *crtc, } if (radeon_crtc->rmx_type != RMX_OFF) { fixed20_12 a, b; - a.full = rfixed_const(crtc->mode.vdisplay); - b.full = rfixed_const(radeon_crtc->native_mode.hdisplay); - radeon_crtc->vsc.full = rfixed_div(a, b); - a.full = rfixed_const(crtc->mode.hdisplay); - b.full = rfixed_const(radeon_crtc->native_mode.vdisplay); - radeon_crtc->hsc.full = rfixed_div(a, b); + a.full = dfixed_const(crtc->mode.vdisplay); + b.full = dfixed_const(radeon_crtc->native_mode.hdisplay); + radeon_crtc->vsc.full = dfixed_div(a, b); + a.full = dfixed_const(crtc->mode.hdisplay); + b.full = dfixed_const(radeon_crtc->native_mode.vdisplay); + radeon_crtc->hsc.full = dfixed_div(a, b); } else { - radeon_crtc->vsc.full = rfixed_const(1); - radeon_crtc->hsc.full = rfixed_const(1); + radeon_crtc->vsc.full = dfixed_const(1); + radeon_crtc->hsc.full = dfixed_const(1); } return true; } diff --git a/drivers/gpu/drm/radeon/radeon_fixed.h b/drivers/gpu/drm/radeon/radeon_fixed.h deleted file mode 100644 index 3d4d84e078ac..000000000000 --- a/drivers/gpu/drm/radeon/radeon_fixed.h +++ /dev/null @@ -1,67 +0,0 @@ -/* - * Copyright 2009 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: Dave Airlie - */ -#ifndef RADEON_FIXED_H -#define RADEON_FIXED_H - -typedef union rfixed { - u32 full; -} fixed20_12; - - -#define rfixed_const(A) (u32)(((A) << 12))/* + ((B + 0.000122)*4096)) */ -#define rfixed_const_half(A) (u32)(((A) << 12) + 2048) -#define rfixed_const_666(A) (u32)(((A) << 12) + 2731) -#define rfixed_const_8(A) (u32)(((A) << 12) + 3277) -#define rfixed_mul(A, B) ((u64)((u64)(A).full * (B).full + 2048) >> 12) -#define fixed_init(A) { .full = rfixed_const((A)) } -#define fixed_init_half(A) { .full = rfixed_const_half((A)) } -#define rfixed_trunc(A) ((A).full >> 12) - -static inline u32 rfixed_floor(fixed20_12 A) -{ - u32 non_frac = rfixed_trunc(A); - - return rfixed_const(non_frac); -} - -static inline u32 rfixed_ceil(fixed20_12 A) -{ - u32 non_frac = rfixed_trunc(A); - - if (A.full > rfixed_const(non_frac)) - return rfixed_const(non_frac + 1); - else - return rfixed_const(non_frac); -} - -static inline u32 rfixed_div(fixed20_12 A, fixed20_12 B) -{ - u64 tmp = ((u64)A.full << 13); - - do_div(tmp, B.full); - tmp += 1; - tmp /= 2; - return lower_32_bits(tmp); -} -#endif diff --git a/drivers/gpu/drm/radeon/radeon_legacy_crtc.c b/drivers/gpu/drm/radeon/radeon_legacy_crtc.c index f4f9cb297e36..7701d42c4804 100644 --- a/drivers/gpu/drm/radeon/radeon_legacy_crtc.c +++ b/drivers/gpu/drm/radeon/radeon_legacy_crtc.c @@ -26,7 +26,7 @@ #include #include #include -#include "radeon_fixed.h" +#include #include "radeon.h" #include "atom.h" diff --git a/drivers/gpu/drm/radeon/radeon_mode.h b/drivers/gpu/drm/radeon/radeon_mode.h index 061a2a6801cc..38c0b63e9bbd 100644 --- a/drivers/gpu/drm/radeon/radeon_mode.h +++ b/drivers/gpu/drm/radeon/radeon_mode.h @@ -34,10 +34,10 @@ #include #include #include +#include #include #include #include -#include "radeon_fixed.h" struct radeon_bo; struct radeon_device; diff --git a/drivers/gpu/drm/radeon/rs690.c b/drivers/gpu/drm/radeon/rs690.c index 56a0aec84af2..e8edfe617286 100644 --- a/drivers/gpu/drm/radeon/rs690.c +++ b/drivers/gpu/drm/radeon/rs690.c @@ -76,59 +76,59 @@ void rs690_pm_info(struct radeon_device *rdev) /* Get various system informations from bios */ switch (crev) { case 1: - tmp.full = rfixed_const(100); - rdev->pm.igp_sideport_mclk.full = rfixed_const(info->info.ulBootUpMemoryClock); - rdev->pm.igp_sideport_mclk.full = rfixed_div(rdev->pm.igp_sideport_mclk, tmp); - rdev->pm.igp_system_mclk.full = rfixed_const(le16_to_cpu(info->info.usK8MemoryClock)); - rdev->pm.igp_ht_link_clk.full = rfixed_const(le16_to_cpu(info->info.usFSBClock)); - rdev->pm.igp_ht_link_width.full = rfixed_const(info->info.ucHTLinkWidth); + tmp.full = dfixed_const(100); + rdev->pm.igp_sideport_mclk.full = dfixed_const(info->info.ulBootUpMemoryClock); + rdev->pm.igp_sideport_mclk.full = dfixed_div(rdev->pm.igp_sideport_mclk, tmp); + rdev->pm.igp_system_mclk.full = dfixed_const(le16_to_cpu(info->info.usK8MemoryClock)); + rdev->pm.igp_ht_link_clk.full = dfixed_const(le16_to_cpu(info->info.usFSBClock)); + rdev->pm.igp_ht_link_width.full = dfixed_const(info->info.ucHTLinkWidth); break; case 2: - tmp.full = rfixed_const(100); - rdev->pm.igp_sideport_mclk.full = rfixed_const(info->info_v2.ulBootUpSidePortClock); - rdev->pm.igp_sideport_mclk.full = rfixed_div(rdev->pm.igp_sideport_mclk, tmp); - rdev->pm.igp_system_mclk.full = rfixed_const(info->info_v2.ulBootUpUMAClock); - rdev->pm.igp_system_mclk.full = rfixed_div(rdev->pm.igp_system_mclk, tmp); - rdev->pm.igp_ht_link_clk.full = rfixed_const(info->info_v2.ulHTLinkFreq); - rdev->pm.igp_ht_link_clk.full = rfixed_div(rdev->pm.igp_ht_link_clk, tmp); - rdev->pm.igp_ht_link_width.full = rfixed_const(le16_to_cpu(info->info_v2.usMinHTLinkWidth)); + tmp.full = dfixed_const(100); + rdev->pm.igp_sideport_mclk.full = dfixed_const(info->info_v2.ulBootUpSidePortClock); + rdev->pm.igp_sideport_mclk.full = dfixed_div(rdev->pm.igp_sideport_mclk, tmp); + rdev->pm.igp_system_mclk.full = dfixed_const(info->info_v2.ulBootUpUMAClock); + rdev->pm.igp_system_mclk.full = dfixed_div(rdev->pm.igp_system_mclk, tmp); + rdev->pm.igp_ht_link_clk.full = dfixed_const(info->info_v2.ulHTLinkFreq); + rdev->pm.igp_ht_link_clk.full = dfixed_div(rdev->pm.igp_ht_link_clk, tmp); + rdev->pm.igp_ht_link_width.full = dfixed_const(le16_to_cpu(info->info_v2.usMinHTLinkWidth)); break; default: - tmp.full = rfixed_const(100); + tmp.full = dfixed_const(100); /* We assume the slower possible clock ie worst case */ /* DDR 333Mhz */ - rdev->pm.igp_sideport_mclk.full = rfixed_const(333); + rdev->pm.igp_sideport_mclk.full = dfixed_const(333); /* FIXME: system clock ? */ - rdev->pm.igp_system_mclk.full = rfixed_const(100); - rdev->pm.igp_system_mclk.full = rfixed_div(rdev->pm.igp_system_mclk, tmp); - rdev->pm.igp_ht_link_clk.full = rfixed_const(200); - rdev->pm.igp_ht_link_width.full = rfixed_const(8); + rdev->pm.igp_system_mclk.full = dfixed_const(100); + rdev->pm.igp_system_mclk.full = dfixed_div(rdev->pm.igp_system_mclk, tmp); + rdev->pm.igp_ht_link_clk.full = dfixed_const(200); + rdev->pm.igp_ht_link_width.full = dfixed_const(8); DRM_ERROR("No integrated system info for your GPU, using safe default\n"); break; } } else { - tmp.full = rfixed_const(100); + tmp.full = dfixed_const(100); /* We assume the slower possible clock ie worst case */ /* DDR 333Mhz */ - rdev->pm.igp_sideport_mclk.full = rfixed_const(333); + rdev->pm.igp_sideport_mclk.full = dfixed_const(333); /* FIXME: system clock ? */ - rdev->pm.igp_system_mclk.full = rfixed_const(100); - rdev->pm.igp_system_mclk.full = rfixed_div(rdev->pm.igp_system_mclk, tmp); - rdev->pm.igp_ht_link_clk.full = rfixed_const(200); - rdev->pm.igp_ht_link_width.full = rfixed_const(8); + rdev->pm.igp_system_mclk.full = dfixed_const(100); + rdev->pm.igp_system_mclk.full = dfixed_div(rdev->pm.igp_system_mclk, tmp); + rdev->pm.igp_ht_link_clk.full = dfixed_const(200); + rdev->pm.igp_ht_link_width.full = dfixed_const(8); DRM_ERROR("No integrated system info for your GPU, using safe default\n"); } /* Compute various bandwidth */ /* k8_bandwidth = (memory_clk / 2) * 2 * 8 * 0.5 = memory_clk * 4 */ - tmp.full = rfixed_const(4); - rdev->pm.k8_bandwidth.full = rfixed_mul(rdev->pm.igp_system_mclk, tmp); + tmp.full = dfixed_const(4); + rdev->pm.k8_bandwidth.full = dfixed_mul(rdev->pm.igp_system_mclk, tmp); /* ht_bandwidth = ht_clk * 2 * ht_width / 8 * 0.8 * = ht_clk * ht_width / 5 */ - tmp.full = rfixed_const(5); - rdev->pm.ht_bandwidth.full = rfixed_mul(rdev->pm.igp_ht_link_clk, + tmp.full = dfixed_const(5); + rdev->pm.ht_bandwidth.full = dfixed_mul(rdev->pm.igp_ht_link_clk, rdev->pm.igp_ht_link_width); - rdev->pm.ht_bandwidth.full = rfixed_div(rdev->pm.ht_bandwidth, tmp); + rdev->pm.ht_bandwidth.full = dfixed_div(rdev->pm.ht_bandwidth, tmp); if (tmp.full < rdev->pm.max_bandwidth.full) { /* HT link is a limiting factor */ rdev->pm.max_bandwidth.full = tmp.full; @@ -136,10 +136,10 @@ void rs690_pm_info(struct radeon_device *rdev) /* sideport_bandwidth = (sideport_clk / 2) * 2 * 2 * 0.7 * = (sideport_clk * 14) / 10 */ - tmp.full = rfixed_const(14); - rdev->pm.sideport_bandwidth.full = rfixed_mul(rdev->pm.igp_sideport_mclk, tmp); - tmp.full = rfixed_const(10); - rdev->pm.sideport_bandwidth.full = rfixed_div(rdev->pm.sideport_bandwidth, tmp); + tmp.full = dfixed_const(14); + rdev->pm.sideport_bandwidth.full = dfixed_mul(rdev->pm.igp_sideport_mclk, tmp); + tmp.full = dfixed_const(10); + rdev->pm.sideport_bandwidth.full = dfixed_div(rdev->pm.sideport_bandwidth, tmp); } void rs690_mc_init(struct radeon_device *rdev) @@ -239,20 +239,20 @@ void rs690_crtc_bandwidth_compute(struct radeon_device *rdev, return; } - if (crtc->vsc.full > rfixed_const(2)) - wm->num_line_pair.full = rfixed_const(2); + if (crtc->vsc.full > dfixed_const(2)) + wm->num_line_pair.full = dfixed_const(2); else - wm->num_line_pair.full = rfixed_const(1); - - b.full = rfixed_const(mode->crtc_hdisplay); - c.full = rfixed_const(256); - a.full = rfixed_div(b, c); - request_fifo_depth.full = rfixed_mul(a, wm->num_line_pair); - request_fifo_depth.full = rfixed_ceil(request_fifo_depth); - if (a.full < rfixed_const(4)) { + wm->num_line_pair.full = dfixed_const(1); + + b.full = dfixed_const(mode->crtc_hdisplay); + c.full = dfixed_const(256); + a.full = dfixed_div(b, c); + request_fifo_depth.full = dfixed_mul(a, wm->num_line_pair); + request_fifo_depth.full = dfixed_ceil(request_fifo_depth); + if (a.full < dfixed_const(4)) { wm->lb_request_fifo_depth = 4; } else { - wm->lb_request_fifo_depth = rfixed_trunc(request_fifo_depth); + wm->lb_request_fifo_depth = dfixed_trunc(request_fifo_depth); } /* Determine consumption rate @@ -261,23 +261,23 @@ void rs690_crtc_bandwidth_compute(struct radeon_device *rdev, * vsc = vertical scaling ratio, defined as source/destination * hsc = horizontal scaling ration, defined as source/destination */ - a.full = rfixed_const(mode->clock); - b.full = rfixed_const(1000); - a.full = rfixed_div(a, b); - pclk.full = rfixed_div(b, a); + a.full = dfixed_const(mode->clock); + b.full = dfixed_const(1000); + a.full = dfixed_div(a, b); + pclk.full = dfixed_div(b, a); if (crtc->rmx_type != RMX_OFF) { - b.full = rfixed_const(2); + b.full = dfixed_const(2); if (crtc->vsc.full > b.full) b.full = crtc->vsc.full; - b.full = rfixed_mul(b, crtc->hsc); - c.full = rfixed_const(2); - b.full = rfixed_div(b, c); - consumption_time.full = rfixed_div(pclk, b); + b.full = dfixed_mul(b, crtc->hsc); + c.full = dfixed_const(2); + b.full = dfixed_div(b, c); + consumption_time.full = dfixed_div(pclk, b); } else { consumption_time.full = pclk.full; } - a.full = rfixed_const(1); - wm->consumption_rate.full = rfixed_div(a, consumption_time); + a.full = dfixed_const(1); + wm->consumption_rate.full = dfixed_div(a, consumption_time); /* Determine line time @@ -285,18 +285,18 @@ void rs690_crtc_bandwidth_compute(struct radeon_device *rdev, * LineTime = total number of horizontal pixels * pclk = pixel clock period(ns) */ - a.full = rfixed_const(crtc->base.mode.crtc_htotal); - line_time.full = rfixed_mul(a, pclk); + a.full = dfixed_const(crtc->base.mode.crtc_htotal); + line_time.full = dfixed_mul(a, pclk); /* Determine active time * ActiveTime = time of active region of display within one line, * hactive = total number of horizontal active pixels * htotal = total number of horizontal pixels */ - a.full = rfixed_const(crtc->base.mode.crtc_htotal); - b.full = rfixed_const(crtc->base.mode.crtc_hdisplay); - wm->active_time.full = rfixed_mul(line_time, b); - wm->active_time.full = rfixed_div(wm->active_time, a); + a.full = dfixed_const(crtc->base.mode.crtc_htotal); + b.full = dfixed_const(crtc->base.mode.crtc_hdisplay); + wm->active_time.full = dfixed_mul(line_time, b); + wm->active_time.full = dfixed_div(wm->active_time, a); /* Maximun bandwidth is the minimun bandwidth of all component */ rdev->pm.max_bandwidth = rdev->pm.core_bandwidth; @@ -304,8 +304,8 @@ void rs690_crtc_bandwidth_compute(struct radeon_device *rdev, if (rdev->pm.max_bandwidth.full > rdev->pm.sideport_bandwidth.full && rdev->pm.sideport_bandwidth.full) rdev->pm.max_bandwidth = rdev->pm.sideport_bandwidth; - read_delay_latency.full = rfixed_const(370 * 800 * 1000); - read_delay_latency.full = rfixed_div(read_delay_latency, + read_delay_latency.full = dfixed_const(370 * 800 * 1000); + read_delay_latency.full = dfixed_div(read_delay_latency, rdev->pm.igp_sideport_mclk); } else { if (rdev->pm.max_bandwidth.full > rdev->pm.k8_bandwidth.full && @@ -314,23 +314,23 @@ void rs690_crtc_bandwidth_compute(struct radeon_device *rdev, if (rdev->pm.max_bandwidth.full > rdev->pm.ht_bandwidth.full && rdev->pm.ht_bandwidth.full) rdev->pm.max_bandwidth = rdev->pm.ht_bandwidth; - read_delay_latency.full = rfixed_const(5000); + read_delay_latency.full = dfixed_const(5000); } /* sclk = system clocks(ns) = 1000 / max_bandwidth / 16 */ - a.full = rfixed_const(16); - rdev->pm.sclk.full = rfixed_mul(rdev->pm.max_bandwidth, a); - a.full = rfixed_const(1000); - rdev->pm.sclk.full = rfixed_div(a, rdev->pm.sclk); + a.full = dfixed_const(16); + rdev->pm.sclk.full = dfixed_mul(rdev->pm.max_bandwidth, a); + a.full = dfixed_const(1000); + rdev->pm.sclk.full = dfixed_div(a, rdev->pm.sclk); /* Determine chunk time * ChunkTime = the time it takes the DCP to send one chunk of data * to the LB which consists of pipeline delay and inter chunk gap * sclk = system clock(ns) */ - a.full = rfixed_const(256 * 13); - chunk_time.full = rfixed_mul(rdev->pm.sclk, a); - a.full = rfixed_const(10); - chunk_time.full = rfixed_div(chunk_time, a); + a.full = dfixed_const(256 * 13); + chunk_time.full = dfixed_mul(rdev->pm.sclk, a); + a.full = dfixed_const(10); + chunk_time.full = dfixed_div(chunk_time, a); /* Determine the worst case latency * NumLinePair = Number of line pairs to request(1=2 lines, 2=4 lines) @@ -340,13 +340,13 @@ void rs690_crtc_bandwidth_compute(struct radeon_device *rdev, * ChunkTime = time it takes the DCP to send one chunk of data to the LB * which consists of pipeline delay and inter chunk gap */ - if (rfixed_trunc(wm->num_line_pair) > 1) { - a.full = rfixed_const(3); - wm->worst_case_latency.full = rfixed_mul(a, chunk_time); + if (dfixed_trunc(wm->num_line_pair) > 1) { + a.full = dfixed_const(3); + wm->worst_case_latency.full = dfixed_mul(a, chunk_time); wm->worst_case_latency.full += read_delay_latency.full; } else { - a.full = rfixed_const(2); - wm->worst_case_latency.full = rfixed_mul(a, chunk_time); + a.full = dfixed_const(2); + wm->worst_case_latency.full = dfixed_mul(a, chunk_time); wm->worst_case_latency.full += read_delay_latency.full; } @@ -360,34 +360,34 @@ void rs690_crtc_bandwidth_compute(struct radeon_device *rdev, * of data to the LB which consists of * pipeline delay and inter chunk gap */ - if ((2+wm->lb_request_fifo_depth) >= rfixed_trunc(request_fifo_depth)) { + if ((2+wm->lb_request_fifo_depth) >= dfixed_trunc(request_fifo_depth)) { tolerable_latency.full = line_time.full; } else { - tolerable_latency.full = rfixed_const(wm->lb_request_fifo_depth - 2); + tolerable_latency.full = dfixed_const(wm->lb_request_fifo_depth - 2); tolerable_latency.full = request_fifo_depth.full - tolerable_latency.full; - tolerable_latency.full = rfixed_mul(tolerable_latency, chunk_time); + tolerable_latency.full = dfixed_mul(tolerable_latency, chunk_time); tolerable_latency.full = line_time.full - tolerable_latency.full; } /* We assume worst case 32bits (4 bytes) */ - wm->dbpp.full = rfixed_const(4 * 8); + wm->dbpp.full = dfixed_const(4 * 8); /* Determine the maximum priority mark * width = viewport width in pixels */ - a.full = rfixed_const(16); - wm->priority_mark_max.full = rfixed_const(crtc->base.mode.crtc_hdisplay); - wm->priority_mark_max.full = rfixed_div(wm->priority_mark_max, a); - wm->priority_mark_max.full = rfixed_ceil(wm->priority_mark_max); + a.full = dfixed_const(16); + wm->priority_mark_max.full = dfixed_const(crtc->base.mode.crtc_hdisplay); + wm->priority_mark_max.full = dfixed_div(wm->priority_mark_max, a); + wm->priority_mark_max.full = dfixed_ceil(wm->priority_mark_max); /* Determine estimated width */ estimated_width.full = tolerable_latency.full - wm->worst_case_latency.full; - estimated_width.full = rfixed_div(estimated_width, consumption_time); - if (rfixed_trunc(estimated_width) > crtc->base.mode.crtc_hdisplay) { - wm->priority_mark.full = rfixed_const(10); + estimated_width.full = dfixed_div(estimated_width, consumption_time); + if (dfixed_trunc(estimated_width) > crtc->base.mode.crtc_hdisplay) { + wm->priority_mark.full = dfixed_const(10); } else { - a.full = rfixed_const(16); - wm->priority_mark.full = rfixed_div(estimated_width, a); - wm->priority_mark.full = rfixed_ceil(wm->priority_mark); + a.full = dfixed_const(16); + wm->priority_mark.full = dfixed_div(estimated_width, a); + wm->priority_mark.full = dfixed_ceil(wm->priority_mark); wm->priority_mark.full = wm->priority_mark_max.full - wm->priority_mark.full; } } @@ -439,58 +439,58 @@ void rs690_bandwidth_update(struct radeon_device *rdev) WREG32(R_006D58_LB_MAX_REQ_OUTSTANDING, tmp); if (mode0 && mode1) { - if (rfixed_trunc(wm0.dbpp) > 64) - a.full = rfixed_mul(wm0.dbpp, wm0.num_line_pair); + if (dfixed_trunc(wm0.dbpp) > 64) + a.full = dfixed_mul(wm0.dbpp, wm0.num_line_pair); else a.full = wm0.num_line_pair.full; - if (rfixed_trunc(wm1.dbpp) > 64) - b.full = rfixed_mul(wm1.dbpp, wm1.num_line_pair); + if (dfixed_trunc(wm1.dbpp) > 64) + b.full = dfixed_mul(wm1.dbpp, wm1.num_line_pair); else b.full = wm1.num_line_pair.full; a.full += b.full; - fill_rate.full = rfixed_div(wm0.sclk, a); + fill_rate.full = dfixed_div(wm0.sclk, a); if (wm0.consumption_rate.full > fill_rate.full) { b.full = wm0.consumption_rate.full - fill_rate.full; - b.full = rfixed_mul(b, wm0.active_time); - a.full = rfixed_mul(wm0.worst_case_latency, + b.full = dfixed_mul(b, wm0.active_time); + a.full = dfixed_mul(wm0.worst_case_latency, wm0.consumption_rate); a.full = a.full + b.full; - b.full = rfixed_const(16 * 1000); - priority_mark02.full = rfixed_div(a, b); + b.full = dfixed_const(16 * 1000); + priority_mark02.full = dfixed_div(a, b); } else { - a.full = rfixed_mul(wm0.worst_case_latency, + a.full = dfixed_mul(wm0.worst_case_latency, wm0.consumption_rate); - b.full = rfixed_const(16 * 1000); - priority_mark02.full = rfixed_div(a, b); + b.full = dfixed_const(16 * 1000); + priority_mark02.full = dfixed_div(a, b); } if (wm1.consumption_rate.full > fill_rate.full) { b.full = wm1.consumption_rate.full - fill_rate.full; - b.full = rfixed_mul(b, wm1.active_time); - a.full = rfixed_mul(wm1.worst_case_latency, + b.full = dfixed_mul(b, wm1.active_time); + a.full = dfixed_mul(wm1.worst_case_latency, wm1.consumption_rate); a.full = a.full + b.full; - b.full = rfixed_const(16 * 1000); - priority_mark12.full = rfixed_div(a, b); + b.full = dfixed_const(16 * 1000); + priority_mark12.full = dfixed_div(a, b); } else { - a.full = rfixed_mul(wm1.worst_case_latency, + a.full = dfixed_mul(wm1.worst_case_latency, wm1.consumption_rate); - b.full = rfixed_const(16 * 1000); - priority_mark12.full = rfixed_div(a, b); + b.full = dfixed_const(16 * 1000); + priority_mark12.full = dfixed_div(a, b); } if (wm0.priority_mark.full > priority_mark02.full) priority_mark02.full = wm0.priority_mark.full; - if (rfixed_trunc(priority_mark02) < 0) + if (dfixed_trunc(priority_mark02) < 0) priority_mark02.full = 0; if (wm0.priority_mark_max.full > priority_mark02.full) priority_mark02.full = wm0.priority_mark_max.full; if (wm1.priority_mark.full > priority_mark12.full) priority_mark12.full = wm1.priority_mark.full; - if (rfixed_trunc(priority_mark12) < 0) + if (dfixed_trunc(priority_mark12) < 0) priority_mark12.full = 0; if (wm1.priority_mark_max.full > priority_mark12.full) priority_mark12.full = wm1.priority_mark_max.full; - d1mode_priority_a_cnt = rfixed_trunc(priority_mark02); - d2mode_priority_a_cnt = rfixed_trunc(priority_mark12); + d1mode_priority_a_cnt = dfixed_trunc(priority_mark02); + d2mode_priority_a_cnt = dfixed_trunc(priority_mark12); if (rdev->disp_priority == 2) { d1mode_priority_a_cnt |= S_006548_D1MODE_PRIORITY_A_ALWAYS_ON(1); d2mode_priority_a_cnt |= S_006D48_D2MODE_PRIORITY_A_ALWAYS_ON(1); @@ -500,32 +500,32 @@ void rs690_bandwidth_update(struct radeon_device *rdev) WREG32(R_006D48_D2MODE_PRIORITY_A_CNT, d2mode_priority_a_cnt); WREG32(R_006D4C_D2MODE_PRIORITY_B_CNT, d2mode_priority_a_cnt); } else if (mode0) { - if (rfixed_trunc(wm0.dbpp) > 64) - a.full = rfixed_mul(wm0.dbpp, wm0.num_line_pair); + if (dfixed_trunc(wm0.dbpp) > 64) + a.full = dfixed_mul(wm0.dbpp, wm0.num_line_pair); else a.full = wm0.num_line_pair.full; - fill_rate.full = rfixed_div(wm0.sclk, a); + fill_rate.full = dfixed_div(wm0.sclk, a); if (wm0.consumption_rate.full > fill_rate.full) { b.full = wm0.consumption_rate.full - fill_rate.full; - b.full = rfixed_mul(b, wm0.active_time); - a.full = rfixed_mul(wm0.worst_case_latency, + b.full = dfixed_mul(b, wm0.active_time); + a.full = dfixed_mul(wm0.worst_case_latency, wm0.consumption_rate); a.full = a.full + b.full; - b.full = rfixed_const(16 * 1000); - priority_mark02.full = rfixed_div(a, b); + b.full = dfixed_const(16 * 1000); + priority_mark02.full = dfixed_div(a, b); } else { - a.full = rfixed_mul(wm0.worst_case_latency, + a.full = dfixed_mul(wm0.worst_case_latency, wm0.consumption_rate); - b.full = rfixed_const(16 * 1000); - priority_mark02.full = rfixed_div(a, b); + b.full = dfixed_const(16 * 1000); + priority_mark02.full = dfixed_div(a, b); } if (wm0.priority_mark.full > priority_mark02.full) priority_mark02.full = wm0.priority_mark.full; - if (rfixed_trunc(priority_mark02) < 0) + if (dfixed_trunc(priority_mark02) < 0) priority_mark02.full = 0; if (wm0.priority_mark_max.full > priority_mark02.full) priority_mark02.full = wm0.priority_mark_max.full; - d1mode_priority_a_cnt = rfixed_trunc(priority_mark02); + d1mode_priority_a_cnt = dfixed_trunc(priority_mark02); if (rdev->disp_priority == 2) d1mode_priority_a_cnt |= S_006548_D1MODE_PRIORITY_A_ALWAYS_ON(1); WREG32(R_006548_D1MODE_PRIORITY_A_CNT, d1mode_priority_a_cnt); @@ -535,32 +535,32 @@ void rs690_bandwidth_update(struct radeon_device *rdev) WREG32(R_006D4C_D2MODE_PRIORITY_B_CNT, S_006D4C_D2MODE_PRIORITY_B_OFF(1)); } else { - if (rfixed_trunc(wm1.dbpp) > 64) - a.full = rfixed_mul(wm1.dbpp, wm1.num_line_pair); + if (dfixed_trunc(wm1.dbpp) > 64) + a.full = dfixed_mul(wm1.dbpp, wm1.num_line_pair); else a.full = wm1.num_line_pair.full; - fill_rate.full = rfixed_div(wm1.sclk, a); + fill_rate.full = dfixed_div(wm1.sclk, a); if (wm1.consumption_rate.full > fill_rate.full) { b.full = wm1.consumption_rate.full - fill_rate.full; - b.full = rfixed_mul(b, wm1.active_time); - a.full = rfixed_mul(wm1.worst_case_latency, + b.full = dfixed_mul(b, wm1.active_time); + a.full = dfixed_mul(wm1.worst_case_latency, wm1.consumption_rate); a.full = a.full + b.full; - b.full = rfixed_const(16 * 1000); - priority_mark12.full = rfixed_div(a, b); + b.full = dfixed_const(16 * 1000); + priority_mark12.full = dfixed_div(a, b); } else { - a.full = rfixed_mul(wm1.worst_case_latency, + a.full = dfixed_mul(wm1.worst_case_latency, wm1.consumption_rate); - b.full = rfixed_const(16 * 1000); - priority_mark12.full = rfixed_div(a, b); + b.full = dfixed_const(16 * 1000); + priority_mark12.full = dfixed_div(a, b); } if (wm1.priority_mark.full > priority_mark12.full) priority_mark12.full = wm1.priority_mark.full; - if (rfixed_trunc(priority_mark12) < 0) + if (dfixed_trunc(priority_mark12) < 0) priority_mark12.full = 0; if (wm1.priority_mark_max.full > priority_mark12.full) priority_mark12.full = wm1.priority_mark_max.full; - d2mode_priority_a_cnt = rfixed_trunc(priority_mark12); + d2mode_priority_a_cnt = dfixed_trunc(priority_mark12); if (rdev->disp_priority == 2) d2mode_priority_a_cnt |= S_006D48_D2MODE_PRIORITY_A_ALWAYS_ON(1); WREG32(R_006548_D1MODE_PRIORITY_A_CNT, diff --git a/drivers/gpu/drm/radeon/rv515.c b/drivers/gpu/drm/radeon/rv515.c index c513473d72ae..2009f4b20c28 100644 --- a/drivers/gpu/drm/radeon/rv515.c +++ b/drivers/gpu/drm/radeon/rv515.c @@ -795,20 +795,20 @@ void rv515_crtc_bandwidth_compute(struct radeon_device *rdev, return; } - if (crtc->vsc.full > rfixed_const(2)) - wm->num_line_pair.full = rfixed_const(2); + if (crtc->vsc.full > dfixed_const(2)) + wm->num_line_pair.full = dfixed_const(2); else - wm->num_line_pair.full = rfixed_const(1); - - b.full = rfixed_const(mode->crtc_hdisplay); - c.full = rfixed_const(256); - a.full = rfixed_div(b, c); - request_fifo_depth.full = rfixed_mul(a, wm->num_line_pair); - request_fifo_depth.full = rfixed_ceil(request_fifo_depth); - if (a.full < rfixed_const(4)) { + wm->num_line_pair.full = dfixed_const(1); + + b.full = dfixed_const(mode->crtc_hdisplay); + c.full = dfixed_const(256); + a.full = dfixed_div(b, c); + request_fifo_depth.full = dfixed_mul(a, wm->num_line_pair); + request_fifo_depth.full = dfixed_ceil(request_fifo_depth); + if (a.full < dfixed_const(4)) { wm->lb_request_fifo_depth = 4; } else { - wm->lb_request_fifo_depth = rfixed_trunc(request_fifo_depth); + wm->lb_request_fifo_depth = dfixed_trunc(request_fifo_depth); } /* Determine consumption rate @@ -817,23 +817,23 @@ void rv515_crtc_bandwidth_compute(struct radeon_device *rdev, * vsc = vertical scaling ratio, defined as source/destination * hsc = horizontal scaling ration, defined as source/destination */ - a.full = rfixed_const(mode->clock); - b.full = rfixed_const(1000); - a.full = rfixed_div(a, b); - pclk.full = rfixed_div(b, a); + a.full = dfixed_const(mode->clock); + b.full = dfixed_const(1000); + a.full = dfixed_div(a, b); + pclk.full = dfixed_div(b, a); if (crtc->rmx_type != RMX_OFF) { - b.full = rfixed_const(2); + b.full = dfixed_const(2); if (crtc->vsc.full > b.full) b.full = crtc->vsc.full; - b.full = rfixed_mul(b, crtc->hsc); - c.full = rfixed_const(2); - b.full = rfixed_div(b, c); - consumption_time.full = rfixed_div(pclk, b); + b.full = dfixed_mul(b, crtc->hsc); + c.full = dfixed_const(2); + b.full = dfixed_div(b, c); + consumption_time.full = dfixed_div(pclk, b); } else { consumption_time.full = pclk.full; } - a.full = rfixed_const(1); - wm->consumption_rate.full = rfixed_div(a, consumption_time); + a.full = dfixed_const(1); + wm->consumption_rate.full = dfixed_div(a, consumption_time); /* Determine line time @@ -841,27 +841,27 @@ void rv515_crtc_bandwidth_compute(struct radeon_device *rdev, * LineTime = total number of horizontal pixels * pclk = pixel clock period(ns) */ - a.full = rfixed_const(crtc->base.mode.crtc_htotal); - line_time.full = rfixed_mul(a, pclk); + a.full = dfixed_const(crtc->base.mode.crtc_htotal); + line_time.full = dfixed_mul(a, pclk); /* Determine active time * ActiveTime = time of active region of display within one line, * hactive = total number of horizontal active pixels * htotal = total number of horizontal pixels */ - a.full = rfixed_const(crtc->base.mode.crtc_htotal); - b.full = rfixed_const(crtc->base.mode.crtc_hdisplay); - wm->active_time.full = rfixed_mul(line_time, b); - wm->active_time.full = rfixed_div(wm->active_time, a); + a.full = dfixed_const(crtc->base.mode.crtc_htotal); + b.full = dfixed_const(crtc->base.mode.crtc_hdisplay); + wm->active_time.full = dfixed_mul(line_time, b); + wm->active_time.full = dfixed_div(wm->active_time, a); /* Determine chunk time * ChunkTime = the time it takes the DCP to send one chunk of data * to the LB which consists of pipeline delay and inter chunk gap * sclk = system clock(Mhz) */ - a.full = rfixed_const(600 * 1000); - chunk_time.full = rfixed_div(a, rdev->pm.sclk); - read_delay_latency.full = rfixed_const(1000); + a.full = dfixed_const(600 * 1000); + chunk_time.full = dfixed_div(a, rdev->pm.sclk); + read_delay_latency.full = dfixed_const(1000); /* Determine the worst case latency * NumLinePair = Number of line pairs to request(1=2 lines, 2=4 lines) @@ -871,9 +871,9 @@ void rv515_crtc_bandwidth_compute(struct radeon_device *rdev, * ChunkTime = time it takes the DCP to send one chunk of data to the LB * which consists of pipeline delay and inter chunk gap */ - if (rfixed_trunc(wm->num_line_pair) > 1) { - a.full = rfixed_const(3); - wm->worst_case_latency.full = rfixed_mul(a, chunk_time); + if (dfixed_trunc(wm->num_line_pair) > 1) { + a.full = dfixed_const(3); + wm->worst_case_latency.full = dfixed_mul(a, chunk_time); wm->worst_case_latency.full += read_delay_latency.full; } else { wm->worst_case_latency.full = chunk_time.full + read_delay_latency.full; @@ -889,34 +889,34 @@ void rv515_crtc_bandwidth_compute(struct radeon_device *rdev, * of data to the LB which consists of * pipeline delay and inter chunk gap */ - if ((2+wm->lb_request_fifo_depth) >= rfixed_trunc(request_fifo_depth)) { + if ((2+wm->lb_request_fifo_depth) >= dfixed_trunc(request_fifo_depth)) { tolerable_latency.full = line_time.full; } else { - tolerable_latency.full = rfixed_const(wm->lb_request_fifo_depth - 2); + tolerable_latency.full = dfixed_const(wm->lb_request_fifo_depth - 2); tolerable_latency.full = request_fifo_depth.full - tolerable_latency.full; - tolerable_latency.full = rfixed_mul(tolerable_latency, chunk_time); + tolerable_latency.full = dfixed_mul(tolerable_latency, chunk_time); tolerable_latency.full = line_time.full - tolerable_latency.full; } /* We assume worst case 32bits (4 bytes) */ - wm->dbpp.full = rfixed_const(2 * 16); + wm->dbpp.full = dfixed_const(2 * 16); /* Determine the maximum priority mark * width = viewport width in pixels */ - a.full = rfixed_const(16); - wm->priority_mark_max.full = rfixed_const(crtc->base.mode.crtc_hdisplay); - wm->priority_mark_max.full = rfixed_div(wm->priority_mark_max, a); - wm->priority_mark_max.full = rfixed_ceil(wm->priority_mark_max); + a.full = dfixed_const(16); + wm->priority_mark_max.full = dfixed_const(crtc->base.mode.crtc_hdisplay); + wm->priority_mark_max.full = dfixed_div(wm->priority_mark_max, a); + wm->priority_mark_max.full = dfixed_ceil(wm->priority_mark_max); /* Determine estimated width */ estimated_width.full = tolerable_latency.full - wm->worst_case_latency.full; - estimated_width.full = rfixed_div(estimated_width, consumption_time); - if (rfixed_trunc(estimated_width) > crtc->base.mode.crtc_hdisplay) { + estimated_width.full = dfixed_div(estimated_width, consumption_time); + if (dfixed_trunc(estimated_width) > crtc->base.mode.crtc_hdisplay) { wm->priority_mark.full = wm->priority_mark_max.full; } else { - a.full = rfixed_const(16); - wm->priority_mark.full = rfixed_div(estimated_width, a); - wm->priority_mark.full = rfixed_ceil(wm->priority_mark); + a.full = dfixed_const(16); + wm->priority_mark.full = dfixed_div(estimated_width, a); + wm->priority_mark.full = dfixed_ceil(wm->priority_mark); wm->priority_mark.full = wm->priority_mark_max.full - wm->priority_mark.full; } } @@ -945,58 +945,58 @@ void rv515_bandwidth_avivo_update(struct radeon_device *rdev) WREG32(LB_MAX_REQ_OUTSTANDING, tmp); if (mode0 && mode1) { - if (rfixed_trunc(wm0.dbpp) > 64) - a.full = rfixed_div(wm0.dbpp, wm0.num_line_pair); + if (dfixed_trunc(wm0.dbpp) > 64) + a.full = dfixed_div(wm0.dbpp, wm0.num_line_pair); else a.full = wm0.num_line_pair.full; - if (rfixed_trunc(wm1.dbpp) > 64) - b.full = rfixed_div(wm1.dbpp, wm1.num_line_pair); + if (dfixed_trunc(wm1.dbpp) > 64) + b.full = dfixed_div(wm1.dbpp, wm1.num_line_pair); else b.full = wm1.num_line_pair.full; a.full += b.full; - fill_rate.full = rfixed_div(wm0.sclk, a); + fill_rate.full = dfixed_div(wm0.sclk, a); if (wm0.consumption_rate.full > fill_rate.full) { b.full = wm0.consumption_rate.full - fill_rate.full; - b.full = rfixed_mul(b, wm0.active_time); - a.full = rfixed_const(16); - b.full = rfixed_div(b, a); - a.full = rfixed_mul(wm0.worst_case_latency, + b.full = dfixed_mul(b, wm0.active_time); + a.full = dfixed_const(16); + b.full = dfixed_div(b, a); + a.full = dfixed_mul(wm0.worst_case_latency, wm0.consumption_rate); priority_mark02.full = a.full + b.full; } else { - a.full = rfixed_mul(wm0.worst_case_latency, + a.full = dfixed_mul(wm0.worst_case_latency, wm0.consumption_rate); - b.full = rfixed_const(16 * 1000); - priority_mark02.full = rfixed_div(a, b); + b.full = dfixed_const(16 * 1000); + priority_mark02.full = dfixed_div(a, b); } if (wm1.consumption_rate.full > fill_rate.full) { b.full = wm1.consumption_rate.full - fill_rate.full; - b.full = rfixed_mul(b, wm1.active_time); - a.full = rfixed_const(16); - b.full = rfixed_div(b, a); - a.full = rfixed_mul(wm1.worst_case_latency, + b.full = dfixed_mul(b, wm1.active_time); + a.full = dfixed_const(16); + b.full = dfixed_div(b, a); + a.full = dfixed_mul(wm1.worst_case_latency, wm1.consumption_rate); priority_mark12.full = a.full + b.full; } else { - a.full = rfixed_mul(wm1.worst_case_latency, + a.full = dfixed_mul(wm1.worst_case_latency, wm1.consumption_rate); - b.full = rfixed_const(16 * 1000); - priority_mark12.full = rfixed_div(a, b); + b.full = dfixed_const(16 * 1000); + priority_mark12.full = dfixed_div(a, b); } if (wm0.priority_mark.full > priority_mark02.full) priority_mark02.full = wm0.priority_mark.full; - if (rfixed_trunc(priority_mark02) < 0) + if (dfixed_trunc(priority_mark02) < 0) priority_mark02.full = 0; if (wm0.priority_mark_max.full > priority_mark02.full) priority_mark02.full = wm0.priority_mark_max.full; if (wm1.priority_mark.full > priority_mark12.full) priority_mark12.full = wm1.priority_mark.full; - if (rfixed_trunc(priority_mark12) < 0) + if (dfixed_trunc(priority_mark12) < 0) priority_mark12.full = 0; if (wm1.priority_mark_max.full > priority_mark12.full) priority_mark12.full = wm1.priority_mark_max.full; - d1mode_priority_a_cnt = rfixed_trunc(priority_mark02); - d2mode_priority_a_cnt = rfixed_trunc(priority_mark12); + d1mode_priority_a_cnt = dfixed_trunc(priority_mark02); + d2mode_priority_a_cnt = dfixed_trunc(priority_mark12); if (rdev->disp_priority == 2) { d1mode_priority_a_cnt |= MODE_PRIORITY_ALWAYS_ON; d2mode_priority_a_cnt |= MODE_PRIORITY_ALWAYS_ON; @@ -1006,32 +1006,32 @@ void rv515_bandwidth_avivo_update(struct radeon_device *rdev) WREG32(D2MODE_PRIORITY_A_CNT, d2mode_priority_a_cnt); WREG32(D2MODE_PRIORITY_B_CNT, d2mode_priority_a_cnt); } else if (mode0) { - if (rfixed_trunc(wm0.dbpp) > 64) - a.full = rfixed_div(wm0.dbpp, wm0.num_line_pair); + if (dfixed_trunc(wm0.dbpp) > 64) + a.full = dfixed_div(wm0.dbpp, wm0.num_line_pair); else a.full = wm0.num_line_pair.full; - fill_rate.full = rfixed_div(wm0.sclk, a); + fill_rate.full = dfixed_div(wm0.sclk, a); if (wm0.consumption_rate.full > fill_rate.full) { b.full = wm0.consumption_rate.full - fill_rate.full; - b.full = rfixed_mul(b, wm0.active_time); - a.full = rfixed_const(16); - b.full = rfixed_div(b, a); - a.full = rfixed_mul(wm0.worst_case_latency, + b.full = dfixed_mul(b, wm0.active_time); + a.full = dfixed_const(16); + b.full = dfixed_div(b, a); + a.full = dfixed_mul(wm0.worst_case_latency, wm0.consumption_rate); priority_mark02.full = a.full + b.full; } else { - a.full = rfixed_mul(wm0.worst_case_latency, + a.full = dfixed_mul(wm0.worst_case_latency, wm0.consumption_rate); - b.full = rfixed_const(16); - priority_mark02.full = rfixed_div(a, b); + b.full = dfixed_const(16); + priority_mark02.full = dfixed_div(a, b); } if (wm0.priority_mark.full > priority_mark02.full) priority_mark02.full = wm0.priority_mark.full; - if (rfixed_trunc(priority_mark02) < 0) + if (dfixed_trunc(priority_mark02) < 0) priority_mark02.full = 0; if (wm0.priority_mark_max.full > priority_mark02.full) priority_mark02.full = wm0.priority_mark_max.full; - d1mode_priority_a_cnt = rfixed_trunc(priority_mark02); + d1mode_priority_a_cnt = dfixed_trunc(priority_mark02); if (rdev->disp_priority == 2) d1mode_priority_a_cnt |= MODE_PRIORITY_ALWAYS_ON; WREG32(D1MODE_PRIORITY_A_CNT, d1mode_priority_a_cnt); @@ -1039,32 +1039,32 @@ void rv515_bandwidth_avivo_update(struct radeon_device *rdev) WREG32(D2MODE_PRIORITY_A_CNT, MODE_PRIORITY_OFF); WREG32(D2MODE_PRIORITY_B_CNT, MODE_PRIORITY_OFF); } else { - if (rfixed_trunc(wm1.dbpp) > 64) - a.full = rfixed_div(wm1.dbpp, wm1.num_line_pair); + if (dfixed_trunc(wm1.dbpp) > 64) + a.full = dfixed_div(wm1.dbpp, wm1.num_line_pair); else a.full = wm1.num_line_pair.full; - fill_rate.full = rfixed_div(wm1.sclk, a); + fill_rate.full = dfixed_div(wm1.sclk, a); if (wm1.consumption_rate.full > fill_rate.full) { b.full = wm1.consumption_rate.full - fill_rate.full; - b.full = rfixed_mul(b, wm1.active_time); - a.full = rfixed_const(16); - b.full = rfixed_div(b, a); - a.full = rfixed_mul(wm1.worst_case_latency, + b.full = dfixed_mul(b, wm1.active_time); + a.full = dfixed_const(16); + b.full = dfixed_div(b, a); + a.full = dfixed_mul(wm1.worst_case_latency, wm1.consumption_rate); priority_mark12.full = a.full + b.full; } else { - a.full = rfixed_mul(wm1.worst_case_latency, + a.full = dfixed_mul(wm1.worst_case_latency, wm1.consumption_rate); - b.full = rfixed_const(16 * 1000); - priority_mark12.full = rfixed_div(a, b); + b.full = dfixed_const(16 * 1000); + priority_mark12.full = dfixed_div(a, b); } if (wm1.priority_mark.full > priority_mark12.full) priority_mark12.full = wm1.priority_mark.full; - if (rfixed_trunc(priority_mark12) < 0) + if (dfixed_trunc(priority_mark12) < 0) priority_mark12.full = 0; if (wm1.priority_mark_max.full > priority_mark12.full) priority_mark12.full = wm1.priority_mark_max.full; - d2mode_priority_a_cnt = rfixed_trunc(priority_mark12); + d2mode_priority_a_cnt = dfixed_trunc(priority_mark12); if (rdev->disp_priority == 2) d2mode_priority_a_cnt |= MODE_PRIORITY_ALWAYS_ON; WREG32(D1MODE_PRIORITY_A_CNT, MODE_PRIORITY_OFF); diff --git a/include/drm/drm_fixed.h b/include/drm/drm_fixed.h new file mode 100644 index 000000000000..4a08a664ff1f --- /dev/null +++ b/include/drm/drm_fixed.h @@ -0,0 +1,67 @@ +/* + * Copyright 2009 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: Dave Airlie + */ +#ifndef DRM_FIXED_H +#define DRM_FIXED_H + +typedef union dfixed { + u32 full; +} fixed20_12; + + +#define dfixed_const(A) (u32)(((A) << 12))/* + ((B + 0.000122)*4096)) */ +#define dfixed_const_half(A) (u32)(((A) << 12) + 2048) +#define dfixed_const_666(A) (u32)(((A) << 12) + 2731) +#define dfixed_const_8(A) (u32)(((A) << 12) + 3277) +#define dfixed_mul(A, B) ((u64)((u64)(A).full * (B).full + 2048) >> 12) +#define dfixed_init(A) { .full = dfixed_const((A)) } +#define dfixed_init_half(A) { .full = dfixed_const_half((A)) } +#define dfixed_trunc(A) ((A).full >> 12) + +static inline u32 dfixed_floor(fixed20_12 A) +{ + u32 non_frac = dfixed_trunc(A); + + return dfixed_const(non_frac); +} + +static inline u32 dfixed_ceil(fixed20_12 A) +{ + u32 non_frac = dfixed_trunc(A); + + if (A.full > dfixed_const(non_frac)) + return dfixed_const(non_frac + 1); + else + return dfixed_const(non_frac); +} + +static inline u32 dfixed_div(fixed20_12 A, fixed20_12 B) +{ + u64 tmp = ((u64)A.full << 13); + + do_div(tmp, B.full); + tmp += 1; + tmp /= 2; + return lower_32_bits(tmp); +} +#endif -- cgit v1.2.3 From 539d24181753e40174746d576d415bfb56131975 Mon Sep 17 00:00:00 2001 From: Alex Deucher Date: Thu, 29 Apr 2010 00:22:43 -0400 Subject: drm/radeon/kms: more pm fixes - disable gui idle interrupt use Seems to hang some r5xx chips - move vbl range check into existing vbl check function in radeon_pm.c - disable crtc mc acccess for the whole reclocking process Signed-off-by: Alex Deucher Signed-off-by: Dave Airlie --- drivers/gpu/drm/radeon/evergreen_reg.h | 2 ++ drivers/gpu/drm/radeon/r100.c | 6 ++-- drivers/gpu/drm/radeon/r600.c | 35 +++--------------- drivers/gpu/drm/radeon/radeon_pm.c | 65 +++++++++++++++++++--------------- 4 files changed, 45 insertions(+), 63 deletions(-) (limited to 'drivers/gpu/drm/radeon') diff --git a/drivers/gpu/drm/radeon/evergreen_reg.h b/drivers/gpu/drm/radeon/evergreen_reg.h index 93aab2ebd9d0..af86af836f13 100644 --- a/drivers/gpu/drm/radeon/evergreen_reg.h +++ b/drivers/gpu/drm/radeon/evergreen_reg.h @@ -164,10 +164,12 @@ #define EVERGREEN_CRTC5_REGISTER_OFFSET (0x129f0 - 0x6df0) /* CRTC blocks at 0x6df0, 0x79f0, 0x105f0, 0x111f0, 0x11df0, 0x129f0 */ +#define EVERGREEN_CRTC_V_BLANK_START_END 0x6e34 #define EVERGREEN_CRTC_CONTROL 0x6e70 # define EVERGREEN_CRTC_MASTER_EN (1 << 0) # define EVERGREEN_CRTC_DISP_READ_REQUEST_DISABLE (1 << 24) #define EVERGREEN_CRTC_STATUS 0x6e8c +#define EVERGREEN_CRTC_STATUS_POSITION 0x6e90 #define EVERGREEN_CRTC_UPDATE_LOCK 0x6ed4 #define EVERGREEN_DC_GPIO_HPD_MASK 0x64b0 diff --git a/drivers/gpu/drm/radeon/r100.c b/drivers/gpu/drm/radeon/r100.c index a5f11c300f6a..493b9b48da30 100644 --- a/drivers/gpu/drm/radeon/r100.c +++ b/drivers/gpu/drm/radeon/r100.c @@ -178,14 +178,12 @@ void r100_set_power_state(struct radeon_device *rdev, bool static_switch) rdev->pm.current_sclk = sclk; DRM_INFO("Setting: e: %d\n", sclk); } -#if 0 /* set memory clock */ if (rdev->asic->set_memory_clock && (mclk != rdev->pm.current_mclk)) { radeon_set_memory_clock(rdev, mclk); rdev->pm.current_mclk = mclk; DRM_INFO("Setting: m: %d\n", mclk); } -#endif radeon_pm_finish(rdev); } else { radeon_sync_with_vblank(rdev); @@ -193,6 +191,7 @@ void r100_set_power_state(struct radeon_device *rdev, bool static_switch) if (!radeon_pm_in_vbl(rdev)) return; + radeon_pm_prepare(rdev); /* set engine clock */ if (sclk != rdev->pm.current_sclk) { radeon_pm_debug_check_in_vbl(rdev, false); @@ -205,13 +204,12 @@ void r100_set_power_state(struct radeon_device *rdev, bool static_switch) /* set memory clock */ if (rdev->asic->set_memory_clock && (mclk != rdev->pm.current_mclk)) { radeon_pm_debug_check_in_vbl(rdev, false); - radeon_pm_prepare(rdev); radeon_set_memory_clock(rdev, mclk); - radeon_pm_finish(rdev); radeon_pm_debug_check_in_vbl(rdev, true); rdev->pm.current_mclk = mclk; DRM_INFO("Setting: m: %d\n", mclk); } + radeon_pm_finish(rdev); } rdev->pm.current_power_state_index = rdev->pm.requested_power_state_index; diff --git a/drivers/gpu/drm/radeon/r600.c b/drivers/gpu/drm/radeon/r600.c index d3a79e0a9125..75c825cb8790 100644 --- a/drivers/gpu/drm/radeon/r600.c +++ b/drivers/gpu/drm/radeon/r600.c @@ -256,7 +256,6 @@ void r600_set_power_state(struct radeon_device *rdev, bool static_switch) return; if (radeon_gui_idle(rdev)) { - sclk = rdev->pm.power_state[rdev->pm.requested_power_state_index]. clock_info[rdev->pm.requested_clock_mode_index].sclk; if (sclk > rdev->clock.default_sclk) @@ -271,52 +270,27 @@ void r600_set_power_state(struct radeon_device *rdev, bool static_switch) radeon_pm_misc(rdev); if (static_switch) { - + radeon_pm_prepare(rdev); /* set engine clock */ if (sclk != rdev->pm.current_sclk) { radeon_set_engine_clock(rdev, sclk); rdev->pm.current_sclk = sclk; DRM_INFO("Setting: e: %d\n", sclk); } - /* set memory clock */ if (rdev->asic->set_memory_clock && (mclk != rdev->pm.current_mclk)) { - radeon_pm_prepare(rdev); radeon_set_memory_clock(rdev, mclk); - radeon_pm_finish(rdev); rdev->pm.current_mclk = mclk; DRM_INFO("Setting: m: %d\n", mclk); } - + radeon_pm_finish(rdev); } else { - u32 position; - u32 vbl; - radeon_sync_with_vblank(rdev); if (!radeon_pm_in_vbl(rdev)) return; - if (rdev->pm.active_crtcs & (1 << 0)) { - vbl = RREG32(AVIVO_D1CRTC_V_BLANK_START_END); - position = RREG32(AVIVO_D1CRTC_STATUS_POSITION); - position &= 0xfff; - vbl &= 0xfff; - - if (position < vbl && position > 1) - return; - } - - if (rdev->pm.active_crtcs & (1 << 1)) { - vbl = RREG32(AVIVO_D2CRTC_V_BLANK_START_END); - position = RREG32(AVIVO_D2CRTC_STATUS_POSITION); - position &= 0xfff; - vbl &= 0xfff; - - if (position < vbl && position > 1) - return; - } - + radeon_pm_prepare(rdev); if (sclk != rdev->pm.current_sclk) { radeon_pm_debug_check_in_vbl(rdev, false); radeon_set_engine_clock(rdev, sclk); @@ -328,13 +302,12 @@ void r600_set_power_state(struct radeon_device *rdev, bool static_switch) /* set memory clock */ if (rdev->asic->set_memory_clock && (mclk != rdev->pm.current_mclk)) { radeon_pm_debug_check_in_vbl(rdev, false); - radeon_pm_prepare(rdev); radeon_set_memory_clock(rdev, mclk); - radeon_pm_finish(rdev); radeon_pm_debug_check_in_vbl(rdev, true); rdev->pm.current_mclk = mclk; DRM_INFO("Setting: m: %d\n", mclk); } + radeon_pm_finish(rdev); } rdev->pm.current_power_state_index = rdev->pm.requested_power_state_index; diff --git a/drivers/gpu/drm/radeon/radeon_pm.c b/drivers/gpu/drm/radeon/radeon_pm.c index 88163e043fcf..2eb675e78440 100644 --- a/drivers/gpu/drm/radeon/radeon_pm.c +++ b/drivers/gpu/drm/radeon/radeon_pm.c @@ -64,7 +64,7 @@ static void radeon_pm_set_clocks(struct radeon_device *rdev, int static_switch) mutex_lock(&rdev->ddev->struct_mutex); mutex_lock(&rdev->vram_mutex); mutex_lock(&rdev->cp.mutex); - +#if 0 /* wait for GPU idle */ rdev->pm.gui_idle = false; rdev->irq.gui_idle = true; @@ -74,7 +74,7 @@ static void radeon_pm_set_clocks(struct radeon_device *rdev, int static_switch) msecs_to_jiffies(RADEON_WAIT_IDLE_TIMEOUT)); rdev->irq.gui_idle = false; radeon_irq_set(rdev); - +#endif radeon_unmap_vram_bos(rdev); if (!static_switch) { @@ -85,7 +85,7 @@ static void radeon_pm_set_clocks(struct radeon_device *rdev, int static_switch) } } } - + radeon_set_power_state(rdev, static_switch); if (!static_switch) { @@ -389,51 +389,57 @@ void radeon_pm_compute_clocks(struct radeon_device *rdev) bool radeon_pm_in_vbl(struct radeon_device *rdev) { - u32 stat_crtc = 0; + u32 stat_crtc = 0, vbl = 0, position = 0; bool in_vbl = true; if (ASIC_IS_DCE4(rdev)) { if (rdev->pm.active_crtcs & (1 << 0)) { - stat_crtc = RREG32(EVERGREEN_CRTC_STATUS + EVERGREEN_CRTC0_REGISTER_OFFSET); - if (!(stat_crtc & 1)) - in_vbl = false; + vbl = RREG32(EVERGREEN_CRTC_V_BLANK_START_END + + EVERGREEN_CRTC0_REGISTER_OFFSET) & 0xfff; + position = RREG32(EVERGREEN_CRTC_STATUS_POSITION + + EVERGREEN_CRTC0_REGISTER_OFFSET) & 0xfff; } if (rdev->pm.active_crtcs & (1 << 1)) { - stat_crtc = RREG32(EVERGREEN_CRTC_STATUS + EVERGREEN_CRTC1_REGISTER_OFFSET); - if (!(stat_crtc & 1)) - in_vbl = false; + vbl = RREG32(EVERGREEN_CRTC_V_BLANK_START_END + + EVERGREEN_CRTC1_REGISTER_OFFSET) & 0xfff; + position = RREG32(EVERGREEN_CRTC_STATUS_POSITION + + EVERGREEN_CRTC1_REGISTER_OFFSET) & 0xfff; } if (rdev->pm.active_crtcs & (1 << 2)) { - stat_crtc = RREG32(EVERGREEN_CRTC_STATUS + EVERGREEN_CRTC2_REGISTER_OFFSET); - if (!(stat_crtc & 1)) - in_vbl = false; + vbl = RREG32(EVERGREEN_CRTC_V_BLANK_START_END + + EVERGREEN_CRTC2_REGISTER_OFFSET) & 0xfff; + position = RREG32(EVERGREEN_CRTC_STATUS_POSITION + + EVERGREEN_CRTC2_REGISTER_OFFSET) & 0xfff; } if (rdev->pm.active_crtcs & (1 << 3)) { - stat_crtc = RREG32(EVERGREEN_CRTC_STATUS + EVERGREEN_CRTC3_REGISTER_OFFSET); - if (!(stat_crtc & 1)) - in_vbl = false; + vbl = RREG32(EVERGREEN_CRTC_V_BLANK_START_END + + EVERGREEN_CRTC3_REGISTER_OFFSET) & 0xfff; + position = RREG32(EVERGREEN_CRTC_STATUS_POSITION + + EVERGREEN_CRTC3_REGISTER_OFFSET) & 0xfff; } if (rdev->pm.active_crtcs & (1 << 4)) { - stat_crtc = RREG32(EVERGREEN_CRTC_STATUS + EVERGREEN_CRTC4_REGISTER_OFFSET); - if (!(stat_crtc & 1)) - in_vbl = false; + vbl = RREG32(EVERGREEN_CRTC_V_BLANK_START_END + + EVERGREEN_CRTC4_REGISTER_OFFSET) & 0xfff; + position = RREG32(EVERGREEN_CRTC_STATUS_POSITION + + EVERGREEN_CRTC4_REGISTER_OFFSET) & 0xfff; } if (rdev->pm.active_crtcs & (1 << 5)) { - stat_crtc = RREG32(EVERGREEN_CRTC_STATUS + EVERGREEN_CRTC5_REGISTER_OFFSET); - if (!(stat_crtc & 1)) - in_vbl = false; + vbl = RREG32(EVERGREEN_CRTC_V_BLANK_START_END + + EVERGREEN_CRTC5_REGISTER_OFFSET) & 0xfff; + position = RREG32(EVERGREEN_CRTC_STATUS_POSITION + + EVERGREEN_CRTC5_REGISTER_OFFSET) & 0xfff; } } else if (ASIC_IS_AVIVO(rdev)) { if (rdev->pm.active_crtcs & (1 << 0)) { - stat_crtc = RREG32(D1CRTC_STATUS); - if (!(stat_crtc & 1)) - in_vbl = false; + vbl = RREG32(AVIVO_D1CRTC_V_BLANK_START_END) & 0xfff; + position = RREG32(AVIVO_D1CRTC_STATUS_POSITION) & 0xfff; } if (rdev->pm.active_crtcs & (1 << 1)) { - stat_crtc = RREG32(D2CRTC_STATUS); - if (!(stat_crtc & 1)) - in_vbl = false; + vbl = RREG32(AVIVO_D2CRTC_V_BLANK_START_END) & 0xfff; + position = RREG32(AVIVO_D2CRTC_STATUS_POSITION) & 0xfff; } + if (position < vbl && position > 1) + in_vbl = false; } else { if (rdev->pm.active_crtcs & (1 << 0)) { stat_crtc = RREG32(RADEON_CRTC_STATUS); @@ -447,6 +453,9 @@ bool radeon_pm_in_vbl(struct radeon_device *rdev) } } + if (position < vbl && position > 1) + in_vbl = false; + return in_vbl; } -- cgit v1.2.3 From f4b7fb94c576265ceffc43031805ade32fa80c6a Mon Sep 17 00:00:00 2001 From: Dave Airlie Date: Thu, 29 Apr 2010 18:37:59 +1000 Subject: drm/radeon/kms: take vram mutex pointer before derefing object. since derefing the object might free it. Signed-off-by: Dave Airlie --- drivers/gpu/drm/radeon/radeon_object.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) (limited to 'drivers/gpu/drm/radeon') diff --git a/drivers/gpu/drm/radeon/radeon_object.c b/drivers/gpu/drm/radeon/radeon_object.c index 06def708b014..a8d18bcae7db 100644 --- a/drivers/gpu/drm/radeon/radeon_object.c +++ b/drivers/gpu/drm/radeon/radeon_object.c @@ -168,13 +168,15 @@ void radeon_bo_kunmap(struct radeon_bo *bo) void radeon_bo_unref(struct radeon_bo **bo) { struct ttm_buffer_object *tbo; + struct radeon_device *rdev; if ((*bo) == NULL) return; + rdev = (*bo)->rdev; tbo = &((*bo)->tbo); - mutex_lock(&(*bo)->rdev->vram_mutex); + mutex_lock(&rdev->vram_mutex); ttm_bo_unref(&tbo); - mutex_unlock(&(*bo)->rdev->vram_mutex); + mutex_unlock(&rdev->vram_mutex); if (tbo == NULL) *bo = NULL; } -- cgit v1.2.3 From 4f3218cbc34f4ffd88f4b3ea0d2f6999aea7b3e6 Mon Sep 17 00:00:00 2001 From: Alex Deucher Date: Thu, 29 Apr 2010 16:14:02 -0400 Subject: drm/radeon/kms: re-enable gui idle interrupts on r6xx+ Signed-off-by: Alex Deucher Signed-off-by: Dave Airlie --- drivers/gpu/drm/radeon/radeon_pm.c | 24 +++++++++++++----------- 1 file changed, 13 insertions(+), 11 deletions(-) (limited to 'drivers/gpu/drm/radeon') diff --git a/drivers/gpu/drm/radeon/radeon_pm.c b/drivers/gpu/drm/radeon/radeon_pm.c index 2eb675e78440..bded834afa5d 100644 --- a/drivers/gpu/drm/radeon/radeon_pm.c +++ b/drivers/gpu/drm/radeon/radeon_pm.c @@ -64,17 +64,19 @@ static void radeon_pm_set_clocks(struct radeon_device *rdev, int static_switch) mutex_lock(&rdev->ddev->struct_mutex); mutex_lock(&rdev->vram_mutex); mutex_lock(&rdev->cp.mutex); -#if 0 - /* wait for GPU idle */ - rdev->pm.gui_idle = false; - rdev->irq.gui_idle = true; - radeon_irq_set(rdev); - wait_event_interruptible_timeout( - rdev->irq.idle_queue, rdev->pm.gui_idle, - msecs_to_jiffies(RADEON_WAIT_IDLE_TIMEOUT)); - rdev->irq.gui_idle = false; - radeon_irq_set(rdev); -#endif + + /* gui idle int has issues on older chips it seems */ + if (rdev->family >= CHIP_R600) { + /* wait for GPU idle */ + rdev->pm.gui_idle = false; + rdev->irq.gui_idle = true; + radeon_irq_set(rdev); + wait_event_interruptible_timeout( + rdev->irq.idle_queue, rdev->pm.gui_idle, + msecs_to_jiffies(RADEON_WAIT_IDLE_TIMEOUT)); + rdev->irq.gui_idle = false; + radeon_irq_set(rdev); + } radeon_unmap_vram_bos(rdev); if (!static_switch) { -- cgit v1.2.3 From 536fcd5124df6af3b95f1bffc925d9ccb6d5b9df Mon Sep 17 00:00:00 2001 From: Alex Deucher Date: Thu, 29 Apr 2010 16:33:38 -0400 Subject: drm/radeon/kms: enable misc pm power state features on r5xx, rs6xx voltage drop, dynamic voltage, dynamic sclk, pcie lane adjust, etc, Signed-off-by: Alex Deucher Signed-off-by: Dave Airlie --- drivers/gpu/drm/radeon/rs600.c | 14 ++++++++++---- drivers/gpu/drm/radeon/rs600d.h | 2 ++ 2 files changed, 12 insertions(+), 4 deletions(-) (limited to 'drivers/gpu/drm/radeon') diff --git a/drivers/gpu/drm/radeon/rs600.c b/drivers/gpu/drm/radeon/rs600.c index c3890b76a1c0..8e0c46060b3a 100644 --- a/drivers/gpu/drm/radeon/rs600.c +++ b/drivers/gpu/drm/radeon/rs600.c @@ -48,12 +48,11 @@ int rs600_mc_wait_for_idle(struct radeon_device *rdev); void rs600_pm_misc(struct radeon_device *rdev) { -#if 0 int requested_index = rdev->pm.requested_power_state_index; struct radeon_power_state *ps = &rdev->pm.power_state[requested_index]; struct radeon_voltage *voltage = &ps->clock_info[0].voltage; u32 tmp, dyn_pwrmgt_sclk_length, dyn_sclk_vol_cntl; - u32 hdp_dyn_cntl, mc_host_dyn_cntl; + u32 hdp_dyn_cntl, /*mc_host_dyn_cntl,*/ dyn_backbias_cntl; if ((voltage->type == VOLTAGE_GPIO) && (voltage->gpio.valid)) { if (ps->misc & ATOM_PM_MISCINFO_VOLTAGE_DROP_SUPPORT) { @@ -112,13 +111,21 @@ void rs600_pm_misc(struct radeon_device *rdev) else hdp_dyn_cntl |= HDP_FORCEON; WREG32_PLL(HDP_DYN_CNTL, hdp_dyn_cntl); - +#if 0 + /* mc_host_dyn seems to cause hangs from time to time */ mc_host_dyn_cntl = RREG32_PLL(MC_HOST_DYN_CNTL); if (ps->misc & ATOM_PM_MISCINFO_DYNAMIC_MC_HOST_BLOCK_EN) mc_host_dyn_cntl &= ~MC_HOST_FORCEON; else mc_host_dyn_cntl |= MC_HOST_FORCEON; WREG32_PLL(MC_HOST_DYN_CNTL, mc_host_dyn_cntl); +#endif + dyn_backbias_cntl = RREG32_PLL(DYN_BACKBIAS_CNTL); + if (ps->misc & ATOM_PM_MISCINFO2_DYNAMIC_BACK_BIAS_EN) + dyn_backbias_cntl |= IO_CG_BACKBIAS_EN; + else + dyn_backbias_cntl &= ~IO_CG_BACKBIAS_EN; + WREG32_PLL(DYN_BACKBIAS_CNTL, dyn_backbias_cntl); /* set pcie lanes */ if ((rdev->flags & RADEON_IS_PCIE) && @@ -130,7 +137,6 @@ void rs600_pm_misc(struct radeon_device *rdev) ps->pcie_lanes); DRM_INFO("Setting: p: %d\n", ps->pcie_lanes); } -#endif } void rs600_pm_prepare(struct radeon_device *rdev) diff --git a/drivers/gpu/drm/radeon/rs600d.h b/drivers/gpu/drm/radeon/rs600d.h index 8f624342927a..a27c13ac47c3 100644 --- a/drivers/gpu/drm/radeon/rs600d.h +++ b/drivers/gpu/drm/radeon/rs600d.h @@ -655,6 +655,8 @@ #define HDP_FORCEON (1 << 0) #define MC_HOST_DYN_CNTL 0x1e #define MC_HOST_FORCEON (1 << 0) +#define DYN_BACKBIAS_CNTL 0x29 +#define IO_CG_BACKBIAS_EN (1 << 0) /* mmreg */ #define DOUT_POWER_MANAGEMENT_CNTL 0x7ee0 -- cgit v1.2.3 From 78930b1c39dd4a5afd5aa873eec11b5bd7079866 Mon Sep 17 00:00:00 2001 From: Alex Deucher Date: Fri, 30 Apr 2010 15:34:12 -0400 Subject: drm/radeon/kms: enable misc pm power state features on r1xx-r4xx voltage drop, dynamic voltage, dynamic sclk, pcie lane adjust, etc, Signed-off-by: Alex Deucher Signed-off-by: Dave Airlie --- drivers/gpu/drm/radeon/r100.c | 2 -- 1 file changed, 2 deletions(-) (limited to 'drivers/gpu/drm/radeon') diff --git a/drivers/gpu/drm/radeon/r100.c b/drivers/gpu/drm/radeon/r100.c index 493b9b48da30..14b7541df38a 100644 --- a/drivers/gpu/drm/radeon/r100.c +++ b/drivers/gpu/drm/radeon/r100.c @@ -220,7 +220,6 @@ void r100_set_power_state(struct radeon_device *rdev, bool static_switch) void r100_pm_misc(struct radeon_device *rdev) { -#if 0 int requested_index = rdev->pm.requested_power_state_index; struct radeon_power_state *ps = &rdev->pm.power_state[requested_index]; struct radeon_voltage *voltage = &ps->clock_info[0].voltage; @@ -308,7 +307,6 @@ void r100_pm_misc(struct radeon_device *rdev) ps->pcie_lanes); DRM_INFO("Setting: p: %d\n", ps->pcie_lanes); } -#endif } void r100_pm_prepare(struct radeon_device *rdev) -- cgit v1.2.3 From 91700f3cac56a1998a56d41e4459a5cebdb4f752 Mon Sep 17 00:00:00 2001 From: Matthew Garrett Date: Fri, 30 Apr 2010 15:24:17 -0400 Subject: radeon: Split out ring locking and allocation We need to handle the ring while we've already locked it, so split out the allocation and commit functions in order to allow them to be used. Signed-off-by: Matthew Garrett Signed-off-by: Dave Airlie --- drivers/gpu/drm/radeon/radeon.h | 2 ++ drivers/gpu/drm/radeon/radeon_ring.c | 27 +++++++++++++++++++++------ 2 files changed, 23 insertions(+), 6 deletions(-) (limited to 'drivers/gpu/drm/radeon') diff --git a/drivers/gpu/drm/radeon/radeon.h b/drivers/gpu/drm/radeon/radeon.h index 93ac88eb6b3a..e39e2b4ec979 100644 --- a/drivers/gpu/drm/radeon/radeon.h +++ b/drivers/gpu/drm/radeon/radeon.h @@ -471,7 +471,9 @@ int radeon_ib_test(struct radeon_device *rdev); extern void radeon_ib_bogus_add(struct radeon_device *rdev, struct radeon_ib *ib); /* Ring access between begin & end cannot sleep */ void radeon_ring_free_size(struct radeon_device *rdev); +int radeon_ring_alloc(struct radeon_device *rdev, unsigned ndw); int radeon_ring_lock(struct radeon_device *rdev, unsigned ndw); +void radeon_ring_commit(struct radeon_device *rdev); void radeon_ring_unlock_commit(struct radeon_device *rdev); void radeon_ring_unlock_undo(struct radeon_device *rdev); int radeon_ring_test(struct radeon_device *rdev); diff --git a/drivers/gpu/drm/radeon/radeon_ring.c b/drivers/gpu/drm/radeon/radeon_ring.c index f6e1e8d4d986..6cc42591abd8 100644 --- a/drivers/gpu/drm/radeon/radeon_ring.c +++ b/drivers/gpu/drm/radeon/radeon_ring.c @@ -258,31 +258,41 @@ void radeon_ring_free_size(struct radeon_device *rdev) } } -int radeon_ring_lock(struct radeon_device *rdev, unsigned ndw) +int radeon_ring_alloc(struct radeon_device *rdev, unsigned ndw) { int r; /* Align requested size with padding so unlock_commit can * pad safely */ ndw = (ndw + rdev->cp.align_mask) & ~rdev->cp.align_mask; - mutex_lock(&rdev->cp.mutex); while (ndw > (rdev->cp.ring_free_dw - 1)) { radeon_ring_free_size(rdev); if (ndw < rdev->cp.ring_free_dw) { break; } r = radeon_fence_wait_next(rdev); - if (r) { - mutex_unlock(&rdev->cp.mutex); + if (r) return r; - } } rdev->cp.count_dw = ndw; rdev->cp.wptr_old = rdev->cp.wptr; return 0; } -void radeon_ring_unlock_commit(struct radeon_device *rdev) +int radeon_ring_lock(struct radeon_device *rdev, unsigned ndw) +{ + int r; + + mutex_lock(&rdev->cp.mutex); + r = radeon_ring_alloc(rdev, ndw); + if (r) { + mutex_unlock(&rdev->cp.mutex); + return r; + } + return 0; +} + +void radeon_ring_commit(struct radeon_device *rdev) { unsigned count_dw_pad; unsigned i; @@ -295,6 +305,11 @@ void radeon_ring_unlock_commit(struct radeon_device *rdev) } DRM_MEMORYBARRIER(); radeon_cp_commit(rdev); +} + +void radeon_ring_unlock_commit(struct radeon_device *rdev) +{ + radeon_ring_commit(rdev); mutex_unlock(&rdev->cp.mutex); } -- cgit v1.2.3 From 01434b4bfba17626fe93a602e540f0004694d9df Mon Sep 17 00:00:00 2001 From: Matthew Garrett Date: Fri, 30 Apr 2010 15:48:23 -0400 Subject: radeon: Use fences to gate entry to reclocking on Signed-off-by: Dave Airlie --- drivers/gpu/drm/radeon/radeon_pm.c | 8 ++++++++ 1 file changed, 8 insertions(+) (limited to 'drivers/gpu/drm/radeon') diff --git a/drivers/gpu/drm/radeon/radeon_pm.c b/drivers/gpu/drm/radeon/radeon_pm.c index bded834afa5d..1ee7fc9918ac 100644 --- a/drivers/gpu/drm/radeon/radeon_pm.c +++ b/drivers/gpu/drm/radeon/radeon_pm.c @@ -76,6 +76,14 @@ static void radeon_pm_set_clocks(struct radeon_device *rdev, int static_switch) msecs_to_jiffies(RADEON_WAIT_IDLE_TIMEOUT)); rdev->irq.gui_idle = false; radeon_irq_set(rdev); + } else { + struct radeon_fence *fence; + radeon_ring_alloc(rdev, 64); + radeon_fence_create(rdev, &fence); + radeon_fence_emit(rdev, fence); + radeon_ring_commit(rdev); + radeon_fence_wait(fence, false); + radeon_fence_unref(&fence); } radeon_unmap_vram_bos(rdev); -- cgit v1.2.3 From ca2af92311eee95820f3b48c35045e5f56bc1477 Mon Sep 17 00:00:00 2001 From: Alex Deucher Date: Thu, 6 May 2010 11:02:24 -0400 Subject: drm/radeon/kms: fix lock ordering in ring, ib handling Signed-off-by: Alex Deucher Signed-off-by: Dave Airlie --- drivers/gpu/drm/radeon/radeon_ring.c | 39 ++++++++++++++++++++---------------- 1 file changed, 22 insertions(+), 17 deletions(-) (limited to 'drivers/gpu/drm/radeon') diff --git a/drivers/gpu/drm/radeon/radeon_ring.c b/drivers/gpu/drm/radeon/radeon_ring.c index 6cc42591abd8..261e98a276db 100644 --- a/drivers/gpu/drm/radeon/radeon_ring.c +++ b/drivers/gpu/drm/radeon/radeon_ring.c @@ -219,24 +219,26 @@ int radeon_ib_pool_init(struct radeon_device *rdev) void radeon_ib_pool_fini(struct radeon_device *rdev) { int r; + struct radeon_bo *robj; if (!rdev->ib_pool.ready) { return; } mutex_lock(&rdev->ib_pool.mutex); radeon_ib_bogus_cleanup(rdev); + robj = rdev->ib_pool.robj; + rdev->ib_pool.robj = NULL; + mutex_unlock(&rdev->ib_pool.mutex); - if (rdev->ib_pool.robj) { - r = radeon_bo_reserve(rdev->ib_pool.robj, false); + if (robj) { + r = radeon_bo_reserve(robj, false); if (likely(r == 0)) { - radeon_bo_kunmap(rdev->ib_pool.robj); - radeon_bo_unpin(rdev->ib_pool.robj); - radeon_bo_unreserve(rdev->ib_pool.robj); + radeon_bo_kunmap(robj); + radeon_bo_unpin(robj); + radeon_bo_unreserve(robj); } - radeon_bo_unref(&rdev->ib_pool.robj); - rdev->ib_pool.robj = NULL; + radeon_bo_unref(&robj); } - mutex_unlock(&rdev->ib_pool.mutex); } @@ -359,20 +361,23 @@ int radeon_ring_init(struct radeon_device *rdev, unsigned ring_size) void radeon_ring_fini(struct radeon_device *rdev) { int r; + struct radeon_bo *ring_obj; mutex_lock(&rdev->cp.mutex); - if (rdev->cp.ring_obj) { - r = radeon_bo_reserve(rdev->cp.ring_obj, false); + ring_obj = rdev->cp.ring_obj; + rdev->cp.ring = NULL; + rdev->cp.ring_obj = NULL; + mutex_unlock(&rdev->cp.mutex); + + if (ring_obj) { + r = radeon_bo_reserve(ring_obj, false); if (likely(r == 0)) { - radeon_bo_kunmap(rdev->cp.ring_obj); - radeon_bo_unpin(rdev->cp.ring_obj); - radeon_bo_unreserve(rdev->cp.ring_obj); + radeon_bo_kunmap(ring_obj); + radeon_bo_unpin(ring_obj); + radeon_bo_unreserve(ring_obj); } - radeon_bo_unref(&rdev->cp.ring_obj); - rdev->cp.ring = NULL; - rdev->cp.ring_obj = NULL; + radeon_bo_unref(&ring_obj); } - mutex_unlock(&rdev->cp.mutex); } -- cgit v1.2.3 From d7311171c4cc8d6231427f7ac5056b939a184b80 Mon Sep 17 00:00:00 2001 From: Alex Deucher Date: Mon, 3 May 2010 01:13:14 -0400 Subject: drm/radeon/kms/pm: add support for no display power states The lowest power states often cause display problems, so only enable them when all displays are off. Signed-off-by: Alex Deucher Signed-off-by: Dave Airlie --- drivers/gpu/drm/radeon/atombios_crtc.c | 9 ++++--- drivers/gpu/drm/radeon/r100.c | 12 ++++++--- drivers/gpu/drm/radeon/r600.c | 20 ++++++++++++--- drivers/gpu/drm/radeon/radeon.h | 7 ++++-- drivers/gpu/drm/radeon/radeon_atombios.c | 37 +++++++++++++++++++--------- drivers/gpu/drm/radeon/radeon_combios.c | 2 +- drivers/gpu/drm/radeon/radeon_legacy_crtc.c | 9 ++++--- drivers/gpu/drm/radeon/radeon_pm.c | 38 ++++++++++++++++++++--------- 8 files changed, 94 insertions(+), 40 deletions(-) (limited to 'drivers/gpu/drm/radeon') diff --git a/drivers/gpu/drm/radeon/atombios_crtc.c b/drivers/gpu/drm/radeon/atombios_crtc.c index 4151ad8affed..03dd6c41dc19 100644 --- a/drivers/gpu/drm/radeon/atombios_crtc.c +++ b/drivers/gpu/drm/radeon/atombios_crtc.c @@ -245,13 +245,15 @@ void atombios_crtc_dpms(struct drm_crtc *crtc, int mode) switch (mode) { case DRM_MODE_DPMS_ON: + radeon_crtc->enabled = true; + /* adjust pm to dpms changes BEFORE enabling crtcs */ + radeon_pm_compute_clocks(rdev); atombios_enable_crtc(crtc, ATOM_ENABLE); if (ASIC_IS_DCE3(rdev)) atombios_enable_crtc_memreq(crtc, ATOM_ENABLE); atombios_blank_crtc(crtc, ATOM_DISABLE); drm_vblank_post_modeset(dev, radeon_crtc->crtc_id); radeon_crtc_load_lut(crtc); - radeon_crtc->enabled = true; break; case DRM_MODE_DPMS_STANDBY: case DRM_MODE_DPMS_SUSPEND: @@ -262,11 +264,10 @@ void atombios_crtc_dpms(struct drm_crtc *crtc, int mode) atombios_enable_crtc_memreq(crtc, ATOM_DISABLE); atombios_enable_crtc(crtc, ATOM_DISABLE); radeon_crtc->enabled = false; + /* adjust pm to dpms changes AFTER disabling crtcs */ + radeon_pm_compute_clocks(rdev); break; } - - /* adjust pm to dpms change */ - radeon_pm_compute_clocks(rdev); } static void diff --git a/drivers/gpu/drm/radeon/r100.c b/drivers/gpu/drm/radeon/r100.c index 14b7541df38a..4161a35dd3d3 100644 --- a/drivers/gpu/drm/radeon/r100.c +++ b/drivers/gpu/drm/radeon/r100.c @@ -87,7 +87,7 @@ void r100_get_power_state(struct radeon_device *rdev, } else { if (rdev->pm.active_crtc_count > 1) { for (i = 0; i < rdev->pm.num_power_states; i++) { - if (rdev->pm.power_state[i].flags & RADEON_PM_SINGLE_DISPLAY_ONLY) + if (rdev->pm.power_state[i].flags & RADEON_PM_STATE_SINGLE_DISPLAY_ONLY) continue; else if (i >= rdev->pm.current_power_state_index) { rdev->pm.requested_power_state_index = rdev->pm.current_power_state_index; @@ -101,6 +101,12 @@ void r100_get_power_state(struct radeon_device *rdev, rdev->pm.requested_power_state_index = rdev->pm.current_power_state_index - 1; } + /* don't use the power state if crtcs are active and no display flag is set */ + if ((rdev->pm.active_crtc_count > 0) && + (rdev->pm.power_state[rdev->pm.requested_power_state_index].clock_info[0].flags & + RADEON_PM_MODE_NO_DISPLAY)) { + rdev->pm.requested_power_state_index++; + } break; case PM_ACTION_UPCLOCK: if (rdev->pm.current_power_state_index == (rdev->pm.num_power_states - 1)) { @@ -109,7 +115,7 @@ void r100_get_power_state(struct radeon_device *rdev, } else { if (rdev->pm.active_crtc_count > 1) { for (i = (rdev->pm.num_power_states - 1); i >= 0; i--) { - if (rdev->pm.power_state[i].flags & RADEON_PM_SINGLE_DISPLAY_ONLY) + if (rdev->pm.power_state[i].flags & RADEON_PM_STATE_SINGLE_DISPLAY_ONLY) continue; else if (i <= rdev->pm.current_power_state_index) { rdev->pm.requested_power_state_index = rdev->pm.current_power_state_index; @@ -215,7 +221,7 @@ void r100_set_power_state(struct radeon_device *rdev, bool static_switch) rdev->pm.current_power_state_index = rdev->pm.requested_power_state_index; rdev->pm.current_clock_mode_index = rdev->pm.requested_clock_mode_index; } else - DRM_INFO("GUI not idle!!!\n"); + DRM_INFO("pm: GUI not idle!!!\n"); } void r100_pm_misc(struct radeon_device *rdev) diff --git a/drivers/gpu/drm/radeon/r600.c b/drivers/gpu/drm/radeon/r600.c index 75c825cb8790..08a328c4165a 100644 --- a/drivers/gpu/drm/radeon/r600.c +++ b/drivers/gpu/drm/radeon/r600.c @@ -120,7 +120,7 @@ void r600_get_power_state(struct radeon_device *rdev, } else { if (rdev->pm.active_crtc_count > 1) { for (i = 0; i < rdev->pm.num_power_states; i++) { - if (rdev->pm.power_state[i].flags & RADEON_PM_SINGLE_DISPLAY_ONLY) + if (rdev->pm.power_state[i].flags & RADEON_PM_STATE_SINGLE_DISPLAY_ONLY) continue; else if (i >= rdev->pm.current_power_state_index) { rdev->pm.requested_power_state_index = @@ -136,6 +136,13 @@ void r600_get_power_state(struct radeon_device *rdev, rdev->pm.current_power_state_index - 1; } rdev->pm.requested_clock_mode_index = 0; + /* don't use the power state if crtcs are active and no display flag is set */ + if ((rdev->pm.active_crtc_count > 0) && + (rdev->pm.power_state[rdev->pm.requested_power_state_index]. + clock_info[rdev->pm.requested_clock_mode_index].flags & + RADEON_PM_MODE_NO_DISPLAY)) { + rdev->pm.requested_power_state_index++; + } break; case PM_ACTION_UPCLOCK: if (rdev->pm.current_power_state_index == (rdev->pm.num_power_states - 1)) { @@ -144,7 +151,7 @@ void r600_get_power_state(struct radeon_device *rdev, } else { if (rdev->pm.active_crtc_count > 1) { for (i = (rdev->pm.num_power_states - 1); i >= 0; i--) { - if (rdev->pm.power_state[i].flags & RADEON_PM_SINGLE_DISPLAY_ONLY) + if (rdev->pm.power_state[i].flags & RADEON_PM_STATE_SINGLE_DISPLAY_ONLY) continue; else if (i <= rdev->pm.current_power_state_index) { rdev->pm.requested_power_state_index = @@ -179,7 +186,7 @@ void r600_get_power_state(struct radeon_device *rdev, rdev->pm.requested_power_state_index = -1; /* start at 1 as we don't want the default mode */ for (i = 1; i < rdev->pm.num_power_states; i++) { - if (rdev->pm.power_state[i].flags & RADEON_PM_SINGLE_DISPLAY_ONLY) + if (rdev->pm.power_state[i].flags & RADEON_PM_STATE_SINGLE_DISPLAY_ONLY) continue; else if ((rdev->pm.power_state[i].type == POWER_STATE_TYPE_PERFORMANCE) || (rdev->pm.power_state[i].type == POWER_STATE_TYPE_BATTERY)) { @@ -210,6 +217,13 @@ void r600_get_power_state(struct radeon_device *rdev, rdev->pm.requested_clock_mode_index = 0; rdev->pm.can_downclock = false; } + /* don't use the power state if crtcs are active and no display flag is set */ + if ((rdev->pm.active_crtc_count > 0) && + (rdev->pm.power_state[rdev->pm.requested_power_state_index]. + clock_info[rdev->pm.requested_clock_mode_index].flags & + RADEON_PM_MODE_NO_DISPLAY)) { + rdev->pm.requested_clock_mode_index++; + } break; case PM_ACTION_UPCLOCK: if (rdev->pm.requested_power_state_index == rdev->pm.current_power_state_index) { diff --git a/drivers/gpu/drm/radeon/radeon.h b/drivers/gpu/drm/radeon/radeon.h index e39e2b4ec979..480a83ff54d5 100644 --- a/drivers/gpu/drm/radeon/radeon.h +++ b/drivers/gpu/drm/radeon/radeon.h @@ -658,6 +658,9 @@ struct radeon_voltage { u32 voltage; }; +/* clock mode flags */ +#define RADEON_PM_MODE_NO_DISPLAY (1 << 0) + struct radeon_pm_clock_info { /* memory clock */ u32 mclk; @@ -665,12 +668,12 @@ struct radeon_pm_clock_info { u32 sclk; /* voltage info */ struct radeon_voltage voltage; - /* standardized clock flags - not sure we'll need these */ + /* standardized clock flags */ u32 flags; }; /* state flags */ -#define RADEON_PM_SINGLE_DISPLAY_ONLY (1 << 0) +#define RADEON_PM_STATE_SINGLE_DISPLAY_ONLY (1 << 0) struct radeon_power_state { enum radeon_pm_state_type type; diff --git a/drivers/gpu/drm/radeon/radeon_atombios.c b/drivers/gpu/drm/radeon/radeon_atombios.c index c29ac74a1d20..9149e4a3af0f 100644 --- a/drivers/gpu/drm/radeon/radeon_atombios.c +++ b/drivers/gpu/drm/radeon/radeon_atombios.c @@ -1549,7 +1549,7 @@ void radeon_atombios_get_power_modes(struct radeon_device *rdev) rdev->pm.power_state[state_index].clock_info[0].voltage.vddc_id = power_info->info.asPowerPlayInfo[i].ucVoltageDropIndex; } - rdev->pm.power_state[state_index].flags = RADEON_PM_SINGLE_DISPLAY_ONLY; + rdev->pm.power_state[state_index].flags = RADEON_PM_STATE_SINGLE_DISPLAY_ONLY; rdev->pm.power_state[state_index].misc = misc; /* order matters! */ if (misc & ATOM_PM_MISCINFO_POWER_SAVING_MODE) @@ -1568,7 +1568,7 @@ void radeon_atombios_get_power_modes(struct radeon_device *rdev) rdev->pm.power_state[state_index].type = POWER_STATE_TYPE_PERFORMANCE; rdev->pm.power_state[state_index].flags &= - ~RADEON_PM_SINGLE_DISPLAY_ONLY; + ~RADEON_PM_STATE_SINGLE_DISPLAY_ONLY; } if (misc & ATOM_PM_MISCINFO_DRIVER_DEFAULT_MODE) { rdev->pm.power_state[state_index].type = @@ -1577,7 +1577,10 @@ void radeon_atombios_get_power_modes(struct radeon_device *rdev) rdev->pm.power_state[state_index].default_clock_mode = &rdev->pm.power_state[state_index].clock_info[0]; rdev->pm.power_state[state_index].flags &= - ~RADEON_PM_SINGLE_DISPLAY_ONLY; + ~RADEON_PM_STATE_SINGLE_DISPLAY_ONLY; + } else if (state_index == 0) { + rdev->pm.power_state[state_index].clock_info[0].flags |= + RADEON_PM_MODE_NO_DISPLAY; } state_index++; break; @@ -1613,7 +1616,7 @@ void radeon_atombios_get_power_modes(struct radeon_device *rdev) rdev->pm.power_state[state_index].clock_info[0].voltage.vddc_id = power_info->info_2.asPowerPlayInfo[i].ucVoltageDropIndex; } - rdev->pm.power_state[state_index].flags = RADEON_PM_SINGLE_DISPLAY_ONLY; + rdev->pm.power_state[state_index].flags = RADEON_PM_STATE_SINGLE_DISPLAY_ONLY; rdev->pm.power_state[state_index].misc = misc; rdev->pm.power_state[state_index].misc2 = misc2; /* order matters! */ @@ -1633,14 +1636,14 @@ void radeon_atombios_get_power_modes(struct radeon_device *rdev) rdev->pm.power_state[state_index].type = POWER_STATE_TYPE_PERFORMANCE; rdev->pm.power_state[state_index].flags &= - ~RADEON_PM_SINGLE_DISPLAY_ONLY; + ~RADEON_PM_STATE_SINGLE_DISPLAY_ONLY; } if (misc2 & ATOM_PM_MISCINFO2_SYSTEM_AC_LITE_MODE) rdev->pm.power_state[state_index].type = POWER_STATE_TYPE_BALANCED; if (misc2 & ATOM_PM_MISCINFO2_MULTI_DISPLAY_SUPPORT) rdev->pm.power_state[state_index].flags &= - ~RADEON_PM_SINGLE_DISPLAY_ONLY; + ~RADEON_PM_STATE_SINGLE_DISPLAY_ONLY; if (misc & ATOM_PM_MISCINFO_DRIVER_DEFAULT_MODE) { rdev->pm.power_state[state_index].type = POWER_STATE_TYPE_DEFAULT; @@ -1648,7 +1651,10 @@ void radeon_atombios_get_power_modes(struct radeon_device *rdev) rdev->pm.power_state[state_index].default_clock_mode = &rdev->pm.power_state[state_index].clock_info[0]; rdev->pm.power_state[state_index].flags &= - ~RADEON_PM_SINGLE_DISPLAY_ONLY; + ~RADEON_PM_STATE_SINGLE_DISPLAY_ONLY; + } else if (state_index == 0) { + rdev->pm.power_state[state_index].clock_info[0].flags |= + RADEON_PM_MODE_NO_DISPLAY; } state_index++; break; @@ -1690,7 +1696,7 @@ void radeon_atombios_get_power_modes(struct radeon_device *rdev) power_info->info_3.asPowerPlayInfo[i].ucVDDCI_VoltageDropIndex; } } - rdev->pm.power_state[state_index].flags = RADEON_PM_SINGLE_DISPLAY_ONLY; + rdev->pm.power_state[state_index].flags = RADEON_PM_STATE_SINGLE_DISPLAY_ONLY; rdev->pm.power_state[state_index].misc = misc; rdev->pm.power_state[state_index].misc2 = misc2; /* order matters! */ @@ -1710,7 +1716,7 @@ void radeon_atombios_get_power_modes(struct radeon_device *rdev) rdev->pm.power_state[state_index].type = POWER_STATE_TYPE_PERFORMANCE; rdev->pm.power_state[state_index].flags &= - ~RADEON_PM_SINGLE_DISPLAY_ONLY; + ~RADEON_PM_STATE_SINGLE_DISPLAY_ONLY; } if (misc2 & ATOM_PM_MISCINFO2_SYSTEM_AC_LITE_MODE) rdev->pm.power_state[state_index].type = @@ -1721,6 +1727,9 @@ void radeon_atombios_get_power_modes(struct radeon_device *rdev) rdev->pm.default_power_state_index = state_index; rdev->pm.power_state[state_index].default_clock_mode = &rdev->pm.power_state[state_index].clock_info[0]; + } else if (state_index == 0) { + rdev->pm.power_state[state_index].clock_info[0].flags |= + RADEON_PM_MODE_NO_DISPLAY; } state_index++; break; @@ -1734,7 +1743,7 @@ void radeon_atombios_get_power_modes(struct radeon_device *rdev) rdev->pm.power_state[state_index - 1].default_clock_mode = &rdev->pm.power_state[state_index - 1].clock_info[0]; rdev->pm.power_state[state_index].flags &= - ~RADEON_PM_SINGLE_DISPLAY_ONLY; + ~RADEON_PM_STATE_SINGLE_DISPLAY_ONLY; rdev->pm.power_state[state_index].misc = 0; rdev->pm.power_state[state_index].misc2 = 0; } @@ -1881,7 +1890,7 @@ void radeon_atombios_get_power_modes(struct radeon_device *rdev) rdev->pm.power_state[state_index].flags = 0; if (misc & ATOM_PPLIB_SINGLE_DISPLAY_ONLY) rdev->pm.power_state[state_index].flags |= - RADEON_PM_SINGLE_DISPLAY_ONLY; + RADEON_PM_STATE_SINGLE_DISPLAY_ONLY; if (misc2 & ATOM_PPLIB_CLASSIFICATION_BOOT) { rdev->pm.power_state[state_index].type = POWER_STATE_TYPE_DEFAULT; @@ -1892,6 +1901,12 @@ void radeon_atombios_get_power_modes(struct radeon_device *rdev) state_index++; } } + /* if multiple clock modes, mark the lowest as no display */ + for (i = 0; i < state_index; i++) { + if (rdev->pm.power_state[i].num_clock_modes > 1) + rdev->pm.power_state[i].clock_info[0].flags |= + RADEON_PM_MODE_NO_DISPLAY; + } /* first mode is usually default */ if (rdev->pm.default_power_state_index == -1) { rdev->pm.power_state[0].type = diff --git a/drivers/gpu/drm/radeon/radeon_combios.c b/drivers/gpu/drm/radeon/radeon_combios.c index c22344b7fc58..93f18bbf744a 100644 --- a/drivers/gpu/drm/radeon/radeon_combios.c +++ b/drivers/gpu/drm/radeon/radeon_combios.c @@ -2437,7 +2437,7 @@ void radeon_combios_get_power_modes(struct radeon_device *rdev) if (rev > 6) rdev->pm.power_state[state_index].pcie_lanes = RBIOS8(offset + 0x5 + 0x10); - rdev->pm.power_state[state_index].flags = RADEON_PM_SINGLE_DISPLAY_ONLY; + rdev->pm.power_state[state_index].flags = RADEON_PM_STATE_SINGLE_DISPLAY_ONLY; state_index++; } else { /* XXX figure out some good default low power mode for mobility cards w/out power tables */ diff --git a/drivers/gpu/drm/radeon/radeon_legacy_crtc.c b/drivers/gpu/drm/radeon/radeon_legacy_crtc.c index 7701d42c4804..e1e5255396ac 100644 --- a/drivers/gpu/drm/radeon/radeon_legacy_crtc.c +++ b/drivers/gpu/drm/radeon/radeon_legacy_crtc.c @@ -314,6 +314,9 @@ void radeon_crtc_dpms(struct drm_crtc *crtc, int mode) switch (mode) { case DRM_MODE_DPMS_ON: + radeon_crtc->enabled = true; + /* adjust pm to dpms changes BEFORE enabling crtcs */ + radeon_pm_compute_clocks(rdev); if (radeon_crtc->crtc_id) WREG32_P(RADEON_CRTC2_GEN_CNTL, RADEON_CRTC2_EN, ~(RADEON_CRTC2_EN | mask)); else { @@ -323,7 +326,6 @@ void radeon_crtc_dpms(struct drm_crtc *crtc, int mode) } drm_vblank_post_modeset(dev, radeon_crtc->crtc_id); radeon_crtc_load_lut(crtc); - radeon_crtc->enabled = true; break; case DRM_MODE_DPMS_STANDBY: case DRM_MODE_DPMS_SUSPEND: @@ -337,11 +339,10 @@ void radeon_crtc_dpms(struct drm_crtc *crtc, int mode) WREG32_P(RADEON_CRTC_EXT_CNTL, mask, ~mask); } radeon_crtc->enabled = false; + /* adjust pm to dpms changes AFTER disabling crtcs */ + radeon_pm_compute_clocks(rdev); break; } - - /* adjust pm to dpms change */ - radeon_pm_compute_clocks(rdev); } int radeon_crtc_set_base(struct drm_crtc *crtc, int x, int y, diff --git a/drivers/gpu/drm/radeon/radeon_pm.c b/drivers/gpu/drm/radeon/radeon_pm.c index 1ee7fc9918ac..0dfa508fe5f2 100644 --- a/drivers/gpu/drm/radeon/radeon_pm.c +++ b/drivers/gpu/drm/radeon/radeon_pm.c @@ -58,7 +58,7 @@ static void radeon_pm_set_clocks(struct radeon_device *rdev, int static_switch) { int i; - if (!static_switch) + if (rdev->pm.state != PM_STATE_DISABLED) radeon_get_power_state(rdev, rdev->pm.planned_action); mutex_lock(&rdev->ddev->struct_mutex); @@ -147,8 +147,11 @@ static ssize_t radeon_set_power_state_static(struct device *dev, mutex_lock(&rdev->pm.mutex); if ((ps >= 0) && (ps < rdev->pm.num_power_states) && (cm >= 0) && (cm < rdev->pm.power_state[ps].num_clock_modes)) { - if ((rdev->pm.active_crtc_count > 1) && - (rdev->pm.power_state[ps].flags & RADEON_PM_SINGLE_DISPLAY_ONLY)) { + if ((rdev->pm.active_crtc_count > 0) && + (rdev->pm.power_state[ps].clock_info[cm].flags & RADEON_PM_MODE_NO_DISPLAY)) { + DRM_ERROR("Invalid power state for display: %d.%d\n", ps, cm); + } else if ((rdev->pm.active_crtc_count > 1) && + (rdev->pm.power_state[ps].flags & RADEON_PM_STATE_SINGLE_DISPLAY_ONLY)) { DRM_ERROR("Invalid power state for multi-head: %d.%d\n", ps, cm); } else { /* disable dynpm */ @@ -248,7 +251,7 @@ static void radeon_print_power_mode_info(struct radeon_device *rdev) is_default ? "(default)" : ""); if ((rdev->flags & RADEON_IS_PCIE) && !(rdev->flags & RADEON_IS_IGP)) DRM_INFO("\t%d PCIE Lanes\n", rdev->pm.power_state[i].pcie_lanes); - if (rdev->pm.power_state[i].flags & RADEON_PM_SINGLE_DISPLAY_ONLY) + if (rdev->pm.power_state[i].flags & RADEON_PM_STATE_SINGLE_DISPLAY_ONLY) DRM_INFO("\tSingle display only\n"); DRM_INFO("\t%d Clock Mode(s)\n", rdev->pm.power_state[i].num_clock_modes); for (j = 0; j < rdev->pm.power_state[i].num_clock_modes; j++) { @@ -261,6 +264,8 @@ static void radeon_print_power_mode_info(struct radeon_device *rdev) j, rdev->pm.power_state[i].clock_info[j].sclk * 10, rdev->pm.power_state[i].clock_info[j].mclk * 10); + if (rdev->pm.power_state[i].clock_info[j].flags & RADEON_PM_MODE_NO_DISPLAY) + DRM_INFO("\t\tNo display only\n"); } } } @@ -318,7 +323,7 @@ void radeon_pm_fini(struct radeon_device *rdev) /* reset default clocks */ rdev->pm.state = PM_STATE_DISABLED; rdev->pm.planned_action = PM_ACTION_DEFAULT; - radeon_pm_set_clocks(rdev, false); + radeon_pm_set_clocks(rdev, true); } else if ((rdev->pm.current_power_state_index != rdev->pm.default_power_state_index) || (rdev->pm.current_clock_mode_index != 0)) { @@ -342,9 +347,6 @@ void radeon_pm_compute_clocks(struct radeon_device *rdev) struct drm_crtc *crtc; struct radeon_crtc *radeon_crtc; - if (rdev->pm.state == PM_STATE_DISABLED) - return; - mutex_lock(&rdev->pm.mutex); rdev->pm.active_crtcs = 0; @@ -358,13 +360,22 @@ void radeon_pm_compute_clocks(struct radeon_device *rdev) } } + if (rdev->pm.state == PM_STATE_DISABLED) { + mutex_unlock(&rdev->pm.mutex); + return; + } + + /* Note, radeon_pm_set_clocks is called with static_switch set + * to true since we always want to statically set the clocks, + * not wait for vbl. + */ if (rdev->pm.active_crtc_count > 1) { if (rdev->pm.state == PM_STATE_ACTIVE) { cancel_delayed_work(&rdev->pm.idle_work); rdev->pm.state = PM_STATE_PAUSED; - rdev->pm.planned_action = PM_ACTION_UPCLOCK; - radeon_pm_set_clocks(rdev, false); + rdev->pm.planned_action = PM_ACTION_DEFAULT; + radeon_pm_set_clocks(rdev, true); DRM_DEBUG("radeon: dynamic power management deactivated\n"); } @@ -374,7 +385,7 @@ void radeon_pm_compute_clocks(struct radeon_device *rdev) if (rdev->pm.state == PM_STATE_MINIMUM) { rdev->pm.state = PM_STATE_ACTIVE; rdev->pm.planned_action = PM_ACTION_UPCLOCK; - radeon_pm_set_clocks(rdev, false); + radeon_pm_set_clocks(rdev, true); queue_delayed_work(rdev->wq, &rdev->pm.idle_work, msecs_to_jiffies(RADEON_IDLE_LOOP_MS)); @@ -390,7 +401,7 @@ void radeon_pm_compute_clocks(struct radeon_device *rdev) rdev->pm.state = PM_STATE_MINIMUM; rdev->pm.planned_action = PM_ACTION_MINIMUM; - radeon_pm_set_clocks(rdev, false); + radeon_pm_set_clocks(rdev, true); } } @@ -526,6 +537,9 @@ static void radeon_pm_idle_work_handler(struct work_struct *work) } } + /* Note, radeon_pm_set_clocks is called with static_switch set + * to false since we want to wait for vbl to avoid flicker. + */ if (rdev->pm.planned_action != PM_ACTION_NONE && jiffies > rdev->pm.action_timeout) { radeon_pm_set_clocks(rdev, false); -- cgit v1.2.3 From ce8f53709bf440100cb9d31b1303291551cf517f Mon Sep 17 00:00:00 2001 From: Alex Deucher Date: Fri, 7 May 2010 15:10:16 -0400 Subject: drm/radeon/kms/pm: rework power management - Separate dynpm and profile based power management methods. You can select the pm method by echoing the selected method ("dynpm" or "profile") to power_method in sysfs. - Expose basic 4 profile in profile method "default" - default clocks "auto" - select between low and high based on ac/dc state "low" - DC, low power mode "high" - AC, performance mode The current base profile is "default", but it should switched to "auto" once we've tested on more systems. Switching the state is a matter of echoing the requested profile to power_profile in sysfs. The lowest power states are selected automatically when dpms turns the monitors off in all states but default. - Remove dynamic fence-based reclocking for the moment. We can revisit this later once we have basic pm in. - Move pm init/fini to modesetting path. pm is tightly coupled with display state. Make sure display side is initialized before pm. - Add pm suspend/resume functions to make sure pm state is properly reinitialized on resume. - Remove dynpm module option. It's now selectable via sysfs. Signed-off-by: Alex Deucher Signed-off-by: Dave Airlie --- drivers/gpu/drm/radeon/Kconfig | 1 + drivers/gpu/drm/radeon/evergreen.c | 3 - drivers/gpu/drm/radeon/r100.c | 128 ++----- drivers/gpu/drm/radeon/r300.c | 3 - drivers/gpu/drm/radeon/r420.c | 32 +- drivers/gpu/drm/radeon/r520.c | 2 - drivers/gpu/drm/radeon/r600.c | 332 ++++++++++++----- drivers/gpu/drm/radeon/radeon.h | 87 +++-- drivers/gpu/drm/radeon/radeon_asic.c | 56 +-- drivers/gpu/drm/radeon/radeon_asic.h | 12 +- drivers/gpu/drm/radeon/radeon_device.c | 2 + drivers/gpu/drm/radeon/radeon_display.c | 4 + drivers/gpu/drm/radeon/radeon_drv.c | 4 - drivers/gpu/drm/radeon/radeon_pm.c | 628 +++++++++++++++++++------------- drivers/gpu/drm/radeon/rs400.c | 3 - drivers/gpu/drm/radeon/rs600.c | 3 - drivers/gpu/drm/radeon/rs690.c | 3 - drivers/gpu/drm/radeon/rv515.c | 3 - drivers/gpu/drm/radeon/rv770.c | 3 - 19 files changed, 790 insertions(+), 519 deletions(-) (limited to 'drivers/gpu/drm/radeon') diff --git a/drivers/gpu/drm/radeon/Kconfig b/drivers/gpu/drm/radeon/Kconfig index 1c02d23f6fcc..80c5b3ea28b4 100644 --- a/drivers/gpu/drm/radeon/Kconfig +++ b/drivers/gpu/drm/radeon/Kconfig @@ -1,6 +1,7 @@ config DRM_RADEON_KMS bool "Enable modesetting on radeon by default - NEW DRIVER" depends on DRM_RADEON + depends on POWER_SUPPLY help Choose this option if you want kernel modesetting enabled by default. diff --git a/drivers/gpu/drm/radeon/evergreen.c b/drivers/gpu/drm/radeon/evergreen.c index 8d86d0568d97..8c8e4d3cbaa3 100644 --- a/drivers/gpu/drm/radeon/evergreen.c +++ b/drivers/gpu/drm/radeon/evergreen.c @@ -2115,8 +2115,6 @@ int evergreen_init(struct radeon_device *rdev) r = radeon_clocks_init(rdev); if (r) return r; - /* Initialize power management */ - radeon_pm_init(rdev); /* Fence driver */ r = radeon_fence_driver_init(rdev); if (r) @@ -2178,7 +2176,6 @@ int evergreen_init(struct radeon_device *rdev) void evergreen_fini(struct radeon_device *rdev) { - radeon_pm_fini(rdev); /*r600_blit_fini(rdev);*/ r700_cp_fini(rdev); r600_wb_fini(rdev); diff --git a/drivers/gpu/drm/radeon/r100.c b/drivers/gpu/drm/radeon/r100.c index 4161a35dd3d3..4c5d21bfa2c4 100644 --- a/drivers/gpu/drm/radeon/r100.c +++ b/drivers/gpu/drm/radeon/r100.c @@ -68,22 +68,21 @@ MODULE_FIRMWARE(FIRMWARE_R520); * r100,rv100,rs100,rv200,rs200,r200,rv250,rs300,rv280 */ -void r100_get_power_state(struct radeon_device *rdev, - enum radeon_pm_action action) +void r100_pm_get_dynpm_state(struct radeon_device *rdev) { int i; - rdev->pm.can_upclock = true; - rdev->pm.can_downclock = true; + rdev->pm.dynpm_can_upclock = true; + rdev->pm.dynpm_can_downclock = true; - switch (action) { - case PM_ACTION_MINIMUM: + switch (rdev->pm.dynpm_planned_action) { + case DYNPM_ACTION_MINIMUM: rdev->pm.requested_power_state_index = 0; - rdev->pm.can_downclock = false; + rdev->pm.dynpm_can_downclock = false; break; - case PM_ACTION_DOWNCLOCK: + case DYNPM_ACTION_DOWNCLOCK: if (rdev->pm.current_power_state_index == 0) { rdev->pm.requested_power_state_index = rdev->pm.current_power_state_index; - rdev->pm.can_downclock = false; + rdev->pm.dynpm_can_downclock = false; } else { if (rdev->pm.active_crtc_count > 1) { for (i = 0; i < rdev->pm.num_power_states; i++) { @@ -108,10 +107,10 @@ void r100_get_power_state(struct radeon_device *rdev, rdev->pm.requested_power_state_index++; } break; - case PM_ACTION_UPCLOCK: + case DYNPM_ACTION_UPCLOCK: if (rdev->pm.current_power_state_index == (rdev->pm.num_power_states - 1)) { rdev->pm.requested_power_state_index = rdev->pm.current_power_state_index; - rdev->pm.can_upclock = false; + rdev->pm.dynpm_can_upclock = false; } else { if (rdev->pm.active_crtc_count > 1) { for (i = (rdev->pm.num_power_states - 1); i >= 0; i--) { @@ -130,11 +129,11 @@ void r100_get_power_state(struct radeon_device *rdev, rdev->pm.current_power_state_index + 1; } break; - case PM_ACTION_DEFAULT: + case DYNPM_ACTION_DEFAULT: rdev->pm.requested_power_state_index = rdev->pm.default_power_state_index; - rdev->pm.can_upclock = false; + rdev->pm.dynpm_can_upclock = false; break; - case PM_ACTION_NONE: + case DYNPM_ACTION_NONE: default: DRM_ERROR("Requested mode for not defined action\n"); return; @@ -151,77 +150,33 @@ void r100_get_power_state(struct radeon_device *rdev, pcie_lanes); } -void r100_set_power_state(struct radeon_device *rdev, bool static_switch) -{ - u32 sclk, mclk; - - if (rdev->pm.current_power_state_index == rdev->pm.requested_power_state_index) - return; - - if (radeon_gui_idle(rdev)) { - - sclk = rdev->pm.power_state[rdev->pm.requested_power_state_index]. - clock_info[rdev->pm.requested_clock_mode_index].sclk; - if (sclk > rdev->clock.default_sclk) - sclk = rdev->clock.default_sclk; - - mclk = rdev->pm.power_state[rdev->pm.requested_power_state_index]. - clock_info[rdev->pm.requested_clock_mode_index].mclk; - if (mclk > rdev->clock.default_mclk) - mclk = rdev->clock.default_mclk; - /* don't change the mclk with multiple crtcs */ - if (rdev->pm.active_crtc_count > 1) - mclk = rdev->clock.default_mclk; - - /* voltage, pcie lanes, etc.*/ - radeon_pm_misc(rdev); - - if (static_switch) { - radeon_pm_prepare(rdev); - /* set engine clock */ - if (sclk != rdev->pm.current_sclk) { - radeon_set_engine_clock(rdev, sclk); - rdev->pm.current_sclk = sclk; - DRM_INFO("Setting: e: %d\n", sclk); - } - /* set memory clock */ - if (rdev->asic->set_memory_clock && (mclk != rdev->pm.current_mclk)) { - radeon_set_memory_clock(rdev, mclk); - rdev->pm.current_mclk = mclk; - DRM_INFO("Setting: m: %d\n", mclk); - } - radeon_pm_finish(rdev); - } else { - radeon_sync_with_vblank(rdev); - - if (!radeon_pm_in_vbl(rdev)) - return; - - radeon_pm_prepare(rdev); - /* set engine clock */ - if (sclk != rdev->pm.current_sclk) { - radeon_pm_debug_check_in_vbl(rdev, false); - radeon_set_engine_clock(rdev, sclk); - radeon_pm_debug_check_in_vbl(rdev, true); - rdev->pm.current_sclk = sclk; - DRM_INFO("Setting: e: %d\n", sclk); - } - - /* set memory clock */ - if (rdev->asic->set_memory_clock && (mclk != rdev->pm.current_mclk)) { - radeon_pm_debug_check_in_vbl(rdev, false); - radeon_set_memory_clock(rdev, mclk); - radeon_pm_debug_check_in_vbl(rdev, true); - rdev->pm.current_mclk = mclk; - DRM_INFO("Setting: m: %d\n", mclk); - } - radeon_pm_finish(rdev); - } - - rdev->pm.current_power_state_index = rdev->pm.requested_power_state_index; - rdev->pm.current_clock_mode_index = rdev->pm.requested_clock_mode_index; - } else - DRM_INFO("pm: GUI not idle!!!\n"); +void r100_pm_init_profile(struct radeon_device *rdev) +{ + /* default */ + rdev->pm.profiles[PM_PROFILE_DEFAULT_IDX].dpms_off_ps_idx = rdev->pm.default_power_state_index; + rdev->pm.profiles[PM_PROFILE_DEFAULT_IDX].dpms_on_ps_idx = rdev->pm.default_power_state_index; + rdev->pm.profiles[PM_PROFILE_DEFAULT_IDX].dpms_off_cm_idx = 0; + rdev->pm.profiles[PM_PROFILE_DEFAULT_IDX].dpms_on_cm_idx = 0; + /* low sh */ + rdev->pm.profiles[PM_PROFILE_LOW_SH_IDX].dpms_off_ps_idx = 0; + rdev->pm.profiles[PM_PROFILE_LOW_SH_IDX].dpms_on_ps_idx = 0; + rdev->pm.profiles[PM_PROFILE_LOW_SH_IDX].dpms_off_cm_idx = 0; + rdev->pm.profiles[PM_PROFILE_LOW_SH_IDX].dpms_on_cm_idx = 0; + /* high sh */ + rdev->pm.profiles[PM_PROFILE_HIGH_SH_IDX].dpms_off_ps_idx = 0; + rdev->pm.profiles[PM_PROFILE_HIGH_SH_IDX].dpms_on_ps_idx = rdev->pm.default_power_state_index; + rdev->pm.profiles[PM_PROFILE_HIGH_SH_IDX].dpms_off_cm_idx = 0; + rdev->pm.profiles[PM_PROFILE_HIGH_SH_IDX].dpms_on_cm_idx = 0; + /* low mh */ + rdev->pm.profiles[PM_PROFILE_LOW_MH_IDX].dpms_off_ps_idx = 0; + rdev->pm.profiles[PM_PROFILE_LOW_MH_IDX].dpms_on_ps_idx = rdev->pm.default_power_state_index; + rdev->pm.profiles[PM_PROFILE_LOW_MH_IDX].dpms_off_cm_idx = 0; + rdev->pm.profiles[PM_PROFILE_LOW_MH_IDX].dpms_on_cm_idx = 0; + /* high mh */ + rdev->pm.profiles[PM_PROFILE_HIGH_MH_IDX].dpms_off_ps_idx = 0; + rdev->pm.profiles[PM_PROFILE_HIGH_MH_IDX].dpms_on_ps_idx = rdev->pm.default_power_state_index; + rdev->pm.profiles[PM_PROFILE_HIGH_MH_IDX].dpms_off_cm_idx = 0; + rdev->pm.profiles[PM_PROFILE_HIGH_MH_IDX].dpms_on_cm_idx = 0; } void r100_pm_misc(struct radeon_device *rdev) @@ -3815,7 +3770,6 @@ int r100_suspend(struct radeon_device *rdev) void r100_fini(struct radeon_device *rdev) { - radeon_pm_fini(rdev); r100_cp_fini(rdev); r100_wb_fini(rdev); r100_ib_fini(rdev); @@ -3871,8 +3825,6 @@ int r100_init(struct radeon_device *rdev) r100_errata(rdev); /* Initialize clocks */ radeon_get_clock_info(rdev->ddev); - /* Initialize power management */ - radeon_pm_init(rdev); /* initialize AGP */ if (rdev->flags & RADEON_IS_AGP) { r = radeon_agp_init(rdev); diff --git a/drivers/gpu/drm/radeon/r300.c b/drivers/gpu/drm/radeon/r300.c index 5d622cb39b33..5c54db51de85 100644 --- a/drivers/gpu/drm/radeon/r300.c +++ b/drivers/gpu/drm/radeon/r300.c @@ -1345,7 +1345,6 @@ int r300_suspend(struct radeon_device *rdev) void r300_fini(struct radeon_device *rdev) { - radeon_pm_fini(rdev); r100_cp_fini(rdev); r100_wb_fini(rdev); r100_ib_fini(rdev); @@ -1401,8 +1400,6 @@ int r300_init(struct radeon_device *rdev) r300_errata(rdev); /* Initialize clocks */ radeon_get_clock_info(rdev->ddev); - /* Initialize power management */ - radeon_pm_init(rdev); /* initialize AGP */ if (rdev->flags & RADEON_IS_AGP) { r = radeon_agp_init(rdev); diff --git a/drivers/gpu/drm/radeon/r420.c b/drivers/gpu/drm/radeon/r420.c index 3759d8384294..87c0e3840034 100644 --- a/drivers/gpu/drm/radeon/r420.c +++ b/drivers/gpu/drm/radeon/r420.c @@ -36,6 +36,35 @@ #include "r420d.h" #include "r420_reg_safe.h" +void r420_pm_init_profile(struct radeon_device *rdev) +{ + /* default */ + rdev->pm.profiles[PM_PROFILE_DEFAULT_IDX].dpms_off_ps_idx = rdev->pm.default_power_state_index; + rdev->pm.profiles[PM_PROFILE_DEFAULT_IDX].dpms_on_ps_idx = rdev->pm.default_power_state_index; + rdev->pm.profiles[PM_PROFILE_DEFAULT_IDX].dpms_off_cm_idx = 0; + rdev->pm.profiles[PM_PROFILE_DEFAULT_IDX].dpms_on_cm_idx = 0; + /* low sh */ + rdev->pm.profiles[PM_PROFILE_LOW_SH_IDX].dpms_off_ps_idx = 0; + rdev->pm.profiles[PM_PROFILE_LOW_SH_IDX].dpms_on_ps_idx = 1; + rdev->pm.profiles[PM_PROFILE_LOW_SH_IDX].dpms_off_cm_idx = 0; + rdev->pm.profiles[PM_PROFILE_LOW_SH_IDX].dpms_on_cm_idx = 0; + /* high sh */ + rdev->pm.profiles[PM_PROFILE_HIGH_SH_IDX].dpms_off_ps_idx = 0; + rdev->pm.profiles[PM_PROFILE_HIGH_SH_IDX].dpms_on_ps_idx = rdev->pm.default_power_state_index; + rdev->pm.profiles[PM_PROFILE_HIGH_SH_IDX].dpms_off_cm_idx = 0; + rdev->pm.profiles[PM_PROFILE_HIGH_SH_IDX].dpms_on_cm_idx = 0; + /* low mh */ + rdev->pm.profiles[PM_PROFILE_LOW_MH_IDX].dpms_off_ps_idx = 0; + rdev->pm.profiles[PM_PROFILE_LOW_MH_IDX].dpms_on_ps_idx = rdev->pm.default_power_state_index; + rdev->pm.profiles[PM_PROFILE_LOW_MH_IDX].dpms_off_cm_idx = 0; + rdev->pm.profiles[PM_PROFILE_LOW_MH_IDX].dpms_on_cm_idx = 0; + /* high mh */ + rdev->pm.profiles[PM_PROFILE_HIGH_MH_IDX].dpms_off_ps_idx = 0; + rdev->pm.profiles[PM_PROFILE_HIGH_MH_IDX].dpms_on_ps_idx = rdev->pm.default_power_state_index; + rdev->pm.profiles[PM_PROFILE_HIGH_MH_IDX].dpms_off_cm_idx = 0; + rdev->pm.profiles[PM_PROFILE_HIGH_MH_IDX].dpms_on_cm_idx = 0; +} + static void r420_set_reg_safe(struct radeon_device *rdev) { rdev->config.r300.reg_safe_bm = r420_reg_safe_bm; @@ -268,7 +297,6 @@ int r420_suspend(struct radeon_device *rdev) void r420_fini(struct radeon_device *rdev) { - radeon_pm_fini(rdev); r100_cp_fini(rdev); r100_wb_fini(rdev); r100_ib_fini(rdev); @@ -328,8 +356,6 @@ int r420_init(struct radeon_device *rdev) /* Initialize clocks */ radeon_get_clock_info(rdev->ddev); - /* Initialize power management */ - radeon_pm_init(rdev); /* initialize AGP */ if (rdev->flags & RADEON_IS_AGP) { r = radeon_agp_init(rdev); diff --git a/drivers/gpu/drm/radeon/r520.c b/drivers/gpu/drm/radeon/r520.c index 870111e26bd1..34330df28483 100644 --- a/drivers/gpu/drm/radeon/r520.c +++ b/drivers/gpu/drm/radeon/r520.c @@ -261,8 +261,6 @@ int r520_init(struct radeon_device *rdev) } /* Initialize clocks */ radeon_get_clock_info(rdev->ddev); - /* Initialize power management */ - radeon_pm_init(rdev); /* initialize AGP */ if (rdev->flags & RADEON_IS_AGP) { r = radeon_agp_init(rdev); diff --git a/drivers/gpu/drm/radeon/r600.c b/drivers/gpu/drm/radeon/r600.c index 08a328c4165a..618d76d366a4 100644 --- a/drivers/gpu/drm/radeon/r600.c +++ b/drivers/gpu/drm/radeon/r600.c @@ -92,13 +92,12 @@ void r600_gpu_init(struct radeon_device *rdev); void r600_fini(struct radeon_device *rdev); void r600_irq_disable(struct radeon_device *rdev); -void r600_get_power_state(struct radeon_device *rdev, - enum radeon_pm_action action) +void r600_pm_get_dynpm_state(struct radeon_device *rdev) { int i; - rdev->pm.can_upclock = true; - rdev->pm.can_downclock = true; + rdev->pm.dynpm_can_upclock = true; + rdev->pm.dynpm_can_downclock = true; /* power state array is low to high, default is first */ if ((rdev->flags & RADEON_IS_IGP) || (rdev->family == CHIP_R600)) { @@ -107,16 +106,16 @@ void r600_get_power_state(struct radeon_device *rdev, if (rdev->pm.num_power_states > 2) min_power_state_index = 1; - switch (action) { - case PM_ACTION_MINIMUM: + switch (rdev->pm.dynpm_planned_action) { + case DYNPM_ACTION_MINIMUM: rdev->pm.requested_power_state_index = min_power_state_index; rdev->pm.requested_clock_mode_index = 0; - rdev->pm.can_downclock = false; + rdev->pm.dynpm_can_downclock = false; break; - case PM_ACTION_DOWNCLOCK: + case DYNPM_ACTION_DOWNCLOCK: if (rdev->pm.current_power_state_index == min_power_state_index) { rdev->pm.requested_power_state_index = rdev->pm.current_power_state_index; - rdev->pm.can_downclock = false; + rdev->pm.dynpm_can_downclock = false; } else { if (rdev->pm.active_crtc_count > 1) { for (i = 0; i < rdev->pm.num_power_states; i++) { @@ -144,10 +143,10 @@ void r600_get_power_state(struct radeon_device *rdev, rdev->pm.requested_power_state_index++; } break; - case PM_ACTION_UPCLOCK: + case DYNPM_ACTION_UPCLOCK: if (rdev->pm.current_power_state_index == (rdev->pm.num_power_states - 1)) { rdev->pm.requested_power_state_index = rdev->pm.current_power_state_index; - rdev->pm.can_upclock = false; + rdev->pm.dynpm_can_upclock = false; } else { if (rdev->pm.active_crtc_count > 1) { for (i = (rdev->pm.num_power_states - 1); i >= 0; i--) { @@ -168,12 +167,12 @@ void r600_get_power_state(struct radeon_device *rdev, } rdev->pm.requested_clock_mode_index = 0; break; - case PM_ACTION_DEFAULT: + case DYNPM_ACTION_DEFAULT: rdev->pm.requested_power_state_index = rdev->pm.default_power_state_index; rdev->pm.requested_clock_mode_index = 0; - rdev->pm.can_upclock = false; + rdev->pm.dynpm_can_upclock = false; break; - case PM_ACTION_NONE: + case DYNPM_ACTION_NONE: default: DRM_ERROR("Requested mode for not defined action\n"); return; @@ -200,22 +199,22 @@ void r600_get_power_state(struct radeon_device *rdev, } else rdev->pm.requested_power_state_index = 1; - switch (action) { - case PM_ACTION_MINIMUM: + switch (rdev->pm.dynpm_planned_action) { + case DYNPM_ACTION_MINIMUM: rdev->pm.requested_clock_mode_index = 0; - rdev->pm.can_downclock = false; + rdev->pm.dynpm_can_downclock = false; break; - case PM_ACTION_DOWNCLOCK: + case DYNPM_ACTION_DOWNCLOCK: if (rdev->pm.requested_power_state_index == rdev->pm.current_power_state_index) { if (rdev->pm.current_clock_mode_index == 0) { rdev->pm.requested_clock_mode_index = 0; - rdev->pm.can_downclock = false; + rdev->pm.dynpm_can_downclock = false; } else rdev->pm.requested_clock_mode_index = rdev->pm.current_clock_mode_index - 1; } else { rdev->pm.requested_clock_mode_index = 0; - rdev->pm.can_downclock = false; + rdev->pm.dynpm_can_downclock = false; } /* don't use the power state if crtcs are active and no display flag is set */ if ((rdev->pm.active_crtc_count > 0) && @@ -225,27 +224,27 @@ void r600_get_power_state(struct radeon_device *rdev, rdev->pm.requested_clock_mode_index++; } break; - case PM_ACTION_UPCLOCK: + case DYNPM_ACTION_UPCLOCK: if (rdev->pm.requested_power_state_index == rdev->pm.current_power_state_index) { if (rdev->pm.current_clock_mode_index == (rdev->pm.power_state[rdev->pm.requested_power_state_index].num_clock_modes - 1)) { rdev->pm.requested_clock_mode_index = rdev->pm.current_clock_mode_index; - rdev->pm.can_upclock = false; + rdev->pm.dynpm_can_upclock = false; } else rdev->pm.requested_clock_mode_index = rdev->pm.current_clock_mode_index + 1; } else { rdev->pm.requested_clock_mode_index = rdev->pm.power_state[rdev->pm.requested_power_state_index].num_clock_modes - 1; - rdev->pm.can_upclock = false; + rdev->pm.dynpm_can_upclock = false; } break; - case PM_ACTION_DEFAULT: + case DYNPM_ACTION_DEFAULT: rdev->pm.requested_power_state_index = rdev->pm.default_power_state_index; rdev->pm.requested_clock_mode_index = 0; - rdev->pm.can_upclock = false; + rdev->pm.dynpm_can_upclock = false; break; - case PM_ACTION_NONE: + case DYNPM_ACTION_NONE: default: DRM_ERROR("Requested mode for not defined action\n"); return; @@ -261,73 +260,225 @@ void r600_get_power_state(struct radeon_device *rdev, pcie_lanes); } -void r600_set_power_state(struct radeon_device *rdev, bool static_switch) +static int r600_pm_get_type_index(struct radeon_device *rdev, + enum radeon_pm_state_type ps_type, + int instance) { - u32 sclk, mclk; - - if ((rdev->pm.requested_clock_mode_index == rdev->pm.current_clock_mode_index) && - (rdev->pm.requested_power_state_index == rdev->pm.current_power_state_index)) - return; - - if (radeon_gui_idle(rdev)) { - sclk = rdev->pm.power_state[rdev->pm.requested_power_state_index]. - clock_info[rdev->pm.requested_clock_mode_index].sclk; - if (sclk > rdev->clock.default_sclk) - sclk = rdev->clock.default_sclk; - - mclk = rdev->pm.power_state[rdev->pm.requested_power_state_index]. - clock_info[rdev->pm.requested_clock_mode_index].mclk; - if (mclk > rdev->clock.default_mclk) - mclk = rdev->clock.default_mclk; - - /* voltage, pcie lanes, etc.*/ - radeon_pm_misc(rdev); + int i; + int found_instance = -1; - if (static_switch) { - radeon_pm_prepare(rdev); - /* set engine clock */ - if (sclk != rdev->pm.current_sclk) { - radeon_set_engine_clock(rdev, sclk); - rdev->pm.current_sclk = sclk; - DRM_INFO("Setting: e: %d\n", sclk); - } - /* set memory clock */ - if (rdev->asic->set_memory_clock && (mclk != rdev->pm.current_mclk)) { - radeon_set_memory_clock(rdev, mclk); - rdev->pm.current_mclk = mclk; - DRM_INFO("Setting: m: %d\n", mclk); - } - radeon_pm_finish(rdev); + for (i = 0; i < rdev->pm.num_power_states; i++) { + if (rdev->pm.power_state[i].type == ps_type) { + found_instance++; + if (found_instance == instance) + return i; + } + } + /* return default if no match */ + return rdev->pm.default_power_state_index; +} + +void rs780_pm_init_profile(struct radeon_device *rdev) +{ + if (rdev->pm.num_power_states == 2) { + /* default */ + rdev->pm.profiles[PM_PROFILE_DEFAULT_IDX].dpms_off_ps_idx = rdev->pm.default_power_state_index; + rdev->pm.profiles[PM_PROFILE_DEFAULT_IDX].dpms_on_ps_idx = rdev->pm.default_power_state_index; + rdev->pm.profiles[PM_PROFILE_DEFAULT_IDX].dpms_off_cm_idx = 0; + rdev->pm.profiles[PM_PROFILE_DEFAULT_IDX].dpms_on_cm_idx = 0; + /* low sh */ + rdev->pm.profiles[PM_PROFILE_LOW_SH_IDX].dpms_off_ps_idx = 0; + rdev->pm.profiles[PM_PROFILE_LOW_SH_IDX].dpms_on_ps_idx = 0; + rdev->pm.profiles[PM_PROFILE_LOW_SH_IDX].dpms_off_cm_idx = 0; + rdev->pm.profiles[PM_PROFILE_LOW_SH_IDX].dpms_on_cm_idx = 0; + /* high sh */ + rdev->pm.profiles[PM_PROFILE_HIGH_SH_IDX].dpms_off_ps_idx = 0; + rdev->pm.profiles[PM_PROFILE_HIGH_SH_IDX].dpms_on_ps_idx = 1; + rdev->pm.profiles[PM_PROFILE_HIGH_SH_IDX].dpms_off_cm_idx = 0; + rdev->pm.profiles[PM_PROFILE_HIGH_SH_IDX].dpms_on_cm_idx = 0; + /* low mh */ + rdev->pm.profiles[PM_PROFILE_LOW_MH_IDX].dpms_off_ps_idx = 0; + rdev->pm.profiles[PM_PROFILE_LOW_MH_IDX].dpms_on_ps_idx = 0; + rdev->pm.profiles[PM_PROFILE_LOW_MH_IDX].dpms_off_cm_idx = 0; + rdev->pm.profiles[PM_PROFILE_LOW_MH_IDX].dpms_on_cm_idx = 0; + /* high mh */ + rdev->pm.profiles[PM_PROFILE_HIGH_MH_IDX].dpms_off_ps_idx = 0; + rdev->pm.profiles[PM_PROFILE_HIGH_MH_IDX].dpms_on_ps_idx = 1; + rdev->pm.profiles[PM_PROFILE_HIGH_MH_IDX].dpms_off_cm_idx = 0; + rdev->pm.profiles[PM_PROFILE_HIGH_MH_IDX].dpms_on_cm_idx = 0; + } else if (rdev->pm.num_power_states == 3) { + /* default */ + rdev->pm.profiles[PM_PROFILE_DEFAULT_IDX].dpms_off_ps_idx = rdev->pm.default_power_state_index; + rdev->pm.profiles[PM_PROFILE_DEFAULT_IDX].dpms_on_ps_idx = rdev->pm.default_power_state_index; + rdev->pm.profiles[PM_PROFILE_DEFAULT_IDX].dpms_off_cm_idx = 0; + rdev->pm.profiles[PM_PROFILE_DEFAULT_IDX].dpms_on_cm_idx = 0; + /* low sh */ + rdev->pm.profiles[PM_PROFILE_LOW_SH_IDX].dpms_off_ps_idx = 1; + rdev->pm.profiles[PM_PROFILE_LOW_SH_IDX].dpms_on_ps_idx = 1; + rdev->pm.profiles[PM_PROFILE_LOW_SH_IDX].dpms_off_cm_idx = 0; + rdev->pm.profiles[PM_PROFILE_LOW_SH_IDX].dpms_on_cm_idx = 0; + /* high sh */ + rdev->pm.profiles[PM_PROFILE_HIGH_SH_IDX].dpms_off_ps_idx = 1; + rdev->pm.profiles[PM_PROFILE_HIGH_SH_IDX].dpms_on_ps_idx = 2; + rdev->pm.profiles[PM_PROFILE_HIGH_SH_IDX].dpms_off_cm_idx = 0; + rdev->pm.profiles[PM_PROFILE_HIGH_SH_IDX].dpms_on_cm_idx = 0; + /* low mh */ + rdev->pm.profiles[PM_PROFILE_LOW_MH_IDX].dpms_off_ps_idx = 1; + rdev->pm.profiles[PM_PROFILE_LOW_MH_IDX].dpms_on_ps_idx = 1; + rdev->pm.profiles[PM_PROFILE_LOW_MH_IDX].dpms_off_cm_idx = 0; + rdev->pm.profiles[PM_PROFILE_LOW_MH_IDX].dpms_on_cm_idx = 0; + /* high mh */ + rdev->pm.profiles[PM_PROFILE_HIGH_MH_IDX].dpms_off_ps_idx = 1; + rdev->pm.profiles[PM_PROFILE_HIGH_MH_IDX].dpms_on_ps_idx = 2; + rdev->pm.profiles[PM_PROFILE_HIGH_MH_IDX].dpms_off_cm_idx = 0; + rdev->pm.profiles[PM_PROFILE_HIGH_MH_IDX].dpms_on_cm_idx = 0; + } else { + /* default */ + rdev->pm.profiles[PM_PROFILE_DEFAULT_IDX].dpms_off_ps_idx = rdev->pm.default_power_state_index; + rdev->pm.profiles[PM_PROFILE_DEFAULT_IDX].dpms_on_ps_idx = rdev->pm.default_power_state_index; + rdev->pm.profiles[PM_PROFILE_DEFAULT_IDX].dpms_off_cm_idx = 0; + rdev->pm.profiles[PM_PROFILE_DEFAULT_IDX].dpms_on_cm_idx = 0; + /* low sh */ + rdev->pm.profiles[PM_PROFILE_LOW_SH_IDX].dpms_off_ps_idx = 2; + rdev->pm.profiles[PM_PROFILE_LOW_SH_IDX].dpms_on_ps_idx = 2; + rdev->pm.profiles[PM_PROFILE_LOW_SH_IDX].dpms_off_cm_idx = 0; + rdev->pm.profiles[PM_PROFILE_LOW_SH_IDX].dpms_on_cm_idx = 0; + /* high sh */ + rdev->pm.profiles[PM_PROFILE_HIGH_SH_IDX].dpms_off_ps_idx = 2; + rdev->pm.profiles[PM_PROFILE_HIGH_SH_IDX].dpms_on_ps_idx = 3; + rdev->pm.profiles[PM_PROFILE_HIGH_SH_IDX].dpms_off_cm_idx = 0; + rdev->pm.profiles[PM_PROFILE_HIGH_SH_IDX].dpms_on_cm_idx = 0; + /* low mh */ + rdev->pm.profiles[PM_PROFILE_LOW_MH_IDX].dpms_off_ps_idx = 2; + rdev->pm.profiles[PM_PROFILE_LOW_MH_IDX].dpms_on_ps_idx = 0; + rdev->pm.profiles[PM_PROFILE_LOW_MH_IDX].dpms_off_cm_idx = 0; + rdev->pm.profiles[PM_PROFILE_LOW_MH_IDX].dpms_on_cm_idx = 0; + /* high mh */ + rdev->pm.profiles[PM_PROFILE_HIGH_MH_IDX].dpms_off_ps_idx = 2; + rdev->pm.profiles[PM_PROFILE_HIGH_MH_IDX].dpms_on_ps_idx = 3; + rdev->pm.profiles[PM_PROFILE_HIGH_MH_IDX].dpms_off_cm_idx = 0; + rdev->pm.profiles[PM_PROFILE_HIGH_MH_IDX].dpms_on_cm_idx = 0; + } +} + +void r600_pm_init_profile(struct radeon_device *rdev) +{ + if (rdev->family == CHIP_R600) { + /* XXX */ + /* default */ + rdev->pm.profiles[PM_PROFILE_DEFAULT_IDX].dpms_off_ps_idx = rdev->pm.default_power_state_index; + rdev->pm.profiles[PM_PROFILE_DEFAULT_IDX].dpms_on_ps_idx = rdev->pm.default_power_state_index; + rdev->pm.profiles[PM_PROFILE_DEFAULT_IDX].dpms_off_cm_idx = 0; + rdev->pm.profiles[PM_PROFILE_DEFAULT_IDX].dpms_on_cm_idx = 2; + /* low sh */ + rdev->pm.profiles[PM_PROFILE_LOW_SH_IDX].dpms_off_ps_idx = rdev->pm.default_power_state_index; + rdev->pm.profiles[PM_PROFILE_LOW_SH_IDX].dpms_on_ps_idx = rdev->pm.default_power_state_index; + rdev->pm.profiles[PM_PROFILE_LOW_SH_IDX].dpms_off_cm_idx = 0; + rdev->pm.profiles[PM_PROFILE_LOW_SH_IDX].dpms_on_cm_idx = 2; + /* high sh */ + rdev->pm.profiles[PM_PROFILE_HIGH_SH_IDX].dpms_off_ps_idx = rdev->pm.default_power_state_index; + rdev->pm.profiles[PM_PROFILE_HIGH_SH_IDX].dpms_on_ps_idx = rdev->pm.default_power_state_index; + rdev->pm.profiles[PM_PROFILE_HIGH_SH_IDX].dpms_off_cm_idx = 0; + rdev->pm.profiles[PM_PROFILE_HIGH_SH_IDX].dpms_on_cm_idx = 2; + /* low mh */ + rdev->pm.profiles[PM_PROFILE_LOW_MH_IDX].dpms_off_ps_idx = rdev->pm.default_power_state_index; + rdev->pm.profiles[PM_PROFILE_LOW_MH_IDX].dpms_on_ps_idx = rdev->pm.default_power_state_index; + rdev->pm.profiles[PM_PROFILE_LOW_MH_IDX].dpms_off_cm_idx = 0; + rdev->pm.profiles[PM_PROFILE_LOW_MH_IDX].dpms_on_cm_idx = 2; + /* high mh */ + rdev->pm.profiles[PM_PROFILE_HIGH_MH_IDX].dpms_off_ps_idx = rdev->pm.default_power_state_index; + rdev->pm.profiles[PM_PROFILE_HIGH_MH_IDX].dpms_on_ps_idx = rdev->pm.default_power_state_index; + rdev->pm.profiles[PM_PROFILE_HIGH_MH_IDX].dpms_off_cm_idx = 0; + rdev->pm.profiles[PM_PROFILE_HIGH_MH_IDX].dpms_on_cm_idx = 2; + } else if (rdev->flags & RADEON_IS_MOBILITY) { + /* default */ + rdev->pm.profiles[PM_PROFILE_DEFAULT_IDX].dpms_off_ps_idx = rdev->pm.default_power_state_index; + rdev->pm.profiles[PM_PROFILE_DEFAULT_IDX].dpms_on_ps_idx = rdev->pm.default_power_state_index; + rdev->pm.profiles[PM_PROFILE_DEFAULT_IDX].dpms_off_cm_idx = 0; + rdev->pm.profiles[PM_PROFILE_DEFAULT_IDX].dpms_on_cm_idx = 2; + /* low sh */ + rdev->pm.profiles[PM_PROFILE_LOW_SH_IDX].dpms_off_ps_idx = + r600_pm_get_type_index(rdev, POWER_STATE_TYPE_BATTERY, 0); + rdev->pm.profiles[PM_PROFILE_LOW_SH_IDX].dpms_on_ps_idx = + r600_pm_get_type_index(rdev, POWER_STATE_TYPE_BATTERY, 0); + rdev->pm.profiles[PM_PROFILE_LOW_SH_IDX].dpms_off_cm_idx = 0; + rdev->pm.profiles[PM_PROFILE_LOW_SH_IDX].dpms_on_cm_idx = 2; + /* high sh */ + rdev->pm.profiles[PM_PROFILE_HIGH_SH_IDX].dpms_off_ps_idx = + r600_pm_get_type_index(rdev, POWER_STATE_TYPE_PERFORMANCE, 0); + rdev->pm.profiles[PM_PROFILE_HIGH_SH_IDX].dpms_on_ps_idx = + r600_pm_get_type_index(rdev, POWER_STATE_TYPE_PERFORMANCE, 0); + rdev->pm.profiles[PM_PROFILE_HIGH_SH_IDX].dpms_off_cm_idx = 0; + rdev->pm.profiles[PM_PROFILE_HIGH_SH_IDX].dpms_on_cm_idx = 2; + /* low mh */ + rdev->pm.profiles[PM_PROFILE_LOW_MH_IDX].dpms_off_ps_idx = + r600_pm_get_type_index(rdev, POWER_STATE_TYPE_BATTERY, 1); + rdev->pm.profiles[PM_PROFILE_LOW_MH_IDX].dpms_on_ps_idx = + r600_pm_get_type_index(rdev, POWER_STATE_TYPE_BATTERY, 1); + rdev->pm.profiles[PM_PROFILE_LOW_MH_IDX].dpms_off_cm_idx = 0; + rdev->pm.profiles[PM_PROFILE_LOW_MH_IDX].dpms_on_cm_idx = 2; + /* high mh */ + rdev->pm.profiles[PM_PROFILE_HIGH_MH_IDX].dpms_off_ps_idx = + r600_pm_get_type_index(rdev, POWER_STATE_TYPE_PERFORMANCE, 1); + rdev->pm.profiles[PM_PROFILE_HIGH_MH_IDX].dpms_on_ps_idx = + r600_pm_get_type_index(rdev, POWER_STATE_TYPE_PERFORMANCE, 1); + rdev->pm.profiles[PM_PROFILE_HIGH_MH_IDX].dpms_off_cm_idx = 0; + rdev->pm.profiles[PM_PROFILE_HIGH_MH_IDX].dpms_on_cm_idx = 2; + } else { + if (rdev->pm.num_power_states < 4) { + /* default */ + rdev->pm.profiles[PM_PROFILE_DEFAULT_IDX].dpms_off_ps_idx = rdev->pm.default_power_state_index; + rdev->pm.profiles[PM_PROFILE_DEFAULT_IDX].dpms_on_ps_idx = rdev->pm.default_power_state_index; + rdev->pm.profiles[PM_PROFILE_DEFAULT_IDX].dpms_off_cm_idx = 0; + rdev->pm.profiles[PM_PROFILE_DEFAULT_IDX].dpms_on_cm_idx = 2; + /* low sh */ + rdev->pm.profiles[PM_PROFILE_LOW_SH_IDX].dpms_off_ps_idx = rdev->pm.default_power_state_index; + rdev->pm.profiles[PM_PROFILE_LOW_SH_IDX].dpms_on_ps_idx = rdev->pm.default_power_state_index; + rdev->pm.profiles[PM_PROFILE_LOW_SH_IDX].dpms_off_cm_idx = 0; + rdev->pm.profiles[PM_PROFILE_LOW_SH_IDX].dpms_on_cm_idx = 2; + /* high sh */ + rdev->pm.profiles[PM_PROFILE_HIGH_SH_IDX].dpms_off_ps_idx = rdev->pm.default_power_state_index; + rdev->pm.profiles[PM_PROFILE_HIGH_SH_IDX].dpms_on_ps_idx = rdev->pm.default_power_state_index; + rdev->pm.profiles[PM_PROFILE_HIGH_SH_IDX].dpms_off_cm_idx = 0; + rdev->pm.profiles[PM_PROFILE_HIGH_SH_IDX].dpms_on_cm_idx = 2; + /* low mh */ + rdev->pm.profiles[PM_PROFILE_LOW_MH_IDX].dpms_off_ps_idx = rdev->pm.default_power_state_index; + rdev->pm.profiles[PM_PROFILE_LOW_MH_IDX].dpms_on_ps_idx = rdev->pm.default_power_state_index; + rdev->pm.profiles[PM_PROFILE_LOW_MH_IDX].dpms_off_cm_idx = 0; + rdev->pm.profiles[PM_PROFILE_LOW_MH_IDX].dpms_on_cm_idx = 2; + /* high mh */ + rdev->pm.profiles[PM_PROFILE_HIGH_MH_IDX].dpms_off_ps_idx = rdev->pm.default_power_state_index; + rdev->pm.profiles[PM_PROFILE_HIGH_MH_IDX].dpms_on_ps_idx = rdev->pm.default_power_state_index; + rdev->pm.profiles[PM_PROFILE_HIGH_MH_IDX].dpms_off_cm_idx = 0; + rdev->pm.profiles[PM_PROFILE_HIGH_MH_IDX].dpms_on_cm_idx = 2; } else { - radeon_sync_with_vblank(rdev); - - if (!radeon_pm_in_vbl(rdev)) - return; - - radeon_pm_prepare(rdev); - if (sclk != rdev->pm.current_sclk) { - radeon_pm_debug_check_in_vbl(rdev, false); - radeon_set_engine_clock(rdev, sclk); - radeon_pm_debug_check_in_vbl(rdev, true); - rdev->pm.current_sclk = sclk; - DRM_INFO("Setting: e: %d\n", sclk); - } - - /* set memory clock */ - if (rdev->asic->set_memory_clock && (mclk != rdev->pm.current_mclk)) { - radeon_pm_debug_check_in_vbl(rdev, false); - radeon_set_memory_clock(rdev, mclk); - radeon_pm_debug_check_in_vbl(rdev, true); - rdev->pm.current_mclk = mclk; - DRM_INFO("Setting: m: %d\n", mclk); - } - radeon_pm_finish(rdev); + /* default */ + rdev->pm.profiles[PM_PROFILE_DEFAULT_IDX].dpms_off_ps_idx = rdev->pm.default_power_state_index; + rdev->pm.profiles[PM_PROFILE_DEFAULT_IDX].dpms_on_ps_idx = rdev->pm.default_power_state_index; + rdev->pm.profiles[PM_PROFILE_DEFAULT_IDX].dpms_off_cm_idx = 0; + rdev->pm.profiles[PM_PROFILE_DEFAULT_IDX].dpms_on_cm_idx = 2; + /* low sh */ + rdev->pm.profiles[PM_PROFILE_LOW_SH_IDX].dpms_off_ps_idx = 1; + rdev->pm.profiles[PM_PROFILE_LOW_SH_IDX].dpms_on_ps_idx = 1; + rdev->pm.profiles[PM_PROFILE_LOW_SH_IDX].dpms_off_cm_idx = 0; + rdev->pm.profiles[PM_PROFILE_LOW_SH_IDX].dpms_on_cm_idx = 2; + /* high sh */ + rdev->pm.profiles[PM_PROFILE_HIGH_SH_IDX].dpms_off_ps_idx = 1; + rdev->pm.profiles[PM_PROFILE_HIGH_SH_IDX].dpms_on_ps_idx = 1; + rdev->pm.profiles[PM_PROFILE_HIGH_SH_IDX].dpms_off_cm_idx = 0; + rdev->pm.profiles[PM_PROFILE_HIGH_SH_IDX].dpms_on_cm_idx = 2; + /* low mh */ + rdev->pm.profiles[PM_PROFILE_LOW_MH_IDX].dpms_off_ps_idx = 3; + rdev->pm.profiles[PM_PROFILE_LOW_MH_IDX].dpms_on_ps_idx = 3; + rdev->pm.profiles[PM_PROFILE_LOW_MH_IDX].dpms_off_cm_idx = 0; + rdev->pm.profiles[PM_PROFILE_LOW_MH_IDX].dpms_on_cm_idx = 2; + /* high mh */ + rdev->pm.profiles[PM_PROFILE_HIGH_MH_IDX].dpms_off_ps_idx = 3; + rdev->pm.profiles[PM_PROFILE_HIGH_MH_IDX].dpms_on_ps_idx = 3; + rdev->pm.profiles[PM_PROFILE_HIGH_MH_IDX].dpms_off_cm_idx = 0; + rdev->pm.profiles[PM_PROFILE_HIGH_MH_IDX].dpms_on_cm_idx = 2; } - - rdev->pm.current_power_state_index = rdev->pm.requested_power_state_index; - rdev->pm.current_clock_mode_index = rdev->pm.requested_clock_mode_index; - } else - DRM_INFO("GUI not idle!!!\n"); + } } void r600_pm_misc(struct radeon_device *rdev) @@ -2320,8 +2471,6 @@ int r600_init(struct radeon_device *rdev) r = radeon_clocks_init(rdev); if (r) return r; - /* Initialize power management */ - radeon_pm_init(rdev); /* Fence driver */ r = radeon_fence_driver_init(rdev); if (r) @@ -2386,7 +2535,6 @@ int r600_init(struct radeon_device *rdev) void r600_fini(struct radeon_device *rdev) { - radeon_pm_fini(rdev); r600_audio_fini(rdev); r600_blit_fini(rdev); r600_cp_fini(rdev); diff --git a/drivers/gpu/drm/radeon/radeon.h b/drivers/gpu/drm/radeon/radeon.h index 480a83ff54d5..5c9ce2beaca3 100644 --- a/drivers/gpu/drm/radeon/radeon.h +++ b/drivers/gpu/drm/radeon/radeon.h @@ -89,7 +89,6 @@ extern int radeon_testing; extern int radeon_connector_table; extern int radeon_tv; extern int radeon_new_pll; -extern int radeon_dynpm; extern int radeon_audio; extern int radeon_disp_priority; extern int radeon_hw_i2c; @@ -173,11 +172,10 @@ struct radeon_clock { int radeon_pm_init(struct radeon_device *rdev); void radeon_pm_fini(struct radeon_device *rdev); void radeon_pm_compute_clocks(struct radeon_device *rdev); +void radeon_pm_suspend(struct radeon_device *rdev); +void radeon_pm_resume(struct radeon_device *rdev); void radeon_combios_get_power_modes(struct radeon_device *rdev); void radeon_atombios_get_power_modes(struct radeon_device *rdev); -bool radeon_pm_in_vbl(struct radeon_device *rdev); -bool radeon_pm_debug_check_in_vbl(struct radeon_device *rdev, bool finish); -void radeon_sync_with_vblank(struct radeon_device *rdev); /* * Fences. @@ -608,18 +606,24 @@ struct radeon_wb { * Equation between gpu/memory clock and available bandwidth is hw dependent * (type of memory, bus size, efficiency, ...) */ -enum radeon_pm_state { - PM_STATE_DISABLED, - PM_STATE_MINIMUM, - PM_STATE_PAUSED, - PM_STATE_ACTIVE + +enum radeon_pm_method { + PM_METHOD_PROFILE, + PM_METHOD_DYNPM, +}; + +enum radeon_dynpm_state { + DYNPM_STATE_DISABLED, + DYNPM_STATE_MINIMUM, + DYNPM_STATE_PAUSED, + DYNPM_STATE_ACTIVE }; -enum radeon_pm_action { - PM_ACTION_NONE, - PM_ACTION_MINIMUM, - PM_ACTION_DOWNCLOCK, - PM_ACTION_UPCLOCK, - PM_ACTION_DEFAULT +enum radeon_dynpm_action { + DYNPM_ACTION_NONE, + DYNPM_ACTION_MINIMUM, + DYNPM_ACTION_DOWNCLOCK, + DYNPM_ACTION_UPCLOCK, + DYNPM_ACTION_DEFAULT }; enum radeon_voltage_type { @@ -637,11 +641,25 @@ enum radeon_pm_state_type { POWER_STATE_TYPE_PERFORMANCE, }; -enum radeon_pm_clock_mode_type { - POWER_MODE_TYPE_DEFAULT, - POWER_MODE_TYPE_LOW, - POWER_MODE_TYPE_MID, - POWER_MODE_TYPE_HIGH, +enum radeon_pm_profile_type { + PM_PROFILE_DEFAULT, + PM_PROFILE_AUTO, + PM_PROFILE_LOW, + PM_PROFILE_HIGH, +}; + +#define PM_PROFILE_DEFAULT_IDX 0 +#define PM_PROFILE_LOW_SH_IDX 1 +#define PM_PROFILE_HIGH_SH_IDX 2 +#define PM_PROFILE_LOW_MH_IDX 3 +#define PM_PROFILE_HIGH_MH_IDX 4 +#define PM_PROFILE_MAX 5 + +struct radeon_pm_profile { + int dpms_off_ps_idx; + int dpms_on_ps_idx; + int dpms_off_cm_idx; + int dpms_on_cm_idx; }; struct radeon_voltage { @@ -696,12 +714,6 @@ struct radeon_power_state { struct radeon_pm { struct mutex mutex; - struct delayed_work idle_work; - enum radeon_pm_state state; - enum radeon_pm_action planned_action; - unsigned long action_timeout; - bool can_upclock; - bool can_downclock; u32 active_crtcs; int active_crtc_count; int req_vblank; @@ -731,6 +743,19 @@ struct radeon_pm { u32 current_sclk; u32 current_mclk; struct radeon_i2c_chan *i2c_bus; + /* selected pm method */ + enum radeon_pm_method pm_method; + /* dynpm power management */ + struct delayed_work dynpm_idle_work; + enum radeon_dynpm_state dynpm_state; + enum radeon_dynpm_action dynpm_planned_action; + unsigned long dynpm_action_timeout; + bool dynpm_can_upclock; + bool dynpm_can_downclock; + /* profile-based power management */ + enum radeon_pm_profile_type profile; + int profile_index; + struct radeon_pm_profile profiles[PM_PROFILE_MAX]; }; @@ -819,11 +844,12 @@ struct radeon_asic { */ void (*ioctl_wait_idle)(struct radeon_device *rdev, struct radeon_bo *bo); bool (*gui_idle)(struct radeon_device *rdev); - void (*get_power_state)(struct radeon_device *rdev, enum radeon_pm_action action); - void (*set_power_state)(struct radeon_device *rdev, bool static_switch); + /* power management */ void (*pm_misc)(struct radeon_device *rdev); void (*pm_prepare)(struct radeon_device *rdev); void (*pm_finish)(struct radeon_device *rdev); + void (*pm_init_profile)(struct radeon_device *rdev); + void (*pm_get_dynpm_state)(struct radeon_device *rdev); }; /* @@ -1041,6 +1067,7 @@ struct radeon_device { uint8_t audio_category_code; bool powered_down; + struct notifier_block acpi_nb; }; int radeon_device_init(struct radeon_device *rdev, @@ -1232,11 +1259,11 @@ static inline void radeon_ring_write(struct radeon_device *rdev, uint32_t v) #define radeon_hpd_sense(rdev, hpd) (rdev)->asic->hpd_sense((rdev), (hpd)) #define radeon_hpd_set_polarity(rdev, hpd) (rdev)->asic->hpd_set_polarity((rdev), (hpd)) #define radeon_gui_idle(rdev) (rdev)->asic->gui_idle((rdev)) -#define radeon_get_power_state(rdev, a) (rdev)->asic->get_power_state((rdev), (a)) -#define radeon_set_power_state(rdev, s) (rdev)->asic->set_power_state((rdev), (s)) #define radeon_pm_misc(rdev) (rdev)->asic->pm_misc((rdev)) #define radeon_pm_prepare(rdev) (rdev)->asic->pm_prepare((rdev)) #define radeon_pm_finish(rdev) (rdev)->asic->pm_finish((rdev)) +#define radeon_pm_init_profile(rdev) (rdev)->asic->pm_init_profile((rdev)) +#define radeon_pm_get_dynpm_state(rdev) (rdev)->asic->pm_get_dynpm_state((rdev)) /* Common functions */ /* AGP */ diff --git a/drivers/gpu/drm/radeon/radeon_asic.c b/drivers/gpu/drm/radeon/radeon_asic.c index 1e6f17bf54fd..e57df08d4aeb 100644 --- a/drivers/gpu/drm/radeon/radeon_asic.c +++ b/drivers/gpu/drm/radeon/radeon_asic.c @@ -166,11 +166,11 @@ static struct radeon_asic r100_asic = { .hpd_set_polarity = &r100_hpd_set_polarity, .ioctl_wait_idle = NULL, .gui_idle = &r100_gui_idle, - .get_power_state = &r100_get_power_state, - .set_power_state = &r100_set_power_state, .pm_misc = &r100_pm_misc, .pm_prepare = &r100_pm_prepare, .pm_finish = &r100_pm_finish, + .pm_init_profile = &r100_pm_init_profile, + .pm_get_dynpm_state = &r100_pm_get_dynpm_state, }; static struct radeon_asic r200_asic = { @@ -210,11 +210,11 @@ static struct radeon_asic r200_asic = { .hpd_set_polarity = &r100_hpd_set_polarity, .ioctl_wait_idle = NULL, .gui_idle = &r100_gui_idle, - .get_power_state = &r100_get_power_state, - .set_power_state = &r100_set_power_state, .pm_misc = &r100_pm_misc, .pm_prepare = &r100_pm_prepare, .pm_finish = &r100_pm_finish, + .pm_init_profile = &r100_pm_init_profile, + .pm_get_dynpm_state = &r100_pm_get_dynpm_state, }; static struct radeon_asic r300_asic = { @@ -255,11 +255,11 @@ static struct radeon_asic r300_asic = { .hpd_set_polarity = &r100_hpd_set_polarity, .ioctl_wait_idle = NULL, .gui_idle = &r100_gui_idle, - .get_power_state = &r100_get_power_state, - .set_power_state = &r100_set_power_state, .pm_misc = &r100_pm_misc, .pm_prepare = &r100_pm_prepare, .pm_finish = &r100_pm_finish, + .pm_init_profile = &r100_pm_init_profile, + .pm_get_dynpm_state = &r100_pm_get_dynpm_state, }; static struct radeon_asic r300_asic_pcie = { @@ -299,11 +299,11 @@ static struct radeon_asic r300_asic_pcie = { .hpd_set_polarity = &r100_hpd_set_polarity, .ioctl_wait_idle = NULL, .gui_idle = &r100_gui_idle, - .get_power_state = &r100_get_power_state, - .set_power_state = &r100_set_power_state, .pm_misc = &r100_pm_misc, .pm_prepare = &r100_pm_prepare, .pm_finish = &r100_pm_finish, + .pm_init_profile = &r100_pm_init_profile, + .pm_get_dynpm_state = &r100_pm_get_dynpm_state, }; static struct radeon_asic r420_asic = { @@ -344,11 +344,11 @@ static struct radeon_asic r420_asic = { .hpd_set_polarity = &r100_hpd_set_polarity, .ioctl_wait_idle = NULL, .gui_idle = &r100_gui_idle, - .get_power_state = &r100_get_power_state, - .set_power_state = &r100_set_power_state, .pm_misc = &r100_pm_misc, .pm_prepare = &r100_pm_prepare, .pm_finish = &r100_pm_finish, + .pm_init_profile = &r420_pm_init_profile, + .pm_get_dynpm_state = &r100_pm_get_dynpm_state, }; static struct radeon_asic rs400_asic = { @@ -389,11 +389,11 @@ static struct radeon_asic rs400_asic = { .hpd_set_polarity = &r100_hpd_set_polarity, .ioctl_wait_idle = NULL, .gui_idle = &r100_gui_idle, - .get_power_state = &r100_get_power_state, - .set_power_state = &r100_set_power_state, .pm_misc = &r100_pm_misc, .pm_prepare = &r100_pm_prepare, .pm_finish = &r100_pm_finish, + .pm_init_profile = &r100_pm_init_profile, + .pm_get_dynpm_state = &r100_pm_get_dynpm_state, }; static struct radeon_asic rs600_asic = { @@ -434,11 +434,11 @@ static struct radeon_asic rs600_asic = { .hpd_set_polarity = &rs600_hpd_set_polarity, .ioctl_wait_idle = NULL, .gui_idle = &r100_gui_idle, - .get_power_state = &r100_get_power_state, - .set_power_state = &r100_set_power_state, .pm_misc = &rs600_pm_misc, .pm_prepare = &rs600_pm_prepare, .pm_finish = &rs600_pm_finish, + .pm_init_profile = &r420_pm_init_profile, + .pm_get_dynpm_state = &r100_pm_get_dynpm_state, }; static struct radeon_asic rs690_asic = { @@ -479,11 +479,11 @@ static struct radeon_asic rs690_asic = { .hpd_set_polarity = &rs600_hpd_set_polarity, .ioctl_wait_idle = NULL, .gui_idle = &r100_gui_idle, - .get_power_state = &r100_get_power_state, - .set_power_state = &r100_set_power_state, .pm_misc = &rs600_pm_misc, .pm_prepare = &rs600_pm_prepare, .pm_finish = &rs600_pm_finish, + .pm_init_profile = &r420_pm_init_profile, + .pm_get_dynpm_state = &r100_pm_get_dynpm_state, }; static struct radeon_asic rv515_asic = { @@ -524,11 +524,11 @@ static struct radeon_asic rv515_asic = { .hpd_set_polarity = &rs600_hpd_set_polarity, .ioctl_wait_idle = NULL, .gui_idle = &r100_gui_idle, - .get_power_state = &r100_get_power_state, - .set_power_state = &r100_set_power_state, .pm_misc = &rs600_pm_misc, .pm_prepare = &rs600_pm_prepare, .pm_finish = &rs600_pm_finish, + .pm_init_profile = &r420_pm_init_profile, + .pm_get_dynpm_state = &r100_pm_get_dynpm_state, }; static struct radeon_asic r520_asic = { @@ -569,11 +569,11 @@ static struct radeon_asic r520_asic = { .hpd_set_polarity = &rs600_hpd_set_polarity, .ioctl_wait_idle = NULL, .gui_idle = &r100_gui_idle, - .get_power_state = &r100_get_power_state, - .set_power_state = &r100_set_power_state, .pm_misc = &rs600_pm_misc, .pm_prepare = &rs600_pm_prepare, .pm_finish = &rs600_pm_finish, + .pm_init_profile = &r420_pm_init_profile, + .pm_get_dynpm_state = &r100_pm_get_dynpm_state, }; static struct radeon_asic r600_asic = { @@ -613,11 +613,11 @@ static struct radeon_asic r600_asic = { .hpd_set_polarity = &r600_hpd_set_polarity, .ioctl_wait_idle = r600_ioctl_wait_idle, .gui_idle = &r600_gui_idle, - .get_power_state = &r600_get_power_state, - .set_power_state = &r600_set_power_state, .pm_misc = &r600_pm_misc, .pm_prepare = &rs600_pm_prepare, .pm_finish = &rs600_pm_finish, + .pm_init_profile = &r600_pm_init_profile, + .pm_get_dynpm_state = &r600_pm_get_dynpm_state, }; static struct radeon_asic rs780_asic = { @@ -657,11 +657,11 @@ static struct radeon_asic rs780_asic = { .hpd_set_polarity = &r600_hpd_set_polarity, .ioctl_wait_idle = r600_ioctl_wait_idle, .gui_idle = &r600_gui_idle, - .get_power_state = &r600_get_power_state, - .set_power_state = &r600_set_power_state, .pm_misc = &r600_pm_misc, .pm_prepare = &rs600_pm_prepare, .pm_finish = &rs600_pm_finish, + .pm_init_profile = &rs780_pm_init_profile, + .pm_get_dynpm_state = &r600_pm_get_dynpm_state, }; static struct radeon_asic rv770_asic = { @@ -701,11 +701,11 @@ static struct radeon_asic rv770_asic = { .hpd_set_polarity = &r600_hpd_set_polarity, .ioctl_wait_idle = r600_ioctl_wait_idle, .gui_idle = &r600_gui_idle, - .get_power_state = &r600_get_power_state, - .set_power_state = &r600_set_power_state, .pm_misc = &rv770_pm_misc, .pm_prepare = &rs600_pm_prepare, .pm_finish = &rs600_pm_finish, + .pm_init_profile = &r600_pm_init_profile, + .pm_get_dynpm_state = &r600_pm_get_dynpm_state, }; static struct radeon_asic evergreen_asic = { @@ -743,11 +743,11 @@ static struct radeon_asic evergreen_asic = { .hpd_sense = &evergreen_hpd_sense, .hpd_set_polarity = &evergreen_hpd_set_polarity, .gui_idle = &r600_gui_idle, - .get_power_state = &r600_get_power_state, - .set_power_state = &r600_set_power_state, .pm_misc = &evergreen_pm_misc, .pm_prepare = &evergreen_pm_prepare, .pm_finish = &evergreen_pm_finish, + .pm_init_profile = &r600_pm_init_profile, + .pm_get_dynpm_state = &r600_pm_get_dynpm_state, }; int radeon_asic_init(struct radeon_device *rdev) diff --git a/drivers/gpu/drm/radeon/radeon_asic.h b/drivers/gpu/drm/radeon/radeon_asic.h index 8a1278629994..5c40a3dfaca2 100644 --- a/drivers/gpu/drm/radeon/radeon_asic.h +++ b/drivers/gpu/drm/radeon/radeon_asic.h @@ -127,12 +127,11 @@ void r100_enable_bm(struct radeon_device *rdev); void r100_set_common_regs(struct radeon_device *rdev); void r100_bm_disable(struct radeon_device *rdev); extern bool r100_gui_idle(struct radeon_device *rdev); -extern void r100_set_power_state(struct radeon_device *rdev, bool static_switch); -extern void r100_get_power_state(struct radeon_device *rdev, - enum radeon_pm_action action); extern void r100_pm_misc(struct radeon_device *rdev); extern void r100_pm_prepare(struct radeon_device *rdev); extern void r100_pm_finish(struct radeon_device *rdev); +extern void r100_pm_init_profile(struct radeon_device *rdev); +extern void r100_pm_get_dynpm_state(struct radeon_device *rdev); /* * r200,rv250,rs300,rv280 @@ -170,6 +169,7 @@ extern int r420_init(struct radeon_device *rdev); extern void r420_fini(struct radeon_device *rdev); extern int r420_suspend(struct radeon_device *rdev); extern int r420_resume(struct radeon_device *rdev); +extern void r420_pm_init_profile(struct radeon_device *rdev); /* * rs400,rs480 @@ -281,10 +281,10 @@ void r600_hpd_set_polarity(struct radeon_device *rdev, enum radeon_hpd_id hpd); extern void r600_ioctl_wait_idle(struct radeon_device *rdev, struct radeon_bo *bo); extern bool r600_gui_idle(struct radeon_device *rdev); -extern void r600_set_power_state(struct radeon_device *rdev, bool static_switch); -extern void r600_get_power_state(struct radeon_device *rdev, - enum radeon_pm_action action); extern void r600_pm_misc(struct radeon_device *rdev); +extern void r600_pm_init_profile(struct radeon_device *rdev); +extern void rs780_pm_init_profile(struct radeon_device *rdev); +extern void r600_pm_get_dynpm_state(struct radeon_device *rdev); /* * rv770,rv730,rv710,rv740 diff --git a/drivers/gpu/drm/radeon/radeon_device.c b/drivers/gpu/drm/radeon/radeon_device.c index e249da81dbfc..a20b612ffe75 100644 --- a/drivers/gpu/drm/radeon/radeon_device.c +++ b/drivers/gpu/drm/radeon/radeon_device.c @@ -748,6 +748,7 @@ int radeon_suspend_kms(struct drm_device *dev, pm_message_t state) radeon_save_bios_scratch_regs(rdev); + radeon_pm_suspend(rdev); radeon_suspend(rdev); radeon_hpd_fini(rdev); /* evict remaining vram memory */ @@ -783,6 +784,7 @@ int radeon_resume_kms(struct drm_device *dev) /* resume AGP if in use */ radeon_agp_resume(rdev); radeon_resume(rdev); + radeon_pm_resume(rdev); radeon_restore_bios_scratch_regs(rdev); radeon_fbdev_set_suspend(rdev, 0); release_console_sem(); diff --git a/drivers/gpu/drm/radeon/radeon_display.c b/drivers/gpu/drm/radeon/radeon_display.c index 10d70540fc50..f48f42454fbb 100644 --- a/drivers/gpu/drm/radeon/radeon_display.c +++ b/drivers/gpu/drm/radeon/radeon_display.c @@ -1037,6 +1037,9 @@ int radeon_modeset_init(struct radeon_device *rdev) /* initialize hpd */ radeon_hpd_init(rdev); + /* Initialize power management */ + radeon_pm_init(rdev); + radeon_fbdev_init(rdev); drm_kms_helper_poll_init(rdev->ddev); @@ -1047,6 +1050,7 @@ void radeon_modeset_fini(struct radeon_device *rdev) { radeon_fbdev_fini(rdev); kfree(rdev->mode_info.bios_hardcoded_edid); + radeon_pm_fini(rdev); if (rdev->mode_info.mode_config_initialized) { drm_kms_helper_poll_fini(rdev->ddev); diff --git a/drivers/gpu/drm/radeon/radeon_drv.c b/drivers/gpu/drm/radeon/radeon_drv.c index 6e22815f7f07..4afba1eca2a7 100644 --- a/drivers/gpu/drm/radeon/radeon_drv.c +++ b/drivers/gpu/drm/radeon/radeon_drv.c @@ -92,7 +92,6 @@ int radeon_testing = 0; int radeon_connector_table = 0; int radeon_tv = 1; int radeon_new_pll = -1; -int radeon_dynpm = -1; int radeon_audio = 1; int radeon_disp_priority = 0; int radeon_hw_i2c = 0; @@ -133,9 +132,6 @@ module_param_named(tv, radeon_tv, int, 0444); MODULE_PARM_DESC(new_pll, "Select new PLL code"); module_param_named(new_pll, radeon_new_pll, int, 0444); -MODULE_PARM_DESC(dynpm, "Disable/Enable dynamic power management (1 = enable)"); -module_param_named(dynpm, radeon_dynpm, int, 0444); - MODULE_PARM_DESC(audio, "Audio enable (0 = disable)"); module_param_named(audio, radeon_audio, int, 0444); diff --git a/drivers/gpu/drm/radeon/radeon_pm.c b/drivers/gpu/drm/radeon/radeon_pm.c index 0dfa508fe5f2..1827317704a2 100644 --- a/drivers/gpu/drm/radeon/radeon_pm.c +++ b/drivers/gpu/drm/radeon/radeon_pm.c @@ -23,14 +23,98 @@ #include "drmP.h" #include "radeon.h" #include "avivod.h" +#ifdef CONFIG_ACPI +#include +#endif +#include #define RADEON_IDLE_LOOP_MS 100 #define RADEON_RECLOCK_DELAY_MS 200 #define RADEON_WAIT_VBLANK_TIMEOUT 200 #define RADEON_WAIT_IDLE_TIMEOUT 200 -static void radeon_pm_idle_work_handler(struct work_struct *work); +static void radeon_dynpm_idle_work_handler(struct work_struct *work); static int radeon_debugfs_pm_init(struct radeon_device *rdev); +static bool radeon_pm_in_vbl(struct radeon_device *rdev); +static bool radeon_pm_debug_check_in_vbl(struct radeon_device *rdev, bool finish); +static void radeon_pm_update_profile(struct radeon_device *rdev); +static void radeon_pm_set_clocks(struct radeon_device *rdev); + +#define ACPI_AC_CLASS "ac_adapter" + +#ifdef CONFIG_ACPI +static int radeon_acpi_event(struct notifier_block *nb, + unsigned long val, + void *data) +{ + struct radeon_device *rdev = container_of(nb, struct radeon_device, acpi_nb); + struct acpi_bus_event *entry = (struct acpi_bus_event *)data; + + if (strcmp(entry->device_class, ACPI_AC_CLASS) == 0) { + if (power_supply_is_system_supplied() > 0) + DRM_INFO("pm: AC\n"); + else + DRM_INFO("pm: DC\n"); + + if (rdev->pm.pm_method == PM_METHOD_PROFILE) { + if (rdev->pm.profile == PM_PROFILE_AUTO) { + mutex_lock(&rdev->pm.mutex); + radeon_pm_update_profile(rdev); + radeon_pm_set_clocks(rdev); + mutex_unlock(&rdev->pm.mutex); + } + } + } + + return NOTIFY_OK; +} +#endif + +static void radeon_pm_update_profile(struct radeon_device *rdev) +{ + switch (rdev->pm.profile) { + case PM_PROFILE_DEFAULT: + rdev->pm.profile_index = PM_PROFILE_DEFAULT_IDX; + break; + case PM_PROFILE_AUTO: + if (power_supply_is_system_supplied() > 0) { + if (rdev->pm.active_crtc_count > 1) + rdev->pm.profile_index = PM_PROFILE_HIGH_MH_IDX; + else + rdev->pm.profile_index = PM_PROFILE_HIGH_SH_IDX; + } else { + if (rdev->pm.active_crtc_count > 1) + rdev->pm.profile_index = PM_PROFILE_LOW_MH_IDX; + else + rdev->pm.profile_index = PM_PROFILE_LOW_SH_IDX; + } + break; + case PM_PROFILE_LOW: + if (rdev->pm.active_crtc_count > 1) + rdev->pm.profile_index = PM_PROFILE_LOW_MH_IDX; + else + rdev->pm.profile_index = PM_PROFILE_LOW_SH_IDX; + break; + case PM_PROFILE_HIGH: + if (rdev->pm.active_crtc_count > 1) + rdev->pm.profile_index = PM_PROFILE_HIGH_MH_IDX; + else + rdev->pm.profile_index = PM_PROFILE_HIGH_SH_IDX; + break; + } + + if (rdev->pm.active_crtc_count == 0) { + rdev->pm.requested_power_state_index = + rdev->pm.profiles[rdev->pm.profile_index].dpms_off_ps_idx; + rdev->pm.requested_clock_mode_index = + rdev->pm.profiles[rdev->pm.profile_index].dpms_off_cm_idx; + } else { + rdev->pm.requested_power_state_index = + rdev->pm.profiles[rdev->pm.profile_index].dpms_on_ps_idx; + rdev->pm.requested_clock_mode_index = + rdev->pm.profiles[rdev->pm.profile_index].dpms_on_cm_idx; + } +} static void radeon_unmap_vram_bos(struct radeon_device *rdev) { @@ -54,12 +138,93 @@ static void radeon_unmap_vram_bos(struct radeon_device *rdev) ttm_bo_unmap_virtual(&rdev->r600_blit.shader_obj->tbo); } -static void radeon_pm_set_clocks(struct radeon_device *rdev, int static_switch) +static void radeon_sync_with_vblank(struct radeon_device *rdev) { - int i; + if (rdev->pm.active_crtcs) { + rdev->pm.vblank_sync = false; + wait_event_timeout( + rdev->irq.vblank_queue, rdev->pm.vblank_sync, + msecs_to_jiffies(RADEON_WAIT_VBLANK_TIMEOUT)); + } +} + +static void radeon_set_power_state(struct radeon_device *rdev) +{ + u32 sclk, mclk; + + if ((rdev->pm.requested_clock_mode_index == rdev->pm.current_clock_mode_index) && + (rdev->pm.requested_power_state_index == rdev->pm.current_power_state_index)) + return; + + if (radeon_gui_idle(rdev)) { + sclk = rdev->pm.power_state[rdev->pm.requested_power_state_index]. + clock_info[rdev->pm.requested_clock_mode_index].sclk; + if (sclk > rdev->clock.default_sclk) + sclk = rdev->clock.default_sclk; + + mclk = rdev->pm.power_state[rdev->pm.requested_power_state_index]. + clock_info[rdev->pm.requested_clock_mode_index].mclk; + if (mclk > rdev->clock.default_mclk) + mclk = rdev->clock.default_mclk; + + /* voltage, pcie lanes, etc.*/ + radeon_pm_misc(rdev); + + if (rdev->pm.pm_method == PM_METHOD_DYNPM) { + radeon_sync_with_vblank(rdev); + + if (!radeon_pm_in_vbl(rdev)) + return; + + radeon_pm_prepare(rdev); + /* set engine clock */ + if (sclk != rdev->pm.current_sclk) { + radeon_pm_debug_check_in_vbl(rdev, false); + radeon_set_engine_clock(rdev, sclk); + radeon_pm_debug_check_in_vbl(rdev, true); + rdev->pm.current_sclk = sclk; + DRM_INFO("Setting: e: %d\n", sclk); + } + + /* set memory clock */ + if (rdev->asic->set_memory_clock && (mclk != rdev->pm.current_mclk)) { + radeon_pm_debug_check_in_vbl(rdev, false); + radeon_set_memory_clock(rdev, mclk); + radeon_pm_debug_check_in_vbl(rdev, true); + rdev->pm.current_mclk = mclk; + DRM_INFO("Setting: m: %d\n", mclk); + } + radeon_pm_finish(rdev); + } else { + /* set engine clock */ + if (sclk != rdev->pm.current_sclk) { + radeon_sync_with_vblank(rdev); + radeon_pm_prepare(rdev); + radeon_set_engine_clock(rdev, sclk); + radeon_pm_finish(rdev); + rdev->pm.current_sclk = sclk; + DRM_INFO("Setting: e: %d\n", sclk); + } + /* set memory clock */ + if (rdev->asic->set_memory_clock && (mclk != rdev->pm.current_mclk)) { + radeon_sync_with_vblank(rdev); + radeon_pm_prepare(rdev); + radeon_set_memory_clock(rdev, mclk); + radeon_pm_finish(rdev); + rdev->pm.current_mclk = mclk; + DRM_INFO("Setting: m: %d\n", mclk); + } + } - if (rdev->pm.state != PM_STATE_DISABLED) - radeon_get_power_state(rdev, rdev->pm.planned_action); + rdev->pm.current_power_state_index = rdev->pm.requested_power_state_index; + rdev->pm.current_clock_mode_index = rdev->pm.requested_clock_mode_index; + } else + DRM_INFO("pm: GUI not idle!!!\n"); +} + +static void radeon_pm_set_clocks(struct radeon_device *rdev) +{ + int i; mutex_lock(&rdev->ddev->struct_mutex); mutex_lock(&rdev->vram_mutex); @@ -67,27 +232,31 @@ static void radeon_pm_set_clocks(struct radeon_device *rdev, int static_switch) /* gui idle int has issues on older chips it seems */ if (rdev->family >= CHIP_R600) { - /* wait for GPU idle */ - rdev->pm.gui_idle = false; - rdev->irq.gui_idle = true; - radeon_irq_set(rdev); - wait_event_interruptible_timeout( - rdev->irq.idle_queue, rdev->pm.gui_idle, - msecs_to_jiffies(RADEON_WAIT_IDLE_TIMEOUT)); - rdev->irq.gui_idle = false; - radeon_irq_set(rdev); + if (rdev->irq.installed) { + /* wait for GPU idle */ + rdev->pm.gui_idle = false; + rdev->irq.gui_idle = true; + radeon_irq_set(rdev); + wait_event_interruptible_timeout( + rdev->irq.idle_queue, rdev->pm.gui_idle, + msecs_to_jiffies(RADEON_WAIT_IDLE_TIMEOUT)); + rdev->irq.gui_idle = false; + radeon_irq_set(rdev); + } } else { - struct radeon_fence *fence; - radeon_ring_alloc(rdev, 64); - radeon_fence_create(rdev, &fence); - radeon_fence_emit(rdev, fence); - radeon_ring_commit(rdev); - radeon_fence_wait(fence, false); - radeon_fence_unref(&fence); + if (rdev->cp.ready) { + struct radeon_fence *fence; + radeon_ring_alloc(rdev, 64); + radeon_fence_create(rdev, &fence); + radeon_fence_emit(rdev, fence); + radeon_ring_commit(rdev); + radeon_fence_wait(fence, false); + radeon_fence_unref(&fence); + } } radeon_unmap_vram_bos(rdev); - if (!static_switch) { + if (rdev->irq.installed) { for (i = 0; i < rdev->num_crtc; i++) { if (rdev->pm.active_crtcs & (1 << i)) { rdev->pm.req_vblank |= (1 << i); @@ -96,9 +265,9 @@ static void radeon_pm_set_clocks(struct radeon_device *rdev, int static_switch) } } - radeon_set_power_state(rdev, static_switch); + radeon_set_power_state(rdev); - if (!static_switch) { + if (rdev->irq.installed) { for (i = 0; i < rdev->num_crtc; i++) { if (rdev->pm.req_vblank & (1 << i)) { rdev->pm.req_vblank &= ~(1 << i); @@ -112,230 +281,195 @@ static void radeon_pm_set_clocks(struct radeon_device *rdev, int static_switch) if (rdev->pm.active_crtc_count) radeon_bandwidth_update(rdev); - rdev->pm.planned_action = PM_ACTION_NONE; + rdev->pm.dynpm_planned_action = DYNPM_ACTION_NONE; mutex_unlock(&rdev->cp.mutex); mutex_unlock(&rdev->vram_mutex); mutex_unlock(&rdev->ddev->struct_mutex); } -static ssize_t radeon_get_power_state_static(struct device *dev, - struct device_attribute *attr, - char *buf) +static ssize_t radeon_get_pm_profile(struct device *dev, + struct device_attribute *attr, + char *buf) { struct drm_device *ddev = pci_get_drvdata(to_pci_dev(dev)); struct radeon_device *rdev = ddev->dev_private; + int cp = rdev->pm.profile; - return snprintf(buf, PAGE_SIZE, "%d.%d\n", rdev->pm.current_power_state_index, - rdev->pm.current_clock_mode_index); + return snprintf(buf, PAGE_SIZE, "%s\n", + (cp == PM_PROFILE_AUTO) ? "auto" : + (cp == PM_PROFILE_LOW) ? "low" : + (cp == PM_PROFILE_HIGH) ? "high" : "default"); } -static ssize_t radeon_set_power_state_static(struct device *dev, - struct device_attribute *attr, - const char *buf, - size_t count) +static ssize_t radeon_set_pm_profile(struct device *dev, + struct device_attribute *attr, + const char *buf, + size_t count) { struct drm_device *ddev = pci_get_drvdata(to_pci_dev(dev)); struct radeon_device *rdev = ddev->dev_private; - int ps, cm; - - if (sscanf(buf, "%u.%u", &ps, &cm) != 2) { - DRM_ERROR("Invalid power state!\n"); - return count; - } mutex_lock(&rdev->pm.mutex); - if ((ps >= 0) && (ps < rdev->pm.num_power_states) && - (cm >= 0) && (cm < rdev->pm.power_state[ps].num_clock_modes)) { - if ((rdev->pm.active_crtc_count > 0) && - (rdev->pm.power_state[ps].clock_info[cm].flags & RADEON_PM_MODE_NO_DISPLAY)) { - DRM_ERROR("Invalid power state for display: %d.%d\n", ps, cm); - } else if ((rdev->pm.active_crtc_count > 1) && - (rdev->pm.power_state[ps].flags & RADEON_PM_STATE_SINGLE_DISPLAY_ONLY)) { - DRM_ERROR("Invalid power state for multi-head: %d.%d\n", ps, cm); - } else { - /* disable dynpm */ - rdev->pm.state = PM_STATE_DISABLED; - rdev->pm.planned_action = PM_ACTION_NONE; - rdev->pm.requested_power_state_index = ps; - rdev->pm.requested_clock_mode_index = cm; - radeon_pm_set_clocks(rdev, true); + if (rdev->pm.pm_method == PM_METHOD_PROFILE) { + if (strncmp("default", buf, strlen("default")) == 0) + rdev->pm.profile = PM_PROFILE_DEFAULT; + else if (strncmp("auto", buf, strlen("auto")) == 0) + rdev->pm.profile = PM_PROFILE_AUTO; + else if (strncmp("low", buf, strlen("low")) == 0) + rdev->pm.profile = PM_PROFILE_LOW; + else if (strncmp("high", buf, strlen("high")) == 0) + rdev->pm.profile = PM_PROFILE_HIGH; + else { + DRM_ERROR("invalid power profile!\n"); + goto fail; } - } else - DRM_ERROR("Invalid power state: %d.%d\n\n", ps, cm); + radeon_pm_update_profile(rdev); + radeon_pm_set_clocks(rdev); + } +fail: mutex_unlock(&rdev->pm.mutex); return count; } -static ssize_t radeon_get_dynpm(struct device *dev, - struct device_attribute *attr, - char *buf) +static ssize_t radeon_get_pm_method(struct device *dev, + struct device_attribute *attr, + char *buf) { struct drm_device *ddev = pci_get_drvdata(to_pci_dev(dev)); struct radeon_device *rdev = ddev->dev_private; + int pm = rdev->pm.pm_method; return snprintf(buf, PAGE_SIZE, "%s\n", - (rdev->pm.state == PM_STATE_DISABLED) ? "disabled" : "enabled"); + (pm == PM_METHOD_DYNPM) ? "dynpm" : "profile"); } -static ssize_t radeon_set_dynpm(struct device *dev, - struct device_attribute *attr, - const char *buf, - size_t count) +static ssize_t radeon_set_pm_method(struct device *dev, + struct device_attribute *attr, + const char *buf, + size_t count) { struct drm_device *ddev = pci_get_drvdata(to_pci_dev(dev)); struct radeon_device *rdev = ddev->dev_private; - int tmp = simple_strtoul(buf, NULL, 10); - if (tmp == 0) { - /* update power mode info */ - radeon_pm_compute_clocks(rdev); - /* disable dynpm */ + + if (strncmp("dynpm", buf, strlen("dynpm")) == 0) { mutex_lock(&rdev->pm.mutex); - rdev->pm.state = PM_STATE_DISABLED; - rdev->pm.planned_action = PM_ACTION_NONE; + rdev->pm.pm_method = PM_METHOD_DYNPM; + rdev->pm.dynpm_state = DYNPM_STATE_PAUSED; + rdev->pm.dynpm_planned_action = DYNPM_ACTION_DEFAULT; mutex_unlock(&rdev->pm.mutex); - DRM_INFO("radeon: dynamic power management disabled\n"); - } else if (tmp == 1) { - if (rdev->pm.num_power_states > 1) { - /* enable dynpm */ - mutex_lock(&rdev->pm.mutex); - rdev->pm.state = PM_STATE_PAUSED; - rdev->pm.planned_action = PM_ACTION_DEFAULT; - radeon_get_power_state(rdev, rdev->pm.planned_action); - mutex_unlock(&rdev->pm.mutex); - /* update power mode info */ - radeon_pm_compute_clocks(rdev); - DRM_INFO("radeon: dynamic power management enabled\n"); - } else - DRM_ERROR("dynpm not valid on this system\n"); - } else - DRM_ERROR("Invalid setting: %d\n", tmp); - + } else if (strncmp("profile", buf, strlen("profile")) == 0) { + mutex_lock(&rdev->pm.mutex); + rdev->pm.pm_method = PM_METHOD_PROFILE; + /* disable dynpm */ + rdev->pm.dynpm_state = DYNPM_STATE_DISABLED; + rdev->pm.dynpm_planned_action = DYNPM_ACTION_NONE; + cancel_delayed_work(&rdev->pm.dynpm_idle_work); + mutex_unlock(&rdev->pm.mutex); + } else { + DRM_ERROR("invalid power method!\n"); + goto fail; + } + radeon_pm_compute_clocks(rdev); +fail: return count; } -static DEVICE_ATTR(power_state, S_IRUGO | S_IWUSR, radeon_get_power_state_static, radeon_set_power_state_static); -static DEVICE_ATTR(dynpm, S_IRUGO | S_IWUSR, radeon_get_dynpm, radeon_set_dynpm); - +static DEVICE_ATTR(power_profile, S_IRUGO | S_IWUSR, radeon_get_pm_profile, radeon_set_pm_profile); +static DEVICE_ATTR(power_method, S_IRUGO | S_IWUSR, radeon_get_pm_method, radeon_set_pm_method); -static const char *pm_state_names[4] = { - "PM_STATE_DISABLED", - "PM_STATE_MINIMUM", - "PM_STATE_PAUSED", - "PM_STATE_ACTIVE" -}; - -static const char *pm_state_types[5] = { - "", - "Powersave", - "Battery", - "Balanced", - "Performance", -}; - -static void radeon_print_power_mode_info(struct radeon_device *rdev) +void radeon_pm_suspend(struct radeon_device *rdev) { - int i, j; - bool is_default; - - DRM_INFO("%d Power State(s)\n", rdev->pm.num_power_states); - for (i = 0; i < rdev->pm.num_power_states; i++) { - if (rdev->pm.default_power_state_index == i) - is_default = true; - else - is_default = false; - DRM_INFO("State %d %s %s\n", i, - pm_state_types[rdev->pm.power_state[i].type], - is_default ? "(default)" : ""); - if ((rdev->flags & RADEON_IS_PCIE) && !(rdev->flags & RADEON_IS_IGP)) - DRM_INFO("\t%d PCIE Lanes\n", rdev->pm.power_state[i].pcie_lanes); - if (rdev->pm.power_state[i].flags & RADEON_PM_STATE_SINGLE_DISPLAY_ONLY) - DRM_INFO("\tSingle display only\n"); - DRM_INFO("\t%d Clock Mode(s)\n", rdev->pm.power_state[i].num_clock_modes); - for (j = 0; j < rdev->pm.power_state[i].num_clock_modes; j++) { - if (rdev->flags & RADEON_IS_IGP) - DRM_INFO("\t\t%d engine: %d\n", - j, - rdev->pm.power_state[i].clock_info[j].sclk * 10); - else - DRM_INFO("\t\t%d engine/memory: %d/%d\n", - j, - rdev->pm.power_state[i].clock_info[j].sclk * 10, - rdev->pm.power_state[i].clock_info[j].mclk * 10); - if (rdev->pm.power_state[i].clock_info[j].flags & RADEON_PM_MODE_NO_DISPLAY) - DRM_INFO("\t\tNo display only\n"); - } - } + mutex_lock(&rdev->pm.mutex); + cancel_delayed_work(&rdev->pm.dynpm_idle_work); + rdev->pm.current_power_state_index = -1; + rdev->pm.current_clock_mode_index = -1; + rdev->pm.current_sclk = 0; + rdev->pm.current_mclk = 0; + mutex_unlock(&rdev->pm.mutex); } -void radeon_sync_with_vblank(struct radeon_device *rdev) +void radeon_pm_resume(struct radeon_device *rdev) { - if (rdev->pm.active_crtcs) { - rdev->pm.vblank_sync = false; - wait_event_timeout( - rdev->irq.vblank_queue, rdev->pm.vblank_sync, - msecs_to_jiffies(RADEON_WAIT_VBLANK_TIMEOUT)); - } + radeon_pm_compute_clocks(rdev); } int radeon_pm_init(struct radeon_device *rdev) { - rdev->pm.state = PM_STATE_DISABLED; - rdev->pm.planned_action = PM_ACTION_NONE; - rdev->pm.can_upclock = true; - rdev->pm.can_downclock = true; + /* default to profile method */ + rdev->pm.pm_method = PM_METHOD_PROFILE; + rdev->pm.dynpm_state = DYNPM_STATE_DISABLED; + rdev->pm.dynpm_planned_action = DYNPM_ACTION_NONE; + rdev->pm.dynpm_can_upclock = true; + rdev->pm.dynpm_can_downclock = true; + rdev->pm.current_sclk = 0; + rdev->pm.current_mclk = 0; if (rdev->bios) { if (rdev->is_atom_bios) radeon_atombios_get_power_modes(rdev); else radeon_combios_get_power_modes(rdev); - radeon_print_power_mode_info(rdev); + radeon_pm_init_profile(rdev); + rdev->pm.current_power_state_index = -1; + rdev->pm.current_clock_mode_index = -1; } - if (radeon_debugfs_pm_init(rdev)) { - DRM_ERROR("Failed to register debugfs file for PM!\n"); - } + if (rdev->pm.num_power_states > 1) { + if (rdev->pm.pm_method == PM_METHOD_PROFILE) { + mutex_lock(&rdev->pm.mutex); + rdev->pm.profile = PM_PROFILE_DEFAULT; + radeon_pm_update_profile(rdev); + radeon_pm_set_clocks(rdev); + mutex_unlock(&rdev->pm.mutex); + } - /* where's the best place to put this? */ - device_create_file(rdev->dev, &dev_attr_power_state); - device_create_file(rdev->dev, &dev_attr_dynpm); + /* where's the best place to put these? */ + device_create_file(rdev->dev, &dev_attr_power_profile); + device_create_file(rdev->dev, &dev_attr_power_method); - INIT_DELAYED_WORK(&rdev->pm.idle_work, radeon_pm_idle_work_handler); +#ifdef CONFIG_ACPI + rdev->acpi_nb.notifier_call = radeon_acpi_event; + register_acpi_notifier(&rdev->acpi_nb); +#endif + INIT_DELAYED_WORK(&rdev->pm.dynpm_idle_work, radeon_dynpm_idle_work_handler); - if ((radeon_dynpm != -1 && radeon_dynpm) && (rdev->pm.num_power_states > 1)) { - rdev->pm.state = PM_STATE_PAUSED; - DRM_INFO("radeon: dynamic power management enabled\n"); - } + if (radeon_debugfs_pm_init(rdev)) { + DRM_ERROR("Failed to register debugfs file for PM!\n"); + } - DRM_INFO("radeon: power management initialized\n"); + DRM_INFO("radeon: power management initialized\n"); + } return 0; } void radeon_pm_fini(struct radeon_device *rdev) { - if (rdev->pm.state != PM_STATE_DISABLED) { - /* cancel work */ - cancel_delayed_work_sync(&rdev->pm.idle_work); - /* reset default clocks */ - rdev->pm.state = PM_STATE_DISABLED; - rdev->pm.planned_action = PM_ACTION_DEFAULT; - radeon_pm_set_clocks(rdev, true); - } else if ((rdev->pm.current_power_state_index != - rdev->pm.default_power_state_index) || - (rdev->pm.current_clock_mode_index != 0)) { - rdev->pm.requested_power_state_index = rdev->pm.default_power_state_index; - rdev->pm.requested_clock_mode_index = 0; + if (rdev->pm.num_power_states > 1) { mutex_lock(&rdev->pm.mutex); - radeon_pm_set_clocks(rdev, true); + if (rdev->pm.pm_method == PM_METHOD_PROFILE) { + rdev->pm.profile = PM_PROFILE_DEFAULT; + radeon_pm_update_profile(rdev); + radeon_pm_set_clocks(rdev); + } else if (rdev->pm.pm_method == PM_METHOD_DYNPM) { + /* cancel work */ + cancel_delayed_work_sync(&rdev->pm.dynpm_idle_work); + /* reset default clocks */ + rdev->pm.dynpm_state = DYNPM_STATE_DISABLED; + rdev->pm.dynpm_planned_action = DYNPM_ACTION_DEFAULT; + radeon_pm_set_clocks(rdev); + } mutex_unlock(&rdev->pm.mutex); - } - device_remove_file(rdev->dev, &dev_attr_power_state); - device_remove_file(rdev->dev, &dev_attr_dynpm); + device_remove_file(rdev->dev, &dev_attr_power_profile); + device_remove_file(rdev->dev, &dev_attr_power_method); +#ifdef CONFIG_ACPI + unregister_acpi_notifier(&rdev->acpi_nb); +#endif + } if (rdev->pm.i2c_bus) radeon_i2c_destroy(rdev->pm.i2c_bus); @@ -347,6 +481,9 @@ void radeon_pm_compute_clocks(struct radeon_device *rdev) struct drm_crtc *crtc; struct radeon_crtc *radeon_crtc; + if (rdev->pm.num_power_states < 2) + return; + mutex_lock(&rdev->pm.mutex); rdev->pm.active_crtcs = 0; @@ -360,55 +497,56 @@ void radeon_pm_compute_clocks(struct radeon_device *rdev) } } - if (rdev->pm.state == PM_STATE_DISABLED) { - mutex_unlock(&rdev->pm.mutex); - return; - } - - /* Note, radeon_pm_set_clocks is called with static_switch set - * to true since we always want to statically set the clocks, - * not wait for vbl. - */ - if (rdev->pm.active_crtc_count > 1) { - if (rdev->pm.state == PM_STATE_ACTIVE) { - cancel_delayed_work(&rdev->pm.idle_work); - - rdev->pm.state = PM_STATE_PAUSED; - rdev->pm.planned_action = PM_ACTION_DEFAULT; - radeon_pm_set_clocks(rdev, true); - - DRM_DEBUG("radeon: dynamic power management deactivated\n"); - } - } else if (rdev->pm.active_crtc_count == 1) { - /* TODO: Increase clocks if needed for current mode */ - - if (rdev->pm.state == PM_STATE_MINIMUM) { - rdev->pm.state = PM_STATE_ACTIVE; - rdev->pm.planned_action = PM_ACTION_UPCLOCK; - radeon_pm_set_clocks(rdev, true); - - queue_delayed_work(rdev->wq, &rdev->pm.idle_work, - msecs_to_jiffies(RADEON_IDLE_LOOP_MS)); - } else if (rdev->pm.state == PM_STATE_PAUSED) { - rdev->pm.state = PM_STATE_ACTIVE; - queue_delayed_work(rdev->wq, &rdev->pm.idle_work, - msecs_to_jiffies(RADEON_IDLE_LOOP_MS)); - DRM_DEBUG("radeon: dynamic power management activated\n"); - } - } else { /* count == 0 */ - if (rdev->pm.state != PM_STATE_MINIMUM) { - cancel_delayed_work(&rdev->pm.idle_work); - - rdev->pm.state = PM_STATE_MINIMUM; - rdev->pm.planned_action = PM_ACTION_MINIMUM; - radeon_pm_set_clocks(rdev, true); + if (rdev->pm.pm_method == PM_METHOD_PROFILE) { + radeon_pm_update_profile(rdev); + radeon_pm_set_clocks(rdev); + } else if (rdev->pm.pm_method == PM_METHOD_DYNPM) { + if (rdev->pm.dynpm_state != DYNPM_STATE_DISABLED) { + if (rdev->pm.active_crtc_count > 1) { + if (rdev->pm.dynpm_state == DYNPM_STATE_ACTIVE) { + cancel_delayed_work(&rdev->pm.dynpm_idle_work); + + rdev->pm.dynpm_state = DYNPM_STATE_PAUSED; + rdev->pm.dynpm_planned_action = DYNPM_ACTION_DEFAULT; + radeon_pm_get_dynpm_state(rdev); + radeon_pm_set_clocks(rdev); + + DRM_DEBUG("radeon: dynamic power management deactivated\n"); + } + } else if (rdev->pm.active_crtc_count == 1) { + /* TODO: Increase clocks if needed for current mode */ + + if (rdev->pm.dynpm_state == DYNPM_STATE_MINIMUM) { + rdev->pm.dynpm_state = DYNPM_STATE_ACTIVE; + rdev->pm.dynpm_planned_action = DYNPM_ACTION_UPCLOCK; + radeon_pm_get_dynpm_state(rdev); + radeon_pm_set_clocks(rdev); + + queue_delayed_work(rdev->wq, &rdev->pm.dynpm_idle_work, + msecs_to_jiffies(RADEON_IDLE_LOOP_MS)); + } else if (rdev->pm.dynpm_state == DYNPM_STATE_PAUSED) { + rdev->pm.dynpm_state = DYNPM_STATE_ACTIVE; + queue_delayed_work(rdev->wq, &rdev->pm.dynpm_idle_work, + msecs_to_jiffies(RADEON_IDLE_LOOP_MS)); + DRM_DEBUG("radeon: dynamic power management activated\n"); + } + } else { /* count == 0 */ + if (rdev->pm.dynpm_state != DYNPM_STATE_MINIMUM) { + cancel_delayed_work(&rdev->pm.dynpm_idle_work); + + rdev->pm.dynpm_state = DYNPM_STATE_MINIMUM; + rdev->pm.dynpm_planned_action = DYNPM_ACTION_MINIMUM; + radeon_pm_get_dynpm_state(rdev); + radeon_pm_set_clocks(rdev); + } + } } } mutex_unlock(&rdev->pm.mutex); } -bool radeon_pm_in_vbl(struct radeon_device *rdev) +static bool radeon_pm_in_vbl(struct radeon_device *rdev) { u32 stat_crtc = 0, vbl = 0, position = 0; bool in_vbl = true; @@ -480,7 +618,7 @@ bool radeon_pm_in_vbl(struct radeon_device *rdev) return in_vbl; } -bool radeon_pm_debug_check_in_vbl(struct radeon_device *rdev, bool finish) +static bool radeon_pm_debug_check_in_vbl(struct radeon_device *rdev, bool finish) { u32 stat_crtc = 0; bool in_vbl = radeon_pm_in_vbl(rdev); @@ -491,16 +629,16 @@ bool radeon_pm_debug_check_in_vbl(struct radeon_device *rdev, bool finish) return in_vbl; } -static void radeon_pm_idle_work_handler(struct work_struct *work) +static void radeon_dynpm_idle_work_handler(struct work_struct *work) { struct radeon_device *rdev; int resched; rdev = container_of(work, struct radeon_device, - pm.idle_work.work); + pm.dynpm_idle_work.work); resched = ttm_bo_lock_delayed_workqueue(&rdev->mman.bdev); mutex_lock(&rdev->pm.mutex); - if (rdev->pm.state == PM_STATE_ACTIVE) { + if (rdev->pm.dynpm_state == DYNPM_STATE_ACTIVE) { unsigned long irq_flags; int not_processed = 0; @@ -516,23 +654,23 @@ static void radeon_pm_idle_work_handler(struct work_struct *work) read_unlock_irqrestore(&rdev->fence_drv.lock, irq_flags); if (not_processed >= 3) { /* should upclock */ - if (rdev->pm.planned_action == PM_ACTION_DOWNCLOCK) { - rdev->pm.planned_action = PM_ACTION_NONE; - } else if (rdev->pm.planned_action == PM_ACTION_NONE && - rdev->pm.can_upclock) { - rdev->pm.planned_action = - PM_ACTION_UPCLOCK; - rdev->pm.action_timeout = jiffies + + if (rdev->pm.dynpm_planned_action == DYNPM_ACTION_DOWNCLOCK) { + rdev->pm.dynpm_planned_action = DYNPM_ACTION_NONE; + } else if (rdev->pm.dynpm_planned_action == DYNPM_ACTION_NONE && + rdev->pm.dynpm_can_upclock) { + rdev->pm.dynpm_planned_action = + DYNPM_ACTION_UPCLOCK; + rdev->pm.dynpm_action_timeout = jiffies + msecs_to_jiffies(RADEON_RECLOCK_DELAY_MS); } } else if (not_processed == 0) { /* should downclock */ - if (rdev->pm.planned_action == PM_ACTION_UPCLOCK) { - rdev->pm.planned_action = PM_ACTION_NONE; - } else if (rdev->pm.planned_action == PM_ACTION_NONE && - rdev->pm.can_downclock) { - rdev->pm.planned_action = - PM_ACTION_DOWNCLOCK; - rdev->pm.action_timeout = jiffies + + if (rdev->pm.dynpm_planned_action == DYNPM_ACTION_UPCLOCK) { + rdev->pm.dynpm_planned_action = DYNPM_ACTION_NONE; + } else if (rdev->pm.dynpm_planned_action == DYNPM_ACTION_NONE && + rdev->pm.dynpm_can_downclock) { + rdev->pm.dynpm_planned_action = + DYNPM_ACTION_DOWNCLOCK; + rdev->pm.dynpm_action_timeout = jiffies + msecs_to_jiffies(RADEON_RECLOCK_DELAY_MS); } } @@ -540,15 +678,16 @@ static void radeon_pm_idle_work_handler(struct work_struct *work) /* Note, radeon_pm_set_clocks is called with static_switch set * to false since we want to wait for vbl to avoid flicker. */ - if (rdev->pm.planned_action != PM_ACTION_NONE && - jiffies > rdev->pm.action_timeout) { - radeon_pm_set_clocks(rdev, false); + if (rdev->pm.dynpm_planned_action != DYNPM_ACTION_NONE && + jiffies > rdev->pm.dynpm_action_timeout) { + radeon_pm_get_dynpm_state(rdev); + radeon_pm_set_clocks(rdev); } } mutex_unlock(&rdev->pm.mutex); ttm_bo_unlock_delayed_workqueue(&rdev->mman.bdev, resched); - queue_delayed_work(rdev->wq, &rdev->pm.idle_work, + queue_delayed_work(rdev->wq, &rdev->pm.dynpm_idle_work, msecs_to_jiffies(RADEON_IDLE_LOOP_MS)); } @@ -563,7 +702,6 @@ static int radeon_debugfs_pm_info(struct seq_file *m, void *data) struct drm_device *dev = node->minor->dev; struct radeon_device *rdev = dev->dev_private; - seq_printf(m, "state: %s\n", pm_state_names[rdev->pm.state]); seq_printf(m, "default engine clock: %u0 kHz\n", rdev->clock.default_sclk); seq_printf(m, "current engine clock: %u0 kHz\n", radeon_get_engine_clock(rdev)); seq_printf(m, "default memory clock: %u0 kHz\n", rdev->clock.default_mclk); diff --git a/drivers/gpu/drm/radeon/rs400.c b/drivers/gpu/drm/radeon/rs400.c index dc76fe76eb25..9e4240b3bf0b 100644 --- a/drivers/gpu/drm/radeon/rs400.c +++ b/drivers/gpu/drm/radeon/rs400.c @@ -456,7 +456,6 @@ int rs400_suspend(struct radeon_device *rdev) void rs400_fini(struct radeon_device *rdev) { - radeon_pm_fini(rdev); r100_cp_fini(rdev); r100_wb_fini(rdev); r100_ib_fini(rdev); @@ -507,8 +506,6 @@ int rs400_init(struct radeon_device *rdev) /* Initialize clocks */ radeon_get_clock_info(rdev->ddev); - /* Initialize power management */ - radeon_pm_init(rdev); /* initialize memory controller */ rs400_mc_init(rdev); /* Fence driver */ diff --git a/drivers/gpu/drm/radeon/rs600.c b/drivers/gpu/drm/radeon/rs600.c index 8e0c46060b3a..e8c68e9c0a1e 100644 --- a/drivers/gpu/drm/radeon/rs600.c +++ b/drivers/gpu/drm/radeon/rs600.c @@ -846,7 +846,6 @@ int rs600_suspend(struct radeon_device *rdev) void rs600_fini(struct radeon_device *rdev) { - radeon_pm_fini(rdev); r100_cp_fini(rdev); r100_wb_fini(rdev); r100_ib_fini(rdev); @@ -896,8 +895,6 @@ int rs600_init(struct radeon_device *rdev) /* Initialize clocks */ radeon_get_clock_info(rdev->ddev); - /* Initialize power management */ - radeon_pm_init(rdev); /* initialize memory controller */ rs600_mc_init(rdev); rs600_debugfs(rdev); diff --git a/drivers/gpu/drm/radeon/rs690.c b/drivers/gpu/drm/radeon/rs690.c index e8edfe617286..bcc33195ebc2 100644 --- a/drivers/gpu/drm/radeon/rs690.c +++ b/drivers/gpu/drm/radeon/rs690.c @@ -676,7 +676,6 @@ int rs690_suspend(struct radeon_device *rdev) void rs690_fini(struct radeon_device *rdev) { - radeon_pm_fini(rdev); r100_cp_fini(rdev); r100_wb_fini(rdev); r100_ib_fini(rdev); @@ -727,8 +726,6 @@ int rs690_init(struct radeon_device *rdev) /* Initialize clocks */ radeon_get_clock_info(rdev->ddev); - /* Initialize power management */ - radeon_pm_init(rdev); /* initialize memory controller */ rs690_mc_init(rdev); rv515_debugfs(rdev); diff --git a/drivers/gpu/drm/radeon/rv515.c b/drivers/gpu/drm/radeon/rv515.c index 2009f4b20c28..7d9a7b0a180a 100644 --- a/drivers/gpu/drm/radeon/rv515.c +++ b/drivers/gpu/drm/radeon/rv515.c @@ -445,7 +445,6 @@ void rv515_set_safe_registers(struct radeon_device *rdev) void rv515_fini(struct radeon_device *rdev) { - radeon_pm_fini(rdev); r100_cp_fini(rdev); r100_wb_fini(rdev); r100_ib_fini(rdev); @@ -494,8 +493,6 @@ int rv515_init(struct radeon_device *rdev) return -EINVAL; /* Initialize clocks */ radeon_get_clock_info(rdev->ddev); - /* Initialize power management */ - radeon_pm_init(rdev); /* initialize AGP */ if (rdev->flags & RADEON_IS_AGP) { r = radeon_agp_init(rdev); diff --git a/drivers/gpu/drm/radeon/rv770.c b/drivers/gpu/drm/radeon/rv770.c index 7c55182a9dd7..253f24aec031 100644 --- a/drivers/gpu/drm/radeon/rv770.c +++ b/drivers/gpu/drm/radeon/rv770.c @@ -1091,8 +1091,6 @@ int rv770_init(struct radeon_device *rdev) r = radeon_clocks_init(rdev); if (r) return r; - /* Initialize power management */ - radeon_pm_init(rdev); /* Fence driver */ r = radeon_fence_driver_init(rdev); if (r) @@ -1161,7 +1159,6 @@ int rv770_init(struct radeon_device *rdev) void rv770_fini(struct radeon_device *rdev) { - radeon_pm_fini(rdev); r600_blit_fini(rdev); r700_cp_fini(rdev); r600_wb_fini(rdev); -- cgit v1.2.3 From ce8a3eb20c4cb7d9e0c33e7560070688cd9066fc Mon Sep 17 00:00:00 2001 From: Alex Deucher Date: Fri, 7 May 2010 16:58:27 -0400 Subject: drm/radeon/kms/pm: make pm spam debug only Signed-off-by: Alex Deucher Signed-off-by: Dave Airlie --- drivers/gpu/drm/radeon/r100.c | 16 ++++++++-------- drivers/gpu/drm/radeon/r600.c | 14 +++++++------- drivers/gpu/drm/radeon/radeon_pm.c | 16 ++++++++-------- drivers/gpu/drm/radeon/rs600.c | 2 +- 4 files changed, 24 insertions(+), 24 deletions(-) (limited to 'drivers/gpu/drm/radeon') diff --git a/drivers/gpu/drm/radeon/r100.c b/drivers/gpu/drm/radeon/r100.c index 4c5d21bfa2c4..9a59ba46f078 100644 --- a/drivers/gpu/drm/radeon/r100.c +++ b/drivers/gpu/drm/radeon/r100.c @@ -141,13 +141,13 @@ void r100_pm_get_dynpm_state(struct radeon_device *rdev) /* only one clock mode per power state */ rdev->pm.requested_clock_mode_index = 0; - DRM_INFO("Requested: e: %d m: %d p: %d\n", - rdev->pm.power_state[rdev->pm.requested_power_state_index]. - clock_info[rdev->pm.requested_clock_mode_index].sclk, - rdev->pm.power_state[rdev->pm.requested_power_state_index]. - clock_info[rdev->pm.requested_clock_mode_index].mclk, - rdev->pm.power_state[rdev->pm.requested_power_state_index]. - pcie_lanes); + DRM_DEBUG("Requested: e: %d m: %d p: %d\n", + rdev->pm.power_state[rdev->pm.requested_power_state_index]. + clock_info[rdev->pm.requested_clock_mode_index].sclk, + rdev->pm.power_state[rdev->pm.requested_power_state_index]. + clock_info[rdev->pm.requested_clock_mode_index].mclk, + rdev->pm.power_state[rdev->pm.requested_power_state_index]. + pcie_lanes); } void r100_pm_init_profile(struct radeon_device *rdev) @@ -266,7 +266,7 @@ void r100_pm_misc(struct radeon_device *rdev) rdev->pm.power_state[rdev->pm.current_power_state_index].pcie_lanes)) { radeon_set_pcie_lanes(rdev, ps->pcie_lanes); - DRM_INFO("Setting: p: %d\n", ps->pcie_lanes); + DRM_DEBUG("Setting: p: %d\n", ps->pcie_lanes); } } diff --git a/drivers/gpu/drm/radeon/r600.c b/drivers/gpu/drm/radeon/r600.c index 618d76d366a4..0fef3351660c 100644 --- a/drivers/gpu/drm/radeon/r600.c +++ b/drivers/gpu/drm/radeon/r600.c @@ -251,13 +251,13 @@ void r600_pm_get_dynpm_state(struct radeon_device *rdev) } } - DRM_INFO("Requested: e: %d m: %d p: %d\n", - rdev->pm.power_state[rdev->pm.requested_power_state_index]. - clock_info[rdev->pm.requested_clock_mode_index].sclk, - rdev->pm.power_state[rdev->pm.requested_power_state_index]. - clock_info[rdev->pm.requested_clock_mode_index].mclk, - rdev->pm.power_state[rdev->pm.requested_power_state_index]. - pcie_lanes); + DRM_DEBUG("Requested: e: %d m: %d p: %d\n", + rdev->pm.power_state[rdev->pm.requested_power_state_index]. + clock_info[rdev->pm.requested_clock_mode_index].sclk, + rdev->pm.power_state[rdev->pm.requested_power_state_index]. + clock_info[rdev->pm.requested_clock_mode_index].mclk, + rdev->pm.power_state[rdev->pm.requested_power_state_index]. + pcie_lanes); } static int r600_pm_get_type_index(struct radeon_device *rdev, diff --git a/drivers/gpu/drm/radeon/radeon_pm.c b/drivers/gpu/drm/radeon/radeon_pm.c index 1827317704a2..c88edae33deb 100644 --- a/drivers/gpu/drm/radeon/radeon_pm.c +++ b/drivers/gpu/drm/radeon/radeon_pm.c @@ -52,9 +52,9 @@ static int radeon_acpi_event(struct notifier_block *nb, if (strcmp(entry->device_class, ACPI_AC_CLASS) == 0) { if (power_supply_is_system_supplied() > 0) - DRM_INFO("pm: AC\n"); + DRM_DEBUG("pm: AC\n"); else - DRM_INFO("pm: DC\n"); + DRM_DEBUG("pm: DC\n"); if (rdev->pm.pm_method == PM_METHOD_PROFILE) { if (rdev->pm.profile == PM_PROFILE_AUTO) { @@ -183,7 +183,7 @@ static void radeon_set_power_state(struct radeon_device *rdev) radeon_set_engine_clock(rdev, sclk); radeon_pm_debug_check_in_vbl(rdev, true); rdev->pm.current_sclk = sclk; - DRM_INFO("Setting: e: %d\n", sclk); + DRM_DEBUG("Setting: e: %d\n", sclk); } /* set memory clock */ @@ -192,7 +192,7 @@ static void radeon_set_power_state(struct radeon_device *rdev) radeon_set_memory_clock(rdev, mclk); radeon_pm_debug_check_in_vbl(rdev, true); rdev->pm.current_mclk = mclk; - DRM_INFO("Setting: m: %d\n", mclk); + DRM_DEBUG("Setting: m: %d\n", mclk); } radeon_pm_finish(rdev); } else { @@ -203,7 +203,7 @@ static void radeon_set_power_state(struct radeon_device *rdev) radeon_set_engine_clock(rdev, sclk); radeon_pm_finish(rdev); rdev->pm.current_sclk = sclk; - DRM_INFO("Setting: e: %d\n", sclk); + DRM_DEBUG("Setting: e: %d\n", sclk); } /* set memory clock */ if (rdev->asic->set_memory_clock && (mclk != rdev->pm.current_mclk)) { @@ -212,14 +212,14 @@ static void radeon_set_power_state(struct radeon_device *rdev) radeon_set_memory_clock(rdev, mclk); radeon_pm_finish(rdev); rdev->pm.current_mclk = mclk; - DRM_INFO("Setting: m: %d\n", mclk); + DRM_DEBUG("Setting: m: %d\n", mclk); } } rdev->pm.current_power_state_index = rdev->pm.requested_power_state_index; rdev->pm.current_clock_mode_index = rdev->pm.requested_clock_mode_index; } else - DRM_INFO("pm: GUI not idle!!!\n"); + DRM_DEBUG("pm: GUI not idle!!!\n"); } static void radeon_pm_set_clocks(struct radeon_device *rdev) @@ -624,7 +624,7 @@ static bool radeon_pm_debug_check_in_vbl(struct radeon_device *rdev, bool finish bool in_vbl = radeon_pm_in_vbl(rdev); if (in_vbl == false) - DRM_INFO("not in vbl for pm change %08x at %s\n", stat_crtc, + DRM_DEBUG("not in vbl for pm change %08x at %s\n", stat_crtc, finish ? "exit" : "entry"); return in_vbl; } diff --git a/drivers/gpu/drm/radeon/rs600.c b/drivers/gpu/drm/radeon/rs600.c index e8c68e9c0a1e..79887cac5b54 100644 --- a/drivers/gpu/drm/radeon/rs600.c +++ b/drivers/gpu/drm/radeon/rs600.c @@ -135,7 +135,7 @@ void rs600_pm_misc(struct radeon_device *rdev) rdev->pm.power_state[rdev->pm.current_power_state_index].pcie_lanes)) { radeon_set_pcie_lanes(rdev, ps->pcie_lanes); - DRM_INFO("Setting: p: %d\n", ps->pcie_lanes); + DRM_DEBUG("Setting: p: %d\n", ps->pcie_lanes); } } -- cgit v1.2.3 From 4bff51711ca8709c5f18640ad6e8ae6b9e8f8047 Mon Sep 17 00:00:00 2001 From: Alex Deucher Date: Mon, 17 May 2010 19:41:26 -0400 Subject: drm/radeon/kms/pm: fix r6xx+ profile setup This patch is a combination of the previous two profile patches, but without the index bugs. It cleans up and fixes some issues with pm profile setup on r6xx chips. Some tables have different orderings for the power states, also, r600 only has 1 clock mode per power state. On desktop cards there are no battery modes, so the low and high power states are the same. For the low profile case, choose the lower clock mode. Signed-off-by: Alex Deucher Signed-off-by: Dave Airlie --- drivers/gpu/drm/radeon/r600.c | 114 ++++++++++++++++++++---------------------- 1 file changed, 53 insertions(+), 61 deletions(-) (limited to 'drivers/gpu/drm/radeon') diff --git a/drivers/gpu/drm/radeon/r600.c b/drivers/gpu/drm/radeon/r600.c index 0fef3351660c..7ffc3892c652 100644 --- a/drivers/gpu/drm/radeon/r600.c +++ b/drivers/gpu/drm/radeon/r600.c @@ -369,61 +369,27 @@ void r600_pm_init_profile(struct radeon_device *rdev) rdev->pm.profiles[PM_PROFILE_DEFAULT_IDX].dpms_off_ps_idx = rdev->pm.default_power_state_index; rdev->pm.profiles[PM_PROFILE_DEFAULT_IDX].dpms_on_ps_idx = rdev->pm.default_power_state_index; rdev->pm.profiles[PM_PROFILE_DEFAULT_IDX].dpms_off_cm_idx = 0; - rdev->pm.profiles[PM_PROFILE_DEFAULT_IDX].dpms_on_cm_idx = 2; + rdev->pm.profiles[PM_PROFILE_DEFAULT_IDX].dpms_on_cm_idx = 0; /* low sh */ rdev->pm.profiles[PM_PROFILE_LOW_SH_IDX].dpms_off_ps_idx = rdev->pm.default_power_state_index; rdev->pm.profiles[PM_PROFILE_LOW_SH_IDX].dpms_on_ps_idx = rdev->pm.default_power_state_index; rdev->pm.profiles[PM_PROFILE_LOW_SH_IDX].dpms_off_cm_idx = 0; - rdev->pm.profiles[PM_PROFILE_LOW_SH_IDX].dpms_on_cm_idx = 2; + rdev->pm.profiles[PM_PROFILE_LOW_SH_IDX].dpms_on_cm_idx = 0; /* high sh */ rdev->pm.profiles[PM_PROFILE_HIGH_SH_IDX].dpms_off_ps_idx = rdev->pm.default_power_state_index; rdev->pm.profiles[PM_PROFILE_HIGH_SH_IDX].dpms_on_ps_idx = rdev->pm.default_power_state_index; rdev->pm.profiles[PM_PROFILE_HIGH_SH_IDX].dpms_off_cm_idx = 0; - rdev->pm.profiles[PM_PROFILE_HIGH_SH_IDX].dpms_on_cm_idx = 2; + rdev->pm.profiles[PM_PROFILE_HIGH_SH_IDX].dpms_on_cm_idx = 0; /* low mh */ rdev->pm.profiles[PM_PROFILE_LOW_MH_IDX].dpms_off_ps_idx = rdev->pm.default_power_state_index; rdev->pm.profiles[PM_PROFILE_LOW_MH_IDX].dpms_on_ps_idx = rdev->pm.default_power_state_index; rdev->pm.profiles[PM_PROFILE_LOW_MH_IDX].dpms_off_cm_idx = 0; - rdev->pm.profiles[PM_PROFILE_LOW_MH_IDX].dpms_on_cm_idx = 2; + rdev->pm.profiles[PM_PROFILE_LOW_MH_IDX].dpms_on_cm_idx = 0; /* high mh */ rdev->pm.profiles[PM_PROFILE_HIGH_MH_IDX].dpms_off_ps_idx = rdev->pm.default_power_state_index; rdev->pm.profiles[PM_PROFILE_HIGH_MH_IDX].dpms_on_ps_idx = rdev->pm.default_power_state_index; rdev->pm.profiles[PM_PROFILE_HIGH_MH_IDX].dpms_off_cm_idx = 0; - rdev->pm.profiles[PM_PROFILE_HIGH_MH_IDX].dpms_on_cm_idx = 2; - } else if (rdev->flags & RADEON_IS_MOBILITY) { - /* default */ - rdev->pm.profiles[PM_PROFILE_DEFAULT_IDX].dpms_off_ps_idx = rdev->pm.default_power_state_index; - rdev->pm.profiles[PM_PROFILE_DEFAULT_IDX].dpms_on_ps_idx = rdev->pm.default_power_state_index; - rdev->pm.profiles[PM_PROFILE_DEFAULT_IDX].dpms_off_cm_idx = 0; - rdev->pm.profiles[PM_PROFILE_DEFAULT_IDX].dpms_on_cm_idx = 2; - /* low sh */ - rdev->pm.profiles[PM_PROFILE_LOW_SH_IDX].dpms_off_ps_idx = - r600_pm_get_type_index(rdev, POWER_STATE_TYPE_BATTERY, 0); - rdev->pm.profiles[PM_PROFILE_LOW_SH_IDX].dpms_on_ps_idx = - r600_pm_get_type_index(rdev, POWER_STATE_TYPE_BATTERY, 0); - rdev->pm.profiles[PM_PROFILE_LOW_SH_IDX].dpms_off_cm_idx = 0; - rdev->pm.profiles[PM_PROFILE_LOW_SH_IDX].dpms_on_cm_idx = 2; - /* high sh */ - rdev->pm.profiles[PM_PROFILE_HIGH_SH_IDX].dpms_off_ps_idx = - r600_pm_get_type_index(rdev, POWER_STATE_TYPE_PERFORMANCE, 0); - rdev->pm.profiles[PM_PROFILE_HIGH_SH_IDX].dpms_on_ps_idx = - r600_pm_get_type_index(rdev, POWER_STATE_TYPE_PERFORMANCE, 0); - rdev->pm.profiles[PM_PROFILE_HIGH_SH_IDX].dpms_off_cm_idx = 0; - rdev->pm.profiles[PM_PROFILE_HIGH_SH_IDX].dpms_on_cm_idx = 2; - /* low mh */ - rdev->pm.profiles[PM_PROFILE_LOW_MH_IDX].dpms_off_ps_idx = - r600_pm_get_type_index(rdev, POWER_STATE_TYPE_BATTERY, 1); - rdev->pm.profiles[PM_PROFILE_LOW_MH_IDX].dpms_on_ps_idx = - r600_pm_get_type_index(rdev, POWER_STATE_TYPE_BATTERY, 1); - rdev->pm.profiles[PM_PROFILE_LOW_MH_IDX].dpms_off_cm_idx = 0; - rdev->pm.profiles[PM_PROFILE_LOW_MH_IDX].dpms_on_cm_idx = 2; - /* high mh */ - rdev->pm.profiles[PM_PROFILE_HIGH_MH_IDX].dpms_off_ps_idx = - r600_pm_get_type_index(rdev, POWER_STATE_TYPE_PERFORMANCE, 1); - rdev->pm.profiles[PM_PROFILE_HIGH_MH_IDX].dpms_on_ps_idx = - r600_pm_get_type_index(rdev, POWER_STATE_TYPE_PERFORMANCE, 1); - rdev->pm.profiles[PM_PROFILE_HIGH_MH_IDX].dpms_off_cm_idx = 0; - rdev->pm.profiles[PM_PROFILE_HIGH_MH_IDX].dpms_on_cm_idx = 2; + rdev->pm.profiles[PM_PROFILE_HIGH_MH_IDX].dpms_on_cm_idx = 0; } else { if (rdev->pm.num_power_states < 4) { /* default */ @@ -432,23 +398,23 @@ void r600_pm_init_profile(struct radeon_device *rdev) rdev->pm.profiles[PM_PROFILE_DEFAULT_IDX].dpms_off_cm_idx = 0; rdev->pm.profiles[PM_PROFILE_DEFAULT_IDX].dpms_on_cm_idx = 2; /* low sh */ - rdev->pm.profiles[PM_PROFILE_LOW_SH_IDX].dpms_off_ps_idx = rdev->pm.default_power_state_index; - rdev->pm.profiles[PM_PROFILE_LOW_SH_IDX].dpms_on_ps_idx = rdev->pm.default_power_state_index; + rdev->pm.profiles[PM_PROFILE_LOW_SH_IDX].dpms_off_ps_idx = 1; + rdev->pm.profiles[PM_PROFILE_LOW_SH_IDX].dpms_on_ps_idx = 1; rdev->pm.profiles[PM_PROFILE_LOW_SH_IDX].dpms_off_cm_idx = 0; - rdev->pm.profiles[PM_PROFILE_LOW_SH_IDX].dpms_on_cm_idx = 2; + rdev->pm.profiles[PM_PROFILE_LOW_SH_IDX].dpms_on_cm_idx = 1; /* high sh */ - rdev->pm.profiles[PM_PROFILE_HIGH_SH_IDX].dpms_off_ps_idx = rdev->pm.default_power_state_index; - rdev->pm.profiles[PM_PROFILE_HIGH_SH_IDX].dpms_on_ps_idx = rdev->pm.default_power_state_index; + rdev->pm.profiles[PM_PROFILE_HIGH_SH_IDX].dpms_off_ps_idx = 1; + rdev->pm.profiles[PM_PROFILE_HIGH_SH_IDX].dpms_on_ps_idx = 1; rdev->pm.profiles[PM_PROFILE_HIGH_SH_IDX].dpms_off_cm_idx = 0; rdev->pm.profiles[PM_PROFILE_HIGH_SH_IDX].dpms_on_cm_idx = 2; /* low mh */ - rdev->pm.profiles[PM_PROFILE_LOW_MH_IDX].dpms_off_ps_idx = rdev->pm.default_power_state_index; - rdev->pm.profiles[PM_PROFILE_LOW_MH_IDX].dpms_on_ps_idx = rdev->pm.default_power_state_index; + rdev->pm.profiles[PM_PROFILE_LOW_MH_IDX].dpms_off_ps_idx = 2; + rdev->pm.profiles[PM_PROFILE_LOW_MH_IDX].dpms_on_ps_idx = 2; rdev->pm.profiles[PM_PROFILE_LOW_MH_IDX].dpms_off_cm_idx = 0; - rdev->pm.profiles[PM_PROFILE_LOW_MH_IDX].dpms_on_cm_idx = 2; + rdev->pm.profiles[PM_PROFILE_LOW_MH_IDX].dpms_on_cm_idx = 1; /* high mh */ - rdev->pm.profiles[PM_PROFILE_HIGH_MH_IDX].dpms_off_ps_idx = rdev->pm.default_power_state_index; - rdev->pm.profiles[PM_PROFILE_HIGH_MH_IDX].dpms_on_ps_idx = rdev->pm.default_power_state_index; + rdev->pm.profiles[PM_PROFILE_HIGH_MH_IDX].dpms_off_ps_idx = 2; + rdev->pm.profiles[PM_PROFILE_HIGH_MH_IDX].dpms_on_ps_idx = 2; rdev->pm.profiles[PM_PROFILE_HIGH_MH_IDX].dpms_off_cm_idx = 0; rdev->pm.profiles[PM_PROFILE_HIGH_MH_IDX].dpms_on_cm_idx = 2; } else { @@ -458,23 +424,49 @@ void r600_pm_init_profile(struct radeon_device *rdev) rdev->pm.profiles[PM_PROFILE_DEFAULT_IDX].dpms_off_cm_idx = 0; rdev->pm.profiles[PM_PROFILE_DEFAULT_IDX].dpms_on_cm_idx = 2; /* low sh */ - rdev->pm.profiles[PM_PROFILE_LOW_SH_IDX].dpms_off_ps_idx = 1; - rdev->pm.profiles[PM_PROFILE_LOW_SH_IDX].dpms_on_ps_idx = 1; - rdev->pm.profiles[PM_PROFILE_LOW_SH_IDX].dpms_off_cm_idx = 0; - rdev->pm.profiles[PM_PROFILE_LOW_SH_IDX].dpms_on_cm_idx = 2; + if (rdev->flags & RADEON_IS_MOBILITY) { + rdev->pm.profiles[PM_PROFILE_LOW_SH_IDX].dpms_off_ps_idx = + r600_pm_get_type_index(rdev, POWER_STATE_TYPE_BATTERY, 0); + rdev->pm.profiles[PM_PROFILE_LOW_SH_IDX].dpms_on_ps_idx = + r600_pm_get_type_index(rdev, POWER_STATE_TYPE_BATTERY, 0); + rdev->pm.profiles[PM_PROFILE_LOW_SH_IDX].dpms_off_cm_idx = 0; + rdev->pm.profiles[PM_PROFILE_LOW_SH_IDX].dpms_on_cm_idx = 2; + } else { + rdev->pm.profiles[PM_PROFILE_LOW_SH_IDX].dpms_off_ps_idx = + r600_pm_get_type_index(rdev, POWER_STATE_TYPE_PERFORMANCE, 0); + rdev->pm.profiles[PM_PROFILE_LOW_SH_IDX].dpms_on_ps_idx = + r600_pm_get_type_index(rdev, POWER_STATE_TYPE_PERFORMANCE, 0); + rdev->pm.profiles[PM_PROFILE_LOW_SH_IDX].dpms_off_cm_idx = 0; + rdev->pm.profiles[PM_PROFILE_LOW_SH_IDX].dpms_on_cm_idx = 1; + } /* high sh */ - rdev->pm.profiles[PM_PROFILE_HIGH_SH_IDX].dpms_off_ps_idx = 1; - rdev->pm.profiles[PM_PROFILE_HIGH_SH_IDX].dpms_on_ps_idx = 1; + rdev->pm.profiles[PM_PROFILE_HIGH_SH_IDX].dpms_off_ps_idx = + r600_pm_get_type_index(rdev, POWER_STATE_TYPE_PERFORMANCE, 0); + rdev->pm.profiles[PM_PROFILE_HIGH_SH_IDX].dpms_on_ps_idx = + r600_pm_get_type_index(rdev, POWER_STATE_TYPE_PERFORMANCE, 0); rdev->pm.profiles[PM_PROFILE_HIGH_SH_IDX].dpms_off_cm_idx = 0; rdev->pm.profiles[PM_PROFILE_HIGH_SH_IDX].dpms_on_cm_idx = 2; /* low mh */ - rdev->pm.profiles[PM_PROFILE_LOW_MH_IDX].dpms_off_ps_idx = 3; - rdev->pm.profiles[PM_PROFILE_LOW_MH_IDX].dpms_on_ps_idx = 3; - rdev->pm.profiles[PM_PROFILE_LOW_MH_IDX].dpms_off_cm_idx = 0; - rdev->pm.profiles[PM_PROFILE_LOW_MH_IDX].dpms_on_cm_idx = 2; + if (rdev->flags & RADEON_IS_MOBILITY) { + rdev->pm.profiles[PM_PROFILE_LOW_MH_IDX].dpms_off_ps_idx = + r600_pm_get_type_index(rdev, POWER_STATE_TYPE_BATTERY, 1); + rdev->pm.profiles[PM_PROFILE_LOW_MH_IDX].dpms_on_ps_idx = + r600_pm_get_type_index(rdev, POWER_STATE_TYPE_BATTERY, 1); + rdev->pm.profiles[PM_PROFILE_LOW_MH_IDX].dpms_off_cm_idx = 0; + rdev->pm.profiles[PM_PROFILE_LOW_MH_IDX].dpms_on_cm_idx = 2; + } else { + rdev->pm.profiles[PM_PROFILE_LOW_MH_IDX].dpms_off_ps_idx = + r600_pm_get_type_index(rdev, POWER_STATE_TYPE_PERFORMANCE, 1); + rdev->pm.profiles[PM_PROFILE_LOW_MH_IDX].dpms_on_ps_idx = + r600_pm_get_type_index(rdev, POWER_STATE_TYPE_PERFORMANCE, 1); + rdev->pm.profiles[PM_PROFILE_LOW_MH_IDX].dpms_off_cm_idx = 0; + rdev->pm.profiles[PM_PROFILE_LOW_MH_IDX].dpms_on_cm_idx = 1; + } /* high mh */ - rdev->pm.profiles[PM_PROFILE_HIGH_MH_IDX].dpms_off_ps_idx = 3; - rdev->pm.profiles[PM_PROFILE_HIGH_MH_IDX].dpms_on_ps_idx = 3; + rdev->pm.profiles[PM_PROFILE_HIGH_MH_IDX].dpms_off_ps_idx = + r600_pm_get_type_index(rdev, POWER_STATE_TYPE_PERFORMANCE, 1); + rdev->pm.profiles[PM_PROFILE_HIGH_MH_IDX].dpms_on_ps_idx = + r600_pm_get_type_index(rdev, POWER_STATE_TYPE_PERFORMANCE, 1); rdev->pm.profiles[PM_PROFILE_HIGH_MH_IDX].dpms_off_cm_idx = 0; rdev->pm.profiles[PM_PROFILE_HIGH_MH_IDX].dpms_on_cm_idx = 2; } -- cgit v1.2.3 From 26481fb15644b5fd85d4cea020f74a234cdf6803 Mon Sep 17 00:00:00 2001 From: Dave Airlie Date: Tue, 18 May 2010 19:00:14 +1000 Subject: drm/radeon/pm: fix device_create_file return value checks. print an error if these fail. Signed-off-by: Dave Airlie --- drivers/gpu/drm/radeon/radeon_pm.c | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) (limited to 'drivers/gpu/drm/radeon') diff --git a/drivers/gpu/drm/radeon/radeon_pm.c b/drivers/gpu/drm/radeon/radeon_pm.c index c88edae33deb..a8d162c6f829 100644 --- a/drivers/gpu/drm/radeon/radeon_pm.c +++ b/drivers/gpu/drm/radeon/radeon_pm.c @@ -398,6 +398,7 @@ void radeon_pm_resume(struct radeon_device *rdev) int radeon_pm_init(struct radeon_device *rdev) { + int ret; /* default to profile method */ rdev->pm.pm_method = PM_METHOD_PROFILE; rdev->pm.dynpm_state = DYNPM_STATE_DISABLED; @@ -427,8 +428,12 @@ int radeon_pm_init(struct radeon_device *rdev) } /* where's the best place to put these? */ - device_create_file(rdev->dev, &dev_attr_power_profile); - device_create_file(rdev->dev, &dev_attr_power_method); + ret = device_create_file(rdev->dev, &dev_attr_power_profile); + if (ret) + DRM_ERROR("failed to create device file for power profile\n"); + ret = device_create_file(rdev->dev, &dev_attr_power_method); + if (ret) + DRM_ERROR("failed to create device file for power method\n"); #ifdef CONFIG_ACPI rdev->acpi_nb.notifier_call = radeon_acpi_event; -- cgit v1.2.3 From 2bfcc0fc698d550689ef020c73b2d977b73e728c Mon Sep 17 00:00:00 2001 From: Alex Deucher Date: Tue, 18 May 2010 19:26:46 -0400 Subject: drm/radeon/kms: reset ddc_bus in object header parsing Some LVDS connectors don't have a ddc bus, so reset the ddc bus to invalid before parsing the next connector to avoid using stale ddc bus data. Should fix fdo bug 28164. Signed-off-by: Alex Deucher Cc: stable@kernel.org Signed-off-by: Dave Airlie --- drivers/gpu/drm/radeon/radeon_atombios.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) (limited to 'drivers/gpu/drm/radeon') diff --git a/drivers/gpu/drm/radeon/radeon_atombios.c b/drivers/gpu/drm/radeon/radeon_atombios.c index 1c24dad0ac39..8cb4173365c3 100644 --- a/drivers/gpu/drm/radeon/radeon_atombios.c +++ b/drivers/gpu/drm/radeon/radeon_atombios.c @@ -530,6 +530,8 @@ bool radeon_get_atom_connector_info_from_object_table(struct drm_device *dev) } /* look up gpio for ddc, hpd */ + ddc_bus.valid = false; + hpd.hpd = RADEON_HPD_NONE; if ((le16_to_cpu(path->usDeviceTag) & (ATOM_DEVICE_TV_SUPPORT | ATOM_DEVICE_CV_SUPPORT)) == 0) { for (j = 0; j < con_obj->ucNumberOfObjects; j++) { @@ -585,9 +587,6 @@ bool radeon_get_atom_connector_info_from_object_table(struct drm_device *dev) break; } } - } else { - hpd.hpd = RADEON_HPD_NONE; - ddc_bus.valid = false; } /* needed for aux chan transactions */ -- cgit v1.2.3 From 8e36ed00842668a39a6ed1b0a00b8ac92b7c4cd5 Mon Sep 17 00:00:00 2001 From: Alex Deucher Date: Tue, 18 May 2010 19:26:47 -0400 Subject: drm/radeon/kms: hpd cleanup - Use radeon hpd enum consistently (in both hotplug and dp) - Legacy r100 with DVI should be HPD_1 not NONE Signed-off-by: Alex Deucher Signed-off-by: Dave Airlie --- drivers/gpu/drm/radeon/atombios_dp.c | 2 +- drivers/gpu/drm/radeon/radeon_atombios.c | 3 +-- drivers/gpu/drm/radeon/radeon_combios.c | 4 ++-- drivers/gpu/drm/radeon/radeon_mode.h | 22 +++++++++++----------- 4 files changed, 15 insertions(+), 16 deletions(-) (limited to 'drivers/gpu/drm/radeon') diff --git a/drivers/gpu/drm/radeon/atombios_dp.c b/drivers/gpu/drm/radeon/atombios_dp.c index 28b31c64f48d..abffb1499e22 100644 --- a/drivers/gpu/drm/radeon/atombios_dp.c +++ b/drivers/gpu/drm/radeon/atombios_dp.c @@ -351,7 +351,7 @@ retry: args.v1.ucChannelID = chan->rec.i2c_id; args.v1.ucDelay = delay / 10; if (ASIC_IS_DCE4(rdev)) - args.v2.ucHPD_ID = chan->rec.hpd_id; + args.v2.ucHPD_ID = chan->rec.hpd; atom_execute_table(rdev->mode_info.atom_context, index, (uint32_t *)&args); diff --git a/drivers/gpu/drm/radeon/radeon_atombios.c b/drivers/gpu/drm/radeon/radeon_atombios.c index 8cb4173365c3..6e733fdc3349 100644 --- a/drivers/gpu/drm/radeon/radeon_atombios.c +++ b/drivers/gpu/drm/radeon/radeon_atombios.c @@ -549,7 +549,6 @@ bool radeon_get_atom_connector_info_from_object_table(struct drm_device *dev) ATOM_I2C_RECORD *i2c_record; ATOM_HPD_INT_RECORD *hpd_record; ATOM_I2C_ID_CONFIG_ACCESS *i2c_config; - hpd.hpd = RADEON_HPD_NONE; while (record->ucRecordType > 0 && record-> @@ -590,7 +589,7 @@ bool radeon_get_atom_connector_info_from_object_table(struct drm_device *dev) } /* needed for aux chan transactions */ - ddc_bus.hpd_id = hpd.hpd ? (hpd.hpd - 1) : 0; + ddc_bus.hpd = hpd.hpd; conn_id = le16_to_cpu(path->usConnObjectId); diff --git a/drivers/gpu/drm/radeon/radeon_combios.c b/drivers/gpu/drm/radeon/radeon_combios.c index 93f18bbf744a..7b5e10d3e9c9 100644 --- a/drivers/gpu/drm/radeon/radeon_combios.c +++ b/drivers/gpu/drm/radeon/radeon_combios.c @@ -600,7 +600,7 @@ static struct radeon_i2c_bus_rec combios_setup_i2c_bus(struct radeon_device *rde } i2c.mm_i2c = false; i2c.i2c_id = 0; - i2c.hpd_id = 0; + i2c.hpd = RADEON_HPD_NONE; if (ddc_line) i2c.valid = true; @@ -2198,7 +2198,7 @@ bool radeon_get_legacy_connector_info_from_bios(struct drm_device *dev) ATOM_DEVICE_DFP1_SUPPORT); ddc_i2c = combios_setup_i2c_bus(rdev, RADEON_GPIO_DVI_DDC); - hpd.hpd = RADEON_HPD_NONE; + hpd.hpd = RADEON_HPD_1; radeon_add_legacy_connector(dev, 0, ATOM_DEVICE_CRT1_SUPPORT | diff --git a/drivers/gpu/drm/radeon/radeon_mode.h b/drivers/gpu/drm/radeon/radeon_mode.h index 71e1f0e7438d..67358baf28b2 100644 --- a/drivers/gpu/drm/radeon/radeon_mode.h +++ b/drivers/gpu/drm/radeon/radeon_mode.h @@ -66,6 +66,16 @@ enum radeon_tv_std { TV_STD_PAL_N, }; +enum radeon_hpd_id { + RADEON_HPD_1 = 0, + RADEON_HPD_2, + RADEON_HPD_3, + RADEON_HPD_4, + RADEON_HPD_5, + RADEON_HPD_6, + RADEON_HPD_NONE = 0xff, +}; + /* radeon gpio-based i2c * 1. "mask" reg and bits * grabs the gpio pins for software use @@ -85,7 +95,7 @@ struct radeon_i2c_bus_rec { /* id used by atom */ uint8_t i2c_id; /* id used by atom */ - uint8_t hpd_id; + enum radeon_hpd_id hpd; /* can be used with hw i2c engine */ bool hw_capable; /* uses multi-media i2c engine */ @@ -370,16 +380,6 @@ struct radeon_gpio_rec { u32 mask; }; -enum radeon_hpd_id { - RADEON_HPD_NONE = 0, - RADEON_HPD_1, - RADEON_HPD_2, - RADEON_HPD_3, - RADEON_HPD_4, - RADEON_HPD_5, - RADEON_HPD_6, -}; - struct radeon_hpd { enum radeon_hpd_id hpd; u8 plugged_state; -- cgit v1.2.3 From 669899878cfe0cd0c1fe60104f3d39b95a80e1d8 Mon Sep 17 00:00:00 2001 From: Dave Airlie Date: Wed, 19 May 2010 10:35:02 +1000 Subject: drm/radeon: fix hdmi offset bug reported by smatch. Reported-by: Dan Carpenter Signed-off-by: Dave Airlie --- drivers/gpu/drm/radeon/r600_hdmi.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/gpu/drm/radeon') diff --git a/drivers/gpu/drm/radeon/r600_hdmi.c b/drivers/gpu/drm/radeon/r600_hdmi.c index 40b1aca6d1f4..26b4bc9d89a5 100644 --- a/drivers/gpu/drm/radeon/r600_hdmi.c +++ b/drivers/gpu/drm/radeon/r600_hdmi.c @@ -539,7 +539,7 @@ void r600_hdmi_disable(struct drm_encoder *encoder) struct drm_device *dev = encoder->dev; struct radeon_device *rdev = dev->dev_private; struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder); - uint8_t offset; + uint32_t offset; if (ASIC_IS_DCE4(rdev)) return; -- cgit v1.2.3 From 45737447ed160faaba036c0709226bf9057f7b72 Mon Sep 17 00:00:00 2001 From: Alex Deucher Date: Thu, 20 May 2010 11:26:11 -0400 Subject: drm/radeon/kms: don't default display priority to high on rs4xx Seems to cause issues with the sound hardware. Fixes kernel bug 15982: https://bugzilla.kernel.org/show_bug.cgi?id=15982 Signed-off-by: Alex Deucher Cc: stable@kernel.org Signed-off-by: Dave Airlie --- drivers/gpu/drm/radeon/radeon_display.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) (limited to 'drivers/gpu/drm/radeon') diff --git a/drivers/gpu/drm/radeon/radeon_display.c b/drivers/gpu/drm/radeon/radeon_display.c index da85cad1152b..1006549d1570 100644 --- a/drivers/gpu/drm/radeon/radeon_display.c +++ b/drivers/gpu/drm/radeon/radeon_display.c @@ -983,8 +983,11 @@ void radeon_update_display_priority(struct radeon_device *rdev) /* set display priority to high for r3xx, rv515 chips * this avoids flickering due to underflow to the * display controllers during heavy acceleration. + * Don't force high on rs4xx igp chips as it seems to + * affect the sound card. See kernel bug 15982. */ - if (ASIC_IS_R300(rdev) || (rdev->family == CHIP_RV515)) + if ((ASIC_IS_R300(rdev) || (rdev->family == CHIP_RV515)) && + !(rdev->flags & RADEON_IS_IGP)) rdev->disp_priority = 2; else rdev->disp_priority = 0; -- cgit v1.2.3 From 365048ff7f977c5983d67b63c47502c5964840e9 Mon Sep 17 00:00:00 2001 From: Michel Dänzer Date: Wed, 19 May 2010 12:46:22 +0200 Subject: drm/radeon: AGP memory is only I/O if the aperture can be mapped by the CPU. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Fixes AGP initialization failure with Apple UniNorth bridges due to trying to ioremap() normal RAM. Signed-off-by: Michel Dänzer Signed-off-by: Dave Airlie --- drivers/gpu/drm/radeon/radeon_ttm.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/gpu/drm/radeon') diff --git a/drivers/gpu/drm/radeon/radeon_ttm.c b/drivers/gpu/drm/radeon/radeon_ttm.c index 3aa3a65800ab..e9918d88f5b0 100644 --- a/drivers/gpu/drm/radeon/radeon_ttm.c +++ b/drivers/gpu/drm/radeon/radeon_ttm.c @@ -451,7 +451,7 @@ static int radeon_ttm_io_mem_reserve(struct ttm_bo_device *bdev, struct ttm_mem_ /* RADEON_IS_AGP is set only if AGP is active */ mem->bus.offset = mem->mm_node->start << PAGE_SHIFT; mem->bus.base = rdev->mc.agp_base; - mem->bus.is_iomem = true; + mem->bus.is_iomem = !rdev->ddev->agp->cant_use_aperture; } #endif break; -- cgit v1.2.3 From e86527533586259875f08fccb173e3347046cc3f Mon Sep 17 00:00:00 2001 From: Jerome Glisse Date: Wed, 19 May 2010 16:05:50 +0200 Subject: drm/radeon/kms: record object that have been list reserved list reservation was too optimistic about ttm object reservation and could think that an object reserved by some other process as reserved by the list reservation which was false. Thus when unreserving the list it might unreserve object that it didn't reserved in the list. Sorry if it's hard to follow but this kind of things are just causing headheck. Signed-off-by: Jerome Glisse Signed-off-by: Dave Airlie --- drivers/gpu/drm/radeon/radeon.h | 1 + drivers/gpu/drm/radeon/radeon_object.c | 6 +++++- 2 files changed, 6 insertions(+), 1 deletion(-) (limited to 'drivers/gpu/drm/radeon') diff --git a/drivers/gpu/drm/radeon/radeon.h b/drivers/gpu/drm/radeon/radeon.h index 5c9ce2beaca3..66a37fb75839 100644 --- a/drivers/gpu/drm/radeon/radeon.h +++ b/drivers/gpu/drm/radeon/radeon.h @@ -261,6 +261,7 @@ struct radeon_bo_list { unsigned rdomain; unsigned wdomain; u32 tiling_flags; + bool reserved; }; /* diff --git a/drivers/gpu/drm/radeon/radeon_object.c b/drivers/gpu/drm/radeon/radeon_object.c index a8d18bcae7db..d5b9373ce06c 100644 --- a/drivers/gpu/drm/radeon/radeon_object.c +++ b/drivers/gpu/drm/radeon/radeon_object.c @@ -301,6 +301,7 @@ int radeon_bo_list_reserve(struct list_head *head) r = radeon_bo_reserve(lobj->bo, false); if (unlikely(r != 0)) return r; + lobj->reserved = true; } return 0; } @@ -311,7 +312,7 @@ void radeon_bo_list_unreserve(struct list_head *head) list_for_each_entry(lobj, head, list) { /* only unreserve object we successfully reserved */ - if (radeon_bo_is_reserved(lobj->bo)) + if (lobj->reserved && radeon_bo_is_reserved(lobj->bo)) radeon_bo_unreserve(lobj->bo); } } @@ -322,6 +323,9 @@ int radeon_bo_list_validate(struct list_head *head) struct radeon_bo *bo; int r; + list_for_each_entry(lobj, head, list) { + lobj->reserved = false; + } r = radeon_bo_list_reserve(head); if (unlikely(r != 0)) { return r; -- cgit v1.2.3 From 5d9b7e2d2db95549aeab129c95d588236137a4c8 Mon Sep 17 00:00:00 2001 From: Dave Airlie Date: Fri, 21 May 2010 15:41:20 +1000 Subject: drm/radeon: fix power supply kconfig interaction. radeon needs power supply to get correct PM info so select it at the radeon level not at the kms option. Signed-off-by: Dave Airlie --- drivers/gpu/drm/Kconfig | 1 + drivers/gpu/drm/radeon/Kconfig | 1 - 2 files changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/gpu/drm/radeon') diff --git a/drivers/gpu/drm/Kconfig b/drivers/gpu/drm/Kconfig index 2583ddfcc33e..88910e5a2c77 100644 --- a/drivers/gpu/drm/Kconfig +++ b/drivers/gpu/drm/Kconfig @@ -60,6 +60,7 @@ config DRM_RADEON select FW_LOADER select DRM_KMS_HELPER select DRM_TTM + select POWER_SUPPLY help Choose this option if you have an ATI Radeon graphics card. There are both PCI and AGP versions. You don't need to choose this to diff --git a/drivers/gpu/drm/radeon/Kconfig b/drivers/gpu/drm/radeon/Kconfig index 80c5b3ea28b4..1c02d23f6fcc 100644 --- a/drivers/gpu/drm/radeon/Kconfig +++ b/drivers/gpu/drm/radeon/Kconfig @@ -1,7 +1,6 @@ config DRM_RADEON_KMS bool "Enable modesetting on radeon by default - NEW DRIVER" depends on DRM_RADEON - depends on POWER_SUPPLY help Choose this option if you want kernel modesetting enabled by default. -- cgit v1.2.3 From b486787ee4797d6e42a9bd3a6f079385ad0f4472 Mon Sep 17 00:00:00 2001 From: Alex Deucher Date: Thu, 20 May 2010 18:44:49 -0400 Subject: drm/radeon/kms/pm/r600: select the mid clock mode for single head low profile This saves some more power at the expense of performance. Signed-off-by: Alex Deucher Signed-off-by: Dave Airlie --- drivers/gpu/drm/radeon/r600.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/gpu/drm/radeon') diff --git a/drivers/gpu/drm/radeon/r600.c b/drivers/gpu/drm/radeon/r600.c index 7ffc3892c652..44e96a2ae25a 100644 --- a/drivers/gpu/drm/radeon/r600.c +++ b/drivers/gpu/drm/radeon/r600.c @@ -430,7 +430,7 @@ void r600_pm_init_profile(struct radeon_device *rdev) rdev->pm.profiles[PM_PROFILE_LOW_SH_IDX].dpms_on_ps_idx = r600_pm_get_type_index(rdev, POWER_STATE_TYPE_BATTERY, 0); rdev->pm.profiles[PM_PROFILE_LOW_SH_IDX].dpms_off_cm_idx = 0; - rdev->pm.profiles[PM_PROFILE_LOW_SH_IDX].dpms_on_cm_idx = 2; + rdev->pm.profiles[PM_PROFILE_LOW_SH_IDX].dpms_on_cm_idx = 1; } else { rdev->pm.profiles[PM_PROFILE_LOW_SH_IDX].dpms_off_ps_idx = r600_pm_get_type_index(rdev, POWER_STATE_TYPE_PERFORMANCE, 0); -- cgit v1.2.3