Skip to content
体验新版
项目
组织
正在加载...
登录
切换导航
打开侧边栏
openeuler
Kernel
提交
d38ac521
K
Kernel
项目概览
openeuler
/
Kernel
1 年多 前同步成功
通知
8
Star
0
Fork
0
代码
文件
提交
分支
Tags
贡献者
分支图
Diff
Issue
0
列表
看板
标记
里程碑
合并请求
0
DevOps
流水线
流水线任务
计划
Wiki
0
Wiki
分析
仓库
DevOps
项目成员
Pages
K
Kernel
项目概览
项目概览
详情
发布
仓库
仓库
文件
提交
分支
标签
贡献者
分支图
比较
Issue
0
Issue
0
列表
看板
标记
里程碑
合并请求
0
合并请求
0
Pages
DevOps
DevOps
流水线
流水线任务
计划
分析
分析
仓库分析
DevOps
Wiki
0
Wiki
成员
成员
收起侧边栏
关闭侧边栏
动态
分支图
创建新Issue
流水线任务
提交
Issue看板
提交
d38ac521
编写于
7月 22, 2012
作者:
B
Ben Skeggs
浏览文件
操作
浏览文件
下载
电子邮件补丁
差异文件
drm/nouveau/mxm: split up into bios code and a subdev module
Signed-off-by:
N
Ben Skeggs
<
bskeggs@redhat.com
>
上级
08c77096
变更
16
隐藏空白更改
内联
并排
Showing
16 changed file
with
952 addition
and
755 deletion
+952
-755
drivers/gpu/drm/nouveau/Makefile
drivers/gpu/drm/nouveau/Makefile
+5
-1
drivers/gpu/drm/nouveau/core/include/subdev/bios/mxm.h
drivers/gpu/drm/nouveau/core/include/subdev/bios/mxm.h
+9
-0
drivers/gpu/drm/nouveau/core/include/subdev/mxm.h
drivers/gpu/drm/nouveau/core/include/subdev/mxm.h
+37
-0
drivers/gpu/drm/nouveau/core/os.h
drivers/gpu/drm/nouveau/core/os.h
+0
-2
drivers/gpu/drm/nouveau/core/subdev/bios/mxm.c
drivers/gpu/drm/nouveau/core/subdev/bios/mxm.c
+135
-0
drivers/gpu/drm/nouveau/core/subdev/device/nv50.c
drivers/gpu/drm/nouveau/core/subdev/device/nv50.c
+15
-0
drivers/gpu/drm/nouveau/core/subdev/device/nvc0.c
drivers/gpu/drm/nouveau/core/subdev/device/nvc0.c
+9
-0
drivers/gpu/drm/nouveau/core/subdev/device/nve0.c
drivers/gpu/drm/nouveau/core/subdev/device/nve0.c
+3
-0
drivers/gpu/drm/nouveau/core/subdev/mxm/base.c
drivers/gpu/drm/nouveau/core/subdev/mxm/base.c
+290
-0
drivers/gpu/drm/nouveau/core/subdev/mxm/mxms.c
drivers/gpu/drm/nouveau/core/subdev/mxm/mxms.c
+193
-0
drivers/gpu/drm/nouveau/core/subdev/mxm/mxms.h
drivers/gpu/drm/nouveau/core/subdev/mxm/mxms.h
+22
-0
drivers/gpu/drm/nouveau/core/subdev/mxm/nv50.c
drivers/gpu/drm/nouveau/core/subdev/mxm/nv50.c
+233
-0
drivers/gpu/drm/nouveau/nouveau_bios.c
drivers/gpu/drm/nouveau/nouveau_bios.c
+0
-5
drivers/gpu/drm/nouveau/nouveau_bios.h
drivers/gpu/drm/nouveau/nouveau_bios.h
+1
-20
drivers/gpu/drm/nouveau/nouveau_drv.h
drivers/gpu/drm/nouveau/nouveau_drv.h
+0
-4
drivers/gpu/drm/nouveau/nouveau_mxm.c
drivers/gpu/drm/nouveau/nouveau_mxm.c
+0
-723
未找到文件。
drivers/gpu/drm/nouveau/Makefile
浏览文件 @
d38ac521
...
...
@@ -33,6 +33,7 @@ nouveau-y += core/subdev/bios/dp.o
nouveau-y
+=
core/subdev/bios/gpio.o
nouveau-y
+=
core/subdev/bios/i2c.o
nouveau-y
+=
core/subdev/bios/init.o
nouveau-y
+=
core/subdev/bios/mxm.o
nouveau-y
+=
core/subdev/bios/pll.o
nouveau-y
+=
core/subdev/clock/nv04.o
nouveau-y
+=
core/subdev/clock/nv40.o
...
...
@@ -83,6 +84,9 @@ nouveau-y += core/subdev/mc/nv44.o
nouveau-y
+=
core/subdev/mc/nv50.o
nouveau-y
+=
core/subdev/mc/nv98.o
nouveau-y
+=
core/subdev/mc/nvc0.o
nouveau-y
+=
core/subdev/mxm/base.o
nouveau-y
+=
core/subdev/mxm/mxms.o
nouveau-y
+=
core/subdev/mxm/nv50.o
nouveau-y
+=
core/subdev/timer/base.o
nouveau-y
+=
core/subdev/timer/nv04.o
nouveau-y
+=
core/subdev/vm/base.o
...
...
@@ -172,7 +176,7 @@ nouveau-y += nouveau_drv.o nouveau_state.o nouveau_irq.o
nouveau-y
+=
nouveau_prime.o
# drm/kms/bios
nouveau-y
+=
nouveau_
mxm.o nouveau_
bios.o
nouveau-y
+=
nouveau_bios.o
# drm/kms/common
nouveau-y
+=
nouveau_display.o nouveau_connector.o
...
...
drivers/gpu/drm/nouveau/core/include/subdev/bios/mxm.h
0 → 100644
浏览文件 @
d38ac521
#ifndef __NVBIOS_MXM_H__
#define __NVBIOS_MXM_H__
u16
mxm_table
(
struct
nouveau_bios
*
,
u8
*
ver
,
u8
*
hdr
);
u8
mxm_sor_map
(
struct
nouveau_bios
*
,
u8
conn
);
u8
mxm_ddc_map
(
struct
nouveau_bios
*
,
u8
port
);
#endif
drivers/gpu/drm/nouveau/core/include/subdev/mxm.h
0 → 100644
浏览文件 @
d38ac521
#ifndef __NOUVEAU_MXM_H__
#define __NOUVEAU_MXM_H__
#include <core/subdev.h>
#include <core/device.h>
#define MXM_SANITISE_DCB 0x00000001
struct
nouveau_mxm
{
struct
nouveau_subdev
base
;
u32
action
;
u8
*
mxms
;
};
static
inline
struct
nouveau_mxm
*
nouveau_mxm
(
void
*
obj
)
{
return
(
void
*
)
nv_device
(
obj
)
->
subdev
[
NVDEV_SUBDEV_MXM
];
}
#define nouveau_mxm_create(p,e,o,d) \
nouveau_mxm_create_((p), (e), (o), sizeof(**d), (void **)d)
#define nouveau_mxm_init(p) \
nouveau_subdev_init(&(p)->base)
#define nouveau_mxm_fini(p,s) \
nouveau_subdev_fini(&(p)->base, (s))
int
nouveau_mxm_create_
(
struct
nouveau_object
*
,
struct
nouveau_object
*
,
struct
nouveau_oclass
*
,
int
,
void
**
);
void
nouveau_mxm_destroy
(
struct
nouveau_mxm
*
);
#define _nouveau_mxm_dtor _nouveau_subdev_dtor
#define _nouveau_mxm_init _nouveau_subdev_init
#define _nouveau_mxm_fini _nouveau_subdev_fini
extern
struct
nouveau_oclass
nv50_mxm_oclass
;
#endif
drivers/gpu/drm/nouveau/core/os.h
浏览文件 @
d38ac521
...
...
@@ -19,8 +19,6 @@
#include <asm/unaligned.h>
#include <asm/unaligned.h>
static
inline
int
ffsll
(
u64
mask
)
{
...
...
drivers/gpu/drm/nouveau/core/subdev/bios/mxm.c
0 → 100644
浏览文件 @
d38ac521
/*
* Copyright 2012 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/bios.h>
#include <subdev/bios/bit.h>
#include <subdev/bios/mxm.h>
u16
mxm_table
(
struct
nouveau_bios
*
bios
,
u8
*
ver
,
u8
*
hdr
)
{
struct
bit_entry
x
;
if
(
bit_entry
(
bios
,
'x'
,
&
x
))
{
nv_debug
(
bios
,
"BIT 'x' table not present
\n
"
);
return
0x0000
;
}
*
ver
=
x
.
version
;
*
hdr
=
x
.
length
;
if
(
*
ver
!=
1
||
*
hdr
<
3
)
{
nv_warn
(
bios
,
"BIT 'x' table %d/%d unknown
\n
"
,
*
ver
,
*
hdr
);
return
0x0000
;
}
return
x
.
offset
;
}
/* These map MXM v2.x digital connection values to the appropriate SOR/link,
* hopefully they're correct for all boards within the same chipset...
*
* MXM v3.x VBIOS are nicer and provide pointers to these tables.
*/
static
u8
nv84_sor_map
[
16
]
=
{
0x00
,
0x12
,
0x22
,
0x11
,
0x32
,
0x31
,
0x11
,
0x31
,
0x00
,
0x00
,
0x00
,
0x00
,
0x00
,
0x00
,
0x00
,
0x00
};
static
u8
nv92_sor_map
[
16
]
=
{
0x00
,
0x12
,
0x22
,
0x11
,
0x32
,
0x31
,
0x11
,
0x31
,
0x11
,
0x31
,
0x00
,
0x00
,
0x00
,
0x00
,
0x00
,
0x00
};
static
u8
nv94_sor_map
[
16
]
=
{
0x00
,
0x14
,
0x24
,
0x11
,
0x34
,
0x31
,
0x11
,
0x31
,
0x11
,
0x31
,
0x12
,
0x00
,
0x00
,
0x00
,
0x00
,
0x00
};
static
u8
nv98_sor_map
[
16
]
=
{
0x00
,
0x14
,
0x12
,
0x11
,
0x00
,
0x31
,
0x11
,
0x31
,
0x11
,
0x31
,
0x00
,
0x00
,
0x00
,
0x00
,
0x00
,
0x00
};
u8
mxm_sor_map
(
struct
nouveau_bios
*
bios
,
u8
conn
)
{
u8
ver
,
hdr
;
u16
mxm
=
mxm_table
(
bios
,
&
ver
,
&
hdr
);
if
(
mxm
&&
hdr
>=
6
)
{
u16
map
=
nv_ro16
(
bios
,
mxm
+
4
);
if
(
map
)
{
ver
=
nv_ro08
(
bios
,
map
);
if
(
ver
==
0x10
)
{
if
(
conn
<
nv_ro08
(
bios
,
map
+
3
))
{
map
+=
nv_ro08
(
bios
,
map
+
1
);
map
+=
conn
;
return
nv_ro08
(
bios
,
map
);
}
return
0x00
;
}
nv_warn
(
bios
,
"unknown sor map v%02x
\n
"
,
ver
);
}
}
if
(
bios
->
version
.
chip
==
0x84
||
bios
->
version
.
chip
==
0x86
)
return
nv84_sor_map
[
conn
];
if
(
bios
->
version
.
chip
==
0x92
)
return
nv92_sor_map
[
conn
];
if
(
bios
->
version
.
chip
==
0x94
||
bios
->
version
.
chip
==
0x96
)
return
nv94_sor_map
[
conn
];
if
(
bios
->
version
.
chip
==
0x98
)
return
nv98_sor_map
[
conn
];
nv_warn
(
bios
,
"missing sor map
\n
"
);
return
0x00
;
}
u8
mxm_ddc_map
(
struct
nouveau_bios
*
bios
,
u8
port
)
{
u8
ver
,
hdr
;
u16
mxm
=
mxm_table
(
bios
,
&
ver
,
&
hdr
);
if
(
mxm
&&
hdr
>=
8
)
{
u16
map
=
nv_ro16
(
bios
,
mxm
+
6
);
if
(
map
)
{
ver
=
nv_ro08
(
bios
,
map
);
if
(
ver
==
0x10
)
{
if
(
port
<
nv_ro08
(
bios
,
map
+
3
))
{
map
+=
nv_ro08
(
bios
,
map
+
1
);
map
+=
port
;
return
nv_ro08
(
bios
,
map
);
}
return
0x00
;
}
nv_warn
(
bios
,
"unknown ddc map v%02x
\n
"
,
ver
);
}
}
/* v2.x: directly write port as dcb i2cidx */
return
(
port
<<
4
)
|
port
;
}
drivers/gpu/drm/nouveau/core/subdev/device/nv50.c
浏览文件 @
d38ac521
...
...
@@ -27,6 +27,7 @@
#include <subdev/gpio.h>
#include <subdev/i2c.h>
#include <subdev/clock.h>
#include <subdev/mxm.h>
#include <subdev/devinit.h>
#include <subdev/mc.h>
#include <subdev/timer.h>
...
...
@@ -56,6 +57,7 @@ nv50_identify(struct nouveau_device *device)
device
->
oclass
[
NVDEV_SUBDEV_GPIO
]
=
&
nv50_gpio_oclass
;
device
->
oclass
[
NVDEV_SUBDEV_I2C
]
=
&
nouveau_i2c_oclass
;
device
->
oclass
[
NVDEV_SUBDEV_CLOCK
]
=
&
nv50_clock_oclass
;
device
->
oclass
[
NVDEV_SUBDEV_MXM
]
=
&
nv50_mxm_oclass
;
device
->
oclass
[
NVDEV_SUBDEV_DEVINIT
]
=
&
nv50_devinit_oclass
;
device
->
oclass
[
NVDEV_SUBDEV_MC
]
=
&
nv50_mc_oclass
;
device
->
oclass
[
NVDEV_SUBDEV_TIMER
]
=
&
nv04_timer_oclass
;
...
...
@@ -75,6 +77,7 @@ nv50_identify(struct nouveau_device *device)
device
->
oclass
[
NVDEV_SUBDEV_GPIO
]
=
&
nv50_gpio_oclass
;
device
->
oclass
[
NVDEV_SUBDEV_I2C
]
=
&
nouveau_i2c_oclass
;
device
->
oclass
[
NVDEV_SUBDEV_CLOCK
]
=
&
nv50_clock_oclass
;
device
->
oclass
[
NVDEV_SUBDEV_MXM
]
=
&
nv50_mxm_oclass
;
device
->
oclass
[
NVDEV_SUBDEV_DEVINIT
]
=
&
nv50_devinit_oclass
;
device
->
oclass
[
NVDEV_SUBDEV_MC
]
=
&
nv50_mc_oclass
;
device
->
oclass
[
NVDEV_SUBDEV_TIMER
]
=
&
nv04_timer_oclass
;
...
...
@@ -97,6 +100,7 @@ nv50_identify(struct nouveau_device *device)
device
->
oclass
[
NVDEV_SUBDEV_GPIO
]
=
&
nv50_gpio_oclass
;
device
->
oclass
[
NVDEV_SUBDEV_I2C
]
=
&
nouveau_i2c_oclass
;
device
->
oclass
[
NVDEV_SUBDEV_CLOCK
]
=
&
nv50_clock_oclass
;
device
->
oclass
[
NVDEV_SUBDEV_MXM
]
=
&
nv50_mxm_oclass
;
device
->
oclass
[
NVDEV_SUBDEV_DEVINIT
]
=
&
nv50_devinit_oclass
;
device
->
oclass
[
NVDEV_SUBDEV_MC
]
=
&
nv50_mc_oclass
;
device
->
oclass
[
NVDEV_SUBDEV_TIMER
]
=
&
nv04_timer_oclass
;
...
...
@@ -119,6 +123,7 @@ nv50_identify(struct nouveau_device *device)
device
->
oclass
[
NVDEV_SUBDEV_GPIO
]
=
&
nv50_gpio_oclass
;
device
->
oclass
[
NVDEV_SUBDEV_I2C
]
=
&
nouveau_i2c_oclass
;
device
->
oclass
[
NVDEV_SUBDEV_CLOCK
]
=
&
nv50_clock_oclass
;
device
->
oclass
[
NVDEV_SUBDEV_MXM
]
=
&
nv50_mxm_oclass
;
device
->
oclass
[
NVDEV_SUBDEV_DEVINIT
]
=
&
nv50_devinit_oclass
;
device
->
oclass
[
NVDEV_SUBDEV_MC
]
=
&
nv50_mc_oclass
;
device
->
oclass
[
NVDEV_SUBDEV_TIMER
]
=
&
nv04_timer_oclass
;
...
...
@@ -141,6 +146,7 @@ nv50_identify(struct nouveau_device *device)
device
->
oclass
[
NVDEV_SUBDEV_GPIO
]
=
&
nv50_gpio_oclass
;
device
->
oclass
[
NVDEV_SUBDEV_I2C
]
=
&
nouveau_i2c_oclass
;
device
->
oclass
[
NVDEV_SUBDEV_CLOCK
]
=
&
nv50_clock_oclass
;
device
->
oclass
[
NVDEV_SUBDEV_MXM
]
=
&
nv50_mxm_oclass
;
device
->
oclass
[
NVDEV_SUBDEV_DEVINIT
]
=
&
nv50_devinit_oclass
;
device
->
oclass
[
NVDEV_SUBDEV_MC
]
=
&
nv50_mc_oclass
;
device
->
oclass
[
NVDEV_SUBDEV_TIMER
]
=
&
nv04_timer_oclass
;
...
...
@@ -163,6 +169,7 @@ nv50_identify(struct nouveau_device *device)
device
->
oclass
[
NVDEV_SUBDEV_GPIO
]
=
&
nv50_gpio_oclass
;
device
->
oclass
[
NVDEV_SUBDEV_I2C
]
=
&
nouveau_i2c_oclass
;
device
->
oclass
[
NVDEV_SUBDEV_CLOCK
]
=
&
nv50_clock_oclass
;
device
->
oclass
[
NVDEV_SUBDEV_MXM
]
=
&
nv50_mxm_oclass
;
device
->
oclass
[
NVDEV_SUBDEV_DEVINIT
]
=
&
nv50_devinit_oclass
;
device
->
oclass
[
NVDEV_SUBDEV_MC
]
=
&
nv50_mc_oclass
;
device
->
oclass
[
NVDEV_SUBDEV_TIMER
]
=
&
nv04_timer_oclass
;
...
...
@@ -185,6 +192,7 @@ nv50_identify(struct nouveau_device *device)
device
->
oclass
[
NVDEV_SUBDEV_GPIO
]
=
&
nv50_gpio_oclass
;
device
->
oclass
[
NVDEV_SUBDEV_I2C
]
=
&
nouveau_i2c_oclass
;
device
->
oclass
[
NVDEV_SUBDEV_CLOCK
]
=
&
nv50_clock_oclass
;
device
->
oclass
[
NVDEV_SUBDEV_MXM
]
=
&
nv50_mxm_oclass
;
device
->
oclass
[
NVDEV_SUBDEV_DEVINIT
]
=
&
nv50_devinit_oclass
;
device
->
oclass
[
NVDEV_SUBDEV_MC
]
=
&
nv98_mc_oclass
;
device
->
oclass
[
NVDEV_SUBDEV_TIMER
]
=
&
nv04_timer_oclass
;
...
...
@@ -207,6 +215,7 @@ nv50_identify(struct nouveau_device *device)
device
->
oclass
[
NVDEV_SUBDEV_GPIO
]
=
&
nv50_gpio_oclass
;
device
->
oclass
[
NVDEV_SUBDEV_I2C
]
=
&
nouveau_i2c_oclass
;
device
->
oclass
[
NVDEV_SUBDEV_CLOCK
]
=
&
nv50_clock_oclass
;
device
->
oclass
[
NVDEV_SUBDEV_MXM
]
=
&
nv50_mxm_oclass
;
device
->
oclass
[
NVDEV_SUBDEV_DEVINIT
]
=
&
nv50_devinit_oclass
;
device
->
oclass
[
NVDEV_SUBDEV_MC
]
=
&
nv98_mc_oclass
;
device
->
oclass
[
NVDEV_SUBDEV_TIMER
]
=
&
nv04_timer_oclass
;
...
...
@@ -229,6 +238,7 @@ nv50_identify(struct nouveau_device *device)
device
->
oclass
[
NVDEV_SUBDEV_GPIO
]
=
&
nv50_gpio_oclass
;
device
->
oclass
[
NVDEV_SUBDEV_I2C
]
=
&
nouveau_i2c_oclass
;
device
->
oclass
[
NVDEV_SUBDEV_CLOCK
]
=
&
nv50_clock_oclass
;
device
->
oclass
[
NVDEV_SUBDEV_MXM
]
=
&
nv50_mxm_oclass
;
device
->
oclass
[
NVDEV_SUBDEV_DEVINIT
]
=
&
nv50_devinit_oclass
;
device
->
oclass
[
NVDEV_SUBDEV_MC
]
=
&
nv98_mc_oclass
;
device
->
oclass
[
NVDEV_SUBDEV_TIMER
]
=
&
nv04_timer_oclass
;
...
...
@@ -251,6 +261,7 @@ nv50_identify(struct nouveau_device *device)
device
->
oclass
[
NVDEV_SUBDEV_GPIO
]
=
&
nv50_gpio_oclass
;
device
->
oclass
[
NVDEV_SUBDEV_I2C
]
=
&
nouveau_i2c_oclass
;
device
->
oclass
[
NVDEV_SUBDEV_CLOCK
]
=
&
nv50_clock_oclass
;
device
->
oclass
[
NVDEV_SUBDEV_MXM
]
=
&
nv50_mxm_oclass
;
device
->
oclass
[
NVDEV_SUBDEV_DEVINIT
]
=
&
nv50_devinit_oclass
;
device
->
oclass
[
NVDEV_SUBDEV_MC
]
=
&
nv98_mc_oclass
;
device
->
oclass
[
NVDEV_SUBDEV_TIMER
]
=
&
nv04_timer_oclass
;
...
...
@@ -273,6 +284,7 @@ nv50_identify(struct nouveau_device *device)
device
->
oclass
[
NVDEV_SUBDEV_GPIO
]
=
&
nv50_gpio_oclass
;
device
->
oclass
[
NVDEV_SUBDEV_I2C
]
=
&
nouveau_i2c_oclass
;
device
->
oclass
[
NVDEV_SUBDEV_CLOCK
]
=
&
nva3_clock_oclass
;
device
->
oclass
[
NVDEV_SUBDEV_MXM
]
=
&
nv50_mxm_oclass
;
device
->
oclass
[
NVDEV_SUBDEV_DEVINIT
]
=
&
nv50_devinit_oclass
;
device
->
oclass
[
NVDEV_SUBDEV_MC
]
=
&
nv98_mc_oclass
;
device
->
oclass
[
NVDEV_SUBDEV_TIMER
]
=
&
nv04_timer_oclass
;
...
...
@@ -296,6 +308,7 @@ nv50_identify(struct nouveau_device *device)
device
->
oclass
[
NVDEV_SUBDEV_GPIO
]
=
&
nv50_gpio_oclass
;
device
->
oclass
[
NVDEV_SUBDEV_I2C
]
=
&
nouveau_i2c_oclass
;
device
->
oclass
[
NVDEV_SUBDEV_CLOCK
]
=
&
nva3_clock_oclass
;
device
->
oclass
[
NVDEV_SUBDEV_MXM
]
=
&
nv50_mxm_oclass
;
device
->
oclass
[
NVDEV_SUBDEV_DEVINIT
]
=
&
nv50_devinit_oclass
;
device
->
oclass
[
NVDEV_SUBDEV_MC
]
=
&
nv98_mc_oclass
;
device
->
oclass
[
NVDEV_SUBDEV_TIMER
]
=
&
nv04_timer_oclass
;
...
...
@@ -318,6 +331,7 @@ nv50_identify(struct nouveau_device *device)
device
->
oclass
[
NVDEV_SUBDEV_GPIO
]
=
&
nv50_gpio_oclass
;
device
->
oclass
[
NVDEV_SUBDEV_I2C
]
=
&
nouveau_i2c_oclass
;
device
->
oclass
[
NVDEV_SUBDEV_CLOCK
]
=
&
nva3_clock_oclass
;
device
->
oclass
[
NVDEV_SUBDEV_MXM
]
=
&
nv50_mxm_oclass
;
device
->
oclass
[
NVDEV_SUBDEV_DEVINIT
]
=
&
nv50_devinit_oclass
;
device
->
oclass
[
NVDEV_SUBDEV_MC
]
=
&
nv98_mc_oclass
;
device
->
oclass
[
NVDEV_SUBDEV_TIMER
]
=
&
nv04_timer_oclass
;
...
...
@@ -340,6 +354,7 @@ nv50_identify(struct nouveau_device *device)
device
->
oclass
[
NVDEV_SUBDEV_GPIO
]
=
&
nv50_gpio_oclass
;
device
->
oclass
[
NVDEV_SUBDEV_I2C
]
=
&
nouveau_i2c_oclass
;
device
->
oclass
[
NVDEV_SUBDEV_CLOCK
]
=
&
nva3_clock_oclass
;
device
->
oclass
[
NVDEV_SUBDEV_MXM
]
=
&
nv50_mxm_oclass
;
device
->
oclass
[
NVDEV_SUBDEV_DEVINIT
]
=
&
nv50_devinit_oclass
;
device
->
oclass
[
NVDEV_SUBDEV_MC
]
=
&
nv98_mc_oclass
;
device
->
oclass
[
NVDEV_SUBDEV_TIMER
]
=
&
nv04_timer_oclass
;
...
...
drivers/gpu/drm/nouveau/core/subdev/device/nvc0.c
浏览文件 @
d38ac521
...
...
@@ -27,6 +27,7 @@
#include <subdev/gpio.h>
#include <subdev/i2c.h>
#include <subdev/clock.h>
#include <subdev/mxm.h>
#include <subdev/devinit.h>
#include <subdev/mc.h>
#include <subdev/timer.h>
...
...
@@ -55,6 +56,7 @@ nvc0_identify(struct nouveau_device *device)
device
->
oclass
[
NVDEV_SUBDEV_GPIO
]
=
&
nv50_gpio_oclass
;
device
->
oclass
[
NVDEV_SUBDEV_I2C
]
=
&
nouveau_i2c_oclass
;
device
->
oclass
[
NVDEV_SUBDEV_CLOCK
]
=
&
nvc0_clock_oclass
;
device
->
oclass
[
NVDEV_SUBDEV_MXM
]
=
&
nv50_mxm_oclass
;
device
->
oclass
[
NVDEV_SUBDEV_DEVINIT
]
=
&
nv50_devinit_oclass
;
device
->
oclass
[
NVDEV_SUBDEV_MC
]
=
&
nvc0_mc_oclass
;
device
->
oclass
[
NVDEV_SUBDEV_TIMER
]
=
&
nv04_timer_oclass
;
...
...
@@ -79,6 +81,7 @@ nvc0_identify(struct nouveau_device *device)
device
->
oclass
[
NVDEV_SUBDEV_GPIO
]
=
&
nv50_gpio_oclass
;
device
->
oclass
[
NVDEV_SUBDEV_I2C
]
=
&
nouveau_i2c_oclass
;
device
->
oclass
[
NVDEV_SUBDEV_CLOCK
]
=
&
nvc0_clock_oclass
;
device
->
oclass
[
NVDEV_SUBDEV_MXM
]
=
&
nv50_mxm_oclass
;
device
->
oclass
[
NVDEV_SUBDEV_DEVINIT
]
=
&
nv50_devinit_oclass
;
device
->
oclass
[
NVDEV_SUBDEV_MC
]
=
&
nvc0_mc_oclass
;
device
->
oclass
[
NVDEV_SUBDEV_TIMER
]
=
&
nv04_timer_oclass
;
...
...
@@ -103,6 +106,7 @@ nvc0_identify(struct nouveau_device *device)
device
->
oclass
[
NVDEV_SUBDEV_GPIO
]
=
&
nv50_gpio_oclass
;
device
->
oclass
[
NVDEV_SUBDEV_I2C
]
=
&
nouveau_i2c_oclass
;
device
->
oclass
[
NVDEV_SUBDEV_CLOCK
]
=
&
nvc0_clock_oclass
;
device
->
oclass
[
NVDEV_SUBDEV_MXM
]
=
&
nv50_mxm_oclass
;
device
->
oclass
[
NVDEV_SUBDEV_DEVINIT
]
=
&
nv50_devinit_oclass
;
device
->
oclass
[
NVDEV_SUBDEV_MC
]
=
&
nvc0_mc_oclass
;
device
->
oclass
[
NVDEV_SUBDEV_TIMER
]
=
&
nv04_timer_oclass
;
...
...
@@ -127,6 +131,7 @@ nvc0_identify(struct nouveau_device *device)
device
->
oclass
[
NVDEV_SUBDEV_GPIO
]
=
&
nv50_gpio_oclass
;
device
->
oclass
[
NVDEV_SUBDEV_I2C
]
=
&
nouveau_i2c_oclass
;
device
->
oclass
[
NVDEV_SUBDEV_CLOCK
]
=
&
nvc0_clock_oclass
;
device
->
oclass
[
NVDEV_SUBDEV_MXM
]
=
&
nv50_mxm_oclass
;
device
->
oclass
[
NVDEV_SUBDEV_DEVINIT
]
=
&
nv50_devinit_oclass
;
device
->
oclass
[
NVDEV_SUBDEV_MC
]
=
&
nvc0_mc_oclass
;
device
->
oclass
[
NVDEV_SUBDEV_TIMER
]
=
&
nv04_timer_oclass
;
...
...
@@ -151,6 +156,7 @@ nvc0_identify(struct nouveau_device *device)
device
->
oclass
[
NVDEV_SUBDEV_GPIO
]
=
&
nv50_gpio_oclass
;
device
->
oclass
[
NVDEV_SUBDEV_I2C
]
=
&
nouveau_i2c_oclass
;
device
->
oclass
[
NVDEV_SUBDEV_CLOCK
]
=
&
nvc0_clock_oclass
;
device
->
oclass
[
NVDEV_SUBDEV_MXM
]
=
&
nv50_mxm_oclass
;
device
->
oclass
[
NVDEV_SUBDEV_DEVINIT
]
=
&
nv50_devinit_oclass
;
device
->
oclass
[
NVDEV_SUBDEV_MC
]
=
&
nvc0_mc_oclass
;
device
->
oclass
[
NVDEV_SUBDEV_TIMER
]
=
&
nv04_timer_oclass
;
...
...
@@ -175,6 +181,7 @@ nvc0_identify(struct nouveau_device *device)
device
->
oclass
[
NVDEV_SUBDEV_GPIO
]
=
&
nv50_gpio_oclass
;
device
->
oclass
[
NVDEV_SUBDEV_I2C
]
=
&
nouveau_i2c_oclass
;
device
->
oclass
[
NVDEV_SUBDEV_CLOCK
]
=
&
nvc0_clock_oclass
;
device
->
oclass
[
NVDEV_SUBDEV_MXM
]
=
&
nv50_mxm_oclass
;
device
->
oclass
[
NVDEV_SUBDEV_DEVINIT
]
=
&
nv50_devinit_oclass
;
device
->
oclass
[
NVDEV_SUBDEV_MC
]
=
&
nvc0_mc_oclass
;
device
->
oclass
[
NVDEV_SUBDEV_TIMER
]
=
&
nv04_timer_oclass
;
...
...
@@ -199,6 +206,7 @@ nvc0_identify(struct nouveau_device *device)
device
->
oclass
[
NVDEV_SUBDEV_GPIO
]
=
&
nv50_gpio_oclass
;
device
->
oclass
[
NVDEV_SUBDEV_I2C
]
=
&
nouveau_i2c_oclass
;
device
->
oclass
[
NVDEV_SUBDEV_CLOCK
]
=
&
nvc0_clock_oclass
;
device
->
oclass
[
NVDEV_SUBDEV_MXM
]
=
&
nv50_mxm_oclass
;
device
->
oclass
[
NVDEV_SUBDEV_DEVINIT
]
=
&
nv50_devinit_oclass
;
device
->
oclass
[
NVDEV_SUBDEV_MC
]
=
&
nvc0_mc_oclass
;
device
->
oclass
[
NVDEV_SUBDEV_TIMER
]
=
&
nv04_timer_oclass
;
...
...
@@ -223,6 +231,7 @@ nvc0_identify(struct nouveau_device *device)
device
->
oclass
[
NVDEV_SUBDEV_GPIO
]
=
&
nvd0_gpio_oclass
;
device
->
oclass
[
NVDEV_SUBDEV_I2C
]
=
&
nouveau_i2c_oclass
;
device
->
oclass
[
NVDEV_SUBDEV_CLOCK
]
=
&
nvc0_clock_oclass
;
device
->
oclass
[
NVDEV_SUBDEV_MXM
]
=
&
nv50_mxm_oclass
;
device
->
oclass
[
NVDEV_SUBDEV_DEVINIT
]
=
&
nv50_devinit_oclass
;
device
->
oclass
[
NVDEV_SUBDEV_MC
]
=
&
nvc0_mc_oclass
;
device
->
oclass
[
NVDEV_SUBDEV_TIMER
]
=
&
nv04_timer_oclass
;
...
...
drivers/gpu/drm/nouveau/core/subdev/device/nve0.c
浏览文件 @
d38ac521
...
...
@@ -27,6 +27,7 @@
#include <subdev/gpio.h>
#include <subdev/i2c.h>
#include <subdev/clock.h>
#include <subdev/mxm.h>
#include <subdev/devinit.h>
#include <subdev/mc.h>
#include <subdev/timer.h>
...
...
@@ -51,6 +52,7 @@ nve0_identify(struct nouveau_device *device)
device
->
oclass
[
NVDEV_SUBDEV_GPIO
]
=
&
nvd0_gpio_oclass
;
device
->
oclass
[
NVDEV_SUBDEV_I2C
]
=
&
nouveau_i2c_oclass
;
device
->
oclass
[
NVDEV_SUBDEV_CLOCK
]
=
&
nvc0_clock_oclass
;
device
->
oclass
[
NVDEV_SUBDEV_MXM
]
=
&
nv50_mxm_oclass
;
device
->
oclass
[
NVDEV_SUBDEV_DEVINIT
]
=
&
nv50_devinit_oclass
;
device
->
oclass
[
NVDEV_SUBDEV_MC
]
=
&
nvc0_mc_oclass
;
device
->
oclass
[
NVDEV_SUBDEV_TIMER
]
=
&
nv04_timer_oclass
;
...
...
@@ -70,6 +72,7 @@ nve0_identify(struct nouveau_device *device)
device
->
oclass
[
NVDEV_SUBDEV_GPIO
]
=
&
nvd0_gpio_oclass
;
device
->
oclass
[
NVDEV_SUBDEV_I2C
]
=
&
nouveau_i2c_oclass
;
device
->
oclass
[
NVDEV_SUBDEV_CLOCK
]
=
&
nvc0_clock_oclass
;
device
->
oclass
[
NVDEV_SUBDEV_MXM
]
=
&
nv50_mxm_oclass
;
device
->
oclass
[
NVDEV_SUBDEV_DEVINIT
]
=
&
nv50_devinit_oclass
;
device
->
oclass
[
NVDEV_SUBDEV_MC
]
=
&
nvc0_mc_oclass
;
device
->
oclass
[
NVDEV_SUBDEV_TIMER
]
=
&
nv04_timer_oclass
;
...
...
drivers/gpu/drm/nouveau/core/subdev/mxm/base.c
0 → 100644
浏览文件 @
d38ac521
/*
* Copyright 2011 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 <core/option.h>
#include <subdev/i2c.h>
#include <subdev/mxm.h>
#include <subdev/bios.h>
#include <subdev/bios/mxm.h>
#include "mxms.h"
static
bool
mxm_shadow_rom_fetch
(
struct
nouveau_i2c_port
*
i2c
,
u8
addr
,
u8
offset
,
u8
size
,
u8
*
data
)
{
struct
i2c_msg
msgs
[]
=
{
{
.
addr
=
addr
,
.
flags
=
0
,
.
len
=
1
,
.
buf
=
&
offset
},
{
.
addr
=
addr
,
.
flags
=
I2C_M_RD
,
.
len
=
size
,
.
buf
=
data
,
},
};
return
i2c_transfer
(
&
i2c
->
adapter
,
msgs
,
2
)
==
2
;
}
static
bool
mxm_shadow_rom
(
struct
nouveau_mxm
*
mxm
,
u8
version
)
{
struct
nouveau_bios
*
bios
=
nouveau_bios
(
mxm
);
struct
nouveau_i2c
*
i2c
=
nouveau_i2c
(
mxm
);
struct
nouveau_i2c_port
*
port
=
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
)
return
false
;
addr
=
0x54
;
if
(
!
mxm_shadow_rom_fetch
(
port
,
addr
,
0
,
6
,
mxms
))
{
addr
=
0x56
;
if
(
!
mxm_shadow_rom_fetch
(
port
,
addr
,
0
,
6
,
mxms
))
return
false
;
}
mxm
->
mxms
=
mxms
;
size
=
mxms_headerlen
(
mxm
)
+
mxms_structlen
(
mxm
);
mxm
->
mxms
=
kmalloc
(
size
,
GFP_KERNEL
);
if
(
mxm
->
mxms
&&
mxm_shadow_rom_fetch
(
port
,
addr
,
0
,
size
,
mxm
->
mxms
))
return
true
;
kfree
(
mxm
->
mxms
);
mxm
->
mxms
=
NULL
;
return
false
;
}
#if defined(CONFIG_ACPI)
static
bool
mxm_shadow_dsm
(
struct
nouveau_mxm
*
mxm
,
u8
version
)
{
struct
nouveau_device
*
device
=
nv_device
(
mxm
);
static
char
muid
[]
=
{
0x00
,
0xA4
,
0x04
,
0x40
,
0x7D
,
0x91
,
0xF2
,
0x4C
,
0xB8
,
0x9C
,
0x79
,
0xB6
,
0x2F
,
0xD5
,
0x56
,
0x65
};
u32
mxms_args
[]
=
{
0x00000000
};
union
acpi_object
args
[
4
]
=
{
/* _DSM MUID */
{
.
buffer
.
type
=
3
,
.
buffer
.
length
=
sizeof
(
muid
),
.
buffer
.
pointer
=
muid
,
},
/* spec says this can be zero to mean "highest revision", but
* of course there's at least one bios out there which fails
* unless you pass in exactly the version it supports..
*/
{
.
integer
.
type
=
ACPI_TYPE_INTEGER
,
.
integer
.
value
=
(
version
&
0xf0
)
<<
4
|
(
version
&
0x0f
),
},
/* MXMS function */
{
.
integer
.
type
=
ACPI_TYPE_INTEGER
,
.
integer
.
value
=
0x00000010
,
},
/* Pointer to MXMS arguments */
{
.
buffer
.
type
=
ACPI_TYPE_BUFFER
,
.
buffer
.
length
=
sizeof
(
mxms_args
),
.
buffer
.
pointer
=
(
char
*
)
mxms_args
,
},
};
struct
acpi_object_list
list
=
{
ARRAY_SIZE
(
args
),
args
};
struct
acpi_buffer
retn
=
{
ACPI_ALLOCATE_BUFFER
,
NULL
};
union
acpi_object
*
obj
;
acpi_handle
handle
;
int
ret
;
handle
=
DEVICE_ACPI_HANDLE
(
&
device
->
pdev
->
dev
);
if
(
!
handle
)
return
false
;
ret
=
acpi_evaluate_object
(
handle
,
"_DSM"
,
&
list
,
&
retn
);
if
(
ret
)
{
nv_debug
(
mxm
,
"DSM MXMS failed: %d
\n
"
,
ret
);
return
false
;
}
obj
=
retn
.
pointer
;
if
(
obj
->
type
==
ACPI_TYPE_BUFFER
)
{
mxm
->
mxms
=
kmemdup
(
obj
->
buffer
.
pointer
,
obj
->
buffer
.
length
,
GFP_KERNEL
);
}
else
if
(
obj
->
type
==
ACPI_TYPE_INTEGER
)
{
nv_debug
(
mxm
,
"DSM MXMS returned 0x%llx
\n
"
,
obj
->
integer
.
value
);
}
kfree
(
obj
);
return
mxm
->
mxms
!=
NULL
;
}
#endif
#if defined(CONFIG_ACPI_WMI) || defined(CONFIG_ACPI_WMI_MODULE)
#define WMI_WMMX_GUID "F6CB5C3C-9CAE-4EBD-B577-931EA32A2CC0"
static
u8
wmi_wmmx_mxmi
(
struct
nouveau_mxm
*
mxm
,
u8
version
)
{
u32
mxmi_args
[]
=
{
0x494D584D
/* MXMI */
,
version
,
0
};
struct
acpi_buffer
args
=
{
sizeof
(
mxmi_args
),
mxmi_args
};
struct
acpi_buffer
retn
=
{
ACPI_ALLOCATE_BUFFER
,
NULL
};
union
acpi_object
*
obj
;
acpi_status
status
;
status
=
wmi_evaluate_method
(
WMI_WMMX_GUID
,
0
,
0
,
&
args
,
&
retn
);
if
(
ACPI_FAILURE
(
status
))
{
nv_debug
(
mxm
,
"WMMX MXMI returned %d
\n
"
,
status
);
return
0x00
;
}
obj
=
retn
.
pointer
;
if
(
obj
->
type
==
ACPI_TYPE_INTEGER
)
{
version
=
obj
->
integer
.
value
;
nv_debug
(
mxm
,
"WMMX MXMI version %d.%d
\n
"
,
(
version
>>
4
),
version
&
0x0f
);
}
else
{
version
=
0
;
nv_debug
(
mxm
,
"WMMX MXMI returned non-integer
\n
"
);
}
kfree
(
obj
);
return
version
;
}
static
bool
mxm_shadow_wmi
(
struct
nouveau_mxm
*
mxm
,
u8
version
)
{
u32
mxms_args
[]
=
{
0x534D584D
/* MXMS */
,
version
,
0
};
struct
acpi_buffer
args
=
{
sizeof
(
mxms_args
),
mxms_args
};
struct
acpi_buffer
retn
=
{
ACPI_ALLOCATE_BUFFER
,
NULL
};
union
acpi_object
*
obj
;
acpi_status
status
;
if
(
!
wmi_has_guid
(
WMI_WMMX_GUID
))
{
nv_debug
(
mxm
,
"WMMX GUID not found
\n
"
);
return
false
;
}
mxms_args
[
1
]
=
wmi_wmmx_mxmi
(
mxm
,
0x00
);
if
(
!
mxms_args
[
1
])
mxms_args
[
1
]
=
wmi_wmmx_mxmi
(
mxm
,
version
);
if
(
!
mxms_args
[
1
])
return
false
;
status
=
wmi_evaluate_method
(
WMI_WMMX_GUID
,
0
,
0
,
&
args
,
&
retn
);
if
(
ACPI_FAILURE
(
status
))
{
nv_debug
(
mxm
,
"WMMX MXMS returned %d
\n
"
,
status
);
return
false
;
}
obj
=
retn
.
pointer
;
if
(
obj
->
type
==
ACPI_TYPE_BUFFER
)
{
mxm
->
mxms
=
kmemdup
(
obj
->
buffer
.
pointer
,
obj
->
buffer
.
length
,
GFP_KERNEL
);
}
kfree
(
obj
);
return
mxm
->
mxms
!=
NULL
;
}
#endif
struct
mxm_shadow_h
{
const
char
*
name
;
bool
(
*
exec
)(
struct
nouveau_mxm
*
,
u8
version
);
}
_mxm_shadow
[]
=
{
{
"ROM"
,
mxm_shadow_rom
},
#if defined(CONFIG_ACPI)
{
"DSM"
,
mxm_shadow_dsm
},
#endif
#if defined(CONFIG_ACPI_WMI) || defined(CONFIG_ACPI_WMI_MODULE)
{
"WMI"
,
mxm_shadow_wmi
},
#endif
{}
};
static
int
mxm_shadow
(
struct
nouveau_mxm
*
mxm
,
u8
version
)
{
struct
mxm_shadow_h
*
shadow
=
_mxm_shadow
;
do
{
nv_debug
(
mxm
,
"checking %s
\n
"
,
shadow
->
name
);
if
(
shadow
->
exec
(
mxm
,
version
))
{
if
(
mxms_valid
(
mxm
))
return
0
;
kfree
(
mxm
->
mxms
);
mxm
->
mxms
=
NULL
;
}
}
while
((
++
shadow
)
->
name
);
return
-
ENOENT
;
}
int
nouveau_mxm_create_
(
struct
nouveau_object
*
parent
,
struct
nouveau_object
*
engine
,
struct
nouveau_oclass
*
oclass
,
int
length
,
void
**
pobject
)
{
struct
nouveau_device
*
device
=
nv_device
(
parent
);
struct
nouveau_bios
*
bios
=
nouveau_bios
(
device
);
struct
nouveau_mxm
*
mxm
;
u8
ver
,
len
;
u16
data
;
int
ret
;
ret
=
nouveau_subdev_create_
(
parent
,
engine
,
oclass
,
0
,
"MXM"
,
"mxm"
,
length
,
pobject
);
mxm
=
*
pobject
;
if
(
ret
)
return
ret
;
data
=
mxm_table
(
bios
,
&
ver
,
&
len
);
if
(
!
data
||
!
(
ver
=
nv_ro08
(
bios
,
data
)))
{
nv_info
(
mxm
,
"no VBIOS data, nothing to do
\n
"
);
return
0
;
}
nv_info
(
mxm
,
"BIOS version %d.%d
\n
"
,
ver
>>
4
,
ver
&
0x0f
);
if
(
mxm_shadow
(
mxm
,
ver
))
{
nv_info
(
mxm
,
"failed to locate valid SIS
\n
"
);
#if 0
/* we should, perhaps, fall back to some kind of limited
* mode here if the x86 vbios hasn't already done the
* work for us (so we prevent loading with completely
* whacked vbios tables).
*/
return -EINVAL;
#else
return
0
;
#endif
}
nv_info
(
mxm
,
"MXMS Version %d.%d
\n
"
,
mxms_version
(
mxm
)
>>
8
,
mxms_version
(
mxm
)
&
0xff
);
mxms_foreach
(
mxm
,
0
,
NULL
,
NULL
);
if
(
nouveau_boolopt
(
device
->
cfgopt
,
"NvMXMDCB"
,
true
))
mxm
->
action
|=
MXM_SANITISE_DCB
;
return
0
;
}
drivers/gpu/drm/nouveau/core/subdev/mxm/mxms.c
0 → 100644
浏览文件 @
d38ac521
/*
* Copyright 2012 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/mxm.h>
#include "mxms.h"
#define ROM16(x) le16_to_cpu(*(u16 *)&(x))
#define ROM32(x) le32_to_cpu(*(u32 *)&(x))
static
u8
*
mxms_data
(
struct
nouveau_mxm
*
mxm
)
{
return
mxm
->
mxms
;
}
u16
mxms_version
(
struct
nouveau_mxm
*
mxm
)
{
u8
*
mxms
=
mxms_data
(
mxm
);
u16
version
=
(
mxms
[
4
]
<<
8
)
|
mxms
[
5
];
switch
(
version
)
{
case
0x0200
:
case
0x0201
:
case
0x0300
:
return
version
;
default:
break
;
}
nv_debug
(
mxm
,
"unknown version %d.%d
\n
"
,
mxms
[
4
],
mxms
[
5
]);
return
0x0000
;
}
u16
mxms_headerlen
(
struct
nouveau_mxm
*
mxm
)
{
return
8
;
}
u16
mxms_structlen
(
struct
nouveau_mxm
*
mxm
)
{
return
*
(
u16
*
)
&
mxms_data
(
mxm
)[
6
];
}
bool
mxms_checksum
(
struct
nouveau_mxm
*
mxm
)
{
u16
size
=
mxms_headerlen
(
mxm
)
+
mxms_structlen
(
mxm
);
u8
*
mxms
=
mxms_data
(
mxm
),
sum
=
0
;
while
(
size
--
)
sum
+=
*
mxms
++
;
if
(
sum
)
{
nv_debug
(
mxm
,
"checksum invalid
\n
"
);
return
false
;
}
return
true
;
}
bool
mxms_valid
(
struct
nouveau_mxm
*
mxm
)
{
u8
*
mxms
=
mxms_data
(
mxm
);
if
(
*
(
u32
*
)
mxms
!=
0x5f4d584d
)
{
nv_debug
(
mxm
,
"signature invalid
\n
"
);
return
false
;
}
if
(
!
mxms_version
(
mxm
)
||
!
mxms_checksum
(
mxm
))
return
false
;
return
true
;
}
bool
mxms_foreach
(
struct
nouveau_mxm
*
mxm
,
u8
types
,
bool
(
*
exec
)(
struct
nouveau_mxm
*
,
u8
*
,
void
*
),
void
*
info
)
{
u8
*
mxms
=
mxms_data
(
mxm
);
u8
*
desc
=
mxms
+
mxms_headerlen
(
mxm
);
u8
*
fini
=
desc
+
mxms_structlen
(
mxm
)
-
1
;
while
(
desc
<
fini
)
{
u8
type
=
desc
[
0
]
&
0x0f
;
u8
headerlen
=
0
;
u8
recordlen
=
0
;
u8
entries
=
0
;
switch
(
type
)
{
case
0
:
/* Output Device Structure */
if
(
mxms_version
(
mxm
)
>=
0x0300
)
headerlen
=
8
;
else
headerlen
=
6
;
break
;
case
1
:
/* System Cooling Capability Structure */
case
2
:
/* Thermal Structure */
case
3
:
/* Input Power Structure */
headerlen
=
4
;
break
;
case
4
:
/* GPIO Device Structure */
headerlen
=
4
;
recordlen
=
2
;
entries
=
(
ROM32
(
desc
[
0
])
&
0x01f00000
)
>>
20
;
break
;
case
5
:
/* Vendor Specific Structure */
headerlen
=
8
;
break
;
case
6
:
/* Backlight Control Structure */
if
(
mxms_version
(
mxm
)
>=
0x0300
)
{
headerlen
=
4
;
recordlen
=
8
;
entries
=
(
desc
[
1
]
&
0xf0
)
>>
4
;
}
else
{
headerlen
=
8
;
}
break
;
case
7
:
/* Fan Control Structure */
headerlen
=
8
;
recordlen
=
4
;
entries
=
desc
[
1
]
&
0x07
;
break
;
default:
nv_debug
(
mxm
,
"unknown descriptor type %d
\n
"
,
type
);
return
false
;
}
if
(
nv_subdev
(
mxm
)
->
debug
>=
NV_DBG_DEBUG
&&
(
exec
==
NULL
))
{
static
const
char
*
mxms_desc_name
[]
=
{
"ODS"
,
"SCCS"
,
"TS"
,
"IPS"
,
"GSD"
,
"VSS"
,
"BCS"
,
"FCS"
,
};
u8
*
dump
=
desc
;
int
i
,
j
;
nv_debug
(
mxm
,
"%4s: "
,
mxms_desc_name
[
type
]);
for
(
j
=
headerlen
-
1
;
j
>=
0
;
j
--
)
printk
(
"%02x"
,
dump
[
j
]);
printk
(
"
\n
"
);
dump
+=
headerlen
;
for
(
i
=
0
;
i
<
entries
;
i
++
,
dump
+=
recordlen
)
{
nv_debug
(
mxm
,
" "
);
for
(
j
=
recordlen
-
1
;
j
>=
0
;
j
--
)
printk
(
"%02x"
,
dump
[
j
]);
printk
(
"
\n
"
);
}
}
if
(
types
&
(
1
<<
type
))
{
if
(
!
exec
(
mxm
,
desc
,
info
))
return
false
;
}
desc
+=
headerlen
+
(
entries
*
recordlen
);
}
return
true
;
}
void
mxms_output_device
(
struct
nouveau_mxm
*
mxm
,
u8
*
pdata
,
struct
mxms_odev
*
desc
)
{
u64
data
=
ROM32
(
pdata
[
0
]);
if
(
mxms_version
(
mxm
)
>=
0x0300
)
data
|=
(
u64
)
ROM16
(
pdata
[
4
])
<<
32
;
desc
->
outp_type
=
(
data
&
0x00000000000000f0ULL
)
>>
4
;
desc
->
ddc_port
=
(
data
&
0x0000000000000f00ULL
)
>>
8
;
desc
->
conn_type
=
(
data
&
0x000000000001f000ULL
)
>>
12
;
desc
->
dig_conn
=
(
data
&
0x0000000000780000ULL
)
>>
19
;
}
drivers/gpu/drm/nouveau/core/subdev/mxm/mxms.h
0 → 100644
浏览文件 @
d38ac521
#ifndef __NVMXM_MXMS_H__
#define __NVMXM_MXMS_H__
struct
mxms_odev
{
u8
outp_type
;
u8
conn_type
;
u8
ddc_port
;
u8
dig_conn
;
};
void
mxms_output_device
(
struct
nouveau_mxm
*
,
u8
*
,
struct
mxms_odev
*
);
u16
mxms_version
(
struct
nouveau_mxm
*
);
u16
mxms_headerlen
(
struct
nouveau_mxm
*
);
u16
mxms_structlen
(
struct
nouveau_mxm
*
);
bool
mxms_checksum
(
struct
nouveau_mxm
*
);
bool
mxms_valid
(
struct
nouveau_mxm
*
);
bool
mxms_foreach
(
struct
nouveau_mxm
*
,
u8
,
bool
(
*
)(
struct
nouveau_mxm
*
,
u8
*
,
void
*
),
void
*
);
#endif
drivers/gpu/drm/nouveau/core/subdev/mxm/nv50.c
0 → 100644
浏览文件 @
d38ac521
/*
* Copyright 2011 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/mxm.h>
#include <subdev/bios.h>
#include <subdev/bios/conn.h>
#include <subdev/bios/dcb.h>
#include <subdev/bios/mxm.h>
#include "mxms.h"
struct
nv50_mxm_priv
{
struct
nouveau_mxm
base
;
};
struct
context
{
u32
*
outp
;
struct
mxms_odev
desc
;
};
static
bool
mxm_match_tmds_partner
(
struct
nouveau_mxm
*
mxm
,
u8
*
data
,
void
*
info
)
{
struct
context
*
ctx
=
info
;
struct
mxms_odev
desc
;
mxms_output_device
(
mxm
,
data
,
&
desc
);
if
(
desc
.
outp_type
==
2
&&
desc
.
dig_conn
==
ctx
->
desc
.
dig_conn
)
return
false
;
return
true
;
}
static
bool
mxm_match_dcb
(
struct
nouveau_mxm
*
mxm
,
u8
*
data
,
void
*
info
)
{
struct
nouveau_bios
*
bios
=
nouveau_bios
(
mxm
);
struct
context
*
ctx
=
info
;
u64
desc
=
*
(
u64
*
)
data
;
mxms_output_device
(
mxm
,
data
,
&
ctx
->
desc
);
/* match dcb encoder type to mxm-ods device type */
if
((
ctx
->
outp
[
0
]
&
0x0000000f
)
!=
ctx
->
desc
.
outp_type
)
return
true
;
/* digital output, have some extra stuff to match here, there's a
* table in the vbios that provides a mapping from the mxm digital
* connection enum values to SOR/link
*/
if
((
desc
&
0x00000000000000f0
)
>=
0x20
)
{
/* check against sor index */
u8
link
=
mxm_sor_map
(
bios
,
ctx
->
desc
.
dig_conn
);
if
((
ctx
->
outp
[
0
]
&
0x0f000000
)
!=
(
link
&
0x0f
)
<<
24
)
return
true
;
/* check dcb entry has a compatible link field */
link
=
(
link
&
0x30
)
>>
4
;
if
((
link
&
((
ctx
->
outp
[
1
]
&
0x00000030
)
>>
4
))
!=
link
)
return
true
;
}
/* mark this descriptor accounted for by setting invalid device type,
* except of course some manufactures don't follow specs properly and
* we need to avoid killing off the TMDS function on DP connectors
* if MXM-SIS is missing an entry for it.
*/
data
[
0
]
&=
~
0xf0
;
if
(
ctx
->
desc
.
outp_type
==
6
&&
ctx
->
desc
.
conn_type
==
6
&&
mxms_foreach
(
mxm
,
0x01
,
mxm_match_tmds_partner
,
ctx
))
{
data
[
0
]
|=
0x20
;
/* modify descriptor to match TMDS now */
}
else
{
data
[
0
]
|=
0xf0
;
}
return
false
;
}
static
int
mxm_dcb_sanitise_entry
(
struct
nouveau_bios
*
bios
,
void
*
data
,
int
idx
,
u16
pdcb
)
{
struct
nouveau_mxm
*
mxm
=
nouveau_mxm
(
bios
);
struct
context
ctx
=
{
.
outp
=
(
u32
*
)(
bios
->
data
+
pdcb
)
};
u8
type
,
i2cidx
,
link
,
ver
,
len
;
u8
*
conn
;
/* look for an output device structure that matches this dcb entry.
* if one isn't found, disable it.
*/
if
(
mxms_foreach
(
mxm
,
0x01
,
mxm_match_dcb
,
&
ctx
))
{
nv_debug
(
mxm
,
"disable %d: 0x%08x 0x%08x
\n
"
,
idx
,
ctx
.
outp
[
0
],
ctx
.
outp
[
1
]);
ctx
.
outp
[
0
]
|=
0x0000000f
;
return
0
;
}
/* modify the output's ddc/aux port, there's a pointer to a table
* with the mapping from mxm ddc/aux port to dcb i2c_index in the
* vbios mxm table
*/
i2cidx
=
mxm_ddc_map
(
bios
,
ctx
.
desc
.
ddc_port
);
if
((
ctx
.
outp
[
0
]
&
0x0000000f
)
!=
DCB_OUTPUT_DP
)
i2cidx
=
(
i2cidx
&
0x0f
)
<<
4
;
else
i2cidx
=
(
i2cidx
&
0xf0
);
if
(
i2cidx
!=
0xf0
)
{
ctx
.
outp
[
0
]
&=
~
0x000000f0
;
ctx
.
outp
[
0
]
|=
i2cidx
;
}
/* override dcb sorconf.link, based on what mxm data says */
switch
(
ctx
.
desc
.
outp_type
)
{
case
0x00
:
/* Analog CRT */
case
0x01
:
/* Analog TV/HDTV */
break
;
default:
link
=
mxm_sor_map
(
bios
,
ctx
.
desc
.
dig_conn
)
&
0x30
;
ctx
.
outp
[
1
]
&=
~
0x00000030
;
ctx
.
outp
[
1
]
|=
link
;
break
;
}
/* we may need to fixup various other vbios tables based on what
* the descriptor says the connector type should be.
*
* in a lot of cases, the vbios tables will claim DVI-I is possible,
* and the mxm data says the connector is really HDMI. another
* common example is DP->eDP.
*/
conn
=
bios
->
data
;
conn
+=
dcb_conn
(
bios
,
(
ctx
.
outp
[
0
]
&
0x0000f000
)
>>
12
,
&
ver
,
&
len
);
type
=
conn
[
0
];
switch
(
ctx
.
desc
.
conn_type
)
{
case
0x01
:
/* LVDS */
ctx
.
outp
[
1
]
|=
0x00000004
;
/* use_power_scripts */
/* XXX: modify default link width in LVDS table */
break
;
case
0x02
:
/* HDMI */
type
=
DCB_CONNECTOR_HDMI_1
;
break
;
case
0x03
:
/* DVI-D */
type
=
DCB_CONNECTOR_DVI_D
;
break
;
case
0x0e
:
/* eDP, falls through to DPint */
ctx
.
outp
[
1
]
|=
0x00010000
;
case
0x07
:
/* DP internal, wtf is this?? HP8670w */
ctx
.
outp
[
1
]
|=
0x00000004
;
/* use_power_scripts? */
type
=
DCB_CONNECTOR_eDP
;
break
;
default:
break
;
}
if
(
mxms_version
(
mxm
)
>=
0x0300
)
conn
[
0
]
=
type
;
return
0
;
}
static
bool
mxm_show_unmatched
(
struct
nouveau_mxm
*
mxm
,
u8
*
data
,
void
*
info
)
{
u64
desc
=
*
(
u64
*
)
data
;
if
((
desc
&
0xf0
)
!=
0xf0
)
nv_info
(
mxm
,
"unmatched output device 0x%016llx
\n
"
,
desc
);
return
true
;
}
static
void
mxm_dcb_sanitise
(
struct
nouveau_mxm
*
mxm
)
{
struct
nouveau_bios
*
bios
=
nouveau_bios
(
mxm
);
u8
ver
,
hdr
,
cnt
,
len
;
u16
dcb
=
dcb_table
(
bios
,
&
ver
,
&
hdr
,
&
cnt
,
&
len
);
if
(
dcb
==
0x0000
||
ver
!=
0x40
)
{
nv_debug
(
mxm
,
"unsupported DCB version
\n
"
);
return
;
}
dcb_outp_foreach
(
bios
,
NULL
,
mxm_dcb_sanitise_entry
);
mxms_foreach
(
mxm
,
0x01
,
mxm_show_unmatched
,
NULL
);
}
static
int
nv50_mxm_ctor
(
struct
nouveau_object
*
parent
,
struct
nouveau_object
*
engine
,
struct
nouveau_oclass
*
oclass
,
void
*
data
,
u32
size
,
struct
nouveau_object
**
pobject
)
{
struct
nv50_mxm_priv
*
priv
;
int
ret
;
ret
=
nouveau_mxm_create
(
parent
,
engine
,
oclass
,
&
priv
);
*
pobject
=
nv_object
(
priv
);
if
(
ret
)
return
ret
;
if
(
priv
->
base
.
action
&
MXM_SANITISE_DCB
)
mxm_dcb_sanitise
(
&
priv
->
base
);
return
0
;
}
struct
nouveau_oclass
nv50_mxm_oclass
=
{
.
handle
=
NV_SUBDEV
(
MXM
,
0x50
),
.
ofuncs
=
&
(
struct
nouveau_ofuncs
)
{
.
ctor
=
nv50_mxm_ctor
,
.
dtor
=
_nouveau_mxm_dtor
,
.
init
=
_nouveau_mxm_init
,
.
fini
=
_nouveau_mxm_fini
,
},
};
drivers/gpu/drm/nouveau/nouveau_bios.c
浏览文件 @
d38ac521
...
...
@@ -2352,10 +2352,6 @@ nouveau_bios_init(struct drm_device *dev)
if
(
ret
)
return
ret
;
ret
=
nouveau_mxm_init
(
dev
);
if
(
ret
)
return
ret
;
ret
=
parse_dcb_table
(
dev
,
bios
);
if
(
ret
)
return
ret
;
...
...
@@ -2396,5 +2392,4 @@ nouveau_bios_init(struct drm_device *dev)
void
nouveau_bios_takedown
(
struct
drm_device
*
dev
)
{
nouveau_mxm_fini
(
dev
);
}
drivers/gpu/drm/nouveau/nouveau_bios.h
浏览文件 @
d38ac521
...
...
@@ -52,27 +52,8 @@ struct bit_entry {
int
bit_table
(
struct
drm_device
*
,
u8
id
,
struct
bit_entry
*
);
enum
dcb_connector_type
{
DCB_CONNECTOR_VGA
=
0x00
,
DCB_CONNECTOR_TV_0
=
0x10
,
DCB_CONNECTOR_TV_1
=
0x11
,
DCB_CONNECTOR_TV_3
=
0x13
,
DCB_CONNECTOR_DVI_I
=
0x30
,
DCB_CONNECTOR_DVI_D
=
0x31
,
DCB_CONNECTOR_DMS59_0
=
0x38
,
DCB_CONNECTOR_DMS59_1
=
0x39
,
DCB_CONNECTOR_LVDS
=
0x40
,
DCB_CONNECTOR_LVDS_SPWG
=
0x41
,
DCB_CONNECTOR_DP
=
0x46
,
DCB_CONNECTOR_eDP
=
0x47
,
DCB_CONNECTOR_HDMI_0
=
0x60
,
DCB_CONNECTOR_HDMI_1
=
0x61
,
DCB_CONNECTOR_DMS59_DP0
=
0x64
,
DCB_CONNECTOR_DMS59_DP1
=
0x65
,
DCB_CONNECTOR_NONE
=
0xff
};
#include <subdev/bios/dcb.h>
#include <subdev/bios/conn.h>
struct
dcb_table
{
uint8_t
version
;
...
...
drivers/gpu/drm/nouveau/nouveau_drv.h
浏览文件 @
d38ac521
...
...
@@ -415,10 +415,6 @@ extern int call_lvds_script(struct drm_device *, struct dcb_output *, int head,
enum
LVDS_script
,
int
pxclk
);
bool
bios_encoder_match
(
struct
dcb_output
*
,
u32
hash
);
/* nouveau_mxm.c */
int
nouveau_mxm_init
(
struct
drm_device
*
dev
);
void
nouveau_mxm_fini
(
struct
drm_device
*
dev
);
/* nouveau_ttm.c */
int
nouveau_ttm_global_init
(
struct
drm_nouveau_private
*
);
void
nouveau_ttm_global_release
(
struct
drm_nouveau_private
*
);
...
...
drivers/gpu/drm/nouveau/nouveau_mxm.c
已删除
100644 → 0
浏览文件 @
08c77096
/*
* Copyright 2011 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 <linux/acpi.h>
#include "drmP.h"
#include "nouveau_drv.h"
#define MXM_DBG(dev, fmt, args...) NV_DEBUG((dev), "MXM: " fmt, ##args)
#define MXM_MSG(dev, fmt, args...) NV_INFO((dev), "MXM: " fmt, ##args)
static
u8
*
mxms_data
(
struct
drm_device
*
dev
)
{
struct
drm_nouveau_private
*
dev_priv
=
dev
->
dev_private
;
return
dev_priv
->
mxms
;
}
static
u16
mxms_version
(
struct
drm_device
*
dev
)
{
u8
*
mxms
=
mxms_data
(
dev
);
u16
version
=
(
mxms
[
4
]
<<
8
)
|
mxms
[
5
];
switch
(
version
)
{
case
0x0200
:
case
0x0201
:
case
0x0300
:
return
version
;
default:
break
;
}
MXM_DBG
(
dev
,
"unknown version %d.%d
\n
"
,
mxms
[
4
],
mxms
[
5
]);
return
0x0000
;
}
static
u16
mxms_headerlen
(
struct
drm_device
*
dev
)
{
return
8
;
}
static
u16
mxms_structlen
(
struct
drm_device
*
dev
)
{
return
*
(
u16
*
)
&
mxms_data
(
dev
)[
6
];
}
static
bool
mxms_checksum
(
struct
drm_device
*
dev
)
{
u16
size
=
mxms_headerlen
(
dev
)
+
mxms_structlen
(
dev
);
u8
*
mxms
=
mxms_data
(
dev
),
sum
=
0
;
while
(
size
--
)
sum
+=
*
mxms
++
;
if
(
sum
)
{
MXM_DBG
(
dev
,
"checksum invalid
\n
"
);
return
false
;
}
return
true
;
}
static
bool
mxms_valid
(
struct
drm_device
*
dev
)
{
u8
*
mxms
=
mxms_data
(
dev
);
if
(
*
(
u32
*
)
mxms
!=
0x5f4d584d
)
{
MXM_DBG
(
dev
,
"signature invalid
\n
"
);
return
false
;
}
if
(
!
mxms_version
(
dev
)
||
!
mxms_checksum
(
dev
))
return
false
;
return
true
;
}
static
bool
mxms_foreach
(
struct
drm_device
*
dev
,
u8
types
,
bool
(
*
exec
)(
struct
drm_device
*
,
u8
*
,
void
*
),
void
*
info
)
{
u8
*
mxms
=
mxms_data
(
dev
);
u8
*
desc
=
mxms
+
mxms_headerlen
(
dev
);
u8
*
fini
=
desc
+
mxms_structlen
(
dev
)
-
1
;
while
(
desc
<
fini
)
{
u8
type
=
desc
[
0
]
&
0x0f
;
u8
headerlen
=
0
;
u8
recordlen
=
0
;
u8
entries
=
0
;
switch
(
type
)
{
case
0
:
/* Output Device Structure */
if
(
mxms_version
(
dev
)
>=
0x0300
)
headerlen
=
8
;
else
headerlen
=
6
;
break
;
case
1
:
/* System Cooling Capability Structure */
case
2
:
/* Thermal Structure */
case
3
:
/* Input Power Structure */
headerlen
=
4
;
break
;
case
4
:
/* GPIO Device Structure */
headerlen
=
4
;
recordlen
=
2
;
entries
=
(
ROM32
(
desc
[
0
])
&
0x01f00000
)
>>
20
;
break
;
case
5
:
/* Vendor Specific Structure */
headerlen
=
8
;
break
;
case
6
:
/* Backlight Control Structure */
if
(
mxms_version
(
dev
)
>=
0x0300
)
{
headerlen
=
4
;
recordlen
=
8
;
entries
=
(
desc
[
1
]
&
0xf0
)
>>
4
;
}
else
{
headerlen
=
8
;
}
break
;
case
7
:
/* Fan Control Structure */
headerlen
=
8
;
recordlen
=
4
;
entries
=
desc
[
1
]
&
0x07
;
break
;
default:
MXM_DBG
(
dev
,
"unknown descriptor type %d
\n
"
,
type
);
return
false
;
}
if
((
drm_debug
&
DRM_UT_DRIVER
)
&&
(
exec
==
NULL
))
{
static
const
char
*
mxms_desc_name
[]
=
{
"ODS"
,
"SCCS"
,
"TS"
,
"IPS"
,
"GSD"
,
"VSS"
,
"BCS"
,
"FCS"
,
};
u8
*
dump
=
desc
;
int
i
,
j
;
MXM_DBG
(
dev
,
"%4s: "
,
mxms_desc_name
[
type
]);
for
(
j
=
headerlen
-
1
;
j
>=
0
;
j
--
)
printk
(
"%02x"
,
dump
[
j
]);
printk
(
"
\n
"
);
dump
+=
headerlen
;
for
(
i
=
0
;
i
<
entries
;
i
++
,
dump
+=
recordlen
)
{
MXM_DBG
(
dev
,
" "
);
for
(
j
=
recordlen
-
1
;
j
>=
0
;
j
--
)
printk
(
"%02x"
,
dump
[
j
]);
printk
(
"
\n
"
);
}
}
if
(
types
&
(
1
<<
type
))
{
if
(
!
exec
(
dev
,
desc
,
info
))
return
false
;
}
desc
+=
headerlen
+
(
entries
*
recordlen
);
}
return
true
;
}
static
u8
*
mxm_table
(
struct
drm_device
*
dev
,
u8
*
size
)
{
struct
bit_entry
x
;
if
(
bit_table
(
dev
,
'x'
,
&
x
))
{
MXM_DBG
(
dev
,
"BIT 'x' table not present
\n
"
);
return
NULL
;
}
if
(
x
.
version
!=
1
||
x
.
length
<
3
)
{
MXM_MSG
(
dev
,
"BIT x table %d/%d unknown
\n
"
,
x
.
version
,
x
.
length
);
return
NULL
;
}
*
size
=
x
.
length
;
return
x
.
data
;
}
/* These map MXM v2.x digital connection values to the appropriate SOR/link,
* hopefully they're correct for all boards within the same chipset...
*
* MXM v3.x VBIOS are nicer and provide pointers to these tables.
*/
static
u8
nv84_sor_map
[
16
]
=
{
0x00
,
0x12
,
0x22
,
0x11
,
0x32
,
0x31
,
0x11
,
0x31
,
0x00
,
0x00
,
0x00
,
0x00
,
0x00
,
0x00
,
0x00
,
0x00
};
static
u8
nv92_sor_map
[
16
]
=
{
0x00
,
0x12
,
0x22
,
0x11
,
0x32
,
0x31
,
0x11
,
0x31
,
0x11
,
0x31
,
0x00
,
0x00
,
0x00
,
0x00
,
0x00
,
0x00
};
static
u8
nv94_sor_map
[
16
]
=
{
0x00
,
0x14
,
0x24
,
0x11
,
0x34
,
0x31
,
0x11
,
0x31
,
0x11
,
0x31
,
0x12
,
0x00
,
0x00
,
0x00
,
0x00
,
0x00
};
static
u8
nv96_sor_map
[
16
]
=
{
0x00
,
0x14
,
0x24
,
0x00
,
0x34
,
0x00
,
0x11
,
0x31
,
0x11
,
0x31
,
0x12
,
0x00
,
0x00
,
0x00
,
0x00
,
0x00
};
static
u8
nv98_sor_map
[
16
]
=
{
0x00
,
0x14
,
0x12
,
0x11
,
0x00
,
0x31
,
0x11
,
0x31
,
0x11
,
0x31
,
0x00
,
0x00
,
0x00
,
0x00
,
0x00
,
0x00
};
static
u8
mxm_sor_map
(
struct
drm_device
*
dev
,
u8
conn
)
{
struct
drm_nouveau_private
*
dev_priv
=
dev
->
dev_private
;
u8
len
,
*
mxm
=
mxm_table
(
dev
,
&
len
);
if
(
mxm
&&
len
>=
6
)
{
u8
*
map
=
ROMPTR
(
dev
,
mxm
[
4
]);
if
(
map
)
{
if
(
map
[
0
]
==
0x10
)
{
if
(
conn
<
map
[
3
])
return
map
[
map
[
1
]
+
conn
];
return
0x00
;
}
MXM_MSG
(
dev
,
"unknown sor map 0x%02x
\n
"
,
map
[
0
]);
}
}
if
(
dev_priv
->
chipset
==
0x84
||
dev_priv
->
chipset
==
0x86
)
return
nv84_sor_map
[
conn
];
if
(
dev_priv
->
chipset
==
0x92
)
return
nv92_sor_map
[
conn
];
if
(
dev_priv
->
chipset
==
0x94
)
return
nv94_sor_map
[
conn
];
if
(
dev_priv
->
chipset
==
0x96
)
return
nv96_sor_map
[
conn
];
if
(
dev_priv
->
chipset
==
0x98
)
return
nv98_sor_map
[
conn
];
MXM_MSG
(
dev
,
"missing sor map
\n
"
);
return
0x00
;
}
static
u8
mxm_ddc_map
(
struct
drm_device
*
dev
,
u8
port
)
{
u8
len
,
*
mxm
=
mxm_table
(
dev
,
&
len
);
if
(
mxm
&&
len
>=
8
)
{
u8
*
map
=
ROMPTR
(
dev
,
mxm
[
6
]);
if
(
map
)
{
if
(
map
[
0
]
==
0x10
)
{
if
(
port
<
map
[
3
])
return
map
[
map
[
1
]
+
port
];
return
0x00
;
}
MXM_MSG
(
dev
,
"unknown ddc map 0x%02x
\n
"
,
map
[
0
]);
}
}
/* v2.x: directly write port as dcb i2cidx */
return
(
port
<<
4
)
|
port
;
}
struct
mxms_odev
{
u8
outp_type
;
u8
conn_type
;
u8
ddc_port
;
u8
dig_conn
;
};
static
void
mxms_output_device
(
struct
drm_device
*
dev
,
u8
*
pdata
,
struct
mxms_odev
*
desc
)
{
u64
data
=
ROM32
(
pdata
[
0
]);
if
(
mxms_version
(
dev
)
>=
0x0300
)
data
|=
(
u64
)
ROM16
(
pdata
[
4
])
<<
32
;
desc
->
outp_type
=
(
data
&
0x00000000000000f0ULL
)
>>
4
;
desc
->
ddc_port
=
(
data
&
0x0000000000000f00ULL
)
>>
8
;
desc
->
conn_type
=
(
data
&
0x000000000001f000ULL
)
>>
12
;
desc
->
dig_conn
=
(
data
&
0x0000000000780000ULL
)
>>
19
;
}
struct
context
{
u32
*
outp
;
struct
mxms_odev
desc
;
};
static
bool
mxm_match_tmds_partner
(
struct
drm_device
*
dev
,
u8
*
data
,
void
*
info
)
{
struct
context
*
ctx
=
info
;
struct
mxms_odev
desc
;
mxms_output_device
(
dev
,
data
,
&
desc
);
if
(
desc
.
outp_type
==
2
&&
desc
.
dig_conn
==
ctx
->
desc
.
dig_conn
)
return
false
;
return
true
;
}
static
bool
mxm_match_dcb
(
struct
drm_device
*
dev
,
u8
*
data
,
void
*
info
)
{
struct
context
*
ctx
=
info
;
u64
desc
=
*
(
u64
*
)
data
;
mxms_output_device
(
dev
,
data
,
&
ctx
->
desc
);
/* match dcb encoder type to mxm-ods device type */
if
((
ctx
->
outp
[
0
]
&
0x0000000f
)
!=
ctx
->
desc
.
outp_type
)
return
true
;
/* digital output, have some extra stuff to match here, there's a
* table in the vbios that provides a mapping from the mxm digital
* connection enum values to SOR/link
*/
if
((
desc
&
0x00000000000000f0
)
>=
0x20
)
{
/* check against sor index */
u8
link
=
mxm_sor_map
(
dev
,
ctx
->
desc
.
dig_conn
);
if
((
ctx
->
outp
[
0
]
&
0x0f000000
)
!=
(
link
&
0x0f
)
<<
24
)
return
true
;
/* check dcb entry has a compatible link field */
link
=
(
link
&
0x30
)
>>
4
;
if
((
link
&
((
ctx
->
outp
[
1
]
&
0x00000030
)
>>
4
))
!=
link
)
return
true
;
}
/* mark this descriptor accounted for by setting invalid device type,
* except of course some manufactures don't follow specs properly and
* we need to avoid killing off the TMDS function on DP connectors
* if MXM-SIS is missing an entry for it.
*/
data
[
0
]
&=
~
0xf0
;
if
(
ctx
->
desc
.
outp_type
==
6
&&
ctx
->
desc
.
conn_type
==
6
&&
mxms_foreach
(
dev
,
0x01
,
mxm_match_tmds_partner
,
ctx
))
{
data
[
0
]
|=
0x20
;
/* modify descriptor to match TMDS now */
}
else
{
data
[
0
]
|=
0xf0
;
}
return
false
;
}
static
int
mxm_dcb_sanitise_entry
(
struct
drm_device
*
dev
,
void
*
data
,
int
idx
,
u8
*
dcbe
)
{
struct
context
ctx
=
{
.
outp
=
(
u32
*
)
dcbe
};
u8
type
,
i2cidx
,
link
;
u8
*
conn
;
/* look for an output device structure that matches this dcb entry.
* if one isn't found, disable it.
*/
if
(
mxms_foreach
(
dev
,
0x01
,
mxm_match_dcb
,
&
ctx
))
{
MXM_DBG
(
dev
,
"disable %d: 0x%08x 0x%08x
\n
"
,
idx
,
ctx
.
outp
[
0
],
ctx
.
outp
[
1
]);
ctx
.
outp
[
0
]
|=
0x0000000f
;
return
0
;
}
/* modify the output's ddc/aux port, there's a pointer to a table
* with the mapping from mxm ddc/aux port to dcb i2c_index in the
* vbios mxm table
*/
i2cidx
=
mxm_ddc_map
(
dev
,
ctx
.
desc
.
ddc_port
);
if
((
ctx
.
outp
[
0
]
&
0x0000000f
)
!=
DCB_OUTPUT_DP
)
i2cidx
=
(
i2cidx
&
0x0f
)
<<
4
;
else
i2cidx
=
(
i2cidx
&
0xf0
);
if
(
i2cidx
!=
0xf0
)
{
ctx
.
outp
[
0
]
&=
~
0x000000f0
;
ctx
.
outp
[
0
]
|=
i2cidx
;
}
/* override dcb sorconf.link, based on what mxm data says */
switch
(
ctx
.
desc
.
outp_type
)
{
case
0x00
:
/* Analog CRT */
case
0x01
:
/* Analog TV/HDTV */
break
;
default:
link
=
mxm_sor_map
(
dev
,
ctx
.
desc
.
dig_conn
)
&
0x30
;
ctx
.
outp
[
1
]
&=
~
0x00000030
;
ctx
.
outp
[
1
]
|=
link
;
break
;
}
/* we may need to fixup various other vbios tables based on what
* the descriptor says the connector type should be.
*
* in a lot of cases, the vbios tables will claim DVI-I is possible,
* and the mxm data says the connector is really HDMI. another
* common example is DP->eDP.
*/
conn
=
olddcb_conn
(
dev
,
(
ctx
.
outp
[
0
]
&
0x0000f000
)
>>
12
);
type
=
conn
[
0
];
switch
(
ctx
.
desc
.
conn_type
)
{
case
0x01
:
/* LVDS */
ctx
.
outp
[
1
]
|=
0x00000004
;
/* use_power_scripts */
/* XXX: modify default link width in LVDS table */
break
;
case
0x02
:
/* HDMI */
type
=
DCB_CONNECTOR_HDMI_1
;
break
;
case
0x03
:
/* DVI-D */
type
=
DCB_CONNECTOR_DVI_D
;
break
;
case
0x0e
:
/* eDP, falls through to DPint */
ctx
.
outp
[
1
]
|=
0x00010000
;
case
0x07
:
/* DP internal, wtf is this?? HP8670w */
ctx
.
outp
[
1
]
|=
0x00000004
;
/* use_power_scripts? */
type
=
DCB_CONNECTOR_eDP
;
break
;
default:
break
;
}
if
(
mxms_version
(
dev
)
>=
0x0300
)
conn
[
0
]
=
type
;
return
0
;
}
static
bool
mxm_show_unmatched
(
struct
drm_device
*
dev
,
u8
*
data
,
void
*
info
)
{
u64
desc
=
*
(
u64
*
)
data
;
if
((
desc
&
0xf0
)
!=
0xf0
)
MXM_MSG
(
dev
,
"unmatched output device 0x%016llx
\n
"
,
desc
);
return
true
;
}
static
void
mxm_dcb_sanitise
(
struct
drm_device
*
dev
)
{
u8
*
dcb
=
olddcb_table
(
dev
);
if
(
!
dcb
||
dcb
[
0
]
!=
0x40
)
{
MXM_DBG
(
dev
,
"unsupported DCB version
\n
"
);
return
;
}
olddcb_outp_foreach
(
dev
,
NULL
,
mxm_dcb_sanitise_entry
);
mxms_foreach
(
dev
,
0x01
,
mxm_show_unmatched
,
NULL
);
}
static
bool
mxm_shadow_rom_fetch
(
struct
nouveau_i2c_port
*
i2c
,
u8
addr
,
u8
offset
,
u8
size
,
u8
*
data
)
{
struct
i2c_msg
msgs
[]
=
{
{
.
addr
=
addr
,
.
flags
=
0
,
.
len
=
1
,
.
buf
=
&
offset
},
{
.
addr
=
addr
,
.
flags
=
I2C_M_RD
,
.
len
=
size
,
.
buf
=
data
,
},
};
return
i2c_transfer
(
nouveau_i2c_adapter
(
i2c
),
msgs
,
2
)
==
2
;
}
static
bool
mxm_shadow_rom
(
struct
drm_device
*
dev
,
u8
version
)
{
struct
drm_nouveau_private
*
dev_priv
=
dev
->
dev_private
;
struct
nouveau_i2c_port
*
i2c
=
NULL
;
u8
i2cidx
,
mxms
[
6
],
addr
,
size
;
i2cidx
=
mxm_ddc_map
(
dev
,
1
/* LVDS_DDC */
)
&
0x0f
;
if
(
i2cidx
<
0x0f
)
i2c
=
nouveau_i2c_find
(
dev
,
i2cidx
);
if
(
!
i2c
)
return
false
;
addr
=
0x54
;
if
(
!
mxm_shadow_rom_fetch
(
i2c
,
addr
,
0
,
6
,
mxms
))
{
addr
=
0x56
;
if
(
!
mxm_shadow_rom_fetch
(
i2c
,
addr
,
0
,
6
,
mxms
))
return
false
;
}
dev_priv
->
mxms
=
mxms
;
size
=
mxms_headerlen
(
dev
)
+
mxms_structlen
(
dev
);
dev_priv
->
mxms
=
kmalloc
(
size
,
GFP_KERNEL
);
if
(
dev_priv
->
mxms
&&
mxm_shadow_rom_fetch
(
i2c
,
addr
,
0
,
size
,
dev_priv
->
mxms
))
return
true
;
kfree
(
dev_priv
->
mxms
);
dev_priv
->
mxms
=
NULL
;
return
false
;
}
#if defined(CONFIG_ACPI)
static
bool
mxm_shadow_dsm
(
struct
drm_device
*
dev
,
u8
version
)
{
struct
drm_nouveau_private
*
dev_priv
=
dev
->
dev_private
;
static
char
muid
[]
=
{
0x00
,
0xA4
,
0x04
,
0x40
,
0x7D
,
0x91
,
0xF2
,
0x4C
,
0xB8
,
0x9C
,
0x79
,
0xB6
,
0x2F
,
0xD5
,
0x56
,
0x65
};
u32
mxms_args
[]
=
{
0x00000000
};
union
acpi_object
args
[
4
]
=
{
/* _DSM MUID */
{
.
buffer
.
type
=
3
,
.
buffer
.
length
=
sizeof
(
muid
),
.
buffer
.
pointer
=
muid
,
},
/* spec says this can be zero to mean "highest revision", but
* of course there's at least one bios out there which fails
* unless you pass in exactly the version it supports..
*/
{
.
integer
.
type
=
ACPI_TYPE_INTEGER
,
.
integer
.
value
=
(
version
&
0xf0
)
<<
4
|
(
version
&
0x0f
),
},
/* MXMS function */
{
.
integer
.
type
=
ACPI_TYPE_INTEGER
,
.
integer
.
value
=
0x00000010
,
},
/* Pointer to MXMS arguments */
{
.
buffer
.
type
=
ACPI_TYPE_BUFFER
,
.
buffer
.
length
=
sizeof
(
mxms_args
),
.
buffer
.
pointer
=
(
char
*
)
mxms_args
,
},
};
struct
acpi_object_list
list
=
{
ARRAY_SIZE
(
args
),
args
};
struct
acpi_buffer
retn
=
{
ACPI_ALLOCATE_BUFFER
,
NULL
};
union
acpi_object
*
obj
;
acpi_handle
handle
;
int
ret
;
handle
=
DEVICE_ACPI_HANDLE
(
&
dev
->
pdev
->
dev
);
if
(
!
handle
)
return
false
;
ret
=
acpi_evaluate_object
(
handle
,
"_DSM"
,
&
list
,
&
retn
);
if
(
ret
)
{
MXM_DBG
(
dev
,
"DSM MXMS failed: %d
\n
"
,
ret
);
return
false
;
}
obj
=
retn
.
pointer
;
if
(
obj
->
type
==
ACPI_TYPE_BUFFER
)
{
dev_priv
->
mxms
=
kmemdup
(
obj
->
buffer
.
pointer
,
obj
->
buffer
.
length
,
GFP_KERNEL
);
}
else
if
(
obj
->
type
==
ACPI_TYPE_INTEGER
)
{
MXM_DBG
(
dev
,
"DSM MXMS returned 0x%llx
\n
"
,
obj
->
integer
.
value
);
}
kfree
(
obj
);
return
dev_priv
->
mxms
!=
NULL
;
}
#endif
#if defined(CONFIG_ACPI_WMI) || defined(CONFIG_ACPI_WMI_MODULE)
#define WMI_WMMX_GUID "F6CB5C3C-9CAE-4EBD-B577-931EA32A2CC0"
static
u8
wmi_wmmx_mxmi
(
struct
drm_device
*
dev
,
u8
version
)
{
u32
mxmi_args
[]
=
{
0x494D584D
/* MXMI */
,
version
,
0
};
struct
acpi_buffer
args
=
{
sizeof
(
mxmi_args
),
mxmi_args
};
struct
acpi_buffer
retn
=
{
ACPI_ALLOCATE_BUFFER
,
NULL
};
union
acpi_object
*
obj
;
acpi_status
status
;
status
=
wmi_evaluate_method
(
WMI_WMMX_GUID
,
0
,
0
,
&
args
,
&
retn
);
if
(
ACPI_FAILURE
(
status
))
{
MXM_DBG
(
dev
,
"WMMX MXMI returned %d
\n
"
,
status
);
return
0x00
;
}
obj
=
retn
.
pointer
;
if
(
obj
->
type
==
ACPI_TYPE_INTEGER
)
{
version
=
obj
->
integer
.
value
;
MXM_DBG
(
dev
,
"WMMX MXMI version %d.%d
\n
"
,
(
version
>>
4
),
version
&
0x0f
);
}
else
{
version
=
0
;
MXM_DBG
(
dev
,
"WMMX MXMI returned non-integer
\n
"
);
}
kfree
(
obj
);
return
version
;
}
static
bool
mxm_shadow_wmi
(
struct
drm_device
*
dev
,
u8
version
)
{
struct
drm_nouveau_private
*
dev_priv
=
dev
->
dev_private
;
u32
mxms_args
[]
=
{
0x534D584D
/* MXMS */
,
version
,
0
};
struct
acpi_buffer
args
=
{
sizeof
(
mxms_args
),
mxms_args
};
struct
acpi_buffer
retn
=
{
ACPI_ALLOCATE_BUFFER
,
NULL
};
union
acpi_object
*
obj
;
acpi_status
status
;
if
(
!
wmi_has_guid
(
WMI_WMMX_GUID
))
{
MXM_DBG
(
dev
,
"WMMX GUID not found
\n
"
);
return
false
;
}
mxms_args
[
1
]
=
wmi_wmmx_mxmi
(
dev
,
0x00
);
if
(
!
mxms_args
[
1
])
mxms_args
[
1
]
=
wmi_wmmx_mxmi
(
dev
,
version
);
if
(
!
mxms_args
[
1
])
return
false
;
status
=
wmi_evaluate_method
(
WMI_WMMX_GUID
,
0
,
0
,
&
args
,
&
retn
);
if
(
ACPI_FAILURE
(
status
))
{
MXM_DBG
(
dev
,
"WMMX MXMS returned %d
\n
"
,
status
);
return
false
;
}
obj
=
retn
.
pointer
;
if
(
obj
->
type
==
ACPI_TYPE_BUFFER
)
{
dev_priv
->
mxms
=
kmemdup
(
obj
->
buffer
.
pointer
,
obj
->
buffer
.
length
,
GFP_KERNEL
);
}
kfree
(
obj
);
return
dev_priv
->
mxms
!=
NULL
;
}
#endif
struct
mxm_shadow_h
{
const
char
*
name
;
bool
(
*
exec
)(
struct
drm_device
*
,
u8
version
);
}
_mxm_shadow
[]
=
{
{
"ROM"
,
mxm_shadow_rom
},
#if defined(CONFIG_ACPI)
{
"DSM"
,
mxm_shadow_dsm
},
#endif
#if defined(CONFIG_ACPI_WMI) || defined(CONFIG_ACPI_WMI_MODULE)
{
"WMI"
,
mxm_shadow_wmi
},
#endif
{}
};
static
int
mxm_shadow
(
struct
drm_device
*
dev
,
u8
version
)
{
struct
drm_nouveau_private
*
dev_priv
=
dev
->
dev_private
;
struct
mxm_shadow_h
*
shadow
=
_mxm_shadow
;
do
{
MXM_DBG
(
dev
,
"checking %s
\n
"
,
shadow
->
name
);
if
(
shadow
->
exec
(
dev
,
version
))
{
if
(
mxms_valid
(
dev
))
return
0
;
kfree
(
dev_priv
->
mxms
);
dev_priv
->
mxms
=
NULL
;
}
}
while
((
++
shadow
)
->
name
);
return
-
ENOENT
;
}
int
nouveau_mxm_init
(
struct
drm_device
*
dev
)
{
u8
mxm_size
,
*
mxm
=
mxm_table
(
dev
,
&
mxm_size
);
if
(
!
mxm
||
!
mxm
[
0
])
{
MXM_MSG
(
dev
,
"no VBIOS data, nothing to do
\n
"
);
return
0
;
}
MXM_MSG
(
dev
,
"BIOS version %d.%d
\n
"
,
mxm
[
0
]
>>
4
,
mxm
[
0
]
&
0x0f
);
if
(
mxm_shadow
(
dev
,
mxm
[
0
]))
{
MXM_MSG
(
dev
,
"failed to locate valid SIS
\n
"
);
#if 0
/* we should, perhaps, fall back to some kind of limited
* mode here if the x86 vbios hasn't already done the
* work for us (so we prevent loading with completely
* whacked vbios tables).
*/
return -EINVAL;
#else
return
0
;
#endif
}
MXM_MSG
(
dev
,
"MXMS Version %d.%d
\n
"
,
mxms_version
(
dev
)
>>
8
,
mxms_version
(
dev
)
&
0xff
);
mxms_foreach
(
dev
,
0
,
NULL
,
NULL
);
if
(
nouveau_mxmdcb
)
mxm_dcb_sanitise
(
dev
);
return
0
;
}
void
nouveau_mxm_fini
(
struct
drm_device
*
dev
)
{
struct
drm_nouveau_private
*
dev_priv
=
dev
->
dev_private
;
kfree
(
dev_priv
->
mxms
);
dev_priv
->
mxms
=
NULL
;
}
编辑
预览
Markdown
is supported
0%
请重试
或
添加新附件
.
添加附件
取消
You are about to add
0
people
to the discussion. Proceed with caution.
先完成此消息的编辑!
取消
想要评论请
注册
或
登录