aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/gpu
diff options
context:
space:
mode:
authorMartin Peres <martin.peres@labri.fr>2012-08-18 10:33:53 -0400
committerBen Skeggs <bskeggs@redhat.com>2012-10-02 23:13:13 -0400
commit32334cc03a12c51f64613608a8b261738406e1e2 (patch)
tree7532a8c9141dc50ee4a135c2af4855ac125b9906 /drivers/gpu
parent7d70e9c1c69a5d22588ff5977249ac944d7cdfb0 (diff)
drm/nouveau/therm: use the EXTDEV table to detect i2c monitoring devices
This commit also adds a static list of all known devices and their possible i2c addresses. v2: use the common table parsing technique as suggested by darktama Signed-off-by: Martin Peres <martin.peres@labri.fr> Signed-off-by: Ben Skeggs <bskeggs@redhat.com>
Diffstat (limited to 'drivers/gpu')
-rw-r--r--drivers/gpu/drm/nouveau/Makefile1
-rw-r--r--drivers/gpu/drm/nouveau/core/include/subdev/bios/extdev.h30
-rw-r--r--drivers/gpu/drm/nouveau/core/subdev/bios/extdev.c100
-rw-r--r--drivers/gpu/drm/nouveau/nouveau_temp.c43
4 files changed, 174 insertions, 0 deletions
diff --git a/drivers/gpu/drm/nouveau/Makefile b/drivers/gpu/drm/nouveau/Makefile
index b6a6fa7fbcd..6adf1455255 100644
--- a/drivers/gpu/drm/nouveau/Makefile
+++ b/drivers/gpu/drm/nouveau/Makefile
@@ -30,6 +30,7 @@ nouveau-y += core/subdev/bios/bit.o
30nouveau-y += core/subdev/bios/conn.o 30nouveau-y += core/subdev/bios/conn.o
31nouveau-y += core/subdev/bios/dcb.o 31nouveau-y += core/subdev/bios/dcb.o
32nouveau-y += core/subdev/bios/dp.o 32nouveau-y += core/subdev/bios/dp.o
33nouveau-y += core/subdev/bios/extdev.o
33nouveau-y += core/subdev/bios/gpio.o 34nouveau-y += core/subdev/bios/gpio.o
34nouveau-y += core/subdev/bios/i2c.o 35nouveau-y += core/subdev/bios/i2c.o
35nouveau-y += core/subdev/bios/init.o 36nouveau-y += core/subdev/bios/init.o
diff --git a/drivers/gpu/drm/nouveau/core/include/subdev/bios/extdev.h b/drivers/gpu/drm/nouveau/core/include/subdev/bios/extdev.h
new file mode 100644
index 00000000000..949fee3af8f
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/core/include/subdev/bios/extdev.h
@@ -0,0 +1,30 @@
1#ifndef __NVBIOS_EXTDEV_H__
2#define __NVBIOS_EXTDEV_H__
3
4struct nouveau_bios;
5
6enum nvbios_extdev_type {
7 NVBIOS_EXTDEV_LM89 = 0x02,
8 NVBIOS_EXTDEV_VT1103M = 0x40,
9 NVBIOS_EXTDEV_PX3540 = 0x41,
10 NVBIOS_EXTDEV_VT1105M = 0x42, /* or close enough... */
11 NVBIOS_EXTDEV_ADT7473 = 0x70, /* can also be a LM64 */
12 NVBIOS_EXTDEV_HDCP_EEPROM = 0x90,
13 NVBIOS_EXTDEV_NONE = 0xff,
14};
15
16struct nvbios_extdev_func {
17 u8 type;
18 u8 addr;
19 u8 bus;
20};
21
22int
23nvbios_extdev_parse(struct nouveau_bios *, int, struct nvbios_extdev_func *);
24
25int
26nvbios_extdev_find(struct nouveau_bios *, enum nvbios_extdev_type,
27 struct nvbios_extdev_func *);
28
29
30#endif
diff --git a/drivers/gpu/drm/nouveau/core/subdev/bios/extdev.c b/drivers/gpu/drm/nouveau/core/subdev/bios/extdev.c
new file mode 100644
index 00000000000..5afb568b2d6
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/core/subdev/bios/extdev.c
@@ -0,0 +1,100 @@
1/*
2 * Copyright 2012 Nouveau Community
3 *
4 * Permission is hereby granted, free of charge, to any person obtaining a
5 * copy of this software and associated documentation files (the "Software"),
6 * to deal in the Software without restriction, including without limitation
7 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
8 * and/or sell copies of the Software, and to permit persons to whom the
9 * Software is furnished to do so, subject to the following conditions:
10 *
11 * The above copyright notice and this permission notice shall be included in
12 * all copies or substantial portions of the Software.
13 *
14 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
17 * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
18 * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
19 * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
20 * OTHER DEALINGS IN THE SOFTWARE.
21 *
22 * Authors: Martin Peres
23 */
24
25#include <subdev/bios.h>
26#include <subdev/bios/dcb.h>
27#include <subdev/bios/extdev.h>
28
29static u16
30extdev_table(struct nouveau_bios *bios, u8 *ver, u8 *hdr, u8 *len, u8 *cnt)
31{
32 u8 dcb_ver, dcb_hdr, dcb_cnt, dcb_len;
33 u16 dcb, extdev = 0;
34
35 dcb = dcb_table(bios, &dcb_ver, &dcb_hdr, &dcb_cnt, &dcb_len);
36 if (!dcb || (dcb_ver != 0x30 && dcb_ver != 0x40))
37 return 0x0000;
38
39 extdev = nv_ro16(bios, dcb + 18);
40 if (!extdev)
41 return 0x0000;
42
43 *ver = nv_ro08(bios, extdev + 0);
44 *hdr = nv_ro08(bios, extdev + 1);
45 *cnt = nv_ro08(bios, extdev + 2);
46 *len = nv_ro08(bios, extdev + 3);
47
48 return extdev + *hdr;
49}
50
51u16
52nvbios_extdev_entry(struct nouveau_bios *bios, int idx, u8 *ver, u8 *len)
53{
54 u8 hdr, cnt;
55 u16 extdev = extdev_table(bios, ver, &hdr, len, &cnt);
56 if (extdev && idx < cnt)
57 return extdev + idx * *len;
58 return 0x0000;
59}
60
61static void
62extdev_parse_entry(struct nouveau_bios *bios, u16 offset,
63 struct nvbios_extdev_func *entry)
64{
65 entry->type = nv_ro08(bios, offset + 0);
66 entry->addr = nv_ro08(bios, offset + 1);
67 entry->bus = (nv_ro08(bios, offset + 2) >> 4) & 1;
68}
69
70int
71nvbios_extdev_parse(struct nouveau_bios *bios, int idx,
72 struct nvbios_extdev_func *func)
73{
74 u8 ver, len;
75 u16 entry;
76
77 if (!(entry = nvbios_extdev_entry(bios, idx, &ver, &len)))
78 return -EINVAL;
79
80 extdev_parse_entry(bios, entry, func);
81
82 return 0;
83}
84
85int
86nvbios_extdev_find(struct nouveau_bios *bios, enum nvbios_extdev_type type,
87 struct nvbios_extdev_func *func)
88{
89 u8 ver, len, i;
90 u16 entry;
91
92 i = 0;
93 while (!(entry = nvbios_extdev_entry(bios, i++, &ver, &len))) {
94 extdev_parse_entry(bios, entry, func);
95 if (func->type == type)
96 return 0;
97 }
98
99 return -EINVAL;
100}
diff --git a/drivers/gpu/drm/nouveau/nouveau_temp.c b/drivers/gpu/drm/nouveau/nouveau_temp.c
index 5465abf87f1..6d2b957ca01 100644
--- a/drivers/gpu/drm/nouveau/nouveau_temp.c
+++ b/drivers/gpu/drm/nouveau/nouveau_temp.c
@@ -31,6 +31,7 @@
31 31
32#include <subdev/i2c.h> 32#include <subdev/i2c.h>
33#include <subdev/bios/therm.h> 33#include <subdev/bios/therm.h>
34#include <subdev/bios/extdev.h>
34 35
35static int 36static int
36nv40_sensor_setup(struct drm_device *dev) 37nv40_sensor_setup(struct drm_device *dev)
@@ -132,16 +133,58 @@ static void
132nouveau_temp_probe_i2c(struct drm_device *dev) 133nouveau_temp_probe_i2c(struct drm_device *dev)
133{ 134{
134 struct nouveau_device *device = nouveau_dev(dev); 135 struct nouveau_device *device = nouveau_dev(dev);
136 struct nouveau_bios *bios = nouveau_bios(device);
135 struct nouveau_i2c *i2c = nouveau_i2c(device); 137 struct nouveau_i2c *i2c = nouveau_i2c(device);
138 struct nvbios_extdev_func extdev_entry;
136 struct i2c_board_info info[] = { 139 struct i2c_board_info info[] = {
137 { I2C_BOARD_INFO("w83l785ts", 0x2d) }, 140 { I2C_BOARD_INFO("w83l785ts", 0x2d) },
138 { I2C_BOARD_INFO("w83781d", 0x2d) }, 141 { I2C_BOARD_INFO("w83781d", 0x2d) },
139 { I2C_BOARD_INFO("adt7473", 0x2e) }, 142 { I2C_BOARD_INFO("adt7473", 0x2e) },
143 { I2C_BOARD_INFO("adt7473", 0x2d) },
144 { I2C_BOARD_INFO("adt7473", 0x2c) },
140 { I2C_BOARD_INFO("f75375", 0x2e) }, 145 { I2C_BOARD_INFO("f75375", 0x2e) },
141 { I2C_BOARD_INFO("lm99", 0x4c) }, 146 { I2C_BOARD_INFO("lm99", 0x4c) },
147 { I2C_BOARD_INFO("lm90", 0x4c) },
148 { I2C_BOARD_INFO("lm90", 0x4d) },
149 { I2C_BOARD_INFO("adm1021", 0x18) },
150 { I2C_BOARD_INFO("adm1021", 0x19) },
151 { I2C_BOARD_INFO("adm1021", 0x1a) },
152 { I2C_BOARD_INFO("adm1021", 0x29) },
153 { I2C_BOARD_INFO("adm1021", 0x2a) },
154 { I2C_BOARD_INFO("adm1021", 0x2b) },
155 { I2C_BOARD_INFO("adm1021", 0x4c) },
156 { I2C_BOARD_INFO("adm1021", 0x4d) },
157 { I2C_BOARD_INFO("adm1021", 0x4e) },
158 { I2C_BOARD_INFO("lm63", 0x18) },
159 { I2C_BOARD_INFO("lm63", 0x4e) },
142 { } 160 { }
143 }; 161 };
144 162
163 if (!nvbios_extdev_find(bios, NVBIOS_EXTDEV_LM89, &extdev_entry)) {
164 struct i2c_board_info board[] = {
165 { I2C_BOARD_INFO("lm90", extdev_entry.addr >> 1) },
166 { }
167 };
168
169 if (i2c->identify(i2c, NV_I2C_DEFAULT(0), "monitoring device",
170 board, probe_monitoring_device))
171 return;
172 }
173
174 if (!nvbios_extdev_find(bios, NVBIOS_EXTDEV_ADT7473, &extdev_entry)) {
175 struct i2c_board_info board[] = {
176 { I2C_BOARD_INFO("adt7473", extdev_entry.addr >> 1) },
177 { }
178 };
179
180 if (i2c->identify(i2c, NV_I2C_DEFAULT(0), "monitoring device",
181 board, probe_monitoring_device))
182 return;
183 }
184
185 /* The vbios doesn't provide the address of an exisiting monitoring
186 device. Let's try our static list.
187 */
145 i2c->identify(i2c, NV_I2C_DEFAULT(0), "monitoring device", info, 188 i2c->identify(i2c, NV_I2C_DEFAULT(0), "monitoring device", info,
146 probe_monitoring_device); 189 probe_monitoring_device);
147} 190}