Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
L
linux
Project overview
Project overview
Details
Activity
Releases
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Issues
0
Issues
0
List
Boards
Labels
Milestones
Merge Requests
0
Merge Requests
0
Analytics
Analytics
Repository
Value Stream
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Create a new issue
Commits
Issue Boards
Open sidebar
nexedi
linux
Commits
be9f1c4f
Commit
be9f1c4f
authored
Jun 21, 2009
by
Eric Anholt
Browse files
Options
Browse Files
Download
Plain Diff
Merge commit 'keithp/drm-intel-next' into drm-intel-next
parents
8c52da50
fb0f8fbf
Changes
23
Hide whitespace changes
Inline
Side-by-side
Showing
23 changed files
with
1933 additions
and
201 deletions
+1933
-201
drivers/gpu/drm/i915/Makefile
drivers/gpu/drm/i915/Makefile
+2
-0
drivers/gpu/drm/i915/dvo.h
drivers/gpu/drm/i915/dvo.h
+2
-2
drivers/gpu/drm/i915/dvo_ch7017.c
drivers/gpu/drm/i915/dvo_ch7017.c
+11
-9
drivers/gpu/drm/i915/dvo_ch7xxx.c
drivers/gpu/drm/i915/dvo_ch7xxx.c
+13
-12
drivers/gpu/drm/i915/dvo_ivch.c
drivers/gpu/drm/i915/dvo_ivch.c
+11
-10
drivers/gpu/drm/i915/dvo_sil164.c
drivers/gpu/drm/i915/dvo_sil164.c
+13
-12
drivers/gpu/drm/i915/dvo_tfp410.c
drivers/gpu/drm/i915/dvo_tfp410.c
+13
-12
drivers/gpu/drm/i915/i915_drv.h
drivers/gpu/drm/i915/i915_drv.h
+12
-0
drivers/gpu/drm/i915/i915_gem_tiling.c
drivers/gpu/drm/i915/i915_gem_tiling.c
+2
-0
drivers/gpu/drm/i915/i915_irq.c
drivers/gpu/drm/i915/i915_irq.c
+11
-1
drivers/gpu/drm/i915/i915_reg.h
drivers/gpu/drm/i915/i915_reg.h
+13
-0
drivers/gpu/drm/i915/i915_suspend.c
drivers/gpu/drm/i915/i915_suspend.c
+33
-1
drivers/gpu/drm/i915/intel_display.c
drivers/gpu/drm/i915/intel_display.c
+145
-54
drivers/gpu/drm/i915/intel_dp.c
drivers/gpu/drm/i915/intel_dp.c
+1153
-0
drivers/gpu/drm/i915/intel_dp.h
drivers/gpu/drm/i915/intel_dp.h
+144
-0
drivers/gpu/drm/i915/intel_dp_i2c.c
drivers/gpu/drm/i915/intel_dp_i2c.c
+272
-0
drivers/gpu/drm/i915/intel_drv.h
drivers/gpu/drm/i915/intel_drv.h
+11
-6
drivers/gpu/drm/i915/intel_dvo.c
drivers/gpu/drm/i915/intel_dvo.c
+6
-10
drivers/gpu/drm/i915/intel_hdmi.c
drivers/gpu/drm/i915/intel_hdmi.c
+17
-15
drivers/gpu/drm/i915/intel_i2c.c
drivers/gpu/drm/i915/intel_i2c.c
+11
-5
drivers/gpu/drm/i915/intel_lvds.c
drivers/gpu/drm/i915/intel_lvds.c
+2
-2
drivers/gpu/drm/i915/intel_modes.c
drivers/gpu/drm/i915/intel_modes.c
+6
-8
drivers/gpu/drm/i915/intel_sdvo.c
drivers/gpu/drm/i915/intel_sdvo.c
+30
-42
No files found.
drivers/gpu/drm/i915/Makefile
View file @
be9f1c4f
...
...
@@ -13,6 +13,8 @@ i915-y := i915_drv.o i915_dma.o i915_irq.o i915_mem.o \
intel_crt.o
\
intel_lvds.o
\
intel_bios.o
\
intel_dp.o
\
intel_dp_i2c.o
\
intel_hdmi.o
\
intel_sdvo.o
\
intel_modes.o
\
...
...
drivers/gpu/drm/i915/dvo.h
View file @
be9f1c4f
...
...
@@ -37,7 +37,7 @@ struct intel_dvo_device {
/* GPIO register used for i2c bus to control this device */
u32
gpio
;
int
slave_addr
;
struct
i
ntel_i2c_chan
*
i2c_bus
;
struct
i
2c_adapter
*
i2c_bus
;
const
struct
intel_dvo_dev_ops
*
dev_ops
;
void
*
dev_priv
;
...
...
@@ -52,7 +52,7 @@ struct intel_dvo_dev_ops {
* Returns NULL if the device does not exist.
*/
bool
(
*
init
)(
struct
intel_dvo_device
*
dvo
,
struct
i
ntel_i2c_chan
*
i2cbus
);
struct
i
2c_adapter
*
i2cbus
);
/*
* Called to allow the output a chance to create properties after the
...
...
drivers/gpu/drm/i915/dvo_ch7017.c
View file @
be9f1c4f
...
...
@@ -176,19 +176,20 @@ static void ch7017_dpms(struct intel_dvo_device *dvo, int mode);
static
bool
ch7017_read
(
struct
intel_dvo_device
*
dvo
,
int
addr
,
uint8_t
*
val
)
{
struct
intel_i2c_chan
*
i2cbus
=
dvo
->
i2c_bus
;
struct
i2c_adapter
*
adapter
=
dvo
->
i2c_bus
;
struct
intel_i2c_chan
*
i2cbus
=
container_of
(
adapter
,
struct
intel_i2c_chan
,
adapter
);
u8
out_buf
[
2
];
u8
in_buf
[
2
];
struct
i2c_msg
msgs
[]
=
{
{
.
addr
=
i2cbus
->
slave_addr
,
.
addr
=
dvo
->
slave_addr
,
.
flags
=
0
,
.
len
=
1
,
.
buf
=
out_buf
,
},
{
.
addr
=
i2cbus
->
slave_addr
,
.
addr
=
dvo
->
slave_addr
,
.
flags
=
I2C_M_RD
,
.
len
=
1
,
.
buf
=
in_buf
,
...
...
@@ -208,10 +209,11 @@ static bool ch7017_read(struct intel_dvo_device *dvo, int addr, uint8_t *val)
static
bool
ch7017_write
(
struct
intel_dvo_device
*
dvo
,
int
addr
,
uint8_t
val
)
{
struct
intel_i2c_chan
*
i2cbus
=
dvo
->
i2c_bus
;
struct
i2c_adapter
*
adapter
=
dvo
->
i2c_bus
;
struct
intel_i2c_chan
*
i2cbus
=
container_of
(
adapter
,
struct
intel_i2c_chan
,
adapter
);
uint8_t
out_buf
[
2
];
struct
i2c_msg
msg
=
{
.
addr
=
i2cbus
->
slave_addr
,
.
addr
=
dvo
->
slave_addr
,
.
flags
=
0
,
.
len
=
2
,
.
buf
=
out_buf
,
...
...
@@ -228,8 +230,9 @@ static bool ch7017_write(struct intel_dvo_device *dvo, int addr, uint8_t val)
/** Probes for a CH7017 on the given bus and slave address. */
static
bool
ch7017_init
(
struct
intel_dvo_device
*
dvo
,
struct
i
ntel_i2c_chan
*
i2cbus
)
struct
i
2c_adapter
*
adapter
)
{
struct
intel_i2c_chan
*
i2cbus
=
container_of
(
adapter
,
struct
intel_i2c_chan
,
adapter
);
struct
ch7017_priv
*
priv
;
uint8_t
val
;
...
...
@@ -237,8 +240,7 @@ static bool ch7017_init(struct intel_dvo_device *dvo,
if
(
priv
==
NULL
)
return
false
;
dvo
->
i2c_bus
=
i2cbus
;
dvo
->
i2c_bus
->
slave_addr
=
dvo
->
slave_addr
;
dvo
->
i2c_bus
=
adapter
;
dvo
->
dev_priv
=
priv
;
if
(
!
ch7017_read
(
dvo
,
CH7017_DEVICE_ID
,
&
val
))
...
...
@@ -248,7 +250,7 @@ static bool ch7017_init(struct intel_dvo_device *dvo,
val
!=
CH7018_DEVICE_ID_VALUE
&&
val
!=
CH7019_DEVICE_ID_VALUE
)
{
DRM_DEBUG
(
"ch701x not detected, got %d: from %s Slave %d.
\n
"
,
val
,
i2cbus
->
adapter
.
name
,
i2cbus
->
slave_addr
);
val
,
i2cbus
->
adapter
.
name
,
dvo
->
slave_addr
);
goto
fail
;
}
...
...
drivers/gpu/drm/i915/dvo_ch7xxx.c
View file @
be9f1c4f
...
...
@@ -123,19 +123,20 @@ static char *ch7xxx_get_id(uint8_t vid)
static
bool
ch7xxx_readb
(
struct
intel_dvo_device
*
dvo
,
int
addr
,
uint8_t
*
ch
)
{
struct
ch7xxx_priv
*
ch7xxx
=
dvo
->
dev_priv
;
struct
intel_i2c_chan
*
i2cbus
=
dvo
->
i2c_bus
;
struct
i2c_adapter
*
adapter
=
dvo
->
i2c_bus
;
struct
intel_i2c_chan
*
i2cbus
=
container_of
(
adapter
,
struct
intel_i2c_chan
,
adapter
);
u8
out_buf
[
2
];
u8
in_buf
[
2
];
struct
i2c_msg
msgs
[]
=
{
{
.
addr
=
i2cbus
->
slave_addr
,
.
addr
=
dvo
->
slave_addr
,
.
flags
=
0
,
.
len
=
1
,
.
buf
=
out_buf
,
},
{
.
addr
=
i2cbus
->
slave_addr
,
.
addr
=
dvo
->
slave_addr
,
.
flags
=
I2C_M_RD
,
.
len
=
1
,
.
buf
=
in_buf
,
...
...
@@ -152,7 +153,7 @@ static bool ch7xxx_readb(struct intel_dvo_device *dvo, int addr, uint8_t *ch)
if
(
!
ch7xxx
->
quiet
)
{
DRM_DEBUG
(
"Unable to read register 0x%02x from %s:%02x.
\n
"
,
addr
,
i2cbus
->
adapter
.
name
,
i2cbus
->
slave_addr
);
addr
,
i2cbus
->
adapter
.
name
,
dvo
->
slave_addr
);
}
return
false
;
}
...
...
@@ -161,10 +162,11 @@ static bool ch7xxx_readb(struct intel_dvo_device *dvo, int addr, uint8_t *ch)
static
bool
ch7xxx_writeb
(
struct
intel_dvo_device
*
dvo
,
int
addr
,
uint8_t
ch
)
{
struct
ch7xxx_priv
*
ch7xxx
=
dvo
->
dev_priv
;
struct
intel_i2c_chan
*
i2cbus
=
dvo
->
i2c_bus
;
struct
i2c_adapter
*
adapter
=
dvo
->
i2c_bus
;
struct
intel_i2c_chan
*
i2cbus
=
container_of
(
adapter
,
struct
intel_i2c_chan
,
adapter
);
uint8_t
out_buf
[
2
];
struct
i2c_msg
msg
=
{
.
addr
=
i2cbus
->
slave_addr
,
.
addr
=
dvo
->
slave_addr
,
.
flags
=
0
,
.
len
=
2
,
.
buf
=
out_buf
,
...
...
@@ -178,14 +180,14 @@ static bool ch7xxx_writeb(struct intel_dvo_device *dvo, int addr, uint8_t ch)
if
(
!
ch7xxx
->
quiet
)
{
DRM_DEBUG
(
"Unable to write register 0x%02x to %s:%d.
\n
"
,
addr
,
i2cbus
->
adapter
.
name
,
i2cbus
->
slave_addr
);
addr
,
i2cbus
->
adapter
.
name
,
dvo
->
slave_addr
);
}
return
false
;
}
static
bool
ch7xxx_init
(
struct
intel_dvo_device
*
dvo
,
struct
i
ntel_i2c_chan
*
i2cbus
)
struct
i
2c_adapter
*
adapter
)
{
/* this will detect the CH7xxx chip on the specified i2c bus */
struct
ch7xxx_priv
*
ch7xxx
;
...
...
@@ -196,8 +198,7 @@ static bool ch7xxx_init(struct intel_dvo_device *dvo,
if
(
ch7xxx
==
NULL
)
return
false
;
dvo
->
i2c_bus
=
i2cbus
;
dvo
->
i2c_bus
->
slave_addr
=
dvo
->
slave_addr
;
dvo
->
i2c_bus
=
adapter
;
dvo
->
dev_priv
=
ch7xxx
;
ch7xxx
->
quiet
=
true
;
...
...
@@ -207,7 +208,7 @@ static bool ch7xxx_init(struct intel_dvo_device *dvo,
name
=
ch7xxx_get_id
(
vendor
);
if
(
!
name
)
{
DRM_DEBUG
(
"ch7xxx not detected; got 0x%02x from %s slave %d.
\n
"
,
vendor
,
i2cbus
->
adapter
.
name
,
i2cbus
->
slave_addr
);
vendor
,
adapter
->
name
,
dvo
->
slave_addr
);
goto
out
;
}
...
...
@@ -217,7 +218,7 @@ static bool ch7xxx_init(struct intel_dvo_device *dvo,
if
(
device
!=
CH7xxx_DID
)
{
DRM_DEBUG
(
"ch7xxx not detected; got 0x%02x from %s slave %d.
\n
"
,
vendor
,
i2cbus
->
adapter
.
name
,
i2cbus
->
slave_addr
);
vendor
,
adapter
->
name
,
dvo
->
slave_addr
);
goto
out
;
}
...
...
drivers/gpu/drm/i915/dvo_ivch.c
View file @
be9f1c4f
...
...
@@ -169,13 +169,14 @@ static void ivch_dump_regs(struct intel_dvo_device *dvo);
static
bool
ivch_read
(
struct
intel_dvo_device
*
dvo
,
int
addr
,
uint16_t
*
data
)
{
struct
ivch_priv
*
priv
=
dvo
->
dev_priv
;
struct
intel_i2c_chan
*
i2cbus
=
dvo
->
i2c_bus
;
struct
i2c_adapter
*
adapter
=
dvo
->
i2c_bus
;
struct
intel_i2c_chan
*
i2cbus
=
container_of
(
adapter
,
struct
intel_i2c_chan
,
adapter
);
u8
out_buf
[
1
];
u8
in_buf
[
2
];
struct
i2c_msg
msgs
[]
=
{
{
.
addr
=
i2cbus
->
slave_addr
,
.
addr
=
dvo
->
slave_addr
,
.
flags
=
I2C_M_RD
,
.
len
=
0
,
},
...
...
@@ -186,7 +187,7 @@ static bool ivch_read(struct intel_dvo_device *dvo, int addr, uint16_t *data)
.
buf
=
out_buf
,
},
{
.
addr
=
i2cbus
->
slave_addr
,
.
addr
=
dvo
->
slave_addr
,
.
flags
=
I2C_M_RD
|
I2C_M_NOSTART
,
.
len
=
2
,
.
buf
=
in_buf
,
...
...
@@ -202,7 +203,7 @@ static bool ivch_read(struct intel_dvo_device *dvo, int addr, uint16_t *data)
if
(
!
priv
->
quiet
)
{
DRM_DEBUG
(
"Unable to read register 0x%02x from %s:%02x.
\n
"
,
addr
,
i2cbus
->
adapter
.
name
,
i2cbus
->
slave_addr
);
addr
,
i2cbus
->
adapter
.
name
,
dvo
->
slave_addr
);
}
return
false
;
}
...
...
@@ -211,10 +212,11 @@ static bool ivch_read(struct intel_dvo_device *dvo, int addr, uint16_t *data)
static
bool
ivch_write
(
struct
intel_dvo_device
*
dvo
,
int
addr
,
uint16_t
data
)
{
struct
ivch_priv
*
priv
=
dvo
->
dev_priv
;
struct
intel_i2c_chan
*
i2cbus
=
dvo
->
i2c_bus
;
struct
i2c_adapter
*
adapter
=
dvo
->
i2c_bus
;
struct
intel_i2c_chan
*
i2cbus
=
container_of
(
adapter
,
struct
intel_i2c_chan
,
adapter
);
u8
out_buf
[
3
];
struct
i2c_msg
msg
=
{
.
addr
=
i2cbus
->
slave_addr
,
.
addr
=
dvo
->
slave_addr
,
.
flags
=
0
,
.
len
=
3
,
.
buf
=
out_buf
,
...
...
@@ -229,7 +231,7 @@ static bool ivch_write(struct intel_dvo_device *dvo, int addr, uint16_t data)
if
(
!
priv
->
quiet
)
{
DRM_DEBUG
(
"Unable to write register 0x%02x to %s:%d.
\n
"
,
addr
,
i2cbus
->
adapter
.
name
,
i2cbus
->
slave_addr
);
addr
,
i2cbus
->
adapter
.
name
,
dvo
->
slave_addr
);
}
return
false
;
...
...
@@ -237,7 +239,7 @@ static bool ivch_write(struct intel_dvo_device *dvo, int addr, uint16_t data)
/** Probes the given bus and slave address for an ivch */
static
bool
ivch_init
(
struct
intel_dvo_device
*
dvo
,
struct
i
ntel_i2c_chan
*
i2cbus
)
struct
i
2c_adapter
*
adapter
)
{
struct
ivch_priv
*
priv
;
uint16_t
temp
;
...
...
@@ -246,8 +248,7 @@ static bool ivch_init(struct intel_dvo_device *dvo,
if
(
priv
==
NULL
)
return
false
;
dvo
->
i2c_bus
=
i2cbus
;
dvo
->
i2c_bus
->
slave_addr
=
dvo
->
slave_addr
;
dvo
->
i2c_bus
=
adapter
;
dvo
->
dev_priv
=
priv
;
priv
->
quiet
=
true
;
...
...
drivers/gpu/drm/i915/dvo_sil164.c
View file @
be9f1c4f
...
...
@@ -76,19 +76,20 @@ struct sil164_priv {
static
bool
sil164_readb
(
struct
intel_dvo_device
*
dvo
,
int
addr
,
uint8_t
*
ch
)
{
struct
sil164_priv
*
sil
=
dvo
->
dev_priv
;
struct
intel_i2c_chan
*
i2cbus
=
dvo
->
i2c_bus
;
struct
i2c_adapter
*
adapter
=
dvo
->
i2c_bus
;
struct
intel_i2c_chan
*
i2cbus
=
container_of
(
adapter
,
struct
intel_i2c_chan
,
adapter
);
u8
out_buf
[
2
];
u8
in_buf
[
2
];
struct
i2c_msg
msgs
[]
=
{
{
.
addr
=
i2cbus
->
slave_addr
,
.
addr
=
dvo
->
slave_addr
,
.
flags
=
0
,
.
len
=
1
,
.
buf
=
out_buf
,
},
{
.
addr
=
i2cbus
->
slave_addr
,
.
addr
=
dvo
->
slave_addr
,
.
flags
=
I2C_M_RD
,
.
len
=
1
,
.
buf
=
in_buf
,
...
...
@@ -105,7 +106,7 @@ static bool sil164_readb(struct intel_dvo_device *dvo, int addr, uint8_t *ch)
if
(
!
sil
->
quiet
)
{
DRM_DEBUG
(
"Unable to read register 0x%02x from %s:%02x.
\n
"
,
addr
,
i2cbus
->
adapter
.
name
,
i2cbus
->
slave_addr
);
addr
,
i2cbus
->
adapter
.
name
,
dvo
->
slave_addr
);
}
return
false
;
}
...
...
@@ -113,10 +114,11 @@ static bool sil164_readb(struct intel_dvo_device *dvo, int addr, uint8_t *ch)
static
bool
sil164_writeb
(
struct
intel_dvo_device
*
dvo
,
int
addr
,
uint8_t
ch
)
{
struct
sil164_priv
*
sil
=
dvo
->
dev_priv
;
struct
intel_i2c_chan
*
i2cbus
=
dvo
->
i2c_bus
;
struct
i2c_adapter
*
adapter
=
dvo
->
i2c_bus
;
struct
intel_i2c_chan
*
i2cbus
=
container_of
(
adapter
,
struct
intel_i2c_chan
,
adapter
);
uint8_t
out_buf
[
2
];
struct
i2c_msg
msg
=
{
.
addr
=
i2cbus
->
slave_addr
,
.
addr
=
dvo
->
slave_addr
,
.
flags
=
0
,
.
len
=
2
,
.
buf
=
out_buf
,
...
...
@@ -130,7 +132,7 @@ static bool sil164_writeb(struct intel_dvo_device *dvo, int addr, uint8_t ch)
if
(
!
sil
->
quiet
)
{
DRM_DEBUG
(
"Unable to write register 0x%02x to %s:%d.
\n
"
,
addr
,
i2cbus
->
adapter
.
name
,
i2cbus
->
slave_addr
);
addr
,
i2cbus
->
adapter
.
name
,
dvo
->
slave_addr
);
}
return
false
;
...
...
@@ -138,7 +140,7 @@ static bool sil164_writeb(struct intel_dvo_device *dvo, int addr, uint8_t ch)
/* Silicon Image 164 driver for chip on i2c bus */
static
bool
sil164_init
(
struct
intel_dvo_device
*
dvo
,
struct
i
ntel_i2c_chan
*
i2cbus
)
struct
i
2c_adapter
*
adapter
)
{
/* this will detect the SIL164 chip on the specified i2c bus */
struct
sil164_priv
*
sil
;
...
...
@@ -148,8 +150,7 @@ static bool sil164_init(struct intel_dvo_device *dvo,
if
(
sil
==
NULL
)
return
false
;
dvo
->
i2c_bus
=
i2cbus
;
dvo
->
i2c_bus
->
slave_addr
=
dvo
->
slave_addr
;
dvo
->
i2c_bus
=
adapter
;
dvo
->
dev_priv
=
sil
;
sil
->
quiet
=
true
;
...
...
@@ -158,7 +159,7 @@ static bool sil164_init(struct intel_dvo_device *dvo,
if
(
ch
!=
(
SIL164_VID
&
0xff
))
{
DRM_DEBUG
(
"sil164 not detected got %d: from %s Slave %d.
\n
"
,
ch
,
i2cbus
->
adapter
.
name
,
i2cbus
->
slave_addr
);
ch
,
adapter
->
name
,
dvo
->
slave_addr
);
goto
out
;
}
...
...
@@ -167,7 +168,7 @@ static bool sil164_init(struct intel_dvo_device *dvo,
if
(
ch
!=
(
SIL164_DID
&
0xff
))
{
DRM_DEBUG
(
"sil164 not detected got %d: from %s Slave %d.
\n
"
,
ch
,
i2cbus
->
adapter
.
name
,
i2cbus
->
slave_addr
);
ch
,
adapter
->
name
,
dvo
->
slave_addr
);
goto
out
;
}
sil
->
quiet
=
false
;
...
...
drivers/gpu/drm/i915/dvo_tfp410.c
View file @
be9f1c4f
...
...
@@ -101,19 +101,20 @@ struct tfp410_priv {
static
bool
tfp410_readb
(
struct
intel_dvo_device
*
dvo
,
int
addr
,
uint8_t
*
ch
)
{
struct
tfp410_priv
*
tfp
=
dvo
->
dev_priv
;
struct
intel_i2c_chan
*
i2cbus
=
dvo
->
i2c_bus
;
struct
i2c_adapter
*
adapter
=
dvo
->
i2c_bus
;
struct
intel_i2c_chan
*
i2cbus
=
container_of
(
adapter
,
struct
intel_i2c_chan
,
adapter
);
u8
out_buf
[
2
];
u8
in_buf
[
2
];
struct
i2c_msg
msgs
[]
=
{
{
.
addr
=
i2cbus
->
slave_addr
,
.
addr
=
dvo
->
slave_addr
,
.
flags
=
0
,
.
len
=
1
,
.
buf
=
out_buf
,
},
{
.
addr
=
i2cbus
->
slave_addr
,
.
addr
=
dvo
->
slave_addr
,
.
flags
=
I2C_M_RD
,
.
len
=
1
,
.
buf
=
in_buf
,
...
...
@@ -130,7 +131,7 @@ static bool tfp410_readb(struct intel_dvo_device *dvo, int addr, uint8_t *ch)
if
(
!
tfp
->
quiet
)
{
DRM_DEBUG
(
"Unable to read register 0x%02x from %s:%02x.
\n
"
,
addr
,
i2cbus
->
adapter
.
name
,
i2cbus
->
slave_addr
);
addr
,
i2cbus
->
adapter
.
name
,
dvo
->
slave_addr
);
}
return
false
;
}
...
...
@@ -138,10 +139,11 @@ static bool tfp410_readb(struct intel_dvo_device *dvo, int addr, uint8_t *ch)
static
bool
tfp410_writeb
(
struct
intel_dvo_device
*
dvo
,
int
addr
,
uint8_t
ch
)
{
struct
tfp410_priv
*
tfp
=
dvo
->
dev_priv
;
struct
intel_i2c_chan
*
i2cbus
=
dvo
->
i2c_bus
;
struct
i2c_adapter
*
adapter
=
dvo
->
i2c_bus
;
struct
intel_i2c_chan
*
i2cbus
=
container_of
(
adapter
,
struct
intel_i2c_chan
,
adapter
);
uint8_t
out_buf
[
2
];
struct
i2c_msg
msg
=
{
.
addr
=
i2cbus
->
slave_addr
,
.
addr
=
dvo
->
slave_addr
,
.
flags
=
0
,
.
len
=
2
,
.
buf
=
out_buf
,
...
...
@@ -155,7 +157,7 @@ static bool tfp410_writeb(struct intel_dvo_device *dvo, int addr, uint8_t ch)
if
(
!
tfp
->
quiet
)
{
DRM_DEBUG
(
"Unable to write register 0x%02x to %s:%d.
\n
"
,
addr
,
i2cbus
->
adapter
.
name
,
i2cbus
->
slave_addr
);
addr
,
i2cbus
->
adapter
.
name
,
dvo
->
slave_addr
);
}
return
false
;
...
...
@@ -174,7 +176,7 @@ static int tfp410_getid(struct intel_dvo_device *dvo, int addr)
/* Ti TFP410 driver for chip on i2c bus */
static
bool
tfp410_init
(
struct
intel_dvo_device
*
dvo
,
struct
i
ntel_i2c_chan
*
i2cbus
)
struct
i
2c_adapter
*
adapter
)
{
/* this will detect the tfp410 chip on the specified i2c bus */
struct
tfp410_priv
*
tfp
;
...
...
@@ -184,20 +186,19 @@ static bool tfp410_init(struct intel_dvo_device *dvo,
if
(
tfp
==
NULL
)
return
false
;
dvo
->
i2c_bus
=
i2cbus
;
dvo
->
i2c_bus
->
slave_addr
=
dvo
->
slave_addr
;
dvo
->
i2c_bus
=
adapter
;
dvo
->
dev_priv
=
tfp
;
tfp
->
quiet
=
true
;
if
((
id
=
tfp410_getid
(
dvo
,
TFP410_VID_LO
))
!=
TFP410_VID
)
{
DRM_DEBUG
(
"tfp410 not detected got VID %X: from %s Slave %d.
\n
"
,
id
,
i2cbus
->
adapter
.
name
,
i2cbus
->
slave_addr
);
id
,
adapter
->
name
,
dvo
->
slave_addr
);
goto
out
;
}
if
((
id
=
tfp410_getid
(
dvo
,
TFP410_DID_LO
))
!=
TFP410_DID
)
{
DRM_DEBUG
(
"tfp410 not detected got DID %X: from %s Slave %d.
\n
"
,
id
,
i2cbus
->
adapter
.
name
,
i2cbus
->
slave_addr
);
id
,
adapter
->
name
,
dvo
->
slave_addr
);
goto
out
;
}
tfp
->
quiet
=
false
;
...
...
drivers/gpu/drm/i915/i915_drv.h
View file @
be9f1c4f
...
...
@@ -306,6 +306,17 @@ typedef struct drm_i915_private {
u32
saveCURBPOS
;
u32
saveCURBBASE
;
u32
saveCURSIZE
;
u32
saveDP_B
;
u32
saveDP_C
;
u32
saveDP_D
;
u32
savePIPEA_GMCH_DATA_M
;
u32
savePIPEB_GMCH_DATA_M
;
u32
savePIPEA_GMCH_DATA_N
;
u32
savePIPEB_GMCH_DATA_N
;
u32
savePIPEA_DP_LINK_M
;
u32
savePIPEB_DP_LINK_M
;
u32
savePIPEA_DP_LINK_N
;
u32
savePIPEB_DP_LINK_N
;
struct
{
struct
drm_mm
gtt_space
;
...
...
@@ -857,6 +868,7 @@ extern int i915_wait_ring(struct drm_device * dev, int n, const char *caller);
#define HAS_128_BYTE_Y_TILING(dev) (IS_I9XX(dev) && !(IS_I915G(dev) || \
IS_I915GM(dev)))
#define SUPPORTS_INTEGRATED_HDMI(dev) (IS_G4X(dev) || IS_IGDNG(dev))
#define SUPPORTS_INTEGRATED_DP(dev) (IS_G4X(dev) || IS_IGDNG(dev))
#define I915_HAS_HOTPLUG(dev) (IS_I945G(dev) || IS_I945GM(dev) || IS_I965G(dev))
#define PRIMARY_RINGBUFFER_SIZE (128*1024)
...
...
drivers/gpu/drm/i915/i915_gem_tiling.c
View file @
be9f1c4f
...
...
@@ -114,11 +114,13 @@ intel_alloc_mchbar_resource(struct drm_device *dev)
mchbar_addr
=
((
u64
)
temp_hi
<<
32
)
|
temp_lo
;
/* If ACPI doesn't have it, assume we need to allocate it ourselves */
#ifdef CONFIG_PNP
if
(
mchbar_addr
&&
pnp_range_reserved
(
mchbar_addr
,
mchbar_addr
+
MCHBAR_SIZE
))
{
ret
=
0
;
goto
out_put
;
}
#endif
/* Get some space for it */
ret
=
pci_bus_alloc_resource
(
bridge_dev
->
bus
,
&
dev_priv
->
mch_res
,
...
...
drivers/gpu/drm/i915/i915_irq.c
View file @
be9f1c4f
...
...
@@ -232,7 +232,17 @@ static void i915_hotplug_work_func(struct work_struct *work)
drm_i915_private_t
*
dev_priv
=
container_of
(
work
,
drm_i915_private_t
,
hotplug_work
);
struct
drm_device
*
dev
=
dev_priv
->
dev
;
struct
drm_mode_config
*
mode_config
=
&
dev
->
mode_config
;
struct
drm_connector
*
connector
;
if
(
mode_config
->
num_connector
)
{
list_for_each_entry
(
connector
,
&
mode_config
->
connector_list
,
head
)
{
struct
intel_output
*
intel_output
=
to_intel_output
(
connector
);
if
(
intel_output
->
hot_plug
)
(
*
intel_output
->
hot_plug
)
(
intel_output
);
}
}
/* Just fire off a uevent and let userspace tell us what to do */
drm_sysfs_hotplug_event
(
dev
);
}
...
...
drivers/gpu/drm/i915/i915_reg.h
View file @
be9f1c4f
...
...
@@ -569,6 +569,19 @@
#define C0DRB3 0x10206
#define C1DRB3 0x10606
/* Clocking configuration register */
#define CLKCFG 0x10c00
#define CLKCFG_FSB_400 (0 << 0)
/* hrawclk 100 */
#define CLKCFG_FSB_533 (1 << 0)
/* hrawclk 133 */
#define CLKCFG_FSB_667 (3 << 0)
/* hrawclk 166 */
#define CLKCFG_FSB_800 (2 << 0)
/* hrawclk 200 */
#define CLKCFG_FSB_1067 (6 << 0)
/* hrawclk 266 */
#define CLKCFG_FSB_1333 (7 << 0)
/* hrawclk 333 */
/* this is a guess, could be 5 as well */
#define CLKCFG_FSB_1600 (4 << 0)
/* hrawclk 400 */
#define CLKCFG_FSB_1600_ALT (5 << 0)
/* hrawclk 400 */
#define CLKCFG_FSB_MASK (7 << 0)
/** GM965 GM45 render standby register */
#define MCHBAR_RENDER_STANDBY 0x111B8
...
...
drivers/gpu/drm/i915/i915_suspend.c
View file @
be9f1c4f
...
...
@@ -322,6 +322,20 @@ int i915_save_state(struct drm_device *dev)
dev_priv
->
savePP_OFF_DELAYS
=
I915_READ
(
PP_OFF_DELAYS
);
dev_priv
->
savePP_DIVISOR
=
I915_READ
(
PP_DIVISOR
);
/* Display Port state */
if
(
SUPPORTS_INTEGRATED_DP
(
dev
))
{
dev_priv
->
saveDP_B
=
I915_READ
(
DP_B
);
dev_priv
->
saveDP_C
=
I915_READ
(
DP_C
);
dev_priv
->
saveDP_D
=
I915_READ
(
DP_D
);
dev_priv
->
savePIPEA_GMCH_DATA_M
=
I915_READ
(
PIPEA_GMCH_DATA_M
);
dev_priv
->
savePIPEB_GMCH_DATA_M
=
I915_READ
(
PIPEB_GMCH_DATA_M
);
dev_priv
->
savePIPEA_GMCH_DATA_N
=
I915_READ
(
PIPEA_GMCH_DATA_N
);
dev_priv
->
savePIPEB_GMCH_DATA_N
=
I915_READ
(
PIPEB_GMCH_DATA_N
);
dev_priv
->
savePIPEA_DP_LINK_M
=
I915_READ
(
PIPEA_DP_LINK_M
);
dev_priv
->
savePIPEB_DP_LINK_M
=
I915_READ
(
PIPEB_DP_LINK_M
);
dev_priv
->
savePIPEA_DP_LINK_N
=
I915_READ
(
PIPEA_DP_LINK_N
);
dev_priv
->
savePIPEB_DP_LINK_N
=
I915_READ
(
PIPEB_DP_LINK_N
);
}
/* FIXME: save TV & SDVO state */
/* FBC state */
...
...
@@ -404,7 +418,19 @@ int i915_restore_state(struct drm_device *dev)
for
(
i
=
0
;
i
<
8
;
i
++
)
I915_WRITE
(
FENCE_REG_945_8
+
(
i
*
4
),
dev_priv
->
saveFENCE
[
i
+
8
]);
}
/* Display port ratios (must be done before clock is set) */
if
(
SUPPORTS_INTEGRATED_DP
(
dev
))
{
I915_WRITE
(
PIPEA_GMCH_DATA_M
,
dev_priv
->
savePIPEA_GMCH_DATA_M
);
I915_WRITE
(
PIPEB_GMCH_DATA_M
,
dev_priv
->
savePIPEB_GMCH_DATA_M
);
I915_WRITE
(
PIPEA_GMCH_DATA_N
,
dev_priv
->
savePIPEA_GMCH_DATA_N
);
I915_WRITE
(
PIPEB_GMCH_DATA_N
,
dev_priv
->
savePIPEB_GMCH_DATA_N
);
I915_WRITE
(
PIPEA_DP_LINK_M
,
dev_priv
->
savePIPEA_DP_LINK_M
);
I915_WRITE
(
PIPEB_DP_LINK_M
,
dev_priv
->
savePIPEB_DP_LINK_M
);
I915_WRITE
(
PIPEA_DP_LINK_N
,
dev_priv
->
savePIPEA_DP_LINK_N
);
I915_WRITE
(
PIPEB_DP_LINK_N
,
dev_priv
->
savePIPEB_DP_LINK_N
);
}
/* Pipe & plane A info */
/* Prime the clock */
if
(
dev_priv
->
saveDPLL_A
&
DPLL_VCO_ENABLE
)
{
...
...
@@ -518,6 +544,12 @@ int i915_restore_state(struct drm_device *dev)
I915_WRITE
(
PP_DIVISOR
,
dev_priv
->
savePP_DIVISOR
);
I915_WRITE
(
PP_CONTROL
,
dev_priv
->
savePP_CONTROL
);
/* Display Port state */
if
(
SUPPORTS_INTEGRATED_DP
(
dev
))
{
I915_WRITE
(
DP_B
,
dev_priv
->
saveDP_B
);
I915_WRITE
(
DP_C
,
dev_priv
->
saveDP_C
);
I915_WRITE
(
DP_D
,
dev_priv
->
saveDP_D
);
}
/* FIXME: restore TV & SDVO state */
/* FBC info */
...
...
drivers/gpu/drm/i915/intel_display.c
View file @
be9f1c4f
...
...
@@ -29,6 +29,7 @@
#include "intel_drv.h"
#include "i915_drm.h"
#include "i915_drv.h"
#include "intel_dp.h"
#include "drm_crtc_helper.h"
...
...
@@ -127,19 +128,6 @@ struct intel_limit {
#define I9XX_P2_LVDS_FAST 7
#define I9XX_P2_LVDS_SLOW_LIMIT 112000
#define INTEL_LIMIT_I8XX_DVO_DAC 0
#define INTEL_LIMIT_I8XX_LVDS 1
#define INTEL_LIMIT_I9XX_SDVO_DAC 2
#define INTEL_LIMIT_I9XX_LVDS 3
#define INTEL_LIMIT_G4X_SDVO 4
#define INTEL_LIMIT_G4X_HDMI_DAC 5
#define INTEL_LIMIT_G4X_SINGLE_CHANNEL_LVDS 6
#define INTEL_LIMIT_G4X_DUAL_CHANNEL_LVDS 7
#define INTEL_LIMIT_IGD_SDVO_DAC 8
#define INTEL_LIMIT_IGD_LVDS 9
#define INTEL_LIMIT_IGDNG_SDVO_DAC 10
#define INTEL_LIMIT_IGDNG_LVDS 11
/*The parameter is for SDVO on G4x platform*/
#define G4X_DOT_SDVO_MIN 25000
#define G4X_DOT_SDVO_MAX 270000
...
...
@@ -218,6 +206,25 @@ struct intel_limit {
#define G4X_P2_DUAL_CHANNEL_LVDS_FAST 7
#define G4X_P2_DUAL_CHANNEL_LVDS_LIMIT 0
/*The parameter is for DISPLAY PORT on G4x platform*/
#define G4X_DOT_DISPLAY_PORT_MIN 161670
#define G4X_DOT_DISPLAY_PORT_MAX 227000
#define G4X_N_DISPLAY_PORT_MIN 1
#define G4X_N_DISPLAY_PORT_MAX 2
#define G4X_M_DISPLAY_PORT_MIN 97
#define G4X_M_DISPLAY_PORT_MAX 108
#define G4X_M1_DISPLAY_PORT_MIN 0x10
#define G4X_M1_DISPLAY_PORT_MAX 0x12
#define G4X_M2_DISPLAY_PORT_MIN 0x05
#define G4X_M2_DISPLAY_PORT_MAX 0x06
#define G4X_P_DISPLAY_PORT_MIN 10
#define G4X_P_DISPLAY_PORT_MAX 20
#define G4X_P1_DISPLAY_PORT_MIN 1
#define G4X_P1_DISPLAY_PORT_MAX 2
#define G4X_P2_DISPLAY_PORT_SLOW 10
#define G4X_P2_DISPLAY_PORT_FAST 10
#define G4X_P2_DISPLAY_PORT_LIMIT 0
/* IGDNG */
/* as we calculate clock using (register_value + 2) for
N/M1/M2, so here the range value for them is (actual_value-2).
...
...
@@ -256,8 +263,11 @@ static bool
intel_igdng_find_best_PLL
(
const
intel_limit_t
*
limit
,
struct
drm_crtc
*
crtc
,
int
target
,
int
refclk
,
intel_clock_t
*
best_clock
);
static
const
intel_limit_t
intel_limits
[]
=
{
{
/* INTEL_LIMIT_I8XX_DVO_DAC */
static
bool
intel_find_pll_g4x_dp
(
const
intel_limit_t
*
,
struct
drm_crtc
*
crtc
,
int
target
,
int
refclk
,
intel_clock_t
*
best_clock
);
static
const
intel_limit_t
intel_limits_i8xx_dvo
=
{
.
dot
=
{
.
min
=
I8XX_DOT_MIN
,
.
max
=
I8XX_DOT_MAX
},
.
vco
=
{
.
min
=
I8XX_VCO_MIN
,
.
max
=
I8XX_VCO_MAX
},
.
n
=
{
.
min
=
I8XX_N_MIN
,
.
max
=
I8XX_N_MAX
},
...
...
@@ -269,8 +279,9 @@ static const intel_limit_t intel_limits[] = {
.
p2
=
{
.
dot_limit
=
I8XX_P2_SLOW_LIMIT
,
.
p2_slow
=
I8XX_P2_SLOW
,
.
p2_fast
=
I8XX_P2_FAST
},
.
find_pll
=
intel_find_best_PLL
,
},
{
/* INTEL_LIMIT_I8XX_LVDS */
};
static
const
intel_limit_t
intel_limits_i8xx_lvds
=
{
.
dot
=
{
.
min
=
I8XX_DOT_MIN
,
.
max
=
I8XX_DOT_MAX
},
.
vco
=
{
.
min
=
I8XX_VCO_MIN
,
.
max
=
I8XX_VCO_MAX
},
.
n
=
{
.
min
=
I8XX_N_MIN
,
.
max
=
I8XX_N_MAX
},
...
...
@@ -282,8 +293,9 @@ static const intel_limit_t intel_limits[] = {
.
p2
=
{
.
dot_limit
=
I8XX_P2_SLOW_LIMIT
,
.
p2_slow
=
I8XX_P2_LVDS_SLOW
,
.
p2_fast
=
I8XX_P2_LVDS_FAST
},
.
find_pll
=
intel_find_best_PLL
,
},
{
/* INTEL_LIMIT_I9XX_SDVO_DAC */
};
static
const
intel_limit_t
intel_limits_i9xx_sdvo
=
{
.
dot
=
{
.
min
=
I9XX_DOT_MIN
,
.
max
=
I9XX_DOT_MAX
},
.
vco
=
{
.
min
=
I9XX_VCO_MIN
,
.
max
=
I9XX_VCO_MAX
},
.
n
=
{
.
min
=
I9XX_N_MIN
,
.
max
=
I9XX_N_MAX
},
...
...
@@ -295,8 +307,9 @@ static const intel_limit_t intel_limits[] = {
.
p2
=
{
.
dot_limit
=
I9XX_P2_SDVO_DAC_SLOW_LIMIT
,
.
p2_slow
=
I9XX_P2_SDVO_DAC_SLOW
,
.
p2_fast
=
I9XX_P2_SDVO_DAC_FAST
},
.
find_pll
=
intel_find_best_PLL
,
},
{
/* INTEL_LIMIT_I9XX_LVDS */
};
static
const
intel_limit_t
intel_limits_i9xx_lvds
=
{
.
dot
=
{
.
min
=
I9XX_DOT_MIN
,
.
max
=
I9XX_DOT_MAX
},
.
vco
=
{
.
min
=
I9XX_VCO_MIN
,
.
max
=
I9XX_VCO_MAX
},
.
n
=
{
.
min
=
I9XX_N_MIN
,
.
max
=
I9XX_N_MAX
},
...
...
@@ -311,9 +324,10 @@ static const intel_limit_t intel_limits[] = {
.
p2
=
{
.
dot_limit
=
I9XX_P2_LVDS_SLOW_LIMIT
,
.
p2_slow
=
I9XX_P2_LVDS_SLOW
,
.
p2_fast
=
I9XX_P2_LVDS_FAST
},
.
find_pll
=
intel_find_best_PLL
,
},
};
/* below parameter and function is for G4X Chipset Family*/
{
/* INTEL_LIMIT_G4X_SDVO */
static
const
intel_limit_t
intel_limits_g4x_sdvo
=
{
.
dot
=
{
.
min
=
G4X_DOT_SDVO_MIN
,
.
max
=
G4X_DOT_SDVO_MAX
},
.
vco
=
{
.
min
=
G4X_VCO_MIN
,
.
max
=
G4X_VCO_MAX
},
.
n
=
{
.
min
=
G4X_N_SDVO_MIN
,
.
max
=
G4X_N_SDVO_MAX
},
...
...
@@ -327,8 +341,9 @@ static const intel_limit_t intel_limits[] = {
.
p2_fast
=
G4X_P2_SDVO_FAST
},
.
find_pll
=
intel_g4x_find_best_PLL
,
},
{
/* INTEL_LIMIT_G4X_HDMI_DAC */
};
static
const
intel_limit_t
intel_limits_g4x_hdmi
=
{
.
dot
=
{
.
min
=
G4X_DOT_HDMI_DAC_MIN
,
.
max
=
G4X_DOT_HDMI_DAC_MAX
},
.
vco
=
{
.
min
=
G4X_VCO_MIN
,
.
max
=
G4X_VCO_MAX
},
.
n
=
{
.
min
=
G4X_N_HDMI_DAC_MIN
,
.
max
=
G4X_N_HDMI_DAC_MAX
},
...
...
@@ -342,8 +357,9 @@ static const intel_limit_t intel_limits[] = {
.
p2_fast
=
G4X_P2_HDMI_DAC_FAST
},
.
find_pll
=
intel_g4x_find_best_PLL
,
},
{
/* INTEL_LIMIT_G4X_SINGLE_CHANNEL_LVDS */
};
static
const
intel_limit_t
intel_limits_g4x_single_channel_lvds
=
{
.
dot
=
{
.
min
=
G4X_DOT_SINGLE_CHANNEL_LVDS_MIN
,
.
max
=
G4X_DOT_SINGLE_CHANNEL_LVDS_MAX
},
.
vco
=
{
.
min
=
G4X_VCO_MIN
,
...
...
@@ -365,8 +381,9 @@ static const intel_limit_t intel_limits[] = {
.
p2_fast
=
G4X_P2_SINGLE_CHANNEL_LVDS_FAST
},
.
find_pll
=
intel_g4x_find_best_PLL
,
},
{
/* INTEL_LIMIT_G4X_DUAL_CHANNEL_LVDS */
};
static
const
intel_limit_t
intel_limits_g4x_dual_channel_lvds
=
{
.
dot
=
{
.
min
=
G4X_DOT_DUAL_CHANNEL_LVDS_MIN
,
.
max
=
G4X_DOT_DUAL_CHANNEL_LVDS_MAX
},
.
vco
=
{
.
min
=
G4X_VCO_MIN
,
...
...
@@ -388,8 +405,32 @@ static const intel_limit_t intel_limits[] = {
.
p2_fast
=
G4X_P2_DUAL_CHANNEL_LVDS_FAST
},
.
find_pll
=
intel_g4x_find_best_PLL
,
},
{
/* INTEL_LIMIT_IGD_SDVO */
};
static
const
intel_limit_t
intel_limits_g4x_display_port
=
{
.
dot
=
{
.
min
=
G4X_DOT_DISPLAY_PORT_MIN
,
.
max
=
G4X_DOT_DISPLAY_PORT_MAX
},
.
vco
=
{
.
min
=
G4X_VCO_MIN
,
.
max
=
G4X_VCO_MAX
},
.
n
=
{
.
min
=
G4X_N_DISPLAY_PORT_MIN
,
.
max
=
G4X_N_DISPLAY_PORT_MAX
},
.
m
=
{
.
min
=
G4X_M_DISPLAY_PORT_MIN
,
.
max
=
G4X_M_DISPLAY_PORT_MAX
},
.
m1
=
{
.
min
=
G4X_M1_DISPLAY_PORT_MIN
,
.
max
=
G4X_M1_DISPLAY_PORT_MAX
},
.
m2
=
{
.
min
=
G4X_M2_DISPLAY_PORT_MIN
,
.
max
=
G4X_M2_DISPLAY_PORT_MAX
},
.
p
=
{
.
min
=
G4X_P_DISPLAY_PORT_MIN
,
.
max
=
G4X_P_DISPLAY_PORT_MAX
},
.
p1
=
{
.
min
=
G4X_P1_DISPLAY_PORT_MIN
,
.
max
=
G4X_P1_DISPLAY_PORT_MAX
},
.
p2
=
{
.
dot_limit
=
G4X_P2_DISPLAY_PORT_LIMIT
,
.
p2_slow
=
G4X_P2_DISPLAY_PORT_SLOW
,
.
p2_fast
=
G4X_P2_DISPLAY_PORT_FAST
},
.
find_pll
=
intel_find_pll_g4x_dp
,
};
static
const
intel_limit_t
intel_limits_igd_sdvo
=
{
.
dot
=
{
.
min
=
I9XX_DOT_MIN
,
.
max
=
I9XX_DOT_MAX
},
.
vco
=
{
.
min
=
IGD_VCO_MIN
,
.
max
=
IGD_VCO_MAX
},
.
n
=
{
.
min
=
IGD_N_MIN
,
.
max
=
IGD_N_MAX
},
...
...
@@ -401,8 +442,9 @@ static const intel_limit_t intel_limits[] = {
.
p2
=
{
.
dot_limit
=
I9XX_P2_SDVO_DAC_SLOW_LIMIT
,
.
p2_slow
=
I9XX_P2_SDVO_DAC_SLOW
,
.
p2_fast
=
I9XX_P2_SDVO_DAC_FAST
},
.
find_pll
=
intel_find_best_PLL
,
},
{
/* INTEL_LIMIT_IGD_LVDS */
};
static
const
intel_limit_t
intel_limits_igd_lvds
=
{
.
dot
=
{
.
min
=
I9XX_DOT_MIN
,
.
max
=
I9XX_DOT_MAX
},
.
vco
=
{
.
min
=
IGD_VCO_MIN
,
.
max
=
IGD_VCO_MAX
},
.
n
=
{
.
min
=
IGD_N_MIN
,
.
max
=
IGD_N_MAX
},
...
...
@@ -415,8 +457,9 @@ static const intel_limit_t intel_limits[] = {
.
p2
=
{
.
dot_limit
=
I9XX_P2_LVDS_SLOW_LIMIT
,
.
p2_slow
=
I9XX_P2_LVDS_SLOW
,
.
p2_fast
=
I9XX_P2_LVDS_SLOW
},
.
find_pll
=
intel_find_best_PLL
,
},
{
/* INTEL_LIMIT_IGDNG_SDVO_DAC */
};
static
const
intel_limit_t
intel_limits_igdng_sdvo
=
{
.
dot
=
{
.
min
=
IGDNG_DOT_MIN
,
.
max
=
IGDNG_DOT_MAX
},
.
vco
=
{
.
min
=
IGDNG_VCO_MIN
,
.
max
=
IGDNG_VCO_MAX
},
.
n
=
{
.
min
=
IGDNG_N_MIN
,
.
max
=
IGDNG_N_MAX
},
...
...
@@ -429,8 +472,9 @@ static const intel_limit_t intel_limits[] = {
.
p2_slow
=
IGDNG_P2_SDVO_DAC_SLOW
,
.
p2_fast
=
IGDNG_P2_SDVO_DAC_FAST
},
.
find_pll
=
intel_igdng_find_best_PLL
,
},
{
/* INTEL_LIMIT_IGDNG_LVDS */
};
static
const
intel_limit_t
intel_limits_igdng_lvds
=
{
.
dot
=
{
.
min
=
IGDNG_DOT_MIN
,
.
max
=
IGDNG_DOT_MAX
},
.
vco
=
{
.
min
=
IGDNG_VCO_MIN
,
.
max
=
IGDNG_VCO_MAX
},
.
n
=
{
.
min
=
IGDNG_N_MIN
,
.
max
=
IGDNG_N_MAX
},
...
...
@@ -443,16 +487,15 @@ static const intel_limit_t intel_limits[] = {
.
p2_slow
=
IGDNG_P2_LVDS_SLOW
,
.
p2_fast
=
IGDNG_P2_LVDS_FAST
},
.
find_pll
=
intel_igdng_find_best_PLL
,
},
};
static
const
intel_limit_t
*
intel_igdng_limit
(
struct
drm_crtc
*
crtc
)
{
const
intel_limit_t
*
limit
;
if
(
intel_pipe_has_type
(
crtc
,
INTEL_OUTPUT_LVDS
))
limit
=
&
intel_limits
[
INTEL_LIMIT_IGDNG_LVDS
]
;
limit
=
&
intel_limits
_igdng_lvds
;
else
limit
=
&
intel_limits
[
INTEL_LIMIT_IGDNG_SDVO_DAC
]
;
limit
=
&
intel_limits
_igdng_sdvo
;
return
limit
;
}
...
...
@@ -467,19 +510,19 @@ static const intel_limit_t *intel_g4x_limit(struct drm_crtc *crtc)
if
((
I915_READ
(
LVDS
)
&
LVDS_CLKB_POWER_MASK
)
==
LVDS_CLKB_POWER_UP
)
/* LVDS with dual channel */
limit
=
&
intel_limits
[
INTEL_LIMIT_G4X_DUAL_CHANNEL_LVDS
];
limit
=
&
intel_limits_g4x_dual_channel_lvds
;
else
/* LVDS with dual channel */
limit
=
&
intel_limits
[
INTEL_LIMIT_G4X_SINGLE_CHANNEL_LVDS
];
limit
=
&
intel_limits_g4x_single_channel_lvds
;
}
else
if
(
intel_pipe_has_type
(
crtc
,
INTEL_OUTPUT_HDMI
)
||
intel_pipe_has_type
(
crtc
,
INTEL_OUTPUT_ANALOG
))
{
limit
=
&
intel_limits
[
INTEL_LIMIT_G4X_HDMI_DAC
]
;
limit
=
&
intel_limits
_g4x_hdmi
;
}
else
if
(
intel_pipe_has_type
(
crtc
,
INTEL_OUTPUT_SDVO
))
{
limit
=
&
intel_limits
[
INTEL_LIMIT_G4X_SDVO
];
limit
=
&
intel_limits_g4x_sdvo
;
}
else
if
(
intel_pipe_has_type
(
crtc
,
INTEL_OUTPUT_DISPLAYPORT
))
{
limit
=
&
intel_limits_g4x_display_port
;
}
else
/* The option is for other outputs */
limit
=
&
intel_limits
[
INTEL_LIMIT_I9XX_SDVO_DAC
]
;
limit
=
&
intel_limits
_i9xx_sdvo
;
return
limit
;
}
...
...
@@ -495,19 +538,19 @@ static const intel_limit_t *intel_limit(struct drm_crtc *crtc)
limit
=
intel_g4x_limit
(
crtc
);
}
else
if
(
IS_I9XX
(
dev
)
&&
!
IS_IGD
(
dev
))
{
if
(
intel_pipe_has_type
(
crtc
,
INTEL_OUTPUT_LVDS
))
limit
=
&
intel_limits
[
INTEL_LIMIT_I9XX_LVDS
]
;
limit
=
&
intel_limits
_i9xx_lvds
;
else
limit
=
&
intel_limits
[
INTEL_LIMIT_I9XX_SDVO_DAC
]
;
limit
=
&
intel_limits
_i9xx_sdvo
;
}
else
if
(
IS_IGD
(
dev
))
{
if
(
intel_pipe_has_type
(
crtc
,
INTEL_OUTPUT_LVDS
))
limit
=
&
intel_limits
[
INTEL_LIMIT_IGD_LVDS
]
;
limit
=
&
intel_limits
_igd_lvds
;
else
limit
=
&
intel_limits
[
INTEL_LIMIT_IGD_SDVO_DAC
]
;
limit
=
&
intel_limits
_igd_sdvo
;
}
else
{
if
(
intel_pipe_has_type
(
crtc
,
INTEL_OUTPUT_LVDS
))
limit
=
&
intel_limits
[
INTEL_LIMIT_I8XX_LVDS
]
;
limit
=
&
intel_limits
_i8xx_lvds
;
else
limit
=
&
intel_limits
[
INTEL_LIMIT_I8XX_DVO_DAC
]
;
limit
=
&
intel_limits
_i8xx_dvo
;
}
return
limit
;
}
...
...
@@ -764,6 +807,35 @@ intel_igdng_find_best_PLL(const intel_limit_t *limit, struct drm_crtc *crtc,
return
found
;
}
/* DisplayPort has only two frequencies, 162MHz and 270MHz */
static
bool
intel_find_pll_g4x_dp
(
const
intel_limit_t
*
limit
,
struct
drm_crtc
*
crtc
,
int
target
,
int
refclk
,
intel_clock_t
*
best_clock
)
{
intel_clock_t
clock
;
if
(
target
<
200000
)
{
clock
.
dot
=
161670
;
clock
.
p
=
20
;
clock
.
p1
=
2
;
clock
.
p2
=
10
;
clock
.
n
=
0x01
;
clock
.
m
=
97
;
clock
.
m1
=
0x10
;
clock
.
m2
=
0x05
;
}
else
{
clock
.
dot
=
270000
;
clock
.
p
=
10
;
clock
.
p1
=
1
;
clock
.
p2
=
10
;
clock
.
n
=
0x02
;
clock
.
m
=
108
;
clock
.
m1
=
0x12
;
clock
.
m2
=
0x06
;
}
memcpy
(
best_clock
,
&
clock
,
sizeof
(
intel_clock_t
));
return
true
;
}
void
intel_wait_for_vblank
(
struct
drm_device
*
dev
)
{
...
...
@@ -1541,7 +1613,7 @@ static int intel_crtc_mode_set(struct drm_crtc *crtc,
intel_clock_t
clock
;
u32
dpll
=
0
,
fp
=
0
,
dspcntr
,
pipeconf
;
bool
ok
,
is_sdvo
=
false
,
is_dvo
=
false
;
bool
is_crt
=
false
,
is_lvds
=
false
,
is_tv
=
false
;
bool
is_crt
=
false
,
is_lvds
=
false
,
is_tv
=
false
,
is_dp
=
false
;
struct
drm_mode_config
*
mode_config
=
&
dev
->
mode_config
;
struct
drm_connector
*
connector
;
const
intel_limit_t
*
limit
;
...
...
@@ -1585,6 +1657,9 @@ static int intel_crtc_mode_set(struct drm_crtc *crtc,
case
INTEL_OUTPUT_ANALOG
:
is_crt
=
true
;
break
;
case
INTEL_OUTPUT_DISPLAYPORT
:
is_dp
=
true
;
break
;
}
num_outputs
++
;
...
...
@@ -1600,6 +1675,7 @@ static int intel_crtc_mode_set(struct drm_crtc *crtc,
}
else
{
refclk
=
48000
;
}
/*
* Returns a set of divisors for the desired target clock with the given
...
...
@@ -1662,6 +1738,8 @@ static int intel_crtc_mode_set(struct drm_crtc *crtc,
else
if
(
IS_IGDNG
(
dev
))
dpll
|=
(
sdvo_pixel_multiply
-
1
)
<<
PLL_REF_SDVO_HDMI_MULTIPLIER_SHIFT
;
}
if
(
is_dp
)
dpll
|=
DPLL_DVO_HIGH_SPEED
;
/* compute bitmask from p1 value */
if
(
IS_IGD
(
dev
))
...
...
@@ -1809,6 +1887,8 @@ static int intel_crtc_mode_set(struct drm_crtc *crtc,
I915_WRITE
(
lvds_reg
,
lvds
);
I915_READ
(
lvds_reg
);
}
if
(
is_dp
)
intel_dp_set_m_n
(
crtc
,
mode
,
adjusted_mode
);
I915_WRITE
(
fp_reg
,
fp
);
I915_WRITE
(
dpll_reg
,
dpll
);
...
...
@@ -2475,6 +2555,8 @@ static void intel_setup_outputs(struct drm_device *dev)
found
=
intel_sdvo_init
(
dev
,
SDVOB
);
if
(
!
found
&&
SUPPORTS_INTEGRATED_HDMI
(
dev
))
intel_hdmi_init
(
dev
,
SDVOB
);
if
(
!
found
&&
SUPPORTS_INTEGRATED_DP
(
dev
))
intel_dp_init
(
dev
,
DP_B
);
}
/* Before G4X SDVOC doesn't have its own detect register */
...
...
@@ -2487,7 +2569,11 @@ static void intel_setup_outputs(struct drm_device *dev)
found
=
intel_sdvo_init
(
dev
,
SDVOC
);
if
(
!
found
&&
SUPPORTS_INTEGRATED_HDMI
(
dev
))
intel_hdmi_init
(
dev
,
SDVOC
);
if
(
!
found
&&
SUPPORTS_INTEGRATED_DP
(
dev
))
intel_dp_init
(
dev
,
DP_C
);
}
if
(
SUPPORTS_INTEGRATED_DP
(
dev
)
&&
(
I915_READ
(
DP_D
)
&
DP_DETECTED
))
intel_dp_init
(
dev
,
DP_D
);
}
else
intel_dvo_init
(
dev
);
...
...
@@ -2530,6 +2616,11 @@ static void intel_setup_outputs(struct drm_device *dev)
(
1
<<
1
));
clone_mask
=
(
1
<<
INTEL_OUTPUT_TVOUT
);
break
;
case
INTEL_OUTPUT_DISPLAYPORT
:
crtc_mask
=
((
1
<<
0
)
|
(
1
<<
1
));
clone_mask
=
(
1
<<
INTEL_OUTPUT_DISPLAYPORT
);
break
;
}
encoder
->
possible_crtcs
=
crtc_mask
;
encoder
->
possible_clones
=
intel_connector_clones
(
dev
,
clone_mask
);
...
...
drivers/gpu/drm/i915/intel_dp.c
0 → 100644
View file @
be9f1c4f
/*
* Copyright © 2008 Intel Corporation
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice (including the next
* paragraph) shall be included in all copies or substantial portions of the
* Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
* IN THE SOFTWARE.
*
* Authors:
* Keith Packard <keithp@keithp.com>
*
*/
#include <linux/i2c.h>
#include "drmP.h"
#include "drm.h"
#include "drm_crtc.h"
#include "drm_crtc_helper.h"
#include "intel_drv.h"
#include "i915_drm.h"
#include "i915_drv.h"
#include "intel_dp.h"
#define DP_LINK_STATUS_SIZE 6
#define DP_LINK_CHECK_TIMEOUT (10 * 1000)
#define DP_LINK_CONFIGURATION_SIZE 9
struct
intel_dp_priv
{
uint32_t
output_reg
;
uint32_t
DP
;
uint8_t
link_configuration
[
DP_LINK_CONFIGURATION_SIZE
];
uint32_t
save_DP
;
uint8_t
save_link_configuration
[
DP_LINK_CONFIGURATION_SIZE
];
bool
has_audio
;
int
dpms_mode
;
uint8_t
link_bw
;
uint8_t
lane_count
;
uint8_t
dpcd
[
4
];
struct
intel_output
*
intel_output
;
struct
i2c_adapter
adapter
;
struct
i2c_algo_dp_aux_data
algo
;
};
static
void
intel_dp_link_train
(
struct
intel_output
*
intel_output
,
uint32_t
DP
,
uint8_t
link_configuration
[
DP_LINK_CONFIGURATION_SIZE
]);
static
void
intel_dp_link_down
(
struct
intel_output
*
intel_output
,
uint32_t
DP
);
static
int
intel_dp_max_lane_count
(
struct
intel_output
*
intel_output
)
{
struct
intel_dp_priv
*
dp_priv
=
intel_output
->
dev_priv
;
int
max_lane_count
=
4
;
if
(
dp_priv
->
dpcd
[
0
]
>=
0x11
)
{
max_lane_count
=
dp_priv
->
dpcd
[
2
]
&
0x1f
;
switch
(
max_lane_count
)
{
case
1
:
case
2
:
case
4
:
break
;
default:
max_lane_count
=
4
;
}
}
return
max_lane_count
;
}
static
int
intel_dp_max_link_bw
(
struct
intel_output
*
intel_output
)
{
struct
intel_dp_priv
*
dp_priv
=
intel_output
->
dev_priv
;
int
max_link_bw
=
dp_priv
->
dpcd
[
1
];
switch
(
max_link_bw
)
{
case
DP_LINK_BW_1_62
:
case
DP_LINK_BW_2_7
:
break
;
default:
max_link_bw
=
DP_LINK_BW_1_62
;
break
;
}
return
max_link_bw
;
}
static
int
intel_dp_link_clock
(
uint8_t
link_bw
)
{
if
(
link_bw
==
DP_LINK_BW_2_7
)
return
270000
;
else
return
162000
;
}
/* I think this is a fiction */
static
int
intel_dp_link_required
(
int
pixel_clock
)
{
return
pixel_clock
*
3
;
}
static
int
intel_dp_mode_valid
(
struct
drm_connector
*
connector
,
struct
drm_display_mode
*
mode
)
{
struct
intel_output
*
intel_output
=
to_intel_output
(
connector
);
int
max_link_clock
=
intel_dp_link_clock
(
intel_dp_max_link_bw
(
intel_output
));
int
max_lanes
=
intel_dp_max_lane_count
(
intel_output
);
if
(
intel_dp_link_required
(
mode
->
clock
)
>
max_link_clock
*
max_lanes
)
return
MODE_CLOCK_HIGH
;
if
(
mode
->
clock
<
10000
)
return
MODE_CLOCK_LOW
;
return
MODE_OK
;
}
static
uint32_t
pack_aux
(
uint8_t
*
src
,
int
src_bytes
)
{
int
i
;
uint32_t
v
=
0
;
if
(
src_bytes
>
4
)
src_bytes
=
4
;
for
(
i
=
0
;
i
<
src_bytes
;
i
++
)
v
|=
((
uint32_t
)
src
[
i
])
<<
((
3
-
i
)
*
8
);
return
v
;
}
static
void
unpack_aux
(
uint32_t
src
,
uint8_t
*
dst
,
int
dst_bytes
)
{
int
i
;
if
(
dst_bytes
>
4
)
dst_bytes
=
4
;
for
(
i
=
0
;
i
<
dst_bytes
;
i
++
)
dst
[
i
]
=
src
>>
((
3
-
i
)
*
8
);
}
/* hrawclock is 1/4 the FSB frequency */
static
int
intel_hrawclk
(
struct
drm_device
*
dev
)
{
struct
drm_i915_private
*
dev_priv
=
dev
->
dev_private
;
uint32_t
clkcfg
;
clkcfg
=
I915_READ
(
CLKCFG
);
switch
(
clkcfg
&
CLKCFG_FSB_MASK
)
{
case
CLKCFG_FSB_400
:
return
100
;
case
CLKCFG_FSB_533
:
return
133
;
case
CLKCFG_FSB_667
:
return
166
;
case
CLKCFG_FSB_800
:
return
200
;
case
CLKCFG_FSB_1067
:
return
266
;
case
CLKCFG_FSB_1333
:
return
333
;
/* these two are just a guess; one of them might be right */
case
CLKCFG_FSB_1600
:
case
CLKCFG_FSB_1600_ALT
:
return
400
;
default:
return
133
;
}
}
static
int
intel_dp_aux_ch
(
struct
intel_output
*
intel_output
,
uint8_t
*
send
,
int
send_bytes
,
uint8_t
*
recv
,
int
recv_size
)
{
struct
intel_dp_priv
*
dp_priv
=
intel_output
->
dev_priv
;
uint32_t
output_reg
=
dp_priv
->
output_reg
;
struct
drm_device
*
dev
=
intel_output
->
base
.
dev
;
struct
drm_i915_private
*
dev_priv
=
dev
->
dev_private
;
uint32_t
ch_ctl
=
output_reg
+
0x10
;
uint32_t
ch_data
=
ch_ctl
+
4
;
int
i
;
int
recv_bytes
;
uint32_t
ctl
;
uint32_t
status
;
uint32_t
aux_clock_divider
;
int
try
;
/* The clock divider is based off the hrawclk,
* and would like to run at 2MHz. So, take the
* hrawclk value and divide by 2 and use that
*/
aux_clock_divider
=
intel_hrawclk
(
dev
)
/
2
;
/* Must try at least 3 times according to DP spec */
for
(
try
=
0
;
try
<
5
;
try
++
)
{
/* Load the send data into the aux channel data registers */
for
(
i
=
0
;
i
<
send_bytes
;
i
+=
4
)
{
uint32_t
d
=
pack_aux
(
send
+
i
,
send_bytes
-
i
);;
I915_WRITE
(
ch_data
+
i
,
d
);
}
ctl
=
(
DP_AUX_CH_CTL_SEND_BUSY
|
DP_AUX_CH_CTL_TIME_OUT_400us
|
(
send_bytes
<<
DP_AUX_CH_CTL_MESSAGE_SIZE_SHIFT
)
|
(
5
<<
DP_AUX_CH_CTL_PRECHARGE_2US_SHIFT
)
|
(
aux_clock_divider
<<
DP_AUX_CH_CTL_BIT_CLOCK_2X_SHIFT
)
|
DP_AUX_CH_CTL_DONE
|
DP_AUX_CH_CTL_TIME_OUT_ERROR
|
DP_AUX_CH_CTL_RECEIVE_ERROR
);
/* Send the command and wait for it to complete */
I915_WRITE
(
ch_ctl
,
ctl
);
(
void
)
I915_READ
(
ch_ctl
);
for
(;;)
{
udelay
(
100
);
status
=
I915_READ
(
ch_ctl
);
if
((
status
&
DP_AUX_CH_CTL_SEND_BUSY
)
==
0
)
break
;
}
/* Clear done status and any errors */
I915_WRITE
(
ch_ctl
,
(
ctl
|
DP_AUX_CH_CTL_DONE
|
DP_AUX_CH_CTL_TIME_OUT_ERROR
|
DP_AUX_CH_CTL_RECEIVE_ERROR
));
(
void
)
I915_READ
(
ch_ctl
);
if
((
status
&
DP_AUX_CH_CTL_TIME_OUT_ERROR
)
==
0
)
break
;
}
if
((
status
&
DP_AUX_CH_CTL_DONE
)
==
0
)
{
printk
(
KERN_ERR
"dp_aux_ch not done status 0x%08x
\n
"
,
status
);
return
-
EBUSY
;
}
/* Check for timeout or receive error.
* Timeouts occur when the sink is not connected
*/
if
(
status
&
DP_AUX_CH_CTL_RECEIVE_ERROR
)
{
printk
(
KERN_ERR
"dp_aux_ch receive error status 0x%08x
\n
"
,
status
);
return
-
EIO
;
}
if
(
status
&
DP_AUX_CH_CTL_TIME_OUT_ERROR
)
{
printk
(
KERN_ERR
"dp_aux_ch timeout status 0x%08x
\n
"
,
status
);
return
-
ETIMEDOUT
;
}
/* Unload any bytes sent back from the other side */
recv_bytes
=
((
status
&
DP_AUX_CH_CTL_MESSAGE_SIZE_MASK
)
>>
DP_AUX_CH_CTL_MESSAGE_SIZE_SHIFT
);
if
(
recv_bytes
>
recv_size
)
recv_bytes
=
recv_size
;
for
(
i
=
0
;
i
<
recv_bytes
;
i
+=
4
)
{
uint32_t
d
=
I915_READ
(
ch_data
+
i
);
unpack_aux
(
d
,
recv
+
i
,
recv_bytes
-
i
);
}
return
recv_bytes
;
}
/* Write data to the aux channel in native mode */
static
int
intel_dp_aux_native_write
(
struct
intel_output
*
intel_output
,
uint16_t
address
,
uint8_t
*
send
,
int
send_bytes
)
{
int
ret
;
uint8_t
msg
[
20
];
int
msg_bytes
;
uint8_t
ack
;
if
(
send_bytes
>
16
)
return
-
1
;
msg
[
0
]
=
AUX_NATIVE_WRITE
<<
4
;
msg
[
1
]
=
address
>>
8
;
msg
[
2
]
=
address
;
msg
[
3
]
=
send_bytes
-
1
;
memcpy
(
&
msg
[
4
],
send
,
send_bytes
);
msg_bytes
=
send_bytes
+
4
;
for
(;;)
{
ret
=
intel_dp_aux_ch
(
intel_output
,
msg
,
msg_bytes
,
&
ack
,
1
);
if
(
ret
<
0
)
return
ret
;
if
((
ack
&
AUX_NATIVE_REPLY_MASK
)
==
AUX_NATIVE_REPLY_ACK
)
break
;
else
if
((
ack
&
AUX_NATIVE_REPLY_MASK
)
==
AUX_NATIVE_REPLY_DEFER
)
udelay
(
100
);
else
return
-
EIO
;
}
return
send_bytes
;
}
/* Write a single byte to the aux channel in native mode */
static
int
intel_dp_aux_native_write_1
(
struct
intel_output
*
intel_output
,
uint16_t
address
,
uint8_t
byte
)
{
return
intel_dp_aux_native_write
(
intel_output
,
address
,
&
byte
,
1
);
}
/* read bytes from a native aux channel */
static
int
intel_dp_aux_native_read
(
struct
intel_output
*
intel_output
,
uint16_t
address
,
uint8_t
*
recv
,
int
recv_bytes
)
{
uint8_t
msg
[
4
];
int
msg_bytes
;
uint8_t
reply
[
20
];
int
reply_bytes
;
uint8_t
ack
;
int
ret
;
msg
[
0
]
=
AUX_NATIVE_READ
<<
4
;
msg
[
1
]
=
address
>>
8
;
msg
[
2
]
=
address
&
0xff
;
msg
[
3
]
=
recv_bytes
-
1
;
msg_bytes
=
4
;
reply_bytes
=
recv_bytes
+
1
;
for
(;;)
{
ret
=
intel_dp_aux_ch
(
intel_output
,
msg
,
msg_bytes
,
reply
,
reply_bytes
);
if
(
ret
==
0
)
return
-
EPROTO
;
if
(
ret
<
0
)
return
ret
;
ack
=
reply
[
0
];
if
((
ack
&
AUX_NATIVE_REPLY_MASK
)
==
AUX_NATIVE_REPLY_ACK
)
{
memcpy
(
recv
,
reply
+
1
,
ret
-
1
);
return
ret
-
1
;
}
else
if
((
ack
&
AUX_NATIVE_REPLY_MASK
)
==
AUX_NATIVE_REPLY_DEFER
)
udelay
(
100
);
else
return
-
EIO
;
}
}
static
int
intel_dp_i2c_aux_ch
(
struct
i2c_adapter
*
adapter
,
uint8_t
*
send
,
int
send_bytes
,
uint8_t
*
recv
,
int
recv_bytes
)
{
struct
intel_dp_priv
*
dp_priv
=
container_of
(
adapter
,
struct
intel_dp_priv
,
adapter
);
struct
intel_output
*
intel_output
=
dp_priv
->
intel_output
;
return
intel_dp_aux_ch
(
intel_output
,
send
,
send_bytes
,
recv
,
recv_bytes
);
}
static
int
intel_dp_i2c_init
(
struct
intel_output
*
intel_output
,
const
char
*
name
)
{
struct
intel_dp_priv
*
dp_priv
=
intel_output
->
dev_priv
;
DRM_ERROR
(
"i2c_init %s
\n
"
,
name
);
dp_priv
->
algo
.
running
=
false
;
dp_priv
->
algo
.
address
=
0
;
dp_priv
->
algo
.
aux_ch
=
intel_dp_i2c_aux_ch
;
memset
(
&
dp_priv
->
adapter
,
'\0'
,
sizeof
(
dp_priv
->
adapter
));
dp_priv
->
adapter
.
owner
=
THIS_MODULE
;
dp_priv
->
adapter
.
class
=
I2C_CLASS_DDC
;
strncpy
(
dp_priv
->
adapter
.
name
,
name
,
sizeof
dp_priv
->
adapter
.
name
-
1
);
dp_priv
->
adapter
.
name
[
sizeof
dp_priv
->
adapter
.
name
-
1
]
=
'\0'
;
dp_priv
->
adapter
.
algo_data
=
&
dp_priv
->
algo
;
dp_priv
->
adapter
.
dev
.
parent
=
&
intel_output
->
base
.
kdev
;
return
i2c_dp_aux_add_bus
(
&
dp_priv
->
adapter
);
}
static
bool
intel_dp_mode_fixup
(
struct
drm_encoder
*
encoder
,
struct
drm_display_mode
*
mode
,
struct
drm_display_mode
*
adjusted_mode
)
{
struct
intel_output
*
intel_output
=
enc_to_intel_output
(
encoder
);
struct
intel_dp_priv
*
dp_priv
=
intel_output
->
dev_priv
;
int
lane_count
,
clock
;
int
max_lane_count
=
intel_dp_max_lane_count
(
intel_output
);
int
max_clock
=
intel_dp_max_link_bw
(
intel_output
)
==
DP_LINK_BW_2_7
?
1
:
0
;
static
int
bws
[
2
]
=
{
DP_LINK_BW_1_62
,
DP_LINK_BW_2_7
};
for
(
lane_count
=
1
;
lane_count
<=
max_lane_count
;
lane_count
<<=
1
)
{
for
(
clock
=
0
;
clock
<=
max_clock
;
clock
++
)
{
int
link_avail
=
intel_dp_link_clock
(
bws
[
clock
])
*
lane_count
;
if
(
intel_dp_link_required
(
mode
->
clock
)
<=
link_avail
)
{
dp_priv
->
link_bw
=
bws
[
clock
];
dp_priv
->
lane_count
=
lane_count
;
adjusted_mode
->
clock
=
intel_dp_link_clock
(
dp_priv
->
link_bw
);
printk
(
KERN_ERR
"link bw %02x lane count %d clock %d
\n
"
,
dp_priv
->
link_bw
,
dp_priv
->
lane_count
,
adjusted_mode
->
clock
);
return
true
;
}
}
}
return
false
;
}
struct
intel_dp_m_n
{
uint32_t
tu
;
uint32_t
gmch_m
;
uint32_t
gmch_n
;
uint32_t
link_m
;
uint32_t
link_n
;
};
static
void
intel_reduce_ratio
(
uint32_t
*
num
,
uint32_t
*
den
)
{
while
(
*
num
>
0xffffff
||
*
den
>
0xffffff
)
{
*
num
>>=
1
;
*
den
>>=
1
;
}
}
static
void
intel_dp_compute_m_n
(
int
bytes_per_pixel
,
int
nlanes
,
int
pixel_clock
,
int
link_clock
,
struct
intel_dp_m_n
*
m_n
)
{
m_n
->
tu
=
64
;
m_n
->
gmch_m
=
pixel_clock
*
bytes_per_pixel
;
m_n
->
gmch_n
=
link_clock
*
nlanes
;
intel_reduce_ratio
(
&
m_n
->
gmch_m
,
&
m_n
->
gmch_n
);
m_n
->
link_m
=
pixel_clock
;
m_n
->
link_n
=
link_clock
;
intel_reduce_ratio
(
&
m_n
->
link_m
,
&
m_n
->
link_n
);
}
void
intel_dp_set_m_n
(
struct
drm_crtc
*
crtc
,
struct
drm_display_mode
*
mode
,
struct
drm_display_mode
*
adjusted_mode
)
{
struct
drm_device
*
dev
=
crtc
->
dev
;
struct
drm_mode_config
*
mode_config
=
&
dev
->
mode_config
;
struct
drm_connector
*
connector
;
struct
drm_i915_private
*
dev_priv
=
dev
->
dev_private
;
struct
intel_crtc
*
intel_crtc
=
to_intel_crtc
(
crtc
);
int
lane_count
=
4
;
struct
intel_dp_m_n
m_n
;
/*
* Find the lane count in the intel_output private
*/
list_for_each_entry
(
connector
,
&
mode_config
->
connector_list
,
head
)
{
struct
intel_output
*
intel_output
=
to_intel_output
(
connector
);
struct
intel_dp_priv
*
dp_priv
=
intel_output
->
dev_priv
;
if
(
!
connector
->
encoder
||
connector
->
encoder
->
crtc
!=
crtc
)
continue
;
if
(
intel_output
->
type
==
INTEL_OUTPUT_DISPLAYPORT
)
{
lane_count
=
dp_priv
->
lane_count
;
break
;
}
}
/*
* Compute the GMCH and Link ratios. The '3' here is
* the number of bytes_per_pixel post-LUT, which we always
* set up for 8-bits of R/G/B, or 3 bytes total.
*/
intel_dp_compute_m_n
(
3
,
lane_count
,
mode
->
clock
,
adjusted_mode
->
clock
,
&
m_n
);
if
(
intel_crtc
->
pipe
==
0
)
{
I915_WRITE
(
PIPEA_GMCH_DATA_M
,
((
m_n
.
tu
-
1
)
<<
PIPE_GMCH_DATA_M_TU_SIZE_SHIFT
)
|
m_n
.
gmch_m
);
I915_WRITE
(
PIPEA_GMCH_DATA_N
,
m_n
.
gmch_n
);
I915_WRITE
(
PIPEA_DP_LINK_M
,
m_n
.
link_m
);
I915_WRITE
(
PIPEA_DP_LINK_N
,
m_n
.
link_n
);
}
else
{
I915_WRITE
(
PIPEB_GMCH_DATA_M
,
((
m_n
.
tu
-
1
)
<<
PIPE_GMCH_DATA_M_TU_SIZE_SHIFT
)
|
m_n
.
gmch_m
);
I915_WRITE
(
PIPEB_GMCH_DATA_N
,
m_n
.
gmch_n
);
I915_WRITE
(
PIPEB_DP_LINK_M
,
m_n
.
link_m
);
I915_WRITE
(
PIPEB_DP_LINK_N
,
m_n
.
link_n
);
}
}
static
void
intel_dp_mode_set
(
struct
drm_encoder
*
encoder
,
struct
drm_display_mode
*
mode
,
struct
drm_display_mode
*
adjusted_mode
)
{
struct
intel_output
*
intel_output
=
enc_to_intel_output
(
encoder
);
struct
intel_dp_priv
*
dp_priv
=
intel_output
->
dev_priv
;
struct
drm_crtc
*
crtc
=
intel_output
->
enc
.
crtc
;
struct
intel_crtc
*
intel_crtc
=
to_intel_crtc
(
crtc
);
dp_priv
->
DP
=
(
DP_LINK_TRAIN_OFF
|
DP_VOLTAGE_0_4
|
DP_PRE_EMPHASIS_0
|
DP_SYNC_VS_HIGH
|
DP_SYNC_HS_HIGH
);
switch
(
dp_priv
->
lane_count
)
{
case
1
:
dp_priv
->
DP
|=
DP_PORT_WIDTH_1
;
break
;
case
2
:
dp_priv
->
DP
|=
DP_PORT_WIDTH_2
;
break
;
case
4
:
dp_priv
->
DP
|=
DP_PORT_WIDTH_4
;
break
;
}
if
(
dp_priv
->
has_audio
)
dp_priv
->
DP
|=
DP_AUDIO_OUTPUT_ENABLE
;
memset
(
dp_priv
->
link_configuration
,
0
,
DP_LINK_CONFIGURATION_SIZE
);
dp_priv
->
link_configuration
[
0
]
=
dp_priv
->
link_bw
;
dp_priv
->
link_configuration
[
1
]
=
dp_priv
->
lane_count
;
/*
* Check for DPCD version > 1.1,
* enable enahanced frame stuff in that case
*/
if
(
dp_priv
->
dpcd
[
0
]
>=
0x11
)
{
dp_priv
->
link_configuration
[
1
]
|=
DP_LANE_COUNT_ENHANCED_FRAME_EN
;
dp_priv
->
DP
|=
DP_ENHANCED_FRAMING
;
}
if
(
intel_crtc
->
pipe
==
1
)
dp_priv
->
DP
|=
DP_PIPEB_SELECT
;
}
static
void
intel_dp_dpms
(
struct
drm_encoder
*
encoder
,
int
mode
)
{
struct
intel_output
*
intel_output
=
enc_to_intel_output
(
encoder
);
struct
intel_dp_priv
*
dp_priv
=
intel_output
->
dev_priv
;
struct
drm_device
*
dev
=
intel_output
->
base
.
dev
;
struct
drm_i915_private
*
dev_priv
=
dev
->
dev_private
;
uint32_t
dp_reg
=
I915_READ
(
dp_priv
->
output_reg
);
if
(
mode
!=
DRM_MODE_DPMS_ON
)
{
if
(
dp_reg
&
DP_PORT_EN
)
intel_dp_link_down
(
intel_output
,
dp_priv
->
DP
);
}
else
{
if
(
!
(
dp_reg
&
DP_PORT_EN
))
intel_dp_link_train
(
intel_output
,
dp_priv
->
DP
,
dp_priv
->
link_configuration
);
}
dp_priv
->
dpms_mode
=
mode
;
}
/*
* Fetch AUX CH registers 0x202 - 0x207 which contain
* link status information
*/
static
bool
intel_dp_get_link_status
(
struct
intel_output
*
intel_output
,
uint8_t
link_status
[
DP_LINK_STATUS_SIZE
])
{
int
ret
;
ret
=
intel_dp_aux_native_read
(
intel_output
,
DP_LANE0_1_STATUS
,
link_status
,
DP_LINK_STATUS_SIZE
);
if
(
ret
!=
DP_LINK_STATUS_SIZE
)
return
false
;
return
true
;
}
static
uint8_t
intel_dp_link_status
(
uint8_t
link_status
[
DP_LINK_STATUS_SIZE
],
int
r
)
{
return
link_status
[
r
-
DP_LANE0_1_STATUS
];
}
static
void
intel_dp_save
(
struct
drm_connector
*
connector
)
{
struct
intel_output
*
intel_output
=
to_intel_output
(
connector
);
struct
drm_device
*
dev
=
intel_output
->
base
.
dev
;
struct
drm_i915_private
*
dev_priv
=
dev
->
dev_private
;
struct
intel_dp_priv
*
dp_priv
=
intel_output
->
dev_priv
;
dp_priv
->
save_DP
=
I915_READ
(
dp_priv
->
output_reg
);
intel_dp_aux_native_read
(
intel_output
,
DP_LINK_BW_SET
,
dp_priv
->
save_link_configuration
,
sizeof
(
dp_priv
->
save_link_configuration
));
}
static
uint8_t
intel_get_adjust_request_voltage
(
uint8_t
link_status
[
DP_LINK_STATUS_SIZE
],
int
lane
)
{
int
i
=
DP_ADJUST_REQUEST_LANE0_1
+
(
lane
>>
1
);
int
s
=
((
lane
&
1
)
?
DP_ADJUST_VOLTAGE_SWING_LANE1_SHIFT
:
DP_ADJUST_VOLTAGE_SWING_LANE0_SHIFT
);
uint8_t
l
=
intel_dp_link_status
(
link_status
,
i
);
return
((
l
>>
s
)
&
3
)
<<
DP_TRAIN_VOLTAGE_SWING_SHIFT
;
}
static
uint8_t
intel_get_adjust_request_pre_emphasis
(
uint8_t
link_status
[
DP_LINK_STATUS_SIZE
],
int
lane
)
{
int
i
=
DP_ADJUST_REQUEST_LANE0_1
+
(
lane
>>
1
);
int
s
=
((
lane
&
1
)
?
DP_ADJUST_PRE_EMPHASIS_LANE1_SHIFT
:
DP_ADJUST_PRE_EMPHASIS_LANE0_SHIFT
);
uint8_t
l
=
intel_dp_link_status
(
link_status
,
i
);
return
((
l
>>
s
)
&
3
)
<<
DP_TRAIN_PRE_EMPHASIS_SHIFT
;
}
#if 0
static char *voltage_names[] = {
"0.4V", "0.6V", "0.8V", "1.2V"
};
static char *pre_emph_names[] = {
"0dB", "3.5dB", "6dB", "9.5dB"
};
static char *link_train_names[] = {
"pattern 1", "pattern 2", "idle", "off"
};
#endif
/*
* These are source-specific values; current Intel hardware supports
* a maximum voltage of 800mV and a maximum pre-emphasis of 6dB
*/
#define I830_DP_VOLTAGE_MAX DP_TRAIN_VOLTAGE_SWING_800
static
uint8_t
intel_dp_pre_emphasis_max
(
uint8_t
voltage_swing
)
{
switch
(
voltage_swing
&
DP_TRAIN_VOLTAGE_SWING_MASK
)
{
case
DP_TRAIN_VOLTAGE_SWING_400
:
return
DP_TRAIN_PRE_EMPHASIS_6
;
case
DP_TRAIN_VOLTAGE_SWING_600
:
return
DP_TRAIN_PRE_EMPHASIS_6
;
case
DP_TRAIN_VOLTAGE_SWING_800
:
return
DP_TRAIN_PRE_EMPHASIS_3_5
;
case
DP_TRAIN_VOLTAGE_SWING_1200
:
default:
return
DP_TRAIN_PRE_EMPHASIS_0
;
}
}
static
void
intel_get_adjust_train
(
struct
intel_output
*
intel_output
,
uint8_t
link_status
[
DP_LINK_STATUS_SIZE
],
int
lane_count
,
uint8_t
train_set
[
4
])
{
uint8_t
v
=
0
;
uint8_t
p
=
0
;
int
lane
;
for
(
lane
=
0
;
lane
<
lane_count
;
lane
++
)
{
uint8_t
this_v
=
intel_get_adjust_request_voltage
(
link_status
,
lane
);
uint8_t
this_p
=
intel_get_adjust_request_pre_emphasis
(
link_status
,
lane
);
if
(
this_v
>
v
)
v
=
this_v
;
if
(
this_p
>
p
)
p
=
this_p
;
}
if
(
v
>=
I830_DP_VOLTAGE_MAX
)
v
=
I830_DP_VOLTAGE_MAX
|
DP_TRAIN_MAX_SWING_REACHED
;
if
(
p
>=
intel_dp_pre_emphasis_max
(
v
))
p
=
intel_dp_pre_emphasis_max
(
v
)
|
DP_TRAIN_MAX_PRE_EMPHASIS_REACHED
;
for
(
lane
=
0
;
lane
<
4
;
lane
++
)
train_set
[
lane
]
=
v
|
p
;
}
static
uint32_t
intel_dp_signal_levels
(
uint8_t
train_set
,
int
lane_count
)
{
uint32_t
signal_levels
=
0
;
switch
(
train_set
&
DP_TRAIN_VOLTAGE_SWING_MASK
)
{
case
DP_TRAIN_VOLTAGE_SWING_400
:
default:
signal_levels
|=
DP_VOLTAGE_0_4
;
break
;
case
DP_TRAIN_VOLTAGE_SWING_600
:
signal_levels
|=
DP_VOLTAGE_0_6
;
break
;
case
DP_TRAIN_VOLTAGE_SWING_800
:
signal_levels
|=
DP_VOLTAGE_0_8
;
break
;
case
DP_TRAIN_VOLTAGE_SWING_1200
:
signal_levels
|=
DP_VOLTAGE_1_2
;
break
;
}
switch
(
train_set
&
DP_TRAIN_PRE_EMPHASIS_MASK
)
{
case
DP_TRAIN_PRE_EMPHASIS_0
:
default:
signal_levels
|=
DP_PRE_EMPHASIS_0
;
break
;
case
DP_TRAIN_PRE_EMPHASIS_3_5
:
signal_levels
|=
DP_PRE_EMPHASIS_3_5
;
break
;
case
DP_TRAIN_PRE_EMPHASIS_6
:
signal_levels
|=
DP_PRE_EMPHASIS_6
;
break
;
case
DP_TRAIN_PRE_EMPHASIS_9_5
:
signal_levels
|=
DP_PRE_EMPHASIS_9_5
;
break
;
}
return
signal_levels
;
}
static
uint8_t
intel_get_lane_status
(
uint8_t
link_status
[
DP_LINK_STATUS_SIZE
],
int
lane
)
{
int
i
=
DP_LANE0_1_STATUS
+
(
lane
>>
1
);
int
s
=
(
lane
&
1
)
*
4
;
uint8_t
l
=
intel_dp_link_status
(
link_status
,
i
);
return
(
l
>>
s
)
&
0xf
;
}
/* Check for clock recovery is done on all channels */
static
bool
intel_clock_recovery_ok
(
uint8_t
link_status
[
DP_LINK_STATUS_SIZE
],
int
lane_count
)
{
int
lane
;
uint8_t
lane_status
;
for
(
lane
=
0
;
lane
<
lane_count
;
lane
++
)
{
lane_status
=
intel_get_lane_status
(
link_status
,
lane
);
if
((
lane_status
&
DP_LANE_CR_DONE
)
==
0
)
return
false
;
}
return
true
;
}
/* Check to see if channel eq is done on all channels */
#define CHANNEL_EQ_BITS (DP_LANE_CR_DONE|\
DP_LANE_CHANNEL_EQ_DONE|\
DP_LANE_SYMBOL_LOCKED)
static
bool
intel_channel_eq_ok
(
uint8_t
link_status
[
DP_LINK_STATUS_SIZE
],
int
lane_count
)
{
uint8_t
lane_align
;
uint8_t
lane_status
;
int
lane
;
lane_align
=
intel_dp_link_status
(
link_status
,
DP_LANE_ALIGN_STATUS_UPDATED
);
if
((
lane_align
&
DP_INTERLANE_ALIGN_DONE
)
==
0
)
return
false
;
for
(
lane
=
0
;
lane
<
lane_count
;
lane
++
)
{
lane_status
=
intel_get_lane_status
(
link_status
,
lane
);
if
((
lane_status
&
CHANNEL_EQ_BITS
)
!=
CHANNEL_EQ_BITS
)
return
false
;
}
return
true
;
}
static
bool
intel_dp_set_link_train
(
struct
intel_output
*
intel_output
,
uint32_t
dp_reg_value
,
uint8_t
dp_train_pat
,
uint8_t
train_set
[
4
],
bool
first
)
{
struct
drm_device
*
dev
=
intel_output
->
base
.
dev
;
struct
drm_i915_private
*
dev_priv
=
dev
->
dev_private
;
struct
intel_dp_priv
*
dp_priv
=
intel_output
->
dev_priv
;
int
ret
;
I915_WRITE
(
dp_priv
->
output_reg
,
dp_reg_value
);
POSTING_READ
(
dp_priv
->
output_reg
);
if
(
first
)
intel_wait_for_vblank
(
dev
);
intel_dp_aux_native_write_1
(
intel_output
,
DP_TRAINING_PATTERN_SET
,
dp_train_pat
);
ret
=
intel_dp_aux_native_write
(
intel_output
,
DP_TRAINING_LANE0_SET
,
train_set
,
4
);
if
(
ret
!=
4
)
return
false
;
return
true
;
}
static
void
intel_dp_link_train
(
struct
intel_output
*
intel_output
,
uint32_t
DP
,
uint8_t
link_configuration
[
DP_LINK_CONFIGURATION_SIZE
])
{
struct
drm_device
*
dev
=
intel_output
->
base
.
dev
;
struct
drm_i915_private
*
dev_priv
=
dev
->
dev_private
;
struct
intel_dp_priv
*
dp_priv
=
intel_output
->
dev_priv
;
uint8_t
train_set
[
4
];
uint8_t
link_status
[
DP_LINK_STATUS_SIZE
];
int
i
;
uint8_t
voltage
;
bool
clock_recovery
=
false
;
bool
channel_eq
=
false
;
bool
first
=
true
;
int
tries
;
/* Write the link configuration data */
intel_dp_aux_native_write
(
intel_output
,
0x100
,
link_configuration
,
DP_LINK_CONFIGURATION_SIZE
);
DP
|=
DP_PORT_EN
;
DP
&=
~
DP_LINK_TRAIN_MASK
;
memset
(
train_set
,
0
,
4
);
voltage
=
0xff
;
tries
=
0
;
clock_recovery
=
false
;
for
(;;)
{
/* Use train_set[0] to set the voltage and pre emphasis values */
uint32_t
signal_levels
=
intel_dp_signal_levels
(
train_set
[
0
],
dp_priv
->
lane_count
);
DP
=
(
DP
&
~
(
DP_VOLTAGE_MASK
|
DP_PRE_EMPHASIS_MASK
))
|
signal_levels
;
if
(
!
intel_dp_set_link_train
(
intel_output
,
DP
|
DP_LINK_TRAIN_PAT_1
,
DP_TRAINING_PATTERN_1
,
train_set
,
first
))
break
;
first
=
false
;
/* Set training pattern 1 */
udelay
(
100
);
if
(
!
intel_dp_get_link_status
(
intel_output
,
link_status
))
break
;
if
(
intel_clock_recovery_ok
(
link_status
,
dp_priv
->
lane_count
))
{
clock_recovery
=
true
;
break
;
}
/* Check to see if we've tried the max voltage */
for
(
i
=
0
;
i
<
dp_priv
->
lane_count
;
i
++
)
if
((
train_set
[
i
]
&
DP_TRAIN_MAX_SWING_REACHED
)
==
0
)
break
;
if
(
i
==
dp_priv
->
lane_count
)
break
;
/* Check to see if we've tried the same voltage 5 times */
if
((
train_set
[
0
]
&
DP_TRAIN_VOLTAGE_SWING_MASK
)
==
voltage
)
{
++
tries
;
if
(
tries
==
5
)
break
;
}
else
tries
=
0
;
voltage
=
train_set
[
0
]
&
DP_TRAIN_VOLTAGE_SWING_MASK
;
/* Compute new train_set as requested by target */
intel_get_adjust_train
(
intel_output
,
link_status
,
dp_priv
->
lane_count
,
train_set
);
}
/* channel equalization */
tries
=
0
;
channel_eq
=
false
;
for
(;;)
{
/* Use train_set[0] to set the voltage and pre emphasis values */
uint32_t
signal_levels
=
intel_dp_signal_levels
(
train_set
[
0
],
dp_priv
->
lane_count
);
DP
=
(
DP
&
~
(
DP_VOLTAGE_MASK
|
DP_PRE_EMPHASIS_MASK
))
|
signal_levels
;
/* channel eq pattern */
if
(
!
intel_dp_set_link_train
(
intel_output
,
DP
|
DP_LINK_TRAIN_PAT_2
,
DP_TRAINING_PATTERN_2
,
train_set
,
false
))
break
;
udelay
(
400
);
if
(
!
intel_dp_get_link_status
(
intel_output
,
link_status
))
break
;
if
(
intel_channel_eq_ok
(
link_status
,
dp_priv
->
lane_count
))
{
channel_eq
=
true
;
break
;
}
/* Try 5 times */
if
(
tries
>
5
)
break
;
/* Compute new train_set as requested by target */
intel_get_adjust_train
(
intel_output
,
link_status
,
dp_priv
->
lane_count
,
train_set
);
++
tries
;
}
I915_WRITE
(
dp_priv
->
output_reg
,
DP
|
DP_LINK_TRAIN_OFF
);
POSTING_READ
(
dp_priv
->
output_reg
);
intel_dp_aux_native_write_1
(
intel_output
,
DP_TRAINING_PATTERN_SET
,
DP_TRAINING_PATTERN_DISABLE
);
}
static
void
intel_dp_link_down
(
struct
intel_output
*
intel_output
,
uint32_t
DP
)
{
struct
drm_device
*
dev
=
intel_output
->
base
.
dev
;
struct
drm_i915_private
*
dev_priv
=
dev
->
dev_private
;
struct
intel_dp_priv
*
dp_priv
=
intel_output
->
dev_priv
;
I915_WRITE
(
dp_priv
->
output_reg
,
DP
&
~
DP_PORT_EN
);
POSTING_READ
(
dp_priv
->
output_reg
);
}
static
void
intel_dp_restore
(
struct
drm_connector
*
connector
)
{
struct
intel_output
*
intel_output
=
to_intel_output
(
connector
);
struct
intel_dp_priv
*
dp_priv
=
intel_output
->
dev_priv
;
if
(
dp_priv
->
save_DP
&
DP_PORT_EN
)
intel_dp_link_train
(
intel_output
,
dp_priv
->
save_DP
,
dp_priv
->
save_link_configuration
);
else
intel_dp_link_down
(
intel_output
,
dp_priv
->
save_DP
);
}
/*
* According to DP spec
* 5.1.2:
* 1. Read DPCD
* 2. Configure link according to Receiver Capabilities
* 3. Use Link Training from 2.5.3.3 and 3.5.1.3
* 4. Check link status on receipt of hot-plug interrupt
*/
static
void
intel_dp_check_link_status
(
struct
intel_output
*
intel_output
)
{
struct
intel_dp_priv
*
dp_priv
=
intel_output
->
dev_priv
;
uint8_t
link_status
[
DP_LINK_STATUS_SIZE
];
if
(
!
intel_output
->
enc
.
crtc
)
return
;
if
(
!
intel_dp_get_link_status
(
intel_output
,
link_status
))
{
intel_dp_link_down
(
intel_output
,
dp_priv
->
DP
);
return
;
}
if
(
!
intel_channel_eq_ok
(
link_status
,
dp_priv
->
lane_count
))
intel_dp_link_train
(
intel_output
,
dp_priv
->
DP
,
dp_priv
->
link_configuration
);
}
/**
* Uses CRT_HOTPLUG_EN and CRT_HOTPLUG_STAT to detect DP connection.
*
* \return true if DP port is connected.
* \return false if DP port is disconnected.
*/
static
enum
drm_connector_status
intel_dp_detect
(
struct
drm_connector
*
connector
)
{
struct
intel_output
*
intel_output
=
to_intel_output
(
connector
);
struct
drm_device
*
dev
=
intel_output
->
base
.
dev
;
struct
drm_i915_private
*
dev_priv
=
dev
->
dev_private
;
struct
intel_dp_priv
*
dp_priv
=
intel_output
->
dev_priv
;
uint32_t
temp
,
bit
;
enum
drm_connector_status
status
;
dp_priv
->
has_audio
=
false
;
temp
=
I915_READ
(
PORT_HOTPLUG_EN
);
I915_WRITE
(
PORT_HOTPLUG_EN
,
temp
|
DPB_HOTPLUG_INT_EN
|
DPC_HOTPLUG_INT_EN
|
DPD_HOTPLUG_INT_EN
);
POSTING_READ
(
PORT_HOTPLUG_EN
);
switch
(
dp_priv
->
output_reg
)
{
case
DP_B
:
bit
=
DPB_HOTPLUG_INT_STATUS
;
break
;
case
DP_C
:
bit
=
DPC_HOTPLUG_INT_STATUS
;
break
;
case
DP_D
:
bit
=
DPD_HOTPLUG_INT_STATUS
;
break
;
default:
return
connector_status_unknown
;
}
temp
=
I915_READ
(
PORT_HOTPLUG_STAT
);
if
((
temp
&
bit
)
==
0
)
return
connector_status_disconnected
;
status
=
connector_status_disconnected
;
if
(
intel_dp_aux_native_read
(
intel_output
,
0x000
,
dp_priv
->
dpcd
,
sizeof
(
dp_priv
->
dpcd
))
==
sizeof
(
dp_priv
->
dpcd
))
{
if
(
dp_priv
->
dpcd
[
0
]
!=
0
)
status
=
connector_status_connected
;
}
return
status
;
}
static
int
intel_dp_get_modes
(
struct
drm_connector
*
connector
)
{
struct
intel_output
*
intel_output
=
to_intel_output
(
connector
);
/* We should parse the EDID data and find out if it has an audio sink
*/
return
intel_ddc_get_modes
(
intel_output
);
}
static
void
intel_dp_destroy
(
struct
drm_connector
*
connector
)
{
struct
intel_output
*
intel_output
=
to_intel_output
(
connector
);
if
(
intel_output
->
i2c_bus
)
intel_i2c_destroy
(
intel_output
->
i2c_bus
);
drm_sysfs_connector_remove
(
connector
);
drm_connector_cleanup
(
connector
);
kfree
(
intel_output
);
}
static
const
struct
drm_encoder_helper_funcs
intel_dp_helper_funcs
=
{
.
dpms
=
intel_dp_dpms
,
.
mode_fixup
=
intel_dp_mode_fixup
,
.
prepare
=
intel_encoder_prepare
,
.
mode_set
=
intel_dp_mode_set
,
.
commit
=
intel_encoder_commit
,
};
static
const
struct
drm_connector_funcs
intel_dp_connector_funcs
=
{
.
dpms
=
drm_helper_connector_dpms
,
.
save
=
intel_dp_save
,
.
restore
=
intel_dp_restore
,
.
detect
=
intel_dp_detect
,
.
fill_modes
=
drm_helper_probe_single_connector_modes
,
.
destroy
=
intel_dp_destroy
,
};
static
const
struct
drm_connector_helper_funcs
intel_dp_connector_helper_funcs
=
{
.
get_modes
=
intel_dp_get_modes
,
.
mode_valid
=
intel_dp_mode_valid
,
.
best_encoder
=
intel_best_encoder
,
};
static
void
intel_dp_enc_destroy
(
struct
drm_encoder
*
encoder
)
{
drm_encoder_cleanup
(
encoder
);
}
static
const
struct
drm_encoder_funcs
intel_dp_enc_funcs
=
{
.
destroy
=
intel_dp_enc_destroy
,
};
void
intel_dp_hot_plug
(
struct
intel_output
*
intel_output
)
{
struct
intel_dp_priv
*
dp_priv
=
intel_output
->
dev_priv
;
if
(
dp_priv
->
dpms_mode
==
DRM_MODE_DPMS_ON
)
intel_dp_check_link_status
(
intel_output
);
}
void
intel_dp_init
(
struct
drm_device
*
dev
,
int
output_reg
)
{
struct
drm_i915_private
*
dev_priv
=
dev
->
dev_private
;
struct
drm_connector
*
connector
;
struct
intel_output
*
intel_output
;
struct
intel_dp_priv
*
dp_priv
;
intel_output
=
kcalloc
(
sizeof
(
struct
intel_output
)
+
sizeof
(
struct
intel_dp_priv
),
1
,
GFP_KERNEL
);
if
(
!
intel_output
)
return
;
dp_priv
=
(
struct
intel_dp_priv
*
)(
intel_output
+
1
);
connector
=
&
intel_output
->
base
;
drm_connector_init
(
dev
,
connector
,
&
intel_dp_connector_funcs
,
DRM_MODE_CONNECTOR_DisplayPort
);
drm_connector_helper_add
(
connector
,
&
intel_dp_connector_helper_funcs
);
intel_output
->
type
=
INTEL_OUTPUT_DISPLAYPORT
;
connector
->
interlace_allowed
=
true
;
connector
->
doublescan_allowed
=
0
;
dp_priv
->
intel_output
=
intel_output
;
dp_priv
->
output_reg
=
output_reg
;
dp_priv
->
has_audio
=
false
;
dp_priv
->
dpms_mode
=
DRM_MODE_DPMS_ON
;
intel_output
->
dev_priv
=
dp_priv
;
drm_encoder_init
(
dev
,
&
intel_output
->
enc
,
&
intel_dp_enc_funcs
,
DRM_MODE_ENCODER_TMDS
);
drm_encoder_helper_add
(
&
intel_output
->
enc
,
&
intel_dp_helper_funcs
);
drm_mode_connector_attach_encoder
(
&
intel_output
->
base
,
&
intel_output
->
enc
);
drm_sysfs_connector_add
(
connector
);
/* Set up the DDC bus. */
intel_dp_i2c_init
(
intel_output
,
(
output_reg
==
DP_B
)
?
"DPDDC-B"
:
(
output_reg
==
DP_C
)
?
"DPDDC-C"
:
"DPDDC-D"
);
intel_output
->
ddc_bus
=
&
dp_priv
->
adapter
;
intel_output
->
hot_plug
=
intel_dp_hot_plug
;
/* For G4X desktop chip, PEG_BAND_GAP_DATA 3:0 must first be written
* 0xd. Failure to do so will result in spurious interrupts being
* generated on the port when a cable is not attached.
*/
if
(
IS_G4X
(
dev
)
&&
!
IS_GM45
(
dev
))
{
u32
temp
=
I915_READ
(
PEG_BAND_GAP_DATA
);
I915_WRITE
(
PEG_BAND_GAP_DATA
,
(
temp
&
~
0xf
)
|
0xd
);
}
}
drivers/gpu/drm/i915/intel_dp.h
0 → 100644
View file @
be9f1c4f
/*
* Copyright © 2008 Keith Packard
*
* Permission to use, copy, modify, distribute, and sell this software and its
* documentation for any purpose is hereby granted without fee, provided that
* the above copyright notice appear in all copies and that both that copyright
* notice and this permission notice appear in supporting documentation, and
* that the name of the copyright holders not be used in advertising or
* publicity pertaining to distribution of the software without specific,
* written prior permission. The copyright holders make no representations
* about the suitability of this software for any purpose. It is provided "as
* is" without express or implied warranty.
*
* THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
* INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
* EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY SPECIAL, INDIRECT OR
* CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
* DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
* TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
* OF THIS SOFTWARE.
*/
#ifndef _INTEL_DP_H_
#define _INTEL_DP_H_
/* From the VESA DisplayPort spec */
#define AUX_NATIVE_WRITE 0x8
#define AUX_NATIVE_READ 0x9
#define AUX_I2C_WRITE 0x0
#define AUX_I2C_READ 0x1
#define AUX_I2C_STATUS 0x2
#define AUX_I2C_MOT 0x4
#define AUX_NATIVE_REPLY_ACK (0x0 << 4)
#define AUX_NATIVE_REPLY_NACK (0x1 << 4)
#define AUX_NATIVE_REPLY_DEFER (0x2 << 4)
#define AUX_NATIVE_REPLY_MASK (0x3 << 4)
#define AUX_I2C_REPLY_ACK (0x0 << 6)
#define AUX_I2C_REPLY_NACK (0x1 << 6)
#define AUX_I2C_REPLY_DEFER (0x2 << 6)
#define AUX_I2C_REPLY_MASK (0x3 << 6)
/* AUX CH addresses */
#define DP_LINK_BW_SET 0x100
# define DP_LINK_BW_1_62 0x06
# define DP_LINK_BW_2_7 0x0a
#define DP_LANE_COUNT_SET 0x101
# define DP_LANE_COUNT_MASK 0x0f
# define DP_LANE_COUNT_ENHANCED_FRAME_EN (1 << 7)
#define DP_TRAINING_PATTERN_SET 0x102
# define DP_TRAINING_PATTERN_DISABLE 0
# define DP_TRAINING_PATTERN_1 1
# define DP_TRAINING_PATTERN_2 2
# define DP_TRAINING_PATTERN_MASK 0x3
# define DP_LINK_QUAL_PATTERN_DISABLE (0 << 2)
# define DP_LINK_QUAL_PATTERN_D10_2 (1 << 2)
# define DP_LINK_QUAL_PATTERN_ERROR_RATE (2 << 2)
# define DP_LINK_QUAL_PATTERN_PRBS7 (3 << 2)
# define DP_LINK_QUAL_PATTERN_MASK (3 << 2)
# define DP_RECOVERED_CLOCK_OUT_EN (1 << 4)
# define DP_LINK_SCRAMBLING_DISABLE (1 << 5)
# define DP_SYMBOL_ERROR_COUNT_BOTH (0 << 6)
# define DP_SYMBOL_ERROR_COUNT_DISPARITY (1 << 6)
# define DP_SYMBOL_ERROR_COUNT_SYMBOL (2 << 6)
# define DP_SYMBOL_ERROR_COUNT_MASK (3 << 6)
#define DP_TRAINING_LANE0_SET 0x103
#define DP_TRAINING_LANE1_SET 0x104
#define DP_TRAINING_LANE2_SET 0x105
#define DP_TRAINING_LANE3_SET 0x106
# define DP_TRAIN_VOLTAGE_SWING_MASK 0x3
# define DP_TRAIN_VOLTAGE_SWING_SHIFT 0
# define DP_TRAIN_MAX_SWING_REACHED (1 << 2)
# define DP_TRAIN_VOLTAGE_SWING_400 (0 << 0)
# define DP_TRAIN_VOLTAGE_SWING_600 (1 << 0)
# define DP_TRAIN_VOLTAGE_SWING_800 (2 << 0)
# define DP_TRAIN_VOLTAGE_SWING_1200 (3 << 0)
# define DP_TRAIN_PRE_EMPHASIS_MASK (3 << 3)
# define DP_TRAIN_PRE_EMPHASIS_0 (0 << 3)
# define DP_TRAIN_PRE_EMPHASIS_3_5 (1 << 3)
# define DP_TRAIN_PRE_EMPHASIS_6 (2 << 3)
# define DP_TRAIN_PRE_EMPHASIS_9_5 (3 << 3)
# define DP_TRAIN_PRE_EMPHASIS_SHIFT 3
# define DP_TRAIN_MAX_PRE_EMPHASIS_REACHED (1 << 5)
#define DP_DOWNSPREAD_CTRL 0x107
# define DP_SPREAD_AMP_0_5 (1 << 4)
#define DP_MAIN_LINK_CHANNEL_CODING_SET 0x108
# define DP_SET_ANSI_8B10B (1 << 0)
#define DP_LANE0_1_STATUS 0x202
#define DP_LANE2_3_STATUS 0x203
# define DP_LANE_CR_DONE (1 << 0)
# define DP_LANE_CHANNEL_EQ_DONE (1 << 1)
# define DP_LANE_SYMBOL_LOCKED (1 << 2)
#define DP_LANE_ALIGN_STATUS_UPDATED 0x204
#define DP_INTERLANE_ALIGN_DONE (1 << 0)
#define DP_DOWNSTREAM_PORT_STATUS_CHANGED (1 << 6)
#define DP_LINK_STATUS_UPDATED (1 << 7)
#define DP_SINK_STATUS 0x205
#define DP_RECEIVE_PORT_0_STATUS (1 << 0)
#define DP_RECEIVE_PORT_1_STATUS (1 << 1)
#define DP_ADJUST_REQUEST_LANE0_1 0x206
#define DP_ADJUST_REQUEST_LANE2_3 0x207
#define DP_ADJUST_VOLTAGE_SWING_LANE0_MASK 0x03
#define DP_ADJUST_VOLTAGE_SWING_LANE0_SHIFT 0
#define DP_ADJUST_PRE_EMPHASIS_LANE0_MASK 0x0c
#define DP_ADJUST_PRE_EMPHASIS_LANE0_SHIFT 2
#define DP_ADJUST_VOLTAGE_SWING_LANE1_MASK 0x30
#define DP_ADJUST_VOLTAGE_SWING_LANE1_SHIFT 4
#define DP_ADJUST_PRE_EMPHASIS_LANE1_MASK 0xc0
#define DP_ADJUST_PRE_EMPHASIS_LANE1_SHIFT 6
struct
i2c_algo_dp_aux_data
{
bool
running
;
u16
address
;
int
(
*
aux_ch
)
(
struct
i2c_adapter
*
adapter
,
uint8_t
*
send
,
int
send_bytes
,
uint8_t
*
recv
,
int
recv_bytes
);
};
int
i2c_dp_aux_add_bus
(
struct
i2c_adapter
*
adapter
);
#endif
/* _INTEL_DP_H_ */
drivers/gpu/drm/i915/intel_dp_i2c.c
0 → 100644
View file @
be9f1c4f
/*
* Copyright © 2009 Keith Packard
*
* Permission to use, copy, modify, distribute, and sell this software and its
* documentation for any purpose is hereby granted without fee, provided that
* the above copyright notice appear in all copies and that both that copyright
* notice and this permission notice appear in supporting documentation, and
* that the name of the copyright holders not be used in advertising or
* publicity pertaining to distribution of the software without specific,
* written prior permission. The copyright holders make no representations
* about the suitability of this software for any purpose. It is provided "as
* is" without express or implied warranty.
*
* THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
* INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
* EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY SPECIAL, INDIRECT OR
* CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
* DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
* TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
* OF THIS SOFTWARE.
*/
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/delay.h>
#include <linux/slab.h>
#include <linux/init.h>
#include <linux/errno.h>
#include <linux/sched.h>
#include <linux/i2c.h>
#include "intel_dp.h"
/* Run a single AUX_CH I2C transaction, writing/reading data as necessary */
#define MODE_I2C_START 1
#define MODE_I2C_WRITE 2
#define MODE_I2C_READ 4
#define MODE_I2C_STOP 8
static
int
i2c_algo_dp_aux_transaction
(
struct
i2c_adapter
*
adapter
,
int
mode
,
uint8_t
write_byte
,
uint8_t
*
read_byte
)
{
struct
i2c_algo_dp_aux_data
*
algo_data
=
adapter
->
algo_data
;
uint16_t
address
=
algo_data
->
address
;
uint8_t
msg
[
5
];
uint8_t
reply
[
2
];
int
msg_bytes
;
int
reply_bytes
;
int
ret
;
/* Set up the command byte */
if
(
mode
&
MODE_I2C_READ
)
msg
[
0
]
=
AUX_I2C_READ
<<
4
;
else
msg
[
0
]
=
AUX_I2C_WRITE
<<
4
;
if
(
!
(
mode
&
MODE_I2C_STOP
))
msg
[
0
]
|=
AUX_I2C_MOT
<<
4
;
msg
[
1
]
=
address
>>
8
;
msg
[
2
]
=
address
;
switch
(
mode
)
{
case
MODE_I2C_WRITE
:
msg
[
3
]
=
0
;
msg
[
4
]
=
write_byte
;
msg_bytes
=
5
;
reply_bytes
=
1
;
break
;
case
MODE_I2C_READ
:
msg
[
3
]
=
0
;
msg_bytes
=
4
;
reply_bytes
=
2
;
break
;
default:
msg_bytes
=
3
;
reply_bytes
=
1
;
break
;
}
for
(;;)
{
ret
=
(
*
algo_data
->
aux_ch
)(
adapter
,
msg
,
msg_bytes
,
reply
,
reply_bytes
);
if
(
ret
<
0
)
{
printk
(
KERN_ERR
"aux_ch failed %d
\n
"
,
ret
);
return
ret
;
}
switch
(
reply
[
0
]
&
AUX_I2C_REPLY_MASK
)
{
case
AUX_I2C_REPLY_ACK
:
if
(
mode
==
MODE_I2C_READ
)
{
*
read_byte
=
reply
[
1
];
}
return
reply_bytes
-
1
;
case
AUX_I2C_REPLY_NACK
:
printk
(
KERN_ERR
"aux_ch nack
\n
"
);
return
-
EREMOTEIO
;
case
AUX_I2C_REPLY_DEFER
:
printk
(
KERN_ERR
"aux_ch defer
\n
"
);
udelay
(
100
);
break
;
default:
printk
(
KERN_ERR
"aux_ch invalid reply 0x%02x
\n
"
,
reply
[
0
]);
return
-
EREMOTEIO
;
}
}
}
/*
* I2C over AUX CH
*/
/*
* Send the address. If the I2C link is running, this 'restarts'
* the connection with the new address, this is used for doing
* a write followed by a read (as needed for DDC)
*/
static
int
i2c_algo_dp_aux_address
(
struct
i2c_adapter
*
adapter
,
u16
address
,
bool
reading
)
{
struct
i2c_algo_dp_aux_data
*
algo_data
=
adapter
->
algo_data
;
int
mode
=
MODE_I2C_START
;
int
ret
;
if
(
reading
)
mode
|=
MODE_I2C_READ
;
else
mode
|=
MODE_I2C_WRITE
;
algo_data
->
address
=
address
;
algo_data
->
running
=
true
;
ret
=
i2c_algo_dp_aux_transaction
(
adapter
,
mode
,
0
,
NULL
);
return
ret
;
}
/*
* Stop the I2C transaction. This closes out the link, sending
* a bare address packet with the MOT bit turned off
*/
static
void
i2c_algo_dp_aux_stop
(
struct
i2c_adapter
*
adapter
,
bool
reading
)
{
struct
i2c_algo_dp_aux_data
*
algo_data
=
adapter
->
algo_data
;
int
mode
=
MODE_I2C_STOP
;
if
(
reading
)
mode
|=
MODE_I2C_READ
;
else
mode
|=
MODE_I2C_WRITE
;
if
(
algo_data
->
running
)
{
(
void
)
i2c_algo_dp_aux_transaction
(
adapter
,
mode
,
0
,
NULL
);
algo_data
->
running
=
false
;
}
}
/*
* Write a single byte to the current I2C address, the
* the I2C link must be running or this returns -EIO
*/
static
int
i2c_algo_dp_aux_put_byte
(
struct
i2c_adapter
*
adapter
,
u8
byte
)
{
struct
i2c_algo_dp_aux_data
*
algo_data
=
adapter
->
algo_data
;
int
ret
;
if
(
!
algo_data
->
running
)
return
-
EIO
;
ret
=
i2c_algo_dp_aux_transaction
(
adapter
,
MODE_I2C_WRITE
,
byte
,
NULL
);
return
ret
;
}
/*
* Read a single byte from the current I2C address, the
* I2C link must be running or this returns -EIO
*/
static
int
i2c_algo_dp_aux_get_byte
(
struct
i2c_adapter
*
adapter
,
u8
*
byte_ret
)
{
struct
i2c_algo_dp_aux_data
*
algo_data
=
adapter
->
algo_data
;
int
ret
;
if
(
!
algo_data
->
running
)
return
-
EIO
;
ret
=
i2c_algo_dp_aux_transaction
(
adapter
,
MODE_I2C_READ
,
0
,
byte_ret
);
return
ret
;
}
static
int
i2c_algo_dp_aux_xfer
(
struct
i2c_adapter
*
adapter
,
struct
i2c_msg
*
msgs
,
int
num
)
{
int
ret
=
0
;
bool
reading
=
false
;
int
m
;
int
b
;
for
(
m
=
0
;
m
<
num
;
m
++
)
{
u16
len
=
msgs
[
m
].
len
;
u8
*
buf
=
msgs
[
m
].
buf
;
reading
=
(
msgs
[
m
].
flags
&
I2C_M_RD
)
!=
0
;
ret
=
i2c_algo_dp_aux_address
(
adapter
,
msgs
[
m
].
addr
,
reading
);
if
(
ret
<
0
)
break
;
if
(
reading
)
{
for
(
b
=
0
;
b
<
len
;
b
++
)
{
ret
=
i2c_algo_dp_aux_get_byte
(
adapter
,
&
buf
[
b
]);
if
(
ret
<
0
)
break
;
}
}
else
{
for
(
b
=
0
;
b
<
len
;
b
++
)
{
ret
=
i2c_algo_dp_aux_put_byte
(
adapter
,
buf
[
b
]);
if
(
ret
<
0
)
break
;
}
}
if
(
ret
<
0
)
break
;
}
if
(
ret
>=
0
)
ret
=
num
;
i2c_algo_dp_aux_stop
(
adapter
,
reading
);
printk
(
KERN_ERR
"dp_aux_xfer return %d
\n
"
,
ret
);
return
ret
;
}
static
u32
i2c_algo_dp_aux_functionality
(
struct
i2c_adapter
*
adapter
)
{
return
I2C_FUNC_I2C
|
I2C_FUNC_SMBUS_EMUL
|
I2C_FUNC_SMBUS_READ_BLOCK_DATA
|
I2C_FUNC_SMBUS_BLOCK_PROC_CALL
|
I2C_FUNC_10BIT_ADDR
;
}
static
const
struct
i2c_algorithm
i2c_dp_aux_algo
=
{
.
master_xfer
=
i2c_algo_dp_aux_xfer
,
.
functionality
=
i2c_algo_dp_aux_functionality
,
};
static
void
i2c_dp_aux_reset_bus
(
struct
i2c_adapter
*
adapter
)
{
(
void
)
i2c_algo_dp_aux_address
(
adapter
,
0
,
false
);
(
void
)
i2c_algo_dp_aux_stop
(
adapter
,
false
);
}
static
int
i2c_dp_aux_prepare_bus
(
struct
i2c_adapter
*
adapter
)
{
adapter
->
algo
=
&
i2c_dp_aux_algo
;
adapter
->
retries
=
3
;
i2c_dp_aux_reset_bus
(
adapter
);
return
0
;
}
int
i2c_dp_aux_add_bus
(
struct
i2c_adapter
*
adapter
)
{
int
error
;
error
=
i2c_dp_aux_prepare_bus
(
adapter
);
if
(
error
)
return
error
;
error
=
i2c_add_adapter
(
adapter
);
return
error
;
}
EXPORT_SYMBOL
(
i2c_dp_aux_add_bus
);
drivers/gpu/drm/i915/intel_drv.h
View file @
be9f1c4f
...
...
@@ -54,6 +54,7 @@
#define INTEL_OUTPUT_LVDS 4
#define INTEL_OUTPUT_TVOUT 5
#define INTEL_OUTPUT_HDMI 6
#define INTEL_OUTPUT_DISPLAYPORT 7
#define INTEL_DVO_CHIP_NONE 0
#define INTEL_DVO_CHIP_LVDS 1
...
...
@@ -65,7 +66,6 @@ struct intel_i2c_chan {
u32
reg
;
/* GPIO reg */
struct
i2c_adapter
adapter
;
struct
i2c_algo_bit_data
algo
;
u8
slave_addr
;
};
struct
intel_framebuffer
{
...
...
@@ -79,11 +79,12 @@ struct intel_output {
struct
drm_encoder
enc
;
int
type
;
struct
i
ntel_i2c_chan
*
i2c_bus
;
/* for control functions */
struct
i
ntel_i2c_chan
*
ddc_bus
;
/* for DDC only stuff */
struct
i
2c_adapter
*
i2c_bus
;
struct
i
2c_adapter
*
ddc_bus
;
bool
load_detect_temp
;
bool
needs_tv_clock
;
void
*
dev_priv
;
void
(
*
hot_plug
)(
struct
intel_output
*
);
};
struct
intel_crtc
{
...
...
@@ -104,9 +105,9 @@ struct intel_crtc {
#define enc_to_intel_output(x) container_of(x, struct intel_output, enc)
#define to_intel_framebuffer(x) container_of(x, struct intel_framebuffer, base)
struct
i
ntel_i2c_chan
*
intel_i2c_create
(
struct
drm_device
*
dev
,
const
u32
reg
,
const
char
*
name
);
void
intel_i2c_destroy
(
struct
i
ntel_i2c_chan
*
chan
);
struct
i
2c_adapter
*
intel_i2c_create
(
struct
drm_device
*
dev
,
const
u32
reg
,
const
char
*
name
);
void
intel_i2c_destroy
(
struct
i
2c_adapter
*
adapter
);
int
intel_ddc_get_modes
(
struct
intel_output
*
intel_output
);
extern
bool
intel_ddc_probe
(
struct
intel_output
*
intel_output
);
void
intel_i2c_quirk_set
(
struct
drm_device
*
dev
,
bool
enable
);
...
...
@@ -116,6 +117,10 @@ extern bool intel_sdvo_init(struct drm_device *dev, int output_device);
extern
void
intel_dvo_init
(
struct
drm_device
*
dev
);
extern
void
intel_tv_init
(
struct
drm_device
*
dev
);
extern
void
intel_lvds_init
(
struct
drm_device
*
dev
);
extern
void
intel_dp_init
(
struct
drm_device
*
dev
,
int
dp_reg
);
void
intel_dp_set_m_n
(
struct
drm_crtc
*
crtc
,
struct
drm_display_mode
*
mode
,
struct
drm_display_mode
*
adjusted_mode
);
extern
void
intel_crtc_load_lut
(
struct
drm_crtc
*
crtc
);
extern
void
intel_encoder_prepare
(
struct
drm_encoder
*
encoder
);
...
...
drivers/gpu/drm/i915/intel_dvo.c
View file @
be9f1c4f
...
...
@@ -384,10 +384,9 @@ void intel_dvo_init(struct drm_device *dev)
{
struct
intel_output
*
intel_output
;
struct
intel_dvo_device
*
dvo
;
struct
i
ntel_i2c_chan
*
i2cbus
=
NULL
;
struct
i
2c_adapter
*
i2cbus
=
NULL
;
int
ret
=
0
;
int
i
;
int
gpio_inited
=
0
;
int
encoder_type
=
DRM_MODE_ENCODER_NONE
;
intel_output
=
kzalloc
(
sizeof
(
struct
intel_output
),
GFP_KERNEL
);
if
(
!
intel_output
)
...
...
@@ -420,14 +419,11 @@ void intel_dvo_init(struct drm_device *dev)
* It appears that everything is on GPIOE except for panels
* on i830 laptops, which are on GPIOB (DVOA).
*/
if
(
gpio_inited
!=
gpio
)
{
if
(
i2cbus
!=
NULL
)
intel_i2c_destroy
(
i2cbus
);
if
(
!
(
i2cbus
=
intel_i2c_create
(
dev
,
gpio
,
gpio
==
GPIOB
?
"DVOI2C_B"
:
"DVOI2C_E"
)))
{
continue
;
}
gpio_inited
=
gpio
;
if
(
i2cbus
!=
NULL
)
intel_i2c_destroy
(
i2cbus
);
if
(
!
(
i2cbus
=
intel_i2c_create
(
dev
,
gpio
,
gpio
==
GPIOB
?
"DVOI2C_B"
:
"DVOI2C_E"
)))
{
continue
;
}
if
(
dvo
->
dev_ops
!=
NULL
)
...
...
drivers/gpu/drm/i915/intel_hdmi.c
View file @
be9f1c4f
...
...
@@ -31,6 +31,7 @@
#include "drmP.h"
#include "drm.h"
#include "drm_crtc.h"
#include "drm_edid.h"
#include "intel_drv.h"
#include "i915_drm.h"
#include "i915_drv.h"
...
...
@@ -129,20 +130,26 @@ static bool intel_hdmi_mode_fixup(struct drm_encoder *encoder,
return
true
;
}
static
void
intel_hdmi_
sink
_detect
(
struct
drm_connector
*
connector
)
static
enum
drm_connector_status
intel_hdmi_
edid
_detect
(
struct
drm_connector
*
connector
)
{
struct
intel_output
*
intel_output
=
to_intel_output
(
connector
);
struct
intel_hdmi_priv
*
hdmi_priv
=
intel_output
->
dev_priv
;
struct
edid
*
edid
=
NULL
;
enum
drm_connector_status
status
=
connector_status_disconnected
;
edid
=
drm_get_edid
(
&
intel_output
->
base
,
&
intel_output
->
ddc_bus
->
adapter
);
if
(
edid
!=
NULL
)
{
hdmi_priv
->
has_hdmi_sink
=
drm_detect_hdmi_monitor
(
edid
);
kfree
(
edid
);
intel_output
->
ddc_bus
);
hdmi_priv
->
has_hdmi_sink
=
false
;
if
(
edid
)
{
if
(
edid
->
input
&
DRM_EDID_INPUT_DIGITAL
)
{
status
=
connector_status_connected
;
hdmi_priv
->
has_hdmi_sink
=
drm_detect_hdmi_monitor
(
edid
);
}
intel_output
->
base
.
display_info
.
raw_edid
=
NULL
;
kfree
(
edid
);
}
return
status
;
}
static
enum
drm_connector_status
...
...
@@ -154,11 +161,7 @@ igdng_hdmi_detect(struct drm_connector *connector)
/* FIXME hotplug detect */
hdmi_priv
->
has_hdmi_sink
=
false
;
intel_hdmi_sink_detect
(
connector
);
if
(
hdmi_priv
->
has_hdmi_sink
)
return
connector_status_connected
;
else
return
connector_status_disconnected
;
return
intel_hdmi_edid_detect
(
connector
);
}
static
enum
drm_connector_status
...
...
@@ -201,10 +204,9 @@ intel_hdmi_detect(struct drm_connector *connector)
return
connector_status_unknown
;
}
if
((
I915_READ
(
PORT_HOTPLUG_STAT
)
&
bit
)
!=
0
)
{
intel_hdmi_sink_detect
(
connector
);
return
connector_status_connected
;
}
else
if
((
I915_READ
(
PORT_HOTPLUG_STAT
)
&
bit
)
!=
0
)
return
intel_hdmi_edid_detect
(
connector
);
else
return
connector_status_disconnected
;
}
...
...
drivers/gpu/drm/i915/intel_i2c.c
View file @
be9f1c4f
...
...
@@ -124,6 +124,7 @@ static void set_data(void *data, int state_high)
* @output: driver specific output device
* @reg: GPIO reg to use
* @name: name for this bus
* @slave_addr: slave address (if fixed)
*
* Creates and registers a new i2c bus with the Linux i2c layer, for use
* in output probing and control (e.g. DDC or SDVO control functions).
...
...
@@ -139,8 +140,8 @@ static void set_data(void *data, int state_high)
* %GPIOH
* see PRM for details on how these different busses are used.
*/
struct
i
ntel_i2c_chan
*
intel_i2c_create
(
struct
drm_device
*
dev
,
const
u32
reg
,
const
char
*
name
)
struct
i
2c_adapter
*
intel_i2c_create
(
struct
drm_device
*
dev
,
const
u32
reg
,
const
char
*
name
)
{
struct
intel_i2c_chan
*
chan
;
...
...
@@ -174,7 +175,7 @@ struct intel_i2c_chan *intel_i2c_create(struct drm_device *dev, const u32 reg,
intel_i2c_quirk_set
(
dev
,
false
);
udelay
(
20
);
return
chan
;
return
&
chan
->
adapter
;
out_free:
kfree
(
chan
);
...
...
@@ -187,11 +188,16 @@ struct intel_i2c_chan *intel_i2c_create(struct drm_device *dev, const u32 reg,
*
* Unregister the adapter from the i2c layer, then free the structure.
*/
void
intel_i2c_destroy
(
struct
i
ntel_i2c_chan
*
chan
)
void
intel_i2c_destroy
(
struct
i
2c_adapter
*
adapter
)
{
if
(
!
chan
)
struct
intel_i2c_chan
*
chan
;
if
(
!
adapter
)
return
;
chan
=
container_of
(
adapter
,
struct
intel_i2c_chan
,
adapter
);
i2c_del_adapter
(
&
chan
->
adapter
);
kfree
(
chan
);
}
drivers/gpu/drm/i915/intel_lvds.c
View file @
be9f1c4f
...
...
@@ -456,7 +456,7 @@ static const struct dmi_system_id intel_no_lvds[] = {
.
callback
=
intel_no_lvds_dmi_callback
,
.
ident
=
"Apple Mac Mini (Core series)"
,
.
matches
=
{
DMI_MATCH
(
DMI_SYS_VENDOR
,
"Apple
Inc.
"
),
DMI_MATCH
(
DMI_SYS_VENDOR
,
"Apple"
),
DMI_MATCH
(
DMI_PRODUCT_NAME
,
"Macmini1,1"
),
},
},
...
...
@@ -464,7 +464,7 @@ static const struct dmi_system_id intel_no_lvds[] = {
.
callback
=
intel_no_lvds_dmi_callback
,
.
ident
=
"Apple Mac Mini (Core 2 series)"
,
.
matches
=
{
DMI_MATCH
(
DMI_SYS_VENDOR
,
"Apple
Inc.
"
),
DMI_MATCH
(
DMI_SYS_VENDOR
,
"Apple"
),
DMI_MATCH
(
DMI_PRODUCT_NAME
,
"Macmini2,1"
),
},
},
...
...
drivers/gpu/drm/i915/intel_modes.c
View file @
be9f1c4f
...
...
@@ -53,10 +53,9 @@ bool intel_ddc_probe(struct intel_output *intel_output)
}
};
intel_i2c_quirk_set
(
intel_output
->
ddc_bus
->
drm_dev
,
true
);
ret
=
i2c_transfer
(
&
intel_output
->
ddc_bus
->
adapter
,
msgs
,
2
);
intel_i2c_quirk_set
(
intel_output
->
ddc_bus
->
drm_dev
,
false
);
intel_i2c_quirk_set
(
intel_output
->
base
.
dev
,
true
);
ret
=
i2c_transfer
(
intel_output
->
ddc_bus
,
msgs
,
2
);
intel_i2c_quirk_set
(
intel_output
->
base
.
dev
,
false
);
if
(
ret
==
2
)
return
true
;
...
...
@@ -74,10 +73,9 @@ int intel_ddc_get_modes(struct intel_output *intel_output)
struct
edid
*
edid
;
int
ret
=
0
;
intel_i2c_quirk_set
(
intel_output
->
ddc_bus
->
drm_dev
,
true
);
edid
=
drm_get_edid
(
&
intel_output
->
base
,
&
intel_output
->
ddc_bus
->
adapter
);
intel_i2c_quirk_set
(
intel_output
->
ddc_bus
->
drm_dev
,
false
);
intel_i2c_quirk_set
(
intel_output
->
base
.
dev
,
true
);
edid
=
drm_get_edid
(
&
intel_output
->
base
,
intel_output
->
ddc_bus
);
intel_i2c_quirk_set
(
intel_output
->
base
.
dev
,
false
);
if
(
edid
)
{
drm_mode_connector_update_edid_property
(
&
intel_output
->
base
,
edid
);
...
...
drivers/gpu/drm/i915/intel_sdvo.c
View file @
be9f1c4f
...
...
@@ -38,8 +38,7 @@
#undef SDVO_DEBUG
#define I915_SDVO "i915_sdvo"
struct
intel_sdvo_priv
{
struct
intel_i2c_chan
*
i2c_bus
;
int
slaveaddr
;
u8
slave_addr
;
/* Register for the SDVO device: SDVOB or SDVOC */
int
output_device
;
...
...
@@ -146,13 +145,13 @@ static bool intel_sdvo_read_byte(struct intel_output *intel_output, u8 addr,
struct
i2c_msg
msgs
[]
=
{
{
.
addr
=
sdvo_priv
->
i2c_bus
->
slave_addr
,
.
addr
=
sdvo_priv
->
slave_addr
>>
1
,
.
flags
=
0
,
.
len
=
1
,
.
buf
=
out_buf
,
},
{
.
addr
=
sdvo_priv
->
i2c_bus
->
slave_addr
,
.
addr
=
sdvo_priv
->
slave_addr
>>
1
,
.
flags
=
I2C_M_RD
,
.
len
=
1
,
.
buf
=
buf
,
...
...
@@ -162,7 +161,7 @@ static bool intel_sdvo_read_byte(struct intel_output *intel_output, u8 addr,
out_buf
[
0
]
=
addr
;
out_buf
[
1
]
=
0
;
if
((
ret
=
i2c_transfer
(
&
sdvo_priv
->
i2c_bus
->
adapter
,
msgs
,
2
))
==
2
)
if
((
ret
=
i2c_transfer
(
intel_output
->
i2c_bus
,
msgs
,
2
))
==
2
)
{
*
ch
=
buf
[
0
];
return
true
;
...
...
@@ -175,10 +174,11 @@ static bool intel_sdvo_read_byte(struct intel_output *intel_output, u8 addr,
static
bool
intel_sdvo_write_byte
(
struct
intel_output
*
intel_output
,
int
addr
,
u8
ch
)
{
struct
intel_sdvo_priv
*
sdvo_priv
=
intel_output
->
dev_priv
;
u8
out_buf
[
2
];
struct
i2c_msg
msgs
[]
=
{
{
.
addr
=
intel_output
->
i2c_bus
->
slave_addr
,
.
addr
=
sdvo_priv
->
slave_addr
>>
1
,
.
flags
=
0
,
.
len
=
2
,
.
buf
=
out_buf
,
...
...
@@ -188,7 +188,7 @@ static bool intel_sdvo_write_byte(struct intel_output *intel_output, int addr,
out_buf
[
0
]
=
addr
;
out_buf
[
1
]
=
ch
;
if
(
i2c_transfer
(
&
intel_output
->
i2c_bus
->
adapter
,
msgs
,
1
)
==
1
)
if
(
i2c_transfer
(
intel_output
->
i2c_bus
,
msgs
,
1
)
==
1
)
{
return
true
;
}
...
...
@@ -1369,9 +1369,8 @@ intel_sdvo_hdmi_sink_detect(struct drm_connector *connector)
struct
intel_sdvo_priv
*
sdvo_priv
=
intel_output
->
dev_priv
;
struct
edid
*
edid
=
NULL
;
intel_sdvo_set_control_bus_switch
(
intel_output
,
sdvo_priv
->
ddc_bus
);
edid
=
drm_get_edid
(
&
intel_output
->
base
,
&
intel_output
->
ddc_bus
->
adapter
);
intel_output
->
ddc_bus
);
if
(
edid
!=
NULL
)
{
sdvo_priv
->
is_hdmi
=
drm_detect_hdmi_monitor
(
edid
);
kfree
(
edid
);
...
...
@@ -1549,7 +1548,6 @@ static void intel_sdvo_get_tv_modes(struct drm_connector *connector)
static
void
intel_sdvo_get_lvds_modes
(
struct
drm_connector
*
connector
)
{
struct
intel_output
*
intel_output
=
to_intel_output
(
connector
);
struct
intel_sdvo_priv
*
sdvo_priv
=
intel_output
->
dev_priv
;
struct
drm_i915_private
*
dev_priv
=
connector
->
dev
->
dev_private
;
/*
...
...
@@ -1557,8 +1555,6 @@ static void intel_sdvo_get_lvds_modes(struct drm_connector *connector)
* Assume that the preferred modes are
* arranged in priority order.
*/
/* set the bus switch and get the modes */
intel_sdvo_set_control_bus_switch
(
intel_output
,
sdvo_priv
->
ddc_bus
);
intel_ddc_get_modes
(
intel_output
);
if
(
list_empty
(
&
connector
->
probed_modes
)
==
false
)
return
;
...
...
@@ -1709,7 +1705,7 @@ intel_sdvo_chan_to_intel_output(struct intel_i2c_chan *chan)
list_for_each_entry
(
connector
,
&
dev
->
mode_config
.
connector_list
,
head
)
{
if
(
to_intel_output
(
connector
)
->
ddc_bus
==
chan
)
{
if
(
to_intel_output
(
connector
)
->
ddc_bus
==
&
chan
->
adapter
)
{
intel_output
=
to_intel_output
(
connector
);
break
;
}
...
...
@@ -1723,7 +1719,7 @@ static int intel_sdvo_master_xfer(struct i2c_adapter *i2c_adap,
struct
intel_output
*
intel_output
;
struct
intel_sdvo_priv
*
sdvo_priv
;
struct
i2c_algo_bit_data
*
algo_data
;
struct
i2c_algorithm
*
algo
;
const
struct
i2c_algorithm
*
algo
;
algo_data
=
(
struct
i2c_algo_bit_data
*
)
i2c_adap
->
algo_data
;
intel_output
=
...
...
@@ -1733,7 +1729,7 @@ static int intel_sdvo_master_xfer(struct i2c_adapter *i2c_adap,
return
-
EINVAL
;
sdvo_priv
=
intel_output
->
dev_priv
;
algo
=
(
struct
i2c_algorithm
*
)
intel_output
->
i2c_bus
->
adapter
.
algo
;
algo
=
intel_output
->
i2c_bus
->
algo
;
intel_sdvo_set_control_bus_switch
(
intel_output
,
sdvo_priv
->
ddc_bus
);
return
algo
->
master_xfer
(
i2c_adap
,
msgs
,
num
);
...
...
@@ -1785,13 +1781,11 @@ bool intel_sdvo_init(struct drm_device *dev, int output_device)
struct
drm_connector
*
connector
;
struct
intel_output
*
intel_output
;
struct
intel_sdvo_priv
*
sdvo_priv
;
struct
intel_i2c_chan
*
i2cbus
=
NULL
;
struct
intel_i2c_chan
*
ddcbus
=
NULL
;
int
connector_type
;
u8
ch
[
0x40
];
int
i
;
int
encoder_type
,
output_id
;
u8
slave_addr
;
int
encoder_type
;
intel_output
=
kcalloc
(
sizeof
(
struct
intel_output
)
+
sizeof
(
struct
intel_sdvo_priv
),
1
,
GFP_KERNEL
);
if
(
!
intel_output
)
{
...
...
@@ -1799,29 +1793,24 @@ bool intel_sdvo_init(struct drm_device *dev, int output_device)
}
sdvo_priv
=
(
struct
intel_sdvo_priv
*
)(
intel_output
+
1
);
sdvo_priv
->
output_device
=
output_device
;
intel_output
->
dev_priv
=
sdvo_priv
;
intel_output
->
type
=
INTEL_OUTPUT_SDVO
;
/* setup the DDC bus. */
if
(
output_device
==
SDVOB
)
i
2c
bus
=
intel_i2c_create
(
dev
,
GPIOE
,
"SDVOCTRL_E for SDVOB"
);
i
ntel_output
->
i2c_
bus
=
intel_i2c_create
(
dev
,
GPIOE
,
"SDVOCTRL_E for SDVOB"
);
else
i
2c
bus
=
intel_i2c_create
(
dev
,
GPIOE
,
"SDVOCTRL_E for SDVOC"
);
i
ntel_output
->
i2c_
bus
=
intel_i2c_create
(
dev
,
GPIOE
,
"SDVOCTRL_E for SDVOC"
);
if
(
!
i
2c
bus
)
if
(
!
i
ntel_output
->
i2c_
bus
)
goto
err_inteloutput
;
slave_addr
=
intel_sdvo_get_slave_addr
(
dev
,
output_device
);
sdvo_priv
->
i2c_bus
=
i2cbus
;
sdvo_priv
->
slave_addr
=
intel_sdvo_get_slave_addr
(
dev
,
output_device
);
if
(
output_device
==
SDVOB
)
{
output_id
=
1
;
}
else
{
output_id
=
2
;
}
sdvo_priv
->
i2c_bus
->
slave_addr
=
slave_addr
>>
1
;
sdvo_priv
->
output_device
=
output_device
;
intel_output
->
i2c_bus
=
i2cbus
;
intel_output
->
dev_priv
=
sdvo_priv
;
/* Save the bit-banging i2c functionality for use by the DDC wrapper */
intel_sdvo_i2c_bit_algo
.
functionality
=
intel_output
->
i2c_bus
->
algo
->
functionality
;
/* Read the regs to test if we can talk to the device */
for
(
i
=
0
;
i
<
0x40
;
i
++
)
{
...
...
@@ -1835,17 +1824,15 @@ bool intel_sdvo_init(struct drm_device *dev, int output_device)
/* setup the DDC bus. */
if
(
output_device
==
SDVOB
)
ddc
bus
=
intel_i2c_create
(
dev
,
GPIOE
,
"SDVOB DDC BUS"
);
intel_output
->
ddc_
bus
=
intel_i2c_create
(
dev
,
GPIOE
,
"SDVOB DDC BUS"
);
else
ddc
bus
=
intel_i2c_create
(
dev
,
GPIOE
,
"SDVOC DDC BUS"
);
intel_output
->
ddc_
bus
=
intel_i2c_create
(
dev
,
GPIOE
,
"SDVOC DDC BUS"
);
if
(
ddc
bus
==
NULL
)
if
(
intel_output
->
ddc_
bus
==
NULL
)
goto
err_i2c
;
intel_sdvo_i2c_bit_algo
.
functionality
=
intel_output
->
i2c_bus
->
adapter
.
algo
->
functionality
;
ddcbus
->
adapter
.
algo
=
&
intel_sdvo_i2c_bit_algo
;
intel_output
->
ddc_bus
=
ddcbus
;
/* Wrap with our custom algo which switches to DDC mode */
intel_output
->
ddc_bus
->
algo
=
&
intel_sdvo_i2c_bit_algo
;
/* In defaut case sdvo lvds is false */
sdvo_priv
->
is_lvds
=
false
;
...
...
@@ -1965,9 +1952,10 @@ bool intel_sdvo_init(struct drm_device *dev, int output_device)
return
true
;
err_i2c:
if
(
ddc
bus
!=
NULL
)
if
(
intel_output
->
ddc_
bus
!=
NULL
)
intel_i2c_destroy
(
intel_output
->
ddc_bus
);
intel_i2c_destroy
(
intel_output
->
i2c_bus
);
if
(
intel_output
->
i2c_bus
!=
NULL
)
intel_i2c_destroy
(
intel_output
->
i2c_bus
);
err_inteloutput:
kfree
(
intel_output
);
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment