Skip to content
体验新版
项目
组织
正在加载...
登录
切换导航
打开侧边栏
openeuler
raspberrypi-kernel
提交
31a34aa4
R
raspberrypi-kernel
项目概览
openeuler
/
raspberrypi-kernel
通知
13
Star
1
Fork
0
代码
文件
提交
分支
Tags
贡献者
分支图
Diff
Issue
0
列表
看板
标记
里程碑
合并请求
0
Wiki
0
Wiki
分析
仓库
DevOps
项目成员
Pages
R
raspberrypi-kernel
项目概览
项目概览
详情
发布
仓库
仓库
文件
提交
分支
标签
贡献者
分支图
比较
Issue
0
Issue
0
列表
看板
标记
里程碑
合并请求
0
合并请求
0
Pages
分析
分析
仓库分析
DevOps
Wiki
0
Wiki
成员
成员
收起侧边栏
关闭侧边栏
动态
分支图
创建新Issue
提交
Issue看板
提交
31a34aa4
编写于
2月 14, 2013
作者:
B
Ben Skeggs
浏览文件
操作
浏览文件
下载
电子邮件补丁
差异文件
drm/nouveau/i2c: aux channels not necessarily on nvio
Signed-off-by:
N
Ben Skeggs
<
bskeggs@redhat.com
>
上级
eaa8e7ab
变更
5
隐藏空白更改
内联
并排
Showing
5 changed file
with
193 addition
and
148 deletion
+193
-148
drivers/gpu/drm/nouveau/Makefile
drivers/gpu/drm/nouveau/Makefile
+1
-0
drivers/gpu/drm/nouveau/core/include/subdev/i2c.h
drivers/gpu/drm/nouveau/core/include/subdev/i2c.h
+5
-0
drivers/gpu/drm/nouveau/core/subdev/i2c/aux.c
drivers/gpu/drm/nouveau/core/subdev/i2c/aux.c
+20
-148
drivers/gpu/drm/nouveau/core/subdev/i2c/base.c
drivers/gpu/drm/nouveau/core/subdev/i2c/base.c
+2
-0
drivers/gpu/drm/nouveau/core/subdev/i2c/nv94.c
drivers/gpu/drm/nouveau/core/subdev/i2c/nv94.c
+165
-0
未找到文件。
drivers/gpu/drm/nouveau/Makefile
浏览文件 @
31a34aa4
...
...
@@ -95,6 +95,7 @@ nouveau-y += core/subdev/gpio/nve0.o
nouveau-y
+=
core/subdev/i2c/base.o
nouveau-y
+=
core/subdev/i2c/aux.o
nouveau-y
+=
core/subdev/i2c/bit.o
nouveau-y
+=
core/subdev/i2c/nv94.o
nouveau-y
+=
core/subdev/ibus/nvc0.o
nouveau-y
+=
core/subdev/ibus/nve0.o
nouveau-y
+=
core/subdev/instmem/base.o
...
...
drivers/gpu/drm/nouveau/core/include/subdev/i2c.h
浏览文件 @
31a34aa4
...
...
@@ -21,6 +21,8 @@ struct nouveau_i2c_port {
u32
drive
;
u32
sense
;
u32
state
;
void
(
*
aux_mux
)(
struct
nouveau_i2c_port
*
);
int
(
*
aux
)(
struct
nouveau_i2c_port
*
,
u8
,
u32
,
u8
*
,
u8
);
};
struct
nouveau_i2c
{
...
...
@@ -57,4 +59,7 @@ int nv_wraux(struct nouveau_i2c_port *, u32 addr, u8 *data, u8 size);
extern
const
struct
i2c_algorithm
nouveau_i2c_bit_algo
;
extern
const
struct
i2c_algorithm
nouveau_i2c_aux_algo
;
void
nv94_aux_mux
(
struct
nouveau_i2c_port
*
);
int
nv94_aux
(
struct
nouveau_i2c_port
*
,
u8
,
u32
,
u8
*
,
u8
);
#endif
drivers/gpu/drm/nouveau/core/subdev/i2c/aux.c
浏览文件 @
31a34aa4
...
...
@@ -24,166 +24,39 @@
#include <subdev/i2c.h>
/******************************************************************************
* aux channel util functions
*****************************************************************************/
#define AUX_DBG(fmt, args...) nv_debug(aux, "AUXCH(%d): " fmt, ch, ##args)
#define AUX_ERR(fmt, args...) nv_error(aux, "AUXCH(%d): " fmt, ch, ##args)
static
void
auxch_fini
(
struct
nouveau_i2c
*
aux
,
int
ch
)
{
nv_mask
(
aux
,
0x00e4e4
+
(
ch
*
0x50
),
0x00310000
,
0x00000000
);
}
static
int
auxch_init
(
struct
nouveau_i2c
*
aux
,
int
ch
)
{
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
=
nv_rd32
(
aux
,
0x00e4e4
+
(
ch
*
0x50
));
udelay
(
1
);
if
(
!
timeout
--
)
{
AUX_ERR
(
"begin idle timeout 0x%08x
\n
"
,
ctrl
);
return
-
EBUSY
;
}
}
while
(
ctrl
&
0x03010000
);
/* set some magic, and wait up to 1ms for it to appear */
nv_mask
(
aux
,
0x00e4e4
+
(
ch
*
0x50
),
0x00300000
,
ureq
);
timeout
=
1000
;
do
{
ctrl
=
nv_rd32
(
aux
,
0x00e4e4
+
(
ch
*
0x50
));
udelay
(
1
);
if
(
!
timeout
--
)
{
AUX_ERR
(
"magic wait 0x%08x
\n
"
,
ctrl
);
auxch_fini
(
aux
,
ch
);
return
-
EBUSY
;
}
}
while
((
ctrl
&
0x03000000
)
!=
urep
);
return
0
;
}
static
int
auxch_tx
(
struct
nouveau_i2c
*
aux
,
int
ch
,
u8
type
,
u32
addr
,
u8
*
data
,
u8
size
)
{
u32
ctrl
,
stat
,
timeout
,
retries
;
u32
xbuf
[
4
]
=
{};
int
ret
,
i
;
AUX_DBG
(
"%d: 0x%08x %d
\n
"
,
type
,
addr
,
size
);
ret
=
auxch_init
(
aux
,
ch
);
if
(
ret
)
goto
out
;
stat
=
nv_rd32
(
aux
,
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 0x%08x
\n
"
,
xbuf
[
i
/
4
]);
nv_wr32
(
aux
,
0x00e4c0
+
(
ch
*
0x50
)
+
i
,
xbuf
[
i
/
4
]);
}
}
ctrl
=
nv_rd32
(
aux
,
0x00e4e4
+
(
ch
*
0x50
));
ctrl
&=
~
0x0001f0ff
;
ctrl
|=
type
<<
12
;
ctrl
|=
size
-
1
;
nv_wr32
(
aux
,
0x00e4e0
+
(
ch
*
0x50
),
addr
);
/* retry transaction a number of times on failure... */
ret
=
-
EREMOTEIO
;
for
(
retries
=
0
;
retries
<
32
;
retries
++
)
{
/* reset, and delay a while if this is a retry */
nv_wr32
(
aux
,
0x00e4e4
+
(
ch
*
0x50
),
0x80000000
|
ctrl
);
nv_wr32
(
aux
,
0x00e4e4
+
(
ch
*
0x50
),
0x00000000
|
ctrl
);
if
(
retries
)
udelay
(
400
);
/* transaction request, wait up to 1ms for it to complete */
nv_wr32
(
aux
,
0x00e4e4
+
(
ch
*
0x50
),
0x00010000
|
ctrl
);
timeout
=
1000
;
do
{
ctrl
=
nv_rd32
(
aux
,
0x00e4e4
+
(
ch
*
0x50
));
udelay
(
1
);
if
(
!
timeout
--
)
{
AUX_ERR
(
"tx req timeout 0x%08x
\n
"
,
ctrl
);
goto
out
;
}
}
while
(
ctrl
&
0x00010000
);
/* read status, and check if transaction completed ok */
stat
=
nv_mask
(
aux
,
0x00e4e8
+
(
ch
*
0x50
),
0
,
0
);
if
(
!
(
stat
&
0x000f0f00
))
{
ret
=
0
;
break
;
}
AUX_DBG
(
"%02d 0x%08x 0x%08x
\n
"
,
retries
,
ctrl
,
stat
);
}
if
(
type
&
1
)
{
for
(
i
=
0
;
i
<
16
;
i
+=
4
)
{
xbuf
[
i
/
4
]
=
nv_rd32
(
aux
,
0x00e4d0
+
(
ch
*
0x50
)
+
i
);
AUX_DBG
(
"rd 0x%08x
\n
"
,
xbuf
[
i
/
4
]);
}
memcpy
(
data
,
xbuf
,
size
);
}
out:
auxch_fini
(
aux
,
ch
);
return
ret
;
}
static
void
auxch_mux
(
struct
nouveau_i2c_port
*
port
)
{
if
(
port
->
dcb
&
0x00000100
)
{
u32
reg
=
0x00e500
+
(
port
->
drive
*
0x50
);
/* nfi, but neither auxch or i2c work if it's 1 */
nv_mask
(
port
->
i2c
,
reg
+
0x0c
,
0x00000001
,
0x00000000
);
/* nfi, but switches auxch vs normal i2c */
nv_mask
(
port
->
i2c
,
reg
+
0x00
,
0x0000f003
,
0x00002002
);
}
}
int
nv_rdaux
(
struct
nouveau_i2c_port
*
auxch
,
u32
addr
,
u8
*
data
,
u8
size
)
nv_rdaux
(
struct
nouveau_i2c_port
*
port
,
u32
addr
,
u8
*
data
,
u8
size
)
{
auxch_mux
(
auxch
);
return
auxch_tx
(
auxch
->
i2c
,
auxch
->
drive
,
9
,
addr
,
data
,
size
);
if
(
port
->
aux
)
{
if
(
port
->
aux_mux
)
port
->
aux_mux
(
port
);
return
port
->
aux
(
port
,
9
,
addr
,
data
,
size
);
}
return
-
ENODEV
;
}
int
nv_wraux
(
struct
nouveau_i2c_port
*
auxch
,
u32
addr
,
u8
*
data
,
u8
size
)
nv_wraux
(
struct
nouveau_i2c_port
*
port
,
u32
addr
,
u8
*
data
,
u8
size
)
{
auxch_mux
(
auxch
);
return
auxch_tx
(
auxch
->
i2c
,
auxch
->
drive
,
8
,
addr
,
data
,
size
);
if
(
port
->
aux
)
{
if
(
port
->
aux_mux
)
port
->
aux_mux
(
port
);
return
port
->
aux
(
port
,
8
,
addr
,
data
,
size
);
}
return
-
ENODEV
;
}
static
int
aux_xfer
(
struct
i2c_adapter
*
adap
,
struct
i2c_msg
*
msgs
,
int
num
)
{
struct
nouveau_i2c_port
*
auxch
=
(
struct
nouveau_i2c_port
*
)
adap
;
struct
nouveau_i2c_port
*
port
=
(
struct
nouveau_i2c_port
*
)
adap
;
struct
i2c_msg
*
msg
=
msgs
;
int
ret
,
mcnt
=
num
;
auxch_mux
(
auxch
);
if
(
!
port
->
aux
)
return
-
ENODEV
;
if
(
port
->
aux_mux
)
port
->
aux_mux
(
port
);
while
(
mcnt
--
)
{
u8
remaining
=
msg
->
len
;
...
...
@@ -201,8 +74,7 @@ aux_xfer(struct i2c_adapter *adap, struct i2c_msg *msgs, int num)
if
(
mcnt
||
remaining
>
16
)
cmd
|=
4
;
/* MOT */
ret
=
auxch_tx
(
auxch
->
i2c
,
auxch
->
drive
,
cmd
,
msg
->
addr
,
ptr
,
cnt
);
ret
=
port
->
aux
(
port
,
cmd
,
msg
->
addr
,
ptr
,
cnt
);
if
(
ret
<
0
)
return
ret
;
...
...
drivers/gpu/drm/nouveau/core/subdev/i2c/base.c
浏览文件 @
31a34aa4
...
...
@@ -303,6 +303,8 @@ nouveau_i2c_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
port
->
drive
=
info
.
drive
&
0x0f
;
port
->
sense
=
port
->
drive
;
port
->
adapter
.
algo
=
&
nouveau_i2c_aux_algo
;
port
->
aux_mux
=
nv94_aux_mux
;
port
->
aux
=
nv94_aux
;
break
;
default:
break
;
...
...
drivers/gpu/drm/nouveau/core/subdev/i2c/nv94.c
0 → 100644
浏览文件 @
31a34aa4
/*
* Copyright 2009 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 <subdev/i2c.h>
/******************************************************************************
* aux channel util functions
*****************************************************************************/
#define AUX_DBG(fmt, args...) nv_debug(aux, "AUXCH(%d): " fmt, ch, ##args)
#define AUX_ERR(fmt, args...) nv_error(aux, "AUXCH(%d): " fmt, ch, ##args)
static
void
auxch_fini
(
struct
nouveau_i2c
*
aux
,
int
ch
)
{
nv_mask
(
aux
,
0x00e4e4
+
(
ch
*
0x50
),
0x00310000
,
0x00000000
);
}
static
int
auxch_init
(
struct
nouveau_i2c
*
aux
,
int
ch
)
{
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
=
nv_rd32
(
aux
,
0x00e4e4
+
(
ch
*
0x50
));
udelay
(
1
);
if
(
!
timeout
--
)
{
AUX_ERR
(
"begin idle timeout 0x%08x
\n
"
,
ctrl
);
return
-
EBUSY
;
}
}
while
(
ctrl
&
0x03010000
);
/* set some magic, and wait up to 1ms for it to appear */
nv_mask
(
aux
,
0x00e4e4
+
(
ch
*
0x50
),
0x00300000
,
ureq
);
timeout
=
1000
;
do
{
ctrl
=
nv_rd32
(
aux
,
0x00e4e4
+
(
ch
*
0x50
));
udelay
(
1
);
if
(
!
timeout
--
)
{
AUX_ERR
(
"magic wait 0x%08x
\n
"
,
ctrl
);
auxch_fini
(
aux
,
ch
);
return
-
EBUSY
;
}
}
while
((
ctrl
&
0x03000000
)
!=
urep
);
return
0
;
}
int
nv94_aux
(
struct
nouveau_i2c_port
*
port
,
u8
type
,
u32
addr
,
u8
*
data
,
u8
size
)
{
struct
nouveau_i2c
*
aux
=
port
->
i2c
;
u32
ctrl
,
stat
,
timeout
,
retries
;
u32
xbuf
[
4
]
=
{};
int
ch
=
port
->
drive
;
int
ret
,
i
;
AUX_DBG
(
"%d: 0x%08x %d
\n
"
,
type
,
addr
,
size
);
ret
=
auxch_init
(
aux
,
ch
);
if
(
ret
)
goto
out
;
stat
=
nv_rd32
(
aux
,
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 0x%08x
\n
"
,
xbuf
[
i
/
4
]);
nv_wr32
(
aux
,
0x00e4c0
+
(
ch
*
0x50
)
+
i
,
xbuf
[
i
/
4
]);
}
}
ctrl
=
nv_rd32
(
aux
,
0x00e4e4
+
(
ch
*
0x50
));
ctrl
&=
~
0x0001f0ff
;
ctrl
|=
type
<<
12
;
ctrl
|=
size
-
1
;
nv_wr32
(
aux
,
0x00e4e0
+
(
ch
*
0x50
),
addr
);
/* retry transaction a number of times on failure... */
ret
=
-
EREMOTEIO
;
for
(
retries
=
0
;
retries
<
32
;
retries
++
)
{
/* reset, and delay a while if this is a retry */
nv_wr32
(
aux
,
0x00e4e4
+
(
ch
*
0x50
),
0x80000000
|
ctrl
);
nv_wr32
(
aux
,
0x00e4e4
+
(
ch
*
0x50
),
0x00000000
|
ctrl
);
if
(
retries
)
udelay
(
400
);
/* transaction request, wait up to 1ms for it to complete */
nv_wr32
(
aux
,
0x00e4e4
+
(
ch
*
0x50
),
0x00010000
|
ctrl
);
timeout
=
1000
;
do
{
ctrl
=
nv_rd32
(
aux
,
0x00e4e4
+
(
ch
*
0x50
));
udelay
(
1
);
if
(
!
timeout
--
)
{
AUX_ERR
(
"tx req timeout 0x%08x
\n
"
,
ctrl
);
goto
out
;
}
}
while
(
ctrl
&
0x00010000
);
/* read status, and check if transaction completed ok */
stat
=
nv_mask
(
aux
,
0x00e4e8
+
(
ch
*
0x50
),
0
,
0
);
if
(
!
(
stat
&
0x000f0f00
))
{
ret
=
0
;
break
;
}
AUX_DBG
(
"%02d 0x%08x 0x%08x
\n
"
,
retries
,
ctrl
,
stat
);
}
if
(
type
&
1
)
{
for
(
i
=
0
;
i
<
16
;
i
+=
4
)
{
xbuf
[
i
/
4
]
=
nv_rd32
(
aux
,
0x00e4d0
+
(
ch
*
0x50
)
+
i
);
AUX_DBG
(
"rd 0x%08x
\n
"
,
xbuf
[
i
/
4
]);
}
memcpy
(
data
,
xbuf
,
size
);
}
out:
auxch_fini
(
aux
,
ch
);
return
ret
;
}
void
nv94_aux_mux
(
struct
nouveau_i2c_port
*
port
)
{
if
(
port
->
dcb
&
0x00000100
)
{
u32
reg
=
0x00e500
+
(
port
->
drive
*
0x50
);
/* nfi, but neither auxch or i2c work if it's 1 */
nv_mask
(
port
->
i2c
,
reg
+
0x0c
,
0x00000001
,
0x00000000
);
/* nfi, but switches auxch vs normal i2c */
nv_mask
(
port
->
i2c
,
reg
+
0x00
,
0x0000f003
,
0x00002002
);
}
}
编辑
预览
Markdown
is supported
0%
请重试
或
添加新附件
.
添加附件
取消
You are about to add
0
people
to the discussion. Proceed with caution.
先完成此消息的编辑!
取消
想要评论请
注册
或
登录