Merge branch 'drm-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/airlied/drm-2.6
* 'drm-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/airlied/drm-2.6: (133 commits) drm/vgaarb: add VGA arbitration support to the drm and kms. drm/radeon: some r420s have a CP race with the DMA engine. drm/radeon/r600/kms: rv670 is not DCE3 drm/radeon/kms: r420 idle after programming GA_ENHANCE drm/radeon/kms: more fixes to rv770 suspend/resume path. drm/radeon/kms: more alignment for rv770.c with r600.c drm/radeon/kms: rv770 blit init called too late. drm/radeon/kms: move around new init path code to avoid posting at init drm/radeon/r600: fix some issues with suspend/resume. drm/radeon/kms: disable VGA rendering engine before taking over VRAM drm/radeon/kms: Move radeon_get_clock_info() call out of radeon_clocks_init(). drm/radeon/kms: add initial connector properties drm/radeon/kms: Use surfaces for scanout / cursor byte swapping on big endian. drm/radeon/kms: don't fail if we fail to init GPU acceleration drm/r600/kms: fixup number of loops per blit calculation. drm/radeon/kms: reprogram format in set base. drm/radeon: avivo chips have no separate int bit for display drm/radeon/r600: don't do interrupts drm: fix _DRM_GEM addmap error message drm: update crtc x/y when only fb changes ... Fixed up trivial conflicts in firmware/Makefile due to network driver (cxgb3) and drm (mga/r128/radeon) firmware being listed next to each other.
This commit is contained in:
commit
44040f107e
165 changed files with 35577 additions and 41361 deletions
|
|
@ -18,6 +18,14 @@ menuconfig DRM
|
|||
details. You should also select and configure AGP
|
||||
(/dev/agpgart) support.
|
||||
|
||||
config DRM_KMS_HELPER
|
||||
tristate
|
||||
depends on DRM
|
||||
select FB
|
||||
select FRAMEBUFFER_CONSOLE if !EMBEDDED
|
||||
help
|
||||
FB and CRTC helpers for KMS drivers.
|
||||
|
||||
config DRM_TTM
|
||||
tristate
|
||||
depends on DRM
|
||||
|
|
@ -36,6 +44,7 @@ config DRM_TDFX
|
|||
config DRM_R128
|
||||
tristate "ATI Rage 128"
|
||||
depends on DRM && PCI
|
||||
select FW_LOADER
|
||||
help
|
||||
Choose this option if you have an ATI Rage 128 graphics card. If M
|
||||
is selected, the module will be called r128. AGP support for
|
||||
|
|
@ -47,8 +56,9 @@ config DRM_RADEON
|
|||
select FB_CFB_FILLRECT
|
||||
select FB_CFB_COPYAREA
|
||||
select FB_CFB_IMAGEBLIT
|
||||
select FB
|
||||
select FRAMEBUFFER_CONSOLE if !EMBEDDED
|
||||
select FW_LOADER
|
||||
select DRM_KMS_HELPER
|
||||
select DRM_TTM
|
||||
help
|
||||
Choose this option if you have an ATI Radeon graphics card. There
|
||||
are both PCI and AGP versions. You don't need to choose this to
|
||||
|
|
@ -82,11 +92,10 @@ config DRM_I830
|
|||
config DRM_I915
|
||||
tristate "i915 driver"
|
||||
depends on AGP_INTEL
|
||||
select DRM_KMS_HELPER
|
||||
select FB_CFB_FILLRECT
|
||||
select FB_CFB_COPYAREA
|
||||
select FB_CFB_IMAGEBLIT
|
||||
select FB
|
||||
select FRAMEBUFFER_CONSOLE if !EMBEDDED
|
||||
# i915 depends on ACPI_VIDEO when ACPI is enabled
|
||||
# but for select to work, need to select ACPI_VIDEO's dependencies, ick
|
||||
select VIDEO_OUTPUT_CONTROL if ACPI
|
||||
|
|
@ -116,6 +125,7 @@ endchoice
|
|||
config DRM_MGA
|
||||
tristate "Matrox g200/g400"
|
||||
depends on DRM
|
||||
select FW_LOADER
|
||||
help
|
||||
Choose this option if you have a Matrox G200, G400 or G450 graphics
|
||||
card. If M is selected, the module will be called mga. AGP
|
||||
|
|
|
|||
|
|
@ -10,11 +10,15 @@ drm-y := drm_auth.o drm_bufs.o drm_cache.o \
|
|||
drm_lock.o drm_memory.o drm_proc.o drm_stub.o drm_vm.o \
|
||||
drm_agpsupport.o drm_scatter.o ati_pcigart.o drm_pci.o \
|
||||
drm_sysfs.o drm_hashtab.o drm_sman.o drm_mm.o \
|
||||
drm_crtc.o drm_crtc_helper.o drm_modes.o drm_edid.o \
|
||||
drm_info.o drm_debugfs.o
|
||||
drm_crtc.o drm_modes.o drm_edid.o \
|
||||
drm_info.o drm_debugfs.o drm_encoder_slave.o
|
||||
|
||||
drm-$(CONFIG_COMPAT) += drm_ioc32.o
|
||||
|
||||
drm_kms_helper-y := drm_fb_helper.o drm_crtc_helper.o
|
||||
|
||||
obj-$(CONFIG_DRM_KMS_HELPER) += drm_kms_helper.o
|
||||
|
||||
obj-$(CONFIG_DRM) += drm.o
|
||||
obj-$(CONFIG_DRM_TTM) += ttm/
|
||||
obj-$(CONFIG_DRM_TDFX) += tdfx/
|
||||
|
|
|
|||
|
|
@ -310,10 +310,10 @@ static int drm_addmap_core(struct drm_device * dev, resource_size_t offset,
|
|||
(unsigned long long)map->offset, map->size);
|
||||
|
||||
break;
|
||||
case _DRM_GEM:
|
||||
DRM_ERROR("tried to rmmap GEM object\n");
|
||||
break;
|
||||
}
|
||||
case _DRM_GEM:
|
||||
DRM_ERROR("tried to addmap GEM object\n");
|
||||
break;
|
||||
case _DRM_SCATTER_GATHER:
|
||||
if (!dev->sg) {
|
||||
kfree(map);
|
||||
|
|
|
|||
|
|
@ -45,6 +45,23 @@ drm_clflush_page(struct page *page)
|
|||
clflush(page_virtual + i);
|
||||
kunmap_atomic(page_virtual, KM_USER0);
|
||||
}
|
||||
|
||||
static void drm_cache_flush_clflush(struct page *pages[],
|
||||
unsigned long num_pages)
|
||||
{
|
||||
unsigned long i;
|
||||
|
||||
mb();
|
||||
for (i = 0; i < num_pages; i++)
|
||||
drm_clflush_page(*pages++);
|
||||
mb();
|
||||
}
|
||||
|
||||
static void
|
||||
drm_clflush_ipi_handler(void *null)
|
||||
{
|
||||
wbinvd();
|
||||
}
|
||||
#endif
|
||||
|
||||
void
|
||||
|
|
@ -53,17 +70,30 @@ drm_clflush_pages(struct page *pages[], unsigned long num_pages)
|
|||
|
||||
#if defined(CONFIG_X86)
|
||||
if (cpu_has_clflush) {
|
||||
unsigned long i;
|
||||
|
||||
mb();
|
||||
for (i = 0; i < num_pages; ++i)
|
||||
drm_clflush_page(*pages++);
|
||||
mb();
|
||||
|
||||
drm_cache_flush_clflush(pages, num_pages);
|
||||
return;
|
||||
}
|
||||
|
||||
wbinvd();
|
||||
if (on_each_cpu(drm_clflush_ipi_handler, NULL, 1) != 0)
|
||||
printk(KERN_ERR "Timed out waiting for cache flush.\n");
|
||||
|
||||
#elif defined(__powerpc__)
|
||||
unsigned long i;
|
||||
for (i = 0; i < num_pages; i++) {
|
||||
struct page *page = pages[i];
|
||||
void *page_virtual;
|
||||
|
||||
if (unlikely(page == NULL))
|
||||
continue;
|
||||
|
||||
page_virtual = kmap_atomic(page, KM_USER0);
|
||||
flush_dcache_range((unsigned long)page_virtual,
|
||||
(unsigned long)page_virtual + PAGE_SIZE);
|
||||
kunmap_atomic(page_virtual, KM_USER0);
|
||||
}
|
||||
#else
|
||||
printk(KERN_ERR "Architecture has no drm_cache.c support\n");
|
||||
WARN_ON_ONCE(1);
|
||||
#endif
|
||||
}
|
||||
EXPORT_SYMBOL(drm_clflush_pages);
|
||||
|
|
|
|||
|
|
@ -68,10 +68,10 @@ DRM_ENUM_NAME_FN(drm_get_dpms_name, drm_dpms_enum_list)
|
|||
*/
|
||||
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" },
|
||||
{ DRM_MODE_SCALE_NONE, "None" },
|
||||
{ DRM_MODE_SCALE_FULLSCREEN, "Full" },
|
||||
{ DRM_MODE_SCALE_CENTER, "Center" },
|
||||
{ DRM_MODE_SCALE_ASPECT, "Full aspect" },
|
||||
};
|
||||
|
||||
static struct drm_prop_enum_list drm_dithering_mode_enum_list[] =
|
||||
|
|
@ -108,6 +108,7 @@ static struct drm_prop_enum_list drm_tv_select_enum_list[] =
|
|||
{ DRM_MODE_SUBCONNECTOR_Composite, "Composite" }, /* TV-out */
|
||||
{ DRM_MODE_SUBCONNECTOR_SVIDEO, "SVIDEO" }, /* TV-out */
|
||||
{ DRM_MODE_SUBCONNECTOR_Component, "Component" }, /* TV-out */
|
||||
{ DRM_MODE_SUBCONNECTOR_SCART, "SCART" }, /* TV-out */
|
||||
};
|
||||
|
||||
DRM_ENUM_NAME_FN(drm_get_tv_select_name, drm_tv_select_enum_list)
|
||||
|
|
@ -118,6 +119,7 @@ static struct drm_prop_enum_list drm_tv_subconnector_enum_list[] =
|
|||
{ DRM_MODE_SUBCONNECTOR_Composite, "Composite" }, /* TV-out */
|
||||
{ DRM_MODE_SUBCONNECTOR_SVIDEO, "SVIDEO" }, /* TV-out */
|
||||
{ DRM_MODE_SUBCONNECTOR_Component, "Component" }, /* TV-out */
|
||||
{ DRM_MODE_SUBCONNECTOR_SCART, "SCART" }, /* TV-out */
|
||||
};
|
||||
|
||||
DRM_ENUM_NAME_FN(drm_get_tv_subconnector_name,
|
||||
|
|
@ -146,6 +148,7 @@ static struct drm_conn_prop_enum_list drm_connector_enum_list[] =
|
|||
{ DRM_MODE_CONNECTOR_DisplayPort, "DisplayPort", 0 },
|
||||
{ DRM_MODE_CONNECTOR_HDMIA, "HDMI Type A", 0 },
|
||||
{ DRM_MODE_CONNECTOR_HDMIB, "HDMI Type B", 0 },
|
||||
{ DRM_MODE_CONNECTOR_TV, "TV", 0 },
|
||||
};
|
||||
|
||||
static struct drm_prop_enum_list drm_encoder_enum_list[] =
|
||||
|
|
@ -165,6 +168,7 @@ char *drm_get_encoder_name(struct drm_encoder *encoder)
|
|||
encoder->base.id);
|
||||
return buf;
|
||||
}
|
||||
EXPORT_SYMBOL(drm_get_encoder_name);
|
||||
|
||||
char *drm_get_connector_name(struct drm_connector *connector)
|
||||
{
|
||||
|
|
@ -699,6 +703,42 @@ int drm_mode_create_tv_properties(struct drm_device *dev, int num_modes,
|
|||
drm_property_add_enum(dev->mode_config.tv_mode_property, i,
|
||||
i, modes[i]);
|
||||
|
||||
dev->mode_config.tv_brightness_property =
|
||||
drm_property_create(dev, DRM_MODE_PROP_RANGE,
|
||||
"brightness", 2);
|
||||
dev->mode_config.tv_brightness_property->values[0] = 0;
|
||||
dev->mode_config.tv_brightness_property->values[1] = 100;
|
||||
|
||||
dev->mode_config.tv_contrast_property =
|
||||
drm_property_create(dev, DRM_MODE_PROP_RANGE,
|
||||
"contrast", 2);
|
||||
dev->mode_config.tv_contrast_property->values[0] = 0;
|
||||
dev->mode_config.tv_contrast_property->values[1] = 100;
|
||||
|
||||
dev->mode_config.tv_flicker_reduction_property =
|
||||
drm_property_create(dev, DRM_MODE_PROP_RANGE,
|
||||
"flicker reduction", 2);
|
||||
dev->mode_config.tv_flicker_reduction_property->values[0] = 0;
|
||||
dev->mode_config.tv_flicker_reduction_property->values[1] = 100;
|
||||
|
||||
dev->mode_config.tv_overscan_property =
|
||||
drm_property_create(dev, DRM_MODE_PROP_RANGE,
|
||||
"overscan", 2);
|
||||
dev->mode_config.tv_overscan_property->values[0] = 0;
|
||||
dev->mode_config.tv_overscan_property->values[1] = 100;
|
||||
|
||||
dev->mode_config.tv_saturation_property =
|
||||
drm_property_create(dev, DRM_MODE_PROP_RANGE,
|
||||
"saturation", 2);
|
||||
dev->mode_config.tv_saturation_property->values[0] = 0;
|
||||
dev->mode_config.tv_saturation_property->values[1] = 100;
|
||||
|
||||
dev->mode_config.tv_hue_property =
|
||||
drm_property_create(dev, DRM_MODE_PROP_RANGE,
|
||||
"hue", 2);
|
||||
dev->mode_config.tv_hue_property->values[0] = 0;
|
||||
dev->mode_config.tv_hue_property->values[1] = 100;
|
||||
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL(drm_mode_create_tv_properties);
|
||||
|
|
@ -1044,7 +1084,7 @@ int drm_mode_getresources(struct drm_device *dev, void *data,
|
|||
if (file_priv->master->minor->type == DRM_MINOR_CONTROL) {
|
||||
list_for_each_entry(crtc, &dev->mode_config.crtc_list,
|
||||
head) {
|
||||
DRM_DEBUG("CRTC ID is %d\n", crtc->base.id);
|
||||
DRM_DEBUG_KMS("CRTC ID is %d\n", crtc->base.id);
|
||||
if (put_user(crtc->base.id, crtc_id + copied)) {
|
||||
ret = -EFAULT;
|
||||
goto out;
|
||||
|
|
@ -1072,7 +1112,7 @@ int drm_mode_getresources(struct drm_device *dev, void *data,
|
|||
list_for_each_entry(encoder,
|
||||
&dev->mode_config.encoder_list,
|
||||
head) {
|
||||
DRM_DEBUG("ENCODER ID is %d\n",
|
||||
DRM_DEBUG_KMS("ENCODER ID is %d\n",
|
||||
encoder->base.id);
|
||||
if (put_user(encoder->base.id, encoder_id +
|
||||
copied)) {
|
||||
|
|
@ -1103,7 +1143,7 @@ int drm_mode_getresources(struct drm_device *dev, void *data,
|
|||
list_for_each_entry(connector,
|
||||
&dev->mode_config.connector_list,
|
||||
head) {
|
||||
DRM_DEBUG("CONNECTOR ID is %d\n",
|
||||
DRM_DEBUG_KMS("CONNECTOR ID is %d\n",
|
||||
connector->base.id);
|
||||
if (put_user(connector->base.id,
|
||||
connector_id + copied)) {
|
||||
|
|
@ -1127,7 +1167,7 @@ int drm_mode_getresources(struct drm_device *dev, void *data,
|
|||
}
|
||||
card_res->count_connectors = connector_count;
|
||||
|
||||
DRM_DEBUG("Counted %d %d %d\n", card_res->count_crtcs,
|
||||
DRM_DEBUG_KMS("Counted %d %d %d\n", card_res->count_crtcs,
|
||||
card_res->count_connectors, card_res->count_encoders);
|
||||
|
||||
out:
|
||||
|
|
@ -1230,7 +1270,7 @@ int drm_mode_getconnector(struct drm_device *dev, void *data,
|
|||
|
||||
memset(&u_mode, 0, sizeof(struct drm_mode_modeinfo));
|
||||
|
||||
DRM_DEBUG("connector id %d:\n", out_resp->connector_id);
|
||||
DRM_DEBUG_KMS("connector id %d:\n", out_resp->connector_id);
|
||||
|
||||
mutex_lock(&dev->mode_config.mutex);
|
||||
|
||||
|
|
@ -1406,7 +1446,7 @@ int drm_mode_setcrtc(struct drm_device *dev, void *data,
|
|||
obj = drm_mode_object_find(dev, crtc_req->crtc_id,
|
||||
DRM_MODE_OBJECT_CRTC);
|
||||
if (!obj) {
|
||||
DRM_DEBUG("Unknown CRTC ID %d\n", crtc_req->crtc_id);
|
||||
DRM_DEBUG_KMS("Unknown CRTC ID %d\n", crtc_req->crtc_id);
|
||||
ret = -EINVAL;
|
||||
goto out;
|
||||
}
|
||||
|
|
@ -1419,7 +1459,8 @@ int drm_mode_setcrtc(struct drm_device *dev, void *data,
|
|||
list_for_each_entry(crtcfb,
|
||||
&dev->mode_config.crtc_list, head) {
|
||||
if (crtcfb == crtc) {
|
||||
DRM_DEBUG("Using current fb for setmode\n");
|
||||
DRM_DEBUG_KMS("Using current fb for "
|
||||
"setmode\n");
|
||||
fb = crtc->fb;
|
||||
}
|
||||
}
|
||||
|
|
@ -1427,7 +1468,8 @@ int drm_mode_setcrtc(struct drm_device *dev, void *data,
|
|||
obj = drm_mode_object_find(dev, crtc_req->fb_id,
|
||||
DRM_MODE_OBJECT_FB);
|
||||
if (!obj) {
|
||||
DRM_DEBUG("Unknown FB ID%d\n", crtc_req->fb_id);
|
||||
DRM_DEBUG_KMS("Unknown FB ID%d\n",
|
||||
crtc_req->fb_id);
|
||||
ret = -EINVAL;
|
||||
goto out;
|
||||
}
|
||||
|
|
@ -1440,13 +1482,13 @@ int drm_mode_setcrtc(struct drm_device *dev, void *data,
|
|||
}
|
||||
|
||||
if (crtc_req->count_connectors == 0 && mode) {
|
||||
DRM_DEBUG("Count connectors is 0 but mode set\n");
|
||||
DRM_DEBUG_KMS("Count connectors is 0 but mode set\n");
|
||||
ret = -EINVAL;
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (crtc_req->count_connectors > 0 && (!mode || !fb)) {
|
||||
DRM_DEBUG("Count connectors is %d but no mode or fb set\n",
|
||||
DRM_DEBUG_KMS("Count connectors is %d but no mode or fb set\n",
|
||||
crtc_req->count_connectors);
|
||||
ret = -EINVAL;
|
||||
goto out;
|
||||
|
|
@ -1479,7 +1521,8 @@ int drm_mode_setcrtc(struct drm_device *dev, void *data,
|
|||
obj = drm_mode_object_find(dev, out_id,
|
||||
DRM_MODE_OBJECT_CONNECTOR);
|
||||
if (!obj) {
|
||||
DRM_DEBUG("Connector id %d unknown\n", out_id);
|
||||
DRM_DEBUG_KMS("Connector id %d unknown\n",
|
||||
out_id);
|
||||
ret = -EINVAL;
|
||||
goto out;
|
||||
}
|
||||
|
|
@ -1512,7 +1555,7 @@ int drm_mode_cursor_ioctl(struct drm_device *dev,
|
|||
struct drm_crtc *crtc;
|
||||
int ret = 0;
|
||||
|
||||
DRM_DEBUG("\n");
|
||||
DRM_DEBUG_KMS("\n");
|
||||
|
||||
if (!req->flags) {
|
||||
DRM_ERROR("no operation set\n");
|
||||
|
|
@ -1522,7 +1565,7 @@ int drm_mode_cursor_ioctl(struct drm_device *dev,
|
|||
mutex_lock(&dev->mode_config.mutex);
|
||||
obj = drm_mode_object_find(dev, req->crtc_id, DRM_MODE_OBJECT_CRTC);
|
||||
if (!obj) {
|
||||
DRM_DEBUG("Unknown CRTC ID %d\n", req->crtc_id);
|
||||
DRM_DEBUG_KMS("Unknown CRTC ID %d\n", req->crtc_id);
|
||||
ret = -EINVAL;
|
||||
goto out;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -33,15 +33,6 @@
|
|||
#include "drm_crtc.h"
|
||||
#include "drm_crtc_helper.h"
|
||||
|
||||
/*
|
||||
* Detailed mode info for 800x600@60Hz
|
||||
*/
|
||||
static struct drm_display_mode std_modes[] = {
|
||||
{ DRM_MODE("800x600", DRM_MODE_TYPE_DEFAULT, 40000, 800, 840,
|
||||
968, 1056, 0, 600, 601, 605, 628, 0,
|
||||
DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC) },
|
||||
};
|
||||
|
||||
static void drm_mode_validate_flag(struct drm_connector *connector,
|
||||
int flags)
|
||||
{
|
||||
|
|
@ -94,7 +85,7 @@ int drm_helper_probe_single_connector_modes(struct drm_connector *connector,
|
|||
int count = 0;
|
||||
int mode_flags = 0;
|
||||
|
||||
DRM_DEBUG("%s\n", drm_get_connector_name(connector));
|
||||
DRM_DEBUG_KMS("%s\n", drm_get_connector_name(connector));
|
||||
/* set all modes to the unverified state */
|
||||
list_for_each_entry_safe(mode, t, &connector->modes, head)
|
||||
mode->status = MODE_UNVERIFIED;
|
||||
|
|
@ -102,15 +93,17 @@ int drm_helper_probe_single_connector_modes(struct drm_connector *connector,
|
|||
connector->status = connector->funcs->detect(connector);
|
||||
|
||||
if (connector->status == connector_status_disconnected) {
|
||||
DRM_DEBUG("%s is disconnected\n",
|
||||
DRM_DEBUG_KMS("%s is disconnected\n",
|
||||
drm_get_connector_name(connector));
|
||||
/* TODO set EDID to NULL */
|
||||
return 0;
|
||||
goto prune;
|
||||
}
|
||||
|
||||
count = (*connector_funcs->get_modes)(connector);
|
||||
if (!count)
|
||||
return 0;
|
||||
if (!count) {
|
||||
count = drm_add_modes_noedid(connector, 800, 600);
|
||||
if (!count)
|
||||
return 0;
|
||||
}
|
||||
|
||||
drm_mode_connector_list_update(connector);
|
||||
|
||||
|
|
@ -130,7 +123,7 @@ int drm_helper_probe_single_connector_modes(struct drm_connector *connector,
|
|||
mode);
|
||||
}
|
||||
|
||||
|
||||
prune:
|
||||
drm_mode_prune_invalid(dev, &connector->modes, true);
|
||||
|
||||
if (list_empty(&connector->modes))
|
||||
|
|
@ -138,7 +131,8 @@ int drm_helper_probe_single_connector_modes(struct drm_connector *connector,
|
|||
|
||||
drm_mode_sort(&connector->modes);
|
||||
|
||||
DRM_DEBUG("Probed modes for %s\n", drm_get_connector_name(connector));
|
||||
DRM_DEBUG_KMS("Probed modes for %s\n",
|
||||
drm_get_connector_name(connector));
|
||||
list_for_each_entry_safe(mode, t, &connector->modes, head) {
|
||||
mode->vrefresh = drm_mode_vrefresh(mode);
|
||||
|
||||
|
|
@ -165,39 +159,6 @@ int drm_helper_probe_connector_modes(struct drm_device *dev, uint32_t maxX,
|
|||
}
|
||||
EXPORT_SYMBOL(drm_helper_probe_connector_modes);
|
||||
|
||||
static void drm_helper_add_std_modes(struct drm_device *dev,
|
||||
struct drm_connector *connector)
|
||||
{
|
||||
struct drm_display_mode *mode, *t;
|
||||
int i;
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(std_modes); i++) {
|
||||
struct drm_display_mode *stdmode;
|
||||
|
||||
/*
|
||||
* When no valid EDID modes are available we end up
|
||||
* here and bailed in the past, now we add some standard
|
||||
* modes and move on.
|
||||
*/
|
||||
stdmode = drm_mode_duplicate(dev, &std_modes[i]);
|
||||
drm_mode_probed_add(connector, stdmode);
|
||||
drm_mode_list_concat(&connector->probed_modes,
|
||||
&connector->modes);
|
||||
|
||||
DRM_DEBUG("Adding mode %s to %s\n", stdmode->name,
|
||||
drm_get_connector_name(connector));
|
||||
}
|
||||
drm_mode_sort(&connector->modes);
|
||||
|
||||
DRM_DEBUG("Added std modes on %s\n", drm_get_connector_name(connector));
|
||||
list_for_each_entry_safe(mode, t, &connector->modes, head) {
|
||||
mode->vrefresh = drm_mode_vrefresh(mode);
|
||||
|
||||
drm_mode_set_crtcinfo(mode, CRTC_INTERLACE_HALVE_V);
|
||||
drm_mode_debug_printmodeline(mode);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* drm_helper_encoder_in_use - check if a given encoder is in use
|
||||
* @encoder: encoder to check
|
||||
|
|
@ -258,13 +219,27 @@ EXPORT_SYMBOL(drm_helper_crtc_in_use);
|
|||
void drm_helper_disable_unused_functions(struct drm_device *dev)
|
||||
{
|
||||
struct drm_encoder *encoder;
|
||||
struct drm_connector *connector;
|
||||
struct drm_encoder_helper_funcs *encoder_funcs;
|
||||
struct drm_crtc *crtc;
|
||||
|
||||
list_for_each_entry(connector, &dev->mode_config.connector_list, head) {
|
||||
if (!connector->encoder)
|
||||
continue;
|
||||
if (connector->status == connector_status_disconnected)
|
||||
connector->encoder = NULL;
|
||||
}
|
||||
|
||||
list_for_each_entry(encoder, &dev->mode_config.encoder_list, head) {
|
||||
encoder_funcs = encoder->helper_private;
|
||||
if (!drm_helper_encoder_in_use(encoder))
|
||||
(*encoder_funcs->dpms)(encoder, DRM_MODE_DPMS_OFF);
|
||||
if (!drm_helper_encoder_in_use(encoder)) {
|
||||
if (encoder_funcs->disable)
|
||||
(*encoder_funcs->disable)(encoder);
|
||||
else
|
||||
(*encoder_funcs->dpms)(encoder, DRM_MODE_DPMS_OFF);
|
||||
/* disconnector encoder from any connector */
|
||||
encoder->crtc = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) {
|
||||
|
|
@ -312,7 +287,7 @@ static void drm_enable_connectors(struct drm_device *dev, bool *enabled)
|
|||
|
||||
list_for_each_entry(connector, &dev->mode_config.connector_list, head) {
|
||||
enabled[i] = drm_connector_enabled(connector, true);
|
||||
DRM_DEBUG("connector %d enabled? %s\n", connector->base.id,
|
||||
DRM_DEBUG_KMS("connector %d enabled? %s\n", connector->base.id,
|
||||
enabled[i] ? "yes" : "no");
|
||||
any_enabled |= enabled[i];
|
||||
i++;
|
||||
|
|
@ -342,7 +317,7 @@ static bool drm_target_preferred(struct drm_device *dev,
|
|||
continue;
|
||||
}
|
||||
|
||||
DRM_DEBUG("looking for preferred mode on connector %d\n",
|
||||
DRM_DEBUG_KMS("looking for preferred mode on connector %d\n",
|
||||
connector->base.id);
|
||||
|
||||
modes[i] = drm_has_preferred_mode(connector, width, height);
|
||||
|
|
@ -351,7 +326,7 @@ static bool drm_target_preferred(struct drm_device *dev,
|
|||
list_for_each_entry(modes[i], &connector->modes, head)
|
||||
break;
|
||||
}
|
||||
DRM_DEBUG("found mode %s\n", modes[i] ? modes[i]->name :
|
||||
DRM_DEBUG_KMS("found mode %s\n", modes[i] ? modes[i]->name :
|
||||
"none");
|
||||
i++;
|
||||
}
|
||||
|
|
@ -409,7 +384,7 @@ static int drm_pick_crtcs(struct drm_device *dev,
|
|||
c = 0;
|
||||
list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) {
|
||||
|
||||
if ((connector->encoder->possible_crtcs & (1 << c)) == 0) {
|
||||
if ((encoder->possible_crtcs & (1 << c)) == 0) {
|
||||
c++;
|
||||
continue;
|
||||
}
|
||||
|
|
@ -452,7 +427,7 @@ static void drm_setup_crtcs(struct drm_device *dev)
|
|||
int width, height;
|
||||
int i, ret;
|
||||
|
||||
DRM_DEBUG("\n");
|
||||
DRM_DEBUG_KMS("\n");
|
||||
|
||||
width = dev->mode_config.max_width;
|
||||
height = dev->mode_config.max_height;
|
||||
|
|
@ -475,7 +450,7 @@ static void drm_setup_crtcs(struct drm_device *dev)
|
|||
if (!ret)
|
||||
DRM_ERROR("Unable to find initial modes\n");
|
||||
|
||||
DRM_DEBUG("picking CRTCs for %dx%d config\n", width, height);
|
||||
DRM_DEBUG_KMS("picking CRTCs for %dx%d config\n", width, height);
|
||||
|
||||
drm_pick_crtcs(dev, crtcs, modes, 0, width, height);
|
||||
|
||||
|
|
@ -490,12 +465,14 @@ static void drm_setup_crtcs(struct drm_device *dev)
|
|||
}
|
||||
|
||||
if (mode && crtc) {
|
||||
DRM_DEBUG("desired mode %s set on crtc %d\n",
|
||||
DRM_DEBUG_KMS("desired mode %s set on crtc %d\n",
|
||||
mode->name, crtc->base.id);
|
||||
crtc->desired_mode = mode;
|
||||
connector->encoder->crtc = crtc;
|
||||
} else
|
||||
} else {
|
||||
connector->encoder->crtc = NULL;
|
||||
connector->encoder = NULL;
|
||||
}
|
||||
i++;
|
||||
}
|
||||
|
||||
|
|
@ -702,18 +679,17 @@ EXPORT_SYMBOL(drm_crtc_helper_set_mode);
|
|||
int drm_crtc_helper_set_config(struct drm_mode_set *set)
|
||||
{
|
||||
struct drm_device *dev;
|
||||
struct drm_crtc **save_crtcs, *new_crtc;
|
||||
struct drm_encoder **save_encoders, *new_encoder;
|
||||
struct drm_crtc *save_crtcs, *new_crtc, *crtc;
|
||||
struct drm_encoder *save_encoders, *new_encoder, *encoder;
|
||||
struct drm_framebuffer *old_fb = NULL;
|
||||
bool save_enabled;
|
||||
bool mode_changed = false; /* if true do a full mode set */
|
||||
bool fb_changed = false; /* if true and !mode_changed just do a flip */
|
||||
struct drm_connector *connector;
|
||||
struct drm_connector *save_connectors, *connector;
|
||||
int count = 0, ro, fail = 0;
|
||||
struct drm_crtc_helper_funcs *crtc_funcs;
|
||||
int ret = 0;
|
||||
|
||||
DRM_DEBUG("\n");
|
||||
DRM_DEBUG_KMS("\n");
|
||||
|
||||
if (!set)
|
||||
return -EINVAL;
|
||||
|
|
@ -726,37 +702,60 @@ int drm_crtc_helper_set_config(struct drm_mode_set *set)
|
|||
|
||||
crtc_funcs = set->crtc->helper_private;
|
||||
|
||||
DRM_DEBUG("crtc: %p %d fb: %p connectors: %p num_connectors: %d (x, y) (%i, %i)\n",
|
||||
DRM_DEBUG_KMS("crtc: %p %d fb: %p connectors: %p num_connectors:"
|
||||
" %d (x, y) (%i, %i)\n",
|
||||
set->crtc, set->crtc->base.id, set->fb, set->connectors,
|
||||
(int)set->num_connectors, set->x, set->y);
|
||||
|
||||
dev = set->crtc->dev;
|
||||
|
||||
/* save previous config */
|
||||
save_enabled = set->crtc->enabled;
|
||||
|
||||
/*
|
||||
* We do mode_config.num_connectors here since we'll look at the
|
||||
* CRTC and encoder associated with each connector later.
|
||||
*/
|
||||
save_crtcs = kzalloc(dev->mode_config.num_connector *
|
||||
sizeof(struct drm_crtc *), GFP_KERNEL);
|
||||
/* Allocate space for the backup of all (non-pointer) crtc, encoder and
|
||||
* connector data. */
|
||||
save_crtcs = kzalloc(dev->mode_config.num_crtc *
|
||||
sizeof(struct drm_crtc), GFP_KERNEL);
|
||||
if (!save_crtcs)
|
||||
return -ENOMEM;
|
||||
|
||||
save_encoders = kzalloc(dev->mode_config.num_connector *
|
||||
sizeof(struct drm_encoders *), GFP_KERNEL);
|
||||
save_encoders = kzalloc(dev->mode_config.num_encoder *
|
||||
sizeof(struct drm_encoder), GFP_KERNEL);
|
||||
if (!save_encoders) {
|
||||
kfree(save_crtcs);
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
save_connectors = kzalloc(dev->mode_config.num_connector *
|
||||
sizeof(struct drm_connector), GFP_KERNEL);
|
||||
if (!save_connectors) {
|
||||
kfree(save_crtcs);
|
||||
kfree(save_encoders);
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
/* Copy data. Note that driver private data is not affected.
|
||||
* Should anything bad happen only the expected state is
|
||||
* restored, not the drivers personal bookkeeping.
|
||||
*/
|
||||
count = 0;
|
||||
list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) {
|
||||
save_crtcs[count++] = *crtc;
|
||||
}
|
||||
|
||||
count = 0;
|
||||
list_for_each_entry(encoder, &dev->mode_config.encoder_list, head) {
|
||||
save_encoders[count++] = *encoder;
|
||||
}
|
||||
|
||||
count = 0;
|
||||
list_for_each_entry(connector, &dev->mode_config.connector_list, head) {
|
||||
save_connectors[count++] = *connector;
|
||||
}
|
||||
|
||||
/* We should be able to check here if the fb has the same properties
|
||||
* and then just flip_or_move it */
|
||||
if (set->crtc->fb != set->fb) {
|
||||
/* If we have no fb then treat it as a full mode set */
|
||||
if (set->crtc->fb == NULL) {
|
||||
DRM_DEBUG("crtc has no fb, full mode set\n");
|
||||
DRM_DEBUG_KMS("crtc has no fb, full mode set\n");
|
||||
mode_changed = true;
|
||||
} else if (set->fb == NULL) {
|
||||
mode_changed = true;
|
||||
|
|
@ -772,7 +771,7 @@ int drm_crtc_helper_set_config(struct drm_mode_set *set)
|
|||
fb_changed = true;
|
||||
|
||||
if (set->mode && !drm_mode_equal(set->mode, &set->crtc->mode)) {
|
||||
DRM_DEBUG("modes are different, full mode set\n");
|
||||
DRM_DEBUG_KMS("modes are different, full mode set\n");
|
||||
drm_mode_debug_printmodeline(&set->crtc->mode);
|
||||
drm_mode_debug_printmodeline(set->mode);
|
||||
mode_changed = true;
|
||||
|
|
@ -783,7 +782,6 @@ int drm_crtc_helper_set_config(struct drm_mode_set *set)
|
|||
list_for_each_entry(connector, &dev->mode_config.connector_list, head) {
|
||||
struct drm_connector_helper_funcs *connector_funcs =
|
||||
connector->helper_private;
|
||||
save_encoders[count++] = connector->encoder;
|
||||
new_encoder = connector->encoder;
|
||||
for (ro = 0; ro < set->num_connectors; ro++) {
|
||||
if (set->connectors[ro] == connector) {
|
||||
|
|
@ -798,15 +796,20 @@ int drm_crtc_helper_set_config(struct drm_mode_set *set)
|
|||
}
|
||||
|
||||
if (new_encoder != connector->encoder) {
|
||||
DRM_DEBUG("encoder changed, full mode switch\n");
|
||||
DRM_DEBUG_KMS("encoder changed, full mode switch\n");
|
||||
mode_changed = true;
|
||||
/* If the encoder is reused for another connector, then
|
||||
* the appropriate crtc will be set later.
|
||||
*/
|
||||
if (connector->encoder)
|
||||
connector->encoder->crtc = NULL;
|
||||
connector->encoder = new_encoder;
|
||||
}
|
||||
}
|
||||
|
||||
if (fail) {
|
||||
ret = -EINVAL;
|
||||
goto fail_no_encoder;
|
||||
goto fail;
|
||||
}
|
||||
|
||||
count = 0;
|
||||
|
|
@ -814,8 +817,6 @@ int drm_crtc_helper_set_config(struct drm_mode_set *set)
|
|||
if (!connector->encoder)
|
||||
continue;
|
||||
|
||||
save_crtcs[count++] = connector->encoder->crtc;
|
||||
|
||||
if (connector->encoder->crtc == set->crtc)
|
||||
new_crtc = NULL;
|
||||
else
|
||||
|
|
@ -830,14 +831,14 @@ int drm_crtc_helper_set_config(struct drm_mode_set *set)
|
|||
if (new_crtc &&
|
||||
!drm_encoder_crtc_ok(connector->encoder, new_crtc)) {
|
||||
ret = -EINVAL;
|
||||
goto fail_set_mode;
|
||||
goto fail;
|
||||
}
|
||||
if (new_crtc != connector->encoder->crtc) {
|
||||
DRM_DEBUG("crtc changed, full mode switch\n");
|
||||
DRM_DEBUG_KMS("crtc changed, full mode switch\n");
|
||||
mode_changed = true;
|
||||
connector->encoder->crtc = new_crtc;
|
||||
}
|
||||
DRM_DEBUG("setting connector %d crtc to %p\n",
|
||||
DRM_DEBUG_KMS("setting connector %d crtc to %p\n",
|
||||
connector->base.id, new_crtc);
|
||||
}
|
||||
|
||||
|
|
@ -850,7 +851,8 @@ int drm_crtc_helper_set_config(struct drm_mode_set *set)
|
|||
set->crtc->fb = set->fb;
|
||||
set->crtc->enabled = (set->mode != NULL);
|
||||
if (set->mode != NULL) {
|
||||
DRM_DEBUG("attempting to set mode from userspace\n");
|
||||
DRM_DEBUG_KMS("attempting to set mode from"
|
||||
" userspace\n");
|
||||
drm_mode_debug_printmodeline(set->mode);
|
||||
if (!drm_crtc_helper_set_mode(set->crtc, set->mode,
|
||||
set->x, set->y,
|
||||
|
|
@ -858,7 +860,7 @@ int drm_crtc_helper_set_config(struct drm_mode_set *set)
|
|||
DRM_ERROR("failed to set mode on crtc %p\n",
|
||||
set->crtc);
|
||||
ret = -EINVAL;
|
||||
goto fail_set_mode;
|
||||
goto fail;
|
||||
}
|
||||
/* TODO are these needed? */
|
||||
set->crtc->desired_x = set->x;
|
||||
|
|
@ -867,43 +869,50 @@ int drm_crtc_helper_set_config(struct drm_mode_set *set)
|
|||
}
|
||||
drm_helper_disable_unused_functions(dev);
|
||||
} else if (fb_changed) {
|
||||
set->crtc->x = set->x;
|
||||
set->crtc->y = set->y;
|
||||
|
||||
old_fb = set->crtc->fb;
|
||||
if (set->crtc->fb != set->fb)
|
||||
set->crtc->fb = set->fb;
|
||||
ret = crtc_funcs->mode_set_base(set->crtc,
|
||||
set->x, set->y, old_fb);
|
||||
if (ret != 0)
|
||||
goto fail_set_mode;
|
||||
goto fail;
|
||||
}
|
||||
|
||||
kfree(save_connectors);
|
||||
kfree(save_encoders);
|
||||
kfree(save_crtcs);
|
||||
return 0;
|
||||
|
||||
fail_set_mode:
|
||||
set->crtc->enabled = save_enabled;
|
||||
set->crtc->fb = old_fb;
|
||||
fail:
|
||||
/* Restore all previous data. */
|
||||
count = 0;
|
||||
list_for_each_entry(connector, &dev->mode_config.connector_list, head) {
|
||||
if (!connector->encoder)
|
||||
continue;
|
||||
list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) {
|
||||
*crtc = save_crtcs[count++];
|
||||
}
|
||||
|
||||
connector->encoder->crtc = save_crtcs[count++];
|
||||
count = 0;
|
||||
list_for_each_entry(encoder, &dev->mode_config.encoder_list, head) {
|
||||
*encoder = save_encoders[count++];
|
||||
}
|
||||
fail_no_encoder:
|
||||
kfree(save_crtcs);
|
||||
|
||||
count = 0;
|
||||
list_for_each_entry(connector, &dev->mode_config.connector_list, head) {
|
||||
connector->encoder = save_encoders[count++];
|
||||
*connector = save_connectors[count++];
|
||||
}
|
||||
|
||||
kfree(save_connectors);
|
||||
kfree(save_encoders);
|
||||
kfree(save_crtcs);
|
||||
return ret;
|
||||
}
|
||||
EXPORT_SYMBOL(drm_crtc_helper_set_config);
|
||||
|
||||
bool drm_helper_plugged_event(struct drm_device *dev)
|
||||
{
|
||||
DRM_DEBUG("\n");
|
||||
DRM_DEBUG_KMS("\n");
|
||||
|
||||
drm_helper_probe_connector_modes(dev, dev->mode_config.max_width,
|
||||
dev->mode_config.max_height);
|
||||
|
|
@ -932,7 +941,6 @@ bool drm_helper_plugged_event(struct drm_device *dev)
|
|||
*/
|
||||
bool drm_helper_initial_config(struct drm_device *dev)
|
||||
{
|
||||
struct drm_connector *connector;
|
||||
int count = 0;
|
||||
|
||||
count = drm_helper_probe_connector_modes(dev,
|
||||
|
|
@ -940,16 +948,9 @@ bool drm_helper_initial_config(struct drm_device *dev)
|
|||
dev->mode_config.max_height);
|
||||
|
||||
/*
|
||||
* None of the available connectors had any modes, so add some
|
||||
* and try to light them up anyway
|
||||
* we shouldn't end up with no modes here.
|
||||
*/
|
||||
if (!count) {
|
||||
DRM_ERROR("connectors have no modes, using standard modes\n");
|
||||
list_for_each_entry(connector,
|
||||
&dev->mode_config.connector_list,
|
||||
head)
|
||||
drm_helper_add_std_modes(dev, connector);
|
||||
}
|
||||
WARN(!count, "Connected connector with 0 modes\n");
|
||||
|
||||
drm_setup_crtcs(dev);
|
||||
|
||||
|
|
|
|||
|
|
@ -63,12 +63,12 @@ static struct drm_ioctl_desc drm_ioctls[] = {
|
|||
DRM_IOCTL_DEF(DRM_IOCTL_GET_MAP, drm_getmap, 0),
|
||||
DRM_IOCTL_DEF(DRM_IOCTL_GET_CLIENT, drm_getclient, 0),
|
||||
DRM_IOCTL_DEF(DRM_IOCTL_GET_STATS, drm_getstats, 0),
|
||||
DRM_IOCTL_DEF(DRM_IOCTL_SET_VERSION, drm_setversion, DRM_MASTER|DRM_ROOT_ONLY),
|
||||
DRM_IOCTL_DEF(DRM_IOCTL_SET_VERSION, drm_setversion, DRM_MASTER),
|
||||
|
||||
DRM_IOCTL_DEF(DRM_IOCTL_SET_UNIQUE, drm_setunique, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY),
|
||||
DRM_IOCTL_DEF(DRM_IOCTL_BLOCK, drm_noop, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY),
|
||||
DRM_IOCTL_DEF(DRM_IOCTL_UNBLOCK, drm_noop, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY),
|
||||
DRM_IOCTL_DEF(DRM_IOCTL_AUTH_MAGIC, drm_authmagic, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY),
|
||||
DRM_IOCTL_DEF(DRM_IOCTL_AUTH_MAGIC, drm_authmagic, DRM_AUTH|DRM_MASTER),
|
||||
|
||||
DRM_IOCTL_DEF(DRM_IOCTL_ADD_MAP, drm_addmap_ioctl, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY),
|
||||
DRM_IOCTL_DEF(DRM_IOCTL_RM_MAP, drm_rmmap_ioctl, DRM_AUTH),
|
||||
|
|
|
|||
|
|
@ -60,6 +60,12 @@
|
|||
#define EDID_QUIRK_FIRST_DETAILED_PREFERRED (1 << 5)
|
||||
/* use +hsync +vsync for detailed mode */
|
||||
#define EDID_QUIRK_DETAILED_SYNC_PP (1 << 6)
|
||||
/* define the number of Extension EDID block */
|
||||
#define MAX_EDID_EXT_NUM 4
|
||||
|
||||
#define LEVEL_DMT 0
|
||||
#define LEVEL_GTF 1
|
||||
#define LEVEL_CVT 2
|
||||
|
||||
static struct edid_quirk {
|
||||
char *vendor;
|
||||
|
|
@ -237,28 +243,291 @@ static void edid_fixup_preferred(struct drm_connector *connector,
|
|||
preferred_mode->type |= DRM_MODE_TYPE_PREFERRED;
|
||||
}
|
||||
|
||||
/*
|
||||
* Add the Autogenerated from the DMT spec.
|
||||
* This table is copied from xfree86/modes/xf86EdidModes.c.
|
||||
* But the mode with Reduced blank feature is deleted.
|
||||
*/
|
||||
static struct drm_display_mode drm_dmt_modes[] = {
|
||||
/* 640x350@85Hz */
|
||||
{ DRM_MODE("640x350", DRM_MODE_TYPE_DRIVER, 31500, 640, 672,
|
||||
736, 832, 0, 350, 382, 385, 445, 0,
|
||||
DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_NVSYNC) },
|
||||
/* 640x400@85Hz */
|
||||
{ DRM_MODE("640x400", DRM_MODE_TYPE_DRIVER, 31500, 640, 672,
|
||||
736, 832, 0, 400, 401, 404, 445, 0,
|
||||
DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_PVSYNC) },
|
||||
/* 720x400@85Hz */
|
||||
{ DRM_MODE("720x400", DRM_MODE_TYPE_DRIVER, 35500, 720, 756,
|
||||
828, 936, 0, 400, 401, 404, 446, 0,
|
||||
DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_PVSYNC) },
|
||||
/* 640x480@60Hz */
|
||||
{ DRM_MODE("640x480", DRM_MODE_TYPE_DRIVER, 25175, 640, 656,
|
||||
752, 800, 0, 480, 489, 492, 525, 0,
|
||||
DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC) },
|
||||
/* 640x480@72Hz */
|
||||
{ DRM_MODE("640x480", DRM_MODE_TYPE_DRIVER, 31500, 640, 664,
|
||||
704, 832, 0, 480, 489, 492, 520, 0,
|
||||
DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC) },
|
||||
/* 640x480@75Hz */
|
||||
{ DRM_MODE("640x480", DRM_MODE_TYPE_DRIVER, 31500, 640, 656,
|
||||
720, 840, 0, 480, 481, 484, 500, 0,
|
||||
DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC) },
|
||||
/* 640x480@85Hz */
|
||||
{ DRM_MODE("640x480", DRM_MODE_TYPE_DRIVER, 36000, 640, 696,
|
||||
752, 832, 0, 480, 481, 484, 509, 0,
|
||||
DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC) },
|
||||
/* 800x600@56Hz */
|
||||
{ DRM_MODE("800x600", DRM_MODE_TYPE_DRIVER, 36000, 800, 824,
|
||||
896, 1024, 0, 600, 601, 603, 625, 0,
|
||||
DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC) },
|
||||
/* 800x600@60Hz */
|
||||
{ DRM_MODE("800x600", DRM_MODE_TYPE_DRIVER, 40000, 800, 840,
|
||||
968, 1056, 0, 600, 601, 605, 628, 0,
|
||||
DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC) },
|
||||
/* 800x600@72Hz */
|
||||
{ DRM_MODE("800x600", DRM_MODE_TYPE_DRIVER, 50000, 800, 856,
|
||||
976, 1040, 0, 600, 637, 643, 666, 0,
|
||||
DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC) },
|
||||
/* 800x600@75Hz */
|
||||
{ DRM_MODE("800x600", DRM_MODE_TYPE_DRIVER, 49500, 800, 816,
|
||||
896, 1056, 0, 600, 601, 604, 625, 0,
|
||||
DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC) },
|
||||
/* 800x600@85Hz */
|
||||
{ DRM_MODE("800x600", DRM_MODE_TYPE_DRIVER, 56250, 800, 832,
|
||||
896, 1048, 0, 600, 601, 604, 631, 0,
|
||||
DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC) },
|
||||
/* 848x480@60Hz */
|
||||
{ DRM_MODE("848x480", DRM_MODE_TYPE_DRIVER, 33750, 848, 864,
|
||||
976, 1088, 0, 480, 486, 494, 517, 0,
|
||||
DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC) },
|
||||
/* 1024x768@43Hz, interlace */
|
||||
{ DRM_MODE("1024x768", DRM_MODE_TYPE_DRIVER, 44900, 1024, 1032,
|
||||
1208, 1264, 0, 768, 768, 772, 817, 0,
|
||||
DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC |
|
||||
DRM_MODE_FLAG_INTERLACE) },
|
||||
/* 1024x768@60Hz */
|
||||
{ DRM_MODE("1024x768", DRM_MODE_TYPE_DRIVER, 65000, 1024, 1048,
|
||||
1184, 1344, 0, 768, 771, 777, 806, 0,
|
||||
DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC) },
|
||||
/* 1024x768@70Hz */
|
||||
{ DRM_MODE("1024x768", DRM_MODE_TYPE_DRIVER, 75000, 1024, 1048,
|
||||
1184, 1328, 0, 768, 771, 777, 806, 0,
|
||||
DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC) },
|
||||
/* 1024x768@75Hz */
|
||||
{ DRM_MODE("1024x768", DRM_MODE_TYPE_DRIVER, 78750, 1024, 1040,
|
||||
1136, 1312, 0, 768, 769, 772, 800, 0,
|
||||
DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC) },
|
||||
/* 1024x768@85Hz */
|
||||
{ DRM_MODE("1024x768", DRM_MODE_TYPE_DRIVER, 94500, 1024, 1072,
|
||||
1072, 1376, 0, 768, 769, 772, 808, 0,
|
||||
DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC) },
|
||||
/* 1152x864@75Hz */
|
||||
{ DRM_MODE("1152x864", DRM_MODE_TYPE_DRIVER, 108000, 1152, 1216,
|
||||
1344, 1600, 0, 864, 865, 868, 900, 0,
|
||||
DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC) },
|
||||
/* 1280x768@60Hz */
|
||||
{ DRM_MODE("1280x768", DRM_MODE_TYPE_DRIVER, 79500, 1280, 1344,
|
||||
1472, 1664, 0, 768, 771, 778, 798, 0,
|
||||
DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_PVSYNC) },
|
||||
/* 1280x768@75Hz */
|
||||
{ DRM_MODE("1280x768", DRM_MODE_TYPE_DRIVER, 102250, 1280, 1360,
|
||||
1488, 1696, 0, 768, 771, 778, 805, 0,
|
||||
DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_NVSYNC) },
|
||||
/* 1280x768@85Hz */
|
||||
{ DRM_MODE("1280x768", DRM_MODE_TYPE_DRIVER, 117500, 1280, 1360,
|
||||
1496, 1712, 0, 768, 771, 778, 809, 0,
|
||||
DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_PVSYNC) },
|
||||
/* 1280x800@60Hz */
|
||||
{ DRM_MODE("1280x800", DRM_MODE_TYPE_DRIVER, 83500, 1280, 1352,
|
||||
1480, 1680, 0, 800, 803, 809, 831, 0,
|
||||
DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_NVSYNC) },
|
||||
/* 1280x800@75Hz */
|
||||
{ DRM_MODE("1280x800", DRM_MODE_TYPE_DRIVER, 106500, 1280, 1360,
|
||||
1488, 1696, 0, 800, 803, 809, 838, 0,
|
||||
DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_PVSYNC) },
|
||||
/* 1280x800@85Hz */
|
||||
{ DRM_MODE("1280x800", DRM_MODE_TYPE_DRIVER, 122500, 1280, 1360,
|
||||
1496, 1712, 0, 800, 803, 809, 843, 0,
|
||||
DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_PVSYNC) },
|
||||
/* 1280x960@60Hz */
|
||||
{ DRM_MODE("1280x960", DRM_MODE_TYPE_DRIVER, 108000, 1280, 1376,
|
||||
1488, 1800, 0, 960, 961, 964, 1000, 0,
|
||||
DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC) },
|
||||
/* 1280x960@85Hz */
|
||||
{ DRM_MODE("1280x960", DRM_MODE_TYPE_DRIVER, 148500, 1280, 1344,
|
||||
1504, 1728, 0, 960, 961, 964, 1011, 0,
|
||||
DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC) },
|
||||
/* 1280x1024@60Hz */
|
||||
{ DRM_MODE("1280x1024", DRM_MODE_TYPE_DRIVER, 108000, 1280, 1328,
|
||||
1440, 1688, 0, 1024, 1025, 1028, 1066, 0,
|
||||
DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC) },
|
||||
/* 1280x1024@75Hz */
|
||||
{ DRM_MODE("1280x1024", DRM_MODE_TYPE_DRIVER, 135000, 1280, 1296,
|
||||
1440, 1688, 0, 1024, 1025, 1028, 1066, 0,
|
||||
DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC) },
|
||||
/* 1280x1024@85Hz */
|
||||
{ DRM_MODE("1280x1024", DRM_MODE_TYPE_DRIVER, 157500, 1280, 1344,
|
||||
1504, 1728, 0, 1024, 1025, 1028, 1072, 0,
|
||||
DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC) },
|
||||
/* 1360x768@60Hz */
|
||||
{ DRM_MODE("1360x768", DRM_MODE_TYPE_DRIVER, 85500, 1360, 1424,
|
||||
1536, 1792, 0, 768, 771, 777, 795, 0,
|
||||
DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC) },
|
||||
/* 1440x1050@60Hz */
|
||||
{ DRM_MODE("1400x1050", DRM_MODE_TYPE_DRIVER, 121750, 1400, 1488,
|
||||
1632, 1864, 0, 1050, 1053, 1057, 1089, 0,
|
||||
DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_PVSYNC) },
|
||||
/* 1440x1050@75Hz */
|
||||
{ DRM_MODE("1400x1050", DRM_MODE_TYPE_DRIVER, 156000, 1400, 1504,
|
||||
1648, 1896, 0, 1050, 1053, 1057, 1099, 0,
|
||||
DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_PVSYNC) },
|
||||
/* 1440x1050@85Hz */
|
||||
{ DRM_MODE("1400x1050", DRM_MODE_TYPE_DRIVER, 179500, 1400, 1504,
|
||||
1656, 1912, 0, 1050, 1053, 1057, 1105, 0,
|
||||
DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_PVSYNC) },
|
||||
/* 1440x900@60Hz */
|
||||
{ DRM_MODE("1440x900", DRM_MODE_TYPE_DRIVER, 106500, 1440, 1520,
|
||||
1672, 1904, 0, 900, 903, 909, 934, 0,
|
||||
DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_PVSYNC) },
|
||||
/* 1440x900@75Hz */
|
||||
{ DRM_MODE("1440x900", DRM_MODE_TYPE_DRIVER, 136750, 1440, 1536,
|
||||
1688, 1936, 0, 900, 903, 909, 942, 0,
|
||||
DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_PVSYNC) },
|
||||
/* 1440x900@85Hz */
|
||||
{ DRM_MODE("1440x900", DRM_MODE_TYPE_DRIVER, 157000, 1440, 1544,
|
||||
1696, 1952, 0, 900, 903, 909, 948, 0,
|
||||
DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_PVSYNC) },
|
||||
/* 1600x1200@60Hz */
|
||||
{ DRM_MODE("1600x1200", DRM_MODE_TYPE_DRIVER, 162000, 1600, 1664,
|
||||
1856, 2160, 0, 1200, 1201, 1204, 1250, 0,
|
||||
DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC) },
|
||||
/* 1600x1200@65Hz */
|
||||
{ DRM_MODE("1600x1200", DRM_MODE_TYPE_DRIVER, 175500, 1600, 1664,
|
||||
1856, 2160, 0, 1200, 1201, 1204, 1250, 0,
|
||||
DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC) },
|
||||
/* 1600x1200@70Hz */
|
||||
{ DRM_MODE("1600x1200", DRM_MODE_TYPE_DRIVER, 189000, 1600, 1664,
|
||||
1856, 2160, 0, 1200, 1201, 1204, 1250, 0,
|
||||
DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC) },
|
||||
/* 1600x1200@75Hz */
|
||||
{ DRM_MODE("1600x1200", DRM_MODE_TYPE_DRIVER, 2025000, 1600, 1664,
|
||||
1856, 2160, 0, 1200, 1201, 1204, 1250, 0,
|
||||
DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC) },
|
||||
/* 1600x1200@85Hz */
|
||||
{ DRM_MODE("1600x1200", DRM_MODE_TYPE_DRIVER, 229500, 1600, 1664,
|
||||
1856, 2160, 0, 1200, 1201, 1204, 1250, 0,
|
||||
DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC) },
|
||||
/* 1680x1050@60Hz */
|
||||
{ DRM_MODE("1680x1050", DRM_MODE_TYPE_DRIVER, 146250, 1680, 1784,
|
||||
1960, 2240, 0, 1050, 1053, 1059, 1089, 0,
|
||||
DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_PVSYNC) },
|
||||
/* 1680x1050@75Hz */
|
||||
{ DRM_MODE("1680x1050", DRM_MODE_TYPE_DRIVER, 187000, 1680, 1800,
|
||||
1976, 2272, 0, 1050, 1053, 1059, 1099, 0,
|
||||
DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_PVSYNC) },
|
||||
/* 1680x1050@85Hz */
|
||||
{ DRM_MODE("1680x1050", DRM_MODE_TYPE_DRIVER, 214750, 1680, 1808,
|
||||
1984, 2288, 0, 1050, 1053, 1059, 1105, 0,
|
||||
DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_PVSYNC) },
|
||||
/* 1792x1344@60Hz */
|
||||
{ DRM_MODE("1792x1344", DRM_MODE_TYPE_DRIVER, 204750, 1792, 1920,
|
||||
2120, 2448, 0, 1344, 1345, 1348, 1394, 0,
|
||||
DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_PVSYNC) },
|
||||
/* 1729x1344@75Hz */
|
||||
{ DRM_MODE("1792x1344", DRM_MODE_TYPE_DRIVER, 261000, 1792, 1888,
|
||||
2104, 2456, 0, 1344, 1345, 1348, 1417, 0,
|
||||
DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_PVSYNC) },
|
||||
/* 1853x1392@60Hz */
|
||||
{ DRM_MODE("1856x1392", DRM_MODE_TYPE_DRIVER, 218250, 1856, 1952,
|
||||
2176, 2528, 0, 1392, 1393, 1396, 1439, 0,
|
||||
DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_PVSYNC) },
|
||||
/* 1856x1392@75Hz */
|
||||
{ DRM_MODE("1856x1392", DRM_MODE_TYPE_DRIVER, 288000, 1856, 1984,
|
||||
2208, 2560, 0, 1392, 1395, 1399, 1500, 0,
|
||||
DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_PVSYNC) },
|
||||
/* 1920x1200@60Hz */
|
||||
{ DRM_MODE("1920x1200", DRM_MODE_TYPE_DRIVER, 193250, 1920, 2056,
|
||||
2256, 2592, 0, 1200, 1203, 1209, 1245, 0,
|
||||
DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_PVSYNC) },
|
||||
/* 1920x1200@75Hz */
|
||||
{ DRM_MODE("1920x1200", DRM_MODE_TYPE_DRIVER, 245250, 1920, 2056,
|
||||
2264, 2608, 0, 1200, 1203, 1209, 1255, 0,
|
||||
DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_PVSYNC) },
|
||||
/* 1920x1200@85Hz */
|
||||
{ DRM_MODE("1920x1200", DRM_MODE_TYPE_DRIVER, 281250, 1920, 2064,
|
||||
2272, 2624, 0, 1200, 1203, 1209, 1262, 0,
|
||||
DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_PVSYNC) },
|
||||
/* 1920x1440@60Hz */
|
||||
{ DRM_MODE("1920x1440", DRM_MODE_TYPE_DRIVER, 234000, 1920, 2048,
|
||||
2256, 2600, 0, 1440, 1441, 1444, 1500, 0,
|
||||
DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_PVSYNC) },
|
||||
/* 1920x1440@75Hz */
|
||||
{ DRM_MODE("1920x1440", DRM_MODE_TYPE_DRIVER, 297000, 1920, 2064,
|
||||
2288, 2640, 0, 1440, 1441, 1444, 1500, 0,
|
||||
DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_PVSYNC) },
|
||||
/* 2560x1600@60Hz */
|
||||
{ DRM_MODE("2560x1600", DRM_MODE_TYPE_DRIVER, 348500, 2560, 2752,
|
||||
3032, 3504, 0, 1600, 1603, 1609, 1658, 0,
|
||||
DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_PVSYNC) },
|
||||
/* 2560x1600@75HZ */
|
||||
{ DRM_MODE("2560x1600", DRM_MODE_TYPE_DRIVER, 443250, 2560, 2768,
|
||||
3048, 3536, 0, 1600, 1603, 1609, 1672, 0,
|
||||
DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_PVSYNC) },
|
||||
/* 2560x1600@85HZ */
|
||||
{ DRM_MODE("2560x1600", DRM_MODE_TYPE_DRIVER, 505250, 2560, 2768,
|
||||
3048, 3536, 0, 1600, 1603, 1609, 1682, 0,
|
||||
DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_PVSYNC) },
|
||||
};
|
||||
|
||||
static struct drm_display_mode *drm_find_dmt(struct drm_device *dev,
|
||||
int hsize, int vsize, int fresh)
|
||||
{
|
||||
int i, count;
|
||||
struct drm_display_mode *ptr, *mode;
|
||||
|
||||
count = sizeof(drm_dmt_modes) / sizeof(struct drm_display_mode);
|
||||
mode = NULL;
|
||||
for (i = 0; i < count; i++) {
|
||||
ptr = &drm_dmt_modes[i];
|
||||
if (hsize == ptr->hdisplay &&
|
||||
vsize == ptr->vdisplay &&
|
||||
fresh == drm_mode_vrefresh(ptr)) {
|
||||
/* get the expected default mode */
|
||||
mode = drm_mode_duplicate(dev, ptr);
|
||||
break;
|
||||
}
|
||||
}
|
||||
return mode;
|
||||
}
|
||||
/**
|
||||
* drm_mode_std - convert standard mode info (width, height, refresh) into mode
|
||||
* @t: standard timing params
|
||||
* @timing_level: standard timing level
|
||||
*
|
||||
* Take the standard timing params (in this case width, aspect, and refresh)
|
||||
* and convert them into a real mode using CVT.
|
||||
* and convert them into a real mode using CVT/GTF/DMT.
|
||||
*
|
||||
* Punts for now, but should eventually use the FB layer's CVT based mode
|
||||
* generation code.
|
||||
*/
|
||||
struct drm_display_mode *drm_mode_std(struct drm_device *dev,
|
||||
struct std_timing *t)
|
||||
struct std_timing *t,
|
||||
int timing_level)
|
||||
{
|
||||
struct drm_display_mode *mode;
|
||||
int hsize = t->hsize * 8 + 248, vsize;
|
||||
int hsize, vsize;
|
||||
int vrefresh_rate;
|
||||
unsigned aspect_ratio = (t->vfreq_aspect & EDID_TIMING_ASPECT_MASK)
|
||||
>> EDID_TIMING_ASPECT_SHIFT;
|
||||
unsigned vfreq = (t->vfreq_aspect & EDID_TIMING_VFREQ_MASK)
|
||||
>> EDID_TIMING_VFREQ_SHIFT;
|
||||
|
||||
mode = drm_mode_create(dev);
|
||||
if (!mode)
|
||||
return NULL;
|
||||
|
||||
/* According to the EDID spec, the hdisplay = hsize * 8 + 248 */
|
||||
hsize = t->hsize * 8 + 248;
|
||||
/* vrefresh_rate = vfreq + 60 */
|
||||
vrefresh_rate = vfreq + 60;
|
||||
/* the vdisplay is calculated based on the aspect ratio */
|
||||
if (aspect_ratio == 0)
|
||||
vsize = (hsize * 10) / 16;
|
||||
else if (aspect_ratio == 1)
|
||||
|
|
@ -267,9 +536,30 @@ struct drm_display_mode *drm_mode_std(struct drm_device *dev,
|
|||
vsize = (hsize * 4) / 5;
|
||||
else
|
||||
vsize = (hsize * 9) / 16;
|
||||
/* HDTV hack */
|
||||
if (hsize == 1360 && vsize == 765 && vrefresh_rate == 60) {
|
||||
mode = drm_cvt_mode(dev, hsize, vsize, vrefresh_rate, 0, 0);
|
||||
mode->hdisplay = 1366;
|
||||
mode->vsync_start = mode->vsync_start - 1;
|
||||
mode->vsync_end = mode->vsync_end - 1;
|
||||
return mode;
|
||||
}
|
||||
mode = NULL;
|
||||
/* check whether it can be found in default mode table */
|
||||
mode = drm_find_dmt(dev, hsize, vsize, vrefresh_rate);
|
||||
if (mode)
|
||||
return mode;
|
||||
|
||||
drm_mode_set_name(mode);
|
||||
|
||||
switch (timing_level) {
|
||||
case LEVEL_DMT:
|
||||
break;
|
||||
case LEVEL_GTF:
|
||||
mode = drm_gtf_mode(dev, hsize, vsize, vrefresh_rate, 0, 0);
|
||||
break;
|
||||
case LEVEL_CVT:
|
||||
mode = drm_cvt_mode(dev, hsize, vsize, vrefresh_rate, 0, 0);
|
||||
break;
|
||||
}
|
||||
return mode;
|
||||
}
|
||||
|
||||
|
|
@ -451,6 +741,19 @@ static int add_established_modes(struct drm_connector *connector, struct edid *e
|
|||
|
||||
return modes;
|
||||
}
|
||||
/**
|
||||
* stanard_timing_level - get std. timing level(CVT/GTF/DMT)
|
||||
* @edid: EDID block to scan
|
||||
*/
|
||||
static int standard_timing_level(struct edid *edid)
|
||||
{
|
||||
if (edid->revision >= 2) {
|
||||
if (edid->revision >= 4 && (edid->features & DRM_EDID_FEATURE_DEFAULT_GTF))
|
||||
return LEVEL_CVT;
|
||||
return LEVEL_GTF;
|
||||
}
|
||||
return LEVEL_DMT;
|
||||
}
|
||||
|
||||
/**
|
||||
* add_standard_modes - get std. modes from EDID and add them
|
||||
|
|
@ -463,6 +766,9 @@ static int add_standard_modes(struct drm_connector *connector, struct edid *edid
|
|||
{
|
||||
struct drm_device *dev = connector->dev;
|
||||
int i, modes = 0;
|
||||
int timing_level;
|
||||
|
||||
timing_level = standard_timing_level(edid);
|
||||
|
||||
for (i = 0; i < EDID_STD_TIMINGS; i++) {
|
||||
struct std_timing *t = &edid->standard_timings[i];
|
||||
|
|
@ -472,7 +778,8 @@ static int add_standard_modes(struct drm_connector *connector, struct edid *edid
|
|||
if (t->hsize == 1 && t->vfreq_aspect == 1)
|
||||
continue;
|
||||
|
||||
newmode = drm_mode_std(dev, &edid->standard_timings[i]);
|
||||
newmode = drm_mode_std(dev, &edid->standard_timings[i],
|
||||
timing_level);
|
||||
if (newmode) {
|
||||
drm_mode_probed_add(connector, newmode);
|
||||
modes++;
|
||||
|
|
@ -496,6 +803,9 @@ static int add_detailed_info(struct drm_connector *connector,
|
|||
{
|
||||
struct drm_device *dev = connector->dev;
|
||||
int i, j, modes = 0;
|
||||
int timing_level;
|
||||
|
||||
timing_level = standard_timing_level(edid);
|
||||
|
||||
for (i = 0; i < EDID_DETAILED_TIMINGS; i++) {
|
||||
struct detailed_timing *timing = &edid->detailed_timings[i];
|
||||
|
|
@ -525,7 +835,8 @@ static int add_detailed_info(struct drm_connector *connector,
|
|||
struct drm_display_mode *newmode;
|
||||
|
||||
std = &data->data.timings[j];
|
||||
newmode = drm_mode_std(dev, std);
|
||||
newmode = drm_mode_std(dev, std,
|
||||
timing_level);
|
||||
if (newmode) {
|
||||
drm_mode_probed_add(connector, newmode);
|
||||
modes++;
|
||||
|
|
@ -551,6 +862,122 @@ static int add_detailed_info(struct drm_connector *connector,
|
|||
|
||||
return modes;
|
||||
}
|
||||
/**
|
||||
* add_detailed_mode_eedid - get detailed mode info from addtional timing
|
||||
* EDID block
|
||||
* @connector: attached connector
|
||||
* @edid: EDID block to scan(It is only to get addtional timing EDID block)
|
||||
* @quirks: quirks to apply
|
||||
*
|
||||
* Some of the detailed timing sections may contain mode information. Grab
|
||||
* it and add it to the list.
|
||||
*/
|
||||
static int add_detailed_info_eedid(struct drm_connector *connector,
|
||||
struct edid *edid, u32 quirks)
|
||||
{
|
||||
struct drm_device *dev = connector->dev;
|
||||
int i, j, modes = 0;
|
||||
char *edid_ext = NULL;
|
||||
struct detailed_timing *timing;
|
||||
struct detailed_non_pixel *data;
|
||||
struct drm_display_mode *newmode;
|
||||
int edid_ext_num;
|
||||
int start_offset, end_offset;
|
||||
int timing_level;
|
||||
|
||||
if (edid->version == 1 && edid->revision < 3) {
|
||||
/* If the EDID version is less than 1.3, there is no
|
||||
* extension EDID.
|
||||
*/
|
||||
return 0;
|
||||
}
|
||||
if (!edid->extensions) {
|
||||
/* if there is no extension EDID, it is unnecessary to
|
||||
* parse the E-EDID to get detailed info
|
||||
*/
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Chose real EDID extension number */
|
||||
edid_ext_num = edid->extensions > MAX_EDID_EXT_NUM ?
|
||||
MAX_EDID_EXT_NUM : edid->extensions;
|
||||
|
||||
/* Find CEA extension */
|
||||
for (i = 0; i < edid_ext_num; i++) {
|
||||
edid_ext = (char *)edid + EDID_LENGTH * (i + 1);
|
||||
/* This block is CEA extension */
|
||||
if (edid_ext[0] == 0x02)
|
||||
break;
|
||||
}
|
||||
|
||||
if (i == edid_ext_num) {
|
||||
/* if there is no additional timing EDID block, return */
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Get the start offset of detailed timing block */
|
||||
start_offset = edid_ext[2];
|
||||
if (start_offset == 0) {
|
||||
/* If the start_offset is zero, it means that neither detailed
|
||||
* info nor data block exist. In such case it is also
|
||||
* unnecessary to parse the detailed timing info.
|
||||
*/
|
||||
return 0;
|
||||
}
|
||||
|
||||
timing_level = standard_timing_level(edid);
|
||||
end_offset = EDID_LENGTH;
|
||||
end_offset -= sizeof(struct detailed_timing);
|
||||
for (i = start_offset; i < end_offset;
|
||||
i += sizeof(struct detailed_timing)) {
|
||||
timing = (struct detailed_timing *)(edid_ext + i);
|
||||
data = &timing->data.other_data;
|
||||
/* Detailed mode timing */
|
||||
if (timing->pixel_clock) {
|
||||
newmode = drm_mode_detailed(dev, edid, timing, quirks);
|
||||
if (!newmode)
|
||||
continue;
|
||||
|
||||
drm_mode_probed_add(connector, newmode);
|
||||
|
||||
modes++;
|
||||
continue;
|
||||
}
|
||||
|
||||
/* Other timing or info */
|
||||
switch (data->type) {
|
||||
case EDID_DETAIL_MONITOR_SERIAL:
|
||||
break;
|
||||
case EDID_DETAIL_MONITOR_STRING:
|
||||
break;
|
||||
case EDID_DETAIL_MONITOR_RANGE:
|
||||
/* Get monitor range data */
|
||||
break;
|
||||
case EDID_DETAIL_MONITOR_NAME:
|
||||
break;
|
||||
case EDID_DETAIL_MONITOR_CPDATA:
|
||||
break;
|
||||
case EDID_DETAIL_STD_MODES:
|
||||
/* Five modes per detailed section */
|
||||
for (j = 0; j < 5; i++) {
|
||||
struct std_timing *std;
|
||||
struct drm_display_mode *newmode;
|
||||
|
||||
std = &data->data.timings[j];
|
||||
newmode = drm_mode_std(dev, std, timing_level);
|
||||
if (newmode) {
|
||||
drm_mode_probed_add(connector, newmode);
|
||||
modes++;
|
||||
}
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return modes;
|
||||
}
|
||||
|
||||
#define DDC_ADDR 0x50
|
||||
/**
|
||||
|
|
@ -584,7 +1011,6 @@ int drm_do_probe_ddc_edid(struct i2c_adapter *adapter,
|
|||
if (i2c_transfer(adapter, msgs, 2) == 2)
|
||||
return 0;
|
||||
|
||||
dev_info(&adapter->dev, "unable to read EDID block.\n");
|
||||
return -1;
|
||||
}
|
||||
EXPORT_SYMBOL(drm_do_probe_ddc_edid);
|
||||
|
|
@ -597,8 +1023,6 @@ static int drm_ddc_read_edid(struct drm_connector *connector,
|
|||
|
||||
ret = drm_do_probe_ddc_edid(adapter, buf, len);
|
||||
if (ret != 0) {
|
||||
dev_info(&connector->dev->pdev->dev, "%s: no EDID data\n",
|
||||
drm_get_connector_name(connector));
|
||||
goto end;
|
||||
}
|
||||
if (!edid_is_valid((struct edid *)buf)) {
|
||||
|
|
@ -610,7 +1034,6 @@ end:
|
|||
return ret;
|
||||
}
|
||||
|
||||
#define MAX_EDID_EXT_NUM 4
|
||||
/**
|
||||
* drm_get_edid - get EDID data, if available
|
||||
* @connector: connector we're probing
|
||||
|
|
@ -763,6 +1186,7 @@ int drm_add_edid_modes(struct drm_connector *connector, struct edid *edid)
|
|||
num_modes += add_established_modes(connector, edid);
|
||||
num_modes += add_standard_modes(connector, edid);
|
||||
num_modes += add_detailed_info(connector, edid, quirks);
|
||||
num_modes += add_detailed_info_eedid(connector, edid, quirks);
|
||||
|
||||
if (quirks & (EDID_QUIRK_PREFER_LARGE_60 | EDID_QUIRK_PREFER_LARGE_75))
|
||||
edid_fixup_preferred(connector, quirks);
|
||||
|
|
@ -788,3 +1212,49 @@ int drm_add_edid_modes(struct drm_connector *connector, struct edid *edid)
|
|||
return num_modes;
|
||||
}
|
||||
EXPORT_SYMBOL(drm_add_edid_modes);
|
||||
|
||||
/**
|
||||
* drm_add_modes_noedid - add modes for the connectors without EDID
|
||||
* @connector: connector we're probing
|
||||
* @hdisplay: the horizontal display limit
|
||||
* @vdisplay: the vertical display limit
|
||||
*
|
||||
* Add the specified modes to the connector's mode list. Only when the
|
||||
* hdisplay/vdisplay is not beyond the given limit, it will be added.
|
||||
*
|
||||
* Return number of modes added or 0 if we couldn't find any.
|
||||
*/
|
||||
int drm_add_modes_noedid(struct drm_connector *connector,
|
||||
int hdisplay, int vdisplay)
|
||||
{
|
||||
int i, count, num_modes = 0;
|
||||
struct drm_display_mode *mode, *ptr;
|
||||
struct drm_device *dev = connector->dev;
|
||||
|
||||
count = sizeof(drm_dmt_modes) / sizeof(struct drm_display_mode);
|
||||
if (hdisplay < 0)
|
||||
hdisplay = 0;
|
||||
if (vdisplay < 0)
|
||||
vdisplay = 0;
|
||||
|
||||
for (i = 0; i < count; i++) {
|
||||
ptr = &drm_dmt_modes[i];
|
||||
if (hdisplay && vdisplay) {
|
||||
/*
|
||||
* Only when two are valid, they will be used to check
|
||||
* whether the mode should be added to the mode list of
|
||||
* the connector.
|
||||
*/
|
||||
if (ptr->hdisplay > hdisplay ||
|
||||
ptr->vdisplay > vdisplay)
|
||||
continue;
|
||||
}
|
||||
mode = drm_mode_duplicate(dev, ptr);
|
||||
if (mode) {
|
||||
drm_mode_probed_add(connector, mode);
|
||||
num_modes++;
|
||||
}
|
||||
}
|
||||
return num_modes;
|
||||
}
|
||||
EXPORT_SYMBOL(drm_add_modes_noedid);
|
||||
|
|
|
|||
116
drivers/gpu/drm/drm_encoder_slave.c
Normal file
116
drivers/gpu/drm/drm_encoder_slave.c
Normal file
|
|
@ -0,0 +1,116 @@
|
|||
/*
|
||||
* Copyright (C) 2009 Francisco Jerez.
|
||||
* All Rights Reserved.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining
|
||||
* a copy of this software and associated documentation files (the
|
||||
* "Software"), to deal in the Software without restriction, including
|
||||
* without limitation the rights to use, copy, modify, merge, publish,
|
||||
* distribute, sublicense, and/or sell copies of the Software, and to
|
||||
* permit persons to whom the Software is furnished to do so, subject to
|
||||
* the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice (including the
|
||||
* next paragraph) shall be included in all copies or substantial
|
||||
* portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
||||
* IN NO EVENT SHALL THE COPYRIGHT OWNER(S) AND/OR ITS SUPPLIERS BE
|
||||
* LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
||||
* OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "drm_encoder_slave.h"
|
||||
|
||||
/**
|
||||
* drm_i2c_encoder_init - Initialize an I2C slave encoder
|
||||
* @dev: DRM device.
|
||||
* @encoder: Encoder to be attached to the I2C device. You aren't
|
||||
* required to have called drm_encoder_init() before.
|
||||
* @adap: I2C adapter that will be used to communicate with
|
||||
* the device.
|
||||
* @info: Information that will be used to create the I2C device.
|
||||
* Required fields are @addr and @type.
|
||||
*
|
||||
* Create an I2C device on the specified bus (the module containing its
|
||||
* driver is transparently loaded) and attach it to the specified
|
||||
* &drm_encoder_slave. The @slave_funcs field will be initialized with
|
||||
* the hooks provided by the slave driver.
|
||||
*
|
||||
* Returns 0 on success or a negative errno on failure, in particular,
|
||||
* -ENODEV is returned when no matching driver is found.
|
||||
*/
|
||||
int drm_i2c_encoder_init(struct drm_device *dev,
|
||||
struct drm_encoder_slave *encoder,
|
||||
struct i2c_adapter *adap,
|
||||
const struct i2c_board_info *info)
|
||||
{
|
||||
char modalias[sizeof(I2C_MODULE_PREFIX)
|
||||
+ I2C_NAME_SIZE];
|
||||
struct module *module = NULL;
|
||||
struct i2c_client *client;
|
||||
struct drm_i2c_encoder_driver *encoder_drv;
|
||||
int err = 0;
|
||||
|
||||
snprintf(modalias, sizeof(modalias),
|
||||
"%s%s", I2C_MODULE_PREFIX, info->type);
|
||||
request_module(modalias);
|
||||
|
||||
client = i2c_new_device(adap, info);
|
||||
if (!client) {
|
||||
err = -ENOMEM;
|
||||
goto fail;
|
||||
}
|
||||
|
||||
if (!client->driver) {
|
||||
err = -ENODEV;
|
||||
goto fail_unregister;
|
||||
}
|
||||
|
||||
module = client->driver->driver.owner;
|
||||
if (!try_module_get(module)) {
|
||||
err = -ENODEV;
|
||||
goto fail_unregister;
|
||||
}
|
||||
|
||||
encoder->bus_priv = client;
|
||||
|
||||
encoder_drv = to_drm_i2c_encoder_driver(client->driver);
|
||||
|
||||
err = encoder_drv->encoder_init(client, dev, encoder);
|
||||
if (err)
|
||||
goto fail_unregister;
|
||||
|
||||
return 0;
|
||||
|
||||
fail_unregister:
|
||||
i2c_unregister_device(client);
|
||||
module_put(module);
|
||||
fail:
|
||||
return err;
|
||||
}
|
||||
EXPORT_SYMBOL(drm_i2c_encoder_init);
|
||||
|
||||
/**
|
||||
* drm_i2c_encoder_destroy - Unregister the I2C device backing an encoder
|
||||
* @drm_encoder: Encoder to be unregistered.
|
||||
*
|
||||
* This should be called from the @destroy method of an I2C slave
|
||||
* encoder driver once I2C access is no longer needed.
|
||||
*/
|
||||
void drm_i2c_encoder_destroy(struct drm_encoder *drm_encoder)
|
||||
{
|
||||
struct drm_encoder_slave *encoder = to_encoder_slave(drm_encoder);
|
||||
struct i2c_client *client = drm_i2c_encoder_get_client(drm_encoder);
|
||||
struct module *module = client->driver->driver.owner;
|
||||
|
||||
i2c_unregister_device(client);
|
||||
encoder->bus_priv = NULL;
|
||||
|
||||
module_put(module);
|
||||
}
|
||||
EXPORT_SYMBOL(drm_i2c_encoder_destroy);
|
||||
707
drivers/gpu/drm/drm_fb_helper.c
Normal file
707
drivers/gpu/drm/drm_fb_helper.c
Normal file
|
|
@ -0,0 +1,707 @@
|
|||
/*
|
||||
* Copyright (c) 2006-2009 Red Hat Inc.
|
||||
* Copyright (c) 2006-2008 Intel Corporation
|
||||
* Copyright (c) 2007 Dave Airlie <airlied@linux.ie>
|
||||
*
|
||||
* DRM framebuffer helper functions
|
||||
*
|
||||
* Permission to use, copy, modify, distribute, and sell this software and its
|
||||
* documentation for any purpose is hereby granted without fee, provided that
|
||||
* the above copyright notice appear in all copies and that both that copyright
|
||||
* notice and this permission notice appear in supporting documentation, and
|
||||
* that the name of the copyright holders not be used in advertising or
|
||||
* publicity pertaining to distribution of the software without specific,
|
||||
* written prior permission. The copyright holders make no representations
|
||||
* about the suitability of this software for any purpose. It is provided "as
|
||||
* is" without express or implied warranty.
|
||||
*
|
||||
* THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
|
||||
* INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
|
||||
* EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY SPECIAL, INDIRECT OR
|
||||
* CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
|
||||
* DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
|
||||
* TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
|
||||
* OF THIS SOFTWARE.
|
||||
*
|
||||
* Authors:
|
||||
* Dave Airlie <airlied@linux.ie>
|
||||
* Jesse Barnes <jesse.barnes@intel.com>
|
||||
*/
|
||||
#include <linux/sysrq.h>
|
||||
#include <linux/fb.h>
|
||||
#include "drmP.h"
|
||||
#include "drm_crtc.h"
|
||||
#include "drm_fb_helper.h"
|
||||
#include "drm_crtc_helper.h"
|
||||
|
||||
MODULE_AUTHOR("David Airlie, Jesse Barnes");
|
||||
MODULE_DESCRIPTION("DRM KMS helper");
|
||||
MODULE_LICENSE("GPL and additional rights");
|
||||
|
||||
static LIST_HEAD(kernel_fb_helper_list);
|
||||
|
||||
bool drm_fb_helper_force_kernel_mode(void)
|
||||
{
|
||||
int i = 0;
|
||||
bool ret, error = false;
|
||||
struct drm_fb_helper *helper;
|
||||
|
||||
if (list_empty(&kernel_fb_helper_list))
|
||||
return false;
|
||||
|
||||
list_for_each_entry(helper, &kernel_fb_helper_list, kernel_fb_list) {
|
||||
for (i = 0; i < helper->crtc_count; i++) {
|
||||
struct drm_mode_set *mode_set = &helper->crtc_info[i].mode_set;
|
||||
ret = drm_crtc_helper_set_config(mode_set);
|
||||
if (ret)
|
||||
error = true;
|
||||
}
|
||||
}
|
||||
return error;
|
||||
}
|
||||
|
||||
int drm_fb_helper_panic(struct notifier_block *n, unsigned long ununsed,
|
||||
void *panic_str)
|
||||
{
|
||||
DRM_ERROR("panic occurred, switching back to text console\n");
|
||||
return drm_fb_helper_force_kernel_mode();
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL(drm_fb_helper_panic);
|
||||
|
||||
static struct notifier_block paniced = {
|
||||
.notifier_call = drm_fb_helper_panic,
|
||||
};
|
||||
|
||||
/**
|
||||
* drm_fb_helper_restore - restore the framebuffer console (kernel) config
|
||||
*
|
||||
* Restore's the kernel's fbcon mode, used for lastclose & panic paths.
|
||||
*/
|
||||
void drm_fb_helper_restore(void)
|
||||
{
|
||||
bool ret;
|
||||
ret = drm_fb_helper_force_kernel_mode();
|
||||
if (ret == true)
|
||||
DRM_ERROR("Failed to restore crtc configuration\n");
|
||||
}
|
||||
EXPORT_SYMBOL(drm_fb_helper_restore);
|
||||
|
||||
static void drm_fb_helper_restore_work_fn(struct work_struct *ignored)
|
||||
{
|
||||
drm_fb_helper_restore();
|
||||
}
|
||||
static DECLARE_WORK(drm_fb_helper_restore_work, drm_fb_helper_restore_work_fn);
|
||||
|
||||
static void drm_fb_helper_sysrq(int dummy1, struct tty_struct *dummy3)
|
||||
{
|
||||
schedule_work(&drm_fb_helper_restore_work);
|
||||
}
|
||||
|
||||
static struct sysrq_key_op sysrq_drm_fb_helper_restore_op = {
|
||||
.handler = drm_fb_helper_sysrq,
|
||||
.help_msg = "force-fb(V)",
|
||||
.action_msg = "Restore framebuffer console",
|
||||
};
|
||||
|
||||
static void drm_fb_helper_on(struct fb_info *info)
|
||||
{
|
||||
struct drm_fb_helper *fb_helper = info->par;
|
||||
struct drm_device *dev = fb_helper->dev;
|
||||
struct drm_crtc *crtc;
|
||||
struct drm_encoder *encoder;
|
||||
int i;
|
||||
|
||||
/*
|
||||
* For each CRTC in this fb, turn the crtc on then,
|
||||
* find all associated encoders and turn them on.
|
||||
*/
|
||||
for (i = 0; i < fb_helper->crtc_count; i++) {
|
||||
list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) {
|
||||
struct drm_crtc_helper_funcs *crtc_funcs =
|
||||
crtc->helper_private;
|
||||
|
||||
/* Only mess with CRTCs in this fb */
|
||||
if (crtc->base.id != fb_helper->crtc_info[i].crtc_id ||
|
||||
!crtc->enabled)
|
||||
continue;
|
||||
|
||||
mutex_lock(&dev->mode_config.mutex);
|
||||
crtc_funcs->dpms(crtc, DRM_MODE_DPMS_ON);
|
||||
mutex_unlock(&dev->mode_config.mutex);
|
||||
|
||||
/* Found a CRTC on this fb, now find encoders */
|
||||
list_for_each_entry(encoder, &dev->mode_config.encoder_list, head) {
|
||||
if (encoder->crtc == crtc) {
|
||||
struct drm_encoder_helper_funcs *encoder_funcs;
|
||||
|
||||
encoder_funcs = encoder->helper_private;
|
||||
mutex_lock(&dev->mode_config.mutex);
|
||||
encoder_funcs->dpms(encoder, DRM_MODE_DPMS_ON);
|
||||
mutex_unlock(&dev->mode_config.mutex);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void drm_fb_helper_off(struct fb_info *info, int dpms_mode)
|
||||
{
|
||||
struct drm_fb_helper *fb_helper = info->par;
|
||||
struct drm_device *dev = fb_helper->dev;
|
||||
struct drm_crtc *crtc;
|
||||
struct drm_encoder *encoder;
|
||||
int i;
|
||||
|
||||
/*
|
||||
* For each CRTC in this fb, find all associated encoders
|
||||
* and turn them off, then turn off the CRTC.
|
||||
*/
|
||||
for (i = 0; i < fb_helper->crtc_count; i++) {
|
||||
list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) {
|
||||
struct drm_crtc_helper_funcs *crtc_funcs =
|
||||
crtc->helper_private;
|
||||
|
||||
/* Only mess with CRTCs in this fb */
|
||||
if (crtc->base.id != fb_helper->crtc_info[i].crtc_id ||
|
||||
!crtc->enabled)
|
||||
continue;
|
||||
|
||||
/* Found a CRTC on this fb, now find encoders */
|
||||
list_for_each_entry(encoder, &dev->mode_config.encoder_list, head) {
|
||||
if (encoder->crtc == crtc) {
|
||||
struct drm_encoder_helper_funcs *encoder_funcs;
|
||||
|
||||
encoder_funcs = encoder->helper_private;
|
||||
mutex_lock(&dev->mode_config.mutex);
|
||||
encoder_funcs->dpms(encoder, dpms_mode);
|
||||
mutex_unlock(&dev->mode_config.mutex);
|
||||
}
|
||||
}
|
||||
if (dpms_mode == DRM_MODE_DPMS_OFF) {
|
||||
mutex_lock(&dev->mode_config.mutex);
|
||||
crtc_funcs->dpms(crtc, dpms_mode);
|
||||
mutex_unlock(&dev->mode_config.mutex);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int drm_fb_helper_blank(int blank, struct fb_info *info)
|
||||
{
|
||||
switch (blank) {
|
||||
case FB_BLANK_UNBLANK:
|
||||
drm_fb_helper_on(info);
|
||||
break;
|
||||
case FB_BLANK_NORMAL:
|
||||
drm_fb_helper_off(info, DRM_MODE_DPMS_STANDBY);
|
||||
break;
|
||||
case FB_BLANK_HSYNC_SUSPEND:
|
||||
drm_fb_helper_off(info, DRM_MODE_DPMS_STANDBY);
|
||||
break;
|
||||
case FB_BLANK_VSYNC_SUSPEND:
|
||||
drm_fb_helper_off(info, DRM_MODE_DPMS_SUSPEND);
|
||||
break;
|
||||
case FB_BLANK_POWERDOWN:
|
||||
drm_fb_helper_off(info, DRM_MODE_DPMS_OFF);
|
||||
break;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL(drm_fb_helper_blank);
|
||||
|
||||
static void drm_fb_helper_crtc_free(struct drm_fb_helper *helper)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < helper->crtc_count; i++)
|
||||
kfree(helper->crtc_info[i].mode_set.connectors);
|
||||
kfree(helper->crtc_info);
|
||||
}
|
||||
|
||||
int drm_fb_helper_init_crtc_count(struct drm_fb_helper *helper, int crtc_count, int max_conn_count)
|
||||
{
|
||||
struct drm_device *dev = helper->dev;
|
||||
struct drm_crtc *crtc;
|
||||
int ret = 0;
|
||||
int i;
|
||||
|
||||
helper->crtc_info = kcalloc(crtc_count, sizeof(struct drm_fb_helper_crtc), GFP_KERNEL);
|
||||
if (!helper->crtc_info)
|
||||
return -ENOMEM;
|
||||
|
||||
helper->crtc_count = crtc_count;
|
||||
|
||||
for (i = 0; i < crtc_count; i++) {
|
||||
helper->crtc_info[i].mode_set.connectors =
|
||||
kcalloc(max_conn_count,
|
||||
sizeof(struct drm_connector *),
|
||||
GFP_KERNEL);
|
||||
|
||||
if (!helper->crtc_info[i].mode_set.connectors) {
|
||||
ret = -ENOMEM;
|
||||
goto out_free;
|
||||
}
|
||||
helper->crtc_info[i].mode_set.num_connectors = 0;
|
||||
}
|
||||
|
||||
i = 0;
|
||||
list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) {
|
||||
helper->crtc_info[i].crtc_id = crtc->base.id;
|
||||
helper->crtc_info[i].mode_set.crtc = crtc;
|
||||
i++;
|
||||
}
|
||||
helper->conn_limit = max_conn_count;
|
||||
return 0;
|
||||
out_free:
|
||||
drm_fb_helper_crtc_free(helper);
|
||||
return -ENOMEM;
|
||||
}
|
||||
EXPORT_SYMBOL(drm_fb_helper_init_crtc_count);
|
||||
|
||||
int drm_fb_helper_setcolreg(unsigned regno,
|
||||
unsigned red,
|
||||
unsigned green,
|
||||
unsigned blue,
|
||||
unsigned transp,
|
||||
struct fb_info *info)
|
||||
{
|
||||
struct drm_fb_helper *fb_helper = info->par;
|
||||
struct drm_device *dev = fb_helper->dev;
|
||||
struct drm_crtc *crtc;
|
||||
int i;
|
||||
|
||||
list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) {
|
||||
struct drm_framebuffer *fb = fb_helper->fb;
|
||||
|
||||
for (i = 0; i < fb_helper->crtc_count; i++) {
|
||||
if (crtc->base.id == fb_helper->crtc_info[i].crtc_id)
|
||||
break;
|
||||
}
|
||||
if (i == fb_helper->crtc_count)
|
||||
continue;
|
||||
|
||||
if (regno > 255)
|
||||
return 1;
|
||||
|
||||
if (fb->depth == 8) {
|
||||
fb_helper->funcs->gamma_set(crtc, red, green, blue, regno);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (regno < 16) {
|
||||
switch (fb->depth) {
|
||||
case 15:
|
||||
fb->pseudo_palette[regno] = ((red & 0xf800) >> 1) |
|
||||
((green & 0xf800) >> 6) |
|
||||
((blue & 0xf800) >> 11);
|
||||
break;
|
||||
case 16:
|
||||
fb->pseudo_palette[regno] = (red & 0xf800) |
|
||||
((green & 0xfc00) >> 5) |
|
||||
((blue & 0xf800) >> 11);
|
||||
break;
|
||||
case 24:
|
||||
case 32:
|
||||
fb->pseudo_palette[regno] =
|
||||
(((red >> 8) & 0xff) << info->var.red.offset) |
|
||||
(((green >> 8) & 0xff) << info->var.green.offset) |
|
||||
(((blue >> 8) & 0xff) << info->var.blue.offset);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL(drm_fb_helper_setcolreg);
|
||||
|
||||
int drm_fb_helper_check_var(struct fb_var_screeninfo *var,
|
||||
struct fb_info *info)
|
||||
{
|
||||
struct drm_fb_helper *fb_helper = info->par;
|
||||
struct drm_framebuffer *fb = fb_helper->fb;
|
||||
int depth;
|
||||
|
||||
if (var->pixclock == -1 || !var->pixclock)
|
||||
return -EINVAL;
|
||||
|
||||
/* Need to resize the fb object !!! */
|
||||
if (var->xres > fb->width || var->yres > fb->height) {
|
||||
DRM_ERROR("Requested width/height is greater than current fb "
|
||||
"object %dx%d > %dx%d\n", var->xres, var->yres,
|
||||
fb->width, fb->height);
|
||||
DRM_ERROR("Need resizing code.\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
switch (var->bits_per_pixel) {
|
||||
case 16:
|
||||
depth = (var->green.length == 6) ? 16 : 15;
|
||||
break;
|
||||
case 32:
|
||||
depth = (var->transp.length > 0) ? 32 : 24;
|
||||
break;
|
||||
default:
|
||||
depth = var->bits_per_pixel;
|
||||
break;
|
||||
}
|
||||
|
||||
switch (depth) {
|
||||
case 8:
|
||||
var->red.offset = 0;
|
||||
var->green.offset = 0;
|
||||
var->blue.offset = 0;
|
||||
var->red.length = 8;
|
||||
var->green.length = 8;
|
||||
var->blue.length = 8;
|
||||
var->transp.length = 0;
|
||||
var->transp.offset = 0;
|
||||
break;
|
||||
case 15:
|
||||
var->red.offset = 10;
|
||||
var->green.offset = 5;
|
||||
var->blue.offset = 0;
|
||||
var->red.length = 5;
|
||||
var->green.length = 5;
|
||||
var->blue.length = 5;
|
||||
var->transp.length = 1;
|
||||
var->transp.offset = 15;
|
||||
break;
|
||||
case 16:
|
||||
var->red.offset = 11;
|
||||
var->green.offset = 5;
|
||||
var->blue.offset = 0;
|
||||
var->red.length = 5;
|
||||
var->green.length = 6;
|
||||
var->blue.length = 5;
|
||||
var->transp.length = 0;
|
||||
var->transp.offset = 0;
|
||||
break;
|
||||
case 24:
|
||||
var->red.offset = 16;
|
||||
var->green.offset = 8;
|
||||
var->blue.offset = 0;
|
||||
var->red.length = 8;
|
||||
var->green.length = 8;
|
||||
var->blue.length = 8;
|
||||
var->transp.length = 0;
|
||||
var->transp.offset = 0;
|
||||
break;
|
||||
case 32:
|
||||
var->red.offset = 16;
|
||||
var->green.offset = 8;
|
||||
var->blue.offset = 0;
|
||||
var->red.length = 8;
|
||||
var->green.length = 8;
|
||||
var->blue.length = 8;
|
||||
var->transp.length = 8;
|
||||
var->transp.offset = 24;
|
||||
break;
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL(drm_fb_helper_check_var);
|
||||
|
||||
/* this will let fbcon do the mode init */
|
||||
int drm_fb_helper_set_par(struct fb_info *info)
|
||||
{
|
||||
struct drm_fb_helper *fb_helper = info->par;
|
||||
struct drm_device *dev = fb_helper->dev;
|
||||
struct fb_var_screeninfo *var = &info->var;
|
||||
struct drm_crtc *crtc;
|
||||
int ret;
|
||||
int i;
|
||||
|
||||
if (var->pixclock != -1) {
|
||||
DRM_ERROR("PIXEL CLCOK SET\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) {
|
||||
|
||||
for (i = 0; i < fb_helper->crtc_count; i++) {
|
||||
if (crtc->base.id == fb_helper->crtc_info[i].crtc_id)
|
||||
break;
|
||||
}
|
||||
if (i == fb_helper->crtc_count)
|
||||
continue;
|
||||
|
||||
if (crtc->fb == fb_helper->crtc_info[i].mode_set.fb) {
|
||||
mutex_lock(&dev->mode_config.mutex);
|
||||
ret = crtc->funcs->set_config(&fb_helper->crtc_info->mode_set);
|
||||
mutex_unlock(&dev->mode_config.mutex);
|
||||
if (ret)
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL(drm_fb_helper_set_par);
|
||||
|
||||
int drm_fb_helper_pan_display(struct fb_var_screeninfo *var,
|
||||
struct fb_info *info)
|
||||
{
|
||||
struct drm_fb_helper *fb_helper = info->par;
|
||||
struct drm_device *dev = fb_helper->dev;
|
||||
struct drm_mode_set *modeset;
|
||||
struct drm_crtc *crtc;
|
||||
int ret = 0;
|
||||
int i;
|
||||
|
||||
list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) {
|
||||
for (i = 0; i < fb_helper->crtc_count; i++) {
|
||||
if (crtc->base.id == fb_helper->crtc_info[i].crtc_id)
|
||||
break;
|
||||
}
|
||||
|
||||
if (i == fb_helper->crtc_count)
|
||||
continue;
|
||||
|
||||
modeset = &fb_helper->crtc_info[i].mode_set;
|
||||
|
||||
modeset->x = var->xoffset;
|
||||
modeset->y = var->yoffset;
|
||||
|
||||
if (modeset->num_connectors) {
|
||||
mutex_lock(&dev->mode_config.mutex);
|
||||
ret = crtc->funcs->set_config(modeset);
|
||||
mutex_unlock(&dev->mode_config.mutex);
|
||||
if (!ret) {
|
||||
info->var.xoffset = var->xoffset;
|
||||
info->var.yoffset = var->yoffset;
|
||||
}
|
||||
}
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
EXPORT_SYMBOL(drm_fb_helper_pan_display);
|
||||
|
||||
int drm_fb_helper_single_fb_probe(struct drm_device *dev,
|
||||
int (*fb_create)(struct drm_device *dev,
|
||||
uint32_t fb_width,
|
||||
uint32_t fb_height,
|
||||
uint32_t surface_width,
|
||||
uint32_t surface_height,
|
||||
struct drm_framebuffer **fb_ptr))
|
||||
{
|
||||
struct drm_crtc *crtc;
|
||||
struct drm_connector *connector;
|
||||
unsigned int fb_width = (unsigned)-1, fb_height = (unsigned)-1;
|
||||
unsigned int surface_width = 0, surface_height = 0;
|
||||
int new_fb = 0;
|
||||
int crtc_count = 0;
|
||||
int ret, i, conn_count = 0;
|
||||
struct fb_info *info;
|
||||
struct drm_framebuffer *fb;
|
||||
struct drm_mode_set *modeset = NULL;
|
||||
struct drm_fb_helper *fb_helper;
|
||||
|
||||
/* first up get a count of crtcs now in use and new min/maxes width/heights */
|
||||
list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) {
|
||||
if (drm_helper_crtc_in_use(crtc)) {
|
||||
if (crtc->desired_mode) {
|
||||
if (crtc->desired_mode->hdisplay < fb_width)
|
||||
fb_width = crtc->desired_mode->hdisplay;
|
||||
|
||||
if (crtc->desired_mode->vdisplay < fb_height)
|
||||
fb_height = crtc->desired_mode->vdisplay;
|
||||
|
||||
if (crtc->desired_mode->hdisplay > surface_width)
|
||||
surface_width = crtc->desired_mode->hdisplay;
|
||||
|
||||
if (crtc->desired_mode->vdisplay > surface_height)
|
||||
surface_height = crtc->desired_mode->vdisplay;
|
||||
}
|
||||
crtc_count++;
|
||||
}
|
||||
}
|
||||
|
||||
if (crtc_count == 0 || fb_width == -1 || fb_height == -1) {
|
||||
/* hmm everyone went away - assume VGA cable just fell out
|
||||
and will come back later. */
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* do we have an fb already? */
|
||||
if (list_empty(&dev->mode_config.fb_kernel_list)) {
|
||||
ret = (*fb_create)(dev, fb_width, fb_height, surface_width,
|
||||
surface_height, &fb);
|
||||
if (ret)
|
||||
return -EINVAL;
|
||||
new_fb = 1;
|
||||
} else {
|
||||
fb = list_first_entry(&dev->mode_config.fb_kernel_list,
|
||||
struct drm_framebuffer, filp_head);
|
||||
|
||||
/* if someone hotplugs something bigger than we have already allocated, we are pwned.
|
||||
As really we can't resize an fbdev that is in the wild currently due to fbdev
|
||||
not really being designed for the lower layers moving stuff around under it.
|
||||
- so in the grand style of things - punt. */
|
||||
if ((fb->width < surface_width) ||
|
||||
(fb->height < surface_height)) {
|
||||
DRM_ERROR("Framebuffer not large enough to scale console onto.\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
}
|
||||
|
||||
info = fb->fbdev;
|
||||
fb_helper = info->par;
|
||||
|
||||
crtc_count = 0;
|
||||
/* okay we need to setup new connector sets in the crtcs */
|
||||
list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) {
|
||||
modeset = &fb_helper->crtc_info[crtc_count].mode_set;
|
||||
modeset->fb = fb;
|
||||
conn_count = 0;
|
||||
list_for_each_entry(connector, &dev->mode_config.connector_list, head) {
|
||||
if (connector->encoder)
|
||||
if (connector->encoder->crtc == modeset->crtc) {
|
||||
modeset->connectors[conn_count] = connector;
|
||||
conn_count++;
|
||||
if (conn_count > fb_helper->conn_limit)
|
||||
BUG();
|
||||
}
|
||||
}
|
||||
|
||||
for (i = conn_count; i < fb_helper->conn_limit; i++)
|
||||
modeset->connectors[i] = NULL;
|
||||
|
||||
modeset->crtc = crtc;
|
||||
crtc_count++;
|
||||
|
||||
modeset->num_connectors = conn_count;
|
||||
if (modeset->crtc->desired_mode) {
|
||||
if (modeset->mode)
|
||||
drm_mode_destroy(dev, modeset->mode);
|
||||
modeset->mode = drm_mode_duplicate(dev,
|
||||
modeset->crtc->desired_mode);
|
||||
}
|
||||
}
|
||||
fb_helper->crtc_count = crtc_count;
|
||||
fb_helper->fb = fb;
|
||||
|
||||
if (new_fb) {
|
||||
info->var.pixclock = -1;
|
||||
if (register_framebuffer(info) < 0)
|
||||
return -EINVAL;
|
||||
} else {
|
||||
drm_fb_helper_set_par(info);
|
||||
}
|
||||
printk(KERN_INFO "fb%d: %s frame buffer device\n", info->node,
|
||||
info->fix.id);
|
||||
|
||||
/* Switch back to kernel console on panic */
|
||||
/* multi card linked list maybe */
|
||||
if (list_empty(&kernel_fb_helper_list)) {
|
||||
printk(KERN_INFO "registered panic notifier\n");
|
||||
atomic_notifier_chain_register(&panic_notifier_list,
|
||||
&paniced);
|
||||
register_sysrq_key('v', &sysrq_drm_fb_helper_restore_op);
|
||||
}
|
||||
list_add(&fb_helper->kernel_fb_list, &kernel_fb_helper_list);
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL(drm_fb_helper_single_fb_probe);
|
||||
|
||||
void drm_fb_helper_free(struct drm_fb_helper *helper)
|
||||
{
|
||||
list_del(&helper->kernel_fb_list);
|
||||
if (list_empty(&kernel_fb_helper_list)) {
|
||||
printk(KERN_INFO "unregistered panic notifier\n");
|
||||
atomic_notifier_chain_unregister(&panic_notifier_list,
|
||||
&paniced);
|
||||
unregister_sysrq_key('v', &sysrq_drm_fb_helper_restore_op);
|
||||
}
|
||||
drm_fb_helper_crtc_free(helper);
|
||||
}
|
||||
EXPORT_SYMBOL(drm_fb_helper_free);
|
||||
|
||||
void drm_fb_helper_fill_fix(struct fb_info *info, uint32_t pitch)
|
||||
{
|
||||
info->fix.type = FB_TYPE_PACKED_PIXELS;
|
||||
info->fix.visual = FB_VISUAL_TRUECOLOR;
|
||||
info->fix.type_aux = 0;
|
||||
info->fix.xpanstep = 1; /* doing it in hw */
|
||||
info->fix.ypanstep = 1; /* doing it in hw */
|
||||
info->fix.ywrapstep = 0;
|
||||
info->fix.accel = FB_ACCEL_NONE;
|
||||
info->fix.type_aux = 0;
|
||||
|
||||
info->fix.line_length = pitch;
|
||||
return;
|
||||
}
|
||||
EXPORT_SYMBOL(drm_fb_helper_fill_fix);
|
||||
|
||||
void drm_fb_helper_fill_var(struct fb_info *info, struct drm_framebuffer *fb,
|
||||
uint32_t fb_width, uint32_t fb_height)
|
||||
{
|
||||
info->pseudo_palette = fb->pseudo_palette;
|
||||
info->var.xres_virtual = fb->width;
|
||||
info->var.yres_virtual = fb->height;
|
||||
info->var.bits_per_pixel = fb->bits_per_pixel;
|
||||
info->var.xoffset = 0;
|
||||
info->var.yoffset = 0;
|
||||
info->var.activate = FB_ACTIVATE_NOW;
|
||||
info->var.height = -1;
|
||||
info->var.width = -1;
|
||||
|
||||
switch (fb->depth) {
|
||||
case 8:
|
||||
info->var.red.offset = 0;
|
||||
info->var.green.offset = 0;
|
||||
info->var.blue.offset = 0;
|
||||
info->var.red.length = 8; /* 8bit DAC */
|
||||
info->var.green.length = 8;
|
||||
info->var.blue.length = 8;
|
||||
info->var.transp.offset = 0;
|
||||
info->var.transp.length = 0;
|
||||
break;
|
||||
case 15:
|
||||
info->var.red.offset = 10;
|
||||
info->var.green.offset = 5;
|
||||
info->var.blue.offset = 0;
|
||||
info->var.red.length = 5;
|
||||
info->var.green.length = 5;
|
||||
info->var.blue.length = 5;
|
||||
info->var.transp.offset = 15;
|
||||
info->var.transp.length = 1;
|
||||
break;
|
||||
case 16:
|
||||
info->var.red.offset = 11;
|
||||
info->var.green.offset = 5;
|
||||
info->var.blue.offset = 0;
|
||||
info->var.red.length = 5;
|
||||
info->var.green.length = 6;
|
||||
info->var.blue.length = 5;
|
||||
info->var.transp.offset = 0;
|
||||
break;
|
||||
case 24:
|
||||
info->var.red.offset = 16;
|
||||
info->var.green.offset = 8;
|
||||
info->var.blue.offset = 0;
|
||||
info->var.red.length = 8;
|
||||
info->var.green.length = 8;
|
||||
info->var.blue.length = 8;
|
||||
info->var.transp.offset = 0;
|
||||
info->var.transp.length = 0;
|
||||
break;
|
||||
case 32:
|
||||
info->var.red.offset = 16;
|
||||
info->var.green.offset = 8;
|
||||
info->var.blue.offset = 0;
|
||||
info->var.red.length = 8;
|
||||
info->var.green.length = 8;
|
||||
info->var.blue.length = 8;
|
||||
info->var.transp.offset = 24;
|
||||
info->var.transp.length = 8;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
info->var.xres = fb_width;
|
||||
info->var.yres = fb_height;
|
||||
}
|
||||
EXPORT_SYMBOL(drm_fb_helper_fill_var);
|
||||
|
|
@ -164,7 +164,7 @@ EXPORT_SYMBOL(drm_gem_object_alloc);
|
|||
* Removes the mapping from handle to filp for this object.
|
||||
*/
|
||||
static int
|
||||
drm_gem_handle_delete(struct drm_file *filp, int handle)
|
||||
drm_gem_handle_delete(struct drm_file *filp, u32 handle)
|
||||
{
|
||||
struct drm_device *dev;
|
||||
struct drm_gem_object *obj;
|
||||
|
|
@ -207,7 +207,7 @@ drm_gem_handle_delete(struct drm_file *filp, int handle)
|
|||
int
|
||||
drm_gem_handle_create(struct drm_file *file_priv,
|
||||
struct drm_gem_object *obj,
|
||||
int *handlep)
|
||||
u32 *handlep)
|
||||
{
|
||||
int ret;
|
||||
|
||||
|
|
@ -221,7 +221,7 @@ again:
|
|||
|
||||
/* do the allocation under our spinlock */
|
||||
spin_lock(&file_priv->table_lock);
|
||||
ret = idr_get_new_above(&file_priv->object_idr, obj, 1, handlep);
|
||||
ret = idr_get_new_above(&file_priv->object_idr, obj, 1, (int *)handlep);
|
||||
spin_unlock(&file_priv->table_lock);
|
||||
if (ret == -EAGAIN)
|
||||
goto again;
|
||||
|
|
@ -237,7 +237,7 @@ EXPORT_SYMBOL(drm_gem_handle_create);
|
|||
/** Returns a reference to the object named by the handle. */
|
||||
struct drm_gem_object *
|
||||
drm_gem_object_lookup(struct drm_device *dev, struct drm_file *filp,
|
||||
int handle)
|
||||
u32 handle)
|
||||
{
|
||||
struct drm_gem_object *obj;
|
||||
|
||||
|
|
@ -344,7 +344,7 @@ drm_gem_open_ioctl(struct drm_device *dev, void *data,
|
|||
struct drm_gem_open *args = data;
|
||||
struct drm_gem_object *obj;
|
||||
int ret;
|
||||
int handle;
|
||||
u32 handle;
|
||||
|
||||
if (!(dev->driver->driver_features & DRIVER_GEM))
|
||||
return -ENODEV;
|
||||
|
|
@ -539,7 +539,6 @@ int drm_gem_mmap(struct file *filp, struct vm_area_struct *vma)
|
|||
vma->vm_flags |= VM_RESERVED | VM_IO | VM_PFNMAP | VM_DONTEXPAND;
|
||||
vma->vm_ops = obj->dev->driver->gem_vm_ops;
|
||||
vma->vm_private_data = map->handle;
|
||||
/* FIXME: use pgprot_writecombine when available */
|
||||
vma->vm_page_prot = pgprot_writecombine(vma->vm_page_prot);
|
||||
|
||||
/* Take a ref for this mapping of the object, so that the fault
|
||||
|
|
|
|||
|
|
@ -37,6 +37,7 @@
|
|||
|
||||
#include <linux/interrupt.h> /* For task queue support */
|
||||
|
||||
#include <linux/vgaarb.h>
|
||||
/**
|
||||
* Get interrupt from bus id.
|
||||
*
|
||||
|
|
@ -171,6 +172,26 @@ err:
|
|||
}
|
||||
EXPORT_SYMBOL(drm_vblank_init);
|
||||
|
||||
static void drm_irq_vgaarb_nokms(void *cookie, bool state)
|
||||
{
|
||||
struct drm_device *dev = cookie;
|
||||
|
||||
if (dev->driver->vgaarb_irq) {
|
||||
dev->driver->vgaarb_irq(dev, state);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!dev->irq_enabled)
|
||||
return;
|
||||
|
||||
if (state)
|
||||
dev->driver->irq_uninstall(dev);
|
||||
else {
|
||||
dev->driver->irq_preinstall(dev);
|
||||
dev->driver->irq_postinstall(dev);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Install IRQ handler.
|
||||
*
|
||||
|
|
@ -231,6 +252,9 @@ int drm_irq_install(struct drm_device *dev)
|
|||
return ret;
|
||||
}
|
||||
|
||||
if (!drm_core_check_feature(dev, DRIVER_MODESET))
|
||||
vga_client_register(dev->pdev, (void *)dev, drm_irq_vgaarb_nokms, NULL);
|
||||
|
||||
/* After installing handler */
|
||||
ret = dev->driver->irq_postinstall(dev);
|
||||
if (ret < 0) {
|
||||
|
|
@ -279,6 +303,9 @@ int drm_irq_uninstall(struct drm_device * dev)
|
|||
|
||||
DRM_DEBUG("irq=%d\n", dev->pdev->irq);
|
||||
|
||||
if (!drm_core_check_feature(dev, DRIVER_MODESET))
|
||||
vga_client_register(dev->pdev, NULL, NULL, NULL);
|
||||
|
||||
dev->driver->irq_uninstall(dev);
|
||||
|
||||
free_irq(dev->pdev->irq, dev);
|
||||
|
|
|
|||
|
|
@ -44,6 +44,7 @@
|
|||
#include "drmP.h"
|
||||
#include "drm_mm.h"
|
||||
#include <linux/slab.h>
|
||||
#include <linux/seq_file.h>
|
||||
|
||||
#define MM_UNUSED_TARGET 4
|
||||
|
||||
|
|
@ -370,3 +371,23 @@ void drm_mm_takedown(struct drm_mm * mm)
|
|||
BUG_ON(mm->num_unused != 0);
|
||||
}
|
||||
EXPORT_SYMBOL(drm_mm_takedown);
|
||||
|
||||
#if defined(CONFIG_DEBUG_FS)
|
||||
int drm_mm_dump_table(struct seq_file *m, struct drm_mm *mm)
|
||||
{
|
||||
struct drm_mm_node *entry;
|
||||
int total_used = 0, total_free = 0, total = 0;
|
||||
|
||||
list_for_each_entry(entry, &mm->ml_entry, ml_entry) {
|
||||
seq_printf(m, "0x%08lx-0x%08lx: 0x%08lx: %s\n", entry->start, entry->start + entry->size, entry->size, entry->free ? "free" : "used");
|
||||
total += entry->size;
|
||||
if (entry->free)
|
||||
total_free += entry->size;
|
||||
else
|
||||
total_used += entry->size;
|
||||
}
|
||||
seq_printf(m, "total: %d, used %d free %d\n", total, total_free, total_used);
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL(drm_mm_dump_table);
|
||||
#endif
|
||||
|
|
|
|||
|
|
@ -8,6 +8,8 @@
|
|||
* Copyright © 2007 Dave Airlie
|
||||
* Copyright © 2007-2008 Intel Corporation
|
||||
* Jesse Barnes <jesse.barnes@intel.com>
|
||||
* Copyright 2005-2006 Luc Verhaegen
|
||||
* Copyright (c) 2001, Andy Ritger aritger@nvidia.com
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a
|
||||
* copy of this software and associated documentation files (the "Software"),
|
||||
|
|
@ -38,7 +40,6 @@
|
|||
#include "drm.h"
|
||||
#include "drm_crtc.h"
|
||||
|
||||
#define DRM_MODESET_DEBUG "drm_mode"
|
||||
/**
|
||||
* drm_mode_debug_printmodeline - debug print a mode
|
||||
* @dev: DRM device
|
||||
|
|
@ -51,8 +52,8 @@
|
|||
*/
|
||||
void drm_mode_debug_printmodeline(struct drm_display_mode *mode)
|
||||
{
|
||||
DRM_DEBUG_MODE(DRM_MODESET_DEBUG,
|
||||
"Modeline %d:\"%s\" %d %d %d %d %d %d %d %d %d %d 0x%x 0x%x\n",
|
||||
DRM_DEBUG_KMS("Modeline %d:\"%s\" %d %d %d %d %d %d %d %d %d %d "
|
||||
"0x%x 0x%x\n",
|
||||
mode->base.id, mode->name, mode->vrefresh, mode->clock,
|
||||
mode->hdisplay, mode->hsync_start,
|
||||
mode->hsync_end, mode->htotal,
|
||||
|
|
@ -61,6 +62,420 @@ void drm_mode_debug_printmodeline(struct drm_display_mode *mode)
|
|||
}
|
||||
EXPORT_SYMBOL(drm_mode_debug_printmodeline);
|
||||
|
||||
/**
|
||||
* drm_cvt_mode -create a modeline based on CVT algorithm
|
||||
* @dev: DRM device
|
||||
* @hdisplay: hdisplay size
|
||||
* @vdisplay: vdisplay size
|
||||
* @vrefresh : vrefresh rate
|
||||
* @reduced : Whether the GTF calculation is simplified
|
||||
* @interlaced:Whether the interlace is supported
|
||||
*
|
||||
* LOCKING:
|
||||
* none.
|
||||
*
|
||||
* return the modeline based on CVT algorithm
|
||||
*
|
||||
* This function is called to generate the modeline based on CVT algorithm
|
||||
* according to the hdisplay, vdisplay, vrefresh.
|
||||
* It is based from the VESA(TM) Coordinated Video Timing Generator by
|
||||
* Graham Loveridge April 9, 2003 available at
|
||||
* http://www.vesa.org/public/CVT/CVTd6r1.xls
|
||||
*
|
||||
* And it is copied from xf86CVTmode in xserver/hw/xfree86/modes/xf86cvt.c.
|
||||
* What I have done is to translate it by using integer calculation.
|
||||
*/
|
||||
#define HV_FACTOR 1000
|
||||
struct drm_display_mode *drm_cvt_mode(struct drm_device *dev, int hdisplay,
|
||||
int vdisplay, int vrefresh,
|
||||
bool reduced, bool interlaced)
|
||||
{
|
||||
/* 1) top/bottom margin size (% of height) - default: 1.8, */
|
||||
#define CVT_MARGIN_PERCENTAGE 18
|
||||
/* 2) character cell horizontal granularity (pixels) - default 8 */
|
||||
#define CVT_H_GRANULARITY 8
|
||||
/* 3) Minimum vertical porch (lines) - default 3 */
|
||||
#define CVT_MIN_V_PORCH 3
|
||||
/* 4) Minimum number of vertical back porch lines - default 6 */
|
||||
#define CVT_MIN_V_BPORCH 6
|
||||
/* Pixel Clock step (kHz) */
|
||||
#define CVT_CLOCK_STEP 250
|
||||
struct drm_display_mode *drm_mode;
|
||||
bool margins = false;
|
||||
unsigned int vfieldrate, hperiod;
|
||||
int hdisplay_rnd, hmargin, vdisplay_rnd, vmargin, vsync;
|
||||
int interlace;
|
||||
|
||||
/* allocate the drm_display_mode structure. If failure, we will
|
||||
* return directly
|
||||
*/
|
||||
drm_mode = drm_mode_create(dev);
|
||||
if (!drm_mode)
|
||||
return NULL;
|
||||
|
||||
/* the CVT default refresh rate is 60Hz */
|
||||
if (!vrefresh)
|
||||
vrefresh = 60;
|
||||
|
||||
/* the required field fresh rate */
|
||||
if (interlaced)
|
||||
vfieldrate = vrefresh * 2;
|
||||
else
|
||||
vfieldrate = vrefresh;
|
||||
|
||||
/* horizontal pixels */
|
||||
hdisplay_rnd = hdisplay - (hdisplay % CVT_H_GRANULARITY);
|
||||
|
||||
/* determine the left&right borders */
|
||||
hmargin = 0;
|
||||
if (margins) {
|
||||
hmargin = hdisplay_rnd * CVT_MARGIN_PERCENTAGE / 1000;
|
||||
hmargin -= hmargin % CVT_H_GRANULARITY;
|
||||
}
|
||||
/* find the total active pixels */
|
||||
drm_mode->hdisplay = hdisplay_rnd + 2 * hmargin;
|
||||
|
||||
/* find the number of lines per field */
|
||||
if (interlaced)
|
||||
vdisplay_rnd = vdisplay / 2;
|
||||
else
|
||||
vdisplay_rnd = vdisplay;
|
||||
|
||||
/* find the top & bottom borders */
|
||||
vmargin = 0;
|
||||
if (margins)
|
||||
vmargin = vdisplay_rnd * CVT_MARGIN_PERCENTAGE / 1000;
|
||||
|
||||
drm_mode->vdisplay = vdisplay + 2 * vmargin;
|
||||
|
||||
/* Interlaced */
|
||||
if (interlaced)
|
||||
interlace = 1;
|
||||
else
|
||||
interlace = 0;
|
||||
|
||||
/* Determine VSync Width from aspect ratio */
|
||||
if (!(vdisplay % 3) && ((vdisplay * 4 / 3) == hdisplay))
|
||||
vsync = 4;
|
||||
else if (!(vdisplay % 9) && ((vdisplay * 16 / 9) == hdisplay))
|
||||
vsync = 5;
|
||||
else if (!(vdisplay % 10) && ((vdisplay * 16 / 10) == hdisplay))
|
||||
vsync = 6;
|
||||
else if (!(vdisplay % 4) && ((vdisplay * 5 / 4) == hdisplay))
|
||||
vsync = 7;
|
||||
else if (!(vdisplay % 9) && ((vdisplay * 15 / 9) == hdisplay))
|
||||
vsync = 7;
|
||||
else /* custom */
|
||||
vsync = 10;
|
||||
|
||||
if (!reduced) {
|
||||
/* simplify the GTF calculation */
|
||||
/* 4) Minimum time of vertical sync + back porch interval (µs)
|
||||
* default 550.0
|
||||
*/
|
||||
int tmp1, tmp2;
|
||||
#define CVT_MIN_VSYNC_BP 550
|
||||
/* 3) Nominal HSync width (% of line period) - default 8 */
|
||||
#define CVT_HSYNC_PERCENTAGE 8
|
||||
unsigned int hblank_percentage;
|
||||
int vsyncandback_porch, vback_porch, hblank;
|
||||
|
||||
/* estimated the horizontal period */
|
||||
tmp1 = HV_FACTOR * 1000000 -
|
||||
CVT_MIN_VSYNC_BP * HV_FACTOR * vfieldrate;
|
||||
tmp2 = (vdisplay_rnd + 2 * vmargin + CVT_MIN_V_PORCH) * 2 +
|
||||
interlace;
|
||||
hperiod = tmp1 * 2 / (tmp2 * vfieldrate);
|
||||
|
||||
tmp1 = CVT_MIN_VSYNC_BP * HV_FACTOR / hperiod + 1;
|
||||
/* 9. Find number of lines in sync + backporch */
|
||||
if (tmp1 < (vsync + CVT_MIN_V_PORCH))
|
||||
vsyncandback_porch = vsync + CVT_MIN_V_PORCH;
|
||||
else
|
||||
vsyncandback_porch = tmp1;
|
||||
/* 10. Find number of lines in back porch */
|
||||
vback_porch = vsyncandback_porch - vsync;
|
||||
drm_mode->vtotal = vdisplay_rnd + 2 * vmargin +
|
||||
vsyncandback_porch + CVT_MIN_V_PORCH;
|
||||
/* 5) Definition of Horizontal blanking time limitation */
|
||||
/* Gradient (%/kHz) - default 600 */
|
||||
#define CVT_M_FACTOR 600
|
||||
/* Offset (%) - default 40 */
|
||||
#define CVT_C_FACTOR 40
|
||||
/* Blanking time scaling factor - default 128 */
|
||||
#define CVT_K_FACTOR 128
|
||||
/* Scaling factor weighting - default 20 */
|
||||
#define CVT_J_FACTOR 20
|
||||
#define CVT_M_PRIME (CVT_M_FACTOR * CVT_K_FACTOR / 256)
|
||||
#define CVT_C_PRIME ((CVT_C_FACTOR - CVT_J_FACTOR) * CVT_K_FACTOR / 256 + \
|
||||
CVT_J_FACTOR)
|
||||
/* 12. Find ideal blanking duty cycle from formula */
|
||||
hblank_percentage = CVT_C_PRIME * HV_FACTOR - CVT_M_PRIME *
|
||||
hperiod / 1000;
|
||||
/* 13. Blanking time */
|
||||
if (hblank_percentage < 20 * HV_FACTOR)
|
||||
hblank_percentage = 20 * HV_FACTOR;
|
||||
hblank = drm_mode->hdisplay * hblank_percentage /
|
||||
(100 * HV_FACTOR - hblank_percentage);
|
||||
hblank -= hblank % (2 * CVT_H_GRANULARITY);
|
||||
/* 14. find the total pixes per line */
|
||||
drm_mode->htotal = drm_mode->hdisplay + hblank;
|
||||
drm_mode->hsync_end = drm_mode->hdisplay + hblank / 2;
|
||||
drm_mode->hsync_start = drm_mode->hsync_end -
|
||||
(drm_mode->htotal * CVT_HSYNC_PERCENTAGE) / 100;
|
||||
drm_mode->hsync_start += CVT_H_GRANULARITY -
|
||||
drm_mode->hsync_start % CVT_H_GRANULARITY;
|
||||
/* fill the Vsync values */
|
||||
drm_mode->vsync_start = drm_mode->vdisplay + CVT_MIN_V_PORCH;
|
||||
drm_mode->vsync_end = drm_mode->vsync_start + vsync;
|
||||
} else {
|
||||
/* Reduced blanking */
|
||||
/* Minimum vertical blanking interval time (µs)- default 460 */
|
||||
#define CVT_RB_MIN_VBLANK 460
|
||||
/* Fixed number of clocks for horizontal sync */
|
||||
#define CVT_RB_H_SYNC 32
|
||||
/* Fixed number of clocks for horizontal blanking */
|
||||
#define CVT_RB_H_BLANK 160
|
||||
/* Fixed number of lines for vertical front porch - default 3*/
|
||||
#define CVT_RB_VFPORCH 3
|
||||
int vbilines;
|
||||
int tmp1, tmp2;
|
||||
/* 8. Estimate Horizontal period. */
|
||||
tmp1 = HV_FACTOR * 1000000 -
|
||||
CVT_RB_MIN_VBLANK * HV_FACTOR * vfieldrate;
|
||||
tmp2 = vdisplay_rnd + 2 * vmargin;
|
||||
hperiod = tmp1 / (tmp2 * vfieldrate);
|
||||
/* 9. Find number of lines in vertical blanking */
|
||||
vbilines = CVT_RB_MIN_VBLANK * HV_FACTOR / hperiod + 1;
|
||||
/* 10. Check if vertical blanking is sufficient */
|
||||
if (vbilines < (CVT_RB_VFPORCH + vsync + CVT_MIN_V_BPORCH))
|
||||
vbilines = CVT_RB_VFPORCH + vsync + CVT_MIN_V_BPORCH;
|
||||
/* 11. Find total number of lines in vertical field */
|
||||
drm_mode->vtotal = vdisplay_rnd + 2 * vmargin + vbilines;
|
||||
/* 12. Find total number of pixels in a line */
|
||||
drm_mode->htotal = drm_mode->hdisplay + CVT_RB_H_BLANK;
|
||||
/* Fill in HSync values */
|
||||
drm_mode->hsync_end = drm_mode->hdisplay + CVT_RB_H_BLANK / 2;
|
||||
drm_mode->hsync_start = drm_mode->hsync_end = CVT_RB_H_SYNC;
|
||||
}
|
||||
/* 15/13. Find pixel clock frequency (kHz for xf86) */
|
||||
drm_mode->clock = drm_mode->htotal * HV_FACTOR * 1000 / hperiod;
|
||||
drm_mode->clock -= drm_mode->clock % CVT_CLOCK_STEP;
|
||||
/* 18/16. Find actual vertical frame frequency */
|
||||
/* ignore - just set the mode flag for interlaced */
|
||||
if (interlaced)
|
||||
drm_mode->vtotal *= 2;
|
||||
/* Fill the mode line name */
|
||||
drm_mode_set_name(drm_mode);
|
||||
if (reduced)
|
||||
drm_mode->flags |= (DRM_MODE_FLAG_PHSYNC |
|
||||
DRM_MODE_FLAG_NVSYNC);
|
||||
else
|
||||
drm_mode->flags |= (DRM_MODE_FLAG_PVSYNC |
|
||||
DRM_MODE_FLAG_NHSYNC);
|
||||
if (interlaced)
|
||||
drm_mode->flags |= DRM_MODE_FLAG_INTERLACE;
|
||||
|
||||
return drm_mode;
|
||||
}
|
||||
EXPORT_SYMBOL(drm_cvt_mode);
|
||||
|
||||
/**
|
||||
* drm_gtf_mode - create the modeline based on GTF algorithm
|
||||
*
|
||||
* @dev :drm device
|
||||
* @hdisplay :hdisplay size
|
||||
* @vdisplay :vdisplay size
|
||||
* @vrefresh :vrefresh rate.
|
||||
* @interlaced :whether the interlace is supported
|
||||
* @margins :whether the margin is supported
|
||||
*
|
||||
* LOCKING.
|
||||
* none.
|
||||
*
|
||||
* return the modeline based on GTF algorithm
|
||||
*
|
||||
* This function is to create the modeline based on the GTF algorithm.
|
||||
* Generalized Timing Formula is derived from:
|
||||
* GTF Spreadsheet by Andy Morrish (1/5/97)
|
||||
* available at http://www.vesa.org
|
||||
*
|
||||
* And it is copied from the file of xserver/hw/xfree86/modes/xf86gtf.c.
|
||||
* What I have done is to translate it by using integer calculation.
|
||||
* I also refer to the function of fb_get_mode in the file of
|
||||
* drivers/video/fbmon.c
|
||||
*/
|
||||
struct drm_display_mode *drm_gtf_mode(struct drm_device *dev, int hdisplay,
|
||||
int vdisplay, int vrefresh,
|
||||
bool interlaced, int margins)
|
||||
{
|
||||
/* 1) top/bottom margin size (% of height) - default: 1.8, */
|
||||
#define GTF_MARGIN_PERCENTAGE 18
|
||||
/* 2) character cell horizontal granularity (pixels) - default 8 */
|
||||
#define GTF_CELL_GRAN 8
|
||||
/* 3) Minimum vertical porch (lines) - default 3 */
|
||||
#define GTF_MIN_V_PORCH 1
|
||||
/* width of vsync in lines */
|
||||
#define V_SYNC_RQD 3
|
||||
/* width of hsync as % of total line */
|
||||
#define H_SYNC_PERCENT 8
|
||||
/* min time of vsync + back porch (microsec) */
|
||||
#define MIN_VSYNC_PLUS_BP 550
|
||||
/* blanking formula gradient */
|
||||
#define GTF_M 600
|
||||
/* blanking formula offset */
|
||||
#define GTF_C 40
|
||||
/* blanking formula scaling factor */
|
||||
#define GTF_K 128
|
||||
/* blanking formula scaling factor */
|
||||
#define GTF_J 20
|
||||
/* C' and M' are part of the Blanking Duty Cycle computation */
|
||||
#define GTF_C_PRIME (((GTF_C - GTF_J) * GTF_K / 256) + GTF_J)
|
||||
#define GTF_M_PRIME (GTF_K * GTF_M / 256)
|
||||
struct drm_display_mode *drm_mode;
|
||||
unsigned int hdisplay_rnd, vdisplay_rnd, vfieldrate_rqd;
|
||||
int top_margin, bottom_margin;
|
||||
int interlace;
|
||||
unsigned int hfreq_est;
|
||||
int vsync_plus_bp, vback_porch;
|
||||
unsigned int vtotal_lines, vfieldrate_est, hperiod;
|
||||
unsigned int vfield_rate, vframe_rate;
|
||||
int left_margin, right_margin;
|
||||
unsigned int total_active_pixels, ideal_duty_cycle;
|
||||
unsigned int hblank, total_pixels, pixel_freq;
|
||||
int hsync, hfront_porch, vodd_front_porch_lines;
|
||||
unsigned int tmp1, tmp2;
|
||||
|
||||
drm_mode = drm_mode_create(dev);
|
||||
if (!drm_mode)
|
||||
return NULL;
|
||||
|
||||
/* 1. In order to give correct results, the number of horizontal
|
||||
* pixels requested is first processed to ensure that it is divisible
|
||||
* by the character size, by rounding it to the nearest character
|
||||
* cell boundary:
|
||||
*/
|
||||
hdisplay_rnd = (hdisplay + GTF_CELL_GRAN / 2) / GTF_CELL_GRAN;
|
||||
hdisplay_rnd = hdisplay_rnd * GTF_CELL_GRAN;
|
||||
|
||||
/* 2. If interlace is requested, the number of vertical lines assumed
|
||||
* by the calculation must be halved, as the computation calculates
|
||||
* the number of vertical lines per field.
|
||||
*/
|
||||
if (interlaced)
|
||||
vdisplay_rnd = vdisplay / 2;
|
||||
else
|
||||
vdisplay_rnd = vdisplay;
|
||||
|
||||
/* 3. Find the frame rate required: */
|
||||
if (interlaced)
|
||||
vfieldrate_rqd = vrefresh * 2;
|
||||
else
|
||||
vfieldrate_rqd = vrefresh;
|
||||
|
||||
/* 4. Find number of lines in Top margin: */
|
||||
top_margin = 0;
|
||||
if (margins)
|
||||
top_margin = (vdisplay_rnd * GTF_MARGIN_PERCENTAGE + 500) /
|
||||
1000;
|
||||
/* 5. Find number of lines in bottom margin: */
|
||||
bottom_margin = top_margin;
|
||||
|
||||
/* 6. If interlace is required, then set variable interlace: */
|
||||
if (interlaced)
|
||||
interlace = 1;
|
||||
else
|
||||
interlace = 0;
|
||||
|
||||
/* 7. Estimate the Horizontal frequency */
|
||||
{
|
||||
tmp1 = (1000000 - MIN_VSYNC_PLUS_BP * vfieldrate_rqd) / 500;
|
||||
tmp2 = (vdisplay_rnd + 2 * top_margin + GTF_MIN_V_PORCH) *
|
||||
2 + interlace;
|
||||
hfreq_est = (tmp2 * 1000 * vfieldrate_rqd) / tmp1;
|
||||
}
|
||||
|
||||
/* 8. Find the number of lines in V sync + back porch */
|
||||
/* [V SYNC+BP] = RINT(([MIN VSYNC+BP] * hfreq_est / 1000000)) */
|
||||
vsync_plus_bp = MIN_VSYNC_PLUS_BP * hfreq_est / 1000;
|
||||
vsync_plus_bp = (vsync_plus_bp + 500) / 1000;
|
||||
/* 9. Find the number of lines in V back porch alone: */
|
||||
vback_porch = vsync_plus_bp - V_SYNC_RQD;
|
||||
/* 10. Find the total number of lines in Vertical field period: */
|
||||
vtotal_lines = vdisplay_rnd + top_margin + bottom_margin +
|
||||
vsync_plus_bp + GTF_MIN_V_PORCH;
|
||||
/* 11. Estimate the Vertical field frequency: */
|
||||
vfieldrate_est = hfreq_est / vtotal_lines;
|
||||
/* 12. Find the actual horizontal period: */
|
||||
hperiod = 1000000 / (vfieldrate_rqd * vtotal_lines);
|
||||
|
||||
/* 13. Find the actual Vertical field frequency: */
|
||||
vfield_rate = hfreq_est / vtotal_lines;
|
||||
/* 14. Find the Vertical frame frequency: */
|
||||
if (interlaced)
|
||||
vframe_rate = vfield_rate / 2;
|
||||
else
|
||||
vframe_rate = vfield_rate;
|
||||
/* 15. Find number of pixels in left margin: */
|
||||
if (margins)
|
||||
left_margin = (hdisplay_rnd * GTF_MARGIN_PERCENTAGE + 500) /
|
||||
1000;
|
||||
else
|
||||
left_margin = 0;
|
||||
|
||||
/* 16.Find number of pixels in right margin: */
|
||||
right_margin = left_margin;
|
||||
/* 17.Find total number of active pixels in image and left and right */
|
||||
total_active_pixels = hdisplay_rnd + left_margin + right_margin;
|
||||
/* 18.Find the ideal blanking duty cycle from blanking duty cycle */
|
||||
ideal_duty_cycle = GTF_C_PRIME * 1000 -
|
||||
(GTF_M_PRIME * 1000000 / hfreq_est);
|
||||
/* 19.Find the number of pixels in the blanking time to the nearest
|
||||
* double character cell: */
|
||||
hblank = total_active_pixels * ideal_duty_cycle /
|
||||
(100000 - ideal_duty_cycle);
|
||||
hblank = (hblank + GTF_CELL_GRAN) / (2 * GTF_CELL_GRAN);
|
||||
hblank = hblank * 2 * GTF_CELL_GRAN;
|
||||
/* 20.Find total number of pixels: */
|
||||
total_pixels = total_active_pixels + hblank;
|
||||
/* 21.Find pixel clock frequency: */
|
||||
pixel_freq = total_pixels * hfreq_est / 1000;
|
||||
/* Stage 1 computations are now complete; I should really pass
|
||||
* the results to another function and do the Stage 2 computations,
|
||||
* but I only need a few more values so I'll just append the
|
||||
* computations here for now */
|
||||
/* 17. Find the number of pixels in the horizontal sync period: */
|
||||
hsync = H_SYNC_PERCENT * total_pixels / 100;
|
||||
hsync = (hsync + GTF_CELL_GRAN / 2) / GTF_CELL_GRAN;
|
||||
hsync = hsync * GTF_CELL_GRAN;
|
||||
/* 18. Find the number of pixels in horizontal front porch period */
|
||||
hfront_porch = hblank / 2 - hsync;
|
||||
/* 36. Find the number of lines in the odd front porch period: */
|
||||
vodd_front_porch_lines = GTF_MIN_V_PORCH ;
|
||||
|
||||
/* finally, pack the results in the mode struct */
|
||||
drm_mode->hdisplay = hdisplay_rnd;
|
||||
drm_mode->hsync_start = hdisplay_rnd + hfront_porch;
|
||||
drm_mode->hsync_end = drm_mode->hsync_start + hsync;
|
||||
drm_mode->htotal = total_pixels;
|
||||
drm_mode->vdisplay = vdisplay_rnd;
|
||||
drm_mode->vsync_start = vdisplay_rnd + vodd_front_porch_lines;
|
||||
drm_mode->vsync_end = drm_mode->vsync_start + V_SYNC_RQD;
|
||||
drm_mode->vtotal = vtotal_lines;
|
||||
|
||||
drm_mode->clock = pixel_freq;
|
||||
|
||||
drm_mode_set_name(drm_mode);
|
||||
drm_mode->flags = DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_PVSYNC;
|
||||
|
||||
if (interlaced) {
|
||||
drm_mode->vtotal *= 2;
|
||||
drm_mode->flags |= DRM_MODE_FLAG_INTERLACE;
|
||||
}
|
||||
|
||||
return drm_mode;
|
||||
}
|
||||
EXPORT_SYMBOL(drm_gtf_mode);
|
||||
/**
|
||||
* drm_mode_set_name - set the name on a mode
|
||||
* @mode: name will be set in this mode
|
||||
|
|
@ -151,7 +566,9 @@ EXPORT_SYMBOL(drm_mode_height);
|
|||
* FIXME: why is this needed? shouldn't vrefresh be set already?
|
||||
*
|
||||
* RETURNS:
|
||||
* Vertical refresh rate of @mode x 1000. For precision reasons.
|
||||
* Vertical refresh rate. It will be the result of actual value plus 0.5.
|
||||
* If it is 70.288, it will return 70Hz.
|
||||
* If it is 59.6, it will return 60Hz.
|
||||
*/
|
||||
int drm_mode_vrefresh(struct drm_display_mode *mode)
|
||||
{
|
||||
|
|
@ -161,14 +578,13 @@ int drm_mode_vrefresh(struct drm_display_mode *mode)
|
|||
if (mode->vrefresh > 0)
|
||||
refresh = mode->vrefresh;
|
||||
else if (mode->htotal > 0 && mode->vtotal > 0) {
|
||||
int vtotal;
|
||||
vtotal = mode->vtotal;
|
||||
/* work out vrefresh the value will be x1000 */
|
||||
calc_val = (mode->clock * 1000);
|
||||
|
||||
calc_val /= mode->htotal;
|
||||
calc_val *= 1000;
|
||||
calc_val /= mode->vtotal;
|
||||
refresh = (calc_val + vtotal / 2) / vtotal;
|
||||
|
||||
refresh = calc_val;
|
||||
if (mode->flags & DRM_MODE_FLAG_INTERLACE)
|
||||
refresh *= 2;
|
||||
if (mode->flags & DRM_MODE_FLAG_DBLSCAN)
|
||||
|
|
@ -403,8 +819,7 @@ void drm_mode_prune_invalid(struct drm_device *dev,
|
|||
list_del(&mode->head);
|
||||
if (verbose) {
|
||||
drm_mode_debug_printmodeline(mode);
|
||||
DRM_DEBUG_MODE(DRM_MODESET_DEBUG,
|
||||
"Not using %s mode %d\n",
|
||||
DRM_DEBUG_KMS("Not using %s mode %d\n",
|
||||
mode->name, mode->status);
|
||||
}
|
||||
drm_mode_destroy(dev, mode);
|
||||
|
|
|
|||
|
|
@ -106,20 +106,25 @@ int drm_proc_create_files(struct drm_info_list *files, int count,
|
|||
continue;
|
||||
|
||||
tmp = kmalloc(sizeof(struct drm_info_node), GFP_KERNEL);
|
||||
ent = create_proc_entry(files[i].name, S_IFREG | S_IRUGO, root);
|
||||
if (tmp == NULL) {
|
||||
ret = -1;
|
||||
goto fail;
|
||||
}
|
||||
tmp->minor = minor;
|
||||
tmp->info_ent = &files[i];
|
||||
list_add(&tmp->list, &minor->proc_nodes.list);
|
||||
|
||||
ent = proc_create_data(files[i].name, S_IRUGO, root,
|
||||
&drm_proc_fops, tmp);
|
||||
if (!ent) {
|
||||
DRM_ERROR("Cannot create /proc/dri/%s/%s\n",
|
||||
name, files[i].name);
|
||||
list_del(&tmp->list);
|
||||
kfree(tmp);
|
||||
ret = -1;
|
||||
goto fail;
|
||||
}
|
||||
|
||||
ent->proc_fops = &drm_proc_fops;
|
||||
ent->data = tmp;
|
||||
tmp->minor = minor;
|
||||
tmp->info_ent = &files[i];
|
||||
list_add(&(tmp->list), &(minor->proc_nodes.list));
|
||||
}
|
||||
return 0;
|
||||
|
||||
|
|
|
|||
|
|
@ -16,6 +16,7 @@
|
|||
#include <linux/kdev_t.h>
|
||||
#include <linux/err.h>
|
||||
|
||||
#include "drm_sysfs.h"
|
||||
#include "drm_core.h"
|
||||
#include "drmP.h"
|
||||
|
||||
|
|
@ -253,6 +254,7 @@ static ssize_t subconnector_show(struct device *device,
|
|||
case DRM_MODE_CONNECTOR_Composite:
|
||||
case DRM_MODE_CONNECTOR_SVIDEO:
|
||||
case DRM_MODE_CONNECTOR_Component:
|
||||
case DRM_MODE_CONNECTOR_TV:
|
||||
prop = dev->mode_config.tv_subconnector_property;
|
||||
is_tv = 1;
|
||||
break;
|
||||
|
|
@ -293,6 +295,7 @@ static ssize_t select_subconnector_show(struct device *device,
|
|||
case DRM_MODE_CONNECTOR_Composite:
|
||||
case DRM_MODE_CONNECTOR_SVIDEO:
|
||||
case DRM_MODE_CONNECTOR_Component:
|
||||
case DRM_MODE_CONNECTOR_TV:
|
||||
prop = dev->mode_config.tv_select_subconnector_property;
|
||||
is_tv = 1;
|
||||
break;
|
||||
|
|
@ -391,6 +394,7 @@ int drm_sysfs_connector_add(struct drm_connector *connector)
|
|||
case DRM_MODE_CONNECTOR_Composite:
|
||||
case DRM_MODE_CONNECTOR_SVIDEO:
|
||||
case DRM_MODE_CONNECTOR_Component:
|
||||
case DRM_MODE_CONNECTOR_TV:
|
||||
for (i = 0; i < ARRAY_SIZE(connector_attrs_opt1); i++) {
|
||||
ret = device_create_file(&connector->kdev, &connector_attrs_opt1[i]);
|
||||
if (ret)
|
||||
|
|
@ -519,3 +523,27 @@ void drm_sysfs_device_remove(struct drm_minor *minor)
|
|||
{
|
||||
device_unregister(&minor->kdev);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* drm_class_device_register - Register a struct device in the drm class.
|
||||
*
|
||||
* @dev: pointer to struct device to register.
|
||||
*
|
||||
* @dev should have all relevant members pre-filled with the exception
|
||||
* of the class member. In particular, the device_type member must
|
||||
* be set.
|
||||
*/
|
||||
|
||||
int drm_class_device_register(struct device *dev)
|
||||
{
|
||||
dev->class = drm_class;
|
||||
return device_register(dev);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(drm_class_device_register);
|
||||
|
||||
void drm_class_device_unregister(struct device *dev)
|
||||
{
|
||||
return device_unregister(dev);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(drm_class_device_unregister);
|
||||
|
|
|
|||
|
|
@ -4,10 +4,10 @@
|
|||
|
||||
ccflags-y := -Iinclude/drm
|
||||
i915-y := i915_drv.o i915_dma.o i915_irq.o i915_mem.o \
|
||||
i915_debugfs.o \
|
||||
i915_suspend.o \
|
||||
i915_gem.o \
|
||||
i915_gem_debug.o \
|
||||
i915_gem_debugfs.o \
|
||||
i915_gem_tiling.o \
|
||||
intel_display.o \
|
||||
intel_crt.o \
|
||||
|
|
|
|||
445
drivers/gpu/drm/i915/i915_debugfs.c
Normal file
445
drivers/gpu/drm/i915/i915_debugfs.c
Normal file
|
|
@ -0,0 +1,445 @@
|
|||
/*
|
||||
* Copyright © 2008 Intel Corporation
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a
|
||||
* copy of this software and associated documentation files (the "Software"),
|
||||
* to deal in the Software without restriction, including without limitation
|
||||
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||||
* and/or sell copies of the Software, and to permit persons to whom the
|
||||
* Software is furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice (including the next
|
||||
* paragraph) shall be included in all copies or substantial portions of the
|
||||
* Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
||||
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
|
||||
* IN THE SOFTWARE.
|
||||
*
|
||||
* Authors:
|
||||
* Eric Anholt <eric@anholt.net>
|
||||
* Keith Packard <keithp@keithp.com>
|
||||
*
|
||||
*/
|
||||
|
||||
#include <linux/seq_file.h>
|
||||
#include "drmP.h"
|
||||
#include "drm.h"
|
||||
#include "i915_drm.h"
|
||||
#include "i915_drv.h"
|
||||
|
||||
#define DRM_I915_RING_DEBUG 1
|
||||
|
||||
|
||||
#if defined(CONFIG_DEBUG_FS)
|
||||
|
||||
#define ACTIVE_LIST 1
|
||||
#define FLUSHING_LIST 2
|
||||
#define INACTIVE_LIST 3
|
||||
|
||||
static const char *get_pin_flag(struct drm_i915_gem_object *obj_priv)
|
||||
{
|
||||
if (obj_priv->user_pin_count > 0)
|
||||
return "P";
|
||||
else if (obj_priv->pin_count > 0)
|
||||
return "p";
|
||||
else
|
||||
return " ";
|
||||
}
|
||||
|
||||
static const char *get_tiling_flag(struct drm_i915_gem_object *obj_priv)
|
||||
{
|
||||
switch (obj_priv->tiling_mode) {
|
||||
default:
|
||||
case I915_TILING_NONE: return " ";
|
||||
case I915_TILING_X: return "X";
|
||||
case I915_TILING_Y: return "Y";
|
||||
}
|
||||
}
|
||||
|
||||
static int i915_gem_object_list_info(struct seq_file *m, void *data)
|
||||
{
|
||||
struct drm_info_node *node = (struct drm_info_node *) m->private;
|
||||
uintptr_t list = (uintptr_t) node->info_ent->data;
|
||||
struct list_head *head;
|
||||
struct drm_device *dev = node->minor->dev;
|
||||
drm_i915_private_t *dev_priv = dev->dev_private;
|
||||
struct drm_i915_gem_object *obj_priv;
|
||||
spinlock_t *lock = NULL;
|
||||
|
||||
switch (list) {
|
||||
case ACTIVE_LIST:
|
||||
seq_printf(m, "Active:\n");
|
||||
lock = &dev_priv->mm.active_list_lock;
|
||||
head = &dev_priv->mm.active_list;
|
||||
break;
|
||||
case INACTIVE_LIST:
|
||||
seq_printf(m, "Inactive:\n");
|
||||
head = &dev_priv->mm.inactive_list;
|
||||
break;
|
||||
case FLUSHING_LIST:
|
||||
seq_printf(m, "Flushing:\n");
|
||||
head = &dev_priv->mm.flushing_list;
|
||||
break;
|
||||
default:
|
||||
DRM_INFO("Ooops, unexpected list\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (lock)
|
||||
spin_lock(lock);
|
||||
list_for_each_entry(obj_priv, head, list)
|
||||
{
|
||||
struct drm_gem_object *obj = obj_priv->obj;
|
||||
|
||||
seq_printf(m, " %p: %s %08x %08x %d",
|
||||
obj,
|
||||
get_pin_flag(obj_priv),
|
||||
obj->read_domains, obj->write_domain,
|
||||
obj_priv->last_rendering_seqno);
|
||||
|
||||
if (obj->name)
|
||||
seq_printf(m, " (name: %d)", obj->name);
|
||||
if (obj_priv->fence_reg != I915_FENCE_REG_NONE)
|
||||
seq_printf(m, " (fence: %d)", obj_priv->fence_reg);
|
||||
if (obj_priv->gtt_space != NULL)
|
||||
seq_printf(m, " (gtt_offset: %08x)", obj_priv->gtt_offset);
|
||||
|
||||
seq_printf(m, "\n");
|
||||
}
|
||||
|
||||
if (lock)
|
||||
spin_unlock(lock);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int i915_gem_request_info(struct seq_file *m, void *data)
|
||||
{
|
||||
struct drm_info_node *node = (struct drm_info_node *) m->private;
|
||||
struct drm_device *dev = node->minor->dev;
|
||||
drm_i915_private_t *dev_priv = dev->dev_private;
|
||||
struct drm_i915_gem_request *gem_request;
|
||||
|
||||
seq_printf(m, "Request:\n");
|
||||
list_for_each_entry(gem_request, &dev_priv->mm.request_list, list) {
|
||||
seq_printf(m, " %d @ %d\n",
|
||||
gem_request->seqno,
|
||||
(int) (jiffies - gem_request->emitted_jiffies));
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int i915_gem_seqno_info(struct seq_file *m, void *data)
|
||||
{
|
||||
struct drm_info_node *node = (struct drm_info_node *) m->private;
|
||||
struct drm_device *dev = node->minor->dev;
|
||||
drm_i915_private_t *dev_priv = dev->dev_private;
|
||||
|
||||
if (dev_priv->hw_status_page != NULL) {
|
||||
seq_printf(m, "Current sequence: %d\n",
|
||||
i915_get_gem_seqno(dev));
|
||||
} else {
|
||||
seq_printf(m, "Current sequence: hws uninitialized\n");
|
||||
}
|
||||
seq_printf(m, "Waiter sequence: %d\n",
|
||||
dev_priv->mm.waiting_gem_seqno);
|
||||
seq_printf(m, "IRQ sequence: %d\n", dev_priv->mm.irq_gem_seqno);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static int i915_interrupt_info(struct seq_file *m, void *data)
|
||||
{
|
||||
struct drm_info_node *node = (struct drm_info_node *) m->private;
|
||||
struct drm_device *dev = node->minor->dev;
|
||||
drm_i915_private_t *dev_priv = dev->dev_private;
|
||||
|
||||
if (!IS_IGDNG(dev)) {
|
||||
seq_printf(m, "Interrupt enable: %08x\n",
|
||||
I915_READ(IER));
|
||||
seq_printf(m, "Interrupt identity: %08x\n",
|
||||
I915_READ(IIR));
|
||||
seq_printf(m, "Interrupt mask: %08x\n",
|
||||
I915_READ(IMR));
|
||||
seq_printf(m, "Pipe A stat: %08x\n",
|
||||
I915_READ(PIPEASTAT));
|
||||
seq_printf(m, "Pipe B stat: %08x\n",
|
||||
I915_READ(PIPEBSTAT));
|
||||
} else {
|
||||
seq_printf(m, "North Display Interrupt enable: %08x\n",
|
||||
I915_READ(DEIER));
|
||||
seq_printf(m, "North Display Interrupt identity: %08x\n",
|
||||
I915_READ(DEIIR));
|
||||
seq_printf(m, "North Display Interrupt mask: %08x\n",
|
||||
I915_READ(DEIMR));
|
||||
seq_printf(m, "South Display Interrupt enable: %08x\n",
|
||||
I915_READ(SDEIER));
|
||||
seq_printf(m, "South Display Interrupt identity: %08x\n",
|
||||
I915_READ(SDEIIR));
|
||||
seq_printf(m, "South Display Interrupt mask: %08x\n",
|
||||
I915_READ(SDEIMR));
|
||||
seq_printf(m, "Graphics Interrupt enable: %08x\n",
|
||||
I915_READ(GTIER));
|
||||
seq_printf(m, "Graphics Interrupt identity: %08x\n",
|
||||
I915_READ(GTIIR));
|
||||
seq_printf(m, "Graphics Interrupt mask: %08x\n",
|
||||
I915_READ(GTIMR));
|
||||
}
|
||||
seq_printf(m, "Interrupts received: %d\n",
|
||||
atomic_read(&dev_priv->irq_received));
|
||||
if (dev_priv->hw_status_page != NULL) {
|
||||
seq_printf(m, "Current sequence: %d\n",
|
||||
i915_get_gem_seqno(dev));
|
||||
} else {
|
||||
seq_printf(m, "Current sequence: hws uninitialized\n");
|
||||
}
|
||||
seq_printf(m, "Waiter sequence: %d\n",
|
||||
dev_priv->mm.waiting_gem_seqno);
|
||||
seq_printf(m, "IRQ sequence: %d\n",
|
||||
dev_priv->mm.irq_gem_seqno);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int i915_gem_fence_regs_info(struct seq_file *m, void *data)
|
||||
{
|
||||
struct drm_info_node *node = (struct drm_info_node *) m->private;
|
||||
struct drm_device *dev = node->minor->dev;
|
||||
drm_i915_private_t *dev_priv = dev->dev_private;
|
||||
int i;
|
||||
|
||||
seq_printf(m, "Reserved fences = %d\n", dev_priv->fence_reg_start);
|
||||
seq_printf(m, "Total fences = %d\n", dev_priv->num_fence_regs);
|
||||
for (i = 0; i < dev_priv->num_fence_regs; i++) {
|
||||
struct drm_gem_object *obj = dev_priv->fence_regs[i].obj;
|
||||
|
||||
if (obj == NULL) {
|
||||
seq_printf(m, "Fenced object[%2d] = unused\n", i);
|
||||
} else {
|
||||
struct drm_i915_gem_object *obj_priv;
|
||||
|
||||
obj_priv = obj->driver_private;
|
||||
seq_printf(m, "Fenced object[%2d] = %p: %s "
|
||||
"%08x %08zx %08x %s %08x %08x %d",
|
||||
i, obj, get_pin_flag(obj_priv),
|
||||
obj_priv->gtt_offset,
|
||||
obj->size, obj_priv->stride,
|
||||
get_tiling_flag(obj_priv),
|
||||
obj->read_domains, obj->write_domain,
|
||||
obj_priv->last_rendering_seqno);
|
||||
if (obj->name)
|
||||
seq_printf(m, " (name: %d)", obj->name);
|
||||
seq_printf(m, "\n");
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int i915_hws_info(struct seq_file *m, void *data)
|
||||
{
|
||||
struct drm_info_node *node = (struct drm_info_node *) m->private;
|
||||
struct drm_device *dev = node->minor->dev;
|
||||
drm_i915_private_t *dev_priv = dev->dev_private;
|
||||
int i;
|
||||
volatile u32 *hws;
|
||||
|
||||
hws = (volatile u32 *)dev_priv->hw_status_page;
|
||||
if (hws == NULL)
|
||||
return 0;
|
||||
|
||||
for (i = 0; i < 4096 / sizeof(u32) / 4; i += 4) {
|
||||
seq_printf(m, "0x%08x: 0x%08x 0x%08x 0x%08x 0x%08x\n",
|
||||
i * 4,
|
||||
hws[i], hws[i + 1], hws[i + 2], hws[i + 3]);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void i915_dump_pages(struct seq_file *m, struct page **pages, int page_count)
|
||||
{
|
||||
int page, i;
|
||||
uint32_t *mem;
|
||||
|
||||
for (page = 0; page < page_count; page++) {
|
||||
mem = kmap(pages[page]);
|
||||
for (i = 0; i < PAGE_SIZE; i += 4)
|
||||
seq_printf(m, "%08x : %08x\n", i, mem[i / 4]);
|
||||
kunmap(pages[page]);
|
||||
}
|
||||
}
|
||||
|
||||
static int i915_batchbuffer_info(struct seq_file *m, void *data)
|
||||
{
|
||||
struct drm_info_node *node = (struct drm_info_node *) m->private;
|
||||
struct drm_device *dev = node->minor->dev;
|
||||
drm_i915_private_t *dev_priv = dev->dev_private;
|
||||
struct drm_gem_object *obj;
|
||||
struct drm_i915_gem_object *obj_priv;
|
||||
int ret;
|
||||
|
||||
spin_lock(&dev_priv->mm.active_list_lock);
|
||||
|
||||
list_for_each_entry(obj_priv, &dev_priv->mm.active_list, list) {
|
||||
obj = obj_priv->obj;
|
||||
if (obj->read_domains & I915_GEM_DOMAIN_COMMAND) {
|
||||
ret = i915_gem_object_get_pages(obj);
|
||||
if (ret) {
|
||||
DRM_ERROR("Failed to get pages: %d\n", ret);
|
||||
spin_unlock(&dev_priv->mm.active_list_lock);
|
||||
return ret;
|
||||
}
|
||||
|
||||
seq_printf(m, "--- gtt_offset = 0x%08x\n", obj_priv->gtt_offset);
|
||||
i915_dump_pages(m, obj_priv->pages, obj->size / PAGE_SIZE);
|
||||
|
||||
i915_gem_object_put_pages(obj);
|
||||
}
|
||||
}
|
||||
|
||||
spin_unlock(&dev_priv->mm.active_list_lock);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int i915_ringbuffer_data(struct seq_file *m, void *data)
|
||||
{
|
||||
struct drm_info_node *node = (struct drm_info_node *) m->private;
|
||||
struct drm_device *dev = node->minor->dev;
|
||||
drm_i915_private_t *dev_priv = dev->dev_private;
|
||||
u8 *virt;
|
||||
uint32_t *ptr, off;
|
||||
|
||||
if (!dev_priv->ring.ring_obj) {
|
||||
seq_printf(m, "No ringbuffer setup\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
virt = dev_priv->ring.virtual_start;
|
||||
|
||||
for (off = 0; off < dev_priv->ring.Size; off += 4) {
|
||||
ptr = (uint32_t *)(virt + off);
|
||||
seq_printf(m, "%08x : %08x\n", off, *ptr);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int i915_ringbuffer_info(struct seq_file *m, void *data)
|
||||
{
|
||||
struct drm_info_node *node = (struct drm_info_node *) m->private;
|
||||
struct drm_device *dev = node->minor->dev;
|
||||
drm_i915_private_t *dev_priv = dev->dev_private;
|
||||
unsigned int head, tail;
|
||||
|
||||
head = I915_READ(PRB0_HEAD) & HEAD_ADDR;
|
||||
tail = I915_READ(PRB0_TAIL) & TAIL_ADDR;
|
||||
|
||||
seq_printf(m, "RingHead : %08x\n", head);
|
||||
seq_printf(m, "RingTail : %08x\n", tail);
|
||||
seq_printf(m, "RingSize : %08lx\n", dev_priv->ring.Size);
|
||||
seq_printf(m, "Acthd : %08x\n", I915_READ(IS_I965G(dev) ? ACTHD_I965 : ACTHD));
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int i915_error_state(struct seq_file *m, void *unused)
|
||||
{
|
||||
struct drm_info_node *node = (struct drm_info_node *) m->private;
|
||||
struct drm_device *dev = node->minor->dev;
|
||||
drm_i915_private_t *dev_priv = dev->dev_private;
|
||||
struct drm_i915_error_state *error;
|
||||
unsigned long flags;
|
||||
|
||||
spin_lock_irqsave(&dev_priv->error_lock, flags);
|
||||
if (!dev_priv->first_error) {
|
||||
seq_printf(m, "no error state collected\n");
|
||||
goto out;
|
||||
}
|
||||
|
||||
error = dev_priv->first_error;
|
||||
|
||||
seq_printf(m, "Time: %ld s %ld us\n", error->time.tv_sec,
|
||||
error->time.tv_usec);
|
||||
seq_printf(m, "EIR: 0x%08x\n", error->eir);
|
||||
seq_printf(m, " PGTBL_ER: 0x%08x\n", error->pgtbl_er);
|
||||
seq_printf(m, " INSTPM: 0x%08x\n", error->instpm);
|
||||
seq_printf(m, " IPEIR: 0x%08x\n", error->ipeir);
|
||||
seq_printf(m, " IPEHR: 0x%08x\n", error->ipehr);
|
||||
seq_printf(m, " INSTDONE: 0x%08x\n", error->instdone);
|
||||
seq_printf(m, " ACTHD: 0x%08x\n", error->acthd);
|
||||
if (IS_I965G(dev)) {
|
||||
seq_printf(m, " INSTPS: 0x%08x\n", error->instps);
|
||||
seq_printf(m, " INSTDONE1: 0x%08x\n", error->instdone1);
|
||||
}
|
||||
|
||||
out:
|
||||
spin_unlock_irqrestore(&dev_priv->error_lock, flags);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int i915_registers_info(struct seq_file *m, void *data) {
|
||||
struct drm_info_node *node = (struct drm_info_node *) m->private;
|
||||
struct drm_device *dev = node->minor->dev;
|
||||
drm_i915_private_t *dev_priv = dev->dev_private;
|
||||
uint32_t reg;
|
||||
|
||||
#define DUMP_RANGE(start, end) \
|
||||
for (reg=start; reg < end; reg += 4) \
|
||||
seq_printf(m, "%08x\t%08x\n", reg, I915_READ(reg));
|
||||
|
||||
DUMP_RANGE(0x00000, 0x00fff); /* VGA registers */
|
||||
DUMP_RANGE(0x02000, 0x02fff); /* instruction, memory, interrupt control registers */
|
||||
DUMP_RANGE(0x03000, 0x031ff); /* FENCE and PPGTT control registers */
|
||||
DUMP_RANGE(0x03200, 0x03fff); /* frame buffer compression registers */
|
||||
DUMP_RANGE(0x05000, 0x05fff); /* I/O control registers */
|
||||
DUMP_RANGE(0x06000, 0x06fff); /* clock control registers */
|
||||
DUMP_RANGE(0x07000, 0x07fff); /* 3D internal debug registers */
|
||||
DUMP_RANGE(0x07400, 0x088ff); /* GPE debug registers */
|
||||
DUMP_RANGE(0x0a000, 0x0afff); /* display palette registers */
|
||||
DUMP_RANGE(0x10000, 0x13fff); /* MMIO MCHBAR */
|
||||
DUMP_RANGE(0x30000, 0x3ffff); /* overlay registers */
|
||||
DUMP_RANGE(0x60000, 0x6ffff); /* display engine pipeline registers */
|
||||
DUMP_RANGE(0x70000, 0x72fff); /* display and cursor registers */
|
||||
DUMP_RANGE(0x73000, 0x73fff); /* performance counters */
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static struct drm_info_list i915_debugfs_list[] = {
|
||||
{"i915_regs", i915_registers_info, 0},
|
||||
{"i915_gem_active", i915_gem_object_list_info, 0, (void *) ACTIVE_LIST},
|
||||
{"i915_gem_flushing", i915_gem_object_list_info, 0, (void *) FLUSHING_LIST},
|
||||
{"i915_gem_inactive", i915_gem_object_list_info, 0, (void *) INACTIVE_LIST},
|
||||
{"i915_gem_request", i915_gem_request_info, 0},
|
||||
{"i915_gem_seqno", i915_gem_seqno_info, 0},
|
||||
{"i915_gem_fence_regs", i915_gem_fence_regs_info, 0},
|
||||
{"i915_gem_interrupt", i915_interrupt_info, 0},
|
||||
{"i915_gem_hws", i915_hws_info, 0},
|
||||
{"i915_ringbuffer_data", i915_ringbuffer_data, 0},
|
||||
{"i915_ringbuffer_info", i915_ringbuffer_info, 0},
|
||||
{"i915_batchbuffers", i915_batchbuffer_info, 0},
|
||||
{"i915_error_state", i915_error_state, 0},
|
||||
};
|
||||
#define I915_DEBUGFS_ENTRIES ARRAY_SIZE(i915_debugfs_list)
|
||||
|
||||
int i915_debugfs_init(struct drm_minor *minor)
|
||||
{
|
||||
return drm_debugfs_create_files(i915_debugfs_list,
|
||||
I915_DEBUGFS_ENTRIES,
|
||||
minor->debugfs_root, minor);
|
||||
}
|
||||
|
||||
void i915_debugfs_cleanup(struct drm_minor *minor)
|
||||
{
|
||||
drm_debugfs_remove_files(i915_debugfs_list,
|
||||
I915_DEBUGFS_ENTRIES, minor);
|
||||
}
|
||||
|
||||
#endif /* CONFIG_DEBUG_FS */
|
||||
|
||||
|
|
@ -29,11 +29,11 @@
|
|||
#include "drmP.h"
|
||||
#include "drm.h"
|
||||
#include "drm_crtc_helper.h"
|
||||
#include "drm_fb_helper.h"
|
||||
#include "intel_drv.h"
|
||||
#include "i915_drm.h"
|
||||
#include "i915_drv.h"
|
||||
|
||||
#define I915_DRV "i915_drv"
|
||||
#include <linux/vgaarb.h>
|
||||
|
||||
/* Really want an OS-independent resettable timer. Would like to have
|
||||
* this loop run for (eg) 3 sec, but have the timer reset every time
|
||||
|
|
@ -80,6 +80,34 @@ int i915_wait_ring(struct drm_device * dev, int n, const char *caller)
|
|||
return -EBUSY;
|
||||
}
|
||||
|
||||
/* As a ringbuffer is only allowed to wrap between instructions, fill
|
||||
* the tail with NOOPs.
|
||||
*/
|
||||
int i915_wrap_ring(struct drm_device *dev)
|
||||
{
|
||||
drm_i915_private_t *dev_priv = dev->dev_private;
|
||||
volatile unsigned int *virt;
|
||||
int rem;
|
||||
|
||||
rem = dev_priv->ring.Size - dev_priv->ring.tail;
|
||||
if (dev_priv->ring.space < rem) {
|
||||
int ret = i915_wait_ring(dev, rem, __func__);
|
||||
if (ret)
|
||||
return ret;
|
||||
}
|
||||
dev_priv->ring.space -= rem;
|
||||
|
||||
virt = (unsigned int *)
|
||||
(dev_priv->ring.virtual_start + dev_priv->ring.tail);
|
||||
rem /= 4;
|
||||
while (rem--)
|
||||
*virt++ = MI_NOOP;
|
||||
|
||||
dev_priv->ring.tail = 0;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets up the hardware status page for devices that need a physical address
|
||||
* in the register.
|
||||
|
|
@ -101,7 +129,7 @@ static int i915_init_phys_hws(struct drm_device *dev)
|
|||
memset(dev_priv->hw_status_page, 0, PAGE_SIZE);
|
||||
|
||||
I915_WRITE(HWS_PGA, dev_priv->dma_status_page);
|
||||
DRM_DEBUG_DRIVER(I915_DRV, "Enabled hardware status page\n");
|
||||
DRM_DEBUG_DRIVER("Enabled hardware status page\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
@ -187,8 +215,7 @@ static int i915_initialize(struct drm_device * dev, drm_i915_init_t * init)
|
|||
master_priv->sarea_priv = (drm_i915_sarea_t *)
|
||||
((u8 *)master_priv->sarea->handle + init->sarea_priv_offset);
|
||||
} else {
|
||||
DRM_DEBUG_DRIVER(I915_DRV,
|
||||
"sarea not found assuming DRI2 userspace\n");
|
||||
DRM_DEBUG_DRIVER("sarea not found assuming DRI2 userspace\n");
|
||||
}
|
||||
|
||||
if (init->ring_size != 0) {
|
||||
|
|
@ -200,7 +227,6 @@ static int i915_initialize(struct drm_device * dev, drm_i915_init_t * init)
|
|||
}
|
||||
|
||||
dev_priv->ring.Size = init->ring_size;
|
||||
dev_priv->ring.tail_mask = dev_priv->ring.Size - 1;
|
||||
|
||||
dev_priv->ring.map.offset = init->ring_start;
|
||||
dev_priv->ring.map.size = init->ring_size;
|
||||
|
|
@ -238,7 +264,7 @@ static int i915_dma_resume(struct drm_device * dev)
|
|||
{
|
||||
drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private;
|
||||
|
||||
DRM_DEBUG_DRIVER(I915_DRV, "%s\n", __func__);
|
||||
DRM_DEBUG_DRIVER("%s\n", __func__);
|
||||
|
||||
if (dev_priv->ring.map.handle == NULL) {
|
||||
DRM_ERROR("can not ioremap virtual address for"
|
||||
|
|
@ -251,14 +277,14 @@ static int i915_dma_resume(struct drm_device * dev)
|
|||
DRM_ERROR("Can not find hardware status page\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
DRM_DEBUG_DRIVER(I915_DRV, "hw status page @ %p\n",
|
||||
DRM_DEBUG_DRIVER("hw status page @ %p\n",
|
||||
dev_priv->hw_status_page);
|
||||
|
||||
if (dev_priv->status_gfx_addr != 0)
|
||||
I915_WRITE(HWS_PGA, dev_priv->status_gfx_addr);
|
||||
else
|
||||
I915_WRITE(HWS_PGA, dev_priv->dma_status_page);
|
||||
DRM_DEBUG_DRIVER(I915_DRV, "Enabled hardware status page\n");
|
||||
DRM_DEBUG_DRIVER("Enabled hardware status page\n");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
@ -552,7 +578,7 @@ static int i915_dispatch_flip(struct drm_device * dev)
|
|||
if (!master_priv->sarea_priv)
|
||||
return -EINVAL;
|
||||
|
||||
DRM_DEBUG_DRIVER(I915_DRV, "%s: page=%d pfCurrentPage=%d\n",
|
||||
DRM_DEBUG_DRIVER("%s: page=%d pfCurrentPage=%d\n",
|
||||
__func__,
|
||||
dev_priv->current_page,
|
||||
master_priv->sarea_priv->pf_current_page);
|
||||
|
|
@ -633,8 +659,7 @@ static int i915_batchbuffer(struct drm_device *dev, void *data,
|
|||
return -EINVAL;
|
||||
}
|
||||
|
||||
DRM_DEBUG_DRIVER(I915_DRV,
|
||||
"i915 batchbuffer, start %x used %d cliprects %d\n",
|
||||
DRM_DEBUG_DRIVER("i915 batchbuffer, start %x used %d cliprects %d\n",
|
||||
batch->start, batch->used, batch->num_cliprects);
|
||||
|
||||
RING_LOCK_TEST_WITH_RETURN(dev, file_priv);
|
||||
|
|
@ -681,8 +706,7 @@ static int i915_cmdbuffer(struct drm_device *dev, void *data,
|
|||
void *batch_data;
|
||||
int ret;
|
||||
|
||||
DRM_DEBUG_DRIVER(I915_DRV,
|
||||
"i915 cmdbuffer, buf %p sz %d cliprects %d\n",
|
||||
DRM_DEBUG_DRIVER("i915 cmdbuffer, buf %p sz %d cliprects %d\n",
|
||||
cmdbuf->buf, cmdbuf->sz, cmdbuf->num_cliprects);
|
||||
|
||||
RING_LOCK_TEST_WITH_RETURN(dev, file_priv);
|
||||
|
|
@ -735,7 +759,7 @@ static int i915_flip_bufs(struct drm_device *dev, void *data,
|
|||
{
|
||||
int ret;
|
||||
|
||||
DRM_DEBUG_DRIVER(I915_DRV, "%s\n", __func__);
|
||||
DRM_DEBUG_DRIVER("%s\n", __func__);
|
||||
|
||||
RING_LOCK_TEST_WITH_RETURN(dev, file_priv);
|
||||
|
||||
|
|
@ -778,7 +802,7 @@ static int i915_getparam(struct drm_device *dev, void *data,
|
|||
value = dev_priv->num_fence_regs - dev_priv->fence_reg_start;
|
||||
break;
|
||||
default:
|
||||
DRM_DEBUG_DRIVER(I915_DRV, "Unknown parameter %d\n",
|
||||
DRM_DEBUG_DRIVER("Unknown parameter %d\n",
|
||||
param->param);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
|
@ -819,7 +843,7 @@ static int i915_setparam(struct drm_device *dev, void *data,
|
|||
dev_priv->fence_reg_start = param->value;
|
||||
break;
|
||||
default:
|
||||
DRM_DEBUG_DRIVER(I915_DRV, "unknown parameter %d\n",
|
||||
DRM_DEBUG_DRIVER("unknown parameter %d\n",
|
||||
param->param);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
|
@ -846,7 +870,7 @@ static int i915_set_status_page(struct drm_device *dev, void *data,
|
|||
return 0;
|
||||
}
|
||||
|
||||
DRM_DEBUG("set status page addr 0x%08x\n", (u32)hws->addr);
|
||||
DRM_DEBUG_DRIVER("set status page addr 0x%08x\n", (u32)hws->addr);
|
||||
|
||||
dev_priv->status_gfx_addr = hws->addr & (0x1ffff<<12);
|
||||
|
||||
|
|
@ -868,13 +892,25 @@ static int i915_set_status_page(struct drm_device *dev, void *data,
|
|||
|
||||
memset(dev_priv->hw_status_page, 0, PAGE_SIZE);
|
||||
I915_WRITE(HWS_PGA, dev_priv->status_gfx_addr);
|
||||
DRM_DEBUG_DRIVER(I915_DRV, "load hws HWS_PGA with gfx mem 0x%x\n",
|
||||
DRM_DEBUG_DRIVER("load hws HWS_PGA with gfx mem 0x%x\n",
|
||||
dev_priv->status_gfx_addr);
|
||||
DRM_DEBUG_DRIVER(I915_DRV, "load hws at %p\n",
|
||||
DRM_DEBUG_DRIVER("load hws at %p\n",
|
||||
dev_priv->hw_status_page);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int i915_get_bridge_dev(struct drm_device *dev)
|
||||
{
|
||||
struct drm_i915_private *dev_priv = dev->dev_private;
|
||||
|
||||
dev_priv->bridge_dev = pci_get_bus_and_slot(0, PCI_DEVFN(0,0));
|
||||
if (!dev_priv->bridge_dev) {
|
||||
DRM_ERROR("bridge device not found\n");
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* i915_probe_agp - get AGP bootup configuration
|
||||
* @pdev: PCI device
|
||||
|
|
@ -888,20 +924,13 @@ static int i915_set_status_page(struct drm_device *dev, void *data,
|
|||
static int i915_probe_agp(struct drm_device *dev, uint32_t *aperture_size,
|
||||
uint32_t *preallocated_size)
|
||||
{
|
||||
struct pci_dev *bridge_dev;
|
||||
struct drm_i915_private *dev_priv = dev->dev_private;
|
||||
u16 tmp = 0;
|
||||
unsigned long overhead;
|
||||
unsigned long stolen;
|
||||
|
||||
bridge_dev = pci_get_bus_and_slot(0, PCI_DEVFN(0,0));
|
||||
if (!bridge_dev) {
|
||||
DRM_ERROR("bridge device not found\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Get the fb aperture size and "stolen" memory amount. */
|
||||
pci_read_config_word(bridge_dev, INTEL_GMCH_CTRL, &tmp);
|
||||
pci_dev_put(bridge_dev);
|
||||
pci_read_config_word(dev_priv->bridge_dev, INTEL_GMCH_CTRL, &tmp);
|
||||
|
||||
*aperture_size = 1024 * 1024;
|
||||
*preallocated_size = 1024 * 1024;
|
||||
|
|
@ -984,6 +1013,19 @@ static int i915_probe_agp(struct drm_device *dev, uint32_t *aperture_size,
|
|||
return 0;
|
||||
}
|
||||
|
||||
/* true = enable decode, false = disable decoder */
|
||||
static unsigned int i915_vga_set_decode(void *cookie, bool state)
|
||||
{
|
||||
struct drm_device *dev = cookie;
|
||||
|
||||
intel_modeset_vga_set_state(dev, state);
|
||||
if (state)
|
||||
return VGA_RSRC_LEGACY_IO | VGA_RSRC_LEGACY_MEM |
|
||||
VGA_RSRC_NORMAL_IO | VGA_RSRC_NORMAL_MEM;
|
||||
else
|
||||
return VGA_RSRC_NORMAL_IO | VGA_RSRC_NORMAL_MEM;
|
||||
}
|
||||
|
||||
static int i915_load_modeset_init(struct drm_device *dev,
|
||||
unsigned long prealloc_size,
|
||||
unsigned long agp_size)
|
||||
|
|
@ -1029,6 +1071,11 @@ static int i915_load_modeset_init(struct drm_device *dev,
|
|||
if (ret)
|
||||
DRM_INFO("failed to find VBIOS tables\n");
|
||||
|
||||
/* if we have > 1 VGA cards, then disable the radeon VGA resources */
|
||||
ret = vga_client_register(dev->pdev, dev, NULL, i915_vga_set_decode);
|
||||
if (ret)
|
||||
goto destroy_ringbuffer;
|
||||
|
||||
ret = drm_irq_install(dev);
|
||||
if (ret)
|
||||
goto destroy_ringbuffer;
|
||||
|
|
@ -1153,11 +1200,16 @@ int i915_driver_load(struct drm_device *dev, unsigned long flags)
|
|||
base = drm_get_resource_start(dev, mmio_bar);
|
||||
size = drm_get_resource_len(dev, mmio_bar);
|
||||
|
||||
if (i915_get_bridge_dev(dev)) {
|
||||
ret = -EIO;
|
||||
goto free_priv;
|
||||
}
|
||||
|
||||
dev_priv->regs = ioremap(base, size);
|
||||
if (!dev_priv->regs) {
|
||||
DRM_ERROR("failed to map registers\n");
|
||||
ret = -EIO;
|
||||
goto free_priv;
|
||||
goto put_bridge;
|
||||
}
|
||||
|
||||
dev_priv->mm.gtt_mapping =
|
||||
|
|
@ -1269,6 +1321,8 @@ out_iomapfree:
|
|||
io_mapping_free(dev_priv->mm.gtt_mapping);
|
||||
out_rmmap:
|
||||
iounmap(dev_priv->regs);
|
||||
put_bridge:
|
||||
pci_dev_put(dev_priv->bridge_dev);
|
||||
free_priv:
|
||||
kfree(dev_priv);
|
||||
return ret;
|
||||
|
|
@ -1289,6 +1343,7 @@ int i915_driver_unload(struct drm_device *dev)
|
|||
|
||||
if (drm_core_check_feature(dev, DRIVER_MODESET)) {
|
||||
drm_irq_uninstall(dev);
|
||||
vga_client_register(dev->pdev, NULL, NULL, NULL);
|
||||
}
|
||||
|
||||
if (dev->pdev->msi_enabled)
|
||||
|
|
@ -1312,6 +1367,7 @@ int i915_driver_unload(struct drm_device *dev)
|
|||
i915_gem_lastclose(dev);
|
||||
}
|
||||
|
||||
pci_dev_put(dev_priv->bridge_dev);
|
||||
kfree(dev->dev_private);
|
||||
|
||||
return 0;
|
||||
|
|
@ -1321,7 +1377,7 @@ int i915_driver_open(struct drm_device *dev, struct drm_file *file_priv)
|
|||
{
|
||||
struct drm_i915_file_private *i915_file_priv;
|
||||
|
||||
DRM_DEBUG_DRIVER(I915_DRV, "\n");
|
||||
DRM_DEBUG_DRIVER("\n");
|
||||
i915_file_priv = (struct drm_i915_file_private *)
|
||||
kmalloc(sizeof(*i915_file_priv), GFP_KERNEL);
|
||||
|
||||
|
|
@ -1352,7 +1408,7 @@ void i915_driver_lastclose(struct drm_device * dev)
|
|||
drm_i915_private_t *dev_priv = dev->dev_private;
|
||||
|
||||
if (!dev_priv || drm_core_check_feature(dev, DRIVER_MODESET)) {
|
||||
intelfb_restore();
|
||||
drm_fb_helper_restore();
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -37,12 +37,15 @@
|
|||
#include <linux/console.h>
|
||||
#include "drm_crtc_helper.h"
|
||||
|
||||
static unsigned int i915_modeset = -1;
|
||||
static int i915_modeset = -1;
|
||||
module_param_named(modeset, i915_modeset, int, 0400);
|
||||
|
||||
unsigned int i915_fbpercrtc = 0;
|
||||
module_param_named(fbpercrtc, i915_fbpercrtc, int, 0400);
|
||||
|
||||
unsigned int i915_powersave = 1;
|
||||
module_param_named(powersave, i915_powersave, int, 0400);
|
||||
|
||||
static struct drm_driver driver;
|
||||
|
||||
static struct pci_device_id pciidlist[] = {
|
||||
|
|
@ -188,8 +191,8 @@ static struct drm_driver driver = {
|
|||
.master_create = i915_master_create,
|
||||
.master_destroy = i915_master_destroy,
|
||||
#if defined(CONFIG_DEBUG_FS)
|
||||
.debugfs_init = i915_gem_debugfs_init,
|
||||
.debugfs_cleanup = i915_gem_debugfs_cleanup,
|
||||
.debugfs_init = i915_debugfs_init,
|
||||
.debugfs_cleanup = i915_debugfs_cleanup,
|
||||
#endif
|
||||
.gem_init_object = i915_gem_init_object,
|
||||
.gem_free_object = i915_gem_free_object,
|
||||
|
|
|
|||
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue