Merge remote branch 'origin/modesetting-101' into modesetting-gem
commit
fb05c4d621
|
@ -60,6 +60,26 @@ char *drm_get_dpms_name(int val)
|
||||||
return "unknown";
|
return "unknown";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Optional properties
|
||||||
|
*/
|
||||||
|
static struct drm_prop_enum_list drm_scaling_mode_enum_list[] =
|
||||||
|
{
|
||||||
|
{ DRM_MODE_SCALE_NON_GPU, "Non-GPU" },
|
||||||
|
{ DRM_MODE_SCALE_FULLSCREEN, "Fullscreen" },
|
||||||
|
{ DRM_MODE_SCALE_NO_SCALE, "No scale" },
|
||||||
|
{ DRM_MODE_SCALE_ASPECT, "Aspect" },
|
||||||
|
};
|
||||||
|
|
||||||
|
static struct drm_prop_enum_list drm_dithering_mode_enum_list[] =
|
||||||
|
{
|
||||||
|
{ DRM_MODE_DITHERING_OFF, "Off" },
|
||||||
|
{ DRM_MODE_DITHERING_ON, "On" },
|
||||||
|
};
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Non-global properties, but "required" for certain connectors.
|
||||||
|
*/
|
||||||
static struct drm_prop_enum_list drm_select_subconnector_enum_list[] =
|
static struct drm_prop_enum_list drm_select_subconnector_enum_list[] =
|
||||||
{
|
{
|
||||||
{ DRM_MODE_SUBCONNECTOR_Automatic, "Automatic" }, /* DVI-I and TV-out */
|
{ DRM_MODE_SUBCONNECTOR_Automatic, "Automatic" }, /* DVI-I and TV-out */
|
||||||
|
@ -102,6 +122,9 @@ char *drm_get_subconnector_name(int val)
|
||||||
return "unknown";
|
return "unknown";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Connector and encoder types.
|
||||||
|
*/
|
||||||
static struct drm_prop_enum_list drm_connector_enum_list[] =
|
static struct drm_prop_enum_list drm_connector_enum_list[] =
|
||||||
{ { DRM_MODE_CONNECTOR_Unknown, "Unknown" },
|
{ { DRM_MODE_CONNECTOR_Unknown, "Unknown" },
|
||||||
{ DRM_MODE_CONNECTOR_VGA, "VGA" },
|
{ DRM_MODE_CONNECTOR_VGA, "VGA" },
|
||||||
|
@ -646,6 +669,52 @@ int drm_mode_create_tv_properties(struct drm_device *dev, int num_modes,
|
||||||
}
|
}
|
||||||
EXPORT_SYMBOL(drm_mode_create_tv_properties);
|
EXPORT_SYMBOL(drm_mode_create_tv_properties);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* drm_mode_create_scaling_mode_property - create scaling mode property
|
||||||
|
* @dev: DRM device
|
||||||
|
*
|
||||||
|
* Called by a driver the first time it's needed, must be attached to desired connectors.
|
||||||
|
*/
|
||||||
|
int drm_mode_create_scaling_mode_property(struct drm_device *dev)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
|
||||||
|
if (dev->mode_config.scaling_mode_property) /* already done */
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
dev->mode_config.scaling_mode_property =
|
||||||
|
drm_property_create(dev, DRM_MODE_PROP_ENUM,
|
||||||
|
"scaling mode", ARRAY_SIZE(drm_scaling_mode_enum_list));
|
||||||
|
for (i = 0; i < ARRAY_SIZE(drm_scaling_mode_enum_list); i++)
|
||||||
|
drm_property_add_enum(dev->mode_config.scaling_mode_property, i, drm_scaling_mode_enum_list[i].type, drm_scaling_mode_enum_list[i].name);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
EXPORT_SYMBOL(drm_mode_create_scaling_mode_property);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* drm_mode_create_dithering_property - create dithering property
|
||||||
|
* @dev: DRM device
|
||||||
|
*
|
||||||
|
* Called by a driver the first time it's needed, must be attached to desired connectors.
|
||||||
|
*/
|
||||||
|
int drm_mode_create_dithering_property(struct drm_device *dev)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
|
||||||
|
if (dev->mode_config.dithering_mode_property) /* already done */
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
dev->mode_config.dithering_mode_property =
|
||||||
|
drm_property_create(dev, DRM_MODE_PROP_ENUM,
|
||||||
|
"dithering", ARRAY_SIZE(drm_dithering_mode_enum_list));
|
||||||
|
for (i = 0; i < ARRAY_SIZE(drm_dithering_mode_enum_list); i++)
|
||||||
|
drm_property_add_enum(dev->mode_config.dithering_mode_property, i, drm_dithering_mode_enum_list[i].type, drm_dithering_mode_enum_list[i].name);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
EXPORT_SYMBOL(drm_mode_create_dithering_property);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* drm_mode_config_init - initialize DRM mode_configuration structure
|
* drm_mode_config_init - initialize DRM mode_configuration structure
|
||||||
* @dev: DRM device
|
* @dev: DRM device
|
||||||
|
@ -2115,12 +2184,12 @@ int drm_mode_connector_property_set_ioctl(struct drm_device *dev,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* store the property value */
|
|
||||||
drm_connector_property_set_value(connector, property, out_resp->value);
|
|
||||||
|
|
||||||
if (connector->funcs->set_property)
|
if (connector->funcs->set_property)
|
||||||
ret = connector->funcs->set_property(connector, property, out_resp->value);
|
ret = connector->funcs->set_property(connector, property, out_resp->value);
|
||||||
|
|
||||||
|
/* store the property value if succesful */
|
||||||
|
if (!ret)
|
||||||
|
drm_connector_property_set_value(connector, property, out_resp->value);
|
||||||
out:
|
out:
|
||||||
mutex_unlock(&dev->mode_config.mutex);
|
mutex_unlock(&dev->mode_config.mutex);
|
||||||
return ret;
|
return ret;
|
||||||
|
|
|
@ -375,7 +375,7 @@ struct drm_connector_funcs {
|
||||||
void (*restore)(struct drm_connector *connector);
|
void (*restore)(struct drm_connector *connector);
|
||||||
enum drm_connector_status (*detect)(struct drm_connector *connector);
|
enum drm_connector_status (*detect)(struct drm_connector *connector);
|
||||||
void (*fill_modes)(struct drm_connector *connector, uint32_t max_width, uint32_t max_height);
|
void (*fill_modes)(struct drm_connector *connector, uint32_t max_width, uint32_t max_height);
|
||||||
bool (*set_property)(struct drm_connector *connector, struct drm_property *property,
|
int (*set_property)(struct drm_connector *connector, struct drm_property *property,
|
||||||
uint64_t val);
|
uint64_t val);
|
||||||
void (*destroy)(struct drm_connector *connector);
|
void (*destroy)(struct drm_connector *connector);
|
||||||
};
|
};
|
||||||
|
@ -536,7 +536,7 @@ struct drm_mode_config {
|
||||||
struct drm_property *edid_property;
|
struct drm_property *edid_property;
|
||||||
struct drm_property *dpms_property;
|
struct drm_property *dpms_property;
|
||||||
|
|
||||||
/* optional properties */
|
/* DVI-I properties */
|
||||||
struct drm_property *dvi_i_subconnector_property;
|
struct drm_property *dvi_i_subconnector_property;
|
||||||
struct drm_property *dvi_i_select_subconnector_property;
|
struct drm_property *dvi_i_select_subconnector_property;
|
||||||
|
|
||||||
|
@ -549,6 +549,10 @@ struct drm_mode_config {
|
||||||
struct drm_property *tv_top_margin_property;
|
struct drm_property *tv_top_margin_property;
|
||||||
struct drm_property *tv_bottom_margin_property;
|
struct drm_property *tv_bottom_margin_property;
|
||||||
|
|
||||||
|
/* Optional properties */
|
||||||
|
struct drm_property *scaling_mode_property;
|
||||||
|
struct drm_property *dithering_mode_property;
|
||||||
|
|
||||||
/* hotplug */
|
/* hotplug */
|
||||||
uint32_t hotplug_counter;
|
uint32_t hotplug_counter;
|
||||||
};
|
};
|
||||||
|
@ -650,6 +654,8 @@ extern int drm_property_add_enum(struct drm_property *property, int index,
|
||||||
extern int drm_mode_create_dvi_i_properties(struct drm_device *dev);
|
extern int drm_mode_create_dvi_i_properties(struct drm_device *dev);
|
||||||
extern int drm_mode_create_tv_properties(struct drm_device *dev, int num_formats,
|
extern int drm_mode_create_tv_properties(struct drm_device *dev, int num_formats,
|
||||||
char *formats[]);
|
char *formats[]);
|
||||||
|
extern int drm_mode_create_scaling_mode_property(struct drm_device *dev);
|
||||||
|
extern int drm_mode_create_dithering_property(struct drm_device *dev);
|
||||||
extern char *drm_get_encoder_name(struct drm_encoder *encoder);
|
extern char *drm_get_encoder_name(struct drm_encoder *encoder);
|
||||||
|
|
||||||
extern int drm_mode_connector_attach_encoder(struct drm_connector *connector,
|
extern int drm_mode_connector_attach_encoder(struct drm_connector *connector,
|
||||||
|
|
|
@ -566,7 +566,8 @@ int drm_crtc_helper_set_config(struct drm_mode_set *set)
|
||||||
ret = -EINVAL;
|
ret = -EINVAL;
|
||||||
goto fail_no_encoder;
|
goto fail_no_encoder;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
count = 0;
|
||||||
list_for_each_entry(connector, &dev->mode_config.connector_list, head) {
|
list_for_each_entry(connector, &dev->mode_config.connector_list, head) {
|
||||||
if (!connector->encoder)
|
if (!connector->encoder)
|
||||||
continue;
|
continue;
|
||||||
|
|
|
@ -246,7 +246,10 @@ int drm_lastclose(struct drm_device * dev)
|
||||||
dev->agp->acquired = 0;
|
dev->agp->acquired = 0;
|
||||||
dev->agp->enabled = 0;
|
dev->agp->enabled = 0;
|
||||||
}
|
}
|
||||||
if (drm_core_check_feature(dev, DRIVER_SG) && dev->sg) {
|
|
||||||
|
/* You're supposed to have a real memory manager for modesetting, but this'll suffice as a temporary workaround. */
|
||||||
|
/* This assumes sgdma is inited at load time. */
|
||||||
|
if (drm_core_check_feature(dev, DRIVER_SG) && !drm_core_check_feature(dev, DRIVER_MODESET) && dev->sg) {
|
||||||
drm_sg_cleanup(dev->sg);
|
drm_sg_cleanup(dev->sg);
|
||||||
dev->sg = NULL;
|
dev->sg = NULL;
|
||||||
}
|
}
|
||||||
|
|
|
@ -398,7 +398,7 @@ void drm_mode_prune_invalid(struct drm_device *dev,
|
||||||
drm_mode_debug_printmodeline(mode);
|
drm_mode_debug_printmodeline(mode);
|
||||||
DRM_DEBUG("Not using %s mode %d\n", mode->name, mode->status);
|
DRM_DEBUG("Not using %s mode %d\n", mode->name, mode->status);
|
||||||
}
|
}
|
||||||
kfree(mode);
|
drm_mode_destroy(dev, mode);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -556,7 +556,7 @@ void drm_mode_connector_list_update(struct drm_connector *connector)
|
||||||
/* if equal delete the probed mode */
|
/* if equal delete the probed mode */
|
||||||
mode->status = pmode->status;
|
mode->status = pmode->status;
|
||||||
list_del(&pmode->head);
|
list_del(&pmode->head);
|
||||||
kfree(pmode);
|
drm_mode_destroy(connector->dev, pmode);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -210,7 +210,7 @@ static int intel_crt_get_modes(struct drm_connector *connector)
|
||||||
return intel_ddc_get_modes(intel_output);
|
return intel_ddc_get_modes(intel_output);
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool intel_crt_set_property(struct drm_connector *connector,
|
static int intel_crt_set_property(struct drm_connector *connector,
|
||||||
struct drm_property *property,
|
struct drm_property *property,
|
||||||
uint64_t value)
|
uint64_t value)
|
||||||
{
|
{
|
||||||
|
@ -219,7 +219,7 @@ static bool intel_crt_set_property(struct drm_connector *connector,
|
||||||
if (property == dev->mode_config.dpms_property && connector->encoder)
|
if (property == dev->mode_config.dpms_property && connector->encoder)
|
||||||
intel_crt_dpms(connector->encoder, (uint32_t)(value & 0xf));
|
intel_crt_dpms(connector->encoder, (uint32_t)(value & 0xf));
|
||||||
|
|
||||||
return true;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
|
|
@ -1560,7 +1560,7 @@ intel_tv_destroy (struct drm_connector *connector)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static bool
|
static int
|
||||||
intel_tv_set_property(struct drm_connector *connector, struct drm_property *property,
|
intel_tv_set_property(struct drm_connector *connector, struct drm_property *property,
|
||||||
uint64_t val)
|
uint64_t val)
|
||||||
{
|
{
|
||||||
|
|
|
@ -128,6 +128,39 @@ struct bit_entry {
|
||||||
uint16_t offset;
|
uint16_t offset;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
static int parse_bit_A_tbl_entry(struct drm_device *dev, struct bios *bios, struct bit_entry *bitentry)
|
||||||
|
{
|
||||||
|
/* Parses the load detect value table.
|
||||||
|
*
|
||||||
|
* Starting at bitentry->offset:
|
||||||
|
*
|
||||||
|
* offset + 0 (16 bits): table pointer
|
||||||
|
*/
|
||||||
|
|
||||||
|
uint16_t load_table_pointer;
|
||||||
|
|
||||||
|
if (bitentry->length != 3) {
|
||||||
|
DRM_ERROR("Do not understand BIT loadval table\n");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
load_table_pointer = le16_to_cpu(*((uint16_t *)(&bios->data[bitentry->offset])));
|
||||||
|
|
||||||
|
if (load_table_pointer == 0x0) {
|
||||||
|
DRM_ERROR("Pointer to loadval table invalid\n");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Some kind of signature */
|
||||||
|
if (bios->data[load_table_pointer] != 16 || bios->data[load_table_pointer + 1] != 4 ||
|
||||||
|
bios->data[load_table_pointer + 2] != 4 || bios->data[load_table_pointer + 3] != 2)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
bios->dactestval = le32_to_cpu(*((uint32_t *)&bios->data[load_table_pointer + 4])) & 0x3FF;
|
||||||
|
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
static int parse_bit_C_tbl_entry(struct drm_device *dev, struct bios *bios, struct bit_entry *bitentry)
|
static int parse_bit_C_tbl_entry(struct drm_device *dev, struct bios *bios, struct bit_entry *bitentry)
|
||||||
{
|
{
|
||||||
/* offset + 8 (16 bits): PLL limits table pointer
|
/* offset + 8 (16 bits): PLL limits table pointer
|
||||||
|
@ -136,7 +169,7 @@ static int parse_bit_C_tbl_entry(struct drm_device *dev, struct bios *bios, stru
|
||||||
*/
|
*/
|
||||||
|
|
||||||
if (bitentry->length < 10) {
|
if (bitentry->length < 10) {
|
||||||
DRM_ERROR( "Do not understand BIT C table\n");
|
DRM_ERROR("Do not understand BIT C table\n");
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -149,7 +182,7 @@ static void parse_bit_structure(struct drm_device *dev, struct bios *bios, const
|
||||||
{
|
{
|
||||||
int entries = bios->data[bitoffset + 4];
|
int entries = bios->data[bitoffset + 4];
|
||||||
/* parse i first, I next (which needs C & M before it), and L before D */
|
/* parse i first, I next (which needs C & M before it), and L before D */
|
||||||
char parseorder[] = "iCMILDT";
|
char parseorder[] = "iCMILDTA";
|
||||||
struct bit_entry bitentry;
|
struct bit_entry bitentry;
|
||||||
int i, j, offset;
|
int i, j, offset;
|
||||||
|
|
||||||
|
@ -164,6 +197,9 @@ static void parse_bit_structure(struct drm_device *dev, struct bios *bios, const
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
switch (bitentry.id[0]) {
|
switch (bitentry.id[0]) {
|
||||||
|
case 'A':
|
||||||
|
parse_bit_A_tbl_entry(dev, bios, &bitentry);
|
||||||
|
break;
|
||||||
case 'C':
|
case 'C':
|
||||||
parse_bit_C_tbl_entry(dev, bios, &bitentry);
|
parse_bit_C_tbl_entry(dev, bios, &bitentry);
|
||||||
break;
|
break;
|
||||||
|
@ -305,11 +341,12 @@ parse_dcb_entry(struct drm_device *dev, int index, uint8_t dcb_version, uint16_t
|
||||||
entry->lvdsconf.use_power_scripts = true;
|
entry->lvdsconf.use_power_scripts = true;
|
||||||
}
|
}
|
||||||
if (conf & mask) {
|
if (conf & mask) {
|
||||||
DRM_ERROR(
|
if (dcb_version < 0x40) { /* we know g80 cards have unknown bits */
|
||||||
"Unknown LVDS configuration bits, please report\n");
|
DRM_ERROR("Unknown LVDS configuration bits, please report\n");
|
||||||
/* cause output setting to fail, so message is seen */
|
/* cause output setting to fail, so message is seen */
|
||||||
dev_priv->dcb_table.entries = 0;
|
dev_priv->dcb_table.entries = 0;
|
||||||
return false;
|
return false;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
|
@ -76,7 +76,44 @@ static struct nv50_output *nv50_connector_to_output(struct nv50_connector *conne
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool nv50_connector_detect(struct nv50_connector *connector)
|
static int nv50_connector_hpd_detect(struct nv50_connector *connector)
|
||||||
|
{
|
||||||
|
struct drm_nouveau_private *dev_priv = connector->dev->dev_private;
|
||||||
|
bool present = 0;
|
||||||
|
uint32_t reg = 0;
|
||||||
|
|
||||||
|
/* Assume connected for the moment. */
|
||||||
|
if (connector->type == CONNECTOR_LVDS) {
|
||||||
|
NV50_DEBUG("LVDS is defaulting to connected for the moment.\n");
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* No i2c port, no idea what to do for hotplug. */
|
||||||
|
if (connector->i2c_chan->index == 15) {
|
||||||
|
DRM_ERROR("You have a non-LVDS SOR with no i2c port, please report\n");
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (connector->i2c_chan->index > 3) {
|
||||||
|
DRM_ERROR("You have an unusual configuration, index is %d\n", connector->i2c_chan->index);
|
||||||
|
DRM_ERROR("Please report.\n");
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Check hotplug pins. */
|
||||||
|
reg = NV_READ(NV50_PCONNECTOR_HOTPLUG_STATE);
|
||||||
|
if (reg & (NV50_PCONNECTOR_HOTPLUG_STATE_PIN_CONNECTED_I2C0 << (4 * connector->i2c_chan->index)))
|
||||||
|
present = 1;
|
||||||
|
|
||||||
|
if (present)
|
||||||
|
NV50_DEBUG("Hotplug detect returned positive for bus %d\n", connector->bus);
|
||||||
|
else
|
||||||
|
NV50_DEBUG("Hotplug detect returned negative for bus %d\n", connector->bus);
|
||||||
|
|
||||||
|
return present;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int nv50_connector_i2c_detect(struct nv50_connector *connector)
|
||||||
{
|
{
|
||||||
/* kindly borrrowed from the intel driver, hope it works. */
|
/* kindly borrrowed from the intel driver, hope it works. */
|
||||||
uint8_t out_buf[] = { 0x0, 0x0};
|
uint8_t out_buf[] = { 0x0, 0x0};
|
||||||
|
@ -97,13 +134,11 @@ static bool nv50_connector_detect(struct nv50_connector *connector)
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
NV50_DEBUG("\n");
|
|
||||||
|
|
||||||
if (!connector->i2c_chan)
|
if (!connector->i2c_chan)
|
||||||
return false;
|
return -EINVAL;
|
||||||
|
|
||||||
ret = i2c_transfer(&connector->i2c_chan->adapter, msgs, 2);
|
ret = i2c_transfer(&connector->i2c_chan->adapter, msgs, 2);
|
||||||
DRM_INFO("I2C detect returned %d\n", ret);
|
NV50_DEBUG("I2C detect returned %d\n", ret);
|
||||||
|
|
||||||
if (ret == 2)
|
if (ret == 2)
|
||||||
return true;
|
return true;
|
||||||
|
@ -185,15 +220,18 @@ int nv50_connector_create(struct drm_device *dev, int bus, int i2c_index, int ty
|
||||||
|
|
||||||
/* some reasonable defaults */
|
/* some reasonable defaults */
|
||||||
if (type == CONNECTOR_DVI_D || type == CONNECTOR_DVI_I || type == CONNECTOR_LVDS)
|
if (type == CONNECTOR_DVI_D || type == CONNECTOR_DVI_I || type == CONNECTOR_LVDS)
|
||||||
connector->scaling_mode = SCALE_FULLSCREEN;
|
connector->requested_scaling_mode = SCALE_FULLSCREEN;
|
||||||
else
|
else
|
||||||
connector->scaling_mode = SCALE_PANEL;
|
connector->requested_scaling_mode = SCALE_NON_GPU;
|
||||||
|
|
||||||
|
connector->use_dithering = false;
|
||||||
|
|
||||||
if (i2c_index < 0xf)
|
if (i2c_index < 0xf)
|
||||||
connector->i2c_chan = nv50_i2c_channel_create(dev, i2c_index);
|
connector->i2c_chan = nv50_i2c_channel_create(dev, i2c_index);
|
||||||
|
|
||||||
/* set function pointers */
|
/* set function pointers */
|
||||||
connector->detect = nv50_connector_detect;
|
connector->hpd_detect = nv50_connector_hpd_detect;
|
||||||
|
connector->i2c_detect = nv50_connector_i2c_detect;
|
||||||
connector->destroy = nv50_connector_destroy;
|
connector->destroy = nv50_connector_destroy;
|
||||||
connector->to_output = nv50_connector_to_output;
|
connector->to_output = nv50_connector_to_output;
|
||||||
|
|
||||||
|
|
|
@ -47,9 +47,12 @@ struct nv50_connector {
|
||||||
struct nv50_i2c_channel *i2c_chan;
|
struct nv50_i2c_channel *i2c_chan;
|
||||||
struct nv50_output *output;
|
struct nv50_output *output;
|
||||||
|
|
||||||
int scaling_mode;
|
int requested_scaling_mode;
|
||||||
|
|
||||||
bool (*detect) (struct nv50_connector *connector);
|
bool use_dithering;
|
||||||
|
|
||||||
|
int (*hpd_detect) (struct nv50_connector *connector);
|
||||||
|
int (*i2c_detect) (struct nv50_connector *connector);
|
||||||
int (*destroy) (struct nv50_connector *connector);
|
int (*destroy) (struct nv50_connector *connector);
|
||||||
struct nv50_output *(*to_output) (struct nv50_connector *connector, bool digital);
|
struct nv50_output *(*to_output) (struct nv50_connector *connector, bool digital);
|
||||||
};
|
};
|
||||||
|
|
|
@ -255,7 +255,7 @@ static int nv50_crtc_set_scale(struct nv50_crtc *crtc)
|
||||||
|
|
||||||
NV50_DEBUG("\n");
|
NV50_DEBUG("\n");
|
||||||
|
|
||||||
switch (crtc->scaling_mode) {
|
switch (crtc->requested_scaling_mode) {
|
||||||
case SCALE_ASPECT:
|
case SCALE_ASPECT:
|
||||||
nv50_crtc_calc_scale(crtc, &outX, &outY);
|
nv50_crtc_calc_scale(crtc, &outX, &outY);
|
||||||
break;
|
break;
|
||||||
|
@ -264,7 +264,7 @@ static int nv50_crtc_set_scale(struct nv50_crtc *crtc)
|
||||||
outY = crtc->native_mode->vdisplay;
|
outY = crtc->native_mode->vdisplay;
|
||||||
break;
|
break;
|
||||||
case SCALE_NOSCALE:
|
case SCALE_NOSCALE:
|
||||||
case SCALE_PANEL:
|
case SCALE_NON_GPU:
|
||||||
default:
|
default:
|
||||||
outX = crtc->mode->hdisplay;
|
outX = crtc->mode->hdisplay;
|
||||||
outY = crtc->mode->vdisplay;
|
outY = crtc->mode->vdisplay;
|
||||||
|
@ -283,6 +283,9 @@ static int nv50_crtc_set_scale(struct nv50_crtc *crtc)
|
||||||
OUT_MODE(NV50_CRTC0_SCALE_RES1 + offset, outY << 16 | outX);
|
OUT_MODE(NV50_CRTC0_SCALE_RES1 + offset, outY << 16 | outX);
|
||||||
OUT_MODE(NV50_CRTC0_SCALE_RES2 + offset, outY << 16 | outX);
|
OUT_MODE(NV50_CRTC0_SCALE_RES2 + offset, outY << 16 | outX);
|
||||||
|
|
||||||
|
/* processed */
|
||||||
|
crtc->scaling_mode = crtc->requested_scaling_mode;
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -492,6 +495,9 @@ int nv50_crtc_create(struct drm_device *dev, int index)
|
||||||
crtc->mode = kzalloc(sizeof(struct nouveau_hw_mode), GFP_KERNEL);
|
crtc->mode = kzalloc(sizeof(struct nouveau_hw_mode), GFP_KERNEL);
|
||||||
crtc->native_mode = kzalloc(sizeof(struct nouveau_hw_mode), GFP_KERNEL);
|
crtc->native_mode = kzalloc(sizeof(struct nouveau_hw_mode), GFP_KERNEL);
|
||||||
|
|
||||||
|
crtc->requested_scaling_mode = SCALE_INVALID;
|
||||||
|
crtc->scaling_mode = SCALE_INVALID;
|
||||||
|
|
||||||
if (!crtc->mode || !crtc->native_mode) {
|
if (!crtc->mode || !crtc->native_mode) {
|
||||||
rval = -ENOMEM;
|
rval = -ENOMEM;
|
||||||
goto out;
|
goto out;
|
||||||
|
|
|
@ -46,6 +46,10 @@ struct nv50_crtc {
|
||||||
|
|
||||||
bool use_native_mode;
|
bool use_native_mode;
|
||||||
bool use_dithering;
|
bool use_dithering;
|
||||||
|
|
||||||
|
/* Changing scaling modes requires a modeset sometimes. */
|
||||||
|
/* We need to know the currently active hw mode, as well as the requested one by the user. */
|
||||||
|
int requested_scaling_mode;
|
||||||
int scaling_mode;
|
int scaling_mode;
|
||||||
|
|
||||||
struct nv50_cursor *cursor;
|
struct nv50_cursor *cursor;
|
||||||
|
|
|
@ -133,6 +133,46 @@ static int nv50_dac_set_power_mode(struct nv50_output *output, int mode)
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int nv50_dac_detect(struct nv50_output *output)
|
||||||
|
{
|
||||||
|
struct drm_nouveau_private *dev_priv = output->dev->dev_private;
|
||||||
|
int or = nv50_output_or_offset(output);
|
||||||
|
bool present = 0;
|
||||||
|
uint32_t dpms_state, load_pattern, load_state;
|
||||||
|
|
||||||
|
NV_WRITE(NV50_PDISPLAY_DAC_REGS_CLK_CTRL1(or), 0x00000001);
|
||||||
|
dpms_state = NV_READ(NV50_PDISPLAY_DAC_REGS_DPMS_CTRL(or));
|
||||||
|
|
||||||
|
NV_WRITE(NV50_PDISPLAY_DAC_REGS_DPMS_CTRL(or), 0x00150000 | NV50_PDISPLAY_DAC_REGS_DPMS_CTRL_PENDING);
|
||||||
|
while (NV_READ(NV50_PDISPLAY_DAC_REGS_DPMS_CTRL(or)) & NV50_PDISPLAY_DAC_REGS_DPMS_CTRL_PENDING);
|
||||||
|
|
||||||
|
/* Use bios provided value if possible. */
|
||||||
|
if (dev_priv->bios.dactestval) {
|
||||||
|
load_pattern = dev_priv->bios.dactestval;
|
||||||
|
NV50_DEBUG("Using bios provided load_pattern of %d\n", load_pattern);
|
||||||
|
} else {
|
||||||
|
load_pattern = 340;
|
||||||
|
NV50_DEBUG("Using default load_pattern of %d\n", load_pattern);
|
||||||
|
}
|
||||||
|
|
||||||
|
NV_WRITE(NV50_PDISPLAY_DAC_REGS_LOAD_CTRL(or), NV50_PDISPLAY_DAC_REGS_LOAD_CTRL_ACTIVE | load_pattern);
|
||||||
|
udelay(10000); /* give it some time to process */
|
||||||
|
load_state = NV_READ(NV50_PDISPLAY_DAC_REGS_LOAD_CTRL(or));
|
||||||
|
|
||||||
|
NV_WRITE(NV50_PDISPLAY_DAC_REGS_LOAD_CTRL(or), 0);
|
||||||
|
NV_WRITE(NV50_PDISPLAY_DAC_REGS_DPMS_CTRL(or), dpms_state);
|
||||||
|
|
||||||
|
if ((load_state & NV50_PDISPLAY_DAC_REGS_LOAD_CTRL_PRESENT) == NV50_PDISPLAY_DAC_REGS_LOAD_CTRL_PRESENT)
|
||||||
|
present = 1;
|
||||||
|
|
||||||
|
if (present)
|
||||||
|
NV50_DEBUG("Load was detected on output with or %d\n", or);
|
||||||
|
else
|
||||||
|
NV50_DEBUG("Load was not detected on output with or %d\n", or);
|
||||||
|
|
||||||
|
return present;
|
||||||
|
}
|
||||||
|
|
||||||
static int nv50_dac_destroy(struct nv50_output *output)
|
static int nv50_dac_destroy(struct nv50_output *output)
|
||||||
{
|
{
|
||||||
struct drm_device *dev = output->dev;
|
struct drm_device *dev = output->dev;
|
||||||
|
@ -210,7 +250,7 @@ int nv50_dac_create(struct drm_device *dev, int dcb_entry)
|
||||||
output->execute_mode = nv50_dac_execute_mode;
|
output->execute_mode = nv50_dac_execute_mode;
|
||||||
output->set_clock_mode = nv50_dac_set_clock_mode;
|
output->set_clock_mode = nv50_dac_set_clock_mode;
|
||||||
output->set_power_mode = nv50_dac_set_power_mode;
|
output->set_power_mode = nv50_dac_set_power_mode;
|
||||||
output->detect = NULL; /* TODO */
|
output->detect = nv50_dac_detect;
|
||||||
output->destroy = nv50_dac_destroy;
|
output->destroy = nv50_dac_destroy;
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
|
|
|
@ -68,7 +68,7 @@ struct nv50_display {
|
||||||
};
|
};
|
||||||
|
|
||||||
enum scaling_modes {
|
enum scaling_modes {
|
||||||
SCALE_PANEL,
|
SCALE_NON_GPU,
|
||||||
SCALE_FULLSCREEN,
|
SCALE_FULLSCREEN,
|
||||||
SCALE_ASPECT,
|
SCALE_ASPECT,
|
||||||
SCALE_NOSCALE,
|
SCALE_NOSCALE,
|
||||||
|
|
|
@ -386,7 +386,7 @@ int nv50_kms_crtc_set_config(struct drm_mode_set *set)
|
||||||
/* This is to ensure it knows the connector subtype. */
|
/* This is to ensure it knows the connector subtype. */
|
||||||
drm_connector->funcs->fill_modes(drm_connector, 0, 0);
|
drm_connector->funcs->fill_modes(drm_connector, 0, 0);
|
||||||
|
|
||||||
output = connector->to_output(connector, nv50_kms_connector_is_digital(drm_connector));
|
output = connector->to_output(connector, nv50_kms_connector_get_digital(drm_connector));
|
||||||
if (!output) {
|
if (!output) {
|
||||||
DRM_ERROR("No output\n");
|
DRM_ERROR("No output\n");
|
||||||
goto out;
|
goto out;
|
||||||
|
@ -458,7 +458,7 @@ int nv50_kms_crtc_set_config(struct drm_mode_set *set)
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
|
|
||||||
output = connector->to_output(connector, nv50_kms_connector_is_digital(drm_connector));
|
output = connector->to_output(connector, nv50_kms_connector_get_digital(drm_connector));
|
||||||
if (!output) {
|
if (!output) {
|
||||||
DRM_ERROR("No output\n");
|
DRM_ERROR("No output\n");
|
||||||
goto out;
|
goto out;
|
||||||
|
@ -635,11 +635,12 @@ int nv50_kms_crtc_set_config(struct drm_mode_set *set)
|
||||||
if (connector->output != output)
|
if (connector->output != output)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
crtc->scaling_mode = connector->scaling_mode;
|
crtc->requested_scaling_mode = connector->requested_scaling_mode;
|
||||||
|
crtc->use_dithering = connector->use_dithering;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (crtc->scaling_mode == SCALE_PANEL)
|
if (crtc->requested_scaling_mode == SCALE_NON_GPU)
|
||||||
crtc->use_native_mode = false;
|
crtc->use_native_mode = false;
|
||||||
else
|
else
|
||||||
crtc->use_native_mode = true;
|
crtc->use_native_mode = true;
|
||||||
|
@ -834,7 +835,9 @@ static int nv50_kms_encoders_init(struct drm_device *dev)
|
||||||
* Connector functions
|
* Connector functions
|
||||||
*/
|
*/
|
||||||
|
|
||||||
bool nv50_kms_connector_is_digital(struct drm_connector *drm_connector)
|
|
||||||
|
/* These 2 functions wrap the connector properties that deal with multiple encoders per connector. */
|
||||||
|
bool nv50_kms_connector_get_digital(struct drm_connector *drm_connector)
|
||||||
{
|
{
|
||||||
struct drm_device *dev = drm_connector->dev;
|
struct drm_device *dev = drm_connector->dev;
|
||||||
|
|
||||||
|
@ -891,6 +894,33 @@ bool nv50_kms_connector_is_digital(struct drm_connector *drm_connector)
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void nv50_kms_connector_set_digital(struct drm_connector *drm_connector, int digital, bool force)
|
||||||
|
{
|
||||||
|
struct drm_device *dev = drm_connector->dev;
|
||||||
|
|
||||||
|
if (drm_connector->connector_type == DRM_MODE_CONNECTOR_DVII) {
|
||||||
|
uint64_t cur_value, new_value;
|
||||||
|
|
||||||
|
int rval = drm_connector_property_get_value(drm_connector, dev->mode_config.dvi_i_subconnector_property, &cur_value);
|
||||||
|
if (rval) {
|
||||||
|
DRM_ERROR("Unable to find subconnector property\n");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Only set when unknown or when forced to do so. */
|
||||||
|
if (cur_value != DRM_MODE_SUBCONNECTOR_Unknown && !force)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (digital == 1)
|
||||||
|
new_value = DRM_MODE_SUBCONNECTOR_DVID;
|
||||||
|
else if (digital == 0)
|
||||||
|
new_value = DRM_MODE_SUBCONNECTOR_DVIA;
|
||||||
|
else
|
||||||
|
new_value = DRM_MODE_SUBCONNECTOR_Unknown;
|
||||||
|
drm_connector_property_set_value(drm_connector, dev->mode_config.dvi_i_subconnector_property, new_value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void nv50_kms_connector_detect_all(struct drm_device *dev)
|
void nv50_kms_connector_detect_all(struct drm_device *dev)
|
||||||
{
|
{
|
||||||
struct drm_connector *drm_connector = NULL;
|
struct drm_connector *drm_connector = NULL;
|
||||||
|
@ -902,16 +932,32 @@ void nv50_kms_connector_detect_all(struct drm_device *dev)
|
||||||
|
|
||||||
static enum drm_connector_status nv50_kms_connector_detect(struct drm_connector *drm_connector)
|
static enum drm_connector_status nv50_kms_connector_detect(struct drm_connector *drm_connector)
|
||||||
{
|
{
|
||||||
struct nv50_connector *connector = to_nv50_connector(drm_connector);
|
|
||||||
struct drm_device *dev = drm_connector->dev;
|
struct drm_device *dev = drm_connector->dev;
|
||||||
bool connected;
|
struct nv50_connector *connector = to_nv50_connector(drm_connector);
|
||||||
int old_status;
|
struct nv50_output *output = NULL;
|
||||||
|
int hpd_detect = 0, load_detect = 0, i2c_detect = 0;
|
||||||
|
int old_status = drm_connector->status;
|
||||||
|
|
||||||
connected = connector->detect(connector);
|
/* hotplug detect */
|
||||||
|
hpd_detect = connector->hpd_detect(connector);
|
||||||
|
|
||||||
old_status = drm_connector->status;
|
/* load detect */
|
||||||
|
output = connector->to_output(connector, FALSE); /* analog */
|
||||||
|
if (output && output->detect)
|
||||||
|
load_detect = output->detect(output);
|
||||||
|
|
||||||
if (connected)
|
if (hpd_detect < 0 || load_detect < 0) /* did an error occur? */
|
||||||
|
i2c_detect = connector->i2c_detect(connector);
|
||||||
|
|
||||||
|
if (load_detect == 1) {
|
||||||
|
nv50_kms_connector_set_digital(drm_connector, 0, TRUE); /* analog, forced */
|
||||||
|
} else if (hpd_detect == 1 && load_detect == 0) {
|
||||||
|
nv50_kms_connector_set_digital(drm_connector, 1, TRUE); /* digital, forced */
|
||||||
|
} else {
|
||||||
|
nv50_kms_connector_set_digital(drm_connector, -1, TRUE); /* unknown, forced */
|
||||||
|
}
|
||||||
|
|
||||||
|
if (hpd_detect == 1 || load_detect == 1 || i2c_detect == 1)
|
||||||
drm_connector->status = connector_status_connected;
|
drm_connector->status = connector_status_connected;
|
||||||
else
|
else
|
||||||
drm_connector->status = connector_status_disconnected;
|
drm_connector->status = connector_status_disconnected;
|
||||||
|
@ -955,7 +1001,7 @@ static void nv50_kms_connector_fill_modes(struct drm_connector *drm_connector, u
|
||||||
struct nv50_connector *connector = to_nv50_connector(drm_connector);
|
struct nv50_connector *connector = to_nv50_connector(drm_connector);
|
||||||
struct drm_device *dev = drm_connector->dev;
|
struct drm_device *dev = drm_connector->dev;
|
||||||
int rval = 0;
|
int rval = 0;
|
||||||
bool connected;
|
bool connected = false;
|
||||||
struct drm_display_mode *mode, *t;
|
struct drm_display_mode *mode, *t;
|
||||||
struct edid *edid = NULL;
|
struct edid *edid = NULL;
|
||||||
|
|
||||||
|
@ -964,16 +1010,13 @@ static void nv50_kms_connector_fill_modes(struct drm_connector *drm_connector, u
|
||||||
list_for_each_entry_safe(mode, t, &drm_connector->modes, head)
|
list_for_each_entry_safe(mode, t, &drm_connector->modes, head)
|
||||||
mode->status = MODE_UNVERIFIED;
|
mode->status = MODE_UNVERIFIED;
|
||||||
|
|
||||||
connected = connector->detect(connector);
|
if (nv50_kms_connector_detect(drm_connector) == connector_status_connected)
|
||||||
|
connected = true;
|
||||||
|
|
||||||
if (connected)
|
if (connected)
|
||||||
drm_connector->status = connector_status_connected;
|
NV50_DEBUG("%s is connected\n", drm_get_connector_name(drm_connector));
|
||||||
else
|
else
|
||||||
drm_connector->status = connector_status_disconnected;
|
|
||||||
|
|
||||||
if (!connected) {
|
|
||||||
NV50_DEBUG("%s is disconnected\n", drm_get_connector_name(drm_connector));
|
NV50_DEBUG("%s is disconnected\n", drm_get_connector_name(drm_connector));
|
||||||
}
|
|
||||||
|
|
||||||
/* Not all connnectors have an i2c channel. */
|
/* Not all connnectors have an i2c channel. */
|
||||||
if (connected && connector->i2c_chan)
|
if (connected && connector->i2c_chan)
|
||||||
|
@ -985,16 +1028,8 @@ static void nv50_kms_connector_fill_modes(struct drm_connector *drm_connector, u
|
||||||
if (edid) {
|
if (edid) {
|
||||||
rval = drm_add_edid_modes(drm_connector, edid);
|
rval = drm_add_edid_modes(drm_connector, edid);
|
||||||
|
|
||||||
/* 2 encoders per connector */
|
/* Only update when relevant and when detect couldn't determine type. */
|
||||||
/* eventually do this based on load detect and hot plug detect */
|
nv50_kms_connector_set_digital(drm_connector, edid->digital ? 1 : 0, FALSE);
|
||||||
if (drm_connector->connector_type == DRM_MODE_CONNECTOR_DVII) {
|
|
||||||
uint64_t subtype = 0;
|
|
||||||
if (edid->digital)
|
|
||||||
subtype = DRM_MODE_SUBCONNECTOR_DVID;
|
|
||||||
else
|
|
||||||
subtype = DRM_MODE_SUBCONNECTOR_DVIA;
|
|
||||||
drm_connector_property_set_value(drm_connector, dev->mode_config.dvi_i_subconnector_property, subtype);
|
|
||||||
}
|
|
||||||
|
|
||||||
kfree(edid);
|
kfree(edid);
|
||||||
}
|
}
|
||||||
|
@ -1008,7 +1043,7 @@ static void nv50_kms_connector_fill_modes(struct drm_connector *drm_connector, u
|
||||||
list_for_each_entry_safe(mode, t, &drm_connector->modes, head) {
|
list_for_each_entry_safe(mode, t, &drm_connector->modes, head) {
|
||||||
if (mode->status == MODE_OK) {
|
if (mode->status == MODE_OK) {
|
||||||
struct nouveau_hw_mode *hw_mode = nv50_kms_to_hw_mode(mode);
|
struct nouveau_hw_mode *hw_mode = nv50_kms_to_hw_mode(mode);
|
||||||
struct nv50_output *output = connector->to_output(connector, nv50_kms_connector_is_digital(drm_connector));
|
struct nv50_output *output = connector->to_output(connector, nv50_kms_connector_get_digital(drm_connector));
|
||||||
|
|
||||||
mode->status = output->validate_mode(output, hw_mode);
|
mode->status = output->validate_mode(output, hw_mode);
|
||||||
/* find native mode, TODO: also check if we actually found one */
|
/* find native mode, TODO: also check if we actually found one */
|
||||||
|
@ -1024,7 +1059,7 @@ static void nv50_kms_connector_fill_modes(struct drm_connector *drm_connector, u
|
||||||
list_for_each_entry_safe(mode, t, &drm_connector->modes, head) {
|
list_for_each_entry_safe(mode, t, &drm_connector->modes, head) {
|
||||||
if (mode->status == MODE_OK) {
|
if (mode->status == MODE_OK) {
|
||||||
struct nouveau_hw_mode *hw_mode = nv50_kms_to_hw_mode(mode);
|
struct nouveau_hw_mode *hw_mode = nv50_kms_to_hw_mode(mode);
|
||||||
struct nv50_output *output = connector->to_output(connector, nv50_kms_connector_is_digital(drm_connector));
|
struct nv50_output *output = connector->to_output(connector, nv50_kms_connector_get_digital(drm_connector));
|
||||||
|
|
||||||
mode->status = output->validate_mode(output, hw_mode);
|
mode->status = output->validate_mode(output, hw_mode);
|
||||||
kfree(hw_mode);
|
kfree(hw_mode);
|
||||||
|
@ -1044,6 +1079,10 @@ static void nv50_kms_connector_fill_modes(struct drm_connector *drm_connector, u
|
||||||
|
|
||||||
NV50_DEBUG("No valid modes on %s\n", drm_get_connector_name(drm_connector));
|
NV50_DEBUG("No valid modes on %s\n", drm_get_connector_name(drm_connector));
|
||||||
|
|
||||||
|
/* Making up native modes for LVDS is a bad idea. */
|
||||||
|
if (drm_connector->connector_type == DRM_MODE_CONNECTOR_LVDS)
|
||||||
|
return;
|
||||||
|
|
||||||
/* Should we do this here ???
|
/* Should we do this here ???
|
||||||
* When no valid EDID modes are available we end up
|
* When no valid EDID modes are available we end up
|
||||||
* here and bailed in the past, now we add a standard
|
* here and bailed in the past, now we add a standard
|
||||||
|
@ -1056,7 +1095,7 @@ static void nv50_kms_connector_fill_modes(struct drm_connector *drm_connector, u
|
||||||
|
|
||||||
/* also add it as native mode */
|
/* also add it as native mode */
|
||||||
hw_mode = nv50_kms_to_hw_mode(mode);
|
hw_mode = nv50_kms_to_hw_mode(mode);
|
||||||
output = connector->to_output(connector, nv50_kms_connector_is_digital(drm_connector));
|
output = connector->to_output(connector, nv50_kms_connector_get_digital(drm_connector));
|
||||||
|
|
||||||
if (hw_mode)
|
if (hw_mode)
|
||||||
*output->native_mode = *hw_mode;
|
*output->native_mode = *hw_mode;
|
||||||
|
@ -1078,22 +1117,109 @@ static void nv50_kms_connector_fill_modes(struct drm_connector *drm_connector, u
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool nv50_kms_connector_set_property(struct drm_connector *connector,
|
static int nv50_kms_connector_set_property(struct drm_connector *drm_connector,
|
||||||
struct drm_property *property,
|
struct drm_property *property,
|
||||||
uint64_t value)
|
uint64_t value)
|
||||||
{
|
{
|
||||||
struct drm_device *dev = connector->dev;
|
struct drm_device *dev = drm_connector->dev;
|
||||||
|
struct nv50_connector *connector = to_nv50_connector(drm_connector);
|
||||||
|
int rval = 0;
|
||||||
|
bool delay_change = false;
|
||||||
|
|
||||||
if (property == dev->mode_config.dpms_property && connector->encoder) {
|
/* DPMS */
|
||||||
struct nv50_output *output = to_nv50_output(connector->encoder);
|
if (property == dev->mode_config.dpms_property && drm_connector->encoder) {
|
||||||
|
struct nv50_output *output = to_nv50_output(drm_connector->encoder);
|
||||||
|
|
||||||
if (!output->set_power_mode(output, (int) value))
|
rval = output->set_power_mode(output, (int) value);
|
||||||
return true;
|
|
||||||
else
|
return rval;
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return false;
|
/* Scaling mode */
|
||||||
|
if (property == dev->mode_config.scaling_mode_property) {
|
||||||
|
struct nv50_crtc *crtc = NULL;
|
||||||
|
struct nv50_display *display = nv50_get_display(dev);
|
||||||
|
int internal_value = 0;
|
||||||
|
|
||||||
|
switch (value) {
|
||||||
|
case DRM_MODE_SCALE_NON_GPU:
|
||||||
|
internal_value = SCALE_NON_GPU;
|
||||||
|
break;
|
||||||
|
case DRM_MODE_SCALE_FULLSCREEN:
|
||||||
|
internal_value = SCALE_FULLSCREEN;
|
||||||
|
break;
|
||||||
|
case DRM_MODE_SCALE_NO_SCALE:
|
||||||
|
internal_value = SCALE_NOSCALE;
|
||||||
|
break;
|
||||||
|
case DRM_MODE_SCALE_ASPECT:
|
||||||
|
internal_value = SCALE_ASPECT;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* LVDS always needs gpu scaling */
|
||||||
|
if (connector->type == CONNECTOR_LVDS && internal_value == SCALE_NON_GPU)
|
||||||
|
return -EINVAL;
|
||||||
|
|
||||||
|
connector->requested_scaling_mode = internal_value;
|
||||||
|
|
||||||
|
if (drm_connector->encoder && drm_connector->encoder->crtc)
|
||||||
|
crtc = to_nv50_crtc(drm_connector->encoder->crtc);
|
||||||
|
|
||||||
|
if (!crtc)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
crtc->requested_scaling_mode = connector->requested_scaling_mode;
|
||||||
|
|
||||||
|
/* going from and to a gpu scaled regime requires a modesetting, so wait until next modeset */
|
||||||
|
if (crtc->scaling_mode == SCALE_NON_GPU || internal_value == SCALE_NON_GPU) {
|
||||||
|
DRM_INFO("Moving from or to a non-gpu scaled mode, this will be processed upon next modeset.");
|
||||||
|
delay_change = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (delay_change)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
rval = crtc->set_scale(crtc);
|
||||||
|
if (rval)
|
||||||
|
return rval;
|
||||||
|
|
||||||
|
/* process command buffer */
|
||||||
|
display->update(display);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Dithering */
|
||||||
|
if (property == dev->mode_config.dithering_mode_property) {
|
||||||
|
struct nv50_crtc *crtc = NULL;
|
||||||
|
struct nv50_display *display = nv50_get_display(dev);
|
||||||
|
|
||||||
|
if (value == DRM_MODE_DITHERING_ON)
|
||||||
|
connector->use_dithering = true;
|
||||||
|
else
|
||||||
|
connector->use_dithering = false;
|
||||||
|
|
||||||
|
if (drm_connector->encoder && drm_connector->encoder->crtc)
|
||||||
|
crtc = to_nv50_crtc(drm_connector->encoder->crtc);
|
||||||
|
|
||||||
|
if (!crtc)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
/* update hw state */
|
||||||
|
crtc->use_dithering = connector->use_dithering;
|
||||||
|
rval = crtc->set_dither(crtc);
|
||||||
|
if (rval)
|
||||||
|
return rval;
|
||||||
|
|
||||||
|
/* process command buffer */
|
||||||
|
display->update(display);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
return -EINVAL;
|
||||||
}
|
}
|
||||||
|
|
||||||
static const struct drm_connector_funcs nv50_kms_connector_funcs = {
|
static const struct drm_connector_funcs nv50_kms_connector_funcs = {
|
||||||
|
@ -1105,12 +1231,48 @@ static const struct drm_connector_funcs nv50_kms_connector_funcs = {
|
||||||
.set_property = nv50_kms_connector_set_property
|
.set_property = nv50_kms_connector_set_property
|
||||||
};
|
};
|
||||||
|
|
||||||
|
static int nv50_kms_get_scaling_mode(struct drm_connector *drm_connector)
|
||||||
|
{
|
||||||
|
struct nv50_connector *connector = NULL;
|
||||||
|
int drm_mode = 0;
|
||||||
|
|
||||||
|
if (!drm_connector) {
|
||||||
|
DRM_ERROR("drm_connector is NULL\n");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
connector = to_nv50_connector(drm_connector);
|
||||||
|
|
||||||
|
switch (connector->requested_scaling_mode) {
|
||||||
|
case SCALE_NON_GPU:
|
||||||
|
drm_mode = DRM_MODE_SCALE_NON_GPU;
|
||||||
|
break;
|
||||||
|
case SCALE_FULLSCREEN:
|
||||||
|
drm_mode = DRM_MODE_SCALE_FULLSCREEN;
|
||||||
|
break;
|
||||||
|
case SCALE_NOSCALE:
|
||||||
|
drm_mode = DRM_MODE_SCALE_NO_SCALE;
|
||||||
|
break;
|
||||||
|
case SCALE_ASPECT:
|
||||||
|
drm_mode = DRM_MODE_SCALE_ASPECT;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
return drm_mode;
|
||||||
|
}
|
||||||
|
|
||||||
static int nv50_kms_connectors_init(struct drm_device *dev)
|
static int nv50_kms_connectors_init(struct drm_device *dev)
|
||||||
{
|
{
|
||||||
struct nv50_display *display = nv50_get_display(dev);
|
struct nv50_display *display = nv50_get_display(dev);
|
||||||
struct nv50_connector *connector = NULL;
|
struct nv50_connector *connector = NULL;
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
|
/* Initialise some optional connector properties. */
|
||||||
|
drm_mode_create_scaling_mode_property(dev);
|
||||||
|
drm_mode_create_dithering_property(dev);
|
||||||
|
|
||||||
list_for_each_entry(connector, &display->connectors, item) {
|
list_for_each_entry(connector, &display->connectors, item) {
|
||||||
struct drm_connector *drm_connector = to_nv50_kms_connector(connector);
|
struct drm_connector *drm_connector = to_nv50_kms_connector(connector);
|
||||||
uint32_t type = DRM_MODE_CONNECTOR_Unknown;
|
uint32_t type = DRM_MODE_CONNECTOR_Unknown;
|
||||||
|
@ -1154,6 +1316,13 @@ static int nv50_kms_connectors_init(struct drm_device *dev)
|
||||||
drm_connector_attach_property(drm_connector, dev->mode_config.dvi_i_select_subconnector_property, 0);
|
drm_connector_attach_property(drm_connector, dev->mode_config.dvi_i_select_subconnector_property, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* If supported in the future, it will have to use the scalers internally and not expose them. */
|
||||||
|
if (type != DRM_MODE_CONNECTOR_SVIDEO) {
|
||||||
|
drm_connector_attach_property(drm_connector, dev->mode_config.scaling_mode_property, nv50_kms_get_scaling_mode(drm_connector));
|
||||||
|
}
|
||||||
|
|
||||||
|
drm_connector_attach_property(drm_connector, dev->mode_config.dithering_mode_property, connector->use_dithering ? DRM_MODE_DITHERING_ON : DRM_MODE_DITHERING_OFF);
|
||||||
|
|
||||||
/* attach encoders, possibilities are analog + digital */
|
/* attach encoders, possibilities are analog + digital */
|
||||||
for (i = 0; i < 2; i++) {
|
for (i = 0; i < 2; i++) {
|
||||||
struct drm_encoder *drm_encoder = NULL;
|
struct drm_encoder *drm_encoder = NULL;
|
||||||
|
|
|
@ -87,7 +87,7 @@ struct nv50_kms_priv {
|
||||||
|
|
||||||
struct nv50_kms_priv *nv50_get_kms_priv(struct drm_device *dev);
|
struct nv50_kms_priv *nv50_get_kms_priv(struct drm_device *dev);
|
||||||
void nv50_kms_connector_detect_all(struct drm_device *dev);
|
void nv50_kms_connector_detect_all(struct drm_device *dev);
|
||||||
bool nv50_kms_connector_is_digital(struct drm_connector *drm_connector);
|
bool nv50_kms_connector_get_digital(struct drm_connector *drm_connector);
|
||||||
|
|
||||||
int nv50_kms_init(struct drm_device *dev);
|
int nv50_kms_init(struct drm_device *dev);
|
||||||
int nv50_kms_destroy(struct drm_device *dev);
|
int nv50_kms_destroy(struct drm_device *dev);
|
||||||
|
|
|
@ -51,7 +51,7 @@ struct nv50_output {
|
||||||
int (*set_clock_mode) (struct nv50_output *output);
|
int (*set_clock_mode) (struct nv50_output *output);
|
||||||
/* this is not a normal modeset call, it is a direct register write, so it's executed immediately */
|
/* this is not a normal modeset call, it is a direct register write, so it's executed immediately */
|
||||||
int (*set_power_mode) (struct nv50_output *output, int mode);
|
int (*set_power_mode) (struct nv50_output *output, int mode);
|
||||||
bool (*detect) (struct nv50_output *output);
|
int (*detect) (struct nv50_output *output);
|
||||||
int (*destroy) (struct nv50_output *output);
|
int (*destroy) (struct nv50_output *output);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -1058,6 +1058,16 @@ struct drm_gem_open {
|
||||||
#define DRM_MODE_DPMS_SUSPEND 2
|
#define DRM_MODE_DPMS_SUSPEND 2
|
||||||
#define DRM_MODE_DPMS_OFF 3
|
#define DRM_MODE_DPMS_OFF 3
|
||||||
|
|
||||||
|
/* Scaling mode options */
|
||||||
|
#define DRM_MODE_SCALE_NON_GPU 0
|
||||||
|
#define DRM_MODE_SCALE_FULLSCREEN 1
|
||||||
|
#define DRM_MODE_SCALE_NO_SCALE 2
|
||||||
|
#define DRM_MODE_SCALE_ASPECT 3
|
||||||
|
|
||||||
|
/* Dithering mode options */
|
||||||
|
#define DRM_MODE_DITHERING_OFF 0
|
||||||
|
#define DRM_MODE_DITHERING_ON 1
|
||||||
|
|
||||||
struct drm_mode_modeinfo {
|
struct drm_mode_modeinfo {
|
||||||
unsigned int clock;
|
unsigned int clock;
|
||||||
unsigned short hdisplay, hsync_start, hsync_end, htotal, hskew;
|
unsigned short hdisplay, hsync_start, hsync_end, htotal, hskew;
|
||||||
|
|
|
@ -25,7 +25,7 @@
|
||||||
#ifndef __NOUVEAU_DRM_H__
|
#ifndef __NOUVEAU_DRM_H__
|
||||||
#define __NOUVEAU_DRM_H__
|
#define __NOUVEAU_DRM_H__
|
||||||
|
|
||||||
#define NOUVEAU_DRM_HEADER_PATCHLEVEL 10
|
#define NOUVEAU_DRM_HEADER_PATCHLEVEL 11
|
||||||
|
|
||||||
struct drm_nouveau_channel_alloc {
|
struct drm_nouveau_channel_alloc {
|
||||||
uint32_t fb_ctxdma_handle;
|
uint32_t fb_ctxdma_handle;
|
||||||
|
@ -85,10 +85,12 @@ struct drm_nouveau_gpuobj_free {
|
||||||
#define NOUVEAU_MEM_PINNED 0x00000040
|
#define NOUVEAU_MEM_PINNED 0x00000040
|
||||||
#define NOUVEAU_MEM_USER_BACKED 0x00000080
|
#define NOUVEAU_MEM_USER_BACKED 0x00000080
|
||||||
#define NOUVEAU_MEM_MAPPED 0x00000100
|
#define NOUVEAU_MEM_MAPPED 0x00000100
|
||||||
#define NOUVEAU_MEM_INSTANCE 0x00000200 /* internal */
|
#define NOUVEAU_MEM_TILE 0x00000200
|
||||||
#define NOUVEAU_MEM_NOTIFIER 0x00000400 /* internal */
|
#define NOUVEAU_MEM_TILE_ZETA 0x00000400
|
||||||
#define NOUVEAU_MEM_NOVM 0x00000800 /* internal */
|
#define NOUVEAU_MEM_INSTANCE 0x01000000 /* internal */
|
||||||
#define NOUVEAU_MEM_USER 0x00001000 /* internal */
|
#define NOUVEAU_MEM_NOTIFIER 0x02000000 /* internal */
|
||||||
|
#define NOUVEAU_MEM_NOVM 0x04000000 /* internal */
|
||||||
|
#define NOUVEAU_MEM_USER 0x08000000 /* internal */
|
||||||
#define NOUVEAU_MEM_INTERNAL (NOUVEAU_MEM_INSTANCE | \
|
#define NOUVEAU_MEM_INTERNAL (NOUVEAU_MEM_INSTANCE | \
|
||||||
NOUVEAU_MEM_NOTIFIER | \
|
NOUVEAU_MEM_NOTIFIER | \
|
||||||
NOUVEAU_MEM_NOVM | \
|
NOUVEAU_MEM_NOVM | \
|
||||||
|
@ -107,6 +109,13 @@ struct drm_nouveau_mem_free {
|
||||||
int flags;
|
int flags;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct drm_nouveau_mem_tile {
|
||||||
|
uint64_t offset;
|
||||||
|
uint64_t delta;
|
||||||
|
uint64_t size;
|
||||||
|
int flags;
|
||||||
|
};
|
||||||
|
|
||||||
/* FIXME : maybe unify {GET,SET}PARAMs */
|
/* FIXME : maybe unify {GET,SET}PARAMs */
|
||||||
#define NOUVEAU_GETPARAM_PCI_VENDOR 3
|
#define NOUVEAU_GETPARAM_PCI_VENDOR 3
|
||||||
#define NOUVEAU_GETPARAM_PCI_DEVICE 4
|
#define NOUVEAU_GETPARAM_PCI_DEVICE 4
|
||||||
|
@ -168,5 +177,6 @@ struct drm_nouveau_sarea {
|
||||||
#define DRM_NOUVEAU_GPUOBJ_FREE 0x07
|
#define DRM_NOUVEAU_GPUOBJ_FREE 0x07
|
||||||
#define DRM_NOUVEAU_MEM_ALLOC 0x08
|
#define DRM_NOUVEAU_MEM_ALLOC 0x08
|
||||||
#define DRM_NOUVEAU_MEM_FREE 0x09
|
#define DRM_NOUVEAU_MEM_FREE 0x09
|
||||||
|
#define DRM_NOUVEAU_MEM_TILE 0x0a
|
||||||
|
|
||||||
#endif /* __NOUVEAU_DRM_H__ */
|
#endif /* __NOUVEAU_DRM_H__ */
|
||||||
|
|
|
@ -34,7 +34,7 @@
|
||||||
|
|
||||||
#define DRIVER_MAJOR 0
|
#define DRIVER_MAJOR 0
|
||||||
#define DRIVER_MINOR 0
|
#define DRIVER_MINOR 0
|
||||||
#define DRIVER_PATCHLEVEL 10
|
#define DRIVER_PATCHLEVEL 11
|
||||||
|
|
||||||
#define NOUVEAU_FAMILY 0x0000FFFF
|
#define NOUVEAU_FAMILY 0x0000FFFF
|
||||||
#define NOUVEAU_FLAGS 0xFFFF0000
|
#define NOUVEAU_FLAGS 0xFFFF0000
|
||||||
|
@ -385,6 +385,8 @@ extern int nouveau_ioctl_mem_alloc(struct drm_device *, void *data,
|
||||||
struct drm_file *);
|
struct drm_file *);
|
||||||
extern int nouveau_ioctl_mem_free(struct drm_device *, void *data,
|
extern int nouveau_ioctl_mem_free(struct drm_device *, void *data,
|
||||||
struct drm_file *);
|
struct drm_file *);
|
||||||
|
extern int nouveau_ioctl_mem_tile(struct drm_device *, void *data,
|
||||||
|
struct drm_file *);
|
||||||
extern struct mem_block* nouveau_mem_alloc(struct drm_device *,
|
extern struct mem_block* nouveau_mem_alloc(struct drm_device *,
|
||||||
int alignment, uint64_t size,
|
int alignment, uint64_t size,
|
||||||
int flags, struct drm_file *);
|
int flags, struct drm_file *);
|
||||||
|
|
|
@ -593,6 +593,7 @@ struct drm_ioctl_desc nouveau_ioctls[] = {
|
||||||
DRM_IOCTL_DEF(DRM_NOUVEAU_GPUOBJ_FREE, nouveau_ioctl_gpuobj_free, DRM_AUTH),
|
DRM_IOCTL_DEF(DRM_NOUVEAU_GPUOBJ_FREE, nouveau_ioctl_gpuobj_free, DRM_AUTH),
|
||||||
DRM_IOCTL_DEF(DRM_NOUVEAU_MEM_ALLOC, nouveau_ioctl_mem_alloc, DRM_AUTH),
|
DRM_IOCTL_DEF(DRM_NOUVEAU_MEM_ALLOC, nouveau_ioctl_mem_alloc, DRM_AUTH),
|
||||||
DRM_IOCTL_DEF(DRM_NOUVEAU_MEM_FREE, nouveau_ioctl_mem_free, DRM_AUTH),
|
DRM_IOCTL_DEF(DRM_NOUVEAU_MEM_FREE, nouveau_ioctl_mem_free, DRM_AUTH),
|
||||||
|
DRM_IOCTL_DEF(DRM_NOUVEAU_MEM_TILE, nouveau_ioctl_mem_tile, DRM_AUTH),
|
||||||
};
|
};
|
||||||
|
|
||||||
int nouveau_max_ioctl = DRM_ARRAY_SIZE(nouveau_ioctls);
|
int nouveau_max_ioctl = DRM_ARRAY_SIZE(nouveau_ioctls);
|
||||||
|
|
|
@ -606,8 +606,11 @@ nouveau_mem_alloc(struct drm_device *dev, int alignment, uint64_t size,
|
||||||
/* Align allocation sizes to 64KiB blocks on G8x. We use a 64KiB
|
/* Align allocation sizes to 64KiB blocks on G8x. We use a 64KiB
|
||||||
* page size in the GPU VM.
|
* page size in the GPU VM.
|
||||||
*/
|
*/
|
||||||
if (flags & NOUVEAU_MEM_FB && dev_priv->card_type >= NV_50)
|
if (flags & NOUVEAU_MEM_FB && dev_priv->card_type >= NV_50) {
|
||||||
size = (size + (64 * 1024)) & ~((64 * 1024) - 1);
|
size = (size + 65535) & ~65535;
|
||||||
|
if (alignment < 16)
|
||||||
|
alignment = 16;
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Warn about 0 sized allocations, but let it go through. It'll return 1 page
|
* Warn about 0 sized allocations, but let it go through. It'll return 1 page
|
||||||
|
@ -669,6 +672,7 @@ alloc_ok:
|
||||||
struct nouveau_gpuobj *pt = dev_priv->vm_vram_pt;
|
struct nouveau_gpuobj *pt = dev_priv->vm_vram_pt;
|
||||||
unsigned offset = block->start;
|
unsigned offset = block->start;
|
||||||
unsigned count = block->size / 65536;
|
unsigned count = block->size / 65536;
|
||||||
|
unsigned tile = 0;
|
||||||
|
|
||||||
if (!pt) {
|
if (!pt) {
|
||||||
DRM_ERROR("vm alloc without vm pt\n");
|
DRM_ERROR("vm alloc without vm pt\n");
|
||||||
|
@ -676,11 +680,22 @@ alloc_ok:
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* The tiling stuff is *not* what NVIDIA does - but both the
|
||||||
|
* 2D and 3D engines seem happy with this simpler method.
|
||||||
|
* Should look into why NVIDIA do what they do at some point.
|
||||||
|
*/
|
||||||
|
if (flags & NOUVEAU_MEM_TILE) {
|
||||||
|
if (flags & NOUVEAU_MEM_TILE_ZETA)
|
||||||
|
tile = 0x00002800;
|
||||||
|
else
|
||||||
|
tile = 0x00007000;
|
||||||
|
}
|
||||||
|
|
||||||
while (count--) {
|
while (count--) {
|
||||||
unsigned pte = offset / 65536;
|
unsigned pte = offset / 65536;
|
||||||
|
|
||||||
INSTANCE_WR(pt, (pte * 2) + 0, offset | 1);
|
INSTANCE_WR(pt, (pte * 2) + 0, offset | 1);
|
||||||
INSTANCE_WR(pt, (pte * 2) + 1, 0x00000000);
|
INSTANCE_WR(pt, (pte * 2) + 1, 0x00000000 | tile);
|
||||||
offset += 65536;
|
offset += 65536;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
@ -791,6 +806,7 @@ int
|
||||||
nouveau_ioctl_mem_alloc(struct drm_device *dev, void *data,
|
nouveau_ioctl_mem_alloc(struct drm_device *dev, void *data,
|
||||||
struct drm_file *file_priv)
|
struct drm_file *file_priv)
|
||||||
{
|
{
|
||||||
|
struct drm_nouveau_private *dev_priv = dev->dev_private;
|
||||||
struct drm_nouveau_mem_alloc *alloc = data;
|
struct drm_nouveau_mem_alloc *alloc = data;
|
||||||
struct mem_block *block;
|
struct mem_block *block;
|
||||||
|
|
||||||
|
@ -807,10 +823,15 @@ nouveau_ioctl_mem_alloc(struct drm_device *dev, void *data,
|
||||||
alloc->offset=block->start;
|
alloc->offset=block->start;
|
||||||
alloc->flags=block->flags;
|
alloc->flags=block->flags;
|
||||||
|
|
||||||
|
if (dev_priv->card_type >= NV_50 && alloc->flags & NOUVEAU_MEM_FB)
|
||||||
|
alloc->offset += 512*1024*1024;
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
int nouveau_ioctl_mem_free(struct drm_device *dev, void *data, struct drm_file *file_priv)
|
int
|
||||||
|
nouveau_ioctl_mem_free(struct drm_device *dev, void *data,
|
||||||
|
struct drm_file *file_priv)
|
||||||
{
|
{
|
||||||
struct drm_nouveau_private *dev_priv = dev->dev_private;
|
struct drm_nouveau_private *dev_priv = dev->dev_private;
|
||||||
struct drm_nouveau_mem_free *memfree = data;
|
struct drm_nouveau_mem_free *memfree = data;
|
||||||
|
@ -818,6 +839,9 @@ int nouveau_ioctl_mem_free(struct drm_device *dev, void *data, struct drm_file *
|
||||||
|
|
||||||
NOUVEAU_CHECK_INITIALISED_WITH_RETURN;
|
NOUVEAU_CHECK_INITIALISED_WITH_RETURN;
|
||||||
|
|
||||||
|
if (dev_priv->card_type >= NV_50 && memfree->flags & NOUVEAU_MEM_FB)
|
||||||
|
memfree->offset -= 512*1024*1024;
|
||||||
|
|
||||||
block=NULL;
|
block=NULL;
|
||||||
if (memfree->flags & NOUVEAU_MEM_FB)
|
if (memfree->flags & NOUVEAU_MEM_FB)
|
||||||
block = find_block(dev_priv->fb_heap, memfree->offset);
|
block = find_block(dev_priv->fb_heap, memfree->offset);
|
||||||
|
@ -833,3 +857,53 @@ int nouveau_ioctl_mem_free(struct drm_device *dev, void *data, struct drm_file *
|
||||||
nouveau_mem_free(dev, block);
|
nouveau_mem_free(dev, block);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
nouveau_ioctl_mem_tile(struct drm_device *dev, void *data,
|
||||||
|
struct drm_file *file_priv)
|
||||||
|
{
|
||||||
|
struct drm_nouveau_private *dev_priv = dev->dev_private;
|
||||||
|
struct drm_nouveau_mem_tile *memtile = data;
|
||||||
|
struct mem_block *block = NULL;
|
||||||
|
|
||||||
|
NOUVEAU_CHECK_INITIALISED_WITH_RETURN;
|
||||||
|
|
||||||
|
if (dev_priv->card_type < NV_50)
|
||||||
|
return -EINVAL;
|
||||||
|
|
||||||
|
if (memtile->flags & NOUVEAU_MEM_FB) {
|
||||||
|
memtile->offset -= 512*1024*1024;
|
||||||
|
block = find_block(dev_priv->fb_heap, memtile->offset);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!block)
|
||||||
|
return -EINVAL;
|
||||||
|
|
||||||
|
if (block->file_priv != file_priv)
|
||||||
|
return -EPERM;
|
||||||
|
|
||||||
|
{
|
||||||
|
struct nouveau_gpuobj *pt = dev_priv->vm_vram_pt;
|
||||||
|
unsigned offset = block->start + memtile->delta;
|
||||||
|
unsigned count = memtile->size / 65536;
|
||||||
|
unsigned tile = 0;
|
||||||
|
|
||||||
|
if (memtile->flags & NOUVEAU_MEM_TILE) {
|
||||||
|
if (memtile->flags & NOUVEAU_MEM_TILE_ZETA)
|
||||||
|
tile = 0x00002800;
|
||||||
|
else
|
||||||
|
tile = 0x00007000;
|
||||||
|
}
|
||||||
|
|
||||||
|
while (count--) {
|
||||||
|
unsigned pte = offset / 65536;
|
||||||
|
|
||||||
|
INSTANCE_WR(pt, (pte * 2) + 0, offset | 1);
|
||||||
|
INSTANCE_WR(pt, (pte * 2) + 1, 0x00000000 | tile);
|
||||||
|
offset += 65536;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
|
@ -1036,8 +1036,7 @@ nouveau_gpuobj_channel_init(struct nouveau_channel *chan,
|
||||||
/* VRAM ctxdma */
|
/* VRAM ctxdma */
|
||||||
if (dev_priv->card_type >= NV_50) {
|
if (dev_priv->card_type >= NV_50) {
|
||||||
ret = nouveau_gpuobj_dma_new(chan, NV_CLASS_DMA_IN_MEMORY,
|
ret = nouveau_gpuobj_dma_new(chan, NV_CLASS_DMA_IN_MEMORY,
|
||||||
512*1024*1024,
|
0, 0x100000000ULL,
|
||||||
dev_priv->fb_available_size,
|
|
||||||
NV_DMA_ACCESS_RW,
|
NV_DMA_ACCESS_RW,
|
||||||
NV_DMA_TARGET_AGP, &vram);
|
NV_DMA_TARGET_AGP, &vram);
|
||||||
if (ret) {
|
if (ret) {
|
||||||
|
@ -1059,6 +1058,9 @@ nouveau_gpuobj_channel_init(struct nouveau_channel *chan,
|
||||||
}
|
}
|
||||||
|
|
||||||
/* TT memory ctxdma */
|
/* TT memory ctxdma */
|
||||||
|
if (dev_priv->card_type >= NV_50) {
|
||||||
|
tt = vram;
|
||||||
|
} else
|
||||||
if (dev_priv->gart_info.type != NOUVEAU_GART_NONE) {
|
if (dev_priv->gart_info.type != NOUVEAU_GART_NONE) {
|
||||||
ret = nouveau_gpuobj_gart_dma_new(chan, 0,
|
ret = nouveau_gpuobj_gart_dma_new(chan, 0,
|
||||||
dev_priv->gart_info.aper_size,
|
dev_priv->gart_info.aper_size,
|
||||||
|
|
Loading…
Reference in New Issue