Merge branch 'topic/drm-vblank-rework' into drm-intel-next-queued
Pull in the drm vblank rework from Ville and me. drm core parts acked by Dave Airlie Conflicts: drivers/gpu/drm/i915/intel_display.c Just a bit of fun around the placement of drm_vblank_on. This merge resolution has been tested in drm-intel-nightly for a while already. Acked-by: Dave Airlie <airlied@gmail.com> Signed-off-by: Daniel Vetter <daniel.vetter@ffwll.ch>
This commit is contained in:
commit
d40d91876a
|
@ -1895,8 +1895,8 @@ void intel_crt_init(struct drm_device *dev)
|
|||
<para>
|
||||
The function filters out modes larger than
|
||||
<parameter>max_width</parameter> and <parameter>max_height</parameter>
|
||||
if specified. It then calls the connector
|
||||
<methodname>mode_valid</methodname> helper operation for each mode in
|
||||
if specified. It then calls the optional connector
|
||||
<methodname>mode_valid</methodname> helper operation for each mode in
|
||||
the probed list to check whether the mode is valid for the connector.
|
||||
</para>
|
||||
</listitem>
|
||||
|
@ -2257,7 +2257,7 @@ void intel_crt_init(struct drm_device *dev)
|
|||
<para>
|
||||
Verify whether a mode is valid for the connector. Return MODE_OK for
|
||||
supported modes and one of the enum drm_mode_status values (MODE_*)
|
||||
for unsupported modes. This operation is mandatory.
|
||||
for unsupported modes. This operation is optional.
|
||||
</para>
|
||||
<para>
|
||||
As the mode rejection reason is currently not used beside for
|
||||
|
@ -2519,6 +2519,10 @@ void (*disable_vblank) (struct drm_device *dev, int crtc);</synopsis>
|
|||
with a call to <function>drm_vblank_cleanup</function> in the driver
|
||||
<methodname>unload</methodname> operation handler.
|
||||
</para>
|
||||
<sect2>
|
||||
<title>Vertical Blanking and Interrupt Handling Functions Reference</title>
|
||||
!Edrivers/gpu/drm/drm_irq.c
|
||||
</sect2>
|
||||
</sect1>
|
||||
|
||||
<!-- Internals: open/close, file operations and ioctls -->
|
||||
|
@ -2861,17 +2865,16 @@ int num_ioctls;</synopsis>
|
|||
<term>DRM_IOCTL_MODESET_CTL</term>
|
||||
<listitem>
|
||||
<para>
|
||||
This should be called by application level drivers before and
|
||||
after mode setting, since on many devices the vertical blank
|
||||
counter is reset at that time. Internally, the DRM snapshots
|
||||
the last vblank count when the ioctl is called with the
|
||||
_DRM_PRE_MODESET command, so that the counter won't go backwards
|
||||
(which is dealt with when _DRM_POST_MODESET is used).
|
||||
This was only used for user-mode-settind drivers around
|
||||
modesetting changes to allow the kernel to update the vblank
|
||||
interrupt after mode setting, since on many devices the vertical
|
||||
blank counter is reset to 0 at some point during modeset. Modern
|
||||
drivers should not call this any more since with kernel mode
|
||||
setting it is a no-op.
|
||||
</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
</variablelist>
|
||||
<!--!Edrivers/char/drm/drm_irq.c-->
|
||||
</para>
|
||||
</sect1>
|
||||
|
||||
|
|
|
@ -4,6 +4,6 @@
|
|||
|
||||
ccflags-y := -Iinclude/drm
|
||||
|
||||
ast-y := ast_drv.o ast_main.o ast_mode.o ast_fb.o ast_ttm.o ast_post.o
|
||||
ast-y := ast_drv.o ast_main.o ast_mode.o ast_fb.o ast_ttm.o ast_post.o ast_dp501.o
|
||||
|
||||
obj-$(CONFIG_DRM_AST) := ast.o
|
||||
obj-$(CONFIG_DRM_AST) := ast.o
|
||||
|
|
|
@ -0,0 +1,410 @@
|
|||
|
||||
#include <linux/firmware.h>
|
||||
#include <drm/drmP.h>
|
||||
#include "ast_drv.h"
|
||||
MODULE_FIRMWARE("ast_dp501_fw.bin");
|
||||
|
||||
int ast_load_dp501_microcode(struct drm_device *dev)
|
||||
{
|
||||
struct ast_private *ast = dev->dev_private;
|
||||
static char *fw_name = "ast_dp501_fw.bin";
|
||||
int err;
|
||||
err = request_firmware(&ast->dp501_fw, fw_name, dev->dev);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void send_ack(struct ast_private *ast)
|
||||
{
|
||||
u8 sendack;
|
||||
sendack = ast_get_index_reg_mask(ast, AST_IO_CRTC_PORT, 0x9b, 0xff);
|
||||
sendack |= 0x80;
|
||||
ast_set_index_reg_mask(ast, AST_IO_CRTC_PORT, 0x9b, 0x00, sendack);
|
||||
}
|
||||
|
||||
static void send_nack(struct ast_private *ast)
|
||||
{
|
||||
u8 sendack;
|
||||
sendack = ast_get_index_reg_mask(ast, AST_IO_CRTC_PORT, 0x9b, 0xff);
|
||||
sendack &= ~0x80;
|
||||
ast_set_index_reg_mask(ast, AST_IO_CRTC_PORT, 0x9b, 0x00, sendack);
|
||||
}
|
||||
|
||||
static bool wait_ack(struct ast_private *ast)
|
||||
{
|
||||
u8 waitack;
|
||||
u32 retry = 0;
|
||||
do {
|
||||
waitack = ast_get_index_reg_mask(ast, AST_IO_CRTC_PORT, 0xd2, 0xff);
|
||||
waitack &= 0x80;
|
||||
udelay(100);
|
||||
} while ((!waitack) && (retry++ < 1000));
|
||||
|
||||
if (retry < 1000)
|
||||
return true;
|
||||
else
|
||||
return false;
|
||||
}
|
||||
|
||||
static bool wait_nack(struct ast_private *ast)
|
||||
{
|
||||
u8 waitack;
|
||||
u32 retry = 0;
|
||||
do {
|
||||
waitack = ast_get_index_reg_mask(ast, AST_IO_CRTC_PORT, 0xd2, 0xff);
|
||||
waitack &= 0x80;
|
||||
udelay(100);
|
||||
} while ((waitack) && (retry++ < 1000));
|
||||
|
||||
if (retry < 1000)
|
||||
return true;
|
||||
else
|
||||
return false;
|
||||
}
|
||||
|
||||
static void set_cmd_trigger(struct ast_private *ast)
|
||||
{
|
||||
ast_set_index_reg_mask(ast, AST_IO_CRTC_PORT, 0x9b, ~0x40, 0x40);
|
||||
}
|
||||
|
||||
static void clear_cmd_trigger(struct ast_private *ast)
|
||||
{
|
||||
ast_set_index_reg_mask(ast, AST_IO_CRTC_PORT, 0x9b, ~0x40, 0x00);
|
||||
}
|
||||
|
||||
#if 0
|
||||
static bool wait_fw_ready(struct ast_private *ast)
|
||||
{
|
||||
u8 waitready;
|
||||
u32 retry = 0;
|
||||
do {
|
||||
waitready = ast_get_index_reg_mask(ast, AST_IO_CRTC_PORT, 0xd2, 0xff);
|
||||
waitready &= 0x40;
|
||||
udelay(100);
|
||||
} while ((!waitready) && (retry++ < 1000));
|
||||
|
||||
if (retry < 1000)
|
||||
return true;
|
||||
else
|
||||
return false;
|
||||
}
|
||||
#endif
|
||||
|
||||
static bool ast_write_cmd(struct drm_device *dev, u8 data)
|
||||
{
|
||||
struct ast_private *ast = dev->dev_private;
|
||||
int retry = 0;
|
||||
if (wait_nack(ast)) {
|
||||
send_nack(ast);
|
||||
ast_set_index_reg_mask(ast, AST_IO_CRTC_PORT, 0x9a, 0x00, data);
|
||||
send_ack(ast);
|
||||
set_cmd_trigger(ast);
|
||||
do {
|
||||
if (wait_ack(ast)) {
|
||||
clear_cmd_trigger(ast);
|
||||
send_nack(ast);
|
||||
return true;
|
||||
}
|
||||
} while (retry++ < 100);
|
||||
}
|
||||
clear_cmd_trigger(ast);
|
||||
send_nack(ast);
|
||||
return false;
|
||||
}
|
||||
|
||||
static bool ast_write_data(struct drm_device *dev, u8 data)
|
||||
{
|
||||
struct ast_private *ast = dev->dev_private;
|
||||
|
||||
if (wait_nack(ast)) {
|
||||
send_nack(ast);
|
||||
ast_set_index_reg_mask(ast, AST_IO_CRTC_PORT, 0x9a, 0x00, data);
|
||||
send_ack(ast);
|
||||
if (wait_ack(ast)) {
|
||||
send_nack(ast);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
send_nack(ast);
|
||||
return false;
|
||||
}
|
||||
|
||||
#if 0
|
||||
static bool ast_read_data(struct drm_device *dev, u8 *data)
|
||||
{
|
||||
struct ast_private *ast = dev->dev_private;
|
||||
u8 tmp;
|
||||
|
||||
*data = 0;
|
||||
|
||||
if (wait_ack(ast) == false)
|
||||
return false;
|
||||
tmp = ast_get_index_reg_mask(ast, AST_IO_CRTC_PORT, 0xd3, 0xff);
|
||||
*data = tmp;
|
||||
if (wait_nack(ast) == false) {
|
||||
send_nack(ast);
|
||||
return false;
|
||||
}
|
||||
send_nack(ast);
|
||||
return true;
|
||||
}
|
||||
|
||||
static void clear_cmd(struct ast_private *ast)
|
||||
{
|
||||
send_nack(ast);
|
||||
ast_set_index_reg_mask(ast, AST_IO_CRTC_PORT, 0x9a, 0x00, 0x00);
|
||||
}
|
||||
#endif
|
||||
|
||||
void ast_set_dp501_video_output(struct drm_device *dev, u8 mode)
|
||||
{
|
||||
ast_write_cmd(dev, 0x40);
|
||||
ast_write_data(dev, mode);
|
||||
|
||||
msleep(10);
|
||||
}
|
||||
|
||||
static u32 get_fw_base(struct ast_private *ast)
|
||||
{
|
||||
return ast_mindwm(ast, 0x1e6e2104) & 0x7fffffff;
|
||||
}
|
||||
|
||||
bool ast_backup_fw(struct drm_device *dev, u8 *addr, u32 size)
|
||||
{
|
||||
struct ast_private *ast = dev->dev_private;
|
||||
u32 i, data;
|
||||
u32 boot_address;
|
||||
|
||||
data = ast_mindwm(ast, 0x1e6e2100) & 0x01;
|
||||
if (data) {
|
||||
boot_address = get_fw_base(ast);
|
||||
for (i = 0; i < size; i += 4)
|
||||
*(u32 *)(addr + i) = ast_mindwm(ast, boot_address + i);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool ast_launch_m68k(struct drm_device *dev)
|
||||
{
|
||||
struct ast_private *ast = dev->dev_private;
|
||||
u32 i, data, len = 0;
|
||||
u32 boot_address;
|
||||
u8 *fw_addr = NULL;
|
||||
u8 jreg;
|
||||
|
||||
data = ast_mindwm(ast, 0x1e6e2100) & 0x01;
|
||||
if (!data) {
|
||||
|
||||
if (ast->dp501_fw_addr) {
|
||||
fw_addr = ast->dp501_fw_addr;
|
||||
len = 32*1024;
|
||||
} else if (ast->dp501_fw) {
|
||||
fw_addr = (u8 *)ast->dp501_fw->data;
|
||||
len = ast->dp501_fw->size;
|
||||
}
|
||||
/* Get BootAddress */
|
||||
ast_moutdwm(ast, 0x1e6e2000, 0x1688a8a8);
|
||||
data = ast_mindwm(ast, 0x1e6e0004);
|
||||
switch (data & 0x03) {
|
||||
case 0:
|
||||
boot_address = 0x44000000;
|
||||
break;
|
||||
default:
|
||||
case 1:
|
||||
boot_address = 0x48000000;
|
||||
break;
|
||||
case 2:
|
||||
boot_address = 0x50000000;
|
||||
break;
|
||||
case 3:
|
||||
boot_address = 0x60000000;
|
||||
break;
|
||||
}
|
||||
boot_address -= 0x200000; /* -2MB */
|
||||
|
||||
/* copy image to buffer */
|
||||
for (i = 0; i < len; i += 4) {
|
||||
data = *(u32 *)(fw_addr + i);
|
||||
ast_moutdwm(ast, boot_address + i, data);
|
||||
}
|
||||
|
||||
/* Init SCU */
|
||||
ast_moutdwm(ast, 0x1e6e2000, 0x1688a8a8);
|
||||
|
||||
/* Launch FW */
|
||||
ast_moutdwm(ast, 0x1e6e2104, 0x80000000 + boot_address);
|
||||
ast_moutdwm(ast, 0x1e6e2100, 1);
|
||||
|
||||
/* Update Scratch */
|
||||
data = ast_mindwm(ast, 0x1e6e2040) & 0xfffff1ff; /* D[11:9] = 100b: UEFI handling */
|
||||
data |= 0x800;
|
||||
ast_moutdwm(ast, 0x1e6e2040, data);
|
||||
|
||||
jreg = ast_get_index_reg_mask(ast, AST_IO_CRTC_PORT, 0x99, 0xfc); /* D[1:0]: Reserved Video Buffer */
|
||||
jreg |= 0x02;
|
||||
ast_set_index_reg(ast, AST_IO_CRTC_PORT, 0x99, jreg);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
u8 ast_get_dp501_max_clk(struct drm_device *dev)
|
||||
{
|
||||
struct ast_private *ast = dev->dev_private;
|
||||
u32 boot_address, offset, data;
|
||||
u8 linkcap[4], linkrate, linklanes, maxclk = 0xff;
|
||||
|
||||
boot_address = get_fw_base(ast);
|
||||
|
||||
/* validate FW version */
|
||||
offset = 0xf000;
|
||||
data = ast_mindwm(ast, boot_address + offset);
|
||||
if ((data & 0xf0) != 0x10) /* version: 1x */
|
||||
return maxclk;
|
||||
|
||||
/* Read Link Capability */
|
||||
offset = 0xf014;
|
||||
*(u32 *)linkcap = ast_mindwm(ast, boot_address + offset);
|
||||
if (linkcap[2] == 0) {
|
||||
linkrate = linkcap[0];
|
||||
linklanes = linkcap[1];
|
||||
data = (linkrate == 0x0a) ? (90 * linklanes) : (54 * linklanes);
|
||||
if (data > 0xff)
|
||||
data = 0xff;
|
||||
maxclk = (u8)data;
|
||||
}
|
||||
return maxclk;
|
||||
}
|
||||
|
||||
bool ast_dp501_read_edid(struct drm_device *dev, u8 *ediddata)
|
||||
{
|
||||
struct ast_private *ast = dev->dev_private;
|
||||
u32 i, boot_address, offset, data;
|
||||
|
||||
boot_address = get_fw_base(ast);
|
||||
|
||||
/* validate FW version */
|
||||
offset = 0xf000;
|
||||
data = ast_mindwm(ast, boot_address + offset);
|
||||
if ((data & 0xf0) != 0x10)
|
||||
return false;
|
||||
|
||||
/* validate PnP Monitor */
|
||||
offset = 0xf010;
|
||||
data = ast_mindwm(ast, boot_address + offset);
|
||||
if (!(data & 0x01))
|
||||
return false;
|
||||
|
||||
/* Read EDID */
|
||||
offset = 0xf020;
|
||||
for (i = 0; i < 128; i += 4) {
|
||||
data = ast_mindwm(ast, boot_address + offset + i);
|
||||
*(u32 *)(ediddata + i) = data;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool ast_init_dvo(struct drm_device *dev)
|
||||
{
|
||||
struct ast_private *ast = dev->dev_private;
|
||||
u8 jreg;
|
||||
u32 data;
|
||||
ast_write32(ast, 0xf004, 0x1e6e0000);
|
||||
ast_write32(ast, 0xf000, 0x1);
|
||||
ast_write32(ast, 0x12000, 0x1688a8a8);
|
||||
|
||||
jreg = ast_get_index_reg_mask(ast, AST_IO_CRTC_PORT, 0xd0, 0xff);
|
||||
if (!(jreg & 0x80)) {
|
||||
/* Init SCU DVO Settings */
|
||||
data = ast_read32(ast, 0x12008);
|
||||
/* delay phase */
|
||||
data &= 0xfffff8ff;
|
||||
data |= 0x00000500;
|
||||
ast_write32(ast, 0x12008, data);
|
||||
|
||||
if (ast->chip == AST2300) {
|
||||
data = ast_read32(ast, 0x12084);
|
||||
/* multi-pins for DVO single-edge */
|
||||
data |= 0xfffe0000;
|
||||
ast_write32(ast, 0x12084, data);
|
||||
|
||||
data = ast_read32(ast, 0x12088);
|
||||
/* multi-pins for DVO single-edge */
|
||||
data |= 0x000fffff;
|
||||
ast_write32(ast, 0x12088, data);
|
||||
|
||||
data = ast_read32(ast, 0x12090);
|
||||
/* multi-pins for DVO single-edge */
|
||||
data &= 0xffffffcf;
|
||||
data |= 0x00000020;
|
||||
ast_write32(ast, 0x12090, data);
|
||||
} else { /* AST2400 */
|
||||
data = ast_read32(ast, 0x12088);
|
||||
/* multi-pins for DVO single-edge */
|
||||
data |= 0x30000000;
|
||||
ast_write32(ast, 0x12088, data);
|
||||
|
||||
data = ast_read32(ast, 0x1208c);
|
||||
/* multi-pins for DVO single-edge */
|
||||
data |= 0x000000cf;
|
||||
ast_write32(ast, 0x1208c, data);
|
||||
|
||||
data = ast_read32(ast, 0x120a4);
|
||||
/* multi-pins for DVO single-edge */
|
||||
data |= 0xffff0000;
|
||||
ast_write32(ast, 0x120a4, data);
|
||||
|
||||
data = ast_read32(ast, 0x120a8);
|
||||
/* multi-pins for DVO single-edge */
|
||||
data |= 0x0000000f;
|
||||
ast_write32(ast, 0x120a8, data);
|
||||
|
||||
data = ast_read32(ast, 0x12094);
|
||||
/* multi-pins for DVO single-edge */
|
||||
data |= 0x00000002;
|
||||
ast_write32(ast, 0x12094, data);
|
||||
}
|
||||
}
|
||||
|
||||
/* Force to DVO */
|
||||
data = ast_read32(ast, 0x1202c);
|
||||
data &= 0xfffbffff;
|
||||
ast_write32(ast, 0x1202c, data);
|
||||
|
||||
/* Init VGA DVO Settings */
|
||||
ast_set_index_reg_mask(ast, AST_IO_CRTC_PORT, 0xa3, 0xcf, 0x80);
|
||||
return true;
|
||||
}
|
||||
|
||||
void ast_init_3rdtx(struct drm_device *dev)
|
||||
{
|
||||
struct ast_private *ast = dev->dev_private;
|
||||
u8 jreg;
|
||||
u32 data;
|
||||
if (ast->chip == AST2300 || ast->chip == AST2400) {
|
||||
jreg = ast_get_index_reg_mask(ast, AST_IO_CRTC_PORT, 0xd1, 0xff);
|
||||
switch (jreg & 0x0e) {
|
||||
case 0x04:
|
||||
ast_init_dvo(dev);
|
||||
break;
|
||||
case 0x08:
|
||||
ast_launch_m68k(dev);
|
||||
break;
|
||||
case 0x0c:
|
||||
ast_init_dvo(dev);
|
||||
break;
|
||||
default:
|
||||
if (ast->tx_chip_type == AST_TX_SIL164)
|
||||
ast_init_dvo(dev);
|
||||
else {
|
||||
ast_write32(ast, 0x12000, 0x1688a8a8);
|
||||
data = ast_read32(ast, 0x1202c);
|
||||
data &= 0xfffcffff;
|
||||
ast_write32(ast, 0, data);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -61,9 +61,17 @@ enum ast_chip {
|
|||
AST2200,
|
||||
AST2150,
|
||||
AST2300,
|
||||
AST2400,
|
||||
AST1180,
|
||||
};
|
||||
|
||||
enum ast_tx_chip {
|
||||
AST_TX_NONE,
|
||||
AST_TX_SIL164,
|
||||
AST_TX_ITE66121,
|
||||
AST_TX_DP501,
|
||||
};
|
||||
|
||||
#define AST_DRAM_512Mx16 0
|
||||
#define AST_DRAM_1Gx16 1
|
||||
#define AST_DRAM_512Mx32 2
|
||||
|
@ -102,6 +110,12 @@ struct ast_private {
|
|||
* we have. */
|
||||
struct ttm_bo_kmap_obj cache_kmap;
|
||||
int next_cursor;
|
||||
bool support_wide_screen;
|
||||
|
||||
enum ast_tx_chip tx_chip_type;
|
||||
u8 dp501_maxclk;
|
||||
u8 *dp501_fw_addr;
|
||||
const struct firmware *dp501_fw; /* dp501 fw */
|
||||
};
|
||||
|
||||
int ast_driver_load(struct drm_device *dev, unsigned long flags);
|
||||
|
@ -368,4 +382,14 @@ int ast_mmap(struct file *filp, struct vm_area_struct *vma);
|
|||
|
||||
/* ast post */
|
||||
void ast_post_gpu(struct drm_device *dev);
|
||||
u32 ast_mindwm(struct ast_private *ast, u32 r);
|
||||
void ast_moutdwm(struct ast_private *ast, u32 r, u32 v);
|
||||
/* ast dp501 */
|
||||
int ast_load_dp501_microcode(struct drm_device *dev);
|
||||
void ast_set_dp501_video_output(struct drm_device *dev, u8 mode);
|
||||
bool ast_launch_m68k(struct drm_device *dev);
|
||||
bool ast_backup_fw(struct drm_device *dev, u8 *addr, u32 size);
|
||||
bool ast_dp501_read_edid(struct drm_device *dev, u8 *ediddata);
|
||||
u8 ast_get_dp501_max_clk(struct drm_device *dev);
|
||||
void ast_init_3rdtx(struct drm_device *dev);
|
||||
#endif
|
||||
|
|
|
@ -66,12 +66,16 @@ uint8_t ast_get_index_reg_mask(struct ast_private *ast,
|
|||
static int ast_detect_chip(struct drm_device *dev)
|
||||
{
|
||||
struct ast_private *ast = dev->dev_private;
|
||||
uint32_t data, jreg;
|
||||
|
||||
if (dev->pdev->device == PCI_CHIP_AST1180) {
|
||||
ast->chip = AST1100;
|
||||
DRM_INFO("AST 1180 detected\n");
|
||||
} else {
|
||||
if (dev->pdev->revision >= 0x20) {
|
||||
if (dev->pdev->revision >= 0x30) {
|
||||
ast->chip = AST2400;
|
||||
DRM_INFO("AST 2400 detected\n");
|
||||
} else if (dev->pdev->revision >= 0x20) {
|
||||
ast->chip = AST2300;
|
||||
DRM_INFO("AST 2300 detected\n");
|
||||
} else if (dev->pdev->revision >= 0x10) {
|
||||
|
@ -104,6 +108,59 @@ static int ast_detect_chip(struct drm_device *dev)
|
|||
DRM_INFO("AST 2000 detected\n");
|
||||
}
|
||||
}
|
||||
|
||||
switch (ast->chip) {
|
||||
case AST1180:
|
||||
ast->support_wide_screen = true;
|
||||
break;
|
||||
case AST2000:
|
||||
ast->support_wide_screen = false;
|
||||
break;
|
||||
default:
|
||||
jreg = ast_get_index_reg_mask(ast, AST_IO_CRTC_PORT, 0xd0, 0xff);
|
||||
if (!(jreg & 0x80))
|
||||
ast->support_wide_screen = true;
|
||||
else if (jreg & 0x01)
|
||||
ast->support_wide_screen = true;
|
||||
else {
|
||||
ast->support_wide_screen = false;
|
||||
ast_write32(ast, 0xf004, 0x1e6e0000);
|
||||
ast_write32(ast, 0xf000, 0x1);
|
||||
data = ast_read32(ast, 0x1207c);
|
||||
data &= 0x300;
|
||||
if (ast->chip == AST2300 && data == 0x0) /* ast1300 */
|
||||
ast->support_wide_screen = true;
|
||||
if (ast->chip == AST2400 && data == 0x100) /* ast1400 */
|
||||
ast->support_wide_screen = true;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
ast->tx_chip_type = AST_TX_NONE;
|
||||
jreg = ast_get_index_reg_mask(ast, AST_IO_CRTC_PORT, 0xa3, 0xff);
|
||||
if (jreg & 0x80)
|
||||
ast->tx_chip_type = AST_TX_SIL164;
|
||||
if ((ast->chip == AST2300) || (ast->chip == AST2400)) {
|
||||
jreg = ast_get_index_reg_mask(ast, AST_IO_CRTC_PORT, 0xd1, 0xff);
|
||||
switch (jreg) {
|
||||
case 0x04:
|
||||
ast->tx_chip_type = AST_TX_SIL164;
|
||||
break;
|
||||
case 0x08:
|
||||
ast->dp501_fw_addr = kzalloc(32*1024, GFP_KERNEL);
|
||||
if (ast->dp501_fw_addr) {
|
||||
/* backup firmware */
|
||||
if (ast_backup_fw(dev, ast->dp501_fw_addr, 32*1024)) {
|
||||
kfree(ast->dp501_fw_addr);
|
||||
ast->dp501_fw_addr = NULL;
|
||||
}
|
||||
}
|
||||
/* fallthrough */
|
||||
case 0x0c:
|
||||
ast->tx_chip_type = AST_TX_DP501;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -129,7 +186,7 @@ static int ast_get_dram_info(struct drm_device *dev)
|
|||
else
|
||||
ast->dram_bus_width = 32;
|
||||
|
||||
if (ast->chip == AST2300) {
|
||||
if (ast->chip == AST2300 || ast->chip == AST2400) {
|
||||
switch (data & 0x03) {
|
||||
case 0:
|
||||
ast->dram_type = AST_DRAM_512Mx16;
|
||||
|
@ -257,17 +314,32 @@ static u32 ast_get_vram_info(struct drm_device *dev)
|
|||
{
|
||||
struct ast_private *ast = dev->dev_private;
|
||||
u8 jreg;
|
||||
|
||||
u32 vram_size;
|
||||
ast_open_key(ast);
|
||||
|
||||
vram_size = AST_VIDMEM_DEFAULT_SIZE;
|
||||
jreg = ast_get_index_reg_mask(ast, AST_IO_CRTC_PORT, 0xaa, 0xff);
|
||||
switch (jreg & 3) {
|
||||
case 0: return AST_VIDMEM_SIZE_8M;
|
||||
case 1: return AST_VIDMEM_SIZE_16M;
|
||||
case 2: return AST_VIDMEM_SIZE_32M;
|
||||
case 3: return AST_VIDMEM_SIZE_64M;
|
||||
case 0: vram_size = AST_VIDMEM_SIZE_8M; break;
|
||||
case 1: vram_size = AST_VIDMEM_SIZE_16M; break;
|
||||
case 2: vram_size = AST_VIDMEM_SIZE_32M; break;
|
||||
case 3: vram_size = AST_VIDMEM_SIZE_64M; break;
|
||||
}
|
||||
return AST_VIDMEM_DEFAULT_SIZE;
|
||||
|
||||
jreg = ast_get_index_reg_mask(ast, AST_IO_CRTC_PORT, 0x99, 0xff);
|
||||
switch (jreg & 0x03) {
|
||||
case 1:
|
||||
vram_size -= 0x100000;
|
||||
break;
|
||||
case 2:
|
||||
vram_size -= 0x200000;
|
||||
break;
|
||||
case 3:
|
||||
vram_size -= 0x400000;
|
||||
break;
|
||||
}
|
||||
|
||||
return vram_size;
|
||||
}
|
||||
|
||||
int ast_driver_load(struct drm_device *dev, unsigned long flags)
|
||||
|
@ -316,6 +388,7 @@ int ast_driver_load(struct drm_device *dev, unsigned long flags)
|
|||
if (ast->chip == AST2100 ||
|
||||
ast->chip == AST2200 ||
|
||||
ast->chip == AST2300 ||
|
||||
ast->chip == AST2400 ||
|
||||
ast->chip == AST1180) {
|
||||
dev->mode_config.max_width = 1920;
|
||||
dev->mode_config.max_height = 2048;
|
||||
|
@ -343,6 +416,7 @@ int ast_driver_unload(struct drm_device *dev)
|
|||
{
|
||||
struct ast_private *ast = dev->dev_private;
|
||||
|
||||
kfree(ast->dp501_fw_addr);
|
||||
ast_mode_fini(dev);
|
||||
ast_fbdev_fini(dev);
|
||||
drm_mode_config_cleanup(dev);
|
||||
|
|
|
@ -115,11 +115,17 @@ static bool ast_get_vbios_mode_info(struct drm_crtc *crtc, struct drm_display_mo
|
|||
else
|
||||
vbios_mode->enh_table = &res_1280x1024[refresh_rate_index];
|
||||
break;
|
||||
case 1360:
|
||||
vbios_mode->enh_table = &res_1360x768[refresh_rate_index];
|
||||
break;
|
||||
case 1440:
|
||||
vbios_mode->enh_table = &res_1440x900[refresh_rate_index];
|
||||
break;
|
||||
case 1600:
|
||||
vbios_mode->enh_table = &res_1600x1200[refresh_rate_index];
|
||||
if (crtc->mode.crtc_vdisplay == 900)
|
||||
vbios_mode->enh_table = &res_1600x900[refresh_rate_index];
|
||||
else
|
||||
vbios_mode->enh_table = &res_1600x1200[refresh_rate_index];
|
||||
break;
|
||||
case 1680:
|
||||
vbios_mode->enh_table = &res_1680x1050[refresh_rate_index];
|
||||
|
@ -175,14 +181,17 @@ static bool ast_get_vbios_mode_info(struct drm_crtc *crtc, struct drm_display_mo
|
|||
ast_set_index_reg(ast, AST_IO_CRTC_PORT, 0x8d, refresh_rate_index & 0xff);
|
||||
ast_set_index_reg(ast, AST_IO_CRTC_PORT, 0x8e, mode_id & 0xff);
|
||||
|
||||
ast_set_index_reg(ast, AST_IO_CRTC_PORT, 0x91, 0xa8);
|
||||
ast_set_index_reg(ast, AST_IO_CRTC_PORT, 0x92, crtc->primary->fb->bits_per_pixel);
|
||||
ast_set_index_reg(ast, AST_IO_CRTC_PORT, 0x93, adjusted_mode->clock / 1000);
|
||||
ast_set_index_reg(ast, AST_IO_CRTC_PORT, 0x94, adjusted_mode->crtc_hdisplay);
|
||||
ast_set_index_reg(ast, AST_IO_CRTC_PORT, 0x95, adjusted_mode->crtc_hdisplay >> 8);
|
||||
ast_set_index_reg(ast, AST_IO_CRTC_PORT, 0x91, 0x00);
|
||||
if (vbios_mode->enh_table->flags & NewModeInfo) {
|
||||
ast_set_index_reg(ast, AST_IO_CRTC_PORT, 0x91, 0xa8);
|
||||
ast_set_index_reg(ast, AST_IO_CRTC_PORT, 0x92, crtc->primary->fb->bits_per_pixel);
|
||||
ast_set_index_reg(ast, AST_IO_CRTC_PORT, 0x93, adjusted_mode->clock / 1000);
|
||||
ast_set_index_reg(ast, AST_IO_CRTC_PORT, 0x94, adjusted_mode->crtc_hdisplay);
|
||||
ast_set_index_reg(ast, AST_IO_CRTC_PORT, 0x95, adjusted_mode->crtc_hdisplay >> 8);
|
||||
|
||||
ast_set_index_reg(ast, AST_IO_CRTC_PORT, 0x96, adjusted_mode->crtc_vdisplay);
|
||||
ast_set_index_reg(ast, AST_IO_CRTC_PORT, 0x97, adjusted_mode->crtc_vdisplay >> 8);
|
||||
ast_set_index_reg(ast, AST_IO_CRTC_PORT, 0x96, adjusted_mode->crtc_vdisplay);
|
||||
ast_set_index_reg(ast, AST_IO_CRTC_PORT, 0x97, adjusted_mode->crtc_vdisplay >> 8);
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
|
@ -389,7 +398,7 @@ static void ast_set_ext_reg(struct drm_crtc *crtc, struct drm_display_mode *mode
|
|||
ast_set_index_reg_mask(ast, AST_IO_CRTC_PORT, 0xa8, 0xfd, jregA8);
|
||||
|
||||
/* Set Threshold */
|
||||
if (ast->chip == AST2300) {
|
||||
if (ast->chip == AST2300 || ast->chip == AST2400) {
|
||||
ast_set_index_reg(ast, AST_IO_CRTC_PORT, 0xa7, 0x78);
|
||||
ast_set_index_reg(ast, AST_IO_CRTC_PORT, 0xa6, 0x60);
|
||||
} else if (ast->chip == AST2100 ||
|
||||
|
@ -451,9 +460,13 @@ static void ast_crtc_dpms(struct drm_crtc *crtc, int mode)
|
|||
case DRM_MODE_DPMS_STANDBY:
|
||||
case DRM_MODE_DPMS_SUSPEND:
|
||||
ast_set_index_reg_mask(ast, AST_IO_SEQ_PORT, 0x1, 0xdf, 0);
|
||||
if (ast->tx_chip_type == AST_TX_DP501)
|
||||
ast_set_dp501_video_output(crtc->dev, 1);
|
||||
ast_crtc_load_lut(crtc);
|
||||
break;
|
||||
case DRM_MODE_DPMS_OFF:
|
||||
if (ast->tx_chip_type == AST_TX_DP501)
|
||||
ast_set_dp501_video_output(crtc->dev, 0);
|
||||
ast_set_index_reg_mask(ast, AST_IO_SEQ_PORT, 0x1, 0xdf, 0x20);
|
||||
break;
|
||||
}
|
||||
|
@ -729,10 +742,24 @@ static int ast_encoder_init(struct drm_device *dev)
|
|||
static int ast_get_modes(struct drm_connector *connector)
|
||||
{
|
||||
struct ast_connector *ast_connector = to_ast_connector(connector);
|
||||
struct ast_private *ast = connector->dev->dev_private;
|
||||
struct edid *edid;
|
||||
int ret;
|
||||
bool flags = false;
|
||||
if (ast->tx_chip_type == AST_TX_DP501) {
|
||||
ast->dp501_maxclk = 0xff;
|
||||
edid = kmalloc(128, GFP_KERNEL);
|
||||
if (!edid)
|
||||
return -ENOMEM;
|
||||
|
||||
edid = drm_get_edid(connector, &ast_connector->i2c->adapter);
|
||||
flags = ast_dp501_read_edid(connector->dev, (u8 *)edid);
|
||||
if (flags)
|
||||
ast->dp501_maxclk = ast_get_dp501_max_clk(connector->dev);
|
||||
else
|
||||
kfree(edid);
|
||||
}
|
||||
if (!flags)
|
||||
edid = drm_get_edid(connector, &ast_connector->i2c->adapter);
|
||||
if (edid) {
|
||||
drm_mode_connector_update_edid_property(&ast_connector->base, edid);
|
||||
ret = drm_add_edid_modes(connector, edid);
|
||||
|
@ -746,7 +773,56 @@ static int ast_get_modes(struct drm_connector *connector)
|
|||
static int ast_mode_valid(struct drm_connector *connector,
|
||||
struct drm_display_mode *mode)
|
||||
{
|
||||
return MODE_OK;
|
||||
struct ast_private *ast = connector->dev->dev_private;
|
||||
int flags = MODE_NOMODE;
|
||||
uint32_t jtemp;
|
||||
|
||||
if (ast->support_wide_screen) {
|
||||
if ((mode->hdisplay == 1680) && (mode->vdisplay == 1050))
|
||||
return MODE_OK;
|
||||
if ((mode->hdisplay == 1280) && (mode->vdisplay == 800))
|
||||
return MODE_OK;
|
||||
if ((mode->hdisplay == 1440) && (mode->vdisplay == 900))
|
||||
return MODE_OK;
|
||||
if ((mode->hdisplay == 1360) && (mode->vdisplay == 768))
|
||||
return MODE_OK;
|
||||
if ((mode->hdisplay == 1600) && (mode->vdisplay == 900))
|
||||
return MODE_OK;
|
||||
|
||||
if ((ast->chip == AST2100) || (ast->chip == AST2200) || (ast->chip == AST2300) || (ast->chip == AST2400) || (ast->chip == AST1180)) {
|
||||
if ((mode->hdisplay == 1920) && (mode->vdisplay == 1080))
|
||||
return MODE_OK;
|
||||
|
||||
if ((mode->hdisplay == 1920) && (mode->vdisplay == 1200)) {
|
||||
jtemp = ast_get_index_reg_mask(ast, AST_IO_CRTC_PORT, 0xd1, 0xff);
|
||||
if (jtemp & 0x01)
|
||||
return MODE_NOMODE;
|
||||
else
|
||||
return MODE_OK;
|
||||
}
|
||||
}
|
||||
}
|
||||
switch (mode->hdisplay) {
|
||||
case 640:
|
||||
if (mode->vdisplay == 480) flags = MODE_OK;
|
||||
break;
|
||||
case 800:
|
||||
if (mode->vdisplay == 600) flags = MODE_OK;
|
||||
break;
|
||||
case 1024:
|
||||
if (mode->vdisplay == 768) flags = MODE_OK;
|
||||
break;
|
||||
case 1280:
|
||||
if (mode->vdisplay == 1024) flags = MODE_OK;
|
||||
break;
|
||||
case 1600:
|
||||
if (mode->vdisplay == 1200) flags = MODE_OK;
|
||||
break;
|
||||
default:
|
||||
return flags;
|
||||
}
|
||||
|
||||
return flags;
|
||||
}
|
||||
|
||||
static void ast_connector_destroy(struct drm_connector *connector)
|
||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -42,7 +42,7 @@
|
|||
#define HBorder 0x00000020
|
||||
#define VBorder 0x00000010
|
||||
#define WideScreenMode 0x00000100
|
||||
|
||||
#define NewModeInfo 0x00000200
|
||||
|
||||
/* DCLK Index */
|
||||
#define VCLK25_175 0x00
|
||||
|
@ -67,6 +67,11 @@
|
|||
#define VCLK106_5 0x12
|
||||
#define VCLK146_25 0x13
|
||||
#define VCLK148_5 0x14
|
||||
#define VCLK71 0x15
|
||||
#define VCLK88_75 0x16
|
||||
#define VCLK119 0x17
|
||||
#define VCLK85_5 0x18
|
||||
#define VCLK97_75 0x19
|
||||
|
||||
static struct ast_vbios_dclk_info dclk_table[] = {
|
||||
{0x2C, 0xE7, 0x03}, /* 00: VCLK25_175 */
|
||||
|
@ -90,6 +95,10 @@ static struct ast_vbios_dclk_info dclk_table[] = {
|
|||
{0x28, 0x49, 0x80}, /* 12: VCLK106.5 */
|
||||
{0x37, 0x49, 0x80}, /* 13: VCLK146.25 */
|
||||
{0x1f, 0x45, 0x80}, /* 14: VCLK148.5 */
|
||||
{0x47, 0x6c, 0x80}, /* 15: VCLK71 */
|
||||
{0x25, 0x65, 0x80}, /* 16: VCLK88.75 */
|
||||
{0x77, 0x58, 0x80}, /* 17: VCLK119 */
|
||||
{0x32, 0x67, 0x80}, /* 18: VCLK85_5 */
|
||||
};
|
||||
|
||||
static struct ast_vbios_stdtable vbios_stdtable[] = {
|
||||
|
@ -225,41 +234,63 @@ static struct ast_vbios_enhtable res_1600x1200[] = {
|
|||
(SyncPP | Charx8Dot), 0xFF, 1, 0x33 },
|
||||
};
|
||||
|
||||
static struct ast_vbios_enhtable res_1920x1200[] = {
|
||||
{2080, 1920, 48, 32, 1235, 1200, 3, 6, VCLK154, /* 60Hz */
|
||||
(SyncNP | Charx8Dot), 60, 1, 0x34 },
|
||||
{2080, 1920, 48, 32, 1235, 1200, 3, 6, VCLK154, /* 60Hz */
|
||||
(SyncNP | Charx8Dot), 0xFF, 1, 0x34 },
|
||||
/* 16:9 */
|
||||
static struct ast_vbios_enhtable res_1360x768[] = {
|
||||
{1792, 1360, 64,112, 795, 768, 3, 6, VCLK85_5, /* 60Hz */
|
||||
(SyncPP | Charx8Dot | LineCompareOff | WideScreenMode | NewModeInfo), 60, 1, 0x39 },
|
||||
{1792, 1360, 64,112, 795, 768, 3, 6, VCLK85_5, /* end */
|
||||
(SyncPP | Charx8Dot | LineCompareOff | WideScreenMode | NewModeInfo), 0xFF, 1, 0x39 },
|
||||
};
|
||||
|
||||
static struct ast_vbios_enhtable res_1600x900[] = {
|
||||
{1760, 1600, 48, 32, 926, 900, 3, 5, VCLK97_75, /* 60Hz CVT RB */
|
||||
(SyncNP | Charx8Dot | LineCompareOff | WideScreenMode | NewModeInfo), 60, 1, 0x3A },
|
||||
{1760, 1600, 48, 32, 926, 900, 3, 5, VCLK97_75, /* end */
|
||||
(SyncNP | Charx8Dot | LineCompareOff | WideScreenMode | NewModeInfo), 0xFF, 1, 0x3A }
|
||||
};
|
||||
|
||||
static struct ast_vbios_enhtable res_1920x1080[] = {
|
||||
{2200, 1920, 88, 44, 1125, 1080, 4, 5, VCLK148_5, /* 60Hz */
|
||||
(SyncNP | Charx8Dot | LineCompareOff | WideScreenMode | NewModeInfo), 60, 1, 0x38 },
|
||||
{2200, 1920, 88, 44, 1125, 1080, 4, 5, VCLK148_5, /* 60Hz */
|
||||
(SyncNP | Charx8Dot | LineCompareOff | WideScreenMode | NewModeInfo), 0xFF, 1, 0x38 },
|
||||
};
|
||||
|
||||
|
||||
/* 16:10 */
|
||||
static struct ast_vbios_enhtable res_1280x800[] = {
|
||||
{1440, 1280, 48, 32, 823, 800, 3, 6, VCLK71, /* 60Hz RB */
|
||||
(SyncNP | Charx8Dot | LineCompareOff | WideScreenMode | NewModeInfo), 60, 1, 35 },
|
||||
{1680, 1280, 72,128, 831, 800, 3, 6, VCLK83_5, /* 60Hz */
|
||||
(SyncPN | Charx8Dot | LineCompareOff | WideScreenMode), 60, 1, 0x35 },
|
||||
(SyncPN | Charx8Dot | LineCompareOff | WideScreenMode | NewModeInfo), 60, 1, 0x35 },
|
||||
{1680, 1280, 72,128, 831, 800, 3, 6, VCLK83_5, /* 60Hz */
|
||||
(SyncPN | Charx8Dot | LineCompareOff | WideScreenMode), 0xFF, 1, 0x35 },
|
||||
(SyncPN | Charx8Dot | LineCompareOff | WideScreenMode | NewModeInfo), 0xFF, 1, 0x35 },
|
||||
|
||||
};
|
||||
|
||||
static struct ast_vbios_enhtable res_1440x900[] = {
|
||||
{1600, 1440, 48, 32, 926, 900, 3, 6, VCLK88_75, /* 60Hz RB */
|
||||
(SyncNP | Charx8Dot | LineCompareOff | WideScreenMode | NewModeInfo), 60, 1, 0x36 },
|
||||
{1904, 1440, 80,152, 934, 900, 3, 6, VCLK106_5, /* 60Hz */
|
||||
(SyncPN | Charx8Dot | LineCompareOff | WideScreenMode), 60, 1, 0x36 },
|
||||
(SyncPN | Charx8Dot | LineCompareOff | WideScreenMode | NewModeInfo), 60, 1, 0x36 },
|
||||
{1904, 1440, 80,152, 934, 900, 3, 6, VCLK106_5, /* 60Hz */
|
||||
(SyncPN | Charx8Dot | LineCompareOff | WideScreenMode), 0xFF, 1, 0x36 },
|
||||
(SyncPN | Charx8Dot | LineCompareOff | WideScreenMode | NewModeInfo), 0xFF, 1, 0x36 },
|
||||
};
|
||||
|
||||
static struct ast_vbios_enhtable res_1680x1050[] = {
|
||||
{1840, 1680, 48, 32, 1080, 1050, 3, 6, VCLK119, /* 60Hz RB */
|
||||
(SyncNP | Charx8Dot | LineCompareOff | WideScreenMode | NewModeInfo), 60, 1, 0x37 },
|
||||
{2240, 1680,104,176, 1089, 1050, 3, 6, VCLK146_25, /* 60Hz */
|
||||
(SyncPN | Charx8Dot | LineCompareOff | WideScreenMode), 60, 1, 0x37 },
|
||||
(SyncPN | Charx8Dot | LineCompareOff | WideScreenMode | NewModeInfo), 60, 1, 0x37 },
|
||||
{2240, 1680,104,176, 1089, 1050, 3, 6, VCLK146_25, /* 60Hz */
|
||||
(SyncPN | Charx8Dot | LineCompareOff | WideScreenMode), 0xFF, 1, 0x37 },
|
||||
(SyncPN | Charx8Dot | LineCompareOff | WideScreenMode | NewModeInfo), 0xFF, 1, 0x37 },
|
||||
};
|
||||
|
||||
/* HDTV */
|
||||
static struct ast_vbios_enhtable res_1920x1080[] = {
|
||||
{2200, 1920, 88, 44, 1125, 1080, 4, 5, VCLK148_5, /* 60Hz */
|
||||
(SyncNP | Charx8Dot | LineCompareOff | WideScreenMode), 60, 1, 0x38 },
|
||||
{2200, 1920, 88, 44, 1125, 1080, 4, 5, VCLK148_5, /* 60Hz */
|
||||
(SyncNP | Charx8Dot | LineCompareOff | WideScreenMode), 0xFF, 1, 0x38 },
|
||||
static struct ast_vbios_enhtable res_1920x1200[] = {
|
||||
{2080, 1920, 48, 32, 1235, 1200, 3, 6, VCLK154, /* 60Hz */
|
||||
(SyncNP | Charx8Dot | LineCompareOff | WideScreenMode | NewModeInfo), 60, 1, 0x34 },
|
||||
{2080, 1920, 48, 32, 1235, 1200, 3, 6, VCLK154, /* 60Hz */
|
||||
(SyncNP | Charx8Dot | LineCompareOff | WideScreenMode | NewModeInfo), 0xFF, 1, 0x34 },
|
||||
};
|
||||
|
||||
#endif
|
||||
|
|
|
@ -225,12 +225,6 @@ out:
|
|||
return num_modes;
|
||||
}
|
||||
|
||||
static int ptn3460_mode_valid(struct drm_connector *connector,
|
||||
struct drm_display_mode *mode)
|
||||
{
|
||||
return MODE_OK;
|
||||
}
|
||||
|
||||
struct drm_encoder *ptn3460_best_encoder(struct drm_connector *connector)
|
||||
{
|
||||
struct ptn3460_bridge *ptn_bridge;
|
||||
|
@ -242,7 +236,6 @@ struct drm_encoder *ptn3460_best_encoder(struct drm_connector *connector)
|
|||
|
||||
struct drm_connector_helper_funcs ptn3460_connector_helper_funcs = {
|
||||
.get_modes = ptn3460_get_modes,
|
||||
.mode_valid = ptn3460_mode_valid,
|
||||
.best_encoder = ptn3460_best_encoder,
|
||||
};
|
||||
|
||||
|
|
|
@ -505,13 +505,6 @@ static int cirrus_vga_get_modes(struct drm_connector *connector)
|
|||
return count;
|
||||
}
|
||||
|
||||
static int cirrus_vga_mode_valid(struct drm_connector *connector,
|
||||
struct drm_display_mode *mode)
|
||||
{
|
||||
/* Any mode we've added is valid */
|
||||
return MODE_OK;
|
||||
}
|
||||
|
||||
static struct drm_encoder *cirrus_connector_best_encoder(struct drm_connector
|
||||
*connector)
|
||||
{
|
||||
|
@ -546,7 +539,6 @@ static void cirrus_connector_destroy(struct drm_connector *connector)
|
|||
|
||||
struct drm_connector_helper_funcs cirrus_vga_connector_helper_funcs = {
|
||||
.get_modes = cirrus_vga_get_modes,
|
||||
.mode_valid = cirrus_vga_mode_valid,
|
||||
.best_encoder = cirrus_connector_best_encoder,
|
||||
};
|
||||
|
||||
|
|
|
@ -363,7 +363,7 @@ static int drm_addmap_core(struct drm_device * dev, resource_size_t offset,
|
|||
list->master = dev->primary->master;
|
||||
*maplist = list;
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
int drm_addmap(struct drm_device * dev, resource_size_t offset,
|
||||
unsigned int size, enum drm_map_type type,
|
||||
|
|
|
@ -1145,16 +1145,19 @@ EXPORT_SYMBOL(drm_plane_cleanup);
|
|||
*/
|
||||
void drm_plane_force_disable(struct drm_plane *plane)
|
||||
{
|
||||
struct drm_framebuffer *old_fb = plane->fb;
|
||||
int ret;
|
||||
|
||||
if (!plane->fb)
|
||||
if (!old_fb)
|
||||
return;
|
||||
|
||||
ret = plane->funcs->disable_plane(plane);
|
||||
if (ret)
|
||||
if (ret) {
|
||||
DRM_ERROR("failed to disable plane with busy fb\n");
|
||||
return;
|
||||
}
|
||||
/* disconnect the plane from the fb and crtc: */
|
||||
__drm_framebuffer_unreference(plane->fb);
|
||||
__drm_framebuffer_unreference(old_fb);
|
||||
plane->fb = NULL;
|
||||
plane->crtc = NULL;
|
||||
}
|
||||
|
@ -1378,6 +1381,12 @@ static int drm_mode_group_init(struct drm_device *dev, struct drm_mode_group *gr
|
|||
return 0;
|
||||
}
|
||||
|
||||
void drm_mode_group_destroy(struct drm_mode_group *group)
|
||||
{
|
||||
kfree(group->id_list);
|
||||
group->id_list = NULL;
|
||||
}
|
||||
|
||||
/*
|
||||
* NOTE: Driver's shouldn't ever call drm_mode_group_init_legacy_group - it is
|
||||
* the drm core's responsibility to set up mode control groups.
|
||||
|
@ -2116,9 +2125,13 @@ int drm_mode_setplane(struct drm_device *dev, void *data,
|
|||
if (!plane_req->fb_id) {
|
||||
drm_modeset_lock_all(dev);
|
||||
old_fb = plane->fb;
|
||||
plane->funcs->disable_plane(plane);
|
||||
plane->crtc = NULL;
|
||||
plane->fb = NULL;
|
||||
ret = plane->funcs->disable_plane(plane);
|
||||
if (!ret) {
|
||||
plane->crtc = NULL;
|
||||
plane->fb = NULL;
|
||||
} else {
|
||||
old_fb = NULL;
|
||||
}
|
||||
drm_modeset_unlock_all(dev);
|
||||
goto out;
|
||||
}
|
||||
|
@ -2187,16 +2200,18 @@ int drm_mode_setplane(struct drm_device *dev, void *data,
|
|||
}
|
||||
|
||||
drm_modeset_lock_all(dev);
|
||||
old_fb = plane->fb;
|
||||
ret = plane->funcs->update_plane(plane, crtc, fb,
|
||||
plane_req->crtc_x, plane_req->crtc_y,
|
||||
plane_req->crtc_w, plane_req->crtc_h,
|
||||
plane_req->src_x, plane_req->src_y,
|
||||
plane_req->src_w, plane_req->src_h);
|
||||
if (!ret) {
|
||||
old_fb = plane->fb;
|
||||
plane->crtc = crtc;
|
||||
plane->fb = fb;
|
||||
fb = NULL;
|
||||
} else {
|
||||
old_fb = NULL;
|
||||
}
|
||||
drm_modeset_unlock_all(dev);
|
||||
|
||||
|
@ -2239,9 +2254,7 @@ int drm_mode_set_config_internal(struct drm_mode_set *set)
|
|||
ret = crtc->funcs->set_config(set);
|
||||
if (ret == 0) {
|
||||
crtc->primary->crtc = crtc;
|
||||
|
||||
/* crtc->fb must be updated by ->set_config, enforces this. */
|
||||
WARN_ON(fb != crtc->primary->fb);
|
||||
crtc->primary->fb = fb;
|
||||
}
|
||||
|
||||
list_for_each_entry(tmp, &crtc->dev->mode_config.crtc_list, head) {
|
||||
|
|
|
@ -140,16 +140,10 @@ drm_encoder_disable(struct drm_encoder *encoder)
|
|||
static void __drm_helper_disable_unused_functions(struct drm_device *dev)
|
||||
{
|
||||
struct drm_encoder *encoder;
|
||||
struct drm_connector *connector;
|
||||
struct drm_crtc *crtc;
|
||||
|
||||
drm_warn_on_modeset_not_all_locked(dev);
|
||||
|
||||
list_for_each_entry(connector, &dev->mode_config.connector_list, head) {
|
||||
if (!connector->encoder)
|
||||
continue;
|
||||
}
|
||||
|
||||
list_for_each_entry(encoder, &dev->mode_config.encoder_list, head) {
|
||||
if (!drm_helper_encoder_in_use(encoder)) {
|
||||
drm_encoder_disable(encoder);
|
||||
|
@ -387,8 +381,7 @@ done:
|
|||
}
|
||||
EXPORT_SYMBOL(drm_crtc_helper_set_mode);
|
||||
|
||||
|
||||
static int
|
||||
static void
|
||||
drm_crtc_helper_disable(struct drm_crtc *crtc)
|
||||
{
|
||||
struct drm_device *dev = crtc->dev;
|
||||
|
@ -417,7 +410,6 @@ drm_crtc_helper_disable(struct drm_crtc *crtc)
|
|||
}
|
||||
|
||||
__drm_helper_disable_unused_functions(dev);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -468,7 +460,8 @@ int drm_crtc_helper_set_config(struct drm_mode_set *set)
|
|||
(int)set->num_connectors, set->x, set->y);
|
||||
} else {
|
||||
DRM_DEBUG_KMS("[CRTC:%d] [NOFB]\n", set->crtc->base.id);
|
||||
return drm_crtc_helper_disable(set->crtc);
|
||||
drm_crtc_helper_disable(set->crtc);
|
||||
return 0;
|
||||
}
|
||||
|
||||
dev = set->crtc->dev;
|
||||
|
|
|
@ -206,7 +206,7 @@ i2c_dp_aux_prepare_bus(struct i2c_adapter *adapter)
|
|||
* i2c_dp_aux_add_bus() - register an i2c adapter using the aux ch helper
|
||||
* @adapter: i2c adapter to register
|
||||
*
|
||||
* This registers an i2c adapater that uses dp aux channel as it's underlaying
|
||||
* This registers an i2c adapter that uses dp aux channel as it's underlaying
|
||||
* transport. The driver needs to fill out the &i2c_algo_dp_aux_data structure
|
||||
* and store it in the algo_data member of the @adapter argument. This will be
|
||||
* used by the i2c over dp aux algorithm to drive the hardware.
|
||||
|
|
|
@ -984,9 +984,13 @@ static const u8 edid_header[] = {
|
|||
0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00
|
||||
};
|
||||
|
||||
/*
|
||||
* Sanity check the header of the base EDID block. Return 8 if the header
|
||||
* is perfect, down to 0 if it's totally wrong.
|
||||
/**
|
||||
* drm_edid_header_is_valid - sanity check the header of the base EDID block
|
||||
* @raw_edid: pointer to raw base EDID block
|
||||
*
|
||||
* Sanity check the header of the base EDID block.
|
||||
*
|
||||
* Return: 8 if the header is perfect, down to 0 if it's totally wrong.
|
||||
*/
|
||||
int drm_edid_header_is_valid(const u8 *raw_edid)
|
||||
{
|
||||
|
@ -1005,9 +1009,16 @@ module_param_named(edid_fixup, edid_fixup, int, 0400);
|
|||
MODULE_PARM_DESC(edid_fixup,
|
||||
"Minimum number of valid EDID header bytes (0-8, default 6)");
|
||||
|
||||
/*
|
||||
* Sanity check the EDID block (base or extension). Return 0 if the block
|
||||
* doesn't check out, or 1 if it's valid.
|
||||
/**
|
||||
* drm_edid_block_valid - Sanity check the EDID block (base or extension)
|
||||
* @raw_edid: pointer to raw EDID block
|
||||
* @block: type of block to validate (0 for base, extension otherwise)
|
||||
* @print_bad_edid: if true, dump bad EDID blocks to the console
|
||||
*
|
||||
* Validate a base or extension EDID block and optionally dump bad blocks to
|
||||
* the console.
|
||||
*
|
||||
* Return: True if the block is valid, false otherwise.
|
||||
*/
|
||||
bool drm_edid_block_valid(u8 *raw_edid, int block, bool print_bad_edid)
|
||||
{
|
||||
|
@ -1077,6 +1088,8 @@ EXPORT_SYMBOL(drm_edid_block_valid);
|
|||
* @edid: EDID data
|
||||
*
|
||||
* Sanity-check an entire EDID record (including extensions)
|
||||
*
|
||||
* Return: True if the EDID data is valid, false otherwise.
|
||||
*/
|
||||
bool drm_edid_is_valid(struct edid *edid)
|
||||
{
|
||||
|
@ -1096,18 +1109,15 @@ EXPORT_SYMBOL(drm_edid_is_valid);
|
|||
|
||||
#define DDC_SEGMENT_ADDR 0x30
|
||||
/**
|
||||
* Get EDID information via I2C.
|
||||
*
|
||||
* @adapter : i2c device adaptor
|
||||
* drm_do_probe_ddc_edid() - get EDID information via I2C
|
||||
* @adapter: I2C device adaptor
|
||||
* @buf: EDID data buffer to be filled
|
||||
* @block: 128 byte EDID block to start fetching from
|
||||
* @len: EDID data buffer length to fetch
|
||||
*
|
||||
* Returns:
|
||||
* Try to fetch EDID information by calling I2C driver functions.
|
||||
*
|
||||
* 0 on success or -1 on failure.
|
||||
*
|
||||
* Try to fetch EDID information by calling i2c driver function.
|
||||
* Return: 0 on success or -1 on failure.
|
||||
*/
|
||||
static int
|
||||
drm_do_probe_ddc_edid(struct i2c_adapter *adapter, unsigned char *buf,
|
||||
|
@ -1118,7 +1128,8 @@ drm_do_probe_ddc_edid(struct i2c_adapter *adapter, unsigned char *buf,
|
|||
unsigned char xfers = segment ? 3 : 2;
|
||||
int ret, retries = 5;
|
||||
|
||||
/* The core i2c driver will automatically retry the transfer if the
|
||||
/*
|
||||
* The core I2C driver will automatically retry the transfer if the
|
||||
* adapter reports EAGAIN. However, we find that bit-banging transfers
|
||||
* are susceptible to errors under a heavily loaded machine and
|
||||
* generate spurious NAKs and timeouts. Retrying the transfer
|
||||
|
@ -1144,10 +1155,10 @@ drm_do_probe_ddc_edid(struct i2c_adapter *adapter, unsigned char *buf,
|
|||
}
|
||||
};
|
||||
|
||||
/*
|
||||
* Avoid sending the segment addr to not upset non-compliant ddc
|
||||
* monitors.
|
||||
*/
|
||||
/*
|
||||
* Avoid sending the segment addr to not upset non-compliant
|
||||
* DDC monitors.
|
||||
*/
|
||||
ret = i2c_transfer(adapter, &msgs[3 - xfers], xfers);
|
||||
|
||||
if (ret == -ENXIO) {
|
||||
|
@ -1246,12 +1257,10 @@ out:
|
|||
}
|
||||
|
||||
/**
|
||||
* Probe DDC presence.
|
||||
* @adapter: i2c adapter to probe
|
||||
* drm_probe_ddc() - probe DDC presence
|
||||
* @adapter: I2C adapter to probe
|
||||
*
|
||||
* Returns:
|
||||
*
|
||||
* 1 on success
|
||||
* Return: True on success, false on failure.
|
||||
*/
|
||||
bool
|
||||
drm_probe_ddc(struct i2c_adapter *adapter)
|
||||
|
@ -1265,12 +1274,12 @@ EXPORT_SYMBOL(drm_probe_ddc);
|
|||
/**
|
||||
* drm_get_edid - get EDID data, if available
|
||||
* @connector: connector we're probing
|
||||
* @adapter: i2c adapter to use for DDC
|
||||
* @adapter: I2C adapter to use for DDC
|
||||
*
|
||||
* Poke the given i2c channel to grab EDID data if possible. If found,
|
||||
* Poke the given I2C channel to grab EDID data if possible. If found,
|
||||
* attach it to the connector.
|
||||
*
|
||||
* Return edid data or NULL if we couldn't find any.
|
||||
* Return: Pointer to valid EDID or NULL if we couldn't find any.
|
||||
*/
|
||||
struct edid *drm_get_edid(struct drm_connector *connector,
|
||||
struct i2c_adapter *adapter)
|
||||
|
@ -1288,7 +1297,7 @@ EXPORT_SYMBOL(drm_get_edid);
|
|||
* drm_edid_duplicate - duplicate an EDID and the extensions
|
||||
* @edid: EDID to duplicate
|
||||
*
|
||||
* Return duplicate edid or NULL on allocation failure.
|
||||
* Return: Pointer to duplicated EDID or NULL on allocation failure.
|
||||
*/
|
||||
struct edid *drm_edid_duplicate(const struct edid *edid)
|
||||
{
|
||||
|
@ -1411,7 +1420,8 @@ mode_is_rb(const struct drm_display_mode *mode)
|
|||
* @rb: Mode reduced-blanking-ness
|
||||
*
|
||||
* Walk the DMT mode list looking for a match for the given parameters.
|
||||
* Return a newly allocated copy of the mode, or NULL if not found.
|
||||
*
|
||||
* Return: A newly allocated copy of the mode, or NULL if not found.
|
||||
*/
|
||||
struct drm_display_mode *drm_mode_find_dmt(struct drm_device *dev,
|
||||
int hsize, int vsize, int fresh,
|
||||
|
@ -1595,14 +1605,13 @@ bad_std_timing(u8 a, u8 b)
|
|||
* @connector: connector of for the EDID block
|
||||
* @edid: EDID block to scan
|
||||
* @t: standard timing params
|
||||
* @revision: standard timing level
|
||||
*
|
||||
* Take the standard timing params (in this case width, aspect, and refresh)
|
||||
* and convert them into a real mode using CVT/GTF/DMT.
|
||||
*/
|
||||
static struct drm_display_mode *
|
||||
drm_mode_std(struct drm_connector *connector, struct edid *edid,
|
||||
struct std_timing *t, int revision)
|
||||
struct std_timing *t)
|
||||
{
|
||||
struct drm_device *dev = connector->dev;
|
||||
struct drm_display_mode *m, *mode = NULL;
|
||||
|
@ -1623,7 +1632,7 @@ drm_mode_std(struct drm_connector *connector, struct edid *edid,
|
|||
vrefresh_rate = vfreq + 60;
|
||||
/* the vdisplay is calculated based on the aspect ratio */
|
||||
if (aspect_ratio == 0) {
|
||||
if (revision < 3)
|
||||
if (edid->revision < 3)
|
||||
vsize = hsize;
|
||||
else
|
||||
vsize = (hsize * 10) / 16;
|
||||
|
@ -2140,7 +2149,7 @@ do_established_modes(struct detailed_timing *timing, void *c)
|
|||
|
||||
/**
|
||||
* add_established_modes - get est. modes from EDID and add them
|
||||
* @connector: connector of for the EDID block
|
||||
* @connector: connector to add mode(s) to
|
||||
* @edid: EDID block to scan
|
||||
*
|
||||
* Each EDID block contains a bitmap of the supported "established modes" list
|
||||
|
@ -2191,8 +2200,7 @@ do_standard_modes(struct detailed_timing *timing, void *c)
|
|||
struct drm_display_mode *newmode;
|
||||
|
||||
std = &data->data.timings[i];
|
||||
newmode = drm_mode_std(connector, edid, std,
|
||||
edid->revision);
|
||||
newmode = drm_mode_std(connector, edid, std);
|
||||
if (newmode) {
|
||||
drm_mode_probed_add(connector, newmode);
|
||||
closure->modes++;
|
||||
|
@ -2203,7 +2211,7 @@ do_standard_modes(struct detailed_timing *timing, void *c)
|
|||
|
||||
/**
|
||||
* add_standard_modes - get std. modes from EDID and add them
|
||||
* @connector: connector of for the EDID block
|
||||
* @connector: connector to add mode(s) to
|
||||
* @edid: EDID block to scan
|
||||
*
|
||||
* Standard modes can be calculated using the appropriate standard (DMT,
|
||||
|
@ -2221,8 +2229,7 @@ add_standard_modes(struct drm_connector *connector, struct edid *edid)
|
|||
struct drm_display_mode *newmode;
|
||||
|
||||
newmode = drm_mode_std(connector, edid,
|
||||
&edid->standard_timings[i],
|
||||
edid->revision);
|
||||
&edid->standard_timings[i]);
|
||||
if (newmode) {
|
||||
drm_mode_probed_add(connector, newmode);
|
||||
modes++;
|
||||
|
@ -2425,7 +2432,7 @@ cea_mode_alternate_clock(const struct drm_display_mode *cea_mode)
|
|||
* drm_match_cea_mode - look for a CEA mode matching given mode
|
||||
* @to_match: display mode
|
||||
*
|
||||
* Returns the CEA Video ID (VIC) of the mode or 0 if it isn't a CEA-861
|
||||
* Return: The CEA Video ID (VIC) of the mode or 0 if it isn't a CEA-861
|
||||
* mode.
|
||||
*/
|
||||
u8 drm_match_cea_mode(const struct drm_display_mode *to_match)
|
||||
|
@ -2452,6 +2459,22 @@ u8 drm_match_cea_mode(const struct drm_display_mode *to_match)
|
|||
}
|
||||
EXPORT_SYMBOL(drm_match_cea_mode);
|
||||
|
||||
/**
|
||||
* drm_get_cea_aspect_ratio - get the picture aspect ratio corresponding to
|
||||
* the input VIC from the CEA mode list
|
||||
* @video_code: ID given to each of the CEA modes
|
||||
*
|
||||
* Returns picture aspect ratio
|
||||
*/
|
||||
enum hdmi_picture_aspect drm_get_cea_aspect_ratio(const u8 video_code)
|
||||
{
|
||||
/* return picture aspect ratio for video_code - 1 to access the
|
||||
* right array element
|
||||
*/
|
||||
return edid_cea_modes[video_code-1].picture_aspect_ratio;
|
||||
}
|
||||
EXPORT_SYMBOL(drm_get_cea_aspect_ratio);
|
||||
|
||||
/*
|
||||
* Calculate the alternate clock for HDMI modes (those from the HDMI vendor
|
||||
* specific block).
|
||||
|
@ -3023,11 +3046,9 @@ monitor_name(struct detailed_timing *t, void *data)
|
|||
* @connector: connector corresponding to the HDMI/DP sink
|
||||
* @edid: EDID to parse
|
||||
*
|
||||
* Fill the ELD (EDID-Like Data) buffer for passing to the audio driver.
|
||||
* Some ELD fields are left to the graphics driver caller:
|
||||
* - Conn_Type
|
||||
* - HDCP
|
||||
* - Port_ID
|
||||
* Fill the ELD (EDID-Like Data) buffer for passing to the audio driver. The
|
||||
* Conn_Type, HDCP and Port_ID ELD fields are left for the graphics driver to
|
||||
* fill in.
|
||||
*/
|
||||
void drm_edid_to_eld(struct drm_connector *connector, struct edid *edid)
|
||||
{
|
||||
|
@ -3111,9 +3132,10 @@ EXPORT_SYMBOL(drm_edid_to_eld);
|
|||
* @sads: pointer that will be set to the extracted SADs
|
||||
*
|
||||
* Looks for CEA EDID block and extracts SADs (Short Audio Descriptors) from it.
|
||||
* Note: returned pointer needs to be kfreed
|
||||
*
|
||||
* Return number of found SADs or negative number on error.
|
||||
* Note: The returned pointer needs to be freed using kfree().
|
||||
*
|
||||
* Return: The number of found SADs or negative number on error.
|
||||
*/
|
||||
int drm_edid_to_sad(struct edid *edid, struct cea_sad **sads)
|
||||
{
|
||||
|
@ -3170,9 +3192,11 @@ EXPORT_SYMBOL(drm_edid_to_sad);
|
|||
* @sadb: pointer to the speaker block
|
||||
*
|
||||
* Looks for CEA EDID block and extracts the Speaker Allocation Data Block from it.
|
||||
* Note: returned pointer needs to be kfreed
|
||||
*
|
||||
* Return number of found Speaker Allocation Blocks or negative number on error.
|
||||
* Note: The returned pointer needs to be freed using kfree().
|
||||
*
|
||||
* Return: The number of found Speaker Allocation Blocks or negative number on
|
||||
* error.
|
||||
*/
|
||||
int drm_edid_to_speaker_allocation(struct edid *edid, u8 **sadb)
|
||||
{
|
||||
|
@ -3219,9 +3243,12 @@ int drm_edid_to_speaker_allocation(struct edid *edid, u8 **sadb)
|
|||
EXPORT_SYMBOL(drm_edid_to_speaker_allocation);
|
||||
|
||||
/**
|
||||
* drm_av_sync_delay - HDMI/DP sink audio-video sync delay in millisecond
|
||||
* drm_av_sync_delay - compute the HDMI/DP sink audio-video sync delay
|
||||
* @connector: connector associated with the HDMI/DP sink
|
||||
* @mode: the display mode
|
||||
*
|
||||
* Return: The HDMI/DP sink's audio-video sync delay in milliseconds or 0 if
|
||||
* the sink doesn't support audio or video.
|
||||
*/
|
||||
int drm_av_sync_delay(struct drm_connector *connector,
|
||||
struct drm_display_mode *mode)
|
||||
|
@ -3263,6 +3290,9 @@ EXPORT_SYMBOL(drm_av_sync_delay);
|
|||
*
|
||||
* It's possible for one encoder to be associated with multiple HDMI/DP sinks.
|
||||
* The policy is now hard coded to simply use the first HDMI/DP sink's ELD.
|
||||
*
|
||||
* Return: The connector associated with the first HDMI/DP sink that has ELD
|
||||
* attached to it.
|
||||
*/
|
||||
struct drm_connector *drm_select_eld(struct drm_encoder *encoder,
|
||||
struct drm_display_mode *mode)
|
||||
|
@ -3279,11 +3309,12 @@ struct drm_connector *drm_select_eld(struct drm_encoder *encoder,
|
|||
EXPORT_SYMBOL(drm_select_eld);
|
||||
|
||||
/**
|
||||
* drm_detect_hdmi_monitor - detect whether monitor is hdmi.
|
||||
* drm_detect_hdmi_monitor - detect whether monitor is HDMI
|
||||
* @edid: monitor EDID information
|
||||
*
|
||||
* Parse the CEA extension according to CEA-861-B.
|
||||
* Return true if HDMI, false if not or unknown.
|
||||
*
|
||||
* Return: True if the monitor is HDMI, false if not or unknown.
|
||||
*/
|
||||
bool drm_detect_hdmi_monitor(struct edid *edid)
|
||||
{
|
||||
|
@ -3321,6 +3352,7 @@ EXPORT_SYMBOL(drm_detect_hdmi_monitor);
|
|||
* audio format, assume at least 'basic audio' support, even if 'basic
|
||||
* audio' is not defined in EDID.
|
||||
*
|
||||
* Return: True if the monitor supports audio, false otherwise.
|
||||
*/
|
||||
bool drm_detect_monitor_audio(struct edid *edid)
|
||||
{
|
||||
|
@ -3364,6 +3396,8 @@ EXPORT_SYMBOL(drm_detect_monitor_audio);
|
|||
* Check whether the monitor reports the RGB quantization range selection
|
||||
* as supported. The AVI infoframe can then be used to inform the monitor
|
||||
* which quantization range (full or limited) is used.
|
||||
*
|
||||
* Return: True if the RGB quantization range is selectable, false otherwise.
|
||||
*/
|
||||
bool drm_rgb_quant_range_selectable(struct edid *edid)
|
||||
{
|
||||
|
@ -3468,11 +3502,11 @@ static void drm_add_display_info(struct edid *edid,
|
|||
/**
|
||||
* drm_add_edid_modes - add modes from EDID data, if available
|
||||
* @connector: connector we're probing
|
||||
* @edid: edid data
|
||||
* @edid: EDID data
|
||||
*
|
||||
* Add the specified modes to the connector's mode list.
|
||||
*
|
||||
* Return number of modes added or 0 if we couldn't find any.
|
||||
* Return: The number of modes added or 0 if we couldn't find any.
|
||||
*/
|
||||
int drm_add_edid_modes(struct drm_connector *connector, struct edid *edid)
|
||||
{
|
||||
|
@ -3534,7 +3568,7 @@ EXPORT_SYMBOL(drm_add_edid_modes);
|
|||
* 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.
|
||||
* Return: The 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)
|
||||
|
@ -3573,13 +3607,22 @@ int drm_add_modes_noedid(struct drm_connector *connector,
|
|||
}
|
||||
EXPORT_SYMBOL(drm_add_modes_noedid);
|
||||
|
||||
/**
|
||||
* drm_set_preferred_mode - Sets the preferred mode of a connector
|
||||
* @connector: connector whose mode list should be processed
|
||||
* @hpref: horizontal resolution of preferred mode
|
||||
* @vpref: vertical resolution of preferred mode
|
||||
*
|
||||
* Marks a mode as preferred if it matches the resolution specified by @hpref
|
||||
* and @vpref.
|
||||
*/
|
||||
void drm_set_preferred_mode(struct drm_connector *connector,
|
||||
int hpref, int vpref)
|
||||
{
|
||||
struct drm_display_mode *mode;
|
||||
|
||||
list_for_each_entry(mode, &connector->probed_modes, head) {
|
||||
if (mode->hdisplay == hpref &&
|
||||
if (mode->hdisplay == hpref &&
|
||||
mode->vdisplay == vpref)
|
||||
mode->type |= DRM_MODE_TYPE_PREFERRED;
|
||||
}
|
||||
|
@ -3592,7 +3635,7 @@ EXPORT_SYMBOL(drm_set_preferred_mode);
|
|||
* @frame: HDMI AVI infoframe
|
||||
* @mode: DRM display mode
|
||||
*
|
||||
* Returns 0 on success or a negative error code on failure.
|
||||
* Return: 0 on success or a negative error code on failure.
|
||||
*/
|
||||
int
|
||||
drm_hdmi_avi_infoframe_from_display_mode(struct hdmi_avi_infoframe *frame,
|
||||
|
@ -3613,6 +3656,12 @@ drm_hdmi_avi_infoframe_from_display_mode(struct hdmi_avi_infoframe *frame,
|
|||
frame->video_code = drm_match_cea_mode(mode);
|
||||
|
||||
frame->picture_aspect = HDMI_PICTURE_ASPECT_NONE;
|
||||
|
||||
/* Populate picture aspect ratio from CEA mode list */
|
||||
if (frame->video_code > 0)
|
||||
frame->picture_aspect = drm_get_cea_aspect_ratio(
|
||||
frame->video_code);
|
||||
|
||||
frame->active_aspect = HDMI_ACTIVE_ASPECT_PICTURE;
|
||||
frame->scan_mode = HDMI_SCAN_MODE_UNDERSCAN;
|
||||
|
||||
|
@ -3657,7 +3706,7 @@ s3d_structure_from_display_mode(const struct drm_display_mode *mode)
|
|||
* 4k or stereoscopic 3D mode. So when giving any other mode as input this
|
||||
* function will return -EINVAL, error that can be safely ignored.
|
||||
*
|
||||
* Returns 0 on success or a negative error code on failure.
|
||||
* Return: 0 on success or a negative error code on failure.
|
||||
*/
|
||||
int
|
||||
drm_hdmi_vendor_infoframe_from_display_mode(struct hdmi_vendor_infoframe *frame,
|
||||
|
|
|
@ -45,13 +45,13 @@ static LIST_HEAD(kernel_fb_helper_list);
|
|||
* DOC: fbdev helpers
|
||||
*
|
||||
* The fb helper functions are useful to provide an fbdev on top of a drm kernel
|
||||
* mode setting driver. They can be used mostly independantely from the crtc
|
||||
* mode setting driver. They can be used mostly independently from the crtc
|
||||
* helper functions used by many drivers to implement the kernel mode setting
|
||||
* interfaces.
|
||||
*
|
||||
* Initialization is done as a three-step process with drm_fb_helper_init(),
|
||||
* drm_fb_helper_single_add_all_connectors() and drm_fb_helper_initial_config().
|
||||
* Drivers with fancier requirements than the default beheviour can override the
|
||||
* Drivers with fancier requirements than the default behaviour can override the
|
||||
* second step with their own code. Teardown is done with drm_fb_helper_fini().
|
||||
*
|
||||
* At runtime drivers should restore the fbdev console by calling
|
||||
|
@ -59,7 +59,7 @@ static LIST_HEAD(kernel_fb_helper_list);
|
|||
* should also notify the fb helper code from updates to the output
|
||||
* configuration by calling drm_fb_helper_hotplug_event(). For easier
|
||||
* integration with the output polling code in drm_crtc_helper.c the modeset
|
||||
* code proves a ->output_poll_changed callback.
|
||||
* code provides a ->output_poll_changed callback.
|
||||
*
|
||||
* All other functions exported by the fb helper library can be used to
|
||||
* implement the fbdev driver interface by the driver.
|
||||
|
@ -326,12 +326,21 @@ static bool drm_fb_helper_force_kernel_mode(void)
|
|||
return false;
|
||||
|
||||
list_for_each_entry(helper, &kernel_fb_helper_list, kernel_fb_list) {
|
||||
if (helper->dev->switch_power_state == DRM_SWITCH_POWER_OFF)
|
||||
struct drm_device *dev = helper->dev;
|
||||
|
||||
if (dev->switch_power_state == DRM_SWITCH_POWER_OFF)
|
||||
continue;
|
||||
|
||||
if (!mutex_trylock(&dev->mode_config.mutex)) {
|
||||
error = true;
|
||||
continue;
|
||||
}
|
||||
|
||||
ret = drm_fb_helper_restore_fbdev_mode(helper);
|
||||
if (ret)
|
||||
error = true;
|
||||
|
||||
mutex_unlock(&dev->mode_config.mutex);
|
||||
}
|
||||
return error;
|
||||
}
|
||||
|
|
|
@ -43,8 +43,7 @@
|
|||
DEFINE_MUTEX(drm_global_mutex);
|
||||
EXPORT_SYMBOL(drm_global_mutex);
|
||||
|
||||
static int drm_open_helper(struct inode *inode, struct file *filp,
|
||||
struct drm_minor *minor);
|
||||
static int drm_open_helper(struct file *filp, struct drm_minor *minor);
|
||||
|
||||
static int drm_setup(struct drm_device * dev)
|
||||
{
|
||||
|
@ -95,7 +94,7 @@ int drm_open(struct inode *inode, struct file *filp)
|
|||
/* share address_space across all char-devs of a single device */
|
||||
filp->f_mapping = dev->anon_inode->i_mapping;
|
||||
|
||||
retcode = drm_open_helper(inode, filp, minor);
|
||||
retcode = drm_open_helper(filp, minor);
|
||||
if (retcode)
|
||||
goto err_undo;
|
||||
if (need_setup) {
|
||||
|
@ -171,7 +170,6 @@ static int drm_cpu_valid(void)
|
|||
/**
|
||||
* Called whenever a process opens /dev/drm.
|
||||
*
|
||||
* \param inode device inode.
|
||||
* \param filp file pointer.
|
||||
* \param minor acquired minor-object.
|
||||
* \return zero on success or a negative number on failure.
|
||||
|
@ -179,8 +177,7 @@ static int drm_cpu_valid(void)
|
|||
* Creates and initializes a drm_file structure for the file private data in \p
|
||||
* filp and add it into the double linked list in \p dev.
|
||||
*/
|
||||
static int drm_open_helper(struct inode *inode, struct file *filp,
|
||||
struct drm_minor *minor)
|
||||
static int drm_open_helper(struct file *filp, struct drm_minor *minor)
|
||||
{
|
||||
struct drm_device *dev = minor->dev;
|
||||
struct drm_file *priv;
|
||||
|
|
|
@ -1,6 +1,5 @@
|
|||
/**
|
||||
* \file drm_irq.c
|
||||
* IRQ support
|
||||
/*
|
||||
* drm_irq.c IRQ and vblank support
|
||||
*
|
||||
* \author Rickard E. (Rik) Faith <faith@valinux.com>
|
||||
* \author Gareth Hughes <gareth@valinux.com>
|
||||
|
@ -140,33 +139,40 @@ static void vblank_disable_and_save(struct drm_device *dev, int crtc)
|
|||
|
||||
static void vblank_disable_fn(unsigned long arg)
|
||||
{
|
||||
struct drm_device *dev = (struct drm_device *)arg;
|
||||
struct drm_vblank_crtc *vblank = (void *)arg;
|
||||
struct drm_device *dev = vblank->dev;
|
||||
unsigned long irqflags;
|
||||
int i;
|
||||
int crtc = vblank->crtc;
|
||||
|
||||
if (!dev->vblank_disable_allowed)
|
||||
return;
|
||||
|
||||
for (i = 0; i < dev->num_crtcs; i++) {
|
||||
spin_lock_irqsave(&dev->vbl_lock, irqflags);
|
||||
if (atomic_read(&dev->vblank[i].refcount) == 0 &&
|
||||
dev->vblank[i].enabled) {
|
||||
DRM_DEBUG("disabling vblank on crtc %d\n", i);
|
||||
vblank_disable_and_save(dev, i);
|
||||
}
|
||||
spin_unlock_irqrestore(&dev->vbl_lock, irqflags);
|
||||
spin_lock_irqsave(&dev->vbl_lock, irqflags);
|
||||
if (atomic_read(&vblank->refcount) == 0 && vblank->enabled) {
|
||||
DRM_DEBUG("disabling vblank on crtc %d\n", crtc);
|
||||
vblank_disable_and_save(dev, crtc);
|
||||
}
|
||||
spin_unlock_irqrestore(&dev->vbl_lock, irqflags);
|
||||
}
|
||||
|
||||
/**
|
||||
* drm_vblank_cleanup - cleanup vblank support
|
||||
* @dev: DRM device
|
||||
*
|
||||
* This function cleans up any resources allocated in drm_vblank_init.
|
||||
*/
|
||||
void drm_vblank_cleanup(struct drm_device *dev)
|
||||
{
|
||||
int crtc;
|
||||
|
||||
/* Bail if the driver didn't call drm_vblank_init() */
|
||||
if (dev->num_crtcs == 0)
|
||||
return;
|
||||
|
||||
del_timer_sync(&dev->vblank_disable_timer);
|
||||
|
||||
vblank_disable_fn((unsigned long)dev);
|
||||
for (crtc = 0; crtc < dev->num_crtcs; crtc++) {
|
||||
del_timer_sync(&dev->vblank[crtc].disable_timer);
|
||||
vblank_disable_fn((unsigned long)&dev->vblank[crtc]);
|
||||
}
|
||||
|
||||
kfree(dev->vblank);
|
||||
|
||||
|
@ -174,12 +180,20 @@ void drm_vblank_cleanup(struct drm_device *dev)
|
|||
}
|
||||
EXPORT_SYMBOL(drm_vblank_cleanup);
|
||||
|
||||
/**
|
||||
* drm_vblank_init - initialize vblank support
|
||||
* @dev: drm_device
|
||||
* @num_crtcs: number of crtcs supported by @dev
|
||||
*
|
||||
* This function initializes vblank support for @num_crtcs display pipelines.
|
||||
*
|
||||
* Returns:
|
||||
* Zero on success or a negative error code on failure.
|
||||
*/
|
||||
int drm_vblank_init(struct drm_device *dev, int num_crtcs)
|
||||
{
|
||||
int i, ret = -ENOMEM;
|
||||
|
||||
setup_timer(&dev->vblank_disable_timer, vblank_disable_fn,
|
||||
(unsigned long)dev);
|
||||
spin_lock_init(&dev->vbl_lock);
|
||||
spin_lock_init(&dev->vblank_time_lock);
|
||||
|
||||
|
@ -189,8 +203,13 @@ int drm_vblank_init(struct drm_device *dev, int num_crtcs)
|
|||
if (!dev->vblank)
|
||||
goto err;
|
||||
|
||||
for (i = 0; i < num_crtcs; i++)
|
||||
for (i = 0; i < num_crtcs; i++) {
|
||||
dev->vblank[i].dev = dev;
|
||||
dev->vblank[i].crtc = i;
|
||||
init_waitqueue_head(&dev->vblank[i].queue);
|
||||
setup_timer(&dev->vblank[i].disable_timer, vblank_disable_fn,
|
||||
(unsigned long)&dev->vblank[i]);
|
||||
}
|
||||
|
||||
DRM_INFO("Supports vblank timestamp caching Rev 2 (21.10.2013).\n");
|
||||
|
||||
|
@ -234,13 +253,21 @@ static void drm_irq_vgaarb_nokms(void *cookie, bool state)
|
|||
}
|
||||
|
||||
/**
|
||||
* Install IRQ handler.
|
||||
*
|
||||
* \param dev DRM device.
|
||||
* drm_irq_install - install IRQ handler
|
||||
* @dev: DRM device
|
||||
* @irq: IRQ number to install the handler for
|
||||
*
|
||||
* Initializes the IRQ related data. Installs the handler, calling the driver
|
||||
* \c irq_preinstall() and \c irq_postinstall() functions
|
||||
* before and after the installation.
|
||||
* irq_preinstall() and irq_postinstall() functions before and after the
|
||||
* installation.
|
||||
*
|
||||
* This is the simplified helper interface provided for drivers with no special
|
||||
* needs. Drivers which need to install interrupt handlers for multiple
|
||||
* interrupts must instead set drm_device->irq_enabled to signal the DRM core
|
||||
* that vblank interrupts are available.
|
||||
*
|
||||
* Returns:
|
||||
* Zero on success or a negative error code on failure.
|
||||
*/
|
||||
int drm_irq_install(struct drm_device *dev, int irq)
|
||||
{
|
||||
|
@ -300,11 +327,20 @@ int drm_irq_install(struct drm_device *dev, int irq)
|
|||
EXPORT_SYMBOL(drm_irq_install);
|
||||
|
||||
/**
|
||||
* Uninstall the IRQ handler.
|
||||
* drm_irq_uninstall - uninstall the IRQ handler
|
||||
* @dev: DRM device
|
||||
*
|
||||
* \param dev DRM device.
|
||||
* Calls the driver's irq_uninstall() function and unregisters the IRQ handler.
|
||||
* This should only be called by drivers which used drm_irq_install() to set up
|
||||
* their interrupt handler. Other drivers must only reset
|
||||
* drm_device->irq_enabled to false.
|
||||
*
|
||||
* Calls the driver's \c irq_uninstall() function, and stops the irq.
|
||||
* Note that for kernel modesetting drivers it is a bug if this function fails.
|
||||
* The sanity checks are only to catch buggy user modesetting drivers which call
|
||||
* the same function through an ioctl.
|
||||
*
|
||||
* Returns:
|
||||
* Zero on success or a negative error code on failure.
|
||||
*/
|
||||
int drm_irq_uninstall(struct drm_device *dev)
|
||||
{
|
||||
|
@ -349,7 +385,7 @@ int drm_irq_uninstall(struct drm_device *dev)
|
|||
}
|
||||
EXPORT_SYMBOL(drm_irq_uninstall);
|
||||
|
||||
/**
|
||||
/*
|
||||
* IRQ control ioctl.
|
||||
*
|
||||
* \param inode device inode.
|
||||
|
@ -402,15 +438,14 @@ int drm_control(struct drm_device *dev, void *data,
|
|||
}
|
||||
|
||||
/**
|
||||
* drm_calc_timestamping_constants - Calculate vblank timestamp constants
|
||||
*
|
||||
* @crtc drm_crtc whose timestamp constants should be updated.
|
||||
* @mode display mode containing the scanout timings
|
||||
* drm_calc_timestamping_constants - calculate vblank timestamp constants
|
||||
* @crtc: drm_crtc whose timestamp constants should be updated.
|
||||
* @mode: display mode containing the scanout timings
|
||||
*
|
||||
* Calculate and store various constants which are later
|
||||
* needed by vblank and swap-completion timestamping, e.g,
|
||||
* by drm_calc_vbltimestamp_from_scanoutpos(). They are
|
||||
* derived from crtc's true scanout timing, so they take
|
||||
* derived from CRTC's true scanout timing, so they take
|
||||
* things like panel scaling or other adjustments into account.
|
||||
*/
|
||||
void drm_calc_timestamping_constants(struct drm_crtc *crtc,
|
||||
|
@ -455,11 +490,22 @@ void drm_calc_timestamping_constants(struct drm_crtc *crtc,
|
|||
EXPORT_SYMBOL(drm_calc_timestamping_constants);
|
||||
|
||||
/**
|
||||
* drm_calc_vbltimestamp_from_scanoutpos - helper routine for kms
|
||||
* drivers. Implements calculation of exact vblank timestamps from
|
||||
* given drm_display_mode timings and current video scanout position
|
||||
* of a crtc. This can be called from within get_vblank_timestamp()
|
||||
* implementation of a kms driver to implement the actual timestamping.
|
||||
* drm_calc_vbltimestamp_from_scanoutpos - precise vblank timestamp helper
|
||||
* @dev: DRM device
|
||||
* @crtc: Which CRTC's vblank timestamp to retrieve
|
||||
* @max_error: Desired maximum allowable error in timestamps (nanosecs)
|
||||
* On return contains true maximum error of timestamp
|
||||
* @vblank_time: Pointer to struct timeval which should receive the timestamp
|
||||
* @flags: Flags to pass to driver:
|
||||
* 0 = Default,
|
||||
* DRM_CALLED_FROM_VBLIRQ = If function is called from vbl IRQ handler
|
||||
* @refcrtc: CRTC which defines scanout timing
|
||||
* @mode: mode which defines the scanout timings
|
||||
*
|
||||
* Implements calculation of exact vblank timestamps from given drm_display_mode
|
||||
* timings and current video scanout position of a CRTC. This can be called from
|
||||
* within get_vblank_timestamp() implementation of a kms driver to implement the
|
||||
* actual timestamping.
|
||||
*
|
||||
* Should return timestamps conforming to the OML_sync_control OpenML
|
||||
* extension specification. The timestamp corresponds to the end of
|
||||
|
@ -474,21 +520,11 @@ EXPORT_SYMBOL(drm_calc_timestamping_constants);
|
|||
* returns as no operation if a doublescan or interlaced video mode is
|
||||
* active. Higher level code is expected to handle this.
|
||||
*
|
||||
* @dev: DRM device.
|
||||
* @crtc: Which crtc's vblank timestamp to retrieve.
|
||||
* @max_error: Desired maximum allowable error in timestamps (nanosecs).
|
||||
* On return contains true maximum error of timestamp.
|
||||
* @vblank_time: Pointer to struct timeval which should receive the timestamp.
|
||||
* @flags: Flags to pass to driver:
|
||||
* 0 = Default.
|
||||
* DRM_CALLED_FROM_VBLIRQ = If function is called from vbl irq handler.
|
||||
* @refcrtc: drm_crtc* of crtc which defines scanout timing.
|
||||
* @mode: mode which defines the scanout timings
|
||||
*
|
||||
* Returns negative value on error, failure or if not supported in current
|
||||
* Returns:
|
||||
* Negative value on error, failure or if not supported in current
|
||||
* video mode:
|
||||
*
|
||||
* -EINVAL - Invalid crtc.
|
||||
* -EINVAL - Invalid CRTC.
|
||||
* -EAGAIN - Temporary unavailable, e.g., called before initial modeset.
|
||||
* -ENOTSUPP - Function not supported in current display mode.
|
||||
* -EIO - Failed, e.g., due to failed scanout position query.
|
||||
|
@ -637,23 +673,23 @@ static struct timeval get_drm_timestamp(void)
|
|||
|
||||
/**
|
||||
* drm_get_last_vbltimestamp - retrieve raw timestamp for the most recent
|
||||
* vblank interval.
|
||||
*
|
||||
* vblank interval
|
||||
* @dev: DRM device
|
||||
* @crtc: which crtc's vblank timestamp to retrieve
|
||||
* @crtc: which CRTC's vblank timestamp to retrieve
|
||||
* @tvblank: Pointer to target struct timeval which should receive the timestamp
|
||||
* @flags: Flags to pass to driver:
|
||||
* 0 = Default.
|
||||
* DRM_CALLED_FROM_VBLIRQ = If function is called from vbl irq handler.
|
||||
* 0 = Default,
|
||||
* DRM_CALLED_FROM_VBLIRQ = If function is called from vbl IRQ handler
|
||||
*
|
||||
* Fetches the system timestamp corresponding to the time of the most recent
|
||||
* vblank interval on specified crtc. May call into kms-driver to
|
||||
* vblank interval on specified CRTC. May call into kms-driver to
|
||||
* compute the timestamp with a high-precision GPU specific method.
|
||||
*
|
||||
* Returns zero if timestamp originates from uncorrected do_gettimeofday()
|
||||
* call, i.e., it isn't very precisely locked to the true vblank.
|
||||
*
|
||||
* Returns non-zero if timestamp is considered to be very precise.
|
||||
* Returns:
|
||||
* Non-zero if timestamp is considered to be very precise, zero otherwise.
|
||||
*/
|
||||
u32 drm_get_last_vbltimestamp(struct drm_device *dev, int crtc,
|
||||
struct timeval *tvblank, unsigned flags)
|
||||
|
@ -688,6 +724,9 @@ EXPORT_SYMBOL(drm_get_last_vbltimestamp);
|
|||
* Fetches the "cooked" vblank count value that represents the number of
|
||||
* vblank events since the system was booted, including lost events due to
|
||||
* modesetting activity.
|
||||
*
|
||||
* Returns:
|
||||
* The software vblank counter.
|
||||
*/
|
||||
u32 drm_vblank_count(struct drm_device *dev, int crtc)
|
||||
{
|
||||
|
@ -706,8 +745,7 @@ EXPORT_SYMBOL(drm_vblank_count);
|
|||
* Fetches the "cooked" vblank count value that represents the number of
|
||||
* vblank events since the system was booted, including lost events due to
|
||||
* modesetting activity. Returns corresponding system timestamp of the time
|
||||
* of the vblank interval that corresponds to the current value vblank counter
|
||||
* value.
|
||||
* of the vblank interval that corresponds to the current vblank counter value.
|
||||
*/
|
||||
u32 drm_vblank_count_and_time(struct drm_device *dev, int crtc,
|
||||
struct timeval *vblanktime)
|
||||
|
@ -835,6 +873,41 @@ static void drm_update_vblank_count(struct drm_device *dev, int crtc)
|
|||
smp_mb__after_atomic_inc();
|
||||
}
|
||||
|
||||
/**
|
||||
* drm_vblank_enable - enable the vblank interrupt on a CRTC
|
||||
* @dev: DRM device
|
||||
* @crtc: CRTC in question
|
||||
*/
|
||||
static int drm_vblank_enable(struct drm_device *dev, int crtc)
|
||||
{
|
||||
int ret = 0;
|
||||
|
||||
assert_spin_locked(&dev->vbl_lock);
|
||||
|
||||
spin_lock(&dev->vblank_time_lock);
|
||||
|
||||
if (!dev->vblank[crtc].enabled) {
|
||||
/* Enable vblank irqs under vblank_time_lock protection.
|
||||
* All vblank count & timestamp updates are held off
|
||||
* until we are done reinitializing master counter and
|
||||
* timestamps. Filtercode in drm_handle_vblank() will
|
||||
* prevent double-accounting of same vblank interval.
|
||||
*/
|
||||
ret = dev->driver->enable_vblank(dev, crtc);
|
||||
DRM_DEBUG("enabling vblank on crtc %d, ret: %d\n", crtc, ret);
|
||||
if (ret)
|
||||
atomic_dec(&dev->vblank[crtc].refcount);
|
||||
else {
|
||||
dev->vblank[crtc].enabled = true;
|
||||
drm_update_vblank_count(dev, crtc);
|
||||
}
|
||||
}
|
||||
|
||||
spin_unlock(&dev->vblank_time_lock);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* drm_vblank_get - get a reference count on vblank events
|
||||
* @dev: DRM device
|
||||
|
@ -843,36 +916,20 @@ static void drm_update_vblank_count(struct drm_device *dev, int crtc)
|
|||
* Acquire a reference count on vblank events to avoid having them disabled
|
||||
* while in use.
|
||||
*
|
||||
* RETURNS
|
||||
* This is the legacy version of drm_crtc_vblank_get().
|
||||
*
|
||||
* Returns:
|
||||
* Zero on success, nonzero on failure.
|
||||
*/
|
||||
int drm_vblank_get(struct drm_device *dev, int crtc)
|
||||
{
|
||||
unsigned long irqflags, irqflags2;
|
||||
unsigned long irqflags;
|
||||
int ret = 0;
|
||||
|
||||
spin_lock_irqsave(&dev->vbl_lock, irqflags);
|
||||
/* Going from 0->1 means we have to enable interrupts again */
|
||||
if (atomic_add_return(1, &dev->vblank[crtc].refcount) == 1) {
|
||||
spin_lock_irqsave(&dev->vblank_time_lock, irqflags2);
|
||||
if (!dev->vblank[crtc].enabled) {
|
||||
/* Enable vblank irqs under vblank_time_lock protection.
|
||||
* All vblank count & timestamp updates are held off
|
||||
* until we are done reinitializing master counter and
|
||||
* timestamps. Filtercode in drm_handle_vblank() will
|
||||
* prevent double-accounting of same vblank interval.
|
||||
*/
|
||||
ret = dev->driver->enable_vblank(dev, crtc);
|
||||
DRM_DEBUG("enabling vblank on crtc %d, ret: %d\n",
|
||||
crtc, ret);
|
||||
if (ret)
|
||||
atomic_dec(&dev->vblank[crtc].refcount);
|
||||
else {
|
||||
dev->vblank[crtc].enabled = true;
|
||||
drm_update_vblank_count(dev, crtc);
|
||||
}
|
||||
}
|
||||
spin_unlock_irqrestore(&dev->vblank_time_lock, irqflags2);
|
||||
ret = drm_vblank_enable(dev, crtc);
|
||||
} else {
|
||||
if (!dev->vblank[crtc].enabled) {
|
||||
atomic_dec(&dev->vblank[crtc].refcount);
|
||||
|
@ -885,6 +942,24 @@ int drm_vblank_get(struct drm_device *dev, int crtc)
|
|||
}
|
||||
EXPORT_SYMBOL(drm_vblank_get);
|
||||
|
||||
/**
|
||||
* drm_crtc_vblank_get - get a reference count on vblank events
|
||||
* @crtc: which CRTC to own
|
||||
*
|
||||
* Acquire a reference count on vblank events to avoid having them disabled
|
||||
* while in use.
|
||||
*
|
||||
* This is the native kms version of drm_vblank_off().
|
||||
*
|
||||
* Returns:
|
||||
* Zero on success, nonzero on failure.
|
||||
*/
|
||||
int drm_crtc_vblank_get(struct drm_crtc *crtc)
|
||||
{
|
||||
return drm_vblank_get(crtc->dev, drm_crtc_index(crtc));
|
||||
}
|
||||
EXPORT_SYMBOL(drm_crtc_vblank_get);
|
||||
|
||||
/**
|
||||
* drm_vblank_put - give up ownership of vblank events
|
||||
* @dev: DRM device
|
||||
|
@ -892,6 +967,8 @@ EXPORT_SYMBOL(drm_vblank_get);
|
|||
*
|
||||
* Release ownership of a given vblank counter, turning off interrupts
|
||||
* if possible. Disable interrupts after drm_vblank_offdelay milliseconds.
|
||||
*
|
||||
* This is the legacy version of drm_crtc_vblank_put().
|
||||
*/
|
||||
void drm_vblank_put(struct drm_device *dev, int crtc)
|
||||
{
|
||||
|
@ -900,17 +977,39 @@ void drm_vblank_put(struct drm_device *dev, int crtc)
|
|||
/* Last user schedules interrupt disable */
|
||||
if (atomic_dec_and_test(&dev->vblank[crtc].refcount) &&
|
||||
(drm_vblank_offdelay > 0))
|
||||
mod_timer(&dev->vblank_disable_timer,
|
||||
mod_timer(&dev->vblank[crtc].disable_timer,
|
||||
jiffies + ((drm_vblank_offdelay * HZ)/1000));
|
||||
}
|
||||
EXPORT_SYMBOL(drm_vblank_put);
|
||||
|
||||
/**
|
||||
* drm_crtc_vblank_put - give up ownership of vblank events
|
||||
* @crtc: which counter to give up
|
||||
*
|
||||
* Release ownership of a given vblank counter, turning off interrupts
|
||||
* if possible. Disable interrupts after drm_vblank_offdelay milliseconds.
|
||||
*
|
||||
* This is the native kms version of drm_vblank_put().
|
||||
*/
|
||||
void drm_crtc_vblank_put(struct drm_crtc *crtc)
|
||||
{
|
||||
drm_vblank_put(crtc->dev, drm_crtc_index(crtc));
|
||||
}
|
||||
EXPORT_SYMBOL(drm_crtc_vblank_put);
|
||||
|
||||
/**
|
||||
* drm_vblank_off - disable vblank events on a CRTC
|
||||
* @dev: DRM device
|
||||
* @crtc: CRTC in question
|
||||
*
|
||||
* Caller must hold event lock.
|
||||
* Drivers can use this function to shut down the vblank interrupt handling when
|
||||
* disabling a crtc. This function ensures that the latest vblank frame count is
|
||||
* stored so that drm_vblank_on() can restore it again.
|
||||
*
|
||||
* Drivers must use this function when the hardware vblank counter can get
|
||||
* reset, e.g. when suspending.
|
||||
*
|
||||
* This is the legacy version of drm_crtc_vblank_off().
|
||||
*/
|
||||
void drm_vblank_off(struct drm_device *dev, int crtc)
|
||||
{
|
||||
|
@ -943,6 +1042,66 @@ void drm_vblank_off(struct drm_device *dev, int crtc)
|
|||
}
|
||||
EXPORT_SYMBOL(drm_vblank_off);
|
||||
|
||||
/**
|
||||
* drm_crtc_vblank_off - disable vblank events on a CRTC
|
||||
* @crtc: CRTC in question
|
||||
*
|
||||
* Drivers can use this function to shut down the vblank interrupt handling when
|
||||
* disabling a crtc. This function ensures that the latest vblank frame count is
|
||||
* stored so that drm_vblank_on can restore it again.
|
||||
*
|
||||
* Drivers must use this function when the hardware vblank counter can get
|
||||
* reset, e.g. when suspending.
|
||||
*
|
||||
* This is the native kms version of drm_vblank_off().
|
||||
*/
|
||||
void drm_crtc_vblank_off(struct drm_crtc *crtc)
|
||||
{
|
||||
drm_vblank_off(crtc->dev, drm_crtc_index(crtc));
|
||||
}
|
||||
EXPORT_SYMBOL(drm_crtc_vblank_off);
|
||||
|
||||
/**
|
||||
* drm_vblank_on - enable vblank events on a CRTC
|
||||
* @dev: DRM device
|
||||
* @crtc: CRTC in question
|
||||
*
|
||||
* This functions restores the vblank interrupt state captured with
|
||||
* drm_vblank_off() again. Note that calls to drm_vblank_on() and
|
||||
* drm_vblank_off() can be unbalanced and so can also be unconditionaly called
|
||||
* in driver load code to reflect the current hardware state of the crtc.
|
||||
*
|
||||
* This is the legacy version of drm_crtc_vblank_on().
|
||||
*/
|
||||
void drm_vblank_on(struct drm_device *dev, int crtc)
|
||||
{
|
||||
unsigned long irqflags;
|
||||
|
||||
spin_lock_irqsave(&dev->vbl_lock, irqflags);
|
||||
/* re-enable interrupts if there's are users left */
|
||||
if (atomic_read(&dev->vblank[crtc].refcount) != 0)
|
||||
WARN_ON(drm_vblank_enable(dev, crtc));
|
||||
spin_unlock_irqrestore(&dev->vbl_lock, irqflags);
|
||||
}
|
||||
EXPORT_SYMBOL(drm_vblank_on);
|
||||
|
||||
/**
|
||||
* drm_crtc_vblank_on - enable vblank events on a CRTC
|
||||
* @crtc: CRTC in question
|
||||
*
|
||||
* This functions restores the vblank interrupt state captured with
|
||||
* drm_vblank_off() again. Note that calls to drm_vblank_on() and
|
||||
* drm_vblank_off() can be unbalanced and so can also be unconditionaly called
|
||||
* in driver load code to reflect the current hardware state of the crtc.
|
||||
*
|
||||
* This is the native kms version of drm_vblank_on().
|
||||
*/
|
||||
void drm_crtc_vblank_on(struct drm_crtc *crtc)
|
||||
{
|
||||
drm_vblank_on(crtc->dev, drm_crtc_index(crtc));
|
||||
}
|
||||
EXPORT_SYMBOL(drm_crtc_vblank_on);
|
||||
|
||||
/**
|
||||
* drm_vblank_pre_modeset - account for vblanks across mode sets
|
||||
* @dev: DRM device
|
||||
|
@ -950,6 +1109,21 @@ EXPORT_SYMBOL(drm_vblank_off);
|
|||
*
|
||||
* Account for vblank events across mode setting events, which will likely
|
||||
* reset the hardware frame counter.
|
||||
*
|
||||
* This is done by grabbing a temporary vblank reference to ensure that the
|
||||
* vblank interrupt keeps running across the modeset sequence. With this the
|
||||
* software-side vblank frame counting will ensure that there are no jumps or
|
||||
* discontinuities.
|
||||
*
|
||||
* Unfortunately this approach is racy and also doesn't work when the vblank
|
||||
* interrupt stops running, e.g. across system suspend resume. It is therefore
|
||||
* highly recommended that drivers use the newer drm_vblank_off() and
|
||||
* drm_vblank_on() instead. drm_vblank_pre_modeset() only works correctly when
|
||||
* using "cooked" software vblank frame counters and not relying on any hardware
|
||||
* counters.
|
||||
*
|
||||
* Drivers must call drm_vblank_post_modeset() when re-enabling the same crtc
|
||||
* again.
|
||||
*/
|
||||
void drm_vblank_pre_modeset(struct drm_device *dev, int crtc)
|
||||
{
|
||||
|
@ -971,6 +1145,14 @@ void drm_vblank_pre_modeset(struct drm_device *dev, int crtc)
|
|||
}
|
||||
EXPORT_SYMBOL(drm_vblank_pre_modeset);
|
||||
|
||||
/**
|
||||
* drm_vblank_post_modeset - undo drm_vblank_pre_modeset changes
|
||||
* @dev: DRM device
|
||||
* @crtc: CRTC in question
|
||||
*
|
||||
* This function again drops the temporary vblank reference acquired in
|
||||
* drm_vblank_pre_modeset.
|
||||
*/
|
||||
void drm_vblank_post_modeset(struct drm_device *dev, int crtc)
|
||||
{
|
||||
unsigned long irqflags;
|
||||
|
@ -992,7 +1174,7 @@ void drm_vblank_post_modeset(struct drm_device *dev, int crtc)
|
|||
}
|
||||
EXPORT_SYMBOL(drm_vblank_post_modeset);
|
||||
|
||||
/**
|
||||
/*
|
||||
* drm_modeset_ctl - handle vblank event counter changes across mode switch
|
||||
* @DRM_IOCTL_ARGS: standard ioctl arguments
|
||||
*
|
||||
|
@ -1105,7 +1287,7 @@ err_put:
|
|||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
/*
|
||||
* Wait for VBLANK.
|
||||
*
|
||||
* \param inode device inode.
|
||||
|
@ -1116,7 +1298,7 @@ err_put:
|
|||
*
|
||||
* This function enables the vblank interrupt on the pipe requested, then
|
||||
* sleeps waiting for the requested sequence number to occur, and drops
|
||||
* the vblank interrupt refcount afterwards. (vblank irq disable follows that
|
||||
* the vblank interrupt refcount afterwards. (vblank IRQ disable follows that
|
||||
* after a timeout with no further vblank waits scheduled).
|
||||
*/
|
||||
int drm_wait_vblank(struct drm_device *dev, void *data,
|
||||
|
@ -1187,6 +1369,7 @@ int drm_wait_vblank(struct drm_device *dev, void *data,
|
|||
DRM_WAIT_ON(ret, dev->vblank[crtc].queue, 3 * HZ,
|
||||
(((drm_vblank_count(dev, crtc) -
|
||||
vblwait->request.sequence) <= (1 << 23)) ||
|
||||
!dev->vblank[crtc].enabled ||
|
||||
!dev->irq_enabled));
|
||||
|
||||
if (ret != -EINTR) {
|
||||
|
|
|
@ -124,7 +124,6 @@ int drm_primary_helper_update(struct drm_plane *plane, struct drm_crtc *crtc,
|
|||
.y2 = crtc->mode.vdisplay,
|
||||
};
|
||||
struct drm_connector **connector_list;
|
||||
struct drm_framebuffer *tmpfb;
|
||||
int num_connectors, ret;
|
||||
|
||||
if (!crtc->enabled) {
|
||||
|
@ -145,6 +144,8 @@ int drm_primary_helper_update(struct drm_plane *plane, struct drm_crtc *crtc,
|
|||
}
|
||||
|
||||
/* Disallow scaling */
|
||||
src_w >>= 16;
|
||||
src_h >>= 16;
|
||||
if (crtc_w != src_w || crtc_h != src_h) {
|
||||
DRM_DEBUG_KMS("Can't scale primary plane\n");
|
||||
return -EINVAL;
|
||||
|
@ -176,21 +177,14 @@ int drm_primary_helper_update(struct drm_plane *plane, struct drm_crtc *crtc,
|
|||
set.num_connectors = num_connectors;
|
||||
|
||||
/*
|
||||
* set_config() adjusts crtc->primary->fb; however the DRM setplane
|
||||
* code that called us expects to handle the framebuffer update and
|
||||
* reference counting; save and restore the current fb before
|
||||
* calling it.
|
||||
*
|
||||
* N.B., we call set_config() directly here rather than using
|
||||
* We call set_config() directly here rather than using
|
||||
* drm_mode_set_config_internal. We're reprogramming the same
|
||||
* connectors that were already in use, so we shouldn't need the extra
|
||||
* cross-CRTC fb refcounting to accomodate stealing connectors.
|
||||
* drm_mode_setplane() already handles the basic refcounting for the
|
||||
* framebuffers involved in this operation.
|
||||
*/
|
||||
tmpfb = plane->fb;
|
||||
ret = crtc->funcs->set_config(&set);
|
||||
plane->fb = tmpfb;
|
||||
|
||||
kfree(connector_list);
|
||||
return ret;
|
||||
|
@ -232,7 +226,6 @@ EXPORT_SYMBOL(drm_primary_helper_disable);
|
|||
*/
|
||||
void drm_primary_helper_destroy(struct drm_plane *plane)
|
||||
{
|
||||
plane->funcs->disable_plane(plane);
|
||||
drm_plane_cleanup(plane);
|
||||
kfree(plane);
|
||||
}
|
||||
|
|
|
@ -151,7 +151,7 @@ static int drm_helper_probe_single_connector_modes_merge_bits(struct drm_connect
|
|||
drm_mode_validate_flag(connector, mode_flags);
|
||||
|
||||
list_for_each_entry(mode, &connector->modes, head) {
|
||||
if (mode->status == MODE_OK)
|
||||
if (mode->status == MODE_OK && connector_funcs->mode_valid)
|
||||
mode->status = connector_funcs->mode_valid(connector,
|
||||
mode);
|
||||
}
|
||||
|
|
|
@ -294,6 +294,7 @@ static void drm_minor_free(struct drm_device *dev, unsigned int type)
|
|||
|
||||
slot = drm_minor_get_slot(dev, type);
|
||||
if (*slot) {
|
||||
drm_mode_group_destroy(&(*slot)->mode_group);
|
||||
kfree(*slot);
|
||||
*slot = NULL;
|
||||
}
|
||||
|
|
|
@ -949,12 +949,6 @@ static int exynos_dp_get_modes(struct drm_connector *connector)
|
|||
return 1;
|
||||
}
|
||||
|
||||
static int exynos_dp_mode_valid(struct drm_connector *connector,
|
||||
struct drm_display_mode *mode)
|
||||
{
|
||||
return MODE_OK;
|
||||
}
|
||||
|
||||
static struct drm_encoder *exynos_dp_best_encoder(
|
||||
struct drm_connector *connector)
|
||||
{
|
||||
|
@ -965,7 +959,6 @@ static struct drm_encoder *exynos_dp_best_encoder(
|
|||
|
||||
static struct drm_connector_helper_funcs exynos_dp_connector_helper_funcs = {
|
||||
.get_modes = exynos_dp_get_modes,
|
||||
.mode_valid = exynos_dp_mode_valid,
|
||||
.best_encoder = exynos_dp_best_encoder,
|
||||
};
|
||||
|
||||
|
|
|
@ -94,12 +94,6 @@ static int exynos_dpi_get_modes(struct drm_connector *connector)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int exynos_dpi_mode_valid(struct drm_connector *connector,
|
||||
struct drm_display_mode *mode)
|
||||
{
|
||||
return MODE_OK;
|
||||
}
|
||||
|
||||
static struct drm_encoder *
|
||||
exynos_dpi_best_encoder(struct drm_connector *connector)
|
||||
{
|
||||
|
@ -110,7 +104,6 @@ exynos_dpi_best_encoder(struct drm_connector *connector)
|
|||
|
||||
static struct drm_connector_helper_funcs exynos_dpi_connector_helper_funcs = {
|
||||
.get_modes = exynos_dpi_get_modes,
|
||||
.mode_valid = exynos_dpi_mode_valid,
|
||||
.best_encoder = exynos_dpi_best_encoder,
|
||||
};
|
||||
|
||||
|
|
|
@ -533,12 +533,6 @@ static int vidi_get_modes(struct drm_connector *connector)
|
|||
return drm_add_edid_modes(connector, edid);
|
||||
}
|
||||
|
||||
static int vidi_mode_valid(struct drm_connector *connector,
|
||||
struct drm_display_mode *mode)
|
||||
{
|
||||
return MODE_OK;
|
||||
}
|
||||
|
||||
static struct drm_encoder *vidi_best_encoder(struct drm_connector *connector)
|
||||
{
|
||||
struct vidi_context *ctx = ctx_from_connector(connector);
|
||||
|
@ -548,7 +542,6 @@ static struct drm_encoder *vidi_best_encoder(struct drm_connector *connector)
|
|||
|
||||
static struct drm_connector_helper_funcs vidi_connector_helper_funcs = {
|
||||
.get_modes = vidi_get_modes,
|
||||
.mode_valid = vidi_mode_valid,
|
||||
.best_encoder = vidi_best_encoder,
|
||||
};
|
||||
|
||||
|
|
|
@ -455,8 +455,8 @@ static void cpt_set_fifo_underrun_reporting(struct drm_device *dev,
|
|||
*
|
||||
* Returns the previous state of underrun reporting.
|
||||
*/
|
||||
bool __intel_set_cpu_fifo_underrun_reporting(struct drm_device *dev,
|
||||
enum pipe pipe, bool enable)
|
||||
static bool __intel_set_cpu_fifo_underrun_reporting(struct drm_device *dev,
|
||||
enum pipe pipe, bool enable)
|
||||
{
|
||||
struct drm_i915_private *dev_priv = dev->dev_private;
|
||||
struct drm_crtc *crtc = dev_priv->pipe_to_crtc_mapping[pipe];
|
||||
|
|
|
@ -3910,7 +3910,7 @@ static void intel_crtc_disable_planes(struct drm_crtc *crtc)
|
|||
int plane = intel_crtc->plane;
|
||||
|
||||
intel_crtc_wait_for_pending_flips(crtc);
|
||||
drm_vblank_off(dev, pipe);
|
||||
drm_crtc_vblank_off(crtc);
|
||||
|
||||
if (dev_priv->fbc.plane == plane)
|
||||
intel_disable_fbc(dev);
|
||||
|
@ -4000,6 +4000,7 @@ static void ironlake_crtc_enable(struct drm_crtc *crtc)
|
|||
|
||||
intel_crtc_enable_planes(crtc);
|
||||
|
||||
drm_crtc_vblank_on(crtc);
|
||||
}
|
||||
|
||||
/* IPS only exists on ULT machines and is tied to pipe A. */
|
||||
|
@ -4113,6 +4114,8 @@ static void haswell_crtc_enable(struct drm_crtc *crtc)
|
|||
* to change the workaround. */
|
||||
haswell_mode_set_planes_workaround(intel_crtc);
|
||||
intel_crtc_enable_planes(crtc);
|
||||
|
||||
drm_crtc_vblank_on(crtc);
|
||||
}
|
||||
|
||||
static void ironlake_pfit_disable(struct intel_crtc *crtc)
|
||||
|
@ -4620,6 +4623,8 @@ static void valleyview_crtc_enable(struct drm_crtc *crtc)
|
|||
encoder->enable(encoder);
|
||||
|
||||
intel_crtc_enable_planes(crtc);
|
||||
|
||||
drm_crtc_vblank_on(crtc);
|
||||
}
|
||||
|
||||
static void i9xx_set_pll_dividers(struct intel_crtc *crtc)
|
||||
|
@ -4697,6 +4702,8 @@ static void i9xx_crtc_enable(struct drm_crtc *crtc)
|
|||
encoder->enable(encoder);
|
||||
|
||||
intel_crtc_enable_planes(crtc);
|
||||
|
||||
drm_crtc_vblank_on(crtc);
|
||||
}
|
||||
|
||||
static void i9xx_pfit_disable(struct intel_crtc *crtc)
|
||||
|
@ -8815,7 +8822,7 @@ static void do_intel_finish_page_flip(struct drm_device *dev,
|
|||
if (work->event)
|
||||
drm_send_vblank_event(dev, intel_crtc->pipe, work->event);
|
||||
|
||||
drm_vblank_put(dev, intel_crtc->pipe);
|
||||
drm_crtc_vblank_put(crtc);
|
||||
|
||||
spin_unlock_irqrestore(&dev->event_lock, flags);
|
||||
|
||||
|
@ -9197,7 +9204,7 @@ static int intel_crtc_page_flip(struct drm_crtc *crtc,
|
|||
work->old_fb_obj = to_intel_framebuffer(old_fb)->obj;
|
||||
INIT_WORK(&work->work, intel_unpin_work_fn);
|
||||
|
||||
ret = drm_vblank_get(dev, intel_crtc->pipe);
|
||||
ret = drm_crtc_vblank_get(crtc);
|
||||
if (ret)
|
||||
goto free_work;
|
||||
|
||||
|
@ -9206,7 +9213,7 @@ static int intel_crtc_page_flip(struct drm_crtc *crtc,
|
|||
if (intel_crtc->unpin_work) {
|
||||
spin_unlock_irqrestore(&dev->event_lock, flags);
|
||||
kfree(work);
|
||||
drm_vblank_put(dev, intel_crtc->pipe);
|
||||
drm_crtc_vblank_put(crtc);
|
||||
|
||||
DRM_DEBUG_DRIVER("flip queue: crtc already busy\n");
|
||||
return -EBUSY;
|
||||
|
@ -9280,7 +9287,7 @@ cleanup:
|
|||
intel_crtc->unpin_work = NULL;
|
||||
spin_unlock_irqrestore(&dev->event_lock, flags);
|
||||
|
||||
drm_vblank_put(dev, intel_crtc->pipe);
|
||||
drm_crtc_vblank_put(crtc);
|
||||
free_work:
|
||||
kfree(work);
|
||||
|
||||
|
@ -10901,6 +10908,8 @@ static void intel_crtc_init(struct drm_device *dev, int pipe)
|
|||
dev_priv->pipe_to_crtc_mapping[intel_crtc->pipe] = &intel_crtc->base;
|
||||
|
||||
drm_crtc_helper_add(&intel_crtc->base, &intel_helper_funcs);
|
||||
|
||||
WARN_ON(drm_crtc_index(&intel_crtc->base) != intel_crtc->pipe);
|
||||
}
|
||||
|
||||
enum pipe intel_get_pipe_from_connector(struct intel_connector *connector)
|
||||
|
@ -11838,11 +11847,18 @@ static void intel_sanitize_crtc(struct intel_crtc *crtc)
|
|||
encoder->base.crtc = NULL;
|
||||
}
|
||||
}
|
||||
if (crtc->active) {
|
||||
|
||||
if (crtc->active || IS_VALLEYVIEW(dev) || INTEL_INFO(dev)->gen < 5) {
|
||||
/*
|
||||
* We start out with underrun reporting disabled to avoid races.
|
||||
* For correct bookkeeping mark this on active crtcs.
|
||||
*
|
||||
* Also on gmch platforms we dont have any hardware bits to
|
||||
* disable the underrun reporting. Which means we need to start
|
||||
* out with underrun reporting disabled also on inactive pipes,
|
||||
* since otherwise we'll complain about the garbage we read when
|
||||
* e.g. coming up after runtime pm.
|
||||
*
|
||||
* No protection against concurrent access is required - at
|
||||
* worst a fifo underrun happens which also sets this to false.
|
||||
*/
|
||||
|
|
|
@ -668,8 +668,6 @@ hdmi_to_dig_port(struct intel_hdmi *intel_hdmi)
|
|||
/* i915_irq.c */
|
||||
bool intel_set_cpu_fifo_underrun_reporting(struct drm_device *dev,
|
||||
enum pipe pipe, bool enable);
|
||||
bool __intel_set_cpu_fifo_underrun_reporting(struct drm_device *dev,
|
||||
enum pipe pipe, bool enable);
|
||||
bool intel_set_pch_fifo_underrun_reporting(struct drm_device *dev,
|
||||
enum transcoder pch_transcoder,
|
||||
bool enable);
|
||||
|
|
|
@ -5635,33 +5635,6 @@ static void hsw_power_well_post_enable(struct drm_i915_private *dev_priv)
|
|||
}
|
||||
}
|
||||
|
||||
static void reset_vblank_counter(struct drm_device *dev, enum pipe pipe)
|
||||
{
|
||||
assert_spin_locked(&dev->vbl_lock);
|
||||
|
||||
dev->vblank[pipe].last = 0;
|
||||
}
|
||||
|
||||
static void hsw_power_well_post_disable(struct drm_i915_private *dev_priv)
|
||||
{
|
||||
struct drm_device *dev = dev_priv->dev;
|
||||
enum pipe pipe;
|
||||
unsigned long irqflags;
|
||||
|
||||
/*
|
||||
* After this, the registers on the pipes that are part of the power
|
||||
* well will become zero, so we have to adjust our counters according to
|
||||
* that.
|
||||
*
|
||||
* FIXME: Should we do this in general in drm_vblank_post_modeset?
|
||||
*/
|
||||
spin_lock_irqsave(&dev->vbl_lock, irqflags);
|
||||
for_each_pipe(pipe)
|
||||
if (pipe != PIPE_A)
|
||||
reset_vblank_counter(dev, pipe);
|
||||
spin_unlock_irqrestore(&dev->vbl_lock, irqflags);
|
||||
}
|
||||
|
||||
static void hsw_set_power_well(struct drm_i915_private *dev_priv,
|
||||
struct i915_power_well *power_well, bool enable)
|
||||
{
|
||||
|
@ -5690,8 +5663,6 @@ static void hsw_set_power_well(struct drm_i915_private *dev_priv,
|
|||
I915_WRITE(HSW_PWR_WELL_DRIVER, 0);
|
||||
POSTING_READ(HSW_PWR_WELL_DRIVER);
|
||||
DRM_DEBUG_KMS("Requesting to disable the power well\n");
|
||||
|
||||
hsw_power_well_post_disable(dev_priv);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -5848,23 +5819,12 @@ static void vlv_display_power_well_enable(struct drm_i915_private *dev_priv,
|
|||
static void vlv_display_power_well_disable(struct drm_i915_private *dev_priv,
|
||||
struct i915_power_well *power_well)
|
||||
{
|
||||
struct drm_device *dev = dev_priv->dev;
|
||||
enum pipe pipe;
|
||||
|
||||
WARN_ON_ONCE(power_well->data != PUNIT_POWER_WELL_DISP2D);
|
||||
|
||||
spin_lock_irq(&dev_priv->irq_lock);
|
||||
for_each_pipe(pipe)
|
||||
__intel_set_cpu_fifo_underrun_reporting(dev, pipe, false);
|
||||
|
||||
valleyview_disable_display_irqs(dev_priv);
|
||||
spin_unlock_irq(&dev_priv->irq_lock);
|
||||
|
||||
spin_lock_irq(&dev->vbl_lock);
|
||||
for_each_pipe(pipe)
|
||||
reset_vblank_counter(dev, pipe);
|
||||
spin_unlock_irq(&dev->vbl_lock);
|
||||
|
||||
vlv_set_power_well(dev_priv, power_well, false);
|
||||
}
|
||||
|
||||
|
|
|
@ -57,15 +57,8 @@ static int rcar_du_lvds_connector_get_modes(struct drm_connector *connector)
|
|||
return 1;
|
||||
}
|
||||
|
||||
static int rcar_du_lvds_connector_mode_valid(struct drm_connector *connector,
|
||||
struct drm_display_mode *mode)
|
||||
{
|
||||
return MODE_OK;
|
||||
}
|
||||
|
||||
static const struct drm_connector_helper_funcs connector_helper_funcs = {
|
||||
.get_modes = rcar_du_lvds_connector_get_modes,
|
||||
.mode_valid = rcar_du_lvds_connector_mode_valid,
|
||||
.best_encoder = rcar_du_connector_best_encoder,
|
||||
};
|
||||
|
||||
|
|
|
@ -25,15 +25,8 @@ static int rcar_du_vga_connector_get_modes(struct drm_connector *connector)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int rcar_du_vga_connector_mode_valid(struct drm_connector *connector,
|
||||
struct drm_display_mode *mode)
|
||||
{
|
||||
return MODE_OK;
|
||||
}
|
||||
|
||||
static const struct drm_connector_helper_funcs connector_helper_funcs = {
|
||||
.get_modes = rcar_du_vga_connector_get_modes,
|
||||
.mode_valid = rcar_du_vga_connector_mode_valid,
|
||||
.best_encoder = rcar_du_connector_best_encoder,
|
||||
};
|
||||
|
||||
|
|
|
@ -674,12 +674,6 @@ static int shmob_drm_connector_get_modes(struct drm_connector *connector)
|
|||
return 1;
|
||||
}
|
||||
|
||||
static int shmob_drm_connector_mode_valid(struct drm_connector *connector,
|
||||
struct drm_display_mode *mode)
|
||||
{
|
||||
return MODE_OK;
|
||||
}
|
||||
|
||||
static struct drm_encoder *
|
||||
shmob_drm_connector_best_encoder(struct drm_connector *connector)
|
||||
{
|
||||
|
@ -690,7 +684,6 @@ shmob_drm_connector_best_encoder(struct drm_connector *connector)
|
|||
|
||||
static const struct drm_connector_helper_funcs connector_helper_funcs = {
|
||||
.get_modes = shmob_drm_connector_get_modes,
|
||||
.mode_valid = shmob_drm_connector_mode_valid,
|
||||
.best_encoder = shmob_drm_connector_best_encoder,
|
||||
};
|
||||
|
||||
|
|
|
@ -200,13 +200,6 @@ static const struct file_operations imx_drm_driver_fops = {
|
|||
.llseek = noop_llseek,
|
||||
};
|
||||
|
||||
int imx_drm_connector_mode_valid(struct drm_connector *connector,
|
||||
struct drm_display_mode *mode)
|
||||
{
|
||||
return MODE_OK;
|
||||
}
|
||||
EXPORT_SYMBOL(imx_drm_connector_mode_valid);
|
||||
|
||||
void imx_drm_connector_destroy(struct drm_connector *connector)
|
||||
{
|
||||
drm_sysfs_connector_remove(connector);
|
||||
|
|
|
@ -50,8 +50,6 @@ int imx_drm_encoder_get_mux_id(struct device_node *node,
|
|||
int imx_drm_encoder_parse_of(struct drm_device *drm,
|
||||
struct drm_encoder *encoder, struct device_node *np);
|
||||
|
||||
int imx_drm_connector_mode_valid(struct drm_connector *connector,
|
||||
struct drm_display_mode *mode);
|
||||
void imx_drm_connector_destroy(struct drm_connector *connector);
|
||||
void imx_drm_encoder_destroy(struct drm_encoder *encoder);
|
||||
|
||||
|
|
|
@ -1492,7 +1492,6 @@ static struct drm_connector_funcs imx_hdmi_connector_funcs = {
|
|||
|
||||
static struct drm_connector_helper_funcs imx_hdmi_connector_helper_funcs = {
|
||||
.get_modes = imx_hdmi_connector_get_modes,
|
||||
.mode_valid = imx_drm_connector_mode_valid,
|
||||
.best_encoder = imx_hdmi_connector_best_encoder,
|
||||
};
|
||||
|
||||
|
|
|
@ -317,7 +317,6 @@ static struct drm_connector_funcs imx_ldb_connector_funcs = {
|
|||
static struct drm_connector_helper_funcs imx_ldb_connector_helper_funcs = {
|
||||
.get_modes = imx_ldb_connector_get_modes,
|
||||
.best_encoder = imx_ldb_connector_best_encoder,
|
||||
.mode_valid = imx_drm_connector_mode_valid,
|
||||
};
|
||||
|
||||
static struct drm_encoder_funcs imx_ldb_encoder_funcs = {
|
||||
|
|
|
@ -251,10 +251,6 @@ static int imx_tve_connector_mode_valid(struct drm_connector *connector,
|
|||
unsigned long rate;
|
||||
int ret;
|
||||
|
||||
ret = imx_drm_connector_mode_valid(connector, mode);
|
||||
if (ret != MODE_OK)
|
||||
return ret;
|
||||
|
||||
/* pixel clock with 2x oversampling */
|
||||
rate = clk_round_rate(tve->clk, 2000UL * mode->clock) / 2000;
|
||||
if (rate == mode->clock)
|
||||
|
|
|
@ -148,7 +148,6 @@ static struct drm_connector_funcs imx_pd_connector_funcs = {
|
|||
static struct drm_connector_helper_funcs imx_pd_connector_helper_funcs = {
|
||||
.get_modes = imx_pd_connector_get_modes,
|
||||
.best_encoder = imx_pd_connector_best_encoder,
|
||||
.mode_valid = imx_drm_connector_mode_valid,
|
||||
};
|
||||
|
||||
static struct drm_encoder_funcs imx_pd_encoder_funcs = {
|
||||
|
|
|
@ -1024,14 +1024,17 @@ struct drm_pending_vblank_event {
|
|||
};
|
||||
|
||||
struct drm_vblank_crtc {
|
||||
struct drm_device *dev; /* pointer to the drm_device */
|
||||
wait_queue_head_t queue; /**< VBLANK wait queue */
|
||||
struct timeval time[DRM_VBLANKTIME_RBSIZE]; /**< timestamp of current count */
|
||||
struct timer_list disable_timer; /* delayed disable timer */
|
||||
atomic_t count; /**< number of VBLANK interrupts */
|
||||
atomic_t refcount; /* number of users of vblank interruptsper crtc */
|
||||
u32 last; /* protected by dev->vbl_lock, used */
|
||||
/* for wraparound handling */
|
||||
u32 last_wait; /* Last vblank seqno waited per CRTC */
|
||||
unsigned int inmodeset; /* Display driver is setting mode */
|
||||
int crtc; /* crtc index */
|
||||
bool enabled; /* so we don't call enable more than
|
||||
once per disable */
|
||||
};
|
||||
|
@ -1119,7 +1122,6 @@ struct drm_device {
|
|||
|
||||
spinlock_t vblank_time_lock; /**< Protects vblank count and time updates during vblank enable/disable */
|
||||
spinlock_t vbl_lock;
|
||||
struct timer_list vblank_disable_timer;
|
||||
|
||||
u32 max_vblank_count; /**< size of vblank counter register */
|
||||
|
||||
|
@ -1357,8 +1359,14 @@ extern void drm_send_vblank_event(struct drm_device *dev, int crtc,
|
|||
extern bool drm_handle_vblank(struct drm_device *dev, int crtc);
|
||||
extern int drm_vblank_get(struct drm_device *dev, int crtc);
|
||||
extern void drm_vblank_put(struct drm_device *dev, int crtc);
|
||||
extern int drm_crtc_vblank_get(struct drm_crtc *crtc);
|
||||
extern void drm_crtc_vblank_put(struct drm_crtc *crtc);
|
||||
extern void drm_vblank_off(struct drm_device *dev, int crtc);
|
||||
extern void drm_vblank_on(struct drm_device *dev, int crtc);
|
||||
extern void drm_crtc_vblank_off(struct drm_crtc *crtc);
|
||||
extern void drm_crtc_vblank_on(struct drm_crtc *crtc);
|
||||
extern void drm_vblank_cleanup(struct drm_device *dev);
|
||||
|
||||
extern u32 drm_get_last_vbltimestamp(struct drm_device *dev, int crtc,
|
||||
struct timeval *tvblank, unsigned flags);
|
||||
extern int drm_calc_vbltimestamp_from_scanoutpos(struct drm_device *dev,
|
||||
|
|
|
@ -915,6 +915,7 @@ extern const char *drm_get_tv_subconnector_name(int val);
|
|||
extern const char *drm_get_tv_select_name(int val);
|
||||
extern void drm_fb_release(struct drm_file *file_priv);
|
||||
extern int drm_mode_group_init_legacy_group(struct drm_device *dev, struct drm_mode_group *group);
|
||||
extern void drm_mode_group_destroy(struct drm_mode_group *group);
|
||||
extern bool drm_probe_ddc(struct i2c_adapter *adapter);
|
||||
extern struct edid *drm_get_edid(struct drm_connector *connector,
|
||||
struct i2c_adapter *adapter);
|
||||
|
@ -1020,6 +1021,7 @@ extern int drm_mode_gamma_get_ioctl(struct drm_device *dev,
|
|||
extern int drm_mode_gamma_set_ioctl(struct drm_device *dev,
|
||||
void *data, struct drm_file *file_priv);
|
||||
extern u8 drm_match_cea_mode(const struct drm_display_mode *to_match);
|
||||
extern enum hdmi_picture_aspect drm_get_cea_aspect_ratio(const u8 video_code);
|
||||
extern bool drm_detect_hdmi_monitor(struct edid *edid);
|
||||
extern bool drm_detect_monitor_audio(struct edid *edid);
|
||||
extern bool drm_rgb_quant_range_selectable(struct edid *edid);
|
||||
|
|
|
@ -114,7 +114,7 @@ struct drm_encoder_helper_funcs {
|
|||
/**
|
||||
* drm_connector_helper_funcs - helper operations for connectors
|
||||
* @get_modes: get mode list for this connector
|
||||
* @mode_valid: is this mode valid on the given connector?
|
||||
* @mode_valid (optional): is this mode valid on the given connector?
|
||||
*
|
||||
* The helper operations are called by the mid-layer CRTC helper.
|
||||
*/
|
||||
|
|
|
@ -57,6 +57,7 @@ typedef void (*drm_flip_func_t)(struct drm_flip_work *work, void *val);
|
|||
* @count: number of committed items
|
||||
* @func: callback fxn called for each committed item
|
||||
* @worker: worker which calls @func
|
||||
* @fifo: queue of committed items
|
||||
*/
|
||||
struct drm_flip_work {
|
||||
const char *name;
|
||||
|
|
Loading…
Reference in New Issue