aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/gpu/drm/nouveau
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/gpu/drm/nouveau')
-rw-r--r--drivers/gpu/drm/nouveau/core/include/subdev/bios/gpio.h8
-rw-r--r--drivers/gpu/drm/nouveau/core/subdev/bios/gpio.c128
-rw-r--r--drivers/gpu/drm/nouveau/core/subdev/gpio/base.c7
-rw-r--r--drivers/gpu/drm/nouveau/core/subdev/gpio/nv50.c4
-rw-r--r--drivers/gpu/drm/nouveau/core/subdev/gpio/nvd0.c4
5 files changed, 90 insertions, 61 deletions
diff --git a/drivers/gpu/drm/nouveau/core/include/subdev/bios/gpio.h b/drivers/gpu/drm/nouveau/core/include/subdev/bios/gpio.h
index 2bf178082a36..e6563b5cb08e 100644
--- a/drivers/gpu/drm/nouveau/core/include/subdev/bios/gpio.h
+++ b/drivers/gpu/drm/nouveau/core/include/subdev/bios/gpio.h
@@ -25,9 +25,11 @@ struct dcb_gpio_func {
25 u8 param; 25 u8 param;
26}; 26};
27 27
28u16 dcb_gpio_table(struct nouveau_bios *); 28u16 dcb_gpio_table(struct nouveau_bios *, u8 *ver, u8 *hdr, u8 *cnt, u8 *len);
29u16 dcb_gpio_entry(struct nouveau_bios *, int idx, int ent, u8 *ver); 29u16 dcb_gpio_entry(struct nouveau_bios *, int idx, int ent, u8 *ver, u8 *len);
30int dcb_gpio_parse(struct nouveau_bios *, int idx, u8 func, u8 line, 30u16 dcb_gpio_parse(struct nouveau_bios *, int idx, int ent, u8 *ver, u8 *len,
31 struct dcb_gpio_func *); 31 struct dcb_gpio_func *);
32u16 dcb_gpio_match(struct nouveau_bios *, int idx, u8 func, u8 line,
33 u8 *ver, u8 *len, struct dcb_gpio_func *);
32 34
33#endif 35#endif
diff --git a/drivers/gpu/drm/nouveau/core/subdev/bios/gpio.c b/drivers/gpu/drm/nouveau/core/subdev/bios/gpio.c
index c90d4aa3ae4f..c84e93fa6d95 100644
--- a/drivers/gpu/drm/nouveau/core/subdev/bios/gpio.c
+++ b/drivers/gpu/drm/nouveau/core/subdev/bios/gpio.c
@@ -27,84 +27,105 @@
27#include <subdev/bios/gpio.h> 27#include <subdev/bios/gpio.h>
28 28
29u16 29u16
30dcb_gpio_table(struct nouveau_bios *bios) 30dcb_gpio_table(struct nouveau_bios *bios, u8 *ver, u8 *hdr, u8 *cnt, u8 *len)
31{ 31{
32 u8 ver, hdr, cnt, len; 32 u16 data = 0x0000;
33 u16 dcb = dcb_table(bios, &ver, &hdr, &cnt, &len); 33 u16 dcb = dcb_table(bios, ver, hdr, cnt, len);
34 if (dcb) { 34 if (dcb) {
35 if (ver >= 0x30 && hdr >= 0x0c) 35 if (*ver >= 0x30 && *hdr >= 0x0c)
36 return nv_ro16(bios, dcb + 0x0a); 36 data = nv_ro16(bios, dcb + 0x0a);
37 if (ver >= 0x22 && nv_ro08(bios, dcb - 1) >= 0x13) 37 else
38 return nv_ro16(bios, dcb - 0x0f); 38 if (*ver >= 0x22 && nv_ro08(bios, dcb - 1) >= 0x13)
39 data = nv_ro16(bios, dcb - 0x0f);
40
41 if (data) {
42 *ver = nv_ro08(bios, data + 0x00);
43 if (*ver < 0x30) {
44 *hdr = 3;
45 *cnt = nv_ro08(bios, data + 0x02);
46 *len = nv_ro08(bios, data + 0x01);
47 } else
48 if (*ver <= 0x41) {
49 *hdr = nv_ro08(bios, data + 0x01);
50 *cnt = nv_ro08(bios, data + 0x02);
51 *len = nv_ro08(bios, data + 0x03);
52 } else {
53 data = 0x0000;
54 }
55 }
39 } 56 }
40 return 0x0000; 57 return data;
41} 58}
42 59
43u16 60u16
44dcb_gpio_entry(struct nouveau_bios *bios, int idx, int ent, u8 *ver) 61dcb_gpio_entry(struct nouveau_bios *bios, int idx, int ent, u8 *ver, u8 *len)
45{ 62{
46 u16 gpio = dcb_gpio_table(bios); 63 u8 hdr, cnt;
47 if (gpio) { 64 u16 gpio = !idx ? dcb_gpio_table(bios, ver, &hdr, &cnt, len) : 0x0000;
48 *ver = nv_ro08(bios, gpio); 65 if (gpio && ent < cnt)
49 if (*ver < 0x30 && ent < nv_ro08(bios, gpio + 2)) 66 return gpio + hdr + (ent * *len);
50 return gpio + 3 + (ent * nv_ro08(bios, gpio + 1));
51 else if (ent < nv_ro08(bios, gpio + 2))
52 return gpio + nv_ro08(bios, gpio + 1) +
53 (ent * nv_ro08(bios, gpio + 3));
54 }
55 return 0x0000; 67 return 0x0000;
56} 68}
57 69
58int 70u16
59dcb_gpio_parse(struct nouveau_bios *bios, int idx, u8 func, u8 line, 71dcb_gpio_parse(struct nouveau_bios *bios, int idx, int ent, u8 *ver, u8 *len,
60 struct dcb_gpio_func *gpio) 72 struct dcb_gpio_func *gpio)
61{ 73{
62 u8 ver, hdr, cnt, len; 74 u16 data = dcb_gpio_entry(bios, idx, ent, ver, len);
63 u16 entry; 75 if (data) {
64 int i = -1; 76 if (*ver < 0x40) {
65 77 u16 info = nv_ro16(bios, data);
66 while ((entry = dcb_gpio_entry(bios, idx, ++i, &ver))) {
67 if (ver < 0x40) {
68 u16 data = nv_ro16(bios, entry);
69 *gpio = (struct dcb_gpio_func) { 78 *gpio = (struct dcb_gpio_func) {
70 .line = (data & 0x001f) >> 0, 79 .line = (info & 0x001f) >> 0,
71 .func = (data & 0x07e0) >> 5, 80 .func = (info & 0x07e0) >> 5,
72 .log[0] = (data & 0x1800) >> 11, 81 .log[0] = (info & 0x1800) >> 11,
73 .log[1] = (data & 0x6000) >> 13, 82 .log[1] = (info & 0x6000) >> 13,
74 .param = !!(data & 0x8000), 83 .param = !!(info & 0x8000),
75 }; 84 };
76 } else 85 } else
77 if (ver < 0x41) { 86 if (*ver < 0x41) {
78 u32 data = nv_ro32(bios, entry); 87 u32 info = nv_ro32(bios, data);
79 *gpio = (struct dcb_gpio_func) { 88 *gpio = (struct dcb_gpio_func) {
80 .line = (data & 0x0000001f) >> 0, 89 .line = (info & 0x0000001f) >> 0,
81 .func = (data & 0x0000ff00) >> 8, 90 .func = (info & 0x0000ff00) >> 8,
82 .log[0] = (data & 0x18000000) >> 27, 91 .log[0] = (info & 0x18000000) >> 27,
83 .log[1] = (data & 0x60000000) >> 29, 92 .log[1] = (info & 0x60000000) >> 29,
84 .param = !!(data & 0x80000000), 93 .param = !!(info & 0x80000000),
85 }; 94 };
86 } else { 95 } else {
87 u32 data = nv_ro32(bios, entry + 0); 96 u32 info = nv_ro32(bios, data + 0);
88 u8 data1 = nv_ro32(bios, entry + 4); 97 u8 info1 = nv_ro32(bios, data + 4);
89 *gpio = (struct dcb_gpio_func) { 98 *gpio = (struct dcb_gpio_func) {
90 .line = (data & 0x0000003f) >> 0, 99 .line = (info & 0x0000003f) >> 0,
91 .func = (data & 0x0000ff00) >> 8, 100 .func = (info & 0x0000ff00) >> 8,
92 .log[0] = (data1 & 0x30) >> 4, 101 .log[0] = (info1 & 0x30) >> 4,
93 .log[1] = (data1 & 0xc0) >> 6, 102 .log[1] = (info1 & 0xc0) >> 6,
94 .param = !!(data & 0x80000000), 103 .param = !!(info & 0x80000000),
95 }; 104 };
96 } 105 }
106 }
107
108 return data;
109}
97 110
111u16
112dcb_gpio_match(struct nouveau_bios *bios, int idx, u8 func, u8 line,
113 u8 *ver, u8 *len, struct dcb_gpio_func *gpio)
114{
115 u8 hdr, cnt, i = 0;
116 u16 data;
117
118 while ((data = dcb_gpio_parse(bios, idx, i++, ver, len, gpio))) {
98 if ((line == 0xff || line == gpio->line) && 119 if ((line == 0xff || line == gpio->line) &&
99 (func == 0xff || func == gpio->func)) 120 (func == 0xff || func == gpio->func))
100 return 0; 121 return data;
101 } 122 }
102 123
103 /* DCB 2.2, fixed TVDAC GPIO data */ 124 /* DCB 2.2, fixed TVDAC GPIO data */
104 if ((entry = dcb_table(bios, &ver, &hdr, &cnt, &len))) { 125 if ((data = dcb_table(bios, ver, &hdr, &cnt, len))) {
105 if (ver >= 0x22 && ver < 0x30 && func == DCB_GPIO_TVDAC0) { 126 if (*ver >= 0x22 && *ver < 0x30 && func == DCB_GPIO_TVDAC0) {
106 u8 conf = nv_ro08(bios, entry - 5); 127 u8 conf = nv_ro08(bios, data - 5);
107 u8 addr = nv_ro08(bios, entry - 4); 128 u8 addr = nv_ro08(bios, data - 4);
108 if (conf & 0x01) { 129 if (conf & 0x01) {
109 *gpio = (struct dcb_gpio_func) { 130 *gpio = (struct dcb_gpio_func) {
110 .func = DCB_GPIO_TVDAC0, 131 .func = DCB_GPIO_TVDAC0,
@@ -112,10 +133,11 @@ dcb_gpio_parse(struct nouveau_bios *bios, int idx, u8 func, u8 line,
112 .log[0] = !!(conf & 0x02), 133 .log[0] = !!(conf & 0x02),
113 .log[1] = !(conf & 0x02), 134 .log[1] = !(conf & 0x02),
114 }; 135 };
115 return 0; 136 *ver = 0x00;
137 return data;
116 } 138 }
117 } 139 }
118 } 140 }
119 141
120 return -EINVAL; 142 return 0x0000;
121} 143}
diff --git a/drivers/gpu/drm/nouveau/core/subdev/gpio/base.c b/drivers/gpu/drm/nouveau/core/subdev/gpio/base.c
index acf818c58bf0..39f267c3241e 100644
--- a/drivers/gpu/drm/nouveau/core/subdev/gpio/base.c
+++ b/drivers/gpu/drm/nouveau/core/subdev/gpio/base.c
@@ -43,10 +43,15 @@ static int
43nouveau_gpio_find(struct nouveau_gpio *gpio, int idx, u8 tag, u8 line, 43nouveau_gpio_find(struct nouveau_gpio *gpio, int idx, u8 tag, u8 line,
44 struct dcb_gpio_func *func) 44 struct dcb_gpio_func *func)
45{ 45{
46 struct nouveau_bios *bios = nouveau_bios(gpio);
47 u8 ver, len;
48 u16 data;
49
46 if (line == 0xff && tag == 0xff) 50 if (line == 0xff && tag == 0xff)
47 return -EINVAL; 51 return -EINVAL;
48 52
49 if (!dcb_gpio_parse(nouveau_bios(gpio), idx, tag, line, func)) 53 data = dcb_gpio_match(bios, idx, tag, line, &ver, &len, func);
54 if (data)
50 return 0; 55 return 0;
51 56
52 /* Apple iMac G4 NV18 */ 57 /* Apple iMac G4 NV18 */
diff --git a/drivers/gpu/drm/nouveau/core/subdev/gpio/nv50.c b/drivers/gpu/drm/nouveau/core/subdev/gpio/nv50.c
index f3502c961cd9..da2341392ced 100644
--- a/drivers/gpu/drm/nouveau/core/subdev/gpio/nv50.c
+++ b/drivers/gpu/drm/nouveau/core/subdev/gpio/nv50.c
@@ -33,11 +33,11 @@ nv50_gpio_reset(struct nouveau_gpio *gpio)
33{ 33{
34 struct nouveau_bios *bios = nouveau_bios(gpio); 34 struct nouveau_bios *bios = nouveau_bios(gpio);
35 struct nv50_gpio_priv *priv = (void *)gpio; 35 struct nv50_gpio_priv *priv = (void *)gpio;
36 u8 ver, len;
36 u16 entry; 37 u16 entry;
37 u8 ver;
38 int ent = -1; 38 int ent = -1;
39 39
40 while ((entry = dcb_gpio_entry(bios, 0, ++ent, &ver))) { 40 while ((entry = dcb_gpio_entry(bios, 0, ++ent, &ver, &len))) {
41 static const u32 regs[] = { 0xe100, 0xe28c }; 41 static const u32 regs[] = { 0xe100, 0xe28c };
42 u32 data = nv_ro32(bios, entry); 42 u32 data = nv_ro32(bios, entry);
43 u8 line = (data & 0x0000001f); 43 u8 line = (data & 0x0000001f);
diff --git a/drivers/gpu/drm/nouveau/core/subdev/gpio/nvd0.c b/drivers/gpu/drm/nouveau/core/subdev/gpio/nvd0.c
index 8d18fcad26e0..cda607f24230 100644
--- a/drivers/gpu/drm/nouveau/core/subdev/gpio/nvd0.c
+++ b/drivers/gpu/drm/nouveau/core/subdev/gpio/nvd0.c
@@ -33,11 +33,11 @@ nvd0_gpio_reset(struct nouveau_gpio *gpio)
33{ 33{
34 struct nouveau_bios *bios = nouveau_bios(gpio); 34 struct nouveau_bios *bios = nouveau_bios(gpio);
35 struct nvd0_gpio_priv *priv = (void *)gpio; 35 struct nvd0_gpio_priv *priv = (void *)gpio;
36 u8 ver, len;
36 u16 entry; 37 u16 entry;
37 u8 ver;
38 int ent = -1; 38 int ent = -1;
39 39
40 while ((entry = dcb_gpio_entry(bios, 0, ++ent, &ver))) { 40 while ((entry = dcb_gpio_entry(bios, 0, ++ent, &ver, &len))) {
41 u32 data = nv_ro32(bios, entry); 41 u32 data = nv_ro32(bios, entry);
42 u8 line = (data & 0x0000003f); 42 u8 line = (data & 0x0000003f);
43 u8 defs = !!(data & 0x00000080); 43 u8 defs = !!(data & 0x00000080);