atikms: RC13

git-svn-id: svn://kolibrios.org@3192 a494cfbc-eb01-0410-851d-a64ba20cac60
This commit is contained in:
Sergey Semyonov (Serge) 2013-01-22 15:16:44 +00:00
parent 5959abc989
commit 649c3b069e
53 changed files with 4665 additions and 1807 deletions

View File

@ -1485,6 +1485,7 @@ extern unsigned int drm_debug;
#if 0 #if 0
extern unsigned int drm_vblank_offdelay; extern unsigned int drm_vblank_offdelay;
extern unsigned int drm_timestamp_precision; extern unsigned int drm_timestamp_precision;
extern unsigned int drm_timestamp_monotonic;
extern struct class *drm_class; extern struct class *drm_class;
extern struct proc_dir_entry *drm_proc_root; extern struct proc_dir_entry *drm_proc_root;
@ -1652,6 +1653,8 @@ drm_gem_object_handle_unreference_unlocked(struct drm_gem_object *obj)
drm_gem_object_unreference_unlocked(obj); drm_gem_object_unreference_unlocked(obj);
} }
void drm_gem_free_mmap_offset(struct drm_gem_object *obj);
int drm_gem_create_mmap_offset(struct drm_gem_object *obj);
struct drm_gem_object *drm_gem_object_lookup(struct drm_device *dev, struct drm_gem_object *drm_gem_object_lookup(struct drm_device *dev,
struct drm_file *filp, struct drm_file *filp,

View File

@ -782,6 +782,7 @@ struct drm_mode_config {
/* output poll support */ /* output poll support */
bool poll_enabled; bool poll_enabled;
bool poll_running;
// struct delayed_work output_poll_work; // struct delayed_work output_poll_work;
/* pointers to standard properties */ /* pointers to standard properties */
@ -877,14 +878,14 @@ extern void drm_mode_remove(struct drm_connector *connector, struct drm_display_
extern void drm_mode_copy(struct drm_display_mode *dst, const struct drm_display_mode *src); extern void drm_mode_copy(struct drm_display_mode *dst, const struct drm_display_mode *src);
extern struct drm_display_mode *drm_mode_duplicate(struct drm_device *dev, extern struct drm_display_mode *drm_mode_duplicate(struct drm_device *dev,
const struct drm_display_mode *mode); const struct drm_display_mode *mode);
extern void drm_mode_debug_printmodeline(struct drm_display_mode *mode); extern void drm_mode_debug_printmodeline(const struct drm_display_mode *mode);
extern void drm_mode_config_init(struct drm_device *dev); extern void drm_mode_config_init(struct drm_device *dev);
extern void drm_mode_config_reset(struct drm_device *dev); extern void drm_mode_config_reset(struct drm_device *dev);
extern void drm_mode_config_cleanup(struct drm_device *dev); extern void drm_mode_config_cleanup(struct drm_device *dev);
extern void drm_mode_set_name(struct drm_display_mode *mode); extern void drm_mode_set_name(struct drm_display_mode *mode);
extern bool drm_mode_equal(struct drm_display_mode *mode1, struct drm_display_mode *mode2); extern bool drm_mode_equal(const struct drm_display_mode *mode1, const struct drm_display_mode *mode2);
extern int drm_mode_width(struct drm_display_mode *mode); extern int drm_mode_width(const struct drm_display_mode *mode);
extern int drm_mode_height(struct drm_display_mode *mode); extern int drm_mode_height(const struct drm_display_mode *mode);
/* for us by fb module */ /* for us by fb module */
extern int drm_mode_attachmode_crtc(struct drm_device *dev, extern int drm_mode_attachmode_crtc(struct drm_device *dev,
@ -909,12 +910,6 @@ extern void drm_mode_set_crtcinfo(struct drm_display_mode *p,
extern void drm_mode_connector_list_update(struct drm_connector *connector); extern void drm_mode_connector_list_update(struct drm_connector *connector);
extern int drm_mode_connector_update_edid_property(struct drm_connector *connector, extern int drm_mode_connector_update_edid_property(struct drm_connector *connector,
struct edid *edid); struct edid *edid);
extern int drm_connector_property_set_value(struct drm_connector *connector,
struct drm_property *property,
uint64_t value);
extern int drm_connector_property_get_value(struct drm_connector *connector,
struct drm_property *property,
uint64_t *value);
extern int drm_object_property_set_value(struct drm_mode_object *obj, extern int drm_object_property_set_value(struct drm_mode_object *obj,
struct drm_property *property, struct drm_property *property,
uint64_t val); uint64_t val);
@ -936,8 +931,6 @@ extern int drmfb_remove(struct drm_device *dev, struct drm_framebuffer *fb);
extern void drm_crtc_probe_connector_modes(struct drm_device *dev, int maxX, int maxY); extern void drm_crtc_probe_connector_modes(struct drm_device *dev, int maxX, int maxY);
extern bool drm_crtc_in_use(struct drm_crtc *crtc); extern bool drm_crtc_in_use(struct drm_crtc *crtc);
extern void drm_connector_attach_property(struct drm_connector *connector,
struct drm_property *property, uint64_t init_val);
extern void drm_object_attach_property(struct drm_mode_object *obj, extern void drm_object_attach_property(struct drm_mode_object *obj,
struct drm_property *property, struct drm_property *property,
uint64_t init_val); uint64_t init_val);
@ -1027,6 +1020,7 @@ extern int drm_mode_gamma_get_ioctl(struct drm_device *dev,
extern int drm_mode_gamma_set_ioctl(struct drm_device *dev, extern int drm_mode_gamma_set_ioctl(struct drm_device *dev,
void *data, struct drm_file *file_priv); void *data, struct drm_file *file_priv);
extern u8 *drm_find_cea_extension(struct edid *edid); extern u8 *drm_find_cea_extension(struct edid *edid);
extern u8 drm_match_cea_mode(struct drm_display_mode *to_match);
extern bool drm_detect_hdmi_monitor(struct edid *edid); extern bool drm_detect_hdmi_monitor(struct edid *edid);
extern bool drm_detect_monitor_audio(struct edid *edid); extern bool drm_detect_monitor_audio(struct edid *edid);
extern int drm_mode_page_flip_ioctl(struct drm_device *dev, extern int drm_mode_page_flip_ioctl(struct drm_device *dev,
@ -1043,6 +1037,7 @@ extern struct drm_display_mode *drm_gtf_mode_complex(struct drm_device *dev,
int GTF_2C, int GTF_K, int GTF_2J); int GTF_2C, int GTF_K, int GTF_2J);
extern int drm_add_modes_noedid(struct drm_connector *connector, extern int drm_add_modes_noedid(struct drm_connector *connector,
int hdisplay, int vdisplay); int hdisplay, int vdisplay);
extern uint8_t drm_mode_cea_vic(const struct drm_display_mode *mode);
extern int drm_edid_header_is_valid(const u8 *raw_edid); extern int drm_edid_header_is_valid(const u8 *raw_edid);
extern bool drm_edid_block_valid(u8 *raw_edid, int block, bool print_bad_edid); extern bool drm_edid_block_valid(u8 *raw_edid, int block, bool print_bad_edid);

View File

@ -137,6 +137,8 @@ extern bool drm_helper_encoder_in_use(struct drm_encoder *encoder);
extern void drm_helper_connector_dpms(struct drm_connector *connector, int mode); extern void drm_helper_connector_dpms(struct drm_connector *connector, int mode);
extern void drm_helper_move_panel_connectors_to_head(struct drm_device *);
extern int drm_helper_mode_fill_fb_struct(struct drm_framebuffer *fb, extern int drm_helper_mode_fill_fb_struct(struct drm_framebuffer *fb,
struct drm_mode_fb_cmd2 *mode_cmd); struct drm_mode_fb_cmd2 *mode_cmd);
@ -162,6 +164,7 @@ 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_init(struct drm_device *dev);
extern void drm_kms_helper_poll_fini(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); extern void drm_helper_hpd_irq_event(struct drm_device *dev);
extern void drm_kms_helper_hotplug_event(struct drm_device *dev);
extern void drm_kms_helper_poll_disable(struct drm_device *dev); extern void drm_kms_helper_poll_disable(struct drm_device *dev);
extern void drm_kms_helper_poll_enable(struct drm_device *dev); extern void drm_kms_helper_poll_enable(struct drm_device *dev);

View File

@ -25,6 +25,7 @@
#include <linux/types.h> #include <linux/types.h>
#include <linux/i2c.h> #include <linux/i2c.h>
#include <linux/delay.h>
/* /*
* Unless otherwise noted, all values are from the DP 1.1a spec. Note that * Unless otherwise noted, all values are from the DP 1.1a spec. Note that
@ -311,6 +312,14 @@
#define MODE_I2C_READ 4 #define MODE_I2C_READ 4
#define MODE_I2C_STOP 8 #define MODE_I2C_STOP 8
/**
* struct i2c_algo_dp_aux_data - driver interface structure for i2c over dp
* aux algorithm
* @running: set by the algo indicating whether an i2c is ongoing or whether
* the i2c bus is quiescent
* @address: i2c target address for the currently ongoing transfer
* @aux_ch: driver callback to transfer a single byte of the i2c payload
*/
struct i2c_algo_dp_aux_data { struct i2c_algo_dp_aux_data {
bool running; bool running;
u16 address; u16 address;
@ -322,4 +331,34 @@ struct i2c_algo_dp_aux_data {
int int
i2c_dp_aux_add_bus(struct i2c_adapter *adapter); i2c_dp_aux_add_bus(struct i2c_adapter *adapter);
#define DP_LINK_STATUS_SIZE 6
bool drm_dp_channel_eq_ok(u8 link_status[DP_LINK_STATUS_SIZE],
int lane_count);
bool drm_dp_clock_recovery_ok(u8 link_status[DP_LINK_STATUS_SIZE],
int lane_count);
u8 drm_dp_get_adjust_request_voltage(u8 link_status[DP_LINK_STATUS_SIZE],
int lane);
u8 drm_dp_get_adjust_request_pre_emphasis(u8 link_status[DP_LINK_STATUS_SIZE],
int lane);
#define DP_RECEIVER_CAP_SIZE 0xf
void drm_dp_link_train_clock_recovery_delay(u8 dpcd[DP_RECEIVER_CAP_SIZE]);
void drm_dp_link_train_channel_eq_delay(u8 dpcd[DP_RECEIVER_CAP_SIZE]);
u8 drm_dp_link_rate_to_bw_code(int link_rate);
int drm_dp_bw_code_to_link_rate(u8 link_bw);
static inline int
drm_dp_max_link_rate(u8 dpcd[DP_RECEIVER_CAP_SIZE])
{
return drm_dp_bw_code_to_link_rate(dpcd[DP_MAX_LINK_RATE]);
}
static inline u8
drm_dp_max_lane_count(u8 dpcd[DP_RECEIVER_CAP_SIZE])
{
return dpcd[DP_MAX_LANE_COUNT] & DP_MAX_LANE_COUNT_MASK;
}
#endif /* _DRM_DP_HELPER_H_ */ #endif /* _DRM_DP_HELPER_H_ */

View File

@ -61,5 +61,19 @@ extern int drm_ht_remove_key(struct drm_open_hash *ht, unsigned long key);
extern int drm_ht_remove_item(struct drm_open_hash *ht, struct drm_hash_item *item); extern int drm_ht_remove_item(struct drm_open_hash *ht, struct drm_hash_item *item);
extern void drm_ht_remove(struct drm_open_hash *ht); extern void drm_ht_remove(struct drm_open_hash *ht);
/*
* RCU-safe interface
*
* The user of this API needs to make sure that two or more instances of the
* hash table manipulation functions are never run simultaneously.
* The lookup function drm_ht_find_item_rcu may, however, run simultaneously
* with any of the manipulation functions as long as it's called from within
* an RCU read-locked section.
*/
#define drm_ht_insert_item_rcu drm_ht_insert_item
#define drm_ht_just_insert_please_rcu drm_ht_just_insert_please
#define drm_ht_remove_key_rcu drm_ht_remove_key
#define drm_ht_remove_item_rcu drm_ht_remove_item
#define drm_ht_find_item_rcu drm_ht_find_item
#endif #endif

View File

@ -70,7 +70,7 @@ struct drm_mm {
unsigned long scan_color; unsigned long scan_color;
unsigned long scan_size; unsigned long scan_size;
unsigned long scan_hit_start; unsigned long scan_hit_start;
unsigned scan_hit_size; unsigned long scan_hit_end;
unsigned scanned_blocks; unsigned scanned_blocks;
unsigned long scan_start; unsigned long scan_start;
unsigned long scan_end; unsigned long scan_end;
@ -158,12 +158,29 @@ static inline struct drm_mm_node *drm_mm_get_block_atomic_range(
return drm_mm_get_block_range_generic(parent, size, alignment, 0, return drm_mm_get_block_range_generic(parent, size, alignment, 0,
start, end, 1); start, end, 1);
} }
extern int drm_mm_insert_node(struct drm_mm *mm, struct drm_mm_node *node,
unsigned long size, unsigned alignment); extern int drm_mm_insert_node(struct drm_mm *mm,
struct drm_mm_node *node,
unsigned long size,
unsigned alignment);
extern int drm_mm_insert_node_in_range(struct drm_mm *mm, extern int drm_mm_insert_node_in_range(struct drm_mm *mm,
struct drm_mm_node *node, struct drm_mm_node *node,
unsigned long size, unsigned alignment, unsigned long size,
unsigned long start, unsigned long end); unsigned alignment,
unsigned long start,
unsigned long end);
extern int drm_mm_insert_node_generic(struct drm_mm *mm,
struct drm_mm_node *node,
unsigned long size,
unsigned alignment,
unsigned long color);
extern int drm_mm_insert_node_in_range_generic(struct drm_mm *mm,
struct drm_mm_node *node,
unsigned long size,
unsigned alignment,
unsigned long color,
unsigned long start,
unsigned long end);
extern void drm_mm_put_block(struct drm_mm_node *cur); extern void drm_mm_put_block(struct drm_mm_node *cur);
extern void drm_mm_remove_node(struct drm_mm_node *node); extern void drm_mm_remove_node(struct drm_mm_node *node);
extern void drm_mm_replace_node(struct drm_mm_node *old, struct drm_mm_node *new); extern void drm_mm_replace_node(struct drm_mm_node *old, struct drm_mm_node *new);

View File

@ -5,7 +5,7 @@
struct agp_bridge_data; struct agp_bridge_data;
const struct intel_gtt { struct intel_gtt {
/* Size of memory reserved for graphics by the BIOS */ /* Size of memory reserved for graphics by the BIOS */
unsigned int stolen_size; unsigned int stolen_size;
/* Total number of gtt entries. */ /* Total number of gtt entries. */

View File

@ -408,4 +408,7 @@ union i2c_smbus_data {
#define I2C_SMBUS_BLOCK_PROC_CALL 7 /* SMBus 2.0 */ #define I2C_SMBUS_BLOCK_PROC_CALL 7 /* SMBus 2.0 */
#define I2C_SMBUS_I2C_BLOCK_DATA 8 #define I2C_SMBUS_I2C_BLOCK_DATA 8
#define i2c_add_adapter(x) 0
#define i2c_del_adapter(x)
#endif /* _LINUX_I2C_H */ #endif /* _LINUX_I2C_H */

View File

@ -1,6 +1,8 @@
#ifndef _LINUX_WAIT_H #ifndef _LINUX_WAIT_H
#define _LINUX_WAIT_H #define _LINUX_WAIT_H
#include <syscall.h>
typedef struct __wait_queue wait_queue_t; typedef struct __wait_queue wait_queue_t;
typedef struct __wait_queue_head wait_queue_head_t; typedef struct __wait_queue_head wait_queue_head_t;
@ -68,6 +70,8 @@ do{ \
__ret; \ __ret; \
}) })
#define wait_event_interruptible_timeout(wq, condition, timeout) \
wait_event_timeout(wq, condition, timeout)
#define wait_event(wq, condition) \ #define wait_event(wq, condition) \

View File

@ -391,10 +391,8 @@ void drm_crtc_cleanup(struct drm_crtc *crtc)
{ {
struct drm_device *dev = crtc->dev; struct drm_device *dev = crtc->dev;
if (crtc->gamma_store) {
kfree(crtc->gamma_store); kfree(crtc->gamma_store);
crtc->gamma_store = NULL; crtc->gamma_store = NULL;
}
drm_mode_object_put(dev, &crtc->base); drm_mode_object_put(dev, &crtc->base);
list_del(&crtc->head); list_del(&crtc->head);
@ -476,16 +474,17 @@ int drm_connector_init(struct drm_device *dev,
INIT_LIST_HEAD(&connector->probed_modes); INIT_LIST_HEAD(&connector->probed_modes);
INIT_LIST_HEAD(&connector->modes); INIT_LIST_HEAD(&connector->modes);
connector->edid_blob_ptr = NULL; connector->edid_blob_ptr = NULL;
connector->status = connector_status_unknown;
list_add_tail(&connector->head, &dev->mode_config.connector_list); list_add_tail(&connector->head, &dev->mode_config.connector_list);
dev->mode_config.num_connector++; dev->mode_config.num_connector++;
if (connector_type != DRM_MODE_CONNECTOR_VIRTUAL) if (connector_type != DRM_MODE_CONNECTOR_VIRTUAL)
drm_connector_attach_property(connector, drm_object_attach_property(&connector->base,
dev->mode_config.edid_property, dev->mode_config.edid_property,
0); 0);
drm_connector_attach_property(connector, drm_object_attach_property(&connector->base,
dev->mode_config.dpms_property, 0); dev->mode_config.dpms_property, 0);
out: out:
@ -2199,13 +2198,21 @@ static int framebuffer_check(const struct drm_mode_fb_cmd2 *r)
for (i = 0; i < num_planes; i++) { for (i = 0; i < num_planes; i++) {
unsigned int width = r->width / (i != 0 ? hsub : 1); unsigned int width = r->width / (i != 0 ? hsub : 1);
unsigned int height = r->height / (i != 0 ? vsub : 1);
unsigned int cpp = drm_format_plane_cpp(r->pixel_format, i);
if (!r->handles[i]) { if (!r->handles[i]) {
DRM_DEBUG_KMS("no buffer object handle for plane %d\n", i); DRM_DEBUG_KMS("no buffer object handle for plane %d\n", i);
return -EINVAL; return -EINVAL;
} }
if (r->pitches[i] < drm_format_plane_cpp(r->pixel_format, i) * width) { if ((uint64_t) width * cpp > UINT_MAX)
return -ERANGE;
if ((uint64_t) height * r->pitches[i] + r->offsets[i] > UINT_MAX)
return -ERANGE;
if (r->pitches[i] < width * cpp) {
DRM_DEBUG_KMS("bad pitch %u for plane %d\n", r->pitches[i], i); DRM_DEBUG_KMS("bad pitch %u for plane %d\n", r->pitches[i], i);
return -EINVAL; return -EINVAL;
} }
@ -2242,6 +2249,11 @@ int drm_mode_addfb2(struct drm_device *dev,
if (!drm_core_check_feature(dev, DRIVER_MODESET)) if (!drm_core_check_feature(dev, DRIVER_MODESET))
return -EINVAL; return -EINVAL;
if (r->flags & ~DRM_MODE_FB_INTERLACED) {
DRM_DEBUG_KMS("bad framebuffer flags 0x%08x\n", r->flags);
return -EINVAL;
}
if ((config->min_width > r->width) || (r->width > config->max_width)) { if ((config->min_width > r->width) || (r->width > config->max_width)) {
DRM_DEBUG_KMS("bad framebuffer width %d, should be >= %d && <= %d\n", DRM_DEBUG_KMS("bad framebuffer width %d, should be >= %d && <= %d\n",
r->width, config->min_width, config->max_width); r->width, config->min_width, config->max_width);
@ -2839,27 +2851,6 @@ void drm_property_destroy(struct drm_device *dev, struct drm_property *property)
} }
EXPORT_SYMBOL(drm_property_destroy); EXPORT_SYMBOL(drm_property_destroy);
void drm_connector_attach_property(struct drm_connector *connector,
struct drm_property *property, uint64_t init_val)
{
drm_object_attach_property(&connector->base, property, init_val);
}
EXPORT_SYMBOL(drm_connector_attach_property);
int drm_connector_property_set_value(struct drm_connector *connector,
struct drm_property *property, uint64_t value)
{
return drm_object_property_set_value(&connector->base, property, value);
}
EXPORT_SYMBOL(drm_connector_property_set_value);
int drm_connector_property_get_value(struct drm_connector *connector,
struct drm_property *property, uint64_t *val)
{
return drm_object_property_get_value(&connector->base, property, val);
}
EXPORT_SYMBOL(drm_connector_property_get_value);
void drm_object_attach_property(struct drm_mode_object *obj, void drm_object_attach_property(struct drm_mode_object *obj,
struct drm_property *property, struct drm_property *property,
uint64_t init_val) uint64_t init_val)
@ -3100,15 +3091,17 @@ int drm_mode_connector_update_edid_property(struct drm_connector *connector,
/* Delete edid, when there is none. */ /* Delete edid, when there is none. */
if (!edid) { if (!edid) {
connector->edid_blob_ptr = NULL; connector->edid_blob_ptr = NULL;
ret = drm_connector_property_set_value(connector, dev->mode_config.edid_property, 0); ret = drm_object_property_set_value(&connector->base, dev->mode_config.edid_property, 0);
return ret; return ret;
} }
size = EDID_LENGTH * (1 + edid->extensions); size = EDID_LENGTH * (1 + edid->extensions);
connector->edid_blob_ptr = drm_property_create_blob(connector->dev, connector->edid_blob_ptr = drm_property_create_blob(connector->dev,
size, edid); size, edid);
if (!connector->edid_blob_ptr)
return -EINVAL;
ret = drm_connector_property_set_value(connector, ret = drm_object_property_set_value(&connector->base,
dev->mode_config.edid_property, dev->mode_config.edid_property,
connector->edid_blob_ptr->base.id); connector->edid_blob_ptr->base.id);
@ -3135,7 +3128,7 @@ static int drm_mode_connector_set_obj_prop(struct drm_mode_object *obj,
/* store the property value if successful */ /* store the property value if successful */
if (!ret) if (!ret)
drm_connector_property_set_value(connector, property, value); drm_object_property_set_value(&connector->base, property, value);
return ret; return ret;
} }
@ -3453,9 +3446,12 @@ void drm_mode_config_reset(struct drm_device *dev)
if (encoder->funcs->reset) if (encoder->funcs->reset)
encoder->funcs->reset(encoder); encoder->funcs->reset(encoder);
list_for_each_entry(connector, &dev->mode_config.connector_list, head) list_for_each_entry(connector, &dev->mode_config.connector_list, head) {
connector->status = connector_status_unknown;
if (connector->funcs->reset) if (connector->funcs->reset)
connector->funcs->reset(connector); connector->funcs->reset(connector);
}
} }
EXPORT_SYMBOL(drm_mode_config_reset); EXPORT_SYMBOL(drm_mode_config_reset);
/* /*

View File

@ -39,6 +39,35 @@
#include <drm/drm_fb_helper.h> #include <drm/drm_fb_helper.h>
#include <drm/drm_edid.h> #include <drm/drm_edid.h>
/**
* drm_helper_move_panel_connectors_to_head() - move panels to the front in the
* connector list
* @dev: drm device to operate on
*
* Some userspace presumes that the first connected connector is the main
* display, where it's supposed to display e.g. the login screen. For
* laptops, this should be the main panel. Use this function to sort all
* (eDP/LVDS) panels to the front of the connector list, instead of
* painstakingly trying to initialize them in the right order.
*/
void drm_helper_move_panel_connectors_to_head(struct drm_device *dev)
{
struct drm_connector *connector, *tmp;
struct list_head panel_list;
INIT_LIST_HEAD(&panel_list);
list_for_each_entry_safe(connector, tmp,
&dev->mode_config.connector_list, head) {
if (connector->connector_type == DRM_MODE_CONNECTOR_LVDS ||
connector->connector_type == DRM_MODE_CONNECTOR_eDP)
list_move_tail(&connector->head, &panel_list);
}
list_splice(&panel_list, &dev->mode_config.connector_list);
}
EXPORT_SYMBOL(drm_helper_move_panel_connectors_to_head);
static bool drm_kms_helper_poll = true; static bool drm_kms_helper_poll = true;
static void drm_mode_validate_flag(struct drm_connector *connector, static void drm_mode_validate_flag(struct drm_connector *connector,
@ -63,22 +92,21 @@ static void drm_mode_validate_flag(struct drm_connector *connector,
/** /**
* drm_helper_probe_single_connector_modes - get complete set of display modes * drm_helper_probe_single_connector_modes - get complete set of display modes
* @dev: DRM device * @connector: connector to probe
* @maxX: max width for modes * @maxX: max width for modes
* @maxY: max height for modes * @maxY: max height for modes
* *
* LOCKING: * LOCKING:
* Caller must hold mode config lock. * Caller must hold mode config lock.
* *
* Based on @dev's mode_config layout, scan all the connectors and try to detect * Based on the helper callbacks implemented by @connector try to detect all
* modes on them. Modes will first be added to the connector's probed_modes * valid modes. Modes will first be added to the connector's probed_modes list,
* list, then culled (based on validity and the @maxX, @maxY parameters) and * then culled (based on validity and the @maxX, @maxY parameters) and put into
* put into the normal modes list. * the normal modes list.
* *
* Intended to be used either at bootup time or when major configuration * Intended to be use as a generic implementation of the ->probe() @connector
* changes have occurred. * callback for drivers that use the crtc helpers for output mode filtering and
* * detection.
* FIXME: take into account monitor limits
* *
* RETURNS: * RETURNS:
* Number of modes found on @connector. * Number of modes found on @connector.
@ -325,17 +353,24 @@ drm_crtc_prepare_encoders(struct drm_device *dev)
} }
/** /**
* drm_crtc_set_mode - set a mode * drm_crtc_helper_set_mode - internal helper to set a mode
* @crtc: CRTC to program * @crtc: CRTC to program
* @mode: mode to use * @mode: mode to use
* @x: width of mode * @x: horizontal offset into the surface
* @y: height of mode * @y: vertical offset into the surface
* @old_fb: old framebuffer, for cleanup
* *
* LOCKING: * LOCKING:
* Caller must hold mode config lock. * Caller must hold mode config lock.
* *
* Try to set @mode on @crtc. Give @crtc and its associated connectors a chance * Try to set @mode on @crtc. Give @crtc and its associated connectors a chance
* to fixup or reject the mode prior to trying to set it. * to fixup or reject the mode prior to trying to set it. This is an internal
* helper that drivers could e.g. use to update properties that require the
* entire output pipe to be disabled and re-enabled in a new configuration. For
* example for changing whether audio is enabled on a hdmi link or for changing
* panel fitter or dither attributes. It is also called by the
* drm_crtc_helper_set_config() helper function to drive the mode setting
* sequence.
* *
* RETURNS: * RETURNS:
* True if the mode was set successfully, or false otherwise. * True if the mode was set successfully, or false otherwise.
@ -357,14 +392,10 @@ bool drm_crtc_helper_set_mode(struct drm_crtc *crtc,
if (!crtc->enabled) if (!crtc->enabled)
return true; return true;
printf("crtc->enabled\n");
adjusted_mode = drm_mode_duplicate(dev, mode); adjusted_mode = drm_mode_duplicate(dev, mode);
if (!adjusted_mode) if (!adjusted_mode)
return false; return false;
printf("adjusted_mode\n");
saved_hwmode = crtc->hwmode; saved_hwmode = crtc->hwmode;
saved_mode = crtc->mode; saved_mode = crtc->mode;
saved_x = crtc->x; saved_x = crtc->x;
@ -393,9 +424,6 @@ bool drm_crtc_helper_set_mode(struct drm_crtc *crtc,
} }
} }
printf("list_for_each_entry\n");
printf("mode_fixup %x\n", crtc_funcs->mode_fixup);
if (!(ret = crtc_funcs->mode_fixup(crtc, mode, adjusted_mode))) { if (!(ret = crtc_funcs->mode_fixup(crtc, mode, adjusted_mode))) {
DRM_DEBUG_KMS("CRTC fixup failed\n"); DRM_DEBUG_KMS("CRTC fixup failed\n");
goto done; goto done;
@ -498,20 +526,19 @@ drm_crtc_helper_disable(struct drm_crtc *crtc)
/** /**
* drm_crtc_helper_set_config - set a new config from userspace * drm_crtc_helper_set_config - set a new config from userspace
* @crtc: CRTC to setup * @set: mode set configuration
* @crtc_info: user provided configuration
* @new_mode: new mode to set
* @connector_set: set of connectors for the new config
* @fb: new framebuffer
* *
* LOCKING: * LOCKING:
* Caller must hold mode config lock. * Caller must hold mode config lock.
* *
* Setup a new configuration, provided by the user in @crtc_info, and enable * Setup a new configuration, provided by the upper layers (either an ioctl call
* it. * from userspace or internally e.g. from the fbdev suppport code) in @set, and
* enable it. This is the main helper functions for drivers that implement
* kernel mode setting with the crtc helper functions and the assorted
* ->prepare(), ->modeset() and ->commit() helper callbacks.
* *
* RETURNS: * RETURNS:
* Zero. (FIXME) * Returns 0 on success, -ERRNO on failure.
*/ */
int drm_crtc_helper_set_config(struct drm_mode_set *set) int drm_crtc_helper_set_config(struct drm_mode_set *set)
{ {
@ -807,12 +834,14 @@ static int drm_helper_choose_crtc_dpms(struct drm_crtc *crtc)
} }
/** /**
* drm_helper_connector_dpms * drm_helper_connector_dpms() - connector dpms helper implementation
* @connector affected connector * @connector: affected connector
* @mode DPMS mode * @mode: DPMS mode
* *
* Calls the low-level connector DPMS function, then * This is the main helper function provided by the crtc helper framework for
* calls appropriate encoder and crtc DPMS functions as well * implementing the DPMS connector attribute. It computes the new desired DPMS
* state for all encoders and crtcs in the output mesh and calls the ->dpms()
* callback provided by the driver appropriately.
*/ */
void drm_helper_connector_dpms(struct drm_connector *connector, int mode) void drm_helper_connector_dpms(struct drm_connector *connector, int mode)
{ {
@ -942,20 +971,22 @@ static void output_poll_execute(struct work_struct *work)
mutex_lock(&dev->mode_config.mutex); mutex_lock(&dev->mode_config.mutex);
list_for_each_entry(connector, &dev->mode_config.connector_list, head) { list_for_each_entry(connector, &dev->mode_config.connector_list, head) {
/* if this is HPD or polled don't check it - /* Ignore forced connectors. */
TV out for instance */ if (connector->force)
if (!connector->polled) continue;
/* Ignore HPD capable connectors and connectors where we don't
* want any hotplug detection at all for polling. */
if (!connector->polled || connector->polled == DRM_CONNECTOR_POLL_HPD)
continue; continue;
else if (connector->polled & (DRM_CONNECTOR_POLL_CONNECT | DRM_CONNECTOR_POLL_DISCONNECT))
repoll = true; repoll = true;
old_status = connector->status; old_status = connector->status;
/* if we are connected and don't want to poll for disconnect /* if we are connected and don't want to poll for disconnect
skip it */ skip it */
if (old_status == connector_status_connected && if (old_status == connector_status_connected &&
!(connector->polled & DRM_CONNECTOR_POLL_DISCONNECT) && !(connector->polled & DRM_CONNECTOR_POLL_DISCONNECT))
!(connector->polled & DRM_CONNECTOR_POLL_HPD))
continue; continue;
connector->status = connector->funcs->detect(connector, false); connector->status = connector->funcs->detect(connector, false);
@ -969,12 +1000,8 @@ static void output_poll_execute(struct work_struct *work)
mutex_unlock(&dev->mode_config.mutex); mutex_unlock(&dev->mode_config.mutex);
if (changed) { if (changed)
/* send a uevent + call fbdev */ drm_kms_helper_hotplug_event(dev);
drm_sysfs_hotplug_event(dev);
if (dev->mode_config.funcs->output_poll_changed)
dev->mode_config.funcs->output_poll_changed(dev);
}
if (repoll) if (repoll)
schedule_delayed_work(delayed_work, DRM_OUTPUT_POLL_PERIOD); schedule_delayed_work(delayed_work, DRM_OUTPUT_POLL_PERIOD);
@ -997,7 +1024,8 @@ void drm_kms_helper_poll_enable(struct drm_device *dev)
return; return;
list_for_each_entry(connector, &dev->mode_config.connector_list, head) { list_for_each_entry(connector, &dev->mode_config.connector_list, head) {
if (connector->polled) if (connector->polled & (DRM_CONNECTOR_POLL_CONNECT |
DRM_CONNECTOR_POLL_DISCONNECT))
poll = true; poll = true;
} }
@ -1023,13 +1051,35 @@ EXPORT_SYMBOL(drm_kms_helper_poll_fini);
void drm_helper_hpd_irq_event(struct drm_device *dev) void drm_helper_hpd_irq_event(struct drm_device *dev)
{ {
struct drm_connector *connector;
enum drm_connector_status old_status;
bool changed = false;
if (!dev->mode_config.poll_enabled) if (!dev->mode_config.poll_enabled)
return; return;
/* kill timer and schedule immediate execution, this doesn't block */ mutex_lock(&dev->mode_config.mutex);
cancel_delayed_work(&dev->mode_config.output_poll_work); list_for_each_entry(connector, &dev->mode_config.connector_list, head) {
if (drm_kms_helper_poll)
schedule_delayed_work(&dev->mode_config.output_poll_work, 0); /* Only handle HPD capable connectors. */
if (!(connector->polled & DRM_CONNECTOR_POLL_HPD))
continue;
old_status = connector->status;
connector->status = connector->funcs->detect(connector, false);
DRM_DEBUG_KMS("[CONNECTOR:%d:%s] status updated from %d to %d\n",
connector->base.id,
drm_get_connector_name(connector),
old_status, connector->status);
if (old_status != connector->status)
changed = true;
}
mutex_unlock(&dev->mode_config.mutex);
if (changed)
drm_kms_helper_hotplug_event(dev);
} }
EXPORT_SYMBOL(drm_helper_hpd_irq_event); EXPORT_SYMBOL(drm_helper_hpd_irq_event);

View File

@ -30,6 +30,15 @@
#include <drm/drm_dp_helper.h> #include <drm/drm_dp_helper.h>
#include <drm/drmP.h> #include <drm/drmP.h>
/**
* DOC: dp helpers
*
* These functions contain some common logic and helpers at various abstraction
* levels to deal with Display Port sink devices and related things like DP aux
* channel transfers, EDID reading over DP aux channels, decoding certain DPCD
* blocks, ...
*/
/* Run a single AUX_CH I2C transaction, writing/reading data as necessary */ /* Run a single AUX_CH I2C transaction, writing/reading data as necessary */
static int static int
i2c_algo_dp_aux_transaction(struct i2c_adapter *adapter, int mode, i2c_algo_dp_aux_transaction(struct i2c_adapter *adapter, int mode,
@ -182,7 +191,6 @@ i2c_dp_aux_reset_bus(struct i2c_adapter *adapter)
{ {
(void) i2c_algo_dp_aux_address(adapter, 0, false); (void) i2c_algo_dp_aux_address(adapter, 0, false);
(void) i2c_algo_dp_aux_stop(adapter, false); (void) i2c_algo_dp_aux_stop(adapter, false);
} }
static int static int
@ -194,6 +202,18 @@ i2c_dp_aux_prepare_bus(struct i2c_adapter *adapter)
return 0; return 0;
} }
/**
* i2c_dp_aux_add_bus() - register an i2c adapter using the aux ch helper
* @adapter: i2c adapter to register
*
* This registers an i2c adapater that uses dp aux channel as it's underlaying
* transport. The driver needs to fill out the &i2c_algo_dp_aux_data structure
* and store it in the algo_data member of the @adapter argument. This will be
* used by the i2c over dp aux algorithm to drive the hardware.
*
* RETURNS:
* 0 on success, -ERRNO on failure.
*/
int int
i2c_dp_aux_add_bus(struct i2c_adapter *adapter) i2c_dp_aux_add_bus(struct i2c_adapter *adapter)
{ {
@ -202,7 +222,127 @@ i2c_dp_aux_add_bus(struct i2c_adapter *adapter)
error = i2c_dp_aux_prepare_bus(adapter); error = i2c_dp_aux_prepare_bus(adapter);
if (error) if (error)
return error; return error;
// error = i2c_add_adapter(adapter); error = i2c_add_adapter(adapter);
return error; return error;
} }
EXPORT_SYMBOL(i2c_dp_aux_add_bus); EXPORT_SYMBOL(i2c_dp_aux_add_bus);
/* Helpers for DP link training */
static u8 dp_link_status(u8 link_status[DP_LINK_STATUS_SIZE], int r)
{
return link_status[r - DP_LANE0_1_STATUS];
}
static u8 dp_get_lane_status(u8 link_status[DP_LINK_STATUS_SIZE],
int lane)
{
int i = DP_LANE0_1_STATUS + (lane >> 1);
int s = (lane & 1) * 4;
u8 l = dp_link_status(link_status, i);
return (l >> s) & 0xf;
}
bool drm_dp_channel_eq_ok(u8 link_status[DP_LINK_STATUS_SIZE],
int lane_count)
{
u8 lane_align;
u8 lane_status;
int lane;
lane_align = dp_link_status(link_status,
DP_LANE_ALIGN_STATUS_UPDATED);
if ((lane_align & DP_INTERLANE_ALIGN_DONE) == 0)
return false;
for (lane = 0; lane < lane_count; lane++) {
lane_status = dp_get_lane_status(link_status, lane);
if ((lane_status & DP_CHANNEL_EQ_BITS) != DP_CHANNEL_EQ_BITS)
return false;
}
return true;
}
EXPORT_SYMBOL(drm_dp_channel_eq_ok);
bool drm_dp_clock_recovery_ok(u8 link_status[DP_LINK_STATUS_SIZE],
int lane_count)
{
int lane;
u8 lane_status;
for (lane = 0; lane < lane_count; lane++) {
lane_status = dp_get_lane_status(link_status, lane);
if ((lane_status & DP_LANE_CR_DONE) == 0)
return false;
}
return true;
}
EXPORT_SYMBOL(drm_dp_clock_recovery_ok);
u8 drm_dp_get_adjust_request_voltage(u8 link_status[DP_LINK_STATUS_SIZE],
int lane)
{
int i = DP_ADJUST_REQUEST_LANE0_1 + (lane >> 1);
int s = ((lane & 1) ?
DP_ADJUST_VOLTAGE_SWING_LANE1_SHIFT :
DP_ADJUST_VOLTAGE_SWING_LANE0_SHIFT);
u8 l = dp_link_status(link_status, i);
return ((l >> s) & 0x3) << DP_TRAIN_VOLTAGE_SWING_SHIFT;
}
EXPORT_SYMBOL(drm_dp_get_adjust_request_voltage);
u8 drm_dp_get_adjust_request_pre_emphasis(u8 link_status[DP_LINK_STATUS_SIZE],
int lane)
{
int i = DP_ADJUST_REQUEST_LANE0_1 + (lane >> 1);
int s = ((lane & 1) ?
DP_ADJUST_PRE_EMPHASIS_LANE1_SHIFT :
DP_ADJUST_PRE_EMPHASIS_LANE0_SHIFT);
u8 l = dp_link_status(link_status, i);
return ((l >> s) & 0x3) << DP_TRAIN_PRE_EMPHASIS_SHIFT;
}
EXPORT_SYMBOL(drm_dp_get_adjust_request_pre_emphasis);
void drm_dp_link_train_clock_recovery_delay(u8 dpcd[DP_RECEIVER_CAP_SIZE]) {
if (dpcd[DP_TRAINING_AUX_RD_INTERVAL] == 0)
udelay(100);
else
mdelay(dpcd[DP_TRAINING_AUX_RD_INTERVAL] * 4);
}
EXPORT_SYMBOL(drm_dp_link_train_clock_recovery_delay);
void drm_dp_link_train_channel_eq_delay(u8 dpcd[DP_RECEIVER_CAP_SIZE]) {
if (dpcd[DP_TRAINING_AUX_RD_INTERVAL] == 0)
udelay(400);
else
mdelay(dpcd[DP_TRAINING_AUX_RD_INTERVAL] * 4);
}
EXPORT_SYMBOL(drm_dp_link_train_channel_eq_delay);
u8 drm_dp_link_rate_to_bw_code(int link_rate)
{
switch (link_rate) {
case 162000:
default:
return DP_LINK_BW_1_62;
case 270000:
return DP_LINK_BW_2_7;
case 540000:
return DP_LINK_BW_5_4;
}
}
EXPORT_SYMBOL(drm_dp_link_rate_to_bw_code);
int drm_dp_bw_code_to_link_rate(u8 link_bw)
{
switch (link_bw) {
case DP_LINK_BW_1_62:
default:
return 162000;
case DP_LINK_BW_2_7:
return 270000;
case DP_LINK_BW_5_4:
return 540000;
}
}
EXPORT_SYMBOL(drm_dp_bw_code_to_link_rate);

View File

@ -1525,6 +1525,26 @@ u8 *drm_find_cea_extension(struct edid *edid)
} }
EXPORT_SYMBOL(drm_find_cea_extension); EXPORT_SYMBOL(drm_find_cea_extension);
/*
* Looks for a CEA mode matching given drm_display_mode.
* Returns its CEA Video ID code, or 0 if not found.
*/
u8 drm_match_cea_mode(struct drm_display_mode *to_match)
{
struct drm_display_mode *cea_mode;
u8 mode;
for (mode = 0; mode < drm_num_cea_modes; mode++) {
cea_mode = (struct drm_display_mode *)&edid_cea_modes[mode];
if (drm_mode_equal(to_match, cea_mode))
return mode + 1;
}
return 0;
}
EXPORT_SYMBOL(drm_match_cea_mode);
static int static int
do_cea_modes (struct drm_connector *connector, u8 *db, u8 len) do_cea_modes (struct drm_connector *connector, u8 *db, u8 len)
{ {
@ -1631,7 +1651,7 @@ parse_hdmi_vsdb(struct drm_connector *connector, const u8 *db)
if (len >= 12) if (len >= 12)
connector->audio_latency[1] = db[12]; connector->audio_latency[1] = db[12];
DRM_LOG_KMS("HDMI: DVI dual %d, " DRM_DEBUG_KMS("HDMI: DVI dual %d, "
"max TMDS clock %d, " "max TMDS clock %d, "
"latency present %d %d, " "latency present %d %d, "
"video latency %d %d, " "video latency %d %d, "
@ -2071,3 +2091,22 @@ int drm_add_modes_noedid(struct drm_connector *connector,
return num_modes; return num_modes;
} }
EXPORT_SYMBOL(drm_add_modes_noedid); EXPORT_SYMBOL(drm_add_modes_noedid);
/**
* drm_mode_cea_vic - return the CEA-861 VIC of a given mode
* @mode: mode
*
* RETURNS:
* The VIC number, 0 in case it's not a CEA-861 mode.
*/
uint8_t drm_mode_cea_vic(const struct drm_display_mode *mode)
{
uint8_t i;
for (i = 0; i < drm_num_cea_modes; i++)
if (drm_mode_equal(mode, &edid_cea_modes[i]))
return i + 1;
return 0;
}
EXPORT_SYMBOL(drm_mode_cea_vic);

View File

@ -27,6 +27,8 @@
* Dave Airlie <airlied@linux.ie> * Dave Airlie <airlied@linux.ie>
* Jesse Barnes <jesse.barnes@intel.com> * Jesse Barnes <jesse.barnes@intel.com>
*/ */
#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
#include <linux/kernel.h> #include <linux/kernel.h>
#include <linux/sysrq.h> #include <linux/sysrq.h>
#include <linux/slab.h> #include <linux/slab.h>
@ -43,6 +45,15 @@ MODULE_LICENSE("GPL and additional rights");
static LIST_HEAD(kernel_fb_helper_list); static LIST_HEAD(kernel_fb_helper_list);
/**
* DOC: fbdev helpers
*
* The fb helper functions are useful to provide an fbdev on top of a drm kernel
* mode setting driver. They can be used mostly independantely from the crtc
* helper functions used by many drivers to implement the kernel mode setting
* interfaces.
*/
/* simple single crtc case helper function */ /* simple single crtc case helper function */
int drm_fb_helper_single_add_all_connectors(struct drm_fb_helper *fb_helper) int drm_fb_helper_single_add_all_connectors(struct drm_fb_helper *fb_helper)
{ {
@ -50,6 +61,8 @@ int drm_fb_helper_single_add_all_connectors(struct drm_fb_helper *fb_helper)
struct drm_connector *connector; struct drm_connector *connector;
int i; int i;
ENTER();
list_for_each_entry(connector, &dev->mode_config.connector_list, head) { list_for_each_entry(connector, &dev->mode_config.connector_list, head) {
struct drm_fb_helper_connector *fb_helper_connector; struct drm_fb_helper_connector *fb_helper_connector;
@ -60,6 +73,7 @@ int drm_fb_helper_single_add_all_connectors(struct drm_fb_helper *fb_helper)
fb_helper_connector->connector = connector; fb_helper_connector->connector = connector;
fb_helper->connector_info[fb_helper->connector_count++] = fb_helper_connector; fb_helper->connector_info[fb_helper->connector_count++] = fb_helper_connector;
} }
LEAVE();
return 0; return 0;
fail: fail:
for (i = 0; i < fb_helper->connector_count; i++) { for (i = 0; i < fb_helper->connector_count; i++) {
@ -67,6 +81,7 @@ fail:
fb_helper->connector_info[i] = NULL; fb_helper->connector_info[i] = NULL;
} }
fb_helper->connector_count = 0; fb_helper->connector_count = 0;
FAIL();
return -ENOMEM; return -ENOMEM;
} }
EXPORT_SYMBOL(drm_fb_helper_single_add_all_connectors); EXPORT_SYMBOL(drm_fb_helper_single_add_all_connectors);
@ -122,7 +137,7 @@ static void drm_fb_helper_dpms(struct fb_info *info, int dpms_mode)
for (j = 0; j < fb_helper->connector_count; j++) { for (j = 0; j < fb_helper->connector_count; j++) {
connector = fb_helper->connector_info[j]->connector; connector = fb_helper->connector_info[j]->connector;
connector->funcs->dpms(connector, dpms_mode); connector->funcs->dpms(connector, dpms_mode);
drm_connector_property_set_value(connector, drm_object_property_set_value(&connector->base,
dev->mode_config.dpms_property, dpms_mode); dev->mode_config.dpms_property, dpms_mode);
} }
} }
@ -179,18 +194,26 @@ int drm_fb_helper_init(struct drm_device *dev,
struct drm_crtc *crtc; struct drm_crtc *crtc;
int i; int i;
ENTER();
dbgprintf("crtc_count %d max_conn_count %d\n", crtc_count, max_conn_count);
fb_helper->dev = dev; fb_helper->dev = dev;
INIT_LIST_HEAD(&fb_helper->kernel_fb_list); INIT_LIST_HEAD(&fb_helper->kernel_fb_list);
fb_helper->crtc_info = kcalloc(crtc_count, sizeof(struct drm_fb_helper_crtc), GFP_KERNEL); fb_helper->crtc_info = kcalloc(crtc_count, sizeof(struct drm_fb_helper_crtc), GFP_KERNEL);
if (!fb_helper->crtc_info) if (!fb_helper->crtc_info)
{
FAIL();
return -ENOMEM; return -ENOMEM;
};
fb_helper->crtc_count = crtc_count; fb_helper->crtc_count = crtc_count;
fb_helper->connector_info = kcalloc(dev->mode_config.num_connector, sizeof(struct drm_fb_helper_connector *), GFP_KERNEL); fb_helper->connector_info = kcalloc(dev->mode_config.num_connector, sizeof(struct drm_fb_helper_connector *), GFP_KERNEL);
if (!fb_helper->connector_info) { if (!fb_helper->connector_info) {
kfree(fb_helper->crtc_info); kfree(fb_helper->crtc_info);
FAIL();
return -ENOMEM; return -ENOMEM;
} }
fb_helper->connector_count = 0; fb_helper->connector_count = 0;
@ -212,9 +235,11 @@ int drm_fb_helper_init(struct drm_device *dev,
i++; i++;
} }
LEAVE();
return 0; return 0;
out_free: out_free:
drm_fb_helper_crtc_free(fb_helper); drm_fb_helper_crtc_free(fb_helper);
FAIL();
return -ENOMEM; return -ENOMEM;
} }
EXPORT_SYMBOL(drm_fb_helper_init); EXPORT_SYMBOL(drm_fb_helper_init);
@ -498,9 +523,9 @@ int drm_fb_helper_single_fb_probe(struct drm_fb_helper *fb_helper,
/* if driver picks 8 or 16 by default use that /* if driver picks 8 or 16 by default use that
for both depth/bpp */ for both depth/bpp */
if (preferred_bpp != sizes.surface_bpp) { if (preferred_bpp != sizes.surface_bpp)
sizes.surface_depth = sizes.surface_bpp = preferred_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 */ /* first up get a count of crtcs now in use and new min/maxes width/heights */
for (i = 0; i < fb_helper->connector_count; i++) { 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_connector *fb_helper_conn = fb_helper->connector_info[i];
@ -568,9 +593,8 @@ int drm_fb_helper_single_fb_probe(struct drm_fb_helper *fb_helper,
info = fb_helper->fbdev; info = fb_helper->fbdev;
/* set the fb pointer */ /* set the fb pointer */
for (i = 0; i < fb_helper->crtc_count; i++) { for (i = 0; i < fb_helper->crtc_count; i++)
fb_helper->crtc_info[i].mode_set.fb = fb_helper->fb; fb_helper->crtc_info[i].mode_set.fb = fb_helper->fb;
}
if (new_fb) { if (new_fb) {
info->var.pixclock = 0; info->var.pixclock = 0;
@ -726,11 +750,11 @@ static bool drm_connector_enabled(struct drm_connector *connector, bool strict)
{ {
bool enable; bool enable;
if (strict) { if (strict)
enable = connector->status == connector_status_connected; enable = connector->status == connector_status_connected;
} else { else
enable = connector->status != connector_status_disconnected; enable = connector->status != connector_status_disconnected;
}
return enable; return enable;
} }
@ -846,9 +870,8 @@ static int drm_pick_crtcs(struct drm_fb_helper *fb_helper,
for (c = 0; c < fb_helper->crtc_count; c++) { for (c = 0; c < fb_helper->crtc_count; c++) {
crtc = &fb_helper->crtc_info[c]; crtc = &fb_helper->crtc_info[c];
if ((encoder->possible_crtcs & (1 << c)) == 0) { if ((encoder->possible_crtcs & (1 << c)) == 0)
continue; continue;
}
for (o = 0; o < n; o++) for (o = 0; o < n; o++)
if (best_crtcs[o] == crtc) if (best_crtcs[o] == crtc)
@ -901,6 +924,11 @@ static void drm_setup_crtcs(struct drm_fb_helper *fb_helper)
sizeof(struct drm_display_mode *), GFP_KERNEL); sizeof(struct drm_display_mode *), GFP_KERNEL);
enabled = kcalloc(dev->mode_config.num_connector, enabled = kcalloc(dev->mode_config.num_connector,
sizeof(bool), GFP_KERNEL); sizeof(bool), GFP_KERNEL);
if (!crtcs || !modes || !enabled) {
DRM_ERROR("Memory allocation failed\n");
goto out;
}
drm_enable_connectors(fb_helper, enabled); drm_enable_connectors(fb_helper, enabled);
@ -942,6 +970,7 @@ static void drm_setup_crtcs(struct drm_fb_helper *fb_helper)
} }
} }
out:
kfree(crtcs); kfree(crtcs);
kfree(modes); kfree(modes);
kfree(enabled); kfree(enabled);
@ -949,12 +978,14 @@ static void drm_setup_crtcs(struct drm_fb_helper *fb_helper)
/** /**
* drm_helper_initial_config - setup a sane initial connector configuration * drm_helper_initial_config - setup a sane initial connector configuration
* @dev: DRM device * @fb_helper: fb_helper device struct
* @bpp_sel: bpp value to use for the framebuffer configuration
* *
* LOCKING: * LOCKING:
* Called at init time, must take mode config lock. * Called at init time by the driver to set up the @fb_helper initial
* configuration, must take the mode config lock.
* *
* Scan the CRTCs and connectors and try to put together an initial setup. * Scans the CRTCs and connectors and tries to put together an initial setup.
* At the moment, this is a cloned configuration across all heads with * At the moment, this is a cloned configuration across all heads with
* a new framebuffer object as the backing store. * a new framebuffer object as the backing store.
* *
@ -965,6 +996,9 @@ bool drm_fb_helper_initial_config(struct drm_fb_helper *fb_helper, int bpp_sel)
{ {
struct drm_device *dev = fb_helper->dev; struct drm_device *dev = fb_helper->dev;
int count = 0; int count = 0;
bool ret;
ENTER();
/* disable all the possible outputs/crtcs before entering KMS mode */ /* disable all the possible outputs/crtcs before entering KMS mode */
drm_helper_disable_unused_functions(fb_helper->dev); drm_helper_disable_unused_functions(fb_helper->dev);
@ -977,11 +1011,70 @@ bool drm_fb_helper_initial_config(struct drm_fb_helper *fb_helper, int bpp_sel)
/* /*
* we shouldn't end up with no modes here. * we shouldn't end up with no modes here.
*/ */
if (count == 0) { if (count == 0)
printk(KERN_INFO "No connectors reported connected with modes\n"); dev_info(fb_helper->dev->dev, "No connectors reported connected with modes\n");
}
drm_setup_crtcs(fb_helper); drm_setup_crtcs(fb_helper);
ret = drm_fb_helper_single_fb_probe(fb_helper, bpp_sel);
LEAVE();
}
EXPORT_SYMBOL(drm_fb_helper_initial_config);
#if 0
/**
* drm_fb_helper_hotplug_event - respond to a hotplug notification by
* probing all the outputs attached to the fb
* @fb_helper: the drm_fb_helper
*
* LOCKING:
* Called at runtime, must take mode config lock.
*
* Scan the connectors attached to the fb_helper and try to put together a
* setup after *notification of a change in output configuration.
*
* RETURNS:
* 0 on success and a non-zero error code otherwise.
*/
int drm_fb_helper_hotplug_event(struct drm_fb_helper *fb_helper)
{
struct drm_device *dev = fb_helper->dev;
int count = 0;
u32 max_width, max_height, bpp_sel;
int bound = 0, crtcs_bound = 0;
struct drm_crtc *crtc;
if (!fb_helper->fb)
return 0;
mutex_lock(&dev->mode_config.mutex);
list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) {
if (crtc->fb)
crtcs_bound++;
if (crtc->fb == fb_helper->fb)
bound++;
}
if (bound < crtcs_bound) {
fb_helper->delayed_hotplug = true;
mutex_unlock(&dev->mode_config.mutex);
return 0;
}
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);
drm_setup_crtcs(fb_helper);
mutex_unlock(&dev->mode_config.mutex);
return drm_fb_helper_single_fb_probe(fb_helper, bpp_sel); return drm_fb_helper_single_fb_probe(fb_helper, bpp_sel);
} }
EXPORT_SYMBOL(drm_fb_helper_initial_config); EXPORT_SYMBOL(drm_fb_helper_hotplug_event);
#endif

View File

@ -184,19 +184,27 @@ EXPORT_SYMBOL(drm_mm_get_block_generic);
* -ENOSPC if no suitable free area is available. The preallocated memory node * -ENOSPC if no suitable free area is available. The preallocated memory node
* must be cleared. * must be cleared.
*/ */
int drm_mm_insert_node(struct drm_mm *mm, struct drm_mm_node *node, int drm_mm_insert_node_generic(struct drm_mm *mm, struct drm_mm_node *node,
unsigned long size, unsigned alignment) unsigned long size, unsigned alignment,
unsigned long color)
{ {
struct drm_mm_node *hole_node; struct drm_mm_node *hole_node;
hole_node = drm_mm_search_free(mm, size, alignment, false); hole_node = drm_mm_search_free_generic(mm, size, alignment,
color, 0);
if (!hole_node) if (!hole_node)
return -ENOSPC; return -ENOSPC;
drm_mm_insert_helper(hole_node, node, size, alignment, 0); drm_mm_insert_helper(hole_node, node, size, alignment, color);
return 0; return 0;
} }
EXPORT_SYMBOL(drm_mm_insert_node_generic);
int drm_mm_insert_node(struct drm_mm *mm, struct drm_mm_node *node,
unsigned long size, unsigned alignment)
{
return drm_mm_insert_node_generic(mm, node, size, alignment, 0);
}
EXPORT_SYMBOL(drm_mm_insert_node); EXPORT_SYMBOL(drm_mm_insert_node);
static void drm_mm_insert_helper_range(struct drm_mm_node *hole_node, static void drm_mm_insert_helper_range(struct drm_mm_node *hole_node,
@ -213,11 +221,13 @@ static void drm_mm_insert_helper_range(struct drm_mm_node *hole_node,
BUG_ON(!hole_node->hole_follows || node->allocated); BUG_ON(!hole_node->hole_follows || node->allocated);
if (mm->color_adjust)
mm->color_adjust(hole_node, color, &adj_start, &adj_end);
if (adj_start < start) if (adj_start < start)
adj_start = start; adj_start = start;
if (adj_end > end)
adj_end = end;
if (mm->color_adjust)
mm->color_adjust(hole_node, color, &adj_start, &adj_end);
if (alignment) { if (alignment) {
unsigned tmp = adj_start % alignment; unsigned tmp = adj_start % alignment;
@ -275,22 +285,31 @@ EXPORT_SYMBOL(drm_mm_get_block_range_generic);
* -ENOSPC if no suitable free area is available. This is for range * -ENOSPC if no suitable free area is available. This is for range
* restricted allocations. The preallocated memory node must be cleared. * restricted allocations. The preallocated memory node must be cleared.
*/ */
int drm_mm_insert_node_in_range(struct drm_mm *mm, struct drm_mm_node *node, int drm_mm_insert_node_in_range_generic(struct drm_mm *mm, struct drm_mm_node *node,
unsigned long size, unsigned alignment, unsigned long size, unsigned alignment, unsigned long color,
unsigned long start, unsigned long end) unsigned long start, unsigned long end)
{ {
struct drm_mm_node *hole_node; struct drm_mm_node *hole_node;
hole_node = drm_mm_search_free_in_range(mm, size, alignment, hole_node = drm_mm_search_free_in_range_generic(mm,
start, end, false); size, alignment, color,
start, end, 0);
if (!hole_node) if (!hole_node)
return -ENOSPC; return -ENOSPC;
drm_mm_insert_helper_range(hole_node, node, size, alignment, 0, drm_mm_insert_helper_range(hole_node, node,
size, alignment, color,
start, end); start, end);
return 0; return 0;
} }
EXPORT_SYMBOL(drm_mm_insert_node_in_range_generic);
int drm_mm_insert_node_in_range(struct drm_mm *mm, struct drm_mm_node *node,
unsigned long size, unsigned alignment,
unsigned long start, unsigned long end)
{
return drm_mm_insert_node_in_range_generic(mm, node, size, alignment, 0, start, end);
}
EXPORT_SYMBOL(drm_mm_insert_node_in_range); EXPORT_SYMBOL(drm_mm_insert_node_in_range);
/** /**
@ -489,7 +508,7 @@ void drm_mm_init_scan(struct drm_mm *mm,
mm->scan_size = size; mm->scan_size = size;
mm->scanned_blocks = 0; mm->scanned_blocks = 0;
mm->scan_hit_start = 0; mm->scan_hit_start = 0;
mm->scan_hit_size = 0; mm->scan_hit_end = 0;
mm->scan_check_range = 0; mm->scan_check_range = 0;
mm->prev_scanned_node = NULL; mm->prev_scanned_node = NULL;
} }
@ -516,7 +535,7 @@ void drm_mm_init_scan_with_range(struct drm_mm *mm,
mm->scan_size = size; mm->scan_size = size;
mm->scanned_blocks = 0; mm->scanned_blocks = 0;
mm->scan_hit_start = 0; mm->scan_hit_start = 0;
mm->scan_hit_size = 0; mm->scan_hit_end = 0;
mm->scan_start = start; mm->scan_start = start;
mm->scan_end = end; mm->scan_end = end;
mm->scan_check_range = 1; mm->scan_check_range = 1;
@ -535,8 +554,7 @@ int drm_mm_scan_add_block(struct drm_mm_node *node)
struct drm_mm *mm = node->mm; struct drm_mm *mm = node->mm;
struct drm_mm_node *prev_node; struct drm_mm_node *prev_node;
unsigned long hole_start, hole_end; unsigned long hole_start, hole_end;
unsigned long adj_start; unsigned long adj_start, adj_end;
unsigned long adj_end;
mm->scanned_blocks++; mm->scanned_blocks++;
@ -553,14 +571,8 @@ int drm_mm_scan_add_block(struct drm_mm_node *node)
node->node_list.next = &mm->prev_scanned_node->node_list; node->node_list.next = &mm->prev_scanned_node->node_list;
mm->prev_scanned_node = node; mm->prev_scanned_node = node;
hole_start = drm_mm_hole_node_start(prev_node); adj_start = hole_start = drm_mm_hole_node_start(prev_node);
hole_end = drm_mm_hole_node_end(prev_node); adj_end = hole_end = drm_mm_hole_node_end(prev_node);
adj_start = hole_start;
adj_end = hole_end;
if (mm->color_adjust)
mm->color_adjust(prev_node, mm->scan_color, &adj_start, &adj_end);
if (mm->scan_check_range) { if (mm->scan_check_range) {
if (adj_start < mm->scan_start) if (adj_start < mm->scan_start)
@ -569,11 +581,14 @@ int drm_mm_scan_add_block(struct drm_mm_node *node)
adj_end = mm->scan_end; adj_end = mm->scan_end;
} }
if (mm->color_adjust)
mm->color_adjust(prev_node, mm->scan_color,
&adj_start, &adj_end);
if (check_free_hole(adj_start, adj_end, if (check_free_hole(adj_start, adj_end,
mm->scan_size, mm->scan_alignment)) { mm->scan_size, mm->scan_alignment)) {
mm->scan_hit_start = hole_start; mm->scan_hit_start = hole_start;
mm->scan_hit_size = hole_end; mm->scan_hit_end = hole_end;
return 1; return 1;
} }
@ -609,19 +624,10 @@ int drm_mm_scan_remove_block(struct drm_mm_node *node)
node_list); node_list);
prev_node->hole_follows = node->scanned_preceeds_hole; prev_node->hole_follows = node->scanned_preceeds_hole;
INIT_LIST_HEAD(&node->node_list);
list_add(&node->node_list, &prev_node->node_list); list_add(&node->node_list, &prev_node->node_list);
/* Only need to check for containement because start&size for the return (drm_mm_hole_node_end(node) > mm->scan_hit_start &&
* complete resulting free block (not just the desired part) is node->start < mm->scan_hit_end);
* stored. */
if (node->start >= mm->scan_hit_start &&
node->start + node->size
<= mm->scan_hit_start + mm->scan_hit_size) {
return 1;
}
return 0;
} }
EXPORT_SYMBOL(drm_mm_scan_remove_block); EXPORT_SYMBOL(drm_mm_scan_remove_block);
@ -679,3 +685,78 @@ void drm_mm_takedown(struct drm_mm * mm)
BUG_ON(mm->num_unused != 0); BUG_ON(mm->num_unused != 0);
} }
EXPORT_SYMBOL(drm_mm_takedown); EXPORT_SYMBOL(drm_mm_takedown);
void drm_mm_debug_table(struct drm_mm *mm, const char *prefix)
{
struct drm_mm_node *entry;
unsigned long total_used = 0, total_free = 0, total = 0;
unsigned long hole_start, hole_end, hole_size;
hole_start = drm_mm_hole_node_start(&mm->head_node);
hole_end = drm_mm_hole_node_end(&mm->head_node);
hole_size = hole_end - hole_start;
if (hole_size)
printk(KERN_DEBUG "%s 0x%08lx-0x%08lx: %8lu: free\n",
prefix, hole_start, hole_end,
hole_size);
total_free += hole_size;
drm_mm_for_each_node(entry, mm) {
printk(KERN_DEBUG "%s 0x%08lx-0x%08lx: %8lu: used\n",
prefix, entry->start, entry->start + entry->size,
entry->size);
total_used += entry->size;
if (entry->hole_follows) {
hole_start = drm_mm_hole_node_start(entry);
hole_end = drm_mm_hole_node_end(entry);
hole_size = hole_end - hole_start;
printk(KERN_DEBUG "%s 0x%08lx-0x%08lx: %8lu: free\n",
prefix, hole_start, hole_end,
hole_size);
total_free += hole_size;
}
}
total = total_free + total_used;
printk(KERN_DEBUG "%s total: %lu, used %lu free %lu\n", prefix, total,
total_used, total_free);
}
EXPORT_SYMBOL(drm_mm_debug_table);
#if defined(CONFIG_DEBUG_FS)
int drm_mm_dump_table(struct seq_file *m, struct drm_mm *mm)
{
struct drm_mm_node *entry;
unsigned long total_used = 0, total_free = 0, total = 0;
unsigned long hole_start, hole_end, hole_size;
hole_start = drm_mm_hole_node_start(&mm->head_node);
hole_end = drm_mm_hole_node_end(&mm->head_node);
hole_size = hole_end - hole_start;
if (hole_size)
seq_printf(m, "0x%08lx-0x%08lx: 0x%08lx: free\n",
hole_start, hole_end, hole_size);
total_free += hole_size;
drm_mm_for_each_node(entry, mm) {
seq_printf(m, "0x%08lx-0x%08lx: 0x%08lx: used\n",
entry->start, entry->start + entry->size,
entry->size);
total_used += entry->size;
if (entry->hole_follows) {
hole_start = drm_mm_hole_node_start(entry);
hole_end = drm_mm_hole_node_end(entry);
hole_size = hole_end - hole_start;
seq_printf(m, "0x%08lx-0x%08lx: 0x%08lx: free\n",
hole_start, hole_end, hole_size);
total_free += hole_size;
}
}
total = total_free + total_used;
seq_printf(m, "total: %lu, used %lu free %lu\n", total, total_used, total_free);
return 0;
}
EXPORT_SYMBOL(drm_mm_dump_table);
#endif

View File

@ -46,7 +46,7 @@
* *
* Describe @mode using DRM_DEBUG. * Describe @mode using DRM_DEBUG.
*/ */
void drm_mode_debug_printmodeline(struct drm_display_mode *mode) void drm_mode_debug_printmodeline(const struct drm_display_mode *mode)
{ {
DRM_DEBUG_KMS("Modeline %d:\"%s\" %d %d %d %d %d %d %d %d %d %d " DRM_DEBUG_KMS("Modeline %d:\"%s\" %d %d %d %d %d %d %d %d %d %d "
"0x%x 0x%x\n", "0x%x 0x%x\n",
@ -558,7 +558,7 @@ EXPORT_SYMBOL(drm_mode_list_concat);
* RETURNS: * RETURNS:
* @mode->hdisplay * @mode->hdisplay
*/ */
int drm_mode_width(struct drm_display_mode *mode) int drm_mode_width(const struct drm_display_mode *mode)
{ {
return mode->hdisplay; return mode->hdisplay;
@ -579,7 +579,7 @@ EXPORT_SYMBOL(drm_mode_width);
* RETURNS: * RETURNS:
* @mode->vdisplay * @mode->vdisplay
*/ */
int drm_mode_height(struct drm_display_mode *mode) int drm_mode_height(const struct drm_display_mode *mode)
{ {
return mode->vdisplay; return mode->vdisplay;
} }
@ -768,7 +768,7 @@ EXPORT_SYMBOL(drm_mode_duplicate);
* RETURNS: * RETURNS:
* True if the modes are equal, false otherwise. * True if the modes are equal, false otherwise.
*/ */
bool drm_mode_equal(struct drm_display_mode *mode1, struct drm_display_mode *mode2) bool drm_mode_equal(const struct drm_display_mode *mode1, const struct drm_display_mode *mode2)
{ {
/* do clock check convert to PICOS so fb modes get matched /* do clock check convert to PICOS so fb modes get matched
* the same */ * the same */

View File

@ -44,7 +44,7 @@ NAME_SRC= \
pci.c \ pci.c \
$(DRM_TOPDIR)/drm_crtc.c \ $(DRM_TOPDIR)/drm_crtc.c \
$(DRM_TOPDIR)/drm_crtc_helper.c \ $(DRM_TOPDIR)/drm_crtc_helper.c \
$(DRM_TOPDIR)/drm_dp_i2c_helper.c \ $(DRM_TOPDIR)/drm_dp_helper.c \
$(DRM_TOPDIR)/drm_edid.c \ $(DRM_TOPDIR)/drm_edid.c \
$(DRM_TOPDIR)/drm_fb_helper.c \ $(DRM_TOPDIR)/drm_fb_helper.c \
$(DRM_TOPDIR)/drm_irq.c \ $(DRM_TOPDIR)/drm_irq.c \

View File

@ -561,6 +561,8 @@ static u32 atombios_adjust_pll(struct drm_crtc *crtc,
/* use frac fb div on APUs */ /* use frac fb div on APUs */
if (ASIC_IS_DCE41(rdev) || ASIC_IS_DCE61(rdev)) if (ASIC_IS_DCE41(rdev) || ASIC_IS_DCE61(rdev))
radeon_crtc->pll_flags |= RADEON_PLL_USE_FRAC_FB_DIV; radeon_crtc->pll_flags |= RADEON_PLL_USE_FRAC_FB_DIV;
if (ASIC_IS_DCE32(rdev) && mode->clock > 165000)
radeon_crtc->pll_flags |= RADEON_PLL_USE_FRAC_FB_DIV;
} else { } else {
radeon_crtc->pll_flags |= RADEON_PLL_LEGACY; radeon_crtc->pll_flags |= RADEON_PLL_LEGACY;

View File

@ -34,8 +34,7 @@
/* move these to drm_dp_helper.c/h */ /* move these to drm_dp_helper.c/h */
#define DP_LINK_CONFIGURATION_SIZE 9 #define DP_LINK_CONFIGURATION_SIZE 9
#define DP_LINK_STATUS_SIZE 6 #define DP_DPCD_SIZE DP_RECEIVER_CAP_SIZE
#define DP_DPCD_SIZE 8
static char *voltage_names[] = { static char *voltage_names[] = {
"0.4V", "0.6V", "0.8V", "1.2V" "0.4V", "0.6V", "0.8V", "1.2V"
@ -290,78 +289,6 @@ int radeon_dp_i2c_aux_ch(struct i2c_adapter *adapter, int mode,
/***** general DP utility functions *****/ /***** general DP utility functions *****/
static u8 dp_link_status(u8 link_status[DP_LINK_STATUS_SIZE], int r)
{
return link_status[r - DP_LANE0_1_STATUS];
}
static u8 dp_get_lane_status(u8 link_status[DP_LINK_STATUS_SIZE],
int lane)
{
int i = DP_LANE0_1_STATUS + (lane >> 1);
int s = (lane & 1) * 4;
u8 l = dp_link_status(link_status, i);
return (l >> s) & 0xf;
}
static bool dp_clock_recovery_ok(u8 link_status[DP_LINK_STATUS_SIZE],
int lane_count)
{
int lane;
u8 lane_status;
for (lane = 0; lane < lane_count; lane++) {
lane_status = dp_get_lane_status(link_status, lane);
if ((lane_status & DP_LANE_CR_DONE) == 0)
return false;
}
return true;
}
static bool dp_channel_eq_ok(u8 link_status[DP_LINK_STATUS_SIZE],
int lane_count)
{
u8 lane_align;
u8 lane_status;
int lane;
lane_align = dp_link_status(link_status,
DP_LANE_ALIGN_STATUS_UPDATED);
if ((lane_align & DP_INTERLANE_ALIGN_DONE) == 0)
return false;
for (lane = 0; lane < lane_count; lane++) {
lane_status = dp_get_lane_status(link_status, lane);
if ((lane_status & DP_CHANNEL_EQ_BITS) != DP_CHANNEL_EQ_BITS)
return false;
}
return true;
}
static u8 dp_get_adjust_request_voltage(u8 link_status[DP_LINK_STATUS_SIZE],
int lane)
{
int i = DP_ADJUST_REQUEST_LANE0_1 + (lane >> 1);
int s = ((lane & 1) ?
DP_ADJUST_VOLTAGE_SWING_LANE1_SHIFT :
DP_ADJUST_VOLTAGE_SWING_LANE0_SHIFT);
u8 l = dp_link_status(link_status, i);
return ((l >> s) & 0x3) << DP_TRAIN_VOLTAGE_SWING_SHIFT;
}
static u8 dp_get_adjust_request_pre_emphasis(u8 link_status[DP_LINK_STATUS_SIZE],
int lane)
{
int i = DP_ADJUST_REQUEST_LANE0_1 + (lane >> 1);
int s = ((lane & 1) ?
DP_ADJUST_PRE_EMPHASIS_LANE1_SHIFT :
DP_ADJUST_PRE_EMPHASIS_LANE0_SHIFT);
u8 l = dp_link_status(link_status, i);
return ((l >> s) & 0x3) << DP_TRAIN_PRE_EMPHASIS_SHIFT;
}
#define DP_VOLTAGE_MAX DP_TRAIN_VOLTAGE_SWING_1200 #define DP_VOLTAGE_MAX DP_TRAIN_VOLTAGE_SWING_1200
#define DP_PRE_EMPHASIS_MAX DP_TRAIN_PRE_EMPHASIS_9_5 #define DP_PRE_EMPHASIS_MAX DP_TRAIN_PRE_EMPHASIS_9_5
@ -374,8 +301,8 @@ static void dp_get_adjust_train(u8 link_status[DP_LINK_STATUS_SIZE],
int lane; int lane;
for (lane = 0; lane < lane_count; lane++) { for (lane = 0; lane < lane_count; lane++) {
u8 this_v = dp_get_adjust_request_voltage(link_status, lane); u8 this_v = drm_dp_get_adjust_request_voltage(link_status, lane);
u8 this_p = dp_get_adjust_request_pre_emphasis(link_status, lane); u8 this_p = drm_dp_get_adjust_request_pre_emphasis(link_status, lane);
DRM_DEBUG_KMS("requested signal parameters: lane %d voltage %s pre_emph %s\n", DRM_DEBUG_KMS("requested signal parameters: lane %d voltage %s pre_emph %s\n",
lane, lane,
@ -420,37 +347,6 @@ static int dp_get_max_dp_pix_clock(int link_rate,
return (link_rate * lane_num * 8) / bpp; return (link_rate * lane_num * 8) / bpp;
} }
static int dp_get_max_link_rate(u8 dpcd[DP_DPCD_SIZE])
{
switch (dpcd[DP_MAX_LINK_RATE]) {
case DP_LINK_BW_1_62:
default:
return 162000;
case DP_LINK_BW_2_7:
return 270000;
case DP_LINK_BW_5_4:
return 540000;
}
}
static u8 dp_get_max_lane_number(u8 dpcd[DP_DPCD_SIZE])
{
return dpcd[DP_MAX_LANE_COUNT] & DP_MAX_LANE_COUNT_MASK;
}
static u8 dp_get_dp_link_rate_coded(int link_rate)
{
switch (link_rate) {
case 162000:
default:
return DP_LINK_BW_1_62;
case 270000:
return DP_LINK_BW_2_7;
case 540000:
return DP_LINK_BW_5_4;
}
}
/***** radeon specific DP functions *****/ /***** radeon specific DP functions *****/
/* First get the min lane# when low rate is used according to pixel clock /* First get the min lane# when low rate is used according to pixel clock
@ -462,8 +358,8 @@ static int radeon_dp_get_dp_lane_number(struct drm_connector *connector,
int pix_clock) int pix_clock)
{ {
int bpp = convert_bpc_to_bpp(radeon_get_monitor_bpc(connector)); int bpp = convert_bpc_to_bpp(radeon_get_monitor_bpc(connector));
int max_link_rate = dp_get_max_link_rate(dpcd); int max_link_rate = drm_dp_max_link_rate(dpcd);
int max_lane_num = dp_get_max_lane_number(dpcd); int max_lane_num = drm_dp_max_lane_count(dpcd);
int lane_num; int lane_num;
int max_dp_pix_clock; int max_dp_pix_clock;
@ -500,7 +396,7 @@ static int radeon_dp_get_dp_link_clock(struct drm_connector *connector,
return 540000; return 540000;
} }
return dp_get_max_link_rate(dpcd); return drm_dp_max_link_rate(dpcd);
} }
static u8 radeon_dp_encoder_service(struct radeon_device *rdev, static u8 radeon_dp_encoder_service(struct radeon_device *rdev,
@ -551,21 +447,25 @@ static void radeon_dp_probe_oui(struct radeon_connector *radeon_connector)
bool radeon_dp_getdpcd(struct radeon_connector *radeon_connector) bool radeon_dp_getdpcd(struct radeon_connector *radeon_connector)
{ {
struct radeon_connector_atom_dig *dig_connector = radeon_connector->con_priv; struct radeon_connector_atom_dig *dig_connector = radeon_connector->con_priv;
u8 msg[25]; u8 msg[DP_DPCD_SIZE];
int ret, i; int ret, i;
ret = radeon_dp_aux_native_read(radeon_connector, DP_DPCD_REV, msg, 8, 0); ENTER();
ret = radeon_dp_aux_native_read(radeon_connector, DP_DPCD_REV, msg,
DP_DPCD_SIZE, 0);
if (ret > 0) { if (ret > 0) {
memcpy(dig_connector->dpcd, msg, 8); memcpy(dig_connector->dpcd, msg, DP_DPCD_SIZE);
DRM_DEBUG_KMS("DPCD: "); DRM_DEBUG_KMS("DPCD: ");
for (i = 0; i < 8; i++) for (i = 0; i < DP_DPCD_SIZE; i++)
DRM_DEBUG_KMS("%02x ", msg[i]); DRM_DEBUG_KMS("%02x ", msg[i]);
DRM_DEBUG_KMS("\n"); DRM_DEBUG_KMS("\n");
radeon_dp_probe_oui(radeon_connector); radeon_dp_probe_oui(radeon_connector);
LEAVE();
return true; return true;
} }
FAIL();
dig_connector->dpcd[0] = 0; dig_connector->dpcd[0] = 0;
return false; return false;
} }
@ -664,7 +564,7 @@ bool radeon_dp_needs_link_train(struct radeon_connector *radeon_connector)
if (!radeon_dp_get_link_status(radeon_connector, link_status)) if (!radeon_dp_get_link_status(radeon_connector, link_status))
return false; return false;
if (dp_channel_eq_ok(link_status, dig->dp_lane_count)) if (drm_dp_channel_eq_ok(link_status, dig->dp_lane_count))
return false; return false;
return true; return true;
} }
@ -677,9 +577,8 @@ struct radeon_dp_link_train_info {
int enc_id; int enc_id;
int dp_clock; int dp_clock;
int dp_lane_count; int dp_lane_count;
int rd_interval;
bool tp3_supported; bool tp3_supported;
u8 dpcd[8]; u8 dpcd[DP_RECEIVER_CAP_SIZE];
u8 train_set[4]; u8 train_set[4];
u8 link_status[DP_LINK_STATUS_SIZE]; u8 link_status[DP_LINK_STATUS_SIZE];
u8 tries; u8 tries;
@ -765,7 +664,7 @@ static int radeon_dp_link_train_init(struct radeon_dp_link_train_info *dp_info)
radeon_write_dpcd_reg(dp_info->radeon_connector, DP_LANE_COUNT_SET, tmp); radeon_write_dpcd_reg(dp_info->radeon_connector, DP_LANE_COUNT_SET, tmp);
/* set the link rate on the sink */ /* set the link rate on the sink */
tmp = dp_get_dp_link_rate_coded(dp_info->dp_clock); tmp = drm_dp_link_rate_to_bw_code(dp_info->dp_clock);
radeon_write_dpcd_reg(dp_info->radeon_connector, DP_LINK_BW_SET, tmp); radeon_write_dpcd_reg(dp_info->radeon_connector, DP_LINK_BW_SET, tmp);
/* start training on the source */ /* start training on the source */
@ -821,17 +720,14 @@ static int radeon_dp_link_train_cr(struct radeon_dp_link_train_info *dp_info)
dp_info->tries = 0; dp_info->tries = 0;
voltage = 0xff; voltage = 0xff;
while (1) { while (1) {
if (dp_info->rd_interval == 0) drm_dp_link_train_clock_recovery_delay(dp_info->dpcd);
udelay(100);
else
mdelay(dp_info->rd_interval * 4);
if (!radeon_dp_get_link_status(dp_info->radeon_connector, dp_info->link_status)) { if (!radeon_dp_get_link_status(dp_info->radeon_connector, dp_info->link_status)) {
DRM_ERROR("displayport link status failed\n"); DRM_ERROR("displayport link status failed\n");
break; break;
} }
if (dp_clock_recovery_ok(dp_info->link_status, dp_info->dp_lane_count)) { if (drm_dp_clock_recovery_ok(dp_info->link_status, dp_info->dp_lane_count)) {
clock_recovery = true; clock_recovery = true;
break; break;
} }
@ -886,17 +782,14 @@ static int radeon_dp_link_train_ce(struct radeon_dp_link_train_info *dp_info)
dp_info->tries = 0; dp_info->tries = 0;
channel_eq = false; channel_eq = false;
while (1) { while (1) {
if (dp_info->rd_interval == 0) drm_dp_link_train_channel_eq_delay(dp_info->dpcd);
udelay(400);
else
mdelay(dp_info->rd_interval * 4);
if (!radeon_dp_get_link_status(dp_info->radeon_connector, dp_info->link_status)) { if (!radeon_dp_get_link_status(dp_info->radeon_connector, dp_info->link_status)) {
DRM_ERROR("displayport link status failed\n"); DRM_ERROR("displayport link status failed\n");
break; break;
} }
if (dp_channel_eq_ok(dp_info->link_status, dp_info->dp_lane_count)) { if (drm_dp_channel_eq_ok(dp_info->link_status, dp_info->dp_lane_count)) {
channel_eq = true; channel_eq = true;
break; break;
} }
@ -974,14 +867,13 @@ void radeon_dp_link_train(struct drm_encoder *encoder,
else else
dp_info.enc_id |= ATOM_DP_CONFIG_LINK_A; dp_info.enc_id |= ATOM_DP_CONFIG_LINK_A;
dp_info.rd_interval = radeon_read_dpcd_reg(radeon_connector, DP_TRAINING_AUX_RD_INTERVAL);
tmp = radeon_read_dpcd_reg(radeon_connector, DP_MAX_LANE_COUNT); tmp = radeon_read_dpcd_reg(radeon_connector, DP_MAX_LANE_COUNT);
if (ASIC_IS_DCE5(rdev) && (tmp & DP_TPS3_SUPPORTED)) if (ASIC_IS_DCE5(rdev) && (tmp & DP_TPS3_SUPPORTED))
dp_info.tp3_supported = true; dp_info.tp3_supported = true;
else else
dp_info.tp3_supported = false; dp_info.tp3_supported = false;
memcpy(dp_info.dpcd, dig_connector->dpcd, 8); memcpy(dp_info.dpcd, dig_connector->dpcd, DP_RECEIVER_CAP_SIZE);
dp_info.rdev = rdev; dp_info.rdev = rdev;
dp_info.encoder = encoder; dp_info.encoder = encoder;
dp_info.connector = connector; dp_info.connector = connector;

View File

@ -340,7 +340,7 @@ static bool radeon_atom_mode_fixup(struct drm_encoder *encoder,
((radeon_encoder->active_device & (ATOM_DEVICE_DFP_SUPPORT | ATOM_DEVICE_LCD_SUPPORT)) || ((radeon_encoder->active_device & (ATOM_DEVICE_DFP_SUPPORT | ATOM_DEVICE_LCD_SUPPORT)) ||
(radeon_encoder_get_dp_bridge_encoder_id(encoder) != ENCODER_OBJECT_ID_NONE))) { (radeon_encoder_get_dp_bridge_encoder_id(encoder) != ENCODER_OBJECT_ID_NONE))) {
struct drm_connector *connector = radeon_get_connector_for_encoder(encoder); struct drm_connector *connector = radeon_get_connector_for_encoder(encoder);
radeon_dp_set_link_config(connector, mode); radeon_dp_set_link_config(connector, adjusted_mode);
} }
return true; return true;

View File

@ -190,7 +190,7 @@ int create_surface(struct drm_device *dev, struct io_call_10 *pbitmap)
bitmap->page_count = size/PAGE_SIZE; bitmap->page_count = size/PAGE_SIZE;
bitmap->max_count = max_size/PAGE_SIZE; bitmap->max_count = max_size/PAGE_SIZE;
DRM_DEBUG("%s alloc %d pages\n", __FUNCTION__, page_count); // DRM_DEBUG("%s alloc %d pages\n", __FUNCTION__, page_count);
bitmap->handle = handle; bitmap->handle = handle;
bitmap->uaddr = uaddr; bitmap->uaddr = uaddr;

View File

@ -1734,7 +1734,7 @@ static void evergreen_gpu_init(struct radeon_device *rdev)
case CHIP_SUMO: case CHIP_SUMO:
rdev->config.evergreen.num_ses = 1; rdev->config.evergreen.num_ses = 1;
rdev->config.evergreen.max_pipes = 4; rdev->config.evergreen.max_pipes = 4;
rdev->config.evergreen.max_tile_pipes = 2; rdev->config.evergreen.max_tile_pipes = 4;
if (rdev->pdev->device == 0x9648) if (rdev->pdev->device == 0x9648)
rdev->config.evergreen.max_simds = 3; rdev->config.evergreen.max_simds = 3;
else if ((rdev->pdev->device == 0x9647) || else if ((rdev->pdev->device == 0x9647) ||
@ -1757,7 +1757,7 @@ static void evergreen_gpu_init(struct radeon_device *rdev)
rdev->config.evergreen.sc_prim_fifo_size = 0x40; rdev->config.evergreen.sc_prim_fifo_size = 0x40;
rdev->config.evergreen.sc_hiz_tile_fifo_size = 0x30; rdev->config.evergreen.sc_hiz_tile_fifo_size = 0x30;
rdev->config.evergreen.sc_earlyz_tile_fifo_size = 0x130; rdev->config.evergreen.sc_earlyz_tile_fifo_size = 0x130;
gb_addr_config = REDWOOD_GB_ADDR_CONFIG_GOLDEN; gb_addr_config = SUMO_GB_ADDR_CONFIG_GOLDEN;
break; break;
case CHIP_SUMO2: case CHIP_SUMO2:
rdev->config.evergreen.num_ses = 1; rdev->config.evergreen.num_ses = 1;
@ -1779,7 +1779,7 @@ static void evergreen_gpu_init(struct radeon_device *rdev)
rdev->config.evergreen.sc_prim_fifo_size = 0x40; rdev->config.evergreen.sc_prim_fifo_size = 0x40;
rdev->config.evergreen.sc_hiz_tile_fifo_size = 0x30; rdev->config.evergreen.sc_hiz_tile_fifo_size = 0x30;
rdev->config.evergreen.sc_earlyz_tile_fifo_size = 0x130; rdev->config.evergreen.sc_earlyz_tile_fifo_size = 0x130;
gb_addr_config = REDWOOD_GB_ADDR_CONFIG_GOLDEN; gb_addr_config = SUMO2_GB_ADDR_CONFIG_GOLDEN;
break; break;
case CHIP_BARTS: case CHIP_BARTS:
rdev->config.evergreen.num_ses = 2; rdev->config.evergreen.num_ses = 2;
@ -1827,7 +1827,7 @@ static void evergreen_gpu_init(struct radeon_device *rdev)
break; break;
case CHIP_CAICOS: case CHIP_CAICOS:
rdev->config.evergreen.num_ses = 1; rdev->config.evergreen.num_ses = 1;
rdev->config.evergreen.max_pipes = 4; rdev->config.evergreen.max_pipes = 2;
rdev->config.evergreen.max_tile_pipes = 2; rdev->config.evergreen.max_tile_pipes = 2;
rdev->config.evergreen.max_simds = 2; rdev->config.evergreen.max_simds = 2;
rdev->config.evergreen.max_backends = 1 * rdev->config.evergreen.num_ses; rdev->config.evergreen.max_backends = 1 * rdev->config.evergreen.num_ses;
@ -1947,6 +1947,7 @@ static void evergreen_gpu_init(struct radeon_device *rdev)
WREG32(GB_ADDR_CONFIG, gb_addr_config); WREG32(GB_ADDR_CONFIG, gb_addr_config);
WREG32(DMIF_ADDR_CONFIG, gb_addr_config); WREG32(DMIF_ADDR_CONFIG, gb_addr_config);
WREG32(HDP_ADDR_CONFIG, gb_addr_config); WREG32(HDP_ADDR_CONFIG, gb_addr_config);
WREG32(DMA_TILING_CONFIG, gb_addr_config);
tmp = gb_addr_config & NUM_PIPES_MASK; tmp = gb_addr_config & NUM_PIPES_MASK;
tmp = r6xx_remap_render_backend(rdev, tmp, rdev->config.evergreen.max_backends, tmp = r6xx_remap_render_backend(rdev, tmp, rdev->config.evergreen.max_backends,
@ -2316,8 +2317,12 @@ void evergreen_disable_interrupt_state(struct radeon_device *rdev)
CNTX_BUSY_INT_ENABLE | CNTX_EMPTY_INT_ENABLE); CNTX_BUSY_INT_ENABLE | CNTX_EMPTY_INT_ENABLE);
cayman_cp_int_cntl_setup(rdev, 1, 0); cayman_cp_int_cntl_setup(rdev, 1, 0);
cayman_cp_int_cntl_setup(rdev, 2, 0); cayman_cp_int_cntl_setup(rdev, 2, 0);
tmp = RREG32(CAYMAN_DMA1_CNTL) & ~TRAP_ENABLE;
WREG32(CAYMAN_DMA1_CNTL, tmp);
} else } else
WREG32(CP_INT_CNTL, CNTX_BUSY_INT_ENABLE | CNTX_EMPTY_INT_ENABLE); WREG32(CP_INT_CNTL, CNTX_BUSY_INT_ENABLE | CNTX_EMPTY_INT_ENABLE);
tmp = RREG32(DMA_CNTL) & ~TRAP_ENABLE;
WREG32(DMA_CNTL, tmp);
WREG32(GRBM_INT_CNTL, 0); WREG32(GRBM_INT_CNTL, 0);
WREG32(INT_MASK + EVERGREEN_CRTC0_REGISTER_OFFSET, 0); WREG32(INT_MASK + EVERGREEN_CRTC0_REGISTER_OFFSET, 0);
WREG32(INT_MASK + EVERGREEN_CRTC1_REGISTER_OFFSET, 0); WREG32(INT_MASK + EVERGREEN_CRTC1_REGISTER_OFFSET, 0);
@ -2370,6 +2375,7 @@ int evergreen_irq_set(struct radeon_device *rdev)
u32 grbm_int_cntl = 0; u32 grbm_int_cntl = 0;
u32 grph1 = 0, grph2 = 0, grph3 = 0, grph4 = 0, grph5 = 0, grph6 = 0; u32 grph1 = 0, grph2 = 0, grph3 = 0, grph4 = 0, grph5 = 0, grph6 = 0;
u32 afmt1 = 0, afmt2 = 0, afmt3 = 0, afmt4 = 0, afmt5 = 0, afmt6 = 0; u32 afmt1 = 0, afmt2 = 0, afmt3 = 0, afmt4 = 0, afmt5 = 0, afmt6 = 0;
u32 dma_cntl, dma_cntl1 = 0;
if (!rdev->irq.installed) { if (!rdev->irq.installed) {
WARN(1, "Can't enable IRQ/MSI because no handler is installed\n"); WARN(1, "Can't enable IRQ/MSI because no handler is installed\n");
@ -2397,6 +2403,8 @@ int evergreen_irq_set(struct radeon_device *rdev)
afmt5 = RREG32(AFMT_AUDIO_PACKET_CONTROL + EVERGREEN_CRTC4_REGISTER_OFFSET) & ~AFMT_AZ_FORMAT_WTRIG_MASK; afmt5 = RREG32(AFMT_AUDIO_PACKET_CONTROL + EVERGREEN_CRTC4_REGISTER_OFFSET) & ~AFMT_AZ_FORMAT_WTRIG_MASK;
afmt6 = RREG32(AFMT_AUDIO_PACKET_CONTROL + EVERGREEN_CRTC5_REGISTER_OFFSET) & ~AFMT_AZ_FORMAT_WTRIG_MASK; afmt6 = RREG32(AFMT_AUDIO_PACKET_CONTROL + EVERGREEN_CRTC5_REGISTER_OFFSET) & ~AFMT_AZ_FORMAT_WTRIG_MASK;
dma_cntl = RREG32(DMA_CNTL) & ~TRAP_ENABLE;
if (rdev->family >= CHIP_CAYMAN) { if (rdev->family >= CHIP_CAYMAN) {
/* enable CP interrupts on all rings */ /* enable CP interrupts on all rings */
if (atomic_read(&rdev->irq.ring_int[RADEON_RING_TYPE_GFX_INDEX])) { if (atomic_read(&rdev->irq.ring_int[RADEON_RING_TYPE_GFX_INDEX])) {
@ -2419,6 +2427,19 @@ int evergreen_irq_set(struct radeon_device *rdev)
} }
} }
if (atomic_read(&rdev->irq.ring_int[R600_RING_TYPE_DMA_INDEX])) {
DRM_DEBUG("r600_irq_set: sw int dma\n");
dma_cntl |= TRAP_ENABLE;
}
if (rdev->family >= CHIP_CAYMAN) {
dma_cntl1 = RREG32(CAYMAN_DMA1_CNTL) & ~TRAP_ENABLE;
if (atomic_read(&rdev->irq.ring_int[CAYMAN_RING_TYPE_DMA1_INDEX])) {
DRM_DEBUG("r600_irq_set: sw int dma1\n");
dma_cntl1 |= TRAP_ENABLE;
}
}
if (rdev->irq.crtc_vblank_int[0] || if (rdev->irq.crtc_vblank_int[0] ||
atomic_read(&rdev->irq.pflip[0])) { atomic_read(&rdev->irq.pflip[0])) {
DRM_DEBUG("evergreen_irq_set: vblank 0\n"); DRM_DEBUG("evergreen_irq_set: vblank 0\n");
@ -2504,6 +2525,12 @@ int evergreen_irq_set(struct radeon_device *rdev)
cayman_cp_int_cntl_setup(rdev, 2, cp_int_cntl2); cayman_cp_int_cntl_setup(rdev, 2, cp_int_cntl2);
} else } else
WREG32(CP_INT_CNTL, cp_int_cntl); WREG32(CP_INT_CNTL, cp_int_cntl);
WREG32(DMA_CNTL, dma_cntl);
if (rdev->family >= CHIP_CAYMAN)
WREG32(CAYMAN_DMA1_CNTL, dma_cntl1);
WREG32(GRBM_INT_CNTL, grbm_int_cntl); WREG32(GRBM_INT_CNTL, grbm_int_cntl);
WREG32(INT_MASK + EVERGREEN_CRTC0_REGISTER_OFFSET, crtc1); WREG32(INT_MASK + EVERGREEN_CRTC0_REGISTER_OFFSET, crtc1);
@ -3006,6 +3033,16 @@ restart_ih:
break; break;
} }
break; break;
case 146:
case 147:
dev_err(rdev->dev, "GPU fault detected: %d 0x%08x\n", src_id, src_data);
dev_err(rdev->dev, " VM_CONTEXT1_PROTECTION_FAULT_ADDR 0x%08X\n",
RREG32(VM_CONTEXT1_PROTECTION_FAULT_ADDR));
dev_err(rdev->dev, " VM_CONTEXT1_PROTECTION_FAULT_STATUS 0x%08X\n",
RREG32(VM_CONTEXT1_PROTECTION_FAULT_STATUS));
/* reset addr and status */
WREG32_P(VM_CONTEXT1_CNTL2, 1, ~1);
break;
case 176: /* CP_INT in ring buffer */ case 176: /* CP_INT in ring buffer */
case 177: /* CP_INT in IB1 */ case 177: /* CP_INT in IB1 */
case 178: /* CP_INT in IB2 */ case 178: /* CP_INT in IB2 */
@ -3029,9 +3066,19 @@ restart_ih:
} else } else
radeon_fence_process(rdev, RADEON_RING_TYPE_GFX_INDEX); radeon_fence_process(rdev, RADEON_RING_TYPE_GFX_INDEX);
break; break;
case 224: /* DMA trap event */
DRM_DEBUG("IH: DMA trap\n");
radeon_fence_process(rdev, R600_RING_TYPE_DMA_INDEX);
break;
case 233: /* GUI IDLE */ case 233: /* GUI IDLE */
DRM_DEBUG("IH: GUI idle\n"); DRM_DEBUG("IH: GUI idle\n");
break; break;
case 244: /* DMA trap event */
if (rdev->family >= CHIP_CAYMAN) {
DRM_DEBUG("IH: DMA1 trap\n");
radeon_fence_process(rdev, CAYMAN_RING_TYPE_DMA1_INDEX);
}
break;
default: default:
DRM_DEBUG("Unhandled interrupt: %d %d\n", src_id, src_data); DRM_DEBUG("Unhandled interrupt: %d %d\n", src_id, src_data);
break; break;
@ -3053,6 +3100,143 @@ restart_ih:
return IRQ_HANDLED; return IRQ_HANDLED;
} }
/**
* evergreen_dma_fence_ring_emit - emit a fence on the DMA ring
*
* @rdev: radeon_device pointer
* @fence: radeon fence object
*
* Add a DMA fence packet to the ring to write
* the fence seq number and DMA trap packet to generate
* an interrupt if needed (evergreen-SI).
*/
void evergreen_dma_fence_ring_emit(struct radeon_device *rdev,
struct radeon_fence *fence)
{
struct radeon_ring *ring = &rdev->ring[fence->ring];
u64 addr = rdev->fence_drv[fence->ring].gpu_addr;
/* write the fence */
radeon_ring_write(ring, DMA_PACKET(DMA_PACKET_FENCE, 0, 0, 0));
radeon_ring_write(ring, addr & 0xfffffffc);
radeon_ring_write(ring, (upper_32_bits(addr) & 0xff));
radeon_ring_write(ring, fence->seq);
/* generate an interrupt */
radeon_ring_write(ring, DMA_PACKET(DMA_PACKET_TRAP, 0, 0, 0));
/* flush HDP */
radeon_ring_write(ring, DMA_PACKET(DMA_PACKET_SRBM_WRITE, 0, 0, 0));
radeon_ring_write(ring, (0xf << 16) | HDP_MEM_COHERENCY_FLUSH_CNTL);
radeon_ring_write(ring, 1);
}
/**
* evergreen_dma_ring_ib_execute - schedule an IB on the DMA engine
*
* @rdev: radeon_device pointer
* @ib: IB object to schedule
*
* Schedule an IB in the DMA ring (evergreen).
*/
void evergreen_dma_ring_ib_execute(struct radeon_device *rdev,
struct radeon_ib *ib)
{
struct radeon_ring *ring = &rdev->ring[ib->ring];
if (rdev->wb.enabled) {
u32 next_rptr = ring->wptr + 4;
while ((next_rptr & 7) != 5)
next_rptr++;
next_rptr += 3;
radeon_ring_write(ring, DMA_PACKET(DMA_PACKET_WRITE, 0, 0, 1));
radeon_ring_write(ring, ring->next_rptr_gpu_addr & 0xfffffffc);
radeon_ring_write(ring, upper_32_bits(ring->next_rptr_gpu_addr) & 0xff);
radeon_ring_write(ring, next_rptr);
}
/* The indirect buffer packet must end on an 8 DW boundary in the DMA ring.
* Pad as necessary with NOPs.
*/
while ((ring->wptr & 7) != 5)
radeon_ring_write(ring, DMA_PACKET(DMA_PACKET_NOP, 0, 0, 0));
radeon_ring_write(ring, DMA_PACKET(DMA_PACKET_INDIRECT_BUFFER, 0, 0, 0));
radeon_ring_write(ring, (ib->gpu_addr & 0xFFFFFFE0));
radeon_ring_write(ring, (ib->length_dw << 12) | (upper_32_bits(ib->gpu_addr) & 0xFF));
}
/**
* evergreen_copy_dma - copy pages using the DMA engine
*
* @rdev: radeon_device pointer
* @src_offset: src GPU address
* @dst_offset: dst GPU address
* @num_gpu_pages: number of GPU pages to xfer
* @fence: radeon fence object
*
* Copy GPU paging using the DMA engine (evergreen-cayman).
* Used by the radeon ttm implementation to move pages if
* registered as the asic copy callback.
*/
int evergreen_copy_dma(struct radeon_device *rdev,
uint64_t src_offset, uint64_t dst_offset,
unsigned num_gpu_pages,
struct radeon_fence **fence)
{
struct radeon_semaphore *sem = NULL;
int ring_index = rdev->asic->copy.dma_ring_index;
struct radeon_ring *ring = &rdev->ring[ring_index];
u32 size_in_dw, cur_size_in_dw;
int i, num_loops;
int r = 0;
r = radeon_semaphore_create(rdev, &sem);
if (r) {
DRM_ERROR("radeon: moving bo (%d).\n", r);
return r;
}
size_in_dw = (num_gpu_pages << RADEON_GPU_PAGE_SHIFT) / 4;
num_loops = DIV_ROUND_UP(size_in_dw, 0xfffff);
r = radeon_ring_lock(rdev, ring, num_loops * 5 + 11);
if (r) {
DRM_ERROR("radeon: moving bo (%d).\n", r);
radeon_semaphore_free(rdev, &sem, NULL);
return r;
}
if (radeon_fence_need_sync(*fence, ring->idx)) {
radeon_semaphore_sync_rings(rdev, sem, (*fence)->ring,
ring->idx);
radeon_fence_note_sync(*fence, ring->idx);
} else {
radeon_semaphore_free(rdev, &sem, NULL);
}
for (i = 0; i < num_loops; i++) {
cur_size_in_dw = size_in_dw;
if (cur_size_in_dw > 0xFFFFF)
cur_size_in_dw = 0xFFFFF;
size_in_dw -= cur_size_in_dw;
radeon_ring_write(ring, DMA_PACKET(DMA_PACKET_COPY, 0, 0, cur_size_in_dw));
radeon_ring_write(ring, dst_offset & 0xfffffffc);
radeon_ring_write(ring, src_offset & 0xfffffffc);
radeon_ring_write(ring, upper_32_bits(dst_offset) & 0xff);
radeon_ring_write(ring, upper_32_bits(src_offset) & 0xff);
src_offset += cur_size_in_dw * 4;
dst_offset += cur_size_in_dw * 4;
}
r = radeon_fence_emit(rdev, fence, ring->idx);
if (r) {
radeon_ring_unlock_undo(rdev, ring);
return r;
}
radeon_ring_unlock_commit(rdev, ring);
radeon_semaphore_free(rdev, &sem, *fence);
return r;
}
static int evergreen_startup(struct radeon_device *rdev) static int evergreen_startup(struct radeon_device *rdev)
{ {
struct radeon_ring *ring = &rdev->ring[RADEON_RING_TYPE_GFX_INDEX]; struct radeon_ring *ring = &rdev->ring[RADEON_RING_TYPE_GFX_INDEX];
@ -3110,6 +3294,18 @@ static int evergreen_startup(struct radeon_device *rdev)
if (r) if (r)
return r; return r;
r = radeon_fence_driver_start_ring(rdev, RADEON_RING_TYPE_GFX_INDEX);
if (r) {
dev_err(rdev->dev, "failed initializing CP fences (%d).\n", r);
return r;
}
r = radeon_fence_driver_start_ring(rdev, R600_RING_TYPE_DMA_INDEX);
if (r) {
dev_err(rdev->dev, "failed initializing DMA fences (%d).\n", r);
return r;
}
/* Enable IRQ */ /* Enable IRQ */
r = r600_irq_init(rdev); r = r600_irq_init(rdev);
if (r) { if (r) {
@ -3124,12 +3320,29 @@ static int evergreen_startup(struct radeon_device *rdev)
0, 0xfffff, RADEON_CP_PACKET2); 0, 0xfffff, RADEON_CP_PACKET2);
if (r) if (r)
return r; return r;
ring = &rdev->ring[R600_RING_TYPE_DMA_INDEX];
r = radeon_ring_init(rdev, ring, ring->ring_size, R600_WB_DMA_RPTR_OFFSET,
DMA_RB_RPTR, DMA_RB_WPTR,
2, 0x3fffc, DMA_PACKET(DMA_PACKET_NOP, 0, 0, 0));
if (r)
return r;
r = evergreen_cp_load_microcode(rdev); r = evergreen_cp_load_microcode(rdev);
if (r) if (r)
return r; return r;
r = evergreen_cp_resume(rdev); r = evergreen_cp_resume(rdev);
if (r) if (r)
return r; return r;
r = r600_dma_resume(rdev);
if (r)
return r;
r = radeon_ib_pool_init(rdev);
if (r) {
dev_err(rdev->dev, "IB initialization failed (%d).\n", r);
return r;
}
return 0; return 0;
} }
@ -3229,6 +3442,9 @@ int evergreen_init(struct radeon_device *rdev)
rdev->ring[RADEON_RING_TYPE_GFX_INDEX].ring_obj = NULL; rdev->ring[RADEON_RING_TYPE_GFX_INDEX].ring_obj = NULL;
r600_ring_init(rdev, &rdev->ring[RADEON_RING_TYPE_GFX_INDEX], 1024 * 1024); r600_ring_init(rdev, &rdev->ring[RADEON_RING_TYPE_GFX_INDEX], 1024 * 1024);
rdev->ring[R600_RING_TYPE_DMA_INDEX].ring_obj = NULL;
r600_ring_init(rdev, &rdev->ring[R600_RING_TYPE_DMA_INDEX], 64 * 1024);
rdev->ih.ring_obj = NULL; rdev->ih.ring_obj = NULL;
r600_ih_ring_init(rdev, 64 * 1024); r600_ih_ring_init(rdev, 64 * 1024);

View File

@ -633,11 +633,6 @@ int evergreen_blit_init(struct radeon_device *rdev)
rdev->r600_blit.max_dim = 16384; rdev->r600_blit.max_dim = 16384;
/* pin copy shader into vram if already initialized */
if (rdev->r600_blit.shader_obj)
goto done;
mutex_init(&rdev->r600_blit.mutex);
rdev->r600_blit.state_offset = 0; rdev->r600_blit.state_offset = 0;
if (rdev->family < CHIP_CAYMAN) if (rdev->family < CHIP_CAYMAN)
@ -668,13 +663,28 @@ int evergreen_blit_init(struct radeon_device *rdev)
obj_size += cayman_ps_size * 4; obj_size += cayman_ps_size * 4;
obj_size = ALIGN(obj_size, 256); obj_size = ALIGN(obj_size, 256);
r = radeon_bo_create(rdev, obj_size, PAGE_SIZE, true, RADEON_GEM_DOMAIN_VRAM, /* pin copy shader into vram if not already initialized */
&rdev->r600_blit.shader_obj); if (!rdev->r600_blit.shader_obj) {
r = radeon_bo_create(rdev, obj_size, PAGE_SIZE, true,
RADEON_GEM_DOMAIN_VRAM,
NULL, &rdev->r600_blit.shader_obj);
if (r) { if (r) {
DRM_ERROR("evergreen failed to allocate shader\n"); DRM_ERROR("evergreen failed to allocate shader\n");
return r; return r;
} }
r = radeon_bo_reserve(rdev->r600_blit.shader_obj, false);
if (unlikely(r != 0))
return r;
r = radeon_bo_pin(rdev->r600_blit.shader_obj, RADEON_GEM_DOMAIN_VRAM,
&rdev->r600_blit.shader_gpu_addr);
radeon_bo_unreserve(rdev->r600_blit.shader_obj);
if (r) {
dev_err(rdev->dev, "(%d) pin blit object failed\n", r);
return r;
}
}
DRM_DEBUG("evergreen blit allocated bo %08x vs %08x ps %08x\n", DRM_DEBUG("evergreen blit allocated bo %08x vs %08x ps %08x\n",
obj_size, obj_size,
rdev->r600_blit.vs_offset, rdev->r600_blit.ps_offset); rdev->r600_blit.vs_offset, rdev->r600_blit.ps_offset);
@ -714,17 +724,6 @@ int evergreen_blit_init(struct radeon_device *rdev)
radeon_bo_kunmap(rdev->r600_blit.shader_obj); radeon_bo_kunmap(rdev->r600_blit.shader_obj);
radeon_bo_unreserve(rdev->r600_blit.shader_obj); radeon_bo_unreserve(rdev->r600_blit.shader_obj);
done:
r = radeon_bo_reserve(rdev->r600_blit.shader_obj, false);
if (unlikely(r != 0))
return r;
r = radeon_bo_pin(rdev->r600_blit.shader_obj, RADEON_GEM_DOMAIN_VRAM,
&rdev->r600_blit.shader_gpu_addr);
radeon_bo_unreserve(rdev->r600_blit.shader_obj);
if (r) {
dev_err(rdev->dev, "(%d) pin blit object failed\n", r);
return r;
}
// radeon_ttm_set_active_vram_size(rdev, rdev->mc.real_vram_size); // radeon_ttm_set_active_vram_size(rdev, rdev->mc.real_vram_size);
#endif #endif

View File

@ -45,6 +45,8 @@
#define TURKS_GB_ADDR_CONFIG_GOLDEN 0x02010002 #define TURKS_GB_ADDR_CONFIG_GOLDEN 0x02010002
#define CEDAR_GB_ADDR_CONFIG_GOLDEN 0x02010001 #define CEDAR_GB_ADDR_CONFIG_GOLDEN 0x02010001
#define CAICOS_GB_ADDR_CONFIG_GOLDEN 0x02010001 #define CAICOS_GB_ADDR_CONFIG_GOLDEN 0x02010001
#define SUMO_GB_ADDR_CONFIG_GOLDEN 0x02010002
#define SUMO2_GB_ADDR_CONFIG_GOLDEN 0x02010002
/* Registers */ /* Registers */
@ -355,6 +357,54 @@
# define AFMT_MPEG_INFO_UPDATE (1 << 10) # define AFMT_MPEG_INFO_UPDATE (1 << 10)
#define AFMT_GENERIC0_7 0x7138 #define AFMT_GENERIC0_7 0x7138
/* DCE4/5 ELD audio interface */
#define AZ_F0_CODEC_PIN0_CONTROL_AUDIO_DESCRIPTOR0 0x5f84 /* LPCM */
#define AZ_F0_CODEC_PIN0_CONTROL_AUDIO_DESCRIPTOR1 0x5f88 /* AC3 */
#define AZ_F0_CODEC_PIN0_CONTROL_AUDIO_DESCRIPTOR2 0x5f8c /* MPEG1 */
#define AZ_F0_CODEC_PIN0_CONTROL_AUDIO_DESCRIPTOR3 0x5f90 /* MP3 */
#define AZ_F0_CODEC_PIN0_CONTROL_AUDIO_DESCRIPTOR4 0x5f94 /* MPEG2 */
#define AZ_F0_CODEC_PIN0_CONTROL_AUDIO_DESCRIPTOR5 0x5f98 /* AAC */
#define AZ_F0_CODEC_PIN0_CONTROL_AUDIO_DESCRIPTOR6 0x5f9c /* DTS */
#define AZ_F0_CODEC_PIN0_CONTROL_AUDIO_DESCRIPTOR7 0x5fa0 /* ATRAC */
#define AZ_F0_CODEC_PIN0_CONTROL_AUDIO_DESCRIPTOR8 0x5fa4 /* one bit audio - leave at 0 (default) */
#define AZ_F0_CODEC_PIN0_CONTROL_AUDIO_DESCRIPTOR9 0x5fa8 /* Dolby Digital */
#define AZ_F0_CODEC_PIN0_CONTROL_AUDIO_DESCRIPTOR10 0x5fac /* DTS-HD */
#define AZ_F0_CODEC_PIN0_CONTROL_AUDIO_DESCRIPTOR11 0x5fb0 /* MAT-MLP */
#define AZ_F0_CODEC_PIN0_CONTROL_AUDIO_DESCRIPTOR12 0x5fb4 /* DTS */
#define AZ_F0_CODEC_PIN0_CONTROL_AUDIO_DESCRIPTOR13 0x5fb8 /* WMA Pro */
# define MAX_CHANNELS(x) (((x) & 0x7) << 0)
/* max channels minus one. 7 = 8 channels */
# define SUPPORTED_FREQUENCIES(x) (((x) & 0xff) << 8)
# define DESCRIPTOR_BYTE_2(x) (((x) & 0xff) << 16)
# define SUPPORTED_FREQUENCIES_STEREO(x) (((x) & 0xff) << 24) /* LPCM only */
/* SUPPORTED_FREQUENCIES, SUPPORTED_FREQUENCIES_STEREO
* bit0 = 32 kHz
* bit1 = 44.1 kHz
* bit2 = 48 kHz
* bit3 = 88.2 kHz
* bit4 = 96 kHz
* bit5 = 176.4 kHz
* bit6 = 192 kHz
*/
#define AZ_HOT_PLUG_CONTROL 0x5e78
# define AZ_FORCE_CODEC_WAKE (1 << 0)
# define PIN0_JACK_DETECTION_ENABLE (1 << 4)
# define PIN1_JACK_DETECTION_ENABLE (1 << 5)
# define PIN2_JACK_DETECTION_ENABLE (1 << 6)
# define PIN3_JACK_DETECTION_ENABLE (1 << 7)
# define PIN0_UNSOLICITED_RESPONSE_ENABLE (1 << 8)
# define PIN1_UNSOLICITED_RESPONSE_ENABLE (1 << 9)
# define PIN2_UNSOLICITED_RESPONSE_ENABLE (1 << 10)
# define PIN3_UNSOLICITED_RESPONSE_ENABLE (1 << 11)
# define CODEC_HOT_PLUG_ENABLE (1 << 12)
# define PIN0_AUDIO_ENABLED (1 << 24)
# define PIN1_AUDIO_ENABLED (1 << 25)
# define PIN2_AUDIO_ENABLED (1 << 26)
# define PIN3_AUDIO_ENABLED (1 << 27)
# define AUDIO_ENABLED (1 << 31)
#define GC_USER_SHADER_PIPE_CONFIG 0x8954 #define GC_USER_SHADER_PIPE_CONFIG 0x8954
#define INACTIVE_QD_PIPES(x) ((x) << 8) #define INACTIVE_QD_PIPES(x) ((x) << 8)
#define INACTIVE_QD_PIPES_MASK 0x0000FF00 #define INACTIVE_QD_PIPES_MASK 0x0000FF00
@ -651,6 +701,7 @@
#define PAGE_TABLE_DEPTH(x) (((x) & 3) << 1) #define PAGE_TABLE_DEPTH(x) (((x) & 3) << 1)
#define RANGE_PROTECTION_FAULT_ENABLE_DEFAULT (1 << 4) #define RANGE_PROTECTION_FAULT_ENABLE_DEFAULT (1 << 4)
#define VM_CONTEXT1_CNTL 0x1414 #define VM_CONTEXT1_CNTL 0x1414
#define VM_CONTEXT1_CNTL2 0x1434
#define VM_CONTEXT0_PAGE_TABLE_BASE_ADDR 0x153C #define VM_CONTEXT0_PAGE_TABLE_BASE_ADDR 0x153C
#define VM_CONTEXT0_PAGE_TABLE_END_ADDR 0x157C #define VM_CONTEXT0_PAGE_TABLE_END_ADDR 0x157C
#define VM_CONTEXT0_PAGE_TABLE_START_ADDR 0x155C #define VM_CONTEXT0_PAGE_TABLE_START_ADDR 0x155C
@ -672,6 +723,8 @@
#define CACHE_UPDATE_MODE(x) ((x) << 6) #define CACHE_UPDATE_MODE(x) ((x) << 6)
#define VM_L2_STATUS 0x140C #define VM_L2_STATUS 0x140C
#define L2_BUSY (1 << 0) #define L2_BUSY (1 << 0)
#define VM_CONTEXT1_PROTECTION_FAULT_ADDR 0x14FC
#define VM_CONTEXT1_PROTECTION_FAULT_STATUS 0x14DC
#define WAIT_UNTIL 0x8040 #define WAIT_UNTIL 0x8040
@ -689,6 +742,7 @@
#define SOFT_RESET_ROM (1 << 14) #define SOFT_RESET_ROM (1 << 14)
#define SOFT_RESET_SEM (1 << 15) #define SOFT_RESET_SEM (1 << 15)
#define SOFT_RESET_VMC (1 << 17) #define SOFT_RESET_VMC (1 << 17)
#define SOFT_RESET_DMA (1 << 20)
#define SOFT_RESET_TST (1 << 21) #define SOFT_RESET_TST (1 << 21)
#define SOFT_RESET_REGBB (1 << 22) #define SOFT_RESET_REGBB (1 << 22)
#define SOFT_RESET_ORB (1 << 23) #define SOFT_RESET_ORB (1 << 23)
@ -854,6 +908,37 @@
# define DC_HPDx_RX_INT_TIMER(x) ((x) << 16) # define DC_HPDx_RX_INT_TIMER(x) ((x) << 16)
# define DC_HPDx_EN (1 << 28) # define DC_HPDx_EN (1 << 28)
/* ASYNC DMA */
#define DMA_RB_RPTR 0xd008
#define DMA_RB_WPTR 0xd00c
#define DMA_CNTL 0xd02c
# define TRAP_ENABLE (1 << 0)
# define SEM_INCOMPLETE_INT_ENABLE (1 << 1)
# define SEM_WAIT_INT_ENABLE (1 << 2)
# define DATA_SWAP_ENABLE (1 << 3)
# define FENCE_SWAP_ENABLE (1 << 4)
# define CTXEMPTY_INT_ENABLE (1 << 28)
#define DMA_TILING_CONFIG 0xD0B8
#define CAYMAN_DMA1_CNTL 0xd82c
/* async DMA packets */
#define DMA_PACKET(cmd, t, s, n) ((((cmd) & 0xF) << 28) | \
(((t) & 0x1) << 23) | \
(((s) & 0x1) << 22) | \
(((n) & 0xFFFFF) << 0))
/* async DMA Packet types */
#define DMA_PACKET_WRITE 0x2
#define DMA_PACKET_COPY 0x3
#define DMA_PACKET_INDIRECT_BUFFER 0x4
#define DMA_PACKET_SEMAPHORE 0x5
#define DMA_PACKET_FENCE 0x6
#define DMA_PACKET_TRAP 0x7
#define DMA_PACKET_SRBM_WRITE 0x9
#define DMA_PACKET_CONSTANT_FILL 0xd
#define DMA_PACKET_NOP 0xf
/* PCIE link stuff */ /* PCIE link stuff */
#define PCIE_LC_TRAINING_CNTL 0xa1 /* PCIE_P */ #define PCIE_LC_TRAINING_CNTL 0xa1 /* PCIE_P */
#define PCIE_LC_LINK_WIDTH_CNTL 0xa2 /* PCIE_P */ #define PCIE_LC_LINK_WIDTH_CNTL 0xa2 /* PCIE_P */
@ -951,6 +1036,53 @@
#define PACKET3_WAIT_REG_MEM 0x3C #define PACKET3_WAIT_REG_MEM 0x3C
#define PACKET3_MEM_WRITE 0x3D #define PACKET3_MEM_WRITE 0x3D
#define PACKET3_INDIRECT_BUFFER 0x32 #define PACKET3_INDIRECT_BUFFER 0x32
#define PACKET3_CP_DMA 0x41
/* 1. header
* 2. SRC_ADDR_LO or DATA [31:0]
* 3. CP_SYNC [31] | SRC_SEL [30:29] | ENGINE [27] | DST_SEL [21:20] |
* SRC_ADDR_HI [7:0]
* 4. DST_ADDR_LO [31:0]
* 5. DST_ADDR_HI [7:0]
* 6. COMMAND [29:22] | BYTE_COUNT [20:0]
*/
# define PACKET3_CP_DMA_DST_SEL(x) ((x) << 20)
/* 0 - SRC_ADDR
* 1 - GDS
*/
# define PACKET3_CP_DMA_ENGINE(x) ((x) << 27)
/* 0 - ME
* 1 - PFP
*/
# define PACKET3_CP_DMA_SRC_SEL(x) ((x) << 29)
/* 0 - SRC_ADDR
* 1 - GDS
* 2 - DATA
*/
# define PACKET3_CP_DMA_CP_SYNC (1 << 31)
/* COMMAND */
# define PACKET3_CP_DMA_DIS_WC (1 << 21)
# define PACKET3_CP_DMA_CMD_SRC_SWAP(x) ((x) << 23)
/* 0 - none
* 1 - 8 in 16
* 2 - 8 in 32
* 3 - 8 in 64
*/
# define PACKET3_CP_DMA_CMD_DST_SWAP(x) ((x) << 24)
/* 0 - none
* 1 - 8 in 16
* 2 - 8 in 32
* 3 - 8 in 64
*/
# define PACKET3_CP_DMA_CMD_SAS (1 << 26)
/* 0 - memory
* 1 - register
*/
# define PACKET3_CP_DMA_CMD_DAS (1 << 27)
/* 0 - memory
* 1 - register
*/
# define PACKET3_CP_DMA_CMD_SAIC (1 << 28)
# define PACKET3_CP_DMA_CMD_DAIC (1 << 29)
#define PACKET3_SURFACE_SYNC 0x43 #define PACKET3_SURFACE_SYNC 0x43
# define PACKET3_CB0_DEST_BASE_ENA (1 << 6) # define PACKET3_CB0_DEST_BASE_ENA (1 << 6)
# define PACKET3_CB1_DEST_BASE_ENA (1 << 7) # define PACKET3_CB1_DEST_BASE_ENA (1 << 7)
@ -1896,4 +2028,15 @@
/* cayman packet3 addition */ /* cayman packet3 addition */
#define CAYMAN_PACKET3_DEALLOC_STATE 0x14 #define CAYMAN_PACKET3_DEALLOC_STATE 0x14
/* DMA regs common on r6xx/r7xx/evergreen/ni */
#define DMA_RB_CNTL 0xd000
# define DMA_RB_ENABLE (1 << 0)
# define DMA_RB_SIZE(x) ((x) << 1) /* log2 */
# define DMA_RB_SWAP_ENABLE (1 << 9) /* 8IN32 */
# define DMA_RPTR_WRITEBACK_ENABLE (1 << 12)
# define DMA_RPTR_WRITEBACK_SWAP_ENABLE (1 << 13) /* 8IN32 */
# define DMA_RPTR_WRITEBACK_TIMER(x) ((x) << 16) /* log2 */
#define DMA_STATUS_REG 0xd034
# define DMA_IDLE (1 << 0)
#endif #endif

View File

@ -611,6 +611,8 @@ static void cayman_gpu_init(struct radeon_device *rdev)
WREG32(GB_ADDR_CONFIG, gb_addr_config); WREG32(GB_ADDR_CONFIG, gb_addr_config);
WREG32(DMIF_ADDR_CONFIG, gb_addr_config); WREG32(DMIF_ADDR_CONFIG, gb_addr_config);
WREG32(HDP_ADDR_CONFIG, gb_addr_config); WREG32(HDP_ADDR_CONFIG, gb_addr_config);
WREG32(DMA_TILING_CONFIG + DMA0_REGISTER_OFFSET, gb_addr_config);
WREG32(DMA_TILING_CONFIG + DMA1_REGISTER_OFFSET, gb_addr_config);
tmp = gb_addr_config & NUM_PIPES_MASK; tmp = gb_addr_config & NUM_PIPES_MASK;
tmp = r6xx_remap_render_backend(rdev, tmp, tmp = r6xx_remap_render_backend(rdev, tmp,
@ -784,10 +786,20 @@ static int cayman_pcie_gart_enable(struct radeon_device *rdev)
/* enable context1-7 */ /* enable context1-7 */
WREG32(VM_CONTEXT1_PROTECTION_FAULT_DEFAULT_ADDR, WREG32(VM_CONTEXT1_PROTECTION_FAULT_DEFAULT_ADDR,
(u32)(rdev->dummy_page.addr >> 12)); (u32)(rdev->dummy_page.addr >> 12));
WREG32(VM_CONTEXT1_CNTL2, 0); WREG32(VM_CONTEXT1_CNTL2, 4);
WREG32(VM_CONTEXT1_CNTL, 0);
WREG32(VM_CONTEXT1_CNTL, ENABLE_CONTEXT | PAGE_TABLE_DEPTH(1) | WREG32(VM_CONTEXT1_CNTL, ENABLE_CONTEXT | PAGE_TABLE_DEPTH(1) |
RANGE_PROTECTION_FAULT_ENABLE_DEFAULT); RANGE_PROTECTION_FAULT_ENABLE_INTERRUPT |
RANGE_PROTECTION_FAULT_ENABLE_DEFAULT |
DUMMY_PAGE_PROTECTION_FAULT_ENABLE_INTERRUPT |
DUMMY_PAGE_PROTECTION_FAULT_ENABLE_DEFAULT |
PDE0_PROTECTION_FAULT_ENABLE_INTERRUPT |
PDE0_PROTECTION_FAULT_ENABLE_DEFAULT |
VALID_PROTECTION_FAULT_ENABLE_INTERRUPT |
VALID_PROTECTION_FAULT_ENABLE_DEFAULT |
READ_PROTECTION_FAULT_ENABLE_INTERRUPT |
READ_PROTECTION_FAULT_ENABLE_DEFAULT |
WRITE_PROTECTION_FAULT_ENABLE_INTERRUPT |
WRITE_PROTECTION_FAULT_ENABLE_DEFAULT);
cayman_pcie_gart_tlb_flush(rdev); cayman_pcie_gart_tlb_flush(rdev);
DRM_INFO("PCIE GART of %uM enabled (table at 0x%016llX).\n", DRM_INFO("PCIE GART of %uM enabled (table at 0x%016llX).\n",
@ -895,8 +907,10 @@ static void cayman_cp_enable(struct radeon_device *rdev, bool enable)
if (enable) if (enable)
WREG32(CP_ME_CNTL, 0); WREG32(CP_ME_CNTL, 0);
else { else {
radeon_ttm_set_active_vram_size(rdev, rdev->mc.visible_vram_size);
WREG32(CP_ME_CNTL, (CP_ME_HALT | CP_PFP_HALT)); WREG32(CP_ME_CNTL, (CP_ME_HALT | CP_PFP_HALT));
WREG32(SCRATCH_UMSK, 0); WREG32(SCRATCH_UMSK, 0);
rdev->ring[RADEON_RING_TYPE_GFX_INDEX].ready = false;
} }
} }
@ -1103,22 +1117,195 @@ static int cayman_cp_resume(struct radeon_device *rdev)
return 0; return 0;
} }
static int cayman_gpu_soft_reset(struct radeon_device *rdev) /*
* DMA
* Starting with R600, the GPU has an asynchronous
* DMA engine. The programming model is very similar
* to the 3D engine (ring buffer, IBs, etc.), but the
* DMA controller has it's own packet format that is
* different form the PM4 format used by the 3D engine.
* It supports copying data, writing embedded data,
* solid fills, and a number of other things. It also
* has support for tiling/detiling of buffers.
* Cayman and newer support two asynchronous DMA engines.
*/
/**
* cayman_dma_ring_ib_execute - Schedule an IB on the DMA engine
*
* @rdev: radeon_device pointer
* @ib: IB object to schedule
*
* Schedule an IB in the DMA ring (cayman-SI).
*/
void cayman_dma_ring_ib_execute(struct radeon_device *rdev,
struct radeon_ib *ib)
{
struct radeon_ring *ring = &rdev->ring[ib->ring];
if (rdev->wb.enabled) {
u32 next_rptr = ring->wptr + 4;
while ((next_rptr & 7) != 5)
next_rptr++;
next_rptr += 3;
radeon_ring_write(ring, DMA_PACKET(DMA_PACKET_WRITE, 0, 0, 1));
radeon_ring_write(ring, ring->next_rptr_gpu_addr & 0xfffffffc);
radeon_ring_write(ring, upper_32_bits(ring->next_rptr_gpu_addr) & 0xff);
radeon_ring_write(ring, next_rptr);
}
/* The indirect buffer packet must end on an 8 DW boundary in the DMA ring.
* Pad as necessary with NOPs.
*/
while ((ring->wptr & 7) != 5)
radeon_ring_write(ring, DMA_PACKET(DMA_PACKET_NOP, 0, 0, 0));
radeon_ring_write(ring, DMA_IB_PACKET(DMA_PACKET_INDIRECT_BUFFER, ib->vm ? ib->vm->id : 0, 0));
radeon_ring_write(ring, (ib->gpu_addr & 0xFFFFFFE0));
radeon_ring_write(ring, (ib->length_dw << 12) | (upper_32_bits(ib->gpu_addr) & 0xFF));
}
/**
* cayman_dma_stop - stop the async dma engines
*
* @rdev: radeon_device pointer
*
* Stop the async dma engines (cayman-SI).
*/
void cayman_dma_stop(struct radeon_device *rdev)
{
u32 rb_cntl;
radeon_ttm_set_active_vram_size(rdev, rdev->mc.visible_vram_size);
/* dma0 */
rb_cntl = RREG32(DMA_RB_CNTL + DMA0_REGISTER_OFFSET);
rb_cntl &= ~DMA_RB_ENABLE;
WREG32(DMA_RB_CNTL + DMA0_REGISTER_OFFSET, rb_cntl);
/* dma1 */
rb_cntl = RREG32(DMA_RB_CNTL + DMA1_REGISTER_OFFSET);
rb_cntl &= ~DMA_RB_ENABLE;
WREG32(DMA_RB_CNTL + DMA1_REGISTER_OFFSET, rb_cntl);
rdev->ring[R600_RING_TYPE_DMA_INDEX].ready = false;
rdev->ring[CAYMAN_RING_TYPE_DMA1_INDEX].ready = false;
}
/**
* cayman_dma_resume - setup and start the async dma engines
*
* @rdev: radeon_device pointer
*
* Set up the DMA ring buffers and enable them. (cayman-SI).
* Returns 0 for success, error for failure.
*/
int cayman_dma_resume(struct radeon_device *rdev)
{
struct radeon_ring *ring;
u32 rb_cntl, dma_cntl;
u32 rb_bufsz;
u32 reg_offset, wb_offset;
int i, r;
/* Reset dma */
WREG32(SRBM_SOFT_RESET, SOFT_RESET_DMA | SOFT_RESET_DMA1);
RREG32(SRBM_SOFT_RESET);
udelay(50);
WREG32(SRBM_SOFT_RESET, 0);
for (i = 0; i < 2; i++) {
if (i == 0) {
ring = &rdev->ring[R600_RING_TYPE_DMA_INDEX];
reg_offset = DMA0_REGISTER_OFFSET;
wb_offset = R600_WB_DMA_RPTR_OFFSET;
} else {
ring = &rdev->ring[CAYMAN_RING_TYPE_DMA1_INDEX];
reg_offset = DMA1_REGISTER_OFFSET;
wb_offset = CAYMAN_WB_DMA1_RPTR_OFFSET;
}
WREG32(DMA_SEM_INCOMPLETE_TIMER_CNTL + reg_offset, 0);
WREG32(DMA_SEM_WAIT_FAIL_TIMER_CNTL + reg_offset, 0);
/* Set ring buffer size in dwords */
rb_bufsz = drm_order(ring->ring_size / 4);
rb_cntl = rb_bufsz << 1;
#ifdef __BIG_ENDIAN
rb_cntl |= DMA_RB_SWAP_ENABLE | DMA_RPTR_WRITEBACK_SWAP_ENABLE;
#endif
WREG32(DMA_RB_CNTL + reg_offset, rb_cntl);
/* Initialize the ring buffer's read and write pointers */
WREG32(DMA_RB_RPTR + reg_offset, 0);
WREG32(DMA_RB_WPTR + reg_offset, 0);
/* set the wb address whether it's enabled or not */
WREG32(DMA_RB_RPTR_ADDR_HI + reg_offset,
upper_32_bits(rdev->wb.gpu_addr + wb_offset) & 0xFF);
WREG32(DMA_RB_RPTR_ADDR_LO + reg_offset,
((rdev->wb.gpu_addr + wb_offset) & 0xFFFFFFFC));
if (rdev->wb.enabled)
rb_cntl |= DMA_RPTR_WRITEBACK_ENABLE;
WREG32(DMA_RB_BASE + reg_offset, ring->gpu_addr >> 8);
/* enable DMA IBs */
WREG32(DMA_IB_CNTL + reg_offset, DMA_IB_ENABLE | CMD_VMID_FORCE);
dma_cntl = RREG32(DMA_CNTL + reg_offset);
dma_cntl &= ~CTXEMPTY_INT_ENABLE;
WREG32(DMA_CNTL + reg_offset, dma_cntl);
ring->wptr = 0;
WREG32(DMA_RB_WPTR + reg_offset, ring->wptr << 2);
ring->rptr = RREG32(DMA_RB_RPTR + reg_offset) >> 2;
WREG32(DMA_RB_CNTL + reg_offset, rb_cntl | DMA_RB_ENABLE);
ring->ready = true;
r = radeon_ring_test(rdev, ring->idx, ring);
if (r) {
ring->ready = false;
return r;
}
}
radeon_ttm_set_active_vram_size(rdev, rdev->mc.real_vram_size);
return 0;
}
/**
* cayman_dma_fini - tear down the async dma engines
*
* @rdev: radeon_device pointer
*
* Stop the async dma engines and free the rings (cayman-SI).
*/
void cayman_dma_fini(struct radeon_device *rdev)
{
cayman_dma_stop(rdev);
radeon_ring_fini(rdev, &rdev->ring[R600_RING_TYPE_DMA_INDEX]);
radeon_ring_fini(rdev, &rdev->ring[CAYMAN_RING_TYPE_DMA1_INDEX]);
}
static void cayman_gpu_soft_reset_gfx(struct radeon_device *rdev)
{ {
struct evergreen_mc_save save;
u32 grbm_reset = 0; u32 grbm_reset = 0;
if (!(RREG32(GRBM_STATUS) & GUI_ACTIVE)) if (!(RREG32(GRBM_STATUS) & GUI_ACTIVE))
return 0; return;
dev_info(rdev->dev, "GPU softreset \n"); dev_info(rdev->dev, " GRBM_STATUS = 0x%08X\n",
dev_info(rdev->dev, " GRBM_STATUS=0x%08X\n",
RREG32(GRBM_STATUS)); RREG32(GRBM_STATUS));
dev_info(rdev->dev, " GRBM_STATUS_SE0=0x%08X\n", dev_info(rdev->dev, " GRBM_STATUS_SE0 = 0x%08X\n",
RREG32(GRBM_STATUS_SE0)); RREG32(GRBM_STATUS_SE0));
dev_info(rdev->dev, " GRBM_STATUS_SE1=0x%08X\n", dev_info(rdev->dev, " GRBM_STATUS_SE1 = 0x%08X\n",
RREG32(GRBM_STATUS_SE1)); RREG32(GRBM_STATUS_SE1));
dev_info(rdev->dev, " SRBM_STATUS=0x%08X\n", dev_info(rdev->dev, " SRBM_STATUS = 0x%08X\n",
RREG32(SRBM_STATUS)); RREG32(SRBM_STATUS));
dev_info(rdev->dev, " R_008674_CP_STALLED_STAT1 = 0x%08X\n", dev_info(rdev->dev, " R_008674_CP_STALLED_STAT1 = 0x%08X\n",
RREG32(CP_STALLED_STAT1)); RREG32(CP_STALLED_STAT1));
@ -1128,19 +1315,7 @@ static int cayman_gpu_soft_reset(struct radeon_device *rdev)
RREG32(CP_BUSY_STAT)); RREG32(CP_BUSY_STAT));
dev_info(rdev->dev, " R_008680_CP_STAT = 0x%08X\n", dev_info(rdev->dev, " R_008680_CP_STAT = 0x%08X\n",
RREG32(CP_STAT)); RREG32(CP_STAT));
dev_info(rdev->dev, " VM_CONTEXT0_PROTECTION_FAULT_ADDR 0x%08X\n",
RREG32(0x14F8));
dev_info(rdev->dev, " VM_CONTEXT0_PROTECTION_FAULT_STATUS 0x%08X\n",
RREG32(0x14D8));
dev_info(rdev->dev, " VM_CONTEXT1_PROTECTION_FAULT_ADDR 0x%08X\n",
RREG32(0x14FC));
dev_info(rdev->dev, " VM_CONTEXT1_PROTECTION_FAULT_STATUS 0x%08X\n",
RREG32(0x14DC));
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 */ /* Disable CP parsing/prefetching */
WREG32(CP_ME_CNTL, CP_ME_HALT | CP_PFP_HALT); WREG32(CP_ME_CNTL, CP_ME_HALT | CP_PFP_HALT);
@ -1165,16 +1340,14 @@ static int cayman_gpu_soft_reset(struct radeon_device *rdev)
udelay(50); udelay(50);
WREG32(GRBM_SOFT_RESET, 0); WREG32(GRBM_SOFT_RESET, 0);
(void)RREG32(GRBM_SOFT_RESET); (void)RREG32(GRBM_SOFT_RESET);
/* Wait a little for things to settle down */
udelay(50);
dev_info(rdev->dev, " GRBM_STATUS=0x%08X\n", dev_info(rdev->dev, " GRBM_STATUS = 0x%08X\n",
RREG32(GRBM_STATUS)); RREG32(GRBM_STATUS));
dev_info(rdev->dev, " GRBM_STATUS_SE0=0x%08X\n", dev_info(rdev->dev, " GRBM_STATUS_SE0 = 0x%08X\n",
RREG32(GRBM_STATUS_SE0)); RREG32(GRBM_STATUS_SE0));
dev_info(rdev->dev, " GRBM_STATUS_SE1=0x%08X\n", dev_info(rdev->dev, " GRBM_STATUS_SE1 = 0x%08X\n",
RREG32(GRBM_STATUS_SE1)); RREG32(GRBM_STATUS_SE1));
dev_info(rdev->dev, " SRBM_STATUS=0x%08X\n", dev_info(rdev->dev, " SRBM_STATUS = 0x%08X\n",
RREG32(SRBM_STATUS)); RREG32(SRBM_STATUS));
dev_info(rdev->dev, " R_008674_CP_STALLED_STAT1 = 0x%08X\n", dev_info(rdev->dev, " R_008674_CP_STALLED_STAT1 = 0x%08X\n",
RREG32(CP_STALLED_STAT1)); RREG32(CP_STALLED_STAT1));
@ -1184,13 +1357,107 @@ static int cayman_gpu_soft_reset(struct radeon_device *rdev)
RREG32(CP_BUSY_STAT)); RREG32(CP_BUSY_STAT));
dev_info(rdev->dev, " R_008680_CP_STAT = 0x%08X\n", dev_info(rdev->dev, " R_008680_CP_STAT = 0x%08X\n",
RREG32(CP_STAT)); RREG32(CP_STAT));
}
static void cayman_gpu_soft_reset_dma(struct radeon_device *rdev)
{
u32 tmp;
if (RREG32(DMA_STATUS_REG) & DMA_IDLE)
return;
dev_info(rdev->dev, " R_00D034_DMA_STATUS_REG = 0x%08X\n",
RREG32(DMA_STATUS_REG));
/* dma0 */
tmp = RREG32(DMA_RB_CNTL + DMA0_REGISTER_OFFSET);
tmp &= ~DMA_RB_ENABLE;
WREG32(DMA_RB_CNTL + DMA0_REGISTER_OFFSET, tmp);
/* dma1 */
tmp = RREG32(DMA_RB_CNTL + DMA1_REGISTER_OFFSET);
tmp &= ~DMA_RB_ENABLE;
WREG32(DMA_RB_CNTL + DMA1_REGISTER_OFFSET, tmp);
/* Reset dma */
WREG32(SRBM_SOFT_RESET, SOFT_RESET_DMA | SOFT_RESET_DMA1);
RREG32(SRBM_SOFT_RESET);
udelay(50);
WREG32(SRBM_SOFT_RESET, 0);
dev_info(rdev->dev, " R_00D034_DMA_STATUS_REG = 0x%08X\n",
RREG32(DMA_STATUS_REG));
}
static int cayman_gpu_soft_reset(struct radeon_device *rdev, u32 reset_mask)
{
struct evergreen_mc_save save;
if (reset_mask == 0)
return 0;
dev_info(rdev->dev, "GPU softreset: 0x%08X\n", reset_mask);
dev_info(rdev->dev, " VM_CONTEXT0_PROTECTION_FAULT_ADDR 0x%08X\n",
RREG32(0x14F8));
dev_info(rdev->dev, " VM_CONTEXT0_PROTECTION_FAULT_STATUS 0x%08X\n",
RREG32(0x14D8));
dev_info(rdev->dev, " VM_CONTEXT1_PROTECTION_FAULT_ADDR 0x%08X\n",
RREG32(0x14FC));
dev_info(rdev->dev, " VM_CONTEXT1_PROTECTION_FAULT_STATUS 0x%08X\n",
RREG32(0x14DC));
evergreen_mc_stop(rdev, &save);
if (evergreen_mc_wait_for_idle(rdev)) {
dev_warn(rdev->dev, "Wait for MC idle timedout !\n");
}
if (reset_mask & (RADEON_RESET_GFX | RADEON_RESET_COMPUTE))
cayman_gpu_soft_reset_gfx(rdev);
if (reset_mask & RADEON_RESET_DMA)
cayman_gpu_soft_reset_dma(rdev);
/* Wait a little for things to settle down */
udelay(50);
evergreen_mc_resume(rdev, &save); evergreen_mc_resume(rdev, &save);
return 0; return 0;
} }
int cayman_asic_reset(struct radeon_device *rdev) int cayman_asic_reset(struct radeon_device *rdev)
{ {
return cayman_gpu_soft_reset(rdev); return cayman_gpu_soft_reset(rdev, (RADEON_RESET_GFX |
RADEON_RESET_COMPUTE |
RADEON_RESET_DMA));
}
/**
* cayman_dma_is_lockup - Check if the DMA engine is locked up
*
* @rdev: radeon_device pointer
* @ring: radeon_ring structure holding ring information
*
* Check if the async DMA engine is locked up (cayman-SI).
* Returns true if the engine appears to be locked up, false if not.
*/
bool cayman_dma_is_lockup(struct radeon_device *rdev, struct radeon_ring *ring)
{
u32 dma_status_reg;
if (ring->idx == R600_RING_TYPE_DMA_INDEX)
dma_status_reg = RREG32(DMA_STATUS_REG + DMA0_REGISTER_OFFSET);
else
dma_status_reg = RREG32(DMA_STATUS_REG + DMA1_REGISTER_OFFSET);
if (dma_status_reg & DMA_IDLE) {
radeon_ring_lockup_update(ring);
return false;
}
/* force ring activities */
radeon_ring_force_activity(rdev, ring);
return radeon_ring_test_lockup(rdev, ring);
} }
static int cayman_startup(struct radeon_device *rdev) static int cayman_startup(struct radeon_device *rdev)
@ -1256,6 +1523,36 @@ static int cayman_startup(struct radeon_device *rdev)
if (r) if (r)
return r; return r;
r = radeon_fence_driver_start_ring(rdev, RADEON_RING_TYPE_GFX_INDEX);
if (r) {
dev_err(rdev->dev, "failed initializing CP fences (%d).\n", r);
return r;
}
r = radeon_fence_driver_start_ring(rdev, CAYMAN_RING_TYPE_CP1_INDEX);
if (r) {
dev_err(rdev->dev, "failed initializing CP fences (%d).\n", r);
return r;
}
r = radeon_fence_driver_start_ring(rdev, CAYMAN_RING_TYPE_CP2_INDEX);
if (r) {
dev_err(rdev->dev, "failed initializing CP fences (%d).\n", r);
return r;
}
r = radeon_fence_driver_start_ring(rdev, R600_RING_TYPE_DMA_INDEX);
if (r) {
dev_err(rdev->dev, "failed initializing DMA fences (%d).\n", r);
return r;
}
r = radeon_fence_driver_start_ring(rdev, CAYMAN_RING_TYPE_DMA1_INDEX);
if (r) {
dev_err(rdev->dev, "failed initializing DMA fences (%d).\n", r);
return r;
}
/* Enable IRQ */ /* Enable IRQ */
r = r600_irq_init(rdev); r = r600_irq_init(rdev);
if (r) { if (r) {
@ -1270,6 +1567,23 @@ static int cayman_startup(struct radeon_device *rdev)
0, 0xfffff, RADEON_CP_PACKET2); 0, 0xfffff, RADEON_CP_PACKET2);
if (r) if (r)
return r; return r;
ring = &rdev->ring[R600_RING_TYPE_DMA_INDEX];
r = radeon_ring_init(rdev, ring, ring->ring_size, R600_WB_DMA_RPTR_OFFSET,
DMA_RB_RPTR + DMA0_REGISTER_OFFSET,
DMA_RB_WPTR + DMA0_REGISTER_OFFSET,
2, 0x3fffc, DMA_PACKET(DMA_PACKET_NOP, 0, 0, 0));
if (r)
return r;
ring = &rdev->ring[CAYMAN_RING_TYPE_DMA1_INDEX];
r = radeon_ring_init(rdev, ring, ring->ring_size, CAYMAN_WB_DMA1_RPTR_OFFSET,
DMA_RB_RPTR + DMA1_REGISTER_OFFSET,
DMA_RB_WPTR + DMA1_REGISTER_OFFSET,
2, 0x3fffc, DMA_PACKET(DMA_PACKET_NOP, 0, 0, 0));
if (r)
return r;
r = cayman_cp_load_microcode(rdev); r = cayman_cp_load_microcode(rdev);
if (r) if (r)
return r; return r;
@ -1277,6 +1591,15 @@ static int cayman_startup(struct radeon_device *rdev)
if (r) if (r)
return r; return r;
r = cayman_dma_resume(rdev);
if (r)
return r;
r = radeon_ib_pool_init(rdev);
if (r) {
dev_err(rdev->dev, "IB initialization failed (%d).\n", r);
return r;
}
return 0; return 0;
} }
@ -1344,6 +1667,14 @@ int cayman_init(struct radeon_device *rdev)
ring->ring_obj = NULL; ring->ring_obj = NULL;
r600_ring_init(rdev, ring, 1024 * 1024); r600_ring_init(rdev, ring, 1024 * 1024);
ring = &rdev->ring[R600_RING_TYPE_DMA_INDEX];
ring->ring_obj = NULL;
r600_ring_init(rdev, ring, 64 * 1024);
ring = &rdev->ring[CAYMAN_RING_TYPE_DMA1_INDEX];
ring->ring_obj = NULL;
r600_ring_init(rdev, ring, 64 * 1024);
rdev->ih.ring_obj = NULL; rdev->ih.ring_obj = NULL;
r600_ih_ring_init(rdev, 64 * 1024); r600_ih_ring_init(rdev, 64 * 1024);
@ -1431,9 +1762,12 @@ void cayman_vm_set_page(struct radeon_device *rdev, uint64_t pe,
{ {
struct radeon_ring *ring = &rdev->ring[rdev->asic->vm.pt_ring_index]; struct radeon_ring *ring = &rdev->ring[rdev->asic->vm.pt_ring_index];
uint32_t r600_flags = cayman_vm_page_flags(rdev, flags); uint32_t r600_flags = cayman_vm_page_flags(rdev, flags);
uint64_t value;
unsigned ndw;
if (rdev->asic->vm.pt_ring_index == RADEON_RING_TYPE_GFX_INDEX) {
while (count) { while (count) {
unsigned ndw = 1 + count * 2; ndw = 1 + count * 2;
if (ndw > 0x3FFF) if (ndw > 0x3FFF)
ndw = 0x3FFF; ndw = 0x3FFF;
@ -1441,22 +1775,46 @@ void cayman_vm_set_page(struct radeon_device *rdev, uint64_t pe,
radeon_ring_write(ring, pe); radeon_ring_write(ring, pe);
radeon_ring_write(ring, upper_32_bits(pe) & 0xff); radeon_ring_write(ring, upper_32_bits(pe) & 0xff);
for (; ndw > 1; ndw -= 2, --count, pe += 8) { for (; ndw > 1; ndw -= 2, --count, pe += 8) {
uint64_t value = 0;
if (flags & RADEON_VM_PAGE_SYSTEM) { if (flags & RADEON_VM_PAGE_SYSTEM) {
value = radeon_vm_map_gart(rdev, addr); value = radeon_vm_map_gart(rdev, addr);
value &= 0xFFFFFFFFFFFFF000ULL; value &= 0xFFFFFFFFFFFFF000ULL;
} else if (flags & RADEON_VM_PAGE_VALID) {
value = addr;
} else {
value = 0;
}
addr += incr; addr += incr;
value |= r600_flags;
radeon_ring_write(ring, value);
radeon_ring_write(ring, upper_32_bits(value));
}
}
} else {
while (count) {
ndw = count * 2;
if (ndw > 0xFFFFE)
ndw = 0xFFFFE;
/* for non-physically contiguous pages (system) */
radeon_ring_write(ring, DMA_PACKET(DMA_PACKET_WRITE, 0, 0, ndw));
radeon_ring_write(ring, pe);
radeon_ring_write(ring, upper_32_bits(pe) & 0xff);
for (; ndw > 0; ndw -= 2, --count, pe += 8) {
if (flags & RADEON_VM_PAGE_SYSTEM) {
value = radeon_vm_map_gart(rdev, addr);
value &= 0xFFFFFFFFFFFFF000ULL;
} else if (flags & RADEON_VM_PAGE_VALID) { } else if (flags & RADEON_VM_PAGE_VALID) {
value = addr; value = addr;
} else {
value = 0;
}
addr += incr; addr += incr;
}
value |= r600_flags; value |= r600_flags;
radeon_ring_write(ring, value); radeon_ring_write(ring, value);
radeon_ring_write(ring, upper_32_bits(value)); radeon_ring_write(ring, upper_32_bits(value));
} }
} }
}
} }
/** /**
@ -1489,3 +1847,26 @@ void cayman_vm_flush(struct radeon_device *rdev, int ridx, struct radeon_vm *vm)
radeon_ring_write(ring, PACKET3(PACKET3_PFP_SYNC_ME, 0)); radeon_ring_write(ring, PACKET3(PACKET3_PFP_SYNC_ME, 0));
radeon_ring_write(ring, 0x0); radeon_ring_write(ring, 0x0);
} }
void cayman_dma_vm_flush(struct radeon_device *rdev, int ridx, struct radeon_vm *vm)
{
struct radeon_ring *ring = &rdev->ring[ridx];
if (vm == NULL)
return;
radeon_ring_write(ring, DMA_PACKET(DMA_PACKET_SRBM_WRITE, 0, 0, 0));
radeon_ring_write(ring, (0xf << 16) | ((VM_CONTEXT0_PAGE_TABLE_BASE_ADDR + (vm->id << 2)) >> 2));
radeon_ring_write(ring, vm->pd_gpu_addr >> 12);
/* flush hdp cache */
radeon_ring_write(ring, DMA_PACKET(DMA_PACKET_SRBM_WRITE, 0, 0, 0));
radeon_ring_write(ring, (0xf << 16) | (HDP_MEM_COHERENCY_FLUSH_CNTL >> 2));
radeon_ring_write(ring, 1);
/* bits 0-7 are the VM contexts0-7 */
radeon_ring_write(ring, DMA_PACKET(DMA_PACKET_SRBM_WRITE, 0, 0, 0));
radeon_ring_write(ring, (0xf << 16) | (VM_INVALIDATE_REQUEST >> 2));
radeon_ring_write(ring, 1 << vm->id);
}

File diff suppressed because it is too large Load Diff

View File

@ -391,7 +391,6 @@ int r100_irq_process(struct radeon_device *rdev)
uint32_t status, msi_rearm; uint32_t status, msi_rearm;
bool queue_hotplug = false; bool queue_hotplug = false;
status = r100_irq_ack(rdev); status = r100_irq_ack(rdev);
if (!status) { if (!status) {
return IRQ_NONE; return IRQ_NONE;
@ -804,7 +803,16 @@ int r100_cp_init(struct radeon_device *rdev, unsigned ring_size)
return r; return r;
} }
ring->ready = true; ring->ready = true;
// radeon_ttm_set_active_vram_size(rdev, rdev->mc.real_vram_size); radeon_ttm_set_active_vram_size(rdev, rdev->mc.real_vram_size);
if (!ring->rptr_save_reg /* not resuming from suspend */
&& radeon_ring_supports_scratch_reg(rdev, ring)) {
r = radeon_scratch_get(rdev, &ring->rptr_save_reg);
if (r) {
DRM_ERROR("failed to get scratch reg for rptr save (%d).\n", r);
ring->rptr_save_reg = 0;
}
}
return 0; return 0;
} }
@ -815,6 +823,7 @@ void r100_cp_fini(struct radeon_device *rdev)
} }
/* Disable ring */ /* Disable ring */
r100_cp_disable(rdev); r100_cp_disable(rdev);
radeon_scratch_free(rdev, rdev->ring[RADEON_RING_TYPE_GFX_INDEX].rptr_save_reg);
radeon_ring_fini(rdev, &rdev->ring[RADEON_RING_TYPE_GFX_INDEX]); radeon_ring_fini(rdev, &rdev->ring[RADEON_RING_TYPE_GFX_INDEX]);
DRM_INFO("radeon: cp finalized\n"); DRM_INFO("radeon: cp finalized\n");
} }
@ -822,7 +831,7 @@ void r100_cp_fini(struct radeon_device *rdev)
void r100_cp_disable(struct radeon_device *rdev) void r100_cp_disable(struct radeon_device *rdev)
{ {
/* Disable ring */ /* Disable ring */
// radeon_ttm_set_active_vram_size(rdev, rdev->mc.visible_vram_size); radeon_ttm_set_active_vram_size(rdev, rdev->mc.visible_vram_size);
rdev->ring[RADEON_RING_TYPE_GFX_INDEX].ready = false; rdev->ring[RADEON_RING_TYPE_GFX_INDEX].ready = false;
WREG32(RADEON_CP_CSQ_MODE, 0); WREG32(RADEON_CP_CSQ_MODE, 0);
WREG32(RADEON_CP_CSQ_CNTL, 0); WREG32(RADEON_CP_CSQ_CNTL, 0);
@ -3708,23 +3717,36 @@ int r100_init(struct radeon_device *rdev)
return 0; return 0;
} }
uint32_t r100_mm_rreg(struct radeon_device *rdev, uint32_t reg) uint32_t r100_mm_rreg(struct radeon_device *rdev, uint32_t reg,
bool always_indirect)
{ {
if (reg < rdev->rmmio_size) if (reg < rdev->rmmio_size && !always_indirect)
return readl(((void __iomem *)rdev->rmmio) + reg); return readl(((void __iomem *)rdev->rmmio) + reg);
else { else {
unsigned long flags;
uint32_t ret;
spin_lock_irqsave(&rdev->mmio_idx_lock, flags);
writel(reg, ((void __iomem *)rdev->rmmio) + RADEON_MM_INDEX); writel(reg, ((void __iomem *)rdev->rmmio) + RADEON_MM_INDEX);
return readl(((void __iomem *)rdev->rmmio) + RADEON_MM_DATA); ret = readl(((void __iomem *)rdev->rmmio) + RADEON_MM_DATA);
spin_unlock_irqrestore(&rdev->mmio_idx_lock, flags);
return ret;
} }
} }
void r100_mm_wreg(struct radeon_device *rdev, uint32_t reg, uint32_t v) void r100_mm_wreg(struct radeon_device *rdev, uint32_t reg, uint32_t v,
bool always_indirect)
{ {
if (reg < rdev->rmmio_size) if (reg < rdev->rmmio_size && !always_indirect)
writel(v, ((void __iomem *)rdev->rmmio) + reg); writel(v, ((void __iomem *)rdev->rmmio) + reg);
else { else {
unsigned long flags;
spin_lock_irqsave(&rdev->mmio_idx_lock, flags);
writel(reg, ((void __iomem *)rdev->rmmio) + RADEON_MM_INDEX); writel(reg, ((void __iomem *)rdev->rmmio) + RADEON_MM_INDEX);
writel(v, ((void __iomem *)rdev->rmmio) + RADEON_MM_DATA); writel(v, ((void __iomem *)rdev->rmmio) + RADEON_MM_DATA);
spin_unlock_irqrestore(&rdev->mmio_idx_lock, flags);
} }
} }

View File

@ -812,9 +812,8 @@ int r600_vram_scratch_init(struct radeon_device *rdev)
* reset, it's up to the caller to determine if the GPU needs one. We * reset, it's up to the caller to determine if the GPU needs one. We
* might add an helper function to check that. * might add an helper function to check that.
*/ */
static int r600_gpu_soft_reset(struct radeon_device *rdev) static void r600_gpu_soft_reset_gfx(struct radeon_device *rdev)
{ {
struct rv515_mc_save save;
u32 grbm_busy_mask = S_008010_VC_BUSY(1) | S_008010_VGT_BUSY_NO_DMA(1) | u32 grbm_busy_mask = S_008010_VC_BUSY(1) | S_008010_VGT_BUSY_NO_DMA(1) |
S_008010_VGT_BUSY(1) | S_008010_TA03_BUSY(1) | S_008010_VGT_BUSY(1) | S_008010_TA03_BUSY(1) |
S_008010_TC_BUSY(1) | S_008010_SX_BUSY(1) | S_008010_TC_BUSY(1) | S_008010_SX_BUSY(1) |
@ -834,14 +833,13 @@ static int r600_gpu_soft_reset(struct radeon_device *rdev)
u32 tmp; u32 tmp;
if (!(RREG32(GRBM_STATUS) & GUI_ACTIVE)) if (!(RREG32(GRBM_STATUS) & GUI_ACTIVE))
return 0; return;
dev_info(rdev->dev, "GPU softreset \n"); dev_info(rdev->dev, " R_008010_GRBM_STATUS = 0x%08X\n",
dev_info(rdev->dev, " R_008010_GRBM_STATUS=0x%08X\n",
RREG32(R_008010_GRBM_STATUS)); RREG32(R_008010_GRBM_STATUS));
dev_info(rdev->dev, " R_008014_GRBM_STATUS2=0x%08X\n", dev_info(rdev->dev, " R_008014_GRBM_STATUS2 = 0x%08X\n",
RREG32(R_008014_GRBM_STATUS2)); RREG32(R_008014_GRBM_STATUS2));
dev_info(rdev->dev, " R_000E50_SRBM_STATUS=0x%08X\n", dev_info(rdev->dev, " R_000E50_SRBM_STATUS = 0x%08X\n",
RREG32(R_000E50_SRBM_STATUS)); RREG32(R_000E50_SRBM_STATUS));
dev_info(rdev->dev, " R_008674_CP_STALLED_STAT1 = 0x%08X\n", dev_info(rdev->dev, " R_008674_CP_STALLED_STAT1 = 0x%08X\n",
RREG32(CP_STALLED_STAT1)); RREG32(CP_STALLED_STAT1));
@ -851,12 +849,10 @@ static int r600_gpu_soft_reset(struct radeon_device *rdev)
RREG32(CP_BUSY_STAT)); RREG32(CP_BUSY_STAT));
dev_info(rdev->dev, " R_008680_CP_STAT = 0x%08X\n", dev_info(rdev->dev, " R_008680_CP_STAT = 0x%08X\n",
RREG32(CP_STAT)); RREG32(CP_STAT));
rv515_mc_stop(rdev, &save);
if (r600_mc_wait_for_idle(rdev)) {
dev_warn(rdev->dev, "Wait for MC idle timedout !\n");
}
/* Disable CP parsing/prefetching */ /* Disable CP parsing/prefetching */
WREG32(R_0086D8_CP_ME_CNTL, S_0086D8_CP_ME_HALT(1)); WREG32(R_0086D8_CP_ME_CNTL, S_0086D8_CP_ME_HALT(1));
/* Check if any of the rendering block is busy and reset it */ /* Check if any of the rendering block is busy and reset it */
if ((RREG32(R_008010_GRBM_STATUS) & grbm_busy_mask) || if ((RREG32(R_008010_GRBM_STATUS) & grbm_busy_mask) ||
(RREG32(R_008014_GRBM_STATUS2) & grbm2_busy_mask)) { (RREG32(R_008014_GRBM_STATUS2) & grbm2_busy_mask)) {
@ -886,13 +882,12 @@ static int r600_gpu_soft_reset(struct radeon_device *rdev)
RREG32(R_008020_GRBM_SOFT_RESET); RREG32(R_008020_GRBM_SOFT_RESET);
mdelay(15); mdelay(15);
WREG32(R_008020_GRBM_SOFT_RESET, 0); WREG32(R_008020_GRBM_SOFT_RESET, 0);
/* Wait a little for things to settle down */
mdelay(1); dev_info(rdev->dev, " R_008010_GRBM_STATUS = 0x%08X\n",
dev_info(rdev->dev, " R_008010_GRBM_STATUS=0x%08X\n",
RREG32(R_008010_GRBM_STATUS)); RREG32(R_008010_GRBM_STATUS));
dev_info(rdev->dev, " R_008014_GRBM_STATUS2=0x%08X\n", dev_info(rdev->dev, " R_008014_GRBM_STATUS2 = 0x%08X\n",
RREG32(R_008014_GRBM_STATUS2)); RREG32(R_008014_GRBM_STATUS2));
dev_info(rdev->dev, " R_000E50_SRBM_STATUS=0x%08X\n", dev_info(rdev->dev, " R_000E50_SRBM_STATUS = 0x%08X\n",
RREG32(R_000E50_SRBM_STATUS)); RREG32(R_000E50_SRBM_STATUS));
dev_info(rdev->dev, " R_008674_CP_STALLED_STAT1 = 0x%08X\n", dev_info(rdev->dev, " R_008674_CP_STALLED_STAT1 = 0x%08X\n",
RREG32(CP_STALLED_STAT1)); RREG32(CP_STALLED_STAT1));
@ -902,6 +897,60 @@ static int r600_gpu_soft_reset(struct radeon_device *rdev)
RREG32(CP_BUSY_STAT)); RREG32(CP_BUSY_STAT));
dev_info(rdev->dev, " R_008680_CP_STAT = 0x%08X\n", dev_info(rdev->dev, " R_008680_CP_STAT = 0x%08X\n",
RREG32(CP_STAT)); RREG32(CP_STAT));
}
static void r600_gpu_soft_reset_dma(struct radeon_device *rdev)
{
u32 tmp;
if (RREG32(DMA_STATUS_REG) & DMA_IDLE)
return;
dev_info(rdev->dev, " R_00D034_DMA_STATUS_REG = 0x%08X\n",
RREG32(DMA_STATUS_REG));
/* Disable DMA */
tmp = RREG32(DMA_RB_CNTL);
tmp &= ~DMA_RB_ENABLE;
WREG32(DMA_RB_CNTL, tmp);
/* Reset dma */
if (rdev->family >= CHIP_RV770)
WREG32(SRBM_SOFT_RESET, RV770_SOFT_RESET_DMA);
else
WREG32(SRBM_SOFT_RESET, SOFT_RESET_DMA);
RREG32(SRBM_SOFT_RESET);
udelay(50);
WREG32(SRBM_SOFT_RESET, 0);
dev_info(rdev->dev, " R_00D034_DMA_STATUS_REG = 0x%08X\n",
RREG32(DMA_STATUS_REG));
}
static int r600_gpu_soft_reset(struct radeon_device *rdev, u32 reset_mask)
{
struct rv515_mc_save save;
if (reset_mask == 0)
return 0;
dev_info(rdev->dev, "GPU softreset: 0x%08X\n", reset_mask);
rv515_mc_stop(rdev, &save);
if (r600_mc_wait_for_idle(rdev)) {
dev_warn(rdev->dev, "Wait for MC idle timedout !\n");
}
if (reset_mask & (RADEON_RESET_GFX | RADEON_RESET_COMPUTE))
r600_gpu_soft_reset_gfx(rdev);
if (reset_mask & RADEON_RESET_DMA)
r600_gpu_soft_reset_dma(rdev);
/* Wait a little for things to settle down */
mdelay(1);
rv515_mc_resume(rdev, &save); rv515_mc_resume(rdev, &save);
return 0; return 0;
} }
@ -924,9 +973,34 @@ bool r600_gpu_is_lockup(struct radeon_device *rdev, struct radeon_ring *ring)
return radeon_ring_test_lockup(rdev, ring); return radeon_ring_test_lockup(rdev, ring);
} }
/**
* r600_dma_is_lockup - Check if the DMA engine is locked up
*
* @rdev: radeon_device pointer
* @ring: radeon_ring structure holding ring information
*
* Check if the async DMA engine is locked up (r6xx-evergreen).
* Returns true if the engine appears to be locked up, false if not.
*/
bool r600_dma_is_lockup(struct radeon_device *rdev, struct radeon_ring *ring)
{
u32 dma_status_reg;
dma_status_reg = RREG32(DMA_STATUS_REG);
if (dma_status_reg & DMA_IDLE) {
radeon_ring_lockup_update(ring);
return false;
}
/* force ring activities */
radeon_ring_force_activity(rdev, ring);
return radeon_ring_test_lockup(rdev, ring);
}
int r600_asic_reset(struct radeon_device *rdev) int r600_asic_reset(struct radeon_device *rdev)
{ {
return r600_gpu_soft_reset(rdev); return r600_gpu_soft_reset(rdev, (RADEON_RESET_GFX |
RADEON_RESET_COMPUTE |
RADEON_RESET_DMA));
} }
u32 r6xx_remap_render_backend(struct radeon_device *rdev, u32 r6xx_remap_render_backend(struct radeon_device *rdev,
@ -978,13 +1052,7 @@ u32 r6xx_remap_render_backend(struct radeon_device *rdev,
int r600_count_pipe_bits(uint32_t val) int r600_count_pipe_bits(uint32_t val)
{ {
int i, ret = 0; return hweight32(val);
for (i = 0; i < 32; i++) {
ret += val & 1;
val >>= 1;
}
return ret;
} }
static void r600_gpu_init(struct radeon_device *rdev) static void r600_gpu_init(struct radeon_device *rdev)
@ -1148,6 +1216,7 @@ static void r600_gpu_init(struct radeon_device *rdev)
WREG32(GB_TILING_CONFIG, tiling_config); WREG32(GB_TILING_CONFIG, tiling_config);
WREG32(DCP_TILING_CONFIG, tiling_config & 0xffff); WREG32(DCP_TILING_CONFIG, tiling_config & 0xffff);
WREG32(HDP_TILING_CONFIG, tiling_config & 0xffff); WREG32(HDP_TILING_CONFIG, tiling_config & 0xffff);
WREG32(DMA_TILING_CONFIG, tiling_config & 0xffff);
tmp = R6XX_MAX_PIPES - r600_count_pipe_bits((cc_gc_shader_pipe_config & INACTIVE_QD_PIPES_MASK) >> 8); tmp = R6XX_MAX_PIPES - r600_count_pipe_bits((cc_gc_shader_pipe_config & INACTIVE_QD_PIPES_MASK) >> 8);
WREG32(VGT_OUT_DEALLOC_CNTL, (tmp * 4) & DEALLOC_DIST_MASK); WREG32(VGT_OUT_DEALLOC_CNTL, (tmp * 4) & DEALLOC_DIST_MASK);
@ -1422,9 +1491,10 @@ void r600_pciep_wreg(struct radeon_device *rdev, u32 reg, u32 v)
*/ */
void r600_cp_stop(struct radeon_device *rdev) void r600_cp_stop(struct radeon_device *rdev)
{ {
// radeon_ttm_set_active_vram_size(rdev, rdev->mc.visible_vram_size); radeon_ttm_set_active_vram_size(rdev, rdev->mc.visible_vram_size);
WREG32(R_0086D8_CP_ME_CNTL, S_0086D8_CP_ME_HALT(1)); WREG32(R_0086D8_CP_ME_CNTL, S_0086D8_CP_ME_HALT(1));
WREG32(SCRATCH_UMSK, 0); WREG32(SCRATCH_UMSK, 0);
rdev->ring[RADEON_RING_TYPE_GFX_INDEX].ready = false;
} }
int r600_init_microcode(struct radeon_device *rdev) int r600_init_microcode(struct radeon_device *rdev)
@ -1750,6 +1820,128 @@ void r600_cp_fini(struct radeon_device *rdev)
radeon_scratch_free(rdev, ring->rptr_save_reg); radeon_scratch_free(rdev, ring->rptr_save_reg);
} }
/*
* DMA
* Starting with R600, the GPU has an asynchronous
* DMA engine. The programming model is very similar
* to the 3D engine (ring buffer, IBs, etc.), but the
* DMA controller has it's own packet format that is
* different form the PM4 format used by the 3D engine.
* It supports copying data, writing embedded data,
* solid fills, and a number of other things. It also
* has support for tiling/detiling of buffers.
*/
/**
* r600_dma_stop - stop the async dma engine
*
* @rdev: radeon_device pointer
*
* Stop the async dma engine (r6xx-evergreen).
*/
void r600_dma_stop(struct radeon_device *rdev)
{
u32 rb_cntl = RREG32(DMA_RB_CNTL);
radeon_ttm_set_active_vram_size(rdev, rdev->mc.visible_vram_size);
rb_cntl &= ~DMA_RB_ENABLE;
WREG32(DMA_RB_CNTL, rb_cntl);
rdev->ring[R600_RING_TYPE_DMA_INDEX].ready = false;
}
/**
* r600_dma_resume - setup and start the async dma engine
*
* @rdev: radeon_device pointer
*
* Set up the DMA ring buffer and enable it. (r6xx-evergreen).
* Returns 0 for success, error for failure.
*/
int r600_dma_resume(struct radeon_device *rdev)
{
struct radeon_ring *ring = &rdev->ring[R600_RING_TYPE_DMA_INDEX];
u32 rb_cntl, dma_cntl;
u32 rb_bufsz;
int r;
/* Reset dma */
if (rdev->family >= CHIP_RV770)
WREG32(SRBM_SOFT_RESET, RV770_SOFT_RESET_DMA);
else
WREG32(SRBM_SOFT_RESET, SOFT_RESET_DMA);
RREG32(SRBM_SOFT_RESET);
udelay(50);
WREG32(SRBM_SOFT_RESET, 0);
WREG32(DMA_SEM_INCOMPLETE_TIMER_CNTL, 0);
WREG32(DMA_SEM_WAIT_FAIL_TIMER_CNTL, 0);
/* Set ring buffer size in dwords */
rb_bufsz = drm_order(ring->ring_size / 4);
rb_cntl = rb_bufsz << 1;
#ifdef __BIG_ENDIAN
rb_cntl |= DMA_RB_SWAP_ENABLE | DMA_RPTR_WRITEBACK_SWAP_ENABLE;
#endif
WREG32(DMA_RB_CNTL, rb_cntl);
/* Initialize the ring buffer's read and write pointers */
WREG32(DMA_RB_RPTR, 0);
WREG32(DMA_RB_WPTR, 0);
/* set the wb address whether it's enabled or not */
WREG32(DMA_RB_RPTR_ADDR_HI,
upper_32_bits(rdev->wb.gpu_addr + R600_WB_DMA_RPTR_OFFSET) & 0xFF);
WREG32(DMA_RB_RPTR_ADDR_LO,
((rdev->wb.gpu_addr + R600_WB_DMA_RPTR_OFFSET) & 0xFFFFFFFC));
if (rdev->wb.enabled)
rb_cntl |= DMA_RPTR_WRITEBACK_ENABLE;
WREG32(DMA_RB_BASE, ring->gpu_addr >> 8);
/* enable DMA IBs */
WREG32(DMA_IB_CNTL, DMA_IB_ENABLE);
dma_cntl = RREG32(DMA_CNTL);
dma_cntl &= ~CTXEMPTY_INT_ENABLE;
WREG32(DMA_CNTL, dma_cntl);
if (rdev->family >= CHIP_RV770)
WREG32(DMA_MODE, 1);
ring->wptr = 0;
WREG32(DMA_RB_WPTR, ring->wptr << 2);
ring->rptr = RREG32(DMA_RB_RPTR) >> 2;
WREG32(DMA_RB_CNTL, rb_cntl | DMA_RB_ENABLE);
ring->ready = true;
r = radeon_ring_test(rdev, R600_RING_TYPE_DMA_INDEX, ring);
if (r) {
ring->ready = false;
return r;
}
radeon_ttm_set_active_vram_size(rdev, rdev->mc.real_vram_size);
return 0;
}
/**
* r600_dma_fini - tear down the async dma engine
*
* @rdev: radeon_device pointer
*
* Stop the async dma engine and free the ring (r6xx-evergreen).
*/
void r600_dma_fini(struct radeon_device *rdev)
{
r600_dma_stop(rdev);
radeon_ring_fini(rdev, &rdev->ring[R600_RING_TYPE_DMA_INDEX]);
}
/* /*
* GPU scratch registers helpers function. * GPU scratch registers helpers function.
@ -1806,6 +1998,64 @@ int r600_ring_test(struct radeon_device *rdev, struct radeon_ring *ring)
return r; return r;
} }
/**
* r600_dma_ring_test - simple async dma engine test
*
* @rdev: radeon_device pointer
* @ring: radeon_ring structure holding ring information
*
* Test the DMA engine by writing using it to write an
* value to memory. (r6xx-SI).
* Returns 0 for success, error for failure.
*/
int r600_dma_ring_test(struct radeon_device *rdev,
struct radeon_ring *ring)
{
unsigned i;
int r;
void __iomem *ptr = (void *)rdev->vram_scratch.ptr;
u32 tmp;
if (!ptr) {
DRM_ERROR("invalid vram scratch pointer\n");
return -EINVAL;
}
tmp = 0xCAFEDEAD;
writel(tmp, ptr);
r = radeon_ring_lock(rdev, ring, 4);
if (r) {
DRM_ERROR("radeon: dma failed to lock ring %d (%d).\n", ring->idx, r);
return r;
}
radeon_ring_write(ring, DMA_PACKET(DMA_PACKET_WRITE, 0, 0, 1));
radeon_ring_write(ring, rdev->vram_scratch.gpu_addr & 0xfffffffc);
radeon_ring_write(ring, upper_32_bits(rdev->vram_scratch.gpu_addr) & 0xff);
radeon_ring_write(ring, 0xDEADBEEF);
radeon_ring_unlock_commit(rdev, ring);
for (i = 0; i < rdev->usec_timeout; i++) {
tmp = readl(ptr);
if (tmp == 0xDEADBEEF)
break;
DRM_UDELAY(1);
}
if (i < rdev->usec_timeout) {
DRM_INFO("ring test on %d succeeded in %d usecs\n", ring->idx, i);
} else {
DRM_ERROR("radeon: ring %d test failed (0x%08X)\n",
ring->idx, tmp);
r = -EINVAL;
}
return r;
}
/*
* CP fences/semaphores
*/
void r600_fence_ring_emit(struct radeon_device *rdev, void r600_fence_ring_emit(struct radeon_device *rdev,
struct radeon_fence *fence) struct radeon_fence *fence)
{ {
@ -1869,6 +2119,59 @@ void r600_semaphore_ring_emit(struct radeon_device *rdev,
radeon_ring_write(ring, (upper_32_bits(addr) & 0xff) | sel); radeon_ring_write(ring, (upper_32_bits(addr) & 0xff) | sel);
} }
/*
* DMA fences/semaphores
*/
/**
* r600_dma_fence_ring_emit - emit a fence on the DMA ring
*
* @rdev: radeon_device pointer
* @fence: radeon fence object
*
* Add a DMA fence packet to the ring to write
* the fence seq number and DMA trap packet to generate
* an interrupt if needed (r6xx-r7xx).
*/
void r600_dma_fence_ring_emit(struct radeon_device *rdev,
struct radeon_fence *fence)
{
struct radeon_ring *ring = &rdev->ring[fence->ring];
u64 addr = rdev->fence_drv[fence->ring].gpu_addr;
/* write the fence */
radeon_ring_write(ring, DMA_PACKET(DMA_PACKET_FENCE, 0, 0, 0));
radeon_ring_write(ring, addr & 0xfffffffc);
radeon_ring_write(ring, (upper_32_bits(addr) & 0xff));
radeon_ring_write(ring, lower_32_bits(fence->seq));
/* generate an interrupt */
radeon_ring_write(ring, DMA_PACKET(DMA_PACKET_TRAP, 0, 0, 0));
}
/**
* r600_dma_semaphore_ring_emit - emit a semaphore on the dma ring
*
* @rdev: radeon_device pointer
* @ring: radeon_ring structure holding ring information
* @semaphore: radeon semaphore object
* @emit_wait: wait or signal semaphore
*
* Add a DMA semaphore packet to the ring wait on or signal
* other rings (r6xx-SI).
*/
void r600_dma_semaphore_ring_emit(struct radeon_device *rdev,
struct radeon_ring *ring,
struct radeon_semaphore *semaphore,
bool emit_wait)
{
u64 addr = semaphore->gpu_addr;
u32 s = emit_wait ? 0 : 1;
radeon_ring_write(ring, DMA_PACKET(DMA_PACKET_SEMAPHORE, 0, s, 0));
radeon_ring_write(ring, addr & 0xfffffffc);
radeon_ring_write(ring, upper_32_bits(addr) & 0xff);
}
int r600_copy_blit(struct radeon_device *rdev, int r600_copy_blit(struct radeon_device *rdev,
uint64_t src_offset, uint64_t src_offset,
uint64_t dst_offset, uint64_t dst_offset,
@ -1888,6 +2191,80 @@ int r600_copy_blit(struct radeon_device *rdev,
return 0; return 0;
} }
/**
* r600_copy_dma - copy pages using the DMA engine
*
* @rdev: radeon_device pointer
* @src_offset: src GPU address
* @dst_offset: dst GPU address
* @num_gpu_pages: number of GPU pages to xfer
* @fence: radeon fence object
*
* Copy GPU paging using the DMA engine (r6xx).
* Used by the radeon ttm implementation to move pages if
* registered as the asic copy callback.
*/
int r600_copy_dma(struct radeon_device *rdev,
uint64_t src_offset, uint64_t dst_offset,
unsigned num_gpu_pages,
struct radeon_fence **fence)
{
struct radeon_semaphore *sem = NULL;
int ring_index = rdev->asic->copy.dma_ring_index;
struct radeon_ring *ring = &rdev->ring[ring_index];
u32 size_in_dw, cur_size_in_dw;
int i, num_loops;
int r = 0;
r = radeon_semaphore_create(rdev, &sem);
if (r) {
DRM_ERROR("radeon: moving bo (%d).\n", r);
return r;
}
size_in_dw = (num_gpu_pages << RADEON_GPU_PAGE_SHIFT) / 4;
num_loops = DIV_ROUND_UP(size_in_dw, 0xFFFE);
r = radeon_ring_lock(rdev, ring, num_loops * 4 + 8);
if (r) {
DRM_ERROR("radeon: moving bo (%d).\n", r);
radeon_semaphore_free(rdev, &sem, NULL);
return r;
}
if (radeon_fence_need_sync(*fence, ring->idx)) {
radeon_semaphore_sync_rings(rdev, sem, (*fence)->ring,
ring->idx);
radeon_fence_note_sync(*fence, ring->idx);
} else {
radeon_semaphore_free(rdev, &sem, NULL);
}
for (i = 0; i < num_loops; i++) {
cur_size_in_dw = size_in_dw;
if (cur_size_in_dw > 0xFFFE)
cur_size_in_dw = 0xFFFE;
size_in_dw -= cur_size_in_dw;
radeon_ring_write(ring, DMA_PACKET(DMA_PACKET_COPY, 0, 0, cur_size_in_dw));
radeon_ring_write(ring, dst_offset & 0xfffffffc);
radeon_ring_write(ring, src_offset & 0xfffffffc);
radeon_ring_write(ring, (((upper_32_bits(dst_offset) & 0xff) << 16) |
(upper_32_bits(src_offset) & 0xff)));
src_offset += cur_size_in_dw * 4;
dst_offset += cur_size_in_dw * 4;
}
r = radeon_fence_emit(rdev, fence, ring->idx);
if (r) {
radeon_ring_unlock_undo(rdev, ring);
return r;
}
radeon_ring_unlock_commit(rdev, ring);
radeon_semaphore_free(rdev, &sem, *fence);
return r;
}
int r600_set_surface_reg(struct radeon_device *rdev, int reg, int r600_set_surface_reg(struct radeon_device *rdev, int reg,
uint32_t tiling_flags, uint32_t pitch, uint32_t tiling_flags, uint32_t pitch,
uint32_t offset, uint32_t obj_size) uint32_t offset, uint32_t obj_size)
@ -1903,7 +2280,7 @@ void r600_clear_surface_reg(struct radeon_device *rdev, int reg)
static int r600_startup(struct radeon_device *rdev) static int r600_startup(struct radeon_device *rdev)
{ {
struct radeon_ring *ring = &rdev->ring[RADEON_RING_TYPE_GFX_INDEX]; struct radeon_ring *ring;
int r; int r;
/* enable pcie gen2 link */ /* enable pcie gen2 link */
@ -1938,6 +2315,18 @@ static int r600_startup(struct radeon_device *rdev)
if (r) if (r)
return r; return r;
r = radeon_fence_driver_start_ring(rdev, RADEON_RING_TYPE_GFX_INDEX);
if (r) {
dev_err(rdev->dev, "failed initializing CP fences (%d).\n", r);
return r;
}
r = radeon_fence_driver_start_ring(rdev, R600_RING_TYPE_DMA_INDEX);
if (r) {
dev_err(rdev->dev, "failed initializing DMA fences (%d).\n", r);
return r;
}
/* Enable IRQ */ /* Enable IRQ */
r = r600_irq_init(rdev); r = r600_irq_init(rdev);
if (r) { if (r) {
@ -1947,12 +2336,20 @@ static int r600_startup(struct radeon_device *rdev)
} }
r600_irq_set(rdev); r600_irq_set(rdev);
ring = &rdev->ring[RADEON_RING_TYPE_GFX_INDEX];
r = radeon_ring_init(rdev, ring, ring->ring_size, RADEON_WB_CP_RPTR_OFFSET, r = radeon_ring_init(rdev, ring, ring->ring_size, RADEON_WB_CP_RPTR_OFFSET,
R600_CP_RB_RPTR, R600_CP_RB_WPTR, R600_CP_RB_RPTR, R600_CP_RB_WPTR,
0, 0xfffff, RADEON_CP_PACKET2); 0, 0xfffff, RADEON_CP_PACKET2);
if (r) if (r)
return r; return r;
ring = &rdev->ring[R600_RING_TYPE_DMA_INDEX];
r = radeon_ring_init(rdev, ring, ring->ring_size, R600_WB_DMA_RPTR_OFFSET,
DMA_RB_RPTR, DMA_RB_WPTR,
2, 0x3fffc, DMA_PACKET(DMA_PACKET_NOP, 0, 0, 0));
if (r)
return r;
r = r600_cp_load_microcode(rdev); r = r600_cp_load_microcode(rdev);
if (r) if (r)
return r; return r;
@ -1960,6 +2357,15 @@ static int r600_startup(struct radeon_device *rdev)
if (r) if (r)
return r; return r;
r = r600_dma_resume(rdev);
if (r)
return r;
r = radeon_ib_pool_init(rdev);
if (r) {
dev_err(rdev->dev, "IB initialization failed (%d).\n", r);
return r;
}
return 0; return 0;
} }
@ -2046,6 +2452,9 @@ int r600_init(struct radeon_device *rdev)
rdev->ring[RADEON_RING_TYPE_GFX_INDEX].ring_obj = NULL; rdev->ring[RADEON_RING_TYPE_GFX_INDEX].ring_obj = NULL;
r600_ring_init(rdev, &rdev->ring[RADEON_RING_TYPE_GFX_INDEX], 1024 * 1024); r600_ring_init(rdev, &rdev->ring[RADEON_RING_TYPE_GFX_INDEX], 1024 * 1024);
rdev->ring[R600_RING_TYPE_DMA_INDEX].ring_obj = NULL;
r600_ring_init(rdev, &rdev->ring[R600_RING_TYPE_DMA_INDEX], 64 * 1024);
rdev->ih.ring_obj = NULL; rdev->ih.ring_obj = NULL;
r600_ih_ring_init(rdev, 64 * 1024); r600_ih_ring_init(rdev, 64 * 1024);
@ -2150,6 +2559,109 @@ free_scratch:
return r; return r;
} }
/**
* r600_dma_ib_test - test an IB on the DMA engine
*
* @rdev: radeon_device pointer
* @ring: radeon_ring structure holding ring information
*
* Test a simple IB in the DMA ring (r6xx-SI).
* Returns 0 on success, error on failure.
*/
int r600_dma_ib_test(struct radeon_device *rdev, struct radeon_ring *ring)
{
struct radeon_ib ib;
unsigned i;
int r;
void __iomem *ptr = (void *)rdev->vram_scratch.ptr;
u32 tmp = 0;
ENTER();
if (!ptr) {
DRM_ERROR("invalid vram scratch pointer\n");
return -EINVAL;
}
tmp = 0xCAFEDEAD;
writel(tmp, ptr);
r = radeon_ib_get(rdev, ring->idx, &ib, NULL, 256);
if (r) {
DRM_ERROR("radeon: failed to get ib (%d).\n", r);
return r;
}
ib.ptr[0] = DMA_PACKET(DMA_PACKET_WRITE, 0, 0, 1);
ib.ptr[1] = rdev->vram_scratch.gpu_addr & 0xfffffffc;
ib.ptr[2] = upper_32_bits(rdev->vram_scratch.gpu_addr) & 0xff;
ib.ptr[3] = 0xDEADBEEF;
ib.length_dw = 4;
r = radeon_ib_schedule(rdev, &ib, NULL);
if (r) {
radeon_ib_free(rdev, &ib);
DRM_ERROR("radeon: failed to schedule ib (%d).\n", r);
return r;
}
r = radeon_fence_wait(ib.fence, false);
if (r) {
DRM_ERROR("radeon: fence wait failed (%d).\n", r);
return r;
}
for (i = 0; i < rdev->usec_timeout; i++) {
tmp = readl(ptr);
if (tmp == 0xDEADBEEF)
break;
DRM_UDELAY(1);
}
if (i < rdev->usec_timeout) {
DRM_INFO("ib test on ring %d succeeded in %u usecs\n", ib.fence->ring, i);
} else {
DRM_ERROR("radeon: ib test failed (0x%08X)\n", tmp);
r = -EINVAL;
}
radeon_ib_free(rdev, &ib);
LEAVE();
return r;
}
/**
* r600_dma_ring_ib_execute - Schedule an IB on the DMA engine
*
* @rdev: radeon_device pointer
* @ib: IB object to schedule
*
* Schedule an IB in the DMA ring (r6xx-r7xx).
*/
void r600_dma_ring_ib_execute(struct radeon_device *rdev, struct radeon_ib *ib)
{
struct radeon_ring *ring = &rdev->ring[ib->ring];
if (rdev->wb.enabled) {
u32 next_rptr = ring->wptr + 4;
while ((next_rptr & 7) != 5)
next_rptr++;
next_rptr += 3;
radeon_ring_write(ring, DMA_PACKET(DMA_PACKET_WRITE, 0, 0, 1));
radeon_ring_write(ring, ring->next_rptr_gpu_addr & 0xfffffffc);
radeon_ring_write(ring, upper_32_bits(ring->next_rptr_gpu_addr) & 0xff);
radeon_ring_write(ring, next_rptr);
}
/* The indirect buffer packet must end on an 8 DW boundary in the DMA ring.
* Pad as necessary with NOPs.
*/
while ((ring->wptr & 7) != 5)
radeon_ring_write(ring, DMA_PACKET(DMA_PACKET_NOP, 0, 0, 0));
radeon_ring_write(ring, DMA_PACKET(DMA_PACKET_INDIRECT_BUFFER, 0, 0, 0));
radeon_ring_write(ring, (ib->gpu_addr & 0xFFFFFFE0));
radeon_ring_write(ring, (ib->length_dw << 16) | (upper_32_bits(ib->gpu_addr) & 0xFF));
}
/* /*
* Interrupts * Interrupts
* *
@ -2341,6 +2853,8 @@ static void r600_disable_interrupt_state(struct radeon_device *rdev)
u32 tmp; u32 tmp;
WREG32(CP_INT_CNTL, CNTX_BUSY_INT_ENABLE | CNTX_EMPTY_INT_ENABLE); WREG32(CP_INT_CNTL, CNTX_BUSY_INT_ENABLE | CNTX_EMPTY_INT_ENABLE);
tmp = RREG32(DMA_CNTL) & ~TRAP_ENABLE;
WREG32(DMA_CNTL, tmp);
WREG32(GRBM_INT_CNTL, 0); WREG32(GRBM_INT_CNTL, 0);
WREG32(DxMODE_INT_MASK, 0); WREG32(DxMODE_INT_MASK, 0);
WREG32(D1GRPH_INTERRUPT_CONTROL, 0); WREG32(D1GRPH_INTERRUPT_CONTROL, 0);
@ -2469,6 +2983,7 @@ int r600_irq_set(struct radeon_device *rdev)
u32 grbm_int_cntl = 0; u32 grbm_int_cntl = 0;
u32 hdmi0, hdmi1; u32 hdmi0, hdmi1;
u32 d1grph = 0, d2grph = 0; u32 d1grph = 0, d2grph = 0;
u32 dma_cntl;
if (!rdev->irq.installed) { if (!rdev->irq.installed) {
WARN(1, "Can't enable IRQ/MSI because no handler is installed\n"); WARN(1, "Can't enable IRQ/MSI because no handler is installed\n");
@ -2503,12 +3018,19 @@ int r600_irq_set(struct radeon_device *rdev)
hdmi0 = RREG32(HDMI0_AUDIO_PACKET_CONTROL) & ~HDMI0_AZ_FORMAT_WTRIG_MASK; hdmi0 = RREG32(HDMI0_AUDIO_PACKET_CONTROL) & ~HDMI0_AZ_FORMAT_WTRIG_MASK;
hdmi1 = RREG32(HDMI1_AUDIO_PACKET_CONTROL) & ~HDMI0_AZ_FORMAT_WTRIG_MASK; hdmi1 = RREG32(HDMI1_AUDIO_PACKET_CONTROL) & ~HDMI0_AZ_FORMAT_WTRIG_MASK;
} }
dma_cntl = RREG32(DMA_CNTL) & ~TRAP_ENABLE;
if (atomic_read(&rdev->irq.ring_int[RADEON_RING_TYPE_GFX_INDEX])) { if (atomic_read(&rdev->irq.ring_int[RADEON_RING_TYPE_GFX_INDEX])) {
DRM_DEBUG("r600_irq_set: sw int\n"); DRM_DEBUG("r600_irq_set: sw int\n");
cp_int_cntl |= RB_INT_ENABLE; cp_int_cntl |= RB_INT_ENABLE;
cp_int_cntl |= TIME_STAMP_INT_ENABLE; cp_int_cntl |= TIME_STAMP_INT_ENABLE;
} }
if (atomic_read(&rdev->irq.ring_int[R600_RING_TYPE_DMA_INDEX])) {
DRM_DEBUG("r600_irq_set: sw int dma\n");
dma_cntl |= TRAP_ENABLE;
}
if (rdev->irq.crtc_vblank_int[0] || if (rdev->irq.crtc_vblank_int[0] ||
atomic_read(&rdev->irq.pflip[0])) { atomic_read(&rdev->irq.pflip[0])) {
DRM_DEBUG("r600_irq_set: vblank 0\n"); DRM_DEBUG("r600_irq_set: vblank 0\n");
@ -2553,6 +3075,7 @@ int r600_irq_set(struct radeon_device *rdev)
} }
WREG32(CP_INT_CNTL, cp_int_cntl); WREG32(CP_INT_CNTL, cp_int_cntl);
WREG32(DMA_CNTL, dma_cntl);
WREG32(DxMODE_INT_MASK, mode_int); WREG32(DxMODE_INT_MASK, mode_int);
WREG32(D1GRPH_INTERRUPT_CONTROL, d1grph); WREG32(D1GRPH_INTERRUPT_CONTROL, d1grph);
WREG32(D2GRPH_INTERRUPT_CONTROL, d2grph); WREG32(D2GRPH_INTERRUPT_CONTROL, d2grph);
@ -2698,6 +3221,15 @@ static void r600_irq_ack(struct radeon_device *rdev)
} }
} }
void r600_irq_disable(struct radeon_device *rdev)
{
r600_disable_interrupts(rdev);
/* Wait and acknowledge irq */
mdelay(1);
r600_irq_ack(rdev);
r600_disable_interrupt_state(rdev);
}
static u32 r600_get_ih_wptr(struct radeon_device *rdev) static u32 r600_get_ih_wptr(struct radeon_device *rdev)
{ {
u32 wptr, tmp; u32 wptr, tmp;
@ -2925,6 +3457,10 @@ restart_ih:
DRM_DEBUG("IH: CP EOP\n"); DRM_DEBUG("IH: CP EOP\n");
radeon_fence_process(rdev, RADEON_RING_TYPE_GFX_INDEX); radeon_fence_process(rdev, RADEON_RING_TYPE_GFX_INDEX);
break; break;
case 224: /* DMA trap event */
DRM_DEBUG("IH: DMA trap\n");
radeon_fence_process(rdev, R600_RING_TYPE_DMA_INDEX);
break;
case 233: /* GUI IDLE */ case 233: /* GUI IDLE */
DRM_DEBUG("IH: GUI idle\n"); DRM_DEBUG("IH: GUI idle\n");
break; break;

View File

@ -23,7 +23,7 @@
* *
* Authors: Christian König * Authors: Christian König
*/ */
#include "drmP.h" #include <drm/drmP.h>
#include "radeon.h" #include "radeon.h"
#include "radeon_reg.h" #include "radeon_reg.h"
#include "radeon_asic.h" #include "radeon_asic.h"

View File

@ -24,6 +24,7 @@
* Alex Deucher <alexander.deucher@amd.com> * Alex Deucher <alexander.deucher@amd.com>
*/ */
#include <linux/bug.h>
#include <linux/types.h> #include <linux/types.h>
#include <linux/kernel.h> #include <linux/kernel.h>

View File

@ -96,6 +96,15 @@
#define R600_CONFIG_F0_BASE 0x542C #define R600_CONFIG_F0_BASE 0x542C
#define R600_CONFIG_APER_SIZE 0x5430 #define R600_CONFIG_APER_SIZE 0x5430
#define R600_BIF_FB_EN 0x5490
#define R600_FB_READ_EN (1 << 0)
#define R600_FB_WRITE_EN (1 << 1)
#define R600_CITF_CNTL 0x200c
#define R600_BLACKOUT_MASK 0x00000003
#define R700_MC_CITF_CNTL 0x25c0
#define R600_ROM_CNTL 0x1600 #define R600_ROM_CNTL 0x1600
# define R600_SCK_OVERWRITE (1 << 1) # define R600_SCK_OVERWRITE (1 << 1)
# define R600_SCK_PRESCALE_CRYSTAL_CLK_SHIFT 28 # define R600_SCK_PRESCALE_CRYSTAL_CLK_SHIFT 28

View File

@ -590,9 +590,59 @@
#define WAIT_2D_IDLECLEAN_bit (1 << 16) #define WAIT_2D_IDLECLEAN_bit (1 << 16)
#define WAIT_3D_IDLECLEAN_bit (1 << 17) #define WAIT_3D_IDLECLEAN_bit (1 << 17)
/* async DMA */
#define DMA_TILING_CONFIG 0x3ec4
#define DMA_CONFIG 0x3e4c
#define DMA_RB_CNTL 0xd000
# define DMA_RB_ENABLE (1 << 0)
# define DMA_RB_SIZE(x) ((x) << 1) /* log2 */
# define DMA_RB_SWAP_ENABLE (1 << 9) /* 8IN32 */
# define DMA_RPTR_WRITEBACK_ENABLE (1 << 12)
# define DMA_RPTR_WRITEBACK_SWAP_ENABLE (1 << 13) /* 8IN32 */
# define DMA_RPTR_WRITEBACK_TIMER(x) ((x) << 16) /* log2 */
#define DMA_RB_BASE 0xd004
#define DMA_RB_RPTR 0xd008
#define DMA_RB_WPTR 0xd00c
#define DMA_RB_RPTR_ADDR_HI 0xd01c
#define DMA_RB_RPTR_ADDR_LO 0xd020
#define DMA_IB_CNTL 0xd024
# define DMA_IB_ENABLE (1 << 0)
# define DMA_IB_SWAP_ENABLE (1 << 4)
#define DMA_IB_RPTR 0xd028
#define DMA_CNTL 0xd02c
# define TRAP_ENABLE (1 << 0)
# define SEM_INCOMPLETE_INT_ENABLE (1 << 1)
# define SEM_WAIT_INT_ENABLE (1 << 2)
# define DATA_SWAP_ENABLE (1 << 3)
# define FENCE_SWAP_ENABLE (1 << 4)
# define CTXEMPTY_INT_ENABLE (1 << 28)
#define DMA_STATUS_REG 0xd034
# define DMA_IDLE (1 << 0)
#define DMA_SEM_INCOMPLETE_TIMER_CNTL 0xd044
#define DMA_SEM_WAIT_FAIL_TIMER_CNTL 0xd048
#define DMA_MODE 0xd0bc
/* async DMA packets */
#define DMA_PACKET(cmd, t, s, n) ((((cmd) & 0xF) << 28) | \
(((t) & 0x1) << 23) | \
(((s) & 0x1) << 22) | \
(((n) & 0xFFFF) << 0))
/* async DMA Packet types */
#define DMA_PACKET_WRITE 0x2
#define DMA_PACKET_COPY 0x3
#define DMA_PACKET_INDIRECT_BUFFER 0x4
#define DMA_PACKET_SEMAPHORE 0x5
#define DMA_PACKET_FENCE 0x6
#define DMA_PACKET_TRAP 0x7
#define DMA_PACKET_CONSTANT_FILL 0xd /* 7xx only */
#define DMA_PACKET_NOP 0xf
#define IH_RB_CNTL 0x3e00 #define IH_RB_CNTL 0x3e00
# define IH_RB_ENABLE (1 << 0) # define IH_RB_ENABLE (1 << 0)
# define IH_IB_SIZE(x) ((x) << 1) /* log2 */ # define IH_RB_SIZE(x) ((x) << 1) /* log2 */
# define IH_RB_FULL_DRAIN_ENABLE (1 << 6) # define IH_RB_FULL_DRAIN_ENABLE (1 << 6)
# define IH_WPTR_WRITEBACK_ENABLE (1 << 8) # define IH_WPTR_WRITEBACK_ENABLE (1 << 8)
# define IH_WPTR_WRITEBACK_TIMER(x) ((x) << 9) /* log2 */ # define IH_WPTR_WRITEBACK_TIMER(x) ((x) << 9) /* log2 */
@ -637,7 +687,9 @@
#define TN_RLC_CLEAR_STATE_RESTORE_BASE 0x3f20 #define TN_RLC_CLEAR_STATE_RESTORE_BASE 0x3f20
#define SRBM_SOFT_RESET 0xe60 #define SRBM_SOFT_RESET 0xe60
# define SOFT_RESET_DMA (1 << 12)
# define SOFT_RESET_RLC (1 << 13) # define SOFT_RESET_RLC (1 << 13)
# define RV770_SOFT_RESET_DMA (1 << 20)
#define CP_INT_CNTL 0xc124 #define CP_INT_CNTL 0xc124
# define CNTX_BUSY_INT_ENABLE (1 << 19) # define CNTX_BUSY_INT_ENABLE (1 << 19)
@ -1134,6 +1186,38 @@
#define PACKET3_WAIT_REG_MEM 0x3C #define PACKET3_WAIT_REG_MEM 0x3C
#define PACKET3_MEM_WRITE 0x3D #define PACKET3_MEM_WRITE 0x3D
#define PACKET3_INDIRECT_BUFFER 0x32 #define PACKET3_INDIRECT_BUFFER 0x32
#define PACKET3_CP_DMA 0x41
/* 1. header
* 2. SRC_ADDR_LO [31:0]
* 3. CP_SYNC [31] | SRC_ADDR_HI [7:0]
* 4. DST_ADDR_LO [31:0]
* 5. DST_ADDR_HI [7:0]
* 6. COMMAND [29:22] | BYTE_COUNT [20:0]
*/
# define PACKET3_CP_DMA_CP_SYNC (1 << 31)
/* COMMAND */
# define PACKET3_CP_DMA_CMD_SRC_SWAP(x) ((x) << 23)
/* 0 - none
* 1 - 8 in 16
* 2 - 8 in 32
* 3 - 8 in 64
*/
# define PACKET3_CP_DMA_CMD_DST_SWAP(x) ((x) << 24)
/* 0 - none
* 1 - 8 in 16
* 2 - 8 in 32
* 3 - 8 in 64
*/
# define PACKET3_CP_DMA_CMD_SAS (1 << 26)
/* 0 - memory
* 1 - register
*/
# define PACKET3_CP_DMA_CMD_DAS (1 << 27)
/* 0 - memory
* 1 - register
*/
# define PACKET3_CP_DMA_CMD_SAIC (1 << 28)
# define PACKET3_CP_DMA_CMD_DAIC (1 << 29)
#define PACKET3_SURFACE_SYNC 0x43 #define PACKET3_SURFACE_SYNC 0x43
# define PACKET3_CB0_DEST_BASE_ENA (1 << 6) # define PACKET3_CB0_DEST_BASE_ENA (1 << 6)
# define PACKET3_TC_ACTION_ENA (1 << 23) # define PACKET3_TC_ACTION_ENA (1 << 23)

View File

@ -129,12 +129,6 @@ static inline void iowrite32(uint32_t b, volatile void __iomem *addr)
out32((u32)addr, b); out32((u32)addr, b);
} }
//struct __wait_queue_head {
// spinlock_t lock;
// struct list_head task_list;
//};
//typedef struct __wait_queue_head wait_queue_head_t;
/* /*
* Copy from radeon_drv.h so we don't have to include both and have conflicting * Copy from radeon_drv.h so we don't have to include both and have conflicting
@ -149,7 +143,7 @@ static inline void iowrite32(uint32_t b, volatile void __iomem *addr)
#define RADEON_BIOS_NUM_SCRATCH 8 #define RADEON_BIOS_NUM_SCRATCH 8
/* max number of rings */ /* max number of rings */
#define RADEON_NUM_RINGS 3 #define RADEON_NUM_RINGS 5
/* fence seq are set to this number when signaled */ /* fence seq are set to this number when signaled */
#define RADEON_FENCE_SIGNALED_SEQ 0LL #define RADEON_FENCE_SIGNALED_SEQ 0LL
@ -162,11 +156,21 @@ static inline void iowrite32(uint32_t b, volatile void __iomem *addr)
#define CAYMAN_RING_TYPE_CP1_INDEX 1 #define CAYMAN_RING_TYPE_CP1_INDEX 1
#define CAYMAN_RING_TYPE_CP2_INDEX 2 #define CAYMAN_RING_TYPE_CP2_INDEX 2
/* R600+ has an async dma ring */
#define R600_RING_TYPE_DMA_INDEX 3
/* cayman add a second async dma ring */
#define CAYMAN_RING_TYPE_DMA1_INDEX 4
/* hardcode those limit for now */ /* hardcode those limit for now */
#define RADEON_VA_IB_OFFSET (1 << 20) #define RADEON_VA_IB_OFFSET (1 << 20)
#define RADEON_VA_RESERVED_SIZE (8 << 20) #define RADEON_VA_RESERVED_SIZE (8 << 20)
#define RADEON_IB_VM_MAX_SIZE (64 << 10) #define RADEON_IB_VM_MAX_SIZE (64 << 10)
/* reset flags */
#define RADEON_RESET_GFX (1 << 0)
#define RADEON_RESET_COMPUTE (1 << 1)
#define RADEON_RESET_DMA (1 << 2)
/* /*
* Errata workarounds. * Errata workarounds.
*/ */
@ -260,12 +264,13 @@ struct radeon_fence {
int radeon_fence_driver_start_ring(struct radeon_device *rdev, int ring); int radeon_fence_driver_start_ring(struct radeon_device *rdev, int ring);
int radeon_fence_driver_init(struct radeon_device *rdev); int radeon_fence_driver_init(struct radeon_device *rdev);
void radeon_fence_driver_fini(struct radeon_device *rdev); void radeon_fence_driver_fini(struct radeon_device *rdev);
void radeon_fence_driver_force_completion(struct radeon_device *rdev);
int radeon_fence_emit(struct radeon_device *rdev, struct radeon_fence **fence, int ring); int radeon_fence_emit(struct radeon_device *rdev, struct radeon_fence **fence, int ring);
void radeon_fence_process(struct radeon_device *rdev, int ring); void radeon_fence_process(struct radeon_device *rdev, int ring);
bool radeon_fence_signaled(struct radeon_fence *fence); bool radeon_fence_signaled(struct radeon_fence *fence);
int radeon_fence_wait(struct radeon_fence *fence, bool interruptible); int radeon_fence_wait(struct radeon_fence *fence, bool interruptible);
int radeon_fence_wait_next_locked(struct radeon_device *rdev, int ring); int radeon_fence_wait_next_locked(struct radeon_device *rdev, int ring);
void radeon_fence_wait_empty_locked(struct radeon_device *rdev, int ring); int radeon_fence_wait_empty_locked(struct radeon_device *rdev, int ring);
int radeon_fence_wait_any(struct radeon_device *rdev, int radeon_fence_wait_any(struct radeon_device *rdev,
struct radeon_fence **fences, struct radeon_fence **fences,
bool intr); bool intr);
@ -353,6 +358,7 @@ struct radeon_bo {
struct list_head list; struct list_head list;
/* Protected by tbo.reserved */ /* Protected by tbo.reserved */
u32 placements[3]; u32 placements[3];
u32 busy_placements[3];
struct ttm_placement placement; struct ttm_placement placement;
struct ttm_buffer_object tbo; struct ttm_buffer_object tbo;
struct ttm_bo_kmap_obj kmap; struct ttm_bo_kmap_obj kmap;
@ -817,6 +823,15 @@ int radeon_ring_init(struct radeon_device *rdev, struct radeon_ring *cp, unsigne
void radeon_ring_fini(struct radeon_device *rdev, struct radeon_ring *cp); void radeon_ring_fini(struct radeon_device *rdev, struct radeon_ring *cp);
/* r600 async dma */
void r600_dma_stop(struct radeon_device *rdev);
int r600_dma_resume(struct radeon_device *rdev);
void r600_dma_fini(struct radeon_device *rdev);
void cayman_dma_stop(struct radeon_device *rdev);
int cayman_dma_resume(struct radeon_device *rdev);
void cayman_dma_fini(struct radeon_device *rdev);
/* /*
* CS. * CS.
*/ */
@ -854,6 +869,7 @@ struct radeon_cs_parser {
struct radeon_cs_reloc *relocs; struct radeon_cs_reloc *relocs;
struct radeon_cs_reloc **relocs_ptr; struct radeon_cs_reloc **relocs_ptr;
struct list_head validated; struct list_head validated;
unsigned dma_reloc_idx;
/* indices of various chunks */ /* indices of various chunks */
int chunk_ib_idx; int chunk_ib_idx;
int chunk_relocs_idx; int chunk_relocs_idx;
@ -913,7 +929,9 @@ struct radeon_wb {
#define RADEON_WB_CP_RPTR_OFFSET 1024 #define RADEON_WB_CP_RPTR_OFFSET 1024
#define RADEON_WB_CP1_RPTR_OFFSET 1280 #define RADEON_WB_CP1_RPTR_OFFSET 1280
#define RADEON_WB_CP2_RPTR_OFFSET 1536 #define RADEON_WB_CP2_RPTR_OFFSET 1536
#define R600_WB_DMA_RPTR_OFFSET 1792
#define R600_WB_IH_WPTR_OFFSET 2048 #define R600_WB_IH_WPTR_OFFSET 2048
#define CAYMAN_WB_DMA1_RPTR_OFFSET 2304
#define R600_WB_EVENT_OFFSET 3072 #define R600_WB_EVENT_OFFSET 3072
/** /**
@ -1458,6 +1476,8 @@ struct radeon_device {
/* Register mmio */ /* Register mmio */
resource_size_t rmmio_base; resource_size_t rmmio_base;
resource_size_t rmmio_size; resource_size_t rmmio_size;
/* protects concurrent MM_INDEX/DATA based register access */
spinlock_t mmio_idx_lock;
void __iomem *rmmio; void __iomem *rmmio;
radeon_rreg_t mc_rreg; radeon_rreg_t mc_rreg;
radeon_wreg_t mc_wreg; radeon_wreg_t mc_wreg;
@ -1533,8 +1553,10 @@ int radeon_device_init(struct radeon_device *rdev,
void radeon_device_fini(struct radeon_device *rdev); void radeon_device_fini(struct radeon_device *rdev);
int radeon_gpu_wait_for_idle(struct radeon_device *rdev); int radeon_gpu_wait_for_idle(struct radeon_device *rdev);
uint32_t r100_mm_rreg(struct radeon_device *rdev, uint32_t reg); 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); bool always_indirect);
void r100_mm_wreg(struct radeon_device *rdev, uint32_t reg, uint32_t v,
bool always_indirect);
u32 r100_io_rreg(struct radeon_device *rdev, u32 reg); u32 r100_io_rreg(struct radeon_device *rdev, u32 reg);
void r100_io_wreg(struct radeon_device *rdev, u32 reg, u32 v); void r100_io_wreg(struct radeon_device *rdev, u32 reg, u32 v);
@ -1550,9 +1572,11 @@ void r100_io_wreg(struct radeon_device *rdev, u32 reg, u32 v);
#define WREG8(reg, v) writeb(v, (rdev->rmmio) + (reg)) #define WREG8(reg, v) writeb(v, (rdev->rmmio) + (reg))
#define RREG16(reg) readw((rdev->rmmio) + (reg)) #define RREG16(reg) readw((rdev->rmmio) + (reg))
#define WREG16(reg, v) writew(v, (rdev->rmmio) + (reg)) #define WREG16(reg, v) writew(v, (rdev->rmmio) + (reg))
#define RREG32(reg) r100_mm_rreg(rdev, (reg)) #define RREG32(reg) r100_mm_rreg(rdev, (reg), false)
#define DREG32(reg) printk(KERN_INFO "REGISTER: " #reg " : 0x%08X\n", r100_mm_rreg(rdev, (reg))) #define RREG32_IDX(reg) r100_mm_rreg(rdev, (reg), true)
#define WREG32(reg, v) r100_mm_wreg(rdev, (reg), (v)) #define DREG32(reg) printk(KERN_INFO "REGISTER: " #reg " : 0x%08X\n", r100_mm_rreg(rdev, (reg), false))
#define WREG32(reg, v) r100_mm_wreg(rdev, (reg), (v), false)
#define WREG32_IDX(reg, v) r100_mm_wreg(rdev, (reg), (v), true)
#define REG_SET(FIELD, v) (((v) << FIELD##_SHIFT) & FIELD##_MASK) #define REG_SET(FIELD, v) (((v) << FIELD##_SHIFT) & FIELD##_MASK)
#define REG_GET(FIELD, v) (((v) << FIELD##_SHIFT) & FIELD##_MASK) #define REG_GET(FIELD, v) (((v) << FIELD##_SHIFT) & FIELD##_MASK)
#define RREG32_PLL(reg) rdev->pll_rreg(rdev, (reg)) #define RREG32_PLL(reg) rdev->pll_rreg(rdev, (reg))
@ -1873,4 +1897,6 @@ bool set_mode(struct drm_device *dev, struct drm_connector *connector,
#define radeon_ttm_set_active_vram_size(a, b)
#endif #endif

View File

@ -24,10 +24,9 @@
* Dave Airlie * Dave Airlie
* Jerome Glisse <glisse@freedesktop.org> * Jerome Glisse <glisse@freedesktop.org>
*/ */
#include "drmP.h" #include <drm/drmP.h>
#include "drm.h"
#include "radeon.h" #include "radeon.h"
#include "radeon_drm.h" #include <drm/radeon_drm.h>
#if __OS_HAS_AGP #if __OS_HAS_AGP
@ -70,9 +69,12 @@ static struct radeon_agpmode_quirk radeon_agpmode_quirk_list[] = {
/* Intel 82830 830 Chipset Host Bridge / Mobility M6 LY Needs AGPMode 2 (fdo #17360)*/ /* Intel 82830 830 Chipset Host Bridge / Mobility M6 LY Needs AGPMode 2 (fdo #17360)*/
{ PCI_VENDOR_ID_INTEL, 0x3575, PCI_VENDOR_ID_ATI, 0x4c59, { PCI_VENDOR_ID_INTEL, 0x3575, PCI_VENDOR_ID_ATI, 0x4c59,
PCI_VENDOR_ID_DELL, 0x00e3, 2}, PCI_VENDOR_ID_DELL, 0x00e3, 2},
/* Intel 82852/82855 host bridge / Mobility FireGL 9000 R250 Needs AGPMode 1 (lp #296617) */ /* Intel 82852/82855 host bridge / Mobility FireGL 9000 RV250 Needs AGPMode 1 (lp #296617) */
{ PCI_VENDOR_ID_INTEL, 0x3580, PCI_VENDOR_ID_ATI, 0x4c66, { PCI_VENDOR_ID_INTEL, 0x3580, PCI_VENDOR_ID_ATI, 0x4c66,
PCI_VENDOR_ID_DELL, 0x0149, 1}, PCI_VENDOR_ID_DELL, 0x0149, 1},
/* Intel 82855PM host bridge / Mobility FireGL 9000 RV250 Needs AGPMode 1 for suspend/resume */
{ PCI_VENDOR_ID_INTEL, 0x3340, PCI_VENDOR_ID_ATI, 0x4c66,
PCI_VENDOR_ID_IBM, 0x0531, 1},
/* Intel 82852/82855 host bridge / Mobility 9600 M10 RV350 Needs AGPMode 1 (deb #467460) */ /* Intel 82852/82855 host bridge / Mobility 9600 M10 RV350 Needs AGPMode 1 (deb #467460) */
{ PCI_VENDOR_ID_INTEL, 0x3580, PCI_VENDOR_ID_ATI, 0x4e50, { PCI_VENDOR_ID_INTEL, 0x3580, PCI_VENDOR_ID_ATI, 0x4e50,
0x1025, 0x0061, 1}, 0x1025, 0x0061, 1},

View File

@ -171,7 +171,7 @@ static struct radeon_asic r100_asic = {
// .resume = &r100_resume, // .resume = &r100_resume,
// .vga_set_state = &r100_vga_set_state, // .vga_set_state = &r100_vga_set_state,
.asic_reset = &r100_asic_reset, .asic_reset = &r100_asic_reset,
// .ioctl_wait_idle = NULL, .ioctl_wait_idle = NULL,
.gui_idle = &r100_gui_idle, .gui_idle = &r100_gui_idle,
.mc_wait_for_idle = &r100_mc_wait_for_idle, .mc_wait_for_idle = &r100_mc_wait_for_idle,
.gart = { .gart = {
@ -228,9 +228,9 @@ static struct radeon_asic r100_asic = {
// .get_engine_clock = &radeon_legacy_get_engine_clock, // .get_engine_clock = &radeon_legacy_get_engine_clock,
// .set_engine_clock = &radeon_legacy_set_engine_clock, // .set_engine_clock = &radeon_legacy_set_engine_clock,
// .get_memory_clock = &radeon_legacy_get_memory_clock, // .get_memory_clock = &radeon_legacy_get_memory_clock,
// .set_memory_clock = NULL, .set_memory_clock = NULL,
// .get_pcie_lanes = NULL, .get_pcie_lanes = NULL,
// .set_pcie_lanes = NULL, .set_pcie_lanes = NULL,
// .set_clock_gating = &radeon_legacy_set_clock_gating, // .set_clock_gating = &radeon_legacy_set_clock_gating,
}, },
.pflip = { .pflip = {
@ -247,7 +247,7 @@ static struct radeon_asic r200_asic = {
// .resume = &r100_resume, // .resume = &r100_resume,
// .vga_set_state = &r100_vga_set_state, // .vga_set_state = &r100_vga_set_state,
.asic_reset = &r100_asic_reset, .asic_reset = &r100_asic_reset,
// .ioctl_wait_idle = NULL, .ioctl_wait_idle = NULL,
.gui_idle = &r100_gui_idle, .gui_idle = &r100_gui_idle,
.mc_wait_for_idle = &r100_mc_wait_for_idle, .mc_wait_for_idle = &r100_mc_wait_for_idle,
.gart = { .gart = {
@ -304,9 +304,9 @@ static struct radeon_asic r200_asic = {
// .get_engine_clock = &radeon_legacy_get_engine_clock, // .get_engine_clock = &radeon_legacy_get_engine_clock,
// .set_engine_clock = &radeon_legacy_set_engine_clock, // .set_engine_clock = &radeon_legacy_set_engine_clock,
// .get_memory_clock = &radeon_legacy_get_memory_clock, // .get_memory_clock = &radeon_legacy_get_memory_clock,
// .set_memory_clock = NULL, .set_memory_clock = NULL,
// .get_pcie_lanes = NULL, .get_pcie_lanes = NULL,
// .set_pcie_lanes = NULL, .set_pcie_lanes = NULL,
// .set_clock_gating = &radeon_legacy_set_clock_gating, // .set_clock_gating = &radeon_legacy_set_clock_gating,
}, },
.pflip = { .pflip = {
@ -323,7 +323,7 @@ static struct radeon_asic r300_asic = {
// .resume = &r300_resume, // .resume = &r300_resume,
// .vga_set_state = &r100_vga_set_state, // .vga_set_state = &r100_vga_set_state,
.asic_reset = &r300_asic_reset, .asic_reset = &r300_asic_reset,
// .ioctl_wait_idle = NULL, .ioctl_wait_idle = NULL,
.gui_idle = &r100_gui_idle, .gui_idle = &r100_gui_idle,
.mc_wait_for_idle = &r300_mc_wait_for_idle, .mc_wait_for_idle = &r300_mc_wait_for_idle,
.gart = { .gart = {
@ -399,7 +399,7 @@ static struct radeon_asic r300_asic_pcie = {
// .resume = &r300_resume, // .resume = &r300_resume,
// .vga_set_state = &r100_vga_set_state, // .vga_set_state = &r100_vga_set_state,
.asic_reset = &r300_asic_reset, .asic_reset = &r300_asic_reset,
// .ioctl_wait_idle = NULL, .ioctl_wait_idle = NULL,
.gui_idle = &r100_gui_idle, .gui_idle = &r100_gui_idle,
.mc_wait_for_idle = &r300_mc_wait_for_idle, .mc_wait_for_idle = &r300_mc_wait_for_idle,
.gart = { .gart = {
@ -475,7 +475,7 @@ static struct radeon_asic r420_asic = {
// .resume = &r420_resume, // .resume = &r420_resume,
// .vga_set_state = &r100_vga_set_state, // .vga_set_state = &r100_vga_set_state,
.asic_reset = &r300_asic_reset, .asic_reset = &r300_asic_reset,
// .ioctl_wait_idle = NULL, .ioctl_wait_idle = NULL,
.gui_idle = &r100_gui_idle, .gui_idle = &r100_gui_idle,
.mc_wait_for_idle = &r300_mc_wait_for_idle, .mc_wait_for_idle = &r300_mc_wait_for_idle,
.gart = { .gart = {
@ -551,7 +551,7 @@ static struct radeon_asic rs400_asic = {
// .resume = &rs400_resume, // .resume = &rs400_resume,
// .vga_set_state = &r100_vga_set_state, // .vga_set_state = &r100_vga_set_state,
.asic_reset = &r300_asic_reset, .asic_reset = &r300_asic_reset,
// .ioctl_wait_idle = NULL, .ioctl_wait_idle = NULL,
.gui_idle = &r100_gui_idle, .gui_idle = &r100_gui_idle,
.mc_wait_for_idle = &rs400_mc_wait_for_idle, .mc_wait_for_idle = &rs400_mc_wait_for_idle,
.gart = { .gart = {
@ -627,7 +627,7 @@ static struct radeon_asic rs600_asic = {
// .resume = &rs600_resume, // .resume = &rs600_resume,
// .vga_set_state = &r100_vga_set_state, // .vga_set_state = &r100_vga_set_state,
.asic_reset = &rs600_asic_reset, .asic_reset = &rs600_asic_reset,
// .ioctl_wait_idle = NULL, .ioctl_wait_idle = NULL,
.gui_idle = &r100_gui_idle, .gui_idle = &r100_gui_idle,
.mc_wait_for_idle = &rs600_mc_wait_for_idle, .mc_wait_for_idle = &rs600_mc_wait_for_idle,
.gart = { .gart = {
@ -703,7 +703,7 @@ static struct radeon_asic rs690_asic = {
// .resume = &rs690_resume, // .resume = &rs690_resume,
// .vga_set_state = &r100_vga_set_state, // .vga_set_state = &r100_vga_set_state,
.asic_reset = &rs600_asic_reset, .asic_reset = &rs600_asic_reset,
// .ioctl_wait_idle = NULL, .ioctl_wait_idle = NULL,
.gui_idle = &r100_gui_idle, .gui_idle = &r100_gui_idle,
.mc_wait_for_idle = &rs690_mc_wait_for_idle, .mc_wait_for_idle = &rs690_mc_wait_for_idle,
.gart = { .gart = {
@ -779,7 +779,7 @@ static struct radeon_asic rv515_asic = {
// .resume = &rv515_resume, // .resume = &rv515_resume,
// .vga_set_state = &r100_vga_set_state, // .vga_set_state = &r100_vga_set_state,
.asic_reset = &rs600_asic_reset, .asic_reset = &rs600_asic_reset,
// .ioctl_wait_idle = NULL, .ioctl_wait_idle = NULL,
.gui_idle = &r100_gui_idle, .gui_idle = &r100_gui_idle,
.mc_wait_for_idle = &rv515_mc_wait_for_idle, .mc_wait_for_idle = &rv515_mc_wait_for_idle,
.gart = { .gart = {
@ -855,7 +855,7 @@ static struct radeon_asic r520_asic = {
// .resume = &r520_resume, // .resume = &r520_resume,
// .vga_set_state = &r100_vga_set_state, // .vga_set_state = &r100_vga_set_state,
.asic_reset = &rs600_asic_reset, .asic_reset = &rs600_asic_reset,
// .ioctl_wait_idle = NULL, .ioctl_wait_idle = NULL,
.gui_idle = &r100_gui_idle, .gui_idle = &r100_gui_idle,
.mc_wait_for_idle = &r520_mc_wait_for_idle, .mc_wait_for_idle = &r520_mc_wait_for_idle,
.gart = { .gart = {
@ -947,6 +947,15 @@ static struct radeon_asic r600_asic = {
.ring_test = &r600_ring_test, .ring_test = &r600_ring_test,
.ib_test = &r600_ib_test, .ib_test = &r600_ib_test,
.is_lockup = &r600_gpu_is_lockup, .is_lockup = &r600_gpu_is_lockup,
},
[R600_RING_TYPE_DMA_INDEX] = {
.ib_execute = &r600_dma_ring_ib_execute,
.emit_fence = &r600_dma_fence_ring_emit,
.emit_semaphore = &r600_dma_semaphore_ring_emit,
// .cs_parse = &r600_dma_cs_parse,
.ring_test = &r600_dma_ring_test,
.ib_test = &r600_dma_ib_test,
.is_lockup = &r600_dma_is_lockup,
} }
}, },
.irq = { .irq = {
@ -963,10 +972,10 @@ static struct radeon_asic r600_asic = {
.copy = { .copy = {
.blit = &r600_copy_blit, .blit = &r600_copy_blit,
.blit_ring_index = RADEON_RING_TYPE_GFX_INDEX, .blit_ring_index = RADEON_RING_TYPE_GFX_INDEX,
.dma = NULL, .dma = &r600_copy_dma,
.dma_ring_index = RADEON_RING_TYPE_GFX_INDEX, .dma_ring_index = R600_RING_TYPE_DMA_INDEX,
.copy = &r600_copy_blit, .copy = &r600_copy_dma,
.copy_ring_index = RADEON_RING_TYPE_GFX_INDEX, .copy_ring_index = R600_RING_TYPE_DMA_INDEX,
}, },
.surface = { .surface = {
.set_reg = r600_set_surface_reg, .set_reg = r600_set_surface_reg,
@ -1022,6 +1031,15 @@ static struct radeon_asic rs780_asic = {
.ring_test = &r600_ring_test, .ring_test = &r600_ring_test,
.ib_test = &r600_ib_test, .ib_test = &r600_ib_test,
.is_lockup = &r600_gpu_is_lockup, .is_lockup = &r600_gpu_is_lockup,
},
[R600_RING_TYPE_DMA_INDEX] = {
.ib_execute = &r600_dma_ring_ib_execute,
.emit_fence = &r600_dma_fence_ring_emit,
.emit_semaphore = &r600_dma_semaphore_ring_emit,
// .cs_parse = &r600_dma_cs_parse,
.ring_test = &r600_dma_ring_test,
.ib_test = &r600_dma_ib_test,
.is_lockup = &r600_dma_is_lockup,
} }
}, },
.irq = { .irq = {
@ -1038,10 +1056,10 @@ static struct radeon_asic rs780_asic = {
.copy = { .copy = {
.blit = &r600_copy_blit, .blit = &r600_copy_blit,
.blit_ring_index = RADEON_RING_TYPE_GFX_INDEX, .blit_ring_index = RADEON_RING_TYPE_GFX_INDEX,
.dma = NULL, .dma = &r600_copy_dma,
.dma_ring_index = RADEON_RING_TYPE_GFX_INDEX, .dma_ring_index = R600_RING_TYPE_DMA_INDEX,
.copy = &r600_copy_blit, .copy = &r600_copy_dma,
.copy_ring_index = RADEON_RING_TYPE_GFX_INDEX, .copy_ring_index = R600_RING_TYPE_DMA_INDEX,
}, },
.surface = { .surface = {
.set_reg = r600_set_surface_reg, .set_reg = r600_set_surface_reg,
@ -1097,6 +1115,15 @@ static struct radeon_asic rv770_asic = {
.ring_test = &r600_ring_test, .ring_test = &r600_ring_test,
.ib_test = &r600_ib_test, .ib_test = &r600_ib_test,
.is_lockup = &r600_gpu_is_lockup, .is_lockup = &r600_gpu_is_lockup,
},
[R600_RING_TYPE_DMA_INDEX] = {
.ib_execute = &r600_dma_ring_ib_execute,
.emit_fence = &r600_dma_fence_ring_emit,
.emit_semaphore = &r600_dma_semaphore_ring_emit,
// .cs_parse = &r600_dma_cs_parse,
.ring_test = &r600_dma_ring_test,
.ib_test = &r600_dma_ib_test,
.is_lockup = &r600_dma_is_lockup,
} }
}, },
.irq = { .irq = {
@ -1113,10 +1140,10 @@ static struct radeon_asic rv770_asic = {
.copy = { .copy = {
.blit = &r600_copy_blit, .blit = &r600_copy_blit,
.blit_ring_index = RADEON_RING_TYPE_GFX_INDEX, .blit_ring_index = RADEON_RING_TYPE_GFX_INDEX,
.dma = NULL, .dma = &r600_copy_dma,
.dma_ring_index = RADEON_RING_TYPE_GFX_INDEX, .dma_ring_index = R600_RING_TYPE_DMA_INDEX,
.copy = &r600_copy_blit, .copy = &r600_copy_dma,
.copy_ring_index = RADEON_RING_TYPE_GFX_INDEX, .copy_ring_index = R600_RING_TYPE_DMA_INDEX,
}, },
.surface = { .surface = {
.set_reg = r600_set_surface_reg, .set_reg = r600_set_surface_reg,
@ -1172,6 +1199,15 @@ static struct radeon_asic evergreen_asic = {
.ring_test = &r600_ring_test, .ring_test = &r600_ring_test,
.ib_test = &r600_ib_test, .ib_test = &r600_ib_test,
.is_lockup = &evergreen_gpu_is_lockup, .is_lockup = &evergreen_gpu_is_lockup,
},
[R600_RING_TYPE_DMA_INDEX] = {
.ib_execute = &evergreen_dma_ring_ib_execute,
.emit_fence = &evergreen_dma_fence_ring_emit,
.emit_semaphore = &r600_dma_semaphore_ring_emit,
// .cs_parse = &evergreen_dma_cs_parse,
.ring_test = &r600_dma_ring_test,
.ib_test = &r600_dma_ib_test,
.is_lockup = &r600_dma_is_lockup,
} }
}, },
.irq = { .irq = {
@ -1188,10 +1224,10 @@ static struct radeon_asic evergreen_asic = {
.copy = { .copy = {
.blit = &r600_copy_blit, .blit = &r600_copy_blit,
.blit_ring_index = RADEON_RING_TYPE_GFX_INDEX, .blit_ring_index = RADEON_RING_TYPE_GFX_INDEX,
.dma = NULL, .dma = &evergreen_copy_dma,
.dma_ring_index = RADEON_RING_TYPE_GFX_INDEX, .dma_ring_index = R600_RING_TYPE_DMA_INDEX,
.copy = &r600_copy_blit, .copy = &evergreen_copy_dma,
.copy_ring_index = RADEON_RING_TYPE_GFX_INDEX, .copy_ring_index = R600_RING_TYPE_DMA_INDEX,
}, },
.surface = { .surface = {
.set_reg = r600_set_surface_reg, .set_reg = r600_set_surface_reg,
@ -1248,6 +1284,15 @@ static struct radeon_asic sumo_asic = {
.ib_test = &r600_ib_test, .ib_test = &r600_ib_test,
.is_lockup = &evergreen_gpu_is_lockup, .is_lockup = &evergreen_gpu_is_lockup,
}, },
[R600_RING_TYPE_DMA_INDEX] = {
.ib_execute = &evergreen_dma_ring_ib_execute,
.emit_fence = &evergreen_dma_fence_ring_emit,
.emit_semaphore = &r600_dma_semaphore_ring_emit,
// .cs_parse = &evergreen_dma_cs_parse,
.ring_test = &r600_dma_ring_test,
.ib_test = &r600_dma_ib_test,
.is_lockup = &r600_dma_is_lockup,
}
}, },
.irq = { .irq = {
.set = &evergreen_irq_set, .set = &evergreen_irq_set,
@ -1263,10 +1308,10 @@ static struct radeon_asic sumo_asic = {
.copy = { .copy = {
.blit = &r600_copy_blit, .blit = &r600_copy_blit,
.blit_ring_index = RADEON_RING_TYPE_GFX_INDEX, .blit_ring_index = RADEON_RING_TYPE_GFX_INDEX,
.dma = NULL, .dma = &evergreen_copy_dma,
.dma_ring_index = RADEON_RING_TYPE_GFX_INDEX, .dma_ring_index = R600_RING_TYPE_DMA_INDEX,
.copy = &r600_copy_blit, .copy = &evergreen_copy_dma,
.copy_ring_index = RADEON_RING_TYPE_GFX_INDEX, .copy_ring_index = R600_RING_TYPE_DMA_INDEX,
}, },
.surface = { .surface = {
.set_reg = r600_set_surface_reg, .set_reg = r600_set_surface_reg,
@ -1322,6 +1367,15 @@ static struct radeon_asic btc_asic = {
.ring_test = &r600_ring_test, .ring_test = &r600_ring_test,
.ib_test = &r600_ib_test, .ib_test = &r600_ib_test,
.is_lockup = &evergreen_gpu_is_lockup, .is_lockup = &evergreen_gpu_is_lockup,
},
[R600_RING_TYPE_DMA_INDEX] = {
.ib_execute = &evergreen_dma_ring_ib_execute,
.emit_fence = &evergreen_dma_fence_ring_emit,
.emit_semaphore = &r600_dma_semaphore_ring_emit,
// .cs_parse = &evergreen_dma_cs_parse,
.ring_test = &r600_dma_ring_test,
.ib_test = &r600_dma_ib_test,
.is_lockup = &r600_dma_is_lockup,
} }
}, },
.irq = { .irq = {
@ -1338,10 +1392,10 @@ static struct radeon_asic btc_asic = {
.copy = { .copy = {
.blit = &r600_copy_blit, .blit = &r600_copy_blit,
.blit_ring_index = RADEON_RING_TYPE_GFX_INDEX, .blit_ring_index = RADEON_RING_TYPE_GFX_INDEX,
.dma = NULL, .dma = &evergreen_copy_dma,
.dma_ring_index = RADEON_RING_TYPE_GFX_INDEX, .dma_ring_index = R600_RING_TYPE_DMA_INDEX,
.copy = &r600_copy_blit, .copy = &evergreen_copy_dma,
.copy_ring_index = RADEON_RING_TYPE_GFX_INDEX, .copy_ring_index = R600_RING_TYPE_DMA_INDEX,
}, },
.surface = { .surface = {
.set_reg = r600_set_surface_reg, .set_reg = r600_set_surface_reg,
@ -1391,7 +1445,7 @@ static struct radeon_asic cayman_asic = {
.vm = { .vm = {
.init = &cayman_vm_init, .init = &cayman_vm_init,
.fini = &cayman_vm_fini, .fini = &cayman_vm_fini,
.pt_ring_index = RADEON_RING_TYPE_GFX_INDEX, .pt_ring_index = R600_RING_TYPE_DMA_INDEX,
.set_page = &cayman_vm_set_page, .set_page = &cayman_vm_set_page,
}, },
.ring = { .ring = {
@ -1427,6 +1481,28 @@ static struct radeon_asic cayman_asic = {
.ib_test = &r600_ib_test, .ib_test = &r600_ib_test,
.is_lockup = &evergreen_gpu_is_lockup, .is_lockup = &evergreen_gpu_is_lockup,
.vm_flush = &cayman_vm_flush, .vm_flush = &cayman_vm_flush,
},
[R600_RING_TYPE_DMA_INDEX] = {
.ib_execute = &cayman_dma_ring_ib_execute,
// .ib_parse = &evergreen_dma_ib_parse,
.emit_fence = &evergreen_dma_fence_ring_emit,
.emit_semaphore = &r600_dma_semaphore_ring_emit,
// .cs_parse = &evergreen_dma_cs_parse,
.ring_test = &r600_dma_ring_test,
.ib_test = &r600_dma_ib_test,
.is_lockup = &cayman_dma_is_lockup,
.vm_flush = &cayman_dma_vm_flush,
},
[CAYMAN_RING_TYPE_DMA1_INDEX] = {
.ib_execute = &cayman_dma_ring_ib_execute,
// .ib_parse = &evergreen_dma_ib_parse,
.emit_fence = &evergreen_dma_fence_ring_emit,
.emit_semaphore = &r600_dma_semaphore_ring_emit,
// .cs_parse = &evergreen_dma_cs_parse,
.ring_test = &r600_dma_ring_test,
.ib_test = &r600_dma_ib_test,
.is_lockup = &cayman_dma_is_lockup,
.vm_flush = &cayman_dma_vm_flush,
} }
}, },
.irq = { .irq = {
@ -1443,10 +1519,10 @@ static struct radeon_asic cayman_asic = {
.copy = { .copy = {
.blit = &r600_copy_blit, .blit = &r600_copy_blit,
.blit_ring_index = RADEON_RING_TYPE_GFX_INDEX, .blit_ring_index = RADEON_RING_TYPE_GFX_INDEX,
.dma = NULL, .dma = &evergreen_copy_dma,
.dma_ring_index = RADEON_RING_TYPE_GFX_INDEX, .dma_ring_index = R600_RING_TYPE_DMA_INDEX,
.copy = &r600_copy_blit, .copy = &evergreen_copy_dma,
.copy_ring_index = RADEON_RING_TYPE_GFX_INDEX, .copy_ring_index = R600_RING_TYPE_DMA_INDEX,
}, },
.surface = { .surface = {
.set_reg = r600_set_surface_reg, .set_reg = r600_set_surface_reg,
@ -1496,7 +1572,7 @@ static struct radeon_asic trinity_asic = {
.vm = { .vm = {
.init = &cayman_vm_init, .init = &cayman_vm_init,
.fini = &cayman_vm_fini, .fini = &cayman_vm_fini,
.pt_ring_index = RADEON_RING_TYPE_GFX_INDEX, .pt_ring_index = R600_RING_TYPE_DMA_INDEX,
.set_page = &cayman_vm_set_page, .set_page = &cayman_vm_set_page,
}, },
.ring = { .ring = {
@ -1532,6 +1608,28 @@ static struct radeon_asic trinity_asic = {
.ib_test = &r600_ib_test, .ib_test = &r600_ib_test,
.is_lockup = &evergreen_gpu_is_lockup, .is_lockup = &evergreen_gpu_is_lockup,
.vm_flush = &cayman_vm_flush, .vm_flush = &cayman_vm_flush,
},
[R600_RING_TYPE_DMA_INDEX] = {
.ib_execute = &cayman_dma_ring_ib_execute,
// .ib_parse = &evergreen_dma_ib_parse,
.emit_fence = &evergreen_dma_fence_ring_emit,
.emit_semaphore = &r600_dma_semaphore_ring_emit,
// .cs_parse = &evergreen_dma_cs_parse,
.ring_test = &r600_dma_ring_test,
.ib_test = &r600_dma_ib_test,
.is_lockup = &cayman_dma_is_lockup,
.vm_flush = &cayman_dma_vm_flush,
},
[CAYMAN_RING_TYPE_DMA1_INDEX] = {
.ib_execute = &cayman_dma_ring_ib_execute,
// .ib_parse = &evergreen_dma_ib_parse,
.emit_fence = &evergreen_dma_fence_ring_emit,
.emit_semaphore = &r600_dma_semaphore_ring_emit,
// .cs_parse = &evergreen_dma_cs_parse,
.ring_test = &r600_dma_ring_test,
.ib_test = &r600_dma_ib_test,
.is_lockup = &cayman_dma_is_lockup,
.vm_flush = &cayman_dma_vm_flush,
} }
}, },
.irq = { .irq = {
@ -1548,10 +1646,10 @@ static struct radeon_asic trinity_asic = {
.copy = { .copy = {
.blit = &r600_copy_blit, .blit = &r600_copy_blit,
.blit_ring_index = RADEON_RING_TYPE_GFX_INDEX, .blit_ring_index = RADEON_RING_TYPE_GFX_INDEX,
.dma = NULL, .dma = &evergreen_copy_dma,
.dma_ring_index = RADEON_RING_TYPE_GFX_INDEX, .dma_ring_index = R600_RING_TYPE_DMA_INDEX,
.copy = &r600_copy_blit, .copy = &evergreen_copy_dma,
.copy_ring_index = RADEON_RING_TYPE_GFX_INDEX, .copy_ring_index = R600_RING_TYPE_DMA_INDEX,
}, },
.surface = { .surface = {
.set_reg = r600_set_surface_reg, .set_reg = r600_set_surface_reg,
@ -1601,7 +1699,7 @@ static struct radeon_asic si_asic = {
.vm = { .vm = {
.init = &si_vm_init, .init = &si_vm_init,
.fini = &si_vm_fini, .fini = &si_vm_fini,
.pt_ring_index = RADEON_RING_TYPE_GFX_INDEX, .pt_ring_index = R600_RING_TYPE_DMA_INDEX,
.set_page = &si_vm_set_page, .set_page = &si_vm_set_page,
}, },
.ring = { .ring = {
@ -1637,6 +1735,28 @@ static struct radeon_asic si_asic = {
.ib_test = &r600_ib_test, .ib_test = &r600_ib_test,
.is_lockup = &si_gpu_is_lockup, .is_lockup = &si_gpu_is_lockup,
.vm_flush = &si_vm_flush, .vm_flush = &si_vm_flush,
},
[R600_RING_TYPE_DMA_INDEX] = {
.ib_execute = &cayman_dma_ring_ib_execute,
// .ib_parse = &evergreen_dma_ib_parse,
.emit_fence = &evergreen_dma_fence_ring_emit,
.emit_semaphore = &r600_dma_semaphore_ring_emit,
.cs_parse = NULL,
.ring_test = &r600_dma_ring_test,
.ib_test = &r600_dma_ib_test,
.is_lockup = &cayman_dma_is_lockup,
.vm_flush = &si_dma_vm_flush,
},
[CAYMAN_RING_TYPE_DMA1_INDEX] = {
.ib_execute = &cayman_dma_ring_ib_execute,
// .ib_parse = &evergreen_dma_ib_parse,
.emit_fence = &evergreen_dma_fence_ring_emit,
.emit_semaphore = &r600_dma_semaphore_ring_emit,
.cs_parse = NULL,
.ring_test = &r600_dma_ring_test,
.ib_test = &r600_dma_ib_test,
.is_lockup = &cayman_dma_is_lockup,
.vm_flush = &si_dma_vm_flush,
} }
}, },
.irq = { .irq = {
@ -1653,10 +1773,10 @@ static struct radeon_asic si_asic = {
.copy = { .copy = {
.blit = NULL, .blit = NULL,
.blit_ring_index = RADEON_RING_TYPE_GFX_INDEX, .blit_ring_index = RADEON_RING_TYPE_GFX_INDEX,
.dma = NULL, .dma = &si_copy_dma,
.dma_ring_index = RADEON_RING_TYPE_GFX_INDEX, .dma_ring_index = R600_RING_TYPE_DMA_INDEX,
.copy = NULL, .copy = &si_copy_dma,
.copy_ring_index = RADEON_RING_TYPE_GFX_INDEX, .copy_ring_index = R600_RING_TYPE_DMA_INDEX,
}, },
.surface = { .surface = {
.set_reg = r600_set_surface_reg, .set_reg = r600_set_surface_reg,

View File

@ -263,6 +263,7 @@ extern int rs690_mc_wait_for_idle(struct radeon_device *rdev);
struct rv515_mc_save { struct rv515_mc_save {
u32 vga_render_control; u32 vga_render_control;
u32 vga_hdp_control; u32 vga_hdp_control;
bool crtc_enabled[2];
}; };
int rv515_init(struct radeon_device *rdev); int rv515_init(struct radeon_device *rdev);
@ -303,12 +304,21 @@ void r600_pcie_gart_tlb_flush(struct radeon_device *rdev);
uint32_t r600_pciep_rreg(struct radeon_device *rdev, uint32_t reg); uint32_t r600_pciep_rreg(struct radeon_device *rdev, uint32_t reg);
void r600_pciep_wreg(struct radeon_device *rdev, uint32_t reg, uint32_t v); void r600_pciep_wreg(struct radeon_device *rdev, uint32_t reg, uint32_t v);
int r600_cs_parse(struct radeon_cs_parser *p); int r600_cs_parse(struct radeon_cs_parser *p);
int r600_dma_cs_parse(struct radeon_cs_parser *p);
void r600_fence_ring_emit(struct radeon_device *rdev, void r600_fence_ring_emit(struct radeon_device *rdev,
struct radeon_fence *fence); struct radeon_fence *fence);
void r600_semaphore_ring_emit(struct radeon_device *rdev, void r600_semaphore_ring_emit(struct radeon_device *rdev,
struct radeon_ring *cp, struct radeon_ring *cp,
struct radeon_semaphore *semaphore, struct radeon_semaphore *semaphore,
bool emit_wait); bool emit_wait);
void r600_dma_fence_ring_emit(struct radeon_device *rdev,
struct radeon_fence *fence);
void r600_dma_semaphore_ring_emit(struct radeon_device *rdev,
struct radeon_ring *ring,
struct radeon_semaphore *semaphore,
bool emit_wait);
void r600_dma_ring_ib_execute(struct radeon_device *rdev, struct radeon_ib *ib);
bool r600_dma_is_lockup(struct radeon_device *rdev, struct radeon_ring *ring);
bool r600_gpu_is_lockup(struct radeon_device *rdev, struct radeon_ring *cp); bool r600_gpu_is_lockup(struct radeon_device *rdev, struct radeon_ring *cp);
int r600_asic_reset(struct radeon_device *rdev); int r600_asic_reset(struct radeon_device *rdev);
int r600_set_surface_reg(struct radeon_device *rdev, int reg, int r600_set_surface_reg(struct radeon_device *rdev, int reg,
@ -316,11 +326,16 @@ int r600_set_surface_reg(struct radeon_device *rdev, int reg,
uint32_t offset, uint32_t obj_size); uint32_t offset, uint32_t obj_size);
void r600_clear_surface_reg(struct radeon_device *rdev, int reg); void r600_clear_surface_reg(struct radeon_device *rdev, int reg);
int r600_ib_test(struct radeon_device *rdev, struct radeon_ring *ring); int r600_ib_test(struct radeon_device *rdev, struct radeon_ring *ring);
int r600_dma_ib_test(struct radeon_device *rdev, struct radeon_ring *ring);
void r600_ring_ib_execute(struct radeon_device *rdev, struct radeon_ib *ib); void r600_ring_ib_execute(struct radeon_device *rdev, struct radeon_ib *ib);
int r600_ring_test(struct radeon_device *rdev, struct radeon_ring *cp); int r600_ring_test(struct radeon_device *rdev, struct radeon_ring *cp);
int r600_dma_ring_test(struct radeon_device *rdev, struct radeon_ring *cp);
int r600_copy_blit(struct radeon_device *rdev, int r600_copy_blit(struct radeon_device *rdev,
uint64_t src_offset, uint64_t dst_offset, uint64_t src_offset, uint64_t dst_offset,
unsigned num_gpu_pages, struct radeon_fence **fence); unsigned num_gpu_pages, struct radeon_fence **fence);
int r600_copy_dma(struct radeon_device *rdev,
uint64_t src_offset, uint64_t dst_offset,
unsigned num_gpu_pages, struct radeon_fence **fence);
void r600_hpd_init(struct radeon_device *rdev); void r600_hpd_init(struct radeon_device *rdev);
void r600_hpd_fini(struct radeon_device *rdev); void r600_hpd_fini(struct radeon_device *rdev);
bool r600_hpd_sense(struct radeon_device *rdev, enum radeon_hpd_id hpd); bool r600_hpd_sense(struct radeon_device *rdev, enum radeon_hpd_id hpd);
@ -388,6 +403,10 @@ u32 rv770_page_flip(struct radeon_device *rdev, int crtc, u64 crtc_base);
void r700_vram_gtt_location(struct radeon_device *rdev, struct radeon_mc *mc); void r700_vram_gtt_location(struct radeon_device *rdev, struct radeon_mc *mc);
void r700_cp_stop(struct radeon_device *rdev); void r700_cp_stop(struct radeon_device *rdev);
void r700_cp_fini(struct radeon_device *rdev); void r700_cp_fini(struct radeon_device *rdev);
int rv770_copy_dma(struct radeon_device *rdev,
uint64_t src_offset, uint64_t dst_offset,
unsigned num_gpu_pages,
struct radeon_fence **fence);
/* /*
* evergreen * evergreen
@ -416,6 +435,7 @@ u32 evergreen_get_vblank_counter(struct radeon_device *rdev, int crtc);
int evergreen_irq_set(struct radeon_device *rdev); int evergreen_irq_set(struct radeon_device *rdev);
int evergreen_irq_process(struct radeon_device *rdev); int evergreen_irq_process(struct radeon_device *rdev);
extern int evergreen_cs_parse(struct radeon_cs_parser *p); extern int evergreen_cs_parse(struct radeon_cs_parser *p);
extern int evergreen_dma_cs_parse(struct radeon_cs_parser *p);
extern void evergreen_pm_misc(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_prepare(struct radeon_device *rdev);
extern void evergreen_pm_finish(struct radeon_device *rdev); extern void evergreen_pm_finish(struct radeon_device *rdev);
@ -428,6 +448,14 @@ extern void dce4_wait_for_vblank(struct radeon_device *rdev, int crtc);
void evergreen_disable_interrupt_state(struct radeon_device *rdev); void evergreen_disable_interrupt_state(struct radeon_device *rdev);
int evergreen_blit_init(struct radeon_device *rdev); int evergreen_blit_init(struct radeon_device *rdev);
int evergreen_mc_wait_for_idle(struct radeon_device *rdev); int evergreen_mc_wait_for_idle(struct radeon_device *rdev);
void evergreen_dma_fence_ring_emit(struct radeon_device *rdev,
struct radeon_fence *fence);
void evergreen_dma_ring_ib_execute(struct radeon_device *rdev,
struct radeon_ib *ib);
int evergreen_copy_dma(struct radeon_device *rdev,
uint64_t src_offset, uint64_t dst_offset,
unsigned num_gpu_pages,
struct radeon_fence **fence);
/* /*
* cayman * cayman
@ -449,6 +477,11 @@ void cayman_vm_set_page(struct radeon_device *rdev, uint64_t pe,
uint64_t addr, unsigned count, uint64_t addr, unsigned count,
uint32_t incr, uint32_t flags); uint32_t incr, uint32_t flags);
int evergreen_ib_parse(struct radeon_device *rdev, struct radeon_ib *ib); int evergreen_ib_parse(struct radeon_device *rdev, struct radeon_ib *ib);
int evergreen_dma_ib_parse(struct radeon_device *rdev, struct radeon_ib *ib);
void cayman_dma_ring_ib_execute(struct radeon_device *rdev,
struct radeon_ib *ib);
bool cayman_dma_is_lockup(struct radeon_device *rdev, struct radeon_ring *ring);
void cayman_dma_vm_flush(struct radeon_device *rdev, int ridx, struct radeon_vm *vm);
/* DCE6 - SI */ /* DCE6 - SI */
void dce6_bandwidth_update(struct radeon_device *rdev); void dce6_bandwidth_update(struct radeon_device *rdev);
@ -476,5 +509,10 @@ void si_vm_set_page(struct radeon_device *rdev, uint64_t pe,
void si_vm_flush(struct radeon_device *rdev, int ridx, struct radeon_vm *vm); void si_vm_flush(struct radeon_device *rdev, int ridx, struct radeon_vm *vm);
int si_ib_parse(struct radeon_device *rdev, struct radeon_ib *ib); int si_ib_parse(struct radeon_device *rdev, struct radeon_ib *ib);
uint64_t si_get_gpu_clock(struct radeon_device *rdev); uint64_t si_get_gpu_clock(struct radeon_device *rdev);
int si_copy_dma(struct radeon_device *rdev,
uint64_t src_offset, uint64_t dst_offset,
unsigned num_gpu_pages,
struct radeon_fence **fence);
void si_dma_vm_flush(struct radeon_device *rdev, int ridx, struct radeon_vm *vm);
#endif #endif

View File

@ -1548,6 +1548,9 @@ bool radeon_get_legacy_connector_info_from_table(struct drm_device *dev)
of_machine_is_compatible("PowerBook6,7")) { of_machine_is_compatible("PowerBook6,7")) {
/* ibook */ /* ibook */
rdev->mode_info.connector_table = CT_IBOOK; rdev->mode_info.connector_table = CT_IBOOK;
} else if (of_machine_is_compatible("PowerMac3,5")) {
/* PowerMac G4 Silver radeon 7500 */
rdev->mode_info.connector_table = CT_MAC_G4_SILVER;
} else if (of_machine_is_compatible("PowerMac4,4")) { } else if (of_machine_is_compatible("PowerMac4,4")) {
/* emac */ /* emac */
rdev->mode_info.connector_table = CT_EMAC; rdev->mode_info.connector_table = CT_EMAC;
@ -2212,6 +2215,54 @@ bool radeon_get_legacy_connector_info_from_table(struct drm_device *dev)
CONNECTOR_OBJECT_ID_SVIDEO, CONNECTOR_OBJECT_ID_SVIDEO,
&hpd); &hpd);
break; break;
case CT_MAC_G4_SILVER:
DRM_INFO("Connector Table: %d (mac g4 silver)\n",
rdev->mode_info.connector_table);
/* DVI-I - tv dac, int tmds */
ddc_i2c = combios_setup_i2c_bus(rdev, DDC_DVI, 0, 0);
hpd.hpd = RADEON_HPD_1; /* ??? */
radeon_add_legacy_encoder(dev,
radeon_get_encoder_enum(dev,
ATOM_DEVICE_DFP1_SUPPORT,
0),
ATOM_DEVICE_DFP1_SUPPORT);
radeon_add_legacy_encoder(dev,
radeon_get_encoder_enum(dev,
ATOM_DEVICE_CRT2_SUPPORT,
2),
ATOM_DEVICE_CRT2_SUPPORT);
radeon_add_legacy_connector(dev, 0,
ATOM_DEVICE_DFP1_SUPPORT |
ATOM_DEVICE_CRT2_SUPPORT,
DRM_MODE_CONNECTOR_DVII, &ddc_i2c,
CONNECTOR_OBJECT_ID_SINGLE_LINK_DVI_I,
&hpd);
/* VGA - primary dac */
ddc_i2c = combios_setup_i2c_bus(rdev, DDC_VGA, 0, 0);
hpd.hpd = RADEON_HPD_NONE;
radeon_add_legacy_encoder(dev,
radeon_get_encoder_enum(dev,
ATOM_DEVICE_CRT1_SUPPORT,
1),
ATOM_DEVICE_CRT1_SUPPORT);
radeon_add_legacy_connector(dev, 1, ATOM_DEVICE_CRT1_SUPPORT,
DRM_MODE_CONNECTOR_VGA, &ddc_i2c,
CONNECTOR_OBJECT_ID_VGA,
&hpd);
/* TV - TV DAC */
ddc_i2c.valid = false;
hpd.hpd = RADEON_HPD_NONE;
radeon_add_legacy_encoder(dev,
radeon_get_encoder_enum(dev,
ATOM_DEVICE_TV1_SUPPORT,
2),
ATOM_DEVICE_TV1_SUPPORT);
radeon_add_legacy_connector(dev, 2, ATOM_DEVICE_TV1_SUPPORT,
DRM_MODE_CONNECTOR_SVIDEO,
&ddc_i2c,
CONNECTOR_OBJECT_ID_SVIDEO,
&hpd);
break;
default: default:
DRM_INFO("Connector table: %d (invalid)\n", DRM_INFO("Connector table: %d (invalid)\n",
rdev->mode_info.connector_table); rdev->mode_info.connector_table);
@ -3246,11 +3297,9 @@ static uint32_t combios_detect_ram(struct drm_device *dev, int ram,
while (ram--) { while (ram--) {
addr = ram * 1024 * 1024; addr = ram * 1024 * 1024;
/* write to each page */ /* write to each page */
WREG32(RADEON_MM_INDEX, (addr) | RADEON_MM_APER); WREG32_IDX((addr) | RADEON_MM_APER, 0xdeadbeef);
WREG32(RADEON_MM_DATA, 0xdeadbeef);
/* read back and verify */ /* read back and verify */
WREG32(RADEON_MM_INDEX, (addr) | RADEON_MM_APER); if (RREG32_IDX((addr) | RADEON_MM_APER) != 0xdeadbeef)
if (RREG32(RADEON_MM_DATA) != 0xdeadbeef)
return 0; return 0;
} }

View File

@ -31,6 +31,9 @@
#include "radeon.h" #include "radeon.h"
#include "atom.h" #include "atom.h"
#define DISABLE_DP 0
extern void extern void
radeon_combios_connected_scratch_regs(struct drm_connector *connector, radeon_combios_connected_scratch_regs(struct drm_connector *connector,
struct drm_encoder *encoder, struct drm_encoder *encoder,
@ -612,6 +615,8 @@ radeon_lvds_detect(struct drm_connector *connector, bool force)
struct drm_encoder *encoder = radeon_best_single_encoder(connector); struct drm_encoder *encoder = radeon_best_single_encoder(connector);
enum drm_connector_status ret = connector_status_disconnected; enum drm_connector_status ret = connector_status_disconnected;
ENTER();
if (encoder) { if (encoder) {
struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder); struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder);
struct drm_display_mode *native_mode = &radeon_encoder->native_mode; struct drm_display_mode *native_mode = &radeon_encoder->native_mode;
@ -636,6 +641,7 @@ radeon_lvds_detect(struct drm_connector *connector, bool force)
/* check acpi lid status ??? */ /* check acpi lid status ??? */
radeon_connector_update_scratch_regs(connector, ret); radeon_connector_update_scratch_regs(connector, ret);
LEAVE();
return ret; return ret;
} }
@ -741,7 +747,7 @@ radeon_vga_detect(struct drm_connector *connector, bool force)
ret = connector_status_disconnected; ret = connector_status_disconnected;
if (radeon_connector->ddc_bus) if (radeon_connector->ddc_bus)
dret = radeon_ddc_probe(radeon_connector); dret = radeon_ddc_probe(radeon_connector, false);
if (dret) { if (dret) {
radeon_connector->detected_by_load = false; radeon_connector->detected_by_load = false;
if (radeon_connector->edid) { if (radeon_connector->edid) {
@ -948,7 +954,7 @@ radeon_dvi_detect(struct drm_connector *connector, bool force)
return connector->status; return connector->status;
if (radeon_connector->ddc_bus) if (radeon_connector->ddc_bus)
dret = radeon_ddc_probe(radeon_connector); dret = radeon_ddc_probe(radeon_connector, false);
if (dret) { if (dret) {
radeon_connector->detected_by_load = false; radeon_connector->detected_by_load = false;
if (radeon_connector->edid) { if (radeon_connector->edid) {
@ -1364,6 +1370,14 @@ radeon_dp_detect(struct drm_connector *connector, bool force)
struct radeon_connector_atom_dig *radeon_dig_connector = radeon_connector->con_priv; struct radeon_connector_atom_dig *radeon_dig_connector = radeon_connector->con_priv;
struct drm_encoder *encoder = radeon_best_single_encoder(connector); struct drm_encoder *encoder = radeon_best_single_encoder(connector);
dbgprintf("%s radeon_connector %p encoder %p\n",
__FUNCTION__, radeon_connector, encoder);
#if DISABLE_DP
connector->status = connector_status_disconnected;
return connector->status;
#endif
if (!force && radeon_check_hpd_status_unchanged(connector)) if (!force && radeon_check_hpd_status_unchanged(connector))
return connector->status; return connector->status;
@ -1387,6 +1401,7 @@ radeon_dp_detect(struct drm_connector *connector, bool force)
if (!radeon_dig_connector->edp_on) if (!radeon_dig_connector->edp_on)
atombios_set_edp_panel_power(connector, atombios_set_edp_panel_power(connector,
ATOM_TRANSMITTER_ACTION_POWER_ON); ATOM_TRANSMITTER_ACTION_POWER_ON);
dbgprintf("check eDP\n");
if (radeon_dp_getdpcd(radeon_connector)) if (radeon_dp_getdpcd(radeon_connector))
ret = connector_status_connected; ret = connector_status_connected;
if (!radeon_dig_connector->edp_on) if (!radeon_dig_connector->edp_on)
@ -1402,7 +1417,8 @@ radeon_dp_detect(struct drm_connector *connector, bool force)
if (encoder) { if (encoder) {
/* setup ddc on the bridge */ /* setup ddc on the bridge */
radeon_atom_ext_encoder_setup_ddc(encoder); radeon_atom_ext_encoder_setup_ddc(encoder);
if (radeon_ddc_probe(radeon_connector)) /* try DDC */ /* bridge chips are always aux */
if (radeon_ddc_probe(radeon_connector, true)) /* try DDC */
ret = connector_status_connected; ret = connector_status_connected;
else if (radeon_connector->dac_load_detect) { /* try load detection */ else if (radeon_connector->dac_load_detect) { /* try load detection */
struct drm_encoder_helper_funcs *encoder_funcs = encoder->helper_private; struct drm_encoder_helper_funcs *encoder_funcs = encoder->helper_private;
@ -1420,13 +1436,15 @@ radeon_dp_detect(struct drm_connector *connector, bool force)
if (radeon_dp_getdpcd(radeon_connector)) if (radeon_dp_getdpcd(radeon_connector))
ret = connector_status_connected; ret = connector_status_connected;
} else { } else {
if (radeon_ddc_probe(radeon_connector)) /* try non-aux ddc (DP to DVI/HMDI/etc. adapter) */
if (radeon_ddc_probe(radeon_connector, false))
ret = connector_status_connected; ret = connector_status_connected;
} }
} }
} }
radeon_connector_update_scratch_regs(connector, ret); radeon_connector_update_scratch_regs(connector, ret);
LEAVE();
return ret; return ret;
} }
@ -1600,7 +1618,7 @@ radeon_add_atom_connector(struct drm_device *dev,
connector->interlace_allowed = true; connector->interlace_allowed = true;
connector->doublescan_allowed = true; connector->doublescan_allowed = true;
radeon_connector->dac_load_detect = true; radeon_connector->dac_load_detect = true;
drm_connector_attach_property(&radeon_connector->base, drm_object_attach_property(&radeon_connector->base.base,
rdev->mode_info.load_detect_property, rdev->mode_info.load_detect_property,
1); 1);
break; break;
@ -1609,13 +1627,13 @@ radeon_add_atom_connector(struct drm_device *dev,
case DRM_MODE_CONNECTOR_HDMIA: case DRM_MODE_CONNECTOR_HDMIA:
case DRM_MODE_CONNECTOR_HDMIB: case DRM_MODE_CONNECTOR_HDMIB:
case DRM_MODE_CONNECTOR_DisplayPort: case DRM_MODE_CONNECTOR_DisplayPort:
drm_connector_attach_property(&radeon_connector->base, drm_object_attach_property(&radeon_connector->base.base,
rdev->mode_info.underscan_property, rdev->mode_info.underscan_property,
UNDERSCAN_OFF); UNDERSCAN_OFF);
drm_connector_attach_property(&radeon_connector->base, drm_object_attach_property(&radeon_connector->base.base,
rdev->mode_info.underscan_hborder_property, rdev->mode_info.underscan_hborder_property,
0); 0);
drm_connector_attach_property(&radeon_connector->base, drm_object_attach_property(&radeon_connector->base.base,
rdev->mode_info.underscan_vborder_property, rdev->mode_info.underscan_vborder_property,
0); 0);
subpixel_order = SubPixelHorizontalRGB; subpixel_order = SubPixelHorizontalRGB;
@ -1626,14 +1644,14 @@ radeon_add_atom_connector(struct drm_device *dev,
connector->doublescan_allowed = false; connector->doublescan_allowed = false;
if (connector_type == DRM_MODE_CONNECTOR_DVII) { if (connector_type == DRM_MODE_CONNECTOR_DVII) {
radeon_connector->dac_load_detect = true; radeon_connector->dac_load_detect = true;
drm_connector_attach_property(&radeon_connector->base, drm_object_attach_property(&radeon_connector->base.base,
rdev->mode_info.load_detect_property, rdev->mode_info.load_detect_property,
1); 1);
} }
break; break;
case DRM_MODE_CONNECTOR_LVDS: case DRM_MODE_CONNECTOR_LVDS:
case DRM_MODE_CONNECTOR_eDP: case DRM_MODE_CONNECTOR_eDP:
drm_connector_attach_property(&radeon_connector->base, drm_object_attach_property(&radeon_connector->base.base,
dev->mode_config.scaling_mode_property, dev->mode_config.scaling_mode_property,
DRM_MODE_SCALE_FULLSCREEN); DRM_MODE_SCALE_FULLSCREEN);
subpixel_order = SubPixelHorizontalRGB; subpixel_order = SubPixelHorizontalRGB;
@ -1652,7 +1670,7 @@ radeon_add_atom_connector(struct drm_device *dev,
DRM_ERROR("VGA: Failed to assign ddc bus! Check dmesg for i2c errors.\n"); DRM_ERROR("VGA: Failed to assign ddc bus! Check dmesg for i2c errors.\n");
} }
radeon_connector->dac_load_detect = true; radeon_connector->dac_load_detect = true;
drm_connector_attach_property(&radeon_connector->base, drm_object_attach_property(&radeon_connector->base.base,
rdev->mode_info.load_detect_property, rdev->mode_info.load_detect_property,
1); 1);
/* no HPD on analog connectors */ /* no HPD on analog connectors */
@ -1670,7 +1688,7 @@ radeon_add_atom_connector(struct drm_device *dev,
DRM_ERROR("DVIA: Failed to assign ddc bus! Check dmesg for i2c errors.\n"); DRM_ERROR("DVIA: Failed to assign ddc bus! Check dmesg for i2c errors.\n");
} }
radeon_connector->dac_load_detect = true; radeon_connector->dac_load_detect = true;
drm_connector_attach_property(&radeon_connector->base, drm_object_attach_property(&radeon_connector->base.base,
rdev->mode_info.load_detect_property, rdev->mode_info.load_detect_property,
1); 1);
/* no HPD on analog connectors */ /* no HPD on analog connectors */
@ -1693,23 +1711,23 @@ radeon_add_atom_connector(struct drm_device *dev,
DRM_ERROR("DVI: Failed to assign ddc bus! Check dmesg for i2c errors.\n"); DRM_ERROR("DVI: Failed to assign ddc bus! Check dmesg for i2c errors.\n");
} }
subpixel_order = SubPixelHorizontalRGB; subpixel_order = SubPixelHorizontalRGB;
drm_connector_attach_property(&radeon_connector->base, drm_object_attach_property(&radeon_connector->base.base,
rdev->mode_info.coherent_mode_property, rdev->mode_info.coherent_mode_property,
1); 1);
if (ASIC_IS_AVIVO(rdev)) { if (ASIC_IS_AVIVO(rdev)) {
drm_connector_attach_property(&radeon_connector->base, drm_object_attach_property(&radeon_connector->base.base,
rdev->mode_info.underscan_property, rdev->mode_info.underscan_property,
UNDERSCAN_OFF); UNDERSCAN_OFF);
drm_connector_attach_property(&radeon_connector->base, drm_object_attach_property(&radeon_connector->base.base,
rdev->mode_info.underscan_hborder_property, rdev->mode_info.underscan_hborder_property,
0); 0);
drm_connector_attach_property(&radeon_connector->base, drm_object_attach_property(&radeon_connector->base.base,
rdev->mode_info.underscan_vborder_property, rdev->mode_info.underscan_vborder_property,
0); 0);
} }
if (connector_type == DRM_MODE_CONNECTOR_DVII) { if (connector_type == DRM_MODE_CONNECTOR_DVII) {
radeon_connector->dac_load_detect = true; radeon_connector->dac_load_detect = true;
drm_connector_attach_property(&radeon_connector->base, drm_object_attach_property(&radeon_connector->base.base,
rdev->mode_info.load_detect_property, rdev->mode_info.load_detect_property,
1); 1);
} }
@ -1733,17 +1751,17 @@ radeon_add_atom_connector(struct drm_device *dev,
if (!radeon_connector->ddc_bus) if (!radeon_connector->ddc_bus)
DRM_ERROR("HDMI: Failed to assign ddc bus! Check dmesg for i2c errors.\n"); DRM_ERROR("HDMI: Failed to assign ddc bus! Check dmesg for i2c errors.\n");
} }
drm_connector_attach_property(&radeon_connector->base, drm_object_attach_property(&radeon_connector->base.base,
rdev->mode_info.coherent_mode_property, rdev->mode_info.coherent_mode_property,
1); 1);
if (ASIC_IS_AVIVO(rdev)) { if (ASIC_IS_AVIVO(rdev)) {
drm_connector_attach_property(&radeon_connector->base, drm_object_attach_property(&radeon_connector->base.base,
rdev->mode_info.underscan_property, rdev->mode_info.underscan_property,
UNDERSCAN_OFF); UNDERSCAN_OFF);
drm_connector_attach_property(&radeon_connector->base, drm_object_attach_property(&radeon_connector->base.base,
rdev->mode_info.underscan_hborder_property, rdev->mode_info.underscan_hborder_property,
0); 0);
drm_connector_attach_property(&radeon_connector->base, drm_object_attach_property(&radeon_connector->base.base,
rdev->mode_info.underscan_vborder_property, rdev->mode_info.underscan_vborder_property,
0); 0);
} }
@ -1772,17 +1790,17 @@ radeon_add_atom_connector(struct drm_device *dev,
DRM_ERROR("DP: Failed to assign ddc bus! Check dmesg for i2c errors.\n"); DRM_ERROR("DP: Failed to assign ddc bus! Check dmesg for i2c errors.\n");
} }
subpixel_order = SubPixelHorizontalRGB; subpixel_order = SubPixelHorizontalRGB;
drm_connector_attach_property(&radeon_connector->base, drm_object_attach_property(&radeon_connector->base.base,
rdev->mode_info.coherent_mode_property, rdev->mode_info.coherent_mode_property,
1); 1);
if (ASIC_IS_AVIVO(rdev)) { if (ASIC_IS_AVIVO(rdev)) {
drm_connector_attach_property(&radeon_connector->base, drm_object_attach_property(&radeon_connector->base.base,
rdev->mode_info.underscan_property, rdev->mode_info.underscan_property,
UNDERSCAN_OFF); UNDERSCAN_OFF);
drm_connector_attach_property(&radeon_connector->base, drm_object_attach_property(&radeon_connector->base.base,
rdev->mode_info.underscan_hborder_property, rdev->mode_info.underscan_hborder_property,
0); 0);
drm_connector_attach_property(&radeon_connector->base, drm_object_attach_property(&radeon_connector->base.base,
rdev->mode_info.underscan_vborder_property, rdev->mode_info.underscan_vborder_property,
0); 0);
} }
@ -1807,7 +1825,7 @@ radeon_add_atom_connector(struct drm_device *dev,
if (!radeon_connector->ddc_bus) if (!radeon_connector->ddc_bus)
DRM_ERROR("DP: Failed to assign ddc bus! Check dmesg for i2c errors.\n"); DRM_ERROR("DP: Failed to assign ddc bus! Check dmesg for i2c errors.\n");
} }
drm_connector_attach_property(&radeon_connector->base, drm_object_attach_property(&radeon_connector->base.base,
dev->mode_config.scaling_mode_property, dev->mode_config.scaling_mode_property,
DRM_MODE_SCALE_FULLSCREEN); DRM_MODE_SCALE_FULLSCREEN);
subpixel_order = SubPixelHorizontalRGB; subpixel_order = SubPixelHorizontalRGB;
@ -1820,10 +1838,10 @@ radeon_add_atom_connector(struct drm_device *dev,
drm_connector_init(dev, &radeon_connector->base, &radeon_tv_connector_funcs, connector_type); drm_connector_init(dev, &radeon_connector->base, &radeon_tv_connector_funcs, connector_type);
drm_connector_helper_add(&radeon_connector->base, &radeon_tv_connector_helper_funcs); drm_connector_helper_add(&radeon_connector->base, &radeon_tv_connector_helper_funcs);
radeon_connector->dac_load_detect = true; radeon_connector->dac_load_detect = true;
drm_connector_attach_property(&radeon_connector->base, drm_object_attach_property(&radeon_connector->base.base,
rdev->mode_info.load_detect_property, rdev->mode_info.load_detect_property,
1); 1);
drm_connector_attach_property(&radeon_connector->base, drm_object_attach_property(&radeon_connector->base.base,
rdev->mode_info.tv_std_property, rdev->mode_info.tv_std_property,
radeon_atombios_get_tv_info(rdev)); radeon_atombios_get_tv_info(rdev));
/* no HPD on analog connectors */ /* no HPD on analog connectors */
@ -1844,7 +1862,7 @@ radeon_add_atom_connector(struct drm_device *dev,
if (!radeon_connector->ddc_bus) if (!radeon_connector->ddc_bus)
DRM_ERROR("LVDS: Failed to assign ddc bus! Check dmesg for i2c errors.\n"); DRM_ERROR("LVDS: Failed to assign ddc bus! Check dmesg for i2c errors.\n");
} }
drm_connector_attach_property(&radeon_connector->base, drm_object_attach_property(&radeon_connector->base.base,
dev->mode_config.scaling_mode_property, dev->mode_config.scaling_mode_property,
DRM_MODE_SCALE_FULLSCREEN); DRM_MODE_SCALE_FULLSCREEN);
subpixel_order = SubPixelHorizontalRGB; subpixel_order = SubPixelHorizontalRGB;
@ -1923,7 +1941,7 @@ radeon_add_legacy_connector(struct drm_device *dev,
DRM_ERROR("VGA: Failed to assign ddc bus! Check dmesg for i2c errors.\n"); DRM_ERROR("VGA: Failed to assign ddc bus! Check dmesg for i2c errors.\n");
} }
radeon_connector->dac_load_detect = true; radeon_connector->dac_load_detect = true;
drm_connector_attach_property(&radeon_connector->base, drm_object_attach_property(&radeon_connector->base.base,
rdev->mode_info.load_detect_property, rdev->mode_info.load_detect_property,
1); 1);
/* no HPD on analog connectors */ /* no HPD on analog connectors */
@ -1941,7 +1959,7 @@ radeon_add_legacy_connector(struct drm_device *dev,
DRM_ERROR("DVIA: Failed to assign ddc bus! Check dmesg for i2c errors.\n"); DRM_ERROR("DVIA: Failed to assign ddc bus! Check dmesg for i2c errors.\n");
} }
radeon_connector->dac_load_detect = true; radeon_connector->dac_load_detect = true;
drm_connector_attach_property(&radeon_connector->base, drm_object_attach_property(&radeon_connector->base.base,
rdev->mode_info.load_detect_property, rdev->mode_info.load_detect_property,
1); 1);
/* no HPD on analog connectors */ /* no HPD on analog connectors */
@ -1960,7 +1978,7 @@ radeon_add_legacy_connector(struct drm_device *dev,
} }
if (connector_type == DRM_MODE_CONNECTOR_DVII) { if (connector_type == DRM_MODE_CONNECTOR_DVII) {
radeon_connector->dac_load_detect = true; radeon_connector->dac_load_detect = true;
drm_connector_attach_property(&radeon_connector->base, drm_object_attach_property(&radeon_connector->base.base,
rdev->mode_info.load_detect_property, rdev->mode_info.load_detect_property,
1); 1);
} }
@ -1984,10 +2002,10 @@ radeon_add_legacy_connector(struct drm_device *dev,
*/ */
if (rdev->family == CHIP_RS400 || rdev->family == CHIP_RS480) if (rdev->family == CHIP_RS400 || rdev->family == CHIP_RS480)
radeon_connector->dac_load_detect = false; radeon_connector->dac_load_detect = false;
drm_connector_attach_property(&radeon_connector->base, drm_object_attach_property(&radeon_connector->base.base,
rdev->mode_info.load_detect_property, rdev->mode_info.load_detect_property,
radeon_connector->dac_load_detect); radeon_connector->dac_load_detect);
drm_connector_attach_property(&radeon_connector->base, drm_object_attach_property(&radeon_connector->base.base,
rdev->mode_info.tv_std_property, rdev->mode_info.tv_std_property,
radeon_combios_get_tv_info(rdev)); radeon_combios_get_tv_info(rdev));
/* no HPD on analog connectors */ /* no HPD on analog connectors */
@ -2003,7 +2021,7 @@ radeon_add_legacy_connector(struct drm_device *dev,
if (!radeon_connector->ddc_bus) if (!radeon_connector->ddc_bus)
DRM_ERROR("LVDS: Failed to assign ddc bus! Check dmesg for i2c errors.\n"); DRM_ERROR("LVDS: Failed to assign ddc bus! Check dmesg for i2c errors.\n");
} }
drm_connector_attach_property(&radeon_connector->base, drm_object_attach_property(&radeon_connector->base.base,
dev->mode_config.scaling_mode_property, dev->mode_config.scaling_mode_property,
DRM_MODE_SCALE_FULLSCREEN); DRM_MODE_SCALE_FULLSCREEN);
subpixel_order = SubPixelHorizontalRGB; subpixel_order = SubPixelHorizontalRGB;

View File

@ -1026,6 +1026,7 @@ int radeon_device_init(struct radeon_device *rdev,
/* Registers mapping */ /* Registers mapping */
/* TODO: block userspace mapping of io register */ /* TODO: block userspace mapping of io register */
spin_lock_init(&rdev->mmio_idx_lock);
rdev->rmmio_base = pci_resource_start(rdev->pdev, 2); rdev->rmmio_base = pci_resource_start(rdev->pdev, 2);
rdev->rmmio_size = pci_resource_len(rdev->pdev, 2); rdev->rmmio_size = pci_resource_len(rdev->pdev, 2);
rdev->rmmio = ioremap(rdev->rmmio_base, rdev->rmmio_size); rdev->rmmio = ioremap(rdev->rmmio_base, rdev->rmmio_size);
@ -1051,6 +1052,10 @@ int radeon_device_init(struct radeon_device *rdev,
if (r) if (r)
return r; return r;
// r = radeon_ib_ring_tests(rdev);
// if (r)
// DRM_ERROR("ib ring test failed (%d).\n", r);
if (rdev->flags & RADEON_IS_AGP && !rdev->accel_working) { if (rdev->flags & RADEON_IS_AGP && !rdev->accel_working) {
/* Acceleration not working on AGP card try again /* Acceleration not working on AGP card try again
* with fallback to PCI or PCIE GART * with fallback to PCI or PCIE GART
@ -1126,15 +1131,15 @@ retry:
ring_data[i] = NULL; ring_data[i] = NULL;
} }
r = radeon_ib_ring_tests(rdev); // r = radeon_ib_ring_tests(rdev);
if (r) { // if (r) {
dev_err(rdev->dev, "ib ring test failed (%d).\n", r); // dev_err(rdev->dev, "ib ring test failed (%d).\n", r);
if (saved) { // if (saved) {
saved = false; // saved = false;
radeon_suspend(rdev); // radeon_suspend(rdev);
goto retry; // goto retry;
} // }
} // }
} else { } else {
for (i = 0; i < RADEON_NUM_RINGS; ++i) { for (i = 0; i < RADEON_NUM_RINGS; ++i) {
kfree(ring_data[i]); kfree(ring_data[i]);
@ -1152,7 +1157,6 @@ retry:
} }
/* /*
* Driver load/unload * Driver load/unload
*/ */
@ -1434,7 +1438,7 @@ u32_t drvEntry(int action, char *cmdline)
if(!dbg_open(log)) if(!dbg_open(log))
{ {
strcpy(log, "/RD/1/DRIVERS/atikms.log"); strcpy(log, "/TMP1/1/atikms.log");
if(!dbg_open(log)) if(!dbg_open(log))
{ {
@ -1442,7 +1446,7 @@ u32_t drvEntry(int action, char *cmdline)
return 0; return 0;
}; };
} }
dbgprintf("Radeon RC12 preview 1 cmdline %s\n", cmdline); dbgprintf("Radeon RC13 cmdline %s\n", cmdline);
enum_pci_devices(); enum_pci_devices();
@ -1491,3 +1495,13 @@ int pci_scan_filter(u32_t id, u32_t busnr, u32_t devfn)
} }
return ret; return ret;
} }
unsigned int hweight32(unsigned int w)
{
unsigned int res = w - ((w >> 1) & 0x55555555);
res = (res & 0x33333333) + ((res >> 2) & 0x33333333);
res = (res + (res >> 4)) & 0x0F0F0F0F;
res = res + (res >> 8);
return (res + (res >> 16)) & 0x000000FF;
}

View File

@ -448,10 +448,15 @@ int radeon_ddc_get_modes(struct radeon_connector *radeon_connector)
if (radeon_connector->router.ddc_valid) if (radeon_connector->router.ddc_valid)
radeon_router_select_ddc_port(radeon_connector); radeon_router_select_ddc_port(radeon_connector);
if ((radeon_connector->base.connector_type == DRM_MODE_CONNECTOR_DisplayPort) || if (radeon_connector_encoder_get_dp_bridge_encoder_id(&radeon_connector->base) !=
(radeon_connector->base.connector_type == DRM_MODE_CONNECTOR_eDP) || ENCODER_OBJECT_ID_NONE) {
(radeon_connector_encoder_get_dp_bridge_encoder_id(&radeon_connector->base) != struct radeon_connector_atom_dig *dig = radeon_connector->con_priv;
ENCODER_OBJECT_ID_NONE)) {
if (dig->dp_i2c_bus)
radeon_connector->edid = drm_get_edid(&radeon_connector->base,
&dig->dp_i2c_bus->adapter);
} else if ((radeon_connector->base.connector_type == DRM_MODE_CONNECTOR_DisplayPort) ||
(radeon_connector->base.connector_type == DRM_MODE_CONNECTOR_eDP)) {
struct radeon_connector_atom_dig *dig = radeon_connector->con_priv; struct radeon_connector_atom_dig *dig = radeon_connector->con_priv;
if ((dig->dp_sink_type == CONNECTOR_OBJECT_ID_DISPLAYPORT || if ((dig->dp_sink_type == CONNECTOR_OBJECT_ID_DISPLAYPORT ||
@ -1038,6 +1043,8 @@ int radeon_modeset_init(struct radeon_device *rdev)
int i; int i;
int ret; int ret;
ENTER();
drm_mode_config_init(rdev->ddev); drm_mode_config_init(rdev->ddev);
rdev->mode_info.mode_config_initialized = true; rdev->mode_info.mode_config_initialized = true;
@ -1067,6 +1074,8 @@ int radeon_modeset_init(struct radeon_device *rdev)
/* init i2c buses */ /* init i2c buses */
radeon_i2c_init(rdev); radeon_i2c_init(rdev);
dbgprintf("i2c init\n");
/* check combios for a valid hardcoded EDID - Sun servers */ /* check combios for a valid hardcoded EDID - Sun servers */
if (!rdev->is_atom_bios) { if (!rdev->is_atom_bios) {
/* check for hardcoded EDID in BIOS */ /* check for hardcoded EDID in BIOS */
@ -1078,6 +1087,8 @@ int radeon_modeset_init(struct radeon_device *rdev)
radeon_crtc_init(rdev->ddev, i); radeon_crtc_init(rdev->ddev, i);
} }
dbgprintf("crtc init\n");
/* okay we should have all the bios connectors */ /* okay we should have all the bios connectors */
ret = radeon_setup_enc_conn(rdev->ddev); ret = radeon_setup_enc_conn(rdev->ddev);
if (!ret) { if (!ret) {
@ -1102,6 +1113,8 @@ int radeon_modeset_init(struct radeon_device *rdev)
radeon_fbdev_init(rdev); radeon_fbdev_init(rdev);
// drm_kms_helper_poll_init(rdev->ddev); // drm_kms_helper_poll_init(rdev->ddev);
LEAVE();
return 0; return 0;
} }

View File

@ -30,7 +30,7 @@
*/ */
#include <linux/seq_file.h> #include <linux/seq_file.h>
#include <asm/atomic.h> #include <asm/atomic.h>
//#include <linux/wait.h> #include <linux/wait.h>
#include <linux/list.h> #include <linux/list.h>
#include <linux/kref.h> #include <linux/kref.h>
#include <linux/slab.h> #include <linux/slab.h>
@ -303,21 +303,19 @@ static int radeon_fence_wait_seq(struct radeon_device *rdev, u64 target_seq,
// trace_radeon_fence_wait_begin(rdev->ddev, seq); // trace_radeon_fence_wait_begin(rdev->ddev, seq);
radeon_irq_kms_sw_irq_get(rdev, ring); radeon_irq_kms_sw_irq_get(rdev, ring);
// if (intr) { if (intr) {
// r = wait_event_interruptible_timeout(rdev->fence_queue, r = wait_event_interruptible_timeout(rdev->fence_queue,
// (signaled = radeon_fence_seq_signaled(rdev, target_seq, ring)), (signaled = radeon_fence_seq_signaled(rdev, target_seq, ring)),
// timeout); timeout);
// } else { } else {
// r = wait_event_timeout(rdev->fence_queue, r = wait_event_timeout(rdev->fence_queue,
// (signaled = radeon_fence_seq_signaled(rdev, target_seq, ring)), (signaled = radeon_fence_seq_signaled(rdev, target_seq, ring)),
// timeout); timeout);
// } }
delay(1);
radeon_irq_kms_sw_irq_put(rdev, ring); radeon_irq_kms_sw_irq_put(rdev, ring);
// if (unlikely(r < 0)) { if (unlikely(r < 0)) {
// return r; return r;
// } }
// trace_radeon_fence_wait_end(rdev->ddev, seq); // trace_radeon_fence_wait_end(rdev->ddev, seq);
if (unlikely(!signaled)) { if (unlikely(!signaled)) {
@ -474,11 +472,15 @@ static int radeon_fence_wait_any_seq(struct radeon_device *rdev,
radeon_irq_kms_sw_irq_get(rdev, i); radeon_irq_kms_sw_irq_get(rdev, i);
} }
} }
if (intr) {
// WaitEvent(fence->evnt); r = wait_event_interruptible_timeout(rdev->fence_queue,
(signaled = radeon_fence_any_seq_signaled(rdev, target_seq)),
r = 1; timeout);
} else {
r = wait_event_timeout(rdev->fence_queue,
(signaled = radeon_fence_any_seq_signaled(rdev, target_seq)),
timeout);
}
for (i = 0; i < RADEON_NUM_RINGS; ++i) { for (i = 0; i < RADEON_NUM_RINGS; ++i) {
if (target_seq[i]) { if (target_seq[i]) {
radeon_irq_kms_sw_irq_put(rdev, i); radeon_irq_kms_sw_irq_put(rdev, i);
@ -606,26 +608,20 @@ int radeon_fence_wait_next_locked(struct radeon_device *rdev, int ring)
* Returns 0 if the fences have passed, error for all other cases. * Returns 0 if the fences have passed, error for all other cases.
* Caller must hold ring lock. * Caller must hold ring lock.
*/ */
void radeon_fence_wait_empty_locked(struct radeon_device *rdev, int ring) int radeon_fence_wait_empty_locked(struct radeon_device *rdev, int ring)
{ {
uint64_t seq = rdev->fence_drv[ring].sync_seq[ring]; uint64_t seq = rdev->fence_drv[ring].sync_seq[ring];
while(1) {
int r; int r;
r = radeon_fence_wait_seq(rdev, seq, ring, false, false); r = radeon_fence_wait_seq(rdev, seq, ring, false, false);
if (r) {
if (r == -EDEADLK) { if (r == -EDEADLK) {
mutex_unlock(&rdev->ring_lock); return -EDEADLK;
r = radeon_gpu_reset(rdev);
mutex_lock(&rdev->ring_lock);
if (!r)
continue;
} }
if (r) { dev_err(rdev->dev, "error waiting for ring[%d] to become idle (%d)\n",
dev_err(rdev->dev, "error waiting for ring to become" ring, r);
" idle (%d)\n", r);
}
return;
} }
return 0;
} }
/** /**
@ -769,7 +765,7 @@ int radeon_fence_driver_start_ring(struct radeon_device *rdev, int ring)
int r; int r;
radeon_scratch_free(rdev, rdev->fence_drv[ring].scratch_reg); radeon_scratch_free(rdev, rdev->fence_drv[ring].scratch_reg);
if (rdev->wb.use_event) { if (rdev->wb.use_event || !radeon_ring_supports_scratch_reg(rdev, &rdev->ring[ring])) {
rdev->fence_drv[ring].scratch_reg = 0; rdev->fence_drv[ring].scratch_reg = 0;
index = R600_WB_EVENT_OFFSET + ring * 4; index = R600_WB_EVENT_OFFSET + ring * 4;
} else { } else {
@ -851,13 +847,17 @@ int radeon_fence_driver_init(struct radeon_device *rdev)
*/ */
void radeon_fence_driver_fini(struct radeon_device *rdev) void radeon_fence_driver_fini(struct radeon_device *rdev)
{ {
int ring; int ring, r;
mutex_lock(&rdev->ring_lock); mutex_lock(&rdev->ring_lock);
for (ring = 0; ring < RADEON_NUM_RINGS; ring++) { for (ring = 0; ring < RADEON_NUM_RINGS; ring++) {
if (!rdev->fence_drv[ring].initialized) if (!rdev->fence_drv[ring].initialized)
continue; continue;
radeon_fence_wait_empty_locked(rdev, ring); r = radeon_fence_wait_empty_locked(rdev, ring);
if (r) {
/* no need to trigger GPU reset as we are unloading */
radeon_fence_driver_force_completion(rdev);
}
wake_up_all(&rdev->fence_queue); wake_up_all(&rdev->fence_queue);
radeon_scratch_free(rdev, rdev->fence_drv[ring].scratch_reg); radeon_scratch_free(rdev, rdev->fence_drv[ring].scratch_reg);
rdev->fence_drv[ring].initialized = false; rdev->fence_drv[ring].initialized = false;
@ -865,6 +865,25 @@ void radeon_fence_driver_fini(struct radeon_device *rdev)
mutex_unlock(&rdev->ring_lock); mutex_unlock(&rdev->ring_lock);
} }
/**
* radeon_fence_driver_force_completion - force all fence waiter to complete
*
* @rdev: radeon device pointer
*
* In case of GPU reset failure make sure no process keep waiting on fence
* that will never complete.
*/
void radeon_fence_driver_force_completion(struct radeon_device *rdev)
{
int ring;
for (ring = 0; ring < RADEON_NUM_RINGS; ring++) {
if (!rdev->fence_drv[ring].initialized)
continue;
radeon_fence_write(rdev, rdev->fence_drv[ring].sync_seq[ring], ring);
}
}
/* /*
* Fence debugfs * Fence debugfs

View File

@ -1248,7 +1248,6 @@ void radeon_vm_bo_invalidate(struct radeon_device *rdev,
{ {
struct radeon_bo_va *bo_va; struct radeon_bo_va *bo_va;
BUG_ON(!atomic_read(&bo->tbo.reserved));
list_for_each_entry(bo_va, &bo->va, bo_list) { list_for_each_entry(bo_va, &bo->va, bo_list) {
bo_va->valid = false; bo_va->valid = false;
} }

View File

@ -39,7 +39,7 @@ extern u32 radeon_atom_hw_i2c_func(struct i2c_adapter *adap);
* radeon_ddc_probe * radeon_ddc_probe
* *
*/ */
bool radeon_ddc_probe(struct radeon_connector *radeon_connector) bool radeon_ddc_probe(struct radeon_connector *radeon_connector, bool use_aux)
{ {
u8 out = 0x0; u8 out = 0x0;
u8 buf[8]; u8 buf[8];
@ -63,7 +63,13 @@ bool radeon_ddc_probe(struct radeon_connector *radeon_connector)
if (radeon_connector->router.ddc_valid) if (radeon_connector->router.ddc_valid)
radeon_router_select_ddc_port(radeon_connector); radeon_router_select_ddc_port(radeon_connector);
if (use_aux) {
struct radeon_connector_atom_dig *dig = radeon_connector->con_priv;
ret = i2c_transfer(&dig->dp_i2c_bus->adapter, msgs, 2);
} else {
ret = i2c_transfer(&radeon_connector->ddc_bus->adapter, msgs, 2); ret = i2c_transfer(&radeon_connector->ddc_bus->adapter, msgs, 2);
}
if (ret != 2) if (ret != 2)
/* Couldn't find an accessible DDC on this connector */ /* Couldn't find an accessible DDC on this connector */
return false; return false;
@ -922,11 +928,11 @@ struct radeon_i2c_chan *radeon_i2c_create(struct drm_device *dev,
snprintf(i2c->adapter.name, sizeof(i2c->adapter.name), snprintf(i2c->adapter.name, sizeof(i2c->adapter.name),
"Radeon i2c hw bus %s", name); "Radeon i2c hw bus %s", name);
i2c->adapter.algo = &radeon_i2c_algo; i2c->adapter.algo = &radeon_i2c_algo;
// ret = i2c_add_adapter(&i2c->adapter); ret = i2c_add_adapter(&i2c->adapter);
// if (ret) { if (ret) {
// DRM_ERROR("Failed to register hw i2c %s\n", name); DRM_ERROR("Failed to register hw i2c %s\n", name);
// goto out_free; goto out_free;
// } }
} else if (rec->hw_capable && } else if (rec->hw_capable &&
radeon_hw_i2c && radeon_hw_i2c &&
ASIC_IS_DCE3(rdev)) { ASIC_IS_DCE3(rdev)) {
@ -934,11 +940,11 @@ struct radeon_i2c_chan *radeon_i2c_create(struct drm_device *dev,
snprintf(i2c->adapter.name, sizeof(i2c->adapter.name), snprintf(i2c->adapter.name, sizeof(i2c->adapter.name),
"Radeon i2c hw bus %s", name); "Radeon i2c hw bus %s", name);
i2c->adapter.algo = &radeon_atom_i2c_algo; i2c->adapter.algo = &radeon_atom_i2c_algo;
// ret = i2c_add_adapter(&i2c->adapter); ret = i2c_add_adapter(&i2c->adapter);
// if (ret) { if (ret) {
// DRM_ERROR("Failed to register hw i2c %s\n", name); DRM_ERROR("Failed to register hw i2c %s\n", name);
// goto out_free; goto out_free;
// } }
} else { } else {
/* set the radeon bit adapter */ /* set the radeon bit adapter */
snprintf(i2c->adapter.name, sizeof(i2c->adapter.name), snprintf(i2c->adapter.name, sizeof(i2c->adapter.name),
@ -1005,7 +1011,7 @@ void radeon_i2c_destroy(struct radeon_i2c_chan *i2c)
{ {
if (!i2c) if (!i2c)
return; return;
// i2c_del_adapter(&i2c->adapter); i2c_del_adapter(&i2c->adapter);
kfree(i2c); kfree(i2c);
} }

View File

@ -209,7 +209,8 @@ enum radeon_connector_table {
CT_RN50_POWER, CT_RN50_POWER,
CT_MAC_X800, CT_MAC_X800,
CT_MAC_G5_9600, CT_MAC_G5_9600,
CT_SAM440EP CT_SAM440EP,
CT_MAC_G4_SILVER
}; };
enum radeon_dvo_chip { enum radeon_dvo_chip {
@ -425,7 +426,7 @@ struct radeon_connector_atom_dig {
uint32_t igp_lane_info; uint32_t igp_lane_info;
/* displayport */ /* displayport */
struct radeon_i2c_chan *dp_i2c_bus; struct radeon_i2c_chan *dp_i2c_bus;
u8 dpcd[8]; u8 dpcd[DP_RECEIVER_CAP_SIZE];
u8 dp_sink_type; u8 dp_sink_type;
int dp_clock; int dp_clock;
int dp_lane_count; int dp_lane_count;
@ -556,7 +557,7 @@ extern void radeon_i2c_put_byte(struct radeon_i2c_chan *i2c,
u8 val); u8 val);
extern void radeon_router_select_ddc_port(struct radeon_connector *radeon_connector); extern void radeon_router_select_ddc_port(struct radeon_connector *radeon_connector);
extern void radeon_router_select_cd_port(struct radeon_connector *radeon_connector); extern void radeon_router_select_cd_port(struct radeon_connector *radeon_connector);
extern bool radeon_ddc_probe(struct radeon_connector *radeon_connector); extern bool radeon_ddc_probe(struct radeon_connector *radeon_connector, bool use_aux);
extern int radeon_ddc_get_modes(struct radeon_connector *radeon_connector); extern int radeon_ddc_get_modes(struct radeon_connector *radeon_connector);
extern struct drm_encoder *radeon_best_encoder(struct drm_connector *connector); extern struct drm_encoder *radeon_best_encoder(struct drm_connector *connector);

View File

@ -385,11 +385,9 @@ int radeon_ring_alloc(struct radeon_device *rdev, struct radeon_ring *ring, unsi
if (ndw < ring->ring_free_dw) { if (ndw < ring->ring_free_dw) {
break; break;
} }
// r = radeon_fence_wait_next(rdev); r = radeon_fence_wait_next_locked(rdev, ring->idx);
// if (r) { if (r)
// mutex_unlock(&rdev->cp.mutex); return r;
// return r;
// }
} }
ring->count_dw = ndw; ring->count_dw = ndw;
ring->wptr_old = ring->wptr; ring->wptr_old = ring->wptr;
@ -461,7 +459,7 @@ void radeon_ring_unlock_commit(struct radeon_device *rdev, struct radeon_ring *r
* *
* @ring: radeon_ring structure holding ring information * @ring: radeon_ring structure holding ring information
* *
* Reset the driver's copy of the wtpr (all asics). * Reset the driver's copy of the wptr (all asics).
*/ */
void radeon_ring_undo(struct radeon_ring *ring) void radeon_ring_undo(struct radeon_ring *ring)
{ {
@ -505,7 +503,7 @@ void radeon_ring_force_activity(struct radeon_device *rdev, struct radeon_ring *
} }
/** /**
* radeon_ring_force_activity - update lockup variables * radeon_ring_lockup_update - update lockup variables
* *
* @ring: radeon_ring structure holding ring information * @ring: radeon_ring structure holding ring information
* *
@ -772,22 +770,30 @@ static int radeon_debugfs_ring_info(struct seq_file *m, void *data)
int ridx = *(int*)node->info_ent->data; int ridx = *(int*)node->info_ent->data;
struct radeon_ring *ring = &rdev->ring[ridx]; struct radeon_ring *ring = &rdev->ring[ridx];
unsigned count, i, j; unsigned count, i, j;
u32 tmp;
radeon_ring_free_size(rdev, ring); radeon_ring_free_size(rdev, ring);
count = (ring->ring_size / 4) - ring->ring_free_dw; count = (ring->ring_size / 4) - ring->ring_free_dw;
seq_printf(m, "wptr(0x%04x): 0x%08x\n", ring->wptr_reg, RREG32(ring->wptr_reg)); tmp = RREG32(ring->wptr_reg) >> ring->ptr_reg_shift;
seq_printf(m, "rptr(0x%04x): 0x%08x\n", ring->rptr_reg, RREG32(ring->rptr_reg)); seq_printf(m, "wptr(0x%04x): 0x%08x [%5d]\n", ring->wptr_reg, tmp, tmp);
tmp = RREG32(ring->rptr_reg) >> ring->ptr_reg_shift;
seq_printf(m, "rptr(0x%04x): 0x%08x [%5d]\n", ring->rptr_reg, tmp, tmp);
if (ring->rptr_save_reg) { if (ring->rptr_save_reg) {
seq_printf(m, "rptr next(0x%04x): 0x%08x\n", ring->rptr_save_reg, seq_printf(m, "rptr next(0x%04x): 0x%08x\n", ring->rptr_save_reg,
RREG32(ring->rptr_save_reg)); RREG32(ring->rptr_save_reg));
} }
seq_printf(m, "driver's copy of the wptr: 0x%08x\n", ring->wptr); seq_printf(m, "driver's copy of the wptr: 0x%08x [%5d]\n", ring->wptr, ring->wptr);
seq_printf(m, "driver's copy of the rptr: 0x%08x\n", ring->rptr); seq_printf(m, "driver's copy of the rptr: 0x%08x [%5d]\n", ring->rptr, ring->rptr);
seq_printf(m, "last semaphore signal addr : 0x%016llx\n", ring->last_semaphore_signal_addr);
seq_printf(m, "last semaphore wait addr : 0x%016llx\n", ring->last_semaphore_wait_addr);
seq_printf(m, "%u free dwords in ring\n", ring->ring_free_dw); seq_printf(m, "%u free dwords in ring\n", ring->ring_free_dw);
seq_printf(m, "%u dwords in ring\n", count); seq_printf(m, "%u dwords in ring\n", count);
i = ring->rptr; /* print 8 dw before current rptr as often it's the last executed
for (j = 0; j <= count; j++) { * packet that is the root issue
seq_printf(m, "r[%04d]=0x%08x\n", i, ring->ring[i]); */
i = (ring->rptr + ring->ptr_mask + 1 - 32) & ring->ptr_mask;
for (j = 0; j <= (count + 32); j++) {
seq_printf(m, "r[%5d]=0x%08x\n", i, ring->ring[i]);
i = (i + 1) & ring->ptr_mask; i = (i + 1) & ring->ptr_mask;
} }
return 0; return 0;
@ -796,11 +802,15 @@ static int radeon_debugfs_ring_info(struct seq_file *m, void *data)
static int radeon_ring_type_gfx_index = RADEON_RING_TYPE_GFX_INDEX; static int radeon_ring_type_gfx_index = RADEON_RING_TYPE_GFX_INDEX;
static int cayman_ring_type_cp1_index = CAYMAN_RING_TYPE_CP1_INDEX; static int cayman_ring_type_cp1_index = CAYMAN_RING_TYPE_CP1_INDEX;
static int cayman_ring_type_cp2_index = CAYMAN_RING_TYPE_CP2_INDEX; static int cayman_ring_type_cp2_index = CAYMAN_RING_TYPE_CP2_INDEX;
static int radeon_ring_type_dma1_index = R600_RING_TYPE_DMA_INDEX;
static int radeon_ring_type_dma2_index = CAYMAN_RING_TYPE_DMA1_INDEX;
static struct drm_info_list radeon_debugfs_ring_info_list[] = { static struct drm_info_list radeon_debugfs_ring_info_list[] = {
{"radeon_ring_gfx", radeon_debugfs_ring_info, 0, &radeon_ring_type_gfx_index}, {"radeon_ring_gfx", radeon_debugfs_ring_info, 0, &radeon_ring_type_gfx_index},
{"radeon_ring_cp1", radeon_debugfs_ring_info, 0, &cayman_ring_type_cp1_index}, {"radeon_ring_cp1", radeon_debugfs_ring_info, 0, &cayman_ring_type_cp1_index},
{"radeon_ring_cp2", radeon_debugfs_ring_info, 0, &cayman_ring_type_cp2_index}, {"radeon_ring_cp2", radeon_debugfs_ring_info, 0, &cayman_ring_type_cp2_index},
{"radeon_ring_dma1", radeon_debugfs_ring_info, 0, &radeon_ring_type_dma1_index},
{"radeon_ring_dma2", radeon_debugfs_ring_info, 0, &radeon_ring_type_dma2_index},
}; };
static int radeon_debugfs_sa_info(struct seq_file *m, void *data) static int radeon_debugfs_sa_info(struct seq_file *m, void *data)

View File

@ -894,6 +894,8 @@ int srv_blit_bitmap(u32 hbitmap, int dst_x, int dst_y,
goto fail; goto fail;
} }
radeon_fence_unref(&ib->fence);
fail: fail:
return ret; return ret;
}; };

View File

@ -705,6 +705,12 @@ static int rs600_startup(struct radeon_device *rdev)
if (r) if (r)
return r; return r;
r = radeon_fence_driver_start_ring(rdev, RADEON_RING_TYPE_GFX_INDEX);
if (r) {
dev_err(rdev->dev, "failed initializing CP fences (%d).\n", r);
return r;
}
/* Enable IRQ */ /* Enable IRQ */
rs600_irq_set(rdev); rs600_irq_set(rdev);
rdev->config.r300.hdp_cntl = RREG32(RADEON_HOST_PATH_CNTL); rdev->config.r300.hdp_cntl = RREG32(RADEON_HOST_PATH_CNTL);

View File

@ -621,6 +621,12 @@ static int rs690_startup(struct radeon_device *rdev)
if (r) if (r)
return r; return r;
r = radeon_fence_driver_start_ring(rdev, RADEON_RING_TYPE_GFX_INDEX);
if (r) {
dev_err(rdev->dev, "failed initializing CP fences (%d).\n", r);
return r;
}
/* Enable IRQ */ /* Enable IRQ */
rs600_irq_set(rdev); rs600_irq_set(rdev);
rdev->config.r300.hdp_cntl = RREG32(RADEON_HOST_PATH_CNTL); rdev->config.r300.hdp_cntl = RREG32(RADEON_HOST_PATH_CNTL);

View File

@ -40,6 +40,12 @@ static int rv515_debugfs_ga_info_init(struct radeon_device *rdev);
static void rv515_gpu_init(struct radeon_device *rdev); static void rv515_gpu_init(struct radeon_device *rdev);
int rv515_mc_wait_for_idle(struct radeon_device *rdev); int rv515_mc_wait_for_idle(struct radeon_device *rdev);
static const u32 crtc_offsets[2] =
{
0,
AVIVO_D2CRTC_H_TOTAL - AVIVO_D1CRTC_H_TOTAL
};
void rv515_debugfs(struct radeon_device *rdev) void rv515_debugfs(struct radeon_device *rdev)
{ {
if (r100_debugfs_rbbm_init(rdev)) { if (r100_debugfs_rbbm_init(rdev)) {
@ -281,30 +287,114 @@ static int rv515_debugfs_ga_info_init(struct radeon_device *rdev)
void rv515_mc_stop(struct radeon_device *rdev, struct rv515_mc_save *save) void rv515_mc_stop(struct radeon_device *rdev, struct rv515_mc_save *save)
{ {
u32 crtc_enabled, tmp, frame_count, blackout;
int i, j;
save->vga_render_control = RREG32(R_000300_VGA_RENDER_CONTROL); save->vga_render_control = RREG32(R_000300_VGA_RENDER_CONTROL);
save->vga_hdp_control = RREG32(R_000328_VGA_HDP_CONTROL); save->vga_hdp_control = RREG32(R_000328_VGA_HDP_CONTROL);
/* Stop all video */ /* disable VGA render */
WREG32(R_0068E8_D2CRTC_UPDATE_LOCK, 0);
WREG32(R_000300_VGA_RENDER_CONTROL, 0); WREG32(R_000300_VGA_RENDER_CONTROL, 0);
WREG32(R_0060E8_D1CRTC_UPDATE_LOCK, 1); /* blank the display controllers */
WREG32(R_0068E8_D2CRTC_UPDATE_LOCK, 1); for (i = 0; i < rdev->num_crtc; i++) {
WREG32(R_006080_D1CRTC_CONTROL, 0); crtc_enabled = RREG32(AVIVO_D1CRTC_CONTROL + crtc_offsets[i]) & AVIVO_CRTC_EN;
WREG32(R_006880_D2CRTC_CONTROL, 0); if (crtc_enabled) {
WREG32(R_0060E8_D1CRTC_UPDATE_LOCK, 0); save->crtc_enabled[i] = true;
WREG32(R_0068E8_D2CRTC_UPDATE_LOCK, 0); tmp = RREG32(AVIVO_D1CRTC_CONTROL + crtc_offsets[i]);
WREG32(R_000330_D1VGA_CONTROL, 0); if (!(tmp & AVIVO_CRTC_DISP_READ_REQUEST_DISABLE)) {
WREG32(R_000338_D2VGA_CONTROL, 0); radeon_wait_for_vblank(rdev, i);
tmp |= AVIVO_CRTC_DISP_READ_REQUEST_DISABLE;
WREG32(AVIVO_D1CRTC_CONTROL + crtc_offsets[i], tmp);
}
/* wait for the next frame */
frame_count = radeon_get_vblank_counter(rdev, i);
for (j = 0; j < rdev->usec_timeout; j++) {
if (radeon_get_vblank_counter(rdev, i) != frame_count)
break;
udelay(1);
}
} else {
save->crtc_enabled[i] = false;
}
}
radeon_mc_wait_for_idle(rdev);
if (rdev->family >= CHIP_R600) {
if (rdev->family >= CHIP_RV770)
blackout = RREG32(R700_MC_CITF_CNTL);
else
blackout = RREG32(R600_CITF_CNTL);
if ((blackout & R600_BLACKOUT_MASK) != R600_BLACKOUT_MASK) {
/* Block CPU access */
WREG32(R600_BIF_FB_EN, 0);
/* blackout the MC */
blackout |= R600_BLACKOUT_MASK;
if (rdev->family >= CHIP_RV770)
WREG32(R700_MC_CITF_CNTL, blackout);
else
WREG32(R600_CITF_CNTL, blackout);
}
}
} }
void rv515_mc_resume(struct radeon_device *rdev, struct rv515_mc_save *save) void rv515_mc_resume(struct radeon_device *rdev, struct rv515_mc_save *save)
{ {
WREG32(R_006110_D1GRPH_PRIMARY_SURFACE_ADDRESS, rdev->mc.vram_start); u32 tmp, frame_count;
WREG32(R_006118_D1GRPH_SECONDARY_SURFACE_ADDRESS, rdev->mc.vram_start); int i, j;
WREG32(R_006910_D2GRPH_PRIMARY_SURFACE_ADDRESS, rdev->mc.vram_start);
WREG32(R_006918_D2GRPH_SECONDARY_SURFACE_ADDRESS, rdev->mc.vram_start); /* update crtc base addresses */
WREG32(R_000310_VGA_MEMORY_BASE_ADDRESS, rdev->mc.vram_start); for (i = 0; i < rdev->num_crtc; i++) {
/* Unlock host access */ if (rdev->family >= CHIP_RV770) {
if (i == 1) {
WREG32(R700_D1GRPH_PRIMARY_SURFACE_ADDRESS_HIGH,
upper_32_bits(rdev->mc.vram_start));
WREG32(R700_D1GRPH_SECONDARY_SURFACE_ADDRESS_HIGH,
upper_32_bits(rdev->mc.vram_start));
} else {
WREG32(R700_D2GRPH_PRIMARY_SURFACE_ADDRESS_HIGH,
upper_32_bits(rdev->mc.vram_start));
WREG32(R700_D2GRPH_SECONDARY_SURFACE_ADDRESS_HIGH,
upper_32_bits(rdev->mc.vram_start));
}
}
WREG32(R_006110_D1GRPH_PRIMARY_SURFACE_ADDRESS + crtc_offsets[i],
(u32)rdev->mc.vram_start);
WREG32(R_006118_D1GRPH_SECONDARY_SURFACE_ADDRESS + crtc_offsets[i],
(u32)rdev->mc.vram_start);
}
WREG32(R_000310_VGA_MEMORY_BASE_ADDRESS, (u32)rdev->mc.vram_start);
if (rdev->family >= CHIP_R600) {
/* unblackout the MC */
if (rdev->family >= CHIP_RV770)
tmp = RREG32(R700_MC_CITF_CNTL);
else
tmp = RREG32(R600_CITF_CNTL);
tmp &= ~R600_BLACKOUT_MASK;
if (rdev->family >= CHIP_RV770)
WREG32(R700_MC_CITF_CNTL, tmp);
else
WREG32(R600_CITF_CNTL, tmp);
/* allow CPU access */
WREG32(R600_BIF_FB_EN, R600_FB_READ_EN | R600_FB_WRITE_EN);
}
for (i = 0; i < rdev->num_crtc; i++) {
if (save->crtc_enabled[i]) {
tmp = RREG32(AVIVO_D1CRTC_CONTROL + crtc_offsets[i]);
tmp &= ~AVIVO_CRTC_DISP_READ_REQUEST_DISABLE;
WREG32(AVIVO_D1CRTC_CONTROL + crtc_offsets[i], tmp);
/* wait for the next frame */
frame_count = radeon_get_vblank_counter(rdev, i);
for (j = 0; j < rdev->usec_timeout; j++) {
if (radeon_get_vblank_counter(rdev, i) != frame_count)
break;
udelay(1);
}
}
}
/* Unlock vga access */
WREG32(R_000328_VGA_HDP_CONTROL, save->vga_hdp_control); WREG32(R_000328_VGA_HDP_CONTROL, save->vga_hdp_control);
mdelay(1); mdelay(1);
WREG32(R_000300_VGA_RENDER_CONTROL, save->vga_render_control); WREG32(R_000300_VGA_RENDER_CONTROL, save->vga_render_control);

View File

@ -239,6 +239,7 @@ void r700_cp_stop(struct radeon_device *rdev)
// radeon_ttm_set_active_vram_size(rdev, rdev->mc.visible_vram_size); // radeon_ttm_set_active_vram_size(rdev, rdev->mc.visible_vram_size);
WREG32(CP_ME_CNTL, (CP_ME_HALT | CP_PFP_HALT)); WREG32(CP_ME_CNTL, (CP_ME_HALT | CP_PFP_HALT));
WREG32(SCRATCH_UMSK, 0); WREG32(SCRATCH_UMSK, 0);
rdev->ring[RADEON_RING_TYPE_GFX_INDEX].ready = false;
} }
static int rv770_cp_load_microcode(struct radeon_device *rdev) static int rv770_cp_load_microcode(struct radeon_device *rdev)
@ -499,6 +500,8 @@ static void rv770_gpu_init(struct radeon_device *rdev)
WREG32(GB_TILING_CONFIG, gb_tiling_config); WREG32(GB_TILING_CONFIG, gb_tiling_config);
WREG32(DCP_TILING_CONFIG, (gb_tiling_config & 0xffff)); WREG32(DCP_TILING_CONFIG, (gb_tiling_config & 0xffff));
WREG32(HDP_TILING_CONFIG, (gb_tiling_config & 0xffff)); WREG32(HDP_TILING_CONFIG, (gb_tiling_config & 0xffff));
WREG32(DMA_TILING_CONFIG, (gb_tiling_config & 0xffff));
WREG32(DMA_TILING_CONFIG2, (gb_tiling_config & 0xffff));
WREG32(CGTS_SYS_TCC_DISABLE, 0); WREG32(CGTS_SYS_TCC_DISABLE, 0);
WREG32(CGTS_TCC_DISABLE, 0); WREG32(CGTS_TCC_DISABLE, 0);
@ -802,7 +805,7 @@ static int rv770_mc_init(struct radeon_device *rdev)
static int rv770_startup(struct radeon_device *rdev) static int rv770_startup(struct radeon_device *rdev)
{ {
struct radeon_ring *ring = &rdev->ring[RADEON_RING_TYPE_GFX_INDEX]; struct radeon_ring *ring;
int r; int r;
/* enable pcie gen2 link */ /* enable pcie gen2 link */
@ -849,6 +852,18 @@ static int rv770_startup(struct radeon_device *rdev)
if (r) if (r)
return r; return r;
r = radeon_fence_driver_start_ring(rdev, RADEON_RING_TYPE_GFX_INDEX);
if (r) {
dev_err(rdev->dev, "failed initializing CP fences (%d).\n", r);
return r;
}
r = radeon_fence_driver_start_ring(rdev, R600_RING_TYPE_DMA_INDEX);
if (r) {
dev_err(rdev->dev, "failed initializing DMA fences (%d).\n", r);
return r;
}
/* Enable IRQ */ /* Enable IRQ */
r = r600_irq_init(rdev); r = r600_irq_init(rdev);
if (r) { if (r) {
@ -858,11 +873,20 @@ static int rv770_startup(struct radeon_device *rdev)
} }
r600_irq_set(rdev); r600_irq_set(rdev);
ring = &rdev->ring[RADEON_RING_TYPE_GFX_INDEX];
r = radeon_ring_init(rdev, ring, ring->ring_size, RADEON_WB_CP_RPTR_OFFSET, r = radeon_ring_init(rdev, ring, ring->ring_size, RADEON_WB_CP_RPTR_OFFSET,
R600_CP_RB_RPTR, R600_CP_RB_WPTR, R600_CP_RB_RPTR, R600_CP_RB_WPTR,
0, 0xfffff, RADEON_CP_PACKET2); 0, 0xfffff, RADEON_CP_PACKET2);
if (r) if (r)
return r; return r;
ring = &rdev->ring[R600_RING_TYPE_DMA_INDEX];
r = radeon_ring_init(rdev, ring, ring->ring_size, R600_WB_DMA_RPTR_OFFSET,
DMA_RB_RPTR, DMA_RB_WPTR,
2, 0x3fffc, DMA_PACKET(DMA_PACKET_NOP, 0, 0, 0));
if (r)
return r;
r = rv770_cp_load_microcode(rdev); r = rv770_cp_load_microcode(rdev);
if (r) if (r)
return r; return r;
@ -870,6 +894,10 @@ static int rv770_startup(struct radeon_device *rdev)
if (r) if (r)
return r; return r;
r = r600_dma_resume(rdev);
if (r)
return r;
r = radeon_ib_pool_init(rdev); r = radeon_ib_pool_init(rdev);
if (r) { if (r) {
dev_err(rdev->dev, "IB initialization failed (%d).\n", r); dev_err(rdev->dev, "IB initialization failed (%d).\n", r);
@ -949,6 +977,9 @@ int rv770_init(struct radeon_device *rdev)
rdev->ring[RADEON_RING_TYPE_GFX_INDEX].ring_obj = NULL; rdev->ring[RADEON_RING_TYPE_GFX_INDEX].ring_obj = NULL;
r600_ring_init(rdev, &rdev->ring[RADEON_RING_TYPE_GFX_INDEX], 1024 * 1024); r600_ring_init(rdev, &rdev->ring[RADEON_RING_TYPE_GFX_INDEX], 1024 * 1024);
rdev->ring[R600_RING_TYPE_DMA_INDEX].ring_obj = NULL;
r600_ring_init(rdev, &rdev->ring[R600_RING_TYPE_DMA_INDEX], 64 * 1024);
rdev->ih.ring_obj = NULL; rdev->ih.ring_obj = NULL;
r600_ih_ring_init(rdev, 64 * 1024); r600_ih_ring_init(rdev, 64 * 1024);

File diff suppressed because it is too large Load Diff

View File

@ -1660,6 +1660,8 @@ static void si_gpu_init(struct radeon_device *rdev)
WREG32(GB_ADDR_CONFIG, gb_addr_config); WREG32(GB_ADDR_CONFIG, gb_addr_config);
WREG32(DMIF_ADDR_CONFIG, gb_addr_config); WREG32(DMIF_ADDR_CONFIG, gb_addr_config);
WREG32(HDP_ADDR_CONFIG, gb_addr_config); WREG32(HDP_ADDR_CONFIG, gb_addr_config);
WREG32(DMA_TILING_CONFIG + DMA0_REGISTER_OFFSET, gb_addr_config);
WREG32(DMA_TILING_CONFIG + DMA1_REGISTER_OFFSET, gb_addr_config);
si_tiling_mode_table_init(rdev); si_tiling_mode_table_init(rdev);
@ -1833,9 +1835,12 @@ static void si_cp_enable(struct radeon_device *rdev, bool enable)
if (enable) if (enable)
WREG32(CP_ME_CNTL, 0); WREG32(CP_ME_CNTL, 0);
else { else {
// radeon_ttm_set_active_vram_size(rdev, rdev->mc.visible_vram_size); radeon_ttm_set_active_vram_size(rdev, rdev->mc.visible_vram_size);
WREG32(CP_ME_CNTL, (CP_ME_HALT | CP_PFP_HALT | CP_CE_HALT)); WREG32(CP_ME_CNTL, (CP_ME_HALT | CP_PFP_HALT | CP_CE_HALT));
WREG32(SCRATCH_UMSK, 0); WREG32(SCRATCH_UMSK, 0);
rdev->ring[RADEON_RING_TYPE_GFX_INDEX].ready = false;
rdev->ring[CAYMAN_RING_TYPE_CP1_INDEX].ready = false;
rdev->ring[CAYMAN_RING_TYPE_CP2_INDEX].ready = false;
} }
udelay(50); udelay(50);
} }
@ -2121,15 +2126,13 @@ bool si_gpu_is_lockup(struct radeon_device *rdev, struct radeon_ring *ring)
return radeon_ring_test_lockup(rdev, ring); return radeon_ring_test_lockup(rdev, ring);
} }
static int si_gpu_soft_reset(struct radeon_device *rdev) static void si_gpu_soft_reset_gfx(struct radeon_device *rdev)
{ {
struct evergreen_mc_save save;
u32 grbm_reset = 0; u32 grbm_reset = 0;
if (!(RREG32(GRBM_STATUS) & GUI_ACTIVE)) if (!(RREG32(GRBM_STATUS) & GUI_ACTIVE))
return 0; return;
dev_info(rdev->dev, "GPU softreset \n");
dev_info(rdev->dev, " GRBM_STATUS=0x%08X\n", dev_info(rdev->dev, " GRBM_STATUS=0x%08X\n",
RREG32(GRBM_STATUS)); RREG32(GRBM_STATUS));
dev_info(rdev->dev, " GRBM_STATUS2=0x%08X\n", dev_info(rdev->dev, " GRBM_STATUS2=0x%08X\n",
@ -2140,10 +2143,7 @@ static int si_gpu_soft_reset(struct radeon_device *rdev)
RREG32(GRBM_STATUS_SE1)); RREG32(GRBM_STATUS_SE1));
dev_info(rdev->dev, " SRBM_STATUS=0x%08X\n", dev_info(rdev->dev, " SRBM_STATUS=0x%08X\n",
RREG32(SRBM_STATUS)); RREG32(SRBM_STATUS));
evergreen_mc_stop(rdev, &save);
if (radeon_mc_wait_for_idle(rdev)) {
dev_warn(rdev->dev, "Wait for MC idle timedout !\n");
}
/* Disable CP parsing/prefetching */ /* Disable CP parsing/prefetching */
WREG32(CP_ME_CNTL, CP_ME_HALT | CP_PFP_HALT | CP_CE_HALT); WREG32(CP_ME_CNTL, CP_ME_HALT | CP_PFP_HALT | CP_CE_HALT);
@ -2168,8 +2168,7 @@ static int si_gpu_soft_reset(struct radeon_device *rdev)
udelay(50); udelay(50);
WREG32(GRBM_SOFT_RESET, 0); WREG32(GRBM_SOFT_RESET, 0);
(void)RREG32(GRBM_SOFT_RESET); (void)RREG32(GRBM_SOFT_RESET);
/* Wait a little for things to settle down */
udelay(50);
dev_info(rdev->dev, " GRBM_STATUS=0x%08X\n", dev_info(rdev->dev, " GRBM_STATUS=0x%08X\n",
RREG32(GRBM_STATUS)); RREG32(GRBM_STATUS));
dev_info(rdev->dev, " GRBM_STATUS2=0x%08X\n", dev_info(rdev->dev, " GRBM_STATUS2=0x%08X\n",
@ -2180,13 +2179,75 @@ static int si_gpu_soft_reset(struct radeon_device *rdev)
RREG32(GRBM_STATUS_SE1)); RREG32(GRBM_STATUS_SE1));
dev_info(rdev->dev, " SRBM_STATUS=0x%08X\n", dev_info(rdev->dev, " SRBM_STATUS=0x%08X\n",
RREG32(SRBM_STATUS)); RREG32(SRBM_STATUS));
}
static void si_gpu_soft_reset_dma(struct radeon_device *rdev)
{
u32 tmp;
if (RREG32(DMA_STATUS_REG) & DMA_IDLE)
return;
dev_info(rdev->dev, " DMA_STATUS_REG = 0x%08X\n",
RREG32(DMA_STATUS_REG));
/* dma0 */
tmp = RREG32(DMA_RB_CNTL + DMA0_REGISTER_OFFSET);
tmp &= ~DMA_RB_ENABLE;
WREG32(DMA_RB_CNTL + DMA0_REGISTER_OFFSET, tmp);
/* dma1 */
tmp = RREG32(DMA_RB_CNTL + DMA1_REGISTER_OFFSET);
tmp &= ~DMA_RB_ENABLE;
WREG32(DMA_RB_CNTL + DMA1_REGISTER_OFFSET, tmp);
/* Reset dma */
WREG32(SRBM_SOFT_RESET, SOFT_RESET_DMA | SOFT_RESET_DMA1);
RREG32(SRBM_SOFT_RESET);
udelay(50);
WREG32(SRBM_SOFT_RESET, 0);
dev_info(rdev->dev, " DMA_STATUS_REG = 0x%08X\n",
RREG32(DMA_STATUS_REG));
}
static int si_gpu_soft_reset(struct radeon_device *rdev, u32 reset_mask)
{
struct evergreen_mc_save save;
if (reset_mask == 0)
return 0;
dev_info(rdev->dev, "GPU softreset: 0x%08X\n", reset_mask);
dev_info(rdev->dev, " VM_CONTEXT1_PROTECTION_FAULT_ADDR 0x%08X\n",
RREG32(VM_CONTEXT1_PROTECTION_FAULT_ADDR));
dev_info(rdev->dev, " VM_CONTEXT1_PROTECTION_FAULT_STATUS 0x%08X\n",
RREG32(VM_CONTEXT1_PROTECTION_FAULT_STATUS));
evergreen_mc_stop(rdev, &save);
if (radeon_mc_wait_for_idle(rdev)) {
dev_warn(rdev->dev, "Wait for MC idle timedout !\n");
}
if (reset_mask & (RADEON_RESET_GFX | RADEON_RESET_COMPUTE))
si_gpu_soft_reset_gfx(rdev);
if (reset_mask & RADEON_RESET_DMA)
si_gpu_soft_reset_dma(rdev);
/* Wait a little for things to settle down */
udelay(50);
evergreen_mc_resume(rdev, &save); evergreen_mc_resume(rdev, &save);
return 0; return 0;
} }
int si_asic_reset(struct radeon_device *rdev) int si_asic_reset(struct radeon_device *rdev)
{ {
return si_gpu_soft_reset(rdev); return si_gpu_soft_reset(rdev, (RADEON_RESET_GFX |
RADEON_RESET_COMPUTE |
RADEON_RESET_DMA));
} }
/* MC */ /* MC */
@ -2426,9 +2487,20 @@ static int si_pcie_gart_enable(struct radeon_device *rdev)
/* enable context1-15 */ /* enable context1-15 */
WREG32(VM_CONTEXT1_PROTECTION_FAULT_DEFAULT_ADDR, WREG32(VM_CONTEXT1_PROTECTION_FAULT_DEFAULT_ADDR,
(u32)(rdev->dummy_page.addr >> 12)); (u32)(rdev->dummy_page.addr >> 12));
WREG32(VM_CONTEXT1_CNTL2, 0); WREG32(VM_CONTEXT1_CNTL2, 4);
WREG32(VM_CONTEXT1_CNTL, ENABLE_CONTEXT | PAGE_TABLE_DEPTH(1) | WREG32(VM_CONTEXT1_CNTL, ENABLE_CONTEXT | PAGE_TABLE_DEPTH(1) |
RANGE_PROTECTION_FAULT_ENABLE_DEFAULT); RANGE_PROTECTION_FAULT_ENABLE_INTERRUPT |
RANGE_PROTECTION_FAULT_ENABLE_DEFAULT |
DUMMY_PAGE_PROTECTION_FAULT_ENABLE_INTERRUPT |
DUMMY_PAGE_PROTECTION_FAULT_ENABLE_DEFAULT |
PDE0_PROTECTION_FAULT_ENABLE_INTERRUPT |
PDE0_PROTECTION_FAULT_ENABLE_DEFAULT |
VALID_PROTECTION_FAULT_ENABLE_INTERRUPT |
VALID_PROTECTION_FAULT_ENABLE_DEFAULT |
READ_PROTECTION_FAULT_ENABLE_INTERRUPT |
READ_PROTECTION_FAULT_ENABLE_DEFAULT |
WRITE_PROTECTION_FAULT_ENABLE_INTERRUPT |
WRITE_PROTECTION_FAULT_ENABLE_DEFAULT);
si_pcie_gart_tlb_flush(rdev); si_pcie_gart_tlb_flush(rdev);
DRM_INFO("PCIE GART of %uM enabled (table at 0x%016llX).\n", DRM_INFO("PCIE GART of %uM enabled (table at 0x%016llX).\n",
@ -2534,6 +2606,7 @@ static int si_vm_packet3_gfx_check(struct radeon_device *rdev,
u32 idx = pkt->idx + 1; u32 idx = pkt->idx + 1;
u32 idx_value = ib[idx]; u32 idx_value = ib[idx];
u32 start_reg, end_reg, reg, i; u32 start_reg, end_reg, reg, i;
u32 command, info;
switch (pkt->opcode) { switch (pkt->opcode) {
case PACKET3_NOP: case PACKET3_NOP:
@ -2633,6 +2706,52 @@ static int si_vm_packet3_gfx_check(struct radeon_device *rdev,
return -EINVAL; return -EINVAL;
} }
break; break;
case PACKET3_CP_DMA:
command = ib[idx + 4];
info = ib[idx + 1];
if (command & PACKET3_CP_DMA_CMD_SAS) {
/* src address space is register */
if (((info & 0x60000000) >> 29) == 0) {
start_reg = idx_value << 2;
if (command & PACKET3_CP_DMA_CMD_SAIC) {
reg = start_reg;
if (!si_vm_reg_valid(reg)) {
DRM_ERROR("CP DMA Bad SRC register\n");
return -EINVAL;
}
} else {
for (i = 0; i < (command & 0x1fffff); i++) {
reg = start_reg + (4 * i);
if (!si_vm_reg_valid(reg)) {
DRM_ERROR("CP DMA Bad SRC register\n");
return -EINVAL;
}
}
}
}
}
if (command & PACKET3_CP_DMA_CMD_DAS) {
/* dst address space is register */
if (((info & 0x00300000) >> 20) == 0) {
start_reg = ib[idx + 2];
if (command & PACKET3_CP_DMA_CMD_DAIC) {
reg = start_reg;
if (!si_vm_reg_valid(reg)) {
DRM_ERROR("CP DMA Bad DST register\n");
return -EINVAL;
}
} else {
for (i = 0; i < (command & 0x1fffff); i++) {
reg = start_reg + (4 * i);
if (!si_vm_reg_valid(reg)) {
DRM_ERROR("CP DMA Bad DST register\n");
return -EINVAL;
}
}
}
}
}
break;
default: default:
DRM_ERROR("Invalid GFX packet3: 0x%x\n", pkt->opcode); DRM_ERROR("Invalid GFX packet3: 0x%x\n", pkt->opcode);
return -EINVAL; return -EINVAL;
@ -2809,9 +2928,12 @@ void si_vm_set_page(struct radeon_device *rdev, uint64_t pe,
{ {
struct radeon_ring *ring = &rdev->ring[rdev->asic->vm.pt_ring_index]; struct radeon_ring *ring = &rdev->ring[rdev->asic->vm.pt_ring_index];
uint32_t r600_flags = cayman_vm_page_flags(rdev, flags); uint32_t r600_flags = cayman_vm_page_flags(rdev, flags);
uint64_t value;
unsigned ndw;
if (rdev->asic->vm.pt_ring_index == RADEON_RING_TYPE_GFX_INDEX) {
while (count) { while (count) {
unsigned ndw = 2 + count * 2; ndw = 2 + count * 2;
if (ndw > 0x3FFE) if (ndw > 0x3FFE)
ndw = 0x3FFE; ndw = 0x3FFE;
@ -2821,20 +2943,73 @@ void si_vm_set_page(struct radeon_device *rdev, uint64_t pe,
radeon_ring_write(ring, pe); radeon_ring_write(ring, pe);
radeon_ring_write(ring, upper_32_bits(pe)); radeon_ring_write(ring, upper_32_bits(pe));
for (; ndw > 2; ndw -= 2, --count, pe += 8) { for (; ndw > 2; ndw -= 2, --count, pe += 8) {
uint64_t value;
if (flags & RADEON_VM_PAGE_SYSTEM) { if (flags & RADEON_VM_PAGE_SYSTEM) {
value = radeon_vm_map_gart(rdev, addr); value = radeon_vm_map_gart(rdev, addr);
value &= 0xFFFFFFFFFFFFF000ULL; value &= 0xFFFFFFFFFFFFF000ULL;
} else if (flags & RADEON_VM_PAGE_VALID) } else if (flags & RADEON_VM_PAGE_VALID) {
value = addr; value = addr;
else } else {
value = 0; value = 0;
}
addr += incr; addr += incr;
value |= r600_flags; value |= r600_flags;
radeon_ring_write(ring, value); radeon_ring_write(ring, value);
radeon_ring_write(ring, upper_32_bits(value)); radeon_ring_write(ring, upper_32_bits(value));
} }
} }
} else {
/* DMA */
if (flags & RADEON_VM_PAGE_SYSTEM) {
while (count) {
ndw = count * 2;
if (ndw > 0xFFFFE)
ndw = 0xFFFFE;
/* for non-physically contiguous pages (system) */
radeon_ring_write(ring, DMA_PACKET(DMA_PACKET_WRITE, 0, 0, 0, ndw));
radeon_ring_write(ring, pe);
radeon_ring_write(ring, upper_32_bits(pe) & 0xff);
for (; ndw > 0; ndw -= 2, --count, pe += 8) {
if (flags & RADEON_VM_PAGE_SYSTEM) {
value = radeon_vm_map_gart(rdev, addr);
value &= 0xFFFFFFFFFFFFF000ULL;
} else if (flags & RADEON_VM_PAGE_VALID) {
value = addr;
} else {
value = 0;
}
addr += incr;
value |= r600_flags;
radeon_ring_write(ring, value);
radeon_ring_write(ring, upper_32_bits(value));
}
}
} else {
while (count) {
ndw = count * 2;
if (ndw > 0xFFFFE)
ndw = 0xFFFFE;
if (flags & RADEON_VM_PAGE_VALID)
value = addr;
else
value = 0;
/* for physically contiguous pages (vram) */
radeon_ring_write(ring, DMA_PTE_PDE_PACKET(ndw));
radeon_ring_write(ring, pe); /* dst addr */
radeon_ring_write(ring, upper_32_bits(pe) & 0xff);
radeon_ring_write(ring, r600_flags); /* mask */
radeon_ring_write(ring, 0);
radeon_ring_write(ring, value); /* value */
radeon_ring_write(ring, upper_32_bits(value));
radeon_ring_write(ring, incr); /* increment size */
radeon_ring_write(ring, 0);
pe += ndw * 4;
addr += (ndw / 2) * incr;
count -= ndw / 2;
}
}
}
} }
void si_vm_flush(struct radeon_device *rdev, int ridx, struct radeon_vm *vm) void si_vm_flush(struct radeon_device *rdev, int ridx, struct radeon_vm *vm)
@ -2880,6 +3055,32 @@ void si_vm_flush(struct radeon_device *rdev, int ridx, struct radeon_vm *vm)
radeon_ring_write(ring, 0x0); radeon_ring_write(ring, 0x0);
} }
void si_dma_vm_flush(struct radeon_device *rdev, int ridx, struct radeon_vm *vm)
{
struct radeon_ring *ring = &rdev->ring[ridx];
if (vm == NULL)
return;
radeon_ring_write(ring, DMA_PACKET(DMA_PACKET_SRBM_WRITE, 0, 0, 0, 0));
if (vm->id < 8) {
radeon_ring_write(ring, (0xf << 16) | ((VM_CONTEXT0_PAGE_TABLE_BASE_ADDR + (vm->id << 2)) >> 2));
} else {
radeon_ring_write(ring, (0xf << 16) | ((VM_CONTEXT8_PAGE_TABLE_BASE_ADDR + ((vm->id - 8) << 2)) >> 2));
}
radeon_ring_write(ring, vm->pd_gpu_addr >> 12);
/* flush hdp cache */
radeon_ring_write(ring, DMA_PACKET(DMA_PACKET_SRBM_WRITE, 0, 0, 0, 0));
radeon_ring_write(ring, (0xf << 16) | (HDP_MEM_COHERENCY_FLUSH_CNTL >> 2));
radeon_ring_write(ring, 1);
/* bits 0-7 are the VM contexts0-7 */
radeon_ring_write(ring, DMA_PACKET(DMA_PACKET_SRBM_WRITE, 0, 0, 0, 0));
radeon_ring_write(ring, (0xf << 16) | (VM_INVALIDATE_REQUEST >> 2));
radeon_ring_write(ring, 1 << vm->id);
}
/* /*
* RLC * RLC
*/ */
@ -3048,6 +3249,10 @@ static void si_disable_interrupt_state(struct radeon_device *rdev)
WREG32(CP_INT_CNTL_RING0, CNTX_BUSY_INT_ENABLE | CNTX_EMPTY_INT_ENABLE); WREG32(CP_INT_CNTL_RING0, CNTX_BUSY_INT_ENABLE | CNTX_EMPTY_INT_ENABLE);
WREG32(CP_INT_CNTL_RING1, 0); WREG32(CP_INT_CNTL_RING1, 0);
WREG32(CP_INT_CNTL_RING2, 0); WREG32(CP_INT_CNTL_RING2, 0);
tmp = RREG32(DMA_CNTL + DMA0_REGISTER_OFFSET) & ~TRAP_ENABLE;
WREG32(DMA_CNTL + DMA0_REGISTER_OFFSET, tmp);
tmp = RREG32(DMA_CNTL + DMA1_REGISTER_OFFSET) & ~TRAP_ENABLE;
WREG32(DMA_CNTL + DMA1_REGISTER_OFFSET, tmp);
WREG32(GRBM_INT_CNTL, 0); WREG32(GRBM_INT_CNTL, 0);
WREG32(INT_MASK + EVERGREEN_CRTC0_REGISTER_OFFSET, 0); WREG32(INT_MASK + EVERGREEN_CRTC0_REGISTER_OFFSET, 0);
WREG32(INT_MASK + EVERGREEN_CRTC1_REGISTER_OFFSET, 0); WREG32(INT_MASK + EVERGREEN_CRTC1_REGISTER_OFFSET, 0);
@ -3167,6 +3372,7 @@ int si_irq_set(struct radeon_device *rdev)
u32 hpd1, hpd2, hpd3, hpd4, hpd5, hpd6; u32 hpd1, hpd2, hpd3, hpd4, hpd5, hpd6;
u32 grbm_int_cntl = 0; u32 grbm_int_cntl = 0;
u32 grph1 = 0, grph2 = 0, grph3 = 0, grph4 = 0, grph5 = 0, grph6 = 0; u32 grph1 = 0, grph2 = 0, grph3 = 0, grph4 = 0, grph5 = 0, grph6 = 0;
u32 dma_cntl, dma_cntl1;
if (!rdev->irq.installed) { if (!rdev->irq.installed) {
WARN(1, "Can't enable IRQ/MSI because no handler is installed\n"); WARN(1, "Can't enable IRQ/MSI because no handler is installed\n");
@ -3187,6 +3393,9 @@ int si_irq_set(struct radeon_device *rdev)
hpd5 = RREG32(DC_HPD5_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; hpd6 = RREG32(DC_HPD6_INT_CONTROL) & ~DC_HPDx_INT_EN;
dma_cntl = RREG32(DMA_CNTL + DMA0_REGISTER_OFFSET) & ~TRAP_ENABLE;
dma_cntl1 = RREG32(DMA_CNTL + DMA1_REGISTER_OFFSET) & ~TRAP_ENABLE;
/* enable CP interrupts on all rings */ /* enable CP interrupts on all rings */
if (atomic_read(&rdev->irq.ring_int[RADEON_RING_TYPE_GFX_INDEX])) { if (atomic_read(&rdev->irq.ring_int[RADEON_RING_TYPE_GFX_INDEX])) {
DRM_DEBUG("si_irq_set: sw int gfx\n"); DRM_DEBUG("si_irq_set: sw int gfx\n");
@ -3200,6 +3409,15 @@ int si_irq_set(struct radeon_device *rdev)
DRM_DEBUG("si_irq_set: sw int cp2\n"); DRM_DEBUG("si_irq_set: sw int cp2\n");
cp_int_cntl2 |= TIME_STAMP_INT_ENABLE; cp_int_cntl2 |= TIME_STAMP_INT_ENABLE;
} }
if (atomic_read(&rdev->irq.ring_int[R600_RING_TYPE_DMA_INDEX])) {
DRM_DEBUG("si_irq_set: sw int dma\n");
dma_cntl |= TRAP_ENABLE;
}
if (atomic_read(&rdev->irq.ring_int[CAYMAN_RING_TYPE_DMA1_INDEX])) {
DRM_DEBUG("si_irq_set: sw int dma1\n");
dma_cntl1 |= TRAP_ENABLE;
}
if (rdev->irq.crtc_vblank_int[0] || if (rdev->irq.crtc_vblank_int[0] ||
atomic_read(&rdev->irq.pflip[0])) { atomic_read(&rdev->irq.pflip[0])) {
DRM_DEBUG("si_irq_set: vblank 0\n"); DRM_DEBUG("si_irq_set: vblank 0\n");
@ -3259,6 +3477,9 @@ int si_irq_set(struct radeon_device *rdev)
WREG32(CP_INT_CNTL_RING1, cp_int_cntl1); WREG32(CP_INT_CNTL_RING1, cp_int_cntl1);
WREG32(CP_INT_CNTL_RING2, cp_int_cntl2); WREG32(CP_INT_CNTL_RING2, cp_int_cntl2);
WREG32(DMA_CNTL + DMA0_REGISTER_OFFSET, dma_cntl);
WREG32(DMA_CNTL + DMA1_REGISTER_OFFSET, dma_cntl1);
WREG32(GRBM_INT_CNTL, grbm_int_cntl); WREG32(GRBM_INT_CNTL, grbm_int_cntl);
WREG32(INT_MASK + EVERGREEN_CRTC0_REGISTER_OFFSET, crtc1); WREG32(INT_MASK + EVERGREEN_CRTC0_REGISTER_OFFSET, crtc1);
@ -3684,6 +3905,16 @@ restart_ih:
break; break;
} }
break; break;
case 146:
case 147:
dev_err(rdev->dev, "GPU fault detected: %d 0x%08x\n", src_id, src_data);
dev_err(rdev->dev, " VM_CONTEXT1_PROTECTION_FAULT_ADDR 0x%08X\n",
RREG32(VM_CONTEXT1_PROTECTION_FAULT_ADDR));
dev_err(rdev->dev, " VM_CONTEXT1_PROTECTION_FAULT_STATUS 0x%08X\n",
RREG32(VM_CONTEXT1_PROTECTION_FAULT_STATUS));
/* reset addr and status */
WREG32_P(VM_CONTEXT1_CNTL2, 1, ~1);
break;
case 176: /* RINGID0 CP_INT */ case 176: /* RINGID0 CP_INT */
radeon_fence_process(rdev, RADEON_RING_TYPE_GFX_INDEX); radeon_fence_process(rdev, RADEON_RING_TYPE_GFX_INDEX);
break; break;
@ -3707,9 +3938,17 @@ restart_ih:
break; break;
} }
break; break;
case 224: /* DMA trap event */
DRM_DEBUG("IH: DMA trap\n");
radeon_fence_process(rdev, R600_RING_TYPE_DMA_INDEX);
break;
case 233: /* GUI IDLE */ case 233: /* GUI IDLE */
DRM_DEBUG("IH: GUI idle\n"); DRM_DEBUG("IH: GUI idle\n");
break; break;
case 244: /* DMA trap event */
DRM_DEBUG("IH: DMA1 trap\n");
radeon_fence_process(rdev, CAYMAN_RING_TYPE_DMA1_INDEX);
break;
default: default:
DRM_DEBUG("Unhandled interrupt: %d %d\n", src_id, src_data); DRM_DEBUG("Unhandled interrupt: %d %d\n", src_id, src_data);
break; break;
@ -3733,6 +3972,80 @@ restart_ih:
return IRQ_HANDLED; return IRQ_HANDLED;
} }
/**
* si_copy_dma - copy pages using the DMA engine
*
* @rdev: radeon_device pointer
* @src_offset: src GPU address
* @dst_offset: dst GPU address
* @num_gpu_pages: number of GPU pages to xfer
* @fence: radeon fence object
*
* Copy GPU paging using the DMA engine (SI).
* Used by the radeon ttm implementation to move pages if
* registered as the asic copy callback.
*/
int si_copy_dma(struct radeon_device *rdev,
uint64_t src_offset, uint64_t dst_offset,
unsigned num_gpu_pages,
struct radeon_fence **fence)
{
struct radeon_semaphore *sem = NULL;
int ring_index = rdev->asic->copy.dma_ring_index;
struct radeon_ring *ring = &rdev->ring[ring_index];
u32 size_in_bytes, cur_size_in_bytes;
int i, num_loops;
int r = 0;
r = radeon_semaphore_create(rdev, &sem);
if (r) {
DRM_ERROR("radeon: moving bo (%d).\n", r);
return r;
}
size_in_bytes = (num_gpu_pages << RADEON_GPU_PAGE_SHIFT);
num_loops = DIV_ROUND_UP(size_in_bytes, 0xfffff);
r = radeon_ring_lock(rdev, ring, num_loops * 5 + 11);
if (r) {
DRM_ERROR("radeon: moving bo (%d).\n", r);
radeon_semaphore_free(rdev, &sem, NULL);
return r;
}
if (radeon_fence_need_sync(*fence, ring->idx)) {
radeon_semaphore_sync_rings(rdev, sem, (*fence)->ring,
ring->idx);
radeon_fence_note_sync(*fence, ring->idx);
} else {
radeon_semaphore_free(rdev, &sem, NULL);
}
for (i = 0; i < num_loops; i++) {
cur_size_in_bytes = size_in_bytes;
if (cur_size_in_bytes > 0xFFFFF)
cur_size_in_bytes = 0xFFFFF;
size_in_bytes -= cur_size_in_bytes;
radeon_ring_write(ring, DMA_PACKET(DMA_PACKET_COPY, 1, 0, 0, cur_size_in_bytes));
radeon_ring_write(ring, dst_offset & 0xffffffff);
radeon_ring_write(ring, src_offset & 0xffffffff);
radeon_ring_write(ring, upper_32_bits(dst_offset) & 0xff);
radeon_ring_write(ring, upper_32_bits(src_offset) & 0xff);
src_offset += cur_size_in_bytes;
dst_offset += cur_size_in_bytes;
}
r = radeon_fence_emit(rdev, fence, ring->idx);
if (r) {
radeon_ring_unlock_undo(rdev, ring);
return r;
}
radeon_ring_unlock_commit(rdev, ring);
radeon_semaphore_free(rdev, &sem, *fence);
return r;
}
/* /*
* startup/shutdown callbacks * startup/shutdown callbacks
*/ */
@ -3804,6 +4117,18 @@ static int si_startup(struct radeon_device *rdev)
return r; return r;
} }
r = radeon_fence_driver_start_ring(rdev, R600_RING_TYPE_DMA_INDEX);
if (r) {
dev_err(rdev->dev, "failed initializing DMA fences (%d).\n", r);
return r;
}
r = radeon_fence_driver_start_ring(rdev, CAYMAN_RING_TYPE_DMA1_INDEX);
if (r) {
dev_err(rdev->dev, "failed initializing DMA fences (%d).\n", r);
return r;
}
/* Enable IRQ */ /* Enable IRQ */
r = si_irq_init(rdev); r = si_irq_init(rdev);
if (r) { if (r) {
@ -3834,6 +4159,22 @@ static int si_startup(struct radeon_device *rdev)
if (r) if (r)
return r; return r;
ring = &rdev->ring[R600_RING_TYPE_DMA_INDEX];
r = radeon_ring_init(rdev, ring, ring->ring_size, R600_WB_DMA_RPTR_OFFSET,
DMA_RB_RPTR + DMA0_REGISTER_OFFSET,
DMA_RB_WPTR + DMA0_REGISTER_OFFSET,
2, 0x3fffc, DMA_PACKET(DMA_PACKET_NOP, 0, 0, 0, 0));
if (r)
return r;
ring = &rdev->ring[CAYMAN_RING_TYPE_DMA1_INDEX];
r = radeon_ring_init(rdev, ring, ring->ring_size, CAYMAN_WB_DMA1_RPTR_OFFSET,
DMA_RB_RPTR + DMA1_REGISTER_OFFSET,
DMA_RB_WPTR + DMA1_REGISTER_OFFSET,
2, 0x3fffc, DMA_PACKET(DMA_PACKET_NOP, 0, 0, 0, 0));
if (r)
return r;
r = si_cp_load_microcode(rdev); r = si_cp_load_microcode(rdev);
if (r) if (r)
return r; return r;
@ -3841,6 +4182,10 @@ static int si_startup(struct radeon_device *rdev)
if (r) if (r)
return r; return r;
r = cayman_dma_resume(rdev);
if (r)
return r;
r = radeon_ib_pool_init(rdev); r = radeon_ib_pool_init(rdev);
if (r) { if (r) {
dev_err(rdev->dev, "IB initialization failed (%d).\n", r); dev_err(rdev->dev, "IB initialization failed (%d).\n", r);
@ -3932,6 +4277,14 @@ int si_init(struct radeon_device *rdev)
ring->ring_obj = NULL; ring->ring_obj = NULL;
r600_ring_init(rdev, ring, 1024 * 1024); r600_ring_init(rdev, ring, 1024 * 1024);
ring = &rdev->ring[R600_RING_TYPE_DMA_INDEX];
ring->ring_obj = NULL;
r600_ring_init(rdev, ring, 64 * 1024);
ring = &rdev->ring[CAYMAN_RING_TYPE_DMA1_INDEX];
ring->ring_obj = NULL;
r600_ring_init(rdev, ring, 64 * 1024);
rdev->ih.ring_obj = NULL; rdev->ih.ring_obj = NULL;
r600_ih_ring_init(rdev, 64 * 1024); r600_ih_ring_init(rdev, 64 * 1024);

View File

@ -62,6 +62,22 @@
#define SRBM_STATUS 0xE50 #define SRBM_STATUS 0xE50
#define SRBM_SOFT_RESET 0x0E60
#define SOFT_RESET_BIF (1 << 1)
#define SOFT_RESET_DC (1 << 5)
#define SOFT_RESET_DMA1 (1 << 6)
#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_ROM (1 << 14)
#define SOFT_RESET_SEM (1 << 15)
#define SOFT_RESET_VMC (1 << 17)
#define SOFT_RESET_DMA (1 << 20)
#define SOFT_RESET_TST (1 << 21)
#define SOFT_RESET_REGBB (1 << 22)
#define SOFT_RESET_ORB (1 << 23)
#define CC_SYS_RB_BACKEND_DISABLE 0xe80 #define CC_SYS_RB_BACKEND_DISABLE 0xe80
#define GC_USER_SYS_RB_BACKEND_DISABLE 0xe84 #define GC_USER_SYS_RB_BACKEND_DISABLE 0xe84
@ -91,7 +107,18 @@
#define VM_CONTEXT0_CNTL 0x1410 #define VM_CONTEXT0_CNTL 0x1410
#define ENABLE_CONTEXT (1 << 0) #define ENABLE_CONTEXT (1 << 0)
#define PAGE_TABLE_DEPTH(x) (((x) & 3) << 1) #define PAGE_TABLE_DEPTH(x) (((x) & 3) << 1)
#define RANGE_PROTECTION_FAULT_ENABLE_INTERRUPT (1 << 3)
#define RANGE_PROTECTION_FAULT_ENABLE_DEFAULT (1 << 4) #define RANGE_PROTECTION_FAULT_ENABLE_DEFAULT (1 << 4)
#define DUMMY_PAGE_PROTECTION_FAULT_ENABLE_INTERRUPT (1 << 6)
#define DUMMY_PAGE_PROTECTION_FAULT_ENABLE_DEFAULT (1 << 7)
#define PDE0_PROTECTION_FAULT_ENABLE_INTERRUPT (1 << 9)
#define PDE0_PROTECTION_FAULT_ENABLE_DEFAULT (1 << 10)
#define VALID_PROTECTION_FAULT_ENABLE_INTERRUPT (1 << 12)
#define VALID_PROTECTION_FAULT_ENABLE_DEFAULT (1 << 13)
#define READ_PROTECTION_FAULT_ENABLE_INTERRUPT (1 << 15)
#define READ_PROTECTION_FAULT_ENABLE_DEFAULT (1 << 16)
#define WRITE_PROTECTION_FAULT_ENABLE_INTERRUPT (1 << 18)
#define WRITE_PROTECTION_FAULT_ENABLE_DEFAULT (1 << 19)
#define VM_CONTEXT1_CNTL 0x1414 #define VM_CONTEXT1_CNTL 0x1414
#define VM_CONTEXT0_CNTL2 0x1430 #define VM_CONTEXT0_CNTL2 0x1430
#define VM_CONTEXT1_CNTL2 0x1434 #define VM_CONTEXT1_CNTL2 0x1434
@ -104,6 +131,9 @@
#define VM_CONTEXT14_PAGE_TABLE_BASE_ADDR 0x1450 #define VM_CONTEXT14_PAGE_TABLE_BASE_ADDR 0x1450
#define VM_CONTEXT15_PAGE_TABLE_BASE_ADDR 0x1454 #define VM_CONTEXT15_PAGE_TABLE_BASE_ADDR 0x1454
#define VM_CONTEXT1_PROTECTION_FAULT_ADDR 0x14FC
#define VM_CONTEXT1_PROTECTION_FAULT_STATUS 0x14DC
#define VM_INVALIDATE_REQUEST 0x1478 #define VM_INVALIDATE_REQUEST 0x1478
#define VM_INVALIDATE_RESPONSE 0x147c #define VM_INVALIDATE_RESPONSE 0x147c
@ -835,6 +865,54 @@
#define PACKET3_WAIT_REG_MEM 0x3C #define PACKET3_WAIT_REG_MEM 0x3C
#define PACKET3_MEM_WRITE 0x3D #define PACKET3_MEM_WRITE 0x3D
#define PACKET3_COPY_DATA 0x40 #define PACKET3_COPY_DATA 0x40
#define PACKET3_CP_DMA 0x41
/* 1. header
* 2. SRC_ADDR_LO or DATA [31:0]
* 3. CP_SYNC [31] | SRC_SEL [30:29] | ENGINE [27] | DST_SEL [21:20] |
* SRC_ADDR_HI [7:0]
* 4. DST_ADDR_LO [31:0]
* 5. DST_ADDR_HI [7:0]
* 6. COMMAND [30:21] | BYTE_COUNT [20:0]
*/
# define PACKET3_CP_DMA_DST_SEL(x) ((x) << 20)
/* 0 - SRC_ADDR
* 1 - GDS
*/
# define PACKET3_CP_DMA_ENGINE(x) ((x) << 27)
/* 0 - ME
* 1 - PFP
*/
# define PACKET3_CP_DMA_SRC_SEL(x) ((x) << 29)
/* 0 - SRC_ADDR
* 1 - GDS
* 2 - DATA
*/
# define PACKET3_CP_DMA_CP_SYNC (1 << 31)
/* COMMAND */
# define PACKET3_CP_DMA_DIS_WC (1 << 21)
# define PACKET3_CP_DMA_CMD_SRC_SWAP(x) ((x) << 23)
/* 0 - none
* 1 - 8 in 16
* 2 - 8 in 32
* 3 - 8 in 64
*/
# define PACKET3_CP_DMA_CMD_DST_SWAP(x) ((x) << 24)
/* 0 - none
* 1 - 8 in 16
* 2 - 8 in 32
* 3 - 8 in 64
*/
# define PACKET3_CP_DMA_CMD_SAS (1 << 26)
/* 0 - memory
* 1 - register
*/
# define PACKET3_CP_DMA_CMD_DAS (1 << 27)
/* 0 - memory
* 1 - register
*/
# define PACKET3_CP_DMA_CMD_SAIC (1 << 28)
# define PACKET3_CP_DMA_CMD_DAIC (1 << 29)
# define PACKET3_CP_DMA_CMD_RAW_WAIT (1 << 30)
#define PACKET3_PFP_SYNC_ME 0x42 #define PACKET3_PFP_SYNC_ME 0x42
#define PACKET3_SURFACE_SYNC 0x43 #define PACKET3_SURFACE_SYNC 0x43
# define PACKET3_DEST_BASE_0_ENA (1 << 0) # define PACKET3_DEST_BASE_0_ENA (1 << 0)
@ -922,4 +1000,63 @@
#define PACKET3_WAIT_ON_AVAIL_BUFFER 0x8A #define PACKET3_WAIT_ON_AVAIL_BUFFER 0x8A
#define PACKET3_SWITCH_BUFFER 0x8B #define PACKET3_SWITCH_BUFFER 0x8B
/* ASYNC DMA - first instance at 0xd000, second at 0xd800 */
#define DMA0_REGISTER_OFFSET 0x0 /* not a register */
#define DMA1_REGISTER_OFFSET 0x800 /* not a register */
#define DMA_RB_CNTL 0xd000
# define DMA_RB_ENABLE (1 << 0)
# define DMA_RB_SIZE(x) ((x) << 1) /* log2 */
# define DMA_RB_SWAP_ENABLE (1 << 9) /* 8IN32 */
# define DMA_RPTR_WRITEBACK_ENABLE (1 << 12)
# define DMA_RPTR_WRITEBACK_SWAP_ENABLE (1 << 13) /* 8IN32 */
# define DMA_RPTR_WRITEBACK_TIMER(x) ((x) << 16) /* log2 */
#define DMA_RB_BASE 0xd004
#define DMA_RB_RPTR 0xd008
#define DMA_RB_WPTR 0xd00c
#define DMA_RB_RPTR_ADDR_HI 0xd01c
#define DMA_RB_RPTR_ADDR_LO 0xd020
#define DMA_IB_CNTL 0xd024
# define DMA_IB_ENABLE (1 << 0)
# define DMA_IB_SWAP_ENABLE (1 << 4)
#define DMA_IB_RPTR 0xd028
#define DMA_CNTL 0xd02c
# define TRAP_ENABLE (1 << 0)
# define SEM_INCOMPLETE_INT_ENABLE (1 << 1)
# define SEM_WAIT_INT_ENABLE (1 << 2)
# define DATA_SWAP_ENABLE (1 << 3)
# define FENCE_SWAP_ENABLE (1 << 4)
# define CTXEMPTY_INT_ENABLE (1 << 28)
#define DMA_STATUS_REG 0xd034
# define DMA_IDLE (1 << 0)
#define DMA_TILING_CONFIG 0xd0b8
#define DMA_PACKET(cmd, b, t, s, n) ((((cmd) & 0xF) << 28) | \
(((b) & 0x1) << 26) | \
(((t) & 0x1) << 23) | \
(((s) & 0x1) << 22) | \
(((n) & 0xFFFFF) << 0))
#define DMA_IB_PACKET(cmd, vmid, n) ((((cmd) & 0xF) << 28) | \
(((vmid) & 0xF) << 20) | \
(((n) & 0xFFFFF) << 0))
#define DMA_PTE_PDE_PACKET(n) ((2 << 28) | \
(1 << 26) | \
(1 << 21) | \
(((n) & 0xFFFFF) << 0))
/* async DMA Packet types */
#define DMA_PACKET_WRITE 0x2
#define DMA_PACKET_COPY 0x3
#define DMA_PACKET_INDIRECT_BUFFER 0x4
#define DMA_PACKET_SEMAPHORE 0x5
#define DMA_PACKET_FENCE 0x6
#define DMA_PACKET_TRAP 0x7
#define DMA_PACKET_SRBM_WRITE 0x9
#define DMA_PACKET_CONSTANT_FILL 0xd
#define DMA_PACKET_NOP 0xf
#endif #endif