aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--drivers/gpu/drm/nouveau/dispnv04/disp.h16
-rw-r--r--drivers/gpu/drm/nouveau/include/nvif/cl5070.h39
-rw-r--r--drivers/gpu/drm/nouveau/include/nvkm/engine/disp.h10
-rw-r--r--drivers/gpu/drm/nouveau/include/nvkm/subdev/bios/init.h27
-rw-r--r--drivers/gpu/drm/nouveau/include/nvkm/subdev/timer.h1
-rw-r--r--drivers/gpu/drm/nouveau/nouveau_bios.c3
-rw-r--r--drivers/gpu/drm/nouveau/nouveau_connector.c10
-rw-r--r--drivers/gpu/drm/nouveau/nouveau_drm.c2
-rw-r--r--drivers/gpu/drm/nouveau/nouveau_encoder.h1
-rw-r--r--drivers/gpu/drm/nouveau/nouveau_hwmon.c983
-rw-r--r--drivers/gpu/drm/nouveau/nouveau_vga.c4
-rw-r--r--drivers/gpu/drm/nouveau/nv50_display.c244
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/engine/device/base.c6
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/engine/device/tegra.c13
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/engine/disp/Kbuild24
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/engine/disp/base.c243
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/engine/disp/basenv50.c3
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/engine/disp/channv50.c1
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/engine/disp/conn.c24
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/engine/disp/conn.h14
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/engine/disp/cursnv50.c3
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/engine/disp/dacgf119.c65
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/engine/disp/dacnv50.c140
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/engine/disp/dp.c652
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/engine/disp/dp.h (renamed from drivers/gpu/drm/nouveau/nvkm/engine/disp/dport.h)38
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/engine/disp/dport.c401
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/engine/disp/g84.c24
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/engine/disp/g94.c25
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/engine/disp/gf119.c422
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/engine/disp/gk104.c21
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/engine/disp/gk110.c21
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/engine/disp/gm107.c21
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/engine/disp/gm200.c22
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/engine/disp/gp100.c21
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/engine/disp/gp102.c21
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/engine/disp/gt200.c24
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/engine/disp/gt215.c26
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/engine/disp/hdagf119.c75
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/engine/disp/hdagt215.c74
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/engine/disp/hdmi.c66
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/engine/disp/hdmi.h15
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/engine/disp/hdmig84.c73
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/engine/disp/hdmigf119.c74
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/engine/disp/hdmigk104.c72
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/engine/disp/hdmigt215.c74
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/engine/disp/head.c105
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/engine/disp/head.h56
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/engine/disp/headgf119.c96
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/engine/disp/headnv04.c74
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/engine/disp/headnv50.c92
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/engine/disp/ior.c72
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/engine/disp/ior.h169
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/engine/disp/mcp77.c43
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/engine/disp/mcp89.c43
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/engine/disp/nv04.c31
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/engine/disp/nv50.c991
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/engine/disp/nv50.h76
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/engine/disp/oimmnv50.c3
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/engine/disp/outp.c214
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/engine/disp/outp.h55
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/engine/disp/outpdp.c282
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/engine/disp/outpdp.h76
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/engine/disp/ovlynv50.c3
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/engine/disp/piornv50.c163
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/engine/disp/priv.h28
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/engine/disp/rootgf119.c60
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/engine/disp/rootnv04.c54
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/engine/disp/rootnv50.c259
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/engine/disp/sorg84.c38
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/engine/disp/sorg94.c290
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/engine/disp/sorgf119.c203
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/engine/disp/sorgk104.c53
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/engine/disp/sorgm107.c49
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/engine/disp/sorgm200.c163
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/engine/disp/sorgt215.c69
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/engine/disp/sormcp77.c48
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/engine/disp/sormcp89.c53
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/engine/disp/sornv50.c100
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/subdev/bios/iccsense.c5
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/subdev/bios/init.c227
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/subdev/bios/volt.c6
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/subdev/devinit/nv04.c2
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/subdev/devinit/nv50.c15
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/subdev/fb/ramgk104.c7
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/subdev/fb/ramgp100.c7
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/subdev/fb/ramnv40.c12
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/subdev/pmu/gk20a.c2
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/subdev/therm/base.c4
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/subdev/therm/fan.c2
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/subdev/therm/temp.c2
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/subdev/timer/base.c9
91 files changed, 4531 insertions, 4018 deletions
diff --git a/drivers/gpu/drm/nouveau/dispnv04/disp.h b/drivers/gpu/drm/nouveau/dispnv04/disp.h
index bea4543554ba..74a8795c2c2b 100644
--- a/drivers/gpu/drm/nouveau/dispnv04/disp.h
+++ b/drivers/gpu/drm/nouveau/dispnv04/disp.h
@@ -169,18 +169,10 @@ static inline void
169nouveau_bios_run_init_table(struct drm_device *dev, u16 table, 169nouveau_bios_run_init_table(struct drm_device *dev, u16 table,
170 struct dcb_output *outp, int crtc) 170 struct dcb_output *outp, int crtc)
171{ 171{
172 struct nouveau_drm *drm = nouveau_drm(dev); 172 nvbios_init(&nvxx_bios(&nouveau_drm(dev)->client.device)->subdev, table,
173 struct nvkm_bios *bios = nvxx_bios(&drm->client.device); 173 init.outp = outp;
174 struct nvbios_init init = { 174 init.head = crtc;
175 .subdev = &bios->subdev, 175 );
176 .bios = bios,
177 .offset = table,
178 .outp = outp,
179 .crtc = crtc,
180 .execute = 1,
181 };
182
183 nvbios_exec(&init);
184} 176}
185 177
186#endif 178#endif
diff --git a/drivers/gpu/drm/nouveau/include/nvif/cl5070.h b/drivers/gpu/drm/nouveau/include/nvif/cl5070.h
index ae49dfd1f97b..542d95145a67 100644
--- a/drivers/gpu/drm/nouveau/include/nvif/cl5070.h
+++ b/drivers/gpu/drm/nouveau/include/nvif/cl5070.h
@@ -27,29 +27,25 @@ struct nv50_disp_scanoutpos_v0 {
27 27
28struct nv50_disp_mthd_v1 { 28struct nv50_disp_mthd_v1 {
29 __u8 version; 29 __u8 version;
30#define NV50_DISP_MTHD_V1_DAC_PWR 0x10 30#define NV50_DISP_MTHD_V1_ACQUIRE 0x01
31#define NV50_DISP_MTHD_V1_RELEASE 0x02
31#define NV50_DISP_MTHD_V1_DAC_LOAD 0x11 32#define NV50_DISP_MTHD_V1_DAC_LOAD 0x11
32#define NV50_DISP_MTHD_V1_SOR_PWR 0x20
33#define NV50_DISP_MTHD_V1_SOR_HDA_ELD 0x21 33#define NV50_DISP_MTHD_V1_SOR_HDA_ELD 0x21
34#define NV50_DISP_MTHD_V1_SOR_HDMI_PWR 0x22 34#define NV50_DISP_MTHD_V1_SOR_HDMI_PWR 0x22
35#define NV50_DISP_MTHD_V1_SOR_LVDS_SCRIPT 0x23 35#define NV50_DISP_MTHD_V1_SOR_LVDS_SCRIPT 0x23
36#define NV50_DISP_MTHD_V1_SOR_DP_PWR 0x24
37#define NV50_DISP_MTHD_V1_SOR_DP_MST_LINK 0x25 36#define NV50_DISP_MTHD_V1_SOR_DP_MST_LINK 0x25
38#define NV50_DISP_MTHD_V1_SOR_DP_MST_VCPI 0x26 37#define NV50_DISP_MTHD_V1_SOR_DP_MST_VCPI 0x26
39#define NV50_DISP_MTHD_V1_PIOR_PWR 0x30
40 __u8 method; 38 __u8 method;
41 __u16 hasht; 39 __u16 hasht;
42 __u16 hashm; 40 __u16 hashm;
43 __u8 pad06[2]; 41 __u8 pad06[2];
44}; 42};
45 43
46struct nv50_disp_dac_pwr_v0 { 44struct nv50_disp_acquire_v0 {
47 __u8 version; 45 __u8 version;
48 __u8 state; 46 __u8 or;
49 __u8 data; 47 __u8 link;
50 __u8 vsync; 48 __u8 pad03[5];
51 __u8 hsync;
52 __u8 pad05[3];
53}; 49};
54 50
55struct nv50_disp_dac_load_v0 { 51struct nv50_disp_dac_load_v0 {
@@ -59,12 +55,6 @@ struct nv50_disp_dac_load_v0 {
59 __u32 data; 55 __u32 data;
60}; 56};
61 57
62struct nv50_disp_sor_pwr_v0 {
63 __u8 version;
64 __u8 state;
65 __u8 pad02[6];
66};
67
68struct nv50_disp_sor_hda_eld_v0 { 58struct nv50_disp_sor_hda_eld_v0 {
69 __u8 version; 59 __u8 version;
70 __u8 pad01[7]; 60 __u8 pad01[7];
@@ -76,7 +66,9 @@ struct nv50_disp_sor_hdmi_pwr_v0 {
76 __u8 state; 66 __u8 state;
77 __u8 max_ac_packet; 67 __u8 max_ac_packet;
78 __u8 rekey; 68 __u8 rekey;
79 __u8 pad04[4]; 69 __u8 avi_infoframe_length;
70 __u8 vendor_infoframe_length;
71 __u8 pad06[2];
80}; 72};
81 73
82struct nv50_disp_sor_lvds_script_v0 { 74struct nv50_disp_sor_lvds_script_v0 {
@@ -86,12 +78,6 @@ struct nv50_disp_sor_lvds_script_v0 {
86 __u8 pad04[4]; 78 __u8 pad04[4];
87}; 79};
88 80
89struct nv50_disp_sor_dp_pwr_v0 {
90 __u8 version;
91 __u8 state;
92 __u8 pad02[6];
93};
94
95struct nv50_disp_sor_dp_mst_link_v0 { 81struct nv50_disp_sor_dp_mst_link_v0 {
96 __u8 version; 82 __u8 version;
97 __u8 state; 83 __u8 state;
@@ -106,11 +92,4 @@ struct nv50_disp_sor_dp_mst_vcpi_v0 {
106 __u16 pbn; 92 __u16 pbn;
107 __u16 aligned_pbn; 93 __u16 aligned_pbn;
108}; 94};
109
110struct nv50_disp_pior_pwr_v0 {
111 __u8 version;
112 __u8 state;
113 __u8 type;
114 __u8 pad03[5];
115};
116#endif 95#endif
diff --git a/drivers/gpu/drm/nouveau/include/nvkm/engine/disp.h b/drivers/gpu/drm/nouveau/include/nvkm/engine/disp.h
index 970ae753968a..05f9c13ab8c3 100644
--- a/drivers/gpu/drm/nouveau/include/nvkm/engine/disp.h
+++ b/drivers/gpu/drm/nouveau/include/nvkm/engine/disp.h
@@ -8,17 +8,15 @@ struct nvkm_disp {
8 const struct nvkm_disp_func *func; 8 const struct nvkm_disp_func *func;
9 struct nvkm_engine engine; 9 struct nvkm_engine engine;
10 10
11 struct nvkm_oproxy *client; 11 struct list_head head;
12 12 struct list_head ior;
13 struct list_head outp; 13 struct list_head outp;
14 struct list_head conn; 14 struct list_head conn;
15 15
16 struct nvkm_event hpd; 16 struct nvkm_event hpd;
17 struct nvkm_event vblank; 17 struct nvkm_event vblank;
18 18
19 struct { 19 struct nvkm_oproxy *client;
20 int nr;
21 } head;
22}; 20};
23 21
24int nv04_disp_new(struct nvkm_device *, int, struct nvkm_disp **); 22int nv04_disp_new(struct nvkm_device *, int, struct nvkm_disp **);
@@ -26,7 +24,9 @@ int nv50_disp_new(struct nvkm_device *, int, struct nvkm_disp **);
26int g84_disp_new(struct nvkm_device *, int, struct nvkm_disp **); 24int g84_disp_new(struct nvkm_device *, int, struct nvkm_disp **);
27int gt200_disp_new(struct nvkm_device *, int, struct nvkm_disp **); 25int gt200_disp_new(struct nvkm_device *, int, struct nvkm_disp **);
28int g94_disp_new(struct nvkm_device *, int, struct nvkm_disp **); 26int g94_disp_new(struct nvkm_device *, int, struct nvkm_disp **);
27int mcp77_disp_new(struct nvkm_device *, int, struct nvkm_disp **);
29int gt215_disp_new(struct nvkm_device *, int, struct nvkm_disp **); 28int gt215_disp_new(struct nvkm_device *, int, struct nvkm_disp **);
29int mcp89_disp_new(struct nvkm_device *, int, struct nvkm_disp **);
30int gf119_disp_new(struct nvkm_device *, int, struct nvkm_disp **); 30int gf119_disp_new(struct nvkm_device *, int, struct nvkm_disp **);
31int gk104_disp_new(struct nvkm_device *, int, struct nvkm_disp **); 31int gk104_disp_new(struct nvkm_device *, int, struct nvkm_disp **);
32int gk110_disp_new(struct nvkm_device *, int, struct nvkm_disp **); 32int gk110_disp_new(struct nvkm_device *, int, struct nvkm_disp **);
diff --git a/drivers/gpu/drm/nouveau/include/nvkm/subdev/bios/init.h b/drivers/gpu/drm/nouveau/include/nvkm/subdev/bios/init.h
index 4dc1c8af840c..06ab48052128 100644
--- a/drivers/gpu/drm/nouveau/include/nvkm/subdev/bios/init.h
+++ b/drivers/gpu/drm/nouveau/include/nvkm/subdev/bios/init.h
@@ -3,19 +3,34 @@
3 3
4struct nvbios_init { 4struct nvbios_init {
5 struct nvkm_subdev *subdev; 5 struct nvkm_subdev *subdev;
6 struct nvkm_bios *bios; 6 u32 offset;
7 u16 offset; 7
8 struct dcb_output *outp; 8 struct dcb_output *outp;
9 int crtc; 9 int or;
10 int link;
11 int head;
10 12
11 /* internal state used during parsing */ 13 /* internal state used during parsing */
12 u8 execute; 14 u8 execute;
13 u32 nested; 15 u32 nested;
14 u16 repeat; 16 u32 repeat;
15 u16 repend; 17 u32 repend;
16 u32 ramcfg; 18 u32 ramcfg;
17}; 19};
18 20
21#define nvbios_init(s,o,ARGS...) ({ \
22 struct nvbios_init init = { \
23 .subdev = (s), \
24 .offset = (o), \
25 .or = -1, \
26 .link = 0, \
27 .head = -1, \
28 .execute = 1, \
29 }; \
30 ARGS \
31 nvbios_exec(&init); \
32})
19int nvbios_exec(struct nvbios_init *); 33int nvbios_exec(struct nvbios_init *);
20int nvbios_init(struct nvkm_subdev *, bool execute); 34
35int nvbios_post(struct nvkm_subdev *, bool execute);
21#endif 36#endif
diff --git a/drivers/gpu/drm/nouveau/include/nvkm/subdev/timer.h b/drivers/gpu/drm/nouveau/include/nvkm/subdev/timer.h
index 820a4805916f..ff0709652f80 100644
--- a/drivers/gpu/drm/nouveau/include/nvkm/subdev/timer.h
+++ b/drivers/gpu/drm/nouveau/include/nvkm/subdev/timer.h
@@ -26,7 +26,6 @@ struct nvkm_timer {
26 26
27u64 nvkm_timer_read(struct nvkm_timer *); 27u64 nvkm_timer_read(struct nvkm_timer *);
28void nvkm_timer_alarm(struct nvkm_timer *, u32 nsec, struct nvkm_alarm *); 28void nvkm_timer_alarm(struct nvkm_timer *, u32 nsec, struct nvkm_alarm *);
29void nvkm_timer_alarm_cancel(struct nvkm_timer *, struct nvkm_alarm *);
30 29
31/* Delay based on GPU time (ie. PTIMER). 30/* Delay based on GPU time (ie. PTIMER).
32 * 31 *
diff --git a/drivers/gpu/drm/nouveau/nouveau_bios.c b/drivers/gpu/drm/nouveau/nouveau_bios.c
index 9a0772ad495a..b998c33af18a 100644
--- a/drivers/gpu/drm/nouveau/nouveau_bios.c
+++ b/drivers/gpu/drm/nouveau/nouveau_bios.c
@@ -1533,7 +1533,8 @@ parse_dcb20_entry(struct drm_device *dev, struct dcb_table *dcb,
1533 if (conf & 0x100000) 1533 if (conf & 0x100000)
1534 entry->i2c_upper_default = true; 1534 entry->i2c_upper_default = true;
1535 1535
1536 entry->hasht = (entry->location << 4) | entry->type; 1536 entry->hasht = (entry->extdev << 8) | (entry->location << 4) |
1537 entry->type;
1537 entry->hashm = (entry->heads << 8) | (link << 6) | entry->or; 1538 entry->hashm = (entry->heads << 8) | (link << 6) | entry->or;
1538 return true; 1539 return true;
1539} 1540}
diff --git a/drivers/gpu/drm/nouveau/nouveau_connector.c b/drivers/gpu/drm/nouveau/nouveau_connector.c
index f802bcd94457..147b22163f9f 100644
--- a/drivers/gpu/drm/nouveau/nouveau_connector.c
+++ b/drivers/gpu/drm/nouveau/nouveau_connector.c
@@ -1045,6 +1045,9 @@ nouveau_connector_mode_valid(struct drm_connector *connector,
1045 return MODE_BAD; 1045 return MODE_BAD;
1046 } 1046 }
1047 1047
1048 if ((mode->flags & DRM_MODE_FLAG_3D_MASK) == DRM_MODE_FLAG_3D_FRAME_PACKING)
1049 clock *= 2;
1050
1048 if (clock < min_clock) 1051 if (clock < min_clock)
1049 return MODE_CLOCK_LOW; 1052 return MODE_CLOCK_LOW;
1050 1053
@@ -1321,6 +1324,13 @@ nouveau_connector_create(struct drm_device *dev, int index)
1321 break; 1324 break;
1322 } 1325 }
1323 1326
1327 /* HDMI 3D support */
1328 if ((disp->disp.oclass >= G82_DISP)
1329 && ((type == DRM_MODE_CONNECTOR_DisplayPort)
1330 || (type == DRM_MODE_CONNECTOR_eDP)
1331 || (type == DRM_MODE_CONNECTOR_HDMIA)))
1332 connector->stereo_allowed = true;
1333
1324 /* defaults, will get overridden in detect() */ 1334 /* defaults, will get overridden in detect() */
1325 connector->interlace_allowed = false; 1335 connector->interlace_allowed = false;
1326 connector->doublescan_allowed = false; 1336 connector->doublescan_allowed = false;
diff --git a/drivers/gpu/drm/nouveau/nouveau_drm.c b/drivers/gpu/drm/nouveau/nouveau_drm.c
index 7acd1cf8c5a6..90757af9bc73 100644
--- a/drivers/gpu/drm/nouveau/nouveau_drm.c
+++ b/drivers/gpu/drm/nouveau/nouveau_drm.c
@@ -727,7 +727,7 @@ nouveau_pmops_thaw(struct device *dev)
727} 727}
728 728
729bool 729bool
730nouveau_pmops_runtime() 730nouveau_pmops_runtime(void)
731{ 731{
732 if (nouveau_runtime_pm == -1) 732 if (nouveau_runtime_pm == -1)
733 return nouveau_is_optimus() || nouveau_is_v1_dsm(); 733 return nouveau_is_optimus() || nouveau_is_v1_dsm();
diff --git a/drivers/gpu/drm/nouveau/nouveau_encoder.h b/drivers/gpu/drm/nouveau/nouveau_encoder.h
index 198e5f27682f..e28d966946a1 100644
--- a/drivers/gpu/drm/nouveau/nouveau_encoder.h
+++ b/drivers/gpu/drm/nouveau/nouveau_encoder.h
@@ -42,6 +42,7 @@ struct nouveau_encoder {
42 42
43 struct dcb_output *dcb; 43 struct dcb_output *dcb;
44 int or; 44 int or;
45 int link;
45 46
46 struct i2c_adapter *i2c; 47 struct i2c_adapter *i2c;
47 struct nvkm_i2c_aux *aux; 48 struct nvkm_i2c_aux *aux;
diff --git a/drivers/gpu/drm/nouveau/nouveau_hwmon.c b/drivers/gpu/drm/nouveau/nouveau_hwmon.c
index 23b1670c1c2f..7c965648df80 100644
--- a/drivers/gpu/drm/nouveau/nouveau_hwmon.c
+++ b/drivers/gpu/drm/nouveau/nouveau_hwmon.c
@@ -38,21 +38,6 @@
38#include <nvkm/subdev/volt.h> 38#include <nvkm/subdev/volt.h>
39 39
40#if defined(CONFIG_HWMON) || (defined(MODULE) && defined(CONFIG_HWMON_MODULE)) 40#if defined(CONFIG_HWMON) || (defined(MODULE) && defined(CONFIG_HWMON_MODULE))
41static ssize_t
42nouveau_hwmon_show_temp(struct device *d, struct device_attribute *a, char *buf)
43{
44 struct drm_device *dev = dev_get_drvdata(d);
45 struct nouveau_drm *drm = nouveau_drm(dev);
46 struct nvkm_therm *therm = nvxx_therm(&drm->client.device);
47 int temp = nvkm_therm_temp_get(therm);
48
49 if (temp < 0)
50 return temp;
51
52 return snprintf(buf, PAGE_SIZE, "%d\n", temp * 1000);
53}
54static SENSOR_DEVICE_ATTR(temp1_input, S_IRUGO, nouveau_hwmon_show_temp,
55 NULL, 0);
56 41
57static ssize_t 42static ssize_t
58nouveau_hwmon_show_temp1_auto_point1_pwm(struct device *d, 43nouveau_hwmon_show_temp1_auto_point1_pwm(struct device *d,
@@ -60,7 +45,7 @@ nouveau_hwmon_show_temp1_auto_point1_pwm(struct device *d,
60{ 45{
61 return snprintf(buf, PAGE_SIZE, "%d\n", 100); 46 return snprintf(buf, PAGE_SIZE, "%d\n", 100);
62} 47}
63static SENSOR_DEVICE_ATTR(temp1_auto_point1_pwm, S_IRUGO, 48static SENSOR_DEVICE_ATTR(temp1_auto_point1_pwm, 0444,
64 nouveau_hwmon_show_temp1_auto_point1_pwm, NULL, 0); 49 nouveau_hwmon_show_temp1_auto_point1_pwm, NULL, 0);
65 50
66static ssize_t 51static ssize_t
@@ -92,7 +77,7 @@ nouveau_hwmon_set_temp1_auto_point1_temp(struct device *d,
92 77
93 return count; 78 return count;
94} 79}
95static SENSOR_DEVICE_ATTR(temp1_auto_point1_temp, S_IRUGO | S_IWUSR, 80static SENSOR_DEVICE_ATTR(temp1_auto_point1_temp, 0644,
96 nouveau_hwmon_temp1_auto_point1_temp, 81 nouveau_hwmon_temp1_auto_point1_temp,
97 nouveau_hwmon_set_temp1_auto_point1_temp, 0); 82 nouveau_hwmon_set_temp1_auto_point1_temp, 0);
98 83
@@ -125,572 +110,595 @@ nouveau_hwmon_set_temp1_auto_point1_temp_hyst(struct device *d,
125 110
126 return count; 111 return count;
127} 112}
128static SENSOR_DEVICE_ATTR(temp1_auto_point1_temp_hyst, S_IRUGO | S_IWUSR, 113static SENSOR_DEVICE_ATTR(temp1_auto_point1_temp_hyst, 0644,
129 nouveau_hwmon_temp1_auto_point1_temp_hyst, 114 nouveau_hwmon_temp1_auto_point1_temp_hyst,
130 nouveau_hwmon_set_temp1_auto_point1_temp_hyst, 0); 115 nouveau_hwmon_set_temp1_auto_point1_temp_hyst, 0);
131 116
132static ssize_t 117static ssize_t
133nouveau_hwmon_max_temp(struct device *d, struct device_attribute *a, char *buf) 118nouveau_hwmon_get_pwm1_max(struct device *d,
134{ 119 struct device_attribute *a, char *buf)
135 struct drm_device *dev = dev_get_drvdata(d);
136 struct nouveau_drm *drm = nouveau_drm(dev);
137 struct nvkm_therm *therm = nvxx_therm(&drm->client.device);
138
139 return snprintf(buf, PAGE_SIZE, "%d\n",
140 therm->attr_get(therm, NVKM_THERM_ATTR_THRS_DOWN_CLK) * 1000);
141}
142static ssize_t
143nouveau_hwmon_set_max_temp(struct device *d, struct device_attribute *a,
144 const char *buf, size_t count)
145{ 120{
146 struct drm_device *dev = dev_get_drvdata(d); 121 struct drm_device *dev = dev_get_drvdata(d);
147 struct nouveau_drm *drm = nouveau_drm(dev); 122 struct nouveau_drm *drm = nouveau_drm(dev);
148 struct nvkm_therm *therm = nvxx_therm(&drm->client.device); 123 struct nvkm_therm *therm = nvxx_therm(&drm->client.device);
149 long value; 124 int ret;
150
151 if (kstrtol(buf, 10, &value) == -EINVAL)
152 return count;
153 125
154 therm->attr_set(therm, NVKM_THERM_ATTR_THRS_DOWN_CLK, value / 1000); 126 ret = therm->attr_get(therm, NVKM_THERM_ATTR_FAN_MAX_DUTY);
127 if (ret < 0)
128 return ret;
155 129
156 return count; 130 return sprintf(buf, "%i\n", ret);
157} 131}
158static SENSOR_DEVICE_ATTR(temp1_max, S_IRUGO | S_IWUSR, nouveau_hwmon_max_temp,
159 nouveau_hwmon_set_max_temp,
160 0);
161 132
162static ssize_t 133static ssize_t
163nouveau_hwmon_max_temp_hyst(struct device *d, struct device_attribute *a, 134nouveau_hwmon_get_pwm1_min(struct device *d,
164 char *buf) 135 struct device_attribute *a, char *buf)
165{ 136{
166 struct drm_device *dev = dev_get_drvdata(d); 137 struct drm_device *dev = dev_get_drvdata(d);
167 struct nouveau_drm *drm = nouveau_drm(dev); 138 struct nouveau_drm *drm = nouveau_drm(dev);
168 struct nvkm_therm *therm = nvxx_therm(&drm->client.device); 139 struct nvkm_therm *therm = nvxx_therm(&drm->client.device);
140 int ret;
169 141
170 return snprintf(buf, PAGE_SIZE, "%d\n", 142 ret = therm->attr_get(therm, NVKM_THERM_ATTR_FAN_MIN_DUTY);
171 therm->attr_get(therm, NVKM_THERM_ATTR_THRS_DOWN_CLK_HYST) * 1000); 143 if (ret < 0)
144 return ret;
145
146 return sprintf(buf, "%i\n", ret);
172} 147}
148
173static ssize_t 149static ssize_t
174nouveau_hwmon_set_max_temp_hyst(struct device *d, struct device_attribute *a, 150nouveau_hwmon_set_pwm1_min(struct device *d, struct device_attribute *a,
175 const char *buf, size_t count) 151 const char *buf, size_t count)
176{ 152{
177 struct drm_device *dev = dev_get_drvdata(d); 153 struct drm_device *dev = dev_get_drvdata(d);
178 struct nouveau_drm *drm = nouveau_drm(dev); 154 struct nouveau_drm *drm = nouveau_drm(dev);
179 struct nvkm_therm *therm = nvxx_therm(&drm->client.device); 155 struct nvkm_therm *therm = nvxx_therm(&drm->client.device);
180 long value; 156 long value;
157 int ret;
181 158
182 if (kstrtol(buf, 10, &value) == -EINVAL) 159 if (kstrtol(buf, 10, &value) == -EINVAL)
183 return count; 160 return -EINVAL;
184 161
185 therm->attr_set(therm, NVKM_THERM_ATTR_THRS_DOWN_CLK_HYST, 162 ret = therm->attr_set(therm, NVKM_THERM_ATTR_FAN_MIN_DUTY, value);
186 value / 1000); 163 if (ret < 0)
164 return ret;
187 165
188 return count; 166 return count;
189} 167}
190static SENSOR_DEVICE_ATTR(temp1_max_hyst, S_IRUGO | S_IWUSR, 168static SENSOR_DEVICE_ATTR(pwm1_min, 0644,
191 nouveau_hwmon_max_temp_hyst, 169 nouveau_hwmon_get_pwm1_min,
192 nouveau_hwmon_set_max_temp_hyst, 0); 170 nouveau_hwmon_set_pwm1_min, 0);
193
194static ssize_t
195nouveau_hwmon_critical_temp(struct device *d, struct device_attribute *a,
196 char *buf)
197{
198 struct drm_device *dev = dev_get_drvdata(d);
199 struct nouveau_drm *drm = nouveau_drm(dev);
200 struct nvkm_therm *therm = nvxx_therm(&drm->client.device);
201 171
202 return snprintf(buf, PAGE_SIZE, "%d\n",
203 therm->attr_get(therm, NVKM_THERM_ATTR_THRS_CRITICAL) * 1000);
204}
205static ssize_t 172static ssize_t
206nouveau_hwmon_set_critical_temp(struct device *d, struct device_attribute *a, 173nouveau_hwmon_set_pwm1_max(struct device *d, struct device_attribute *a,
207 const char *buf, 174 const char *buf, size_t count)
208 size_t count)
209{ 175{
210 struct drm_device *dev = dev_get_drvdata(d); 176 struct drm_device *dev = dev_get_drvdata(d);
211 struct nouveau_drm *drm = nouveau_drm(dev); 177 struct nouveau_drm *drm = nouveau_drm(dev);
212 struct nvkm_therm *therm = nvxx_therm(&drm->client.device); 178 struct nvkm_therm *therm = nvxx_therm(&drm->client.device);
213 long value; 179 long value;
180 int ret;
214 181
215 if (kstrtol(buf, 10, &value) == -EINVAL) 182 if (kstrtol(buf, 10, &value) == -EINVAL)
216 return count; 183 return -EINVAL;
217 184
218 therm->attr_set(therm, NVKM_THERM_ATTR_THRS_CRITICAL, value / 1000); 185 ret = therm->attr_set(therm, NVKM_THERM_ATTR_FAN_MAX_DUTY, value);
186 if (ret < 0)
187 return ret;
219 188
220 return count; 189 return count;
221} 190}
222static SENSOR_DEVICE_ATTR(temp1_crit, S_IRUGO | S_IWUSR, 191static SENSOR_DEVICE_ATTR(pwm1_max, 0644,
223 nouveau_hwmon_critical_temp, 192 nouveau_hwmon_get_pwm1_max,
224 nouveau_hwmon_set_critical_temp, 193 nouveau_hwmon_set_pwm1_max, 0);
225 0);
226 194
227static ssize_t 195static struct attribute *pwm_fan_sensor_attrs[] = {
228nouveau_hwmon_critical_temp_hyst(struct device *d, struct device_attribute *a, 196 &sensor_dev_attr_pwm1_min.dev_attr.attr,
229 char *buf) 197 &sensor_dev_attr_pwm1_max.dev_attr.attr,
230{ 198 NULL
231 struct drm_device *dev = dev_get_drvdata(d); 199};
232 struct nouveau_drm *drm = nouveau_drm(dev); 200static const struct attribute_group pwm_fan_sensor_group = {
233 struct nvkm_therm *therm = nvxx_therm(&drm->client.device); 201 .attrs = pwm_fan_sensor_attrs,
202};
234 203
235 return snprintf(buf, PAGE_SIZE, "%d\n", 204static struct attribute *temp1_auto_point_sensor_attrs[] = {
236 therm->attr_get(therm, NVKM_THERM_ATTR_THRS_CRITICAL_HYST) * 1000); 205 &sensor_dev_attr_temp1_auto_point1_pwm.dev_attr.attr,
237} 206 &sensor_dev_attr_temp1_auto_point1_temp.dev_attr.attr,
238static ssize_t 207 &sensor_dev_attr_temp1_auto_point1_temp_hyst.dev_attr.attr,
239nouveau_hwmon_set_critical_temp_hyst(struct device *d, 208 NULL
240 struct device_attribute *a, 209};
241 const char *buf, 210static const struct attribute_group temp1_auto_point_sensor_group = {
242 size_t count) 211 .attrs = temp1_auto_point_sensor_attrs,
243{ 212};
244 struct drm_device *dev = dev_get_drvdata(d);
245 struct nouveau_drm *drm = nouveau_drm(dev);
246 struct nvkm_therm *therm = nvxx_therm(&drm->client.device);
247 long value;
248 213
249 if (kstrtol(buf, 10, &value) == -EINVAL) 214#define N_ATTR_GROUPS 3
250 return count;
251 215
252 therm->attr_set(therm, NVKM_THERM_ATTR_THRS_CRITICAL_HYST, 216static const u32 nouveau_config_chip[] = {
253 value / 1000); 217 HWMON_C_UPDATE_INTERVAL,
218 0
219};
254 220
255 return count; 221static const u32 nouveau_config_in[] = {
256} 222 HWMON_I_INPUT | HWMON_I_MIN | HWMON_I_MAX | HWMON_I_LABEL,
257static SENSOR_DEVICE_ATTR(temp1_crit_hyst, S_IRUGO | S_IWUSR, 223 0
258 nouveau_hwmon_critical_temp_hyst, 224};
259 nouveau_hwmon_set_critical_temp_hyst, 0);
260static ssize_t
261nouveau_hwmon_emergency_temp(struct device *d, struct device_attribute *a,
262 char *buf)
263{
264 struct drm_device *dev = dev_get_drvdata(d);
265 struct nouveau_drm *drm = nouveau_drm(dev);
266 struct nvkm_therm *therm = nvxx_therm(&drm->client.device);
267 225
268 return snprintf(buf, PAGE_SIZE, "%d\n", 226static const u32 nouveau_config_temp[] = {
269 therm->attr_get(therm, NVKM_THERM_ATTR_THRS_SHUTDOWN) * 1000); 227 HWMON_T_INPUT | HWMON_T_MAX | HWMON_T_MAX_HYST |
270} 228 HWMON_T_CRIT | HWMON_T_CRIT_HYST | HWMON_T_EMERGENCY |
271static ssize_t 229 HWMON_T_EMERGENCY_HYST,
272nouveau_hwmon_set_emergency_temp(struct device *d, struct device_attribute *a, 230 0
273 const char *buf, 231};
274 size_t count)
275{
276 struct drm_device *dev = dev_get_drvdata(d);
277 struct nouveau_drm *drm = nouveau_drm(dev);
278 struct nvkm_therm *therm = nvxx_therm(&drm->client.device);
279 long value;
280 232
281 if (kstrtol(buf, 10, &value) == -EINVAL) 233static const u32 nouveau_config_fan[] = {
282 return count; 234 HWMON_F_INPUT,
235 0
236};
283 237
284 therm->attr_set(therm, NVKM_THERM_ATTR_THRS_SHUTDOWN, value / 1000); 238static const u32 nouveau_config_pwm[] = {
239 HWMON_PWM_INPUT | HWMON_PWM_ENABLE,
240 0
241};
285 242
286 return count; 243static const u32 nouveau_config_power[] = {
287} 244 HWMON_P_INPUT | HWMON_P_CAP_MAX | HWMON_P_CRIT,
288static SENSOR_DEVICE_ATTR(temp1_emergency, S_IRUGO | S_IWUSR, 245 0
289 nouveau_hwmon_emergency_temp, 246};
290 nouveau_hwmon_set_emergency_temp,
291 0);
292 247
293static ssize_t 248static const struct hwmon_channel_info nouveau_chip = {
294nouveau_hwmon_emergency_temp_hyst(struct device *d, struct device_attribute *a, 249 .type = hwmon_chip,
295 char *buf) 250 .config = nouveau_config_chip,
296{ 251};
297 struct drm_device *dev = dev_get_drvdata(d);
298 struct nouveau_drm *drm = nouveau_drm(dev);
299 struct nvkm_therm *therm = nvxx_therm(&drm->client.device);
300 252
301 return snprintf(buf, PAGE_SIZE, "%d\n", 253static const struct hwmon_channel_info nouveau_temp = {
302 therm->attr_get(therm, NVKM_THERM_ATTR_THRS_SHUTDOWN_HYST) * 1000); 254 .type = hwmon_temp,
303} 255 .config = nouveau_config_temp,
304static ssize_t 256};
305nouveau_hwmon_set_emergency_temp_hyst(struct device *d,
306 struct device_attribute *a,
307 const char *buf,
308 size_t count)
309{
310 struct drm_device *dev = dev_get_drvdata(d);
311 struct nouveau_drm *drm = nouveau_drm(dev);
312 struct nvkm_therm *therm = nvxx_therm(&drm->client.device);
313 long value;
314 257
315 if (kstrtol(buf, 10, &value) == -EINVAL) 258static const struct hwmon_channel_info nouveau_fan = {
316 return count; 259 .type = hwmon_fan,
260 .config = nouveau_config_fan,
261};
317 262
318 therm->attr_set(therm, NVKM_THERM_ATTR_THRS_SHUTDOWN_HYST, 263static const struct hwmon_channel_info nouveau_in = {
319 value / 1000); 264 .type = hwmon_in,
265 .config = nouveau_config_in,
266};
320 267
321 return count; 268static const struct hwmon_channel_info nouveau_pwm = {
322} 269 .type = hwmon_pwm,
323static SENSOR_DEVICE_ATTR(temp1_emergency_hyst, S_IRUGO | S_IWUSR, 270 .config = nouveau_config_pwm,
324 nouveau_hwmon_emergency_temp_hyst, 271};
325 nouveau_hwmon_set_emergency_temp_hyst, 272
326 0); 273static const struct hwmon_channel_info nouveau_power = {
327 274 .type = hwmon_power,
328static ssize_t nouveau_hwmon_show_name(struct device *dev, 275 .config = nouveau_config_power,
329 struct device_attribute *attr, 276};
330 char *buf) 277
278static const struct hwmon_channel_info *nouveau_info[] = {
279 &nouveau_chip,
280 &nouveau_temp,
281 &nouveau_fan,
282 &nouveau_in,
283 &nouveau_pwm,
284 &nouveau_power,
285 NULL
286};
287
288static umode_t
289nouveau_chip_is_visible(const void *data, u32 attr, int channel)
331{ 290{
332 return sprintf(buf, "nouveau\n"); 291 switch (attr) {
292 case hwmon_chip_update_interval:
293 return 0444;
294 default:
295 return 0;
296 }
333} 297}
334static SENSOR_DEVICE_ATTR(name, S_IRUGO, nouveau_hwmon_show_name, NULL, 0);
335 298
336static ssize_t nouveau_hwmon_show_update_rate(struct device *dev, 299static umode_t
337 struct device_attribute *attr, 300nouveau_power_is_visible(const void *data, u32 attr, int channel)
338 char *buf)
339{ 301{
340 return sprintf(buf, "1000\n"); 302 struct nouveau_drm *drm = nouveau_drm((struct drm_device *)data);
303 struct nvkm_iccsense *iccsense = nvxx_iccsense(&drm->client.device);
304
305 if (!iccsense || !iccsense->data_valid || list_empty(&iccsense->rails))
306 return 0;
307
308 switch (attr) {
309 case hwmon_power_input:
310 return 0444;
311 case hwmon_power_max:
312 if (iccsense->power_w_max)
313 return 0444;
314 return 0;
315 case hwmon_power_crit:
316 if (iccsense->power_w_crit)
317 return 0444;
318 return 0;
319 default:
320 return 0;
321 }
341} 322}
342static SENSOR_DEVICE_ATTR(update_rate, S_IRUGO,
343 nouveau_hwmon_show_update_rate,
344 NULL, 0);
345 323
346static ssize_t 324static umode_t
347nouveau_hwmon_show_fan1_input(struct device *d, struct device_attribute *attr, 325nouveau_temp_is_visible(const void *data, u32 attr, int channel)
348 char *buf)
349{ 326{
350 struct drm_device *dev = dev_get_drvdata(d); 327 struct nouveau_drm *drm = nouveau_drm((struct drm_device *)data);
351 struct nouveau_drm *drm = nouveau_drm(dev);
352 struct nvkm_therm *therm = nvxx_therm(&drm->client.device); 328 struct nvkm_therm *therm = nvxx_therm(&drm->client.device);
353 329
354 return snprintf(buf, PAGE_SIZE, "%d\n", nvkm_therm_fan_sense(therm)); 330 if (therm && therm->attr_get && nvkm_therm_temp_get(therm) < 0)
331 return 0;
332
333 switch (attr) {
334 case hwmon_temp_input:
335 return 0444;
336 case hwmon_temp_max:
337 case hwmon_temp_max_hyst:
338 case hwmon_temp_crit:
339 case hwmon_temp_crit_hyst:
340 case hwmon_temp_emergency:
341 case hwmon_temp_emergency_hyst:
342 return 0644;
343 default:
344 return 0;
345 }
355} 346}
356static SENSOR_DEVICE_ATTR(fan1_input, S_IRUGO, nouveau_hwmon_show_fan1_input,
357 NULL, 0);
358 347
359 static ssize_t 348static umode_t
360nouveau_hwmon_get_pwm1_enable(struct device *d, 349nouveau_pwm_is_visible(const void *data, u32 attr, int channel)
361 struct device_attribute *a, char *buf)
362{ 350{
363 struct drm_device *dev = dev_get_drvdata(d); 351 struct nouveau_drm *drm = nouveau_drm((struct drm_device *)data);
364 struct nouveau_drm *drm = nouveau_drm(dev);
365 struct nvkm_therm *therm = nvxx_therm(&drm->client.device); 352 struct nvkm_therm *therm = nvxx_therm(&drm->client.device);
366 int ret;
367 353
368 ret = therm->attr_get(therm, NVKM_THERM_ATTR_FAN_MODE); 354 if (therm && therm->attr_get && therm->fan_get &&
369 if (ret < 0) 355 therm->fan_get(therm) < 0)
370 return ret; 356 return 0;
371 357
372 return sprintf(buf, "%i\n", ret); 358 switch (attr) {
359 case hwmon_pwm_enable:
360 case hwmon_pwm_input:
361 return 0644;
362 default:
363 return 0;
364 }
373} 365}
374 366
375static ssize_t 367static umode_t
376nouveau_hwmon_set_pwm1_enable(struct device *d, struct device_attribute *a, 368nouveau_input_is_visible(const void *data, u32 attr, int channel)
377 const char *buf, size_t count)
378{ 369{
379 struct drm_device *dev = dev_get_drvdata(d); 370 struct nouveau_drm *drm = nouveau_drm((struct drm_device *)data);
380 struct nouveau_drm *drm = nouveau_drm(dev); 371 struct nvkm_volt *volt = nvxx_volt(&drm->client.device);
381 struct nvkm_therm *therm = nvxx_therm(&drm->client.device);
382 long value;
383 int ret;
384
385 ret = kstrtol(buf, 10, &value);
386 if (ret)
387 return ret;
388 372
389 ret = therm->attr_set(therm, NVKM_THERM_ATTR_FAN_MODE, value); 373 if (!volt || nvkm_volt_get(volt) < 0)
390 if (ret) 374 return 0;
391 return ret; 375
392 else 376 switch (attr) {
393 return count; 377 case hwmon_in_input:
378 case hwmon_in_label:
379 case hwmon_in_min:
380 case hwmon_in_max:
381 return 0444;
382 default:
383 return 0;
384 }
394} 385}
395static SENSOR_DEVICE_ATTR(pwm1_enable, S_IRUGO | S_IWUSR,
396 nouveau_hwmon_get_pwm1_enable,
397 nouveau_hwmon_set_pwm1_enable, 0);
398 386
399static ssize_t 387static umode_t
400nouveau_hwmon_get_pwm1(struct device *d, struct device_attribute *a, char *buf) 388nouveau_fan_is_visible(const void *data, u32 attr, int channel)
401{ 389{
402 struct drm_device *dev = dev_get_drvdata(d); 390 struct nouveau_drm *drm = nouveau_drm((struct drm_device *)data);
403 struct nouveau_drm *drm = nouveau_drm(dev);
404 struct nvkm_therm *therm = nvxx_therm(&drm->client.device); 391 struct nvkm_therm *therm = nvxx_therm(&drm->client.device);
405 int ret;
406 392
407 ret = therm->fan_get(therm); 393 if (!therm || !therm->attr_get || nvkm_therm_fan_sense(therm) < 0)
408 if (ret < 0) 394 return 0;
409 return ret;
410 395
411 return sprintf(buf, "%i\n", ret); 396 switch (attr) {
397 case hwmon_fan_input:
398 return 0444;
399 default:
400 return 0;
401 }
412} 402}
413 403
414static ssize_t 404static int
415nouveau_hwmon_set_pwm1(struct device *d, struct device_attribute *a, 405nouveau_chip_read(struct device *dev, u32 attr, int channel, long *val)
416 const char *buf, size_t count)
417{ 406{
418 struct drm_device *dev = dev_get_drvdata(d); 407 switch (attr) {
419 struct nouveau_drm *drm = nouveau_drm(dev); 408 case hwmon_chip_update_interval:
420 struct nvkm_therm *therm = nvxx_therm(&drm->client.device); 409 *val = 1000;
421 int ret = -ENODEV; 410 break;
422 long value; 411 default:
423 412 return -EOPNOTSUPP;
424 if (kstrtol(buf, 10, &value) == -EINVAL) 413 }
425 return -EINVAL;
426
427 ret = therm->fan_set(therm, value);
428 if (ret)
429 return ret;
430 414
431 return count; 415 return 0;
432} 416}
433 417
434static SENSOR_DEVICE_ATTR(pwm1, S_IRUGO | S_IWUSR, 418static int
435 nouveau_hwmon_get_pwm1, 419nouveau_temp_read(struct device *dev, u32 attr, int channel, long *val)
436 nouveau_hwmon_set_pwm1, 0);
437
438static ssize_t
439nouveau_hwmon_get_pwm1_min(struct device *d,
440 struct device_attribute *a, char *buf)
441{ 420{
442 struct drm_device *dev = dev_get_drvdata(d); 421 struct drm_device *drm_dev = dev_get_drvdata(dev);
443 struct nouveau_drm *drm = nouveau_drm(dev); 422 struct nouveau_drm *drm = nouveau_drm(drm_dev);
444 struct nvkm_therm *therm = nvxx_therm(&drm->client.device); 423 struct nvkm_therm *therm = nvxx_therm(&drm->client.device);
445 int ret; 424 int ret;
446 425
447 ret = therm->attr_get(therm, NVKM_THERM_ATTR_FAN_MIN_DUTY); 426 if (!therm || !therm->attr_get)
448 if (ret < 0) 427 return -EOPNOTSUPP;
449 return ret; 428
429 switch (attr) {
430 case hwmon_temp_input:
431 ret = nvkm_therm_temp_get(therm);
432 *val = ret < 0 ? ret : (ret * 1000);
433 break;
434 case hwmon_temp_max:
435 *val = therm->attr_get(therm, NVKM_THERM_ATTR_THRS_DOWN_CLK)
436 * 1000;
437 break;
438 case hwmon_temp_max_hyst:
439 *val = therm->attr_get(therm, NVKM_THERM_ATTR_THRS_DOWN_CLK_HYST)
440 * 1000;
441 break;
442 case hwmon_temp_crit:
443 *val = therm->attr_get(therm, NVKM_THERM_ATTR_THRS_CRITICAL)
444 * 1000;
445 break;
446 case hwmon_temp_crit_hyst:
447 *val = therm->attr_get(therm, NVKM_THERM_ATTR_THRS_CRITICAL_HYST)
448 * 1000;
449 break;
450 case hwmon_temp_emergency:
451 *val = therm->attr_get(therm, NVKM_THERM_ATTR_THRS_SHUTDOWN)
452 * 1000;
453 break;
454 case hwmon_temp_emergency_hyst:
455 *val = therm->attr_get(therm, NVKM_THERM_ATTR_THRS_SHUTDOWN_HYST)
456 * 1000;
457 break;
458 default:
459 return -EOPNOTSUPP;
460 }
450 461
451 return sprintf(buf, "%i\n", ret); 462 return 0;
452} 463}
453 464
454static ssize_t 465static int
455nouveau_hwmon_set_pwm1_min(struct device *d, struct device_attribute *a, 466nouveau_fan_read(struct device *dev, u32 attr, int channel, long *val)
456 const char *buf, size_t count)
457{ 467{
458 struct drm_device *dev = dev_get_drvdata(d); 468 struct drm_device *drm_dev = dev_get_drvdata(dev);
459 struct nouveau_drm *drm = nouveau_drm(dev); 469 struct nouveau_drm *drm = nouveau_drm(drm_dev);
460 struct nvkm_therm *therm = nvxx_therm(&drm->client.device); 470 struct nvkm_therm *therm = nvxx_therm(&drm->client.device);
461 long value;
462 int ret;
463 471
464 if (kstrtol(buf, 10, &value) == -EINVAL) 472 if (!therm)
465 return -EINVAL; 473 return -EOPNOTSUPP;
466 474
467 ret = therm->attr_set(therm, NVKM_THERM_ATTR_FAN_MIN_DUTY, value); 475 switch (attr) {
468 if (ret < 0) 476 case hwmon_fan_input:
469 return ret; 477 *val = nvkm_therm_fan_sense(therm);
478 break;
479 default:
480 return -EOPNOTSUPP;
481 }
470 482
471 return count; 483 return 0;
472} 484}
473 485
474static SENSOR_DEVICE_ATTR(pwm1_min, S_IRUGO | S_IWUSR, 486static int
475 nouveau_hwmon_get_pwm1_min, 487nouveau_in_read(struct device *dev, u32 attr, int channel, long *val)
476 nouveau_hwmon_set_pwm1_min, 0);
477
478static ssize_t
479nouveau_hwmon_get_pwm1_max(struct device *d,
480 struct device_attribute *a, char *buf)
481{ 488{
482 struct drm_device *dev = dev_get_drvdata(d); 489 struct drm_device *drm_dev = dev_get_drvdata(dev);
483 struct nouveau_drm *drm = nouveau_drm(dev); 490 struct nouveau_drm *drm = nouveau_drm(drm_dev);
484 struct nvkm_therm *therm = nvxx_therm(&drm->client.device); 491 struct nvkm_volt *volt = nvxx_volt(&drm->client.device);
485 int ret; 492 int ret;
486 493
487 ret = therm->attr_get(therm, NVKM_THERM_ATTR_FAN_MAX_DUTY); 494 if (!volt)
488 if (ret < 0) 495 return -EOPNOTSUPP;
489 return ret; 496
497 switch (attr) {
498 case hwmon_in_input:
499 ret = nvkm_volt_get(volt);
500 *val = ret < 0 ? ret : (ret / 1000);
501 break;
502 case hwmon_in_min:
503 *val = volt->min_uv > 0 ? (volt->min_uv / 1000) : -ENODEV;
504 break;
505 case hwmon_in_max:
506 *val = volt->max_uv > 0 ? (volt->max_uv / 1000) : -ENODEV;
507 break;
508 default:
509 return -EOPNOTSUPP;
510 }
490 511
491 return sprintf(buf, "%i\n", ret); 512 return 0;
492} 513}
493 514
494static ssize_t 515static int
495nouveau_hwmon_set_pwm1_max(struct device *d, struct device_attribute *a, 516nouveau_pwm_read(struct device *dev, u32 attr, int channel, long *val)
496 const char *buf, size_t count)
497{ 517{
498 struct drm_device *dev = dev_get_drvdata(d); 518 struct drm_device *drm_dev = dev_get_drvdata(dev);
499 struct nouveau_drm *drm = nouveau_drm(dev); 519 struct nouveau_drm *drm = nouveau_drm(drm_dev);
500 struct nvkm_therm *therm = nvxx_therm(&drm->client.device); 520 struct nvkm_therm *therm = nvxx_therm(&drm->client.device);
501 long value;
502 int ret;
503 521
504 if (kstrtol(buf, 10, &value) == -EINVAL) 522 if (!therm || !therm->attr_get || !therm->fan_get)
505 return -EINVAL; 523 return -EOPNOTSUPP;
506 524
507 ret = therm->attr_set(therm, NVKM_THERM_ATTR_FAN_MAX_DUTY, value); 525 switch (attr) {
508 if (ret < 0) 526 case hwmon_pwm_enable:
509 return ret; 527 *val = therm->attr_get(therm, NVKM_THERM_ATTR_FAN_MODE);
528 break;
529 case hwmon_pwm_input:
530 *val = therm->fan_get(therm);
531 break;
532 default:
533 return -EOPNOTSUPP;
534 }
510 535
511 return count; 536 return 0;
512} 537}
513 538
514static SENSOR_DEVICE_ATTR(pwm1_max, S_IRUGO | S_IWUSR, 539static int
515 nouveau_hwmon_get_pwm1_max, 540nouveau_power_read(struct device *dev, u32 attr, int channel, long *val)
516 nouveau_hwmon_set_pwm1_max, 0);
517
518static ssize_t
519nouveau_hwmon_get_in0_input(struct device *d,
520 struct device_attribute *a, char *buf)
521{ 541{
522 struct drm_device *dev = dev_get_drvdata(d); 542 struct drm_device *drm_dev = dev_get_drvdata(dev);
523 struct nouveau_drm *drm = nouveau_drm(dev); 543 struct nouveau_drm *drm = nouveau_drm(drm_dev);
524 struct nvkm_volt *volt = nvxx_volt(&drm->client.device); 544 struct nvkm_iccsense *iccsense = nvxx_iccsense(&drm->client.device);
525 int ret;
526 545
527 ret = nvkm_volt_get(volt); 546 if (!iccsense)
528 if (ret < 0) 547 return -EOPNOTSUPP;
529 return ret; 548
549 switch (attr) {
550 case hwmon_power_input:
551 *val = nvkm_iccsense_read_all(iccsense);
552 break;
553 case hwmon_power_max:
554 *val = iccsense->power_w_max;
555 break;
556 case hwmon_power_crit:
557 *val = iccsense->power_w_crit;
558 break;
559 default:
560 return -EOPNOTSUPP;
561 }
530 562
531 return sprintf(buf, "%i\n", ret / 1000); 563 return 0;
532} 564}
533 565
534static SENSOR_DEVICE_ATTR(in0_input, S_IRUGO, 566static int
535 nouveau_hwmon_get_in0_input, NULL, 0); 567nouveau_temp_write(struct device *dev, u32 attr, int channel, long val)
536
537static ssize_t
538nouveau_hwmon_get_in0_min(struct device *d,
539 struct device_attribute *a, char *buf)
540{ 568{
541 struct drm_device *dev = dev_get_drvdata(d); 569 struct drm_device *drm_dev = dev_get_drvdata(dev);
542 struct nouveau_drm *drm = nouveau_drm(dev); 570 struct nouveau_drm *drm = nouveau_drm(drm_dev);
543 struct nvkm_volt *volt = nvxx_volt(&drm->client.device); 571 struct nvkm_therm *therm = nvxx_therm(&drm->client.device);
544
545 if (!volt || !volt->min_uv)
546 return -ENODEV;
547 572
548 return sprintf(buf, "%i\n", volt->min_uv / 1000); 573 if (!therm || !therm->attr_set)
574 return -EOPNOTSUPP;
575
576 switch (attr) {
577 case hwmon_temp_max:
578 return therm->attr_set(therm, NVKM_THERM_ATTR_THRS_DOWN_CLK,
579 val / 1000);
580 case hwmon_temp_max_hyst:
581 return therm->attr_set(therm, NVKM_THERM_ATTR_THRS_DOWN_CLK_HYST,
582 val / 1000);
583 case hwmon_temp_crit:
584 return therm->attr_set(therm, NVKM_THERM_ATTR_THRS_CRITICAL,
585 val / 1000);
586 case hwmon_temp_crit_hyst:
587 return therm->attr_set(therm, NVKM_THERM_ATTR_THRS_CRITICAL_HYST,
588 val / 1000);
589 case hwmon_temp_emergency:
590 return therm->attr_set(therm, NVKM_THERM_ATTR_THRS_SHUTDOWN,
591 val / 1000);
592 case hwmon_temp_emergency_hyst:
593 return therm->attr_set(therm, NVKM_THERM_ATTR_THRS_SHUTDOWN_HYST,
594 val / 1000);
595 default:
596 return -EOPNOTSUPP;
597 }
549} 598}
550 599
551static SENSOR_DEVICE_ATTR(in0_min, S_IRUGO, 600static int
552 nouveau_hwmon_get_in0_min, NULL, 0); 601nouveau_pwm_write(struct device *dev, u32 attr, int channel, long val)
553
554static ssize_t
555nouveau_hwmon_get_in0_max(struct device *d,
556 struct device_attribute *a, char *buf)
557{ 602{
558 struct drm_device *dev = dev_get_drvdata(d); 603 struct drm_device *drm_dev = dev_get_drvdata(dev);
559 struct nouveau_drm *drm = nouveau_drm(dev); 604 struct nouveau_drm *drm = nouveau_drm(drm_dev);
560 struct nvkm_volt *volt = nvxx_volt(&drm->client.device); 605 struct nvkm_therm *therm = nvxx_therm(&drm->client.device);
561 606
562 if (!volt || !volt->max_uv) 607 if (!therm || !therm->attr_set)
563 return -ENODEV; 608 return -EOPNOTSUPP;
564 609
565 return sprintf(buf, "%i\n", volt->max_uv / 1000); 610 switch (attr) {
611 case hwmon_pwm_input:
612 return therm->fan_set(therm, val);
613 case hwmon_pwm_enable:
614 return therm->attr_set(therm, NVKM_THERM_ATTR_FAN_MODE, val);
615 default:
616 return -EOPNOTSUPP;
617 }
566} 618}
567 619
568static SENSOR_DEVICE_ATTR(in0_max, S_IRUGO, 620static umode_t
569 nouveau_hwmon_get_in0_max, NULL, 0); 621nouveau_is_visible(const void *data, enum hwmon_sensor_types type, u32 attr,
570 622 int channel)
571static ssize_t 623{
572nouveau_hwmon_get_in0_label(struct device *d, 624 switch (type) {
573 struct device_attribute *a, char *buf) 625 case hwmon_chip:
574{ 626 return nouveau_chip_is_visible(data, attr, channel);
575 return sprintf(buf, "GPU core\n"); 627 case hwmon_temp:
628 return nouveau_temp_is_visible(data, attr, channel);
629 case hwmon_fan:
630 return nouveau_fan_is_visible(data, attr, channel);
631 case hwmon_in:
632 return nouveau_input_is_visible(data, attr, channel);
633 case hwmon_pwm:
634 return nouveau_pwm_is_visible(data, attr, channel);
635 case hwmon_power:
636 return nouveau_power_is_visible(data, attr, channel);
637 default:
638 return 0;
639 }
576} 640}
577 641
578static SENSOR_DEVICE_ATTR(in0_label, S_IRUGO, 642static const char input_label[] = "GPU core";
579 nouveau_hwmon_get_in0_label, NULL, 0);
580 643
581static ssize_t 644static int
582nouveau_hwmon_get_power1_input(struct device *d, struct device_attribute *a, 645nouveau_read_string(struct device *dev, enum hwmon_sensor_types type, u32 attr,
583 char *buf) 646 int channel, const char **buf)
584{ 647{
585 struct drm_device *dev = dev_get_drvdata(d); 648 if (type == hwmon_in && attr == hwmon_in_label) {
586 struct nouveau_drm *drm = nouveau_drm(dev); 649 *buf = input_label;
587 struct nvkm_iccsense *iccsense = nvxx_iccsense(&drm->client.device); 650 return 0;
588 int result = nvkm_iccsense_read_all(iccsense); 651 }
589
590 if (result < 0)
591 return result;
592
593 return sprintf(buf, "%i\n", result);
594}
595
596static SENSOR_DEVICE_ATTR(power1_input, S_IRUGO,
597 nouveau_hwmon_get_power1_input, NULL, 0);
598 652
599static ssize_t 653 return -EOPNOTSUPP;
600nouveau_hwmon_get_power1_max(struct device *d, struct device_attribute *a, 654}
601 char *buf) 655
602{ 656static int
603 struct drm_device *dev = dev_get_drvdata(d); 657nouveau_read(struct device *dev, enum hwmon_sensor_types type, u32 attr,
604 struct nouveau_drm *drm = nouveau_drm(dev); 658 int channel, long *val)
605 struct nvkm_iccsense *iccsense = nvxx_iccsense(&drm->client.device); 659{
606 return sprintf(buf, "%i\n", iccsense->power_w_max); 660 switch (type) {
661 case hwmon_chip:
662 return nouveau_chip_read(dev, attr, channel, val);
663 case hwmon_temp:
664 return nouveau_temp_read(dev, attr, channel, val);
665 case hwmon_fan:
666 return nouveau_fan_read(dev, attr, channel, val);
667 case hwmon_in:
668 return nouveau_in_read(dev, attr, channel, val);
669 case hwmon_pwm:
670 return nouveau_pwm_read(dev, attr, channel, val);
671 case hwmon_power:
672 return nouveau_power_read(dev, attr, channel, val);
673 default:
674 return -EOPNOTSUPP;
675 }
607} 676}
608 677
609static SENSOR_DEVICE_ATTR(power1_max, S_IRUGO, 678static int
610 nouveau_hwmon_get_power1_max, NULL, 0); 679nouveau_write(struct device *dev, enum hwmon_sensor_types type, u32 attr,
611 680 int channel, long val)
612static ssize_t
613nouveau_hwmon_get_power1_crit(struct device *d, struct device_attribute *a,
614 char *buf)
615{ 681{
616 struct drm_device *dev = dev_get_drvdata(d); 682 switch (type) {
617 struct nouveau_drm *drm = nouveau_drm(dev); 683 case hwmon_temp:
618 struct nvkm_iccsense *iccsense = nvxx_iccsense(&drm->client.device); 684 return nouveau_temp_write(dev, attr, channel, val);
619 return sprintf(buf, "%i\n", iccsense->power_w_crit); 685 case hwmon_pwm:
686 return nouveau_pwm_write(dev, attr, channel, val);
687 default:
688 return -EOPNOTSUPP;
689 }
620} 690}
621 691
622static SENSOR_DEVICE_ATTR(power1_crit, S_IRUGO, 692static const struct hwmon_ops nouveau_hwmon_ops = {
623 nouveau_hwmon_get_power1_crit, NULL, 0); 693 .is_visible = nouveau_is_visible,
624 694 .read = nouveau_read,
625static struct attribute *hwmon_default_attributes[] = { 695 .read_string = nouveau_read_string,
626 &sensor_dev_attr_name.dev_attr.attr, 696 .write = nouveau_write,
627 &sensor_dev_attr_update_rate.dev_attr.attr,
628 NULL
629};
630static struct attribute *hwmon_temp_attributes[] = {
631 &sensor_dev_attr_temp1_input.dev_attr.attr,
632 &sensor_dev_attr_temp1_auto_point1_pwm.dev_attr.attr,
633 &sensor_dev_attr_temp1_auto_point1_temp.dev_attr.attr,
634 &sensor_dev_attr_temp1_auto_point1_temp_hyst.dev_attr.attr,
635 &sensor_dev_attr_temp1_max.dev_attr.attr,
636 &sensor_dev_attr_temp1_max_hyst.dev_attr.attr,
637 &sensor_dev_attr_temp1_crit.dev_attr.attr,
638 &sensor_dev_attr_temp1_crit_hyst.dev_attr.attr,
639 &sensor_dev_attr_temp1_emergency.dev_attr.attr,
640 &sensor_dev_attr_temp1_emergency_hyst.dev_attr.attr,
641 NULL
642};
643static struct attribute *hwmon_fan_rpm_attributes[] = {
644 &sensor_dev_attr_fan1_input.dev_attr.attr,
645 NULL
646};
647static struct attribute *hwmon_pwm_fan_attributes[] = {
648 &sensor_dev_attr_pwm1_enable.dev_attr.attr,
649 &sensor_dev_attr_pwm1.dev_attr.attr,
650 &sensor_dev_attr_pwm1_min.dev_attr.attr,
651 &sensor_dev_attr_pwm1_max.dev_attr.attr,
652 NULL
653};
654
655static struct attribute *hwmon_in0_attributes[] = {
656 &sensor_dev_attr_in0_input.dev_attr.attr,
657 &sensor_dev_attr_in0_min.dev_attr.attr,
658 &sensor_dev_attr_in0_max.dev_attr.attr,
659 &sensor_dev_attr_in0_label.dev_attr.attr,
660 NULL
661}; 697};
662 698
663static struct attribute *hwmon_power_attributes[] = { 699static const struct hwmon_chip_info nouveau_chip_info = {
664 &sensor_dev_attr_power1_input.dev_attr.attr, 700 .ops = &nouveau_hwmon_ops,
665 NULL 701 .info = nouveau_info,
666};
667
668static struct attribute *hwmon_power_caps_attributes[] = {
669 &sensor_dev_attr_power1_max.dev_attr.attr,
670 &sensor_dev_attr_power1_crit.dev_attr.attr,
671 NULL
672};
673
674static const struct attribute_group hwmon_default_attrgroup = {
675 .attrs = hwmon_default_attributes,
676};
677static const struct attribute_group hwmon_temp_attrgroup = {
678 .attrs = hwmon_temp_attributes,
679};
680static const struct attribute_group hwmon_fan_rpm_attrgroup = {
681 .attrs = hwmon_fan_rpm_attributes,
682};
683static const struct attribute_group hwmon_pwm_fan_attrgroup = {
684 .attrs = hwmon_pwm_fan_attributes,
685};
686static const struct attribute_group hwmon_in0_attrgroup = {
687 .attrs = hwmon_in0_attributes,
688};
689static const struct attribute_group hwmon_power_attrgroup = {
690 .attrs = hwmon_power_attributes,
691};
692static const struct attribute_group hwmon_power_caps_attrgroup = {
693 .attrs = hwmon_power_caps_attributes,
694}; 702};
695#endif 703#endif
696 704
@@ -700,90 +708,36 @@ nouveau_hwmon_init(struct drm_device *dev)
700#if defined(CONFIG_HWMON) || (defined(MODULE) && defined(CONFIG_HWMON_MODULE)) 708#if defined(CONFIG_HWMON) || (defined(MODULE) && defined(CONFIG_HWMON_MODULE))
701 struct nouveau_drm *drm = nouveau_drm(dev); 709 struct nouveau_drm *drm = nouveau_drm(dev);
702 struct nvkm_therm *therm = nvxx_therm(&drm->client.device); 710 struct nvkm_therm *therm = nvxx_therm(&drm->client.device);
703 struct nvkm_volt *volt = nvxx_volt(&drm->client.device); 711 const struct attribute_group *special_groups[N_ATTR_GROUPS];
704 struct nvkm_iccsense *iccsense = nvxx_iccsense(&drm->client.device);
705 struct nouveau_hwmon *hwmon; 712 struct nouveau_hwmon *hwmon;
706 struct device *hwmon_dev; 713 struct device *hwmon_dev;
707 int ret = 0; 714 int ret = 0;
715 int i = 0;
708 716
709 hwmon = drm->hwmon = kzalloc(sizeof(*hwmon), GFP_KERNEL); 717 hwmon = drm->hwmon = kzalloc(sizeof(*hwmon), GFP_KERNEL);
710 if (!hwmon) 718 if (!hwmon)
711 return -ENOMEM; 719 return -ENOMEM;
712 hwmon->dev = dev; 720 hwmon->dev = dev;
713 721
714 hwmon_dev = hwmon_device_register(dev->dev); 722 if (therm && therm->attr_get && therm->attr_set) {
723 if (nvkm_therm_temp_get(therm) >= 0)
724 special_groups[i++] = &temp1_auto_point_sensor_group;
725 if (therm->fan_get && therm->fan_get(therm) >= 0)
726 special_groups[i++] = &pwm_fan_sensor_group;
727 }
728
729 special_groups[i] = 0;
730 hwmon_dev = hwmon_device_register_with_info(dev->dev, "nouveau", dev,
731 &nouveau_chip_info,
732 special_groups);
715 if (IS_ERR(hwmon_dev)) { 733 if (IS_ERR(hwmon_dev)) {
716 ret = PTR_ERR(hwmon_dev); 734 ret = PTR_ERR(hwmon_dev);
717 NV_ERROR(drm, "Unable to register hwmon device: %d\n", ret); 735 NV_ERROR(drm, "Unable to register hwmon device: %d\n", ret);
718 return ret; 736 return ret;
719 } 737 }
720 dev_set_drvdata(hwmon_dev, dev);
721
722 /* set the default attributes */
723 ret = sysfs_create_group(&hwmon_dev->kobj, &hwmon_default_attrgroup);
724 if (ret)
725 goto error;
726
727 if (therm && therm->attr_get && therm->attr_set) {
728 /* if the card has a working thermal sensor */
729 if (nvkm_therm_temp_get(therm) >= 0) {
730 ret = sysfs_create_group(&hwmon_dev->kobj, &hwmon_temp_attrgroup);
731 if (ret)
732 goto error;
733 }
734
735 /* if the card has a pwm fan */
736 /*XXX: incorrect, need better detection for this, some boards have
737 * the gpio entries for pwm fan control even when there's no
738 * actual fan connected to it... therm table? */
739 if (therm->fan_get && therm->fan_get(therm) >= 0) {
740 ret = sysfs_create_group(&hwmon_dev->kobj,
741 &hwmon_pwm_fan_attrgroup);
742 if (ret)
743 goto error;
744 }
745 }
746
747 /* if the card can read the fan rpm */
748 if (therm && nvkm_therm_fan_sense(therm) >= 0) {
749 ret = sysfs_create_group(&hwmon_dev->kobj,
750 &hwmon_fan_rpm_attrgroup);
751 if (ret)
752 goto error;
753 }
754
755 if (volt && nvkm_volt_get(volt) >= 0) {
756 ret = sysfs_create_group(&hwmon_dev->kobj,
757 &hwmon_in0_attrgroup);
758
759 if (ret)
760 goto error;
761 }
762
763 if (iccsense && iccsense->data_valid && !list_empty(&iccsense->rails)) {
764 ret = sysfs_create_group(&hwmon_dev->kobj,
765 &hwmon_power_attrgroup);
766
767 if (ret)
768 goto error;
769
770 if (iccsense->power_w_max && iccsense->power_w_crit) {
771 ret = sysfs_create_group(&hwmon_dev->kobj,
772 &hwmon_power_caps_attrgroup);
773 if (ret)
774 goto error;
775 }
776 }
777 738
778 hwmon->hwmon = hwmon_dev; 739 hwmon->hwmon = hwmon_dev;
779
780 return 0; 740 return 0;
781
782error:
783 NV_ERROR(drm, "Unable to create some hwmon sysfs files: %d\n", ret);
784 hwmon_device_unregister(hwmon_dev);
785 hwmon->hwmon = NULL;
786 return ret;
787#else 741#else
788 return 0; 742 return 0;
789#endif 743#endif
@@ -795,17 +749,8 @@ nouveau_hwmon_fini(struct drm_device *dev)
795#if defined(CONFIG_HWMON) || (defined(MODULE) && defined(CONFIG_HWMON_MODULE)) 749#if defined(CONFIG_HWMON) || (defined(MODULE) && defined(CONFIG_HWMON_MODULE))
796 struct nouveau_hwmon *hwmon = nouveau_hwmon(dev); 750 struct nouveau_hwmon *hwmon = nouveau_hwmon(dev);
797 751
798 if (hwmon->hwmon) { 752 if (hwmon->hwmon)
799 sysfs_remove_group(&hwmon->hwmon->kobj, &hwmon_default_attrgroup);
800 sysfs_remove_group(&hwmon->hwmon->kobj, &hwmon_temp_attrgroup);
801 sysfs_remove_group(&hwmon->hwmon->kobj, &hwmon_pwm_fan_attrgroup);
802 sysfs_remove_group(&hwmon->hwmon->kobj, &hwmon_fan_rpm_attrgroup);
803 sysfs_remove_group(&hwmon->hwmon->kobj, &hwmon_in0_attrgroup);
804 sysfs_remove_group(&hwmon->hwmon->kobj, &hwmon_power_attrgroup);
805 sysfs_remove_group(&hwmon->hwmon->kobj, &hwmon_power_caps_attrgroup);
806
807 hwmon_device_unregister(hwmon->hwmon); 753 hwmon_device_unregister(hwmon->hwmon);
808 }
809 754
810 nouveau_drm(dev)->hwmon = NULL; 755 nouveau_drm(dev)->hwmon = NULL;
811 kfree(hwmon); 756 kfree(hwmon);
diff --git a/drivers/gpu/drm/nouveau/nouveau_vga.c b/drivers/gpu/drm/nouveau/nouveau_vga.c
index 02fe0efb9e16..48393a4f6331 100644
--- a/drivers/gpu/drm/nouveau/nouveau_vga.c
+++ b/drivers/gpu/drm/nouveau/nouveau_vga.c
@@ -111,6 +111,10 @@ nouveau_vga_fini(struct nouveau_drm *drm)
111 struct drm_device *dev = drm->dev; 111 struct drm_device *dev = drm->dev;
112 bool runtime = nouveau_pmops_runtime(); 112 bool runtime = nouveau_pmops_runtime();
113 113
114 /* only relevant for PCI devices */
115 if (!dev->pdev)
116 return;
117
114 vga_client_register(dev->pdev, NULL, NULL, NULL); 118 vga_client_register(dev->pdev, NULL, NULL, NULL);
115 119
116 if (pci_is_thunderbolt_attached(dev->pdev)) 120 if (pci_is_thunderbolt_attached(dev->pdev))
diff --git a/drivers/gpu/drm/nouveau/nv50_display.c b/drivers/gpu/drm/nouveau/nv50_display.c
index 775c10015dbe..e3132a2ce34d 100644
--- a/drivers/gpu/drm/nouveau/nv50_display.c
+++ b/drivers/gpu/drm/nouveau/nv50_display.c
@@ -23,6 +23,7 @@
23 */ 23 */
24 24
25#include <linux/dma-mapping.h> 25#include <linux/dma-mapping.h>
26#include <linux/hdmi.h>
26 27
27#include <drm/drmP.h> 28#include <drm/drmP.h>
28#include <drm/drm_atomic.h> 29#include <drm/drm_atomic.h>
@@ -31,6 +32,7 @@
31#include <drm/drm_dp_helper.h> 32#include <drm/drm_dp_helper.h>
32#include <drm/drm_fb_helper.h> 33#include <drm/drm_fb_helper.h>
33#include <drm/drm_plane_helper.h> 34#include <drm/drm_plane_helper.h>
35#include <drm/drm_edid.h>
34 36
35#include <nvif/class.h> 37#include <nvif/class.h>
36#include <nvif/cl0002.h> 38#include <nvif/cl0002.h>
@@ -1965,6 +1967,7 @@ nv50_head_atomic_check_view(struct nv50_head_atom *armh,
1965 struct drm_display_mode *umode = &asyh->state.mode; 1967 struct drm_display_mode *umode = &asyh->state.mode;
1966 int mode = asyc->scaler.mode; 1968 int mode = asyc->scaler.mode;
1967 struct edid *edid; 1969 struct edid *edid;
1970 int umode_vdisplay, omode_hdisplay, omode_vdisplay;
1968 1971
1969 if (connector->edid_blob_ptr) 1972 if (connector->edid_blob_ptr)
1970 edid = (struct edid *)connector->edid_blob_ptr->data; 1973 edid = (struct edid *)connector->edid_blob_ptr->data;
@@ -1979,12 +1982,18 @@ nv50_head_atomic_check_view(struct nv50_head_atom *armh,
1979 mode = DRM_MODE_SCALE_FULLSCREEN; 1982 mode = DRM_MODE_SCALE_FULLSCREEN;
1980 } 1983 }
1981 1984
1985 /* For the user-specified mode, we must ignore doublescan and
1986 * the like, but honor frame packing.
1987 */
1988 umode_vdisplay = umode->vdisplay;
1989 if ((umode->flags & DRM_MODE_FLAG_3D_MASK) == DRM_MODE_FLAG_3D_FRAME_PACKING)
1990 umode_vdisplay += umode->vtotal;
1982 asyh->view.iW = umode->hdisplay; 1991 asyh->view.iW = umode->hdisplay;
1983 asyh->view.iH = umode->vdisplay; 1992 asyh->view.iH = umode_vdisplay;
1984 asyh->view.oW = omode->hdisplay; 1993 /* For the output mode, we can just use the stock helper. */
1985 asyh->view.oH = omode->vdisplay; 1994 drm_mode_get_hv_timing(omode, &omode_hdisplay, &omode_vdisplay);
1986 if (omode->flags & DRM_MODE_FLAG_DBLSCAN) 1995 asyh->view.oW = omode_hdisplay;
1987 asyh->view.oH *= 2; 1996 asyh->view.oH = omode_vdisplay;
1988 1997
1989 /* Add overscan compensation if necessary, will keep the aspect 1998 /* Add overscan compensation if necessary, will keep the aspect
1990 * ratio the same as the backend mode unless overridden by the 1999 * ratio the same as the backend mode unless overridden by the
@@ -2014,7 +2023,7 @@ nv50_head_atomic_check_view(struct nv50_head_atom *armh,
2014 switch (mode) { 2023 switch (mode) {
2015 case DRM_MODE_SCALE_CENTER: 2024 case DRM_MODE_SCALE_CENTER:
2016 asyh->view.oW = min((u16)umode->hdisplay, asyh->view.oW); 2025 asyh->view.oW = min((u16)umode->hdisplay, asyh->view.oW);
2017 asyh->view.oH = min((u16)umode->vdisplay, asyh->view.oH); 2026 asyh->view.oH = min((u16)umode_vdisplay, asyh->view.oH);
2018 /* fall-through */ 2027 /* fall-through */
2019 case DRM_MODE_SCALE_ASPECT: 2028 case DRM_MODE_SCALE_ASPECT:
2020 if (asyh->view.oH < asyh->view.oW) { 2029 if (asyh->view.oH < asyh->view.oW) {
@@ -2036,34 +2045,37 @@ static void
2036nv50_head_atomic_check_mode(struct nv50_head *head, struct nv50_head_atom *asyh) 2045nv50_head_atomic_check_mode(struct nv50_head *head, struct nv50_head_atom *asyh)
2037{ 2046{
2038 struct drm_display_mode *mode = &asyh->state.adjusted_mode; 2047 struct drm_display_mode *mode = &asyh->state.adjusted_mode;
2039 u32 ilace = (mode->flags & DRM_MODE_FLAG_INTERLACE) ? 2 : 1;
2040 u32 vscan = (mode->flags & DRM_MODE_FLAG_DBLSCAN) ? 2 : 1;
2041 u32 hbackp = mode->htotal - mode->hsync_end;
2042 u32 vbackp = (mode->vtotal - mode->vsync_end) * vscan / ilace;
2043 u32 hfrontp = mode->hsync_start - mode->hdisplay;
2044 u32 vfrontp = (mode->vsync_start - mode->vdisplay) * vscan / ilace;
2045 u32 blankus;
2046 struct nv50_head_mode *m = &asyh->mode; 2048 struct nv50_head_mode *m = &asyh->mode;
2049 u32 blankus;
2047 2050
2048 m->h.active = mode->htotal; 2051 drm_mode_set_crtcinfo(mode, CRTC_INTERLACE_HALVE_V | CRTC_STEREO_DOUBLE);
2049 m->h.synce = mode->hsync_end - mode->hsync_start - 1;
2050 m->h.blanke = m->h.synce + hbackp;
2051 m->h.blanks = mode->htotal - hfrontp - 1;
2052 2052
2053 m->v.active = mode->vtotal * vscan / ilace; 2053 /*
2054 m->v.synce = ((mode->vsync_end - mode->vsync_start) * vscan / ilace) - 1; 2054 * DRM modes are defined in terms of a repeating interval
2055 m->v.blanke = m->v.synce + vbackp; 2055 * starting with the active display area. The hardware modes
2056 m->v.blanks = m->v.active - vfrontp - 1; 2056 * are defined in terms of a repeating interval starting one
2057 * unit (pixel or line) into the sync pulse. So, add bias.
2058 */
2059
2060 m->h.active = mode->crtc_htotal;
2061 m->h.synce = mode->crtc_hsync_end - mode->crtc_hsync_start - 1;
2062 m->h.blanke = mode->crtc_hblank_end - mode->crtc_hsync_start - 1;
2063 m->h.blanks = m->h.blanke + mode->crtc_hdisplay;
2064
2065 m->v.active = mode->crtc_vtotal;
2066 m->v.synce = mode->crtc_vsync_end - mode->crtc_vsync_start - 1;
2067 m->v.blanke = mode->crtc_vblank_end - mode->crtc_vsync_start - 1;
2068 m->v.blanks = m->v.blanke + mode->crtc_vdisplay;
2057 2069
2058 /*XXX: Safe underestimate, even "0" works */ 2070 /*XXX: Safe underestimate, even "0" works */
2059 blankus = (m->v.active - mode->vdisplay - 2) * m->h.active; 2071 blankus = (m->v.active - mode->crtc_vdisplay - 2) * m->h.active;
2060 blankus *= 1000; 2072 blankus *= 1000;
2061 blankus /= mode->clock; 2073 blankus /= mode->crtc_clock;
2062 m->v.blankus = blankus; 2074 m->v.blankus = blankus;
2063 2075
2064 if (mode->flags & DRM_MODE_FLAG_INTERLACE) { 2076 if (mode->flags & DRM_MODE_FLAG_INTERLACE) {
2065 m->v.blank2e = m->v.active + m->v.synce + vbackp; 2077 m->v.blank2e = m->v.active + m->v.blanke;
2066 m->v.blank2s = m->v.blank2e + (mode->vdisplay * vscan / ilace); 2078 m->v.blank2s = m->v.blank2e + mode->crtc_vdisplay;
2067 m->v.active = (m->v.active * 2) + 1; 2079 m->v.active = (m->v.active * 2) + 1;
2068 m->interlace = true; 2080 m->interlace = true;
2069 } else { 2081 } else {
@@ -2071,9 +2083,8 @@ nv50_head_atomic_check_mode(struct nv50_head *head, struct nv50_head_atom *asyh)
2071 m->v.blank2s = 1; 2083 m->v.blank2s = 1;
2072 m->interlace = false; 2084 m->interlace = false;
2073 } 2085 }
2074 m->clock = mode->clock; 2086 m->clock = mode->crtc_clock;
2075 2087
2076 drm_mode_set_crtcinfo(mode, CRTC_INTERLACE_HALVE_V);
2077 asyh->set.mode = true; 2088 asyh->set.mode = true;
2078} 2089}
2079 2090
@@ -2392,6 +2403,51 @@ out:
2392/****************************************************************************** 2403/******************************************************************************
2393 * Output path helpers 2404 * Output path helpers
2394 *****************************************************************************/ 2405 *****************************************************************************/
2406static void
2407nv50_outp_release(struct nouveau_encoder *nv_encoder)
2408{
2409 struct nv50_disp *disp = nv50_disp(nv_encoder->base.base.dev);
2410 struct {
2411 struct nv50_disp_mthd_v1 base;
2412 } args = {
2413 .base.version = 1,
2414 .base.method = NV50_DISP_MTHD_V1_RELEASE,
2415 .base.hasht = nv_encoder->dcb->hasht,
2416 .base.hashm = nv_encoder->dcb->hashm,
2417 };
2418
2419 nvif_mthd(disp->disp, 0, &args, sizeof(args));
2420 nv_encoder->or = -1;
2421 nv_encoder->link = 0;
2422}
2423
2424static int
2425nv50_outp_acquire(struct nouveau_encoder *nv_encoder)
2426{
2427 struct nouveau_drm *drm = nouveau_drm(nv_encoder->base.base.dev);
2428 struct nv50_disp *disp = nv50_disp(drm->dev);
2429 struct {
2430 struct nv50_disp_mthd_v1 base;
2431 struct nv50_disp_acquire_v0 info;
2432 } args = {
2433 .base.version = 1,
2434 .base.method = NV50_DISP_MTHD_V1_ACQUIRE,
2435 .base.hasht = nv_encoder->dcb->hasht,
2436 .base.hashm = nv_encoder->dcb->hashm,
2437 };
2438 int ret;
2439
2440 ret = nvif_mthd(disp->disp, 0, &args, sizeof(args));
2441 if (ret) {
2442 NV_ERROR(drm, "error acquiring output path: %d\n", ret);
2443 return ret;
2444 }
2445
2446 nv_encoder->or = args.info.or;
2447 nv_encoder->link = args.info.link;
2448 return 0;
2449}
2450
2395static int 2451static int
2396nv50_outp_atomic_check_view(struct drm_encoder *encoder, 2452nv50_outp_atomic_check_view(struct drm_encoder *encoder,
2397 struct drm_crtc_state *crtc_state, 2453 struct drm_crtc_state *crtc_state,
@@ -2449,30 +2505,6 @@ nv50_outp_atomic_check(struct drm_encoder *encoder,
2449 * DAC 2505 * DAC
2450 *****************************************************************************/ 2506 *****************************************************************************/
2451static void 2507static void
2452nv50_dac_dpms(struct drm_encoder *encoder, int mode)
2453{
2454 struct nouveau_encoder *nv_encoder = nouveau_encoder(encoder);
2455 struct nv50_disp *disp = nv50_disp(encoder->dev);
2456 struct {
2457 struct nv50_disp_mthd_v1 base;
2458 struct nv50_disp_dac_pwr_v0 pwr;
2459 } args = {
2460 .base.version = 1,
2461 .base.method = NV50_DISP_MTHD_V1_DAC_PWR,
2462 .base.hasht = nv_encoder->dcb->hasht,
2463 .base.hashm = nv_encoder->dcb->hashm,
2464 .pwr.state = 1,
2465 .pwr.data = 1,
2466 .pwr.vsync = (mode != DRM_MODE_DPMS_SUSPEND &&
2467 mode != DRM_MODE_DPMS_OFF),
2468 .pwr.hsync = (mode != DRM_MODE_DPMS_STANDBY &&
2469 mode != DRM_MODE_DPMS_OFF),
2470 };
2471
2472 nvif_mthd(disp->disp, 0, &args, sizeof(args));
2473}
2474
2475static void
2476nv50_dac_disable(struct drm_encoder *encoder) 2508nv50_dac_disable(struct drm_encoder *encoder)
2477{ 2509{
2478 struct nouveau_encoder *nv_encoder = nouveau_encoder(encoder); 2510 struct nouveau_encoder *nv_encoder = nouveau_encoder(encoder);
@@ -2495,6 +2527,7 @@ nv50_dac_disable(struct drm_encoder *encoder)
2495 } 2527 }
2496 2528
2497 nv_encoder->crtc = NULL; 2529 nv_encoder->crtc = NULL;
2530 nv50_outp_release(nv_encoder);
2498} 2531}
2499 2532
2500static void 2533static void
@@ -2506,6 +2539,8 @@ nv50_dac_enable(struct drm_encoder *encoder)
2506 struct drm_display_mode *mode = &nv_crtc->base.state->adjusted_mode; 2539 struct drm_display_mode *mode = &nv_crtc->base.state->adjusted_mode;
2507 u32 *push; 2540 u32 *push;
2508 2541
2542 nv50_outp_acquire(nv_encoder);
2543
2509 push = evo_wait(mast, 8); 2544 push = evo_wait(mast, 8);
2510 if (push) { 2545 if (push) {
2511 if (nv50_vers(mast) < GF110_DISP_CORE_CHANNEL_DMA) { 2546 if (nv50_vers(mast) < GF110_DISP_CORE_CHANNEL_DMA) {
@@ -2573,7 +2608,6 @@ nv50_dac_detect(struct drm_encoder *encoder, struct drm_connector *connector)
2573 2608
2574static const struct drm_encoder_helper_funcs 2609static const struct drm_encoder_helper_funcs
2575nv50_dac_help = { 2610nv50_dac_help = {
2576 .dpms = nv50_dac_dpms,
2577 .atomic_check = nv50_outp_atomic_check, 2611 .atomic_check = nv50_outp_atomic_check,
2578 .enable = nv50_dac_enable, 2612 .enable = nv50_dac_enable,
2579 .disable = nv50_dac_disable, 2613 .disable = nv50_dac_disable,
@@ -2606,7 +2640,6 @@ nv50_dac_create(struct drm_connector *connector, struct dcb_output *dcbe)
2606 if (!nv_encoder) 2640 if (!nv_encoder)
2607 return -ENOMEM; 2641 return -ENOMEM;
2608 nv_encoder->dcb = dcbe; 2642 nv_encoder->dcb = dcbe;
2609 nv_encoder->or = ffs(dcbe->or) - 1;
2610 2643
2611 bus = nvkm_i2c_bus_find(i2c, dcbe->i2c_index); 2644 bus = nvkm_i2c_bus_find(i2c, dcbe->i2c_index);
2612 if (bus) 2645 if (bus)
@@ -2708,6 +2741,7 @@ nv50_hdmi_enable(struct drm_encoder *encoder, struct drm_display_mode *mode)
2708 struct { 2741 struct {
2709 struct nv50_disp_mthd_v1 base; 2742 struct nv50_disp_mthd_v1 base;
2710 struct nv50_disp_sor_hdmi_pwr_v0 pwr; 2743 struct nv50_disp_sor_hdmi_pwr_v0 pwr;
2744 u8 infoframes[2 * 17]; /* two frames, up to 17 bytes each */
2711 } args = { 2745 } args = {
2712 .base.version = 1, 2746 .base.version = 1,
2713 .base.method = NV50_DISP_MTHD_V1_SOR_HDMI_PWR, 2747 .base.method = NV50_DISP_MTHD_V1_SOR_HDMI_PWR,
@@ -2719,17 +2753,42 @@ nv50_hdmi_enable(struct drm_encoder *encoder, struct drm_display_mode *mode)
2719 }; 2753 };
2720 struct nouveau_connector *nv_connector; 2754 struct nouveau_connector *nv_connector;
2721 u32 max_ac_packet; 2755 u32 max_ac_packet;
2756 union hdmi_infoframe avi_frame;
2757 union hdmi_infoframe vendor_frame;
2758 int ret;
2759 int size;
2722 2760
2723 nv_connector = nouveau_encoder_connector_get(nv_encoder); 2761 nv_connector = nouveau_encoder_connector_get(nv_encoder);
2724 if (!drm_detect_hdmi_monitor(nv_connector->edid)) 2762 if (!drm_detect_hdmi_monitor(nv_connector->edid))
2725 return; 2763 return;
2726 2764
2765 ret = drm_hdmi_avi_infoframe_from_display_mode(&avi_frame.avi, mode);
2766 if (!ret) {
2767 /* We have an AVI InfoFrame, populate it to the display */
2768 args.pwr.avi_infoframe_length
2769 = hdmi_infoframe_pack(&avi_frame, args.infoframes, 17);
2770 }
2771
2772 ret = drm_hdmi_vendor_infoframe_from_display_mode(&vendor_frame.vendor.hdmi, mode);
2773 if (!ret) {
2774 /* We have a Vendor InfoFrame, populate it to the display */
2775 args.pwr.vendor_infoframe_length
2776 = hdmi_infoframe_pack(&vendor_frame,
2777 args.infoframes
2778 + args.pwr.avi_infoframe_length,
2779 17);
2780 }
2781
2727 max_ac_packet = mode->htotal - mode->hdisplay; 2782 max_ac_packet = mode->htotal - mode->hdisplay;
2728 max_ac_packet -= args.pwr.rekey; 2783 max_ac_packet -= args.pwr.rekey;
2729 max_ac_packet -= 18; /* constant from tegra */ 2784 max_ac_packet -= 18; /* constant from tegra */
2730 args.pwr.max_ac_packet = max_ac_packet / 32; 2785 args.pwr.max_ac_packet = max_ac_packet / 32;
2731 2786
2732 nvif_mthd(disp->disp, 0, &args, sizeof(args)); 2787 size = sizeof(args.base)
2788 + sizeof(args.pwr)
2789 + args.pwr.avi_infoframe_length
2790 + args.pwr.vendor_infoframe_length;
2791 nvif_mthd(disp->disp, 0, &args, size);
2733 nv50_audio_enable(encoder, mode); 2792 nv50_audio_enable(encoder, mode);
2734} 2793}
2735 2794
@@ -2747,6 +2806,8 @@ struct nv50_mstm {
2747 struct nv50_msto *msto[4]; 2806 struct nv50_msto *msto[4];
2748 2807
2749 bool modified; 2808 bool modified;
2809 bool disabled;
2810 int links;
2750}; 2811};
2751 2812
2752struct nv50_mstc { 2813struct nv50_mstc {
@@ -2895,7 +2956,10 @@ nv50_msto_enable(struct drm_encoder *encoder)
2895 r = drm_dp_mst_allocate_vcpi(&mstm->mgr, mstc->port, mstc->pbn, slots); 2956 r = drm_dp_mst_allocate_vcpi(&mstm->mgr, mstc->port, mstc->pbn, slots);
2896 WARN_ON(!r); 2957 WARN_ON(!r);
2897 2958
2898 if (mstm->outp->dcb->sorconf.link & 1) 2959 if (!mstm->links++)
2960 nv50_outp_acquire(mstm->outp);
2961
2962 if (mstm->outp->link & 1)
2899 proto = 0x8; 2963 proto = 0x8;
2900 else 2964 else
2901 proto = 0x9; 2965 proto = 0x9;
@@ -2927,6 +2991,8 @@ nv50_msto_disable(struct drm_encoder *encoder)
2927 2991
2928 mstm->outp->update(mstm->outp, msto->head->base.index, NULL, 0, 0); 2992 mstm->outp->update(mstm->outp, msto->head->base.index, NULL, 0, 0);
2929 mstm->modified = true; 2993 mstm->modified = true;
2994 if (!--mstm->links)
2995 mstm->disabled = true;
2930 msto->disabled = true; 2996 msto->disabled = true;
2931} 2997}
2932 2998
@@ -3142,6 +3208,12 @@ nv50_mstm_prepare(struct nv50_mstm *mstm)
3142 nv50_msto_prepare(msto); 3208 nv50_msto_prepare(msto);
3143 } 3209 }
3144 } 3210 }
3211
3212 if (mstm->disabled) {
3213 if (!mstm->links)
3214 nv50_outp_release(mstm->outp);
3215 mstm->disabled = false;
3216 }
3145} 3217}
3146 3218
3147static void 3219static void
@@ -3369,25 +3441,6 @@ nv50_mstm_new(struct nouveau_encoder *outp, struct drm_dp_aux *aux, int aux_max,
3369 * SOR 3441 * SOR
3370 *****************************************************************************/ 3442 *****************************************************************************/
3371static void 3443static void
3372nv50_sor_dpms(struct drm_encoder *encoder, int mode)
3373{
3374 struct nouveau_encoder *nv_encoder = nouveau_encoder(encoder);
3375 struct nv50_disp *disp = nv50_disp(encoder->dev);
3376 struct {
3377 struct nv50_disp_mthd_v1 base;
3378 struct nv50_disp_sor_pwr_v0 pwr;
3379 } args = {
3380 .base.version = 1,
3381 .base.method = NV50_DISP_MTHD_V1_SOR_PWR,
3382 .base.hasht = nv_encoder->dcb->hasht,
3383 .base.hashm = nv_encoder->dcb->hashm,
3384 .pwr.state = mode == DRM_MODE_DPMS_ON,
3385 };
3386
3387 nvif_mthd(disp->disp, 0, &args, sizeof(args));
3388}
3389
3390static void
3391nv50_sor_update(struct nouveau_encoder *nv_encoder, u8 head, 3444nv50_sor_update(struct nouveau_encoder *nv_encoder, u8 head,
3392 struct drm_display_mode *mode, u8 proto, u8 depth) 3445 struct drm_display_mode *mode, u8 proto, u8 depth)
3393{ 3446{
@@ -3459,6 +3512,7 @@ nv50_sor_disable(struct drm_encoder *encoder)
3459 nv_encoder->update(nv_encoder, nv_crtc->index, NULL, 0, 0); 3512 nv_encoder->update(nv_encoder, nv_crtc->index, NULL, 0, 0);
3460 nv50_audio_disable(encoder, nv_crtc); 3513 nv50_audio_disable(encoder, nv_crtc);
3461 nv50_hdmi_disable(&nv_encoder->base.base, nv_crtc); 3514 nv50_hdmi_disable(&nv_encoder->base.base, nv_crtc);
3515 nv50_outp_release(nv_encoder);
3462 } 3516 }
3463} 3517}
3464 3518
@@ -3487,10 +3541,11 @@ nv50_sor_enable(struct drm_encoder *encoder)
3487 3541
3488 nv_connector = nouveau_encoder_connector_get(nv_encoder); 3542 nv_connector = nouveau_encoder_connector_get(nv_encoder);
3489 nv_encoder->crtc = encoder->crtc; 3543 nv_encoder->crtc = encoder->crtc;
3544 nv50_outp_acquire(nv_encoder);
3490 3545
3491 switch (nv_encoder->dcb->type) { 3546 switch (nv_encoder->dcb->type) {
3492 case DCB_OUTPUT_TMDS: 3547 case DCB_OUTPUT_TMDS:
3493 if (nv_encoder->dcb->sorconf.link & 1) { 3548 if (nv_encoder->link & 1) {
3494 proto = 0x1; 3549 proto = 0x1;
3495 /* Only enable dual-link if: 3550 /* Only enable dual-link if:
3496 * - Need to (i.e. rate > 165MHz) 3551 * - Need to (i.e. rate > 165MHz)
@@ -3548,7 +3603,7 @@ nv50_sor_enable(struct drm_encoder *encoder)
3548 else 3603 else
3549 depth = 0x6; 3604 depth = 0x6;
3550 3605
3551 if (nv_encoder->dcb->sorconf.link & 1) 3606 if (nv_encoder->link & 1)
3552 proto = 0x8; 3607 proto = 0x8;
3553 else 3608 else
3554 proto = 0x9; 3609 proto = 0x9;
@@ -3565,7 +3620,6 @@ nv50_sor_enable(struct drm_encoder *encoder)
3565 3620
3566static const struct drm_encoder_helper_funcs 3621static const struct drm_encoder_helper_funcs
3567nv50_sor_help = { 3622nv50_sor_help = {
3568 .dpms = nv50_sor_dpms,
3569 .atomic_check = nv50_outp_atomic_check, 3623 .atomic_check = nv50_outp_atomic_check,
3570 .enable = nv50_sor_enable, 3624 .enable = nv50_sor_enable,
3571 .disable = nv50_sor_disable, 3625 .disable = nv50_sor_disable,
@@ -3608,7 +3662,6 @@ nv50_sor_create(struct drm_connector *connector, struct dcb_output *dcbe)
3608 if (!nv_encoder) 3662 if (!nv_encoder)
3609 return -ENOMEM; 3663 return -ENOMEM;
3610 nv_encoder->dcb = dcbe; 3664 nv_encoder->dcb = dcbe;
3611 nv_encoder->or = ffs(dcbe->or) - 1;
3612 nv_encoder->update = nv50_sor_update; 3665 nv_encoder->update = nv50_sor_update;
3613 3666
3614 encoder = to_drm_encoder(nv_encoder); 3667 encoder = to_drm_encoder(nv_encoder);
@@ -3649,26 +3702,6 @@ nv50_sor_create(struct drm_connector *connector, struct dcb_output *dcbe)
3649/****************************************************************************** 3702/******************************************************************************
3650 * PIOR 3703 * PIOR
3651 *****************************************************************************/ 3704 *****************************************************************************/
3652static void
3653nv50_pior_dpms(struct drm_encoder *encoder, int mode)
3654{
3655 struct nouveau_encoder *nv_encoder = nouveau_encoder(encoder);
3656 struct nv50_disp *disp = nv50_disp(encoder->dev);
3657 struct {
3658 struct nv50_disp_mthd_v1 base;
3659 struct nv50_disp_pior_pwr_v0 pwr;
3660 } args = {
3661 .base.version = 1,
3662 .base.method = NV50_DISP_MTHD_V1_PIOR_PWR,
3663 .base.hasht = nv_encoder->dcb->hasht,
3664 .base.hashm = nv_encoder->dcb->hashm,
3665 .pwr.state = mode == DRM_MODE_DPMS_ON,
3666 .pwr.type = nv_encoder->dcb->type,
3667 };
3668
3669 nvif_mthd(disp->disp, 0, &args, sizeof(args));
3670}
3671
3672static int 3705static int
3673nv50_pior_atomic_check(struct drm_encoder *encoder, 3706nv50_pior_atomic_check(struct drm_encoder *encoder,
3674 struct drm_crtc_state *crtc_state, 3707 struct drm_crtc_state *crtc_state,
@@ -3701,6 +3734,7 @@ nv50_pior_disable(struct drm_encoder *encoder)
3701 } 3734 }
3702 3735
3703 nv_encoder->crtc = NULL; 3736 nv_encoder->crtc = NULL;
3737 nv50_outp_release(nv_encoder);
3704} 3738}
3705 3739
3706static void 3740static void
@@ -3715,6 +3749,8 @@ nv50_pior_enable(struct drm_encoder *encoder)
3715 u8 proto, depth; 3749 u8 proto, depth;
3716 u32 *push; 3750 u32 *push;
3717 3751
3752 nv50_outp_acquire(nv_encoder);
3753
3718 nv_connector = nouveau_encoder_connector_get(nv_encoder); 3754 nv_connector = nouveau_encoder_connector_get(nv_encoder);
3719 switch (nv_connector->base.display_info.bpc) { 3755 switch (nv_connector->base.display_info.bpc) {
3720 case 10: depth = 0x6; break; 3756 case 10: depth = 0x6; break;
@@ -3753,7 +3789,6 @@ nv50_pior_enable(struct drm_encoder *encoder)
3753 3789
3754static const struct drm_encoder_helper_funcs 3790static const struct drm_encoder_helper_funcs
3755nv50_pior_help = { 3791nv50_pior_help = {
3756 .dpms = nv50_pior_dpms,
3757 .atomic_check = nv50_pior_atomic_check, 3792 .atomic_check = nv50_pior_atomic_check,
3758 .enable = nv50_pior_enable, 3793 .enable = nv50_pior_enable,
3759 .disable = nv50_pior_disable, 3794 .disable = nv50_pior_disable,
@@ -3803,7 +3838,6 @@ nv50_pior_create(struct drm_connector *connector, struct dcb_output *dcbe)
3803 if (!nv_encoder) 3838 if (!nv_encoder)
3804 return -ENOMEM; 3839 return -ENOMEM;
3805 nv_encoder->dcb = dcbe; 3840 nv_encoder->dcb = dcbe;
3806 nv_encoder->or = ffs(dcbe->or) - 1;
3807 nv_encoder->i2c = ddc; 3841 nv_encoder->i2c = ddc;
3808 nv_encoder->aux = aux; 3842 nv_encoder->aux = aux;
3809 3843
@@ -4318,14 +4352,8 @@ nv50_display_init(struct drm_device *dev)
4318 4352
4319 list_for_each_entry(encoder, &dev->mode_config.encoder_list, head) { 4353 list_for_each_entry(encoder, &dev->mode_config.encoder_list, head) {
4320 if (encoder->encoder_type != DRM_MODE_ENCODER_DPMST) { 4354 if (encoder->encoder_type != DRM_MODE_ENCODER_DPMST) {
4321 const struct drm_encoder_helper_funcs *help; 4355 struct nouveau_encoder *nv_encoder =
4322 struct nouveau_encoder *nv_encoder; 4356 nouveau_encoder(encoder);
4323
4324 nv_encoder = nouveau_encoder(encoder);
4325 help = encoder->helper_private;
4326 if (help && help->dpms)
4327 help->dpms(encoder, DRM_MODE_DPMS_ON);
4328
4329 nv50_mstm_init(nv_encoder->dp.mstm); 4357 nv50_mstm_init(nv_encoder->dp.mstm);
4330 } 4358 }
4331 } 4359 }
diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/device/base.c b/drivers/gpu/drm/nouveau/nvkm/engine/device/base.c
index b690bc12a5b7..7bdc7a5ae723 100644
--- a/drivers/gpu/drm/nouveau/nvkm/engine/device/base.c
+++ b/drivers/gpu/drm/nouveau/nvkm/engine/device/base.c
@@ -1257,7 +1257,7 @@ nvaa_chipset = {
1257 .therm = g84_therm_new, 1257 .therm = g84_therm_new,
1258 .timer = nv41_timer_new, 1258 .timer = nv41_timer_new,
1259 .volt = nv40_volt_new, 1259 .volt = nv40_volt_new,
1260 .disp = g94_disp_new, 1260 .disp = mcp77_disp_new,
1261 .dma = nv50_dma_new, 1261 .dma = nv50_dma_new,
1262 .fifo = g84_fifo_new, 1262 .fifo = g84_fifo_new,
1263 .gr = gt200_gr_new, 1263 .gr = gt200_gr_new,
@@ -1289,7 +1289,7 @@ nvac_chipset = {
1289 .therm = g84_therm_new, 1289 .therm = g84_therm_new,
1290 .timer = nv41_timer_new, 1290 .timer = nv41_timer_new,
1291 .volt = nv40_volt_new, 1291 .volt = nv40_volt_new,
1292 .disp = g94_disp_new, 1292 .disp = mcp77_disp_new,
1293 .dma = nv50_dma_new, 1293 .dma = nv50_dma_new,
1294 .fifo = g84_fifo_new, 1294 .fifo = g84_fifo_new,
1295 .gr = mcp79_gr_new, 1295 .gr = mcp79_gr_new,
@@ -1323,7 +1323,7 @@ nvaf_chipset = {
1323 .timer = nv41_timer_new, 1323 .timer = nv41_timer_new,
1324 .volt = nv40_volt_new, 1324 .volt = nv40_volt_new,
1325 .ce[0] = gt215_ce_new, 1325 .ce[0] = gt215_ce_new,
1326 .disp = gt215_disp_new, 1326 .disp = mcp89_disp_new,
1327 .dma = nv50_dma_new, 1327 .dma = nv50_dma_new,
1328 .fifo = g84_fifo_new, 1328 .fifo = g84_fifo_new,
1329 .gr = mcp89_gr_new, 1329 .gr = mcp89_gr_new,
diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/device/tegra.c b/drivers/gpu/drm/nouveau/nvkm/engine/device/tegra.c
index 6474bd2a6d07..189ed80e21ff 100644
--- a/drivers/gpu/drm/nouveau/nvkm/engine/device/tegra.c
+++ b/drivers/gpu/drm/nouveau/nvkm/engine/device/tegra.c
@@ -51,10 +51,12 @@ nvkm_device_tegra_power_up(struct nvkm_device_tegra *tdev)
51 reset_control_assert(tdev->rst); 51 reset_control_assert(tdev->rst);
52 udelay(10); 52 udelay(10);
53 53
54 ret = tegra_powergate_remove_clamping(TEGRA_POWERGATE_3D); 54 if (!tdev->pdev->dev.pm_domain) {
55 if (ret) 55 ret = tegra_powergate_remove_clamping(TEGRA_POWERGATE_3D);
56 goto err_clamp; 56 if (ret)
57 udelay(10); 57 goto err_clamp;
58 udelay(10);
59 }
58 60
59 reset_control_deassert(tdev->rst); 61 reset_control_deassert(tdev->rst);
60 udelay(10); 62 udelay(10);
@@ -80,9 +82,6 @@ nvkm_device_tegra_power_down(struct nvkm_device_tegra *tdev)
80{ 82{
81 int ret; 83 int ret;
82 84
83 reset_control_assert(tdev->rst);
84 udelay(10);
85
86 clk_disable_unprepare(tdev->clk_pwr); 85 clk_disable_unprepare(tdev->clk_pwr);
87 if (tdev->clk_ref) 86 if (tdev->clk_ref)
88 clk_disable_unprepare(tdev->clk_ref); 87 clk_disable_unprepare(tdev->clk_ref);
diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/Kbuild b/drivers/gpu/drm/nouveau/nvkm/engine/disp/Kbuild
index fa05d16ae948..48ce6699183e 100644
--- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/Kbuild
+++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/Kbuild
@@ -4,7 +4,9 @@ nvkm-y += nvkm/engine/disp/nv50.o
4nvkm-y += nvkm/engine/disp/g84.o 4nvkm-y += nvkm/engine/disp/g84.o
5nvkm-y += nvkm/engine/disp/g94.o 5nvkm-y += nvkm/engine/disp/g94.o
6nvkm-y += nvkm/engine/disp/gt200.o 6nvkm-y += nvkm/engine/disp/gt200.o
7nvkm-y += nvkm/engine/disp/mcp77.o
7nvkm-y += nvkm/engine/disp/gt215.o 8nvkm-y += nvkm/engine/disp/gt215.o
9nvkm-y += nvkm/engine/disp/mcp89.o
8nvkm-y += nvkm/engine/disp/gf119.o 10nvkm-y += nvkm/engine/disp/gf119.o
9nvkm-y += nvkm/engine/disp/gk104.o 11nvkm-y += nvkm/engine/disp/gk104.o
10nvkm-y += nvkm/engine/disp/gk110.o 12nvkm-y += nvkm/engine/disp/gk110.o
@@ -12,29 +14,41 @@ nvkm-y += nvkm/engine/disp/gm107.o
12nvkm-y += nvkm/engine/disp/gm200.o 14nvkm-y += nvkm/engine/disp/gm200.o
13nvkm-y += nvkm/engine/disp/gp100.o 15nvkm-y += nvkm/engine/disp/gp100.o
14nvkm-y += nvkm/engine/disp/gp102.o 16nvkm-y += nvkm/engine/disp/gp102.o
17nvkm-y += nvkm/engine/disp/vga.o
15 18
16nvkm-y += nvkm/engine/disp/outp.o 19nvkm-y += nvkm/engine/disp/head.o
17nvkm-y += nvkm/engine/disp/outpdp.o 20nvkm-y += nvkm/engine/disp/headnv04.o
21nvkm-y += nvkm/engine/disp/headnv50.o
22nvkm-y += nvkm/engine/disp/headgf119.o
23
24nvkm-y += nvkm/engine/disp/ior.o
18nvkm-y += nvkm/engine/disp/dacnv50.o 25nvkm-y += nvkm/engine/disp/dacnv50.o
26nvkm-y += nvkm/engine/disp/dacgf119.o
19nvkm-y += nvkm/engine/disp/piornv50.o 27nvkm-y += nvkm/engine/disp/piornv50.o
20nvkm-y += nvkm/engine/disp/sornv50.o 28nvkm-y += nvkm/engine/disp/sornv50.o
29nvkm-y += nvkm/engine/disp/sorg84.o
21nvkm-y += nvkm/engine/disp/sorg94.o 30nvkm-y += nvkm/engine/disp/sorg94.o
31nvkm-y += nvkm/engine/disp/sormcp77.o
32nvkm-y += nvkm/engine/disp/sorgt215.o
33nvkm-y += nvkm/engine/disp/sormcp89.o
22nvkm-y += nvkm/engine/disp/sorgf119.o 34nvkm-y += nvkm/engine/disp/sorgf119.o
35nvkm-y += nvkm/engine/disp/sorgk104.o
23nvkm-y += nvkm/engine/disp/sorgm107.o 36nvkm-y += nvkm/engine/disp/sorgm107.o
24nvkm-y += nvkm/engine/disp/sorgm200.o 37nvkm-y += nvkm/engine/disp/sorgm200.o
25nvkm-y += nvkm/engine/disp/dport.o
26 38
27nvkm-y += nvkm/engine/disp/conn.o 39nvkm-y += nvkm/engine/disp/outp.o
40nvkm-y += nvkm/engine/disp/dp.o
28 41
29nvkm-y += nvkm/engine/disp/hdagt215.o 42nvkm-y += nvkm/engine/disp/hdagt215.o
30nvkm-y += nvkm/engine/disp/hdagf119.o 43nvkm-y += nvkm/engine/disp/hdagf119.o
31 44
45nvkm-y += nvkm/engine/disp/hdmi.o
32nvkm-y += nvkm/engine/disp/hdmig84.o 46nvkm-y += nvkm/engine/disp/hdmig84.o
33nvkm-y += nvkm/engine/disp/hdmigt215.o 47nvkm-y += nvkm/engine/disp/hdmigt215.o
34nvkm-y += nvkm/engine/disp/hdmigf119.o 48nvkm-y += nvkm/engine/disp/hdmigf119.o
35nvkm-y += nvkm/engine/disp/hdmigk104.o 49nvkm-y += nvkm/engine/disp/hdmigk104.o
36 50
37nvkm-y += nvkm/engine/disp/vga.o 51nvkm-y += nvkm/engine/disp/conn.o
38 52
39nvkm-y += nvkm/engine/disp/rootnv04.o 53nvkm-y += nvkm/engine/disp/rootnv04.o
40nvkm-y += nvkm/engine/disp/rootnv50.o 54nvkm-y += nvkm/engine/disp/rootnv50.o
diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/base.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/base.c
index 1efe91b1e22b..c7c84d34d97e 100644
--- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/base.c
+++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/base.c
@@ -23,6 +23,9 @@
23 */ 23 */
24#include "priv.h" 24#include "priv.h"
25#include "conn.h" 25#include "conn.h"
26#include "dp.h"
27#include "head.h"
28#include "ior.h"
26#include "outp.h" 29#include "outp.h"
27 30
28#include <core/client.h> 31#include <core/client.h>
@@ -37,17 +40,21 @@
37#include <nvif/unpack.h> 40#include <nvif/unpack.h>
38 41
39static void 42static void
40nvkm_disp_vblank_fini(struct nvkm_event *event, int type, int head) 43nvkm_disp_vblank_fini(struct nvkm_event *event, int type, int id)
41{ 44{
42 struct nvkm_disp *disp = container_of(event, typeof(*disp), vblank); 45 struct nvkm_disp *disp = container_of(event, typeof(*disp), vblank);
43 disp->func->head.vblank_fini(disp, head); 46 struct nvkm_head *head = nvkm_head_find(disp, id);
47 if (head)
48 head->func->vblank_put(head);
44} 49}
45 50
46static void 51static void
47nvkm_disp_vblank_init(struct nvkm_event *event, int type, int head) 52nvkm_disp_vblank_init(struct nvkm_event *event, int type, int id)
48{ 53{
49 struct nvkm_disp *disp = container_of(event, typeof(*disp), vblank); 54 struct nvkm_disp *disp = container_of(event, typeof(*disp), vblank);
50 disp->func->head.vblank_init(disp, head); 55 struct nvkm_head *head = nvkm_head_find(disp, id);
56 if (head)
57 head->func->vblank_get(head);
51} 58}
52 59
53static int 60static int
@@ -96,7 +103,7 @@ nvkm_disp_hpd_ctor(struct nvkm_object *object, void *data, u32 size,
96 union { 103 union {
97 struct nvif_notify_conn_req_v0 v0; 104 struct nvif_notify_conn_req_v0 v0;
98 } *req = data; 105 } *req = data;
99 struct nvkm_output *outp; 106 struct nvkm_outp *outp;
100 int ret = -ENOSYS; 107 int ret = -ENOSYS;
101 108
102 if (!(ret = nvif_unpack(ret, &data, &size, req->v0, 0, 0, false))) { 109 if (!(ret = nvif_unpack(ret, &data, &size, req->v0, 0, 0, false))) {
@@ -210,15 +217,15 @@ static int
210nvkm_disp_fini(struct nvkm_engine *engine, bool suspend) 217nvkm_disp_fini(struct nvkm_engine *engine, bool suspend)
211{ 218{
212 struct nvkm_disp *disp = nvkm_disp(engine); 219 struct nvkm_disp *disp = nvkm_disp(engine);
213 struct nvkm_connector *conn; 220 struct nvkm_conn *conn;
214 struct nvkm_output *outp; 221 struct nvkm_outp *outp;
215 222
216 list_for_each_entry(outp, &disp->outp, head) { 223 list_for_each_entry(outp, &disp->outp, head) {
217 nvkm_output_fini(outp); 224 nvkm_outp_fini(outp);
218 } 225 }
219 226
220 list_for_each_entry(conn, &disp->conn, head) { 227 list_for_each_entry(conn, &disp->conn, head) {
221 nvkm_connector_fini(conn); 228 nvkm_conn_fini(conn);
222 } 229 }
223 230
224 return 0; 231 return 0;
@@ -228,129 +235,70 @@ static int
228nvkm_disp_init(struct nvkm_engine *engine) 235nvkm_disp_init(struct nvkm_engine *engine)
229{ 236{
230 struct nvkm_disp *disp = nvkm_disp(engine); 237 struct nvkm_disp *disp = nvkm_disp(engine);
231 struct nvkm_connector *conn; 238 struct nvkm_conn *conn;
232 struct nvkm_output *outp; 239 struct nvkm_outp *outp;
233 240
234 list_for_each_entry(conn, &disp->conn, head) { 241 list_for_each_entry(conn, &disp->conn, head) {
235 nvkm_connector_init(conn); 242 nvkm_conn_init(conn);
236 } 243 }
237 244
238 list_for_each_entry(outp, &disp->outp, head) { 245 list_for_each_entry(outp, &disp->outp, head) {
239 nvkm_output_init(outp); 246 nvkm_outp_init(outp);
240 } 247 }
241 248
242 return 0; 249 return 0;
243} 250}
244 251
245static void * 252static int
246nvkm_disp_dtor(struct nvkm_engine *engine) 253nvkm_disp_oneinit(struct nvkm_engine *engine)
247{ 254{
248 struct nvkm_disp *disp = nvkm_disp(engine); 255 struct nvkm_disp *disp = nvkm_disp(engine);
249 struct nvkm_connector *conn; 256 struct nvkm_subdev *subdev = &disp->engine.subdev;
250 struct nvkm_output *outp; 257 struct nvkm_bios *bios = subdev->device->bios;
251 void *data = disp; 258 struct nvkm_outp *outp, *outt, *pair;
252 259 struct nvkm_conn *conn;
253 if (disp->func->dtor) 260 struct nvkm_head *head;
254 data = disp->func->dtor(disp);
255
256 nvkm_event_fini(&disp->vblank);
257 nvkm_event_fini(&disp->hpd);
258
259 while (!list_empty(&disp->outp)) {
260 outp = list_first_entry(&disp->outp, typeof(*outp), head);
261 list_del(&outp->head);
262 nvkm_output_del(&outp);
263 }
264
265 while (!list_empty(&disp->conn)) {
266 conn = list_first_entry(&disp->conn, typeof(*conn), head);
267 list_del(&conn->head);
268 nvkm_connector_del(&conn);
269 }
270
271 return data;
272}
273
274static const struct nvkm_engine_func
275nvkm_disp = {
276 .dtor = nvkm_disp_dtor,
277 .init = nvkm_disp_init,
278 .fini = nvkm_disp_fini,
279 .intr = nvkm_disp_intr,
280 .base.sclass = nvkm_disp_class_get,
281};
282
283int
284nvkm_disp_ctor(const struct nvkm_disp_func *func, struct nvkm_device *device,
285 int index, int heads, struct nvkm_disp *disp)
286{
287 struct nvkm_bios *bios = device->bios;
288 struct nvkm_output *outp, *outt, *pair;
289 struct nvkm_connector *conn;
290 struct nvbios_connE connE; 261 struct nvbios_connE connE;
291 struct dcb_output dcbE; 262 struct dcb_output dcbE;
292 u8 hpd = 0, ver, hdr; 263 u8 hpd = 0, ver, hdr;
293 u32 data; 264 u32 data;
294 int ret, i; 265 int ret, i;
295 266
296 INIT_LIST_HEAD(&disp->outp); 267 /* Create output path objects for each VBIOS display path. */
297 INIT_LIST_HEAD(&disp->conn);
298 disp->func = func;
299 disp->head.nr = heads;
300
301 ret = nvkm_engine_ctor(&nvkm_disp, device, index, true, &disp->engine);
302 if (ret)
303 return ret;
304
305 /* create output objects for each display path in the vbios */
306 i = -1; 268 i = -1;
307 while ((data = dcb_outp_parse(bios, ++i, &ver, &hdr, &dcbE))) { 269 while ((data = dcb_outp_parse(bios, ++i, &ver, &hdr, &dcbE))) {
308 const struct nvkm_disp_func_outp *outps;
309 int (*ctor)(struct nvkm_disp *, int, struct dcb_output *,
310 struct nvkm_output **);
311
312 if (dcbE.type == DCB_OUTPUT_UNUSED) 270 if (dcbE.type == DCB_OUTPUT_UNUSED)
313 continue; 271 continue;
314 if (dcbE.type == DCB_OUTPUT_EOL) 272 if (dcbE.type == DCB_OUTPUT_EOL)
315 break; 273 break;
316 outp = NULL; 274 outp = NULL;
317 275
318 switch (dcbE.location) {
319 case 0: outps = &disp->func->outp.internal; break;
320 case 1: outps = &disp->func->outp.external; break;
321 default:
322 nvkm_warn(&disp->engine.subdev,
323 "dcb %d locn %d unknown\n", i, dcbE.location);
324 continue;
325 }
326
327 switch (dcbE.type) { 276 switch (dcbE.type) {
328 case DCB_OUTPUT_ANALOG: ctor = outps->crt ; break; 277 case DCB_OUTPUT_ANALOG:
329 case DCB_OUTPUT_TV : ctor = outps->tv ; break; 278 case DCB_OUTPUT_TV:
330 case DCB_OUTPUT_TMDS : ctor = outps->tmds; break; 279 case DCB_OUTPUT_TMDS:
331 case DCB_OUTPUT_LVDS : ctor = outps->lvds; break; 280 case DCB_OUTPUT_LVDS:
332 case DCB_OUTPUT_DP : ctor = outps->dp ; break; 281 ret = nvkm_outp_new(disp, i, &dcbE, &outp);
282 break;
283 case DCB_OUTPUT_DP:
284 ret = nvkm_dp_new(disp, i, &dcbE, &outp);
285 break;
333 default: 286 default:
334 nvkm_warn(&disp->engine.subdev, 287 nvkm_warn(subdev, "dcb %d type %d unknown\n",
335 "dcb %d type %d unknown\n", i, dcbE.type); 288 i, dcbE.type);
336 continue; 289 continue;
337 } 290 }
338 291
339 if (ctor)
340 ret = ctor(disp, i, &dcbE, &outp);
341 else
342 ret = -ENODEV;
343
344 if (ret) { 292 if (ret) {
345 if (ret == -ENODEV) { 293 if (outp) {
346 nvkm_debug(&disp->engine.subdev, 294 if (ret != -ENODEV)
347 "dcb %d %d/%d not supported\n", 295 OUTP_ERR(outp, "ctor failed: %d", ret);
348 i, dcbE.location, dcbE.type); 296 else
297 OUTP_DBG(outp, "not supported");
298 nvkm_outp_del(&outp);
349 continue; 299 continue;
350 } 300 }
351 nvkm_error(&disp->engine.subdev, 301 nvkm_error(subdev, "failed to create outp %d\n", i);
352 "failed to create output %d\n", i);
353 nvkm_output_del(&outp);
354 continue; 302 continue;
355 } 303 }
356 304
@@ -358,18 +306,18 @@ nvkm_disp_ctor(const struct nvkm_disp_func *func, struct nvkm_device *device,
358 hpd = max(hpd, (u8)(dcbE.connector + 1)); 306 hpd = max(hpd, (u8)(dcbE.connector + 1));
359 } 307 }
360 308
361 /* create connector objects based on the outputs we support */ 309 /* Create connector objects based on available output paths. */
362 list_for_each_entry_safe(outp, outt, &disp->outp, head) { 310 list_for_each_entry_safe(outp, outt, &disp->outp, head) {
363 /* bios data *should* give us the most useful information */ 311 /* VBIOS data *should* give us the most useful information. */
364 data = nvbios_connEp(bios, outp->info.connector, &ver, &hdr, 312 data = nvbios_connEp(bios, outp->info.connector, &ver, &hdr,
365 &connE); 313 &connE);
366 314
367 /* no bios connector data... */ 315 /* No bios connector data... */
368 if (!data) { 316 if (!data) {
369 /* heuristic: anything with the same ccb index is 317 /* Heuristic: anything with the same ccb index is
370 * considered to be on the same connector, any 318 * considered to be on the same connector, any
371 * output path without an associated ccb entry will 319 * output path without an associated ccb entry will
372 * be put on its own connector 320 * be put on its own connector.
373 */ 321 */
374 int ccb_index = outp->info.i2c_index; 322 int ccb_index = outp->info.i2c_index;
375 if (ccb_index != 0xf) { 323 if (ccb_index != 0xf) {
@@ -381,7 +329,7 @@ nvkm_disp_ctor(const struct nvkm_disp_func *func, struct nvkm_device *device,
381 } 329 }
382 } 330 }
383 331
384 /* connector shared with another output path */ 332 /* Connector shared with another output path. */
385 if (outp->conn) 333 if (outp->conn)
386 continue; 334 continue;
387 335
@@ -392,7 +340,7 @@ nvkm_disp_ctor(const struct nvkm_disp_func *func, struct nvkm_device *device,
392 i = outp->info.connector; 340 i = outp->info.connector;
393 } 341 }
394 342
395 /* check that we haven't already created this connector */ 343 /* Check that we haven't already created this connector. */
396 list_for_each_entry(conn, &disp->conn, head) { 344 list_for_each_entry(conn, &disp->conn, head) {
397 if (conn->index == outp->info.connector) { 345 if (conn->index == outp->info.connector) {
398 outp->conn = conn; 346 outp->conn = conn;
@@ -403,15 +351,15 @@ nvkm_disp_ctor(const struct nvkm_disp_func *func, struct nvkm_device *device,
403 if (outp->conn) 351 if (outp->conn)
404 continue; 352 continue;
405 353
406 /* apparently we need to create a new one! */ 354 /* Apparently we need to create a new one! */
407 ret = nvkm_connector_new(disp, i, &connE, &outp->conn); 355 ret = nvkm_conn_new(disp, i, &connE, &outp->conn);
408 if (ret) { 356 if (ret) {
409 nvkm_error(&disp->engine.subdev, 357 nvkm_error(&disp->engine.subdev,
410 "failed to create output %d conn: %d\n", 358 "failed to create outp %d conn: %d\n",
411 outp->index, ret); 359 outp->index, ret);
412 nvkm_connector_del(&outp->conn); 360 nvkm_conn_del(&outp->conn);
413 list_del(&outp->head); 361 list_del(&outp->head);
414 nvkm_output_del(&outp); 362 nvkm_outp_del(&outp);
415 continue; 363 continue;
416 } 364 }
417 365
@@ -422,18 +370,81 @@ nvkm_disp_ctor(const struct nvkm_disp_func *func, struct nvkm_device *device,
422 if (ret) 370 if (ret)
423 return ret; 371 return ret;
424 372
425 ret = nvkm_event_init(&nvkm_disp_vblank_func, 1, heads, &disp->vblank); 373 i = 0;
426 if (ret) 374 list_for_each_entry(head, &disp->head, head)
427 return ret; 375 i = max(i, head->id + 1);
428 376
429 return 0; 377 return nvkm_event_init(&nvkm_disp_vblank_func, 1, i, &disp->vblank);
378}
379
380static void *
381nvkm_disp_dtor(struct nvkm_engine *engine)
382{
383 struct nvkm_disp *disp = nvkm_disp(engine);
384 struct nvkm_conn *conn;
385 struct nvkm_outp *outp;
386 void *data = disp;
387
388 if (disp->func->dtor)
389 data = disp->func->dtor(disp);
390
391 nvkm_event_fini(&disp->vblank);
392 nvkm_event_fini(&disp->hpd);
393
394 while (!list_empty(&disp->conn)) {
395 conn = list_first_entry(&disp->conn, typeof(*conn), head);
396 list_del(&conn->head);
397 nvkm_conn_del(&conn);
398 }
399
400 while (!list_empty(&disp->outp)) {
401 outp = list_first_entry(&disp->outp, typeof(*outp), head);
402 list_del(&outp->head);
403 nvkm_outp_del(&outp);
404 }
405
406 while (!list_empty(&disp->ior)) {
407 struct nvkm_ior *ior =
408 list_first_entry(&disp->ior, typeof(*ior), head);
409 nvkm_ior_del(&ior);
410 }
411
412 while (!list_empty(&disp->head)) {
413 struct nvkm_head *head =
414 list_first_entry(&disp->head, typeof(*head), head);
415 nvkm_head_del(&head);
416 }
417
418 return data;
419}
420
421static const struct nvkm_engine_func
422nvkm_disp = {
423 .dtor = nvkm_disp_dtor,
424 .oneinit = nvkm_disp_oneinit,
425 .init = nvkm_disp_init,
426 .fini = nvkm_disp_fini,
427 .intr = nvkm_disp_intr,
428 .base.sclass = nvkm_disp_class_get,
429};
430
431int
432nvkm_disp_ctor(const struct nvkm_disp_func *func, struct nvkm_device *device,
433 int index, struct nvkm_disp *disp)
434{
435 disp->func = func;
436 INIT_LIST_HEAD(&disp->head);
437 INIT_LIST_HEAD(&disp->ior);
438 INIT_LIST_HEAD(&disp->outp);
439 INIT_LIST_HEAD(&disp->conn);
440 return nvkm_engine_ctor(&nvkm_disp, device, index, true, &disp->engine);
430} 441}
431 442
432int 443int
433nvkm_disp_new_(const struct nvkm_disp_func *func, struct nvkm_device *device, 444nvkm_disp_new_(const struct nvkm_disp_func *func, struct nvkm_device *device,
434 int index, int heads, struct nvkm_disp **pdisp) 445 int index, struct nvkm_disp **pdisp)
435{ 446{
436 if (!(*pdisp = kzalloc(sizeof(**pdisp), GFP_KERNEL))) 447 if (!(*pdisp = kzalloc(sizeof(**pdisp), GFP_KERNEL)))
437 return -ENOMEM; 448 return -ENOMEM;
438 return nvkm_disp_ctor(func, device, index, heads, *pdisp); 449 return nvkm_disp_ctor(func, device, index, *pdisp);
439} 450}
diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/basenv50.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/basenv50.c
index 83f152300ec0..f1d6b820d482 100644
--- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/basenv50.c
+++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/basenv50.c
@@ -22,6 +22,7 @@
22 * Authors: Ben Skeggs 22 * Authors: Ben Skeggs
23 */ 23 */
24#include "dmacnv50.h" 24#include "dmacnv50.h"
25#include "head.h"
25#include "rootnv50.h" 26#include "rootnv50.h"
26 27
27#include <core/client.h> 28#include <core/client.h>
@@ -50,7 +51,7 @@ nv50_disp_base_new(const struct nv50_disp_dmac_func *func,
50 nvif_ioctl(parent, "create disp base channel dma vers %d " 51 nvif_ioctl(parent, "create disp base channel dma vers %d "
51 "pushbuf %016llx head %d\n", 52 "pushbuf %016llx head %d\n",
52 args->v0.version, args->v0.pushbuf, args->v0.head); 53 args->v0.version, args->v0.pushbuf, args->v0.head);
53 if (args->v0.head > disp->base.head.nr) 54 if (!nvkm_head_find(&disp->base, args->v0.head))
54 return -EINVAL; 55 return -EINVAL;
55 push = args->v0.pushbuf; 56 push = args->v0.pushbuf;
56 head = args->v0.head; 57 head = args->v0.head;
diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/channv50.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/channv50.c
index 524a24eae1a0..0c0310498afd 100644
--- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/channv50.c
+++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/channv50.c
@@ -25,6 +25,7 @@
25#include "rootnv50.h" 25#include "rootnv50.h"
26 26
27#include <core/client.h> 27#include <core/client.h>
28#include <core/notify.h>
28#include <core/ramht.h> 29#include <core/ramht.h>
29#include <engine/dma.h> 30#include <engine/dma.h>
30 31
diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/conn.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/conn.c
index c6910d644a3d..febc5c274488 100644
--- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/conn.c
+++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/conn.c
@@ -30,9 +30,9 @@
30#include <nvif/event.h> 30#include <nvif/event.h>
31 31
32static int 32static int
33nvkm_connector_hpd(struct nvkm_notify *notify) 33nvkm_conn_hpd(struct nvkm_notify *notify)
34{ 34{
35 struct nvkm_connector *conn = container_of(notify, typeof(*conn), hpd); 35 struct nvkm_conn *conn = container_of(notify, typeof(*conn), hpd);
36 struct nvkm_disp *disp = conn->disp; 36 struct nvkm_disp *disp = conn->disp;
37 struct nvkm_gpio *gpio = disp->engine.subdev.device->gpio; 37 struct nvkm_gpio *gpio = disp->engine.subdev.device->gpio;
38 const struct nvkm_gpio_ntfy_rep *line = notify->data; 38 const struct nvkm_gpio_ntfy_rep *line = notify->data;
@@ -52,21 +52,21 @@ nvkm_connector_hpd(struct nvkm_notify *notify)
52} 52}
53 53
54void 54void
55nvkm_connector_fini(struct nvkm_connector *conn) 55nvkm_conn_fini(struct nvkm_conn *conn)
56{ 56{
57 nvkm_notify_put(&conn->hpd); 57 nvkm_notify_put(&conn->hpd);
58} 58}
59 59
60void 60void
61nvkm_connector_init(struct nvkm_connector *conn) 61nvkm_conn_init(struct nvkm_conn *conn)
62{ 62{
63 nvkm_notify_get(&conn->hpd); 63 nvkm_notify_get(&conn->hpd);
64} 64}
65 65
66void 66void
67nvkm_connector_del(struct nvkm_connector **pconn) 67nvkm_conn_del(struct nvkm_conn **pconn)
68{ 68{
69 struct nvkm_connector *conn = *pconn; 69 struct nvkm_conn *conn = *pconn;
70 if (conn) { 70 if (conn) {
71 nvkm_notify_fini(&conn->hpd); 71 nvkm_notify_fini(&conn->hpd);
72 kfree(*pconn); 72 kfree(*pconn);
@@ -75,8 +75,8 @@ nvkm_connector_del(struct nvkm_connector **pconn)
75} 75}
76 76
77static void 77static void
78nvkm_connector_ctor(struct nvkm_disp *disp, int index, 78nvkm_conn_ctor(struct nvkm_disp *disp, int index, struct nvbios_connE *info,
79 struct nvbios_connE *info, struct nvkm_connector *conn) 79 struct nvkm_conn *conn)
80{ 80{
81 static const u8 hpd[] = { 0x07, 0x08, 0x51, 0x52, 0x5e, 0x5f, 0x60 }; 81 static const u8 hpd[] = { 0x07, 0x08, 0x51, 0x52, 0x5e, 0x5f, 0x60 };
82 struct nvkm_gpio *gpio = disp->engine.subdev.device->gpio; 82 struct nvkm_gpio *gpio = disp->engine.subdev.device->gpio;
@@ -105,7 +105,7 @@ nvkm_connector_ctor(struct nvkm_disp *disp, int index,
105 return; 105 return;
106 } 106 }
107 107
108 ret = nvkm_notify_init(NULL, &gpio->event, nvkm_connector_hpd, 108 ret = nvkm_notify_init(NULL, &gpio->event, nvkm_conn_hpd,
109 true, &(struct nvkm_gpio_ntfy_req) { 109 true, &(struct nvkm_gpio_ntfy_req) {
110 .mask = NVKM_GPIO_TOGGLED, 110 .mask = NVKM_GPIO_TOGGLED,
111 .line = func.line, 111 .line = func.line,
@@ -122,11 +122,11 @@ nvkm_connector_ctor(struct nvkm_disp *disp, int index,
122} 122}
123 123
124int 124int
125nvkm_connector_new(struct nvkm_disp *disp, int index, 125nvkm_conn_new(struct nvkm_disp *disp, int index, struct nvbios_connE *info,
126 struct nvbios_connE *info, struct nvkm_connector **pconn) 126 struct nvkm_conn **pconn)
127{ 127{
128 if (!(*pconn = kzalloc(sizeof(**pconn), GFP_KERNEL))) 128 if (!(*pconn = kzalloc(sizeof(**pconn), GFP_KERNEL)))
129 return -ENOMEM; 129 return -ENOMEM;
130 nvkm_connector_ctor(disp, index, info, *pconn); 130 nvkm_conn_ctor(disp, index, info, *pconn);
131 return 0; 131 return 0;
132} 132}
diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/conn.h b/drivers/gpu/drm/nouveau/nvkm/engine/disp/conn.h
index ed32fe7f1864..de962b7b026d 100644
--- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/conn.h
+++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/conn.h
@@ -6,7 +6,7 @@
6#include <subdev/bios.h> 6#include <subdev/bios.h>
7#include <subdev/bios/conn.h> 7#include <subdev/bios/conn.h>
8 8
9struct nvkm_connector { 9struct nvkm_conn {
10 struct nvkm_disp *disp; 10 struct nvkm_disp *disp;
11 int index; 11 int index;
12 struct nvbios_connE info; 12 struct nvbios_connE info;
@@ -16,14 +16,14 @@ struct nvkm_connector {
16 struct list_head head; 16 struct list_head head;
17}; 17};
18 18
19int nvkm_connector_new(struct nvkm_disp *, int index, struct nvbios_connE *, 19int nvkm_conn_new(struct nvkm_disp *, int index, struct nvbios_connE *,
20 struct nvkm_connector **); 20 struct nvkm_conn **);
21void nvkm_connector_del(struct nvkm_connector **); 21void nvkm_conn_del(struct nvkm_conn **);
22void nvkm_connector_init(struct nvkm_connector *); 22void nvkm_conn_init(struct nvkm_conn *);
23void nvkm_connector_fini(struct nvkm_connector *); 23void nvkm_conn_fini(struct nvkm_conn *);
24 24
25#define CONN_MSG(c,l,f,a...) do { \ 25#define CONN_MSG(c,l,f,a...) do { \
26 struct nvkm_connector *_conn = (c); \ 26 struct nvkm_conn *_conn = (c); \
27 nvkm_##l(&_conn->disp->engine.subdev, "conn %02x:%02x%02x: "f"\n", \ 27 nvkm_##l(&_conn->disp->engine.subdev, "conn %02x:%02x%02x: "f"\n", \
28 _conn->index, _conn->info.location, _conn->info.type, ##a); \ 28 _conn->index, _conn->info.location, _conn->info.type, ##a); \
29} while(0) 29} while(0)
diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/cursnv50.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/cursnv50.c
index 82ff82d8c1ab..ab51121b7982 100644
--- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/cursnv50.c
+++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/cursnv50.c
@@ -22,6 +22,7 @@
22 * Authors: Ben Skeggs 22 * Authors: Ben Skeggs
23 */ 23 */
24#include "channv50.h" 24#include "channv50.h"
25#include "head.h"
25#include "rootnv50.h" 26#include "rootnv50.h"
26 27
27#include <core/client.h> 28#include <core/client.h>
@@ -48,7 +49,7 @@ nv50_disp_curs_new(const struct nv50_disp_chan_func *func,
48 if (!(ret = nvif_unpack(ret, &data, &size, args->v0, 0, 0, false))) { 49 if (!(ret = nvif_unpack(ret, &data, &size, args->v0, 0, 0, false))) {
49 nvif_ioctl(parent, "create disp cursor vers %d head %d\n", 50 nvif_ioctl(parent, "create disp cursor vers %d head %d\n",
50 args->v0.version, args->v0.head); 51 args->v0.version, args->v0.head);
51 if (args->v0.head > disp->base.head.nr) 52 if (!nvkm_head_find(&disp->base, args->v0.head))
52 return -EINVAL; 53 return -EINVAL;
53 head = args->v0.head; 54 head = args->v0.head;
54 } else 55 } else
diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/dacgf119.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/dacgf119.c
new file mode 100644
index 000000000000..dbd032ef352a
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/dacgf119.c
@@ -0,0 +1,65 @@
1/*
2 * Copyright 2017 Red Hat Inc.
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#include "ior.h"
23
24static void
25gf119_dac_clock(struct nvkm_ior *dac)
26{
27 struct nvkm_device *device = dac->disp->engine.subdev.device;
28 const u32 doff = nv50_ior_base(dac);
29 nvkm_mask(device, 0x612280 + doff, 0x07070707, 0x00000000);
30}
31
32static void
33gf119_dac_state(struct nvkm_ior *dac, struct nvkm_ior_state *state)
34{
35 struct nvkm_device *device = dac->disp->engine.subdev.device;
36 const u32 coff = (state == &dac->asy) * 0x20000 + dac->id * 0x20;
37 u32 ctrl = nvkm_rd32(device, 0x640180 + coff);
38
39 state->proto_evo = (ctrl & 0x00000f00) >> 8;
40 switch (state->proto_evo) {
41 case 0: state->proto = CRT; break;
42 default:
43 state->proto = UNKNOWN;
44 break;
45 }
46
47 state->head = ctrl & 0x0000000f;
48}
49
50static const struct nvkm_ior_func
51gf119_dac = {
52 .state = gf119_dac_state,
53 .power = nv50_dac_power,
54 .sense = nv50_dac_sense,
55 .clock = gf119_dac_clock,
56};
57
58int
59gf119_dac_new(struct nvkm_disp *disp, int id)
60{
61 struct nvkm_device *device = disp->engine.subdev.device;
62 if (!(nvkm_rd32(device, 0x612004) & (0x00000010 << id)))
63 return 0;
64 return nvkm_ior_new_(&gf119_dac, disp, DAC, id);
65}
diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/dacnv50.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/dacnv50.c
index c9b78b8f9c87..85e692b12260 100644
--- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/dacnv50.c
+++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/dacnv50.c
@@ -21,106 +21,96 @@
21 * 21 *
22 * Authors: Ben Skeggs 22 * Authors: Ben Skeggs
23 */ 23 */
24#include "nv50.h" 24#include "ior.h"
25#include "outp.h"
26 25
27#include <core/client.h>
28#include <subdev/timer.h> 26#include <subdev/timer.h>
29 27
30#include <nvif/cl5070.h> 28static void
31#include <nvif/unpack.h> 29nv50_dac_clock(struct nvkm_ior *dac)
32
33int
34nv50_dac_power(NV50_DISP_MTHD_V1)
35{ 30{
36 struct nvkm_device *device = disp->base.engine.subdev.device; 31 struct nvkm_device *device = dac->disp->engine.subdev.device;
37 const u32 doff = outp->or * 0x800; 32 const u32 doff = nv50_ior_base(dac);
38 union { 33 nvkm_mask(device, 0x614280 + doff, 0x07070707, 0x00000000);
39 struct nv50_disp_dac_pwr_v0 v0;
40 } *args = data;
41 u32 stat;
42 int ret = -ENOSYS;
43
44 nvif_ioctl(object, "disp dac pwr size %d\n", size);
45 if (!(ret = nvif_unpack(ret, &data, &size, args->v0, 0, 0, false))) {
46 nvif_ioctl(object, "disp dac pwr vers %d state %d data %d "
47 "vsync %d hsync %d\n",
48 args->v0.version, args->v0.state, args->v0.data,
49 args->v0.vsync, args->v0.hsync);
50 stat = 0x00000040 * !args->v0.state;
51 stat |= 0x00000010 * !args->v0.data;
52 stat |= 0x00000004 * !args->v0.vsync;
53 stat |= 0x00000001 * !args->v0.hsync;
54 } else
55 return ret;
56
57 nvkm_msec(device, 2000,
58 if (!(nvkm_rd32(device, 0x61a004 + doff) & 0x80000000))
59 break;
60 );
61 nvkm_mask(device, 0x61a004 + doff, 0xc000007f, 0x80000000 | stat);
62 nvkm_msec(device, 2000,
63 if (!(nvkm_rd32(device, 0x61a004 + doff) & 0x80000000))
64 break;
65 );
66 return 0;
67} 34}
68 35
69int 36int
70nv50_dac_sense(NV50_DISP_MTHD_V1) 37nv50_dac_sense(struct nvkm_ior *dac, u32 loadval)
71{ 38{
72 struct nvkm_subdev *subdev = &disp->base.engine.subdev; 39 struct nvkm_device *device = dac->disp->engine.subdev.device;
73 struct nvkm_device *device = subdev->device; 40 const u32 doff = nv50_ior_base(dac);
74 union {
75 struct nv50_disp_dac_load_v0 v0;
76 } *args = data;
77 const u32 doff = outp->or * 0x800;
78 u32 loadval;
79 int ret = -ENOSYS;
80 41
81 nvif_ioctl(object, "disp dac load size %d\n", size); 42 dac->func->power(dac, false, true, false, false, false);
82 if (!(ret = nvif_unpack(ret, &data, &size, args->v0, 0, 0, false))) {
83 nvif_ioctl(object, "disp dac load vers %d data %08x\n",
84 args->v0.version, args->v0.data);
85 if (args->v0.data & 0xfff00000)
86 return -EINVAL;
87 loadval = args->v0.data;
88 } else
89 return ret;
90
91 nvkm_mask(device, 0x61a004 + doff, 0x807f0000, 0x80150000);
92 nvkm_msec(device, 2000,
93 if (!(nvkm_rd32(device, 0x61a004 + doff) & 0x80000000))
94 break;
95 );
96 43
97 nvkm_wr32(device, 0x61a00c + doff, 0x00100000 | loadval); 44 nvkm_wr32(device, 0x61a00c + doff, 0x00100000 | loadval);
98 mdelay(9); 45 mdelay(9);
99 udelay(500); 46 udelay(500);
100 loadval = nvkm_mask(device, 0x61a00c + doff, 0xffffffff, 0x00000000); 47 loadval = nvkm_mask(device, 0x61a00c + doff, 0xffffffff, 0x00000000);
101 48
102 nvkm_mask(device, 0x61a004 + doff, 0x807f0000, 0x80550000); 49 dac->func->power(dac, false, false, false, false, false);
50 if (!(loadval & 0x80000000))
51 return -ETIMEDOUT;
52
53 return (loadval & 0x38000000) >> 27;
54}
55
56static void
57nv50_dac_power_wait(struct nvkm_device *device, const u32 doff)
58{
103 nvkm_msec(device, 2000, 59 nvkm_msec(device, 2000,
104 if (!(nvkm_rd32(device, 0x61a004 + doff) & 0x80000000)) 60 if (!(nvkm_rd32(device, 0x61a004 + doff) & 0x80000000))
105 break; 61 break;
106 ); 62 );
63}
107 64
108 nvkm_debug(subdev, "DAC%d sense: %08x\n", outp->or, loadval); 65void
109 if (!(loadval & 0x80000000)) 66nv50_dac_power(struct nvkm_ior *dac, bool normal, bool pu,
110 return -ETIMEDOUT; 67 bool data, bool vsync, bool hsync)
68{
69 struct nvkm_device *device = dac->disp->engine.subdev.device;
70 const u32 doff = nv50_ior_base(dac);
71 const u32 shift = normal ? 0 : 16;
72 const u32 state = 0x80000000 | (0x00000040 * ! pu |
73 0x00000010 * ! data |
74 0x00000004 * ! vsync |
75 0x00000001 * ! hsync) << shift;
76 const u32 field = 0xc0000000 | (0x00000055 << shift);
77
78 nv50_dac_power_wait(device, doff);
79 nvkm_mask(device, 0x61a004 + doff, field, state);
80 nv50_dac_power_wait(device, doff);
81}
82
83static void
84nv50_dac_state(struct nvkm_ior *dac, struct nvkm_ior_state *state)
85{
86 struct nvkm_device *device = dac->disp->engine.subdev.device;
87 const u32 coff = dac->id * 8 + (state == &dac->arm) * 4;
88 u32 ctrl = nvkm_rd32(device, 0x610b58 + coff);
89
90 state->proto_evo = (ctrl & 0x00000f00) >> 8;
91 switch (state->proto_evo) {
92 case 0: state->proto = CRT; break;
93 default:
94 state->proto = UNKNOWN;
95 break;
96 }
111 97
112 args->v0.load = (loadval & 0x38000000) >> 27; 98 state->head = ctrl & 0x00000003;
113 return 0;
114} 99}
115 100
116static const struct nvkm_output_func 101static const struct nvkm_ior_func
117nv50_dac_output_func = { 102nv50_dac = {
103 .state = nv50_dac_state,
104 .power = nv50_dac_power,
105 .sense = nv50_dac_sense,
106 .clock = nv50_dac_clock,
118}; 107};
119 108
120int 109int
121nv50_dac_output_new(struct nvkm_disp *disp, int index, 110nv50_dac_new(struct nvkm_disp *disp, int id)
122 struct dcb_output *dcbE, struct nvkm_output **poutp)
123{ 111{
124 return nvkm_output_new_(&nv50_dac_output_func, disp, 112 struct nvkm_device *device = disp->engine.subdev.device;
125 index, dcbE, poutp); 113 if (!(nvkm_rd32(device, 0x610184) & (0x00100000 << id)))
114 return 0;
115 return nvkm_ior_new_(&nv50_dac, disp, DAC, id);
126} 116}
diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/dp.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/dp.c
new file mode 100644
index 000000000000..7c5bed29ffef
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/dp.c
@@ -0,0 +1,652 @@
1/*
2 * Copyright 2014 Red Hat Inc.
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: Ben Skeggs
23 */
24#include "dp.h"
25#include "conn.h"
26#include "head.h"
27#include "ior.h"
28
29#include <subdev/bios.h>
30#include <subdev/bios/init.h>
31#include <subdev/i2c.h>
32
33#include <nvif/event.h>
34
35struct lt_state {
36 struct nvkm_dp *dp;
37 u8 stat[6];
38 u8 conf[4];
39 bool pc2;
40 u8 pc2stat;
41 u8 pc2conf[2];
42};
43
44static int
45nvkm_dp_train_sense(struct lt_state *lt, bool pc, u32 delay)
46{
47 struct nvkm_dp *dp = lt->dp;
48 int ret;
49
50 if (dp->dpcd[DPCD_RC0E_AUX_RD_INTERVAL])
51 mdelay(dp->dpcd[DPCD_RC0E_AUX_RD_INTERVAL] * 4);
52 else
53 udelay(delay);
54
55 ret = nvkm_rdaux(dp->aux, DPCD_LS02, lt->stat, 6);
56 if (ret)
57 return ret;
58
59 if (pc) {
60 ret = nvkm_rdaux(dp->aux, DPCD_LS0C, &lt->pc2stat, 1);
61 if (ret)
62 lt->pc2stat = 0x00;
63 OUTP_TRACE(&dp->outp, "status %6ph pc2 %02x",
64 lt->stat, lt->pc2stat);
65 } else {
66 OUTP_TRACE(&dp->outp, "status %6ph", lt->stat);
67 }
68
69 return 0;
70}
71
72static int
73nvkm_dp_train_drive(struct lt_state *lt, bool pc)
74{
75 struct nvkm_dp *dp = lt->dp;
76 struct nvkm_ior *ior = dp->outp.ior;
77 struct nvkm_bios *bios = ior->disp->engine.subdev.device->bios;
78 struct nvbios_dpout info;
79 struct nvbios_dpcfg ocfg;
80 u8 ver, hdr, cnt, len;
81 u32 data;
82 int ret, i;
83
84 for (i = 0; i < ior->dp.nr; i++) {
85 u8 lane = (lt->stat[4 + (i >> 1)] >> ((i & 1) * 4)) & 0xf;
86 u8 lpc2 = (lt->pc2stat >> (i * 2)) & 0x3;
87 u8 lpre = (lane & 0x0c) >> 2;
88 u8 lvsw = (lane & 0x03) >> 0;
89 u8 hivs = 3 - lpre;
90 u8 hipe = 3;
91 u8 hipc = 3;
92
93 if (lpc2 >= hipc)
94 lpc2 = hipc | DPCD_LC0F_LANE0_MAX_POST_CURSOR2_REACHED;
95 if (lpre >= hipe) {
96 lpre = hipe | DPCD_LC03_MAX_SWING_REACHED; /* yes. */
97 lvsw = hivs = 3 - (lpre & 3);
98 } else
99 if (lvsw >= hivs) {
100 lvsw = hivs | DPCD_LC03_MAX_SWING_REACHED;
101 }
102
103 lt->conf[i] = (lpre << 3) | lvsw;
104 lt->pc2conf[i >> 1] |= lpc2 << ((i & 1) * 4);
105
106 OUTP_TRACE(&dp->outp, "config lane %d %02x %02x",
107 i, lt->conf[i], lpc2);
108
109 data = nvbios_dpout_match(bios, dp->outp.info.hasht,
110 dp->outp.info.hashm,
111 &ver, &hdr, &cnt, &len, &info);
112 if (!data)
113 continue;
114
115 data = nvbios_dpcfg_match(bios, data, lpc2 & 3, lvsw & 3,
116 lpre & 3, &ver, &hdr, &cnt, &len,
117 &ocfg);
118 if (!data)
119 continue;
120
121 ior->func->dp.drive(ior, i, ocfg.pc, ocfg.dc,
122 ocfg.pe, ocfg.tx_pu);
123 }
124
125 ret = nvkm_wraux(dp->aux, DPCD_LC03(0), lt->conf, 4);
126 if (ret)
127 return ret;
128
129 if (pc) {
130 ret = nvkm_wraux(dp->aux, DPCD_LC0F, lt->pc2conf, 2);
131 if (ret)
132 return ret;
133 }
134
135 return 0;
136}
137
138static void
139nvkm_dp_train_pattern(struct lt_state *lt, u8 pattern)
140{
141 struct nvkm_dp *dp = lt->dp;
142 u8 sink_tp;
143
144 OUTP_TRACE(&dp->outp, "training pattern %d", pattern);
145 dp->outp.ior->func->dp.pattern(dp->outp.ior, pattern);
146
147 nvkm_rdaux(dp->aux, DPCD_LC02, &sink_tp, 1);
148 sink_tp &= ~DPCD_LC02_TRAINING_PATTERN_SET;
149 sink_tp |= pattern;
150 nvkm_wraux(dp->aux, DPCD_LC02, &sink_tp, 1);
151}
152
153static int
154nvkm_dp_train_eq(struct lt_state *lt)
155{
156 bool eq_done = false, cr_done = true;
157 int tries = 0, i;
158
159 if (lt->dp->dpcd[DPCD_RC02] & DPCD_RC02_TPS3_SUPPORTED)
160 nvkm_dp_train_pattern(lt, 3);
161 else
162 nvkm_dp_train_pattern(lt, 2);
163
164 do {
165 if ((tries &&
166 nvkm_dp_train_drive(lt, lt->pc2)) ||
167 nvkm_dp_train_sense(lt, lt->pc2, 400))
168 break;
169
170 eq_done = !!(lt->stat[2] & DPCD_LS04_INTERLANE_ALIGN_DONE);
171 for (i = 0; i < lt->dp->outp.ior->dp.nr && eq_done; i++) {
172 u8 lane = (lt->stat[i >> 1] >> ((i & 1) * 4)) & 0xf;
173 if (!(lane & DPCD_LS02_LANE0_CR_DONE))
174 cr_done = false;
175 if (!(lane & DPCD_LS02_LANE0_CHANNEL_EQ_DONE) ||
176 !(lane & DPCD_LS02_LANE0_SYMBOL_LOCKED))
177 eq_done = false;
178 }
179 } while (!eq_done && cr_done && ++tries <= 5);
180
181 return eq_done ? 0 : -1;
182}
183
184static int
185nvkm_dp_train_cr(struct lt_state *lt)
186{
187 bool cr_done = false, abort = false;
188 int voltage = lt->conf[0] & DPCD_LC03_VOLTAGE_SWING_SET;
189 int tries = 0, i;
190
191 nvkm_dp_train_pattern(lt, 1);
192
193 do {
194 if (nvkm_dp_train_drive(lt, false) ||
195 nvkm_dp_train_sense(lt, false, 100))
196 break;
197
198 cr_done = true;
199 for (i = 0; i < lt->dp->outp.ior->dp.nr; i++) {
200 u8 lane = (lt->stat[i >> 1] >> ((i & 1) * 4)) & 0xf;
201 if (!(lane & DPCD_LS02_LANE0_CR_DONE)) {
202 cr_done = false;
203 if (lt->conf[i] & DPCD_LC03_MAX_SWING_REACHED)
204 abort = true;
205 break;
206 }
207 }
208
209 if ((lt->conf[0] & DPCD_LC03_VOLTAGE_SWING_SET) != voltage) {
210 voltage = lt->conf[0] & DPCD_LC03_VOLTAGE_SWING_SET;
211 tries = 0;
212 }
213 } while (!cr_done && !abort && ++tries < 5);
214
215 return cr_done ? 0 : -1;
216}
217
218static int
219nvkm_dp_train_links(struct nvkm_dp *dp)
220{
221 struct nvkm_ior *ior = dp->outp.ior;
222 struct nvkm_disp *disp = dp->outp.disp;
223 struct nvkm_subdev *subdev = &disp->engine.subdev;
224 struct nvkm_bios *bios = subdev->device->bios;
225 struct lt_state lt = {
226 .dp = dp,
227 };
228 u32 lnkcmp;
229 u8 sink[2];
230 int ret;
231
232 OUTP_DBG(&dp->outp, "training %d x %d MB/s",
233 ior->dp.nr, ior->dp.bw * 27);
234
235 /* Intersect misc. capabilities of the OR and sink. */
236 if (disp->engine.subdev.device->chipset < 0xd0)
237 dp->dpcd[DPCD_RC02] &= ~DPCD_RC02_TPS3_SUPPORTED;
238 lt.pc2 = dp->dpcd[DPCD_RC02] & DPCD_RC02_TPS3_SUPPORTED;
239
240 /* Set desired link configuration on the source. */
241 if ((lnkcmp = lt.dp->info.lnkcmp)) {
242 if (dp->version < 0x30) {
243 while ((ior->dp.bw * 2700) < nvbios_rd16(bios, lnkcmp))
244 lnkcmp += 4;
245 lnkcmp = nvbios_rd16(bios, lnkcmp + 2);
246 } else {
247 while (ior->dp.bw < nvbios_rd08(bios, lnkcmp))
248 lnkcmp += 3;
249 lnkcmp = nvbios_rd16(bios, lnkcmp + 1);
250 }
251
252 nvbios_init(subdev, lnkcmp,
253 init.outp = &dp->outp.info;
254 init.or = ior->id;
255 init.link = ior->asy.link;
256 );
257 }
258
259 ret = ior->func->dp.links(ior, dp->aux);
260 if (ret) {
261 if (ret < 0) {
262 OUTP_ERR(&dp->outp, "train failed with %d", ret);
263 return ret;
264 }
265 return 0;
266 }
267
268 ior->func->dp.power(ior, ior->dp.nr);
269
270 /* Set desired link configuration on the sink. */
271 sink[0] = ior->dp.bw;
272 sink[1] = ior->dp.nr;
273 if (ior->dp.ef)
274 sink[1] |= DPCD_LC01_ENHANCED_FRAME_EN;
275
276 ret = nvkm_wraux(dp->aux, DPCD_LC00_LINK_BW_SET, sink, 2);
277 if (ret)
278 return ret;
279
280 /* Attempt to train the link in this configuration. */
281 memset(lt.stat, 0x00, sizeof(lt.stat));
282 ret = nvkm_dp_train_cr(&lt);
283 if (ret == 0)
284 ret = nvkm_dp_train_eq(&lt);
285 nvkm_dp_train_pattern(&lt, 0);
286 return ret;
287}
288
289static void
290nvkm_dp_train_fini(struct nvkm_dp *dp)
291{
292 /* Execute AfterLinkTraining script from DP Info table. */
293 nvbios_init(&dp->outp.disp->engine.subdev, dp->info.script[1],
294 init.outp = &dp->outp.info;
295 init.or = dp->outp.ior->id;
296 init.link = dp->outp.ior->asy.link;
297 );
298}
299
300static void
301nvkm_dp_train_init(struct nvkm_dp *dp)
302{
303 /* Execute EnableSpread/DisableSpread script from DP Info table. */
304 if (dp->dpcd[DPCD_RC03] & DPCD_RC03_MAX_DOWNSPREAD) {
305 nvbios_init(&dp->outp.disp->engine.subdev, dp->info.script[2],
306 init.outp = &dp->outp.info;
307 init.or = dp->outp.ior->id;
308 init.link = dp->outp.ior->asy.link;
309 );
310 } else {
311 nvbios_init(&dp->outp.disp->engine.subdev, dp->info.script[3],
312 init.outp = &dp->outp.info;
313 init.or = dp->outp.ior->id;
314 init.link = dp->outp.ior->asy.link;
315 );
316 }
317
318 /* Execute BeforeLinkTraining script from DP Info table. */
319 nvbios_init(&dp->outp.disp->engine.subdev, dp->info.script[0],
320 init.outp = &dp->outp.info;
321 init.or = dp->outp.ior->id;
322 init.link = dp->outp.ior->asy.link;
323 );
324}
325
326static const struct dp_rates {
327 u32 rate;
328 u8 bw;
329 u8 nr;
330} nvkm_dp_rates[] = {
331 { 2160000, 0x14, 4 },
332 { 1080000, 0x0a, 4 },
333 { 1080000, 0x14, 2 },
334 { 648000, 0x06, 4 },
335 { 540000, 0x0a, 2 },
336 { 540000, 0x14, 1 },
337 { 324000, 0x06, 2 },
338 { 270000, 0x0a, 1 },
339 { 162000, 0x06, 1 },
340 {}
341};
342
343static int
344nvkm_dp_train(struct nvkm_dp *dp, u32 dataKBps)
345{
346 struct nvkm_ior *ior = dp->outp.ior;
347 const u8 sink_nr = dp->dpcd[DPCD_RC02] & DPCD_RC02_MAX_LANE_COUNT;
348 const u8 sink_bw = dp->dpcd[DPCD_RC01_MAX_LINK_RATE];
349 const u8 outp_nr = dp->outp.info.dpconf.link_nr;
350 const u8 outp_bw = dp->outp.info.dpconf.link_bw;
351 const struct dp_rates *failsafe = NULL, *cfg;
352 int ret = -EINVAL;
353 u8 pwr;
354
355 /* Find the lowest configuration of the OR that can support
356 * the required link rate.
357 *
358 * We will refuse to program the OR to lower rates, even if
359 * link training fails at higher rates (or even if the sink
360 * can't support the rate at all, though the DD is supposed
361 * to prevent such situations from happening).
362 *
363 * Attempting to do so can cause the entire display to hang,
364 * and it's better to have a failed modeset than that.
365 */
366 for (cfg = nvkm_dp_rates; cfg->rate; cfg++) {
367 if (cfg->nr <= outp_nr && cfg->nr <= outp_bw)
368 failsafe = cfg;
369 if (failsafe && cfg[1].rate < dataKBps)
370 break;
371 }
372
373 if (WARN_ON(!failsafe))
374 return ret;
375
376 /* Ensure sink is not in a low-power state. */
377 if (!nvkm_rdaux(dp->aux, DPCD_SC00, &pwr, 1)) {
378 if ((pwr & DPCD_SC00_SET_POWER) != DPCD_SC00_SET_POWER_D0) {
379 pwr &= ~DPCD_SC00_SET_POWER;
380 pwr |= DPCD_SC00_SET_POWER_D0;
381 nvkm_wraux(dp->aux, DPCD_SC00, &pwr, 1);
382 }
383 }
384
385 /* Link training. */
386 OUTP_DBG(&dp->outp, "training (min: %d x %d MB/s)",
387 failsafe->nr, failsafe->bw * 27);
388 nvkm_dp_train_init(dp);
389 for (cfg = nvkm_dp_rates; ret < 0 && cfg <= failsafe; cfg++) {
390 /* Skip configurations not supported by both OR and sink. */
391 if ((cfg->nr > outp_nr || cfg->bw > outp_bw ||
392 cfg->nr > sink_nr || cfg->bw > sink_bw)) {
393 if (cfg != failsafe)
394 continue;
395 OUTP_ERR(&dp->outp, "link rate unsupported by sink");
396 }
397 ior->dp.mst = dp->lt.mst;
398 ior->dp.ef = dp->dpcd[DPCD_RC02] & DPCD_RC02_ENHANCED_FRAME_CAP;
399 ior->dp.bw = cfg->bw;
400 ior->dp.nr = cfg->nr;
401
402 /* Program selected link configuration. */
403 ret = nvkm_dp_train_links(dp);
404 }
405 nvkm_dp_train_fini(dp);
406 if (ret < 0)
407 OUTP_ERR(&dp->outp, "training failed");
408 else
409 OUTP_DBG(&dp->outp, "training done");
410 atomic_set(&dp->lt.done, 1);
411 return ret;
412}
413
414static void
415nvkm_dp_release(struct nvkm_outp *outp, struct nvkm_ior *ior)
416{
417 struct nvkm_dp *dp = nvkm_dp(outp);
418
419 /* Prevent link from being retrained if sink sends an IRQ. */
420 atomic_set(&dp->lt.done, 0);
421 ior->dp.nr = 0;
422
423 /* Execute DisableLT script from DP Info Table. */
424 nvbios_init(&ior->disp->engine.subdev, dp->info.script[4],
425 init.outp = &dp->outp.info;
426 init.or = ior->id;
427 init.link = ior->arm.link;
428 );
429}
430
431static int
432nvkm_dp_acquire(struct nvkm_outp *outp)
433{
434 struct nvkm_dp *dp = nvkm_dp(outp);
435 struct nvkm_ior *ior = dp->outp.ior;
436 struct nvkm_head *head;
437 bool retrain = true;
438 u32 datakbps = 0;
439 u32 dataKBps;
440 u32 linkKBps;
441 u8 stat[3];
442 int ret, i;
443
444 mutex_lock(&dp->mutex);
445
446 /* Check that link configuration meets current requirements. */
447 list_for_each_entry(head, &outp->disp->head, head) {
448 if (ior->asy.head & (1 << head->id)) {
449 u32 khz = (head->asy.hz >> ior->asy.rgdiv) / 1000;
450 datakbps += khz * head->asy.or.depth;
451 }
452 }
453
454 linkKBps = ior->dp.bw * 27000 * ior->dp.nr;
455 dataKBps = DIV_ROUND_UP(datakbps, 8);
456 OUTP_DBG(&dp->outp, "data %d KB/s link %d KB/s mst %d->%d",
457 dataKBps, linkKBps, ior->dp.mst, dp->lt.mst);
458 if (linkKBps < dataKBps || ior->dp.mst != dp->lt.mst) {
459 OUTP_DBG(&dp->outp, "link requirements changed");
460 goto done;
461 }
462
463 /* Check that link is still trained. */
464 ret = nvkm_rdaux(dp->aux, DPCD_LS02, stat, 3);
465 if (ret) {
466 OUTP_DBG(&dp->outp,
467 "failed to read link status, assuming no sink");
468 goto done;
469 }
470
471 if (stat[2] & DPCD_LS04_INTERLANE_ALIGN_DONE) {
472 for (i = 0; i < ior->dp.nr; i++) {
473 u8 lane = (stat[i >> 1] >> ((i & 1) * 4)) & 0x0f;
474 if (!(lane & DPCD_LS02_LANE0_CR_DONE) ||
475 !(lane & DPCD_LS02_LANE0_CHANNEL_EQ_DONE) ||
476 !(lane & DPCD_LS02_LANE0_SYMBOL_LOCKED)) {
477 OUTP_DBG(&dp->outp,
478 "lane %d not equalised", lane);
479 goto done;
480 }
481 }
482 retrain = false;
483 } else {
484 OUTP_DBG(&dp->outp, "no inter-lane alignment");
485 }
486
487done:
488 if (retrain || !atomic_read(&dp->lt.done))
489 ret = nvkm_dp_train(dp, dataKBps);
490 mutex_unlock(&dp->mutex);
491 return ret;
492}
493
494static void
495nvkm_dp_enable(struct nvkm_dp *dp, bool enable)
496{
497 struct nvkm_i2c_aux *aux = dp->aux;
498
499 if (enable) {
500 if (!dp->present) {
501 OUTP_DBG(&dp->outp, "aux power -> always");
502 nvkm_i2c_aux_monitor(aux, true);
503 dp->present = true;
504 }
505
506 if (!nvkm_rdaux(aux, DPCD_RC00_DPCD_REV, dp->dpcd,
507 sizeof(dp->dpcd)))
508 return;
509 }
510
511 if (dp->present) {
512 OUTP_DBG(&dp->outp, "aux power -> demand");
513 nvkm_i2c_aux_monitor(aux, false);
514 dp->present = false;
515 }
516
517 atomic_set(&dp->lt.done, 0);
518}
519
520static int
521nvkm_dp_hpd(struct nvkm_notify *notify)
522{
523 const struct nvkm_i2c_ntfy_rep *line = notify->data;
524 struct nvkm_dp *dp = container_of(notify, typeof(*dp), hpd);
525 struct nvkm_conn *conn = dp->outp.conn;
526 struct nvkm_disp *disp = dp->outp.disp;
527 struct nvif_notify_conn_rep_v0 rep = {};
528
529 OUTP_DBG(&dp->outp, "HPD: %d", line->mask);
530 if (line->mask & NVKM_I2C_IRQ) {
531 if (atomic_read(&dp->lt.done))
532 dp->outp.func->acquire(&dp->outp);
533 rep.mask |= NVIF_NOTIFY_CONN_V0_IRQ;
534 } else {
535 nvkm_dp_enable(dp, true);
536 }
537
538 if (line->mask & NVKM_I2C_UNPLUG)
539 rep.mask |= NVIF_NOTIFY_CONN_V0_UNPLUG;
540 if (line->mask & NVKM_I2C_PLUG)
541 rep.mask |= NVIF_NOTIFY_CONN_V0_PLUG;
542
543 nvkm_event_send(&disp->hpd, rep.mask, conn->index, &rep, sizeof(rep));
544 return NVKM_NOTIFY_KEEP;
545}
546
547static void
548nvkm_dp_fini(struct nvkm_outp *outp)
549{
550 struct nvkm_dp *dp = nvkm_dp(outp);
551 nvkm_notify_put(&dp->hpd);
552 nvkm_dp_enable(dp, false);
553}
554
555static void
556nvkm_dp_init(struct nvkm_outp *outp)
557{
558 struct nvkm_dp *dp = nvkm_dp(outp);
559 nvkm_notify_put(&dp->outp.conn->hpd);
560 nvkm_dp_enable(dp, true);
561 nvkm_notify_get(&dp->hpd);
562}
563
564static void *
565nvkm_dp_dtor(struct nvkm_outp *outp)
566{
567 struct nvkm_dp *dp = nvkm_dp(outp);
568 nvkm_notify_fini(&dp->hpd);
569 return dp;
570}
571
572static const struct nvkm_outp_func
573nvkm_dp_func = {
574 .dtor = nvkm_dp_dtor,
575 .init = nvkm_dp_init,
576 .fini = nvkm_dp_fini,
577 .acquire = nvkm_dp_acquire,
578 .release = nvkm_dp_release,
579};
580
581static int
582nvkm_dp_ctor(struct nvkm_disp *disp, int index, struct dcb_output *dcbE,
583 struct nvkm_i2c_aux *aux, struct nvkm_dp *dp)
584{
585 struct nvkm_device *device = disp->engine.subdev.device;
586 struct nvkm_bios *bios = device->bios;
587 struct nvkm_i2c *i2c = device->i2c;
588 u8 hdr, cnt, len;
589 u32 data;
590 int ret;
591
592 ret = nvkm_outp_ctor(&nvkm_dp_func, disp, index, dcbE, &dp->outp);
593 if (ret)
594 return ret;
595
596 dp->aux = aux;
597 if (!dp->aux) {
598 OUTP_ERR(&dp->outp, "no aux");
599 return -EINVAL;
600 }
601
602 /* bios data is not optional */
603 data = nvbios_dpout_match(bios, dp->outp.info.hasht,
604 dp->outp.info.hashm, &dp->version,
605 &hdr, &cnt, &len, &dp->info);
606 if (!data) {
607 OUTP_ERR(&dp->outp, "no bios dp data");
608 return -EINVAL;
609 }
610
611 OUTP_DBG(&dp->outp, "bios dp %02x %02x %02x %02x",
612 dp->version, hdr, cnt, len);
613
614 /* hotplug detect, replaces gpio-based mechanism with aux events */
615 ret = nvkm_notify_init(NULL, &i2c->event, nvkm_dp_hpd, true,
616 &(struct nvkm_i2c_ntfy_req) {
617 .mask = NVKM_I2C_PLUG | NVKM_I2C_UNPLUG |
618 NVKM_I2C_IRQ,
619 .port = dp->aux->id,
620 },
621 sizeof(struct nvkm_i2c_ntfy_req),
622 sizeof(struct nvkm_i2c_ntfy_rep),
623 &dp->hpd);
624 if (ret) {
625 OUTP_ERR(&dp->outp, "error monitoring aux hpd: %d", ret);
626 return ret;
627 }
628
629 mutex_init(&dp->mutex);
630 atomic_set(&dp->lt.done, 0);
631 return 0;
632}
633
634int
635nvkm_dp_new(struct nvkm_disp *disp, int index, struct dcb_output *dcbE,
636 struct nvkm_outp **poutp)
637{
638 struct nvkm_i2c *i2c = disp->engine.subdev.device->i2c;
639 struct nvkm_i2c_aux *aux;
640 struct nvkm_dp *dp;
641
642 if (dcbE->location == 0)
643 aux = nvkm_i2c_aux_find(i2c, NVKM_I2C_AUX_CCB(dcbE->i2c_index));
644 else
645 aux = nvkm_i2c_aux_find(i2c, NVKM_I2C_AUX_EXT(dcbE->extdev));
646
647 if (!(dp = kzalloc(sizeof(*dp), GFP_KERNEL)))
648 return -ENOMEM;
649 *poutp = &dp->outp;
650
651 return nvkm_dp_ctor(disp, index, dcbE, aux, dp);
652}
diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/dport.h b/drivers/gpu/drm/nouveau/nvkm/engine/disp/dp.h
index baf1dd9ff975..59173c290525 100644
--- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/dport.h
+++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/dp.h
@@ -1,6 +1,36 @@
1#ifndef __NVKM_DISP_DPORT_H__ 1#ifndef __NVKM_DISP_DP_H__
2#define __NVKM_DISP_DPORT_H__ 2#define __NVKM_DISP_DP_H__
3struct nvkm_output_dp; 3#define nvkm_dp(p) container_of((p), struct nvkm_dp, outp)
4#include "outp.h"
5
6#include <core/notify.h>
7#include <subdev/bios.h>
8#include <subdev/bios/dp.h>
9
10struct nvkm_dp {
11 union {
12 struct nvkm_outp base;
13 struct nvkm_outp outp;
14 };
15
16 struct nvbios_dpout info;
17 u8 version;
18
19 struct nvkm_i2c_aux *aux;
20
21 struct nvkm_notify hpd;
22 bool present;
23 u8 dpcd[16];
24
25 struct mutex mutex;
26 struct {
27 atomic_t done;
28 bool mst;
29 } lt;
30};
31
32int nvkm_dp_new(struct nvkm_disp *, int index, struct dcb_output *,
33 struct nvkm_outp **);
4 34
5/* DPCD Receiver Capabilities */ 35/* DPCD Receiver Capabilities */
6#define DPCD_RC00_DPCD_REV 0x00000 36#define DPCD_RC00_DPCD_REV 0x00000
@@ -76,6 +106,4 @@ struct nvkm_output_dp;
76#define DPCD_SC00_SET_POWER 0x03 106#define DPCD_SC00_SET_POWER 0x03
77#define DPCD_SC00_SET_POWER_D0 0x01 107#define DPCD_SC00_SET_POWER_D0 0x01
78#define DPCD_SC00_SET_POWER_D3 0x03 108#define DPCD_SC00_SET_POWER_D3 0x03
79
80void nvkm_dp_train(struct nvkm_output_dp *);
81#endif 109#endif
diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/dport.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/dport.c
deleted file mode 100644
index 4a93ceb850ac..000000000000
--- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/dport.c
+++ /dev/null
@@ -1,401 +0,0 @@
1/*
2 * Copyright 2013 Red Hat Inc.
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: Ben Skeggs
23 */
24#include "dport.h"
25#include "outpdp.h"
26#include "nv50.h"
27
28#include <subdev/bios.h>
29#include <subdev/bios/init.h>
30#include <subdev/i2c.h>
31
32#include <nvif/class.h>
33
34/******************************************************************************
35 * link training
36 *****************************************************************************/
37struct dp_state {
38 struct nvkm_output_dp *outp;
39 int link_nr;
40 u32 link_bw;
41 u8 stat[6];
42 u8 conf[4];
43 bool pc2;
44 u8 pc2stat;
45 u8 pc2conf[2];
46};
47
48static int
49dp_set_link_config(struct dp_state *dp)
50{
51 struct nvkm_output_dp *outp = dp->outp;
52 struct nvkm_disp *disp = outp->base.disp;
53 struct nvkm_subdev *subdev = &disp->engine.subdev;
54 struct nvkm_bios *bios = subdev->device->bios;
55 struct nvbios_init init = {
56 .subdev = subdev,
57 .bios = bios,
58 .offset = 0x0000,
59 .outp = &outp->base.info,
60 .crtc = -1,
61 .execute = 1,
62 };
63 u32 lnkcmp;
64 u8 sink[2];
65 int ret;
66
67 OUTP_DBG(&outp->base, "%d lanes at %d KB/s", dp->link_nr, dp->link_bw);
68
69 /* set desired link configuration on the source */
70 if ((lnkcmp = dp->outp->info.lnkcmp)) {
71 if (outp->version < 0x30) {
72 while ((dp->link_bw / 10) < nvbios_rd16(bios, lnkcmp))
73 lnkcmp += 4;
74 init.offset = nvbios_rd16(bios, lnkcmp + 2);
75 } else {
76 while ((dp->link_bw / 27000) < nvbios_rd08(bios, lnkcmp))
77 lnkcmp += 3;
78 init.offset = nvbios_rd16(bios, lnkcmp + 1);
79 }
80
81 nvbios_exec(&init);
82 }
83
84 ret = outp->func->lnk_ctl(outp, dp->link_nr, dp->link_bw / 27000,
85 outp->dpcd[DPCD_RC02] &
86 DPCD_RC02_ENHANCED_FRAME_CAP);
87 if (ret) {
88 if (ret < 0)
89 OUTP_ERR(&outp->base, "lnk_ctl failed with %d", ret);
90 return ret;
91 }
92
93 outp->func->lnk_pwr(outp, dp->link_nr);
94
95 /* set desired link configuration on the sink */
96 sink[0] = dp->link_bw / 27000;
97 sink[1] = dp->link_nr;
98 if (outp->dpcd[DPCD_RC02] & DPCD_RC02_ENHANCED_FRAME_CAP)
99 sink[1] |= DPCD_LC01_ENHANCED_FRAME_EN;
100
101 return nvkm_wraux(outp->aux, DPCD_LC00_LINK_BW_SET, sink, 2);
102}
103
104static void
105dp_set_training_pattern(struct dp_state *dp, u8 pattern)
106{
107 struct nvkm_output_dp *outp = dp->outp;
108 u8 sink_tp;
109
110 OUTP_DBG(&outp->base, "training pattern %d", pattern);
111 outp->func->pattern(outp, pattern);
112
113 nvkm_rdaux(outp->aux, DPCD_LC02, &sink_tp, 1);
114 sink_tp &= ~DPCD_LC02_TRAINING_PATTERN_SET;
115 sink_tp |= pattern;
116 nvkm_wraux(outp->aux, DPCD_LC02, &sink_tp, 1);
117}
118
119static int
120dp_link_train_commit(struct dp_state *dp, bool pc)
121{
122 struct nvkm_output_dp *outp = dp->outp;
123 int ret, i;
124
125 for (i = 0; i < dp->link_nr; i++) {
126 u8 lane = (dp->stat[4 + (i >> 1)] >> ((i & 1) * 4)) & 0xf;
127 u8 lpc2 = (dp->pc2stat >> (i * 2)) & 0x3;
128 u8 lpre = (lane & 0x0c) >> 2;
129 u8 lvsw = (lane & 0x03) >> 0;
130 u8 hivs = 3 - lpre;
131 u8 hipe = 3;
132 u8 hipc = 3;
133
134 if (lpc2 >= hipc)
135 lpc2 = hipc | DPCD_LC0F_LANE0_MAX_POST_CURSOR2_REACHED;
136 if (lpre >= hipe) {
137 lpre = hipe | DPCD_LC03_MAX_SWING_REACHED; /* yes. */
138 lvsw = hivs = 3 - (lpre & 3);
139 } else
140 if (lvsw >= hivs) {
141 lvsw = hivs | DPCD_LC03_MAX_SWING_REACHED;
142 }
143
144 dp->conf[i] = (lpre << 3) | lvsw;
145 dp->pc2conf[i >> 1] |= lpc2 << ((i & 1) * 4);
146
147 OUTP_DBG(&outp->base, "config lane %d %02x %02x",
148 i, dp->conf[i], lpc2);
149 outp->func->drv_ctl(outp, i, lvsw & 3, lpre & 3, lpc2 & 3);
150 }
151
152 ret = nvkm_wraux(outp->aux, DPCD_LC03(0), dp->conf, 4);
153 if (ret)
154 return ret;
155
156 if (pc) {
157 ret = nvkm_wraux(outp->aux, DPCD_LC0F, dp->pc2conf, 2);
158 if (ret)
159 return ret;
160 }
161
162 return 0;
163}
164
165static int
166dp_link_train_update(struct dp_state *dp, bool pc, u32 delay)
167{
168 struct nvkm_output_dp *outp = dp->outp;
169 int ret;
170
171 if (outp->dpcd[DPCD_RC0E_AUX_RD_INTERVAL])
172 mdelay(outp->dpcd[DPCD_RC0E_AUX_RD_INTERVAL] * 4);
173 else
174 udelay(delay);
175
176 ret = nvkm_rdaux(outp->aux, DPCD_LS02, dp->stat, 6);
177 if (ret)
178 return ret;
179
180 if (pc) {
181 ret = nvkm_rdaux(outp->aux, DPCD_LS0C, &dp->pc2stat, 1);
182 if (ret)
183 dp->pc2stat = 0x00;
184 OUTP_DBG(&outp->base, "status %6ph pc2 %02x",
185 dp->stat, dp->pc2stat);
186 } else {
187 OUTP_DBG(&outp->base, "status %6ph", dp->stat);
188 }
189
190 return 0;
191}
192
193static int
194dp_link_train_cr(struct dp_state *dp)
195{
196 bool cr_done = false, abort = false;
197 int voltage = dp->conf[0] & DPCD_LC03_VOLTAGE_SWING_SET;
198 int tries = 0, i;
199
200 dp_set_training_pattern(dp, 1);
201
202 do {
203 if (dp_link_train_commit(dp, false) ||
204 dp_link_train_update(dp, false, 100))
205 break;
206
207 cr_done = true;
208 for (i = 0; i < dp->link_nr; i++) {
209 u8 lane = (dp->stat[i >> 1] >> ((i & 1) * 4)) & 0xf;
210 if (!(lane & DPCD_LS02_LANE0_CR_DONE)) {
211 cr_done = false;
212 if (dp->conf[i] & DPCD_LC03_MAX_SWING_REACHED)
213 abort = true;
214 break;
215 }
216 }
217
218 if ((dp->conf[0] & DPCD_LC03_VOLTAGE_SWING_SET) != voltage) {
219 voltage = dp->conf[0] & DPCD_LC03_VOLTAGE_SWING_SET;
220 tries = 0;
221 }
222 } while (!cr_done && !abort && ++tries < 5);
223
224 return cr_done ? 0 : -1;
225}
226
227static int
228dp_link_train_eq(struct dp_state *dp)
229{
230 struct nvkm_output_dp *outp = dp->outp;
231 bool eq_done = false, cr_done = true;
232 int tries = 0, i;
233
234 if (outp->dpcd[2] & DPCD_RC02_TPS3_SUPPORTED)
235 dp_set_training_pattern(dp, 3);
236 else
237 dp_set_training_pattern(dp, 2);
238
239 do {
240 if ((tries &&
241 dp_link_train_commit(dp, dp->pc2)) ||
242 dp_link_train_update(dp, dp->pc2, 400))
243 break;
244
245 eq_done = !!(dp->stat[2] & DPCD_LS04_INTERLANE_ALIGN_DONE);
246 for (i = 0; i < dp->link_nr && eq_done; i++) {
247 u8 lane = (dp->stat[i >> 1] >> ((i & 1) * 4)) & 0xf;
248 if (!(lane & DPCD_LS02_LANE0_CR_DONE))
249 cr_done = false;
250 if (!(lane & DPCD_LS02_LANE0_CHANNEL_EQ_DONE) ||
251 !(lane & DPCD_LS02_LANE0_SYMBOL_LOCKED))
252 eq_done = false;
253 }
254 } while (!eq_done && cr_done && ++tries <= 5);
255
256 return eq_done ? 0 : -1;
257}
258
259static void
260dp_link_train_init(struct dp_state *dp, bool spread)
261{
262 struct nvkm_output_dp *outp = dp->outp;
263 struct nvkm_disp *disp = outp->base.disp;
264 struct nvkm_subdev *subdev = &disp->engine.subdev;
265 struct nvbios_init init = {
266 .subdev = subdev,
267 .bios = subdev->device->bios,
268 .outp = &outp->base.info,
269 .crtc = -1,
270 .execute = 1,
271 };
272
273 /* set desired spread */
274 if (spread)
275 init.offset = outp->info.script[2];
276 else
277 init.offset = outp->info.script[3];
278 nvbios_exec(&init);
279
280 /* pre-train script */
281 init.offset = outp->info.script[0];
282 nvbios_exec(&init);
283}
284
285static void
286dp_link_train_fini(struct dp_state *dp)
287{
288 struct nvkm_output_dp *outp = dp->outp;
289 struct nvkm_disp *disp = outp->base.disp;
290 struct nvkm_subdev *subdev = &disp->engine.subdev;
291 struct nvbios_init init = {
292 .subdev = subdev,
293 .bios = subdev->device->bios,
294 .outp = &outp->base.info,
295 .crtc = -1,
296 .execute = 1,
297 };
298
299 /* post-train script */
300 init.offset = outp->info.script[1],
301 nvbios_exec(&init);
302}
303
304static const struct dp_rates {
305 u32 rate;
306 u8 bw;
307 u8 nr;
308} nvkm_dp_rates[] = {
309 { 2160000, 0x14, 4 },
310 { 1080000, 0x0a, 4 },
311 { 1080000, 0x14, 2 },
312 { 648000, 0x06, 4 },
313 { 540000, 0x0a, 2 },
314 { 540000, 0x14, 1 },
315 { 324000, 0x06, 2 },
316 { 270000, 0x0a, 1 },
317 { 162000, 0x06, 1 },
318 {}
319};
320
321void
322nvkm_dp_train(struct nvkm_output_dp *outp)
323{
324 struct nv50_disp *disp = nv50_disp(outp->base.disp);
325 const struct dp_rates *cfg = nvkm_dp_rates;
326 struct dp_state _dp = {
327 .outp = outp,
328 }, *dp = &_dp;
329 u32 datarate = 0;
330 u8 pwr;
331 int ret;
332
333 if (!outp->base.info.location && disp->func->sor.magic)
334 disp->func->sor.magic(&outp->base);
335
336 /* bring capabilities within encoder limits */
337 if (disp->base.engine.subdev.device->chipset < 0xd0)
338 outp->dpcd[2] &= ~DPCD_RC02_TPS3_SUPPORTED;
339 if ((outp->dpcd[2] & 0x1f) > outp->base.info.dpconf.link_nr) {
340 outp->dpcd[2] &= ~DPCD_RC02_MAX_LANE_COUNT;
341 outp->dpcd[2] |= outp->base.info.dpconf.link_nr;
342 }
343 if (outp->dpcd[1] > outp->base.info.dpconf.link_bw)
344 outp->dpcd[1] = outp->base.info.dpconf.link_bw;
345 dp->pc2 = outp->dpcd[2] & DPCD_RC02_TPS3_SUPPORTED;
346
347 /* restrict link config to the lowest required rate, if requested */
348 if (datarate) {
349 datarate = (datarate / 8) * 10; /* 8B/10B coding overhead */
350 while (cfg[1].rate >= datarate)
351 cfg++;
352 }
353 cfg--;
354
355 /* ensure sink is not in a low-power state */
356 if (!nvkm_rdaux(outp->aux, DPCD_SC00, &pwr, 1)) {
357 if ((pwr & DPCD_SC00_SET_POWER) != DPCD_SC00_SET_POWER_D0) {
358 pwr &= ~DPCD_SC00_SET_POWER;
359 pwr |= DPCD_SC00_SET_POWER_D0;
360 nvkm_wraux(outp->aux, DPCD_SC00, &pwr, 1);
361 }
362 }
363
364 /* enable down-spreading and execute pre-train script from vbios */
365 dp_link_train_init(dp, outp->dpcd[3] & 0x01);
366
367 while (ret = -EIO, (++cfg)->rate) {
368 /* select next configuration supported by encoder and sink */
369 while (cfg->nr > (outp->dpcd[2] & DPCD_RC02_MAX_LANE_COUNT) ||
370 cfg->bw > (outp->dpcd[DPCD_RC01_MAX_LINK_RATE]))
371 cfg++;
372 dp->link_bw = cfg->bw * 27000;
373 dp->link_nr = cfg->nr;
374
375 /* program selected link configuration */
376 ret = dp_set_link_config(dp);
377 if (ret == 0) {
378 /* attempt to train the link at this configuration */
379 memset(dp->stat, 0x00, sizeof(dp->stat));
380 if (!dp_link_train_cr(dp) &&
381 !dp_link_train_eq(dp))
382 break;
383 } else
384 if (ret) {
385 /* dp_set_link_config() handled training, or
386 * we failed to communicate with the sink.
387 */
388 break;
389 }
390 }
391
392 /* finish link training and execute post-train script from vbios */
393 dp_set_training_pattern(dp, 0);
394 if (ret < 0)
395 OUTP_ERR(&outp->base, "link training failed");
396
397 dp_link_train_fini(dp);
398
399 OUTP_DBG(&outp->base, "training complete");
400 atomic_set(&outp->lt.done, 1);
401}
diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/g84.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/g84.c
index 3e3e592cd09f..842e1b72ee42 100644
--- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/g84.c
+++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/g84.c
@@ -22,30 +22,20 @@
22 * Authors: Ben Skeggs 22 * Authors: Ben Skeggs
23 */ 23 */
24#include "nv50.h" 24#include "nv50.h"
25#include "head.h"
26#include "ior.h"
25#include "rootnv50.h" 27#include "rootnv50.h"
26 28
27static const struct nv50_disp_func 29static const struct nv50_disp_func
28g84_disp = { 30g84_disp = {
29 .intr = nv50_disp_intr, 31 .intr = nv50_disp_intr,
30 .uevent = &nv50_disp_chan_uevent, 32 .uevent = &nv50_disp_chan_uevent,
31 .super = nv50_disp_intr_supervisor, 33 .super = nv50_disp_super,
32 .root = &g84_disp_root_oclass, 34 .root = &g84_disp_root_oclass,
33 .head.vblank_init = nv50_disp_vblank_init, 35 .head.new = nv50_head_new,
34 .head.vblank_fini = nv50_disp_vblank_fini, 36 .dac = { .nr = 3, .new = nv50_dac_new },
35 .head.scanoutpos = nv50_disp_root_scanoutpos, 37 .sor = { .nr = 2, .new = g84_sor_new },
36 .outp.internal.crt = nv50_dac_output_new, 38 .pior = { .nr = 3, .new = nv50_pior_new },
37 .outp.internal.tmds = nv50_sor_output_new,
38 .outp.internal.lvds = nv50_sor_output_new,
39 .outp.external.tmds = nv50_pior_output_new,
40 .outp.external.dp = nv50_pior_dp_new,
41 .dac.nr = 3,
42 .dac.power = nv50_dac_power,
43 .dac.sense = nv50_dac_sense,
44 .sor.nr = 2,
45 .sor.power = nv50_sor_power,
46 .sor.hdmi = g84_hdmi_ctrl,
47 .pior.nr = 3,
48 .pior.power = nv50_pior_power,
49}; 39};
50 40
51int 41int
diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/g94.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/g94.c
index 7a7af3b478f8..d184e6ab8918 100644
--- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/g94.c
+++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/g94.c
@@ -22,31 +22,20 @@
22 * Authors: Ben Skeggs 22 * Authors: Ben Skeggs
23 */ 23 */
24#include "nv50.h" 24#include "nv50.h"
25#include "head.h"
26#include "ior.h"
25#include "rootnv50.h" 27#include "rootnv50.h"
26 28
27static const struct nv50_disp_func 29static const struct nv50_disp_func
28g94_disp = { 30g94_disp = {
29 .intr = nv50_disp_intr, 31 .intr = nv50_disp_intr,
30 .uevent = &nv50_disp_chan_uevent, 32 .uevent = &nv50_disp_chan_uevent,
31 .super = nv50_disp_intr_supervisor, 33 .super = nv50_disp_super,
32 .root = &g94_disp_root_oclass, 34 .root = &g94_disp_root_oclass,
33 .head.vblank_init = nv50_disp_vblank_init, 35 .head.new = nv50_head_new,
34 .head.vblank_fini = nv50_disp_vblank_fini, 36 .dac = { .nr = 3, .new = nv50_dac_new },
35 .head.scanoutpos = nv50_disp_root_scanoutpos, 37 .sor = { .nr = 4, .new = g94_sor_new },
36 .outp.internal.crt = nv50_dac_output_new, 38 .pior = { .nr = 3, .new = nv50_pior_new },
37 .outp.internal.tmds = nv50_sor_output_new,
38 .outp.internal.lvds = nv50_sor_output_new,
39 .outp.internal.dp = g94_sor_dp_new,
40 .outp.external.tmds = nv50_pior_output_new,
41 .outp.external.dp = nv50_pior_dp_new,
42 .dac.nr = 3,
43 .dac.power = nv50_dac_power,
44 .dac.sense = nv50_dac_sense,
45 .sor.nr = 4,
46 .sor.power = nv50_sor_power,
47 .sor.hdmi = g84_hdmi_ctrl,
48 .pior.nr = 3,
49 .pior.power = nv50_pior_power,
50}; 39};
51 40
52int 41int
diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/gf119.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/gf119.c
index 7b346ccc38b7..d8765b57180b 100644
--- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/gf119.c
+++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/gf119.c
@@ -22,397 +22,63 @@
22 * Authors: Ben Skeggs 22 * Authors: Ben Skeggs
23 */ 23 */
24#include "nv50.h" 24#include "nv50.h"
25#include "head.h"
26#include "ior.h"
25#include "rootnv50.h" 27#include "rootnv50.h"
26 28
27#include <subdev/bios.h>
28#include <subdev/bios/disp.h>
29#include <subdev/bios/init.h>
30#include <subdev/bios/pll.h>
31#include <subdev/devinit.h>
32
33void
34gf119_disp_vblank_init(struct nv50_disp *disp, int head)
35{
36 struct nvkm_device *device = disp->base.engine.subdev.device;
37 nvkm_mask(device, 0x6100c0 + (head * 0x800), 0x00000001, 0x00000001);
38}
39
40void
41gf119_disp_vblank_fini(struct nv50_disp *disp, int head)
42{
43 struct nvkm_device *device = disp->base.engine.subdev.device;
44 nvkm_mask(device, 0x6100c0 + (head * 0x800), 0x00000001, 0x00000000);
45}
46
47static struct nvkm_output *
48exec_lookup(struct nv50_disp *disp, int head, int or, u32 ctrl,
49 u32 *data, u8 *ver, u8 *hdr, u8 *cnt, u8 *len,
50 struct nvbios_outp *info)
51{
52 struct nvkm_subdev *subdev = &disp->base.engine.subdev;
53 struct nvkm_bios *bios = subdev->device->bios;
54 struct nvkm_output *outp;
55 u16 mask, type;
56
57 if (or < 4) {
58 type = DCB_OUTPUT_ANALOG;
59 mask = 0;
60 } else {
61 or -= 4;
62 switch (ctrl & 0x00000f00) {
63 case 0x00000000: type = DCB_OUTPUT_LVDS; mask = 1; break;
64 case 0x00000100: type = DCB_OUTPUT_TMDS; mask = 1; break;
65 case 0x00000200: type = DCB_OUTPUT_TMDS; mask = 2; break;
66 case 0x00000500: type = DCB_OUTPUT_TMDS; mask = 3; break;
67 case 0x00000800: type = DCB_OUTPUT_DP; mask = 1; break;
68 case 0x00000900: type = DCB_OUTPUT_DP; mask = 2; break;
69 default:
70 nvkm_error(subdev, "unknown SOR mc %08x\n", ctrl);
71 return NULL;
72 }
73 }
74
75 mask = 0x00c0 & (mask << 6);
76 mask |= 0x0001 << or;
77 mask |= 0x0100 << head;
78
79 list_for_each_entry(outp, &disp->base.outp, head) {
80 if ((outp->info.hasht & 0xff) == type &&
81 (outp->info.hashm & mask) == mask) {
82 *data = nvbios_outp_match(bios, outp->info.hasht, mask,
83 ver, hdr, cnt, len, info);
84 if (!*data)
85 return NULL;
86 return outp;
87 }
88 }
89
90 return NULL;
91}
92
93static struct nvkm_output *
94exec_script(struct nv50_disp *disp, int head, int id)
95{
96 struct nvkm_subdev *subdev = &disp->base.engine.subdev;
97 struct nvkm_device *device = subdev->device;
98 struct nvkm_bios *bios = device->bios;
99 struct nvkm_output *outp;
100 struct nvbios_outp info;
101 u8 ver, hdr, cnt, len;
102 u32 data, ctrl = 0;
103 int or;
104
105 for (or = 0; !(ctrl & (1 << head)) && or < 8; or++) {
106 ctrl = nvkm_rd32(device, 0x640180 + (or * 0x20));
107 if (ctrl & (1 << head))
108 break;
109 }
110
111 if (or == 8)
112 return NULL;
113
114 outp = exec_lookup(disp, head, or, ctrl, &data, &ver, &hdr, &cnt, &len, &info);
115 if (outp) {
116 struct nvbios_init init = {
117 .subdev = subdev,
118 .bios = bios,
119 .offset = info.script[id],
120 .outp = &outp->info,
121 .crtc = head,
122 .execute = 1,
123 };
124
125 nvbios_exec(&init);
126 }
127
128 return outp;
129}
130
131static struct nvkm_output *
132exec_clkcmp(struct nv50_disp *disp, int head, int id, u32 pclk, u32 *conf)
133{
134 struct nvkm_subdev *subdev = &disp->base.engine.subdev;
135 struct nvkm_device *device = subdev->device;
136 struct nvkm_bios *bios = device->bios;
137 struct nvkm_output *outp;
138 struct nvbios_outp info1;
139 struct nvbios_ocfg info2;
140 u8 ver, hdr, cnt, len;
141 u32 data, ctrl = 0;
142 int or;
143
144 for (or = 0; !(ctrl & (1 << head)) && or < 8; or++) {
145 ctrl = nvkm_rd32(device, 0x660180 + (or * 0x20));
146 if (ctrl & (1 << head))
147 break;
148 }
149
150 if (or == 8)
151 return NULL;
152
153 outp = exec_lookup(disp, head, or, ctrl, &data, &ver, &hdr, &cnt, &len, &info1);
154 if (!outp)
155 return NULL;
156
157 *conf = (ctrl & 0x00000f00) >> 8;
158 switch (outp->info.type) {
159 case DCB_OUTPUT_TMDS:
160 if (*conf == 5)
161 *conf |= 0x0100;
162 break;
163 case DCB_OUTPUT_LVDS:
164 *conf |= disp->sor.lvdsconf;
165 break;
166 default:
167 break;
168 }
169
170 data = nvbios_ocfg_match(bios, data, *conf & 0xff, *conf >> 8,
171 &ver, &hdr, &cnt, &len, &info2);
172 if (data && id < 0xff) {
173 data = nvbios_oclk_match(bios, info2.clkcmp[id], pclk);
174 if (data) {
175 struct nvbios_init init = {
176 .subdev = subdev,
177 .bios = bios,
178 .offset = data,
179 .outp = &outp->info,
180 .crtc = head,
181 .execute = 1,
182 };
183
184 nvbios_exec(&init);
185 }
186 }
187
188 return outp;
189}
190
191static void
192gf119_disp_intr_unk1_0(struct nv50_disp *disp, int head)
193{
194 exec_script(disp, head, 1);
195}
196
197static void
198gf119_disp_intr_unk2_0(struct nv50_disp *disp, int head)
199{
200 struct nvkm_subdev *subdev = &disp->base.engine.subdev;
201 struct nvkm_output *outp = exec_script(disp, head, 2);
202
203 /* see note in nv50_disp_intr_unk20_0() */
204 if (outp && outp->info.type == DCB_OUTPUT_DP) {
205 struct nvkm_output_dp *outpdp = nvkm_output_dp(outp);
206 if (!outpdp->lt.mst) {
207 struct nvbios_init init = {
208 .subdev = subdev,
209 .bios = subdev->device->bios,
210 .outp = &outp->info,
211 .crtc = head,
212 .offset = outpdp->info.script[4],
213 .execute = 1,
214 };
215
216 nvkm_notify_put(&outpdp->irq);
217 nvbios_exec(&init);
218 atomic_set(&outpdp->lt.done, 0);
219 }
220 }
221}
222
223static void
224gf119_disp_intr_unk2_1(struct nv50_disp *disp, int head)
225{
226 struct nvkm_device *device = disp->base.engine.subdev.device;
227 struct nvkm_devinit *devinit = device->devinit;
228 u32 pclk = nvkm_rd32(device, 0x660450 + (head * 0x300)) / 1000;
229 if (pclk)
230 nvkm_devinit_pll_set(devinit, PLL_VPLL0 + head, pclk);
231 nvkm_wr32(device, 0x612200 + (head * 0x800), 0x00000000);
232}
233
234static void
235gf119_disp_intr_unk2_2_tu(struct nv50_disp *disp, int head,
236 struct dcb_output *outp)
237{
238 struct nvkm_device *device = disp->base.engine.subdev.device;
239 const int or = ffs(outp->or) - 1;
240 const u32 ctrl = nvkm_rd32(device, 0x660200 + (or * 0x020));
241 const u32 conf = nvkm_rd32(device, 0x660404 + (head * 0x300));
242 const s32 vactive = nvkm_rd32(device, 0x660414 + (head * 0x300)) & 0xffff;
243 const s32 vblanke = nvkm_rd32(device, 0x66041c + (head * 0x300)) & 0xffff;
244 const s32 vblanks = nvkm_rd32(device, 0x660420 + (head * 0x300)) & 0xffff;
245 const u32 pclk = nvkm_rd32(device, 0x660450 + (head * 0x300)) / 1000;
246 const u32 link = ((ctrl & 0xf00) == 0x800) ? 0 : 1;
247 const u32 hoff = (head * 0x800);
248 const u32 soff = ( or * 0x800);
249 const u32 loff = (link * 0x080) + soff;
250 const u32 symbol = 100000;
251 const u32 TU = 64;
252 u32 dpctrl = nvkm_rd32(device, 0x61c10c + loff);
253 u32 clksor = nvkm_rd32(device, 0x612300 + soff);
254 u32 datarate, link_nr, link_bw, bits;
255 u64 ratio, value;
256
257 link_nr = hweight32(dpctrl & 0x000f0000);
258 link_bw = (clksor & 0x007c0000) >> 18;
259 link_bw *= 27000;
260
261 /* symbols/hblank - algorithm taken from comments in tegra driver */
262 value = vblanke + vactive - vblanks - 7;
263 value = value * link_bw;
264 do_div(value, pclk);
265 value = value - (3 * !!(dpctrl & 0x00004000)) - (12 / link_nr);
266 nvkm_mask(device, 0x616620 + hoff, 0x0000ffff, value);
267
268 /* symbols/vblank - algorithm taken from comments in tegra driver */
269 value = vblanks - vblanke - 25;
270 value = value * link_bw;
271 do_div(value, pclk);
272 value = value - ((36 / link_nr) + 3) - 1;
273 nvkm_mask(device, 0x616624 + hoff, 0x00ffffff, value);
274
275 /* watermark */
276 if ((conf & 0x3c0) == 0x180) bits = 30;
277 else if ((conf & 0x3c0) == 0x140) bits = 24;
278 else bits = 18;
279 datarate = (pclk * bits) / 8;
280
281 ratio = datarate;
282 ratio *= symbol;
283 do_div(ratio, link_nr * link_bw);
284
285 value = (symbol - ratio) * TU;
286 value *= ratio;
287 do_div(value, symbol);
288 do_div(value, symbol);
289
290 value += 5;
291 value |= 0x08000000;
292
293 nvkm_wr32(device, 0x616610 + hoff, value);
294}
295
296static void
297gf119_disp_intr_unk2_2(struct nv50_disp *disp, int head)
298{
299 struct nvkm_device *device = disp->base.engine.subdev.device;
300 struct nvkm_output *outp;
301 u32 pclk = nvkm_rd32(device, 0x660450 + (head * 0x300)) / 1000;
302 u32 conf, addr, data;
303
304 outp = exec_clkcmp(disp, head, 0xff, pclk, &conf);
305 if (!outp)
306 return;
307
308 /* see note in nv50_disp_intr_unk20_2() */
309 if (outp->info.type == DCB_OUTPUT_DP) {
310 u32 sync = nvkm_rd32(device, 0x660404 + (head * 0x300));
311 switch ((sync & 0x000003c0) >> 6) {
312 case 6: pclk = pclk * 30; break;
313 case 5: pclk = pclk * 24; break;
314 case 2:
315 default:
316 pclk = pclk * 18;
317 break;
318 }
319
320 if (nvkm_output_dp_train(outp, pclk))
321 OUTP_ERR(outp, "link not trained before attach");
322 } else {
323 if (disp->func->sor.magic)
324 disp->func->sor.magic(outp);
325 }
326
327 exec_clkcmp(disp, head, 0, pclk, &conf);
328
329 if (outp->info.type == DCB_OUTPUT_ANALOG) {
330 addr = 0x612280 + (ffs(outp->info.or) - 1) * 0x800;
331 data = 0x00000000;
332 } else {
333 addr = 0x612300 + (ffs(outp->info.or) - 1) * 0x800;
334 data = (conf & 0x0100) ? 0x00000101 : 0x00000000;
335 switch (outp->info.type) {
336 case DCB_OUTPUT_TMDS:
337 nvkm_mask(device, addr, 0x007c0000, 0x00280000);
338 break;
339 case DCB_OUTPUT_DP:
340 gf119_disp_intr_unk2_2_tu(disp, head, &outp->info);
341 break;
342 default:
343 break;
344 }
345 }
346
347 nvkm_mask(device, addr, 0x00000707, data);
348}
349
350static void
351gf119_disp_intr_unk4_0(struct nv50_disp *disp, int head)
352{
353 struct nvkm_device *device = disp->base.engine.subdev.device;
354 u32 pclk = nvkm_rd32(device, 0x660450 + (head * 0x300)) / 1000;
355 u32 conf;
356
357 exec_clkcmp(disp, head, 1, pclk, &conf);
358}
359
360void 29void
361gf119_disp_intr_supervisor(struct work_struct *work) 30gf119_disp_super(struct work_struct *work)
362{ 31{
363 struct nv50_disp *disp = 32 struct nv50_disp *disp =
364 container_of(work, struct nv50_disp, supervisor); 33 container_of(work, struct nv50_disp, supervisor);
365 struct nvkm_subdev *subdev = &disp->base.engine.subdev; 34 struct nvkm_subdev *subdev = &disp->base.engine.subdev;
366 struct nvkm_device *device = subdev->device; 35 struct nvkm_device *device = subdev->device;
36 struct nvkm_head *head;
367 u32 mask[4]; 37 u32 mask[4];
368 int head;
369 38
370 nvkm_debug(subdev, "supervisor %d\n", ffs(disp->super)); 39 nvkm_debug(subdev, "supervisor %d\n", ffs(disp->super));
371 for (head = 0; head < disp->base.head.nr; head++) { 40 list_for_each_entry(head, &disp->base.head, head) {
372 mask[head] = nvkm_rd32(device, 0x6101d4 + (head * 0x800)); 41 mask[head->id] = nvkm_rd32(device, 0x6101d4 + (head->id * 0x800));
373 nvkm_debug(subdev, "head %d: %08x\n", head, mask[head]); 42 HEAD_DBG(head, "%08x", mask[head->id]);
374 } 43 }
375 44
376 if (disp->super & 0x00000001) { 45 if (disp->super & 0x00000001) {
377 nv50_disp_chan_mthd(disp->chan[0], NV_DBG_DEBUG); 46 nv50_disp_chan_mthd(disp->chan[0], NV_DBG_DEBUG);
378 for (head = 0; head < disp->base.head.nr; head++) { 47 nv50_disp_super_1(disp);
379 if (!(mask[head] & 0x00001000)) 48 list_for_each_entry(head, &disp->base.head, head) {
49 if (!(mask[head->id] & 0x00001000))
380 continue; 50 continue;
381 nvkm_debug(subdev, "supervisor 1.0 - head %d\n", head); 51 nv50_disp_super_1_0(disp, head);
382 gf119_disp_intr_unk1_0(disp, head);
383 } 52 }
384 } else 53 } else
385 if (disp->super & 0x00000002) { 54 if (disp->super & 0x00000002) {
386 for (head = 0; head < disp->base.head.nr; head++) { 55 list_for_each_entry(head, &disp->base.head, head) {
387 if (!(mask[head] & 0x00001000)) 56 if (!(mask[head->id] & 0x00001000))
388 continue; 57 continue;
389 nvkm_debug(subdev, "supervisor 2.0 - head %d\n", head); 58 nv50_disp_super_2_0(disp, head);
390 gf119_disp_intr_unk2_0(disp, head);
391 } 59 }
392 for (head = 0; head < disp->base.head.nr; head++) { 60 nvkm_outp_route(&disp->base);
393 if (!(mask[head] & 0x00010000)) 61 list_for_each_entry(head, &disp->base.head, head) {
62 if (!(mask[head->id] & 0x00010000))
394 continue; 63 continue;
395 nvkm_debug(subdev, "supervisor 2.1 - head %d\n", head); 64 nv50_disp_super_2_1(disp, head);
396 gf119_disp_intr_unk2_1(disp, head);
397 } 65 }
398 for (head = 0; head < disp->base.head.nr; head++) { 66 list_for_each_entry(head, &disp->base.head, head) {
399 if (!(mask[head] & 0x00001000)) 67 if (!(mask[head->id] & 0x00001000))
400 continue; 68 continue;
401 nvkm_debug(subdev, "supervisor 2.2 - head %d\n", head); 69 nv50_disp_super_2_2(disp, head);
402 gf119_disp_intr_unk2_2(disp, head);
403 } 70 }
404 } else 71 } else
405 if (disp->super & 0x00000004) { 72 if (disp->super & 0x00000004) {
406 for (head = 0; head < disp->base.head.nr; head++) { 73 list_for_each_entry(head, &disp->base.head, head) {
407 if (!(mask[head] & 0x00001000)) 74 if (!(mask[head->id] & 0x00001000))
408 continue; 75 continue;
409 nvkm_debug(subdev, "supervisor 3.0 - head %d\n", head); 76 nv50_disp_super_3_0(disp, head);
410 gf119_disp_intr_unk4_0(disp, head);
411 } 77 }
412 } 78 }
413 79
414 for (head = 0; head < disp->base.head.nr; head++) 80 list_for_each_entry(head, &disp->base.head, head)
415 nvkm_wr32(device, 0x6101d4 + (head * 0x800), 0x00000000); 81 nvkm_wr32(device, 0x6101d4 + (head->id * 0x800), 0x00000000);
416 nvkm_wr32(device, 0x6101d0, 0x80000000); 82 nvkm_wr32(device, 0x6101d0, 0x80000000);
417} 83}
418 84
@@ -447,8 +113,8 @@ gf119_disp_intr(struct nv50_disp *disp)
447{ 113{
448 struct nvkm_subdev *subdev = &disp->base.engine.subdev; 114 struct nvkm_subdev *subdev = &disp->base.engine.subdev;
449 struct nvkm_device *device = subdev->device; 115 struct nvkm_device *device = subdev->device;
116 struct nvkm_head *head;
450 u32 intr = nvkm_rd32(device, 0x610088); 117 u32 intr = nvkm_rd32(device, 0x610088);
451 int i;
452 118
453 if (intr & 0x00000001) { 119 if (intr & 0x00000001) {
454 u32 stat = nvkm_rd32(device, 0x61008c); 120 u32 stat = nvkm_rd32(device, 0x61008c);
@@ -472,7 +138,7 @@ gf119_disp_intr(struct nv50_disp *disp)
472 u32 stat = nvkm_rd32(device, 0x6100ac); 138 u32 stat = nvkm_rd32(device, 0x6100ac);
473 if (stat & 0x00000007) { 139 if (stat & 0x00000007) {
474 disp->super = (stat & 0x00000007); 140 disp->super = (stat & 0x00000007);
475 schedule_work(&disp->supervisor); 141 queue_work(disp->wq, &disp->supervisor);
476 nvkm_wr32(device, 0x6100ac, disp->super); 142 nvkm_wr32(device, 0x6100ac, disp->super);
477 stat &= ~0x00000007; 143 stat &= ~0x00000007;
478 } 144 }
@@ -485,14 +151,15 @@ gf119_disp_intr(struct nv50_disp *disp)
485 intr &= ~0x00100000; 151 intr &= ~0x00100000;
486 } 152 }
487 153
488 for (i = 0; i < disp->base.head.nr; i++) { 154 list_for_each_entry(head, &disp->base.head, head) {
489 u32 mask = 0x01000000 << i; 155 const u32 hoff = head->id * 0x800;
156 u32 mask = 0x01000000 << head->id;
490 if (mask & intr) { 157 if (mask & intr) {
491 u32 stat = nvkm_rd32(device, 0x6100bc + (i * 0x800)); 158 u32 stat = nvkm_rd32(device, 0x6100bc + hoff);
492 if (stat & 0x00000001) 159 if (stat & 0x00000001)
493 nvkm_disp_vblank(&disp->base, i); 160 nvkm_disp_vblank(&disp->base, head->id);
494 nvkm_mask(device, 0x6100bc + (i * 0x800), 0, 0); 161 nvkm_mask(device, 0x6100bc + hoff, 0, 0);
495 nvkm_rd32(device, 0x6100c0 + (i * 0x800)); 162 nvkm_rd32(device, 0x6100c0 + hoff);
496 } 163 }
497 } 164 }
498} 165}
@@ -510,22 +177,11 @@ gf119_disp = {
510 .intr = gf119_disp_intr, 177 .intr = gf119_disp_intr,
511 .intr_error = gf119_disp_intr_error, 178 .intr_error = gf119_disp_intr_error,
512 .uevent = &gf119_disp_chan_uevent, 179 .uevent = &gf119_disp_chan_uevent,
513 .super = gf119_disp_intr_supervisor, 180 .super = gf119_disp_super,
514 .root = &gf119_disp_root_oclass, 181 .root = &gf119_disp_root_oclass,
515 .head.vblank_init = gf119_disp_vblank_init, 182 .head.new = gf119_head_new,
516 .head.vblank_fini = gf119_disp_vblank_fini, 183 .dac = { .nr = 3, .new = gf119_dac_new },
517 .head.scanoutpos = gf119_disp_root_scanoutpos, 184 .sor = { .nr = 4, .new = gf119_sor_new },
518 .outp.internal.crt = nv50_dac_output_new,
519 .outp.internal.tmds = nv50_sor_output_new,
520 .outp.internal.lvds = nv50_sor_output_new,
521 .outp.internal.dp = gf119_sor_dp_new,
522 .dac.nr = 3,
523 .dac.power = nv50_dac_power,
524 .dac.sense = nv50_dac_sense,
525 .sor.nr = 4,
526 .sor.power = nv50_sor_power,
527 .sor.hda_eld = gf119_hda_eld,
528 .sor.hdmi = gf119_hdmi_ctrl,
529}; 185};
530 186
531int 187int
diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/gk104.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/gk104.c
index 37f145cf30d7..e8fe9f315d64 100644
--- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/gk104.c
+++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/gk104.c
@@ -22,6 +22,8 @@
22 * Authors: Ben Skeggs 22 * Authors: Ben Skeggs
23 */ 23 */
24#include "nv50.h" 24#include "nv50.h"
25#include "head.h"
26#include "ior.h"
25#include "rootnv50.h" 27#include "rootnv50.h"
26 28
27static const struct nv50_disp_func 29static const struct nv50_disp_func
@@ -29,22 +31,11 @@ gk104_disp = {
29 .intr = gf119_disp_intr, 31 .intr = gf119_disp_intr,
30 .intr_error = gf119_disp_intr_error, 32 .intr_error = gf119_disp_intr_error,
31 .uevent = &gf119_disp_chan_uevent, 33 .uevent = &gf119_disp_chan_uevent,
32 .super = gf119_disp_intr_supervisor, 34 .super = gf119_disp_super,
33 .root = &gk104_disp_root_oclass, 35 .root = &gk104_disp_root_oclass,
34 .head.vblank_init = gf119_disp_vblank_init, 36 .head.new = gf119_head_new,
35 .head.vblank_fini = gf119_disp_vblank_fini, 37 .dac = { .nr = 3, .new = gf119_dac_new },
36 .head.scanoutpos = gf119_disp_root_scanoutpos, 38 .sor = { .nr = 4, .new = gk104_sor_new },
37 .outp.internal.crt = nv50_dac_output_new,
38 .outp.internal.tmds = nv50_sor_output_new,
39 .outp.internal.lvds = nv50_sor_output_new,
40 .outp.internal.dp = gf119_sor_dp_new,
41 .dac.nr = 3,
42 .dac.power = nv50_dac_power,
43 .dac.sense = nv50_dac_sense,
44 .sor.nr = 4,
45 .sor.power = nv50_sor_power,
46 .sor.hda_eld = gf119_hda_eld,
47 .sor.hdmi = gk104_hdmi_ctrl,
48}; 39};
49 40
50int 41int
diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/gk110.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/gk110.c
index e14ac946608c..769687502e7a 100644
--- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/gk110.c
+++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/gk110.c
@@ -22,6 +22,8 @@
22 * Authors: Ben Skeggs 22 * Authors: Ben Skeggs
23 */ 23 */
24#include "nv50.h" 24#include "nv50.h"
25#include "head.h"
26#include "ior.h"
25#include "rootnv50.h" 27#include "rootnv50.h"
26 28
27static const struct nv50_disp_func 29static const struct nv50_disp_func
@@ -29,22 +31,11 @@ gk110_disp = {
29 .intr = gf119_disp_intr, 31 .intr = gf119_disp_intr,
30 .intr_error = gf119_disp_intr_error, 32 .intr_error = gf119_disp_intr_error,
31 .uevent = &gf119_disp_chan_uevent, 33 .uevent = &gf119_disp_chan_uevent,
32 .super = gf119_disp_intr_supervisor, 34 .super = gf119_disp_super,
33 .root = &gk110_disp_root_oclass, 35 .root = &gk110_disp_root_oclass,
34 .head.vblank_init = gf119_disp_vblank_init, 36 .head.new = gf119_head_new,
35 .head.vblank_fini = gf119_disp_vblank_fini, 37 .dac = { .nr = 3, .new = gf119_dac_new },
36 .head.scanoutpos = gf119_disp_root_scanoutpos, 38 .sor = { .nr = 4, .new = gk104_sor_new },
37 .outp.internal.crt = nv50_dac_output_new,
38 .outp.internal.tmds = nv50_sor_output_new,
39 .outp.internal.lvds = nv50_sor_output_new,
40 .outp.internal.dp = gf119_sor_dp_new,
41 .dac.nr = 3,
42 .dac.power = nv50_dac_power,
43 .dac.sense = nv50_dac_sense,
44 .sor.nr = 4,
45 .sor.power = nv50_sor_power,
46 .sor.hda_eld = gf119_hda_eld,
47 .sor.hdmi = gk104_hdmi_ctrl,
48}; 39};
49 40
50int 41int
diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/gm107.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/gm107.c
index 2f2437cc5891..ede70e5d188e 100644
--- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/gm107.c
+++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/gm107.c
@@ -22,6 +22,8 @@
22 * Authors: Ben Skeggs 22 * Authors: Ben Skeggs
23 */ 23 */
24#include "nv50.h" 24#include "nv50.h"
25#include "head.h"
26#include "ior.h"
25#include "rootnv50.h" 27#include "rootnv50.h"
26 28
27static const struct nv50_disp_func 29static const struct nv50_disp_func
@@ -29,22 +31,11 @@ gm107_disp = {
29 .intr = gf119_disp_intr, 31 .intr = gf119_disp_intr,
30 .intr_error = gf119_disp_intr_error, 32 .intr_error = gf119_disp_intr_error,
31 .uevent = &gf119_disp_chan_uevent, 33 .uevent = &gf119_disp_chan_uevent,
32 .super = gf119_disp_intr_supervisor, 34 .super = gf119_disp_super,
33 .root = &gm107_disp_root_oclass, 35 .root = &gm107_disp_root_oclass,
34 .head.vblank_init = gf119_disp_vblank_init, 36 .head.new = gf119_head_new,
35 .head.vblank_fini = gf119_disp_vblank_fini, 37 .dac = { .nr = 3, .new = gf119_dac_new },
36 .head.scanoutpos = gf119_disp_root_scanoutpos, 38 .sor = { .nr = 4, .new = gm107_sor_new },
37 .outp.internal.crt = nv50_dac_output_new,
38 .outp.internal.tmds = nv50_sor_output_new,
39 .outp.internal.lvds = nv50_sor_output_new,
40 .outp.internal.dp = gm107_sor_dp_new,
41 .dac.nr = 3,
42 .dac.power = nv50_dac_power,
43 .dac.sense = nv50_dac_sense,
44 .sor.nr = 4,
45 .sor.power = nv50_sor_power,
46 .sor.hda_eld = gf119_hda_eld,
47 .sor.hdmi = gk104_hdmi_ctrl,
48}; 39};
49 40
50int 41int
diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/gm200.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/gm200.c
index 9f368d4ee61e..292d3b5f9704 100644
--- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/gm200.c
+++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/gm200.c
@@ -22,6 +22,8 @@
22 * Authors: Ben Skeggs 22 * Authors: Ben Skeggs
23 */ 23 */
24#include "nv50.h" 24#include "nv50.h"
25#include "head.h"
26#include "ior.h"
25#include "rootnv50.h" 27#include "rootnv50.h"
26 28
27static const struct nv50_disp_func 29static const struct nv50_disp_func
@@ -29,23 +31,11 @@ gm200_disp = {
29 .intr = gf119_disp_intr, 31 .intr = gf119_disp_intr,
30 .intr_error = gf119_disp_intr_error, 32 .intr_error = gf119_disp_intr_error,
31 .uevent = &gf119_disp_chan_uevent, 33 .uevent = &gf119_disp_chan_uevent,
32 .super = gf119_disp_intr_supervisor, 34 .super = gf119_disp_super,
33 .root = &gm200_disp_root_oclass, 35 .root = &gm200_disp_root_oclass,
34 .head.vblank_init = gf119_disp_vblank_init, 36 .head.new = gf119_head_new,
35 .head.vblank_fini = gf119_disp_vblank_fini, 37 .dac = { .nr = 3, .new = gf119_dac_new },
36 .head.scanoutpos = gf119_disp_root_scanoutpos, 38 .sor = { .nr = 4, .new = gm200_sor_new },
37 .outp.internal.crt = nv50_dac_output_new,
38 .outp.internal.tmds = nv50_sor_output_new,
39 .outp.internal.lvds = nv50_sor_output_new,
40 .outp.internal.dp = gm200_sor_dp_new,
41 .dac.nr = 3,
42 .dac.power = nv50_dac_power,
43 .dac.sense = nv50_dac_sense,
44 .sor.nr = 4,
45 .sor.power = nv50_sor_power,
46 .sor.hda_eld = gf119_hda_eld,
47 .sor.hdmi = gk104_hdmi_ctrl,
48 .sor.magic = gm200_sor_magic,
49}; 39};
50 40
51int 41int
diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/gp100.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/gp100.c
index 4f81bf31435e..39eb98b2c3a2 100644
--- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/gp100.c
+++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/gp100.c
@@ -22,6 +22,8 @@
22 * Authors: Ben Skeggs <bskeggs@redhat.com> 22 * Authors: Ben Skeggs <bskeggs@redhat.com>
23 */ 23 */
24#include "nv50.h" 24#include "nv50.h"
25#include "head.h"
26#include "ior.h"
25#include "rootnv50.h" 27#include "rootnv50.h"
26 28
27static const struct nv50_disp_func 29static const struct nv50_disp_func
@@ -29,23 +31,10 @@ gp100_disp = {
29 .intr = gf119_disp_intr, 31 .intr = gf119_disp_intr,
30 .intr_error = gf119_disp_intr_error, 32 .intr_error = gf119_disp_intr_error,
31 .uevent = &gf119_disp_chan_uevent, 33 .uevent = &gf119_disp_chan_uevent,
32 .super = gf119_disp_intr_supervisor, 34 .super = gf119_disp_super,
33 .root = &gp100_disp_root_oclass, 35 .root = &gp100_disp_root_oclass,
34 .head.vblank_init = gf119_disp_vblank_init, 36 .head.new = gf119_head_new,
35 .head.vblank_fini = gf119_disp_vblank_fini, 37 .sor = { .nr = 4, .new = gm200_sor_new },
36 .head.scanoutpos = gf119_disp_root_scanoutpos,
37 .outp.internal.crt = nv50_dac_output_new,
38 .outp.internal.tmds = nv50_sor_output_new,
39 .outp.internal.lvds = nv50_sor_output_new,
40 .outp.internal.dp = gm200_sor_dp_new,
41 .dac.nr = 3,
42 .dac.power = nv50_dac_power,
43 .dac.sense = nv50_dac_sense,
44 .sor.nr = 4,
45 .sor.power = nv50_sor_power,
46 .sor.hda_eld = gf119_hda_eld,
47 .sor.hdmi = gk104_hdmi_ctrl,
48 .sor.magic = gm200_sor_magic,
49}; 38};
50 39
51int 40int
diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/gp102.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/gp102.c
index f5d613f82709..91d70fe18275 100644
--- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/gp102.c
+++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/gp102.c
@@ -22,6 +22,8 @@
22 * Authors: Ben Skeggs <bskeggs@redhat.com> 22 * Authors: Ben Skeggs <bskeggs@redhat.com>
23 */ 23 */
24#include "nv50.h" 24#include "nv50.h"
25#include "head.h"
26#include "ior.h"
25#include "rootnv50.h" 27#include "rootnv50.h"
26 28
27static void 29static void
@@ -55,23 +57,10 @@ gp102_disp = {
55 .intr = gf119_disp_intr, 57 .intr = gf119_disp_intr,
56 .intr_error = gp102_disp_intr_error, 58 .intr_error = gp102_disp_intr_error,
57 .uevent = &gf119_disp_chan_uevent, 59 .uevent = &gf119_disp_chan_uevent,
58 .super = gf119_disp_intr_supervisor, 60 .super = gf119_disp_super,
59 .root = &gp102_disp_root_oclass, 61 .root = &gp102_disp_root_oclass,
60 .head.vblank_init = gf119_disp_vblank_init, 62 .head.new = gf119_head_new,
61 .head.vblank_fini = gf119_disp_vblank_fini, 63 .sor = { .nr = 4, .new = gm200_sor_new },
62 .head.scanoutpos = gf119_disp_root_scanoutpos,
63 .outp.internal.crt = nv50_dac_output_new,
64 .outp.internal.tmds = nv50_sor_output_new,
65 .outp.internal.lvds = nv50_sor_output_new,
66 .outp.internal.dp = gm200_sor_dp_new,
67 .dac.nr = 3,
68 .dac.power = nv50_dac_power,
69 .dac.sense = nv50_dac_sense,
70 .sor.nr = 4,
71 .sor.power = nv50_sor_power,
72 .sor.hda_eld = gf119_hda_eld,
73 .sor.hdmi = gk104_hdmi_ctrl,
74 .sor.magic = gm200_sor_magic,
75}; 64};
76 65
77int 66int
diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/gt200.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/gt200.c
index 6bc3bf096001..bf00c4e3be3a 100644
--- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/gt200.c
+++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/gt200.c
@@ -22,30 +22,20 @@
22 * Authors: Ben Skeggs 22 * Authors: Ben Skeggs
23 */ 23 */
24#include "nv50.h" 24#include "nv50.h"
25#include "head.h"
26#include "ior.h"
25#include "rootnv50.h" 27#include "rootnv50.h"
26 28
27static const struct nv50_disp_func 29static const struct nv50_disp_func
28gt200_disp = { 30gt200_disp = {
29 .intr = nv50_disp_intr, 31 .intr = nv50_disp_intr,
30 .uevent = &nv50_disp_chan_uevent, 32 .uevent = &nv50_disp_chan_uevent,
31 .super = nv50_disp_intr_supervisor, 33 .super = nv50_disp_super,
32 .root = &gt200_disp_root_oclass, 34 .root = &gt200_disp_root_oclass,
33 .head.vblank_init = nv50_disp_vblank_init, 35 .head.new = nv50_head_new,
34 .head.vblank_fini = nv50_disp_vblank_fini, 36 .dac = { .nr = 3, .new = nv50_dac_new },
35 .head.scanoutpos = nv50_disp_root_scanoutpos, 37 .sor = { .nr = 2, .new = g84_sor_new },
36 .outp.internal.crt = nv50_dac_output_new, 38 .pior = { .nr = 3, .new = nv50_pior_new },
37 .outp.internal.tmds = nv50_sor_output_new,
38 .outp.internal.lvds = nv50_sor_output_new,
39 .outp.external.tmds = nv50_pior_output_new,
40 .outp.external.dp = nv50_pior_dp_new,
41 .dac.nr = 3,
42 .dac.power = nv50_dac_power,
43 .dac.sense = nv50_dac_sense,
44 .sor.nr = 2,
45 .sor.power = nv50_sor_power,
46 .sor.hdmi = g84_hdmi_ctrl,
47 .pior.nr = 3,
48 .pior.power = nv50_pior_power,
49}; 39};
50 40
51int 41int
diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/gt215.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/gt215.c
index 94026288ab4d..2cdd4d7a98d3 100644
--- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/gt215.c
+++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/gt215.c
@@ -22,32 +22,20 @@
22 * Authors: Ben Skeggs 22 * Authors: Ben Skeggs
23 */ 23 */
24#include "nv50.h" 24#include "nv50.h"
25#include "head.h"
26#include "ior.h"
25#include "rootnv50.h" 27#include "rootnv50.h"
26 28
27static const struct nv50_disp_func 29static const struct nv50_disp_func
28gt215_disp = { 30gt215_disp = {
29 .intr = nv50_disp_intr, 31 .intr = nv50_disp_intr,
30 .uevent = &nv50_disp_chan_uevent, 32 .uevent = &nv50_disp_chan_uevent,
31 .super = nv50_disp_intr_supervisor, 33 .super = nv50_disp_super,
32 .root = &gt215_disp_root_oclass, 34 .root = &gt215_disp_root_oclass,
33 .head.vblank_init = nv50_disp_vblank_init, 35 .head.new = nv50_head_new,
34 .head.vblank_fini = nv50_disp_vblank_fini, 36 .dac = { .nr = 3, .new = nv50_dac_new },
35 .head.scanoutpos = nv50_disp_root_scanoutpos, 37 .sor = { .nr = 4, .new = gt215_sor_new },
36 .outp.internal.crt = nv50_dac_output_new, 38 .pior = { .nr = 3, .new = nv50_pior_new },
37 .outp.internal.tmds = nv50_sor_output_new,
38 .outp.internal.lvds = nv50_sor_output_new,
39 .outp.internal.dp = g94_sor_dp_new,
40 .outp.external.tmds = nv50_pior_output_new,
41 .outp.external.dp = nv50_pior_dp_new,
42 .dac.nr = 3,
43 .dac.power = nv50_dac_power,
44 .dac.sense = nv50_dac_sense,
45 .sor.nr = 4,
46 .sor.power = nv50_sor_power,
47 .sor.hda_eld = gt215_hda_eld,
48 .sor.hdmi = gt215_hdmi_ctrl,
49 .pior.nr = 3,
50 .pior.power = nv50_pior_power,
51}; 39};
52 40
53int 41int
diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/hdagf119.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/hdagf119.c
index da6129b2b78f..0fa0ec0a1de0 100644
--- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/hdagf119.c
+++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/hdagf119.c
@@ -21,63 +21,34 @@
21 * 21 *
22 * Authors: Ben Skeggs 22 * Authors: Ben Skeggs
23 */ 23 */
24#include "nv50.h" 24#include "ior.h"
25#include "outp.h"
26 25
27#include <core/client.h> 26void
28#include <subdev/bios.h> 27gf119_hda_eld(struct nvkm_ior *ior, u8 *data, u8 size)
29#include <subdev/bios/dcb.h>
30#include <subdev/timer.h>
31
32#include <nvif/cl5070.h>
33#include <nvif/unpack.h>
34
35int
36gf119_hda_eld(NV50_DISP_MTHD_V1)
37{ 28{
38 struct nvkm_device *device = disp->base.engine.subdev.device; 29 struct nvkm_device *device = ior->disp->engine.subdev.device;
39 union { 30 const u32 soff = 0x030 * ior->id;
40 struct nv50_disp_sor_hda_eld_v0 v0; 31 int i;
41 } *args = data;
42 const u32 soff = outp->or * 0x030;
43 const u32 hoff = head * 0x800;
44 int ret = -ENOSYS, i;
45 32
46 nvif_ioctl(object, "disp sor hda eld size %d\n", size); 33 for (i = 0; i < size; i++)
47 if (!(ret = nvif_unpack(ret, &data, &size, args->v0, 0, 0, true))) { 34 nvkm_wr32(device, 0x10ec00 + soff, (i << 8) | data[i]);
48 nvif_ioctl(object, "disp sor hda eld vers %d\n", 35 for (; i < 0x60; i++)
49 args->v0.version); 36 nvkm_wr32(device, 0x10ec00 + soff, (i << 8));
50 if (size > 0x60) 37 nvkm_mask(device, 0x10ec10 + soff, 0x80000002, 0x80000002);
51 return -E2BIG; 38}
52 } else
53 return ret;
54 39
55 if (size && args->v0.data[0]) { 40void
56 if (outp->info.type == DCB_OUTPUT_DP) { 41gf119_hda_hpd(struct nvkm_ior *ior, int head, bool present)
57 nvkm_mask(device, 0x616618 + hoff, 0x8000000c, 0x80000001); 42{
58 nvkm_msec(device, 2000, 43 struct nvkm_device *device = ior->disp->engine.subdev.device;
59 u32 tmp = nvkm_rd32(device, 0x616618 + hoff); 44 const u32 hoff = 0x800 * head;
60 if (!(tmp & 0x80000000)) 45 u32 data = 0x80000000;
61 break; 46 u32 mask = 0x80000001;
62 ); 47 if (present) {
63 }
64 nvkm_mask(device, 0x616548 + hoff, 0x00000070, 0x00000000); 48 nvkm_mask(device, 0x616548 + hoff, 0x00000070, 0x00000000);
65 for (i = 0; i < size; i++) 49 data |= 0x00000001;
66 nvkm_wr32(device, 0x10ec00 + soff, (i << 8) | args->v0.data[i]);
67 for (; i < 0x60; i++)
68 nvkm_wr32(device, 0x10ec00 + soff, (i << 8));
69 nvkm_mask(device, 0x10ec10 + soff, 0x80000003, 0x80000003);
70 } else { 50 } else {
71 if (outp->info.type == DCB_OUTPUT_DP) { 51 mask |= 0x00000002;
72 nvkm_mask(device, 0x616618 + hoff, 0x80000001, 0x80000000);
73 nvkm_msec(device, 2000,
74 u32 tmp = nvkm_rd32(device, 0x616618 + hoff);
75 if (!(tmp & 0x80000000))
76 break;
77 );
78 }
79 nvkm_mask(device, 0x10ec10 + soff, 0x80000003, 0x80000000 | !!size);
80 } 52 }
81 53 nvkm_mask(device, 0x10ec10 + ior->id * 0x030, mask, data);
82 return 0;
83} 54}
diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/hdagt215.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/hdagt215.c
index f8f2f16c22a2..4509d2ba880e 100644
--- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/hdagt215.c
+++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/hdagt215.c
@@ -21,59 +21,31 @@
21 * 21 *
22 * Authors: Ben Skeggs 22 * Authors: Ben Skeggs
23 */ 23 */
24#include "nv50.h" 24#include "ior.h"
25#include "outp.h"
26 25
27#include <core/client.h> 26void
28#include <subdev/timer.h> 27gt215_hda_eld(struct nvkm_ior *ior, u8 *data, u8 size)
29
30#include <nvif/cl5070.h>
31#include <nvif/unpack.h>
32
33int
34gt215_hda_eld(NV50_DISP_MTHD_V1)
35{ 28{
36 struct nvkm_device *device = disp->base.engine.subdev.device; 29 struct nvkm_device *device = ior->disp->engine.subdev.device;
37 union { 30 const u32 soff = ior->id * 0x800;
38 struct nv50_disp_sor_hda_eld_v0 v0; 31 int i;
39 } *args = data;
40 const u32 soff = outp->or * 0x800;
41 int ret = -ENOSYS, i;
42
43 nvif_ioctl(object, "disp sor hda eld size %d\n", size);
44 if (!(ret = nvif_unpack(ret, &data, &size, args->v0, 0, 0, true))) {
45 nvif_ioctl(object, "disp sor hda eld vers %d\n",
46 args->v0.version);
47 if (size > 0x60)
48 return -E2BIG;
49 } else
50 return ret;
51 32
52 if (size && args->v0.data[0]) { 33 for (i = 0; i < size; i++)
53 if (outp->info.type == DCB_OUTPUT_DP) { 34 nvkm_wr32(device, 0x61c440 + soff, (i << 8) | data[i]);
54 nvkm_mask(device, 0x61c1e0 + soff, 0x8000000d, 0x80000001); 35 for (; i < 0x60; i++)
55 nvkm_msec(device, 2000, 36 nvkm_wr32(device, 0x61c440 + soff, (i << 8));
56 u32 tmp = nvkm_rd32(device, 0x61c1e0 + soff); 37 nvkm_mask(device, 0x61c448 + soff, 0x80000002, 0x80000002);
57 if (!(tmp & 0x80000000)) 38}
58 break;
59 );
60 }
61 for (i = 0; i < size; i++)
62 nvkm_wr32(device, 0x61c440 + soff, (i << 8) | args->v0.data[i]);
63 for (; i < 0x60; i++)
64 nvkm_wr32(device, 0x61c440 + soff, (i << 8));
65 nvkm_mask(device, 0x61c448 + soff, 0x80000003, 0x80000003);
66 } else {
67 if (outp->info.type == DCB_OUTPUT_DP) {
68 nvkm_mask(device, 0x61c1e0 + soff, 0x80000001, 0x80000000);
69 nvkm_msec(device, 2000,
70 u32 tmp = nvkm_rd32(device, 0x61c1e0 + soff);
71 if (!(tmp & 0x80000000))
72 break;
73 );
74 }
75 nvkm_mask(device, 0x61c448 + soff, 0x80000003, 0x80000000 | !!size);
76 }
77 39
78 return 0; 40void
41gt215_hda_hpd(struct nvkm_ior *ior, int head, bool present)
42{
43 struct nvkm_device *device = ior->disp->engine.subdev.device;
44 u32 data = 0x80000000;
45 u32 mask = 0x80000001;
46 if (present)
47 data |= 0x00000001;
48 else
49 mask |= 0x00000002;
50 nvkm_mask(device, 0x61c448 + ior->id * 0x800, mask, data);
79} 51}
diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/hdmi.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/hdmi.c
new file mode 100644
index 000000000000..e82c68f18444
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/hdmi.c
@@ -0,0 +1,66 @@
1#include "hdmi.h"
2
3void pack_hdmi_infoframe(struct packed_hdmi_infoframe *packed_frame,
4 u8 *raw_frame, ssize_t len)
5{
6 u32 header = 0;
7 u32 subpack0_low = 0;
8 u32 subpack0_high = 0;
9 u32 subpack1_low = 0;
10 u32 subpack1_high = 0;
11
12 switch (len) {
13 /*
14 * "When in doubt, use brute force."
15 * -- Ken Thompson.
16 */
17 default:
18 /*
19 * We presume that no valid frame is longer than 17
20 * octets, including header... And truncate to that
21 * if it's longer.
22 */
23 case 17:
24 subpack1_high = (raw_frame[16] << 16);
25 case 16:
26 subpack1_high |= (raw_frame[15] << 8);
27 case 15:
28 subpack1_high |= raw_frame[14];
29 case 14:
30 subpack1_low = (raw_frame[13] << 24);
31 case 13:
32 subpack1_low |= (raw_frame[12] << 16);
33 case 12:
34 subpack1_low |= (raw_frame[11] << 8);
35 case 11:
36 subpack1_low |= raw_frame[10];
37 case 10:
38 subpack0_high = (raw_frame[9] << 16);
39 case 9:
40 subpack0_high |= (raw_frame[8] << 8);
41 case 8:
42 subpack0_high |= raw_frame[7];
43 case 7:
44 subpack0_low = (raw_frame[6] << 24);
45 case 6:
46 subpack0_low |= (raw_frame[5] << 16);
47 case 5:
48 subpack0_low |= (raw_frame[4] << 8);
49 case 4:
50 subpack0_low |= raw_frame[3];
51 case 3:
52 header = (raw_frame[2] << 16);
53 case 2:
54 header |= (raw_frame[1] << 8);
55 case 1:
56 header |= raw_frame[0];
57 case 0:
58 break;
59 }
60
61 packed_frame->header = header;
62 packed_frame->subpack0_low = subpack0_low;
63 packed_frame->subpack0_high = subpack0_high;
64 packed_frame->subpack1_low = subpack1_low;
65 packed_frame->subpack1_high = subpack1_high;
66}
diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/hdmi.h b/drivers/gpu/drm/nouveau/nvkm/engine/disp/hdmi.h
new file mode 100644
index 000000000000..528f5621a496
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/hdmi.h
@@ -0,0 +1,15 @@
1#ifndef __NVKM_DISP_HDMI_H__
2#define __NVKM_DISP_HDMI_H__
3#include "ior.h"
4
5struct packed_hdmi_infoframe {
6 u32 header;
7 u32 subpack0_low;
8 u32 subpack0_high;
9 u32 subpack1_low;
10 u32 subpack1_high;
11};
12
13void pack_hdmi_infoframe(struct packed_hdmi_infoframe *packed_frame,
14 u8 *raw_frame, ssize_t len);
15#endif
diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/hdmig84.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/hdmig84.c
index 1c4256e8cbd6..661410f9b457 100644
--- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/hdmig84.c
+++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/hdmig84.c
@@ -21,54 +21,42 @@
21 * 21 *
22 * Authors: Ben Skeggs 22 * Authors: Ben Skeggs
23 */ 23 */
24#include "nv50.h" 24#include "hdmi.h"
25 25
26#include <core/client.h> 26void
27 27g84_hdmi_ctrl(struct nvkm_ior *ior, int head, bool enable, u8 max_ac_packet,
28#include <nvif/cl5070.h> 28 u8 rekey, u8 *avi, u8 avi_size, u8 *vendor, u8 vendor_size)
29#include <nvif/unpack.h>
30
31int
32g84_hdmi_ctrl(NV50_DISP_MTHD_V1)
33{ 29{
34 struct nvkm_device *device = disp->base.engine.subdev.device; 30 struct nvkm_device *device = ior->disp->engine.subdev.device;
35 const u32 hoff = (head * 0x800); 31 const u32 ctrl = 0x40000000 * enable |
36 union { 32 0x1f000000 /* ??? */ |
37 struct nv50_disp_sor_hdmi_pwr_v0 v0; 33 max_ac_packet << 16 |
38 } *args = data; 34 rekey;
39 u32 ctrl; 35 const u32 hoff = head * 0x800;
40 int ret = -ENOSYS; 36 struct packed_hdmi_infoframe avi_infoframe;
37 struct packed_hdmi_infoframe vendor_infoframe;
41 38
42 nvif_ioctl(object, "disp sor hdmi ctrl size %d\n", size); 39 pack_hdmi_infoframe(&avi_infoframe, avi, avi_size);
43 if (!(ret = nvif_unpack(ret, &data, &size, args->v0, 0, 0, false))) { 40 pack_hdmi_infoframe(&vendor_infoframe, vendor, vendor_size);
44 nvif_ioctl(object, "disp sor hdmi ctrl vers %d state %d "
45 "max_ac_packet %d rekey %d\n",
46 args->v0.version, args->v0.state,
47 args->v0.max_ac_packet, args->v0.rekey);
48 if (args->v0.max_ac_packet > 0x1f || args->v0.rekey > 0x7f)
49 return -EINVAL;
50 ctrl = 0x40000000 * !!args->v0.state;
51 ctrl |= args->v0.max_ac_packet << 16;
52 ctrl |= args->v0.rekey;
53 ctrl |= 0x1f000000; /* ??? */
54 } else
55 return ret;
56 41
57 if (!(ctrl & 0x40000000)) { 42 if (!(ctrl & 0x40000000)) {
58 nvkm_mask(device, 0x6165a4 + hoff, 0x40000000, 0x00000000); 43 nvkm_mask(device, 0x6165a4 + hoff, 0x40000000, 0x00000000);
44 nvkm_mask(device, 0x61653c + hoff, 0x00000001, 0x00000000);
59 nvkm_mask(device, 0x616520 + hoff, 0x00000001, 0x00000000); 45 nvkm_mask(device, 0x616520 + hoff, 0x00000001, 0x00000000);
60 nvkm_mask(device, 0x616500 + hoff, 0x00000001, 0x00000000); 46 nvkm_mask(device, 0x616500 + hoff, 0x00000001, 0x00000000);
61 return 0; 47 return;
62 } 48 }
63 49
64 /* AVI InfoFrame */ 50 /* AVI InfoFrame */
65 nvkm_mask(device, 0x616520 + hoff, 0x00000001, 0x00000000); 51 nvkm_mask(device, 0x616520 + hoff, 0x00000001, 0x00000000);
66 nvkm_wr32(device, 0x616528 + hoff, 0x000d0282); 52 if (avi_size) {
67 nvkm_wr32(device, 0x61652c + hoff, 0x0000006f); 53 nvkm_wr32(device, 0x616528 + hoff, avi_infoframe.header);
68 nvkm_wr32(device, 0x616530 + hoff, 0x00000000); 54 nvkm_wr32(device, 0x61652c + hoff, avi_infoframe.subpack0_low);
69 nvkm_wr32(device, 0x616534 + hoff, 0x00000000); 55 nvkm_wr32(device, 0x616530 + hoff, avi_infoframe.subpack0_high);
70 nvkm_wr32(device, 0x616538 + hoff, 0x00000000); 56 nvkm_wr32(device, 0x616534 + hoff, avi_infoframe.subpack1_low);
71 nvkm_mask(device, 0x616520 + hoff, 0x00000001, 0x00000001); 57 nvkm_wr32(device, 0x616538 + hoff, avi_infoframe.subpack1_high);
58 nvkm_mask(device, 0x616520 + hoff, 0x00000001, 0x00000001);
59 }
72 60
73 /* Audio InfoFrame */ 61 /* Audio InfoFrame */
74 nvkm_mask(device, 0x616500 + hoff, 0x00000001, 0x00000000); 62 nvkm_mask(device, 0x616500 + hoff, 0x00000001, 0x00000000);
@@ -77,6 +65,18 @@ g84_hdmi_ctrl(NV50_DISP_MTHD_V1)
77 nvkm_wr32(device, 0x616510 + hoff, 0x00000000); 65 nvkm_wr32(device, 0x616510 + hoff, 0x00000000);
78 nvkm_mask(device, 0x616500 + hoff, 0x00000001, 0x00000001); 66 nvkm_mask(device, 0x616500 + hoff, 0x00000001, 0x00000001);
79 67
68 /* Vendor InfoFrame */
69 nvkm_mask(device, 0x61653c + hoff, 0x00010001, 0x00010000);
70 if (vendor_size) {
71 nvkm_wr32(device, 0x616544 + hoff, vendor_infoframe.header);
72 nvkm_wr32(device, 0x616548 + hoff, vendor_infoframe.subpack0_low);
73 nvkm_wr32(device, 0x61654c + hoff, vendor_infoframe.subpack0_high);
74 /* Is there a second (or up to fourth?) set of subpack registers here? */
75 /* nvkm_wr32(device, 0x616550 + hoff, vendor_infoframe->subpack1_low); */
76 /* nvkm_wr32(device, 0x616554 + hoff, vendor_infoframe->subpack1_high); */
77 nvkm_mask(device, 0x61653c + hoff, 0x00010001, 0x00010001);
78 }
79
80 nvkm_mask(device, 0x6165d0 + hoff, 0x00070001, 0x00010001); /* SPARE, HW_CTS */ 80 nvkm_mask(device, 0x6165d0 + hoff, 0x00070001, 0x00010001); /* SPARE, HW_CTS */
81 nvkm_mask(device, 0x616568 + hoff, 0x00010101, 0x00000000); /* ACR_CTRL, ?? */ 81 nvkm_mask(device, 0x616568 + hoff, 0x00010101, 0x00000000); /* ACR_CTRL, ?? */
82 nvkm_mask(device, 0x616578 + hoff, 0x80000000, 0x80000000); /* ACR_0441_ENABLE */ 82 nvkm_mask(device, 0x616578 + hoff, 0x80000000, 0x80000000); /* ACR_0441_ENABLE */
@@ -88,5 +88,4 @@ g84_hdmi_ctrl(NV50_DISP_MTHD_V1)
88 88
89 /* HDMI_CTRL */ 89 /* HDMI_CTRL */
90 nvkm_mask(device, 0x6165a4 + hoff, 0x5f1f007f, ctrl); 90 nvkm_mask(device, 0x6165a4 + hoff, 0x5f1f007f, ctrl);
91 return 0;
92} 91}
diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/hdmigf119.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/hdmigf119.c
index 632f02da1382..6cac0e72b4cc 100644
--- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/hdmigf119.c
+++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/hdmigf119.c
@@ -21,53 +21,56 @@
21 * 21 *
22 * Authors: Ben Skeggs 22 * Authors: Ben Skeggs
23 */ 23 */
24#include "nv50.h" 24#include "hdmi.h"
25 25
26#include <core/client.h> 26void
27 27gf119_hdmi_ctrl(struct nvkm_ior *ior, int head, bool enable, u8 max_ac_packet,
28#include <nvif/cl5070.h> 28 u8 rekey, u8 *avi, u8 avi_size, u8 *vendor, u8 vendor_size)
29#include <nvif/unpack.h>
30
31int
32gf119_hdmi_ctrl(NV50_DISP_MTHD_V1)
33{ 29{
34 struct nvkm_device *device = disp->base.engine.subdev.device; 30 struct nvkm_device *device = ior->disp->engine.subdev.device;
35 const u32 hoff = (head * 0x800); 31 const u32 ctrl = 0x40000000 * enable |
36 union { 32 max_ac_packet << 16 |
37 struct nv50_disp_sor_hdmi_pwr_v0 v0; 33 rekey;
38 } *args = data; 34 const u32 hoff = head * 0x800;
39 u32 ctrl; 35 struct packed_hdmi_infoframe avi_infoframe;
40 int ret = -ENOSYS; 36 struct packed_hdmi_infoframe vendor_infoframe;
41 37
42 nvif_ioctl(object, "disp sor hdmi ctrl size %d\n", size); 38 pack_hdmi_infoframe(&avi_infoframe, avi, avi_size);
43 if (!(ret = nvif_unpack(ret, &data, &size, args->v0, 0, 0, false))) { 39 pack_hdmi_infoframe(&vendor_infoframe, vendor, vendor_size);
44 nvif_ioctl(object, "disp sor hdmi ctrl vers %d state %d "
45 "max_ac_packet %d rekey %d\n",
46 args->v0.version, args->v0.state,
47 args->v0.max_ac_packet, args->v0.rekey);
48 if (args->v0.max_ac_packet > 0x1f || args->v0.rekey > 0x7f)
49 return -EINVAL;
50 ctrl = 0x40000000 * !!args->v0.state;
51 ctrl |= args->v0.max_ac_packet << 16;
52 ctrl |= args->v0.rekey;
53 } else
54 return ret;
55 40
56 if (!(ctrl & 0x40000000)) { 41 if (!(ctrl & 0x40000000)) {
57 nvkm_mask(device, 0x616798 + hoff, 0x40000000, 0x00000000); 42 nvkm_mask(device, 0x616798 + hoff, 0x40000000, 0x00000000);
43 nvkm_mask(device, 0x616730 + hoff, 0x00000001, 0x00000000);
58 nvkm_mask(device, 0x6167a4 + hoff, 0x00000001, 0x00000000); 44 nvkm_mask(device, 0x6167a4 + hoff, 0x00000001, 0x00000000);
59 nvkm_mask(device, 0x616714 + hoff, 0x00000001, 0x00000000); 45 nvkm_mask(device, 0x616714 + hoff, 0x00000001, 0x00000000);
60 return 0; 46 return;
61 } 47 }
62 48
63 /* AVI InfoFrame */ 49 /* AVI InfoFrame */
64 nvkm_mask(device, 0x616714 + hoff, 0x00000001, 0x00000000); 50 nvkm_mask(device, 0x616714 + hoff, 0x00000001, 0x00000000);
65 nvkm_wr32(device, 0x61671c + hoff, 0x000d0282); 51 if (avi_size) {
66 nvkm_wr32(device, 0x616720 + hoff, 0x0000006f); 52 nvkm_wr32(device, 0x61671c + hoff, avi_infoframe.header);
67 nvkm_wr32(device, 0x616724 + hoff, 0x00000000); 53 nvkm_wr32(device, 0x616720 + hoff, avi_infoframe.subpack0_low);
68 nvkm_wr32(device, 0x616728 + hoff, 0x00000000); 54 nvkm_wr32(device, 0x616724 + hoff, avi_infoframe.subpack0_high);
69 nvkm_wr32(device, 0x61672c + hoff, 0x00000000); 55 nvkm_wr32(device, 0x616728 + hoff, avi_infoframe.subpack1_low);
70 nvkm_mask(device, 0x616714 + hoff, 0x00000001, 0x00000001); 56 nvkm_wr32(device, 0x61672c + hoff, avi_infoframe.subpack1_high);
57 nvkm_mask(device, 0x616714 + hoff, 0x00000001, 0x00000001);
58 }
59
60 /* GENERIC(?) / Vendor InfoFrame? */
61 nvkm_mask(device, 0x616730 + hoff, 0x00010001, 0x00010000);
62 if (vendor_size) {
63 /*
64 * These appear to be the audio infoframe registers,
65 * but no other set of infoframe registers has yet
66 * been found.
67 */
68 nvkm_wr32(device, 0x616738 + hoff, vendor_infoframe.header);
69 nvkm_wr32(device, 0x61673c + hoff, vendor_infoframe.subpack0_low);
70 nvkm_wr32(device, 0x616740 + hoff, vendor_infoframe.subpack0_high);
71 /* Is there a second (or further?) set of subpack registers here? */
72 nvkm_mask(device, 0x616730 + hoff, 0x00000001, 0x00000001);
73 }
71 74
72 /* ??? InfoFrame? */ 75 /* ??? InfoFrame? */
73 nvkm_mask(device, 0x6167a4 + hoff, 0x00000001, 0x00000000); 76 nvkm_mask(device, 0x6167a4 + hoff, 0x00000001, 0x00000000);
@@ -76,5 +79,4 @@ gf119_hdmi_ctrl(NV50_DISP_MTHD_V1)
76 79
77 /* HDMI_CTRL */ 80 /* HDMI_CTRL */
78 nvkm_mask(device, 0x616798 + hoff, 0x401f007f, ctrl); 81 nvkm_mask(device, 0x616798 + hoff, 0x401f007f, ctrl);
79 return 0;
80} 82}
diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/hdmigk104.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/hdmigk104.c
index 4e8067d511d7..ed0a6100d76b 100644
--- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/hdmigk104.c
+++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/hdmigk104.c
@@ -21,54 +21,53 @@
21 * 21 *
22 * Authors: Ben Skeggs 22 * Authors: Ben Skeggs
23 */ 23 */
24#include "nv50.h" 24#include "hdmi.h"
25 25
26#include <core/client.h> 26void
27 27gk104_hdmi_ctrl(struct nvkm_ior *ior, int head, bool enable, u8 max_ac_packet,
28#include <nvif/cl5070.h> 28 u8 rekey, u8 *avi, u8 avi_size, u8 *vendor, u8 vendor_size)
29#include <nvif/unpack.h>
30
31int
32gk104_hdmi_ctrl(NV50_DISP_MTHD_V1)
33{ 29{
34 struct nvkm_device *device = disp->base.engine.subdev.device; 30 struct nvkm_device *device = ior->disp->engine.subdev.device;
35 const u32 hoff = (head * 0x800); 31 const u32 ctrl = 0x40000000 * enable |
36 const u32 hdmi = (head * 0x400); 32 max_ac_packet << 16 |
37 union { 33 rekey;
38 struct nv50_disp_sor_hdmi_pwr_v0 v0; 34 const u32 hoff = head * 0x800;
39 } *args = data; 35 const u32 hdmi = head * 0x400;
40 u32 ctrl; 36 struct packed_hdmi_infoframe avi_infoframe;
41 int ret = -ENOSYS; 37 struct packed_hdmi_infoframe vendor_infoframe;
42 38
43 nvif_ioctl(object, "disp sor hdmi ctrl size %d\n", size); 39 pack_hdmi_infoframe(&avi_infoframe, avi, avi_size);
44 if (!(ret = nvif_unpack(ret, &data, &size, args->v0, 0, 0, false))) { 40 pack_hdmi_infoframe(&vendor_infoframe, vendor, vendor_size);
45 nvif_ioctl(object, "disp sor hdmi ctrl vers %d state %d "
46 "max_ac_packet %d rekey %d\n",
47 args->v0.version, args->v0.state,
48 args->v0.max_ac_packet, args->v0.rekey);
49 if (args->v0.max_ac_packet > 0x1f || args->v0.rekey > 0x7f)
50 return -EINVAL;
51 ctrl = 0x40000000 * !!args->v0.state;
52 ctrl |= args->v0.max_ac_packet << 16;
53 ctrl |= args->v0.rekey;
54 } else
55 return ret;
56 41
57 if (!(ctrl & 0x40000000)) { 42 if (!(ctrl & 0x40000000)) {
58 nvkm_mask(device, 0x616798 + hoff, 0x40000000, 0x00000000); 43 nvkm_mask(device, 0x616798 + hoff, 0x40000000, 0x00000000);
44 nvkm_mask(device, 0x690100 + hdmi, 0x00000001, 0x00000000);
59 nvkm_mask(device, 0x6900c0 + hdmi, 0x00000001, 0x00000000); 45 nvkm_mask(device, 0x6900c0 + hdmi, 0x00000001, 0x00000000);
60 nvkm_mask(device, 0x690000 + hdmi, 0x00000001, 0x00000000); 46 nvkm_mask(device, 0x690000 + hdmi, 0x00000001, 0x00000000);
61 return 0; 47 return;
62 } 48 }
63 49
64 /* AVI InfoFrame */ 50 /* AVI InfoFrame */
65 nvkm_mask(device, 0x690000 + hdmi, 0x00000001, 0x00000000); 51 nvkm_mask(device, 0x690000 + hdmi, 0x00000001, 0x00000000);
66 nvkm_wr32(device, 0x690008 + hdmi, 0x000d0282); 52 if (avi_size) {
67 nvkm_wr32(device, 0x69000c + hdmi, 0x0000006f); 53 nvkm_wr32(device, 0x690008 + hdmi, avi_infoframe.header);
68 nvkm_wr32(device, 0x690010 + hdmi, 0x00000000); 54 nvkm_wr32(device, 0x69000c + hdmi, avi_infoframe.subpack0_low);
69 nvkm_wr32(device, 0x690014 + hdmi, 0x00000000); 55 nvkm_wr32(device, 0x690010 + hdmi, avi_infoframe.subpack0_high);
70 nvkm_wr32(device, 0x690018 + hdmi, 0x00000000); 56 nvkm_wr32(device, 0x690014 + hdmi, avi_infoframe.subpack1_low);
71 nvkm_mask(device, 0x690000 + hdmi, 0x00000001, 0x00000001); 57 nvkm_wr32(device, 0x690018 + hdmi, avi_infoframe.subpack1_high);
58 nvkm_mask(device, 0x690000 + hdmi, 0x00000001, 0x00000001);
59 }
60
61 /* GENERIC(?) / Vendor InfoFrame? */
62 nvkm_mask(device, 0x690100 + hdmi, 0x00010001, 0x00000000);
63 if (vendor_size) {
64 nvkm_wr32(device, 0x690108 + hdmi, vendor_infoframe.header);
65 nvkm_wr32(device, 0x69010c + hdmi, vendor_infoframe.subpack0_low);
66 nvkm_wr32(device, 0x690110 + hdmi, vendor_infoframe.subpack0_high);
67 /* Is there a second (or further?) set of subpack registers here? */
68 nvkm_mask(device, 0x690100 + hdmi, 0x00000001, 0x00000001);
69 }
70
72 71
73 /* ??? InfoFrame? */ 72 /* ??? InfoFrame? */
74 nvkm_mask(device, 0x6900c0 + hdmi, 0x00000001, 0x00000000); 73 nvkm_mask(device, 0x6900c0 + hdmi, 0x00000001, 0x00000000);
@@ -80,5 +79,4 @@ gk104_hdmi_ctrl(NV50_DISP_MTHD_V1)
80 79
81 /* HDMI_CTRL */ 80 /* HDMI_CTRL */
82 nvkm_mask(device, 0x616798 + hoff, 0x401f007f, ctrl); 81 nvkm_mask(device, 0x616798 + hoff, 0x401f007f, ctrl);
83 return 0;
84} 82}
diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/hdmigt215.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/hdmigt215.c
index f1afc16494b6..0993d223bb9c 100644
--- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/hdmigt215.c
+++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/hdmigt215.c
@@ -21,55 +21,42 @@
21 * 21 *
22 * Authors: Ben Skeggs 22 * Authors: Ben Skeggs
23 */ 23 */
24#include "nv50.h" 24#include "hdmi.h"
25#include "outp.h"
26 25
27#include <core/client.h> 26void
28 27gt215_hdmi_ctrl(struct nvkm_ior *ior, int head, bool enable, u8 max_ac_packet,
29#include <nvif/cl5070.h> 28 u8 rekey, u8 *avi, u8 avi_size, u8 *vendor, u8 vendor_size)
30#include <nvif/unpack.h>
31
32int
33gt215_hdmi_ctrl(NV50_DISP_MTHD_V1)
34{ 29{
35 struct nvkm_device *device = disp->base.engine.subdev.device; 30 struct nvkm_device *device = ior->disp->engine.subdev.device;
36 const u32 soff = outp->or * 0x800; 31 const u32 ctrl = 0x40000000 * enable |
37 union { 32 0x1f000000 /* ??? */ |
38 struct nv50_disp_sor_hdmi_pwr_v0 v0; 33 max_ac_packet << 16 |
39 } *args = data; 34 rekey;
40 u32 ctrl; 35 const u32 soff = nv50_ior_base(ior);
41 int ret = -ENOSYS; 36 struct packed_hdmi_infoframe avi_infoframe;
37 struct packed_hdmi_infoframe vendor_infoframe;
42 38
43 nvif_ioctl(object, "disp sor hdmi ctrl size %d\n", size); 39 pack_hdmi_infoframe(&avi_infoframe, avi, avi_size);
44 if (!(ret = nvif_unpack(ret, &data, &size, args->v0, 0, 0, false))) { 40 pack_hdmi_infoframe(&vendor_infoframe, vendor, vendor_size);
45 nvif_ioctl(object, "disp sor hdmi ctrl vers %d state %d "
46 "max_ac_packet %d rekey %d\n",
47 args->v0.version, args->v0.state,
48 args->v0.max_ac_packet, args->v0.rekey);
49 if (args->v0.max_ac_packet > 0x1f || args->v0.rekey > 0x7f)
50 return -EINVAL;
51 ctrl = 0x40000000 * !!args->v0.state;
52 ctrl |= args->v0.max_ac_packet << 16;
53 ctrl |= args->v0.rekey;
54 ctrl |= 0x1f000000; /* ??? */
55 } else
56 return ret;
57 41
58 if (!(ctrl & 0x40000000)) { 42 if (!(ctrl & 0x40000000)) {
59 nvkm_mask(device, 0x61c5a4 + soff, 0x40000000, 0x00000000); 43 nvkm_mask(device, 0x61c5a4 + soff, 0x40000000, 0x00000000);
44 nvkm_mask(device, 0x61c53c + soff, 0x00000001, 0x00000000);
60 nvkm_mask(device, 0x61c520 + soff, 0x00000001, 0x00000000); 45 nvkm_mask(device, 0x61c520 + soff, 0x00000001, 0x00000000);
61 nvkm_mask(device, 0x61c500 + soff, 0x00000001, 0x00000000); 46 nvkm_mask(device, 0x61c500 + soff, 0x00000001, 0x00000000);
62 return 0; 47 return;
63 } 48 }
64 49
65 /* AVI InfoFrame */ 50 /* AVI InfoFrame */
66 nvkm_mask(device, 0x61c520 + soff, 0x00000001, 0x00000000); 51 nvkm_mask(device, 0x61c520 + soff, 0x00000001, 0x00000000);
67 nvkm_wr32(device, 0x61c528 + soff, 0x000d0282); 52 if (avi_size) {
68 nvkm_wr32(device, 0x61c52c + soff, 0x0000006f); 53 nvkm_wr32(device, 0x61c528 + soff, avi_infoframe.header);
69 nvkm_wr32(device, 0x61c530 + soff, 0x00000000); 54 nvkm_wr32(device, 0x61c52c + soff, avi_infoframe.subpack0_low);
70 nvkm_wr32(device, 0x61c534 + soff, 0x00000000); 55 nvkm_wr32(device, 0x61c530 + soff, avi_infoframe.subpack0_high);
71 nvkm_wr32(device, 0x61c538 + soff, 0x00000000); 56 nvkm_wr32(device, 0x61c534 + soff, avi_infoframe.subpack1_low);
72 nvkm_mask(device, 0x61c520 + soff, 0x00000001, 0x00000001); 57 nvkm_wr32(device, 0x61c538 + soff, avi_infoframe.subpack1_high);
58 nvkm_mask(device, 0x61c520 + soff, 0x00000001, 0x00000001);
59 }
73 60
74 /* Audio InfoFrame */ 61 /* Audio InfoFrame */
75 nvkm_mask(device, 0x61c500 + soff, 0x00000001, 0x00000000); 62 nvkm_mask(device, 0x61c500 + soff, 0x00000001, 0x00000000);
@@ -78,6 +65,18 @@ gt215_hdmi_ctrl(NV50_DISP_MTHD_V1)
78 nvkm_wr32(device, 0x61c510 + soff, 0x00000000); 65 nvkm_wr32(device, 0x61c510 + soff, 0x00000000);
79 nvkm_mask(device, 0x61c500 + soff, 0x00000001, 0x00000001); 66 nvkm_mask(device, 0x61c500 + soff, 0x00000001, 0x00000001);
80 67
68 /* Vendor InfoFrame */
69 nvkm_mask(device, 0x61c53c + soff, 0x00010001, 0x00010000);
70 if (vendor_size) {
71 nvkm_wr32(device, 0x61c544 + soff, vendor_infoframe.header);
72 nvkm_wr32(device, 0x61c548 + soff, vendor_infoframe.subpack0_low);
73 nvkm_wr32(device, 0x61c54c + soff, vendor_infoframe.subpack0_high);
74 /* Is there a second (or up to fourth?) set of subpack registers here? */
75 /* nvkm_wr32(device, 0x61c550 + soff, vendor_infoframe.subpack1_low); */
76 /* nvkm_wr32(device, 0x61c554 + soff, vendor_infoframe.subpack1_high); */
77 nvkm_mask(device, 0x61c53c + soff, 0x00010001, 0x00010001);
78 }
79
81 nvkm_mask(device, 0x61c5d0 + soff, 0x00070001, 0x00010001); /* SPARE, HW_CTS */ 80 nvkm_mask(device, 0x61c5d0 + soff, 0x00070001, 0x00010001); /* SPARE, HW_CTS */
82 nvkm_mask(device, 0x61c568 + soff, 0x00010101, 0x00000000); /* ACR_CTRL, ?? */ 81 nvkm_mask(device, 0x61c568 + soff, 0x00010101, 0x00000000); /* ACR_CTRL, ?? */
83 nvkm_mask(device, 0x61c578 + soff, 0x80000000, 0x80000000); /* ACR_0441_ENABLE */ 82 nvkm_mask(device, 0x61c578 + soff, 0x80000000, 0x80000000); /* ACR_0441_ENABLE */
@@ -89,5 +88,4 @@ gt215_hdmi_ctrl(NV50_DISP_MTHD_V1)
89 88
90 /* HDMI_CTRL */ 89 /* HDMI_CTRL */
91 nvkm_mask(device, 0x61c5a4 + soff, 0x5f1f007f, ctrl); 90 nvkm_mask(device, 0x61c5a4 + soff, 0x5f1f007f, ctrl);
92 return 0;
93} 91}
diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/head.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/head.c
new file mode 100644
index 000000000000..5c557f3e6c2c
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/head.c
@@ -0,0 +1,105 @@
1/*
2 * Copyright 2017 Red Hat Inc.
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: Ben Skeggs <bskeggs@redhat.com>
23 */
24#include "head.h"
25
26#include <core/client.h>
27
28#include <nvif/cl0046.h>
29#include <nvif/unpack.h>
30
31struct nvkm_head *
32nvkm_head_find(struct nvkm_disp *disp, int id)
33{
34 struct nvkm_head *head;
35 list_for_each_entry(head, &disp->head, head) {
36 if (head->id == id)
37 return head;
38 }
39 return NULL;
40}
41
42int
43nvkm_head_mthd_scanoutpos(struct nvkm_object *object,
44 struct nvkm_head *head, void *data, u32 size)
45{
46 union {
47 struct nv04_disp_scanoutpos_v0 v0;
48 } *args = data;
49 int ret = -ENOSYS;
50
51 nvif_ioctl(object, "head scanoutpos size %d\n", size);
52 if (!(ret = nvif_unpack(ret, &data, &size, args->v0, 0, 0, false))) {
53 nvif_ioctl(object, "head scanoutpos vers %d\n",
54 args->v0.version);
55
56 head->func->state(head, &head->arm);
57 args->v0.vtotal = head->arm.vtotal;
58 args->v0.vblanks = head->arm.vblanks;
59 args->v0.vblanke = head->arm.vblanke;
60 args->v0.htotal = head->arm.htotal;
61 args->v0.hblanks = head->arm.hblanks;
62 args->v0.hblanke = head->arm.hblanke;
63
64 /* We don't support reading htotal/vtotal on pre-NV50 VGA,
65 * so we have to give up and trigger the timestamping
66 * fallback in the drm core.
67 */
68 if (!args->v0.vtotal || !args->v0.htotal)
69 return -ENOTSUPP;
70
71 args->v0.time[0] = ktime_to_ns(ktime_get());
72 head->func->rgpos(head, &args->v0.hline, &args->v0.vline);
73 args->v0.time[1] = ktime_to_ns(ktime_get());
74 } else
75 return ret;
76
77 return 0;
78}
79
80void
81nvkm_head_del(struct nvkm_head **phead)
82{
83 struct nvkm_head *head = *phead;
84 if (head) {
85 HEAD_DBG(head, "dtor");
86 list_del(&head->head);
87 kfree(*phead);
88 *phead = NULL;
89 }
90}
91
92int
93nvkm_head_new_(const struct nvkm_head_func *func,
94 struct nvkm_disp *disp, int id)
95{
96 struct nvkm_head *head;
97 if (!(head = kzalloc(sizeof(*head), GFP_KERNEL)))
98 return -ENOMEM;
99 head->func = func;
100 head->disp = disp;
101 head->id = id;
102 list_add_tail(&head->head, &disp->head);
103 HEAD_DBG(head, "ctor");
104 return 0;
105}
diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/head.h b/drivers/gpu/drm/nouveau/nvkm/engine/disp/head.h
new file mode 100644
index 000000000000..b04c49d2eeeb
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/head.h
@@ -0,0 +1,56 @@
1#ifndef __NVKM_DISP_HEAD_H__
2#define __NVKM_DISP_HEAD_H__
3#include "priv.h"
4
5struct nvkm_head {
6 const struct nvkm_head_func *func;
7 struct nvkm_disp *disp;
8 int id;
9
10 struct list_head head;
11
12 struct nvkm_head_state {
13 u16 htotal;
14 u16 hsynce;
15 u16 hblanke;
16 u16 hblanks;
17 u16 vtotal;
18 u16 vsynce;
19 u16 vblanke;
20 u16 vblanks;
21 u32 hz;
22
23 /* Prior to GF119, these are set by the OR. */
24 struct {
25 u8 depth;
26 } or;
27 } arm, asy;
28};
29
30int nvkm_head_new_(const struct nvkm_head_func *, struct nvkm_disp *, int id);
31void nvkm_head_del(struct nvkm_head **);
32int nvkm_head_mthd_scanoutpos(struct nvkm_object *,
33 struct nvkm_head *, void *, u32);
34struct nvkm_head *nvkm_head_find(struct nvkm_disp *, int id);
35
36struct nvkm_head_func {
37 void (*state)(struct nvkm_head *, struct nvkm_head_state *);
38 void (*rgpos)(struct nvkm_head *, u16 *hline, u16 *vline);
39 void (*rgclk)(struct nvkm_head *, int div);
40 void (*vblank_get)(struct nvkm_head *);
41 void (*vblank_put)(struct nvkm_head *);
42};
43
44void nv50_head_rgpos(struct nvkm_head *, u16 *, u16 *);
45
46#define HEAD_MSG(h,l,f,a...) do { \
47 struct nvkm_head *_h = (h); \
48 nvkm_##l(&_h->disp->engine.subdev, "head-%d: "f"\n", _h->id, ##a); \
49} while(0)
50#define HEAD_WARN(h,f,a...) HEAD_MSG((h), warn, f, ##a)
51#define HEAD_DBG(h,f,a...) HEAD_MSG((h), debug, f, ##a)
52
53int nv04_head_new(struct nvkm_disp *, int id);
54int nv50_head_new(struct nvkm_disp *, int id);
55int gf119_head_new(struct nvkm_disp *, int id);
56#endif
diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/headgf119.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/headgf119.c
new file mode 100644
index 000000000000..b33552757647
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/headgf119.c
@@ -0,0 +1,96 @@
1/*
2 * Copyright 2017 Red Hat Inc.
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: Ben Skeggs <bskeggs@redhat.com>
23 */
24#include "head.h"
25
26static void
27gf119_head_vblank_put(struct nvkm_head *head)
28{
29 struct nvkm_device *device = head->disp->engine.subdev.device;
30 const u32 hoff = head->id * 0x800;
31 nvkm_mask(device, 0x6100c0 + hoff, 0x00000001, 0x00000000);
32}
33
34static void
35gf119_head_vblank_get(struct nvkm_head *head)
36{
37 struct nvkm_device *device = head->disp->engine.subdev.device;
38 const u32 hoff = head->id * 0x800;
39 nvkm_mask(device, 0x6100c0 + hoff, 0x00000001, 0x00000001);
40}
41
42static void
43gf119_head_rgclk(struct nvkm_head *head, int div)
44{
45 struct nvkm_device *device = head->disp->engine.subdev.device;
46 nvkm_mask(device, 0x612200 + (head->id * 0x800), 0x0000000f, div);
47}
48
49static void
50gf119_head_state(struct nvkm_head *head, struct nvkm_head_state *state)
51{
52 struct nvkm_device *device = head->disp->engine.subdev.device;
53 const u32 hoff = (state == &head->asy) * 0x20000 + head->id * 0x300;
54 u32 data;
55
56 data = nvkm_rd32(device, 0x640414 + hoff);
57 state->vtotal = (data & 0xffff0000) >> 16;
58 state->htotal = (data & 0x0000ffff);
59 data = nvkm_rd32(device, 0x640418 + hoff);
60 state->vsynce = (data & 0xffff0000) >> 16;
61 state->hsynce = (data & 0x0000ffff);
62 data = nvkm_rd32(device, 0x64041c + hoff);
63 state->vblanke = (data & 0xffff0000) >> 16;
64 state->hblanke = (data & 0x0000ffff);
65 data = nvkm_rd32(device, 0x640420 + hoff);
66 state->vblanks = (data & 0xffff0000) >> 16;
67 state->hblanks = (data & 0x0000ffff);
68 state->hz = nvkm_rd32(device, 0x640450 + hoff);
69
70 data = nvkm_rd32(device, 0x640404 + hoff);
71 switch ((data & 0x000003c0) >> 6) {
72 case 6: state->or.depth = 30; break;
73 case 5: state->or.depth = 24; break;
74 case 2: state->or.depth = 18; break;
75 case 0: state->or.depth = 18; break; /*XXX: "default" */
76 default:
77 state->or.depth = 18;
78 WARN_ON(1);
79 break;
80 }
81}
82
83static const struct nvkm_head_func
84gf119_head = {
85 .state = gf119_head_state,
86 .rgpos = nv50_head_rgpos,
87 .rgclk = gf119_head_rgclk,
88 .vblank_get = gf119_head_vblank_get,
89 .vblank_put = gf119_head_vblank_put,
90};
91
92int
93gf119_head_new(struct nvkm_disp *disp, int id)
94{
95 return nvkm_head_new_(&gf119_head, disp, id);
96}
diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/headnv04.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/headnv04.c
new file mode 100644
index 000000000000..dcf459282aa1
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/headnv04.c
@@ -0,0 +1,74 @@
1/*
2 * Copyright 2017 Red Hat Inc.
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: Ben Skeggs <bskeggs@redhat.com>
23 */
24#include "head.h"
25
26static void
27nv04_head_vblank_put(struct nvkm_head *head)
28{
29 struct nvkm_device *device = head->disp->engine.subdev.device;
30 nvkm_wr32(device, 0x600140 + (head->id * 0x2000) , 0x00000000);
31}
32
33static void
34nv04_head_vblank_get(struct nvkm_head *head)
35{
36 struct nvkm_device *device = head->disp->engine.subdev.device;
37 nvkm_wr32(device, 0x600140 + (head->id * 0x2000) , 0x00000001);
38}
39
40static void
41nv04_head_rgpos(struct nvkm_head *head, u16 *hline, u16 *vline)
42{
43 struct nvkm_device *device = head->disp->engine.subdev.device;
44 u32 data = nvkm_rd32(device, 0x600868 + (head->id * 0x2000));
45 *hline = (data & 0xffff0000) >> 16;
46 *vline = (data & 0x0000ffff);
47}
48
49static void
50nv04_head_state(struct nvkm_head *head, struct nvkm_head_state *state)
51{
52 struct nvkm_device *device = head->disp->engine.subdev.device;
53 const u32 hoff = head->id * 0x0200;
54 state->vblanks = nvkm_rd32(device, 0x680800 + hoff) & 0x0000ffff;
55 state->vtotal = nvkm_rd32(device, 0x680804 + hoff) & 0x0000ffff;
56 state->vblanke = state->vtotal - 1;
57 state->hblanks = nvkm_rd32(device, 0x680820 + hoff) & 0x0000ffff;
58 state->htotal = nvkm_rd32(device, 0x680824 + hoff) & 0x0000ffff;
59 state->hblanke = state->htotal - 1;
60}
61
62static const struct nvkm_head_func
63nv04_head = {
64 .state = nv04_head_state,
65 .rgpos = nv04_head_rgpos,
66 .vblank_get = nv04_head_vblank_get,
67 .vblank_put = nv04_head_vblank_put,
68};
69
70int
71nv04_head_new(struct nvkm_disp *disp, int id)
72{
73 return nvkm_head_new_(&nv04_head, disp, id);
74}
diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/headnv50.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/headnv50.c
new file mode 100644
index 000000000000..c80d06d5168f
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/headnv50.c
@@ -0,0 +1,92 @@
1/*
2 * Copyright 2017 Red Hat Inc.
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: Ben Skeggs <bskeggs@redhat.com>
23 */
24#include "head.h"
25
26static void
27nv50_head_vblank_put(struct nvkm_head *head)
28{
29 struct nvkm_device *device = head->disp->engine.subdev.device;
30 nvkm_mask(device, 0x61002c, (4 << head->id), 0);
31}
32
33static void
34nv50_head_vblank_get(struct nvkm_head *head)
35{
36 struct nvkm_device *device = head->disp->engine.subdev.device;
37 nvkm_mask(device, 0x61002c, (4 << head->id), (4 << head->id));
38}
39
40static void
41nv50_head_rgclk(struct nvkm_head *head, int div)
42{
43 struct nvkm_device *device = head->disp->engine.subdev.device;
44 nvkm_mask(device, 0x614200 + (head->id * 0x800), 0x0000000f, div);
45}
46
47void
48nv50_head_rgpos(struct nvkm_head *head, u16 *hline, u16 *vline)
49{
50 struct nvkm_device *device = head->disp->engine.subdev.device;
51 const u32 hoff = head->id * 0x800;
52 /* vline read locks hline. */
53 *vline = nvkm_rd32(device, 0x616340 + hoff) & 0x0000ffff;
54 *hline = nvkm_rd32(device, 0x616344 + hoff) & 0x0000ffff;
55}
56
57static void
58nv50_head_state(struct nvkm_head *head, struct nvkm_head_state *state)
59{
60 struct nvkm_device *device = head->disp->engine.subdev.device;
61 const u32 hoff = head->id * 0x540 + (state == &head->arm) * 4;
62 u32 data;
63
64 data = nvkm_rd32(device, 0x610ae8 + hoff);
65 state->vblanke = (data & 0xffff0000) >> 16;
66 state->hblanke = (data & 0x0000ffff);
67 data = nvkm_rd32(device, 0x610af0 + hoff);
68 state->vblanks = (data & 0xffff0000) >> 16;
69 state->hblanks = (data & 0x0000ffff);
70 data = nvkm_rd32(device, 0x610af8 + hoff);
71 state->vtotal = (data & 0xffff0000) >> 16;
72 state->htotal = (data & 0x0000ffff);
73 data = nvkm_rd32(device, 0x610b00 + hoff);
74 state->vsynce = (data & 0xffff0000) >> 16;
75 state->hsynce = (data & 0x0000ffff);
76 state->hz = (nvkm_rd32(device, 0x610ad0 + hoff) & 0x003fffff) * 1000;
77}
78
79static const struct nvkm_head_func
80nv50_head = {
81 .state = nv50_head_state,
82 .rgpos = nv50_head_rgpos,
83 .rgclk = nv50_head_rgclk,
84 .vblank_get = nv50_head_vblank_get,
85 .vblank_put = nv50_head_vblank_put,
86};
87
88int
89nv50_head_new(struct nvkm_disp *disp, int id)
90{
91 return nvkm_head_new_(&nv50_head, disp, id);
92}
diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/ior.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/ior.c
new file mode 100644
index 000000000000..a475ea56795c
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/ior.c
@@ -0,0 +1,72 @@
1/*
2 * Copyright 2017 Red Hat Inc.
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: Ben Skeggs <bskeggs@redhat.com>
23 */
24#include "ior.h"
25
26static const char *
27nvkm_ior_name[] = {
28 [DAC] = "DAC",
29 [SOR] = "SOR",
30 [PIOR] = "PIOR",
31};
32
33struct nvkm_ior *
34nvkm_ior_find(struct nvkm_disp *disp, enum nvkm_ior_type type, int id)
35{
36 struct nvkm_ior *ior;
37 list_for_each_entry(ior, &disp->ior, head) {
38 if (ior->type == type && (id < 0 || ior->id == id))
39 return ior;
40 }
41 return NULL;
42}
43
44void
45nvkm_ior_del(struct nvkm_ior **pior)
46{
47 struct nvkm_ior *ior = *pior;
48 if (ior) {
49 IOR_DBG(ior, "dtor");
50 list_del(&ior->head);
51 kfree(*pior);
52 *pior = NULL;
53 }
54}
55
56int
57nvkm_ior_new_(const struct nvkm_ior_func *func, struct nvkm_disp *disp,
58 enum nvkm_ior_type type, int id)
59{
60 struct nvkm_ior *ior;
61 if (!(ior = kzalloc(sizeof(*ior), GFP_KERNEL)))
62 return -ENOMEM;
63 ior->func = func;
64 ior->disp = disp;
65 ior->type = type;
66 ior->id = id;
67 snprintf(ior->name, sizeof(ior->name), "%s-%d",
68 nvkm_ior_name[ior->type], ior->id);
69 list_add_tail(&ior->head, &disp->ior);
70 IOR_DBG(ior, "ctor");
71 return 0;
72}
diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/ior.h b/drivers/gpu/drm/nouveau/nvkm/engine/disp/ior.h
new file mode 100644
index 000000000000..a24312fb0228
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/ior.h
@@ -0,0 +1,169 @@
1#ifndef __NVKM_DISP_IOR_H__
2#define __NVKM_DISP_IOR_H__
3#include "priv.h"
4struct nvkm_i2c_aux;
5
6struct nvkm_ior {
7 const struct nvkm_ior_func *func;
8 struct nvkm_disp *disp;
9 enum nvkm_ior_type {
10 DAC,
11 SOR,
12 PIOR,
13 } type;
14 int id;
15 char name[8];
16
17 struct list_head head;
18
19 struct nvkm_ior_state {
20 struct nvkm_outp *outp;
21 unsigned rgdiv;
22 unsigned proto_evo:4;
23 enum nvkm_ior_proto {
24 CRT,
25 TMDS,
26 LVDS,
27 DP,
28 UNKNOWN
29 } proto:3;
30 unsigned link:2;
31 unsigned head:4;
32 } arm, asy;
33
34 /* Armed DP state. */
35 struct {
36 bool mst;
37 bool ef;
38 u8 nr;
39 u8 bw;
40 } dp;
41};
42
43struct nvkm_ior_func {
44 struct {
45 int (*get)(struct nvkm_outp *, int *link);
46 void (*set)(struct nvkm_outp *, struct nvkm_ior *);
47 } route;
48
49 void (*state)(struct nvkm_ior *, struct nvkm_ior_state *);
50 void (*power)(struct nvkm_ior *, bool normal, bool pu,
51 bool data, bool vsync, bool hsync);
52 int (*sense)(struct nvkm_ior *, u32 loadval);
53 void (*clock)(struct nvkm_ior *);
54 void (*war_2)(struct nvkm_ior *);
55 void (*war_3)(struct nvkm_ior *);
56
57 struct {
58 void (*ctrl)(struct nvkm_ior *, int head, bool enable,
59 u8 max_ac_packet, u8 rekey, u8 *avi, u8 avi_size,
60 u8 *vendor, u8 vendor_size);
61 } hdmi;
62
63 struct {
64 u8 lanes[4];
65 int (*links)(struct nvkm_ior *, struct nvkm_i2c_aux *);
66 void (*power)(struct nvkm_ior *, int nr);
67 void (*pattern)(struct nvkm_ior *, int pattern);
68 void (*drive)(struct nvkm_ior *, int ln, int pc,
69 int dc, int pe, int tx_pu);
70 void (*vcpi)(struct nvkm_ior *, int head, u8 slot,
71 u8 slot_nr, u16 pbn, u16 aligned);
72 void (*audio)(struct nvkm_ior *, int head, bool enable);
73 void (*audio_sym)(struct nvkm_ior *, int head, u16 h, u32 v);
74 void (*activesym)(struct nvkm_ior *, int head,
75 u8 TU, u8 VTUa, u8 VTUf, u8 VTUi);
76 void (*watermark)(struct nvkm_ior *, int head, u8 watermark);
77 } dp;
78
79 struct {
80 void (*hpd)(struct nvkm_ior *, int head, bool present);
81 void (*eld)(struct nvkm_ior *, u8 *data, u8 size);
82 } hda;
83};
84
85int nvkm_ior_new_(const struct nvkm_ior_func *func, struct nvkm_disp *,
86 enum nvkm_ior_type type, int id);
87void nvkm_ior_del(struct nvkm_ior **);
88struct nvkm_ior *nvkm_ior_find(struct nvkm_disp *, enum nvkm_ior_type, int id);
89
90static inline u32
91nv50_ior_base(struct nvkm_ior *ior)
92{
93 return ior->id * 0x800;
94}
95
96void nv50_dac_power(struct nvkm_ior *, bool, bool, bool, bool, bool);
97int nv50_dac_sense(struct nvkm_ior *, u32);
98
99void nv50_pior_depth(struct nvkm_ior *, struct nvkm_ior_state *, u32 ctrl);
100
101static inline u32
102nv50_sor_link(struct nvkm_ior *ior)
103{
104 return nv50_ior_base(ior) + ((ior->asy.link == 2) * 0x80);
105}
106
107int nv50_sor_new_(const struct nvkm_ior_func *, struct nvkm_disp *, int id);
108void nv50_sor_state(struct nvkm_ior *, struct nvkm_ior_state *);
109void nv50_sor_power(struct nvkm_ior *, bool, bool, bool, bool, bool);
110void nv50_sor_clock(struct nvkm_ior *);
111
112void g94_sor_state(struct nvkm_ior *, struct nvkm_ior_state *);
113int g94_sor_dp_links(struct nvkm_ior *, struct nvkm_i2c_aux *);
114void g94_sor_dp_power(struct nvkm_ior *, int);
115void g94_sor_dp_pattern(struct nvkm_ior *, int);
116void g94_sor_dp_drive(struct nvkm_ior *, int, int, int, int, int);
117void g94_sor_dp_audio_sym(struct nvkm_ior *, int, u16, u32);
118void g94_sor_dp_activesym(struct nvkm_ior *, int, u8, u8, u8, u8);
119void g94_sor_dp_watermark(struct nvkm_ior *, int, u8);
120
121void gt215_sor_dp_audio(struct nvkm_ior *, int, bool);
122
123int gf119_sor_new_(const struct nvkm_ior_func *, struct nvkm_disp *, int id);
124void gf119_sor_state(struct nvkm_ior *, struct nvkm_ior_state *);
125void gf119_sor_clock(struct nvkm_ior *);
126int gf119_sor_dp_links(struct nvkm_ior *, struct nvkm_i2c_aux *);
127void gf119_sor_dp_pattern(struct nvkm_ior *, int);
128void gf119_sor_dp_drive(struct nvkm_ior *, int, int, int, int, int);
129void gf119_sor_dp_vcpi(struct nvkm_ior *, int, u8, u8, u16, u16);
130void gf119_sor_dp_audio(struct nvkm_ior *, int, bool);
131void gf119_sor_dp_audio_sym(struct nvkm_ior *, int, u16, u32);
132void gf119_sor_dp_watermark(struct nvkm_ior *, int, u8);
133
134void gm107_sor_dp_pattern(struct nvkm_ior *, int);
135
136void g84_hdmi_ctrl(struct nvkm_ior *, int, bool, u8, u8, u8 *, u8 , u8 *, u8);
137void gt215_hdmi_ctrl(struct nvkm_ior *, int, bool, u8, u8, u8 *, u8 , u8 *, u8);
138void gf119_hdmi_ctrl(struct nvkm_ior *, int, bool, u8, u8, u8 *, u8 , u8 *, u8);
139void gk104_hdmi_ctrl(struct nvkm_ior *, int, bool, u8, u8, u8 *, u8 , u8 *, u8);
140
141void gt215_hda_hpd(struct nvkm_ior *, int, bool);
142void gt215_hda_eld(struct nvkm_ior *, u8 *, u8);
143
144void gf119_hda_hpd(struct nvkm_ior *, int, bool);
145void gf119_hda_eld(struct nvkm_ior *, u8 *, u8);
146
147#define IOR_MSG(i,l,f,a...) do { \
148 struct nvkm_ior *_ior = (i); \
149 nvkm_##l(&_ior->disp->engine.subdev, "%s: "f, _ior->name, ##a); \
150} while(0)
151#define IOR_WARN(i,f,a...) IOR_MSG((i), warn, f, ##a)
152#define IOR_DBG(i,f,a...) IOR_MSG((i), debug, f, ##a)
153
154int nv50_dac_new(struct nvkm_disp *, int);
155int gf119_dac_new(struct nvkm_disp *, int);
156
157int nv50_pior_new(struct nvkm_disp *, int);
158
159int nv50_sor_new(struct nvkm_disp *, int);
160int g84_sor_new(struct nvkm_disp *, int);
161int g94_sor_new(struct nvkm_disp *, int);
162int mcp77_sor_new(struct nvkm_disp *, int);
163int gt215_sor_new(struct nvkm_disp *, int);
164int mcp89_sor_new(struct nvkm_disp *, int);
165int gf119_sor_new(struct nvkm_disp *, int);
166int gk104_sor_new(struct nvkm_disp *, int);
167int gm107_sor_new(struct nvkm_disp *, int);
168int gm200_sor_new(struct nvkm_disp *, int);
169#endif
diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/mcp77.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/mcp77.c
new file mode 100644
index 000000000000..d7e0fbb12bf1
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/mcp77.c
@@ -0,0 +1,43 @@
1/*
2 * Copyright 2017 Red Hat Inc.
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#include "nv50.h"
23#include "head.h"
24#include "ior.h"
25#include "rootnv50.h"
26
27static const struct nv50_disp_func
28mcp77_disp = {
29 .intr = nv50_disp_intr,
30 .uevent = &nv50_disp_chan_uevent,
31 .super = nv50_disp_super,
32 .root = &g94_disp_root_oclass,
33 .head.new = nv50_head_new,
34 .dac = { .nr = 3, .new = nv50_dac_new },
35 .sor = { .nr = 4, .new = mcp77_sor_new },
36 .pior = { .nr = 3, .new = nv50_pior_new },
37};
38
39int
40mcp77_disp_new(struct nvkm_device *device, int index, struct nvkm_disp **pdisp)
41{
42 return nv50_disp_new_(&mcp77_disp, device, index, 2, pdisp);
43}
diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/mcp89.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/mcp89.c
new file mode 100644
index 000000000000..7b75c57c12ed
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/mcp89.c
@@ -0,0 +1,43 @@
1/*
2 * Copyright 2017 Red Hat Inc.
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#include "nv50.h"
23#include "head.h"
24#include "ior.h"
25#include "rootnv50.h"
26
27static const struct nv50_disp_func
28mcp89_disp = {
29 .intr = nv50_disp_intr,
30 .uevent = &nv50_disp_chan_uevent,
31 .super = nv50_disp_super,
32 .root = &gt215_disp_root_oclass,
33 .head.new = nv50_head_new,
34 .dac = { .nr = 3, .new = nv50_dac_new },
35 .sor = { .nr = 4, .new = mcp89_sor_new },
36 .pior = { .nr = 3, .new = nv50_pior_new },
37};
38
39int
40mcp89_disp_new(struct nvkm_device *device, int index, struct nvkm_disp **pdisp)
41{
42 return nv50_disp_new_(&mcp89_disp, device, index, 2, pdisp);
43}
diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/nv04.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/nv04.c
index 67254ce6f83f..b780ba1a3bc7 100644
--- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/nv04.c
+++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/nv04.c
@@ -22,6 +22,7 @@
22 * Authors: Ben Skeggs 22 * Authors: Ben Skeggs
23 */ 23 */
24#include "priv.h" 24#include "priv.h"
25#include "head.h"
25 26
26static const struct nvkm_disp_oclass * 27static const struct nvkm_disp_oclass *
27nv04_disp_root(struct nvkm_disp *disp) 28nv04_disp_root(struct nvkm_disp *disp)
@@ -30,20 +31,6 @@ nv04_disp_root(struct nvkm_disp *disp)
30} 31}
31 32
32static void 33static void
33nv04_disp_vblank_init(struct nvkm_disp *disp, int head)
34{
35 struct nvkm_device *device = disp->engine.subdev.device;
36 nvkm_wr32(device, 0x600140 + (head * 0x2000) , 0x00000001);
37}
38
39static void
40nv04_disp_vblank_fini(struct nvkm_disp *disp, int head)
41{
42 struct nvkm_device *device = disp->engine.subdev.device;
43 nvkm_wr32(device, 0x600140 + (head * 0x2000) , 0x00000000);
44}
45
46static void
47nv04_disp_intr(struct nvkm_disp *disp) 34nv04_disp_intr(struct nvkm_disp *disp)
48{ 35{
49 struct nvkm_subdev *subdev = &disp->engine.subdev; 36 struct nvkm_subdev *subdev = &disp->engine.subdev;
@@ -74,12 +61,22 @@ static const struct nvkm_disp_func
74nv04_disp = { 61nv04_disp = {
75 .intr = nv04_disp_intr, 62 .intr = nv04_disp_intr,
76 .root = nv04_disp_root, 63 .root = nv04_disp_root,
77 .head.vblank_init = nv04_disp_vblank_init,
78 .head.vblank_fini = nv04_disp_vblank_fini,
79}; 64};
80 65
81int 66int
82nv04_disp_new(struct nvkm_device *device, int index, struct nvkm_disp **pdisp) 67nv04_disp_new(struct nvkm_device *device, int index, struct nvkm_disp **pdisp)
83{ 68{
84 return nvkm_disp_new_(&nv04_disp, device, index, 2, pdisp); 69 int ret, i;
70
71 ret = nvkm_disp_new_(&nv04_disp, device, index, pdisp);
72 if (ret)
73 return ret;
74
75 for (i = 0; i < 2; i++) {
76 ret = nv04_head_new(*pdisp, i);
77 if (ret)
78 return ret;
79 }
80
81 return 0;
85} 82}
diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/nv50.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/nv50.c
index 0db8efbf1c2e..0c570dbd3021 100644
--- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/nv50.c
+++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/nv50.c
@@ -22,6 +22,8 @@
22 * Authors: Ben Skeggs 22 * Authors: Ben Skeggs
23 */ 23 */
24#include "nv50.h" 24#include "nv50.h"
25#include "head.h"
26#include "ior.h"
25#include "rootnv50.h" 27#include "rootnv50.h"
26 28
27#include <core/client.h> 29#include <core/client.h>
@@ -40,77 +42,6 @@ nv50_disp_root_(struct nvkm_disp *base)
40 return nv50_disp(base)->func->root; 42 return nv50_disp(base)->func->root;
41} 43}
42 44
43static int
44nv50_disp_outp_internal_crt_(struct nvkm_disp *base, int index,
45 struct dcb_output *dcb, struct nvkm_output **poutp)
46{
47 struct nv50_disp *disp = nv50_disp(base);
48 return disp->func->outp.internal.crt(base, index, dcb, poutp);
49}
50
51static int
52nv50_disp_outp_internal_tmds_(struct nvkm_disp *base, int index,
53 struct dcb_output *dcb,
54 struct nvkm_output **poutp)
55{
56 struct nv50_disp *disp = nv50_disp(base);
57 return disp->func->outp.internal.tmds(base, index, dcb, poutp);
58}
59
60static int
61nv50_disp_outp_internal_lvds_(struct nvkm_disp *base, int index,
62 struct dcb_output *dcb,
63 struct nvkm_output **poutp)
64{
65 struct nv50_disp *disp = nv50_disp(base);
66 return disp->func->outp.internal.lvds(base, index, dcb, poutp);
67}
68
69static int
70nv50_disp_outp_internal_dp_(struct nvkm_disp *base, int index,
71 struct dcb_output *dcb, struct nvkm_output **poutp)
72{
73 struct nv50_disp *disp = nv50_disp(base);
74 if (disp->func->outp.internal.dp)
75 return disp->func->outp.internal.dp(base, index, dcb, poutp);
76 return -ENODEV;
77}
78
79static int
80nv50_disp_outp_external_tmds_(struct nvkm_disp *base, int index,
81 struct dcb_output *dcb,
82 struct nvkm_output **poutp)
83{
84 struct nv50_disp *disp = nv50_disp(base);
85 if (disp->func->outp.external.tmds)
86 return disp->func->outp.external.tmds(base, index, dcb, poutp);
87 return -ENODEV;
88}
89
90static int
91nv50_disp_outp_external_dp_(struct nvkm_disp *base, int index,
92 struct dcb_output *dcb, struct nvkm_output **poutp)
93{
94 struct nv50_disp *disp = nv50_disp(base);
95 if (disp->func->outp.external.dp)
96 return disp->func->outp.external.dp(base, index, dcb, poutp);
97 return -ENODEV;
98}
99
100static void
101nv50_disp_vblank_fini_(struct nvkm_disp *base, int head)
102{
103 struct nv50_disp *disp = nv50_disp(base);
104 disp->func->head.vblank_fini(disp, head);
105}
106
107static void
108nv50_disp_vblank_init_(struct nvkm_disp *base, int head)
109{
110 struct nv50_disp *disp = nv50_disp(base);
111 disp->func->head.vblank_init(disp, head);
112}
113
114static void 45static void
115nv50_disp_intr_(struct nvkm_disp *base) 46nv50_disp_intr_(struct nvkm_disp *base)
116{ 47{
@@ -123,6 +54,8 @@ nv50_disp_dtor_(struct nvkm_disp *base)
123{ 54{
124 struct nv50_disp *disp = nv50_disp(base); 55 struct nv50_disp *disp = nv50_disp(base);
125 nvkm_event_fini(&disp->uevent); 56 nvkm_event_fini(&disp->uevent);
57 if (disp->wq)
58 destroy_workqueue(disp->wq);
126 return disp; 59 return disp;
127} 60}
128 61
@@ -131,14 +64,6 @@ nv50_disp_ = {
131 .dtor = nv50_disp_dtor_, 64 .dtor = nv50_disp_dtor_,
132 .intr = nv50_disp_intr_, 65 .intr = nv50_disp_intr_,
133 .root = nv50_disp_root_, 66 .root = nv50_disp_root_,
134 .outp.internal.crt = nv50_disp_outp_internal_crt_,
135 .outp.internal.tmds = nv50_disp_outp_internal_tmds_,
136 .outp.internal.lvds = nv50_disp_outp_internal_lvds_,
137 .outp.internal.dp = nv50_disp_outp_internal_dp_,
138 .outp.external.tmds = nv50_disp_outp_external_tmds_,
139 .outp.external.dp = nv50_disp_outp_external_dp_,
140 .head.vblank_init = nv50_disp_vblank_init_,
141 .head.vblank_fini = nv50_disp_vblank_fini_,
142}; 67};
143 68
144int 69int
@@ -146,517 +71,227 @@ nv50_disp_new_(const struct nv50_disp_func *func, struct nvkm_device *device,
146 int index, int heads, struct nvkm_disp **pdisp) 71 int index, int heads, struct nvkm_disp **pdisp)
147{ 72{
148 struct nv50_disp *disp; 73 struct nv50_disp *disp;
149 int ret; 74 int ret, i;
150 75
151 if (!(disp = kzalloc(sizeof(*disp), GFP_KERNEL))) 76 if (!(disp = kzalloc(sizeof(*disp), GFP_KERNEL)))
152 return -ENOMEM; 77 return -ENOMEM;
153 INIT_WORK(&disp->supervisor, func->super);
154 disp->func = func; 78 disp->func = func;
155 *pdisp = &disp->base; 79 *pdisp = &disp->base;
156 80
157 ret = nvkm_disp_ctor(&nv50_disp_, device, index, heads, &disp->base); 81 ret = nvkm_disp_ctor(&nv50_disp_, device, index, &disp->base);
158 if (ret) 82 if (ret)
159 return ret; 83 return ret;
160 84
161 return nvkm_event_init(func->uevent, 1, 1 + (heads * 4), &disp->uevent); 85 disp->wq = create_singlethread_workqueue("nvkm-disp");
162} 86 if (!disp->wq)
163 87 return -ENOMEM;
164void 88 INIT_WORK(&disp->supervisor, func->super);
165nv50_disp_vblank_fini(struct nv50_disp *disp, int head)
166{
167 struct nvkm_device *device = disp->base.engine.subdev.device;
168 nvkm_mask(device, 0x61002c, (4 << head), 0);
169}
170
171void
172nv50_disp_vblank_init(struct nv50_disp *disp, int head)
173{
174 struct nvkm_device *device = disp->base.engine.subdev.device;
175 nvkm_mask(device, 0x61002c, (4 << head), (4 << head));
176}
177
178static const struct nvkm_enum
179nv50_disp_intr_error_type[] = {
180 { 3, "ILLEGAL_MTHD" },
181 { 4, "INVALID_VALUE" },
182 { 5, "INVALID_STATE" },
183 { 7, "INVALID_HANDLE" },
184 {}
185};
186
187static const struct nvkm_enum
188nv50_disp_intr_error_code[] = {
189 { 0x00, "" },
190 {}
191};
192
193static void
194nv50_disp_intr_error(struct nv50_disp *disp, int chid)
195{
196 struct nvkm_subdev *subdev = &disp->base.engine.subdev;
197 struct nvkm_device *device = subdev->device;
198 u32 data = nvkm_rd32(device, 0x610084 + (chid * 0x08));
199 u32 addr = nvkm_rd32(device, 0x610080 + (chid * 0x08));
200 u32 code = (addr & 0x00ff0000) >> 16;
201 u32 type = (addr & 0x00007000) >> 12;
202 u32 mthd = (addr & 0x00000ffc);
203 const struct nvkm_enum *ec, *et;
204
205 et = nvkm_enum_find(nv50_disp_intr_error_type, type);
206 ec = nvkm_enum_find(nv50_disp_intr_error_code, code);
207
208 nvkm_error(subdev,
209 "ERROR %d [%s] %02x [%s] chid %d mthd %04x data %08x\n",
210 type, et ? et->name : "", code, ec ? ec->name : "",
211 chid, mthd, data);
212
213 if (chid < ARRAY_SIZE(disp->chan)) {
214 switch (mthd) {
215 case 0x0080:
216 nv50_disp_chan_mthd(disp->chan[chid], NV_DBG_ERROR);
217 break;
218 default:
219 break;
220 }
221 }
222
223 nvkm_wr32(device, 0x610020, 0x00010000 << chid);
224 nvkm_wr32(device, 0x610080 + (chid * 0x08), 0x90000000);
225}
226
227static struct nvkm_output *
228exec_lookup(struct nv50_disp *disp, int head, int or, u32 ctrl,
229 u32 *data, u8 *ver, u8 *hdr, u8 *cnt, u8 *len,
230 struct nvbios_outp *info)
231{
232 struct nvkm_subdev *subdev = &disp->base.engine.subdev;
233 struct nvkm_bios *bios = subdev->device->bios;
234 struct nvkm_output *outp;
235 u16 mask, type;
236
237 if (or < 4) {
238 type = DCB_OUTPUT_ANALOG;
239 mask = 0;
240 } else
241 if (or < 8) {
242 switch (ctrl & 0x00000f00) {
243 case 0x00000000: type = DCB_OUTPUT_LVDS; mask = 1; break;
244 case 0x00000100: type = DCB_OUTPUT_TMDS; mask = 1; break;
245 case 0x00000200: type = DCB_OUTPUT_TMDS; mask = 2; break;
246 case 0x00000500: type = DCB_OUTPUT_TMDS; mask = 3; break;
247 case 0x00000800: type = DCB_OUTPUT_DP; mask = 1; break;
248 case 0x00000900: type = DCB_OUTPUT_DP; mask = 2; break;
249 default:
250 nvkm_error(subdev, "unknown SOR mc %08x\n", ctrl);
251 return NULL;
252 }
253 or -= 4;
254 } else {
255 or = or - 8;
256 type = 0x0010;
257 mask = 0;
258 switch (ctrl & 0x00000f00) {
259 case 0x00000000: type |= disp->pior.type[or]; break;
260 default:
261 nvkm_error(subdev, "unknown PIOR mc %08x\n", ctrl);
262 return NULL;
263 }
264 }
265 89
266 mask = 0x00c0 & (mask << 6); 90 for (i = 0; func->head.new && i < heads; i++) {
267 mask |= 0x0001 << or; 91 ret = func->head.new(&disp->base, i);
268 mask |= 0x0100 << head; 92 if (ret)
269 93 return ret;
270 list_for_each_entry(outp, &disp->base.outp, head) {
271 if ((outp->info.hasht & 0xff) == type &&
272 (outp->info.hashm & mask) == mask) {
273 *data = nvbios_outp_match(bios, outp->info.hasht, mask,
274 ver, hdr, cnt, len, info);
275 if (!*data)
276 return NULL;
277 return outp;
278 }
279 } 94 }
280 95
281 return NULL; 96 for (i = 0; func->dac.new && i < func->dac.nr; i++) {
282} 97 ret = func->dac.new(&disp->base, i);
283 98 if (ret)
284static struct nvkm_output * 99 return ret;
285exec_script(struct nv50_disp *disp, int head, int id)
286{
287 struct nvkm_subdev *subdev = &disp->base.engine.subdev;
288 struct nvkm_device *device = subdev->device;
289 struct nvkm_bios *bios = device->bios;
290 struct nvkm_output *outp;
291 struct nvbios_outp info;
292 u8 ver, hdr, cnt, len;
293 u32 data, ctrl = 0;
294 u32 reg;
295 int i;
296
297 /* DAC */
298 for (i = 0; !(ctrl & (1 << head)) && i < disp->func->dac.nr; i++)
299 ctrl = nvkm_rd32(device, 0x610b5c + (i * 8));
300
301 /* SOR */
302 if (!(ctrl & (1 << head))) {
303 if (device->chipset < 0x90 ||
304 device->chipset == 0x92 ||
305 device->chipset == 0xa0) {
306 reg = 0x610b74;
307 } else {
308 reg = 0x610798;
309 }
310 for (i = 0; !(ctrl & (1 << head)) && i < disp->func->sor.nr; i++)
311 ctrl = nvkm_rd32(device, reg + (i * 8));
312 i += 4;
313 } 100 }
314 101
315 /* PIOR */ 102 for (i = 0; func->pior.new && i < func->pior.nr; i++) {
316 if (!(ctrl & (1 << head))) { 103 ret = func->pior.new(&disp->base, i);
317 for (i = 0; !(ctrl & (1 << head)) && i < disp->func->pior.nr; i++) 104 if (ret)
318 ctrl = nvkm_rd32(device, 0x610b84 + (i * 8)); 105 return ret;
319 i += 8;
320 } 106 }
321 107
322 if (!(ctrl & (1 << head))) 108 for (i = 0; func->sor.new && i < func->sor.nr; i++) {
323 return NULL; 109 ret = func->sor.new(&disp->base, i);
324 i--; 110 if (ret)
325 111 return ret;
326 outp = exec_lookup(disp, head, i, ctrl, &data, &ver, &hdr, &cnt, &len, &info);
327 if (outp) {
328 struct nvbios_init init = {
329 .subdev = subdev,
330 .bios = bios,
331 .offset = info.script[id],
332 .outp = &outp->info,
333 .crtc = head,
334 .execute = 1,
335 };
336
337 nvbios_exec(&init);
338 } 112 }
339 113
340 return outp; 114 return nvkm_event_init(func->uevent, 1, 1 + (heads * 4), &disp->uevent);
341} 115}
342 116
343static struct nvkm_output * 117static u32
344exec_clkcmp(struct nv50_disp *disp, int head, int id, u32 pclk, u32 *conf) 118nv50_disp_super_iedt(struct nvkm_head *head, struct nvkm_outp *outp,
119 u8 *ver, u8 *hdr, u8 *cnt, u8 *len,
120 struct nvbios_outp *iedt)
345{ 121{
346 struct nvkm_subdev *subdev = &disp->base.engine.subdev; 122 struct nvkm_bios *bios = head->disp->engine.subdev.device->bios;
347 struct nvkm_device *device = subdev->device; 123 const u8 l = ffs(outp->info.link);
348 struct nvkm_bios *bios = device->bios; 124 const u16 t = outp->info.hasht;
349 struct nvkm_output *outp; 125 const u16 m = (0x0100 << head->id) | (l << 6) | outp->info.or;
350 struct nvbios_outp info1; 126 u32 data = nvbios_outp_match(bios, t, m, ver, hdr, cnt, len, iedt);
351 struct nvbios_ocfg info2; 127 if (!data)
352 u8 ver, hdr, cnt, len; 128 OUTP_DBG(outp, "missing IEDT for %04x:%04x", t, m);
353 u32 data, ctrl = 0; 129 return data;
354 u32 reg;
355 int i;
356
357 /* DAC */
358 for (i = 0; !(ctrl & (1 << head)) && i < disp->func->dac.nr; i++)
359 ctrl = nvkm_rd32(device, 0x610b58 + (i * 8));
360
361 /* SOR */
362 if (!(ctrl & (1 << head))) {
363 if (device->chipset < 0x90 ||
364 device->chipset == 0x92 ||
365 device->chipset == 0xa0) {
366 reg = 0x610b70;
367 } else {
368 reg = 0x610794;
369 }
370 for (i = 0; !(ctrl & (1 << head)) && i < disp->func->sor.nr; i++)
371 ctrl = nvkm_rd32(device, reg + (i * 8));
372 i += 4;
373 }
374
375 /* PIOR */
376 if (!(ctrl & (1 << head))) {
377 for (i = 0; !(ctrl & (1 << head)) && i < disp->func->pior.nr; i++)
378 ctrl = nvkm_rd32(device, 0x610b80 + (i * 8));
379 i += 8;
380 }
381
382 if (!(ctrl & (1 << head)))
383 return NULL;
384 i--;
385
386 outp = exec_lookup(disp, head, i, ctrl, &data, &ver, &hdr, &cnt, &len, &info1);
387 if (!outp)
388 return NULL;
389
390 *conf = (ctrl & 0x00000f00) >> 8;
391 if (outp->info.location == 0) {
392 switch (outp->info.type) {
393 case DCB_OUTPUT_TMDS:
394 if (*conf == 5)
395 *conf |= 0x0100;
396 break;
397 case DCB_OUTPUT_LVDS:
398 *conf |= disp->sor.lvdsconf;
399 break;
400 default:
401 break;
402 }
403 } else {
404 *conf = (ctrl & 0x00000f00) >> 8;
405 pclk = pclk / 2;
406 }
407
408 data = nvbios_ocfg_match(bios, data, *conf & 0xff, *conf >> 8,
409 &ver, &hdr, &cnt, &len, &info2);
410 if (data && id < 0xff) {
411 data = nvbios_oclk_match(bios, info2.clkcmp[id], pclk);
412 if (data) {
413 struct nvbios_init init = {
414 .subdev = subdev,
415 .bios = bios,
416 .offset = data,
417 .outp = &outp->info,
418 .crtc = head,
419 .execute = 1,
420 };
421
422 nvbios_exec(&init);
423 }
424 }
425
426 return outp;
427} 130}
428 131
429static bool 132static void
430nv50_disp_dptmds_war(struct nvkm_device *device) 133nv50_disp_super_ied_on(struct nvkm_head *head,
134 struct nvkm_ior *ior, int id, u32 khz)
431{ 135{
432 switch (device->chipset) { 136 struct nvkm_subdev *subdev = &head->disp->engine.subdev;
433 case 0x94: 137 struct nvkm_bios *bios = subdev->device->bios;
434 case 0x96: 138 struct nvkm_outp *outp = ior->asy.outp;
435 case 0x98: 139 struct nvbios_ocfg iedtrs;
436 return true; 140 struct nvbios_outp iedt;
437 default: 141 u8 ver, hdr, cnt, len, flags = 0x00;
438 break; 142 u32 data;
143
144 if (!outp) {
145 IOR_DBG(ior, "nothing to attach");
146 return;
439 } 147 }
440 return false;
441}
442 148
443static bool 149 /* Lookup IED table for the device. */
444nv50_disp_dptmds_war_needed(struct nv50_disp *disp, struct dcb_output *outp) 150 data = nv50_disp_super_iedt(head, outp, &ver, &hdr, &cnt, &len, &iedt);
445{ 151 if (!data)
446 struct nvkm_device *device = disp->base.engine.subdev.device; 152 return;
447 const u32 soff = __ffs(outp->or) * 0x800; 153
448 if (nv50_disp_dptmds_war(device) && outp->type == DCB_OUTPUT_TMDS) { 154 /* Lookup IEDT runtime settings for the current configuration. */
449 switch (nvkm_rd32(device, 0x614300 + soff) & 0x00030000) { 155 if (ior->type == SOR) {
450 case 0x00000000: 156 if (ior->asy.proto == LVDS) {
451 case 0x00030000: 157 if (head->asy.or.depth == 24)
452 return true; 158 flags |= 0x02;
453 default:
454 break;
455 } 159 }
160 if (ior->asy.link == 3)
161 flags |= 0x01;
456 } 162 }
457 return false;
458
459}
460
461static void
462nv50_disp_dptmds_war_2(struct nv50_disp *disp, struct dcb_output *outp)
463{
464 struct nvkm_device *device = disp->base.engine.subdev.device;
465 const u32 soff = __ffs(outp->or) * 0x800;
466 163
467 if (!nv50_disp_dptmds_war_needed(disp, outp)) 164 data = nvbios_ocfg_match(bios, data, ior->asy.proto_evo, flags,
165 &ver, &hdr, &cnt, &len, &iedtrs);
166 if (!data) {
167 OUTP_DBG(outp, "missing IEDT RS for %02x:%02x",
168 ior->asy.proto_evo, flags);
468 return; 169 return;
469
470 nvkm_mask(device, 0x00e840, 0x80000000, 0x80000000);
471 nvkm_mask(device, 0x614300 + soff, 0x03000000, 0x03000000);
472 nvkm_mask(device, 0x61c10c + soff, 0x00000001, 0x00000001);
473
474 nvkm_mask(device, 0x61c00c + soff, 0x0f000000, 0x00000000);
475 nvkm_mask(device, 0x61c008 + soff, 0xff000000, 0x14000000);
476 nvkm_usec(device, 400, NVKM_DELAY);
477 nvkm_mask(device, 0x61c008 + soff, 0xff000000, 0x00000000);
478 nvkm_mask(device, 0x61c00c + soff, 0x0f000000, 0x01000000);
479
480 if (nvkm_rd32(device, 0x61c004 + soff) & 0x00000001) {
481 u32 seqctl = nvkm_rd32(device, 0x61c030 + soff);
482 u32 pu_pc = seqctl & 0x0000000f;
483 nvkm_wr32(device, 0x61c040 + soff + pu_pc * 4, 0x1f008000);
484 } 170 }
485}
486 171
487static void 172 /* Execute the OnInt[23] script for the current frequency. */
488nv50_disp_dptmds_war_3(struct nv50_disp *disp, struct dcb_output *outp) 173 data = nvbios_oclk_match(bios, iedtrs.clkcmp[id], khz);
489{ 174 if (!data) {
490 struct nvkm_device *device = disp->base.engine.subdev.device; 175 OUTP_DBG(outp, "missing IEDT RSS %d for %02x:%02x %d khz",
491 const u32 soff = __ffs(outp->or) * 0x800; 176 id, ior->asy.proto_evo, flags, khz);
492 u32 sorpwr;
493
494 if (!nv50_disp_dptmds_war_needed(disp, outp))
495 return; 177 return;
496
497 sorpwr = nvkm_rd32(device, 0x61c004 + soff);
498 if (sorpwr & 0x00000001) {
499 u32 seqctl = nvkm_rd32(device, 0x61c030 + soff);
500 u32 pd_pc = (seqctl & 0x00000f00) >> 8;
501 u32 pu_pc = seqctl & 0x0000000f;
502
503 nvkm_wr32(device, 0x61c040 + soff + pd_pc * 4, 0x1f008000);
504
505 nvkm_msec(device, 2000,
506 if (!(nvkm_rd32(device, 0x61c030 + soff) & 0x10000000))
507 break;
508 );
509 nvkm_mask(device, 0x61c004 + soff, 0x80000001, 0x80000000);
510 nvkm_msec(device, 2000,
511 if (!(nvkm_rd32(device, 0x61c030 + soff) & 0x10000000))
512 break;
513 );
514
515 nvkm_wr32(device, 0x61c040 + soff + pd_pc * 4, 0x00002000);
516 nvkm_wr32(device, 0x61c040 + soff + pu_pc * 4, 0x1f000000);
517 } 178 }
518 179
519 nvkm_mask(device, 0x61c10c + soff, 0x00000001, 0x00000000); 180 nvbios_init(subdev, data,
520 nvkm_mask(device, 0x614300 + soff, 0x03000000, 0x00000000); 181 init.outp = &outp->info;
521 182 init.or = ior->id;
522 if (sorpwr & 0x00000001) { 183 init.link = ior->asy.link;
523 nvkm_mask(device, 0x61c004 + soff, 0x80000001, 0x80000001); 184 init.head = head->id;
524 } 185 );
525} 186}
526 187
527static void 188static void
528nv50_disp_update_sppll1(struct nv50_disp *disp) 189nv50_disp_super_ied_off(struct nvkm_head *head, struct nvkm_ior *ior, int id)
529{ 190{
530 struct nvkm_device *device = disp->base.engine.subdev.device; 191 struct nvkm_outp *outp = ior->arm.outp;
531 bool used = false; 192 struct nvbios_outp iedt;
532 int sor; 193 u8 ver, hdr, cnt, len;
194 u32 data;
533 195
534 if (!nv50_disp_dptmds_war(device)) 196 if (!outp) {
197 IOR_DBG(ior, "nothing attached");
535 return; 198 return;
536
537 for (sor = 0; sor < disp->func->sor.nr; sor++) {
538 u32 clksor = nvkm_rd32(device, 0x614300 + (sor * 0x800));
539 switch (clksor & 0x03000000) {
540 case 0x02000000:
541 case 0x03000000:
542 used = true;
543 break;
544 default:
545 break;
546 }
547 } 199 }
548 200
549 if (used) 201 data = nv50_disp_super_iedt(head, outp, &ver, &hdr, &cnt, &len, &iedt);
202 if (!data)
550 return; 203 return;
551 204
552 nvkm_mask(device, 0x00e840, 0x80000000, 0x00000000); 205 nvbios_init(&head->disp->engine.subdev, iedt.script[id],
206 init.outp = &outp->info;
207 init.or = ior->id;
208 init.link = ior->arm.link;
209 init.head = head->id;
210 );
553} 211}
554 212
555static void 213static struct nvkm_ior *
556nv50_disp_intr_unk10_0(struct nv50_disp *disp, int head) 214nv50_disp_super_ior_asy(struct nvkm_head *head)
557{ 215{
558 exec_script(disp, head, 1); 216 struct nvkm_ior *ior;
217 list_for_each_entry(ior, &head->disp->ior, head) {
218 if (ior->asy.head & (1 << head->id)) {
219 HEAD_DBG(head, "to %s", ior->name);
220 return ior;
221 }
222 }
223 HEAD_DBG(head, "nothing to attach");
224 return NULL;
559} 225}
560 226
561static void 227static struct nvkm_ior *
562nv50_disp_intr_unk20_0(struct nv50_disp *disp, int head) 228nv50_disp_super_ior_arm(struct nvkm_head *head)
563{ 229{
564 struct nvkm_subdev *subdev = &disp->base.engine.subdev; 230 struct nvkm_ior *ior;
565 struct nvkm_output *outp = exec_script(disp, head, 2); 231 list_for_each_entry(ior, &head->disp->ior, head) {
566 232 if (ior->arm.head & (1 << head->id)) {
567 /* the binary driver does this outside of the supervisor handling 233 HEAD_DBG(head, "on %s", ior->name);
568 * (after the third supervisor from a detach). we (currently?) 234 return ior;
569 * allow both detach/attach to happen in the same set of 235 }
570 * supervisor interrupts, so it would make sense to execute this
571 * (full power down?) script after all the detach phases of the
572 * supervisor handling. like with training if needed from the
573 * second supervisor, nvidia doesn't do this, so who knows if it's
574 * entirely safe, but it does appear to work..
575 *
576 * without this script being run, on some configurations i've
577 * seen, switching from DP to TMDS on a DP connector may result
578 * in a blank screen (SOR_PWR off/on can restore it)
579 */
580 if (outp && outp->info.type == DCB_OUTPUT_DP) {
581 struct nvkm_output_dp *outpdp = nvkm_output_dp(outp);
582 struct nvbios_init init = {
583 .subdev = subdev,
584 .bios = subdev->device->bios,
585 .outp = &outp->info,
586 .crtc = head,
587 .offset = outpdp->info.script[4],
588 .execute = 1,
589 };
590
591 nvkm_notify_put(&outpdp->irq);
592 nvbios_exec(&init);
593 atomic_set(&outpdp->lt.done, 0);
594 } 236 }
237 HEAD_DBG(head, "nothing attached");
238 return NULL;
595} 239}
596 240
597static void 241void
598nv50_disp_intr_unk20_1(struct nv50_disp *disp, int head) 242nv50_disp_super_3_0(struct nv50_disp *disp, struct nvkm_head *head)
599{ 243{
600 struct nvkm_device *device = disp->base.engine.subdev.device; 244 struct nvkm_ior *ior;
601 struct nvkm_devinit *devinit = device->devinit; 245
602 u32 pclk = nvkm_rd32(device, 0x610ad0 + (head * 0x540)) & 0x3fffff; 246 /* Determine which OR, if any, we're attaching to the head. */
603 if (pclk) 247 HEAD_DBG(head, "supervisor 3.0");
604 nvkm_devinit_pll_set(devinit, PLL_VPLL0 + head, pclk); 248 ior = nv50_disp_super_ior_asy(head);
249 if (!ior)
250 return;
251
252 /* Execute OnInt3 IED script. */
253 nv50_disp_super_ied_on(head, ior, 1, head->asy.hz / 1000);
254
255 /* OR-specific handling. */
256 if (ior->func->war_3)
257 ior->func->war_3(ior);
605} 258}
606 259
607static void 260static void
608nv50_disp_intr_unk20_2_dp(struct nv50_disp *disp, int head, 261nv50_disp_super_2_2_dp(struct nvkm_head *head, struct nvkm_ior *ior)
609 struct dcb_output *outp, u32 pclk)
610{ 262{
611 struct nvkm_subdev *subdev = &disp->base.engine.subdev; 263 struct nvkm_subdev *subdev = &head->disp->engine.subdev;
612 struct nvkm_device *device = subdev->device; 264 const u32 khz = head->asy.hz / 1000;
613 const int link = !(outp->sorconf.link & 1); 265 const u32 linkKBps = ior->dp.bw * 27000;
614 const int or = ffs(outp->or) - 1; 266 const u32 symbol = 100000;
615 const u32 soff = ( or * 0x800);
616 const u32 loff = (link * 0x080) + soff;
617 const u32 ctrl = nvkm_rd32(device, 0x610794 + (or * 8));
618 const u32 symbol = 100000;
619 const s32 vactive = nvkm_rd32(device, 0x610af8 + (head * 0x540)) & 0xffff;
620 const s32 vblanke = nvkm_rd32(device, 0x610ae8 + (head * 0x540)) & 0xffff;
621 const s32 vblanks = nvkm_rd32(device, 0x610af0 + (head * 0x540)) & 0xffff;
622 u32 dpctrl = nvkm_rd32(device, 0x61c10c + loff);
623 u32 clksor = nvkm_rd32(device, 0x614300 + soff);
624 int bestTU = 0, bestVTUi = 0, bestVTUf = 0, bestVTUa = 0; 267 int bestTU = 0, bestVTUi = 0, bestVTUf = 0, bestVTUa = 0;
625 int TU, VTUi, VTUf, VTUa; 268 int TU, VTUi, VTUf, VTUa;
626 u64 link_data_rate, link_ratio, unk; 269 u64 link_data_rate, link_ratio, unk;
627 u32 best_diff = 64 * symbol; 270 u32 best_diff = 64 * symbol;
628 u32 link_nr, link_bw, bits; 271 u64 h, v;
629 u64 value;
630
631 link_bw = (clksor & 0x000c0000) ? 270000 : 162000;
632 link_nr = hweight32(dpctrl & 0x000f0000);
633 272
634 /* symbols/hblank - algorithm taken from comments in tegra driver */ 273 /* symbols/hblank - algorithm taken from comments in tegra driver */
635 value = vblanke + vactive - vblanks - 7; 274 h = head->asy.hblanke + head->asy.htotal - head->asy.hblanks - 7;
636 value = value * link_bw; 275 h = h * linkKBps;
637 do_div(value, pclk); 276 do_div(h, khz);
638 value = value - (3 * !!(dpctrl & 0x00004000)) - (12 / link_nr); 277 h = h - (3 * ior->dp.ef) - (12 / ior->dp.nr);
639 nvkm_mask(device, 0x61c1e8 + soff, 0x0000ffff, value);
640 278
641 /* symbols/vblank - algorithm taken from comments in tegra driver */ 279 /* symbols/vblank - algorithm taken from comments in tegra driver */
642 value = vblanks - vblanke - 25; 280 v = head->asy.vblanks - head->asy.vblanke - 25;
643 value = value * link_bw; 281 v = v * linkKBps;
644 do_div(value, pclk); 282 do_div(v, khz);
645 value = value - ((36 / link_nr) + 3) - 1; 283 v = v - ((36 / ior->dp.nr) + 3) - 1;
646 nvkm_mask(device, 0x61c1ec + soff, 0x00ffffff, value);
647 284
648 /* watermark / activesym */ 285 ior->func->dp.audio_sym(ior, head->id, h, v);
649 if ((ctrl & 0xf0000) == 0x60000) bits = 30;
650 else if ((ctrl & 0xf0000) == 0x50000) bits = 24;
651 else bits = 18;
652 286
653 link_data_rate = (pclk * bits / 8) / link_nr; 287 /* watermark / activesym */
288 link_data_rate = (khz * head->asy.or.depth / 8) / ior->dp.nr;
654 289
655 /* calculate ratio of packed data rate to link symbol rate */ 290 /* calculate ratio of packed data rate to link symbol rate */
656 link_ratio = link_data_rate * symbol; 291 link_ratio = link_data_rate * symbol;
657 do_div(link_ratio, link_bw); 292 do_div(link_ratio, linkKBps);
658 293
659 for (TU = 64; TU >= 32; TU--) { 294 for (TU = 64; ior->func->dp.activesym && TU >= 32; TU--) {
660 /* calculate average number of valid symbols in each TU */ 295 /* calculate average number of valid symbols in each TU */
661 u32 tu_valid = link_ratio * TU; 296 u32 tu_valid = link_ratio * TU;
662 u32 calc, diff; 297 u32 calc, diff;
@@ -707,9 +342,15 @@ nv50_disp_intr_unk20_2_dp(struct nv50_disp *disp, int head,
707 } 342 }
708 } 343 }
709 344
710 if (!bestTU) { 345 if (ior->func->dp.activesym) {
711 nvkm_error(subdev, "unable to find suitable dp config\n"); 346 if (!bestTU) {
712 return; 347 nvkm_error(subdev, "unable to determine dp config\n");
348 return;
349 }
350 ior->func->dp.activesym(ior, head->id, bestTU,
351 bestVTUa, bestVTUf, bestVTUi);
352 } else {
353 bestTU = 64;
713 } 354 }
714 355
715 /* XXX close to vbios numbers, but not right */ 356 /* XXX close to vbios numbers, but not right */
@@ -719,190 +360,223 @@ nv50_disp_intr_unk20_2_dp(struct nv50_disp *disp, int head,
719 do_div(unk, symbol); 360 do_div(unk, symbol);
720 unk += 6; 361 unk += 6;
721 362
722 nvkm_mask(device, 0x61c10c + loff, 0x000001fc, bestTU << 2); 363 ior->func->dp.watermark(ior, head->id, unk);
723 nvkm_mask(device, 0x61c128 + loff, 0x010f7f3f, bestVTUa << 24 |
724 bestVTUf << 16 |
725 bestVTUi << 8 | unk);
726} 364}
727 365
728static void 366void
729nv50_disp_intr_unk20_2(struct nv50_disp *disp, int head) 367nv50_disp_super_2_2(struct nv50_disp *disp, struct nvkm_head *head)
730{ 368{
731 struct nvkm_device *device = disp->base.engine.subdev.device; 369 const u32 khz = head->asy.hz / 1000;
732 struct nvkm_output *outp; 370 struct nvkm_outp *outp;
733 u32 pclk = nvkm_rd32(device, 0x610ad0 + (head * 0x540)) & 0x3fffff; 371 struct nvkm_ior *ior;
734 u32 hval, hreg = 0x614200 + (head * 0x800); 372
735 u32 oval, oreg; 373 /* Determine which OR, if any, we're attaching from the head. */
736 u32 mask, conf; 374 HEAD_DBG(head, "supervisor 2.2");
737 375 ior = nv50_disp_super_ior_asy(head);
738 outp = exec_clkcmp(disp, head, 0xff, pclk, &conf); 376 if (!ior)
739 if (!outp)
740 return; 377 return;
741 378
742 /* we allow both encoder attach and detach operations to occur 379 /* For some reason, NVIDIA decided not to:
743 * within a single supervisor (ie. modeset) sequence. the
744 * encoder detach scripts quite often switch off power to the
745 * lanes, which requires the link to be re-trained.
746 *
747 * this is not generally an issue as the sink "must" (heh)
748 * signal an irq when it's lost sync so the driver can
749 * re-train.
750 * 380 *
751 * however, on some boards, if one does not configure at least 381 * A) Give dual-link LVDS a separate EVO protocol, like for TMDS.
752 * the gpu side of the link *before* attaching, then various 382 * and
753 * things can go horribly wrong (PDISP disappearing from mmio, 383 * B) Use SetControlOutputResource.PixelDepth on LVDS.
754 * third supervisor never happens, etc).
755 * 384 *
756 * the solution is simply to retrain here, if necessary. last 385 * Override the values we usually read from HW with the same
757 * i checked, the binary driver userspace does not appear to 386 * data we pass though an ioctl instead.
758 * trigger this situation (it forces an UPDATE between steps).
759 */ 387 */
760 if (outp->info.type == DCB_OUTPUT_DP) { 388 if (ior->type == SOR && ior->asy.proto == LVDS) {
761 u32 soff = (ffs(outp->info.or) - 1) * 0x08; 389 head->asy.or.depth = (disp->sor.lvdsconf & 0x0200) ? 24 : 18;
762 u32 ctrl, datarate; 390 ior->asy.link = (disp->sor.lvdsconf & 0x0100) ? 3 : 1;
763 391 }
764 if (outp->info.location == 0) {
765 ctrl = nvkm_rd32(device, 0x610794 + soff);
766 soff = 1;
767 } else {
768 ctrl = nvkm_rd32(device, 0x610b80 + soff);
769 soff = 2;
770 }
771 392
772 switch ((ctrl & 0x000f0000) >> 16) { 393 /* Handle any link training, etc. */
773 case 6: datarate = pclk * 30; break; 394 if ((outp = ior->asy.outp) && outp->func->acquire)
774 case 5: datarate = pclk * 24; break; 395 outp->func->acquire(outp);
775 case 2:
776 default:
777 datarate = pclk * 18;
778 break;
779 }
780 396
781 if (nvkm_output_dp_train(outp, datarate / soff)) 397 /* Execute OnInt2 IED script. */
782 OUTP_ERR(outp, "link not trained before attach"); 398 nv50_disp_super_ied_on(head, ior, 0, khz);
783 }
784 399
785 exec_clkcmp(disp, head, 0, pclk, &conf); 400 /* Program RG clock divider. */
401 head->func->rgclk(head, ior->asy.rgdiv);
786 402
787 if (!outp->info.location && outp->info.type == DCB_OUTPUT_ANALOG) { 403 /* Mode-specific internal DP configuration. */
788 oreg = 0x614280 + (ffs(outp->info.or) - 1) * 0x800; 404 if (ior->type == SOR && ior->asy.proto == DP)
789 oval = 0x00000000; 405 nv50_disp_super_2_2_dp(head, ior);
790 hval = 0x00000000;
791 mask = 0xffffffff;
792 } else
793 if (!outp->info.location) {
794 if (outp->info.type == DCB_OUTPUT_DP)
795 nv50_disp_intr_unk20_2_dp(disp, head, &outp->info, pclk);
796 oreg = 0x614300 + (ffs(outp->info.or) - 1) * 0x800;
797 oval = (conf & 0x0100) ? 0x00000101 : 0x00000000;
798 hval = 0x00000000;
799 mask = 0x00000707;
800 } else {
801 oreg = 0x614380 + (ffs(outp->info.or) - 1) * 0x800;
802 oval = 0x00000001;
803 hval = 0x00000001;
804 mask = 0x00000707;
805 }
806 406
807 nvkm_mask(device, hreg, 0x0000000f, hval); 407 /* OR-specific handling. */
808 nvkm_mask(device, oreg, mask, oval); 408 ior->func->clock(ior);
409 if (ior->func->war_2)
410 ior->func->war_2(ior);
411}
809 412
810 nv50_disp_dptmds_war_2(disp, &outp->info); 413void
414nv50_disp_super_2_1(struct nv50_disp *disp, struct nvkm_head *head)
415{
416 struct nvkm_devinit *devinit = disp->base.engine.subdev.device->devinit;
417 const u32 khz = head->asy.hz / 1000;
418 HEAD_DBG(head, "supervisor 2.1 - %d khz", khz);
419 if (khz)
420 nvkm_devinit_pll_set(devinit, PLL_VPLL0 + head->id, khz);
811} 421}
812 422
813/* If programming a TMDS output on a SOR that can also be configured for 423void
814 * DisplayPort, make sure NV50_SOR_DP_CTRL_ENABLE is forced off. 424nv50_disp_super_2_0(struct nv50_disp *disp, struct nvkm_head *head)
815 *
816 * It looks like the VBIOS TMDS scripts make an attempt at this, however,
817 * the VBIOS scripts on at least one board I have only switch it off on
818 * link 0, causing a blank display if the output has previously been
819 * programmed for DisplayPort.
820 */
821static void
822nv50_disp_intr_unk40_0_tmds(struct nv50_disp *disp,
823 struct dcb_output *outp)
824{ 425{
825 struct nvkm_device *device = disp->base.engine.subdev.device; 426 struct nvkm_outp *outp;
826 struct nvkm_bios *bios = device->bios; 427 struct nvkm_ior *ior;
827 const int link = !(outp->sorconf.link & 1); 428
828 const int or = ffs(outp->or) - 1; 429 /* Determine which OR, if any, we're detaching from the head. */
829 const u32 loff = (or * 0x800) + (link * 0x80); 430 HEAD_DBG(head, "supervisor 2.0");
830 const u16 mask = (outp->sorconf.link << 6) | outp->or; 431 ior = nv50_disp_super_ior_arm(head);
831 struct dcb_output match; 432 if (!ior)
832 u8 ver, hdr; 433 return;
833 434
834 if (dcb_outp_match(bios, DCB_OUTPUT_DP, mask, &ver, &hdr, &match)) 435 /* Execute OffInt2 IED script. */
835 nvkm_mask(device, 0x61c10c + loff, 0x00000001, 0x00000000); 436 nv50_disp_super_ied_off(head, ior, 2);
437
438 /* If we're shutting down the OR's only active head, execute
439 * the output path's release function.
440 */
441 if (ior->arm.head == (1 << head->id)) {
442 if ((outp = ior->arm.outp) && outp->func->release)
443 outp->func->release(outp, ior);
444 }
836} 445}
837 446
838static void 447void
839nv50_disp_intr_unk40_0(struct nv50_disp *disp, int head) 448nv50_disp_super_1_0(struct nv50_disp *disp, struct nvkm_head *head)
840{ 449{
841 struct nvkm_device *device = disp->base.engine.subdev.device; 450 struct nvkm_ior *ior;
842 struct nvkm_output *outp;
843 u32 pclk = nvkm_rd32(device, 0x610ad0 + (head * 0x540)) & 0x3fffff;
844 u32 conf;
845 451
846 outp = exec_clkcmp(disp, head, 1, pclk, &conf); 452 /* Determine which OR, if any, we're detaching from the head. */
847 if (!outp) 453 HEAD_DBG(head, "supervisor 1.0");
454 ior = nv50_disp_super_ior_arm(head);
455 if (!ior)
848 return; 456 return;
849 457
850 if (outp->info.location == 0 && outp->info.type == DCB_OUTPUT_TMDS) 458 /* Execute OffInt1 IED script. */
851 nv50_disp_intr_unk40_0_tmds(disp, &outp->info); 459 nv50_disp_super_ied_off(head, ior, 1);
852 nv50_disp_dptmds_war_3(disp, &outp->info);
853} 460}
854 461
855void 462void
856nv50_disp_intr_supervisor(struct work_struct *work) 463nv50_disp_super_1(struct nv50_disp *disp)
464{
465 struct nvkm_head *head;
466 struct nvkm_ior *ior;
467
468 list_for_each_entry(head, &disp->base.head, head) {
469 head->func->state(head, &head->arm);
470 head->func->state(head, &head->asy);
471 }
472
473 list_for_each_entry(ior, &disp->base.ior, head) {
474 ior->func->state(ior, &ior->arm);
475 ior->func->state(ior, &ior->asy);
476 }
477}
478
479void
480nv50_disp_super(struct work_struct *work)
857{ 481{
858 struct nv50_disp *disp = 482 struct nv50_disp *disp =
859 container_of(work, struct nv50_disp, supervisor); 483 container_of(work, struct nv50_disp, supervisor);
860 struct nvkm_subdev *subdev = &disp->base.engine.subdev; 484 struct nvkm_subdev *subdev = &disp->base.engine.subdev;
861 struct nvkm_device *device = subdev->device; 485 struct nvkm_device *device = subdev->device;
486 struct nvkm_head *head;
862 u32 super = nvkm_rd32(device, 0x610030); 487 u32 super = nvkm_rd32(device, 0x610030);
863 int head;
864 488
865 nvkm_debug(subdev, "supervisor %08x %08x\n", disp->super, super); 489 nvkm_debug(subdev, "supervisor %08x %08x\n", disp->super, super);
866 490
867 if (disp->super & 0x00000010) { 491 if (disp->super & 0x00000010) {
868 nv50_disp_chan_mthd(disp->chan[0], NV_DBG_DEBUG); 492 nv50_disp_chan_mthd(disp->chan[0], NV_DBG_DEBUG);
869 for (head = 0; head < disp->base.head.nr; head++) { 493 nv50_disp_super_1(disp);
870 if (!(super & (0x00000020 << head))) 494 list_for_each_entry(head, &disp->base.head, head) {
495 if (!(super & (0x00000020 << head->id)))
871 continue; 496 continue;
872 if (!(super & (0x00000080 << head))) 497 if (!(super & (0x00000080 << head->id)))
873 continue; 498 continue;
874 nv50_disp_intr_unk10_0(disp, head); 499 nv50_disp_super_1_0(disp, head);
875 } 500 }
876 } else 501 } else
877 if (disp->super & 0x00000020) { 502 if (disp->super & 0x00000020) {
878 for (head = 0; head < disp->base.head.nr; head++) { 503 list_for_each_entry(head, &disp->base.head, head) {
879 if (!(super & (0x00000080 << head))) 504 if (!(super & (0x00000080 << head->id)))
880 continue; 505 continue;
881 nv50_disp_intr_unk20_0(disp, head); 506 nv50_disp_super_2_0(disp, head);
882 } 507 }
883 for (head = 0; head < disp->base.head.nr; head++) { 508 nvkm_outp_route(&disp->base);
884 if (!(super & (0x00000200 << head))) 509 list_for_each_entry(head, &disp->base.head, head) {
510 if (!(super & (0x00000200 << head->id)))
885 continue; 511 continue;
886 nv50_disp_intr_unk20_1(disp, head); 512 nv50_disp_super_2_1(disp, head);
887 } 513 }
888 for (head = 0; head < disp->base.head.nr; head++) { 514 list_for_each_entry(head, &disp->base.head, head) {
889 if (!(super & (0x00000080 << head))) 515 if (!(super & (0x00000080 << head->id)))
890 continue; 516 continue;
891 nv50_disp_intr_unk20_2(disp, head); 517 nv50_disp_super_2_2(disp, head);
892 } 518 }
893 } else 519 } else
894 if (disp->super & 0x00000040) { 520 if (disp->super & 0x00000040) {
895 for (head = 0; head < disp->base.head.nr; head++) { 521 list_for_each_entry(head, &disp->base.head, head) {
896 if (!(super & (0x00000080 << head))) 522 if (!(super & (0x00000080 << head->id)))
897 continue; 523 continue;
898 nv50_disp_intr_unk40_0(disp, head); 524 nv50_disp_super_3_0(disp, head);
899 } 525 }
900 nv50_disp_update_sppll1(disp);
901 } 526 }
902 527
903 nvkm_wr32(device, 0x610030, 0x80000000); 528 nvkm_wr32(device, 0x610030, 0x80000000);
904} 529}
905 530
531static const struct nvkm_enum
532nv50_disp_intr_error_type[] = {
533 { 3, "ILLEGAL_MTHD" },
534 { 4, "INVALID_VALUE" },
535 { 5, "INVALID_STATE" },
536 { 7, "INVALID_HANDLE" },
537 {}
538};
539
540static const struct nvkm_enum
541nv50_disp_intr_error_code[] = {
542 { 0x00, "" },
543 {}
544};
545
546static void
547nv50_disp_intr_error(struct nv50_disp *disp, int chid)
548{
549 struct nvkm_subdev *subdev = &disp->base.engine.subdev;
550 struct nvkm_device *device = subdev->device;
551 u32 data = nvkm_rd32(device, 0x610084 + (chid * 0x08));
552 u32 addr = nvkm_rd32(device, 0x610080 + (chid * 0x08));
553 u32 code = (addr & 0x00ff0000) >> 16;
554 u32 type = (addr & 0x00007000) >> 12;
555 u32 mthd = (addr & 0x00000ffc);
556 const struct nvkm_enum *ec, *et;
557
558 et = nvkm_enum_find(nv50_disp_intr_error_type, type);
559 ec = nvkm_enum_find(nv50_disp_intr_error_code, code);
560
561 nvkm_error(subdev,
562 "ERROR %d [%s] %02x [%s] chid %d mthd %04x data %08x\n",
563 type, et ? et->name : "", code, ec ? ec->name : "",
564 chid, mthd, data);
565
566 if (chid < ARRAY_SIZE(disp->chan)) {
567 switch (mthd) {
568 case 0x0080:
569 nv50_disp_chan_mthd(disp->chan[chid], NV_DBG_ERROR);
570 break;
571 default:
572 break;
573 }
574 }
575
576 nvkm_wr32(device, 0x610020, 0x00010000 << chid);
577 nvkm_wr32(device, 0x610080 + (chid * 0x08), 0x90000000);
578}
579
906void 580void
907nv50_disp_intr(struct nv50_disp *disp) 581nv50_disp_intr(struct nv50_disp *disp)
908{ 582{
@@ -934,7 +608,7 @@ nv50_disp_intr(struct nv50_disp *disp)
934 608
935 if (intr1 & 0x00000070) { 609 if (intr1 & 0x00000070) {
936 disp->super = (intr1 & 0x00000070); 610 disp->super = (intr1 & 0x00000070);
937 schedule_work(&disp->supervisor); 611 queue_work(disp->wq, &disp->supervisor);
938 nvkm_wr32(device, 0x610024, disp->super); 612 nvkm_wr32(device, 0x610024, disp->super);
939 } 613 }
940} 614}
@@ -943,23 +617,12 @@ static const struct nv50_disp_func
943nv50_disp = { 617nv50_disp = {
944 .intr = nv50_disp_intr, 618 .intr = nv50_disp_intr,
945 .uevent = &nv50_disp_chan_uevent, 619 .uevent = &nv50_disp_chan_uevent,
946 .super = nv50_disp_intr_supervisor, 620 .super = nv50_disp_super,
947 .root = &nv50_disp_root_oclass, 621 .root = &nv50_disp_root_oclass,
948 .head.vblank_init = nv50_disp_vblank_init, 622 .head.new = nv50_head_new,
949 .head.vblank_fini = nv50_disp_vblank_fini, 623 .dac = { .nr = 3, .new = nv50_dac_new },
950 .head.scanoutpos = nv50_disp_root_scanoutpos, 624 .sor = { .nr = 2, .new = nv50_sor_new },
951 .outp.internal.crt = nv50_dac_output_new, 625 .pior = { .nr = 3, .new = nv50_pior_new },
952 .outp.internal.tmds = nv50_sor_output_new,
953 .outp.internal.lvds = nv50_sor_output_new,
954 .outp.external.tmds = nv50_pior_output_new,
955 .outp.external.dp = nv50_pior_dp_new,
956 .dac.nr = 3,
957 .dac.power = nv50_dac_power,
958 .dac.sense = nv50_dac_sense,
959 .sor.nr = 2,
960 .sor.power = nv50_sor_power,
961 .pior.nr = 3,
962 .pior.power = nv50_pior_power,
963}; 626};
964 627
965int 628int
diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/nv50.h b/drivers/gpu/drm/nouveau/nvkm/engine/disp/nv50.h
index 1e1de6bfe85a..19c635663399 100644
--- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/nv50.h
+++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/nv50.h
@@ -2,18 +2,13 @@
2#define __NV50_DISP_H__ 2#define __NV50_DISP_H__
3#define nv50_disp(p) container_of((p), struct nv50_disp, base) 3#define nv50_disp(p) container_of((p), struct nv50_disp, base)
4#include "priv.h" 4#include "priv.h"
5struct nvkm_output; 5struct nvkm_head;
6struct nvkm_output_dp;
7
8#define NV50_DISP_MTHD_ struct nvkm_object *object, \
9 struct nv50_disp *disp, void *data, u32 size
10#define NV50_DISP_MTHD_V0 NV50_DISP_MTHD_, int head
11#define NV50_DISP_MTHD_V1 NV50_DISP_MTHD_, int head, struct nvkm_output *outp
12 6
13struct nv50_disp { 7struct nv50_disp {
14 const struct nv50_disp_func *func; 8 const struct nv50_disp_func *func;
15 struct nvkm_disp base; 9 struct nvkm_disp base;
16 10
11 struct workqueue_struct *wq;
17 struct work_struct supervisor; 12 struct work_struct supervisor;
18 u32 super; 13 u32 super;
19 14
@@ -30,42 +25,18 @@ struct nv50_disp {
30 struct nv50_disp_chan *chan[17]; 25 struct nv50_disp_chan *chan[17];
31}; 26};
32 27
33int nv50_disp_root_scanoutpos(NV50_DISP_MTHD_V0); 28void nv50_disp_super_1(struct nv50_disp *);
34 29void nv50_disp_super_1_0(struct nv50_disp *, struct nvkm_head *);
35int gf119_disp_root_scanoutpos(NV50_DISP_MTHD_V0); 30void nv50_disp_super_2_0(struct nv50_disp *, struct nvkm_head *);
36 31void nv50_disp_super_2_1(struct nv50_disp *, struct nvkm_head *);
37int nv50_dac_power(NV50_DISP_MTHD_V1); 32void nv50_disp_super_2_2(struct nv50_disp *, struct nvkm_head *);
38int nv50_dac_sense(NV50_DISP_MTHD_V1); 33void nv50_disp_super_3_0(struct nv50_disp *, struct nvkm_head *);
39
40int gt215_hda_eld(NV50_DISP_MTHD_V1);
41int gf119_hda_eld(NV50_DISP_MTHD_V1);
42
43int g84_hdmi_ctrl(NV50_DISP_MTHD_V1);
44int gt215_hdmi_ctrl(NV50_DISP_MTHD_V1);
45int gf119_hdmi_ctrl(NV50_DISP_MTHD_V1);
46int gk104_hdmi_ctrl(NV50_DISP_MTHD_V1);
47
48int nv50_sor_power(NV50_DISP_MTHD_V1);
49int nv50_pior_power(NV50_DISP_MTHD_V1);
50 34
51int nv50_disp_new_(const struct nv50_disp_func *, struct nvkm_device *, 35int nv50_disp_new_(const struct nv50_disp_func *, struct nvkm_device *,
52 int index, int heads, struct nvkm_disp **); 36 int index, int heads, struct nvkm_disp **);
53int gf119_disp_new_(const struct nv50_disp_func *, struct nvkm_device *, 37int gf119_disp_new_(const struct nv50_disp_func *, struct nvkm_device *,
54 int index, struct nvkm_disp **); 38 int index, struct nvkm_disp **);
55 39
56struct nv50_disp_func_outp {
57 int (* crt)(struct nvkm_disp *, int index, struct dcb_output *,
58 struct nvkm_output **);
59 int (* tv)(struct nvkm_disp *, int index, struct dcb_output *,
60 struct nvkm_output **);
61 int (*tmds)(struct nvkm_disp *, int index, struct dcb_output *,
62 struct nvkm_output **);
63 int (*lvds)(struct nvkm_disp *, int index, struct dcb_output *,
64 struct nvkm_output **);
65 int (* dp)(struct nvkm_disp *, int index, struct dcb_output *,
66 struct nvkm_output **);
67};
68
69struct nv50_disp_func { 40struct nv50_disp_func {
70 void (*intr)(struct nv50_disp *); 41 void (*intr)(struct nv50_disp *);
71 void (*intr_error)(struct nv50_disp *, int chid); 42 void (*intr_error)(struct nv50_disp *, int chid);
@@ -76,44 +47,33 @@ struct nv50_disp_func {
76 const struct nvkm_disp_oclass *root; 47 const struct nvkm_disp_oclass *root;
77 48
78 struct { 49 struct {
79 void (*vblank_init)(struct nv50_disp *, int head); 50 int (*new)(struct nvkm_disp *, int id);
80 void (*vblank_fini)(struct nv50_disp *, int head);
81 int (*scanoutpos)(NV50_DISP_MTHD_V0);
82 } head; 51 } head;
83 52
84 struct { 53 struct {
85 const struct nv50_disp_func_outp internal;
86 const struct nv50_disp_func_outp external;
87 } outp;
88
89 struct {
90 int nr; 54 int nr;
91 int (*power)(NV50_DISP_MTHD_V1); 55 int (*new)(struct nvkm_disp *, int id);
92 int (*sense)(NV50_DISP_MTHD_V1);
93 } dac; 56 } dac;
94 57
95 struct { 58 struct {
96 int nr; 59 int nr;
97 int (*power)(NV50_DISP_MTHD_V1); 60 int (*new)(struct nvkm_disp *, int id);
98 int (*hda_eld)(NV50_DISP_MTHD_V1);
99 int (*hdmi)(NV50_DISP_MTHD_V1);
100 void (*magic)(struct nvkm_output *);
101 } sor; 61 } sor;
102 62
103 struct { 63 struct {
104 int nr; 64 int nr;
105 int (*power)(NV50_DISP_MTHD_V1); 65 int (*new)(struct nvkm_disp *, int id);
106 } pior; 66 } pior;
107}; 67};
108 68
109void nv50_disp_vblank_init(struct nv50_disp *, int);
110void nv50_disp_vblank_fini(struct nv50_disp *, int);
111void nv50_disp_intr(struct nv50_disp *); 69void nv50_disp_intr(struct nv50_disp *);
112void nv50_disp_intr_supervisor(struct work_struct *); 70void nv50_disp_super(struct work_struct *);
113 71
114void gf119_disp_vblank_init(struct nv50_disp *, int);
115void gf119_disp_vblank_fini(struct nv50_disp *, int);
116void gf119_disp_intr(struct nv50_disp *); 72void gf119_disp_intr(struct nv50_disp *);
117void gf119_disp_intr_supervisor(struct work_struct *); 73void gf119_disp_super(struct work_struct *);
118void gf119_disp_intr_error(struct nv50_disp *, int); 74void gf119_disp_intr_error(struct nv50_disp *, int);
75
76void nv50_disp_dptmds_war_2(struct nv50_disp *, struct dcb_output *);
77void nv50_disp_dptmds_war_3(struct nv50_disp *, struct dcb_output *);
78void nv50_disp_update_sppll1(struct nv50_disp *);
119#endif 79#endif
diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/oimmnv50.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/oimmnv50.c
index 07540f3d32dc..f3b0fa2c5924 100644
--- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/oimmnv50.c
+++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/oimmnv50.c
@@ -22,6 +22,7 @@
22 * Authors: Ben Skeggs 22 * Authors: Ben Skeggs
23 */ 23 */
24#include "channv50.h" 24#include "channv50.h"
25#include "head.h"
25#include "rootnv50.h" 26#include "rootnv50.h"
26 27
27#include <core/client.h> 28#include <core/client.h>
@@ -48,7 +49,7 @@ nv50_disp_oimm_new(const struct nv50_disp_chan_func *func,
48 if (!(ret = nvif_unpack(ret, &data, &size, args->v0, 0, 0, false))) { 49 if (!(ret = nvif_unpack(ret, &data, &size, args->v0, 0, 0, false))) {
49 nvif_ioctl(parent, "create disp overlay vers %d head %d\n", 50 nvif_ioctl(parent, "create disp overlay vers %d head %d\n",
50 args->v0.version, args->v0.head); 51 args->v0.version, args->v0.head);
51 if (args->v0.head > disp->base.head.nr) 52 if (!nvkm_head_find(&disp->base, args->v0.head))
52 return -EINVAL; 53 return -EINVAL;
53 head = args->v0.head; 54 head = args->v0.head;
54 } else 55 } else
diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/outp.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/outp.c
index bbe5ec0dedb2..85aff85394ac 100644
--- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/outp.c
+++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/outp.c
@@ -22,29 +22,207 @@
22 * Authors: Ben Skeggs 22 * Authors: Ben Skeggs
23 */ 23 */
24#include "outp.h" 24#include "outp.h"
25#include "ior.h"
25 26
26#include <subdev/bios.h> 27#include <subdev/bios.h>
27#include <subdev/bios/dcb.h> 28#include <subdev/bios/dcb.h>
28#include <subdev/i2c.h> 29#include <subdev/i2c.h>
29 30
30void 31void
31nvkm_output_fini(struct nvkm_output *outp) 32nvkm_outp_route(struct nvkm_disp *disp)
33{
34 struct nvkm_outp *outp;
35 struct nvkm_ior *ior;
36
37 list_for_each_entry(ior, &disp->ior, head) {
38 if ((outp = ior->arm.outp) && ior->arm.outp != ior->asy.outp) {
39 OUTP_DBG(outp, "release %s", ior->name);
40 if (ior->func->route.set)
41 ior->func->route.set(outp, NULL);
42 ior->arm.outp = NULL;
43 }
44 }
45
46 list_for_each_entry(ior, &disp->ior, head) {
47 if ((outp = ior->asy.outp)) {
48 OUTP_DBG(outp, "acquire %s", ior->name);
49 if (ior->asy.outp != ior->arm.outp) {
50 if (ior->func->route.set)
51 ior->func->route.set(outp, ior);
52 ior->arm.outp = ior->asy.outp;
53 }
54 }
55 }
56}
57
58static enum nvkm_ior_proto
59nvkm_outp_xlat(struct nvkm_outp *outp, enum nvkm_ior_type *type)
60{
61 switch (outp->info.location) {
62 case 0:
63 switch (outp->info.type) {
64 case DCB_OUTPUT_ANALOG: *type = DAC; return CRT;
65 case DCB_OUTPUT_TMDS : *type = SOR; return TMDS;
66 case DCB_OUTPUT_LVDS : *type = SOR; return LVDS;
67 case DCB_OUTPUT_DP : *type = SOR; return DP;
68 default:
69 break;
70 }
71 break;
72 case 1:
73 switch (outp->info.type) {
74 case DCB_OUTPUT_TMDS: *type = PIOR; return TMDS;
75 case DCB_OUTPUT_DP : *type = PIOR; return TMDS; /* not a bug */
76 default:
77 break;
78 }
79 break;
80 default:
81 break;
82 }
83 WARN_ON(1);
84 return UNKNOWN;
85}
86
87void
88nvkm_outp_release(struct nvkm_outp *outp, u8 user)
89{
90 struct nvkm_ior *ior = outp->ior;
91 OUTP_TRACE(outp, "release %02x &= %02x %p", outp->acquired, ~user, ior);
92 if (ior) {
93 outp->acquired &= ~user;
94 if (!outp->acquired) {
95 outp->ior->asy.outp = NULL;
96 outp->ior = NULL;
97 }
98 }
99}
100
101static inline int
102nvkm_outp_acquire_ior(struct nvkm_outp *outp, u8 user, struct nvkm_ior *ior)
103{
104 outp->ior = ior;
105 outp->ior->asy.outp = outp;
106 outp->ior->asy.link = outp->info.sorconf.link;
107 outp->acquired |= user;
108 return 0;
109}
110
111int
112nvkm_outp_acquire(struct nvkm_outp *outp, u8 user)
113{
114 struct nvkm_ior *ior = outp->ior;
115 enum nvkm_ior_proto proto;
116 enum nvkm_ior_type type;
117
118 OUTP_TRACE(outp, "acquire %02x |= %02x %p", outp->acquired, user, ior);
119 if (ior) {
120 outp->acquired |= user;
121 return 0;
122 }
123
124 /* Lookup a compatible, and unused, OR to assign to the device. */
125 proto = nvkm_outp_xlat(outp, &type);
126 if (proto == UNKNOWN)
127 return -ENOSYS;
128
129 /* First preference is to reuse the OR that is currently armed
130 * on HW, if any, in order to prevent unnecessary switching.
131 */
132 list_for_each_entry(ior, &outp->disp->ior, head) {
133 if (!ior->asy.outp && ior->arm.outp == outp)
134 return nvkm_outp_acquire_ior(outp, user, ior);
135 }
136
137 /* Failing that, a completely unused OR is the next best thing. */
138 list_for_each_entry(ior, &outp->disp->ior, head) {
139 if (!ior->asy.outp && ior->type == type && !ior->arm.outp &&
140 (ior->func->route.set || ior->id == __ffs(outp->info.or)))
141 return nvkm_outp_acquire_ior(outp, user, ior);
142 }
143
144 /* Last resort is to assign an OR that's already active on HW,
145 * but will be released during the next modeset.
146 */
147 list_for_each_entry(ior, &outp->disp->ior, head) {
148 if (!ior->asy.outp && ior->type == type &&
149 (ior->func->route.set || ior->id == __ffs(outp->info.or)))
150 return nvkm_outp_acquire_ior(outp, user, ior);
151 }
152
153 return -ENOSPC;
154}
155
156void
157nvkm_outp_fini(struct nvkm_outp *outp)
32{ 158{
33 if (outp->func->fini) 159 if (outp->func->fini)
34 outp->func->fini(outp); 160 outp->func->fini(outp);
35} 161}
36 162
163static void
164nvkm_outp_init_route(struct nvkm_outp *outp)
165{
166 struct nvkm_disp *disp = outp->disp;
167 enum nvkm_ior_proto proto;
168 enum nvkm_ior_type type;
169 struct nvkm_ior *ior;
170 int id, link;
171
172 /* Find any OR from the class that is able to support this device. */
173 proto = nvkm_outp_xlat(outp, &type);
174 if (proto == UNKNOWN)
175 return;
176
177 ior = nvkm_ior_find(disp, type, -1);
178 if (!ior) {
179 WARN_ON(1);
180 return;
181 }
182
183 /* Determine the specific OR, if any, this device is attached to. */
184 if (ior->func->route.get) {
185 id = ior->func->route.get(outp, &link);
186 if (id < 0) {
187 OUTP_DBG(outp, "no route");
188 return;
189 }
190 } else {
191 /* Prior to DCB 4.1, this is hardwired like so. */
192 id = ffs(outp->info.or) - 1;
193 link = (ior->type == SOR) ? outp->info.sorconf.link : 0;
194 }
195
196 ior = nvkm_ior_find(disp, type, id);
197 if (!ior) {
198 WARN_ON(1);
199 return;
200 }
201
202 /* Determine if the OR is already configured for this device. */
203 ior->func->state(ior, &ior->arm);
204 if (!ior->arm.head || ior->arm.proto != proto) {
205 OUTP_DBG(outp, "no heads (%x %d %d)", ior->arm.head,
206 ior->arm.proto, proto);
207 return;
208 }
209
210 OUTP_DBG(outp, "on %s link %x", ior->name, ior->arm.link);
211 ior->arm.outp = outp;
212}
213
37void 214void
38nvkm_output_init(struct nvkm_output *outp) 215nvkm_outp_init(struct nvkm_outp *outp)
39{ 216{
217 nvkm_outp_init_route(outp);
40 if (outp->func->init) 218 if (outp->func->init)
41 outp->func->init(outp); 219 outp->func->init(outp);
42} 220}
43 221
44void 222void
45nvkm_output_del(struct nvkm_output **poutp) 223nvkm_outp_del(struct nvkm_outp **poutp)
46{ 224{
47 struct nvkm_output *outp = *poutp; 225 struct nvkm_outp *outp = *poutp;
48 if (outp && !WARN_ON(!outp->func)) { 226 if (outp && !WARN_ON(!outp->func)) {
49 if (outp->func->dtor) 227 if (outp->func->dtor)
50 *poutp = outp->func->dtor(outp); 228 *poutp = outp->func->dtor(outp);
@@ -53,11 +231,13 @@ nvkm_output_del(struct nvkm_output **poutp)
53 } 231 }
54} 232}
55 233
56void 234int
57nvkm_output_ctor(const struct nvkm_output_func *func, struct nvkm_disp *disp, 235nvkm_outp_ctor(const struct nvkm_outp_func *func, struct nvkm_disp *disp,
58 int index, struct dcb_output *dcbE, struct nvkm_output *outp) 236 int index, struct dcb_output *dcbE, struct nvkm_outp *outp)
59{ 237{
60 struct nvkm_i2c *i2c = disp->engine.subdev.device->i2c; 238 struct nvkm_i2c *i2c = disp->engine.subdev.device->i2c;
239 enum nvkm_ior_proto proto;
240 enum nvkm_ior_type type;
61 241
62 outp->func = func; 242 outp->func = func;
63 outp->disp = disp; 243 outp->disp = disp;
@@ -72,16 +252,24 @@ nvkm_output_ctor(const struct nvkm_output_func *func, struct nvkm_disp *disp,
72 outp->info.type >= 2 ? outp->info.sorconf.link : 0, 252 outp->info.type >= 2 ? outp->info.sorconf.link : 0,
73 outp->info.connector, outp->info.i2c_index, 253 outp->info.connector, outp->info.i2c_index,
74 outp->info.bus, outp->info.heads); 254 outp->info.bus, outp->info.heads);
255
256 /* Cull output paths we can't map to an output resource. */
257 proto = nvkm_outp_xlat(outp, &type);
258 if (proto == UNKNOWN)
259 return -ENODEV;
260
261 return 0;
75} 262}
76 263
264static const struct nvkm_outp_func
265nvkm_outp = {
266};
267
77int 268int
78nvkm_output_new_(const struct nvkm_output_func *func, 269nvkm_outp_new(struct nvkm_disp *disp, int index, struct dcb_output *dcbE,
79 struct nvkm_disp *disp, int index, struct dcb_output *dcbE, 270 struct nvkm_outp **poutp)
80 struct nvkm_output **poutp)
81{ 271{
82 if (!(*poutp = kzalloc(sizeof(**poutp), GFP_KERNEL))) 272 if (!(*poutp = kzalloc(sizeof(**poutp), GFP_KERNEL)))
83 return -ENOMEM; 273 return -ENOMEM;
84 274 return nvkm_outp_ctor(&nvkm_outp, disp, index, dcbE, *poutp);
85 nvkm_output_ctor(func, disp, index, dcbE, *poutp);
86 return 0;
87} 275}
diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/outp.h b/drivers/gpu/drm/nouveau/nvkm/engine/disp/outp.h
index 07727198d7ce..146d101d4891 100644
--- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/outp.h
+++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/outp.h
@@ -5,47 +5,46 @@
5#include <subdev/bios.h> 5#include <subdev/bios.h>
6#include <subdev/bios/dcb.h> 6#include <subdev/bios/dcb.h>
7 7
8struct nvkm_output { 8struct nvkm_outp {
9 const struct nvkm_output_func *func; 9 const struct nvkm_outp_func *func;
10 struct nvkm_disp *disp; 10 struct nvkm_disp *disp;
11 int index; 11 int index;
12 struct dcb_output info; 12 struct dcb_output info;
13 13
14 // whatever (if anything) is pointed at by the dcb device entry
15 struct nvkm_i2c_bus *i2c; 14 struct nvkm_i2c_bus *i2c;
16 int or; 15 int or;
17 16
18 struct list_head head; 17 struct list_head head;
19 struct nvkm_connector *conn; 18 struct nvkm_conn *conn;
20};
21 19
22struct nvkm_output_func { 20 /* Assembly state. */
23 void *(*dtor)(struct nvkm_output *); 21#define NVKM_OUTP_PRIV 1
24 void (*init)(struct nvkm_output *); 22#define NVKM_OUTP_USER 2
25 void (*fini)(struct nvkm_output *); 23 u8 acquired:2;
24 struct nvkm_ior *ior;
26}; 25};
27 26
28void nvkm_output_ctor(const struct nvkm_output_func *, struct nvkm_disp *, 27int nvkm_outp_ctor(const struct nvkm_outp_func *, struct nvkm_disp *,
29 int index, struct dcb_output *, struct nvkm_output *); 28 int index, struct dcb_output *, struct nvkm_outp *);
30int nvkm_output_new_(const struct nvkm_output_func *, struct nvkm_disp *, 29int nvkm_outp_new(struct nvkm_disp *, int index, struct dcb_output *,
31 int index, struct dcb_output *, struct nvkm_output **); 30 struct nvkm_outp **);
32void nvkm_output_del(struct nvkm_output **); 31void nvkm_outp_del(struct nvkm_outp **);
33void nvkm_output_init(struct nvkm_output *); 32void nvkm_outp_init(struct nvkm_outp *);
34void nvkm_output_fini(struct nvkm_output *); 33void nvkm_outp_fini(struct nvkm_outp *);
35 34int nvkm_outp_acquire(struct nvkm_outp *, u8 user);
36int nv50_dac_output_new(struct nvkm_disp *, int, struct dcb_output *, 35void nvkm_outp_release(struct nvkm_outp *, u8 user);
37 struct nvkm_output **); 36void nvkm_outp_route(struct nvkm_disp *);
38int nv50_sor_output_new(struct nvkm_disp *, int, struct dcb_output *, 37
39 struct nvkm_output **); 38struct nvkm_outp_func {
40int nv50_pior_output_new(struct nvkm_disp *, int, struct dcb_output *, 39 void *(*dtor)(struct nvkm_outp *);
41 struct nvkm_output **); 40 void (*init)(struct nvkm_outp *);
42 41 void (*fini)(struct nvkm_outp *);
43u32 g94_sor_dp_lane_map(struct nvkm_device *, u8 lane); 42 int (*acquire)(struct nvkm_outp *);
44 43 void (*release)(struct nvkm_outp *, struct nvkm_ior *);
45void gm200_sor_magic(struct nvkm_output *outp); 44};
46 45
47#define OUTP_MSG(o,l,f,a...) do { \ 46#define OUTP_MSG(o,l,f,a...) do { \
48 struct nvkm_output *_outp = (o); \ 47 struct nvkm_outp *_outp = (o); \
49 nvkm_##l(&_outp->disp->engine.subdev, "outp %02x:%04x:%04x: "f"\n", \ 48 nvkm_##l(&_outp->disp->engine.subdev, "outp %02x:%04x:%04x: "f"\n", \
50 _outp->index, _outp->info.hasht, _outp->info.hashm, ##a); \ 49 _outp->index, _outp->info.hasht, _outp->info.hashm, ##a); \
51} while(0) 50} while(0)
diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/outpdp.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/outpdp.c
deleted file mode 100644
index de36f73b14dc..000000000000
--- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/outpdp.c
+++ /dev/null
@@ -1,282 +0,0 @@
1/*
2 * Copyright 2014 Red Hat Inc.
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: Ben Skeggs
23 */
24#include "outpdp.h"
25#include "conn.h"
26#include "dport.h"
27#include "priv.h"
28
29#include <subdev/i2c.h>
30
31#include <nvif/event.h>
32
33int
34nvkm_output_dp_train(struct nvkm_output *base, u32 datarate)
35{
36 struct nvkm_output_dp *outp = nvkm_output_dp(base);
37 bool retrain = true;
38 u8 link[2], stat[3];
39 u32 linkrate;
40 int ret, i;
41
42 mutex_lock(&outp->mutex);
43
44 /* check that the link is trained at a high enough rate */
45 ret = nvkm_rdaux(outp->aux, DPCD_LC00_LINK_BW_SET, link, 2);
46 if (ret) {
47 OUTP_DBG(&outp->base,
48 "failed to read link config, assuming no sink");
49 goto done;
50 }
51
52 linkrate = link[0] * 27000 * (link[1] & DPCD_LC01_LANE_COUNT_SET);
53 linkrate = (linkrate * 8) / 10; /* 8B/10B coding overhead */
54 datarate = (datarate + 9) / 10; /* -> decakilobits */
55 if (linkrate < datarate) {
56 OUTP_DBG(&outp->base, "link not trained at sufficient rate");
57 goto done;
58 }
59
60 /* check that link is still trained */
61 ret = nvkm_rdaux(outp->aux, DPCD_LS02, stat, 3);
62 if (ret) {
63 OUTP_DBG(&outp->base,
64 "failed to read link status, assuming no sink");
65 goto done;
66 }
67
68 if (stat[2] & DPCD_LS04_INTERLANE_ALIGN_DONE) {
69 for (i = 0; i < (link[1] & DPCD_LC01_LANE_COUNT_SET); i++) {
70 u8 lane = (stat[i >> 1] >> ((i & 1) * 4)) & 0x0f;
71 if (!(lane & DPCD_LS02_LANE0_CR_DONE) ||
72 !(lane & DPCD_LS02_LANE0_CHANNEL_EQ_DONE) ||
73 !(lane & DPCD_LS02_LANE0_SYMBOL_LOCKED)) {
74 OUTP_DBG(&outp->base,
75 "lane %d not equalised", lane);
76 goto done;
77 }
78 }
79 retrain = false;
80 } else {
81 OUTP_DBG(&outp->base, "no inter-lane alignment");
82 }
83
84done:
85 if (retrain || !atomic_read(&outp->lt.done)) {
86 /* no sink, but still need to configure source */
87 if (outp->dpcd[DPCD_RC00_DPCD_REV] == 0x00) {
88 outp->dpcd[DPCD_RC01_MAX_LINK_RATE] =
89 outp->base.info.dpconf.link_bw;
90 outp->dpcd[DPCD_RC02] =
91 outp->base.info.dpconf.link_nr;
92 }
93 nvkm_dp_train(outp);
94 }
95
96 mutex_unlock(&outp->mutex);
97 return ret;
98}
99
100static void
101nvkm_output_dp_enable(struct nvkm_output_dp *outp, bool enable)
102{
103 struct nvkm_i2c_aux *aux = outp->aux;
104
105 if (enable) {
106 if (!outp->present) {
107 OUTP_DBG(&outp->base, "aux power -> always");
108 nvkm_i2c_aux_monitor(aux, true);
109 outp->present = true;
110 }
111
112 if (!nvkm_rdaux(aux, DPCD_RC00_DPCD_REV, outp->dpcd,
113 sizeof(outp->dpcd))) {
114 nvkm_output_dp_train(&outp->base, 0);
115 return;
116 }
117 }
118
119 if (outp->present) {
120 OUTP_DBG(&outp->base, "aux power -> demand");
121 nvkm_i2c_aux_monitor(aux, false);
122 outp->present = false;
123 }
124
125 atomic_set(&outp->lt.done, 0);
126}
127
128static int
129nvkm_output_dp_hpd(struct nvkm_notify *notify)
130{
131 const struct nvkm_i2c_ntfy_rep *line = notify->data;
132 struct nvkm_output_dp *outp = container_of(notify, typeof(*outp), hpd);
133 struct nvkm_connector *conn = outp->base.conn;
134 struct nvkm_disp *disp = outp->base.disp;
135 struct nvif_notify_conn_rep_v0 rep = {};
136
137 OUTP_DBG(&outp->base, "HPD: %d", line->mask);
138 nvkm_output_dp_enable(outp, true);
139
140 if (line->mask & NVKM_I2C_UNPLUG)
141 rep.mask |= NVIF_NOTIFY_CONN_V0_UNPLUG;
142 if (line->mask & NVKM_I2C_PLUG)
143 rep.mask |= NVIF_NOTIFY_CONN_V0_PLUG;
144
145 nvkm_event_send(&disp->hpd, rep.mask, conn->index, &rep, sizeof(rep));
146 return NVKM_NOTIFY_KEEP;
147}
148
149static int
150nvkm_output_dp_irq(struct nvkm_notify *notify)
151{
152 const struct nvkm_i2c_ntfy_rep *line = notify->data;
153 struct nvkm_output_dp *outp = container_of(notify, typeof(*outp), irq);
154 struct nvkm_connector *conn = outp->base.conn;
155 struct nvkm_disp *disp = outp->base.disp;
156 struct nvif_notify_conn_rep_v0 rep = {
157 .mask = NVIF_NOTIFY_CONN_V0_IRQ,
158 };
159
160 OUTP_DBG(&outp->base, "IRQ: %d", line->mask);
161 nvkm_output_dp_train(&outp->base, 0);
162
163 nvkm_event_send(&disp->hpd, rep.mask, conn->index, &rep, sizeof(rep));
164 return NVKM_NOTIFY_KEEP;
165}
166
167static void
168nvkm_output_dp_fini(struct nvkm_output *base)
169{
170 struct nvkm_output_dp *outp = nvkm_output_dp(base);
171 nvkm_notify_put(&outp->hpd);
172 nvkm_notify_put(&outp->irq);
173 nvkm_output_dp_enable(outp, false);
174}
175
176static void
177nvkm_output_dp_init(struct nvkm_output *base)
178{
179 struct nvkm_output_dp *outp = nvkm_output_dp(base);
180 nvkm_notify_put(&outp->base.conn->hpd);
181 nvkm_output_dp_enable(outp, true);
182 nvkm_notify_get(&outp->irq);
183 nvkm_notify_get(&outp->hpd);
184}
185
186static void *
187nvkm_output_dp_dtor(struct nvkm_output *base)
188{
189 struct nvkm_output_dp *outp = nvkm_output_dp(base);
190 nvkm_notify_fini(&outp->hpd);
191 nvkm_notify_fini(&outp->irq);
192 return outp;
193}
194
195static const struct nvkm_output_func
196nvkm_output_dp_func = {
197 .dtor = nvkm_output_dp_dtor,
198 .init = nvkm_output_dp_init,
199 .fini = nvkm_output_dp_fini,
200};
201
202int
203nvkm_output_dp_ctor(const struct nvkm_output_dp_func *func,
204 struct nvkm_disp *disp, int index, struct dcb_output *dcbE,
205 struct nvkm_i2c_aux *aux, struct nvkm_output_dp *outp)
206{
207 struct nvkm_device *device = disp->engine.subdev.device;
208 struct nvkm_bios *bios = device->bios;
209 struct nvkm_i2c *i2c = device->i2c;
210 u8 hdr, cnt, len;
211 u32 data;
212 int ret;
213
214 nvkm_output_ctor(&nvkm_output_dp_func, disp, index, dcbE, &outp->base);
215 outp->func = func;
216 outp->aux = aux;
217 if (!outp->aux) {
218 OUTP_ERR(&outp->base, "no aux");
219 return -ENODEV;
220 }
221
222 /* bios data is not optional */
223 data = nvbios_dpout_match(bios, outp->base.info.hasht,
224 outp->base.info.hashm, &outp->version,
225 &hdr, &cnt, &len, &outp->info);
226 if (!data) {
227 OUTP_ERR(&outp->base, "no bios dp data");
228 return -ENODEV;
229 }
230
231 OUTP_DBG(&outp->base, "bios dp %02x %02x %02x %02x",
232 outp->version, hdr, cnt, len);
233
234 /* link maintenance */
235 ret = nvkm_notify_init(NULL, &i2c->event, nvkm_output_dp_irq, true,
236 &(struct nvkm_i2c_ntfy_req) {
237 .mask = NVKM_I2C_IRQ,
238 .port = outp->aux->id,
239 },
240 sizeof(struct nvkm_i2c_ntfy_req),
241 sizeof(struct nvkm_i2c_ntfy_rep),
242 &outp->irq);
243 if (ret) {
244 OUTP_ERR(&outp->base, "error monitoring aux irq: %d", ret);
245 return ret;
246 }
247
248 mutex_init(&outp->mutex);
249 atomic_set(&outp->lt.done, 0);
250
251 /* hotplug detect, replaces gpio-based mechanism with aux events */
252 ret = nvkm_notify_init(NULL, &i2c->event, nvkm_output_dp_hpd, true,
253 &(struct nvkm_i2c_ntfy_req) {
254 .mask = NVKM_I2C_PLUG | NVKM_I2C_UNPLUG,
255 .port = outp->aux->id,
256 },
257 sizeof(struct nvkm_i2c_ntfy_req),
258 sizeof(struct nvkm_i2c_ntfy_rep),
259 &outp->hpd);
260 if (ret) {
261 OUTP_ERR(&outp->base, "error monitoring aux hpd: %d", ret);
262 return ret;
263 }
264
265 return 0;
266}
267
268int
269nvkm_output_dp_new_(const struct nvkm_output_dp_func *func,
270 struct nvkm_disp *disp, int index, struct dcb_output *dcbE,
271 struct nvkm_output **poutp)
272{
273 struct nvkm_i2c *i2c = disp->engine.subdev.device->i2c;
274 struct nvkm_i2c_aux *aux = nvkm_i2c_aux_find(i2c, dcbE->i2c_index);
275 struct nvkm_output_dp *outp;
276
277 if (!(outp = kzalloc(sizeof(*outp), GFP_KERNEL)))
278 return -ENOMEM;
279 *poutp = &outp->base;
280
281 return nvkm_output_dp_ctor(func, disp, index, dcbE, aux, outp);
282}
diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/outpdp.h b/drivers/gpu/drm/nouveau/nvkm/engine/disp/outpdp.h
deleted file mode 100644
index 3c83a561cd88..000000000000
--- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/outpdp.h
+++ /dev/null
@@ -1,76 +0,0 @@
1#ifndef __NVKM_DISP_OUTP_DP_H__
2#define __NVKM_DISP_OUTP_DP_H__
3#define nvkm_output_dp(p) container_of((p), struct nvkm_output_dp, base)
4#ifndef MSG
5#define MSG(l,f,a...) \
6 nvkm_##l(&outp->base.disp->engine.subdev, "%02x:%04x:%04x: "f, \
7 outp->base.index, outp->base.info.hasht, \
8 outp->base.info.hashm, ##a)
9#define DBG(f,a...) MSG(debug, f, ##a)
10#define ERR(f,a...) MSG(error, f, ##a)
11#endif
12#include "outp.h"
13
14#include <core/notify.h>
15#include <subdev/bios.h>
16#include <subdev/bios/dp.h>
17
18struct nvkm_output_dp {
19 const struct nvkm_output_dp_func *func;
20 struct nvkm_output base;
21
22 struct nvbios_dpout info;
23 u8 version;
24
25 struct nvkm_i2c_aux *aux;
26
27 struct nvkm_notify irq;
28 struct nvkm_notify hpd;
29 bool present;
30 u8 dpcd[16];
31
32 struct mutex mutex;
33 struct {
34 atomic_t done;
35 bool mst;
36 } lt;
37};
38
39struct nvkm_output_dp_func {
40 int (*pattern)(struct nvkm_output_dp *, int);
41 int (*lnk_pwr)(struct nvkm_output_dp *, int nr);
42 int (*lnk_ctl)(struct nvkm_output_dp *, int nr, int bw, bool ef);
43 int (*drv_ctl)(struct nvkm_output_dp *, int ln, int vs, int pe, int pc);
44 void (*vcpi)(struct nvkm_output_dp *, int head, u8 start_slot,
45 u8 num_slots, u16 pbn, u16 aligned_pbn);
46};
47
48int nvkm_output_dp_train(struct nvkm_output *, u32 rate);
49
50int nvkm_output_dp_ctor(const struct nvkm_output_dp_func *, struct nvkm_disp *,
51 int index, struct dcb_output *, struct nvkm_i2c_aux *,
52 struct nvkm_output_dp *);
53int nvkm_output_dp_new_(const struct nvkm_output_dp_func *, struct nvkm_disp *,
54 int index, struct dcb_output *,
55 struct nvkm_output **);
56
57int nv50_pior_dp_new(struct nvkm_disp *, int, struct dcb_output *,
58 struct nvkm_output **);
59
60int g94_sor_dp_new(struct nvkm_disp *, int, struct dcb_output *,
61 struct nvkm_output **);
62int g94_sor_dp_lnk_pwr(struct nvkm_output_dp *, int);
63
64int gf119_sor_dp_new(struct nvkm_disp *, int, struct dcb_output *,
65 struct nvkm_output **);
66int gf119_sor_dp_lnk_ctl(struct nvkm_output_dp *, int, int, bool);
67int gf119_sor_dp_drv_ctl(struct nvkm_output_dp *, int, int, int, int);
68void gf119_sor_dp_vcpi(struct nvkm_output_dp *, int, u8, u8, u16, u16);
69
70int gm107_sor_dp_new(struct nvkm_disp *, int, struct dcb_output *,
71 struct nvkm_output **);
72int gm107_sor_dp_pattern(struct nvkm_output_dp *, int);
73
74int gm200_sor_dp_new(struct nvkm_disp *, int, struct dcb_output *,
75 struct nvkm_output **);
76#endif
diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/ovlynv50.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/ovlynv50.c
index 2a49c46425cd..9ebaaa6e9e33 100644
--- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/ovlynv50.c
+++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/ovlynv50.c
@@ -22,6 +22,7 @@
22 * Authors: Ben Skeggs 22 * Authors: Ben Skeggs
23 */ 23 */
24#include "dmacnv50.h" 24#include "dmacnv50.h"
25#include "head.h"
25#include "rootnv50.h" 26#include "rootnv50.h"
26 27
27#include <core/client.h> 28#include <core/client.h>
@@ -50,7 +51,7 @@ nv50_disp_ovly_new(const struct nv50_disp_dmac_func *func,
50 nvif_ioctl(parent, "create disp overlay channel dma vers %d " 51 nvif_ioctl(parent, "create disp overlay channel dma vers %d "
51 "pushbuf %016llx head %d\n", 52 "pushbuf %016llx head %d\n",
52 args->v0.version, args->v0.pushbuf, args->v0.head); 53 args->v0.version, args->v0.pushbuf, args->v0.head);
53 if (args->v0.head > disp->base.head.nr) 54 if (!nvkm_head_find(&disp->base, args->v0.head))
54 return -EINVAL; 55 return -EINVAL;
55 push = args->v0.pushbuf; 56 push = args->v0.pushbuf;
56 head = args->v0.head; 57 head = args->v0.head;
diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/piornv50.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/piornv50.c
index 6c532eadba17..99b3b9050635 100644
--- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/piornv50.c
+++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/piornv50.c
@@ -21,111 +21,114 @@
21 * 21 *
22 * Authors: Ben Skeggs 22 * Authors: Ben Skeggs
23 */ 23 */
24#include "outpdp.h" 24#include "ior.h"
25#include "nv50.h" 25#include "head.h"
26 26
27#include <core/client.h>
28#include <subdev/i2c.h> 27#include <subdev/i2c.h>
29#include <subdev/timer.h> 28#include <subdev/timer.h>
30 29
31#include <nvif/cl5070.h> 30static void
32#include <nvif/unpack.h> 31nv50_pior_clock(struct nvkm_ior *pior)
33
34int
35nv50_pior_power(NV50_DISP_MTHD_V1)
36{ 32{
37 struct nvkm_device *device = disp->base.engine.subdev.device; 33 struct nvkm_device *device = pior->disp->engine.subdev.device;
38 const u32 soff = outp->or * 0x800; 34 const u32 poff = nv50_ior_base(pior);
39 union { 35 nvkm_mask(device, 0x614380 + poff, 0x00000707, 0x00000001);
40 struct nv50_disp_pior_pwr_v0 v0; 36}
41 } *args = data;
42 u32 ctrl, type;
43 int ret = -ENOSYS;
44 37
45 nvif_ioctl(object, "disp pior pwr size %d\n", size); 38static int
46 if (!(ret = nvif_unpack(ret, &data, &size, args->v0, 0, 0, false))) { 39nv50_pior_dp_links(struct nvkm_ior *pior, struct nvkm_i2c_aux *aux)
47 nvif_ioctl(object, "disp pior pwr vers %d state %d type %x\n", 40{
48 args->v0.version, args->v0.state, args->v0.type); 41 int ret = nvkm_i2c_aux_lnk_ctl(aux, pior->dp.nr, pior->dp.bw,
49 if (args->v0.type > 0x0f) 42 pior->dp.ef);
50 return -EINVAL; 43 if (ret)
51 ctrl = !!args->v0.state;
52 type = args->v0.type;
53 } else
54 return ret; 44 return ret;
45 return 1;
46}
55 47
48static void
49nv50_pior_power_wait(struct nvkm_device *device, u32 poff)
50{
56 nvkm_msec(device, 2000, 51 nvkm_msec(device, 2000,
57 if (!(nvkm_rd32(device, 0x61e004 + soff) & 0x80000000)) 52 if (!(nvkm_rd32(device, 0x61e004 + poff) & 0x80000000))
58 break;
59 );
60 nvkm_mask(device, 0x61e004 + soff, 0x80000101, 0x80000000 | ctrl);
61 nvkm_msec(device, 2000,
62 if (!(nvkm_rd32(device, 0x61e004 + soff) & 0x80000000))
63 break; 53 break;
64 ); 54 );
65 disp->pior.type[outp->or] = type;
66 return 0;
67} 55}
68 56
69/****************************************************************************** 57static void
70 * TMDS 58nv50_pior_power(struct nvkm_ior *pior, bool normal, bool pu,
71 *****************************************************************************/ 59 bool data, bool vsync, bool hsync)
72static const struct nvkm_output_func
73nv50_pior_output_func = {
74};
75
76int
77nv50_pior_output_new(struct nvkm_disp *disp, int index,
78 struct dcb_output *dcbE, struct nvkm_output **poutp)
79{ 60{
80 return nvkm_output_new_(&nv50_pior_output_func, disp, 61 struct nvkm_device *device = pior->disp->engine.subdev.device;
81 index, dcbE, poutp); 62 const u32 poff = nv50_ior_base(pior);
82} 63 const u32 shift = normal ? 0 : 16;
64 const u32 state = 0x80000000 | (0x00000001 * !!pu) << shift;
65 const u32 field = 0x80000000 | (0x00000101 << shift);
83 66
84/****************************************************************************** 67 nv50_pior_power_wait(device, poff);
85 * DisplayPort 68 nvkm_mask(device, 0x61e004 + poff, field, state);
86 *****************************************************************************/ 69 nv50_pior_power_wait(device, poff);
87static int
88nv50_pior_output_dp_pattern(struct nvkm_output_dp *outp, int pattern)
89{
90 return 0;
91} 70}
92 71
93static int 72void
94nv50_pior_output_dp_lnk_pwr(struct nvkm_output_dp *outp, int nr) 73nv50_pior_depth(struct nvkm_ior *ior, struct nvkm_ior_state *state, u32 ctrl)
95{ 74{
96 return 0; 75 /* GF119 moves this information to per-head methods, which is
76 * a lot more convenient, and where our shared code expect it.
77 */
78 if (state->head && state == &ior->asy) {
79 struct nvkm_head *head =
80 nvkm_head_find(ior->disp, __ffs(state->head));
81 if (!WARN_ON(!head)) {
82 struct nvkm_head_state *state = &head->asy;
83 switch ((ctrl & 0x000f0000) >> 16) {
84 case 6: state->or.depth = 30; break;
85 case 5: state->or.depth = 24; break;
86 case 2: state->or.depth = 18; break;
87 case 0: state->or.depth = 18; break; /*XXX*/
88 default:
89 state->or.depth = 18;
90 WARN_ON(1);
91 break;
92 }
93 }
94 }
97} 95}
98 96
99static int 97static void
100nv50_pior_output_dp_lnk_ctl(struct nvkm_output_dp *outp, 98nv50_pior_state(struct nvkm_ior *pior, struct nvkm_ior_state *state)
101 int nr, int bw, bool ef)
102{ 99{
103 int ret = nvkm_i2c_aux_lnk_ctl(outp->aux, nr, bw, ef); 100 struct nvkm_device *device = pior->disp->engine.subdev.device;
104 if (ret) 101 const u32 coff = pior->id * 8 + (state == &pior->arm) * 4;
105 return ret; 102 u32 ctrl = nvkm_rd32(device, 0x610b80 + coff);
106 return 1; 103
104 state->proto_evo = (ctrl & 0x00000f00) >> 8;
105 state->rgdiv = 1;
106 switch (state->proto_evo) {
107 case 0: state->proto = TMDS; break;
108 default:
109 state->proto = UNKNOWN;
110 break;
111 }
112
113 state->head = ctrl & 0x00000003;
114 nv50_pior_depth(pior, state, ctrl);
107} 115}
108 116
109static const struct nvkm_output_dp_func 117static const struct nvkm_ior_func
110nv50_pior_output_dp_func = { 118nv50_pior = {
111 .pattern = nv50_pior_output_dp_pattern, 119 .state = nv50_pior_state,
112 .lnk_pwr = nv50_pior_output_dp_lnk_pwr, 120 .power = nv50_pior_power,
113 .lnk_ctl = nv50_pior_output_dp_lnk_ctl, 121 .clock = nv50_pior_clock,
122 .dp = {
123 .links = nv50_pior_dp_links,
124 },
114}; 125};
115 126
116int 127int
117nv50_pior_dp_new(struct nvkm_disp *disp, int index, struct dcb_output *dcbE, 128nv50_pior_new(struct nvkm_disp *disp, int id)
118 struct nvkm_output **poutp)
119{ 129{
120 struct nvkm_i2c *i2c = disp->engine.subdev.device->i2c; 130 struct nvkm_device *device = disp->engine.subdev.device;
121 struct nvkm_i2c_aux *aux = 131 if (!(nvkm_rd32(device, 0x610184) & (0x10000000 << id)))
122 nvkm_i2c_aux_find(i2c, NVKM_I2C_AUX_EXT(dcbE->extdev)); 132 return 0;
123 struct nvkm_output_dp *outp; 133 return nvkm_ior_new_(&nv50_pior, disp, PIOR, id);
124
125 if (!(outp = kzalloc(sizeof(*outp), GFP_KERNEL)))
126 return -ENOMEM;
127 *poutp = &outp->base;
128
129 return nvkm_output_dp_ctor(&nv50_pior_output_dp_func, disp,
130 index, dcbE, aux, outp);
131} 134}
diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/priv.h b/drivers/gpu/drm/nouveau/nvkm/engine/disp/priv.h
index c2452957fc57..5772f0094129 100644
--- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/priv.h
+++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/priv.h
@@ -2,42 +2,18 @@
2#define __NVKM_DISP_PRIV_H__ 2#define __NVKM_DISP_PRIV_H__
3#include <engine/disp.h> 3#include <engine/disp.h>
4#include "outp.h" 4#include "outp.h"
5#include "outpdp.h"
6 5
7int nvkm_disp_ctor(const struct nvkm_disp_func *, struct nvkm_device *, 6int nvkm_disp_ctor(const struct nvkm_disp_func *, struct nvkm_device *,
8 int index, int heads, struct nvkm_disp *); 7 int index, struct nvkm_disp *);
9int nvkm_disp_new_(const struct nvkm_disp_func *, struct nvkm_device *, 8int nvkm_disp_new_(const struct nvkm_disp_func *, struct nvkm_device *,
10 int index, int heads, struct nvkm_disp **); 9 int index, struct nvkm_disp **);
11void nvkm_disp_vblank(struct nvkm_disp *, int head); 10void nvkm_disp_vblank(struct nvkm_disp *, int head);
12 11
13struct nvkm_disp_func_outp {
14 int (* crt)(struct nvkm_disp *, int index, struct dcb_output *,
15 struct nvkm_output **);
16 int (* tv)(struct nvkm_disp *, int index, struct dcb_output *,
17 struct nvkm_output **);
18 int (*tmds)(struct nvkm_disp *, int index, struct dcb_output *,
19 struct nvkm_output **);
20 int (*lvds)(struct nvkm_disp *, int index, struct dcb_output *,
21 struct nvkm_output **);
22 int (* dp)(struct nvkm_disp *, int index, struct dcb_output *,
23 struct nvkm_output **);
24};
25
26struct nvkm_disp_func { 12struct nvkm_disp_func {
27 void *(*dtor)(struct nvkm_disp *); 13 void *(*dtor)(struct nvkm_disp *);
28 void (*intr)(struct nvkm_disp *); 14 void (*intr)(struct nvkm_disp *);
29 15
30 const struct nvkm_disp_oclass *(*root)(struct nvkm_disp *); 16 const struct nvkm_disp_oclass *(*root)(struct nvkm_disp *);
31
32 struct {
33 void (*vblank_init)(struct nvkm_disp *, int head);
34 void (*vblank_fini)(struct nvkm_disp *, int head);
35 } head;
36
37 struct {
38 const struct nvkm_disp_func_outp internal;
39 const struct nvkm_disp_func_outp external;
40 } outp;
41}; 17};
42 18
43int nvkm_disp_ntfy(struct nvkm_object *, u32, struct nvkm_event **); 19int nvkm_disp_ntfy(struct nvkm_object *, u32, struct nvkm_event **);
diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/rootgf119.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/rootgf119.c
index 335d88823c22..333c8424b413 100644
--- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/rootgf119.c
+++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/rootgf119.c
@@ -22,49 +22,13 @@
22 * Authors: Ben Skeggs 22 * Authors: Ben Skeggs
23 */ 23 */
24#include "rootnv50.h" 24#include "rootnv50.h"
25#include "head.h"
25#include "dmacnv50.h" 26#include "dmacnv50.h"
26 27
27#include <core/client.h>
28#include <core/ramht.h> 28#include <core/ramht.h>
29#include <subdev/timer.h> 29#include <subdev/timer.h>
30 30
31#include <nvif/class.h> 31#include <nvif/class.h>
32#include <nvif/cl5070.h>
33#include <nvif/unpack.h>
34
35int
36gf119_disp_root_scanoutpos(NV50_DISP_MTHD_V0)
37{
38 struct nvkm_device *device = disp->base.engine.subdev.device;
39 const u32 total = nvkm_rd32(device, 0x640414 + (head * 0x300));
40 const u32 blanke = nvkm_rd32(device, 0x64041c + (head * 0x300));
41 const u32 blanks = nvkm_rd32(device, 0x640420 + (head * 0x300));
42 union {
43 struct nv50_disp_scanoutpos_v0 v0;
44 } *args = data;
45 int ret = -ENOSYS;
46
47 nvif_ioctl(object, "disp scanoutpos size %d\n", size);
48 if (!(ret = nvif_unpack(ret, &data, &size, args->v0, 0, 0, false))) {
49 nvif_ioctl(object, "disp scanoutpos vers %d\n",
50 args->v0.version);
51 args->v0.vblanke = (blanke & 0xffff0000) >> 16;
52 args->v0.hblanke = (blanke & 0x0000ffff);
53 args->v0.vblanks = (blanks & 0xffff0000) >> 16;
54 args->v0.hblanks = (blanks & 0x0000ffff);
55 args->v0.vtotal = ( total & 0xffff0000) >> 16;
56 args->v0.htotal = ( total & 0x0000ffff);
57 args->v0.time[0] = ktime_to_ns(ktime_get());
58 args->v0.vline = /* vline read locks hline */
59 nvkm_rd32(device, 0x616340 + (head * 0x800)) & 0xffff;
60 args->v0.time[1] = ktime_to_ns(ktime_get());
61 args->v0.hline =
62 nvkm_rd32(device, 0x616344 + (head * 0x800)) & 0xffff;
63 } else
64 return ret;
65
66 return 0;
67}
68 32
69void 33void
70gf119_disp_root_fini(struct nv50_disp_root *root) 34gf119_disp_root_fini(struct nv50_disp_root *root)
@@ -78,6 +42,7 @@ int
78gf119_disp_root_init(struct nv50_disp_root *root) 42gf119_disp_root_init(struct nv50_disp_root *root)
79{ 43{
80 struct nv50_disp *disp = root->disp; 44 struct nv50_disp *disp = root->disp;
45 struct nvkm_head *head;
81 struct nvkm_device *device = disp->base.engine.subdev.device; 46 struct nvkm_device *device = disp->base.engine.subdev.device;
82 u32 tmp; 47 u32 tmp;
83 int i; 48 int i;
@@ -88,13 +53,14 @@ gf119_disp_root_init(struct nv50_disp_root *root)
88 */ 53 */
89 54
90 /* ... CRTC caps */ 55 /* ... CRTC caps */
91 for (i = 0; i < disp->base.head.nr; i++) { 56 list_for_each_entry(head, &disp->base.head, head) {
92 tmp = nvkm_rd32(device, 0x616104 + (i * 0x800)); 57 const u32 hoff = head->id * 0x800;
93 nvkm_wr32(device, 0x6101b4 + (i * 0x800), tmp); 58 tmp = nvkm_rd32(device, 0x616104 + hoff);
94 tmp = nvkm_rd32(device, 0x616108 + (i * 0x800)); 59 nvkm_wr32(device, 0x6101b4 + hoff, tmp);
95 nvkm_wr32(device, 0x6101b8 + (i * 0x800), tmp); 60 tmp = nvkm_rd32(device, 0x616108 + hoff);
96 tmp = nvkm_rd32(device, 0x61610c + (i * 0x800)); 61 nvkm_wr32(device, 0x6101b8 + hoff, tmp);
97 nvkm_wr32(device, 0x6101bc + (i * 0x800), tmp); 62 tmp = nvkm_rd32(device, 0x61610c + hoff);
63 nvkm_wr32(device, 0x6101bc + hoff, tmp);
98 } 64 }
99 65
100 /* ... DAC caps */ 66 /* ... DAC caps */
@@ -134,8 +100,10 @@ gf119_disp_root_init(struct nv50_disp_root *root)
134 * 100 *
135 * ftp://download.nvidia.com/open-gpu-doc/gk104-disable-underflow-reporting/1/gk104-disable-underflow-reporting.txt 101 * ftp://download.nvidia.com/open-gpu-doc/gk104-disable-underflow-reporting/1/gk104-disable-underflow-reporting.txt
136 */ 102 */
137 for (i = 0; i < disp->base.head.nr; i++) 103 list_for_each_entry(head, &disp->base.head, head) {
138 nvkm_mask(device, 0x616308 + (i * 0x800), 0x00000111, 0x00000010); 104 const u32 hoff = head->id * 0x800;
105 nvkm_mask(device, 0x616308 + hoff, 0x00000111, 0x00000010);
106 }
139 107
140 return 0; 108 return 0;
141} 109}
diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/rootnv04.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/rootnv04.c
index f535f43231e2..7f3e2554a83d 100644
--- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/rootnv04.c
+++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/rootnv04.c
@@ -23,6 +23,7 @@
23 */ 23 */
24#define nv04_disp_root(p) container_of((p), struct nv04_disp_root, object) 24#define nv04_disp_root(p) container_of((p), struct nv04_disp_root, object)
25#include "priv.h" 25#include "priv.h"
26#include "head.h"
26 27
27#include <core/client.h> 28#include <core/client.h>
28 29
@@ -36,73 +37,30 @@ struct nv04_disp_root {
36}; 37};
37 38
38static int 39static int
39nv04_disp_scanoutpos(struct nv04_disp_root *root,
40 void *data, u32 size, int head)
41{
42 struct nvkm_device *device = root->disp->engine.subdev.device;
43 struct nvkm_object *object = &root->object;
44 const u32 hoff = head * 0x2000;
45 union {
46 struct nv04_disp_scanoutpos_v0 v0;
47 } *args = data;
48 u32 line;
49 int ret = -ENOSYS;
50
51 nvif_ioctl(object, "disp scanoutpos size %d\n", size);
52 if (!(ret = nvif_unpack(ret, &data, &size, args->v0, 0, 0, false))) {
53 nvif_ioctl(object, "disp scanoutpos vers %d\n",
54 args->v0.version);
55 args->v0.vblanks = nvkm_rd32(device, 0x680800 + hoff) & 0xffff;
56 args->v0.vtotal = nvkm_rd32(device, 0x680804 + hoff) & 0xffff;
57 args->v0.vblanke = args->v0.vtotal - 1;
58
59 args->v0.hblanks = nvkm_rd32(device, 0x680820 + hoff) & 0xffff;
60 args->v0.htotal = nvkm_rd32(device, 0x680824 + hoff) & 0xffff;
61 args->v0.hblanke = args->v0.htotal - 1;
62
63 /*
64 * If output is vga instead of digital then vtotal/htotal is
65 * invalid so we have to give up and trigger the timestamping
66 * fallback in the drm core.
67 */
68 if (!args->v0.vtotal || !args->v0.htotal)
69 return -ENOTSUPP;
70
71 args->v0.time[0] = ktime_to_ns(ktime_get());
72 line = nvkm_rd32(device, 0x600868 + hoff);
73 args->v0.time[1] = ktime_to_ns(ktime_get());
74 args->v0.hline = (line & 0xffff0000) >> 16;
75 args->v0.vline = (line & 0x0000ffff);
76 } else
77 return ret;
78
79 return 0;
80}
81
82static int
83nv04_disp_mthd(struct nvkm_object *object, u32 mthd, void *data, u32 size) 40nv04_disp_mthd(struct nvkm_object *object, u32 mthd, void *data, u32 size)
84{ 41{
85 struct nv04_disp_root *root = nv04_disp_root(object); 42 struct nv04_disp_root *root = nv04_disp_root(object);
86 union { 43 union {
87 struct nv04_disp_mthd_v0 v0; 44 struct nv04_disp_mthd_v0 v0;
88 } *args = data; 45 } *args = data;
89 int head, ret = -ENOSYS; 46 struct nvkm_head *head;
47 int id, ret = -ENOSYS;
90 48
91 nvif_ioctl(object, "disp mthd size %d\n", size); 49 nvif_ioctl(object, "disp mthd size %d\n", size);
92 if (!(ret = nvif_unpack(ret, &data, &size, args->v0, 0, 0, true))) { 50 if (!(ret = nvif_unpack(ret, &data, &size, args->v0, 0, 0, true))) {
93 nvif_ioctl(object, "disp mthd vers %d mthd %02x head %d\n", 51 nvif_ioctl(object, "disp mthd vers %d mthd %02x head %d\n",
94 args->v0.version, args->v0.method, args->v0.head); 52 args->v0.version, args->v0.method, args->v0.head);
95 mthd = args->v0.method; 53 mthd = args->v0.method;
96 head = args->v0.head; 54 id = args->v0.head;
97 } else 55 } else
98 return ret; 56 return ret;
99 57
100 if (head < 0 || head >= 2) 58 if (!(head = nvkm_head_find(root->disp, id)))
101 return -ENXIO; 59 return -ENXIO;
102 60
103 switch (mthd) { 61 switch (mthd) {
104 case NV04_DISP_SCANOUTPOS: 62 case NV04_DISP_SCANOUTPOS:
105 return nv04_disp_scanoutpos(root, data, size, head); 63 return nvkm_head_mthd_scanoutpos(object, head, data, size);
106 default: 64 default:
107 break; 65 break;
108 } 66 }
diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/rootnv50.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/rootnv50.c
index e70dc6a9ff7d..1208524aae14 100644
--- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/rootnv50.c
+++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/rootnv50.c
@@ -23,6 +23,9 @@
23 */ 23 */
24#include "rootnv50.h" 24#include "rootnv50.h"
25#include "dmacnv50.h" 25#include "dmacnv50.h"
26#include "dp.h"
27#include "head.h"
28#include "ior.h"
26 29
27#include <core/client.h> 30#include <core/client.h>
28#include <core/ramht.h> 31#include <core/ramht.h>
@@ -32,40 +35,6 @@
32#include <nvif/cl5070.h> 35#include <nvif/cl5070.h>
33#include <nvif/unpack.h> 36#include <nvif/unpack.h>
34 37
35int
36nv50_disp_root_scanoutpos(NV50_DISP_MTHD_V0)
37{
38 struct nvkm_device *device = disp->base.engine.subdev.device;
39 const u32 blanke = nvkm_rd32(device, 0x610aec + (head * 0x540));
40 const u32 blanks = nvkm_rd32(device, 0x610af4 + (head * 0x540));
41 const u32 total = nvkm_rd32(device, 0x610afc + (head * 0x540));
42 union {
43 struct nv50_disp_scanoutpos_v0 v0;
44 } *args = data;
45 int ret = -ENOSYS;
46
47 nvif_ioctl(object, "disp scanoutpos size %d\n", size);
48 if (!(ret = nvif_unpack(ret, &data, &size, args->v0, 0, 0, false))) {
49 nvif_ioctl(object, "disp scanoutpos vers %d\n",
50 args->v0.version);
51 args->v0.vblanke = (blanke & 0xffff0000) >> 16;
52 args->v0.hblanke = (blanke & 0x0000ffff);
53 args->v0.vblanks = (blanks & 0xffff0000) >> 16;
54 args->v0.hblanks = (blanks & 0x0000ffff);
55 args->v0.vtotal = ( total & 0xffff0000) >> 16;
56 args->v0.htotal = ( total & 0x0000ffff);
57 args->v0.time[0] = ktime_to_ns(ktime_get());
58 args->v0.vline = /* vline read locks hline */
59 nvkm_rd32(device, 0x616340 + (head * 0x800)) & 0xffff;
60 args->v0.time[1] = ktime_to_ns(ktime_get());
61 args->v0.hline =
62 nvkm_rd32(device, 0x616344 + (head * 0x800)) & 0xffff;
63 } else
64 return ret;
65
66 return 0;
67}
68
69static int 38static int
70nv50_disp_root_mthd_(struct nvkm_object *object, u32 mthd, void *data, u32 size) 39nv50_disp_root_mthd_(struct nvkm_object *object, u32 mthd, void *data, u32 size)
71{ 40{
@@ -75,11 +44,10 @@ nv50_disp_root_mthd_(struct nvkm_object *object, u32 mthd, void *data, u32 size)
75 } *args = data; 44 } *args = data;
76 struct nv50_disp_root *root = nv50_disp_root(object); 45 struct nv50_disp_root *root = nv50_disp_root(object);
77 struct nv50_disp *disp = root->disp; 46 struct nv50_disp *disp = root->disp;
78 const struct nv50_disp_func *func = disp->func; 47 struct nvkm_outp *temp, *outp = NULL;
79 struct nvkm_output *outp = NULL; 48 struct nvkm_head *head;
80 struct nvkm_output *temp;
81 u16 type, mask = 0; 49 u16 type, mask = 0;
82 int head, ret = -ENOSYS; 50 int hidx, ret = -ENOSYS;
83 51
84 if (mthd != NV50_DISP_MTHD) 52 if (mthd != NV50_DISP_MTHD)
85 return -EINVAL; 53 return -EINVAL;
@@ -89,7 +57,7 @@ nv50_disp_root_mthd_(struct nvkm_object *object, u32 mthd, void *data, u32 size)
89 nvif_ioctl(object, "disp mthd vers %d mthd %02x head %d\n", 57 nvif_ioctl(object, "disp mthd vers %d mthd %02x head %d\n",
90 args->v0.version, args->v0.method, args->v0.head); 58 args->v0.version, args->v0.method, args->v0.head);
91 mthd = args->v0.method; 59 mthd = args->v0.method;
92 head = args->v0.head; 60 hidx = args->v0.head;
93 } else 61 } else
94 if (!(ret = nvif_unpack(ret, &data, &size, args->v1, 1, 1, true))) { 62 if (!(ret = nvif_unpack(ret, &data, &size, args->v1, 1, 1, true))) {
95 nvif_ioctl(object, "disp mthd vers %d mthd %02x " 63 nvif_ioctl(object, "disp mthd vers %d mthd %02x "
@@ -99,11 +67,11 @@ nv50_disp_root_mthd_(struct nvkm_object *object, u32 mthd, void *data, u32 size)
99 mthd = args->v1.method; 67 mthd = args->v1.method;
100 type = args->v1.hasht; 68 type = args->v1.hasht;
101 mask = args->v1.hashm; 69 mask = args->v1.hashm;
102 head = ffs((mask >> 8) & 0x0f) - 1; 70 hidx = ffs((mask >> 8) & 0x0f) - 1;
103 } else 71 } else
104 return ret; 72 return ret;
105 73
106 if (head < 0 || head >= disp->base.head.nr) 74 if (!(head = nvkm_head_find(&disp->base, hidx)))
107 return -ENXIO; 75 return -ENXIO;
108 76
109 if (mask) { 77 if (mask) {
@@ -119,27 +87,126 @@ nv50_disp_root_mthd_(struct nvkm_object *object, u32 mthd, void *data, u32 size)
119 } 87 }
120 88
121 switch (mthd) { 89 switch (mthd) {
122 case NV50_DISP_SCANOUTPOS: 90 case NV50_DISP_SCANOUTPOS: {
123 return func->head.scanoutpos(object, disp, data, size, head); 91 return nvkm_head_mthd_scanoutpos(object, head, data, size);
92 }
124 default: 93 default:
125 break; 94 break;
126 } 95 }
127 96
128 switch (mthd * !!outp) { 97 switch (mthd * !!outp) {
129 case NV50_DISP_MTHD_V1_DAC_PWR: 98 case NV50_DISP_MTHD_V1_ACQUIRE: {
130 return func->dac.power(object, disp, data, size, head, outp); 99 union {
131 case NV50_DISP_MTHD_V1_DAC_LOAD: 100 struct nv50_disp_acquire_v0 v0;
132 return func->dac.sense(object, disp, data, size, head, outp); 101 } *args = data;
133 case NV50_DISP_MTHD_V1_SOR_PWR: 102 int ret = -ENOSYS;
134 return func->sor.power(object, disp, data, size, head, outp); 103 if (!(ret = nvif_unpack(ret, &data, &size, args->v0, 0, 0, false))) {
135 case NV50_DISP_MTHD_V1_SOR_HDA_ELD: 104 ret = nvkm_outp_acquire(outp, NVKM_OUTP_USER);
136 if (!func->sor.hda_eld) 105 if (ret == 0) {
106 args->v0.or = outp->ior->id;
107 args->v0.link = outp->ior->asy.link;
108 }
109 }
110 return ret;
111 }
112 break;
113 case NV50_DISP_MTHD_V1_RELEASE:
114 nvkm_outp_release(outp, NVKM_OUTP_USER);
115 return 0;
116 case NV50_DISP_MTHD_V1_DAC_LOAD: {
117 union {
118 struct nv50_disp_dac_load_v0 v0;
119 } *args = data;
120 int ret = -ENOSYS;
121 if (!(ret = nvif_unpack(ret, &data, &size, args->v0, 0, 0, false))) {
122 if (args->v0.data & 0xfff00000)
123 return -EINVAL;
124 ret = nvkm_outp_acquire(outp, NVKM_OUTP_PRIV);
125 if (ret)
126 return ret;
127 ret = outp->ior->func->sense(outp->ior, args->v0.data);
128 nvkm_outp_release(outp, NVKM_OUTP_PRIV);
129 if (ret < 0)
130 return ret;
131 args->v0.load = ret;
132 return 0;
133 } else
134 return ret;
135 }
136 break;
137 case NV50_DISP_MTHD_V1_SOR_HDA_ELD: {
138 union {
139 struct nv50_disp_sor_hda_eld_v0 v0;
140 } *args = data;
141 struct nvkm_ior *ior = outp->ior;
142 int ret = -ENOSYS;
143
144 nvif_ioctl(object, "disp sor hda eld size %d\n", size);
145 if (!(ret = nvif_unpack(ret, &data, &size, args->v0, 0, 0, true))) {
146 nvif_ioctl(object, "disp sor hda eld vers %d\n",
147 args->v0.version);
148 if (size > 0x60)
149 return -E2BIG;
150 } else
151 return ret;
152
153 if (!ior->func->hda.hpd)
137 return -ENODEV; 154 return -ENODEV;
138 return func->sor.hda_eld(object, disp, data, size, head, outp); 155
139 case NV50_DISP_MTHD_V1_SOR_HDMI_PWR: 156 if (size && args->v0.data[0]) {
140 if (!func->sor.hdmi) 157 if (outp->info.type == DCB_OUTPUT_DP)
158 ior->func->dp.audio(ior, hidx, true);
159 ior->func->hda.hpd(ior, hidx, true);
160 ior->func->hda.eld(ior, data, size);
161 } else {
162 if (outp->info.type == DCB_OUTPUT_DP)
163 ior->func->dp.audio(ior, hidx, false);
164 ior->func->hda.hpd(ior, hidx, false);
165 }
166
167 return 0;
168 }
169 break;
170 case NV50_DISP_MTHD_V1_SOR_HDMI_PWR: {
171 union {
172 struct nv50_disp_sor_hdmi_pwr_v0 v0;
173 } *args = data;
174 u8 *vendor, vendor_size;
175 u8 *avi, avi_size;
176 int ret = -ENOSYS;
177
178 nvif_ioctl(object, "disp sor hdmi ctrl size %d\n", size);
179 if (!(ret = nvif_unpack(ret, &data, &size, args->v0, 0, 0, true))) {
180 nvif_ioctl(object, "disp sor hdmi ctrl vers %d state %d "
181 "max_ac_packet %d rekey %d\n",
182 args->v0.version, args->v0.state,
183 args->v0.max_ac_packet, args->v0.rekey);
184 if (args->v0.max_ac_packet > 0x1f || args->v0.rekey > 0x7f)
185 return -EINVAL;
186 if ((args->v0.avi_infoframe_length
187 + args->v0.vendor_infoframe_length) > size)
188 return -EINVAL;
189 else
190 if ((args->v0.avi_infoframe_length
191 + args->v0.vendor_infoframe_length) < size)
192 return -E2BIG;
193 avi = data;
194 avi_size = args->v0.avi_infoframe_length;
195 vendor = avi + avi_size;
196 vendor_size = args->v0.vendor_infoframe_length;
197 } else
198 return ret;
199
200 if (!outp->ior->func->hdmi.ctrl)
141 return -ENODEV; 201 return -ENODEV;
142 return func->sor.hdmi(object, disp, data, size, head, outp); 202
203 outp->ior->func->hdmi.ctrl(outp->ior, hidx, args->v0.state,
204 args->v0.max_ac_packet,
205 args->v0.rekey, avi, avi_size,
206 vendor, vendor_size);
207 return 0;
208 }
209 break;
143 case NV50_DISP_MTHD_V1_SOR_LVDS_SCRIPT: { 210 case NV50_DISP_MTHD_V1_SOR_LVDS_SCRIPT: {
144 union { 211 union {
145 struct nv50_disp_sor_lvds_script_v0 v0; 212 struct nv50_disp_sor_lvds_script_v0 v0;
@@ -156,32 +223,8 @@ nv50_disp_root_mthd_(struct nvkm_object *object, u32 mthd, void *data, u32 size)
156 return ret; 223 return ret;
157 } 224 }
158 break; 225 break;
159 case NV50_DISP_MTHD_V1_SOR_DP_PWR: {
160 struct nvkm_output_dp *outpdp = nvkm_output_dp(outp);
161 union {
162 struct nv50_disp_sor_dp_pwr_v0 v0;
163 } *args = data;
164 int ret = -ENOSYS;
165 nvif_ioctl(object, "disp sor dp pwr size %d\n", size);
166 if (!(ret = nvif_unpack(ret, &data, &size, args->v0, 0, 0, false))) {
167 nvif_ioctl(object, "disp sor dp pwr vers %d state %d\n",
168 args->v0.version, args->v0.state);
169 if (args->v0.state == 0) {
170 nvkm_notify_put(&outpdp->irq);
171 outpdp->func->lnk_pwr(outpdp, 0);
172 atomic_set(&outpdp->lt.done, 0);
173 return 0;
174 } else
175 if (args->v0.state != 0) {
176 nvkm_output_dp_train(&outpdp->base, 0);
177 return 0;
178 }
179 } else
180 return ret;
181 }
182 break;
183 case NV50_DISP_MTHD_V1_SOR_DP_MST_LINK: { 226 case NV50_DISP_MTHD_V1_SOR_DP_MST_LINK: {
184 struct nvkm_output_dp *outpdp = nvkm_output_dp(outp); 227 struct nvkm_dp *dp = nvkm_dp(outp);
185 union { 228 union {
186 struct nv50_disp_sor_dp_mst_link_v0 v0; 229 struct nv50_disp_sor_dp_mst_link_v0 v0;
187 } *args = data; 230 } *args = data;
@@ -190,18 +233,13 @@ nv50_disp_root_mthd_(struct nvkm_object *object, u32 mthd, void *data, u32 size)
190 if (!(ret = nvif_unpack(ret, &data, &size, args->v0, 0, 0, false))) { 233 if (!(ret = nvif_unpack(ret, &data, &size, args->v0, 0, 0, false))) {
191 nvif_ioctl(object, "disp sor dp mst link vers %d state %d\n", 234 nvif_ioctl(object, "disp sor dp mst link vers %d state %d\n",
192 args->v0.version, args->v0.state); 235 args->v0.version, args->v0.state);
193 if (outpdp->lt.mst != !!args->v0.state) { 236 dp->lt.mst = !!args->v0.state;
194 outpdp->lt.mst = !!args->v0.state;
195 atomic_set(&outpdp->lt.done, 0);
196 nvkm_output_dp_train(&outpdp->base, 0);
197 }
198 return 0; 237 return 0;
199 } else 238 } else
200 return ret; 239 return ret;
201 } 240 }
202 break; 241 break;
203 case NV50_DISP_MTHD_V1_SOR_DP_MST_VCPI: { 242 case NV50_DISP_MTHD_V1_SOR_DP_MST_VCPI: {
204 struct nvkm_output_dp *outpdp = nvkm_output_dp(outp);
205 union { 243 union {
206 struct nv50_disp_sor_dp_mst_vcpi_v0 v0; 244 struct nv50_disp_sor_dp_mst_vcpi_v0 v0;
207 } *args = data; 245 } *args = data;
@@ -213,20 +251,18 @@ nv50_disp_root_mthd_(struct nvkm_object *object, u32 mthd, void *data, u32 size)
213 args->v0.version, args->v0.start_slot, 251 args->v0.version, args->v0.start_slot,
214 args->v0.num_slots, args->v0.pbn, 252 args->v0.num_slots, args->v0.pbn,
215 args->v0.aligned_pbn); 253 args->v0.aligned_pbn);
216 if (!outpdp->func->vcpi) 254 if (!outp->ior->func->dp.vcpi)
217 return -ENODEV; 255 return -ENODEV;
218 outpdp->func->vcpi(outpdp, head, args->v0.start_slot, 256 outp->ior->func->dp.vcpi(outp->ior, hidx,
219 args->v0.num_slots, args->v0.pbn, 257 args->v0.start_slot,
220 args->v0.aligned_pbn); 258 args->v0.num_slots,
259 args->v0.pbn,
260 args->v0.aligned_pbn);
221 return 0; 261 return 0;
222 } else 262 } else
223 return ret; 263 return ret;
224 } 264 }
225 break; 265 break;
226 case NV50_DISP_MTHD_V1_PIOR_PWR:
227 if (!func->pior.power)
228 return -ENODEV;
229 return func->pior.power(object, disp, data, size, head, outp);
230 default: 266 default:
231 break; 267 break;
232 } 268 }
@@ -291,7 +327,21 @@ static int
291nv50_disp_root_init_(struct nvkm_object *object) 327nv50_disp_root_init_(struct nvkm_object *object)
292{ 328{
293 struct nv50_disp_root *root = nv50_disp_root(object); 329 struct nv50_disp_root *root = nv50_disp_root(object);
294 return root->func->init(root); 330 struct nvkm_ior *ior;
331 int ret;
332
333 ret = root->func->init(root);
334 if (ret)
335 return ret;
336
337 /* Set 'normal' (ie. when it's attached to a head) state for
338 * each output resource to 'fully enabled'.
339 */
340 list_for_each_entry(ior, &root->disp->base.ior, head) {
341 ior->func->power(ior, true, true, true, true, true);
342 }
343
344 return 0;
295} 345}
296 346
297static void * 347static void *
@@ -352,6 +402,7 @@ int
352nv50_disp_root_init(struct nv50_disp_root *root) 402nv50_disp_root_init(struct nv50_disp_root *root)
353{ 403{
354 struct nv50_disp *disp = root->disp; 404 struct nv50_disp *disp = root->disp;
405 struct nvkm_head *head;
355 struct nvkm_device *device = disp->base.engine.subdev.device; 406 struct nvkm_device *device = disp->base.engine.subdev.device;
356 u32 tmp; 407 u32 tmp;
357 int i; 408 int i;
@@ -364,15 +415,15 @@ nv50_disp_root_init(struct nv50_disp_root *root)
364 nvkm_wr32(device, 0x610184, tmp); 415 nvkm_wr32(device, 0x610184, tmp);
365 416
366 /* ... CRTC caps */ 417 /* ... CRTC caps */
367 for (i = 0; i < disp->base.head.nr; i++) { 418 list_for_each_entry(head, &disp->base.head, head) {
368 tmp = nvkm_rd32(device, 0x616100 + (i * 0x800)); 419 tmp = nvkm_rd32(device, 0x616100 + (head->id * 0x800));
369 nvkm_wr32(device, 0x610190 + (i * 0x10), tmp); 420 nvkm_wr32(device, 0x610190 + (head->id * 0x10), tmp);
370 tmp = nvkm_rd32(device, 0x616104 + (i * 0x800)); 421 tmp = nvkm_rd32(device, 0x616104 + (head->id * 0x800));
371 nvkm_wr32(device, 0x610194 + (i * 0x10), tmp); 422 nvkm_wr32(device, 0x610194 + (head->id * 0x10), tmp);
372 tmp = nvkm_rd32(device, 0x616108 + (i * 0x800)); 423 tmp = nvkm_rd32(device, 0x616108 + (head->id * 0x800));
373 nvkm_wr32(device, 0x610198 + (i * 0x10), tmp); 424 nvkm_wr32(device, 0x610198 + (head->id * 0x10), tmp);
374 tmp = nvkm_rd32(device, 0x61610c + (i * 0x800)); 425 tmp = nvkm_rd32(device, 0x61610c + (head->id * 0x800));
375 nvkm_wr32(device, 0x61019c + (i * 0x10), tmp); 426 nvkm_wr32(device, 0x61019c + (head->id * 0x10), tmp);
376 } 427 }
377 428
378 /* ... DAC caps */ 429 /* ... DAC caps */
diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/sorg84.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/sorg84.c
new file mode 100644
index 000000000000..f40b909b4ca2
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/sorg84.c
@@ -0,0 +1,38 @@
1/*
2 * Copyright 2017 Red Hat Inc.
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#include "ior.h"
23
24static const struct nvkm_ior_func
25g84_sor = {
26 .state = nv50_sor_state,
27 .power = nv50_sor_power,
28 .clock = nv50_sor_clock,
29 .hdmi = {
30 .ctrl = g84_hdmi_ctrl,
31 },
32};
33
34int
35g84_sor_new(struct nvkm_disp *disp, int id)
36{
37 return nv50_sor_new_(&g84_sor, disp, id);
38}
diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/sorg94.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/sorg94.c
index 627b9ee1ddd2..49aeafde0031 100644
--- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/sorg94.c
+++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/sorg94.c
@@ -21,58 +21,75 @@
21 * 21 *
22 * Authors: Ben Skeggs 22 * Authors: Ben Skeggs
23 */ 23 */
24#include "nv50.h" 24#include "ior.h"
25#include "outpdp.h"
26 25
27#include <subdev/timer.h> 26#include <subdev/timer.h>
28 27
29static inline u32 28void
30g94_sor_soff(struct nvkm_output_dp *outp) 29g94_sor_dp_watermark(struct nvkm_ior *sor, int head, u8 watermark)
31{ 30{
32 return (ffs(outp->base.info.or) - 1) * 0x800; 31 struct nvkm_device *device = sor->disp->engine.subdev.device;
32 const u32 loff = nv50_sor_link(sor);
33 nvkm_mask(device, 0x61c128 + loff, 0x0000003f, watermark);
33} 34}
34 35
35static inline u32 36void
36g94_sor_loff(struct nvkm_output_dp *outp) 37g94_sor_dp_activesym(struct nvkm_ior *sor, int head,
38 u8 TU, u8 VTUa, u8 VTUf, u8 VTUi)
37{ 39{
38 return g94_sor_soff(outp) + !(outp->base.info.sorconf.link & 1) * 0x80; 40 struct nvkm_device *device = sor->disp->engine.subdev.device;
41 const u32 loff = nv50_sor_link(sor);
42 nvkm_mask(device, 0x61c10c + loff, 0x000001fc, TU << 2);
43 nvkm_mask(device, 0x61c128 + loff, 0x010f7f00, VTUa << 24 |
44 VTUf << 16 |
45 VTUi << 8);
39} 46}
40 47
41/******************************************************************************* 48void
42 * DisplayPort 49g94_sor_dp_audio_sym(struct nvkm_ior *sor, int head, u16 h, u32 v)
43 ******************************************************************************/
44u32
45g94_sor_dp_lane_map(struct nvkm_device *device, u8 lane)
46{ 50{
47 static const u8 gm100[] = { 0, 8, 16, 24 }; 51 struct nvkm_device *device = sor->disp->engine.subdev.device;
48 static const u8 mcp89[] = { 24, 16, 8, 0 }; /* thanks, apple.. */ 52 const u32 soff = nv50_ior_base(sor);
49 static const u8 g94[] = { 16, 8, 0, 24 }; 53 nvkm_mask(device, 0x61c1e8 + soff, 0x0000ffff, h);
50 if (device->chipset >= 0x110) 54 nvkm_mask(device, 0x61c1ec + soff, 0x00ffffff, v);
51 return gm100[lane];
52 if (device->chipset == 0xaf)
53 return mcp89[lane];
54 return g94[lane];
55} 55}
56 56
57static int 57void
58g94_sor_dp_pattern(struct nvkm_output_dp *outp, int pattern) 58g94_sor_dp_drive(struct nvkm_ior *sor, int ln, int pc, int dc, int pe, int pu)
59{ 59{
60 struct nvkm_device *device = outp->base.disp->engine.subdev.device; 60 struct nvkm_device *device = sor->disp->engine.subdev.device;
61 const u32 loff = g94_sor_loff(outp); 61 const u32 loff = nv50_sor_link(sor);
62 const u32 shift = sor->func->dp.lanes[ln] * 8;
63 u32 data[3];
64
65 data[0] = nvkm_rd32(device, 0x61c118 + loff) & ~(0x000000ff << shift);
66 data[1] = nvkm_rd32(device, 0x61c120 + loff) & ~(0x000000ff << shift);
67 data[2] = nvkm_rd32(device, 0x61c130 + loff);
68 if ((data[2] & 0x0000ff00) < (pu << 8) || ln == 0)
69 data[2] = (data[2] & ~0x0000ff00) | (pu << 8);
70 nvkm_wr32(device, 0x61c118 + loff, data[0] | (dc << shift));
71 nvkm_wr32(device, 0x61c120 + loff, data[1] | (pe << shift));
72 nvkm_wr32(device, 0x61c130 + loff, data[2]);
73}
74
75void
76g94_sor_dp_pattern(struct nvkm_ior *sor, int pattern)
77{
78 struct nvkm_device *device = sor->disp->engine.subdev.device;
79 const u32 loff = nv50_sor_link(sor);
62 nvkm_mask(device, 0x61c10c + loff, 0x0f000000, pattern << 24); 80 nvkm_mask(device, 0x61c10c + loff, 0x0f000000, pattern << 24);
63 return 0;
64} 81}
65 82
66int 83void
67g94_sor_dp_lnk_pwr(struct nvkm_output_dp *outp, int nr) 84g94_sor_dp_power(struct nvkm_ior *sor, int nr)
68{ 85{
69 struct nvkm_device *device = outp->base.disp->engine.subdev.device; 86 struct nvkm_device *device = sor->disp->engine.subdev.device;
70 const u32 soff = g94_sor_soff(outp); 87 const u32 soff = nv50_ior_base(sor);
71 const u32 loff = g94_sor_loff(outp); 88 const u32 loff = nv50_sor_link(sor);
72 u32 mask = 0, i; 89 u32 mask = 0, i;
73 90
74 for (i = 0; i < nr; i++) 91 for (i = 0; i < nr; i++)
75 mask |= 1 << (g94_sor_dp_lane_map(device, i) >> 3); 92 mask |= 1 << sor->func->dp.lanes[i];
76 93
77 nvkm_mask(device, 0x61c130 + loff, 0x0000000f, mask); 94 nvkm_mask(device, 0x61c130 + loff, 0x0000000f, mask);
78 nvkm_mask(device, 0x61c034 + soff, 0x80000000, 0x80000000); 95 nvkm_mask(device, 0x61c034 + soff, 0x80000000, 0x80000000);
@@ -80,22 +97,21 @@ g94_sor_dp_lnk_pwr(struct nvkm_output_dp *outp, int nr)
80 if (!(nvkm_rd32(device, 0x61c034 + soff) & 0x80000000)) 97 if (!(nvkm_rd32(device, 0x61c034 + soff) & 0x80000000))
81 break; 98 break;
82 ); 99 );
83 return 0;
84} 100}
85 101
86static int 102int
87g94_sor_dp_lnk_ctl(struct nvkm_output_dp *outp, int nr, int bw, bool ef) 103g94_sor_dp_links(struct nvkm_ior *sor, struct nvkm_i2c_aux *aux)
88{ 104{
89 struct nvkm_device *device = outp->base.disp->engine.subdev.device; 105 struct nvkm_device *device = sor->disp->engine.subdev.device;
90 const u32 soff = g94_sor_soff(outp); 106 const u32 soff = nv50_ior_base(sor);
91 const u32 loff = g94_sor_loff(outp); 107 const u32 loff = nv50_sor_link(sor);
92 u32 dpctrl = 0x00000000; 108 u32 dpctrl = 0x00000000;
93 u32 clksor = 0x00000000; 109 u32 clksor = 0x00000000;
94 110
95 dpctrl |= ((1 << nr) - 1) << 16; 111 dpctrl |= ((1 << sor->dp.nr) - 1) << 16;
96 if (ef) 112 if (sor->dp.ef)
97 dpctrl |= 0x00004000; 113 dpctrl |= 0x00004000;
98 if (bw > 0x06) 114 if (sor->dp.bw > 0x06)
99 clksor |= 0x00040000; 115 clksor |= 0x00040000;
100 116
101 nvkm_mask(device, 0x614300 + soff, 0x000c0000, clksor); 117 nvkm_mask(device, 0x614300 + soff, 0x000c0000, clksor);
@@ -103,51 +119,165 @@ g94_sor_dp_lnk_ctl(struct nvkm_output_dp *outp, int nr, int bw, bool ef)
103 return 0; 119 return 0;
104} 120}
105 121
106static int 122static bool
107g94_sor_dp_drv_ctl(struct nvkm_output_dp *outp, int ln, int vs, int pe, int pc) 123g94_sor_war_needed(struct nvkm_ior *sor)
108{ 124{
109 struct nvkm_device *device = outp->base.disp->engine.subdev.device; 125 struct nvkm_device *device = sor->disp->engine.subdev.device;
110 struct nvkm_bios *bios = device->bios; 126 const u32 soff = nv50_ior_base(sor);
111 const u32 shift = g94_sor_dp_lane_map(device, ln); 127 if (sor->asy.proto == TMDS) {
112 const u32 loff = g94_sor_loff(outp); 128 switch (nvkm_rd32(device, 0x614300 + soff) & 0x00030000) {
113 u32 addr, data[3]; 129 case 0x00000000:
114 u8 ver, hdr, cnt, len; 130 case 0x00030000:
115 struct nvbios_dpout info; 131 return true;
116 struct nvbios_dpcfg ocfg; 132 default:
117 133 break;
118 addr = nvbios_dpout_match(bios, outp->base.info.hasht, 134 }
119 outp->base.info.hashm, 135 }
120 &ver, &hdr, &cnt, &len, &info); 136 return false;
121 if (!addr) 137}
122 return -ENODEV;
123
124 addr = nvbios_dpcfg_match(bios, addr, 0, vs, pe,
125 &ver, &hdr, &cnt, &len, &ocfg);
126 if (!addr)
127 return -EINVAL;
128 138
129 data[0] = nvkm_rd32(device, 0x61c118 + loff) & ~(0x000000ff << shift); 139static void
130 data[1] = nvkm_rd32(device, 0x61c120 + loff) & ~(0x000000ff << shift); 140g94_sor_war_update_sppll1(struct nvkm_disp *disp)
131 data[2] = nvkm_rd32(device, 0x61c130 + loff); 141{
132 if ((data[2] & 0x0000ff00) < (ocfg.tx_pu << 8) || ln == 0) 142 struct nvkm_device *device = disp->engine.subdev.device;
133 data[2] = (data[2] & ~0x0000ff00) | (ocfg.tx_pu << 8); 143 struct nvkm_ior *ior;
134 nvkm_wr32(device, 0x61c118 + loff, data[0] | (ocfg.dc << shift)); 144 bool used = false;
135 nvkm_wr32(device, 0x61c120 + loff, data[1] | (ocfg.pe << shift)); 145 u32 clksor;
136 nvkm_wr32(device, 0x61c130 + loff, data[2]); 146
137 return 0; 147 list_for_each_entry(ior, &disp->ior, head) {
148 if (ior->type != SOR)
149 continue;
150
151 clksor = nvkm_rd32(device, 0x614300 + nv50_ior_base(ior));
152 switch (clksor & 0x03000000) {
153 case 0x02000000:
154 case 0x03000000:
155 used = true;
156 break;
157 default:
158 break;
159 }
160 }
161
162 if (used)
163 return;
164
165 nvkm_mask(device, 0x00e840, 0x80000000, 0x00000000);
166}
167
168static void
169g94_sor_war_3(struct nvkm_ior *sor)
170{
171 struct nvkm_device *device = sor->disp->engine.subdev.device;
172 const u32 soff = nv50_ior_base(sor);
173 u32 sorpwr;
174
175 if (!g94_sor_war_needed(sor))
176 return;
177
178 sorpwr = nvkm_rd32(device, 0x61c004 + soff);
179 if (sorpwr & 0x00000001) {
180 u32 seqctl = nvkm_rd32(device, 0x61c030 + soff);
181 u32 pd_pc = (seqctl & 0x00000f00) >> 8;
182 u32 pu_pc = seqctl & 0x0000000f;
183
184 nvkm_wr32(device, 0x61c040 + soff + pd_pc * 4, 0x1f008000);
185
186 nvkm_msec(device, 2000,
187 if (!(nvkm_rd32(device, 0x61c030 + soff) & 0x10000000))
188 break;
189 );
190 nvkm_mask(device, 0x61c004 + soff, 0x80000001, 0x80000000);
191 nvkm_msec(device, 2000,
192 if (!(nvkm_rd32(device, 0x61c030 + soff) & 0x10000000))
193 break;
194 );
195
196 nvkm_wr32(device, 0x61c040 + soff + pd_pc * 4, 0x00002000);
197 nvkm_wr32(device, 0x61c040 + soff + pu_pc * 4, 0x1f000000);
198 }
199
200 nvkm_mask(device, 0x61c10c + soff, 0x00000001, 0x00000000);
201 nvkm_mask(device, 0x614300 + soff, 0x03000000, 0x00000000);
202
203 if (sorpwr & 0x00000001) {
204 nvkm_mask(device, 0x61c004 + soff, 0x80000001, 0x80000001);
205 }
206
207 g94_sor_war_update_sppll1(sor->disp);
208}
209
210static void
211g94_sor_war_2(struct nvkm_ior *sor)
212{
213 struct nvkm_device *device = sor->disp->engine.subdev.device;
214 const u32 soff = nv50_ior_base(sor);
215
216 if (!g94_sor_war_needed(sor))
217 return;
218
219 nvkm_mask(device, 0x00e840, 0x80000000, 0x80000000);
220 nvkm_mask(device, 0x614300 + soff, 0x03000000, 0x03000000);
221 nvkm_mask(device, 0x61c10c + soff, 0x00000001, 0x00000001);
222
223 nvkm_mask(device, 0x61c00c + soff, 0x0f000000, 0x00000000);
224 nvkm_mask(device, 0x61c008 + soff, 0xff000000, 0x14000000);
225 nvkm_usec(device, 400, NVKM_DELAY);
226 nvkm_mask(device, 0x61c008 + soff, 0xff000000, 0x00000000);
227 nvkm_mask(device, 0x61c00c + soff, 0x0f000000, 0x01000000);
228
229 if (nvkm_rd32(device, 0x61c004 + soff) & 0x00000001) {
230 u32 seqctl = nvkm_rd32(device, 0x61c030 + soff);
231 u32 pu_pc = seqctl & 0x0000000f;
232 nvkm_wr32(device, 0x61c040 + soff + pu_pc * 4, 0x1f008000);
233 }
234}
235
236void
237g94_sor_state(struct nvkm_ior *sor, struct nvkm_ior_state *state)
238{
239 struct nvkm_device *device = sor->disp->engine.subdev.device;
240 const u32 coff = sor->id * 8 + (state == &sor->arm) * 4;
241 u32 ctrl = nvkm_rd32(device, 0x610794 + coff);
242
243 state->proto_evo = (ctrl & 0x00000f00) >> 8;
244 switch (state->proto_evo) {
245 case 0: state->proto = LVDS; state->link = 1; break;
246 case 1: state->proto = TMDS; state->link = 1; break;
247 case 2: state->proto = TMDS; state->link = 2; break;
248 case 5: state->proto = TMDS; state->link = 3; break;
249 case 8: state->proto = DP; state->link = 1; break;
250 case 9: state->proto = DP; state->link = 2; break;
251 default:
252 state->proto = UNKNOWN;
253 break;
254 }
255
256 state->head = ctrl & 0x00000003;
257 nv50_pior_depth(sor, state, ctrl);
138} 258}
139 259
140static const struct nvkm_output_dp_func 260static const struct nvkm_ior_func
141g94_sor_dp_func = { 261g94_sor = {
142 .pattern = g94_sor_dp_pattern, 262 .state = g94_sor_state,
143 .lnk_pwr = g94_sor_dp_lnk_pwr, 263 .power = nv50_sor_power,
144 .lnk_ctl = g94_sor_dp_lnk_ctl, 264 .clock = nv50_sor_clock,
145 .drv_ctl = g94_sor_dp_drv_ctl, 265 .war_2 = g94_sor_war_2,
266 .war_3 = g94_sor_war_3,
267 .dp = {
268 .lanes = { 2, 1, 0, 3},
269 .links = g94_sor_dp_links,
270 .power = g94_sor_dp_power,
271 .pattern = g94_sor_dp_pattern,
272 .drive = g94_sor_dp_drive,
273 .audio_sym = g94_sor_dp_audio_sym,
274 .activesym = g94_sor_dp_activesym,
275 .watermark = g94_sor_dp_watermark,
276 },
146}; 277};
147 278
148int 279int
149g94_sor_dp_new(struct nvkm_disp *disp, int index, struct dcb_output *dcbE, 280g94_sor_new(struct nvkm_disp *disp, int id)
150 struct nvkm_output **poutp)
151{ 281{
152 return nvkm_output_dp_new_(&g94_sor_dp_func, disp, index, dcbE, poutp); 282 return nv50_sor_new_(&g94_sor, disp, id);
153} 283}
diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/sorgf119.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/sorgf119.c
index 6ffdaa65aa77..a2978a37b4f3 100644
--- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/sorgf119.c
+++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/sorgf119.c
@@ -21,44 +21,94 @@
21 * 21 *
22 * Authors: Ben Skeggs 22 * Authors: Ben Skeggs
23 */ 23 */
24#include "nv50.h" 24#include "ior.h"
25#include "outpdp.h"
26 25
27static inline u32 26#include <subdev/timer.h>
28gf119_sor_soff(struct nvkm_output_dp *outp) 27
28void
29gf119_sor_dp_watermark(struct nvkm_ior *sor, int head, u8 watermark)
30{
31 struct nvkm_device *device = sor->disp->engine.subdev.device;
32 const u32 hoff = head * 0x800;
33 nvkm_mask(device, 0x616610 + hoff, 0x0800003f, 0x08000000 | watermark);
34}
35
36void
37gf119_sor_dp_audio_sym(struct nvkm_ior *sor, int head, u16 h, u32 v)
29{ 38{
30 return (ffs(outp->base.info.or) - 1) * 0x800; 39 struct nvkm_device *device = sor->disp->engine.subdev.device;
40 const u32 hoff = head * 0x800;
41 nvkm_mask(device, 0x616620 + hoff, 0x0000ffff, h);
42 nvkm_mask(device, 0x616624 + hoff, 0x00ffffff, v);
31} 43}
32 44
33static inline u32 45void
34gf119_sor_loff(struct nvkm_output_dp *outp) 46gf119_sor_dp_audio(struct nvkm_ior *sor, int head, bool enable)
35{ 47{
36 return gf119_sor_soff(outp) + !(outp->base.info.sorconf.link & 1) * 0x80; 48 struct nvkm_device *device = sor->disp->engine.subdev.device;
49 const u32 hoff = 0x800 * head;
50 const u32 data = 0x80000000 | (0x00000001 * enable);
51 const u32 mask = 0x8000000d;
52 nvkm_mask(device, 0x616618 + hoff, mask, data);
53 nvkm_msec(device, 2000,
54 if (!(nvkm_rd32(device, 0x616618 + hoff) & 0x80000000))
55 break;
56 );
57}
58
59void
60gf119_sor_dp_vcpi(struct nvkm_ior *sor, int head,
61 u8 slot, u8 slot_nr, u16 pbn, u16 aligned)
62{
63 struct nvkm_device *device = sor->disp->engine.subdev.device;
64 const u32 hoff = head * 0x800;
65
66 nvkm_mask(device, 0x616588 + hoff, 0x00003f3f, (slot_nr << 8) | slot);
67 nvkm_mask(device, 0x61658c + hoff, 0xffffffff, (aligned << 16) | pbn);
68}
69
70void
71gf119_sor_dp_drive(struct nvkm_ior *sor, int ln, int pc, int dc, int pe, int pu)
72{
73 struct nvkm_device *device = sor->disp->engine.subdev.device;
74 const u32 loff = nv50_sor_link(sor);
75 const u32 shift = sor->func->dp.lanes[ln] * 8;
76 u32 data[4];
77
78 data[0] = nvkm_rd32(device, 0x61c118 + loff) & ~(0x000000ff << shift);
79 data[1] = nvkm_rd32(device, 0x61c120 + loff) & ~(0x000000ff << shift);
80 data[2] = nvkm_rd32(device, 0x61c130 + loff);
81 if ((data[2] & 0x0000ff00) < (pu << 8) || ln == 0)
82 data[2] = (data[2] & ~0x0000ff00) | (pu << 8);
83 nvkm_wr32(device, 0x61c118 + loff, data[0] | (dc << shift));
84 nvkm_wr32(device, 0x61c120 + loff, data[1] | (pe << shift));
85 nvkm_wr32(device, 0x61c130 + loff, data[2]);
86 data[3] = nvkm_rd32(device, 0x61c13c + loff) & ~(0x000000ff << shift);
87 nvkm_wr32(device, 0x61c13c + loff, data[3] | (pc << shift));
37} 88}
38 89
39static int 90void
40gf119_sor_dp_pattern(struct nvkm_output_dp *outp, int pattern) 91gf119_sor_dp_pattern(struct nvkm_ior *sor, int pattern)
41{ 92{
42 struct nvkm_device *device = outp->base.disp->engine.subdev.device; 93 struct nvkm_device *device = sor->disp->engine.subdev.device;
43 const u32 soff = gf119_sor_soff(outp); 94 const u32 soff = nv50_ior_base(sor);
44 nvkm_mask(device, 0x61c110 + soff, 0x0f0f0f0f, 0x01010101 * pattern); 95 nvkm_mask(device, 0x61c110 + soff, 0x0f0f0f0f, 0x01010101 * pattern);
45 return 0;
46} 96}
47 97
48int 98int
49gf119_sor_dp_lnk_ctl(struct nvkm_output_dp *outp, int nr, int bw, bool ef) 99gf119_sor_dp_links(struct nvkm_ior *sor, struct nvkm_i2c_aux *aux)
50{ 100{
51 struct nvkm_device *device = outp->base.disp->engine.subdev.device; 101 struct nvkm_device *device = sor->disp->engine.subdev.device;
52 const u32 soff = gf119_sor_soff(outp); 102 const u32 soff = nv50_ior_base(sor);
53 const u32 loff = gf119_sor_loff(outp); 103 const u32 loff = nv50_sor_link(sor);
54 u32 dpctrl = 0x00000000; 104 u32 dpctrl = 0x00000000;
55 u32 clksor = 0x00000000; 105 u32 clksor = 0x00000000;
56 106
57 clksor |= bw << 18; 107 clksor |= sor->dp.bw << 18;
58 dpctrl |= ((1 << nr) - 1) << 16; 108 dpctrl |= ((1 << sor->dp.nr) - 1) << 16;
59 if (outp->lt.mst) 109 if (sor->dp.mst)
60 dpctrl |= 0x40000000; 110 dpctrl |= 0x40000000;
61 if (ef) 111 if (sor->dp.ef)
62 dpctrl |= 0x00004000; 112 dpctrl |= 0x00004000;
63 113
64 nvkm_mask(device, 0x612300 + soff, 0x007c0000, clksor); 114 nvkm_mask(device, 0x612300 + soff, 0x007c0000, clksor);
@@ -66,66 +116,77 @@ gf119_sor_dp_lnk_ctl(struct nvkm_output_dp *outp, int nr, int bw, bool ef)
66 return 0; 116 return 0;
67} 117}
68 118
69int 119void
70gf119_sor_dp_drv_ctl(struct nvkm_output_dp *outp, 120gf119_sor_clock(struct nvkm_ior *sor)
71 int ln, int vs, int pe, int pc)
72{ 121{
73 struct nvkm_device *device = outp->base.disp->engine.subdev.device; 122 struct nvkm_device *device = sor->disp->engine.subdev.device;
74 struct nvkm_bios *bios = device->bios; 123 const int div = sor->asy.link == 3;
75 const u32 shift = g94_sor_dp_lane_map(device, ln); 124 const u32 soff = nv50_ior_base(sor);
76 const u32 loff = gf119_sor_loff(outp); 125 if (sor->asy.proto == TMDS) {
77 u32 addr, data[4]; 126 /* NFI why, but this sets DP_LINK_BW_2_7 when using TMDS. */
78 u8 ver, hdr, cnt, len; 127 nvkm_mask(device, 0x612300 + soff, 0x007c0000, 0x0a << 18);
79 struct nvbios_dpout info; 128 }
80 struct nvbios_dpcfg ocfg; 129 nvkm_mask(device, 0x612300 + soff, 0x00000707, (div << 8) | div);
81
82 addr = nvbios_dpout_match(bios, outp->base.info.hasht,
83 outp->base.info.hashm,
84 &ver, &hdr, &cnt, &len, &info);
85 if (!addr)
86 return -ENODEV;
87
88 addr = nvbios_dpcfg_match(bios, addr, pc, vs, pe,
89 &ver, &hdr, &cnt, &len, &ocfg);
90 if (!addr)
91 return -EINVAL;
92
93 data[0] = nvkm_rd32(device, 0x61c118 + loff) & ~(0x000000ff << shift);
94 data[1] = nvkm_rd32(device, 0x61c120 + loff) & ~(0x000000ff << shift);
95 data[2] = nvkm_rd32(device, 0x61c130 + loff);
96 if ((data[2] & 0x0000ff00) < (ocfg.tx_pu << 8) || ln == 0)
97 data[2] = (data[2] & ~0x0000ff00) | (ocfg.tx_pu << 8);
98 nvkm_wr32(device, 0x61c118 + loff, data[0] | (ocfg.dc << shift));
99 nvkm_wr32(device, 0x61c120 + loff, data[1] | (ocfg.pe << shift));
100 nvkm_wr32(device, 0x61c130 + loff, data[2]);
101 data[3] = nvkm_rd32(device, 0x61c13c + loff) & ~(0x000000ff << shift);
102 nvkm_wr32(device, 0x61c13c + loff, data[3] | (ocfg.pc << shift));
103 return 0;
104} 130}
105 131
106void 132void
107gf119_sor_dp_vcpi(struct nvkm_output_dp *outp, int head, u8 slot, 133gf119_sor_state(struct nvkm_ior *sor, struct nvkm_ior_state *state)
108 u8 slot_nr, u16 pbn, u16 aligned)
109{ 134{
110 struct nvkm_device *device = outp->base.disp->engine.subdev.device; 135 struct nvkm_device *device = sor->disp->engine.subdev.device;
111 const u32 hoff = head * 0x800; 136 const u32 coff = (state == &sor->asy) * 0x20000 + sor->id * 0x20;
137 u32 ctrl = nvkm_rd32(device, 0x640200 + coff);
112 138
113 nvkm_mask(device, 0x616588 + hoff, 0x00003f3f, (slot_nr << 8) | slot); 139 state->proto_evo = (ctrl & 0x00000f00) >> 8;
114 nvkm_mask(device, 0x61658c + hoff, 0xffffffff, (aligned << 16) | pbn); 140 switch (state->proto_evo) {
141 case 0: state->proto = LVDS; state->link = 1; break;
142 case 1: state->proto = TMDS; state->link = 1; break;
143 case 2: state->proto = TMDS; state->link = 2; break;
144 case 5: state->proto = TMDS; state->link = 3; break;
145 case 8: state->proto = DP; state->link = 1; break;
146 case 9: state->proto = DP; state->link = 2; break;
147 default:
148 state->proto = UNKNOWN;
149 break;
150 }
151
152 state->head = ctrl & 0x0000000f;
153}
154
155int
156gf119_sor_new_(const struct nvkm_ior_func *func, struct nvkm_disp *disp, int id)
157{
158 struct nvkm_device *device = disp->engine.subdev.device;
159 if (!(nvkm_rd32(device, 0x612004) & (0x00000100 << id)))
160 return 0;
161 return nvkm_ior_new_(func, disp, SOR, id);
115} 162}
116 163
117static const struct nvkm_output_dp_func 164static const struct nvkm_ior_func
118gf119_sor_dp_func = { 165gf119_sor = {
119 .pattern = gf119_sor_dp_pattern, 166 .state = gf119_sor_state,
120 .lnk_pwr = g94_sor_dp_lnk_pwr, 167 .power = nv50_sor_power,
121 .lnk_ctl = gf119_sor_dp_lnk_ctl, 168 .clock = gf119_sor_clock,
122 .drv_ctl = gf119_sor_dp_drv_ctl, 169 .hdmi = {
123 .vcpi = gf119_sor_dp_vcpi, 170 .ctrl = gf119_hdmi_ctrl,
171 },
172 .dp = {
173 .lanes = { 2, 1, 0, 3 },
174 .links = gf119_sor_dp_links,
175 .power = g94_sor_dp_power,
176 .pattern = gf119_sor_dp_pattern,
177 .vcpi = gf119_sor_dp_vcpi,
178 .audio = gf119_sor_dp_audio,
179 .audio_sym = gf119_sor_dp_audio_sym,
180 .watermark = gf119_sor_dp_watermark,
181 },
182 .hda = {
183 .hpd = gf119_hda_hpd,
184 .eld = gf119_hda_eld,
185 },
124}; 186};
125 187
126int 188int
127gf119_sor_dp_new(struct nvkm_disp *disp, int index, 189gf119_sor_new(struct nvkm_disp *disp, int id)
128 struct dcb_output *dcbE, struct nvkm_output **poutp)
129{ 190{
130 return nvkm_output_dp_new_(&gf119_sor_dp_func, disp, index, dcbE, poutp); 191 return gf119_sor_new_(&gf119_sor, disp, id);
131} 192}
diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/sorgk104.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/sorgk104.c
new file mode 100644
index 000000000000..a1547bdf490b
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/sorgk104.c
@@ -0,0 +1,53 @@
1/*
2 * Copyright 2017 Red Hat Inc.
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#include "ior.h"
23
24static const struct nvkm_ior_func
25gk104_sor = {
26 .state = gf119_sor_state,
27 .power = nv50_sor_power,
28 .clock = gf119_sor_clock,
29 .hdmi = {
30 .ctrl = gk104_hdmi_ctrl,
31 },
32 .dp = {
33 .lanes = { 2, 1, 0, 3 },
34 .links = gf119_sor_dp_links,
35 .power = g94_sor_dp_power,
36 .pattern = gf119_sor_dp_pattern,
37 .drive = gf119_sor_dp_drive,
38 .vcpi = gf119_sor_dp_vcpi,
39 .audio = gf119_sor_dp_audio,
40 .audio_sym = gf119_sor_dp_audio_sym,
41 .watermark = gf119_sor_dp_watermark,
42 },
43 .hda = {
44 .hpd = gf119_hda_hpd,
45 .eld = gf119_hda_eld,
46 },
47};
48
49int
50gk104_sor_new(struct nvkm_disp *disp, int id)
51{
52 return gf119_sor_new_(&gk104_sor, disp, id);
53}
diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/sorgm107.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/sorgm107.c
index 4cf8ad4d18ab..60230957d82b 100644
--- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/sorgm107.c
+++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/sorgm107.c
@@ -21,34 +21,47 @@
21 * 21 *
22 * Authors: Ben Skeggs <bskeggs@redhat.com> 22 * Authors: Ben Skeggs <bskeggs@redhat.com>
23 */ 23 */
24#include "nv50.h" 24#include "ior.h"
25#include "outpdp.h"
26 25
27int 26void
28gm107_sor_dp_pattern(struct nvkm_output_dp *outp, int pattern) 27gm107_sor_dp_pattern(struct nvkm_ior *sor, int pattern)
29{ 28{
30 struct nvkm_device *device = outp->base.disp->engine.subdev.device; 29 struct nvkm_device *device = sor->disp->engine.subdev.device;
31 const u32 soff = outp->base.or * 0x800; 30 const u32 soff = nv50_ior_base(sor);
32 const u32 data = 0x01010101 * pattern; 31 const u32 data = 0x01010101 * pattern;
33 if (outp->base.info.sorconf.link & 1) 32 if (sor->asy.link & 1)
34 nvkm_mask(device, 0x61c110 + soff, 0x0f0f0f0f, data); 33 nvkm_mask(device, 0x61c110 + soff, 0x0f0f0f0f, data);
35 else 34 else
36 nvkm_mask(device, 0x61c12c + soff, 0x0f0f0f0f, data); 35 nvkm_mask(device, 0x61c12c + soff, 0x0f0f0f0f, data);
37 return 0;
38} 36}
39 37
40static const struct nvkm_output_dp_func 38static const struct nvkm_ior_func
41gm107_sor_dp_func = { 39gm107_sor = {
42 .pattern = gm107_sor_dp_pattern, 40 .state = gf119_sor_state,
43 .lnk_pwr = g94_sor_dp_lnk_pwr, 41 .power = nv50_sor_power,
44 .lnk_ctl = gf119_sor_dp_lnk_ctl, 42 .clock = gf119_sor_clock,
45 .drv_ctl = gf119_sor_dp_drv_ctl, 43 .hdmi = {
46 .vcpi = gf119_sor_dp_vcpi, 44 .ctrl = gk104_hdmi_ctrl,
45 },
46 .dp = {
47 .lanes = { 0, 1, 2, 3 },
48 .links = gf119_sor_dp_links,
49 .power = g94_sor_dp_power,
50 .pattern = gm107_sor_dp_pattern,
51 .drive = gf119_sor_dp_drive,
52 .vcpi = gf119_sor_dp_vcpi,
53 .audio = gf119_sor_dp_audio,
54 .audio_sym = gf119_sor_dp_audio_sym,
55 .watermark = gf119_sor_dp_watermark,
56 },
57 .hda = {
58 .hpd = gf119_hda_hpd,
59 .eld = gf119_hda_eld,
60 },
47}; 61};
48 62
49int 63int
50gm107_sor_dp_new(struct nvkm_disp *disp, int index, 64gm107_sor_new(struct nvkm_disp *disp, int id)
51 struct dcb_output *dcbE, struct nvkm_output **poutp)
52{ 65{
53 return nvkm_output_dp_new_(&gm107_sor_dp_func, disp, index, dcbE, poutp); 66 return gf119_sor_new_(&gm107_sor, disp, id);
54} 67}
diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/sorgm200.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/sorgm200.c
index 81b788fa61be..f9b8107aa2a2 100644
--- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/sorgm200.c
+++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/sorgm200.c
@@ -21,111 +21,104 @@
21 * 21 *
22 * Authors: Ben Skeggs 22 * Authors: Ben Skeggs
23 */ 23 */
24#include "nv50.h" 24#include "ior.h"
25#include "outpdp.h"
26 25
27#include <subdev/timer.h> 26static void
28 27gm200_sor_dp_drive(struct nvkm_ior *sor, int ln, int pc, int dc, int pe, int pu)
29static inline u32
30gm200_sor_soff(struct nvkm_output_dp *outp)
31{
32 return (ffs(outp->base.info.or) - 1) * 0x800;
33}
34
35static inline u32
36gm200_sor_loff(struct nvkm_output_dp *outp)
37{ 28{
38 return gm200_sor_soff(outp) + !(outp->base.info.sorconf.link & 1) * 0x80; 29 struct nvkm_device *device = sor->disp->engine.subdev.device;
39} 30 const u32 loff = nv50_sor_link(sor);
31 const u32 shift = sor->func->dp.lanes[ln] * 8;
32 u32 data[4];
40 33
41void 34 pu &= 0x0f;
42gm200_sor_magic(struct nvkm_output *outp)
43{
44 struct nvkm_device *device = outp->disp->engine.subdev.device;
45 const u32 soff = outp->or * 0x100;
46 const u32 data = outp->or + 1;
47 if (outp->info.sorconf.link & 1)
48 nvkm_mask(device, 0x612308 + soff, 0x0000001f, 0x00000000 | data);
49 if (outp->info.sorconf.link & 2)
50 nvkm_mask(device, 0x612388 + soff, 0x0000001f, 0x00000010 | data);
51}
52 35
53static inline u32 36 data[0] = nvkm_rd32(device, 0x61c118 + loff) & ~(0x000000ff << shift);
54gm200_sor_dp_lane_map(struct nvkm_device *device, u8 lane) 37 data[1] = nvkm_rd32(device, 0x61c120 + loff) & ~(0x000000ff << shift);
55{ 38 data[2] = nvkm_rd32(device, 0x61c130 + loff);
56 return lane * 0x08; 39 if ((data[2] & 0x00000f00) < (pu << 8) || ln == 0)
40 data[2] = (data[2] & ~0x00000f00) | (pu << 8);
41 nvkm_wr32(device, 0x61c118 + loff, data[0] | (dc << shift));
42 nvkm_wr32(device, 0x61c120 + loff, data[1] | (pe << shift));
43 nvkm_wr32(device, 0x61c130 + loff, data[2]);
44 data[3] = nvkm_rd32(device, 0x61c13c + loff) & ~(0x000000ff << shift);
45 nvkm_wr32(device, 0x61c13c + loff, data[3] | (pc << shift));
57} 46}
58 47
59static int 48static void
60gm200_sor_dp_lnk_pwr(struct nvkm_output_dp *outp, int nr) 49gm200_sor_route_set(struct nvkm_outp *outp, struct nvkm_ior *ior)
61{ 50{
62 struct nvkm_device *device = outp->base.disp->engine.subdev.device; 51 struct nvkm_device *device = outp->disp->engine.subdev.device;
63 const u32 soff = gm200_sor_soff(outp); 52 const u32 moff = __ffs(outp->info.or) * 0x100;
64 const u32 loff = gm200_sor_loff(outp); 53 const u32 sor = ior ? ior->id + 1 : 0;
65 u32 mask = 0, i; 54 u32 link = ior ? (ior->asy.link == 2) : 0;
66 55
67 for (i = 0; i < nr; i++) 56 if (outp->info.sorconf.link & 1) {
68 mask |= 1 << (gm200_sor_dp_lane_map(device, i) >> 3); 57 nvkm_mask(device, 0x612308 + moff, 0x0000001f, link << 4 | sor);
58 link++;
59 }
69 60
70 nvkm_mask(device, 0x61c130 + loff, 0x0000000f, mask); 61 if (outp->info.sorconf.link & 2)
71 nvkm_mask(device, 0x61c034 + soff, 0x80000000, 0x80000000); 62 nvkm_mask(device, 0x612388 + moff, 0x0000001f, link << 4 | sor);
72 nvkm_msec(device, 2000,
73 if (!(nvkm_rd32(device, 0x61c034 + soff) & 0x80000000))
74 break;
75 );
76 return 0;
77} 63}
78 64
79static int 65static int
80gm200_sor_dp_drv_ctl(struct nvkm_output_dp *outp, 66gm200_sor_route_get(struct nvkm_outp *outp, int *link)
81 int ln, int vs, int pe, int pc)
82{ 67{
83 struct nvkm_device *device = outp->base.disp->engine.subdev.device; 68 struct nvkm_device *device = outp->disp->engine.subdev.device;
84 struct nvkm_bios *bios = device->bios; 69 const int sublinks = outp->info.sorconf.link;
85 const u32 shift = gm200_sor_dp_lane_map(device, ln); 70 int lnk[2], sor[2], m, s;
86 const u32 loff = gm200_sor_loff(outp);
87 u32 addr, data[4];
88 u8 ver, hdr, cnt, len;
89 struct nvbios_dpout info;
90 struct nvbios_dpcfg ocfg;
91 71
92 addr = nvbios_dpout_match(bios, outp->base.info.hasht, 72 for (*link = 0, m = __ffs(outp->info.or) * 2, s = 0; s < 2; m++, s++) {
93 outp->base.info.hashm, 73 if (sublinks & BIT(s)) {
94 &ver, &hdr, &cnt, &len, &info); 74 u32 data = nvkm_rd32(device, 0x612308 + (m * 0x80));
95 if (!addr) 75 lnk[s] = (data & 0x00000010) >> 4;
96 return -ENODEV; 76 sor[s] = (data & 0x0000000f);
77 if (!sor[s])
78 return -1;
79 *link |= lnk[s];
80 }
81 }
97 82
98 addr = nvbios_dpcfg_match(bios, addr, pc, vs, pe, 83 if (sublinks == 3) {
99 &ver, &hdr, &cnt, &len, &ocfg); 84 if (sor[0] != sor[1] || WARN_ON(lnk[0] || !lnk[1]))
100 if (!addr) 85 return -1;
101 return -EINVAL; 86 }
102 ocfg.tx_pu &= 0x0f;
103 87
104 data[0] = nvkm_rd32(device, 0x61c118 + loff) & ~(0x000000ff << shift); 88 return ((sublinks & 1) ? sor[0] : sor[1]) - 1;
105 data[1] = nvkm_rd32(device, 0x61c120 + loff) & ~(0x000000ff << shift);
106 data[2] = nvkm_rd32(device, 0x61c130 + loff);
107 if ((data[2] & 0x00000f00) < (ocfg.tx_pu << 8) || ln == 0)
108 data[2] = (data[2] & ~0x00000f00) | (ocfg.tx_pu << 8);
109 nvkm_wr32(device, 0x61c118 + loff, data[0] | (ocfg.dc << shift));
110 nvkm_wr32(device, 0x61c120 + loff, data[1] | (ocfg.pe << shift));
111 nvkm_wr32(device, 0x61c130 + loff, data[2]);
112 data[3] = nvkm_rd32(device, 0x61c13c + loff) & ~(0x000000ff << shift);
113 nvkm_wr32(device, 0x61c13c + loff, data[3] | (ocfg.pc << shift));
114 return 0;
115} 89}
116 90
117static const struct nvkm_output_dp_func 91static const struct nvkm_ior_func
118gm200_sor_dp_func = { 92gm200_sor = {
119 .pattern = gm107_sor_dp_pattern, 93 .route = {
120 .lnk_pwr = gm200_sor_dp_lnk_pwr, 94 .get = gm200_sor_route_get,
121 .lnk_ctl = gf119_sor_dp_lnk_ctl, 95 .set = gm200_sor_route_set,
122 .drv_ctl = gm200_sor_dp_drv_ctl, 96 },
123 .vcpi = gf119_sor_dp_vcpi, 97 .state = gf119_sor_state,
98 .power = nv50_sor_power,
99 .clock = gf119_sor_clock,
100 .hdmi = {
101 .ctrl = gk104_hdmi_ctrl,
102 },
103 .dp = {
104 .lanes = { 0, 1, 2, 3 },
105 .links = gf119_sor_dp_links,
106 .power = g94_sor_dp_power,
107 .pattern = gm107_sor_dp_pattern,
108 .drive = gm200_sor_dp_drive,
109 .vcpi = gf119_sor_dp_vcpi,
110 .audio = gf119_sor_dp_audio,
111 .audio_sym = gf119_sor_dp_audio_sym,
112 .watermark = gf119_sor_dp_watermark,
113 },
114 .hda = {
115 .hpd = gf119_hda_hpd,
116 .eld = gf119_hda_eld,
117 },
124}; 118};
125 119
126int 120int
127gm200_sor_dp_new(struct nvkm_disp *disp, int index, struct dcb_output *dcbE, 121gm200_sor_new(struct nvkm_disp *disp, int id)
128 struct nvkm_output **poutp)
129{ 122{
130 return nvkm_output_dp_new_(&gm200_sor_dp_func, disp, index, dcbE, poutp); 123 return gf119_sor_new_(&gm200_sor, disp, id);
131} 124}
diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/sorgt215.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/sorgt215.c
new file mode 100644
index 000000000000..da228b54b43e
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/sorgt215.c
@@ -0,0 +1,69 @@
1/*
2 * Copyright 2017 Red Hat Inc.
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#include "ior.h"
23
24#include <subdev/timer.h>
25
26void
27gt215_sor_dp_audio(struct nvkm_ior *sor, int head, bool enable)
28{
29 struct nvkm_device *device = sor->disp->engine.subdev.device;
30 const u32 soff = nv50_ior_base(sor);
31 const u32 data = 0x80000000 | (0x00000001 * enable);
32 const u32 mask = 0x8000000d;
33 nvkm_mask(device, 0x61c1e0 + soff, mask, data);
34 nvkm_msec(device, 2000,
35 if (!(nvkm_rd32(device, 0x61c1e0 + soff) & 0x80000000))
36 break;
37 );
38}
39
40static const struct nvkm_ior_func
41gt215_sor = {
42 .state = g94_sor_state,
43 .power = nv50_sor_power,
44 .clock = nv50_sor_clock,
45 .hdmi = {
46 .ctrl = gt215_hdmi_ctrl,
47 },
48 .dp = {
49 .lanes = { 2, 1, 0, 3 },
50 .links = g94_sor_dp_links,
51 .power = g94_sor_dp_power,
52 .pattern = g94_sor_dp_pattern,
53 .drive = g94_sor_dp_drive,
54 .audio = gt215_sor_dp_audio,
55 .audio_sym = g94_sor_dp_audio_sym,
56 .activesym = g94_sor_dp_activesym,
57 .watermark = g94_sor_dp_watermark,
58 },
59 .hda = {
60 .hpd = gt215_hda_hpd,
61 .eld = gt215_hda_eld,
62 },
63};
64
65int
66gt215_sor_new(struct nvkm_disp *disp, int id)
67{
68 return nv50_sor_new_(&gt215_sor, disp, id);
69}
diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/sormcp77.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/sormcp77.c
new file mode 100644
index 000000000000..c0179ccb956d
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/sormcp77.c
@@ -0,0 +1,48 @@
1/*
2 * Copyright 2017 Red Hat Inc.
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#include "ior.h"
23
24static const struct nvkm_ior_func
25mcp77_sor = {
26 .state = g94_sor_state,
27 .power = nv50_sor_power,
28 .clock = nv50_sor_clock,
29 .hdmi = {
30 .ctrl = g84_hdmi_ctrl,
31 },
32 .dp = {
33 .lanes = { 2, 1, 0, 3},
34 .links = g94_sor_dp_links,
35 .power = g94_sor_dp_power,
36 .pattern = g94_sor_dp_pattern,
37 .drive = g94_sor_dp_drive,
38 .audio_sym = g94_sor_dp_audio_sym,
39 .activesym = g94_sor_dp_activesym,
40 .watermark = g94_sor_dp_watermark,
41 },
42};
43
44int
45mcp77_sor_new(struct nvkm_disp *disp, int id)
46{
47 return nv50_sor_new_(&mcp77_sor, disp, id);
48}
diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/sormcp89.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/sormcp89.c
new file mode 100644
index 000000000000..9bb01cd96697
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/sormcp89.c
@@ -0,0 +1,53 @@
1/*
2 * Copyright 2017 Red Hat Inc.
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#include "ior.h"
23
24static const struct nvkm_ior_func
25mcp89_sor = {
26 .state = g94_sor_state,
27 .power = nv50_sor_power,
28 .clock = nv50_sor_clock,
29 .hdmi = {
30 .ctrl = gt215_hdmi_ctrl,
31 },
32 .dp = {
33 .lanes = { 3, 2, 1, 0 },
34 .links = g94_sor_dp_links,
35 .power = g94_sor_dp_power,
36 .pattern = g94_sor_dp_pattern,
37 .drive = g94_sor_dp_drive,
38 .audio = gt215_sor_dp_audio,
39 .audio_sym = g94_sor_dp_audio_sym,
40 .activesym = g94_sor_dp_activesym,
41 .watermark = g94_sor_dp_watermark,
42 },
43 .hda = {
44 .hpd = gt215_hda_hpd,
45 .eld = gt215_hda_eld,
46 },
47};
48
49int
50mcp89_sor_new(struct nvkm_disp *disp, int id)
51{
52 return nv50_sor_new_(&mcp89_sor, disp, id);
53}
diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/sornv50.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/sornv50.c
index 53596bed3c36..f3ebd0c22e7d 100644
--- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/sornv50.c
+++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/sornv50.c
@@ -21,59 +21,87 @@
21 * 21 *
22 * Authors: Ben Skeggs 22 * Authors: Ben Skeggs
23 */ 23 */
24#include "nv50.h" 24#include "ior.h"
25#include "outp.h"
26 25
27#include <core/client.h>
28#include <subdev/timer.h> 26#include <subdev/timer.h>
29 27
30#include <nvif/cl5070.h> 28void
31#include <nvif/unpack.h> 29nv50_sor_clock(struct nvkm_ior *sor)
32
33int
34nv50_sor_power(NV50_DISP_MTHD_V1)
35{ 30{
36 struct nvkm_device *device = disp->base.engine.subdev.device; 31 struct nvkm_device *device = sor->disp->engine.subdev.device;
37 union { 32 const int div = sor->asy.link == 3;
38 struct nv50_disp_sor_pwr_v0 v0; 33 const u32 soff = nv50_ior_base(sor);
39 } *args = data; 34 nvkm_mask(device, 0x614300 + soff, 0x00000707, (div << 8) | div);
40 const u32 soff = outp->or * 0x800; 35}
41 u32 stat;
42 int ret = -ENOSYS;
43
44 nvif_ioctl(object, "disp sor pwr size %d\n", size);
45 if (!(ret = nvif_unpack(ret, &data, &size, args->v0, 0, 0, false))) {
46 nvif_ioctl(object, "disp sor pwr vers %d state %d\n",
47 args->v0.version, args->v0.state);
48 stat = !!args->v0.state;
49 } else
50 return ret;
51
52 36
37static void
38nv50_sor_power_wait(struct nvkm_device *device, u32 soff)
39{
53 nvkm_msec(device, 2000, 40 nvkm_msec(device, 2000,
54 if (!(nvkm_rd32(device, 0x61c004 + soff) & 0x80000000)) 41 if (!(nvkm_rd32(device, 0x61c004 + soff) & 0x80000000))
55 break; 42 break;
56 ); 43 );
57 nvkm_mask(device, 0x61c004 + soff, 0x80000001, 0x80000000 | stat); 44}
58 nvkm_msec(device, 2000, 45
59 if (!(nvkm_rd32(device, 0x61c004 + soff) & 0x80000000)) 46void
60 break; 47nv50_sor_power(struct nvkm_ior *sor, bool normal, bool pu,
61 ); 48 bool data, bool vsync, bool hsync)
49{
50 struct nvkm_device *device = sor->disp->engine.subdev.device;
51 const u32 soff = nv50_ior_base(sor);
52 const u32 shift = normal ? 0 : 16;
53 const u32 state = 0x80000000 | (0x00000001 * !!pu) << shift;
54 const u32 field = 0x80000000 | (0x00000001 << shift);
55
56 nv50_sor_power_wait(device, soff);
57 nvkm_mask(device, 0x61c004 + soff, field, state);
58 nv50_sor_power_wait(device, soff);
59
62 nvkm_msec(device, 2000, 60 nvkm_msec(device, 2000,
63 if (!(nvkm_rd32(device, 0x61c030 + soff) & 0x10000000)) 61 if (!(nvkm_rd32(device, 0x61c030 + soff) & 0x10000000))
64 break; 62 break;
65 ); 63 );
66 return 0;
67} 64}
68 65
69static const struct nvkm_output_func 66void
70nv50_sor_output_func = { 67nv50_sor_state(struct nvkm_ior *sor, struct nvkm_ior_state *state)
68{
69 struct nvkm_device *device = sor->disp->engine.subdev.device;
70 const u32 coff = sor->id * 8 + (state == &sor->arm) * 4;
71 u32 ctrl = nvkm_rd32(device, 0x610b70 + coff);
72
73 state->proto_evo = (ctrl & 0x00000f00) >> 8;
74 switch (state->proto_evo) {
75 case 0: state->proto = LVDS; state->link = 1; break;
76 case 1: state->proto = TMDS; state->link = 1; break;
77 case 2: state->proto = TMDS; state->link = 2; break;
78 case 5: state->proto = TMDS; state->link = 3; break;
79 default:
80 state->proto = UNKNOWN;
81 break;
82 }
83
84 state->head = ctrl & 0x00000003;
85}
86
87int
88nv50_sor_new_(const struct nvkm_ior_func *func, struct nvkm_disp *disp, int id)
89{
90 struct nvkm_device *device = disp->engine.subdev.device;
91 if (!(nvkm_rd32(device, 0x610184) & (0x01000000 << id)))
92 return 0;
93 return nvkm_ior_new_(func, disp, SOR, id);
94}
95
96static const struct nvkm_ior_func
97nv50_sor = {
98 .state = nv50_sor_state,
99 .power = nv50_sor_power,
100 .clock = nv50_sor_clock,
71}; 101};
72 102
73int 103int
74nv50_sor_output_new(struct nvkm_disp *disp, int index, 104nv50_sor_new(struct nvkm_disp *disp, int id)
75 struct dcb_output *dcbE, struct nvkm_output **poutp)
76{ 105{
77 return nvkm_output_new_(&nv50_sor_output_func, disp, 106 return nv50_sor_new_(&nv50_sor, disp, id);
78 index, dcbE, poutp);
79} 107}
diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/bios/iccsense.c b/drivers/gpu/drm/nouveau/nvkm/subdev/bios/iccsense.c
index 3953d11844ea..23caef8df17f 100644
--- a/drivers/gpu/drm/nouveau/nvkm/subdev/bios/iccsense.c
+++ b/drivers/gpu/drm/nouveau/nvkm/subdev/bios/iccsense.c
@@ -87,7 +87,10 @@ nvbios_iccsense_parse(struct nvkm_bios *bios, struct nvbios_iccsense *iccsense)
87 87
88 switch(ver) { 88 switch(ver) {
89 case 0x10: 89 case 0x10:
90 rail->mode = nvbios_rd08(bios, entry + 0x1); 90 if ((nvbios_rd08(bios, entry + 0x1) & 0xf8) == 0xf8)
91 rail->mode = 1;
92 else
93 rail->mode = 0;
91 rail->extdev_id = nvbios_rd08(bios, entry + 0x2); 94 rail->extdev_id = nvbios_rd08(bios, entry + 0x2);
92 res_start = 0x3; 95 res_start = 0x3;
93 break; 96 break;
diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/bios/init.c b/drivers/gpu/drm/nouveau/nvkm/subdev/bios/init.c
index 38ed09fd3d2f..b58ee99f7bfc 100644
--- a/drivers/gpu/drm/nouveau/nvkm/subdev/bios/init.c
+++ b/drivers/gpu/drm/nouveau/nvkm/subdev/bios/init.c
@@ -37,7 +37,7 @@
37#include <subdev/vga.h> 37#include <subdev/vga.h>
38 38
39#define bioslog(lvl, fmt, args...) do { \ 39#define bioslog(lvl, fmt, args...) do { \
40 nvkm_printk(init->subdev, lvl, info, "0x%04x[%c]: "fmt, \ 40 nvkm_printk(init->subdev, lvl, info, "0x%08x[%c]: "fmt, \
41 init->offset, init_exec(init) ? \ 41 init->offset, init_exec(init) ? \
42 '0' + (init->nested - 1) : ' ', ##args); \ 42 '0' + (init->nested - 1) : ' ', ##args); \
43} while(0) 43} while(0)
@@ -87,8 +87,8 @@ static inline int
87init_or(struct nvbios_init *init) 87init_or(struct nvbios_init *init)
88{ 88{
89 if (init_exec(init)) { 89 if (init_exec(init)) {
90 if (init->outp) 90 if (init->or >= 0)
91 return ffs(init->outp->or) - 1; 91 return init->or;
92 error("script needs OR!!\n"); 92 error("script needs OR!!\n");
93 } 93 }
94 return 0; 94 return 0;
@@ -98,20 +98,20 @@ static inline int
98init_link(struct nvbios_init *init) 98init_link(struct nvbios_init *init)
99{ 99{
100 if (init_exec(init)) { 100 if (init_exec(init)) {
101 if (init->outp) 101 if (init->link)
102 return !(init->outp->sorconf.link & 1); 102 return init->link == 2;
103 error("script needs OR link\n"); 103 error("script needs OR link\n");
104 } 104 }
105 return 0; 105 return 0;
106} 106}
107 107
108static inline int 108static inline int
109init_crtc(struct nvbios_init *init) 109init_head(struct nvbios_init *init)
110{ 110{
111 if (init_exec(init)) { 111 if (init_exec(init)) {
112 if (init->crtc >= 0) 112 if (init->head >= 0)
113 return init->crtc; 113 return init->head;
114 error("script needs crtc\n"); 114 error("script needs head\n");
115 } 115 }
116 return 0; 116 return 0;
117} 117}
@@ -119,7 +119,7 @@ init_crtc(struct nvbios_init *init)
119static u8 119static u8
120init_conn(struct nvbios_init *init) 120init_conn(struct nvbios_init *init)
121{ 121{
122 struct nvkm_bios *bios = init->bios; 122 struct nvkm_bios *bios = init->subdev->device->bios;
123 struct nvbios_connE connE; 123 struct nvbios_connE connE;
124 u8 ver, hdr; 124 u8 ver, hdr;
125 u32 conn; 125 u32 conn;
@@ -141,7 +141,7 @@ init_conn(struct nvbios_init *init)
141static inline u32 141static inline u32
142init_nvreg(struct nvbios_init *init, u32 reg) 142init_nvreg(struct nvbios_init *init, u32 reg)
143{ 143{
144 struct nvkm_devinit *devinit = init->bios->subdev.device->devinit; 144 struct nvkm_devinit *devinit = init->subdev->device->devinit;
145 145
146 /* C51 (at least) sometimes has the lower bits set which the VBIOS 146 /* C51 (at least) sometimes has the lower bits set which the VBIOS
147 * interprets to mean that access needs to go through certain IO 147 * interprets to mean that access needs to go through certain IO
@@ -154,9 +154,9 @@ init_nvreg(struct nvbios_init *init, u32 reg)
154 /* GF8+ display scripts need register addresses mangled a bit to 154 /* GF8+ display scripts need register addresses mangled a bit to
155 * select a specific CRTC/OR 155 * select a specific CRTC/OR
156 */ 156 */
157 if (init->bios->subdev.device->card_type >= NV_50) { 157 if (init->subdev->device->card_type >= NV_50) {
158 if (reg & 0x80000000) { 158 if (reg & 0x80000000) {
159 reg += init_crtc(init) * 0x800; 159 reg += init_head(init) * 0x800;
160 reg &= ~0x80000000; 160 reg &= ~0x80000000;
161 } 161 }
162 162
@@ -179,7 +179,7 @@ init_nvreg(struct nvbios_init *init, u32 reg)
179static u32 179static u32
180init_rd32(struct nvbios_init *init, u32 reg) 180init_rd32(struct nvbios_init *init, u32 reg)
181{ 181{
182 struct nvkm_device *device = init->bios->subdev.device; 182 struct nvkm_device *device = init->subdev->device;
183 reg = init_nvreg(init, reg); 183 reg = init_nvreg(init, reg);
184 if (reg != ~0 && init_exec(init)) 184 if (reg != ~0 && init_exec(init))
185 return nvkm_rd32(device, reg); 185 return nvkm_rd32(device, reg);
@@ -189,7 +189,7 @@ init_rd32(struct nvbios_init *init, u32 reg)
189static void 189static void
190init_wr32(struct nvbios_init *init, u32 reg, u32 val) 190init_wr32(struct nvbios_init *init, u32 reg, u32 val)
191{ 191{
192 struct nvkm_device *device = init->bios->subdev.device; 192 struct nvkm_device *device = init->subdev->device;
193 reg = init_nvreg(init, reg); 193 reg = init_nvreg(init, reg);
194 if (reg != ~0 && init_exec(init)) 194 if (reg != ~0 && init_exec(init))
195 nvkm_wr32(device, reg, val); 195 nvkm_wr32(device, reg, val);
@@ -198,7 +198,7 @@ init_wr32(struct nvbios_init *init, u32 reg, u32 val)
198static u32 198static u32
199init_mask(struct nvbios_init *init, u32 reg, u32 mask, u32 val) 199init_mask(struct nvbios_init *init, u32 reg, u32 mask, u32 val)
200{ 200{
201 struct nvkm_device *device = init->bios->subdev.device; 201 struct nvkm_device *device = init->subdev->device;
202 reg = init_nvreg(init, reg); 202 reg = init_nvreg(init, reg);
203 if (reg != ~0 && init_exec(init)) { 203 if (reg != ~0 && init_exec(init)) {
204 u32 tmp = nvkm_rd32(device, reg); 204 u32 tmp = nvkm_rd32(device, reg);
@@ -212,7 +212,7 @@ static u8
212init_rdport(struct nvbios_init *init, u16 port) 212init_rdport(struct nvbios_init *init, u16 port)
213{ 213{
214 if (init_exec(init)) 214 if (init_exec(init))
215 return nvkm_rdport(init->subdev->device, init->crtc, port); 215 return nvkm_rdport(init->subdev->device, init->head, port);
216 return 0x00; 216 return 0x00;
217} 217}
218 218
@@ -220,7 +220,7 @@ static void
220init_wrport(struct nvbios_init *init, u16 port, u8 value) 220init_wrport(struct nvbios_init *init, u16 port, u8 value)
221{ 221{
222 if (init_exec(init)) 222 if (init_exec(init))
223 nvkm_wrport(init->subdev->device, init->crtc, port, value); 223 nvkm_wrport(init->subdev->device, init->head, port, value);
224} 224}
225 225
226static u8 226static u8
@@ -228,7 +228,7 @@ init_rdvgai(struct nvbios_init *init, u16 port, u8 index)
228{ 228{
229 struct nvkm_subdev *subdev = init->subdev; 229 struct nvkm_subdev *subdev = init->subdev;
230 if (init_exec(init)) { 230 if (init_exec(init)) {
231 int head = init->crtc < 0 ? 0 : init->crtc; 231 int head = init->head < 0 ? 0 : init->head;
232 return nvkm_rdvgai(subdev->device, head, port, index); 232 return nvkm_rdvgai(subdev->device, head, port, index);
233 } 233 }
234 return 0x00; 234 return 0x00;
@@ -242,25 +242,25 @@ init_wrvgai(struct nvbios_init *init, u16 port, u8 index, u8 value)
242 /* force head 0 for updates to cr44, it only exists on first head */ 242 /* force head 0 for updates to cr44, it only exists on first head */
243 if (device->card_type < NV_50) { 243 if (device->card_type < NV_50) {
244 if (port == 0x03d4 && index == 0x44) 244 if (port == 0x03d4 && index == 0x44)
245 init->crtc = 0; 245 init->head = 0;
246 } 246 }
247 247
248 if (init_exec(init)) { 248 if (init_exec(init)) {
249 int head = init->crtc < 0 ? 0 : init->crtc; 249 int head = init->head < 0 ? 0 : init->head;
250 nvkm_wrvgai(device, head, port, index, value); 250 nvkm_wrvgai(device, head, port, index, value);
251 } 251 }
252 252
253 /* select head 1 if cr44 write selected it */ 253 /* select head 1 if cr44 write selected it */
254 if (device->card_type < NV_50) { 254 if (device->card_type < NV_50) {
255 if (port == 0x03d4 && index == 0x44 && value == 3) 255 if (port == 0x03d4 && index == 0x44 && value == 3)
256 init->crtc = 1; 256 init->head = 1;
257 } 257 }
258} 258}
259 259
260static struct i2c_adapter * 260static struct i2c_adapter *
261init_i2c(struct nvbios_init *init, int index) 261init_i2c(struct nvbios_init *init, int index)
262{ 262{
263 struct nvkm_i2c *i2c = init->bios->subdev.device->i2c; 263 struct nvkm_i2c *i2c = init->subdev->device->i2c;
264 struct nvkm_i2c_bus *bus; 264 struct nvkm_i2c_bus *bus;
265 265
266 if (index == 0xff) { 266 if (index == 0xff) {
@@ -300,7 +300,7 @@ init_wri2cr(struct nvbios_init *init, u8 index, u8 addr, u8 reg, u8 val)
300static struct nvkm_i2c_aux * 300static struct nvkm_i2c_aux *
301init_aux(struct nvbios_init *init) 301init_aux(struct nvbios_init *init)
302{ 302{
303 struct nvkm_i2c *i2c = init->bios->subdev.device->i2c; 303 struct nvkm_i2c *i2c = init->subdev->device->i2c;
304 if (!init->outp) { 304 if (!init->outp) {
305 if (init_exec(init)) 305 if (init_exec(init))
306 error("script needs output for aux\n"); 306 error("script needs output for aux\n");
@@ -341,7 +341,7 @@ init_wrauxr(struct nvbios_init *init, u32 addr, u8 data)
341static void 341static void
342init_prog_pll(struct nvbios_init *init, u32 id, u32 freq) 342init_prog_pll(struct nvbios_init *init, u32 id, u32 freq)
343{ 343{
344 struct nvkm_devinit *devinit = init->bios->subdev.device->devinit; 344 struct nvkm_devinit *devinit = init->subdev->device->devinit;
345 if (init_exec(init)) { 345 if (init_exec(init)) {
346 int ret = nvkm_devinit_pll_set(devinit, id, freq); 346 int ret = nvkm_devinit_pll_set(devinit, id, freq);
347 if (ret) 347 if (ret)
@@ -374,7 +374,7 @@ init_table(struct nvkm_bios *bios, u16 *len)
374static u16 374static u16
375init_table_(struct nvbios_init *init, u16 offset, const char *name) 375init_table_(struct nvbios_init *init, u16 offset, const char *name)
376{ 376{
377 struct nvkm_bios *bios = init->bios; 377 struct nvkm_bios *bios = init->subdev->device->bios;
378 u16 len, data = init_table(bios, &len); 378 u16 len, data = init_table(bios, &len);
379 if (data) { 379 if (data) {
380 if (len >= offset + 2) { 380 if (len >= offset + 2) {
@@ -406,7 +406,7 @@ init_table_(struct nvbios_init *init, u16 offset, const char *name)
406static u16 406static u16
407init_script(struct nvkm_bios *bios, int index) 407init_script(struct nvkm_bios *bios, int index)
408{ 408{
409 struct nvbios_init init = { .bios = bios }; 409 struct nvbios_init init = { .subdev = &bios->subdev };
410 u16 bmp_ver = bmp_version(bios), data; 410 u16 bmp_ver = bmp_version(bios), data;
411 411
412 if (bmp_ver && bmp_ver < 0x0510) { 412 if (bmp_ver && bmp_ver < 0x0510) {
@@ -436,7 +436,7 @@ init_unknown_script(struct nvkm_bios *bios)
436static u8 436static u8
437init_ram_restrict_group_count(struct nvbios_init *init) 437init_ram_restrict_group_count(struct nvbios_init *init)
438{ 438{
439 return nvbios_ramcfg_count(init->bios); 439 return nvbios_ramcfg_count(init->subdev->device->bios);
440} 440}
441 441
442static u8 442static u8
@@ -450,7 +450,7 @@ init_ram_restrict(struct nvbios_init *init)
450 * Preserving the non-caching behaviour on earlier chipsets just 450 * Preserving the non-caching behaviour on earlier chipsets just
451 * in case *not* re-reading the strap causes similar breakage. 451 * in case *not* re-reading the strap causes similar breakage.
452 */ 452 */
453 if (!init->ramcfg || init->bios->version.major < 0x70) 453 if (!init->ramcfg || init->subdev->device->bios->version.major < 0x70)
454 init->ramcfg = 0x80000000 | nvbios_ramcfg_index(init->subdev); 454 init->ramcfg = 0x80000000 | nvbios_ramcfg_index(init->subdev);
455 return (init->ramcfg & 0x7fffffff); 455 return (init->ramcfg & 0x7fffffff);
456} 456}
@@ -458,7 +458,7 @@ init_ram_restrict(struct nvbios_init *init)
458static u8 458static u8
459init_xlat_(struct nvbios_init *init, u8 index, u8 offset) 459init_xlat_(struct nvbios_init *init, u8 index, u8 offset)
460{ 460{
461 struct nvkm_bios *bios = init->bios; 461 struct nvkm_bios *bios = init->subdev->device->bios;
462 u16 table = init_xlat_table(init); 462 u16 table = init_xlat_table(init);
463 if (table) { 463 if (table) {
464 u16 data = nvbios_rd16(bios, table + (index * 2)); 464 u16 data = nvbios_rd16(bios, table + (index * 2));
@@ -476,7 +476,7 @@ init_xlat_(struct nvbios_init *init, u8 index, u8 offset)
476static bool 476static bool
477init_condition_met(struct nvbios_init *init, u8 cond) 477init_condition_met(struct nvbios_init *init, u8 cond)
478{ 478{
479 struct nvkm_bios *bios = init->bios; 479 struct nvkm_bios *bios = init->subdev->device->bios;
480 u16 table = init_condition_table(init); 480 u16 table = init_condition_table(init);
481 if (table) { 481 if (table) {
482 u32 reg = nvbios_rd32(bios, table + (cond * 12) + 0); 482 u32 reg = nvbios_rd32(bios, table + (cond * 12) + 0);
@@ -492,7 +492,7 @@ init_condition_met(struct nvbios_init *init, u8 cond)
492static bool 492static bool
493init_io_condition_met(struct nvbios_init *init, u8 cond) 493init_io_condition_met(struct nvbios_init *init, u8 cond)
494{ 494{
495 struct nvkm_bios *bios = init->bios; 495 struct nvkm_bios *bios = init->subdev->device->bios;
496 u16 table = init_io_condition_table(init); 496 u16 table = init_io_condition_table(init);
497 if (table) { 497 if (table) {
498 u16 port = nvbios_rd16(bios, table + (cond * 5) + 0); 498 u16 port = nvbios_rd16(bios, table + (cond * 5) + 0);
@@ -509,7 +509,7 @@ init_io_condition_met(struct nvbios_init *init, u8 cond)
509static bool 509static bool
510init_io_flag_condition_met(struct nvbios_init *init, u8 cond) 510init_io_flag_condition_met(struct nvbios_init *init, u8 cond)
511{ 511{
512 struct nvkm_bios *bios = init->bios; 512 struct nvkm_bios *bios = init->subdev->device->bios;
513 u16 table = init_io_flag_condition_table(init); 513 u16 table = init_io_flag_condition_table(init);
514 if (table) { 514 if (table) {
515 u16 port = nvbios_rd16(bios, table + (cond * 9) + 0); 515 u16 port = nvbios_rd16(bios, table + (cond * 9) + 0);
@@ -580,7 +580,8 @@ init_tmds_reg(struct nvbios_init *init, u8 tmds)
580static void 580static void
581init_reserved(struct nvbios_init *init) 581init_reserved(struct nvbios_init *init)
582{ 582{
583 u8 opcode = nvbios_rd08(init->bios, init->offset); 583 struct nvkm_bios *bios = init->subdev->device->bios;
584 u8 opcode = nvbios_rd08(bios, init->offset);
584 u8 length, i; 585 u8 length, i;
585 586
586 switch (opcode) { 587 switch (opcode) {
@@ -594,7 +595,7 @@ init_reserved(struct nvbios_init *init)
594 595
595 trace("RESERVED 0x%02x\t", opcode); 596 trace("RESERVED 0x%02x\t", opcode);
596 for (i = 1; i < length; i++) 597 for (i = 1; i < length; i++)
597 cont(" 0x%02x", nvbios_rd08(init->bios, init->offset + i)); 598 cont(" 0x%02x", nvbios_rd08(bios, init->offset + i));
598 cont("\n"); 599 cont("\n");
599 init->offset += length; 600 init->offset += length;
600} 601}
@@ -617,7 +618,7 @@ init_done(struct nvbios_init *init)
617static void 618static void
618init_io_restrict_prog(struct nvbios_init *init) 619init_io_restrict_prog(struct nvbios_init *init)
619{ 620{
620 struct nvkm_bios *bios = init->bios; 621 struct nvkm_bios *bios = init->subdev->device->bios;
621 u16 port = nvbios_rd16(bios, init->offset + 1); 622 u16 port = nvbios_rd16(bios, init->offset + 1);
622 u8 index = nvbios_rd08(bios, init->offset + 3); 623 u8 index = nvbios_rd08(bios, init->offset + 3);
623 u8 mask = nvbios_rd08(bios, init->offset + 4); 624 u8 mask = nvbios_rd08(bios, init->offset + 4);
@@ -654,7 +655,7 @@ init_io_restrict_prog(struct nvbios_init *init)
654static void 655static void
655init_repeat(struct nvbios_init *init) 656init_repeat(struct nvbios_init *init)
656{ 657{
657 struct nvkm_bios *bios = init->bios; 658 struct nvkm_bios *bios = init->subdev->device->bios;
658 u8 count = nvbios_rd08(bios, init->offset + 1); 659 u8 count = nvbios_rd08(bios, init->offset + 1);
659 u16 repeat = init->repeat; 660 u16 repeat = init->repeat;
660 661
@@ -680,7 +681,7 @@ init_repeat(struct nvbios_init *init)
680static void 681static void
681init_io_restrict_pll(struct nvbios_init *init) 682init_io_restrict_pll(struct nvbios_init *init)
682{ 683{
683 struct nvkm_bios *bios = init->bios; 684 struct nvkm_bios *bios = init->subdev->device->bios;
684 u16 port = nvbios_rd16(bios, init->offset + 1); 685 u16 port = nvbios_rd16(bios, init->offset + 1);
685 u8 index = nvbios_rd08(bios, init->offset + 3); 686 u8 index = nvbios_rd08(bios, init->offset + 3);
686 u8 mask = nvbios_rd08(bios, init->offset + 4); 687 u8 mask = nvbios_rd08(bios, init->offset + 4);
@@ -736,7 +737,7 @@ init_end_repeat(struct nvbios_init *init)
736static void 737static void
737init_copy(struct nvbios_init *init) 738init_copy(struct nvbios_init *init)
738{ 739{
739 struct nvkm_bios *bios = init->bios; 740 struct nvkm_bios *bios = init->subdev->device->bios;
740 u32 reg = nvbios_rd32(bios, init->offset + 1); 741 u32 reg = nvbios_rd32(bios, init->offset + 1);
741 u8 shift = nvbios_rd08(bios, init->offset + 5); 742 u8 shift = nvbios_rd08(bios, init->offset + 5);
742 u8 smask = nvbios_rd08(bios, init->offset + 6); 743 u8 smask = nvbios_rd08(bios, init->offset + 6);
@@ -775,7 +776,7 @@ init_not(struct nvbios_init *init)
775static void 776static void
776init_io_flag_condition(struct nvbios_init *init) 777init_io_flag_condition(struct nvbios_init *init)
777{ 778{
778 struct nvkm_bios *bios = init->bios; 779 struct nvkm_bios *bios = init->subdev->device->bios;
779 u8 cond = nvbios_rd08(bios, init->offset + 1); 780 u8 cond = nvbios_rd08(bios, init->offset + 1);
780 781
781 trace("IO_FLAG_CONDITION\t0x%02x\n", cond); 782 trace("IO_FLAG_CONDITION\t0x%02x\n", cond);
@@ -792,7 +793,7 @@ init_io_flag_condition(struct nvbios_init *init)
792static void 793static void
793init_generic_condition(struct nvbios_init *init) 794init_generic_condition(struct nvbios_init *init)
794{ 795{
795 struct nvkm_bios *bios = init->bios; 796 struct nvkm_bios *bios = init->subdev->device->bios;
796 struct nvbios_dpout info; 797 struct nvbios_dpout info;
797 u8 cond = nvbios_rd08(bios, init->offset + 1); 798 u8 cond = nvbios_rd08(bios, init->offset + 1);
798 u8 size = nvbios_rd08(bios, init->offset + 2); 799 u8 size = nvbios_rd08(bios, init->offset + 2);
@@ -841,7 +842,7 @@ init_generic_condition(struct nvbios_init *init)
841static void 842static void
842init_io_mask_or(struct nvbios_init *init) 843init_io_mask_or(struct nvbios_init *init)
843{ 844{
844 struct nvkm_bios *bios = init->bios; 845 struct nvkm_bios *bios = init->subdev->device->bios;
845 u8 index = nvbios_rd08(bios, init->offset + 1); 846 u8 index = nvbios_rd08(bios, init->offset + 1);
846 u8 or = init_or(init); 847 u8 or = init_or(init);
847 u8 data; 848 u8 data;
@@ -860,7 +861,7 @@ init_io_mask_or(struct nvbios_init *init)
860static void 861static void
861init_io_or(struct nvbios_init *init) 862init_io_or(struct nvbios_init *init)
862{ 863{
863 struct nvkm_bios *bios = init->bios; 864 struct nvkm_bios *bios = init->subdev->device->bios;
864 u8 index = nvbios_rd08(bios, init->offset + 1); 865 u8 index = nvbios_rd08(bios, init->offset + 1);
865 u8 or = init_or(init); 866 u8 or = init_or(init);
866 u8 data; 867 u8 data;
@@ -879,7 +880,7 @@ init_io_or(struct nvbios_init *init)
879static void 880static void
880init_andn_reg(struct nvbios_init *init) 881init_andn_reg(struct nvbios_init *init)
881{ 882{
882 struct nvkm_bios *bios = init->bios; 883 struct nvkm_bios *bios = init->subdev->device->bios;
883 u32 reg = nvbios_rd32(bios, init->offset + 1); 884 u32 reg = nvbios_rd32(bios, init->offset + 1);
884 u32 mask = nvbios_rd32(bios, init->offset + 5); 885 u32 mask = nvbios_rd32(bios, init->offset + 5);
885 886
@@ -896,7 +897,7 @@ init_andn_reg(struct nvbios_init *init)
896static void 897static void
897init_or_reg(struct nvbios_init *init) 898init_or_reg(struct nvbios_init *init)
898{ 899{
899 struct nvkm_bios *bios = init->bios; 900 struct nvkm_bios *bios = init->subdev->device->bios;
900 u32 reg = nvbios_rd32(bios, init->offset + 1); 901 u32 reg = nvbios_rd32(bios, init->offset + 1);
901 u32 mask = nvbios_rd32(bios, init->offset + 5); 902 u32 mask = nvbios_rd32(bios, init->offset + 5);
902 903
@@ -913,7 +914,7 @@ init_or_reg(struct nvbios_init *init)
913static void 914static void
914init_idx_addr_latched(struct nvbios_init *init) 915init_idx_addr_latched(struct nvbios_init *init)
915{ 916{
916 struct nvkm_bios *bios = init->bios; 917 struct nvkm_bios *bios = init->subdev->device->bios;
917 u32 creg = nvbios_rd32(bios, init->offset + 1); 918 u32 creg = nvbios_rd32(bios, init->offset + 1);
918 u32 dreg = nvbios_rd32(bios, init->offset + 5); 919 u32 dreg = nvbios_rd32(bios, init->offset + 5);
919 u32 mask = nvbios_rd32(bios, init->offset + 9); 920 u32 mask = nvbios_rd32(bios, init->offset + 9);
@@ -943,7 +944,7 @@ init_idx_addr_latched(struct nvbios_init *init)
943static void 944static void
944init_io_restrict_pll2(struct nvbios_init *init) 945init_io_restrict_pll2(struct nvbios_init *init)
945{ 946{
946 struct nvkm_bios *bios = init->bios; 947 struct nvkm_bios *bios = init->subdev->device->bios;
947 u16 port = nvbios_rd16(bios, init->offset + 1); 948 u16 port = nvbios_rd16(bios, init->offset + 1);
948 u8 index = nvbios_rd08(bios, init->offset + 3); 949 u8 index = nvbios_rd08(bios, init->offset + 3);
949 u8 mask = nvbios_rd08(bios, init->offset + 4); 950 u8 mask = nvbios_rd08(bios, init->offset + 4);
@@ -978,7 +979,7 @@ init_io_restrict_pll2(struct nvbios_init *init)
978static void 979static void
979init_pll2(struct nvbios_init *init) 980init_pll2(struct nvbios_init *init)
980{ 981{
981 struct nvkm_bios *bios = init->bios; 982 struct nvkm_bios *bios = init->subdev->device->bios;
982 u32 reg = nvbios_rd32(bios, init->offset + 1); 983 u32 reg = nvbios_rd32(bios, init->offset + 1);
983 u32 freq = nvbios_rd32(bios, init->offset + 5); 984 u32 freq = nvbios_rd32(bios, init->offset + 5);
984 985
@@ -995,7 +996,7 @@ init_pll2(struct nvbios_init *init)
995static void 996static void
996init_i2c_byte(struct nvbios_init *init) 997init_i2c_byte(struct nvbios_init *init)
997{ 998{
998 struct nvkm_bios *bios = init->bios; 999 struct nvkm_bios *bios = init->subdev->device->bios;
999 u8 index = nvbios_rd08(bios, init->offset + 1); 1000 u8 index = nvbios_rd08(bios, init->offset + 1);
1000 u8 addr = nvbios_rd08(bios, init->offset + 2) >> 1; 1001 u8 addr = nvbios_rd08(bios, init->offset + 2) >> 1;
1001 u8 count = nvbios_rd08(bios, init->offset + 3); 1002 u8 count = nvbios_rd08(bios, init->offset + 3);
@@ -1026,7 +1027,7 @@ init_i2c_byte(struct nvbios_init *init)
1026static void 1027static void
1027init_zm_i2c_byte(struct nvbios_init *init) 1028init_zm_i2c_byte(struct nvbios_init *init)
1028{ 1029{
1029 struct nvkm_bios *bios = init->bios; 1030 struct nvkm_bios *bios = init->subdev->device->bios;
1030 u8 index = nvbios_rd08(bios, init->offset + 1); 1031 u8 index = nvbios_rd08(bios, init->offset + 1);
1031 u8 addr = nvbios_rd08(bios, init->offset + 2) >> 1; 1032 u8 addr = nvbios_rd08(bios, init->offset + 2) >> 1;
1032 u8 count = nvbios_rd08(bios, init->offset + 3); 1033 u8 count = nvbios_rd08(bios, init->offset + 3);
@@ -1052,7 +1053,7 @@ init_zm_i2c_byte(struct nvbios_init *init)
1052static void 1053static void
1053init_zm_i2c(struct nvbios_init *init) 1054init_zm_i2c(struct nvbios_init *init)
1054{ 1055{
1055 struct nvkm_bios *bios = init->bios; 1056 struct nvkm_bios *bios = init->subdev->device->bios;
1056 u8 index = nvbios_rd08(bios, init->offset + 1); 1057 u8 index = nvbios_rd08(bios, init->offset + 1);
1057 u8 addr = nvbios_rd08(bios, init->offset + 2) >> 1; 1058 u8 addr = nvbios_rd08(bios, init->offset + 2) >> 1;
1058 u8 count = nvbios_rd08(bios, init->offset + 3); 1059 u8 count = nvbios_rd08(bios, init->offset + 3);
@@ -1086,7 +1087,7 @@ init_zm_i2c(struct nvbios_init *init)
1086static void 1087static void
1087init_tmds(struct nvbios_init *init) 1088init_tmds(struct nvbios_init *init)
1088{ 1089{
1089 struct nvkm_bios *bios = init->bios; 1090 struct nvkm_bios *bios = init->subdev->device->bios;
1090 u8 tmds = nvbios_rd08(bios, init->offset + 1); 1091 u8 tmds = nvbios_rd08(bios, init->offset + 1);
1091 u8 addr = nvbios_rd08(bios, init->offset + 2); 1092 u8 addr = nvbios_rd08(bios, init->offset + 2);
1092 u8 mask = nvbios_rd08(bios, init->offset + 3); 1093 u8 mask = nvbios_rd08(bios, init->offset + 3);
@@ -1112,7 +1113,7 @@ init_tmds(struct nvbios_init *init)
1112static void 1113static void
1113init_zm_tmds_group(struct nvbios_init *init) 1114init_zm_tmds_group(struct nvbios_init *init)
1114{ 1115{
1115 struct nvkm_bios *bios = init->bios; 1116 struct nvkm_bios *bios = init->subdev->device->bios;
1116 u8 tmds = nvbios_rd08(bios, init->offset + 1); 1117 u8 tmds = nvbios_rd08(bios, init->offset + 1);
1117 u8 count = nvbios_rd08(bios, init->offset + 2); 1118 u8 count = nvbios_rd08(bios, init->offset + 2);
1118 u32 reg = init_tmds_reg(init, tmds); 1119 u32 reg = init_tmds_reg(init, tmds);
@@ -1139,7 +1140,7 @@ init_zm_tmds_group(struct nvbios_init *init)
1139static void 1140static void
1140init_cr_idx_adr_latch(struct nvbios_init *init) 1141init_cr_idx_adr_latch(struct nvbios_init *init)
1141{ 1142{
1142 struct nvkm_bios *bios = init->bios; 1143 struct nvkm_bios *bios = init->subdev->device->bios;
1143 u8 addr0 = nvbios_rd08(bios, init->offset + 1); 1144 u8 addr0 = nvbios_rd08(bios, init->offset + 1);
1144 u8 addr1 = nvbios_rd08(bios, init->offset + 2); 1145 u8 addr1 = nvbios_rd08(bios, init->offset + 2);
1145 u8 base = nvbios_rd08(bios, init->offset + 3); 1146 u8 base = nvbios_rd08(bios, init->offset + 3);
@@ -1169,7 +1170,7 @@ init_cr_idx_adr_latch(struct nvbios_init *init)
1169static void 1170static void
1170init_cr(struct nvbios_init *init) 1171init_cr(struct nvbios_init *init)
1171{ 1172{
1172 struct nvkm_bios *bios = init->bios; 1173 struct nvkm_bios *bios = init->subdev->device->bios;
1173 u8 addr = nvbios_rd08(bios, init->offset + 1); 1174 u8 addr = nvbios_rd08(bios, init->offset + 1);
1174 u8 mask = nvbios_rd08(bios, init->offset + 2); 1175 u8 mask = nvbios_rd08(bios, init->offset + 2);
1175 u8 data = nvbios_rd08(bios, init->offset + 3); 1176 u8 data = nvbios_rd08(bios, init->offset + 3);
@@ -1189,7 +1190,7 @@ init_cr(struct nvbios_init *init)
1189static void 1190static void
1190init_zm_cr(struct nvbios_init *init) 1191init_zm_cr(struct nvbios_init *init)
1191{ 1192{
1192 struct nvkm_bios *bios = init->bios; 1193 struct nvkm_bios *bios = init->subdev->device->bios;
1193 u8 addr = nvbios_rd08(bios, init->offset + 1); 1194 u8 addr = nvbios_rd08(bios, init->offset + 1);
1194 u8 data = nvbios_rd08(bios, init->offset + 2); 1195 u8 data = nvbios_rd08(bios, init->offset + 2);
1195 1196
@@ -1206,7 +1207,7 @@ init_zm_cr(struct nvbios_init *init)
1206static void 1207static void
1207init_zm_cr_group(struct nvbios_init *init) 1208init_zm_cr_group(struct nvbios_init *init)
1208{ 1209{
1209 struct nvkm_bios *bios = init->bios; 1210 struct nvkm_bios *bios = init->subdev->device->bios;
1210 u8 count = nvbios_rd08(bios, init->offset + 1); 1211 u8 count = nvbios_rd08(bios, init->offset + 1);
1211 1212
1212 trace("ZM_CR_GROUP\n"); 1213 trace("ZM_CR_GROUP\n");
@@ -1230,7 +1231,7 @@ init_zm_cr_group(struct nvbios_init *init)
1230static void 1231static void
1231init_condition_time(struct nvbios_init *init) 1232init_condition_time(struct nvbios_init *init)
1232{ 1233{
1233 struct nvkm_bios *bios = init->bios; 1234 struct nvkm_bios *bios = init->subdev->device->bios;
1234 u8 cond = nvbios_rd08(bios, init->offset + 1); 1235 u8 cond = nvbios_rd08(bios, init->offset + 1);
1235 u8 retry = nvbios_rd08(bios, init->offset + 2); 1236 u8 retry = nvbios_rd08(bios, init->offset + 2);
1236 u8 wait = min((u16)retry * 50, 100); 1237 u8 wait = min((u16)retry * 50, 100);
@@ -1257,7 +1258,7 @@ init_condition_time(struct nvbios_init *init)
1257static void 1258static void
1258init_ltime(struct nvbios_init *init) 1259init_ltime(struct nvbios_init *init)
1259{ 1260{
1260 struct nvkm_bios *bios = init->bios; 1261 struct nvkm_bios *bios = init->subdev->device->bios;
1261 u16 msec = nvbios_rd16(bios, init->offset + 1); 1262 u16 msec = nvbios_rd16(bios, init->offset + 1);
1262 1263
1263 trace("LTIME\t0x%04x\n", msec); 1264 trace("LTIME\t0x%04x\n", msec);
@@ -1274,7 +1275,7 @@ init_ltime(struct nvbios_init *init)
1274static void 1275static void
1275init_zm_reg_sequence(struct nvbios_init *init) 1276init_zm_reg_sequence(struct nvbios_init *init)
1276{ 1277{
1277 struct nvkm_bios *bios = init->bios; 1278 struct nvkm_bios *bios = init->subdev->device->bios;
1278 u32 base = nvbios_rd32(bios, init->offset + 1); 1279 u32 base = nvbios_rd32(bios, init->offset + 1);
1279 u8 count = nvbios_rd08(bios, init->offset + 5); 1280 u8 count = nvbios_rd08(bios, init->offset + 5);
1280 1281
@@ -1299,7 +1300,7 @@ init_zm_reg_sequence(struct nvbios_init *init)
1299static void 1300static void
1300init_pll_indirect(struct nvbios_init *init) 1301init_pll_indirect(struct nvbios_init *init)
1301{ 1302{
1302 struct nvkm_bios *bios = init->bios; 1303 struct nvkm_bios *bios = init->subdev->device->bios;
1303 u32 reg = nvbios_rd32(bios, init->offset + 1); 1304 u32 reg = nvbios_rd32(bios, init->offset + 1);
1304 u16 addr = nvbios_rd16(bios, init->offset + 5); 1305 u16 addr = nvbios_rd16(bios, init->offset + 5);
1305 u32 freq = (u32)nvbios_rd16(bios, addr) * 1000; 1306 u32 freq = (u32)nvbios_rd16(bios, addr) * 1000;
@@ -1318,7 +1319,7 @@ init_pll_indirect(struct nvbios_init *init)
1318static void 1319static void
1319init_zm_reg_indirect(struct nvbios_init *init) 1320init_zm_reg_indirect(struct nvbios_init *init)
1320{ 1321{
1321 struct nvkm_bios *bios = init->bios; 1322 struct nvkm_bios *bios = init->subdev->device->bios;
1322 u32 reg = nvbios_rd32(bios, init->offset + 1); 1323 u32 reg = nvbios_rd32(bios, init->offset + 1);
1323 u16 addr = nvbios_rd16(bios, init->offset + 5); 1324 u16 addr = nvbios_rd16(bios, init->offset + 5);
1324 u32 data = nvbios_rd32(bios, addr); 1325 u32 data = nvbios_rd32(bios, addr);
@@ -1337,7 +1338,7 @@ init_zm_reg_indirect(struct nvbios_init *init)
1337static void 1338static void
1338init_sub_direct(struct nvbios_init *init) 1339init_sub_direct(struct nvbios_init *init)
1339{ 1340{
1340 struct nvkm_bios *bios = init->bios; 1341 struct nvkm_bios *bios = init->subdev->device->bios;
1341 u16 addr = nvbios_rd16(bios, init->offset + 1); 1342 u16 addr = nvbios_rd16(bios, init->offset + 1);
1342 u16 save; 1343 u16 save;
1343 1344
@@ -1363,7 +1364,7 @@ init_sub_direct(struct nvbios_init *init)
1363static void 1364static void
1364init_jump(struct nvbios_init *init) 1365init_jump(struct nvbios_init *init)
1365{ 1366{
1366 struct nvkm_bios *bios = init->bios; 1367 struct nvkm_bios *bios = init->subdev->device->bios;
1367 u16 offset = nvbios_rd16(bios, init->offset + 1); 1368 u16 offset = nvbios_rd16(bios, init->offset + 1);
1368 1369
1369 trace("JUMP\t0x%04x\n", offset); 1370 trace("JUMP\t0x%04x\n", offset);
@@ -1381,7 +1382,7 @@ init_jump(struct nvbios_init *init)
1381static void 1382static void
1382init_i2c_if(struct nvbios_init *init) 1383init_i2c_if(struct nvbios_init *init)
1383{ 1384{
1384 struct nvkm_bios *bios = init->bios; 1385 struct nvkm_bios *bios = init->subdev->device->bios;
1385 u8 index = nvbios_rd08(bios, init->offset + 1); 1386 u8 index = nvbios_rd08(bios, init->offset + 1);
1386 u8 addr = nvbios_rd08(bios, init->offset + 2); 1387 u8 addr = nvbios_rd08(bios, init->offset + 2);
1387 u8 reg = nvbios_rd08(bios, init->offset + 3); 1388 u8 reg = nvbios_rd08(bios, init->offset + 3);
@@ -1408,7 +1409,7 @@ init_i2c_if(struct nvbios_init *init)
1408static void 1409static void
1409init_copy_nv_reg(struct nvbios_init *init) 1410init_copy_nv_reg(struct nvbios_init *init)
1410{ 1411{
1411 struct nvkm_bios *bios = init->bios; 1412 struct nvkm_bios *bios = init->subdev->device->bios;
1412 u32 sreg = nvbios_rd32(bios, init->offset + 1); 1413 u32 sreg = nvbios_rd32(bios, init->offset + 1);
1413 u8 shift = nvbios_rd08(bios, init->offset + 5); 1414 u8 shift = nvbios_rd08(bios, init->offset + 5);
1414 u32 smask = nvbios_rd32(bios, init->offset + 6); 1415 u32 smask = nvbios_rd32(bios, init->offset + 6);
@@ -1434,7 +1435,7 @@ init_copy_nv_reg(struct nvbios_init *init)
1434static void 1435static void
1435init_zm_index_io(struct nvbios_init *init) 1436init_zm_index_io(struct nvbios_init *init)
1436{ 1437{
1437 struct nvkm_bios *bios = init->bios; 1438 struct nvkm_bios *bios = init->subdev->device->bios;
1438 u16 port = nvbios_rd16(bios, init->offset + 1); 1439 u16 port = nvbios_rd16(bios, init->offset + 1);
1439 u8 index = nvbios_rd08(bios, init->offset + 3); 1440 u8 index = nvbios_rd08(bios, init->offset + 3);
1440 u8 data = nvbios_rd08(bios, init->offset + 4); 1441 u8 data = nvbios_rd08(bios, init->offset + 4);
@@ -1452,7 +1453,7 @@ init_zm_index_io(struct nvbios_init *init)
1452static void 1453static void
1453init_compute_mem(struct nvbios_init *init) 1454init_compute_mem(struct nvbios_init *init)
1454{ 1455{
1455 struct nvkm_devinit *devinit = init->bios->subdev.device->devinit; 1456 struct nvkm_devinit *devinit = init->subdev->device->devinit;
1456 1457
1457 trace("COMPUTE_MEM\n"); 1458 trace("COMPUTE_MEM\n");
1458 init->offset += 1; 1459 init->offset += 1;
@@ -1470,7 +1471,7 @@ init_compute_mem(struct nvbios_init *init)
1470static void 1471static void
1471init_reset(struct nvbios_init *init) 1472init_reset(struct nvbios_init *init)
1472{ 1473{
1473 struct nvkm_bios *bios = init->bios; 1474 struct nvkm_bios *bios = init->subdev->device->bios;
1474 u32 reg = nvbios_rd32(bios, init->offset + 1); 1475 u32 reg = nvbios_rd32(bios, init->offset + 1);
1475 u32 data1 = nvbios_rd32(bios, init->offset + 5); 1476 u32 data1 = nvbios_rd32(bios, init->offset + 5);
1476 u32 data2 = nvbios_rd32(bios, init->offset + 9); 1477 u32 data2 = nvbios_rd32(bios, init->offset + 9);
@@ -1497,7 +1498,7 @@ init_reset(struct nvbios_init *init)
1497static u16 1498static u16
1498init_configure_mem_clk(struct nvbios_init *init) 1499init_configure_mem_clk(struct nvbios_init *init)
1499{ 1500{
1500 u16 mdata = bmp_mem_init_table(init->bios); 1501 u16 mdata = bmp_mem_init_table(init->subdev->device->bios);
1501 if (mdata) 1502 if (mdata)
1502 mdata += (init_rdvgai(init, 0x03d4, 0x3c) >> 4) * 66; 1503 mdata += (init_rdvgai(init, 0x03d4, 0x3c) >> 4) * 66;
1503 return mdata; 1504 return mdata;
@@ -1506,7 +1507,7 @@ init_configure_mem_clk(struct nvbios_init *init)
1506static void 1507static void
1507init_configure_mem(struct nvbios_init *init) 1508init_configure_mem(struct nvbios_init *init)
1508{ 1509{
1509 struct nvkm_bios *bios = init->bios; 1510 struct nvkm_bios *bios = init->subdev->device->bios;
1510 u16 mdata, sdata; 1511 u16 mdata, sdata;
1511 u32 addr, data; 1512 u32 addr, data;
1512 1513
@@ -1556,7 +1557,7 @@ init_configure_mem(struct nvbios_init *init)
1556static void 1557static void
1557init_configure_clk(struct nvbios_init *init) 1558init_configure_clk(struct nvbios_init *init)
1558{ 1559{
1559 struct nvkm_bios *bios = init->bios; 1560 struct nvkm_bios *bios = init->subdev->device->bios;
1560 u16 mdata, clock; 1561 u16 mdata, clock;
1561 1562
1562 trace("CONFIGURE_CLK\n"); 1563 trace("CONFIGURE_CLK\n");
@@ -1590,7 +1591,7 @@ init_configure_clk(struct nvbios_init *init)
1590static void 1591static void
1591init_configure_preinit(struct nvbios_init *init) 1592init_configure_preinit(struct nvbios_init *init)
1592{ 1593{
1593 struct nvkm_bios *bios = init->bios; 1594 struct nvkm_bios *bios = init->subdev->device->bios;
1594 u32 strap; 1595 u32 strap;
1595 1596
1596 trace("CONFIGURE_PREINIT\n"); 1597 trace("CONFIGURE_PREINIT\n");
@@ -1616,7 +1617,7 @@ init_configure_preinit(struct nvbios_init *init)
1616static void 1617static void
1617init_io(struct nvbios_init *init) 1618init_io(struct nvbios_init *init)
1618{ 1619{
1619 struct nvkm_bios *bios = init->bios; 1620 struct nvkm_bios *bios = init->subdev->device->bios;
1620 u16 port = nvbios_rd16(bios, init->offset + 1); 1621 u16 port = nvbios_rd16(bios, init->offset + 1);
1621 u8 mask = nvbios_rd16(bios, init->offset + 3); 1622 u8 mask = nvbios_rd16(bios, init->offset + 3);
1622 u8 data = nvbios_rd16(bios, init->offset + 4); 1623 u8 data = nvbios_rd16(bios, init->offset + 4);
@@ -1656,7 +1657,7 @@ init_io(struct nvbios_init *init)
1656static void 1657static void
1657init_sub(struct nvbios_init *init) 1658init_sub(struct nvbios_init *init)
1658{ 1659{
1659 struct nvkm_bios *bios = init->bios; 1660 struct nvkm_bios *bios = init->subdev->device->bios;
1660 u8 index = nvbios_rd08(bios, init->offset + 1); 1661 u8 index = nvbios_rd08(bios, init->offset + 1);
1661 u16 addr, save; 1662 u16 addr, save;
1662 1663
@@ -1683,7 +1684,7 @@ init_sub(struct nvbios_init *init)
1683static void 1684static void
1684init_ram_condition(struct nvbios_init *init) 1685init_ram_condition(struct nvbios_init *init)
1685{ 1686{
1686 struct nvkm_bios *bios = init->bios; 1687 struct nvkm_bios *bios = init->subdev->device->bios;
1687 u8 mask = nvbios_rd08(bios, init->offset + 1); 1688 u8 mask = nvbios_rd08(bios, init->offset + 1);
1688 u8 value = nvbios_rd08(bios, init->offset + 2); 1689 u8 value = nvbios_rd08(bios, init->offset + 2);
1689 1690
@@ -1702,7 +1703,7 @@ init_ram_condition(struct nvbios_init *init)
1702static void 1703static void
1703init_nv_reg(struct nvbios_init *init) 1704init_nv_reg(struct nvbios_init *init)
1704{ 1705{
1705 struct nvkm_bios *bios = init->bios; 1706 struct nvkm_bios *bios = init->subdev->device->bios;
1706 u32 reg = nvbios_rd32(bios, init->offset + 1); 1707 u32 reg = nvbios_rd32(bios, init->offset + 1);
1707 u32 mask = nvbios_rd32(bios, init->offset + 5); 1708 u32 mask = nvbios_rd32(bios, init->offset + 5);
1708 u32 data = nvbios_rd32(bios, init->offset + 9); 1709 u32 data = nvbios_rd32(bios, init->offset + 9);
@@ -1720,7 +1721,7 @@ init_nv_reg(struct nvbios_init *init)
1720static void 1721static void
1721init_macro(struct nvbios_init *init) 1722init_macro(struct nvbios_init *init)
1722{ 1723{
1723 struct nvkm_bios *bios = init->bios; 1724 struct nvkm_bios *bios = init->subdev->device->bios;
1724 u8 macro = nvbios_rd08(bios, init->offset + 1); 1725 u8 macro = nvbios_rd08(bios, init->offset + 1);
1725 u16 table; 1726 u16 table;
1726 1727
@@ -1756,7 +1757,7 @@ init_resume(struct nvbios_init *init)
1756static void 1757static void
1757init_strap_condition(struct nvbios_init *init) 1758init_strap_condition(struct nvbios_init *init)
1758{ 1759{
1759 struct nvkm_bios *bios = init->bios; 1760 struct nvkm_bios *bios = init->subdev->device->bios;
1760 u32 mask = nvbios_rd32(bios, init->offset + 1); 1761 u32 mask = nvbios_rd32(bios, init->offset + 1);
1761 u32 value = nvbios_rd32(bios, init->offset + 5); 1762 u32 value = nvbios_rd32(bios, init->offset + 5);
1762 1763
@@ -1774,7 +1775,7 @@ init_strap_condition(struct nvbios_init *init)
1774static void 1775static void
1775init_time(struct nvbios_init *init) 1776init_time(struct nvbios_init *init)
1776{ 1777{
1777 struct nvkm_bios *bios = init->bios; 1778 struct nvkm_bios *bios = init->subdev->device->bios;
1778 u16 usec = nvbios_rd16(bios, init->offset + 1); 1779 u16 usec = nvbios_rd16(bios, init->offset + 1);
1779 1780
1780 trace("TIME\t0x%04x\n", usec); 1781 trace("TIME\t0x%04x\n", usec);
@@ -1795,7 +1796,7 @@ init_time(struct nvbios_init *init)
1795static void 1796static void
1796init_condition(struct nvbios_init *init) 1797init_condition(struct nvbios_init *init)
1797{ 1798{
1798 struct nvkm_bios *bios = init->bios; 1799 struct nvkm_bios *bios = init->subdev->device->bios;
1799 u8 cond = nvbios_rd08(bios, init->offset + 1); 1800 u8 cond = nvbios_rd08(bios, init->offset + 1);
1800 1801
1801 trace("CONDITION\t0x%02x\n", cond); 1802 trace("CONDITION\t0x%02x\n", cond);
@@ -1812,7 +1813,7 @@ init_condition(struct nvbios_init *init)
1812static void 1813static void
1813init_io_condition(struct nvbios_init *init) 1814init_io_condition(struct nvbios_init *init)
1814{ 1815{
1815 struct nvkm_bios *bios = init->bios; 1816 struct nvkm_bios *bios = init->subdev->device->bios;
1816 u8 cond = nvbios_rd08(bios, init->offset + 1); 1817 u8 cond = nvbios_rd08(bios, init->offset + 1);
1817 1818
1818 trace("IO_CONDITION\t0x%02x\n", cond); 1819 trace("IO_CONDITION\t0x%02x\n", cond);
@@ -1829,7 +1830,7 @@ init_io_condition(struct nvbios_init *init)
1829static void 1830static void
1830init_zm_reg16(struct nvbios_init *init) 1831init_zm_reg16(struct nvbios_init *init)
1831{ 1832{
1832 struct nvkm_bios *bios = init->bios; 1833 struct nvkm_bios *bios = init->subdev->device->bios;
1833 u32 addr = nvbios_rd32(bios, init->offset + 1); 1834 u32 addr = nvbios_rd32(bios, init->offset + 1);
1834 u16 data = nvbios_rd16(bios, init->offset + 5); 1835 u16 data = nvbios_rd16(bios, init->offset + 5);
1835 1836
@@ -1846,7 +1847,7 @@ init_zm_reg16(struct nvbios_init *init)
1846static void 1847static void
1847init_index_io(struct nvbios_init *init) 1848init_index_io(struct nvbios_init *init)
1848{ 1849{
1849 struct nvkm_bios *bios = init->bios; 1850 struct nvkm_bios *bios = init->subdev->device->bios;
1850 u16 port = nvbios_rd16(bios, init->offset + 1); 1851 u16 port = nvbios_rd16(bios, init->offset + 1);
1851 u8 index = nvbios_rd16(bios, init->offset + 3); 1852 u8 index = nvbios_rd16(bios, init->offset + 3);
1852 u8 mask = nvbios_rd08(bios, init->offset + 4); 1853 u8 mask = nvbios_rd08(bios, init->offset + 4);
@@ -1868,7 +1869,7 @@ init_index_io(struct nvbios_init *init)
1868static void 1869static void
1869init_pll(struct nvbios_init *init) 1870init_pll(struct nvbios_init *init)
1870{ 1871{
1871 struct nvkm_bios *bios = init->bios; 1872 struct nvkm_bios *bios = init->subdev->device->bios;
1872 u32 reg = nvbios_rd32(bios, init->offset + 1); 1873 u32 reg = nvbios_rd32(bios, init->offset + 1);
1873 u32 freq = nvbios_rd16(bios, init->offset + 5) * 10; 1874 u32 freq = nvbios_rd16(bios, init->offset + 5) * 10;
1874 1875
@@ -1885,7 +1886,7 @@ init_pll(struct nvbios_init *init)
1885static void 1886static void
1886init_zm_reg(struct nvbios_init *init) 1887init_zm_reg(struct nvbios_init *init)
1887{ 1888{
1888 struct nvkm_bios *bios = init->bios; 1889 struct nvkm_bios *bios = init->subdev->device->bios;
1889 u32 addr = nvbios_rd32(bios, init->offset + 1); 1890 u32 addr = nvbios_rd32(bios, init->offset + 1);
1890 u32 data = nvbios_rd32(bios, init->offset + 5); 1891 u32 data = nvbios_rd32(bios, init->offset + 5);
1891 1892
@@ -1905,7 +1906,7 @@ init_zm_reg(struct nvbios_init *init)
1905static void 1906static void
1906init_ram_restrict_pll(struct nvbios_init *init) 1907init_ram_restrict_pll(struct nvbios_init *init)
1907{ 1908{
1908 struct nvkm_bios *bios = init->bios; 1909 struct nvkm_bios *bios = init->subdev->device->bios;
1909 u8 type = nvbios_rd08(bios, init->offset + 1); 1910 u8 type = nvbios_rd08(bios, init->offset + 1);
1910 u8 count = init_ram_restrict_group_count(init); 1911 u8 count = init_ram_restrict_group_count(init);
1911 u8 strap = init_ram_restrict(init); 1912 u8 strap = init_ram_restrict(init);
@@ -1935,7 +1936,7 @@ init_ram_restrict_pll(struct nvbios_init *init)
1935static void 1936static void
1936init_gpio(struct nvbios_init *init) 1937init_gpio(struct nvbios_init *init)
1937{ 1938{
1938 struct nvkm_gpio *gpio = init->bios->subdev.device->gpio; 1939 struct nvkm_gpio *gpio = init->subdev->device->gpio;
1939 1940
1940 trace("GPIO\n"); 1941 trace("GPIO\n");
1941 init->offset += 1; 1942 init->offset += 1;
@@ -1951,7 +1952,7 @@ init_gpio(struct nvbios_init *init)
1951static void 1952static void
1952init_ram_restrict_zm_reg_group(struct nvbios_init *init) 1953init_ram_restrict_zm_reg_group(struct nvbios_init *init)
1953{ 1954{
1954 struct nvkm_bios *bios = init->bios; 1955 struct nvkm_bios *bios = init->subdev->device->bios;
1955 u32 addr = nvbios_rd32(bios, init->offset + 1); 1956 u32 addr = nvbios_rd32(bios, init->offset + 1);
1956 u8 incr = nvbios_rd08(bios, init->offset + 5); 1957 u8 incr = nvbios_rd08(bios, init->offset + 5);
1957 u8 num = nvbios_rd08(bios, init->offset + 6); 1958 u8 num = nvbios_rd08(bios, init->offset + 6);
@@ -1989,7 +1990,7 @@ init_ram_restrict_zm_reg_group(struct nvbios_init *init)
1989static void 1990static void
1990init_copy_zm_reg(struct nvbios_init *init) 1991init_copy_zm_reg(struct nvbios_init *init)
1991{ 1992{
1992 struct nvkm_bios *bios = init->bios; 1993 struct nvkm_bios *bios = init->subdev->device->bios;
1993 u32 sreg = nvbios_rd32(bios, init->offset + 1); 1994 u32 sreg = nvbios_rd32(bios, init->offset + 1);
1994 u32 dreg = nvbios_rd32(bios, init->offset + 5); 1995 u32 dreg = nvbios_rd32(bios, init->offset + 5);
1995 1996
@@ -2006,7 +2007,7 @@ init_copy_zm_reg(struct nvbios_init *init)
2006static void 2007static void
2007init_zm_reg_group(struct nvbios_init *init) 2008init_zm_reg_group(struct nvbios_init *init)
2008{ 2009{
2009 struct nvkm_bios *bios = init->bios; 2010 struct nvkm_bios *bios = init->subdev->device->bios;
2010 u32 addr = nvbios_rd32(bios, init->offset + 1); 2011 u32 addr = nvbios_rd32(bios, init->offset + 1);
2011 u8 count = nvbios_rd08(bios, init->offset + 5); 2012 u8 count = nvbios_rd08(bios, init->offset + 5);
2012 2013
@@ -2028,7 +2029,7 @@ init_zm_reg_group(struct nvbios_init *init)
2028static void 2029static void
2029init_xlat(struct nvbios_init *init) 2030init_xlat(struct nvbios_init *init)
2030{ 2031{
2031 struct nvkm_bios *bios = init->bios; 2032 struct nvkm_bios *bios = init->subdev->device->bios;
2032 u32 saddr = nvbios_rd32(bios, init->offset + 1); 2033 u32 saddr = nvbios_rd32(bios, init->offset + 1);
2033 u8 sshift = nvbios_rd08(bios, init->offset + 5); 2034 u8 sshift = nvbios_rd08(bios, init->offset + 5);
2034 u8 smask = nvbios_rd08(bios, init->offset + 6); 2035 u8 smask = nvbios_rd08(bios, init->offset + 6);
@@ -2056,7 +2057,7 @@ init_xlat(struct nvbios_init *init)
2056static void 2057static void
2057init_zm_mask_add(struct nvbios_init *init) 2058init_zm_mask_add(struct nvbios_init *init)
2058{ 2059{
2059 struct nvkm_bios *bios = init->bios; 2060 struct nvkm_bios *bios = init->subdev->device->bios;
2060 u32 addr = nvbios_rd32(bios, init->offset + 1); 2061 u32 addr = nvbios_rd32(bios, init->offset + 1);
2061 u32 mask = nvbios_rd32(bios, init->offset + 5); 2062 u32 mask = nvbios_rd32(bios, init->offset + 5);
2062 u32 add = nvbios_rd32(bios, init->offset + 9); 2063 u32 add = nvbios_rd32(bios, init->offset + 9);
@@ -2077,7 +2078,7 @@ init_zm_mask_add(struct nvbios_init *init)
2077static void 2078static void
2078init_auxch(struct nvbios_init *init) 2079init_auxch(struct nvbios_init *init)
2079{ 2080{
2080 struct nvkm_bios *bios = init->bios; 2081 struct nvkm_bios *bios = init->subdev->device->bios;
2081 u32 addr = nvbios_rd32(bios, init->offset + 1); 2082 u32 addr = nvbios_rd32(bios, init->offset + 1);
2082 u8 count = nvbios_rd08(bios, init->offset + 5); 2083 u8 count = nvbios_rd08(bios, init->offset + 5);
2083 2084
@@ -2101,7 +2102,7 @@ init_auxch(struct nvbios_init *init)
2101static void 2102static void
2102init_zm_auxch(struct nvbios_init *init) 2103init_zm_auxch(struct nvbios_init *init)
2103{ 2104{
2104 struct nvkm_bios *bios = init->bios; 2105 struct nvkm_bios *bios = init->subdev->device->bios;
2105 u32 addr = nvbios_rd32(bios, init->offset + 1); 2106 u32 addr = nvbios_rd32(bios, init->offset + 1);
2106 u8 count = nvbios_rd08(bios, init->offset + 5); 2107 u8 count = nvbios_rd08(bios, init->offset + 5);
2107 2108
@@ -2123,7 +2124,7 @@ init_zm_auxch(struct nvbios_init *init)
2123static void 2124static void
2124init_i2c_long_if(struct nvbios_init *init) 2125init_i2c_long_if(struct nvbios_init *init)
2125{ 2126{
2126 struct nvkm_bios *bios = init->bios; 2127 struct nvkm_bios *bios = init->subdev->device->bios;
2127 u8 index = nvbios_rd08(bios, init->offset + 1); 2128 u8 index = nvbios_rd08(bios, init->offset + 1);
2128 u8 addr = nvbios_rd08(bios, init->offset + 2) >> 1; 2129 u8 addr = nvbios_rd08(bios, init->offset + 2) >> 1;
2129 u8 reglo = nvbios_rd08(bios, init->offset + 3); 2130 u8 reglo = nvbios_rd08(bios, init->offset + 3);
@@ -2162,7 +2163,7 @@ init_i2c_long_if(struct nvbios_init *init)
2162static void 2163static void
2163init_gpio_ne(struct nvbios_init *init) 2164init_gpio_ne(struct nvbios_init *init)
2164{ 2165{
2165 struct nvkm_bios *bios = init->bios; 2166 struct nvkm_bios *bios = init->subdev->device->bios;
2166 struct nvkm_gpio *gpio = bios->subdev.device->gpio; 2167 struct nvkm_gpio *gpio = bios->subdev.device->gpio;
2167 struct dcb_gpio_func func; 2168 struct dcb_gpio_func func;
2168 u8 count = nvbios_rd08(bios, init->offset + 1); 2169 u8 count = nvbios_rd08(bios, init->offset + 1);
@@ -2275,9 +2276,11 @@ static struct nvbios_init_opcode {
2275int 2276int
2276nvbios_exec(struct nvbios_init *init) 2277nvbios_exec(struct nvbios_init *init)
2277{ 2278{
2279 struct nvkm_bios *bios = init->subdev->device->bios;
2280
2278 init->nested++; 2281 init->nested++;
2279 while (init->offset) { 2282 while (init->offset) {
2280 u8 opcode = nvbios_rd08(init->bios, init->offset); 2283 u8 opcode = nvbios_rd08(bios, init->offset);
2281 if (opcode >= init_opcode_nr || !init_opcode[opcode].exec) { 2284 if (opcode >= init_opcode_nr || !init_opcode[opcode].exec) {
2282 error("unknown opcode 0x%02x\n", opcode); 2285 error("unknown opcode 0x%02x\n", opcode);
2283 return -EINVAL; 2286 return -EINVAL;
@@ -2290,7 +2293,7 @@ nvbios_exec(struct nvbios_init *init)
2290} 2293}
2291 2294
2292int 2295int
2293nvbios_init(struct nvkm_subdev *subdev, bool execute) 2296nvbios_post(struct nvkm_subdev *subdev, bool execute)
2294{ 2297{
2295 struct nvkm_bios *bios = subdev->device->bios; 2298 struct nvkm_bios *bios = subdev->device->bios;
2296 int ret = 0; 2299 int ret = 0;
@@ -2300,32 +2303,18 @@ nvbios_init(struct nvkm_subdev *subdev, bool execute)
2300 if (execute) 2303 if (execute)
2301 nvkm_debug(subdev, "running init tables\n"); 2304 nvkm_debug(subdev, "running init tables\n");
2302 while (!ret && (data = (init_script(bios, ++i)))) { 2305 while (!ret && (data = (init_script(bios, ++i)))) {
2303 struct nvbios_init init = { 2306 ret = nvbios_init(subdev, data,
2304 .subdev = subdev, 2307 init.execute = execute ? 1 : 0;
2305 .bios = bios, 2308 );
2306 .offset = data,
2307 .outp = NULL,
2308 .crtc = -1,
2309 .execute = execute ? 1 : 0,
2310 };
2311
2312 ret = nvbios_exec(&init);
2313 } 2309 }
2314 2310
2315 /* the vbios parser will run this right after the normal init 2311 /* the vbios parser will run this right after the normal init
2316 * tables, whereas the binary driver appears to run it later. 2312 * tables, whereas the binary driver appears to run it later.
2317 */ 2313 */
2318 if (!ret && (data = init_unknown_script(bios))) { 2314 if (!ret && (data = init_unknown_script(bios))) {
2319 struct nvbios_init init = { 2315 ret = nvbios_init(subdev, data,
2320 .subdev = subdev, 2316 init.execute = execute ? 1 : 0;
2321 .bios = bios, 2317 );
2322 .offset = data,
2323 .outp = NULL,
2324 .crtc = -1,
2325 .execute = execute ? 1 : 0,
2326 };
2327
2328 ret = nvbios_exec(&init);
2329 } 2318 }
2330 2319
2331 return ret; 2320 return ret;
diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/bios/volt.c b/drivers/gpu/drm/nouveau/nvkm/subdev/bios/volt.c
index a7797a9e9cbc..7143ea4611aa 100644
--- a/drivers/gpu/drm/nouveau/nvkm/subdev/bios/volt.c
+++ b/drivers/gpu/drm/nouveau/nvkm/subdev/bios/volt.c
@@ -93,9 +93,9 @@ nvbios_volt_parse(struct nvkm_bios *bios, u8 *ver, u8 *hdr, u8 *cnt, u8 *len,
93 info->step = nvbios_rd16(bios, volt + 0x08); 93 info->step = nvbios_rd16(bios, volt + 0x08);
94 info->vidmask = nvbios_rd08(bios, volt + 0x0b); 94 info->vidmask = nvbios_rd08(bios, volt + 0x0b);
95 info->ranged = true; /* XXX: find the flag byte */ 95 info->ranged = true; /* XXX: find the flag byte */
96 /*XXX*/ 96 info->min = min(info->base,
97 info->min = 0; 97 info->base + info->step * info->vidmask);
98 info->max = info->base; 98 info->max = nvbios_rd32(bios, volt + 0x0e);
99 break; 99 break;
100 case 0x50: 100 case 0x50:
101 info->min = nvbios_rd32(bios, volt + 0x0a); 101 info->min = nvbios_rd32(bios, volt + 0x0a);
diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/devinit/nv04.c b/drivers/gpu/drm/nouveau/nvkm/subdev/devinit/nv04.c
index c8d455346fcd..158977f8a6e6 100644
--- a/drivers/gpu/drm/nouveau/nvkm/subdev/devinit/nv04.c
+++ b/drivers/gpu/drm/nouveau/nvkm/subdev/devinit/nv04.c
@@ -393,7 +393,7 @@ nv04_devinit_pll_set(struct nvkm_devinit *devinit, u32 type, u32 freq)
393int 393int
394nv04_devinit_post(struct nvkm_devinit *init, bool execute) 394nv04_devinit_post(struct nvkm_devinit *init, bool execute)
395{ 395{
396 return nvbios_init(&init->subdev, execute); 396 return nvbios_post(&init->subdev, execute);
397} 397}
398 398
399void 399void
diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/devinit/nv50.c b/drivers/gpu/drm/nouveau/nvkm/subdev/devinit/nv50.c
index 59362f8dee22..d7947c4391dc 100644
--- a/drivers/gpu/drm/nouveau/nvkm/subdev/devinit/nv50.c
+++ b/drivers/gpu/drm/nouveau/nvkm/subdev/devinit/nv50.c
@@ -137,16 +137,11 @@ nv50_devinit_init(struct nvkm_devinit *base)
137 while (init->base.post && dcb_outp_parse(bios, i, &ver, &hdr, &outp)) { 137 while (init->base.post && dcb_outp_parse(bios, i, &ver, &hdr, &outp)) {
138 if (nvbios_outp_match(bios, outp.hasht, outp.hashm, 138 if (nvbios_outp_match(bios, outp.hasht, outp.hashm,
139 &ver, &hdr, &cnt, &len, &info)) { 139 &ver, &hdr, &cnt, &len, &info)) {
140 struct nvbios_init exec = { 140 nvbios_init(subdev, info.script[0],
141 .subdev = subdev, 141 init.outp = &outp;
142 .bios = bios, 142 init.or = ffs(outp.or) - 1;
143 .offset = info.script[0], 143 init.link = outp.sorconf.link == 2;
144 .outp = &outp, 144 );
145 .crtc = -1,
146 .execute = 1,
147 };
148
149 nvbios_exec(&exec);
150 } 145 }
151 i++; 146 i++;
152 } 147 }
diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/fb/ramgk104.c b/drivers/gpu/drm/nouveau/nvkm/subdev/fb/ramgk104.c
index f6c00791722c..75814f15eb53 100644
--- a/drivers/gpu/drm/nouveau/nvkm/subdev/fb/ramgk104.c
+++ b/drivers/gpu/drm/nouveau/nvkm/subdev/fb/ramgk104.c
@@ -1424,12 +1424,7 @@ gk104_ram_init(struct nvkm_ram *ram)
1424 for (i = 0; i < cnt; i++, data += 4) { 1424 for (i = 0; i < cnt; i++, data += 4) {
1425 if (i != save >> 4) { 1425 if (i != save >> 4) {
1426 nvkm_mask(device, 0x10f65c, 0x000000f0, i << 4); 1426 nvkm_mask(device, 0x10f65c, 0x000000f0, i << 4);
1427 nvbios_exec(&(struct nvbios_init) { 1427 nvbios_init(subdev, nvbios_rd32(bios, data));
1428 .subdev = subdev,
1429 .bios = bios,
1430 .offset = nvbios_rd32(bios, data),
1431 .execute = 1,
1432 });
1433 } 1428 }
1434 } 1429 }
1435 nvkm_mask(device, 0x10f65c, 0x000000f0, save); 1430 nvkm_mask(device, 0x10f65c, 0x000000f0, save);
diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/fb/ramgp100.c b/drivers/gpu/drm/nouveau/nvkm/subdev/fb/ramgp100.c
index cac70047ad5a..df8a87333b67 100644
--- a/drivers/gpu/drm/nouveau/nvkm/subdev/fb/ramgp100.c
+++ b/drivers/gpu/drm/nouveau/nvkm/subdev/fb/ramgp100.c
@@ -59,12 +59,7 @@ gp100_ram_init(struct nvkm_ram *ram)
59 for (i = 0; i < cnt; i++, data += 4) { 59 for (i = 0; i < cnt; i++, data += 4) {
60 if (i != save >> 4) { 60 if (i != save >> 4) {
61 nvkm_mask(device, 0x9a065c, 0x000000f0, i << 4); 61 nvkm_mask(device, 0x9a065c, 0x000000f0, i << 4);
62 nvbios_exec(&(struct nvbios_init) { 62 nvbios_init(subdev, nvbios_rd32(bios, data));
63 .subdev = subdev,
64 .bios = bios,
65 .offset = nvbios_rd32(bios, data),
66 .execute = 1,
67 });
68 } 63 }
69 } 64 }
70 nvkm_mask(device, 0x9a065c, 0x000000f0, save); 65 nvkm_mask(device, 0x9a065c, 0x000000f0, save);
diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/fb/ramnv40.c b/drivers/gpu/drm/nouveau/nvkm/subdev/fb/ramnv40.c
index 56f8cffc2560..70c63535d56b 100644
--- a/drivers/gpu/drm/nouveau/nvkm/subdev/fb/ramnv40.c
+++ b/drivers/gpu/drm/nouveau/nvkm/subdev/fb/ramnv40.c
@@ -150,16 +150,8 @@ nv40_ram_prog(struct nvkm_ram *base)
150 udelay(100); 150 udelay(100);
151 151
152 /* execute memory reset script from vbios */ 152 /* execute memory reset script from vbios */
153 if (!bit_entry(bios, 'M', &M)) { 153 if (!bit_entry(bios, 'M', &M))
154 struct nvbios_init init = { 154 nvbios_init(subdev, nvbios_rd16(bios, M.offset + 0x00));
155 .subdev = subdev,
156 .bios = bios,
157 .offset = nvbios_rd16(bios, M.offset + 0x00),
158 .execute = 1,
159 };
160
161 nvbios_exec(&init);
162 }
163 155
164 /* make sure we're in vblank (hopefully the same one as before), and 156 /* make sure we're in vblank (hopefully the same one as before), and
165 * then re-enable crtc memory access 157 * then re-enable crtc memory access
diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/pmu/gk20a.c b/drivers/gpu/drm/nouveau/nvkm/subdev/pmu/gk20a.c
index 9ca0db796cbe..978aae3c1001 100644
--- a/drivers/gpu/drm/nouveau/nvkm/subdev/pmu/gk20a.c
+++ b/drivers/gpu/drm/nouveau/nvkm/subdev/pmu/gk20a.c
@@ -158,7 +158,7 @@ static void
158gk20a_pmu_fini(struct nvkm_pmu *pmu) 158gk20a_pmu_fini(struct nvkm_pmu *pmu)
159{ 159{
160 struct gk20a_pmu *gpmu = gk20a_pmu(pmu); 160 struct gk20a_pmu *gpmu = gk20a_pmu(pmu);
161 nvkm_timer_alarm_cancel(pmu->subdev.device->timer, &gpmu->alarm); 161 nvkm_timer_alarm(pmu->subdev.device->timer, 0, &gpmu->alarm);
162 162
163 nvkm_falcon_put(pmu->falcon, &pmu->subdev); 163 nvkm_falcon_put(pmu->falcon, &pmu->subdev);
164} 164}
diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/therm/base.c b/drivers/gpu/drm/nouveau/nvkm/subdev/therm/base.c
index be691a7b972f..952a7cb0a59a 100644
--- a/drivers/gpu/drm/nouveau/nvkm/subdev/therm/base.c
+++ b/drivers/gpu/drm/nouveau/nvkm/subdev/therm/base.c
@@ -116,7 +116,7 @@ nvkm_therm_update(struct nvkm_therm *therm, int mode)
116 116
117 switch (mode) { 117 switch (mode) {
118 case NVKM_THERM_CTRL_MANUAL: 118 case NVKM_THERM_CTRL_MANUAL:
119 nvkm_timer_alarm_cancel(tmr, &therm->alarm); 119 nvkm_timer_alarm(tmr, 0, &therm->alarm);
120 duty = nvkm_therm_fan_get(therm); 120 duty = nvkm_therm_fan_get(therm);
121 if (duty < 0) 121 if (duty < 0)
122 duty = 100; 122 duty = 100;
@@ -142,7 +142,7 @@ nvkm_therm_update(struct nvkm_therm *therm, int mode)
142 break; 142 break;
143 case NVKM_THERM_CTRL_NONE: 143 case NVKM_THERM_CTRL_NONE:
144 default: 144 default:
145 nvkm_timer_alarm_cancel(tmr, &therm->alarm); 145 nvkm_timer_alarm(tmr, 0, &therm->alarm);
146 poll = false; 146 poll = false;
147 } 147 }
148 148
diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/therm/fan.c b/drivers/gpu/drm/nouveau/nvkm/subdev/therm/fan.c
index e2feccec25f5..f8fa43c8a7d2 100644
--- a/drivers/gpu/drm/nouveau/nvkm/subdev/therm/fan.c
+++ b/drivers/gpu/drm/nouveau/nvkm/subdev/therm/fan.c
@@ -215,7 +215,7 @@ nvkm_therm_fan_fini(struct nvkm_therm *therm, bool suspend)
215{ 215{
216 struct nvkm_timer *tmr = therm->subdev.device->timer; 216 struct nvkm_timer *tmr = therm->subdev.device->timer;
217 if (suspend) 217 if (suspend)
218 nvkm_timer_alarm_cancel(tmr, &therm->fan->alarm); 218 nvkm_timer_alarm(tmr, 0, &therm->fan->alarm);
219 return 0; 219 return 0;
220} 220}
221 221
diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/therm/temp.c b/drivers/gpu/drm/nouveau/nvkm/subdev/therm/temp.c
index 9a79e91fdfdc..e93b2410c38b 100644
--- a/drivers/gpu/drm/nouveau/nvkm/subdev/therm/temp.c
+++ b/drivers/gpu/drm/nouveau/nvkm/subdev/therm/temp.c
@@ -220,7 +220,7 @@ nvkm_therm_sensor_fini(struct nvkm_therm *therm, bool suspend)
220{ 220{
221 struct nvkm_timer *tmr = therm->subdev.device->timer; 221 struct nvkm_timer *tmr = therm->subdev.device->timer;
222 if (suspend) 222 if (suspend)
223 nvkm_timer_alarm_cancel(tmr, &therm->sensor.therm_poll_alarm); 223 nvkm_timer_alarm(tmr, 0, &therm->sensor.therm_poll_alarm);
224 return 0; 224 return 0;
225} 225}
226 226
diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/timer/base.c b/drivers/gpu/drm/nouveau/nvkm/subdev/timer/base.c
index 2437f7d41ca2..36de23d12ae4 100644
--- a/drivers/gpu/drm/nouveau/nvkm/subdev/timer/base.c
+++ b/drivers/gpu/drm/nouveau/nvkm/subdev/timer/base.c
@@ -105,15 +105,6 @@ nvkm_timer_alarm(struct nvkm_timer *tmr, u32 nsec, struct nvkm_alarm *alarm)
105 spin_unlock_irqrestore(&tmr->lock, flags); 105 spin_unlock_irqrestore(&tmr->lock, flags);
106} 106}
107 107
108void
109nvkm_timer_alarm_cancel(struct nvkm_timer *tmr, struct nvkm_alarm *alarm)
110{
111 unsigned long flags;
112 spin_lock_irqsave(&tmr->lock, flags);
113 list_del_init(&alarm->head);
114 spin_unlock_irqrestore(&tmr->lock, flags);
115}
116
117static void 108static void
118nvkm_timer_intr(struct nvkm_subdev *subdev) 109nvkm_timer_intr(struct nvkm_subdev *subdev)
119{ 110{