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
Kirill Smelkov
linux
Commits
2aa5eac5
Commit
2aa5eac5
authored
Aug 20, 2015
by
Ben Skeggs
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
drm/nouveau/i2c: transition pad/ports away from being based on nvkm_object
Signed-off-by:
Ben Skeggs
<
bskeggs@redhat.com
>
parent
d36a99d2
Changes
52
Show whitespace changes
Inline
Side-by-side
Showing
52 changed files
with
2293 additions
and
2021 deletions
+2293
-2021
drivers/gpu/drm/nouveau/dispnv04/dfp.c
drivers/gpu/drm/nouveau/dispnv04/dfp.c
+5
-6
drivers/gpu/drm/nouveau/dispnv04/disp.c
drivers/gpu/drm/nouveau/dispnv04/disp.c
+3
-1
drivers/gpu/drm/nouveau/dispnv04/tvnv04.c
drivers/gpu/drm/nouveau/dispnv04/tvnv04.c
+10
-6
drivers/gpu/drm/nouveau/include/nvkm/subdev/i2c.h
drivers/gpu/drm/nouveau/include/nvkm/subdev/i2c.h
+73
-52
drivers/gpu/drm/nouveau/nouveau_bios.c
drivers/gpu/drm/nouveau/nouveau_bios.c
+0
-1
drivers/gpu/drm/nouveau/nouveau_connector.c
drivers/gpu/drm/nouveau/nouveau_connector.c
+13
-13
drivers/gpu/drm/nouveau/nouveau_dp.c
drivers/gpu/drm/nouveau/nouveau_dp.c
+8
-9
drivers/gpu/drm/nouveau/nouveau_encoder.h
drivers/gpu/drm/nouveau/nouveau_encoder.h
+3
-1
drivers/gpu/drm/nouveau/nv50_display.c
drivers/gpu/drm/nouveau/nv50_display.c
+27
-5
drivers/gpu/drm/nouveau/nvkm/engine/disp/dport.c
drivers/gpu/drm/nouveau/nvkm/engine/disp/dport.c
+7
-7
drivers/gpu/drm/nouveau/nvkm/engine/disp/outp.c
drivers/gpu/drm/nouveau/nvkm/engine/disp/outp.c
+1
-5
drivers/gpu/drm/nouveau/nvkm/engine/disp/outp.h
drivers/gpu/drm/nouveau/nvkm/engine/disp/outp.h
+2
-2
drivers/gpu/drm/nouveau/nvkm/engine/disp/outpdp.c
drivers/gpu/drm/nouveau/nvkm/engine/disp/outpdp.c
+25
-29
drivers/gpu/drm/nouveau/nvkm/engine/disp/outpdp.h
drivers/gpu/drm/nouveau/nvkm/engine/disp/outpdp.h
+2
-0
drivers/gpu/drm/nouveau/nvkm/engine/disp/piornv50.c
drivers/gpu/drm/nouveau/nvkm/engine/disp/piornv50.c
+4
-16
drivers/gpu/drm/nouveau/nvkm/subdev/bios/i2c.c
drivers/gpu/drm/nouveau/nvkm/subdev/bios/i2c.c
+2
-2
drivers/gpu/drm/nouveau/nvkm/subdev/bios/init.c
drivers/gpu/drm/nouveau/nvkm/subdev/bios/init.c
+37
-39
drivers/gpu/drm/nouveau/nvkm/subdev/i2c/Kbuild
drivers/gpu/drm/nouveau/nvkm/subdev/i2c/Kbuild
+21
-7
drivers/gpu/drm/nouveau/nvkm/subdev/i2c/anx9805.c
drivers/gpu/drm/nouveau/nvkm/subdev/i2c/anx9805.c
+180
-196
drivers/gpu/drm/nouveau/nvkm/subdev/i2c/aux.c
drivers/gpu/drm/nouveau/nvkm/subdev/i2c/aux.c
+106
-45
drivers/gpu/drm/nouveau/nvkm/subdev/i2c/aux.h
drivers/gpu/drm/nouveau/nvkm/subdev/i2c/aux.h
+30
-0
drivers/gpu/drm/nouveau/nvkm/subdev/i2c/auxg94.c
drivers/gpu/drm/nouveau/nvkm/subdev/i2c/auxg94.c
+181
-0
drivers/gpu/drm/nouveau/nvkm/subdev/i2c/auxgm204.c
drivers/gpu/drm/nouveau/nvkm/subdev/i2c/auxgm204.c
+181
-0
drivers/gpu/drm/nouveau/nvkm/subdev/i2c/base.c
drivers/gpu/drm/nouveau/nvkm/subdev/i2c/base.c
+233
-436
drivers/gpu/drm/nouveau/nvkm/subdev/i2c/bit.c
drivers/gpu/drm/nouveau/nvkm/subdev/i2c/bit.c
+66
-83
drivers/gpu/drm/nouveau/nvkm/subdev/i2c/bus.c
drivers/gpu/drm/nouveau/nvkm/subdev/i2c/bus.c
+245
-0
drivers/gpu/drm/nouveau/nvkm/subdev/i2c/bus.h
drivers/gpu/drm/nouveau/nvkm/subdev/i2c/bus.h
+37
-0
drivers/gpu/drm/nouveau/nvkm/subdev/i2c/busgf119.c
drivers/gpu/drm/nouveau/nvkm/subdev/i2c/busgf119.c
+95
-0
drivers/gpu/drm/nouveau/nvkm/subdev/i2c/busnv04.c
drivers/gpu/drm/nouveau/nvkm/subdev/i2c/busnv04.c
+96
-0
drivers/gpu/drm/nouveau/nvkm/subdev/i2c/busnv4e.c
drivers/gpu/drm/nouveau/nvkm/subdev/i2c/busnv4e.c
+86
-0
drivers/gpu/drm/nouveau/nvkm/subdev/i2c/busnv50.c
drivers/gpu/drm/nouveau/nvkm/subdev/i2c/busnv50.c
+113
-0
drivers/gpu/drm/nouveau/nvkm/subdev/i2c/g94.c
drivers/gpu/drm/nouveau/nvkm/subdev/i2c/g94.c
+4
-217
drivers/gpu/drm/nouveau/nvkm/subdev/i2c/gf110.c
drivers/gpu/drm/nouveau/nvkm/subdev/i2c/gf110.c
+4
-71
drivers/gpu/drm/nouveau/nvkm/subdev/i2c/gf117.c
drivers/gpu/drm/nouveau/nvkm/subdev/i2c/gf117.c
+3
-4
drivers/gpu/drm/nouveau/nvkm/subdev/i2c/gk104.c
drivers/gpu/drm/nouveau/nvkm/subdev/i2c/gk104.c
+4
-4
drivers/gpu/drm/nouveau/nvkm/subdev/i2c/gm204.c
drivers/gpu/drm/nouveau/nvkm/subdev/i2c/gm204.c
+4
-187
drivers/gpu/drm/nouveau/nvkm/subdev/i2c/nv04.c
drivers/gpu/drm/nouveau/nvkm/subdev/i2c/nv04.c
+2
-89
drivers/gpu/drm/nouveau/nvkm/subdev/i2c/nv4e.c
drivers/gpu/drm/nouveau/nvkm/subdev/i2c/nv4e.c
+2
-85
drivers/gpu/drm/nouveau/nvkm/subdev/i2c/nv50.c
drivers/gpu/drm/nouveau/nvkm/subdev/i2c/nv50.c
+3
-104
drivers/gpu/drm/nouveau/nvkm/subdev/i2c/nv50.h
drivers/gpu/drm/nouveau/nvkm/subdev/i2c/nv50.h
+0
-28
drivers/gpu/drm/nouveau/nvkm/subdev/i2c/pad.c
drivers/gpu/drm/nouveau/nvkm/subdev/i2c/pad.c
+76
-43
drivers/gpu/drm/nouveau/nvkm/subdev/i2c/pad.h
drivers/gpu/drm/nouveau/nvkm/subdev/i2c/pad.h
+59
-50
drivers/gpu/drm/nouveau/nvkm/subdev/i2c/padg94.c
drivers/gpu/drm/nouveau/nvkm/subdev/i2c/padg94.c
+39
-50
drivers/gpu/drm/nouveau/nvkm/subdev/i2c/padgf119.c
drivers/gpu/drm/nouveau/nvkm/subdev/i2c/padgf119.c
+51
-0
drivers/gpu/drm/nouveau/nvkm/subdev/i2c/padgm204.c
drivers/gpu/drm/nouveau/nvkm/subdev/i2c/padgm204.c
+39
-50
drivers/gpu/drm/nouveau/nvkm/subdev/i2c/padnv04.c
drivers/gpu/drm/nouveau/nvkm/subdev/i2c/padnv04.c
+10
-8
drivers/gpu/drm/nouveau/nvkm/subdev/i2c/padnv4e.c
drivers/gpu/drm/nouveau/nvkm/subdev/i2c/padnv4e.c
+36
-0
drivers/gpu/drm/nouveau/nvkm/subdev/i2c/padnv50.c
drivers/gpu/drm/nouveau/nvkm/subdev/i2c/padnv50.c
+36
-0
drivers/gpu/drm/nouveau/nvkm/subdev/i2c/port.h
drivers/gpu/drm/nouveau/nvkm/subdev/i2c/port.h
+0
-14
drivers/gpu/drm/nouveau/nvkm/subdev/i2c/priv.h
drivers/gpu/drm/nouveau/nvkm/subdev/i2c/priv.h
+2
-35
drivers/gpu/drm/nouveau/nvkm/subdev/mxm/base.c
drivers/gpu/drm/nouveau/nvkm/subdev/mxm/base.c
+8
-8
drivers/gpu/drm/nouveau/nvkm/subdev/therm/ic.c
drivers/gpu/drm/nouveau/nvkm/subdev/therm/ic.c
+19
-13
No files found.
drivers/gpu/drm/nouveau/dispnv04/dfp.c
View file @
2aa5eac5
...
...
@@ -624,8 +624,8 @@ static void nv04_tmds_slave_init(struct drm_encoder *encoder)
struct
dcb_output
*
dcb
=
nouveau_encoder
(
encoder
)
->
dcb
;
struct
nouveau_drm
*
drm
=
nouveau_drm
(
dev
);
struct
nvkm_i2c
*
i2c
=
nvxx_i2c
(
&
drm
->
device
);
struct
nvkm_i2c_
port
*
port
=
i2c
->
find
(
i2c
,
2
);
struct
nvkm_i2c_b
oard_info
info
[]
=
{
struct
nvkm_i2c_
bus
*
bus
=
nvkm_i2c_bus_find
(
i2c
,
NVKM_I2C_BUS_PRI
);
struct
nvkm_i2c_b
us_probe
info
[]
=
{
{
{
.
type
=
"sil164"
,
...
...
@@ -639,16 +639,15 @@ static void nv04_tmds_slave_init(struct drm_encoder *encoder)
};
int
type
;
if
(
!
nv_gf4_disp_arch
(
dev
)
||
!
port
||
get_tmds_slave
(
encoder
))
if
(
!
nv_gf4_disp_arch
(
dev
)
||
!
bus
||
get_tmds_slave
(
encoder
))
return
;
type
=
i2c
->
identify
(
i2c
,
2
,
"TMDS transmitter"
,
info
,
NULL
,
NULL
);
type
=
nvkm_i2c_bus_probe
(
bus
,
"TMDS transmitter"
,
info
,
NULL
,
NULL
);
if
(
type
<
0
)
return
;
drm_i2c_encoder_init
(
dev
,
to_encoder_slave
(
encoder
),
&
port
->
adapter
,
&
info
[
type
].
dev
);
&
bus
->
i2c
,
&
info
[
type
].
dev
);
}
static
const
struct
drm_encoder_helper_funcs
nv04_lvds_helper_funcs
=
{
...
...
drivers/gpu/drm/nouveau/dispnv04/disp.c
View file @
2aa5eac5
...
...
@@ -101,7 +101,9 @@ nv04_display_create(struct drm_device *dev)
list_for_each_entry
(
encoder
,
&
dev
->
mode_config
.
encoder_list
,
head
)
{
struct
nouveau_encoder
*
nv_encoder
=
nouveau_encoder
(
encoder
);
nv_encoder
->
i2c
=
i2c
->
find
(
i2c
,
nv_encoder
->
dcb
->
i2c_index
);
struct
nvkm_i2c_bus
*
bus
=
nvkm_i2c_bus_find
(
i2c
,
nv_encoder
->
dcb
->
i2c_index
);
nv_encoder
->
i2c
=
bus
?
&
bus
->
i2c
:
NULL
;
}
/* Save previous state */
...
...
drivers/gpu/drm/nouveau/dispnv04/tvnv04.c
View file @
2aa5eac5
...
...
@@ -35,7 +35,7 @@
#include <drm/i2c/ch7006.h>
static
struct
nvkm_i2c_b
oard_info
nv04_tv_encoder_info
[]
=
{
static
struct
nvkm_i2c_b
us_probe
nv04_tv_encoder_info
[]
=
{
{
{
I2C_BOARD_INFO
(
"ch7006"
,
0x75
),
...
...
@@ -55,9 +55,13 @@ int nv04_tv_identify(struct drm_device *dev, int i2c_index)
{
struct
nouveau_drm
*
drm
=
nouveau_drm
(
dev
);
struct
nvkm_i2c
*
i2c
=
nvxx_i2c
(
&
drm
->
device
);
return
i2c
->
identify
(
i2c
,
i2c_index
,
"TV encoder"
,
nv04_tv_encoder_info
,
NULL
,
NULL
);
struct
nvkm_i2c_bus
*
bus
=
nvkm_i2c_bus_find
(
i2c
,
i2c_index
);
if
(
bus
)
{
return
nvkm_i2c_bus_probe
(
bus
,
"TV encoder"
,
nv04_tv_encoder_info
,
NULL
,
NULL
);
}
return
-
ENODEV
;
}
...
...
@@ -205,7 +209,7 @@ nv04_tv_create(struct drm_connector *connector, struct dcb_output *entry)
struct
drm_device
*
dev
=
connector
->
dev
;
struct
nouveau_drm
*
drm
=
nouveau_drm
(
dev
);
struct
nvkm_i2c
*
i2c
=
nvxx_i2c
(
&
drm
->
device
);
struct
nvkm_i2c_
port
*
port
=
i2c
->
find
(
i2c
,
entry
->
i2c_index
);
struct
nvkm_i2c_
bus
*
bus
=
nvkm_i2c_bus_
find
(
i2c
,
entry
->
i2c_index
);
int
type
,
ret
;
/* Ensure that we can talk to this encoder */
...
...
@@ -231,7 +235,7 @@ nv04_tv_create(struct drm_connector *connector, struct dcb_output *entry)
/* Run the slave-specific initialization */
ret
=
drm_i2c_encoder_init
(
dev
,
to_encoder_slave
(
encoder
),
&
port
->
adapter
,
&
bus
->
i2c
,
&
nv04_tv_encoder_info
[
type
].
dev
);
if
(
ret
<
0
)
goto
fail_cleanup
;
...
...
drivers/gpu/drm/nouveau/include/nvkm/subdev/i2c.h
View file @
2aa5eac5
...
...
@@ -6,15 +6,6 @@
#include <subdev/bios.h>
#include <subdev/bios/i2c.h>
#define NV_I2C_PORT(n) (0x00 + (n))
#define NV_I2C_AUX(n) (0x10 + (n))
#define NV_I2C_EXT(n) (0x20 + (n))
#define NV_I2C_DEFAULT(n) (0x80 + (n))
#define NV_I2C_TYPE_DCBI2C(n) (0x0000 | (n))
#define NV_I2C_TYPE_EXTDDC(e) (0x0005 | (e) << 8)
#define NV_I2C_TYPE_EXTAUX(e) (0x0006 | (e) << 8)
struct
nvkm_i2c_ntfy_req
{
#define NVKM_I2C_PLUG 0x01
#define NVKM_I2C_UNPLUG 0x02
...
...
@@ -29,55 +20,66 @@ struct nvkm_i2c_ntfy_rep {
u8
mask
;
};
struct
nvkm_i2c_
port
{
struct
nvkm_object
base
;
struct
i2c_adapter
adapter
;
struct
mutex
mutex
;
struct
nvkm_i2c_
bus_probe
{
struct
i2c_board_info
dev
;
u8
udelay
;
/* set to 0 to use the standard delay */
}
;
struct
list_head
head
;
u8
index
;
int
aux
;
struct
nvkm_i2c_bus
{
const
struct
nvkm_i2c_bus_func
*
func
;
struct
nvkm_i2c_pad
*
pad
;
#define NVKM_I2C_BUS_CCB(n)
/* 'n' is ccb index */
(n)
#define NVKM_I2C_BUS_EXT(n)
/* 'n' is dcb external encoder type */
((n) + 0x100)
#define NVKM_I2C_BUS_PRI
/* ccb primary comm. port */
-1
#define NVKM_I2C_BUS_SEC
/* ccb secondary comm. port */
-2
int
id
;
const
struct
nvkm_i2c_func
*
func
;
struct
mutex
mutex
;
struct
list_head
head
;
struct
i2c_adapter
i2c
;
};
struct
nvkm_i2c_func
{
void
(
*
drive_scl
)(
struct
nvkm_i2c_port
*
,
int
);
void
(
*
drive_sda
)(
struct
nvkm_i2c_port
*
,
int
);
int
(
*
sense_scl
)(
struct
nvkm_i2c_port
*
);
int
(
*
sense_sda
)(
struct
nvkm_i2c_port
*
);
int
nvkm_i2c_bus_acquire
(
struct
nvkm_i2c_bus
*
);
void
nvkm_i2c_bus_release
(
struct
nvkm_i2c_bus
*
);
int
nvkm_i2c_bus_probe
(
struct
nvkm_i2c_bus
*
,
const
char
*
,
struct
nvkm_i2c_bus_probe
*
,
bool
(
*
)(
struct
nvkm_i2c_bus
*
,
struct
i2c_board_info
*
,
void
*
),
void
*
);
int
(
*
aux
)(
struct
nvkm_i2c_port
*
,
bool
,
u8
,
u32
,
u8
*
,
u8
);
int
(
*
pattern
)(
struct
nvkm_i2c_port
*
,
int
pattern
);
int
(
*
lnk_ctl
)(
struct
nvkm_i2c_port
*
,
int
nr
,
int
bw
,
bool
enh
);
int
(
*
drv_ctl
)(
struct
nvkm_i2c_port
*
,
int
lane
,
int
sw
,
int
pe
);
};
struct
nvkm_i2c_aux
{
const
struct
nvkm_i2c_aux_func
*
func
;
struct
nvkm_i2c_pad
*
pad
;
#define NVKM_I2C_AUX_CCB(n)
/* 'n' is ccb index */
(n)
#define NVKM_I2C_AUX_EXT(n)
/* 'n' is dcb external encoder type */
((n) + 0x100)
int
id
;
struct
nvkm_i2c_board_info
{
struct
i2c_board_info
dev
;
u8
udelay
;
/* set to 0 to use the standard delay */
struct
mutex
mutex
;
struct
list_head
head
;
struct
i2c_adapter
i2c
;
u32
intr
;
};
void
nvkm_i2c_aux_monitor
(
struct
nvkm_i2c_aux
*
,
bool
monitor
);
int
nvkm_i2c_aux_acquire
(
struct
nvkm_i2c_aux
*
);
void
nvkm_i2c_aux_release
(
struct
nvkm_i2c_aux
*
);
int
nvkm_i2c_aux_xfer
(
struct
nvkm_i2c_aux
*
,
bool
retry
,
u8
type
,
u32
addr
,
u8
*
data
,
u8
size
);
int
nvkm_i2c_aux_lnk_ctl
(
struct
nvkm_i2c_aux
*
,
int
link_nr
,
int
link_bw
,
bool
enhanced_framing
);
struct
nvkm_i2c
{
struct
nvkm_subdev
subdev
;
struct
nvkm_event
event
;
struct
nvkm_i2c_port
*
(
*
find
)(
struct
nvkm_i2c
*
,
u8
index
);
struct
nvkm_i2c_port
*
(
*
find_type
)(
struct
nvkm_i2c
*
,
u16
type
);
int
(
*
acquire_pad
)(
struct
nvkm_i2c_port
*
,
unsigned
long
timeout
);
void
(
*
release_pad
)(
struct
nvkm_i2c_port
*
);
int
(
*
acquire
)(
struct
nvkm_i2c_port
*
,
unsigned
long
timeout
);
void
(
*
release
)(
struct
nvkm_i2c_port
*
);
int
(
*
identify
)(
struct
nvkm_i2c
*
,
int
index
,
const
char
*
what
,
struct
nvkm_i2c_board_info
*
,
bool
(
*
match
)(
struct
nvkm_i2c_port
*
,
struct
i2c_board_info
*
,
void
*
),
void
*
);
wait_queue_head_t
wait
;
struct
list_head
ports
;
struct
list_head
pad
;
struct
list_head
bus
;
struct
list_head
aux
;
};
struct
nvkm_i2c_bus
*
nvkm_i2c_bus_find
(
struct
nvkm_i2c
*
,
int
);
struct
nvkm_i2c_aux
*
nvkm_i2c_aux_find
(
struct
nvkm_i2c
*
,
int
);
static
inline
struct
nvkm_i2c
*
nvkm_i2c
(
void
*
obj
)
{
...
...
@@ -94,7 +96,7 @@ extern struct nvkm_oclass *gk104_i2c_oclass;
extern
struct
nvkm_oclass
*
gm204_i2c_oclass
;
static
inline
int
nv
_rdi2cr
(
struct
nvkm_i2c_port
*
port
,
u8
addr
,
u8
reg
)
nv
km_rdi2cr
(
struct
i2c_adapter
*
adap
,
u8
addr
,
u8
reg
)
{
u8
val
;
struct
i2c_msg
msgs
[]
=
{
...
...
@@ -102,7 +104,7 @@ nv_rdi2cr(struct nvkm_i2c_port *port, u8 addr, u8 reg)
{
.
addr
=
addr
,
.
flags
=
I2C_M_RD
,
.
len
=
1
,
.
buf
=
&
val
},
};
int
ret
=
i2c_transfer
(
&
port
->
adapter
,
msgs
,
2
);
int
ret
=
i2c_transfer
(
adap
,
msgs
,
ARRAY_SIZE
(
msgs
)
);
if
(
ret
!=
2
)
return
-
EIO
;
...
...
@@ -110,14 +112,14 @@ nv_rdi2cr(struct nvkm_i2c_port *port, u8 addr, u8 reg)
}
static
inline
int
nv
_wri2cr
(
struct
nvkm_i2c_port
*
port
,
u8
addr
,
u8
reg
,
u8
val
)
nv
km_wri2cr
(
struct
i2c_adapter
*
adap
,
u8
addr
,
u8
reg
,
u8
val
)
{
u8
buf
[
2
]
=
{
reg
,
val
};
struct
i2c_msg
msgs
[]
=
{
{
.
addr
=
addr
,
.
flags
=
0
,
.
len
=
2
,
.
buf
=
buf
},
};
int
ret
=
i2c_transfer
(
&
port
->
adapter
,
msgs
,
1
);
int
ret
=
i2c_transfer
(
adap
,
msgs
,
ARRAY_SIZE
(
msgs
)
);
if
(
ret
!=
1
)
return
-
EIO
;
...
...
@@ -125,11 +127,30 @@ nv_wri2cr(struct nvkm_i2c_port *port, u8 addr, u8 reg, u8 val)
}
static
inline
bool
nv_probe_i2c
(
struct
nvkm_i2c_port
*
port
,
u8
addr
)
nvkm_probe_i2c
(
struct
i2c_adapter
*
adap
,
u8
addr
)
{
return
nvkm_rdi2cr
(
adap
,
addr
,
0
)
>=
0
;
}
static
inline
int
nvkm_rdaux
(
struct
nvkm_i2c_aux
*
aux
,
u32
addr
,
u8
*
data
,
u8
size
)
{
return
nv_rdi2cr
(
port
,
addr
,
0
)
>=
0
;
int
ret
=
nvkm_i2c_aux_acquire
(
aux
);
if
(
ret
==
0
)
{
ret
=
nvkm_i2c_aux_xfer
(
aux
,
true
,
9
,
addr
,
data
,
size
);
nvkm_i2c_aux_release
(
aux
);
}
return
ret
;
}
int
nv_rdaux
(
struct
nvkm_i2c_port
*
,
u32
addr
,
u8
*
data
,
u8
size
);
int
nv_wraux
(
struct
nvkm_i2c_port
*
,
u32
addr
,
u8
*
data
,
u8
size
);
static
inline
int
nvkm_wraux
(
struct
nvkm_i2c_aux
*
aux
,
u32
addr
,
u8
*
data
,
u8
size
)
{
int
ret
=
nvkm_i2c_aux_acquire
(
aux
);
if
(
ret
==
0
)
{
ret
=
nvkm_i2c_aux_xfer
(
aux
,
true
,
8
,
addr
,
data
,
size
);
nvkm_i2c_aux_release
(
aux
);
}
return
ret
;
}
#endif
drivers/gpu/drm/nouveau/nouveau_bios.c
View file @
2aa5eac5
...
...
@@ -1495,7 +1495,6 @@ parse_dcb20_entry(struct drm_device *dev, struct dcb_table *dcb,
break
;
}
link
=
entry
->
dpconf
.
sor
.
link
;
entry
->
i2c_index
+=
NV_I2C_AUX
(
0
);
break
;
case
DCB_OUTPUT_TMDS
:
if
(
dcb
->
version
>=
0x40
)
{
...
...
drivers/gpu/drm/nouveau/nouveau_connector.c
View file @
2aa5eac5
...
...
@@ -148,7 +148,7 @@ nouveau_connector_ddc_detect(struct drm_connector *connector)
break
;
}
else
if
(
nv_encoder
->
i2c
)
{
if
(
nv_probe_i2c
(
nv_encoder
->
i2c
,
0x50
))
if
(
nv
km
_probe_i2c
(
nv_encoder
->
i2c
,
0x50
))
break
;
}
}
...
...
@@ -241,7 +241,7 @@ nouveau_connector_detect(struct drm_connector *connector, bool force)
struct
nouveau_connector
*
nv_connector
=
nouveau_connector
(
connector
);
struct
nouveau_encoder
*
nv_encoder
=
NULL
;
struct
nouveau_encoder
*
nv_partner
;
struct
nvkm_i2c_port
*
i2c
;
struct
i2c_adapter
*
i2c
;
int
type
;
int
ret
;
enum
drm_connector_status
conn_status
=
connector_status_disconnected
;
...
...
@@ -259,7 +259,7 @@ nouveau_connector_detect(struct drm_connector *connector, bool force)
nv_encoder
=
nouveau_connector_ddc_detect
(
connector
);
if
(
nv_encoder
&&
(
i2c
=
nv_encoder
->
i2c
)
!=
NULL
)
{
nv_connector
->
edid
=
drm_get_edid
(
connector
,
&
i2c
->
adapter
);
nv_connector
->
edid
=
drm_get_edid
(
connector
,
i2c
);
drm_mode_connector_update_edid_property
(
connector
,
nv_connector
->
edid
);
if
(
!
nv_connector
->
edid
)
{
...
...
@@ -930,11 +930,11 @@ nouveau_connector_dp_dpms(struct drm_connector *connector, int mode)
nv_encoder
->
dcb
->
type
==
DCB_OUTPUT_DP
)
{
if
(
mode
==
DRM_MODE_DPMS_ON
)
{
u8
data
=
DP_SET_POWER_D0
;
nv
_wraux
(
nv_encoder
->
i2c
,
DP_SET_POWER
,
&
data
,
1
);
nv
km_wraux
(
nv_encoder
->
aux
,
DP_SET_POWER
,
&
data
,
1
);
usleep_range
(
1000
,
2000
);
}
else
{
u8
data
=
DP_SET_POWER_D3
;
nv
_wraux
(
nv_encoder
->
i2c
,
DP_SET_POWER
,
&
data
,
1
);
nv
km_wraux
(
nv_encoder
->
aux
,
DP_SET_POWER
,
&
data
,
1
);
}
}
...
...
@@ -980,29 +980,29 @@ nouveau_connector_hotplug(struct nvif_notify *notify)
}
static
ssize_t
nouveau_connector_aux_xfer
(
struct
drm_dp_aux
*
aux
,
struct
drm_dp_aux_msg
*
msg
)
nouveau_connector_aux_xfer
(
struct
drm_dp_aux
*
obj
,
struct
drm_dp_aux_msg
*
msg
)
{
struct
nouveau_connector
*
nv_connector
=
container_of
(
aux
,
typeof
(
*
nv_connector
),
aux
);
container_of
(
obj
,
typeof
(
*
nv_connector
),
aux
);
struct
nouveau_encoder
*
nv_encoder
;
struct
nvkm_i2c_
port
*
port
;
struct
nvkm_i2c_
aux
*
aux
;
int
ret
;
nv_encoder
=
find_encoder
(
&
nv_connector
->
base
,
DCB_OUTPUT_DP
);
if
(
!
nv_encoder
||
!
(
port
=
nv_encoder
->
i2c
))
if
(
!
nv_encoder
||
!
(
aux
=
nv_encoder
->
aux
))
return
-
ENODEV
;
if
(
WARN_ON
(
msg
->
size
>
16
))
return
-
E2BIG
;
if
(
msg
->
size
==
0
)
return
msg
->
size
;
ret
=
nvkm_i2c
(
port
)
->
acquire
(
port
,
0
);
ret
=
nvkm_i2c
_aux_acquire
(
aux
);
if
(
ret
)
return
ret
;
ret
=
port
->
func
->
aux
(
port
,
false
,
msg
->
request
,
msg
->
address
,
ret
=
nvkm_i2c_aux_xfer
(
aux
,
false
,
msg
->
request
,
msg
->
address
,
msg
->
buffer
,
msg
->
size
);
nvkm_i2c
(
port
)
->
release
(
port
);
nvkm_i2c
_aux_release
(
aux
);
if
(
ret
>=
0
)
{
msg
->
reply
=
ret
;
return
msg
->
size
;
...
...
drivers/gpu/drm/nouveau/nouveau_dp.c
View file @
2aa5eac5
...
...
@@ -31,8 +31,7 @@
#include "nouveau_crtc.h"
static
void
nouveau_dp_probe_oui
(
struct
drm_device
*
dev
,
struct
nvkm_i2c_port
*
auxch
,
u8
*
dpcd
)
nouveau_dp_probe_oui
(
struct
drm_device
*
dev
,
struct
nvkm_i2c_aux
*
aux
,
u8
*
dpcd
)
{
struct
nouveau_drm
*
drm
=
nouveau_drm
(
dev
);
u8
buf
[
3
];
...
...
@@ -40,11 +39,11 @@ nouveau_dp_probe_oui(struct drm_device *dev, struct nvkm_i2c_port *auxch,
if
(
!
(
dpcd
[
DP_DOWN_STREAM_PORT_COUNT
]
&
DP_OUI_SUPPORT
))
return
;
if
(
!
nv
_rdaux
(
auxch
,
DP_SINK_OUI
,
buf
,
3
))
if
(
!
nv
km_rdaux
(
aux
,
DP_SINK_OUI
,
buf
,
3
))
NV_DEBUG
(
drm
,
"Sink OUI: %02hx%02hx%02hx
\n
"
,
buf
[
0
],
buf
[
1
],
buf
[
2
]);
if
(
!
nv
_rdaux
(
auxch
,
DP_BRANCH_OUI
,
buf
,
3
))
if
(
!
nv
km_rdaux
(
aux
,
DP_BRANCH_OUI
,
buf
,
3
))
NV_DEBUG
(
drm
,
"Branch OUI: %02hx%02hx%02hx
\n
"
,
buf
[
0
],
buf
[
1
],
buf
[
2
]);
...
...
@@ -55,15 +54,15 @@ nouveau_dp_detect(struct nouveau_encoder *nv_encoder)
{
struct
drm_device
*
dev
=
nv_encoder
->
base
.
base
.
dev
;
struct
nouveau_drm
*
drm
=
nouveau_drm
(
dev
);
struct
nvkm_i2c_
port
*
auxch
;
struct
nvkm_i2c_
aux
*
aux
;
u8
*
dpcd
=
nv_encoder
->
dp
.
dpcd
;
int
ret
;
aux
ch
=
nv_encoder
->
i2c
;
if
(
!
aux
ch
)
aux
=
nv_encoder
->
aux
;
if
(
!
aux
)
return
-
ENODEV
;
ret
=
nv
_rdaux
(
auxch
,
DP_DPCD_REV
,
dpcd
,
8
);
ret
=
nv
km_rdaux
(
aux
,
DP_DPCD_REV
,
dpcd
,
8
);
if
(
ret
)
return
ret
;
...
...
@@ -84,6 +83,6 @@ nouveau_dp_detect(struct nouveau_encoder *nv_encoder)
NV_DEBUG
(
drm
,
"maximum: %dx%d
\n
"
,
nv_encoder
->
dp
.
link_nr
,
nv_encoder
->
dp
.
link_bw
);
nouveau_dp_probe_oui
(
dev
,
aux
ch
,
dpcd
);
nouveau_dp_probe_oui
(
dev
,
aux
,
dpcd
);
return
0
;
}
drivers/gpu/drm/nouveau/nouveau_encoder.h
View file @
2aa5eac5
...
...
@@ -41,7 +41,9 @@ struct nouveau_encoder {
struct
dcb_output
*
dcb
;
int
or
;
struct
nvkm_i2c_port
*
i2c
;
struct
i2c_adapter
*
i2c
;
struct
nvkm_i2c_aux
*
aux
;
/* different to drm_encoder.crtc, this reflects what's
* actually programmed on the hw, not the proposed crtc */
...
...
drivers/gpu/drm/nouveau/nv50_display.c
View file @
2aa5eac5
...
...
@@ -1688,6 +1688,7 @@ nv50_dac_create(struct drm_connector *connector, struct dcb_output *dcbe)
{
struct
nouveau_drm
*
drm
=
nouveau_drm
(
connector
->
dev
);
struct
nvkm_i2c
*
i2c
=
nvxx_i2c
(
&
drm
->
device
);
struct
nvkm_i2c_bus
*
bus
;
struct
nouveau_encoder
*
nv_encoder
;
struct
drm_encoder
*
encoder
;
int
type
=
DRM_MODE_ENCODER_DAC
;
...
...
@@ -1697,7 +1698,10 @@ nv50_dac_create(struct drm_connector *connector, struct dcb_output *dcbe)
return
-
ENOMEM
;
nv_encoder
->
dcb
=
dcbe
;
nv_encoder
->
or
=
ffs
(
dcbe
->
or
)
-
1
;
nv_encoder
->
i2c
=
i2c
->
find
(
i2c
,
dcbe
->
i2c_index
);
bus
=
nvkm_i2c_bus_find
(
i2c
,
dcbe
->
i2c_index
);
if
(
bus
)
nv_encoder
->
i2c
=
&
bus
->
i2c
;
encoder
=
to_drm_encoder
(
nv_encoder
);
encoder
->
possible_crtcs
=
dcbe
->
heads
;
...
...
@@ -2091,9 +2095,22 @@ nv50_sor_create(struct drm_connector *connector, struct dcb_output *dcbe)
return
-
ENOMEM
;
nv_encoder
->
dcb
=
dcbe
;
nv_encoder
->
or
=
ffs
(
dcbe
->
or
)
-
1
;
nv_encoder
->
i2c
=
i2c
->
find
(
i2c
,
dcbe
->
i2c_index
);
nv_encoder
->
last_dpms
=
DRM_MODE_DPMS_OFF
;
if
(
dcbe
->
type
==
DCB_OUTPUT_DP
)
{
struct
nvkm_i2c_aux
*
aux
=
nvkm_i2c_aux_find
(
i2c
,
dcbe
->
i2c_index
);
if
(
aux
)
{
nv_encoder
->
i2c
=
&
aux
->
i2c
;
nv_encoder
->
aux
=
aux
;
}
}
else
{
struct
nvkm_i2c_bus
*
bus
=
nvkm_i2c_bus_find
(
i2c
,
dcbe
->
i2c_index
);
if
(
bus
)
nv_encoder
->
i2c
=
&
bus
->
i2c
;
}
encoder
=
to_drm_encoder
(
nv_encoder
);
encoder
->
possible_crtcs
=
dcbe
->
heads
;
encoder
->
possible_clones
=
0
;
...
...
@@ -2244,18 +2261,22 @@ nv50_pior_create(struct drm_connector *connector, struct dcb_output *dcbe)
{
struct
nouveau_drm
*
drm
=
nouveau_drm
(
connector
->
dev
);
struct
nvkm_i2c
*
i2c
=
nvxx_i2c
(
&
drm
->
device
);
struct
nvkm_i2c_port
*
ddc
=
NULL
;
struct
nvkm_i2c_bus
*
bus
=
NULL
;
struct
nvkm_i2c_aux
*
aux
=
NULL
;
struct
i2c_adapter
*
ddc
;
struct
nouveau_encoder
*
nv_encoder
;
struct
drm_encoder
*
encoder
;
int
type
;
switch
(
dcbe
->
type
)
{
case
DCB_OUTPUT_TMDS
:
ddc
=
i2c
->
find_type
(
i2c
,
NV_I2C_TYPE_EXTDDC
(
dcbe
->
extdev
));
bus
=
nvkm_i2c_bus_find
(
i2c
,
NVKM_I2C_BUS_EXT
(
dcbe
->
extdev
));
ddc
=
bus
?
&
bus
->
i2c
:
NULL
;
type
=
DRM_MODE_ENCODER_TMDS
;
break
;
case
DCB_OUTPUT_DP
:
ddc
=
i2c
->
find_type
(
i2c
,
NV_I2C_TYPE_EXTAUX
(
dcbe
->
extdev
));
aux
=
nvkm_i2c_aux_find
(
i2c
,
NVKM_I2C_AUX_EXT
(
dcbe
->
extdev
));
ddc
=
aux
?
&
aux
->
i2c
:
NULL
;
type
=
DRM_MODE_ENCODER_TMDS
;
break
;
default:
...
...
@@ -2268,6 +2289,7 @@ nv50_pior_create(struct drm_connector *connector, struct dcb_output *dcbe)
nv_encoder
->
dcb
=
dcbe
;
nv_encoder
->
or
=
ffs
(
dcbe
->
or
)
-
1
;
nv_encoder
->
i2c
=
ddc
;
nv_encoder
->
aux
=
aux
;
encoder
=
to_drm_encoder
(
nv_encoder
);
encoder
->
possible_crtcs
=
dcbe
->
heads
;
...
...
drivers/gpu/drm/nouveau/nvkm/engine/disp/dport.c
View file @
2aa5eac5
...
...
@@ -98,7 +98,7 @@ dp_set_link_config(struct dp_state *dp)
if
(
outp
->
dpcd
[
DPCD_RC02
]
&
DPCD_RC02_ENHANCED_FRAME_CAP
)
sink
[
1
]
|=
DPCD_LC01_ENHANCED_FRAME_EN
;
return
nv
_wraux
(
outp
->
base
.
edid
,
DPCD_LC00_LINK_BW_SET
,
sink
,
2
);
return
nv
km_wraux
(
outp
->
aux
,
DPCD_LC00_LINK_BW_SET
,
sink
,
2
);
}
static
void
...
...
@@ -111,10 +111,10 @@ dp_set_training_pattern(struct dp_state *dp, u8 pattern)
DBG
(
"training pattern %d
\n
"
,
pattern
);
impl
->
pattern
(
outp
,
pattern
);
nv
_rdaux
(
outp
->
base
.
edid
,
DPCD_LC02
,
&
sink_tp
,
1
);
nv
km_rdaux
(
outp
->
aux
,
DPCD_LC02
,
&
sink_tp
,
1
);
sink_tp
&=
~
DPCD_LC02_TRAINING_PATTERN_SET
;
sink_tp
|=
pattern
;
nv
_wraux
(
outp
->
base
.
edid
,
DPCD_LC02
,
&
sink_tp
,
1
);
nv
km_wraux
(
outp
->
aux
,
DPCD_LC02
,
&
sink_tp
,
1
);
}
static
int
...
...
@@ -150,12 +150,12 @@ dp_link_train_commit(struct dp_state *dp, bool pc)
impl
->
drv_ctl
(
outp
,
i
,
lvsw
&
3
,
lpre
&
3
,
lpc2
&
3
);
}
ret
=
nv
_wraux
(
outp
->
base
.
edid
,
DPCD_LC03
(
0
),
dp
->
conf
,
4
);
ret
=
nv
km_wraux
(
outp
->
aux
,
DPCD_LC03
(
0
),
dp
->
conf
,
4
);
if
(
ret
)
return
ret
;
if
(
pc
)
{
ret
=
nv
_wraux
(
outp
->
base
.
edid
,
DPCD_LC0F
,
dp
->
pc2conf
,
2
);
ret
=
nv
km_wraux
(
outp
->
aux
,
DPCD_LC0F
,
dp
->
pc2conf
,
2
);
if
(
ret
)
return
ret
;
}
...
...
@@ -174,12 +174,12 @@ dp_link_train_update(struct dp_state *dp, bool pc, u32 delay)
else
udelay
(
delay
);
ret
=
nv
_rdaux
(
outp
->
base
.
edid
,
DPCD_LS02
,
dp
->
stat
,
6
);
ret
=
nv
km_rdaux
(
outp
->
aux
,
DPCD_LS02
,
dp
->
stat
,
6
);
if
(
ret
)
return
ret
;
if
(
pc
)
{
ret
=
nv
_rdaux
(
outp
->
base
.
edid
,
DPCD_LS0C
,
&
dp
->
pc2stat
,
1
);
ret
=
nv
km_rdaux
(
outp
->
aux
,
DPCD_LS0C
,
&
dp
->
pc2stat
,
1
);
if
(
ret
)
dp
->
pc2stat
=
0x00
;
DBG
(
"status %6ph pc2 %02x
\n
"
,
dp
->
stat
,
dp
->
pc2stat
);
...
...
drivers/gpu/drm/nouveau/nvkm/engine/disp/outp.c
View file @
2aa5eac5
...
...
@@ -86,11 +86,7 @@ nvkm_output_create_(struct nvkm_object *parent,
dcbE
->
sorconf
.
link
:
0
,
dcbE
->
connector
,
dcbE
->
i2c_index
,
dcbE
->
bus
,
dcbE
->
heads
);
if
(
outp
->
info
.
type
!=
DCB_OUTPUT_DP
)
outp
->
port
=
i2c
->
find
(
i2c
,
NV_I2C_PORT
(
outp
->
info
.
i2c_index
));
else
outp
->
port
=
i2c
->
find
(
i2c
,
NV_I2C_AUX
(
outp
->
info
.
i2c_index
));
outp
->
edid
=
outp
->
port
;
outp
->
i2c
=
nvkm_i2c_bus_find
(
i2c
,
outp
->
info
.
i2c_index
);
data
=
nvbios_connEp
(
bios
,
outp
->
info
.
connector
,
&
ver
,
&
hdr
,
&
connE
);
if
(
!
data
)
{
...
...
drivers/gpu/drm/nouveau/nvkm/engine/disp/outp.h
View file @
2aa5eac5
...
...
@@ -13,8 +13,8 @@ struct nvkm_output {
int
index
;
int
or
;
struct
nvkm_i2c_port
*
port
;
struct
nvkm_i2c_
port
*
edid
;
// whatever (if anything) is pointed at by the dcb device entry
struct
nvkm_i2c_
bus
*
i2c
;
struct
nvkm_connector
*
conn
;
};
...
...
drivers/gpu/drm/nouveau/nvkm/engine/disp/outpdp.c
View file @
2aa5eac5
...
...
@@ -40,7 +40,7 @@ nvkm_output_dp_train(struct nvkm_output *base, u32 datarate, bool wait)
int
ret
,
i
;
/* check that the link is trained at a high enough rate */
ret
=
nv
_rdaux
(
outp
->
base
.
edid
,
DPCD_LC00_LINK_BW_SET
,
link
,
2
);
ret
=
nv
km_rdaux
(
outp
->
aux
,
DPCD_LC00_LINK_BW_SET
,
link
,
2
);
if
(
ret
)
{
DBG
(
"failed to read link config, assuming no sink
\n
"
);
goto
done
;
...
...
@@ -55,7 +55,7 @@ nvkm_output_dp_train(struct nvkm_output *base, u32 datarate, bool wait)
}
/* check that link is still trained */
ret
=
nv
_rdaux
(
outp
->
base
.
edid
,
DPCD_LS02
,
stat
,
3
);
ret
=
nv
km_rdaux
(
outp
->
aux
,
DPCD_LS02
,
stat
,
3
);
if
(
ret
)
{
DBG
(
"failed to read link status, assuming no sink
\n
"
);
goto
done
;
...
...
@@ -102,37 +102,31 @@ nvkm_output_dp_train(struct nvkm_output *base, u32 datarate, bool wait)
}
static
void
nvkm_output_dp_enable
(
struct
nvkm_output_dp
*
outp
,
bool
present
)
nvkm_output_dp_enable
(
struct
nvkm_output_dp
*
outp
,
bool
enable
)
{
struct
nvkm_i2c_port
*
port
=
outp
->
base
.
edid
;
if
(
present
)
{
struct
nvkm_i2c_aux
*
aux
=
outp
->
aux
;
if
(
enable
)
{
if
(
!
outp
->
present
)
{
nvkm_i2c
(
port
)
->
acquire_pad
(
port
,
0
);
DBG
(
"aux power -> always
\n
"
);
nvkm_i2c_aux_monitor
(
aux
,
true
);
outp
->
present
=
true
;
}
if
(
!
nvkm_rdaux
(
aux
,
DPCD_RC00_DPCD_REV
,
outp
->
dpcd
,
sizeof
(
outp
->
dpcd
)))
{
nvkm_output_dp_train
(
&
outp
->
base
,
0
,
true
);
}
else
{
return
;
}
}
if
(
outp
->
present
)
{
nvkm_i2c
(
port
)
->
release_pad
(
port
);
DBG
(
"aux power -> demand
\n
"
);
nvkm_i2c_aux_monitor
(
aux
,
false
);
outp
->
present
=
false
;
}
atomic_set
(
&
outp
->
lt
.
done
,
0
);
}
}
static
void
nvkm_output_dp_detect
(
struct
nvkm_output_dp
*
outp
)
{
struct
nvkm_i2c_port
*
port
=
outp
->
base
.
edid
;
int
ret
=
nvkm_i2c
(
port
)
->
acquire_pad
(
port
,
0
);
if
(
ret
==
0
)
{
ret
=
nv_rdaux
(
outp
->
base
.
edid
,
DPCD_RC00_DPCD_REV
,
outp
->
dpcd
,
sizeof
(
outp
->
dpcd
));
nvkm_output_dp_enable
(
outp
,
ret
==
0
);
nvkm_i2c
(
port
)
->
release_pad
(
port
);
}
atomic_set
(
&
outp
->
lt
.
done
,
0
);
}
static
int
...
...
@@ -148,7 +142,7 @@ nvkm_output_dp_hpd(struct nvkm_notify *notify)
if
(
outp
->
base
.
conn
==
conn
&&
outp
->
info
.
type
==
DCB_OUTPUT_DP
)
{
DBG
(
"HPD: %d
\n
"
,
line
->
mask
);
nvkm_output_dp_
detect
(
outp
);
nvkm_output_dp_
enable
(
outp
,
true
);
if
(
line
->
mask
&
NVKM_I2C_UNPLUG
)
rep
.
mask
|=
NVIF_NOTIFY_CONN_V0_UNPLUG
;
...
...
@@ -196,7 +190,7 @@ int
_nvkm_output_dp_init
(
struct
nvkm_object
*
object
)
{
struct
nvkm_output_dp
*
outp
=
(
void
*
)
object
;
nvkm_output_dp_
detect
(
outp
);
nvkm_output_dp_
enable
(
outp
,
true
);
return
nvkm_output_init
(
&
outp
->
base
);
}
...
...
@@ -231,7 +225,9 @@ nvkm_output_dp_create_(struct nvkm_object *parent,
nvkm_notify_fini
(
&
outp
->
base
.
conn
->
hpd
);
/* access to the aux channel is not optional... */
if
(
!
outp
->
base
.
edid
)
{
//XXX: breaks anx support
outp
->
aux
=
nvkm_i2c_aux_find
(
i2c
,
outp
->
base
.
info
.
i2c_index
);
if
(
!
outp
->
aux
)
{
ERR
(
"aux channel not found
\n
"
);
return
-
ENODEV
;
}
...
...
@@ -256,7 +252,7 @@ nvkm_output_dp_create_(struct nvkm_object *parent,
ret
=
nvkm_notify_init
(
NULL
,
&
i2c
->
event
,
nvkm_output_dp_irq
,
true
,
&
(
struct
nvkm_i2c_ntfy_req
)
{
.
mask
=
NVKM_I2C_IRQ
,
.
port
=
outp
->
base
.
edid
->
index
,
.
port
=
outp
->
aux
->
id
,
},
sizeof
(
struct
nvkm_i2c_ntfy_req
),
sizeof
(
struct
nvkm_i2c_ntfy_rep
),
...
...
@@ -270,7 +266,7 @@ nvkm_output_dp_create_(struct nvkm_object *parent,
ret
=
nvkm_notify_init
(
NULL
,
&
i2c
->
event
,
nvkm_output_dp_hpd
,
true
,
&
(
struct
nvkm_i2c_ntfy_req
)
{
.
mask
=
NVKM_I2C_PLUG
|
NVKM_I2C_UNPLUG
,
.
port
=
outp
->
base
.
edid
->
index
,
.
port
=
outp
->
aux
->
id
,
},
sizeof
(
struct
nvkm_i2c_ntfy_req
),
sizeof
(
struct
nvkm_i2c_ntfy_rep
),
...
...
drivers/gpu/drm/nouveau/nvkm/engine/disp/outpdp.h
View file @
2aa5eac5
...
...
@@ -12,6 +12,8 @@ struct nvkm_output_dp {
struct
nvbios_dpout
info
;
u8
version
;
struct
nvkm_i2c_aux
*
aux
;
struct
nvkm_notify
irq
;
bool
present
;
u8
dpcd
[
16
];
...
...
drivers/gpu/drm/nouveau/nvkm/engine/disp/piornv50.c
View file @
2aa5eac5
...
...
@@ -41,7 +41,6 @@ nv50_pior_tmds_ctor(struct nvkm_object *parent,
struct
nvkm_oclass
*
oclass
,
void
*
info
,
u32
index
,
struct
nvkm_object
**
pobject
)
{
struct
nvkm_i2c
*
i2c
=
nvkm_i2c
(
parent
);
struct
nvkm_output
*
outp
;
int
ret
;
...
...
@@ -50,7 +49,6 @@ nv50_pior_tmds_ctor(struct nvkm_object *parent,
if
(
ret
)
return
ret
;
outp
->
edid
=
i2c
->
find_type
(
i2c
,
NV_I2C_TYPE_EXTDDC
(
outp
->
info
.
extdev
));
return
0
;
}
...
...
@@ -72,10 +70,7 @@ nv50_pior_tmds_impl = {
static
int
nv50_pior_dp_pattern
(
struct
nvkm_output_dp
*
outp
,
int
pattern
)
{
struct
nvkm_i2c_port
*
port
=
outp
->
base
.
edid
;
if
(
port
&&
port
->
func
->
pattern
)
return
port
->
func
->
pattern
(
port
,
pattern
);
return
port
?
0
:
-
ENODEV
;
return
-
ENODEV
;
}
static
int
...
...
@@ -87,19 +82,13 @@ nv50_pior_dp_lnk_pwr(struct nvkm_output_dp *outp, int nr)
static
int
nv50_pior_dp_lnk_ctl
(
struct
nvkm_output_dp
*
outp
,
int
nr
,
int
bw
,
bool
ef
)
{
struct
nvkm_i2c_port
*
port
=
outp
->
base
.
edid
;
if
(
port
&&
port
->
func
->
lnk_ctl
)
return
port
->
func
->
lnk_ctl
(
port
,
nr
,
bw
,
ef
);
return
port
?
0
:
-
ENODEV
;
return
nvkm_i2c_aux_lnk_ctl
(
outp
->
aux
,
nr
,
bw
,
ef
);
}
static
int
nv50_pior_dp_drv_ctl
(
struct
nvkm_output_dp
*
outp
,
int
ln
,
int
vs
,
int
pe
,
int
pc
)
{
struct
nvkm_i2c_port
*
port
=
outp
->
base
.
edid
;
if
(
port
&&
port
->
func
->
drv_ctl
)
return
port
->
func
->
drv_ctl
(
port
,
ln
,
vs
,
pe
);
return
port
?
0
:
-
ENODEV
;
return
-
ENODEV
;
}
static
int
...
...
@@ -117,8 +106,7 @@ nv50_pior_dp_ctor(struct nvkm_object *parent,
if
(
ret
)
return
ret
;
outp
->
base
.
edid
=
i2c
->
find_type
(
i2c
,
NV_I2C_TYPE_EXTAUX
(
outp
->
base
.
info
.
extdev
));
outp
->
aux
=
nvkm_i2c_aux_find
(
i2c
,
NVKM_I2C_AUX_EXT
(
outp
->
base
.
info
.
extdev
));
return
0
;
}
...
...
drivers/gpu/drm/nouveau/nvkm/subdev/bios/i2c.c
View file @
2aa5eac5
...
...
@@ -76,8 +76,8 @@ dcb_i2c_parse(struct nvkm_bios *bios, u8 idx, struct dcb_i2c_entry *info)
if
(
ent
)
{
if
(
ver
>=
0x41
)
{
u32
ent_value
=
nvbios_rd32
(
bios
,
ent
);
u8
i2c_port
=
(
ent_value
>>
27
)
&
0x1f
;
u8
dpaux_port
=
(
ent_value
>>
22
)
&
0x1f
;
u8
i2c_port
=
(
ent_value
>>
0
)
&
0x1f
;
u8
dpaux_port
=
(
ent_value
>>
5
)
&
0x1f
;
/* value 0x1f means unused according to DCB 4.x spec */
if
(
i2c_port
==
0x1f
&&
dpaux_port
==
0x1f
)
info
->
type
=
DCB_I2C_UNUSED
;
...
...
drivers/gpu/drm/nouveau/nvkm/subdev/bios/init.c
View file @
2aa5eac5
...
...
@@ -259,62 +259,60 @@ init_wrvgai(struct nvbios_init *init, u16 port, u8 index, u8 value)
}
}
static
struct
nvkm_i2c_port
*
static
struct
i2c_adapter
*
init_i2c
(
struct
nvbios_init
*
init
,
int
index
)
{
struct
nvkm_i2c
*
i2c
=
nvkm_i2c
(
init
->
bios
);
struct
nvkm_i2c
*
i2c
=
init
->
bios
->
subdev
.
device
->
i2c
;
struct
nvkm_i2c_bus
*
bus
;
if
(
index
==
0xff
)
{
index
=
NV
_I2C_DEFAULT
(
0
)
;
index
=
NV
KM_I2C_BUS_PRI
;
if
(
init
->
outp
&&
init
->
outp
->
i2c_upper_default
)
index
=
NV_I2C_DEFAULT
(
1
);
}
else
if
(
index
<
0
)
{
if
(
!
init
->
outp
)
{
if
(
init_exec
(
init
))
error
(
"script needs output for i2c
\n
"
);
return
NULL
;
}
if
(
index
==
-
2
&&
init
->
outp
->
location
)
{
index
=
NV_I2C_TYPE_EXTAUX
(
init
->
outp
->
extdev
);
return
i2c
->
find_type
(
i2c
,
index
);
}
index
=
init
->
outp
->
i2c_index
;
if
(
init
->
outp
->
type
==
DCB_OUTPUT_DP
)
index
+=
NV_I2C_AUX
(
0
);
index
=
NVKM_I2C_BUS_SEC
;
}
return
i2c
->
find
(
i2c
,
index
);
bus
=
nvkm_i2c_bus_find
(
i2c
,
index
);
return
bus
?
&
bus
->
i2c
:
NULL
;
}
static
int
init_rdi2cr
(
struct
nvbios_init
*
init
,
u8
index
,
u8
addr
,
u8
reg
)
{
struct
nvkm_i2c_port
*
port
=
init_i2c
(
init
,
index
);
if
(
port
&&
init_exec
(
init
))
return
nv
_rdi2cr
(
port
,
addr
,
reg
);
struct
i2c_adapter
*
adap
=
init_i2c
(
init
,
index
);
if
(
adap
&&
init_exec
(
init
))
return
nv
km_rdi2cr
(
adap
,
addr
,
reg
);
return
-
ENODEV
;
}
static
int
init_wri2cr
(
struct
nvbios_init
*
init
,
u8
index
,
u8
addr
,
u8
reg
,
u8
val
)
{
struct
nvkm_i2c_port
*
port
=
init_i2c
(
init
,
index
);
if
(
port
&&
init_exec
(
init
))
return
nv
_wri2cr
(
port
,
addr
,
reg
,
val
);
struct
i2c_adapter
*
adap
=
init_i2c
(
init
,
index
);
if
(
adap
&&
init_exec
(
init
))
return
nv
km_wri2cr
(
adap
,
addr
,
reg
,
val
);
return
-
ENODEV
;
}
static
struct
nvkm_i2c_aux
*
init_aux
(
struct
nvbios_init
*
init
)
{
struct
nvkm_i2c
*
i2c
=
init
->
bios
->
subdev
.
device
->
i2c
;
if
(
!
init
->
outp
)
{
if
(
init_exec
(
init
))
error
(
"script needs output for aux
\n
"
);
return
NULL
;
}
return
nvkm_i2c_aux_find
(
i2c
,
init
->
outp
->
i2c_index
);
}
static
u8
init_rdauxr
(
struct
nvbios_init
*
init
,
u32
addr
)
{
struct
nvkm_i2c_
port
*
port
=
init_i2c
(
init
,
-
2
);
struct
nvkm_i2c_
aux
*
aux
=
init_aux
(
init
);
u8
data
;
if
(
port
&&
init_exec
(
init
))
{
int
ret
=
nv
_rdaux
(
port
,
addr
,
&
data
,
1
);
if
(
aux
&&
init_exec
(
init
))
{
int
ret
=
nv
km_rdaux
(
aux
,
addr
,
&
data
,
1
);
if
(
ret
==
0
)
return
data
;
trace
(
"auxch read failed with %d
\n
"
,
ret
);
...
...
@@ -326,9 +324,9 @@ init_rdauxr(struct nvbios_init *init, u32 addr)
static
int
init_wrauxr
(
struct
nvbios_init
*
init
,
u32
addr
,
u8
data
)
{
struct
nvkm_i2c_
port
*
port
=
init_i2c
(
init
,
-
2
);
if
(
port
&&
init_exec
(
init
))
{
int
ret
=
nv
_wraux
(
port
,
addr
,
&
data
,
1
);
struct
nvkm_i2c_
aux
*
aux
=
init_aux
(
init
);
if
(
aux
&&
init_exec
(
init
))
{
int
ret
=
nv
km_wraux
(
aux
,
addr
,
&
data
,
1
);
if
(
ret
)
trace
(
"auxch write failed with %d
\n
"
,
ret
);
return
ret
;
...
...
@@ -1065,13 +1063,13 @@ init_zm_i2c(struct nvbios_init *init)
}
if
(
init_exec
(
init
))
{
struct
nvkm_i2c_port
*
port
=
init_i2c
(
init
,
index
);
struct
i2c_adapter
*
adap
=
init_i2c
(
init
,
index
);
struct
i2c_msg
msg
=
{
.
addr
=
addr
,
.
flags
=
0
,
.
len
=
count
,
.
buf
=
data
,
};
int
ret
;
if
(
port
&&
(
ret
=
i2c_transfer
(
&
port
->
adapter
,
&
msg
,
1
))
!=
1
)
if
(
adap
&&
(
ret
=
i2c_transfer
(
adap
,
&
msg
,
1
))
!=
1
)
warn
(
"i2c wr failed, %d
\n
"
,
ret
);
}
}
...
...
@@ -2127,15 +2125,15 @@ init_i2c_long_if(struct nvbios_init *init)
u8
reghi
=
nvbios_rd08
(
bios
,
init
->
offset
+
4
);
u8
mask
=
nvbios_rd08
(
bios
,
init
->
offset
+
5
);
u8
data
=
nvbios_rd08
(
bios
,
init
->
offset
+
6
);
struct
nvkm_i2c_port
*
port
;
struct
i2c_adapter
*
adap
;
trace
(
"I2C_LONG_IF
\t
"
"I2C[0x%02x][0x%02x][0x%02x%02x] & 0x%02x == 0x%02x
\n
"
,
index
,
addr
,
reglo
,
reghi
,
mask
,
data
);
init
->
offset
+=
7
;
port
=
init_i2c
(
init
,
index
);
if
(
port
)
{
adap
=
init_i2c
(
init
,
index
);
if
(
adap
)
{
u8
i
[
2
]
=
{
reghi
,
reglo
};
u8
o
[
1
]
=
{};
struct
i2c_msg
msg
[]
=
{
...
...
@@ -2144,7 +2142,7 @@ init_i2c_long_if(struct nvbios_init *init)
};
int
ret
;
ret
=
i2c_transfer
(
&
port
->
adapter
,
msg
,
2
);
ret
=
i2c_transfer
(
adap
,
msg
,
2
);
if
(
ret
==
2
&&
((
o
[
0
]
&
mask
)
==
data
))
return
;
}
...
...
drivers/gpu/drm/nouveau/nvkm/subdev/i2c/Kbuild
View file @
2aa5eac5
nvkm-y += nvkm/subdev/i2c/base.o
nvkm-y += nvkm/subdev/i2c/anx9805.o
nvkm-y += nvkm/subdev/i2c/aux.o
nvkm-y += nvkm/subdev/i2c/bit.o
nvkm-y += nvkm/subdev/i2c/pad.o
nvkm-y += nvkm/subdev/i2c/padnv04.o
nvkm-y += nvkm/subdev/i2c/padg94.o
nvkm-y += nvkm/subdev/i2c/padgm204.o
nvkm-y += nvkm/subdev/i2c/nv04.o
nvkm-y += nvkm/subdev/i2c/nv4e.o
nvkm-y += nvkm/subdev/i2c/nv50.o
...
...
@@ -14,3 +7,24 @@ nvkm-y += nvkm/subdev/i2c/gf110.o
nvkm-y += nvkm/subdev/i2c/gf117.o
nvkm-y += nvkm/subdev/i2c/gk104.o
nvkm-y += nvkm/subdev/i2c/gm204.o
nvkm-y += nvkm/subdev/i2c/pad.o
nvkm-y += nvkm/subdev/i2c/padnv04.o
nvkm-y += nvkm/subdev/i2c/padnv4e.o
nvkm-y += nvkm/subdev/i2c/padnv50.o
nvkm-y += nvkm/subdev/i2c/padg94.o
nvkm-y += nvkm/subdev/i2c/padgf119.o
nvkm-y += nvkm/subdev/i2c/padgm204.o
nvkm-y += nvkm/subdev/i2c/bus.o
nvkm-y += nvkm/subdev/i2c/busnv04.o
nvkm-y += nvkm/subdev/i2c/busnv4e.o
nvkm-y += nvkm/subdev/i2c/busnv50.o
nvkm-y += nvkm/subdev/i2c/busgf119.o
nvkm-y += nvkm/subdev/i2c/bit.o
nvkm-y += nvkm/subdev/i2c/aux.o
nvkm-y += nvkm/subdev/i2c/auxg94.o
nvkm-y += nvkm/subdev/i2c/auxgm204.o
nvkm-y += nvkm/subdev/i2c/anx9805.o
drivers/gpu/drm/nouveau/nvkm/subdev/i2c/anx9805.c
View file @
2aa5eac5
...
...
@@ -21,274 +21,258 @@
*
* Authors: Ben Skeggs <bskeggs@redhat.com>
*/
#include "port.h"
#define anx9805_pad(p) container_of((p), struct anx9805_pad, base)
#define anx9805_bus(p) container_of((p), struct anx9805_bus, base)
#define anx9805_aux(p) container_of((p), struct anx9805_aux, base)
#include "aux.h"
#include "bus.h"
struct
anx9805_pad
{
struct
nvkm_i2c_pad
base
;
struct
nvkm_i2c_bus
*
bus
;
u8
addr
;
};
struct
anx9805_
i2c_port
{
struct
nvkm_i2c_
port
base
;
u32
addr
;
u
32
ctrl
;
struct
anx9805_
bus
{
struct
nvkm_i2c_
bus
base
;
struct
anx9805_pad
*
pad
;
u
8
addr
;
};
static
int
anx9805_
train
(
struct
nvkm_i2c_port
*
port
,
int
link_nr
,
int
link_bw
,
bool
enh
)
anx9805_
bus_xfer
(
struct
nvkm_i2c_bus
*
base
,
struct
i2c_msg
*
msgs
,
int
num
)
{
struct
nvkm_i2c
*
i2c
=
nvkm_i2c
(
port
);
struct
nvkm_subdev
*
subdev
=
&
i2c
->
subdev
;
struct
anx9805_i2c_port
*
chan
=
(
void
*
)
port
;
struct
nvkm_i2c_port
*
mast
=
(
void
*
)
nv_object
(
chan
)
->
parent
;
u8
tmp
,
i
;
DBG
(
"ANX9805 train %d %02x %d
\n
"
,
link_nr
,
link_bw
,
enh
)
;
struct
anx9805_bus
*
bus
=
anx9805_bus
(
base
);
struct
anx9805_pad
*
pad
=
bus
->
pad
;
struct
i2c_adapter
*
adap
=
&
pad
->
bus
->
i2c
;
struct
i2c_msg
*
msg
=
msgs
;
int
ret
=
-
ETIMEDOUT
;
int
i
,
j
,
cnt
=
num
;
u8
seg
=
0x00
,
off
=
0x00
,
tmp
;
nv_wri2cr
(
mast
,
chan
->
addr
,
0xa0
,
link_bw
);
nv_wri2cr
(
mast
,
chan
->
addr
,
0xa1
,
link_nr
|
(
enh
?
0x80
:
0x00
));
nv_wri2cr
(
mast
,
chan
->
addr
,
0xa2
,
0x01
);
nv_wri2cr
(
mast
,
chan
->
addr
,
0xa8
,
0x01
);
tmp
=
nvkm_rdi2cr
(
adap
,
pad
->
addr
,
0x07
)
&
~
0x10
;
nvkm_wri2cr
(
adap
,
pad
->
addr
,
0x07
,
tmp
|
0x10
);
nvkm_wri2cr
(
adap
,
pad
->
addr
,
0x07
,
tmp
);
nvkm_wri2cr
(
adap
,
bus
->
addr
,
0x43
,
0x05
);
mdelay
(
5
);
i
=
0
;
while
((
tmp
=
nv_rdi2cr
(
mast
,
chan
->
addr
,
0xa8
))
&
0x01
)
{
while
(
cnt
--
)
{
if
(
(
msg
->
flags
&
I2C_M_RD
)
&&
msg
->
addr
==
0x50
)
{
nvkm_wri2cr
(
adap
,
bus
->
addr
,
0x40
,
msg
->
addr
<<
1
);
nvkm_wri2cr
(
adap
,
bus
->
addr
,
0x41
,
seg
);
nvkm_wri2cr
(
adap
,
bus
->
addr
,
0x42
,
off
);
nvkm_wri2cr
(
adap
,
bus
->
addr
,
0x44
,
msg
->
len
);
nvkm_wri2cr
(
adap
,
bus
->
addr
,
0x45
,
0x00
);
nvkm_wri2cr
(
adap
,
bus
->
addr
,
0x43
,
0x01
);
for
(
i
=
0
;
i
<
msg
->
len
;
i
++
)
{
j
=
0
;
while
(
nvkm_rdi2cr
(
adap
,
bus
->
addr
,
0x46
)
&
0x10
)
{
mdelay
(
5
);
if
(
i
++
==
100
)
{
nvkm_error
(
subdev
,
"link training timed out
\n
"
);
return
-
ETIMEDOUT
;
if
(
j
++
==
32
)
goto
done
;
}
msg
->
buf
[
i
]
=
nvkm_rdi2cr
(
adap
,
bus
->
addr
,
0x47
);
}
}
else
if
(
!
(
msg
->
flags
&
I2C_M_RD
))
{
if
(
msg
->
addr
==
0x50
&&
msg
->
len
==
0x01
)
{
off
=
msg
->
buf
[
0
];
}
else
if
(
msg
->
addr
==
0x30
&&
msg
->
len
==
0x01
)
{
seg
=
msg
->
buf
[
0
];
}
else
goto
done
;
}
else
{
goto
done
;
}
msg
++
;
}
if
(
tmp
&
0x70
)
{
nvkm_error
(
subdev
,
"link training failed: %02x
\n
"
,
tmp
);
return
-
EIO
;
ret
=
num
;
done:
nvkm_wri2cr
(
adap
,
bus
->
addr
,
0x43
,
0x00
);
return
ret
;
}
static
const
struct
nvkm_i2c_bus_func
anx9805_bus_func
=
{
.
xfer
=
anx9805_bus_xfer
,
};
static
int
anx9805_bus_new
(
struct
nvkm_i2c_pad
*
base
,
int
id
,
u8
drive
,
struct
nvkm_i2c_bus
**
pbus
)
{
struct
anx9805_pad
*
pad
=
anx9805_pad
(
base
);
struct
anx9805_bus
*
bus
;
int
ret
;
if
(
!
(
bus
=
kzalloc
(
sizeof
(
*
bus
),
GFP_KERNEL
)))
return
-
ENOMEM
;
*
pbus
=
&
bus
->
base
;
bus
->
pad
=
pad
;
ret
=
nvkm_i2c_bus_ctor
(
&
anx9805_bus_func
,
&
pad
->
base
,
id
,
&
bus
->
base
);
if
(
ret
)
return
ret
;
switch
(
pad
->
addr
)
{
case
0x39
:
bus
->
addr
=
0x3d
;
break
;
case
0x3b
:
bus
->
addr
=
0x3f
;
break
;
default:
return
-
ENOSYS
;
}
return
1
;
return
0
;
}
struct
anx9805_aux
{
struct
nvkm_i2c_aux
base
;
struct
anx9805_pad
*
pad
;
u8
addr
;
};
static
int
anx9805_aux
(
struct
nvkm_i2c_port
*
port
,
bool
retry
,
anx9805_aux
_xfer
(
struct
nvkm_i2c_aux
*
base
,
bool
retry
,
u8
type
,
u32
addr
,
u8
*
data
,
u8
size
)
{
struct
anx9805_i2c_port
*
chan
=
(
void
*
)
port
;
struct
nvkm_i2c_port
*
mast
=
(
void
*
)
nv_object
(
chan
)
->
parent
;
struct
anx9805_aux
*
aux
=
anx9805_aux
(
base
);
struct
anx9805_pad
*
pad
=
aux
->
pad
;
struct
i2c_adapter
*
adap
=
&
pad
->
bus
->
i2c
;
int
i
,
ret
=
-
ETIMEDOUT
;
u8
buf
[
16
]
=
{};
u8
tmp
;
DBG
(
"%02x %05x %d
\n
"
,
type
,
addr
,
size
);
AUX_DBG
(
&
aux
->
base
,
"%02x %05x %d
"
,
type
,
addr
,
size
);
tmp
=
nv
_rdi2cr
(
mast
,
chan
->
ctrl
,
0x07
)
&
~
0x04
;
nv
_wri2cr
(
mast
,
chan
->
ctrl
,
0x07
,
tmp
|
0x04
);
nv
_wri2cr
(
mast
,
chan
->
ctrl
,
0x07
,
tmp
);
nv
_wri2cr
(
mast
,
chan
->
ctrl
,
0xf7
,
0x01
);
tmp
=
nv
km_rdi2cr
(
adap
,
pad
->
addr
,
0x07
)
&
~
0x04
;
nv
km_wri2cr
(
adap
,
pad
->
addr
,
0x07
,
tmp
|
0x04
);
nv
km_wri2cr
(
adap
,
pad
->
addr
,
0x07
,
tmp
);
nv
km_wri2cr
(
adap
,
pad
->
addr
,
0xf7
,
0x01
);
nv
_wri2cr
(
mast
,
chan
->
addr
,
0xe4
,
0x80
);
nv
km_wri2cr
(
adap
,
aux
->
addr
,
0xe4
,
0x80
);
if
(
!
(
type
&
1
))
{
memcpy
(
buf
,
data
,
size
);
DBG
(
"%16ph"
,
buf
);
AUX_DBG
(
&
aux
->
base
,
"%16ph"
,
buf
);
for
(
i
=
0
;
i
<
size
;
i
++
)
nv
_wri2cr
(
mast
,
chan
->
addr
,
0xf0
+
i
,
buf
[
i
]);
nv
km_wri2cr
(
adap
,
aux
->
addr
,
0xf0
+
i
,
buf
[
i
]);
}
nv
_wri2cr
(
mast
,
chan
->
addr
,
0xe5
,
((
size
-
1
)
<<
4
)
|
type
);
nv
_wri2cr
(
mast
,
chan
->
addr
,
0xe6
,
(
addr
&
0x000ff
)
>>
0
);
nv
_wri2cr
(
mast
,
chan
->
addr
,
0xe7
,
(
addr
&
0x0ff00
)
>>
8
);
nv
_wri2cr
(
mast
,
chan
->
addr
,
0xe8
,
(
addr
&
0xf0000
)
>>
16
);
nv
_wri2cr
(
mast
,
chan
->
addr
,
0xe9
,
0x01
);
nv
km_wri2cr
(
adap
,
aux
->
addr
,
0xe5
,
((
size
-
1
)
<<
4
)
|
type
);
nv
km_wri2cr
(
adap
,
aux
->
addr
,
0xe6
,
(
addr
&
0x000ff
)
>>
0
);
nv
km_wri2cr
(
adap
,
aux
->
addr
,
0xe7
,
(
addr
&
0x0ff00
)
>>
8
);
nv
km_wri2cr
(
adap
,
aux
->
addr
,
0xe8
,
(
addr
&
0xf0000
)
>>
16
);
nv
km_wri2cr
(
adap
,
aux
->
addr
,
0xe9
,
0x01
);
i
=
0
;
while
((
tmp
=
nv
_rdi2cr
(
mast
,
chan
->
addr
,
0xe9
))
&
0x01
)
{
while
((
tmp
=
nv
km_rdi2cr
(
adap
,
aux
->
addr
,
0xe9
))
&
0x01
)
{
mdelay
(
5
);
if
(
i
++
==
32
)
goto
done
;
}
if
((
tmp
=
nv
_rdi2cr
(
mast
,
chan
->
ctrl
,
0xf7
))
&
0x01
)
{
if
((
tmp
=
nv
km_rdi2cr
(
adap
,
pad
->
addr
,
0xf7
))
&
0x01
)
{
ret
=
-
EIO
;
goto
done
;
}
if
(
type
&
1
)
{
for
(
i
=
0
;
i
<
size
;
i
++
)
buf
[
i
]
=
nv
_rdi2cr
(
mast
,
chan
->
addr
,
0xf0
+
i
);
DBG
(
"%16ph"
,
buf
);
buf
[
i
]
=
nv
km_rdi2cr
(
adap
,
aux
->
addr
,
0xf0
+
i
);
AUX_DBG
(
&
aux
->
base
,
"%16ph"
,
buf
);
memcpy
(
data
,
buf
,
size
);
}
ret
=
0
;
done:
nv
_wri2cr
(
mast
,
chan
->
ctrl
,
0xf7
,
0x01
);
nv
km_wri2cr
(
adap
,
pad
->
addr
,
0xf7
,
0x01
);
return
ret
;
}
static
const
struct
nvkm_i2c_func
anx9805_aux_func
=
{
.
aux
=
anx9805_aux
,
.
lnk_ctl
=
anx9805_train
,
};
static
int
anx9805_aux_chan_ctor
(
struct
nvkm_object
*
parent
,
struct
nvkm_object
*
engine
,
struct
nvkm_oclass
*
oclass
,
void
*
data
,
u32
index
,
struct
nvkm_object
**
pobject
)
anx9805_aux_lnk_ctl
(
struct
nvkm_i2c_aux
*
base
,
int
link_nr
,
int
link_bw
,
bool
enh
)
{
struct
nvkm_i2c_port
*
mast
=
(
void
*
)
parent
;
struct
anx9805_i2c_port
*
chan
;
int
ret
;
ret
=
nvkm_i2c_port_create
(
parent
,
engine
,
oclass
,
index
,
&
nvkm_i2c_aux_algo
,
&
anx9805_aux_func
,
&
chan
);
*
pobject
=
nv_object
(
chan
);
if
(
ret
)
return
ret
;
switch
((
oclass
->
handle
&
0xff00
)
>>
8
)
{
case
0x0d
:
chan
->
addr
=
0x38
;
chan
->
ctrl
=
0x39
;
break
;
case
0x0e
:
chan
->
addr
=
0x3c
;
chan
->
ctrl
=
0x3b
;
break
;
default:
BUG_ON
(
1
);
}
if
(
mast
->
adapter
.
algo
==
&
i2c_bit_algo
)
{
struct
i2c_algo_bit_data
*
algo
=
mast
->
adapter
.
algo_data
;
algo
->
udelay
=
max
(
algo
->
udelay
,
40
);
}
return
0
;
}
static
struct
nvkm_ofuncs
anx9805_aux_ofuncs
=
{
.
ctor
=
anx9805_aux_chan_ctor
,
.
dtor
=
_nvkm_i2c_port_dtor
,
.
init
=
_nvkm_i2c_port_init
,
.
fini
=
_nvkm_i2c_port_fini
,
};
struct
anx9805_aux
*
aux
=
anx9805_aux
(
base
);
struct
anx9805_pad
*
pad
=
aux
->
pad
;
struct
i2c_adapter
*
adap
=
&
pad
->
bus
->
i2c
;
u8
tmp
,
i
;
static
int
anx9805_xfer
(
struct
i2c_adapter
*
adap
,
struct
i2c_msg
*
msgs
,
int
num
)
{
struct
anx9805_i2c_port
*
port
=
adap
->
algo_data
;
struct
nvkm_i2c_port
*
mast
=
(
void
*
)
nv_object
(
port
)
->
parent
;
struct
i2c_msg
*
msg
=
msgs
;
int
ret
=
-
ETIMEDOUT
;
int
i
,
j
,
cnt
=
num
;
u8
seg
=
0x00
,
off
=
0x00
,
tmp
;
AUX_DBG
(
&
aux
->
base
,
"ANX9805 train %d %02x %d"
,
link_nr
,
link_bw
,
enh
);
tmp
=
nv_rdi2cr
(
mast
,
port
->
ctrl
,
0x07
)
&
~
0x10
;
nv_wri2cr
(
mast
,
port
->
ctrl
,
0x07
,
tmp
|
0x10
);
nv_wri2cr
(
mast
,
port
->
ctrl
,
0x07
,
tmp
);
nv_wri2cr
(
mast
,
port
->
addr
,
0x43
,
0x05
);
mdelay
(
5
);
nvkm_wri2cr
(
adap
,
aux
->
addr
,
0xa0
,
link_bw
);
nvkm_wri2cr
(
adap
,
aux
->
addr
,
0xa1
,
link_nr
|
(
enh
?
0x80
:
0x00
));
nvkm_wri2cr
(
adap
,
aux
->
addr
,
0xa2
,
0x01
);
nvkm_wri2cr
(
adap
,
aux
->
addr
,
0xa8
,
0x01
);
while
(
cnt
--
)
{
if
(
(
msg
->
flags
&
I2C_M_RD
)
&&
msg
->
addr
==
0x50
)
{
nv_wri2cr
(
mast
,
port
->
addr
,
0x40
,
msg
->
addr
<<
1
);
nv_wri2cr
(
mast
,
port
->
addr
,
0x41
,
seg
);
nv_wri2cr
(
mast
,
port
->
addr
,
0x42
,
off
);
nv_wri2cr
(
mast
,
port
->
addr
,
0x44
,
msg
->
len
);
nv_wri2cr
(
mast
,
port
->
addr
,
0x45
,
0x00
);
nv_wri2cr
(
mast
,
port
->
addr
,
0x43
,
0x01
);
for
(
i
=
0
;
i
<
msg
->
len
;
i
++
)
{
j
=
0
;
while
(
nv_rdi2cr
(
mast
,
port
->
addr
,
0x46
)
&
0x10
)
{
i
=
0
;
while
((
tmp
=
nvkm_rdi2cr
(
adap
,
aux
->
addr
,
0xa8
))
&
0x01
)
{
mdelay
(
5
);
if
(
j
++
==
32
)
goto
done
;
}
msg
->
buf
[
i
]
=
nv_rdi2cr
(
mast
,
port
->
addr
,
0x47
);
}
}
else
if
(
!
(
msg
->
flags
&
I2C_M_RD
))
{
if
(
msg
->
addr
==
0x50
&&
msg
->
len
==
0x01
)
{
off
=
msg
->
buf
[
0
];
}
else
if
(
msg
->
addr
==
0x30
&&
msg
->
len
==
0x01
)
{
seg
=
msg
->
buf
[
0
];
}
else
goto
done
;
}
else
{
goto
done
;
if
(
i
++
==
100
)
{
AUX_ERR
(
&
aux
->
base
,
"link training timeout"
);
return
-
ETIMEDOUT
;
}
msg
++
;
}
ret
=
num
;
done:
nv_wri2cr
(
mast
,
port
->
addr
,
0x43
,
0x00
);
return
ret
;
}
if
(
tmp
&
0x70
)
{
AUX_ERR
(
&
aux
->
base
,
"link training failed"
);
return
-
EIO
;
}
static
u32
anx9805_func
(
struct
i2c_adapter
*
adap
)
{
return
I2C_FUNC_I2C
|
I2C_FUNC_SMBUS_EMUL
;
return
0
;
}
static
const
struct
i2c_algorithm
anx9805_i2c_algo
=
{
.
master_xfer
=
anx9805_xfer
,
.
functionality
=
anx9805_func
};
static
const
struct
nvkm_i2c_func
anx9805_i2c_func
=
{
static
const
struct
nvkm_i2c_aux_func
anx9805_aux_func
=
{
.
xfer
=
anx9805_aux_xfer
,
.
lnk_ctl
=
anx9805_aux_lnk_ctl
,
};
static
int
anx9805_ddc_port_ctor
(
struct
nvkm_object
*
parent
,
struct
nvkm_object
*
engine
,
struct
nvkm_oclass
*
oclass
,
void
*
data
,
u32
index
,
struct
nvkm_object
**
pobject
)
anx9805_aux_new
(
struct
nvkm_i2c_pad
*
base
,
int
id
,
u8
drive
,
struct
nvkm_i2c_aux
**
pbus
)
{
struct
nvkm_i2c_port
*
mast
=
(
void
*
)
parent
;
struct
anx9805_
i2c_port
*
port
;
struct
anx9805_pad
*
pad
=
anx9805_pad
(
base
)
;
struct
anx9805_
aux
*
aux
;
int
ret
;
ret
=
nvkm_i2c_port_create
(
parent
,
engine
,
oclass
,
index
,
&
anx9805_i2c_algo
,
&
anx9805_i2c_func
,
&
port
);
*
pobject
=
nv_object
(
port
);
if
(
!
(
aux
=
kzalloc
(
sizeof
(
*
aux
),
GFP_KERNEL
)))
return
-
ENOMEM
;
*
pbus
=
&
aux
->
base
;
aux
->
pad
=
pad
;
ret
=
nvkm_i2c_aux_ctor
(
&
anx9805_aux_func
,
&
pad
->
base
,
id
,
&
aux
->
base
);
if
(
ret
)
return
ret
;
switch
((
oclass
->
handle
&
0xff00
)
>>
8
)
{
case
0x0d
:
port
->
addr
=
0x3d
;
port
->
ctrl
=
0x39
;
break
;
case
0x0e
:
port
->
addr
=
0x3f
;
port
->
ctrl
=
0x3b
;
break
;
switch
(
pad
->
addr
)
{
case
0x39
:
aux
->
addr
=
0x38
;
break
;
case
0x3b
:
aux
->
addr
=
0x3c
;
break
;
default:
BUG_ON
(
1
);
}
if
(
mast
->
adapter
.
algo
==
&
i2c_bit_algo
)
{
struct
i2c_algo_bit_data
*
algo
=
mast
->
adapter
.
algo_data
;
algo
->
udelay
=
max
(
algo
->
udelay
,
40
);
return
-
ENOSYS
;
}
return
0
;
}
static
struct
nvkm_ofuncs
anx9805_ddc_ofuncs
=
{
.
ctor
=
anx9805_ddc_port_ctor
,
.
dtor
=
_nvkm_i2c_port_dtor
,
.
init
=
_nvkm_i2c_port_init
,
.
fini
=
_nvkm_i2c_port_fini
,
static
const
struct
nvkm_i2c_pad_func
anx9805_pad_func
=
{
.
bus_new_4
=
anx9805_bus_new
,
.
aux_new_6
=
anx9805_aux_new
,
};
struct
nvkm_oclass
nvkm_anx9805_sclass
[]
=
{
{
.
handle
=
NV_I2C_TYPE_EXTDDC
(
0x0d
),
.
ofuncs
=
&
anx9805_ddc_ofuncs
},
{
.
handle
=
NV_I2C_TYPE_EXTAUX
(
0x0d
),
.
ofuncs
=
&
anx9805_aux_ofuncs
},
{
.
handle
=
NV_I2C_TYPE_EXTDDC
(
0x0e
),
.
ofuncs
=
&
anx9805_ddc_ofuncs
},
{
.
handle
=
NV_I2C_TYPE_EXTAUX
(
0x0e
),
.
ofuncs
=
&
anx9805_aux_ofuncs
},
{}
};
int
anx9805_pad_new
(
struct
nvkm_i2c_bus
*
bus
,
int
id
,
u8
addr
,
struct
nvkm_i2c_pad
**
ppad
)
{
struct
anx9805_pad
*
pad
;
if
(
!
(
pad
=
kzalloc
(
sizeof
(
*
pad
),
GFP_KERNEL
)))
return
-
ENOMEM
;
*
ppad
=
&
pad
->
base
;
nvkm_i2c_pad_ctor
(
&
anx9805_pad_func
,
bus
->
pad
->
i2c
,
id
,
&
pad
->
base
);
pad
->
bus
=
bus
;
pad
->
addr
=
addr
;
return
0
;
}
drivers/gpu/drm/nouveau/nvkm/subdev/i2c/aux.c
View file @
2aa5eac5
...
...
@@ -21,50 +21,17 @@
*
* Authors: Ben Skeggs
*/
#include "priv.h"
int
nv_rdaux
(
struct
nvkm_i2c_port
*
port
,
u32
addr
,
u8
*
data
,
u8
size
)
{
struct
nvkm_i2c
*
i2c
=
nvkm_i2c
(
port
);
if
(
port
->
func
->
aux
)
{
int
ret
=
i2c
->
acquire
(
port
,
0
);
if
(
ret
==
0
)
{
ret
=
port
->
func
->
aux
(
port
,
true
,
9
,
addr
,
data
,
size
);
i2c
->
release
(
port
);
}
return
ret
;
}
return
-
ENODEV
;
}
int
nv_wraux
(
struct
nvkm_i2c_port
*
port
,
u32
addr
,
u8
*
data
,
u8
size
)
{
struct
nvkm_i2c
*
i2c
=
nvkm_i2c
(
port
);
if
(
port
->
func
->
aux
)
{
int
ret
=
i2c
->
acquire
(
port
,
0
);
if
(
ret
==
0
)
{
ret
=
port
->
func
->
aux
(
port
,
true
,
8
,
addr
,
data
,
size
);
i2c
->
release
(
port
);
}
return
ret
;
}
return
-
ENODEV
;
}
#include "aux.h"
#include "pad.h"
static
int
aux
_xfer
(
struct
i2c_adapter
*
adap
,
struct
i2c_msg
*
msgs
,
int
num
)
nvkm_i2c_aux_i2c
_xfer
(
struct
i2c_adapter
*
adap
,
struct
i2c_msg
*
msgs
,
int
num
)
{
struct
nvkm_i2c_port
*
port
=
adap
->
algo_data
;
struct
nvkm_i2c
*
i2c
=
nvkm_i2c
(
port
);
struct
nvkm_i2c_aux
*
aux
=
container_of
(
adap
,
typeof
(
*
aux
),
i2c
);
struct
i2c_msg
*
msg
=
msgs
;
int
ret
,
mcnt
=
num
;
if
(
!
port
->
func
->
aux
)
return
-
ENODEV
;
ret
=
i2c
->
acquire
(
port
,
0
);
ret
=
nvkm_i2c_aux_acquire
(
aux
);
if
(
ret
)
return
ret
;
...
...
@@ -84,9 +51,9 @@ aux_xfer(struct i2c_adapter *adap, struct i2c_msg *msgs, int num)
if
(
mcnt
||
remaining
>
16
)
cmd
|=
4
;
/* MOT */
ret
=
port
->
func
->
aux
(
port
,
true
,
cmd
,
msg
->
addr
,
ptr
,
cnt
);
ret
=
aux
->
func
->
xfer
(
aux
,
true
,
cmd
,
msg
->
addr
,
ptr
,
cnt
);
if
(
ret
<
0
)
{
i2c
->
release
(
port
);
nvkm_i2c_aux_release
(
aux
);
return
ret
;
}
...
...
@@ -97,17 +64,111 @@ aux_xfer(struct i2c_adapter *adap, struct i2c_msg *msgs, int num)
msg
++
;
}
i2c
->
release
(
port
);
nvkm_i2c_aux_release
(
aux
);
return
num
;
}
static
u32
aux
_func
(
struct
i2c_adapter
*
adap
)
nvkm_i2c_aux_i2c
_func
(
struct
i2c_adapter
*
adap
)
{
return
I2C_FUNC_I2C
|
I2C_FUNC_SMBUS_EMUL
;
}
const
struct
i2c_algorithm
nvkm_i2c_aux_algo
=
{
.
master_xfer
=
aux_xfer
,
.
functionality
=
aux_func
const
struct
i2c_algorithm
nvkm_i2c_aux_i2c_algo
=
{
.
master_xfer
=
nvkm_i2c_aux_i2c_xfer
,
.
functionality
=
nvkm_i2c_aux_i2c_func
};
void
nvkm_i2c_aux_monitor
(
struct
nvkm_i2c_aux
*
aux
,
bool
monitor
)
{
struct
nvkm_i2c_pad
*
pad
=
aux
->
pad
;
AUX_TRACE
(
aux
,
"monitor: %s"
,
monitor
?
"yes"
:
"no"
);
if
(
monitor
)
nvkm_i2c_pad_mode
(
pad
,
NVKM_I2C_PAD_AUX
);
else
nvkm_i2c_pad_mode
(
pad
,
NVKM_I2C_PAD_OFF
);
}
void
nvkm_i2c_aux_release
(
struct
nvkm_i2c_aux
*
aux
)
{
struct
nvkm_i2c_pad
*
pad
=
aux
->
pad
;
AUX_TRACE
(
aux
,
"release"
);
nvkm_i2c_pad_release
(
pad
);
mutex_unlock
(
&
aux
->
mutex
);
}
int
nvkm_i2c_aux_acquire
(
struct
nvkm_i2c_aux
*
aux
)
{
struct
nvkm_i2c_pad
*
pad
=
aux
->
pad
;
int
ret
;
AUX_TRACE
(
aux
,
"acquire"
);
mutex_lock
(
&
aux
->
mutex
);
ret
=
nvkm_i2c_pad_acquire
(
pad
,
NVKM_I2C_PAD_AUX
);
if
(
ret
)
mutex_unlock
(
&
aux
->
mutex
);
return
ret
;
}
int
nvkm_i2c_aux_xfer
(
struct
nvkm_i2c_aux
*
aux
,
bool
retry
,
u8
type
,
u32
addr
,
u8
*
data
,
u8
size
)
{
return
aux
->
func
->
xfer
(
aux
,
retry
,
type
,
addr
,
data
,
size
);
}
int
nvkm_i2c_aux_lnk_ctl
(
struct
nvkm_i2c_aux
*
aux
,
int
nr
,
int
bw
,
bool
ef
)
{
if
(
aux
->
func
->
lnk_ctl
)
return
aux
->
func
->
lnk_ctl
(
aux
,
nr
,
bw
,
ef
);
return
-
ENODEV
;
}
void
nvkm_i2c_aux_del
(
struct
nvkm_i2c_aux
**
paux
)
{
struct
nvkm_i2c_aux
*
aux
=
*
paux
;
if
(
aux
&&
!
WARN_ON
(
!
aux
->
func
))
{
AUX_TRACE
(
aux
,
"dtor"
);
list_del
(
&
aux
->
head
);
i2c_del_adapter
(
&
aux
->
i2c
);
kfree
(
*
paux
);
*
paux
=
NULL
;
}
}
int
nvkm_i2c_aux_ctor
(
const
struct
nvkm_i2c_aux_func
*
func
,
struct
nvkm_i2c_pad
*
pad
,
int
id
,
struct
nvkm_i2c_aux
*
aux
)
{
struct
nvkm_device
*
device
=
pad
->
i2c
->
subdev
.
device
;
aux
->
func
=
func
;
aux
->
pad
=
pad
;
aux
->
id
=
id
;
mutex_init
(
&
aux
->
mutex
);
list_add_tail
(
&
aux
->
head
,
&
pad
->
i2c
->
aux
);
AUX_TRACE
(
aux
,
"ctor"
);
snprintf
(
aux
->
i2c
.
name
,
sizeof
(
aux
->
i2c
.
name
),
"nvkm-%s-aux-%04x"
,
dev_name
(
device
->
dev
),
id
);
aux
->
i2c
.
owner
=
THIS_MODULE
;
aux
->
i2c
.
dev
.
parent
=
device
->
dev
;
aux
->
i2c
.
algo
=
&
nvkm_i2c_aux_i2c_algo
;
return
i2c_add_adapter
(
&
aux
->
i2c
);
}
int
nvkm_i2c_aux_new_
(
const
struct
nvkm_i2c_aux_func
*
func
,
struct
nvkm_i2c_pad
*
pad
,
int
id
,
struct
nvkm_i2c_aux
**
paux
)
{
if
(
!
(
*
paux
=
kzalloc
(
sizeof
(
**
paux
),
GFP_KERNEL
)))
return
-
ENOMEM
;
return
nvkm_i2c_aux_ctor
(
func
,
pad
,
id
,
*
paux
);
}
drivers/gpu/drm/nouveau/nvkm/subdev/i2c/aux.h
0 → 100644
View file @
2aa5eac5
#ifndef __NVKM_I2C_AUX_H__
#define __NVKM_I2C_AUX_H__
#include "pad.h"
struct
nvkm_i2c_aux_func
{
int
(
*
xfer
)(
struct
nvkm_i2c_aux
*
,
bool
retry
,
u8
type
,
u32
addr
,
u8
*
data
,
u8
size
);
int
(
*
lnk_ctl
)(
struct
nvkm_i2c_aux
*
,
int
link_nr
,
int
link_bw
,
bool
enhanced_framing
);
};
int
nvkm_i2c_aux_ctor
(
const
struct
nvkm_i2c_aux_func
*
,
struct
nvkm_i2c_pad
*
,
int
id
,
struct
nvkm_i2c_aux
*
);
int
nvkm_i2c_aux_new_
(
const
struct
nvkm_i2c_aux_func
*
,
struct
nvkm_i2c_pad
*
,
int
id
,
struct
nvkm_i2c_aux
**
);
void
nvkm_i2c_aux_del
(
struct
nvkm_i2c_aux
**
);
int
nvkm_i2c_aux_xfer
(
struct
nvkm_i2c_aux
*
,
bool
retry
,
u8
type
,
u32
addr
,
u8
*
data
,
u8
size
);
int
g94_i2c_aux_new
(
struct
nvkm_i2c_pad
*
,
int
,
u8
,
struct
nvkm_i2c_aux
**
);
int
gm204_i2c_aux_new
(
struct
nvkm_i2c_pad
*
,
int
,
u8
,
struct
nvkm_i2c_aux
**
);
#define AUX_MSG(b,l,f,a...) do { \
struct nvkm_i2c_aux *_aux = (b); \
nvkm_##l(&_aux->pad->i2c->subdev, "aux %04x: "f"\n", _aux->id, ##a); \
} while(0)
#define AUX_ERR(b,f,a...) AUX_MSG((b), error, f, ##a)
#define AUX_DBG(b,f,a...) AUX_MSG((b), debug, f, ##a)
#define AUX_TRACE(b,f,a...) AUX_MSG((b), trace, f, ##a)
#endif
drivers/gpu/drm/nouveau/nvkm/subdev/i2c/auxg94.c
0 → 100644
View file @
2aa5eac5
/*
* Copyright 2015 Red Hat Inc.
*
* 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 shall be included in
* all copies or substantial busions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* THE COPYRIGHT HOLDER(S) OR AUTHOR(S) 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: Ben Skeggs <bskeggs@redhat.com>
*/
#define g94_i2c_aux(p) container_of((p), struct g94_i2c_aux, base)
#include "aux.h"
struct
g94_i2c_aux
{
struct
nvkm_i2c_aux
base
;
int
ch
;
};
static
void
g94_i2c_aux_fini
(
struct
g94_i2c_aux
*
aux
)
{
struct
nvkm_device
*
device
=
aux
->
base
.
pad
->
i2c
->
subdev
.
device
;
nvkm_mask
(
device
,
0x00e4e4
+
(
aux
->
ch
*
0x50
),
0x00310000
,
0x00000000
);
}
static
int
g94_i2c_aux_init
(
struct
g94_i2c_aux
*
aux
)
{
struct
nvkm_device
*
device
=
aux
->
base
.
pad
->
i2c
->
subdev
.
device
;
const
u32
unksel
=
1
;
/* nfi which to use, or if it matters.. */
const
u32
ureq
=
unksel
?
0x00100000
:
0x00200000
;
const
u32
urep
=
unksel
?
0x01000000
:
0x02000000
;
u32
ctrl
,
timeout
;
/* wait up to 1ms for any previous transaction to be done... */
timeout
=
1000
;
do
{
ctrl
=
nvkm_rd32
(
device
,
0x00e4e4
+
(
aux
->
ch
*
0x50
));
udelay
(
1
);
if
(
!
timeout
--
)
{
AUX_ERR
(
&
aux
->
base
,
"begin idle timeout %08x"
,
ctrl
);
return
-
EBUSY
;
}
}
while
(
ctrl
&
0x03010000
);
/* set some magic, and wait up to 1ms for it to appear */
nvkm_mask
(
device
,
0x00e4e4
+
(
aux
->
ch
*
0x50
),
0x00300000
,
ureq
);
timeout
=
1000
;
do
{
ctrl
=
nvkm_rd32
(
device
,
0x00e4e4
+
(
aux
->
ch
*
0x50
));
udelay
(
1
);
if
(
!
timeout
--
)
{
AUX_ERR
(
&
aux
->
base
,
"magic wait %08x"
,
ctrl
);
g94_i2c_aux_fini
(
aux
);
return
-
EBUSY
;
}
}
while
((
ctrl
&
0x03000000
)
!=
urep
);
return
0
;
}
static
int
g94_i2c_aux_xfer
(
struct
nvkm_i2c_aux
*
obj
,
bool
retry
,
u8
type
,
u32
addr
,
u8
*
data
,
u8
size
)
{
struct
g94_i2c_aux
*
aux
=
g94_i2c_aux
(
obj
);
struct
nvkm_device
*
device
=
aux
->
base
.
pad
->
i2c
->
subdev
.
device
;
const
u32
base
=
aux
->
ch
*
0x50
;
u32
ctrl
,
stat
,
timeout
,
retries
;
u32
xbuf
[
4
]
=
{};
int
ret
,
i
;
AUX_TRACE
(
&
aux
->
base
,
"%d: %08x %d"
,
type
,
addr
,
size
);
ret
=
g94_i2c_aux_init
(
aux
);
if
(
ret
<
0
)
goto
out
;
stat
=
nvkm_rd32
(
device
,
0x00e4e8
+
base
);
if
(
!
(
stat
&
0x10000000
))
{
AUX_TRACE
(
&
aux
->
base
,
"sink not detected"
);
ret
=
-
ENXIO
;
goto
out
;
}
if
(
!
(
type
&
1
))
{
memcpy
(
xbuf
,
data
,
size
);
for
(
i
=
0
;
i
<
16
;
i
+=
4
)
{
AUX_TRACE
(
&
aux
->
base
,
"wr %08x"
,
xbuf
[
i
/
4
]);
nvkm_wr32
(
device
,
0x00e4c0
+
base
+
i
,
xbuf
[
i
/
4
]);
}
}
ctrl
=
nvkm_rd32
(
device
,
0x00e4e4
+
base
);
ctrl
&=
~
0x0001f0ff
;
ctrl
|=
type
<<
12
;
ctrl
|=
size
-
1
;
nvkm_wr32
(
device
,
0x00e4e0
+
base
,
addr
);
/* (maybe) retry transaction a number of times on failure... */
for
(
retries
=
0
;
!
ret
&&
retries
<
32
;
retries
++
)
{
/* reset, and delay a while if this is a retry */
nvkm_wr32
(
device
,
0x00e4e4
+
base
,
0x80000000
|
ctrl
);
nvkm_wr32
(
device
,
0x00e4e4
+
base
,
0x00000000
|
ctrl
);
if
(
retries
)
udelay
(
400
);
/* transaction request, wait up to 1ms for it to complete */
nvkm_wr32
(
device
,
0x00e4e4
+
base
,
0x00010000
|
ctrl
);
timeout
=
1000
;
do
{
ctrl
=
nvkm_rd32
(
device
,
0x00e4e4
+
base
);
udelay
(
1
);
if
(
!
timeout
--
)
{
AUX_ERR
(
&
aux
->
base
,
"timeout %08x"
,
ctrl
);
ret
=
-
EIO
;
goto
out
;
}
}
while
(
ctrl
&
0x00010000
);
ret
=
1
;
/* read status, and check if transaction completed ok */
stat
=
nvkm_mask
(
device
,
0x00e4e8
+
base
,
0
,
0
);
if
((
stat
&
0x000f0000
)
==
0x00080000
||
(
stat
&
0x000f0000
)
==
0x00020000
)
ret
=
retry
?
0
:
1
;
if
((
stat
&
0x00000100
))
ret
=
-
ETIMEDOUT
;
if
((
stat
&
0x00000e00
))
ret
=
-
EIO
;
AUX_TRACE
(
&
aux
->
base
,
"%02d %08x %08x"
,
retries
,
ctrl
,
stat
);
}
if
(
type
&
1
)
{
for
(
i
=
0
;
i
<
16
;
i
+=
4
)
{
xbuf
[
i
/
4
]
=
nvkm_rd32
(
device
,
0x00e4d0
+
base
+
i
);
AUX_TRACE
(
&
aux
->
base
,
"rd %08x"
,
xbuf
[
i
/
4
]);
}
memcpy
(
data
,
xbuf
,
size
);
}
out:
g94_i2c_aux_fini
(
aux
);
return
ret
<
0
?
ret
:
(
stat
&
0x000f0000
)
>>
16
;
}
static
const
struct
nvkm_i2c_aux_func
g94_i2c_aux_func
=
{
.
xfer
=
g94_i2c_aux_xfer
,
};
int
g94_i2c_aux_new
(
struct
nvkm_i2c_pad
*
pad
,
int
index
,
u8
drive
,
struct
nvkm_i2c_aux
**
paux
)
{
struct
g94_i2c_aux
*
aux
;
if
(
!
(
aux
=
kzalloc
(
sizeof
(
*
aux
),
GFP_KERNEL
)))
return
-
ENOMEM
;
*
paux
=
&
aux
->
base
;
nvkm_i2c_aux_ctor
(
&
g94_i2c_aux_func
,
pad
,
index
,
&
aux
->
base
);
aux
->
ch
=
drive
;
aux
->
base
.
intr
=
1
<<
aux
->
ch
;
return
0
;
}
drivers/gpu/drm/nouveau/nvkm/subdev/i2c/auxgm204.c
0 → 100644
View file @
2aa5eac5
/*
* Copyright 2015 Red Hat Inc.
*
* 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 shall be included in
* all copies or substantial busions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* THE COPYRIGHT HOLDER(S) OR AUTHOR(S) 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: Ben Skeggs <bskeggs@redhat.com>
*/
#define gm204_i2c_aux(p) container_of((p), struct gm204_i2c_aux, base)
#include "aux.h"
struct
gm204_i2c_aux
{
struct
nvkm_i2c_aux
base
;
int
ch
;
};
static
void
gm204_i2c_aux_fini
(
struct
gm204_i2c_aux
*
aux
)
{
struct
nvkm_device
*
device
=
aux
->
base
.
pad
->
i2c
->
subdev
.
device
;
nvkm_mask
(
device
,
0x00d954
+
(
aux
->
ch
*
0x50
),
0x00310000
,
0x00000000
);
}
static
int
gm204_i2c_aux_init
(
struct
gm204_i2c_aux
*
aux
)
{
struct
nvkm_device
*
device
=
aux
->
base
.
pad
->
i2c
->
subdev
.
device
;
const
u32
unksel
=
1
;
/* nfi which to use, or if it matters.. */
const
u32
ureq
=
unksel
?
0x00100000
:
0x00200000
;
const
u32
urep
=
unksel
?
0x01000000
:
0x02000000
;
u32
ctrl
,
timeout
;
/* wait up to 1ms for any previous transaction to be done... */
timeout
=
1000
;
do
{
ctrl
=
nvkm_rd32
(
device
,
0x00d954
+
(
aux
->
ch
*
0x50
));
udelay
(
1
);
if
(
!
timeout
--
)
{
AUX_ERR
(
&
aux
->
base
,
"begin idle timeout %08x"
,
ctrl
);
return
-
EBUSY
;
}
}
while
(
ctrl
&
0x03010000
);
/* set some magic, and wait up to 1ms for it to appear */
nvkm_mask
(
device
,
0x00d954
+
(
aux
->
ch
*
0x50
),
0x00300000
,
ureq
);
timeout
=
1000
;
do
{
ctrl
=
nvkm_rd32
(
device
,
0x00d954
+
(
aux
->
ch
*
0x50
));
udelay
(
1
);
if
(
!
timeout
--
)
{
AUX_ERR
(
&
aux
->
base
,
"magic wait %08x"
,
ctrl
);
gm204_i2c_aux_fini
(
aux
);
return
-
EBUSY
;
}
}
while
((
ctrl
&
0x03000000
)
!=
urep
);
return
0
;
}
static
int
gm204_i2c_aux_xfer
(
struct
nvkm_i2c_aux
*
obj
,
bool
retry
,
u8
type
,
u32
addr
,
u8
*
data
,
u8
size
)
{
struct
gm204_i2c_aux
*
aux
=
gm204_i2c_aux
(
obj
);
struct
nvkm_device
*
device
=
aux
->
base
.
pad
->
i2c
->
subdev
.
device
;
const
u32
base
=
aux
->
ch
*
0x50
;
u32
ctrl
,
stat
,
timeout
,
retries
;
u32
xbuf
[
4
]
=
{};
int
ret
,
i
;
AUX_TRACE
(
&
aux
->
base
,
"%d: %08x %d"
,
type
,
addr
,
size
);
ret
=
gm204_i2c_aux_init
(
aux
);
if
(
ret
<
0
)
goto
out
;
stat
=
nvkm_rd32
(
device
,
0x00d958
+
base
);
if
(
!
(
stat
&
0x10000000
))
{
AUX_TRACE
(
&
aux
->
base
,
"sink not detected"
);
ret
=
-
ENXIO
;
goto
out
;
}
if
(
!
(
type
&
1
))
{
memcpy
(
xbuf
,
data
,
size
);
for
(
i
=
0
;
i
<
16
;
i
+=
4
)
{
AUX_TRACE
(
&
aux
->
base
,
"wr %08x"
,
xbuf
[
i
/
4
]);
nvkm_wr32
(
device
,
0x00d930
+
base
+
i
,
xbuf
[
i
/
4
]);
}
}
ctrl
=
nvkm_rd32
(
device
,
0x00d954
+
base
);
ctrl
&=
~
0x0001f0ff
;
ctrl
|=
type
<<
12
;
ctrl
|=
size
-
1
;
nvkm_wr32
(
device
,
0x00d950
+
base
,
addr
);
/* (maybe) retry transaction a number of times on failure... */
for
(
retries
=
0
;
!
ret
&&
retries
<
32
;
retries
++
)
{
/* reset, and delay a while if this is a retry */
nvkm_wr32
(
device
,
0x00d954
+
base
,
0x80000000
|
ctrl
);
nvkm_wr32
(
device
,
0x00d954
+
base
,
0x00000000
|
ctrl
);
if
(
retries
)
udelay
(
400
);
/* transaction request, wait up to 1ms for it to complete */
nvkm_wr32
(
device
,
0x00d954
+
base
,
0x00010000
|
ctrl
);
timeout
=
1000
;
do
{
ctrl
=
nvkm_rd32
(
device
,
0x00d954
+
base
);
udelay
(
1
);
if
(
!
timeout
--
)
{
AUX_ERR
(
&
aux
->
base
,
"timeout %08x"
,
ctrl
);
ret
=
-
EIO
;
goto
out
;
}
}
while
(
ctrl
&
0x00010000
);
ret
=
1
;
/* read status, and check if transaction completed ok */
stat
=
nvkm_mask
(
device
,
0x00d958
+
base
,
0
,
0
);
if
((
stat
&
0x000f0000
)
==
0x00080000
||
(
stat
&
0x000f0000
)
==
0x00020000
)
ret
=
retry
?
0
:
1
;
if
((
stat
&
0x00000100
))
ret
=
-
ETIMEDOUT
;
if
((
stat
&
0x00000e00
))
ret
=
-
EIO
;
AUX_TRACE
(
&
aux
->
base
,
"%02d %08x %08x"
,
retries
,
ctrl
,
stat
);
}
if
(
type
&
1
)
{
for
(
i
=
0
;
i
<
16
;
i
+=
4
)
{
xbuf
[
i
/
4
]
=
nvkm_rd32
(
device
,
0x00d940
+
base
+
i
);
AUX_TRACE
(
&
aux
->
base
,
"rd %08x"
,
xbuf
[
i
/
4
]);
}
memcpy
(
data
,
xbuf
,
size
);
}
out:
gm204_i2c_aux_fini
(
aux
);
return
ret
<
0
?
ret
:
(
stat
&
0x000f0000
)
>>
16
;
}
static
const
struct
nvkm_i2c_aux_func
gm204_i2c_aux_func
=
{
.
xfer
=
gm204_i2c_aux_xfer
,
};
int
gm204_i2c_aux_new
(
struct
nvkm_i2c_pad
*
pad
,
int
index
,
u8
drive
,
struct
nvkm_i2c_aux
**
paux
)
{
struct
gm204_i2c_aux
*
aux
;
if
(
!
(
aux
=
kzalloc
(
sizeof
(
*
aux
),
GFP_KERNEL
)))
return
-
ENOMEM
;
*
paux
=
&
aux
->
base
;
nvkm_i2c_aux_ctor
(
&
gm204_i2c_aux_func
,
pad
,
index
,
&
aux
->
base
);
aux
->
ch
=
drive
;
aux
->
base
.
intr
=
1
<<
aux
->
ch
;
return
0
;
}
drivers/gpu/drm/nouveau/nvkm/subdev/i2c/base.c
View file @
2aa5eac5
...
...
@@ -22,325 +22,88 @@
* Authors: Ben Skeggs
*/
#include "priv.h"
#include "aux.h"
#include "bus.h"
#include "pad.h"
#include <core/notify.h>
#include <core/option.h>
#include <subdev/bios.h>
#include <subdev/bios/dcb.h>
#include <subdev/bios/i2c.h>
/******************************************************************************
* interface to linux i2c bit-banging algorithm
*****************************************************************************/
#ifdef CONFIG_NOUVEAU_I2C_INTERNAL_DEFAULT
#define CSTMSEL true
#else
#define CSTMSEL false
#endif
static
int
nvkm_i2c_pre_xfer
(
struct
i2c_adapter
*
adap
)
{
struct
i2c_algo_bit_data
*
bit
=
adap
->
algo_data
;
struct
nvkm_i2c_port
*
port
=
bit
->
data
;
return
nvkm_i2c
(
port
)
->
acquire
(
port
,
bit
->
timeout
);
}
static
void
nvkm_i2c_post_xfer
(
struct
i2c_adapter
*
adap
)
{
struct
i2c_algo_bit_data
*
bit
=
adap
->
algo_data
;
struct
nvkm_i2c_port
*
port
=
bit
->
data
;
return
nvkm_i2c
(
port
)
->
release
(
port
);
}
static
void
nvkm_i2c_setscl
(
void
*
data
,
int
state
)
{
struct
nvkm_i2c_port
*
port
=
data
;
port
->
func
->
drive_scl
(
port
,
state
);
}
static
void
nvkm_i2c_setsda
(
void
*
data
,
int
state
)
{
struct
nvkm_i2c_port
*
port
=
data
;
port
->
func
->
drive_sda
(
port
,
state
);
}
static
int
nvkm_i2c_getscl
(
void
*
data
)
{
struct
nvkm_i2c_port
*
port
=
data
;
return
port
->
func
->
sense_scl
(
port
);
}
static
int
nvkm_i2c_getsda
(
void
*
data
)
{
struct
nvkm_i2c_port
*
port
=
data
;
return
port
->
func
->
sense_sda
(
port
);
}
/******************************************************************************
* base i2c "port" class implementation
*****************************************************************************/
int
_nvkm_i2c_port_fini
(
struct
nvkm_object
*
object
,
bool
suspend
)
{
struct
nvkm_i2c_port
*
port
=
(
void
*
)
object
;
struct
nvkm_i2c_pad
*
pad
=
nvkm_i2c_pad
(
port
);
nv_ofuncs
(
pad
)
->
fini
(
nv_object
(
pad
),
suspend
);
return
nvkm_object_fini
(
&
port
->
base
,
suspend
);
}
void
_nvkm_i2c_port_dtor
(
struct
nvkm_object
*
object
)
{
struct
nvkm_i2c_port
*
port
=
(
void
*
)
object
;
i2c_del_adapter
(
&
port
->
adapter
);
nvkm_object_destroy
(
&
port
->
base
);
}
int
nvkm_i2c_port_create_
(
struct
nvkm_object
*
parent
,
struct
nvkm_object
*
engine
,
struct
nvkm_oclass
*
oclass
,
u8
index
,
const
struct
i2c_algorithm
*
algo
,
const
struct
nvkm_i2c_func
*
func
,
int
size
,
void
**
pobject
)
static
struct
nvkm_i2c_pad
*
nvkm_i2c_pad_find
(
struct
nvkm_i2c
*
i2c
,
int
id
)
{
struct
nvkm_device
*
device
=
nv_device
(
parent
);
struct
nvkm_i2c
*
i2c
=
nvkm_i2c
(
parent
);
struct
nvkm_i2c_port
*
port
;
int
ret
;
ret
=
nvkm_object_create_
(
parent
,
engine
,
oclass
,
0
,
size
,
pobject
);
port
=
*
pobject
;
if
(
ret
)
return
ret
;
struct
nvkm_i2c_pad
*
pad
;
snprintf
(
port
->
adapter
.
name
,
sizeof
(
port
->
adapter
.
name
),
"nvkm-%s-%d"
,
device
->
name
,
index
);
port
->
adapter
.
owner
=
THIS_MODULE
;
port
->
adapter
.
dev
.
parent
=
nv_device_base
(
device
);
port
->
index
=
index
;
port
->
aux
=
-
1
;
port
->
func
=
func
;
mutex_init
(
&
port
->
mutex
);
if
(
algo
==
&
nvkm_i2c_bit_algo
&&
!
nvkm_boolopt
(
device
->
cfgopt
,
"NvI2C"
,
CSTMSEL
))
{
struct
i2c_algo_bit_data
*
bit
;
bit
=
kzalloc
(
sizeof
(
*
bit
),
GFP_KERNEL
);
if
(
!
bit
)
return
-
ENOMEM
;
bit
->
udelay
=
10
;
bit
->
timeout
=
usecs_to_jiffies
(
2200
);
bit
->
data
=
port
;
bit
->
pre_xfer
=
nvkm_i2c_pre_xfer
;
bit
->
post_xfer
=
nvkm_i2c_post_xfer
;
bit
->
setsda
=
nvkm_i2c_setsda
;
bit
->
setscl
=
nvkm_i2c_setscl
;
bit
->
getsda
=
nvkm_i2c_getsda
;
bit
->
getscl
=
nvkm_i2c_getscl
;
port
->
adapter
.
algo_data
=
bit
;
ret
=
i2c_bit_add_bus
(
&
port
->
adapter
);
}
else
{
port
->
adapter
.
algo_data
=
port
;
port
->
adapter
.
algo
=
algo
;
ret
=
i2c_add_adapter
(
&
port
->
adapter
);
list_for_each_entry
(
pad
,
&
i2c
->
pad
,
head
)
{
if
(
pad
->
id
==
id
)
return
pad
;
}
if
(
ret
==
0
)
list_add_tail
(
&
port
->
head
,
&
i2c
->
ports
);
return
ret
;
return
NULL
;
}
/******************************************************************************
* base i2c subdev class implementation
*****************************************************************************/
static
struct
nvkm_i2c_port
*
nvkm_i2c_find
(
struct
nvkm_i2c
*
i2c
,
u8
index
)
struct
nvkm_i2c_bus
*
nvkm_i2c_bus_find
(
struct
nvkm_i2c
*
i2c
,
int
id
)
{
struct
nvkm_bios
*
bios
=
nvkm_bios
(
i2c
)
;
struct
nvkm_i2c_
port
*
port
;
struct
nvkm_bios
*
bios
=
i2c
->
subdev
.
device
->
bios
;
struct
nvkm_i2c_
bus
*
bus
;
if
(
index
==
NV_I2C_DEFAULT
(
0
)
||
index
==
NV_I2C_DEFAULT
(
1
))
{
if
(
id
==
NVKM_I2C_BUS_PRI
||
id
==
NVKM_I2C_BUS_SEC
)
{
u8
ver
,
hdr
,
cnt
,
len
;
u16
i2c
=
dcb_i2c_table
(
bios
,
&
ver
,
&
hdr
,
&
cnt
,
&
len
);
if
(
i2c
&&
ver
>=
0x30
)
{
u8
auxidx
=
nvbios_rd08
(
bios
,
i2c
+
4
);
if
(
i
ndex
==
NV_I2C_DEFAULT
(
0
)
)
i
ndex
=
(
auxidx
&
0x0f
)
>>
0
;
if
(
i
d
==
NVKM_I2C_BUS_PRI
)
i
d
=
NVKM_I2C_BUS_CCB
((
auxidx
&
0x0f
)
>>
0
)
;
else
i
ndex
=
(
auxidx
&
0xf0
)
>>
4
;
i
d
=
NVKM_I2C_BUS_CCB
((
auxidx
&
0xf0
)
>>
4
)
;
}
else
{
i
ndex
=
2
;
i
d
=
NVKM_I2C_BUS_CCB
(
2
)
;
}
}
list_for_each_entry
(
port
,
&
i2c
->
port
s
,
head
)
{
if
(
port
->
index
==
index
)
return
port
;
list_for_each_entry
(
bus
,
&
i2c
->
bu
s
,
head
)
{
if
(
bus
->
id
==
id
)
return
bus
;
}
return
NULL
;
}
st
atic
struct
nvkm_i2c_port
*
nvkm_i2c_
find_type
(
struct
nvkm_i2c
*
i2c
,
u16
type
)
st
ruct
nvkm_i2c_aux
*
nvkm_i2c_
aux_find
(
struct
nvkm_i2c
*
i2c
,
int
id
)
{
struct
nvkm_i2c_
port
*
port
;
struct
nvkm_i2c_
aux
*
aux
;
list_for_each_entry
(
port
,
&
i2c
->
ports
,
head
)
{
if
(
nv_hclass
(
port
)
==
type
)
return
port
;
list_for_each_entry
(
aux
,
&
i2c
->
aux
,
head
)
{
if
(
aux
->
id
==
id
)
return
aux
;
}
return
NULL
;
}
static
void
nvkm_i2c_release_pad
(
struct
nvkm_i2c_port
*
port
)
{
struct
nvkm_i2c_pad
*
pad
=
nvkm_i2c_pad
(
port
);
struct
nvkm_i2c
*
i2c
=
nvkm_i2c
(
port
);
if
(
atomic_dec_and_test
(
&
nv_object
(
pad
)
->
usecount
))
{
nv_ofuncs
(
pad
)
->
fini
(
nv_object
(
pad
),
false
);
wake_up_all
(
&
i2c
->
wait
);
}
}
static
int
nvkm_i2c_try_acquire_pad
(
struct
nvkm_i2c_port
*
port
)
{
struct
nvkm_i2c_pad
*
pad
=
nvkm_i2c_pad
(
port
);
if
(
atomic_add_return
(
1
,
&
nv_object
(
pad
)
->
usecount
)
!=
1
)
{
struct
nvkm_object
*
owner
=
(
void
*
)
pad
->
port
;
do
{
if
(
owner
==
(
void
*
)
port
)
return
0
;
owner
=
owner
->
parent
;
}
while
(
owner
);
nvkm_i2c_release_pad
(
port
);
return
-
EBUSY
;
}
pad
->
next
=
port
;
nv_ofuncs
(
pad
)
->
init
(
nv_object
(
pad
));
return
0
;
}
static
int
nvkm_i2c_acquire_pad
(
struct
nvkm_i2c_port
*
port
,
unsigned
long
timeout
)
{
struct
nvkm_i2c
*
i2c
=
nvkm_i2c
(
port
);
if
(
timeout
)
{
if
(
wait_event_timeout
(
i2c
->
wait
,
nvkm_i2c_try_acquire_pad
(
port
)
==
0
,
timeout
)
==
0
)
return
-
EBUSY
;
}
else
{
wait_event
(
i2c
->
wait
,
nvkm_i2c_try_acquire_pad
(
port
)
==
0
);
}
return
0
;
}
static
void
nvkm_i2c_release
(
struct
nvkm_i2c_port
*
port
)
__releases
(
pad
->
mutex
)
{
nvkm_i2c
(
port
)
->
release_pad
(
port
);
mutex_unlock
(
&
port
->
mutex
);
}
static
int
nvkm_i2c_acquire
(
struct
nvkm_i2c_port
*
port
,
unsigned
long
timeout
)
__acquires
(
pad
->
mutex
)
{
int
ret
;
mutex_lock
(
&
port
->
mutex
);
if
((
ret
=
nvkm_i2c
(
port
)
->
acquire_pad
(
port
,
timeout
)))
mutex_unlock
(
&
port
->
mutex
);
return
ret
;
}
static
int
nvkm_i2c_identify
(
struct
nvkm_i2c
*
i2c
,
int
index
,
const
char
*
what
,
struct
nvkm_i2c_board_info
*
info
,
bool
(
*
match
)(
struct
nvkm_i2c_port
*
,
struct
i2c_board_info
*
,
void
*
),
void
*
data
)
{
struct
nvkm_subdev
*
subdev
=
&
i2c
->
subdev
;
struct
nvkm_i2c_port
*
port
=
nvkm_i2c_find
(
i2c
,
index
);
int
i
;
if
(
!
port
)
{
nvkm_debug
(
subdev
,
"no bus when probing %s on %d
\n
"
,
what
,
index
);
return
-
ENODEV
;
}
nvkm_debug
(
subdev
,
"probing %ss on bus: %d
\n
"
,
what
,
port
->
index
);
for
(
i
=
0
;
info
[
i
].
dev
.
addr
;
i
++
)
{
u8
orig_udelay
=
0
;
if
((
port
->
adapter
.
algo
==
&
i2c_bit_algo
)
&&
(
info
[
i
].
udelay
!=
0
))
{
struct
i2c_algo_bit_data
*
algo
=
port
->
adapter
.
algo_data
;
nvkm_debug
(
subdev
,
"using custom udelay %d instead of %d
\n
"
,
info
[
i
].
udelay
,
algo
->
udelay
);
orig_udelay
=
algo
->
udelay
;
algo
->
udelay
=
info
[
i
].
udelay
;
}
if
(
nv_probe_i2c
(
port
,
info
[
i
].
dev
.
addr
)
&&
(
!
match
||
match
(
port
,
&
info
[
i
].
dev
,
data
)))
{
nvkm_info
(
subdev
,
"detected %s: %s
\n
"
,
what
,
info
[
i
].
dev
.
type
);
return
i
;
}
if
(
orig_udelay
)
{
struct
i2c_algo_bit_data
*
algo
=
port
->
adapter
.
algo_data
;
algo
->
udelay
=
orig_udelay
;
}
}
nvkm_debug
(
subdev
,
"no devices found.
\n
"
);
return
-
ENODEV
;
}
static
void
nvkm_i2c_intr_fini
(
struct
nvkm_event
*
event
,
int
type
,
int
index
)
nvkm_i2c_intr_fini
(
struct
nvkm_event
*
event
,
int
type
,
int
id
)
{
struct
nvkm_i2c
*
i2c
=
container_of
(
event
,
typeof
(
*
i2c
),
event
);
struct
nvkm_i2c_
port
*
port
=
i2c
->
find
(
i2c
,
index
);
struct
nvkm_i2c_
aux
*
aux
=
nvkm_i2c_aux_find
(
i2c
,
id
);
const
struct
nvkm_i2c_impl
*
impl
=
(
void
*
)
nv_object
(
i2c
)
->
oclass
;
if
(
port
&&
port
->
aux
>=
0
)
impl
->
aux_mask
(
i2c
,
type
,
1
<<
port
->
aux
,
0
);
if
(
aux
)
impl
->
aux_mask
(
i2c
,
type
,
aux
->
intr
,
0
);
}
static
void
nvkm_i2c_intr_init
(
struct
nvkm_event
*
event
,
int
type
,
int
i
ndex
)
nvkm_i2c_intr_init
(
struct
nvkm_event
*
event
,
int
type
,
int
i
d
)
{
struct
nvkm_i2c
*
i2c
=
container_of
(
event
,
typeof
(
*
i2c
),
event
);
struct
nvkm_i2c_
port
*
port
=
i2c
->
find
(
i2c
,
index
);
struct
nvkm_i2c_
aux
*
aux
=
nvkm_i2c_aux_find
(
i2c
,
id
);
const
struct
nvkm_i2c_impl
*
impl
=
(
void
*
)
nv_object
(
i2c
)
->
oclass
;
if
(
port
&&
port
->
aux
>=
0
)
impl
->
aux_mask
(
i2c
,
type
,
1
<<
port
->
aux
,
1
<<
port
->
aux
);
if
(
aux
)
impl
->
aux_mask
(
i2c
,
type
,
aux
->
intr
,
aux
->
intr
);
}
static
int
...
...
@@ -358,33 +121,32 @@ nvkm_i2c_intr_ctor(struct nvkm_object *object, void *data, u32 size,
}
static
void
nvkm_i2c_intr
(
struct
nvkm_subdev
*
subdev
)
nvkm_i2c_intr
(
struct
nvkm_subdev
*
obj
)
{
struct
nvkm_i2c_impl
*
impl
=
(
void
*
)
nv_oclass
(
subdev
);
struct
nvkm_i2c
*
i2c
=
nvkm_i2c
(
subdev
);
struct
nvkm_i2c_port
*
port
;
u32
hi
,
lo
,
rq
,
tx
,
e
;
struct
nvkm_i2c
*
i2c
=
container_of
(
obj
,
typeof
(
*
i2c
),
subdev
);
struct
nvkm_i2c_impl
*
impl
=
(
void
*
)
i2c
->
subdev
.
object
.
oclass
;
struct
nvkm_i2c_aux
*
aux
;
u32
hi
,
lo
,
rq
,
tx
;
if
(
!
impl
->
aux_stat
)
return
;
if
(
impl
->
aux_stat
)
{
impl
->
aux_stat
(
i2c
,
&
hi
,
&
lo
,
&
rq
,
&
tx
);
if
(
hi
||
lo
||
rq
||
tx
)
{
list_for_each_entry
(
port
,
&
i2c
->
ports
,
head
)
{
if
(
e
=
0
,
port
->
aux
<
0
)
continue
;
if
(
!
hi
&&
!
lo
&&
!
rq
&&
!
tx
)
return
;
if
(
hi
&
(
1
<<
port
->
aux
))
e
|=
NVKM_I2C_PLUG
;
if
(
lo
&
(
1
<<
port
->
aux
))
e
|=
NVKM_I2C_UNPLUG
;
if
(
rq
&
(
1
<<
port
->
aux
))
e
|=
NVKM_I2C_IRQ
;
if
(
tx
&
(
1
<<
port
->
aux
))
e
|=
NVKM_I2C_DONE
;
if
(
e
)
{
list_for_each_entry
(
aux
,
&
i2c
->
aux
,
head
)
{
u32
mask
=
0
;
if
(
hi
&
aux
->
intr
)
mask
|=
NVKM_I2C_PLUG
;
if
(
lo
&
aux
->
intr
)
mask
|=
NVKM_I2C_UNPLUG
;
if
(
rq
&
aux
->
intr
)
mask
|=
NVKM_I2C_IRQ
;
if
(
tx
&
aux
->
intr
)
mask
|=
NVKM_I2C_DONE
;
if
(
mask
)
{
struct
nvkm_i2c_ntfy_rep
rep
=
{
.
mask
=
e
,
.
mask
=
mask
,
};
nvkm_event_send
(
&
i2c
->
event
,
rep
.
mask
,
port
->
index
,
&
rep
,
sizeof
(
rep
));
}
}
nvkm_event_send
(
&
i2c
->
event
,
rep
.
mask
,
aux
->
id
,
&
rep
,
sizeof
(
rep
));
}
}
}
...
...
@@ -401,206 +163,241 @@ _nvkm_i2c_fini(struct nvkm_object *object, bool suspend)
{
struct
nvkm_i2c_impl
*
impl
=
(
void
*
)
nv_oclass
(
object
);
struct
nvkm_i2c
*
i2c
=
(
void
*
)
object
;
struct
nvkm_i2c_p
ort
*
port
;
struct
nvkm_i2c_p
ad
*
pad
;
u32
mask
;
int
ret
;
list_for_each_entry
(
port
,
&
i2c
->
ports
,
head
)
{
ret
=
nv_ofuncs
(
port
)
->
fini
(
nv_object
(
port
),
suspend
);
if
(
ret
&&
suspend
)
goto
fail
;
}
if
((
mask
=
(
1
<<
impl
->
aux
)
-
1
),
impl
->
aux_stat
)
{
impl
->
aux_mask
(
i2c
,
NVKM_I2C_ANY
,
mask
,
0
);
impl
->
aux_stat
(
i2c
,
&
mask
,
&
mask
,
&
mask
,
&
mask
);
}
return
nvkm_subdev_fini
(
&
i2c
->
subdev
,
suspend
);
fail:
list_for_each_entry_continue_reverse
(
port
,
&
i2c
->
ports
,
head
)
{
nv_ofuncs
(
port
)
->
init
(
nv_object
(
port
));
list_for_each_entry
(
pad
,
&
i2c
->
pad
,
head
)
{
nvkm_i2c_pad_fini
(
pad
);
}
return
ret
;
return
nvkm_subdev_fini
(
&
i2c
->
subdev
,
suspend
)
;
}
int
_nvkm_i2c_init
(
struct
nvkm_object
*
object
)
{
struct
nvkm_i2c
*
i2c
=
(
void
*
)
object
;
struct
nvkm_i2c_port
*
port
;
struct
nvkm_i2c_bus
*
bus
;
struct
nvkm_i2c_pad
*
pad
;
int
ret
;
ret
=
nvkm_subdev_init
(
&
i2c
->
subdev
);
if
(
ret
==
0
)
{
list_for_each_entry
(
port
,
&
i2c
->
ports
,
head
)
{
ret
=
nv_ofuncs
(
port
)
->
init
(
nv_object
(
port
));
if
(
ret
)
goto
fail
;
}
return
ret
;
list_for_each_entry
(
pad
,
&
i2c
->
pad
,
head
)
{
nvkm_i2c_pad_init
(
pad
);
}
return
ret
;
fail:
list_for_each_entry_continue_reverse
(
port
,
&
i2c
->
ports
,
head
)
{
nv_ofuncs
(
port
)
->
fini
(
nv_object
(
port
),
false
);
list_for_each_entry
(
bus
,
&
i2c
->
bus
,
head
)
{
nvkm_i2c_bus_init
(
bus
);
}
return
ret
;
return
0
;
}
void
_nvkm_i2c_dtor
(
struct
nvkm_object
*
object
)
{
struct
nvkm_i2c
*
i2c
=
(
void
*
)
object
;
struct
nvkm_i2c_port
*
port
,
*
temp
;
nvkm_event_fini
(
&
i2c
->
event
);
list_for_each_entry_safe
(
port
,
temp
,
&
i2c
->
ports
,
head
)
{
nvkm_object_ref
(
NULL
,
(
struct
nvkm_object
**
)
&
port
);
while
(
!
list_empty
(
&
i2c
->
aux
))
{
struct
nvkm_i2c_aux
*
aux
=
list_first_entry
(
&
i2c
->
aux
,
typeof
(
*
aux
),
head
);
nvkm_i2c_aux_del
(
&
aux
);
}
nvkm_subdev_destroy
(
&
i2c
->
subdev
);
}
static
struct
nvkm_oclass
*
nvkm_i2c_extdev_sclass
[]
=
{
nvkm_anx9805_sclass
,
};
static
void
nvkm_i2c_create_port
(
struct
nvkm_i2c
*
i2c
,
int
index
,
u8
type
,
struct
dcb_i2c_entry
*
info
)
{
const
struct
nvkm_i2c_impl
*
impl
=
(
void
*
)
nv_oclass
(
i2c
);
struct
nvkm_oclass
*
oclass
;
struct
nvkm_object
*
parent
;
struct
nvkm_object
*
object
;
int
ret
,
pad
;
if
(
info
->
share
!=
DCB_I2C_UNUSED
)
{
pad
=
info
->
share
;
oclass
=
impl
->
pad_s
;
}
else
{
if
(
type
!=
DCB_I2C_NVIO_AUX
)
pad
=
0x100
+
info
->
drive
;
else
pad
=
0x100
+
info
->
auxch
;
oclass
=
impl
->
pad_x
;
while
(
!
list_empty
(
&
i2c
->
bus
))
{
struct
nvkm_i2c_bus
*
bus
=
list_first_entry
(
&
i2c
->
bus
,
typeof
(
*
bus
),
head
);
nvkm_i2c_bus_del
(
&
bus
);
}
ret
=
nvkm_object_ctor
(
nv_object
(
i2c
),
NULL
,
oclass
,
NULL
,
pad
,
&
parent
);
if
(
ret
<
0
)
return
;
oclass
=
impl
->
sclass
;
do
{
ret
=
-
EINVAL
;
if
(
oclass
->
handle
==
type
)
{
ret
=
nvkm_object_ctor
(
parent
,
NULL
,
oclass
,
info
,
index
,
&
object
);
while
(
!
list_empty
(
&
i2c
->
pad
))
{
struct
nvkm_i2c_pad
*
pad
=
list_first_entry
(
&
i2c
->
pad
,
typeof
(
*
pad
),
head
);
nvkm_i2c_pad_del
(
&
pad
);
}
}
while
(
ret
&&
(
++
oclass
)
->
handle
);
nvkm_object_ref
(
NULL
,
&
parent
);
nvkm_subdev_destroy
(
&
i2c
->
subdev
);
}
static
const
struct
nvkm_i2c_drv
{
u8
bios
;
u8
addr
;
int
(
*
pad_new
)(
struct
nvkm_i2c_bus
*
,
int
id
,
u8
addr
,
struct
nvkm_i2c_pad
**
);
}
nvkm_i2c_drv
[]
=
{
{
0x0d
,
0x39
,
anx9805_pad_new
},
{
0x0e
,
0x3b
,
anx9805_pad_new
},
{}
};
int
nvkm_i2c_create_
(
struct
nvkm_object
*
parent
,
struct
nvkm_object
*
engine
,
struct
nvkm_oclass
*
oclass
,
int
length
,
void
**
pobject
)
{
struct
nvkm_bios
*
bios
=
nvkm_bios
(
parent
);
struct
nvkm_i2c_impl
*
impl
=
(
void
*
)
oclass
;
struct
nvkm_device
*
device
=
(
void
*
)
parent
;
struct
nvkm_bios
*
bios
=
device
->
bios
;
struct
nvkm_i2c
*
i2c
;
struct
nvkm_object
*
object
;
struct
dcb_i2c_entry
info
;
int
ret
,
i
,
j
,
index
=
-
1
;
struct
dcb_output
outp
;
struct
dcb_i2c_entry
ccbE
;
struct
dcb_output
dcbE
;
u8
ver
,
hdr
;
u32
data
;
int
ret
,
i
;
ret
=
nvkm_subdev_create
(
parent
,
engine
,
oclass
,
0
,
"I2C"
,
"i2c"
,
&
i2c
);
*
pobject
=
nv_object
(
i2c
);
if
(
ret
)
return
ret
;
INIT_LIST_HEAD
(
&
i2c
->
pad
);
INIT_LIST_HEAD
(
&
i2c
->
bus
);
INIT_LIST_HEAD
(
&
i2c
->
aux
);
nv_subdev
(
i2c
)
->
intr
=
nvkm_i2c_intr
;
i2c
->
find
=
nvkm_i2c_find
;
i2c
->
find_type
=
nvkm_i2c_find_type
;
i2c
->
acquire_pad
=
nvkm_i2c_acquire_pad
;
i2c
->
release_pad
=
nvkm_i2c_release_pad
;
i2c
->
acquire
=
nvkm_i2c_acquire
;
i2c
->
release
=
nvkm_i2c_release
;
i2c
->
identify
=
nvkm_i2c_identify
;
init_waitqueue_head
(
&
i2c
->
wait
);
INIT_LIST_HEAD
(
&
i2c
->
ports
);
while
(
!
dcb_i2c_parse
(
bios
,
++
index
,
&
info
))
{
switch
(
info
.
type
)
{
case
DCB_I2C_NV04_BIT
:
case
DCB_I2C_NV4E_BIT
:
case
DCB_I2C_NVIO_BIT
:
nvkm_i2c_create_port
(
i2c
,
NV_I2C_PORT
(
index
),
info
.
type
,
&
info
);
break
;
case
DCB_I2C_NVIO_AUX
:
nvkm_i2c_create_port
(
i2c
,
NV_I2C_AUX
(
index
),
info
.
type
,
&
info
);
break
;
case
DCB_I2C_PMGR
:
if
(
info
.
drive
!=
DCB_I2C_UNUSED
)
{
nvkm_i2c_create_port
(
i2c
,
NV_I2C_PORT
(
index
),
DCB_I2C_NVIO_BIT
,
&
info
);
i
=
-
1
;
while
(
!
dcb_i2c_parse
(
bios
,
++
i
,
&
ccbE
))
{
struct
nvkm_i2c_pad
*
pad
=
NULL
;
struct
nvkm_i2c_bus
*
bus
=
NULL
;
struct
nvkm_i2c_aux
*
aux
=
NULL
;
nvkm_debug
(
&
i2c
->
subdev
,
"ccb %02x: type %02x drive %02x "
"sense %02x share %02x auxch %02x
\n
"
,
i
,
ccbE
.
type
,
ccbE
.
drive
,
ccbE
.
sense
,
ccbE
.
share
,
ccbE
.
auxch
);
if
(
ccbE
.
share
!=
DCB_I2C_UNUSED
)
{
const
int
id
=
NVKM_I2C_PAD_HYBRID
(
ccbE
.
share
);
if
(
!
(
pad
=
nvkm_i2c_pad_find
(
i2c
,
id
)))
ret
=
impl
->
pad_s_new
(
i2c
,
id
,
&
pad
);
else
ret
=
0
;
}
else
{
ret
=
impl
->
pad_x_new
(
i2c
,
NVKM_I2C_PAD_CCB
(
i
),
&
pad
);
}
if
(
ret
)
{
nvkm_error
(
&
i2c
->
subdev
,
"ccb %02x pad, %d
\n
"
,
i
,
ret
);
nvkm_i2c_pad_del
(
&
pad
);
continue
;
}
if
(
info
.
auxch
!=
DCB_I2C_UNUSED
)
{
nvkm_i2c_create_port
(
i2c
,
NV_I2C_AUX
(
index
),
DCB_I2C_NVIO_AUX
,
&
info
);
if
(
pad
->
func
->
bus_new_0
&&
ccbE
.
type
==
DCB_I2C_NV04_BIT
)
{
ret
=
pad
->
func
->
bus_new_0
(
pad
,
NVKM_I2C_BUS_CCB
(
i
),
ccbE
.
drive
,
ccbE
.
sense
,
&
bus
);
}
else
if
(
pad
->
func
->
bus_new_4
&&
(
ccbE
.
type
==
DCB_I2C_NV4E_BIT
||
ccbE
.
type
==
DCB_I2C_NVIO_BIT
||
(
ccbE
.
type
==
DCB_I2C_PMGR
&&
ccbE
.
drive
!=
DCB_I2C_UNUSED
)))
{
ret
=
pad
->
func
->
bus_new_4
(
pad
,
NVKM_I2C_BUS_CCB
(
i
),
ccbE
.
drive
,
&
bus
);
}
break
;
case
DCB_I2C_UNUSED
:
default:
if
(
ret
)
{
nvkm_error
(
&
i2c
->
subdev
,
"ccb %02x bus, %d
\n
"
,
i
,
ret
);
nvkm_i2c_bus_del
(
&
bus
);
}
if
(
pad
->
func
->
aux_new_6
&&
(
ccbE
.
type
==
DCB_I2C_NVIO_AUX
||
(
ccbE
.
type
==
DCB_I2C_PMGR
&&
ccbE
.
auxch
!=
DCB_I2C_UNUSED
)))
{
ret
=
pad
->
func
->
aux_new_6
(
pad
,
NVKM_I2C_BUS_CCB
(
i
),
ccbE
.
auxch
,
&
aux
);
}
else
{
ret
=
0
;
}
if
(
ret
)
{
nvkm_error
(
&
i2c
->
subdev
,
"ccb %02x aux, %d
\n
"
,
i
,
ret
);
nvkm_i2c_aux_del
(
&
aux
);
}
if
(
ccbE
.
type
!=
DCB_I2C_UNUSED
&&
!
bus
&&
!
aux
)
{
nvkm_warn
(
&
i2c
->
subdev
,
"ccb %02x was ignored
\n
"
,
i
);
continue
;
}
}
/* in addition to the busses specified in the i2c table, there
* may be ddc/aux channels hiding behind external tmds/dp/etc
* transmitters.
*/
index
=
NV_I2C_EXT
(
0
);
i
=
-
1
;
while
((
data
=
dcb_outp_parse
(
bios
,
++
i
,
&
ver
,
&
hdr
,
&
outp
)))
{
if
(
!
outp
.
location
||
!
outp
.
extdev
)
while
(
dcb_outp_parse
(
bios
,
++
i
,
&
ver
,
&
hdr
,
&
dcbE
))
{
const
struct
nvkm_i2c_drv
*
drv
=
nvkm_i2c_drv
;
struct
nvkm_i2c_bus
*
bus
;
struct
nvkm_i2c_pad
*
pad
;
/* internal outputs handled by native i2c busses (above) */
if
(
!
dcbE
.
location
)
continue
;
switch
(
outp
.
type
)
{
case
DCB_OUTPUT_TMDS
:
info
.
type
=
NV_I2C_TYPE_EXTDDC
(
outp
.
extdev
);
break
;
case
DCB_OUTPUT_DP
:
info
.
type
=
NV_I2C_TYPE_EXTAUX
(
outp
.
extdev
);
/* we need an i2c bus to talk to the external encoder */
bus
=
nvkm_i2c_bus_find
(
i2c
,
dcbE
.
i2c_index
);
if
(
!
bus
)
{
nvkm_debug
(
&
i2c
->
subdev
,
"dcb %02x no bus
\n
"
,
i
);
continue
;
}
/* ... and a driver for it */
while
(
drv
->
pad_new
)
{
if
(
drv
->
bios
==
dcbE
.
extdev
)
break
;
default:
drv
++
;
}
if
(
!
drv
->
pad_new
)
{
nvkm_debug
(
&
i2c
->
subdev
,
"dcb %02x drv %02x unknown
\n
"
,
i
,
dcbE
.
extdev
);
continue
;
}
ret
=
-
ENODEV
;
j
=
-
1
;
while
(
ret
&&
++
j
<
ARRAY_SIZE
(
nvkm_i2c_extdev_sclass
))
{
parent
=
nv_object
(
i2c
->
find
(
i2c
,
outp
.
i2c_index
));
oclass
=
nvkm_i2c_extdev_sclass
[
j
];
do
{
if
(
oclass
->
handle
!=
info
.
type
)
/* find/create an instance of the driver */
pad
=
nvkm_i2c_pad_find
(
i2c
,
NVKM_I2C_PAD_EXT
(
dcbE
.
extdev
));
if
(
!
pad
)
{
const
int
id
=
NVKM_I2C_PAD_EXT
(
dcbE
.
extdev
);
ret
=
drv
->
pad_new
(
bus
,
id
,
drv
->
addr
,
&
pad
);
if
(
ret
)
{
nvkm_error
(
&
i2c
->
subdev
,
"dcb %02x pad, %d
\n
"
,
i
,
ret
);
nvkm_i2c_pad_del
(
&
pad
);
continue
;
ret
=
nvkm_object_ctor
(
parent
,
NULL
,
oclass
,
NULL
,
index
++
,
&
object
);
}
while
(
ret
&&
(
++
oclass
)
->
handle
);
}
}
ret
=
nvkm_event_init
(
&
nvkm_i2c_intr_func
,
4
,
index
,
&
i2c
->
event
);
/* create any i2c bus / aux channel required by the output */
if
(
pad
->
func
->
aux_new_6
&&
dcbE
.
type
==
DCB_OUTPUT_DP
)
{
const
int
id
=
NVKM_I2C_AUX_EXT
(
dcbE
.
extdev
);
struct
nvkm_i2c_aux
*
aux
=
NULL
;
ret
=
pad
->
func
->
aux_new_6
(
pad
,
id
,
0
,
&
aux
);
if
(
ret
)
{
nvkm_error
(
&
i2c
->
subdev
,
"dcb %02x aux, %d
\n
"
,
i
,
ret
);
nvkm_i2c_aux_del
(
&
aux
);
}
}
else
if
(
pad
->
func
->
bus_new_4
)
{
const
int
id
=
NVKM_I2C_BUS_EXT
(
dcbE
.
extdev
);
struct
nvkm_i2c_bus
*
bus
=
NULL
;
ret
=
pad
->
func
->
bus_new_4
(
pad
,
id
,
0
,
&
bus
);
if
(
ret
)
{
nvkm_error
(
&
i2c
->
subdev
,
"dcb %02x bus, %d
\n
"
,
i
,
ret
);
nvkm_i2c_bus_del
(
&
bus
);
}
}
}
ret
=
nvkm_event_init
(
&
nvkm_i2c_intr_func
,
4
,
i
,
&
i2c
->
event
);
if
(
ret
)
return
ret
;
...
...
drivers/gpu/drm/nouveau/nvkm/subdev/i2c/bit.c
View file @
2aa5eac5
...
...
@@ -9,7 +9,7 @@
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial
port
ions of the Software.
* all copies or substantial
bus
ions 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,
...
...
@@ -21,7 +21,7 @@
*
* Authors: Ben Skeggs
*/
#include "
priv
.h"
#include "
bus
.h"
#ifdef CONFIG_NOUVEAU_I2C_INTERNAL
#define T_TIMEOUT 2200000
...
...
@@ -29,205 +29,188 @@
#define T_HOLD 5000
static
inline
void
i2c_drive_scl
(
struct
nvkm_i2c_port
*
port
,
int
state
)
nvkm_i2c_drive_scl
(
struct
nvkm_i2c_bus
*
bus
,
int
state
)
{
port
->
func
->
drive_scl
(
port
,
state
);
bus
->
func
->
drive_scl
(
bus
,
state
);
}
static
inline
void
i2c_drive_sda
(
struct
nvkm_i2c_port
*
port
,
int
state
)
nvkm_i2c_drive_sda
(
struct
nvkm_i2c_bus
*
bus
,
int
state
)
{
port
->
func
->
drive_sda
(
port
,
state
);
bus
->
func
->
drive_sda
(
bus
,
state
);
}
static
inline
int
i2c_sense_scl
(
struct
nvkm_i2c_port
*
port
)
nvkm_i2c_sense_scl
(
struct
nvkm_i2c_bus
*
bus
)
{
return
port
->
func
->
sense_scl
(
port
);
return
bus
->
func
->
sense_scl
(
bus
);
}
static
inline
int
i2c_sense_sda
(
struct
nvkm_i2c_port
*
port
)
nvkm_i2c_sense_sda
(
struct
nvkm_i2c_bus
*
bus
)
{
return
port
->
func
->
sense_sda
(
port
);
return
bus
->
func
->
sense_sda
(
bus
);
}
static
void
i2c_delay
(
struct
nvkm_i2c_port
*
port
,
u32
nsec
)
nvkm_i2c_delay
(
struct
nvkm_i2c_bus
*
bus
,
u32
nsec
)
{
udelay
((
nsec
+
500
)
/
1000
);
}
static
bool
i2c_raise_scl
(
struct
nvkm_i2c_port
*
port
)
nvkm_i2c_raise_scl
(
struct
nvkm_i2c_bus
*
bus
)
{
u32
timeout
=
T_TIMEOUT
/
T_RISEFALL
;
i2c_drive_scl
(
port
,
1
);
nvkm_i2c_drive_scl
(
bus
,
1
);
do
{
i2c_delay
(
port
,
T_RISEFALL
);
}
while
(
!
i2c_sense_scl
(
port
)
&&
--
timeout
);
nvkm_i2c_delay
(
bus
,
T_RISEFALL
);
}
while
(
!
nvkm_i2c_sense_scl
(
bus
)
&&
--
timeout
);
return
timeout
!=
0
;
}
static
int
i2c_start
(
struct
nvkm_i2c_
port
*
port
)
i2c_start
(
struct
nvkm_i2c_
bus
*
bus
)
{
int
ret
=
0
;
if
(
!
i2c_sense_scl
(
port
)
||
!
i2c_sense_sda
(
port
))
{
i2c_drive_scl
(
port
,
0
);
i2c_drive_sda
(
port
,
1
);
if
(
!
i2c_raise_scl
(
port
))
if
(
!
nvkm_i2c_sense_scl
(
bus
)
||
!
nvkm_i2c_sense_sda
(
bus
))
{
nvkm_i2c_drive_scl
(
bus
,
0
);
nvkm_i2c_drive_sda
(
bus
,
1
);
if
(
!
nvkm_i2c_raise_scl
(
bus
))
ret
=
-
EBUSY
;
}
i2c_drive_sda
(
port
,
0
);
i2c_delay
(
port
,
T_HOLD
);
i2c_drive_scl
(
port
,
0
);
i2c_delay
(
port
,
T_HOLD
);
nvkm_i2c_drive_sda
(
bus
,
0
);
nvkm_i2c_delay
(
bus
,
T_HOLD
);
nvkm_i2c_drive_scl
(
bus
,
0
);
nvkm_i2c_delay
(
bus
,
T_HOLD
);
return
ret
;
}
static
void
i2c_stop
(
struct
nvkm_i2c_
port
*
port
)
i2c_stop
(
struct
nvkm_i2c_
bus
*
bus
)
{
i2c_drive_scl
(
port
,
0
);
i2c_drive_sda
(
port
,
0
);
i2c_delay
(
port
,
T_RISEFALL
);
i2c_drive_scl
(
port
,
1
);
i2c_delay
(
port
,
T_HOLD
);
i2c_drive_sda
(
port
,
1
);
i2c_delay
(
port
,
T_HOLD
);
nvkm_i2c_drive_scl
(
bus
,
0
);
nvkm_i2c_drive_sda
(
bus
,
0
);
nvkm_i2c_delay
(
bus
,
T_RISEFALL
);
nvkm_i2c_drive_scl
(
bus
,
1
);
nvkm_i2c_delay
(
bus
,
T_HOLD
);
nvkm_i2c_drive_sda
(
bus
,
1
);
nvkm_i2c_delay
(
bus
,
T_HOLD
);
}
static
int
i2c_bitw
(
struct
nvkm_i2c_
port
*
port
,
int
sda
)
i2c_bitw
(
struct
nvkm_i2c_
bus
*
bus
,
int
sda
)
{
i2c_drive_sda
(
port
,
sda
);
i2c_delay
(
port
,
T_RISEFALL
);
nvkm_i2c_drive_sda
(
bus
,
sda
);
nvkm_i2c_delay
(
bus
,
T_RISEFALL
);
if
(
!
i2c_raise_scl
(
port
))
if
(
!
nvkm_i2c_raise_scl
(
bus
))
return
-
ETIMEDOUT
;
i2c_delay
(
port
,
T_HOLD
);
nvkm_i2c_delay
(
bus
,
T_HOLD
);
i2c_drive_scl
(
port
,
0
);
i2c_delay
(
port
,
T_HOLD
);
nvkm_i2c_drive_scl
(
bus
,
0
);
nvkm_i2c_delay
(
bus
,
T_HOLD
);
return
0
;
}
static
int
i2c_bitr
(
struct
nvkm_i2c_
port
*
port
)
i2c_bitr
(
struct
nvkm_i2c_
bus
*
bus
)
{
int
sda
;
i2c_drive_sda
(
port
,
1
);
i2c_delay
(
port
,
T_RISEFALL
);
nvkm_i2c_drive_sda
(
bus
,
1
);
nvkm_i2c_delay
(
bus
,
T_RISEFALL
);
if
(
!
i2c_raise_scl
(
port
))
if
(
!
nvkm_i2c_raise_scl
(
bus
))
return
-
ETIMEDOUT
;
i2c_delay
(
port
,
T_HOLD
);
nvkm_i2c_delay
(
bus
,
T_HOLD
);
sda
=
i2c_sense_sda
(
port
);
sda
=
nvkm_i2c_sense_sda
(
bus
);
i2c_drive_scl
(
port
,
0
);
i2c_delay
(
port
,
T_HOLD
);
nvkm_i2c_drive_scl
(
bus
,
0
);
nvkm_i2c_delay
(
bus
,
T_HOLD
);
return
sda
;
}
static
int
i2c_get_byte
(
struct
nvkm_i2c_port
*
port
,
u8
*
byte
,
bool
last
)
nvkm_i2c_get_byte
(
struct
nvkm_i2c_bus
*
bus
,
u8
*
byte
,
bool
last
)
{
int
i
,
bit
;
*
byte
=
0
;
for
(
i
=
7
;
i
>=
0
;
i
--
)
{
bit
=
i2c_bitr
(
port
);
bit
=
i2c_bitr
(
bus
);
if
(
bit
<
0
)
return
bit
;
*
byte
|=
bit
<<
i
;
}
return
i2c_bitw
(
port
,
last
?
1
:
0
);
return
i2c_bitw
(
bus
,
last
?
1
:
0
);
}
static
int
i2c_put_byte
(
struct
nvkm_i2c_port
*
port
,
u8
byte
)
nvkm_i2c_put_byte
(
struct
nvkm_i2c_bus
*
bus
,
u8
byte
)
{
int
i
,
ret
;
for
(
i
=
7
;
i
>=
0
;
i
--
)
{
ret
=
i2c_bitw
(
port
,
!!
(
byte
&
(
1
<<
i
)));
ret
=
i2c_bitw
(
bus
,
!!
(
byte
&
(
1
<<
i
)));
if
(
ret
<
0
)
return
ret
;
}
ret
=
i2c_bitr
(
port
);
ret
=
i2c_bitr
(
bus
);
if
(
ret
==
1
)
/* nack */
ret
=
-
EIO
;
return
ret
;
}
static
int
i2c_addr
(
struct
nvkm_i2c_
port
*
port
,
struct
i2c_msg
*
msg
)
i2c_addr
(
struct
nvkm_i2c_
bus
*
bus
,
struct
i2c_msg
*
msg
)
{
u32
addr
=
msg
->
addr
<<
1
;
if
(
msg
->
flags
&
I2C_M_RD
)
addr
|=
1
;
return
i2c_put_byte
(
port
,
addr
);
return
nvkm_i2c_put_byte
(
bus
,
addr
);
}
static
int
i2c_bit_xfer
(
struct
i2c_adapter
*
adap
,
struct
i2c_msg
*
msgs
,
int
num
)
int
nvkm_i2c_bit_xfer
(
struct
nvkm_i2c_bus
*
bus
,
struct
i2c_msg
*
msgs
,
int
num
)
{
struct
nvkm_i2c_port
*
port
=
adap
->
algo_data
;
struct
i2c_msg
*
msg
=
msgs
;
int
ret
=
0
,
mcnt
=
num
;
ret
=
nvkm_i2c
(
port
)
->
acquire
(
port
,
nsecs_to_jiffies
(
T_TIMEOUT
));
if
(
ret
)
return
ret
;
while
(
!
ret
&&
mcnt
--
)
{
u8
remaining
=
msg
->
len
;
u8
*
ptr
=
msg
->
buf
;
ret
=
i2c_start
(
port
);
ret
=
i2c_start
(
bus
);
if
(
ret
==
0
)
ret
=
i2c_addr
(
port
,
msg
);
ret
=
i2c_addr
(
bus
,
msg
);
if
(
msg
->
flags
&
I2C_M_RD
)
{
while
(
!
ret
&&
remaining
--
)
ret
=
i2c_get_byte
(
port
,
ptr
++
,
!
remaining
);
ret
=
nvkm_i2c_get_byte
(
bus
,
ptr
++
,
!
remaining
);
}
else
{
while
(
!
ret
&&
remaining
--
)
ret
=
i2c_put_byte
(
port
,
*
ptr
++
);
ret
=
nvkm_i2c_put_byte
(
bus
,
*
ptr
++
);
}
msg
++
;
}
i2c_stop
(
port
);
nvkm_i2c
(
port
)
->
release
(
port
);
i2c_stop
(
bus
);
return
(
ret
<
0
)
?
ret
:
num
;
}
#else
static
int
i2c_bit_xfer
(
struct
i2c_adapter
*
adap
,
struct
i2c_msg
*
msgs
,
int
num
)
int
nvkm_i2c_bit_xfer
(
struct
nvkm_i2c_bus
*
bus
,
struct
i2c_msg
*
msgs
,
int
num
)
{
return
-
ENODEV
;
}
#endif
static
u32
i2c_bit_func
(
struct
i2c_adapter
*
adap
)
{
return
I2C_FUNC_I2C
|
I2C_FUNC_SMBUS_EMUL
;
}
const
struct
i2c_algorithm
nvkm_i2c_bit_algo
=
{
.
master_xfer
=
i2c_bit_xfer
,
.
functionality
=
i2c_bit_func
};
drivers/gpu/drm/nouveau/nvkm/subdev/i2c/bus.c
0 → 100644
View file @
2aa5eac5
/*
* Copyright 2015 Red Hat Inc.
*
* 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 shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* THE COPYRIGHT HOLDER(S) OR AUTHOR(S) 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: Ben Skeggs <bskeggs@redhat.com>
*/
#include "bus.h"
#include "pad.h"
#include <core/option.h>
/*******************************************************************************
* i2c-algo-bit
******************************************************************************/
static
int
nvkm_i2c_bus_pre_xfer
(
struct
i2c_adapter
*
adap
)
{
struct
nvkm_i2c_bus
*
bus
=
container_of
(
adap
,
typeof
(
*
bus
),
i2c
);
return
nvkm_i2c_bus_acquire
(
bus
);
}
static
void
nvkm_i2c_bus_post_xfer
(
struct
i2c_adapter
*
adap
)
{
struct
nvkm_i2c_bus
*
bus
=
container_of
(
adap
,
typeof
(
*
bus
),
i2c
);
return
nvkm_i2c_bus_release
(
bus
);
}
static
void
nvkm_i2c_bus_setscl
(
void
*
data
,
int
state
)
{
struct
nvkm_i2c_bus
*
bus
=
data
;
bus
->
func
->
drive_scl
(
bus
,
state
);
}
static
void
nvkm_i2c_bus_setsda
(
void
*
data
,
int
state
)
{
struct
nvkm_i2c_bus
*
bus
=
data
;
bus
->
func
->
drive_sda
(
bus
,
state
);
}
static
int
nvkm_i2c_bus_getscl
(
void
*
data
)
{
struct
nvkm_i2c_bus
*
bus
=
data
;
return
bus
->
func
->
sense_scl
(
bus
);
}
static
int
nvkm_i2c_bus_getsda
(
void
*
data
)
{
struct
nvkm_i2c_bus
*
bus
=
data
;
return
bus
->
func
->
sense_sda
(
bus
);
}
/*******************************************************************************
* !i2c-algo-bit (off-chip i2c bus / hw i2c / internal bit-banging algo)
******************************************************************************/
static
int
nvkm_i2c_bus_xfer
(
struct
i2c_adapter
*
adap
,
struct
i2c_msg
*
msgs
,
int
num
)
{
struct
nvkm_i2c_bus
*
bus
=
container_of
(
adap
,
typeof
(
*
bus
),
i2c
);
int
ret
;
ret
=
nvkm_i2c_bus_acquire
(
bus
);
if
(
ret
)
return
ret
;
ret
=
bus
->
func
->
xfer
(
bus
,
msgs
,
num
);
nvkm_i2c_bus_release
(
bus
);
return
ret
;
}
static
u32
nvkm_i2c_bus_func
(
struct
i2c_adapter
*
adap
)
{
return
I2C_FUNC_I2C
|
I2C_FUNC_SMBUS_EMUL
;
}
static
const
struct
i2c_algorithm
nvkm_i2c_bus_algo
=
{
.
master_xfer
=
nvkm_i2c_bus_xfer
,
.
functionality
=
nvkm_i2c_bus_func
,
};
/*******************************************************************************
* nvkm_i2c_bus base
******************************************************************************/
void
nvkm_i2c_bus_init
(
struct
nvkm_i2c_bus
*
bus
)
{
BUS_TRACE
(
bus
,
"init"
);
if
(
bus
->
func
->
init
)
bus
->
func
->
init
(
bus
);
}
void
nvkm_i2c_bus_release
(
struct
nvkm_i2c_bus
*
bus
)
{
struct
nvkm_i2c_pad
*
pad
=
bus
->
pad
;
BUS_TRACE
(
bus
,
"release"
);
nvkm_i2c_pad_release
(
pad
);
mutex_unlock
(
&
bus
->
mutex
);
}
int
nvkm_i2c_bus_acquire
(
struct
nvkm_i2c_bus
*
bus
)
{
struct
nvkm_i2c_pad
*
pad
=
bus
->
pad
;
int
ret
;
BUS_TRACE
(
bus
,
"acquire"
);
mutex_lock
(
&
bus
->
mutex
);
ret
=
nvkm_i2c_pad_acquire
(
pad
,
NVKM_I2C_PAD_I2C
);
if
(
ret
)
mutex_unlock
(
&
bus
->
mutex
);
return
ret
;
}
int
nvkm_i2c_bus_probe
(
struct
nvkm_i2c_bus
*
bus
,
const
char
*
what
,
struct
nvkm_i2c_bus_probe
*
info
,
bool
(
*
match
)(
struct
nvkm_i2c_bus
*
,
struct
i2c_board_info
*
,
void
*
),
void
*
data
)
{
int
i
;
BUS_DBG
(
bus
,
"probing %ss"
,
what
);
for
(
i
=
0
;
info
[
i
].
dev
.
addr
;
i
++
)
{
u8
orig_udelay
=
0
;
if
((
bus
->
i2c
.
algo
==
&
i2c_bit_algo
)
&&
(
info
[
i
].
udelay
!=
0
))
{
struct
i2c_algo_bit_data
*
algo
=
bus
->
i2c
.
algo_data
;
BUS_DBG
(
bus
,
"%dms delay instead of %dms"
,
info
[
i
].
udelay
,
algo
->
udelay
);
orig_udelay
=
algo
->
udelay
;
algo
->
udelay
=
info
[
i
].
udelay
;
}
if
(
nvkm_probe_i2c
(
&
bus
->
i2c
,
info
[
i
].
dev
.
addr
)
&&
(
!
match
||
match
(
bus
,
&
info
[
i
].
dev
,
data
)))
{
BUS_DBG
(
bus
,
"detected %s: %s"
,
what
,
info
[
i
].
dev
.
type
);
return
i
;
}
if
(
orig_udelay
)
{
struct
i2c_algo_bit_data
*
algo
=
bus
->
i2c
.
algo_data
;
algo
->
udelay
=
orig_udelay
;
}
}
BUS_DBG
(
bus
,
"no devices found."
);
return
-
ENODEV
;
}
void
nvkm_i2c_bus_del
(
struct
nvkm_i2c_bus
**
pbus
)
{
struct
nvkm_i2c_bus
*
bus
=
*
pbus
;
if
(
bus
&&
!
WARN_ON
(
!
bus
->
func
))
{
BUS_TRACE
(
bus
,
"dtor"
);
list_del
(
&
bus
->
head
);
i2c_del_adapter
(
&
bus
->
i2c
);
kfree
(
bus
->
i2c
.
algo_data
);
kfree
(
*
pbus
);
*
pbus
=
NULL
;
}
}
int
nvkm_i2c_bus_ctor
(
const
struct
nvkm_i2c_bus_func
*
func
,
struct
nvkm_i2c_pad
*
pad
,
int
id
,
struct
nvkm_i2c_bus
*
bus
)
{
struct
nvkm_device
*
device
=
pad
->
i2c
->
subdev
.
device
;
struct
i2c_algo_bit_data
*
bit
;
#ifndef CONFIG_NOUVEAU_I2C_INTERNAL_DEFAULT
const
bool
internal
=
false
;
#else
const
bool
internal
=
true
;
#endif
int
ret
;
bus
->
func
=
func
;
bus
->
pad
=
pad
;
bus
->
id
=
id
;
mutex_init
(
&
bus
->
mutex
);
list_add_tail
(
&
bus
->
head
,
&
pad
->
i2c
->
bus
);
BUS_TRACE
(
bus
,
"ctor"
);
snprintf
(
bus
->
i2c
.
name
,
sizeof
(
bus
->
i2c
.
name
),
"nvkm-%s-bus-%04x"
,
dev_name
(
device
->
dev
),
id
);
bus
->
i2c
.
owner
=
THIS_MODULE
;
bus
->
i2c
.
dev
.
parent
=
device
->
dev
;
if
(
bus
->
func
->
drive_scl
&&
!
nvkm_boolopt
(
device
->
cfgopt
,
"NvI2C"
,
internal
))
{
if
(
!
(
bit
=
kzalloc
(
sizeof
(
*
bit
),
GFP_KERNEL
)))
return
-
ENOMEM
;
bit
->
udelay
=
10
;
bit
->
timeout
=
usecs_to_jiffies
(
2200
);
bit
->
data
=
bus
;
bit
->
pre_xfer
=
nvkm_i2c_bus_pre_xfer
;
bit
->
post_xfer
=
nvkm_i2c_bus_post_xfer
;
bit
->
setscl
=
nvkm_i2c_bus_setscl
;
bit
->
setsda
=
nvkm_i2c_bus_setsda
;
bit
->
getscl
=
nvkm_i2c_bus_getscl
;
bit
->
getsda
=
nvkm_i2c_bus_getsda
;
bus
->
i2c
.
algo_data
=
bit
;
ret
=
i2c_bit_add_bus
(
&
bus
->
i2c
);
}
else
{
bus
->
i2c
.
algo
=
&
nvkm_i2c_bus_algo
;
ret
=
i2c_add_adapter
(
&
bus
->
i2c
);
}
return
ret
;
}
int
nvkm_i2c_bus_new_
(
const
struct
nvkm_i2c_bus_func
*
func
,
struct
nvkm_i2c_pad
*
pad
,
int
id
,
struct
nvkm_i2c_bus
**
pbus
)
{
if
(
!
(
*
pbus
=
kzalloc
(
sizeof
(
**
pbus
),
GFP_KERNEL
)))
return
-
ENOMEM
;
return
nvkm_i2c_bus_ctor
(
func
,
pad
,
id
,
*
pbus
);
}
drivers/gpu/drm/nouveau/nvkm/subdev/i2c/bus.h
0 → 100644
View file @
2aa5eac5
#ifndef __NVKM_I2C_BUS_H__
#define __NVKM_I2C_BUS_H__
#include "pad.h"
struct
nvkm_i2c_bus_func
{
void
(
*
init
)(
struct
nvkm_i2c_bus
*
);
void
(
*
drive_scl
)(
struct
nvkm_i2c_bus
*
,
int
state
);
void
(
*
drive_sda
)(
struct
nvkm_i2c_bus
*
,
int
state
);
int
(
*
sense_scl
)(
struct
nvkm_i2c_bus
*
);
int
(
*
sense_sda
)(
struct
nvkm_i2c_bus
*
);
int
(
*
xfer
)(
struct
nvkm_i2c_bus
*
,
struct
i2c_msg
*
,
int
num
);
};
int
nvkm_i2c_bus_ctor
(
const
struct
nvkm_i2c_bus_func
*
,
struct
nvkm_i2c_pad
*
,
int
id
,
struct
nvkm_i2c_bus
*
);
int
nvkm_i2c_bus_new_
(
const
struct
nvkm_i2c_bus_func
*
,
struct
nvkm_i2c_pad
*
,
int
id
,
struct
nvkm_i2c_bus
**
);
void
nvkm_i2c_bus_del
(
struct
nvkm_i2c_bus
**
);
void
nvkm_i2c_bus_init
(
struct
nvkm_i2c_bus
*
);
int
nvkm_i2c_bit_xfer
(
struct
nvkm_i2c_bus
*
,
struct
i2c_msg
*
,
int
);
int
nv04_i2c_bus_new
(
struct
nvkm_i2c_pad
*
,
int
,
u8
,
u8
,
struct
nvkm_i2c_bus
**
);
int
nv4e_i2c_bus_new
(
struct
nvkm_i2c_pad
*
,
int
,
u8
,
struct
nvkm_i2c_bus
**
);
int
nv50_i2c_bus_new
(
struct
nvkm_i2c_pad
*
,
int
,
u8
,
struct
nvkm_i2c_bus
**
);
int
gf119_i2c_bus_new
(
struct
nvkm_i2c_pad
*
,
int
,
u8
,
struct
nvkm_i2c_bus
**
);
#define BUS_MSG(b,l,f,a...) do { \
struct nvkm_i2c_bus *_bus = (b); \
nvkm_##l(&_bus->pad->i2c->subdev, "bus %04x: "f"\n", _bus->id, ##a); \
} while(0)
#define BUS_ERR(b,f,a...) BUS_MSG((b), error, f, ##a)
#define BUS_DBG(b,f,a...) BUS_MSG((b), debug, f, ##a)
#define BUS_TRACE(b,f,a...) BUS_MSG((b), trace, f, ##a)
#endif
drivers/gpu/drm/nouveau/nvkm/subdev/i2c/busgf119.c
0 → 100644
View file @
2aa5eac5
/*
* Copyright 2015 Red Hat Inc.
*
* 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 shall be included in
* all copies or substantial busions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* THE COPYRIGHT HOLDER(S) OR AUTHOR(S) 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: Ben Skeggs <bskeggs@redhat.com>
*/
#define gf119_i2c_bus(p) container_of((p), struct gf119_i2c_bus, base)
#include "bus.h"
struct
gf119_i2c_bus
{
struct
nvkm_i2c_bus
base
;
u32
addr
;
};
static
void
gf119_i2c_bus_drive_scl
(
struct
nvkm_i2c_bus
*
base
,
int
state
)
{
struct
gf119_i2c_bus
*
bus
=
gf119_i2c_bus
(
base
);
struct
nvkm_device
*
device
=
bus
->
base
.
pad
->
i2c
->
subdev
.
device
;
nvkm_mask
(
device
,
bus
->
addr
,
0x00000001
,
state
?
0x00000001
:
0
);
}
static
void
gf119_i2c_bus_drive_sda
(
struct
nvkm_i2c_bus
*
base
,
int
state
)
{
struct
gf119_i2c_bus
*
bus
=
gf119_i2c_bus
(
base
);
struct
nvkm_device
*
device
=
bus
->
base
.
pad
->
i2c
->
subdev
.
device
;
nvkm_mask
(
device
,
bus
->
addr
,
0x00000002
,
state
?
0x00000002
:
0
);
}
static
int
gf119_i2c_bus_sense_scl
(
struct
nvkm_i2c_bus
*
base
)
{
struct
gf119_i2c_bus
*
bus
=
gf119_i2c_bus
(
base
);
struct
nvkm_device
*
device
=
bus
->
base
.
pad
->
i2c
->
subdev
.
device
;
return
!!
(
nvkm_rd32
(
device
,
bus
->
addr
)
&
0x00000010
);
}
static
int
gf119_i2c_bus_sense_sda
(
struct
nvkm_i2c_bus
*
base
)
{
struct
gf119_i2c_bus
*
bus
=
gf119_i2c_bus
(
base
);
struct
nvkm_device
*
device
=
bus
->
base
.
pad
->
i2c
->
subdev
.
device
;
return
!!
(
nvkm_rd32
(
device
,
bus
->
addr
)
&
0x00000020
);
}
static
void
gf119_i2c_bus_init
(
struct
nvkm_i2c_bus
*
base
)
{
struct
gf119_i2c_bus
*
bus
=
gf119_i2c_bus
(
base
);
struct
nvkm_device
*
device
=
bus
->
base
.
pad
->
i2c
->
subdev
.
device
;
nvkm_wr32
(
device
,
bus
->
addr
,
0x00000007
);
}
static
const
struct
nvkm_i2c_bus_func
gf119_i2c_bus_func
=
{
.
init
=
gf119_i2c_bus_init
,
.
drive_scl
=
gf119_i2c_bus_drive_scl
,
.
drive_sda
=
gf119_i2c_bus_drive_sda
,
.
sense_scl
=
gf119_i2c_bus_sense_scl
,
.
sense_sda
=
gf119_i2c_bus_sense_sda
,
.
xfer
=
nvkm_i2c_bit_xfer
,
};
int
gf119_i2c_bus_new
(
struct
nvkm_i2c_pad
*
pad
,
int
id
,
u8
drive
,
struct
nvkm_i2c_bus
**
pbus
)
{
struct
gf119_i2c_bus
*
bus
;
if
(
!
(
bus
=
kzalloc
(
sizeof
(
*
bus
),
GFP_KERNEL
)))
return
-
ENOMEM
;
*
pbus
=
&
bus
->
base
;
nvkm_i2c_bus_ctor
(
&
gf119_i2c_bus_func
,
pad
,
id
,
&
bus
->
base
);
bus
->
addr
=
0x00d014
+
(
drive
*
0x20
);
return
0
;
}
drivers/gpu/drm/nouveau/nvkm/subdev/i2c/busnv04.c
0 → 100644
View file @
2aa5eac5
/*
* Copyright 2015 Red Hat Inc.
*
* 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 shall be included in
* all copies or substantial busions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* THE COPYRIGHT HOLDER(S) OR AUTHOR(S) 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: Ben Skeggs <bskeggs@redhat.com>
*/
#define nv04_i2c_bus(p) container_of((p), struct nv04_i2c_bus, base)
#include "bus.h"
#include <subdev/vga.h>
struct
nv04_i2c_bus
{
struct
nvkm_i2c_bus
base
;
u8
drive
;
u8
sense
;
};
static
void
nv04_i2c_bus_drive_scl
(
struct
nvkm_i2c_bus
*
base
,
int
state
)
{
struct
nv04_i2c_bus
*
bus
=
nv04_i2c_bus
(
base
);
struct
nvkm_device
*
device
=
bus
->
base
.
pad
->
i2c
->
subdev
.
device
;
u8
val
=
nvkm_rdvgac
(
device
,
0
,
bus
->
drive
);
if
(
state
)
val
|=
0x20
;
else
val
&=
0xdf
;
nvkm_wrvgac
(
device
,
0
,
bus
->
drive
,
val
|
0x01
);
}
static
void
nv04_i2c_bus_drive_sda
(
struct
nvkm_i2c_bus
*
base
,
int
state
)
{
struct
nv04_i2c_bus
*
bus
=
nv04_i2c_bus
(
base
);
struct
nvkm_device
*
device
=
bus
->
base
.
pad
->
i2c
->
subdev
.
device
;
u8
val
=
nvkm_rdvgac
(
device
,
0
,
bus
->
drive
);
if
(
state
)
val
|=
0x10
;
else
val
&=
0xef
;
nvkm_wrvgac
(
device
,
0
,
bus
->
drive
,
val
|
0x01
);
}
static
int
nv04_i2c_bus_sense_scl
(
struct
nvkm_i2c_bus
*
base
)
{
struct
nv04_i2c_bus
*
bus
=
nv04_i2c_bus
(
base
);
struct
nvkm_device
*
device
=
bus
->
base
.
pad
->
i2c
->
subdev
.
device
;
return
!!
(
nvkm_rdvgac
(
device
,
0
,
bus
->
sense
)
&
0x04
);
}
static
int
nv04_i2c_bus_sense_sda
(
struct
nvkm_i2c_bus
*
base
)
{
struct
nv04_i2c_bus
*
bus
=
nv04_i2c_bus
(
base
);
struct
nvkm_device
*
device
=
bus
->
base
.
pad
->
i2c
->
subdev
.
device
;
return
!!
(
nvkm_rdvgac
(
device
,
0
,
bus
->
sense
)
&
0x08
);
}
static
const
struct
nvkm_i2c_bus_func
nv04_i2c_bus_func
=
{
.
drive_scl
=
nv04_i2c_bus_drive_scl
,
.
drive_sda
=
nv04_i2c_bus_drive_sda
,
.
sense_scl
=
nv04_i2c_bus_sense_scl
,
.
sense_sda
=
nv04_i2c_bus_sense_sda
,
.
xfer
=
nvkm_i2c_bit_xfer
,
};
int
nv04_i2c_bus_new
(
struct
nvkm_i2c_pad
*
pad
,
int
id
,
u8
drive
,
u8
sense
,
struct
nvkm_i2c_bus
**
pbus
)
{
struct
nv04_i2c_bus
*
bus
;
if
(
!
(
bus
=
kzalloc
(
sizeof
(
*
bus
),
GFP_KERNEL
)))
return
-
ENOMEM
;
*
pbus
=
&
bus
->
base
;
nvkm_i2c_bus_ctor
(
&
nv04_i2c_bus_func
,
pad
,
id
,
&
bus
->
base
);
bus
->
drive
=
drive
;
bus
->
sense
=
sense
;
return
0
;
}
drivers/gpu/drm/nouveau/nvkm/subdev/i2c/busnv4e.c
0 → 100644
View file @
2aa5eac5
/*
* Copyright 2015 Red Hat Inc.
*
* 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 shall be included in
* all copies or substantial busions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* THE COPYRIGHT HOLDER(S) OR AUTHOR(S) 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: Ben Skeggs <bskeggs@redhat.com>
*/
#define nv4e_i2c_bus(p) container_of((p), struct nv4e_i2c_bus, base)
#include "bus.h"
struct
nv4e_i2c_bus
{
struct
nvkm_i2c_bus
base
;
u32
addr
;
};
static
void
nv4e_i2c_bus_drive_scl
(
struct
nvkm_i2c_bus
*
base
,
int
state
)
{
struct
nv4e_i2c_bus
*
bus
=
nv4e_i2c_bus
(
base
);
struct
nvkm_device
*
device
=
bus
->
base
.
pad
->
i2c
->
subdev
.
device
;
nvkm_mask
(
device
,
bus
->
addr
,
0x2f
,
state
?
0x21
:
0x01
);
}
static
void
nv4e_i2c_bus_drive_sda
(
struct
nvkm_i2c_bus
*
base
,
int
state
)
{
struct
nv4e_i2c_bus
*
bus
=
nv4e_i2c_bus
(
base
);
struct
nvkm_device
*
device
=
bus
->
base
.
pad
->
i2c
->
subdev
.
device
;
nvkm_mask
(
device
,
bus
->
addr
,
0x1f
,
state
?
0x11
:
0x01
);
}
static
int
nv4e_i2c_bus_sense_scl
(
struct
nvkm_i2c_bus
*
base
)
{
struct
nv4e_i2c_bus
*
bus
=
nv4e_i2c_bus
(
base
);
struct
nvkm_device
*
device
=
bus
->
base
.
pad
->
i2c
->
subdev
.
device
;
return
!!
(
nvkm_rd32
(
device
,
bus
->
addr
)
&
0x00040000
);
}
static
int
nv4e_i2c_bus_sense_sda
(
struct
nvkm_i2c_bus
*
base
)
{
struct
nv4e_i2c_bus
*
bus
=
nv4e_i2c_bus
(
base
);
struct
nvkm_device
*
device
=
bus
->
base
.
pad
->
i2c
->
subdev
.
device
;
return
!!
(
nvkm_rd32
(
device
,
bus
->
addr
)
&
0x00080000
);
}
static
const
struct
nvkm_i2c_bus_func
nv4e_i2c_bus_func
=
{
.
drive_scl
=
nv4e_i2c_bus_drive_scl
,
.
drive_sda
=
nv4e_i2c_bus_drive_sda
,
.
sense_scl
=
nv4e_i2c_bus_sense_scl
,
.
sense_sda
=
nv4e_i2c_bus_sense_sda
,
.
xfer
=
nvkm_i2c_bit_xfer
,
};
int
nv4e_i2c_bus_new
(
struct
nvkm_i2c_pad
*
pad
,
int
id
,
u8
drive
,
struct
nvkm_i2c_bus
**
pbus
)
{
struct
nv4e_i2c_bus
*
bus
;
if
(
!
(
bus
=
kzalloc
(
sizeof
(
*
bus
),
GFP_KERNEL
)))
return
-
ENOMEM
;
*
pbus
=
&
bus
->
base
;
nvkm_i2c_bus_ctor
(
&
nv4e_i2c_bus_func
,
pad
,
id
,
&
bus
->
base
);
bus
->
addr
=
0x600800
+
drive
;
return
0
;
}
drivers/gpu/drm/nouveau/nvkm/subdev/i2c/busnv50.c
0 → 100644
View file @
2aa5eac5
/*
* Copyright 2015 Red Hat Inc.
*
* 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 shall be included in
* all copies or substantial busions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* THE COPYRIGHT HOLDER(S) OR AUTHOR(S) 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: Ben Skeggs <bskeggs@redhat.com>
*/
#define nv50_i2c_bus(p) container_of((p), struct nv50_i2c_bus, base)
#include "bus.h"
#include <subdev/vga.h>
struct
nv50_i2c_bus
{
struct
nvkm_i2c_bus
base
;
u32
addr
;
u32
data
;
};
static
void
nv50_i2c_bus_drive_scl
(
struct
nvkm_i2c_bus
*
base
,
int
state
)
{
struct
nv50_i2c_bus
*
bus
=
nv50_i2c_bus
(
base
);
struct
nvkm_device
*
device
=
bus
->
base
.
pad
->
i2c
->
subdev
.
device
;
if
(
state
)
bus
->
data
|=
0x01
;
else
bus
->
data
&=
0xfe
;
nvkm_wr32
(
device
,
bus
->
addr
,
bus
->
data
);
}
static
void
nv50_i2c_bus_drive_sda
(
struct
nvkm_i2c_bus
*
base
,
int
state
)
{
struct
nv50_i2c_bus
*
bus
=
nv50_i2c_bus
(
base
);
struct
nvkm_device
*
device
=
bus
->
base
.
pad
->
i2c
->
subdev
.
device
;
if
(
state
)
bus
->
data
|=
0x02
;
else
bus
->
data
&=
0xfd
;
nvkm_wr32
(
device
,
bus
->
addr
,
bus
->
data
);
}
static
int
nv50_i2c_bus_sense_scl
(
struct
nvkm_i2c_bus
*
base
)
{
struct
nv50_i2c_bus
*
bus
=
nv50_i2c_bus
(
base
);
struct
nvkm_device
*
device
=
bus
->
base
.
pad
->
i2c
->
subdev
.
device
;
return
!!
(
nvkm_rd32
(
device
,
bus
->
addr
)
&
0x00000001
);
}
static
int
nv50_i2c_bus_sense_sda
(
struct
nvkm_i2c_bus
*
base
)
{
struct
nv50_i2c_bus
*
bus
=
nv50_i2c_bus
(
base
);
struct
nvkm_device
*
device
=
bus
->
base
.
pad
->
i2c
->
subdev
.
device
;
return
!!
(
nvkm_rd32
(
device
,
bus
->
addr
)
&
0x00000002
);
}
static
void
nv50_i2c_bus_init
(
struct
nvkm_i2c_bus
*
base
)
{
struct
nv50_i2c_bus
*
bus
=
nv50_i2c_bus
(
base
);
struct
nvkm_device
*
device
=
bus
->
base
.
pad
->
i2c
->
subdev
.
device
;
nvkm_wr32
(
device
,
bus
->
addr
,
(
bus
->
data
=
0x00000007
));
}
static
const
struct
nvkm_i2c_bus_func
nv50_i2c_bus_func
=
{
.
init
=
nv50_i2c_bus_init
,
.
drive_scl
=
nv50_i2c_bus_drive_scl
,
.
drive_sda
=
nv50_i2c_bus_drive_sda
,
.
sense_scl
=
nv50_i2c_bus_sense_scl
,
.
sense_sda
=
nv50_i2c_bus_sense_sda
,
.
xfer
=
nvkm_i2c_bit_xfer
,
};
int
nv50_i2c_bus_new
(
struct
nvkm_i2c_pad
*
pad
,
int
id
,
u8
drive
,
struct
nvkm_i2c_bus
**
pbus
)
{
static
const
u32
addr
[]
=
{
0x00e138
,
0x00e150
,
0x00e168
,
0x00e180
,
0x00e254
,
0x00e274
,
0x00e764
,
0x00e780
,
0x00e79c
,
0x00e7b8
};
struct
nv50_i2c_bus
*
bus
;
if
(
drive
>=
ARRAY_SIZE
(
addr
))
{
nvkm_warn
(
&
pad
->
i2c
->
subdev
,
"bus %d unknown
\n
"
,
drive
);
return
-
ENODEV
;
}
if
(
!
(
bus
=
kzalloc
(
sizeof
(
*
bus
),
GFP_KERNEL
)))
return
-
ENOMEM
;
*
pbus
=
&
bus
->
base
;
nvkm_i2c_bus_ctor
(
&
nv50_i2c_bus_func
,
pad
,
id
,
&
bus
->
base
);
bus
->
addr
=
addr
[
drive
];
bus
->
data
=
0x00000007
;
return
0
;
}
drivers/gpu/drm/nouveau/nvkm/subdev/i2c/g94.c
View file @
2aa5eac5
...
...
@@ -21,7 +21,8 @@
*
* Authors: Ben Skeggs
*/
#include "nv50.h"
#include "priv.h"
#include "pad.h"
void
g94_aux_stat
(
struct
nvkm_i2c
*
i2c
,
u32
*
hi
,
u32
*
lo
,
u32
*
rq
,
u32
*
tx
)
...
...
@@ -55,219 +56,6 @@ g94_aux_mask(struct nvkm_i2c *i2c, u32 type, u32 mask, u32 data)
nvkm_wr32
(
device
,
0x00e068
,
temp
);
}
#define AUX_DBG(fmt, args...) \
nvkm_debug(&i2c->subdev, "AUXCH(%d): " fmt, ch, ##args)
#define AUX_ERR(fmt, args...) \
nvkm_error(&i2c->subdev, "AUXCH(%d): " fmt, ch, ##args)
static
void
auxch_fini
(
struct
nvkm_i2c
*
i2c
,
int
ch
)
{
struct
nvkm_device
*
device
=
i2c
->
subdev
.
device
;
nvkm_mask
(
device
,
0x00e4e4
+
(
ch
*
0x50
),
0x00310000
,
0x00000000
);
}
static
int
auxch_init
(
struct
nvkm_i2c
*
i2c
,
int
ch
)
{
struct
nvkm_device
*
device
=
i2c
->
subdev
.
device
;
const
u32
unksel
=
1
;
/* nfi which to use, or if it matters.. */
const
u32
ureq
=
unksel
?
0x00100000
:
0x00200000
;
const
u32
urep
=
unksel
?
0x01000000
:
0x02000000
;
u32
ctrl
,
timeout
;
/* wait up to 1ms for any previous transaction to be done... */
timeout
=
1000
;
do
{
ctrl
=
nvkm_rd32
(
device
,
0x00e4e4
+
(
ch
*
0x50
));
udelay
(
1
);
if
(
!
timeout
--
)
{
AUX_ERR
(
"begin idle timeout %08x
\n
"
,
ctrl
);
return
-
EBUSY
;
}
}
while
(
ctrl
&
0x03010000
);
/* set some magic, and wait up to 1ms for it to appear */
nvkm_mask
(
device
,
0x00e4e4
+
(
ch
*
0x50
),
0x00300000
,
ureq
);
timeout
=
1000
;
do
{
ctrl
=
nvkm_rd32
(
device
,
0x00e4e4
+
(
ch
*
0x50
));
udelay
(
1
);
if
(
!
timeout
--
)
{
AUX_ERR
(
"magic wait %08x
\n
"
,
ctrl
);
auxch_fini
(
i2c
,
ch
);
return
-
EBUSY
;
}
}
while
((
ctrl
&
0x03000000
)
!=
urep
);
return
0
;
}
int
g94_aux
(
struct
nvkm_i2c_port
*
base
,
bool
retry
,
u8
type
,
u32
addr
,
u8
*
data
,
u8
size
)
{
struct
nvkm_i2c
*
i2c
=
nvkm_i2c
(
base
);
struct
nvkm_device
*
device
=
i2c
->
subdev
.
device
;
struct
nv50_i2c_port
*
port
=
(
void
*
)
base
;
u32
ctrl
,
stat
,
timeout
,
retries
;
u32
xbuf
[
4
]
=
{};
int
ch
=
port
->
addr
;
int
ret
,
i
;
AUX_DBG
(
"%d: %08x %d
\n
"
,
type
,
addr
,
size
);
ret
=
auxch_init
(
i2c
,
ch
);
if
(
ret
<
0
)
goto
out
;
stat
=
nvkm_rd32
(
device
,
0x00e4e8
+
(
ch
*
0x50
));
if
(
!
(
stat
&
0x10000000
))
{
AUX_DBG
(
"sink not detected
\n
"
);
ret
=
-
ENXIO
;
goto
out
;
}
if
(
!
(
type
&
1
))
{
memcpy
(
xbuf
,
data
,
size
);
for
(
i
=
0
;
i
<
16
;
i
+=
4
)
{
AUX_DBG
(
"wr %08x
\n
"
,
xbuf
[
i
/
4
]);
nvkm_wr32
(
device
,
0x00e4c0
+
(
ch
*
0x50
)
+
i
,
xbuf
[
i
/
4
]);
}
}
ctrl
=
nvkm_rd32
(
device
,
0x00e4e4
+
(
ch
*
0x50
));
ctrl
&=
~
0x0001f0ff
;
ctrl
|=
type
<<
12
;
ctrl
|=
size
-
1
;
nvkm_wr32
(
device
,
0x00e4e0
+
(
ch
*
0x50
),
addr
);
/* (maybe) retry transaction a number of times on failure... */
for
(
retries
=
0
;
!
ret
&&
retries
<
32
;
retries
++
)
{
/* reset, and delay a while if this is a retry */
nvkm_wr32
(
device
,
0x00e4e4
+
(
ch
*
0x50
),
0x80000000
|
ctrl
);
nvkm_wr32
(
device
,
0x00e4e4
+
(
ch
*
0x50
),
0x00000000
|
ctrl
);
if
(
retries
)
udelay
(
400
);
/* transaction request, wait up to 1ms for it to complete */
nvkm_wr32
(
device
,
0x00e4e4
+
(
ch
*
0x50
),
0x00010000
|
ctrl
);
timeout
=
1000
;
do
{
ctrl
=
nvkm_rd32
(
device
,
0x00e4e4
+
(
ch
*
0x50
));
udelay
(
1
);
if
(
!
timeout
--
)
{
AUX_ERR
(
"tx req timeout %08x
\n
"
,
ctrl
);
ret
=
-
EIO
;
goto
out
;
}
}
while
(
ctrl
&
0x00010000
);
ret
=
1
;
/* read status, and check if transaction completed ok */
stat
=
nvkm_mask
(
device
,
0x00e4e8
+
(
ch
*
0x50
),
0
,
0
);
if
((
stat
&
0x000f0000
)
==
0x00080000
||
(
stat
&
0x000f0000
)
==
0x00020000
)
ret
=
retry
?
0
:
1
;
if
((
stat
&
0x00000100
))
ret
=
-
ETIMEDOUT
;
if
((
stat
&
0x00000e00
))
ret
=
-
EIO
;
AUX_DBG
(
"%02d %08x %08x
\n
"
,
retries
,
ctrl
,
stat
);
}
if
(
type
&
1
)
{
for
(
i
=
0
;
i
<
16
;
i
+=
4
)
{
xbuf
[
i
/
4
]
=
nvkm_rd32
(
device
,
0x00e4d0
+
(
ch
*
0x50
)
+
i
);
AUX_DBG
(
"rd %08x
\n
"
,
xbuf
[
i
/
4
]);
}
memcpy
(
data
,
xbuf
,
size
);
}
out:
auxch_fini
(
i2c
,
ch
);
return
ret
<
0
?
ret
:
(
stat
&
0x000f0000
)
>>
16
;
}
static
const
struct
nvkm_i2c_func
g94_i2c_func
=
{
.
drive_scl
=
nv50_i2c_drive_scl
,
.
drive_sda
=
nv50_i2c_drive_sda
,
.
sense_scl
=
nv50_i2c_sense_scl
,
.
sense_sda
=
nv50_i2c_sense_sda
,
};
static
int
g94_i2c_port_ctor
(
struct
nvkm_object
*
parent
,
struct
nvkm_object
*
engine
,
struct
nvkm_oclass
*
oclass
,
void
*
data
,
u32
index
,
struct
nvkm_object
**
pobject
)
{
struct
dcb_i2c_entry
*
info
=
data
;
struct
nv50_i2c_port
*
port
;
int
ret
;
ret
=
nvkm_i2c_port_create
(
parent
,
engine
,
oclass
,
index
,
&
nvkm_i2c_bit_algo
,
&
g94_i2c_func
,
&
port
);
*
pobject
=
nv_object
(
port
);
if
(
ret
)
return
ret
;
if
(
info
->
drive
>=
nv50_i2c_addr_nr
)
return
-
EINVAL
;
port
->
state
=
7
;
port
->
addr
=
nv50_i2c_addr
[
info
->
drive
];
return
0
;
}
static
const
struct
nvkm_i2c_func
g94_aux_func
=
{
.
aux
=
g94_aux
,
};
int
g94_aux_port_ctor
(
struct
nvkm_object
*
parent
,
struct
nvkm_object
*
engine
,
struct
nvkm_oclass
*
oclass
,
void
*
data
,
u32
index
,
struct
nvkm_object
**
pobject
)
{
struct
dcb_i2c_entry
*
info
=
data
;
struct
nv50_i2c_port
*
port
;
int
ret
;
ret
=
nvkm_i2c_port_create
(
parent
,
engine
,
oclass
,
index
,
&
nvkm_i2c_aux_algo
,
&
g94_aux_func
,
&
port
);
*
pobject
=
nv_object
(
port
);
if
(
ret
)
return
ret
;
port
->
base
.
aux
=
info
->
auxch
;
port
->
addr
=
info
->
auxch
;
return
0
;
}
static
struct
nvkm_oclass
g94_i2c_sclass
[]
=
{
{
.
handle
=
NV_I2C_TYPE_DCBI2C
(
DCB_I2C_NVIO_BIT
),
.
ofuncs
=
&
(
struct
nvkm_ofuncs
)
{
.
ctor
=
g94_i2c_port_ctor
,
.
dtor
=
_nvkm_i2c_port_dtor
,
.
init
=
nv50_i2c_port_init
,
.
fini
=
_nvkm_i2c_port_fini
,
},
},
{
.
handle
=
NV_I2C_TYPE_DCBI2C
(
DCB_I2C_NVIO_AUX
),
.
ofuncs
=
&
(
struct
nvkm_ofuncs
)
{
.
ctor
=
g94_aux_port_ctor
,
.
dtor
=
_nvkm_i2c_port_dtor
,
.
init
=
_nvkm_i2c_port_init
,
.
fini
=
_nvkm_i2c_port_fini
,
},
},
{}
};
struct
nvkm_oclass
*
g94_i2c_oclass
=
&
(
struct
nvkm_i2c_impl
)
{
.
base
.
handle
=
NV_SUBDEV
(
I2C
,
0x94
),
...
...
@@ -277,9 +65,8 @@ g94_i2c_oclass = &(struct nvkm_i2c_impl) {
.
init
=
_nvkm_i2c_init
,
.
fini
=
_nvkm_i2c_fini
,
},
.
sclass
=
g94_i2c_sclass
,
.
pad_x
=
&
nv04_i2c_pad_oclass
,
.
pad_s
=
&
g94_i2c_pad_oclass
,
.
pad_x_new
=
g94_i2c_pad_x_new
,
.
pad_s_new
=
g94_i2c_pad_s_new
,
.
aux
=
4
,
.
aux_stat
=
g94_aux_stat
,
.
aux_mask
=
g94_aux_mask
,
...
...
drivers/gpu/drm/nouveau/nvkm/subdev/i2c/gf110.c
View file @
2aa5eac5
...
...
@@ -21,74 +21,8 @@
*
* Authors: Ben Skeggs
*/
#include "nv50.h"
static
int
gf110_i2c_sense_scl
(
struct
nvkm_i2c_port
*
base
)
{
struct
nvkm_i2c
*
i2c
=
(
void
*
)
nvkm_i2c
(
base
);
struct
nvkm_device
*
device
=
i2c
->
subdev
.
device
;
struct
nv50_i2c_port
*
port
=
(
void
*
)
base
;
return
!!
(
nvkm_rd32
(
device
,
port
->
addr
)
&
0x00000010
);
}
static
int
gf110_i2c_sense_sda
(
struct
nvkm_i2c_port
*
base
)
{
struct
nvkm_i2c
*
i2c
=
(
void
*
)
nvkm_i2c
(
base
);
struct
nvkm_device
*
device
=
i2c
->
subdev
.
device
;
struct
nv50_i2c_port
*
port
=
(
void
*
)
base
;
return
!!
(
nvkm_rd32
(
device
,
port
->
addr
)
&
0x00000020
);
}
static
const
struct
nvkm_i2c_func
gf110_i2c_func
=
{
.
drive_scl
=
nv50_i2c_drive_scl
,
.
drive_sda
=
nv50_i2c_drive_sda
,
.
sense_scl
=
gf110_i2c_sense_scl
,
.
sense_sda
=
gf110_i2c_sense_sda
,
};
int
gf110_i2c_port_ctor
(
struct
nvkm_object
*
parent
,
struct
nvkm_object
*
engine
,
struct
nvkm_oclass
*
oclass
,
void
*
data
,
u32
index
,
struct
nvkm_object
**
pobject
)
{
struct
dcb_i2c_entry
*
info
=
data
;
struct
nv50_i2c_port
*
port
;
int
ret
;
ret
=
nvkm_i2c_port_create
(
parent
,
engine
,
oclass
,
index
,
&
nvkm_i2c_bit_algo
,
&
gf110_i2c_func
,
&
port
);
*
pobject
=
nv_object
(
port
);
if
(
ret
)
return
ret
;
port
->
state
=
0x00000007
;
port
->
addr
=
0x00d014
+
(
info
->
drive
*
0x20
);
return
0
;
}
struct
nvkm_oclass
gf110_i2c_sclass
[]
=
{
{
.
handle
=
NV_I2C_TYPE_DCBI2C
(
DCB_I2C_NVIO_BIT
),
.
ofuncs
=
&
(
struct
nvkm_ofuncs
)
{
.
ctor
=
gf110_i2c_port_ctor
,
.
dtor
=
_nvkm_i2c_port_dtor
,
.
init
=
nv50_i2c_port_init
,
.
fini
=
_nvkm_i2c_port_fini
,
},
},
{
.
handle
=
NV_I2C_TYPE_DCBI2C
(
DCB_I2C_NVIO_AUX
),
.
ofuncs
=
&
(
struct
nvkm_ofuncs
)
{
.
ctor
=
g94_aux_port_ctor
,
.
dtor
=
_nvkm_i2c_port_dtor
,
.
init
=
_nvkm_i2c_port_init
,
.
fini
=
_nvkm_i2c_port_fini
,
},
},
{}
};
#include "priv.h"
#include "pad.h"
struct
nvkm_oclass
*
gf110_i2c_oclass
=
&
(
struct
nvkm_i2c_impl
)
{
...
...
@@ -99,9 +33,8 @@ gf110_i2c_oclass = &(struct nvkm_i2c_impl) {
.
init
=
_nvkm_i2c_init
,
.
fini
=
_nvkm_i2c_fini
,
},
.
sclass
=
gf110_i2c_sclass
,
.
pad_x
=
&
nv04_i2c_pad_oclass
,
.
pad_s
=
&
g94_i2c_pad_oclass
,
.
pad_x_new
=
gf119_i2c_pad_x_new
,
.
pad_s_new
=
gf119_i2c_pad_s_new
,
.
aux
=
4
,
.
aux_stat
=
g94_aux_stat
,
.
aux_mask
=
g94_aux_mask
,
...
...
drivers/gpu/drm/nouveau/nvkm/subdev/i2c/gf117.c
View file @
2aa5eac5
...
...
@@ -21,7 +21,8 @@
*
* Authors: Ben Skeggs
*/
#include "nv50.h"
#include "priv.h"
#include "pad.h"
struct
nvkm_oclass
*
gf117_i2c_oclass
=
&
(
struct
nvkm_i2c_impl
)
{
...
...
@@ -32,7 +33,5 @@ gf117_i2c_oclass = &(struct nvkm_i2c_impl) {
.
init
=
_nvkm_i2c_init
,
.
fini
=
_nvkm_i2c_fini
,
},
.
sclass
=
gf110_i2c_sclass
,
.
pad_x
=
&
nv04_i2c_pad_oclass
,
.
pad_s
=
&
nv04_i2c_pad_oclass
,
.
pad_x_new
=
gf119_i2c_pad_x_new
,
}.
base
;
drivers/gpu/drm/nouveau/nvkm/subdev/i2c/gk104.c
View file @
2aa5eac5
...
...
@@ -21,7 +21,8 @@
*
* Authors: Ben Skeggs
*/
#include "nv50.h"
#include "priv.h"
#include "pad.h"
void
gk104_aux_stat
(
struct
nvkm_i2c
*
i2c
,
u32
*
hi
,
u32
*
lo
,
u32
*
rq
,
u32
*
tx
)
...
...
@@ -64,9 +65,8 @@ gk104_i2c_oclass = &(struct nvkm_i2c_impl) {
.
init
=
_nvkm_i2c_init
,
.
fini
=
_nvkm_i2c_fini
,
},
.
sclass
=
gf110_i2c_sclass
,
.
pad_x
=
&
nv04_i2c_pad_oclass
,
.
pad_s
=
&
g94_i2c_pad_oclass
,
.
pad_x_new
=
gf119_i2c_pad_x_new
,
.
pad_s_new
=
gf119_i2c_pad_s_new
,
.
aux
=
4
,
.
aux_stat
=
gk104_aux_stat
,
.
aux_mask
=
gk104_aux_mask
,
...
...
drivers/gpu/drm/nouveau/nvkm/subdev/i2c/gm204.c
View file @
2aa5eac5
...
...
@@ -21,190 +21,8 @@
*
* Authors: Ben Skeggs
*/
#include "nv50.h"
#define AUX_DBG(fmt, args...) \
nvkm_debug(&i2c->subdev, "AUXCH(%d): " fmt, ch, ##args)
#define AUX_ERR(fmt, args...) \
nvkm_error(&i2c->subdev, "AUXCH(%d): " fmt, ch, ##args)
static
void
auxch_fini
(
struct
nvkm_i2c
*
i2c
,
int
ch
)
{
struct
nvkm_device
*
device
=
i2c
->
subdev
.
device
;
nvkm_mask
(
device
,
0x00d954
+
(
ch
*
0x50
),
0x00310000
,
0x00000000
);
}
static
int
auxch_init
(
struct
nvkm_i2c
*
i2c
,
int
ch
)
{
struct
nvkm_device
*
device
=
i2c
->
subdev
.
device
;
const
u32
unksel
=
1
;
/* nfi which to use, or if it matters.. */
const
u32
ureq
=
unksel
?
0x00100000
:
0x00200000
;
const
u32
urep
=
unksel
?
0x01000000
:
0x02000000
;
u32
ctrl
,
timeout
;
/* wait up to 1ms for any previous transaction to be done... */
timeout
=
1000
;
do
{
ctrl
=
nvkm_rd32
(
device
,
0x00d954
+
(
ch
*
0x50
));
udelay
(
1
);
if
(
!
timeout
--
)
{
AUX_ERR
(
"begin idle timeout %08x
\n
"
,
ctrl
);
return
-
EBUSY
;
}
}
while
(
ctrl
&
0x03010000
);
/* set some magic, and wait up to 1ms for it to appear */
nvkm_mask
(
device
,
0x00d954
+
(
ch
*
0x50
),
0x00300000
,
ureq
);
timeout
=
1000
;
do
{
ctrl
=
nvkm_rd32
(
device
,
0x00d954
+
(
ch
*
0x50
));
udelay
(
1
);
if
(
!
timeout
--
)
{
AUX_ERR
(
"magic wait %08x
\n
"
,
ctrl
);
auxch_fini
(
i2c
,
ch
);
return
-
EBUSY
;
}
}
while
((
ctrl
&
0x03000000
)
!=
urep
);
return
0
;
}
int
gm204_aux
(
struct
nvkm_i2c_port
*
base
,
bool
retry
,
u8
type
,
u32
addr
,
u8
*
data
,
u8
size
)
{
struct
nvkm_i2c
*
i2c
=
nvkm_i2c
(
base
);
struct
nvkm_device
*
device
=
i2c
->
subdev
.
device
;
struct
nv50_i2c_port
*
port
=
(
void
*
)
base
;
u32
ctrl
,
stat
,
timeout
,
retries
;
u32
xbuf
[
4
]
=
{};
int
ch
=
port
->
addr
;
int
ret
,
i
;
AUX_DBG
(
"%d: %08x %d
\n
"
,
type
,
addr
,
size
);
ret
=
auxch_init
(
i2c
,
ch
);
if
(
ret
<
0
)
goto
out
;
stat
=
nvkm_rd32
(
device
,
0x00d958
+
(
ch
*
0x50
));
if
(
!
(
stat
&
0x10000000
))
{
AUX_DBG
(
"sink not detected
\n
"
);
ret
=
-
ENXIO
;
goto
out
;
}
if
(
!
(
type
&
1
))
{
memcpy
(
xbuf
,
data
,
size
);
for
(
i
=
0
;
i
<
16
;
i
+=
4
)
{
AUX_DBG
(
"wr %08x
\n
"
,
xbuf
[
i
/
4
]);
nvkm_wr32
(
device
,
0x00d930
+
(
ch
*
0x50
)
+
i
,
xbuf
[
i
/
4
]);
}
}
ctrl
=
nvkm_rd32
(
device
,
0x00d954
+
(
ch
*
0x50
));
ctrl
&=
~
0x0001f0ff
;
ctrl
|=
type
<<
12
;
ctrl
|=
size
-
1
;
nvkm_wr32
(
device
,
0x00d950
+
(
ch
*
0x50
),
addr
);
/* (maybe) retry transaction a number of times on failure... */
for
(
retries
=
0
;
!
ret
&&
retries
<
32
;
retries
++
)
{
/* reset, and delay a while if this is a retry */
nvkm_wr32
(
device
,
0x00d954
+
(
ch
*
0x50
),
0x80000000
|
ctrl
);
nvkm_wr32
(
device
,
0x00d954
+
(
ch
*
0x50
),
0x00000000
|
ctrl
);
if
(
retries
)
udelay
(
400
);
/* transaction request, wait up to 1ms for it to complete */
nvkm_wr32
(
device
,
0x00d954
+
(
ch
*
0x50
),
0x00010000
|
ctrl
);
timeout
=
1000
;
do
{
ctrl
=
nvkm_rd32
(
device
,
0x00d954
+
(
ch
*
0x50
));
udelay
(
1
);
if
(
!
timeout
--
)
{
AUX_ERR
(
"tx req timeout %08x
\n
"
,
ctrl
);
ret
=
-
EIO
;
goto
out
;
}
}
while
(
ctrl
&
0x00010000
);
ret
=
1
;
/* read status, and check if transaction completed ok */
stat
=
nvkm_mask
(
device
,
0x00d958
+
(
ch
*
0x50
),
0
,
0
);
if
((
stat
&
0x000f0000
)
==
0x00080000
||
(
stat
&
0x000f0000
)
==
0x00020000
)
ret
=
retry
?
0
:
1
;
if
((
stat
&
0x00000100
))
ret
=
-
ETIMEDOUT
;
if
((
stat
&
0x00000e00
))
ret
=
-
EIO
;
AUX_DBG
(
"%02d %08x %08x
\n
"
,
retries
,
ctrl
,
stat
);
}
if
(
type
&
1
)
{
for
(
i
=
0
;
i
<
16
;
i
+=
4
)
{
xbuf
[
i
/
4
]
=
nvkm_rd32
(
device
,
0x00d940
+
(
ch
*
0x50
)
+
i
);
AUX_DBG
(
"rd %08x
\n
"
,
xbuf
[
i
/
4
]);
}
memcpy
(
data
,
xbuf
,
size
);
}
out:
auxch_fini
(
i2c
,
ch
);
return
ret
<
0
?
ret
:
(
stat
&
0x000f0000
)
>>
16
;
}
static
const
struct
nvkm_i2c_func
gm204_aux_func
=
{
.
aux
=
gm204_aux
,
};
int
gm204_aux_port_ctor
(
struct
nvkm_object
*
parent
,
struct
nvkm_object
*
engine
,
struct
nvkm_oclass
*
oclass
,
void
*
data
,
u32
index
,
struct
nvkm_object
**
pobject
)
{
struct
dcb_i2c_entry
*
info
=
data
;
struct
nv50_i2c_port
*
port
;
int
ret
;
ret
=
nvkm_i2c_port_create
(
parent
,
engine
,
oclass
,
index
,
&
nvkm_i2c_aux_algo
,
&
gm204_aux_func
,
&
port
);
*
pobject
=
nv_object
(
port
);
if
(
ret
)
return
ret
;
port
->
base
.
aux
=
info
->
auxch
;
port
->
addr
=
info
->
auxch
;
return
0
;
}
struct
nvkm_oclass
gm204_i2c_sclass
[]
=
{
{
.
handle
=
NV_I2C_TYPE_DCBI2C
(
DCB_I2C_NVIO_BIT
),
.
ofuncs
=
&
(
struct
nvkm_ofuncs
)
{
.
ctor
=
gf110_i2c_port_ctor
,
.
dtor
=
_nvkm_i2c_port_dtor
,
.
init
=
nv50_i2c_port_init
,
.
fini
=
_nvkm_i2c_port_fini
,
},
},
{
.
handle
=
NV_I2C_TYPE_DCBI2C
(
DCB_I2C_NVIO_AUX
),
.
ofuncs
=
&
(
struct
nvkm_ofuncs
)
{
.
ctor
=
gm204_aux_port_ctor
,
.
dtor
=
_nvkm_i2c_port_dtor
,
.
init
=
_nvkm_i2c_port_init
,
.
fini
=
_nvkm_i2c_port_fini
,
},
},
{}
};
#include "priv.h"
#include "pad.h"
struct
nvkm_oclass
*
gm204_i2c_oclass
=
&
(
struct
nvkm_i2c_impl
)
{
...
...
@@ -215,9 +33,8 @@ gm204_i2c_oclass = &(struct nvkm_i2c_impl) {
.
init
=
_nvkm_i2c_init
,
.
fini
=
_nvkm_i2c_fini
,
},
.
sclass
=
gm204_i2c_sclass
,
.
pad_x
=
&
nv04_i2c_pad_oclass
,
.
pad_s
=
&
gm204_i2c_pad_oclass
,
.
pad_x_new
=
gf119_i2c_pad_x_new
,
.
pad_s_new
=
gm204_i2c_pad_s_new
,
.
aux
=
8
,
.
aux_stat
=
gk104_aux_stat
,
.
aux_mask
=
gk104_aux_mask
,
...
...
drivers/gpu/drm/nouveau/nvkm/subdev/i2c/nv04.c
View file @
2aa5eac5
...
...
@@ -22,93 +22,7 @@
* Authors: Ben Skeggs
*/
#include "priv.h"
#include <subdev/vga.h>
struct
nv04_i2c_port
{
struct
nvkm_i2c_port
base
;
u8
drive
;
u8
sense
;
};
static
void
nv04_i2c_drive_scl
(
struct
nvkm_i2c_port
*
base
,
int
state
)
{
struct
nvkm_device
*
device
=
nvkm_i2c
(
base
)
->
subdev
.
device
;
struct
nv04_i2c_port
*
port
=
(
void
*
)
base
;
u8
val
=
nvkm_rdvgac
(
device
,
0
,
port
->
drive
);
if
(
state
)
val
|=
0x20
;
else
val
&=
0xdf
;
nvkm_wrvgac
(
device
,
0
,
port
->
drive
,
val
|
0x01
);
}
static
void
nv04_i2c_drive_sda
(
struct
nvkm_i2c_port
*
base
,
int
state
)
{
struct
nvkm_device
*
device
=
nvkm_i2c
(
base
)
->
subdev
.
device
;
struct
nv04_i2c_port
*
port
=
(
void
*
)
base
;
u8
val
=
nvkm_rdvgac
(
device
,
0
,
port
->
drive
);
if
(
state
)
val
|=
0x10
;
else
val
&=
0xef
;
nvkm_wrvgac
(
device
,
0
,
port
->
drive
,
val
|
0x01
);
}
static
int
nv04_i2c_sense_scl
(
struct
nvkm_i2c_port
*
base
)
{
struct
nvkm_device
*
device
=
nvkm_i2c
(
base
)
->
subdev
.
device
;
struct
nv04_i2c_port
*
port
=
(
void
*
)
base
;
return
!!
(
nvkm_rdvgac
(
device
,
0
,
port
->
sense
)
&
0x04
);
}
static
int
nv04_i2c_sense_sda
(
struct
nvkm_i2c_port
*
base
)
{
struct
nvkm_device
*
device
=
nvkm_i2c
(
base
)
->
subdev
.
device
;
struct
nv04_i2c_port
*
port
=
(
void
*
)
base
;
return
!!
(
nvkm_rdvgac
(
device
,
0
,
port
->
sense
)
&
0x08
);
}
static
const
struct
nvkm_i2c_func
nv04_i2c_func
=
{
.
drive_scl
=
nv04_i2c_drive_scl
,
.
drive_sda
=
nv04_i2c_drive_sda
,
.
sense_scl
=
nv04_i2c_sense_scl
,
.
sense_sda
=
nv04_i2c_sense_sda
,
};
static
int
nv04_i2c_port_ctor
(
struct
nvkm_object
*
parent
,
struct
nvkm_object
*
engine
,
struct
nvkm_oclass
*
oclass
,
void
*
data
,
u32
index
,
struct
nvkm_object
**
pobject
)
{
struct
dcb_i2c_entry
*
info
=
data
;
struct
nv04_i2c_port
*
port
;
int
ret
;
ret
=
nvkm_i2c_port_create
(
parent
,
engine
,
oclass
,
index
,
&
nvkm_i2c_bit_algo
,
&
nv04_i2c_func
,
&
port
);
*
pobject
=
nv_object
(
port
);
if
(
ret
)
return
ret
;
port
->
drive
=
info
->
drive
;
port
->
sense
=
info
->
sense
;
return
0
;
}
static
struct
nvkm_oclass
nv04_i2c_sclass
[]
=
{
{
.
handle
=
NV_I2C_TYPE_DCBI2C
(
DCB_I2C_NV04_BIT
),
.
ofuncs
=
&
(
struct
nvkm_ofuncs
)
{
.
ctor
=
nv04_i2c_port_ctor
,
.
dtor
=
_nvkm_i2c_port_dtor
,
.
init
=
_nvkm_i2c_port_init
,
.
fini
=
_nvkm_i2c_port_fini
,
},
},
{}
};
#include "pad.h"
struct
nvkm_oclass
*
nv04_i2c_oclass
=
&
(
struct
nvkm_i2c_impl
)
{
...
...
@@ -119,6 +33,5 @@ nv04_i2c_oclass = &(struct nvkm_i2c_impl) {
.
init
=
_nvkm_i2c_init
,
.
fini
=
_nvkm_i2c_fini
,
},
.
sclass
=
nv04_i2c_sclass
,
.
pad_x
=
&
nv04_i2c_pad_oclass
,
.
pad_x_new
=
nv04_i2c_pad_new
,
}.
base
;
drivers/gpu/drm/nouveau/nvkm/subdev/i2c/nv4e.c
View file @
2aa5eac5
...
...
@@ -22,89 +22,7 @@
* Authors: Ben Skeggs
*/
#include "priv.h"
#include <subdev/vga.h>
struct
nv4e_i2c_port
{
struct
nvkm_i2c_port
base
;
u32
addr
;
};
static
void
nv4e_i2c_drive_scl
(
struct
nvkm_i2c_port
*
base
,
int
state
)
{
struct
nvkm_i2c
*
i2c
=
(
void
*
)
nvkm_i2c
(
base
);
struct
nvkm_device
*
device
=
i2c
->
subdev
.
device
;
struct
nv4e_i2c_port
*
port
=
(
void
*
)
base
;
nvkm_mask
(
device
,
port
->
addr
,
0x2f
,
state
?
0x21
:
0x01
);
}
static
void
nv4e_i2c_drive_sda
(
struct
nvkm_i2c_port
*
base
,
int
state
)
{
struct
nvkm_i2c
*
i2c
=
(
void
*
)
nvkm_i2c
(
base
);
struct
nvkm_device
*
device
=
i2c
->
subdev
.
device
;
struct
nv4e_i2c_port
*
port
=
(
void
*
)
base
;
nvkm_mask
(
device
,
port
->
addr
,
0x1f
,
state
?
0x11
:
0x01
);
}
static
int
nv4e_i2c_sense_scl
(
struct
nvkm_i2c_port
*
base
)
{
struct
nvkm_i2c
*
i2c
=
(
void
*
)
nvkm_i2c
(
base
);
struct
nvkm_device
*
device
=
i2c
->
subdev
.
device
;
struct
nv4e_i2c_port
*
port
=
(
void
*
)
base
;
return
!!
(
nvkm_rd32
(
device
,
port
->
addr
)
&
0x00040000
);
}
static
int
nv4e_i2c_sense_sda
(
struct
nvkm_i2c_port
*
base
)
{
struct
nvkm_i2c
*
i2c
=
(
void
*
)
nvkm_i2c
(
base
);
struct
nvkm_device
*
device
=
i2c
->
subdev
.
device
;
struct
nv4e_i2c_port
*
port
=
(
void
*
)
base
;
return
!!
(
nvkm_rd32
(
device
,
port
->
addr
)
&
0x00080000
);
}
static
const
struct
nvkm_i2c_func
nv4e_i2c_func
=
{
.
drive_scl
=
nv4e_i2c_drive_scl
,
.
drive_sda
=
nv4e_i2c_drive_sda
,
.
sense_scl
=
nv4e_i2c_sense_scl
,
.
sense_sda
=
nv4e_i2c_sense_sda
,
};
static
int
nv4e_i2c_port_ctor
(
struct
nvkm_object
*
parent
,
struct
nvkm_object
*
engine
,
struct
nvkm_oclass
*
oclass
,
void
*
data
,
u32
index
,
struct
nvkm_object
**
pobject
)
{
struct
dcb_i2c_entry
*
info
=
data
;
struct
nv4e_i2c_port
*
port
;
int
ret
;
ret
=
nvkm_i2c_port_create
(
parent
,
engine
,
oclass
,
index
,
&
nvkm_i2c_bit_algo
,
&
nv4e_i2c_func
,
&
port
);
*
pobject
=
nv_object
(
port
);
if
(
ret
)
return
ret
;
port
->
addr
=
0x600800
+
info
->
drive
;
return
0
;
}
static
struct
nvkm_oclass
nv4e_i2c_sclass
[]
=
{
{
.
handle
=
NV_I2C_TYPE_DCBI2C
(
DCB_I2C_NV4E_BIT
),
.
ofuncs
=
&
(
struct
nvkm_ofuncs
)
{
.
ctor
=
nv4e_i2c_port_ctor
,
.
dtor
=
_nvkm_i2c_port_dtor
,
.
init
=
_nvkm_i2c_port_init
,
.
fini
=
_nvkm_i2c_port_fini
,
},
},
{}
};
#include "pad.h"
struct
nvkm_oclass
*
nv4e_i2c_oclass
=
&
(
struct
nvkm_i2c_impl
)
{
...
...
@@ -115,6 +33,5 @@ nv4e_i2c_oclass = &(struct nvkm_i2c_impl) {
.
init
=
_nvkm_i2c_init
,
.
fini
=
_nvkm_i2c_fini
,
},
.
sclass
=
nv4e_i2c_sclass
,
.
pad_x
=
&
nv04_i2c_pad_oclass
,
.
pad_x_new
=
nv4e_i2c_pad_new
,
}.
base
;
drivers/gpu/drm/nouveau/nvkm/subdev/i2c/nv50.c
View file @
2aa5eac5
...
...
@@ -21,108 +21,8 @@
*
* Authors: Ben Skeggs
*/
#include "nv50.h"
void
nv50_i2c_drive_scl
(
struct
nvkm_i2c_port
*
base
,
int
state
)
{
struct
nvkm_i2c
*
i2c
=
(
void
*
)
nvkm_i2c
(
base
);
struct
nvkm_device
*
device
=
i2c
->
subdev
.
device
;
struct
nv50_i2c_port
*
port
=
(
void
*
)
base
;
if
(
state
)
port
->
state
|=
0x01
;
else
port
->
state
&=
0xfe
;
nvkm_wr32
(
device
,
port
->
addr
,
port
->
state
);
}
void
nv50_i2c_drive_sda
(
struct
nvkm_i2c_port
*
base
,
int
state
)
{
struct
nvkm_i2c
*
i2c
=
(
void
*
)
nvkm_i2c
(
base
);
struct
nvkm_device
*
device
=
i2c
->
subdev
.
device
;
struct
nv50_i2c_port
*
port
=
(
void
*
)
base
;
if
(
state
)
port
->
state
|=
0x02
;
else
port
->
state
&=
0xfd
;
nvkm_wr32
(
device
,
port
->
addr
,
port
->
state
);
}
int
nv50_i2c_sense_scl
(
struct
nvkm_i2c_port
*
base
)
{
struct
nvkm_i2c
*
i2c
=
(
void
*
)
nvkm_i2c
(
base
);
struct
nvkm_device
*
device
=
i2c
->
subdev
.
device
;
struct
nv50_i2c_port
*
port
=
(
void
*
)
base
;
return
!!
(
nvkm_rd32
(
device
,
port
->
addr
)
&
0x00000001
);
}
int
nv50_i2c_sense_sda
(
struct
nvkm_i2c_port
*
base
)
{
struct
nvkm_i2c
*
i2c
=
(
void
*
)
nvkm_i2c
(
base
);
struct
nvkm_device
*
device
=
i2c
->
subdev
.
device
;
struct
nv50_i2c_port
*
port
=
(
void
*
)
base
;
return
!!
(
nvkm_rd32
(
device
,
port
->
addr
)
&
0x00000002
);
}
static
const
struct
nvkm_i2c_func
nv50_i2c_func
=
{
.
drive_scl
=
nv50_i2c_drive_scl
,
.
drive_sda
=
nv50_i2c_drive_sda
,
.
sense_scl
=
nv50_i2c_sense_scl
,
.
sense_sda
=
nv50_i2c_sense_sda
,
};
const
u32
nv50_i2c_addr
[]
=
{
0x00e138
,
0x00e150
,
0x00e168
,
0x00e180
,
0x00e254
,
0x00e274
,
0x00e764
,
0x00e780
,
0x00e79c
,
0x00e7b8
};
const
int
nv50_i2c_addr_nr
=
ARRAY_SIZE
(
nv50_i2c_addr
);
static
int
nv50_i2c_port_ctor
(
struct
nvkm_object
*
parent
,
struct
nvkm_object
*
engine
,
struct
nvkm_oclass
*
oclass
,
void
*
data
,
u32
index
,
struct
nvkm_object
**
pobject
)
{
struct
dcb_i2c_entry
*
info
=
data
;
struct
nv50_i2c_port
*
port
;
int
ret
;
ret
=
nvkm_i2c_port_create
(
parent
,
engine
,
oclass
,
index
,
&
nvkm_i2c_bit_algo
,
&
nv50_i2c_func
,
&
port
);
*
pobject
=
nv_object
(
port
);
if
(
ret
)
return
ret
;
if
(
info
->
drive
>=
nv50_i2c_addr_nr
)
return
-
EINVAL
;
port
->
state
=
0x00000007
;
port
->
addr
=
nv50_i2c_addr
[
info
->
drive
];
return
0
;
}
int
nv50_i2c_port_init
(
struct
nvkm_object
*
object
)
{
struct
nvkm_i2c
*
i2c
=
(
void
*
)
nvkm_i2c
(
object
);
struct
nvkm_device
*
device
=
i2c
->
subdev
.
device
;
struct
nv50_i2c_port
*
port
=
(
void
*
)
object
;
nvkm_wr32
(
device
,
port
->
addr
,
port
->
state
);
return
nvkm_i2c_port_init
(
&
port
->
base
);
}
static
struct
nvkm_oclass
nv50_i2c_sclass
[]
=
{
{
.
handle
=
NV_I2C_TYPE_DCBI2C
(
DCB_I2C_NVIO_BIT
),
.
ofuncs
=
&
(
struct
nvkm_ofuncs
)
{
.
ctor
=
nv50_i2c_port_ctor
,
.
dtor
=
_nvkm_i2c_port_dtor
,
.
init
=
nv50_i2c_port_init
,
.
fini
=
_nvkm_i2c_port_fini
,
},
},
{}
};
#include "priv.h"
#include "pad.h"
struct
nvkm_oclass
*
nv50_i2c_oclass
=
&
(
struct
nvkm_i2c_impl
)
{
...
...
@@ -133,6 +33,5 @@ nv50_i2c_oclass = &(struct nvkm_i2c_impl) {
.
init
=
_nvkm_i2c_init
,
.
fini
=
_nvkm_i2c_fini
,
},
.
sclass
=
nv50_i2c_sclass
,
.
pad_x
=
&
nv04_i2c_pad_oclass
,
.
pad_x_new
=
nv50_i2c_pad_new
,
}.
base
;
drivers/gpu/drm/nouveau/nvkm/subdev/i2c/nv50.h
deleted
100644 → 0
View file @
d36a99d2
#ifndef __NV50_I2C_H__
#define __NV50_I2C_H__
#include "priv.h"
struct
nv50_i2c_port
{
struct
nvkm_i2c_port
base
;
u32
addr
;
u32
state
;
};
extern
const
u32
nv50_i2c_addr
[];
extern
const
int
nv50_i2c_addr_nr
;
int
nv50_i2c_port_init
(
struct
nvkm_object
*
);
int
nv50_i2c_sense_scl
(
struct
nvkm_i2c_port
*
);
int
nv50_i2c_sense_sda
(
struct
nvkm_i2c_port
*
);
void
nv50_i2c_drive_scl
(
struct
nvkm_i2c_port
*
,
int
state
);
void
nv50_i2c_drive_sda
(
struct
nvkm_i2c_port
*
,
int
state
);
int
g94_aux_port_ctor
(
struct
nvkm_object
*
,
struct
nvkm_object
*
,
struct
nvkm_oclass
*
,
void
*
,
u32
,
struct
nvkm_object
**
);
void
g94_i2c_acquire
(
struct
nvkm_i2c_port
*
);
void
g94_i2c_release
(
struct
nvkm_i2c_port
*
);
int
gf110_i2c_port_ctor
(
struct
nvkm_object
*
,
struct
nvkm_object
*
,
struct
nvkm_oclass
*
,
void
*
,
u32
,
struct
nvkm_object
**
);
#endif
drivers/gpu/drm/nouveau/nvkm/subdev/i2c/pad.c
View file @
2aa5eac5
/*
* Copyright 201
4
Red Hat Inc.
* Copyright 201
5
Red Hat Inc.
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
...
...
@@ -19,65 +19,98 @@
* ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
* OTHER DEALINGS IN THE SOFTWARE.
*
* Authors: Ben Skeggs
* Authors: Ben Skeggs
<bskeggs@redhat.com>
*/
#include "pad.h"
int
_nvkm_i2c_pad_fini
(
struct
nvkm_object
*
object
,
bool
suspend
)
static
void
nvkm_i2c_pad_mode_locked
(
struct
nvkm_i2c_pad
*
pad
,
enum
nvkm_i2c_pad_mode
mode
)
{
struct
nvkm_i2c_pad
*
pad
=
(
void
*
)
object
;
DBG
(
"-> NULL
\n
"
);
pad
->
port
=
NULL
;
return
nvkm_object_fini
(
&
pad
->
base
,
suspend
);
PAD_TRACE
(
pad
,
"-> %s"
,
(
mode
==
NVKM_I2C_PAD_AUX
)
?
"aux"
:
(
mode
==
NVKM_I2C_PAD_I2C
)
?
"i2c"
:
"off
"
);
if
(
pad
->
func
->
mode
)
pad
->
func
->
mode
(
pad
,
mode
);
}
int
_nvkm_i2c_pad_init
(
struct
nvkm_object
*
object
)
void
nvkm_i2c_pad_mode
(
struct
nvkm_i2c_pad
*
pad
,
enum
nvkm_i2c_pad_mode
mode
)
{
struct
nvkm_i2c_pad
*
pad
=
(
void
*
)
object
;
DBG
(
"-> PORT:%02x
\n
"
,
pad
->
next
->
index
);
pad
->
port
=
pad
->
next
;
return
nvkm_object_init
(
&
pad
->
base
);
PAD_TRACE
(
pad
,
"mode %d"
,
mode
);
mutex_lock
(
&
pad
->
mutex
);
nvkm_i2c_pad_mode_locked
(
pad
,
mode
);
pad
->
mode
=
mode
;
mutex_unlock
(
&
pad
->
mutex
);
}
int
nvkm_i2c_pad_create_
(
struct
nvkm_object
*
parent
,
struct
nvkm_object
*
engine
,
struct
nvkm_oclass
*
oclass
,
int
index
,
int
size
,
void
**
pobject
)
void
nvkm_i2c_pad_release
(
struct
nvkm_i2c_pad
*
pad
)
{
struct
nvkm_i2c
*
i2c
=
nvkm_i2c
(
parent
);
struct
nvkm_i2c_port
*
port
;
struct
nvkm_i2c_pad
*
pad
;
int
ret
;
PAD_TRACE
(
pad
,
"release"
);
if
(
pad
->
mode
==
NVKM_I2C_PAD_OFF
)
nvkm_i2c_pad_mode_locked
(
pad
,
pad
->
mode
);
mutex_unlock
(
&
pad
->
mutex
);
}
list_for_each_entry
(
port
,
&
i2c
->
ports
,
head
)
{
pad
=
nvkm_i2c_pad
(
port
);
if
(
pad
->
index
==
index
)
{
atomic_inc
(
&
nv_object
(
pad
)
->
refcount
);
*
pobject
=
pad
;
return
1
;
int
nvkm_i2c_pad_acquire
(
struct
nvkm_i2c_pad
*
pad
,
enum
nvkm_i2c_pad_mode
mode
)
{
PAD_TRACE
(
pad
,
"acquire"
);
mutex_lock
(
&
pad
->
mutex
);
if
(
pad
->
mode
!=
mode
)
{
if
(
pad
->
mode
!=
NVKM_I2C_PAD_OFF
)
{
mutex_unlock
(
&
pad
->
mutex
);
return
-
EBUSY
;
}
nvkm_i2c_pad_mode_locked
(
pad
,
mode
);
}
return
0
;
}
void
nvkm_i2c_pad_fini
(
struct
nvkm_i2c_pad
*
pad
)
{
PAD_TRACE
(
pad
,
"fini"
);
nvkm_i2c_pad_mode_locked
(
pad
,
NVKM_I2C_PAD_OFF
);
}
ret
=
nvkm_object_create_
(
parent
,
engine
,
oclass
,
0
,
size
,
pobject
);
pad
=
*
pobject
;
if
(
ret
)
return
ret
;
void
nvkm_i2c_pad_init
(
struct
nvkm_i2c_pad
*
pad
)
{
PAD_TRACE
(
pad
,
"init"
);
nvkm_i2c_pad_mode_locked
(
pad
,
pad
->
mode
);
}
pad
->
index
=
index
;
return
0
;
void
nvkm_i2c_pad_del
(
struct
nvkm_i2c_pad
**
ppad
)
{
struct
nvkm_i2c_pad
*
pad
=
*
ppad
;
if
(
pad
)
{
PAD_TRACE
(
pad
,
"dtor"
);
list_del
(
&
pad
->
head
);
kfree
(
pad
);
pad
=
NULL
;
}
}
void
nvkm_i2c_pad_ctor
(
const
struct
nvkm_i2c_pad_func
*
func
,
struct
nvkm_i2c
*
i2c
,
int
id
,
struct
nvkm_i2c_pad
*
pad
)
{
pad
->
func
=
func
;
pad
->
i2c
=
i2c
;
pad
->
id
=
id
;
pad
->
mode
=
NVKM_I2C_PAD_OFF
;
mutex_init
(
&
pad
->
mutex
);
list_add_tail
(
&
pad
->
head
,
&
i2c
->
pad
);
PAD_TRACE
(
pad
,
"ctor"
);
}
int
_nvkm_i2c_pad_ctor
(
struct
nvkm_object
*
parent
,
struct
nvkm_object
*
engine
,
struct
nvkm_oclass
*
oclass
,
void
*
data
,
u32
index
,
struct
nvkm_object
**
pobject
)
nvkm_i2c_pad_new_
(
const
struct
nvkm_i2c_pad_func
*
func
,
struct
nvkm_i2c
*
i2c
,
int
id
,
struct
nvkm_i2c_pad
**
ppad
)
{
struct
nvkm_i2c_pad
*
pad
;
int
ret
;
ret
=
nvkm_i2c_pad_create
(
parent
,
engine
,
oclass
,
index
,
&
pad
);
*
pobject
=
nv_object
(
pad
);
return
ret
;
if
(
!
(
*
ppad
=
kzalloc
(
sizeof
(
**
ppad
),
GFP_KERNEL
)))
return
-
ENOMEM
;
nvkm_i2c_pad_ctor
(
func
,
i2c
,
id
,
*
ppad
);
return
0
;
}
drivers/gpu/drm/nouveau/nvkm/subdev/i2c/pad.h
View file @
2aa5eac5
#ifndef __NVKM_I2C_PAD_H__
#define __NVKM_I2C_PAD_H__
#include
"priv.h"
#include
<subdev/i2c.h>
struct
nvkm_i2c_pad
{
struct
nvkm_object
base
;
int
index
;
struct
nvkm_i2c_port
*
port
;
struct
nvkm_i2c_port
*
next
;
const
struct
nvkm_i2c_pad_func
*
func
;
struct
nvkm_i2c
*
i2c
;
#define NVKM_I2C_PAD_HYBRID(n)
/* 'n' is hw pad index */
(n)
#define NVKM_I2C_PAD_CCB(n)
/* 'n' is ccb index */
((n) + 0x100)
#define NVKM_I2C_PAD_EXT(n)
/* 'n' is dcb external encoder type */
((n) + 0x200)
int
id
;
enum
nvkm_i2c_pad_mode
{
NVKM_I2C_PAD_OFF
,
NVKM_I2C_PAD_I2C
,
NVKM_I2C_PAD_AUX
,
}
mode
;
struct
mutex
mutex
;
struct
list_head
head
;
};
struct
nvkm_i2c_pad_func
{
int
(
*
bus_new_0
)(
struct
nvkm_i2c_pad
*
,
int
id
,
u8
drive
,
u8
sense
,
struct
nvkm_i2c_bus
**
);
int
(
*
bus_new_4
)(
struct
nvkm_i2c_pad
*
,
int
id
,
u8
drive
,
struct
nvkm_i2c_bus
**
);
int
(
*
aux_new_6
)(
struct
nvkm_i2c_pad
*
,
int
id
,
u8
drive
,
struct
nvkm_i2c_aux
**
);
void
(
*
mode
)(
struct
nvkm_i2c_pad
*
,
enum
nvkm_i2c_pad_mode
);
};
static
inline
struct
nvkm_i2c_pad
*
nvkm_i2c_pad
(
struct
nvkm_i2c_port
*
port
)
{
struct
nvkm_object
*
pad
=
nv_object
(
port
);
while
(
!
nv_iclass
(
pad
->
parent
,
NV_SUBDEV_CLASS
))
pad
=
pad
->
parent
;
return
(
void
*
)
pad
;
}
#define nvkm_i2c_pad_create(p,e,o,i,d) \
nvkm_i2c_pad_create_((p), (e), (o), (i), sizeof(**d), (void **)d)
#define nvkm_i2c_pad_destroy(p) ({ \
struct nvkm_i2c_pad *_p = (p); \
_nvkm_i2c_pad_dtor(nv_object(_p)); \
})
#define nvkm_i2c_pad_init(p) ({ \
struct nvkm_i2c_pad *_p = (p); \
_nvkm_i2c_pad_init(nv_object(_p)); \
})
#define nvkm_i2c_pad_fini(p,s) ({ \
struct nvkm_i2c_pad *_p = (p); \
_nvkm_i2c_pad_fini(nv_object(_p), (s)); \
})
int
nvkm_i2c_pad_create_
(
struct
nvkm_object
*
,
struct
nvkm_object
*
,
struct
nvkm_oclass
*
,
int
index
,
int
,
void
**
);
int
_nvkm_i2c_pad_ctor
(
struct
nvkm_object
*
,
struct
nvkm_object
*
,
struct
nvkm_oclass
*
,
void
*
,
u32
,
struct
nvkm_object
**
);
#define _nvkm_i2c_pad_dtor nvkm_object_destroy
int
_nvkm_i2c_pad_init
(
struct
nvkm_object
*
);
int
_nvkm_i2c_pad_fini
(
struct
nvkm_object
*
,
bool
);
#ifndef MSG
#define MSG(l,f,a...) do { \
struct nvkm_i2c_pad *_pad = (void *)pad; \
struct nvkm_i2c *_i2c = nvkm_i2c(_pad); \
nvkm_##l(&_i2c->subdev, "PAD:%c:%02x: "f, \
_pad->index >= 0x100 ? 'X' : 'S', \
_pad->index >= 0x100 ? \
_pad->index - 0x100 : _pad->index, ##a); \
void
nvkm_i2c_pad_ctor
(
const
struct
nvkm_i2c_pad_func
*
,
struct
nvkm_i2c
*
,
int
id
,
struct
nvkm_i2c_pad
*
);
int
nvkm_i2c_pad_new_
(
const
struct
nvkm_i2c_pad_func
*
,
struct
nvkm_i2c
*
,
int
id
,
struct
nvkm_i2c_pad
**
);
void
nvkm_i2c_pad_del
(
struct
nvkm_i2c_pad
**
);
void
nvkm_i2c_pad_init
(
struct
nvkm_i2c_pad
*
);
void
nvkm_i2c_pad_fini
(
struct
nvkm_i2c_pad
*
);
void
nvkm_i2c_pad_mode
(
struct
nvkm_i2c_pad
*
,
enum
nvkm_i2c_pad_mode
);
int
nvkm_i2c_pad_acquire
(
struct
nvkm_i2c_pad
*
,
enum
nvkm_i2c_pad_mode
);
void
nvkm_i2c_pad_release
(
struct
nvkm_i2c_pad
*
);
void
g94_i2c_pad_mode
(
struct
nvkm_i2c_pad
*
,
enum
nvkm_i2c_pad_mode
);
int
nv04_i2c_pad_new
(
struct
nvkm_i2c
*
,
int
,
struct
nvkm_i2c_pad
**
);
int
nv4e_i2c_pad_new
(
struct
nvkm_i2c
*
,
int
,
struct
nvkm_i2c_pad
**
);
int
nv50_i2c_pad_new
(
struct
nvkm_i2c
*
,
int
,
struct
nvkm_i2c_pad
**
);
int
g94_i2c_pad_x_new
(
struct
nvkm_i2c
*
,
int
,
struct
nvkm_i2c_pad
**
);
int
gf119_i2c_pad_x_new
(
struct
nvkm_i2c
*
,
int
,
struct
nvkm_i2c_pad
**
);
int
gm204_i2c_pad_x_new
(
struct
nvkm_i2c
*
,
int
,
struct
nvkm_i2c_pad
**
);
int
g94_i2c_pad_s_new
(
struct
nvkm_i2c
*
,
int
,
struct
nvkm_i2c_pad
**
);
int
gf119_i2c_pad_s_new
(
struct
nvkm_i2c
*
,
int
,
struct
nvkm_i2c_pad
**
);
int
gm204_i2c_pad_s_new
(
struct
nvkm_i2c
*
,
int
,
struct
nvkm_i2c_pad
**
);
int
anx9805_pad_new
(
struct
nvkm_i2c_bus
*
,
int
,
u8
,
struct
nvkm_i2c_pad
**
);
#define PAD_MSG(p,l,f,a...) do { \
struct nvkm_i2c_pad *_pad = (p); \
nvkm_##l(&_pad->i2c->subdev, "pad %04x: "f"\n", _pad->id, ##a); \
} while(0)
#define
DBG(f,a...) MSG(debug
, f, ##a)
#define
ERR(f,a...) MSG(error
, f, ##a)
#
endif
#define
PAD_ERR(p,f,a...) PAD_MSG((p), error
, f, ##a)
#define
PAD_DBG(p,f,a...) PAD_MSG((p), debug
, f, ##a)
#
define PAD_TRACE(p,f,a...) PAD_MSG((p), trace, f, ##a)
#endif
drivers/gpu/drm/nouveau/nvkm/subdev/i2c/padg94.c
View file @
2aa5eac5
...
...
@@ -22,66 +22,55 @@
* Authors: Ben Skeggs
*/
#include "pad.h"
#include "aux.h"
#include "bus.h"
struct
g94_i2c_pad
{
struct
nvkm_i2c_pad
base
;
int
addr
;
};
static
int
g94_i2c_pad_fini
(
struct
nvkm_object
*
object
,
bool
suspend
)
{
struct
nvkm_i2c
*
i2c
=
(
void
*
)
nvkm_i2c
(
object
);
struct
nvkm_device
*
device
=
i2c
->
subdev
.
device
;
struct
g94_i2c_pad
*
pad
=
(
void
*
)
object
;
nvkm_mask
(
device
,
0x00e50c
+
pad
->
addr
,
0x00000001
,
0x00000001
);
return
nvkm_i2c_pad_fini
(
&
pad
->
base
,
suspend
);
}
static
int
g94_i2c_pad_init
(
struct
nvkm_object
*
object
)
void
g94_i2c_pad_mode
(
struct
nvkm_i2c_pad
*
pad
,
enum
nvkm_i2c_pad_mode
mode
)
{
struct
nvkm_
i2c
*
i2c
=
(
void
*
)
nvkm_i2c
(
object
)
;
struct
nvkm_device
*
device
=
i2c
->
subdev
.
device
;
struct
g94_i2c_pad
*
pad
=
(
void
*
)
object
;
struct
nvkm_
subdev
*
subdev
=
&
pad
->
i2c
->
subdev
;
struct
nvkm_device
*
device
=
subdev
->
device
;
const
u32
base
=
(
pad
->
id
-
NVKM_I2C_PAD_HYBRID
(
0
))
*
0x50
;
switch
(
nv_oclass
(
pad
->
base
.
next
)
->
handle
)
{
case
NV_I2C_TYPE_DCBI2C
(
DCB_I2C_NVIO_AUX
):
nvkm_mask
(
device
,
0x00e500
+
pad
->
addr
,
0x0000c003
,
0x00000002
);
switch
(
mode
)
{
case
NVKM_I2C_PAD_OFF
:
nvkm_mask
(
device
,
0x00e50c
+
base
,
0x00000001
,
0x00000001
);
break
;
case
NVKM_I2C_PAD_I2C
:
nvkm_mask
(
device
,
0x00e500
+
base
,
0x0000c003
,
0x0000c001
);
nvkm_mask
(
device
,
0x00e50c
+
base
,
0x00000001
,
0x00000000
);
break
;
case
NVKM_I2C_PAD_AUX
:
nvkm_mask
(
device
,
0x00e500
+
base
,
0x0000c003
,
0x00000002
);
nvkm_mask
(
device
,
0x00e50c
+
base
,
0x00000001
,
0x00000000
);
break
;
case
NV_I2C_TYPE_DCBI2C
(
DCB_I2C_NVIO_BIT
):
default:
nvkm_mask
(
device
,
0x00e500
+
pad
->
addr
,
0x0000c003
,
0x0000c00
1
);
WARN_ON
(
1
);
break
;
}
nvkm_mask
(
device
,
0x00e50c
+
pad
->
addr
,
0x00000001
,
0x00000000
);
return
nvkm_i2c_pad_init
(
&
pad
->
base
);
}
static
int
g94_i2c_pad_ctor
(
struct
nvkm_object
*
parent
,
struct
nvkm_object
*
engine
,
struct
nvkm_oclass
*
oclass
,
void
*
data
,
u32
index
,
struct
nvkm_object
**
pobject
)
{
struct
g94_i2c_pad
*
pad
;
int
ret
;
ret
=
nvkm_i2c_pad_create
(
parent
,
engine
,
oclass
,
index
,
&
pad
);
*
pobject
=
nv_object
(
pad
);
if
(
ret
)
return
ret
;
static
const
struct
nvkm_i2c_pad_func
g94_i2c_pad_s_func
=
{
.
bus_new_4
=
nv50_i2c_bus_new
,
.
aux_new_6
=
g94_i2c_aux_new
,
.
mode
=
g94_i2c_pad_mode
,
};
pad
->
addr
=
index
*
0x50
;;
return
0
;
int
g94_i2c_pad_s_new
(
struct
nvkm_i2c
*
i2c
,
int
id
,
struct
nvkm_i2c_pad
**
ppad
)
{
return
nvkm_i2c_pad_new_
(
&
g94_i2c_pad_s_func
,
i2c
,
id
,
ppad
);
}
struct
nvkm_oclass
g94_i2c_pad_oclass
=
{
.
ofuncs
=
&
(
struct
nvkm_ofuncs
)
{
.
ctor
=
g94_i2c_pad_ctor
,
.
dtor
=
_nvkm_i2c_pad_dtor
,
.
init
=
g94_i2c_pad_init
,
.
fini
=
g94_i2c_pad_fini
,
},
static
const
struct
nvkm_i2c_pad_func
g94_i2c_pad_x_func
=
{
.
bus_new_4
=
nv50_i2c_bus_new
,
.
aux_new_6
=
g94_i2c_aux_new
,
};
int
g94_i2c_pad_x_new
(
struct
nvkm_i2c
*
i2c
,
int
id
,
struct
nvkm_i2c_pad
**
ppad
)
{
return
nvkm_i2c_pad_new_
(
&
g94_i2c_pad_x_func
,
i2c
,
id
,
ppad
);
}
drivers/gpu/drm/nouveau/nvkm/subdev/i2c/padgf119.c
0 → 100644
View file @
2aa5eac5
/*
* Copyright 2014 Red Hat Inc.
*
* 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 shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* THE COPYRIGHT HOLDER(S) OR AUTHOR(S) 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: Ben Skeggs
*/
#include "pad.h"
#include "aux.h"
#include "bus.h"
static
const
struct
nvkm_i2c_pad_func
gf119_i2c_pad_s_func
=
{
.
bus_new_4
=
gf119_i2c_bus_new
,
.
aux_new_6
=
g94_i2c_aux_new
,
.
mode
=
g94_i2c_pad_mode
,
};
int
gf119_i2c_pad_s_new
(
struct
nvkm_i2c
*
i2c
,
int
id
,
struct
nvkm_i2c_pad
**
ppad
)
{
return
nvkm_i2c_pad_new_
(
&
gf119_i2c_pad_s_func
,
i2c
,
id
,
ppad
);
}
static
const
struct
nvkm_i2c_pad_func
gf119_i2c_pad_x_func
=
{
.
bus_new_4
=
gf119_i2c_bus_new
,
.
aux_new_6
=
g94_i2c_aux_new
,
};
int
gf119_i2c_pad_x_new
(
struct
nvkm_i2c
*
i2c
,
int
id
,
struct
nvkm_i2c_pad
**
ppad
)
{
return
nvkm_i2c_pad_new_
(
&
gf119_i2c_pad_x_func
,
i2c
,
id
,
ppad
);
}
drivers/gpu/drm/nouveau/nvkm/subdev/i2c/padgm204.c
View file @
2aa5eac5
...
...
@@ -22,66 +22,55 @@
* Authors: Ben Skeggs
*/
#include "pad.h"
#include "aux.h"
#include "bus.h"
struct
gm204_i2c_pad
{
struct
nvkm_i2c_pad
base
;
int
addr
;
};
static
int
gm204_i2c_pad_fini
(
struct
nvkm_object
*
object
,
bool
suspend
)
{
struct
nvkm_i2c
*
i2c
=
(
void
*
)
nvkm_i2c
(
object
);
struct
nvkm_device
*
device
=
i2c
->
subdev
.
device
;
struct
gm204_i2c_pad
*
pad
=
(
void
*
)
object
;
nvkm_mask
(
device
,
0x00d97c
+
pad
->
addr
,
0x00000001
,
0x00000001
);
return
nvkm_i2c_pad_fini
(
&
pad
->
base
,
suspend
);
}
static
int
gm204_i2c_pad_init
(
struct
nvkm_object
*
object
)
static
void
gm204_i2c_pad_mode
(
struct
nvkm_i2c_pad
*
pad
,
enum
nvkm_i2c_pad_mode
mode
)
{
struct
nvkm_
i2c
*
i2c
=
(
void
*
)
nvkm_i2c
(
object
)
;
struct
nvkm_device
*
device
=
i2c
->
subdev
.
device
;
struct
gm204_i2c_pad
*
pad
=
(
void
*
)
object
;
struct
nvkm_
subdev
*
subdev
=
&
pad
->
i2c
->
subdev
;
struct
nvkm_device
*
device
=
subdev
->
device
;
const
u32
base
=
(
pad
->
id
-
NVKM_I2C_PAD_HYBRID
(
0
))
*
0x50
;
switch
(
nv_oclass
(
pad
->
base
.
next
)
->
handle
)
{
case
NV_I2C_TYPE_DCBI2C
(
DCB_I2C_NVIO_AUX
):
nvkm_mask
(
device
,
0x00d970
+
pad
->
addr
,
0x0000c003
,
0x00000002
);
switch
(
mode
)
{
case
NVKM_I2C_PAD_OFF
:
nvkm_mask
(
device
,
0x00d97c
+
base
,
0x00000001
,
0x00000001
);
break
;
case
NVKM_I2C_PAD_I2C
:
nvkm_mask
(
device
,
0x00d970
+
base
,
0x0000c003
,
0x0000c001
);
nvkm_mask
(
device
,
0x00d97c
+
base
,
0x00000001
,
0x00000000
);
break
;
case
NVKM_I2C_PAD_AUX
:
nvkm_mask
(
device
,
0x00d970
+
base
,
0x0000c003
,
0x00000002
);
nvkm_mask
(
device
,
0x00d97c
+
base
,
0x00000001
,
0x00000000
);
break
;
case
NV_I2C_TYPE_DCBI2C
(
DCB_I2C_NVIO_BIT
):
default:
nvkm_mask
(
device
,
0x00d970
+
pad
->
addr
,
0x0000c003
,
0x0000c00
1
);
WARN_ON
(
1
);
break
;
}
nvkm_mask
(
device
,
0x00d97c
+
pad
->
addr
,
0x00000001
,
0x00000000
);
return
nvkm_i2c_pad_init
(
&
pad
->
base
);
}
static
int
gm204_i2c_pad_ctor
(
struct
nvkm_object
*
parent
,
struct
nvkm_object
*
engine
,
struct
nvkm_oclass
*
oclass
,
void
*
data
,
u32
index
,
struct
nvkm_object
**
pobject
)
{
struct
gm204_i2c_pad
*
pad
;
int
ret
;
ret
=
nvkm_i2c_pad_create
(
parent
,
engine
,
oclass
,
index
,
&
pad
);
*
pobject
=
nv_object
(
pad
);
if
(
ret
)
return
ret
;
static
const
struct
nvkm_i2c_pad_func
gm204_i2c_pad_s_func
=
{
.
bus_new_4
=
gf119_i2c_bus_new
,
.
aux_new_6
=
gm204_i2c_aux_new
,
.
mode
=
gm204_i2c_pad_mode
,
};
pad
->
addr
=
index
*
0x50
;;
return
0
;
int
gm204_i2c_pad_s_new
(
struct
nvkm_i2c
*
i2c
,
int
id
,
struct
nvkm_i2c_pad
**
ppad
)
{
return
nvkm_i2c_pad_new_
(
&
gm204_i2c_pad_s_func
,
i2c
,
id
,
ppad
);
}
struct
nvkm_oclass
gm204_i2c_pad_oclass
=
{
.
ofuncs
=
&
(
struct
nvkm_ofuncs
)
{
.
ctor
=
gm204_i2c_pad_ctor
,
.
dtor
=
_nvkm_i2c_pad_dtor
,
.
init
=
gm204_i2c_pad_init
,
.
fini
=
gm204_i2c_pad_fini
,
},
static
const
struct
nvkm_i2c_pad_func
gm204_i2c_pad_x_func
=
{
.
bus_new_4
=
gf119_i2c_bus_new
,
.
aux_new_6
=
gm204_i2c_aux_new
,
};
int
gm204_i2c_pad_x_new
(
struct
nvkm_i2c
*
i2c
,
int
id
,
struct
nvkm_i2c_pad
**
ppad
)
{
return
nvkm_i2c_pad_new_
(
&
gm204_i2c_pad_x_func
,
i2c
,
id
,
ppad
);
}
drivers/gpu/drm/nouveau/nvkm/subdev/i2c/padnv04.c
View file @
2aa5eac5
...
...
@@ -22,13 +22,15 @@
* Authors: Ben Skeggs
*/
#include "pad.h"
#include "bus.h"
struct
nvkm_oclass
nv04_i2c_pad_oclass
=
{
.
ofuncs
=
&
(
struct
nvkm_ofuncs
)
{
.
ctor
=
_nvkm_i2c_pad_ctor
,
.
dtor
=
_nvkm_i2c_pad_dtor
,
.
init
=
_nvkm_i2c_pad_init
,
.
fini
=
_nvkm_i2c_pad_fini
,
},
static
const
struct
nvkm_i2c_pad_func
nv04_i2c_pad_func
=
{
.
bus_new_0
=
nv04_i2c_bus_new
,
};
int
nv04_i2c_pad_new
(
struct
nvkm_i2c
*
i2c
,
int
id
,
struct
nvkm_i2c_pad
**
ppad
)
{
return
nvkm_i2c_pad_new_
(
&
nv04_i2c_pad_func
,
i2c
,
id
,
ppad
);
}
drivers/gpu/drm/nouveau/nvkm/subdev/i2c/padnv4e.c
0 → 100644
View file @
2aa5eac5
/*
* Copyright 2014 Red Hat Inc.
*
* 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 shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* THE COPYRIGHT HOLDER(S) OR AUTHOR(S) 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: Ben Skeggs
*/
#include "pad.h"
#include "bus.h"
static
const
struct
nvkm_i2c_pad_func
nv4e_i2c_pad_func
=
{
.
bus_new_4
=
nv4e_i2c_bus_new
,
};
int
nv4e_i2c_pad_new
(
struct
nvkm_i2c
*
i2c
,
int
id
,
struct
nvkm_i2c_pad
**
ppad
)
{
return
nvkm_i2c_pad_new_
(
&
nv4e_i2c_pad_func
,
i2c
,
id
,
ppad
);
}
drivers/gpu/drm/nouveau/nvkm/subdev/i2c/padnv50.c
0 → 100644
View file @
2aa5eac5
/*
* Copyright 2014 Red Hat Inc.
*
* 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 shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* THE COPYRIGHT HOLDER(S) OR AUTHOR(S) 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: Ben Skeggs
*/
#include "pad.h"
#include "bus.h"
static
const
struct
nvkm_i2c_pad_func
nv50_i2c_pad_func
=
{
.
bus_new_4
=
nv50_i2c_bus_new
,
};
int
nv50_i2c_pad_new
(
struct
nvkm_i2c
*
i2c
,
int
id
,
struct
nvkm_i2c_pad
**
ppad
)
{
return
nvkm_i2c_pad_new_
(
&
nv50_i2c_pad_func
,
i2c
,
id
,
ppad
);
}
drivers/gpu/drm/nouveau/nvkm/subdev/i2c/port.h
deleted
100644 → 0
View file @
d36a99d2
#ifndef __NVKM_I2C_PORT_H__
#define __NVKM_I2C_PORT_H__
#include "priv.h"
#ifndef MSG
#define MSG(l,f,a...) do { \
struct nvkm_i2c_port *_port = (void *)port; \
struct nvkm_i2c *_i2c = nvkm_i2c(_port); \
nvkm_##l(&_i2c->subdev, "PORT:%02x: "f, _port->index, ##a); \
} while(0)
#define DBG(f,a...) MSG(debug, f, ##a)
#define ERR(f,a...) MSG(error, f, ##a)
#endif
#endif
drivers/gpu/drm/nouveau/nvkm/subdev/i2c/priv.h
View file @
2aa5eac5
...
...
@@ -2,31 +2,6 @@
#define __NVKM_I2C_PRIV_H__
#include <subdev/i2c.h>
extern
struct
nvkm_oclass
nv04_i2c_pad_oclass
;
extern
struct
nvkm_oclass
g94_i2c_pad_oclass
;
extern
struct
nvkm_oclass
gm204_i2c_pad_oclass
;
#define nvkm_i2c_port_create(p,e,o,i,a,f,d) \
nvkm_i2c_port_create_((p), (e), (o), (i), (a), (f), \
sizeof(**d), (void **)d)
#define nvkm_i2c_port_destroy(p) ({ \
struct nvkm_i2c_port *port = (p); \
_nvkm_i2c_port_dtor(nv_object(i2c)); \
})
#define nvkm_i2c_port_init(p) \
nvkm_object_init(&(p)->base)
#define nvkm_i2c_port_fini(p,s) \
nvkm_object_fini(&(p)->base, (s))
int
nvkm_i2c_port_create_
(
struct
nvkm_object
*
,
struct
nvkm_object
*
,
struct
nvkm_oclass
*
,
u8
,
const
struct
i2c_algorithm
*
,
const
struct
nvkm_i2c_func
*
,
int
,
void
**
);
void
_nvkm_i2c_port_dtor
(
struct
nvkm_object
*
);
#define _nvkm_i2c_port_init nvkm_object_init
int
_nvkm_i2c_port_fini
(
struct
nvkm_object
*
,
bool
);
#define nvkm_i2c_create(p,e,o,d) \
nvkm_i2c_create_((p), (e), (o), sizeof(**d), (void **)d)
#define nvkm_i2c_destroy(p) ({ \
...
...
@@ -51,19 +26,11 @@ void _nvkm_i2c_dtor(struct nvkm_object *);
int
_nvkm_i2c_init
(
struct
nvkm_object
*
);
int
_nvkm_i2c_fini
(
struct
nvkm_object
*
,
bool
);
extern
struct
nvkm_oclass
nvkm_anx9805_sclass
[];
extern
struct
nvkm_oclass
gf110_i2c_sclass
[];
extern
const
struct
i2c_algorithm
nvkm_i2c_bit_algo
;
extern
const
struct
i2c_algorithm
nvkm_i2c_aux_algo
;
struct
nvkm_i2c_impl
{
struct
nvkm_oclass
base
;
/* supported i2c port classes */
struct
nvkm_oclass
*
sclass
;
struct
nvkm_oclass
*
pad_x
;
struct
nvkm_oclass
*
pad_s
;
int
(
*
pad_x_new
)(
struct
nvkm_i2c
*
,
int
id
,
struct
nvkm_i2c_pad
**
);
int
(
*
pad_s_new
)(
struct
nvkm_i2c
*
,
int
id
,
struct
nvkm_i2c_pad
**
);
/* number of native dp aux channels present */
int
aux
;
...
...
drivers/gpu/drm/nouveau/nvkm/subdev/mxm/base.c
View file @
2aa5eac5
...
...
@@ -29,7 +29,7 @@
#include <subdev/i2c.h>
static
bool
mxm_shadow_rom_fetch
(
struct
nvkm_i2c_
port
*
i2c
,
u8
addr
,
mxm_shadow_rom_fetch
(
struct
nvkm_i2c_
bus
*
bus
,
u8
addr
,
u8
offset
,
u8
size
,
u8
*
data
)
{
struct
i2c_msg
msgs
[]
=
{
...
...
@@ -37,7 +37,7 @@ mxm_shadow_rom_fetch(struct nvkm_i2c_port *i2c, u8 addr,
{
.
addr
=
addr
,
.
flags
=
I2C_M_RD
,
.
len
=
size
,
.
buf
=
data
,
},
};
return
i2c_transfer
(
&
i2c
->
adapter
,
msgs
,
2
)
==
2
;
return
i2c_transfer
(
&
bus
->
i2c
,
msgs
,
2
)
==
2
;
}
static
bool
...
...
@@ -45,19 +45,19 @@ mxm_shadow_rom(struct nvkm_mxm *mxm, u8 version)
{
struct
nvkm_bios
*
bios
=
nvkm_bios
(
mxm
);
struct
nvkm_i2c
*
i2c
=
nvkm_i2c
(
mxm
);
struct
nvkm_i2c_
port
*
port
=
NULL
;
struct
nvkm_i2c_
bus
*
bus
=
NULL
;
u8
i2cidx
,
mxms
[
6
],
addr
,
size
;
i2cidx
=
mxm_ddc_map
(
bios
,
1
/* LVDS_DDC */
)
&
0x0f
;
if
(
i2cidx
<
0x0f
)
port
=
i2c
->
find
(
i2c
,
i2cidx
);
if
(
!
port
)
bus
=
nvkm_i2c_bus_
find
(
i2c
,
i2cidx
);
if
(
!
bus
)
return
false
;
addr
=
0x54
;
if
(
!
mxm_shadow_rom_fetch
(
port
,
addr
,
0
,
6
,
mxms
))
{
if
(
!
mxm_shadow_rom_fetch
(
bus
,
addr
,
0
,
6
,
mxms
))
{
addr
=
0x56
;
if
(
!
mxm_shadow_rom_fetch
(
port
,
addr
,
0
,
6
,
mxms
))
if
(
!
mxm_shadow_rom_fetch
(
bus
,
addr
,
0
,
6
,
mxms
))
return
false
;
}
...
...
@@ -66,7 +66,7 @@ mxm_shadow_rom(struct nvkm_mxm *mxm, u8 version)
mxm
->
mxms
=
kmalloc
(
size
,
GFP_KERNEL
);
if
(
mxm
->
mxms
&&
mxm_shadow_rom_fetch
(
port
,
addr
,
0
,
size
,
mxm
->
mxms
))
mxm_shadow_rom_fetch
(
bus
,
addr
,
0
,
size
,
mxm
->
mxms
))
return
true
;
kfree
(
mxm
->
mxms
);
...
...
drivers/gpu/drm/nouveau/nvkm/subdev/therm/ic.c
View file @
2aa5eac5
...
...
@@ -27,7 +27,7 @@
#include <subdev/i2c.h>
static
bool
probe_monitoring_device
(
struct
nvkm_i2c_
port
*
i2c
,
probe_monitoring_device
(
struct
nvkm_i2c_
bus
*
bus
,
struct
i2c_board_info
*
info
,
void
*
data
)
{
struct
nvkm_therm_priv
*
therm
=
data
;
...
...
@@ -36,7 +36,7 @@ probe_monitoring_device(struct nvkm_i2c_port *i2c,
request_module
(
"%s%s"
,
I2C_MODULE_PREFIX
,
info
->
type
);
client
=
i2c_new_device
(
&
i2c
->
adapter
,
info
);
client
=
i2c_new_device
(
&
bus
->
i2c
,
info
);
if
(
!
client
)
return
false
;
...
...
@@ -54,7 +54,7 @@ probe_monitoring_device(struct nvkm_i2c_port *i2c,
return
true
;
}
static
struct
nvkm_i2c_b
oard_info
static
struct
nvkm_i2c_b
us_probe
nv_board_infos
[]
=
{
{
{
I2C_BOARD_INFO
(
"w83l785ts"
,
0x2d
)
},
0
},
{
{
I2C_BOARD_INFO
(
"w83781d"
,
0x2d
)
},
0
},
...
...
@@ -83,30 +83,36 @@ void
nvkm_therm_ic_ctor
(
struct
nvkm_therm
*
obj
)
{
struct
nvkm_therm_priv
*
therm
=
container_of
(
obj
,
typeof
(
*
therm
),
base
);
struct
nvkm_bios
*
bios
=
nvkm_bios
(
therm
);
struct
nvkm_i2c
*
i2c
=
nvkm_i2c
(
therm
);
struct
nvkm_device
*
device
=
therm
->
base
.
subdev
.
device
;
struct
nvkm_bios
*
bios
=
device
->
bios
;
struct
nvkm_i2c
*
i2c
=
device
->
i2c
;
struct
nvkm_i2c_bus
*
bus
;
struct
nvbios_extdev_func
extdev_entry
;
bus
=
nvkm_i2c_bus_find
(
i2c
,
NVKM_I2C_BUS_PRI
);
if
(
!
bus
)
return
;
if
(
!
nvbios_extdev_find
(
bios
,
NVBIOS_EXTDEV_LM89
,
&
extdev_entry
))
{
struct
nvkm_i2c_b
oard_info
board
[]
=
{
struct
nvkm_i2c_b
us_probe
board
[]
=
{
{
{
I2C_BOARD_INFO
(
"lm90"
,
extdev_entry
.
addr
>>
1
)
},
0
},
{
}
};
i2c
->
identify
(
i2c
,
NV_I2C_DEFAULT
(
0
),
"monitoring device"
,
board
,
probe_monitoring_device
,
therm
);
nvkm_i2c_bus_probe
(
bus
,
"monitoring device"
,
board
,
probe_monitoring_device
,
therm
);
if
(
therm
->
ic
)
return
;
}
if
(
!
nvbios_extdev_find
(
bios
,
NVBIOS_EXTDEV_ADT7473
,
&
extdev_entry
))
{
struct
nvkm_i2c_b
oard_info
board
[]
=
{
struct
nvkm_i2c_b
us_probe
board
[]
=
{
{
{
I2C_BOARD_INFO
(
"adt7473"
,
extdev_entry
.
addr
>>
1
)
},
20
},
{
}
};
i2c
->
identify
(
i2c
,
NV_I2C_DEFAULT
(
0
),
"monitoring device"
,
board
,
probe_monitoring_device
,
therm
);
nvkm_i2c_bus_probe
(
bus
,
"monitoring device"
,
board
,
probe_monitoring_device
,
therm
);
if
(
therm
->
ic
)
return
;
}
...
...
@@ -114,6 +120,6 @@ nvkm_therm_ic_ctor(struct nvkm_therm *obj)
/* The vbios doesn't provide the address of an exisiting monitoring
device. Let's try our static list.
*/
i2c
->
identify
(
i2c
,
NV_I2C_DEFAULT
(
0
),
"monitoring device"
,
nv_board_infos
,
probe_monitoring_device
,
therm
);
nvkm_i2c_bus_probe
(
bus
,
"monitoring device"
,
nv_board_infos
,
probe_monitoring_device
,
therm
);
}
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