Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
L
linux
Project overview
Project overview
Details
Activity
Releases
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Issues
0
Issues
0
List
Boards
Labels
Milestones
Merge Requests
0
Merge Requests
0
Analytics
Analytics
Repository
Value Stream
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Create a new issue
Commits
Issue Boards
Open sidebar
nexedi
linux
Commits
d38ac521
Commit
d38ac521
authored
Jul 22, 2012
by
Ben Skeggs
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
drm/nouveau/mxm: split up into bios code and a subdev module
Signed-off-by:
Ben Skeggs
<
bskeggs@redhat.com
>
parent
08c77096
Changes
16
Hide whitespace changes
Inline
Side-by-side
Showing
16 changed files
with
952 additions
and
755 deletions
+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
No files found.
drivers/gpu/drm/nouveau/Makefile
View file @
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
View file @
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
View file @
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
View file @
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
View file @
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
View file @
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
View file @
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
View file @
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
View file @
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
View file @
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
View file @
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
View file @
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
View file @
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
View file @
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
View file @
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
deleted
100644 → 0
View file @
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
;
}
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