aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDave Airlie <airlied@redhat.com>2013-02-20 16:13:17 -0500
committerDave Airlie <airlied@redhat.com>2013-02-20 16:13:56 -0500
commite9f211ad7d65b264998928cea822c11c88e5586b (patch)
tree5d24895f6a9bdb7c8438f405867fc1b61b549fd5
parent2e82b5dd47d826baf0f6e34334fe6b899aa6ad1e (diff)
parent33b903e82873ba9233bd89c44d016b87347ed158 (diff)
Merge branch 'drm-nouveau-next' of git://anongit.freedesktop.org/git/nouveau/linux-2.6 into drm-next
restore debugfs vbios, fix multiple actions with supervisor intrs * 'drm-nouveau-next' of git://anongit.freedesktop.org/git/nouveau/linux-2.6: drm/nouveau: restore debugfs/vbios.rom support drm/nv50-/kms: remove UPDATE methods after each encoder disconnect drm/nvd0/disp: handle multiple actions from one set of supervisor intrs drm/nv50/disp: handle multiple actions from one set of supervisor intrs
-rw-r--r--drivers/gpu/drm/nouveau/Makefile1
-rw-r--r--drivers/gpu/drm/nouveau/core/engine/disp/nv50.c226
-rw-r--r--drivers/gpu/drm/nouveau/core/engine/disp/nvd0.c221
-rw-r--r--drivers/gpu/drm/nouveau/nouveau_debugfs.c64
-rw-r--r--drivers/gpu/drm/nouveau/nouveau_debugfs.h22
-rw-r--r--drivers/gpu/drm/nouveau/nouveau_drm.c6
-rw-r--r--drivers/gpu/drm/nouveau/nv50_display.c9
7 files changed, 329 insertions, 220 deletions
diff --git a/drivers/gpu/drm/nouveau/Makefile b/drivers/gpu/drm/nouveau/Makefile
index 51d09729fc56..90f9140eeefd 100644
--- a/drivers/gpu/drm/nouveau/Makefile
+++ b/drivers/gpu/drm/nouveau/Makefile
@@ -242,5 +242,6 @@ ifdef CONFIG_X86
242nouveau-$(CONFIG_ACPI) += nouveau_acpi.o 242nouveau-$(CONFIG_ACPI) += nouveau_acpi.o
243endif 243endif
244nouveau-$(CONFIG_DRM_NOUVEAU_BACKLIGHT) += nouveau_backlight.o 244nouveau-$(CONFIG_DRM_NOUVEAU_BACKLIGHT) += nouveau_backlight.o
245nouveau-$(CONFIG_DEBUG_FS) += nouveau_debugfs.o
245 246
246obj-$(CONFIG_DRM_NOUVEAU)+= nouveau.o 247obj-$(CONFIG_DRM_NOUVEAU)+= nouveau.o
diff --git a/drivers/gpu/drm/nouveau/core/engine/disp/nv50.c b/drivers/gpu/drm/nouveau/core/engine/disp/nv50.c
index 314dda6d7cb8..5fa13267bd9f 100644
--- a/drivers/gpu/drm/nouveau/core/engine/disp/nv50.c
+++ b/drivers/gpu/drm/nouveau/core/engine/disp/nv50.c
@@ -972,21 +972,29 @@ exec_clkcmp(struct nv50_disp_priv *priv, int head, int id, u32 pclk,
972} 972}
973 973
974static void 974static void
975nv50_disp_intr_unk10(struct nv50_disp_priv *priv, u32 super) 975nv50_disp_intr_unk10_0(struct nv50_disp_priv *priv, int head)
976{ 976{
977 int head = ffs((super & 0x00000060) >> 5) - 1; 977 exec_script(priv, head, 1);
978 if (head >= 0) { 978}
979 head = ffs((super & 0x00000180) >> 7) - 1;
980 if (head >= 0)
981 exec_script(priv, head, 1);
982 }
983 979
984 nv_wr32(priv, 0x610030, 0x80000000); 980static void
981nv50_disp_intr_unk20_0(struct nv50_disp_priv *priv, int head)
982{
983 exec_script(priv, head, 2);
985} 984}
986 985
987static void 986static void
988nv50_disp_intr_unk20_dp(struct nv50_disp_priv *priv, 987nv50_disp_intr_unk20_1(struct nv50_disp_priv *priv, int head)
989 struct dcb_output *outp, u32 pclk) 988{
989 struct nouveau_clock *clk = nouveau_clock(priv);
990 u32 pclk = nv_rd32(priv, 0x610ad0 + (head * 0x540)) & 0x3fffff;
991 if (pclk)
992 clk->pll_set(clk, PLL_VPLL0 + head, pclk);
993}
994
995static void
996nv50_disp_intr_unk20_2_dp(struct nv50_disp_priv *priv,
997 struct dcb_output *outp, u32 pclk)
990{ 998{
991 const int link = !(outp->sorconf.link & 1); 999 const int link = !(outp->sorconf.link & 1);
992 const int or = ffs(outp->or) - 1; 1000 const int or = ffs(outp->or) - 1;
@@ -1092,77 +1100,54 @@ nv50_disp_intr_unk20_dp(struct nv50_disp_priv *priv,
1092} 1100}
1093 1101
1094static void 1102static void
1095nv50_disp_intr_unk20(struct nv50_disp_priv *priv, u32 super) 1103nv50_disp_intr_unk20_2(struct nv50_disp_priv *priv, int head)
1096{ 1104{
1097 struct dcb_output outp; 1105 struct dcb_output outp;
1098 int head; 1106 u32 pclk = nv_rd32(priv, 0x610ad0 + (head * 0x540)) & 0x3fffff;
1099 1107 u32 hval, hreg = 0x614200 + (head * 0x800);
1100 /* finish detaching encoder? */ 1108 u32 oval, oreg;
1101 head = ffs((super & 0x00000180) >> 7) - 1; 1109 u32 conf = exec_clkcmp(priv, head, 0xff, pclk, &outp);
1102 if (head >= 0) 1110 if (conf != ~0) {
1103 exec_script(priv, head, 2); 1111 if (outp.location == 0 && outp.type == DCB_OUTPUT_DP) {
1104 1112 u32 soff = (ffs(outp.or) - 1) * 0x08;
1105 /* check whether a vpll change is required */ 1113 u32 ctrl = nv_rd32(priv, 0x610798 + soff);
1106 head = ffs((super & 0x00000600) >> 9) - 1; 1114 u32 datarate;
1107 if (head >= 0) { 1115
1108 u32 pclk = nv_rd32(priv, 0x610ad0 + (head * 0x540)) & 0x3fffff; 1116 switch ((ctrl & 0x000f0000) >> 16) {
1109 if (pclk) { 1117 case 6: datarate = pclk * 30 / 8; break;
1110 struct nouveau_clock *clk = nouveau_clock(priv); 1118 case 5: datarate = pclk * 24 / 8; break;
1111 clk->pll_set(clk, PLL_VPLL0 + head, pclk); 1119 case 2:
1112 } 1120 default:
1113 } 1121 datarate = pclk * 18 / 8;
1114 1122 break;
1115 /* (re)attach the relevant OR to the head */
1116 head = ffs((super & 0x00000180) >> 7) - 1;
1117 if (head >= 0) {
1118 u32 pclk = nv_rd32(priv, 0x610ad0 + (head * 0x540)) & 0x3fffff;
1119 u32 hval, hreg = 0x614200 + (head * 0x800);
1120 u32 oval, oreg;
1121 u32 conf = exec_clkcmp(priv, head, 0xff, pclk, &outp);
1122 if (conf != ~0) {
1123 if (outp.location == 0 && outp.type == DCB_OUTPUT_DP) {
1124 u32 soff = (ffs(outp.or) - 1) * 0x08;
1125 u32 ctrl = nv_rd32(priv, 0x610798 + soff);
1126 u32 datarate;
1127
1128 switch ((ctrl & 0x000f0000) >> 16) {
1129 case 6: datarate = pclk * 30 / 8; break;
1130 case 5: datarate = pclk * 24 / 8; break;
1131 case 2:
1132 default:
1133 datarate = pclk * 18 / 8;
1134 break;
1135 }
1136
1137 nouveau_dp_train(&priv->base, priv->sor.dp,
1138 &outp, head, datarate);
1139 } 1123 }
1140 1124
1141 exec_clkcmp(priv, head, 0, pclk, &outp); 1125 nouveau_dp_train(&priv->base, priv->sor.dp,
1142 1126 &outp, head, datarate);
1143 if (!outp.location && outp.type == DCB_OUTPUT_ANALOG) { 1127 }
1144 oreg = 0x614280 + (ffs(outp.or) - 1) * 0x800;
1145 oval = 0x00000000;
1146 hval = 0x00000000;
1147 } else
1148 if (!outp.location) {
1149 if (outp.type == DCB_OUTPUT_DP)
1150 nv50_disp_intr_unk20_dp(priv, &outp, pclk);
1151 oreg = 0x614300 + (ffs(outp.or) - 1) * 0x800;
1152 oval = (conf & 0x0100) ? 0x0101 : 0x0000;
1153 hval = 0x00000000;
1154 } else {
1155 oreg = 0x614380 + (ffs(outp.or) - 1) * 0x800;
1156 oval = 0x00000001;
1157 hval = 0x00000001;
1158 }
1159 1128
1160 nv_mask(priv, hreg, 0x0000000f, hval); 1129 exec_clkcmp(priv, head, 0, pclk, &outp);
1161 nv_mask(priv, oreg, 0x00000707, oval); 1130
1131 if (!outp.location && outp.type == DCB_OUTPUT_ANALOG) {
1132 oreg = 0x614280 + (ffs(outp.or) - 1) * 0x800;
1133 oval = 0x00000000;
1134 hval = 0x00000000;
1135 } else
1136 if (!outp.location) {
1137 if (outp.type == DCB_OUTPUT_DP)
1138 nv50_disp_intr_unk20_2_dp(priv, &outp, pclk);
1139 oreg = 0x614300 + (ffs(outp.or) - 1) * 0x800;
1140 oval = (conf & 0x0100) ? 0x00000101 : 0x00000000;
1141 hval = 0x00000000;
1142 } else {
1143 oreg = 0x614380 + (ffs(outp.or) - 1) * 0x800;
1144 oval = 0x00000001;
1145 hval = 0x00000001;
1162 } 1146 }
1163 }
1164 1147
1165 nv_wr32(priv, 0x610030, 0x80000000); 1148 nv_mask(priv, hreg, 0x0000000f, hval);
1149 nv_mask(priv, oreg, 0x00000707, oval);
1150 }
1166} 1151}
1167 1152
1168/* If programming a TMDS output on a SOR that can also be configured for 1153/* If programming a TMDS output on a SOR that can also be configured for
@@ -1174,7 +1159,7 @@ nv50_disp_intr_unk20(struct nv50_disp_priv *priv, u32 super)
1174 * programmed for DisplayPort. 1159 * programmed for DisplayPort.
1175 */ 1160 */
1176static void 1161static void
1177nv50_disp_intr_unk40_tmds(struct nv50_disp_priv *priv, struct dcb_output *outp) 1162nv50_disp_intr_unk40_0_tmds(struct nv50_disp_priv *priv, struct dcb_output *outp)
1178{ 1163{
1179 struct nouveau_bios *bios = nouveau_bios(priv); 1164 struct nouveau_bios *bios = nouveau_bios(priv);
1180 const int link = !(outp->sorconf.link & 1); 1165 const int link = !(outp->sorconf.link & 1);
@@ -1188,37 +1173,32 @@ nv50_disp_intr_unk40_tmds(struct nv50_disp_priv *priv, struct dcb_output *outp)
1188} 1173}
1189 1174
1190static void 1175static void
1191nv50_disp_intr_unk40(struct nv50_disp_priv *priv, u32 super) 1176nv50_disp_intr_unk40_0(struct nv50_disp_priv *priv, int head)
1192{ 1177{
1193 int head = ffs((super & 0x00000180) >> 7) - 1; 1178 struct dcb_output outp;
1194 if (head >= 0) { 1179 u32 pclk = nv_rd32(priv, 0x610ad0 + (head * 0x540)) & 0x3fffff;
1195 struct dcb_output outp; 1180 if (exec_clkcmp(priv, head, 1, pclk, &outp) != ~0) {
1196 u32 pclk = nv_rd32(priv, 0x610ad0 + (head * 0x540)) & 0x3fffff; 1181 if (outp.location == 0 && outp.type == DCB_OUTPUT_TMDS)
1197 if (exec_clkcmp(priv, head, 1, pclk, &outp) != ~0) { 1182 nv50_disp_intr_unk40_0_tmds(priv, &outp);
1198 if (outp.location == 0 && outp.type == DCB_OUTPUT_TMDS) 1183 else
1199 nv50_disp_intr_unk40_tmds(priv, &outp); 1184 if (outp.location == 1 && outp.type == DCB_OUTPUT_DP) {
1200 else 1185 u32 soff = (ffs(outp.or) - 1) * 0x08;
1201 if (outp.location == 1 && outp.type == DCB_OUTPUT_DP) { 1186 u32 ctrl = nv_rd32(priv, 0x610b84 + soff);
1202 u32 soff = (ffs(outp.or) - 1) * 0x08; 1187 u32 datarate;
1203 u32 ctrl = nv_rd32(priv, 0x610b84 + soff); 1188
1204 u32 datarate; 1189 switch ((ctrl & 0x000f0000) >> 16) {
1205 1190 case 6: datarate = pclk * 30 / 8; break;
1206 switch ((ctrl & 0x000f0000) >> 16) { 1191 case 5: datarate = pclk * 24 / 8; break;
1207 case 6: datarate = pclk * 30 / 8; break; 1192 case 2:
1208 case 5: datarate = pclk * 24 / 8; break; 1193 default:
1209 case 2: 1194 datarate = pclk * 18 / 8;
1210 default: 1195 break;
1211 datarate = pclk * 18 / 8;
1212 break;
1213 }
1214
1215 nouveau_dp_train(&priv->base, priv->pior.dp,
1216 &outp, head, datarate);
1217 } 1196 }
1197
1198 nouveau_dp_train(&priv->base, priv->pior.dp,
1199 &outp, head, datarate);
1218 } 1200 }
1219 } 1201 }
1220
1221 nv_wr32(priv, 0x610030, 0x80000000);
1222} 1202}
1223 1203
1224void 1204void
@@ -1227,15 +1207,45 @@ nv50_disp_intr_supervisor(struct work_struct *work)
1227 struct nv50_disp_priv *priv = 1207 struct nv50_disp_priv *priv =
1228 container_of(work, struct nv50_disp_priv, supervisor); 1208 container_of(work, struct nv50_disp_priv, supervisor);
1229 u32 super = nv_rd32(priv, 0x610030); 1209 u32 super = nv_rd32(priv, 0x610030);
1210 int head;
1230 1211
1231 nv_debug(priv, "supervisor 0x%08x 0x%08x\n", priv->super, super); 1212 nv_debug(priv, "supervisor 0x%08x 0x%08x\n", priv->super, super);
1232 1213
1233 if (priv->super & 0x00000010) 1214 if (priv->super & 0x00000010) {
1234 nv50_disp_intr_unk10(priv, super); 1215 for (head = 0; head < priv->head.nr; head++) {
1235 if (priv->super & 0x00000020) 1216 if (!(super & (0x00000020 << head)))
1236 nv50_disp_intr_unk20(priv, super); 1217 continue;
1237 if (priv->super & 0x00000040) 1218 if (!(super & (0x00000080 << head)))
1238 nv50_disp_intr_unk40(priv, super); 1219 continue;
1220 nv50_disp_intr_unk10_0(priv, head);
1221 }
1222 } else
1223 if (priv->super & 0x00000020) {
1224 for (head = 0; head < priv->head.nr; head++) {
1225 if (!(super & (0x00000080 << head)))
1226 continue;
1227 nv50_disp_intr_unk20_0(priv, head);
1228 }
1229 for (head = 0; head < priv->head.nr; head++) {
1230 if (!(super & (0x00000200 << head)))
1231 continue;
1232 nv50_disp_intr_unk20_1(priv, head);
1233 }
1234 for (head = 0; head < priv->head.nr; head++) {
1235 if (!(super & (0x00000080 << head)))
1236 continue;
1237 nv50_disp_intr_unk20_2(priv, head);
1238 }
1239 } else
1240 if (priv->super & 0x00000040) {
1241 for (head = 0; head < priv->head.nr; head++) {
1242 if (!(super & (0x00000080 << head)))
1243 continue;
1244 nv50_disp_intr_unk40_0(priv, head);
1245 }
1246 }
1247
1248 nv_wr32(priv, 0x610030, 0x80000000);
1239} 1249}
1240 1250
1241void 1251void
diff --git a/drivers/gpu/drm/nouveau/core/engine/disp/nvd0.c b/drivers/gpu/drm/nouveau/core/engine/disp/nvd0.c
index 7106a72e611e..788dd34ccb54 100644
--- a/drivers/gpu/drm/nouveau/core/engine/disp/nvd0.c
+++ b/drivers/gpu/drm/nouveau/core/engine/disp/nvd0.c
@@ -623,13 +623,24 @@ exec_lookup(struct nv50_disp_priv *priv, int head, int outp, u32 ctrl,
623} 623}
624 624
625static bool 625static bool
626exec_script(struct nv50_disp_priv *priv, int head, int outp, u32 ctrl, int id) 626exec_script(struct nv50_disp_priv *priv, int head, int id)
627{ 627{
628 struct nouveau_bios *bios = nouveau_bios(priv); 628 struct nouveau_bios *bios = nouveau_bios(priv);
629 struct nvbios_outp info; 629 struct nvbios_outp info;
630 struct dcb_output dcb; 630 struct dcb_output dcb;
631 u8 ver, hdr, cnt, len; 631 u8 ver, hdr, cnt, len;
632 u32 ctrl = 0x00000000;
632 u16 data; 633 u16 data;
634 int outp;
635
636 for (outp = 0; !(ctrl & (1 << head)) && outp < 8; outp++) {
637 ctrl = nv_rd32(priv, 0x640180 + (outp * 0x20));
638 if (ctrl & (1 << head))
639 break;
640 }
641
642 if (outp == 8)
643 return false;
633 644
634 data = exec_lookup(priv, head, outp, ctrl, &dcb, &ver, &hdr, &cnt, &len, &info); 645 data = exec_lookup(priv, head, outp, ctrl, &dcb, &ver, &hdr, &cnt, &len, &info);
635 if (data) { 646 if (data) {
@@ -649,14 +660,25 @@ exec_script(struct nv50_disp_priv *priv, int head, int outp, u32 ctrl, int id)
649} 660}
650 661
651static u32 662static u32
652exec_clkcmp(struct nv50_disp_priv *priv, int head, int outp, 663exec_clkcmp(struct nv50_disp_priv *priv, int head, int id,
653 u32 ctrl, int id, u32 pclk, struct dcb_output *dcb) 664 u32 pclk, struct dcb_output *dcb)
654{ 665{
655 struct nouveau_bios *bios = nouveau_bios(priv); 666 struct nouveau_bios *bios = nouveau_bios(priv);
656 struct nvbios_outp info1; 667 struct nvbios_outp info1;
657 struct nvbios_ocfg info2; 668 struct nvbios_ocfg info2;
658 u8 ver, hdr, cnt, len; 669 u8 ver, hdr, cnt, len;
670 u32 ctrl = 0x00000000;
659 u32 data, conf = ~0; 671 u32 data, conf = ~0;
672 int outp;
673
674 for (outp = 0; !(ctrl & (1 << head)) && outp < 8; outp++) {
675 ctrl = nv_rd32(priv, 0x660180 + (outp * 0x20));
676 if (ctrl & (1 << head))
677 break;
678 }
679
680 if (outp == 8)
681 return false;
660 682
661 data = exec_lookup(priv, head, outp, ctrl, dcb, &ver, &hdr, &cnt, &len, &info1); 683 data = exec_lookup(priv, head, outp, ctrl, dcb, &ver, &hdr, &cnt, &len, &info1);
662 if (data == 0x0000) 684 if (data == 0x0000)
@@ -701,24 +723,32 @@ exec_clkcmp(struct nv50_disp_priv *priv, int head, int outp,
701} 723}
702 724
703static void 725static void
704nvd0_display_unk1_handler(struct nv50_disp_priv *priv, u32 head, u32 mask) 726nvd0_disp_intr_unk1_0(struct nv50_disp_priv *priv, int head)
705{ 727{
706 int i; 728 exec_script(priv, head, 1);
729}
707 730
708 for (i = 0; mask && i < 8; i++) { 731static void
709 u32 mcc = nv_rd32(priv, 0x640180 + (i * 0x20)); 732nvd0_disp_intr_unk2_0(struct nv50_disp_priv *priv, int head)
710 if (mcc & (1 << head)) 733{
711 exec_script(priv, head, i, mcc, 1); 734 exec_script(priv, head, 2);
712 } 735}
713 736
714 nv_wr32(priv, 0x6101d4, 0x00000000); 737static void
715 nv_wr32(priv, 0x6109d4, 0x00000000); 738nvd0_disp_intr_unk2_1(struct nv50_disp_priv *priv, int head)
716 nv_wr32(priv, 0x6101d0, 0x80000000); 739{
740 struct nouveau_clock *clk = nouveau_clock(priv);
741 u32 pclk = nv_rd32(priv, 0x660450 + (head * 0x300)) / 1000;
742 if (pclk)
743 clk->pll_set(clk, PLL_VPLL0 + head, pclk);
744 nv_wr32(priv, 0x612200 + (head * 0x800), 0x00000000);
717} 745}
718 746
719static void 747static void
720nvd0_display_unk2_calc_tu(struct nv50_disp_priv *priv, int head, int or) 748nvd0_disp_intr_unk2_2_tu(struct nv50_disp_priv *priv, int head,
749 struct dcb_output *outp)
721{ 750{
751 const int or = ffs(outp->or) - 1;
722 const u32 ctrl = nv_rd32(priv, 0x660200 + (or * 0x020)); 752 const u32 ctrl = nv_rd32(priv, 0x660200 + (or * 0x020));
723 const u32 conf = nv_rd32(priv, 0x660404 + (head * 0x300)); 753 const u32 conf = nv_rd32(priv, 0x660404 + (head * 0x300));
724 const u32 pclk = nv_rd32(priv, 0x660450 + (head * 0x300)) / 1000; 754 const u32 pclk = nv_rd32(priv, 0x660450 + (head * 0x300)) / 1000;
@@ -761,97 +791,51 @@ nvd0_display_unk2_calc_tu(struct nv50_disp_priv *priv, int head, int or)
761} 791}
762 792
763static void 793static void
764nvd0_display_unk2_handler(struct nv50_disp_priv *priv, u32 head, u32 mask) 794nvd0_disp_intr_unk2_2(struct nv50_disp_priv *priv, int head)
765{ 795{
766 struct dcb_output outp; 796 struct dcb_output outp;
767 u32 pclk; 797 u32 pclk = nv_rd32(priv, 0x660450 + (head * 0x300)) / 1000;
768 int i; 798 u32 conf = exec_clkcmp(priv, head, 0xff, pclk, &outp);
769 799 if (conf != ~0) {
770 for (i = 0; mask && i < 8; i++) { 800 u32 addr, data;
771 u32 mcc = nv_rd32(priv, 0x640180 + (i * 0x20)); 801
772 if (mcc & (1 << head)) 802 if (outp.type == DCB_OUTPUT_DP) {
773 exec_script(priv, head, i, mcc, 2); 803 u32 sync = nv_rd32(priv, 0x660404 + (head * 0x300));
774 } 804 switch ((sync & 0x000003c0) >> 6) {
805 case 6: pclk = pclk * 30 / 8; break;
806 case 5: pclk = pclk * 24 / 8; break;
807 case 2:
808 default:
809 pclk = pclk * 18 / 8;
810 break;
811 }
775 812
776 pclk = nv_rd32(priv, 0x660450 + (head * 0x300)) / 1000; 813 nouveau_dp_train(&priv->base, priv->sor.dp,
777 nv_debug(priv, "head %d pclk %d mask 0x%08x\n", head, pclk, mask); 814 &outp, head, pclk);
778 if (pclk && (mask & 0x00010000)) { 815 }
779 struct nouveau_clock *clk = nouveau_clock(priv);
780 clk->pll_set(clk, PLL_VPLL0 + head, pclk);
781 }
782 816
783 nv_wr32(priv, 0x612200 + (head * 0x800), 0x00000000); 817 exec_clkcmp(priv, head, 0, pclk, &outp);
784 818
785 for (i = 0; mask && i < 8; i++) { 819 if (outp.type == DCB_OUTPUT_ANALOG) {
786 u32 mcp = nv_rd32(priv, 0x660180 + (i * 0x20)); 820 addr = 0x612280 + (ffs(outp.or) - 1) * 0x800;
787 if (mcp & (1 << head)) { 821 data = 0x00000000;
788 u32 cfg = exec_clkcmp(priv, head, i, mcp, 0xff, pclk, &outp); 822 } else {
789 if (cfg != ~0) { 823 if (outp.type == DCB_OUTPUT_DP)
790 u32 addr, mask, data = 0x00000000; 824 nvd0_disp_intr_unk2_2_tu(priv, head, &outp);
791 825 addr = 0x612300 + (ffs(outp.or) - 1) * 0x800;
792 if (outp.type == DCB_OUTPUT_DP) { 826 data = (conf & 0x0100) ? 0x00000101 : 0x00000000;
793 switch ((mcp & 0x000f0000) >> 16) {
794 case 6: pclk = pclk * 30 / 8; break;
795 case 5: pclk = pclk * 24 / 8; break;
796 case 2:
797 default:
798 pclk = pclk * 18 / 8;
799 break;
800 }
801
802 nouveau_dp_train(&priv->base,
803 priv->sor.dp,
804 &outp, head, pclk);
805 }
806
807 exec_clkcmp(priv, head, i, mcp, 0, pclk, &outp);
808
809 if (i < 4) {
810 addr = 0x612280 + ((i - 0) * 0x800);
811 mask = 0xffffffff;
812 } else {
813 switch (mcp & 0x00000f00) {
814 case 0x00000800:
815 case 0x00000900:
816 nvd0_display_unk2_calc_tu(priv, head, i - 4);
817 break;
818 default:
819 break;
820 }
821
822 addr = 0x612300 + ((i - 4) * 0x800);
823 mask = 0x00000707;
824 if (cfg & 0x00000100)
825 data = 0x00000101;
826 }
827 nv_mask(priv, addr, mask, data);
828 }
829 break;
830 } 827 }
831 }
832 828
833 nv_wr32(priv, 0x6101d4, 0x00000000); 829 nv_mask(priv, addr, 0x00000707, data);
834 nv_wr32(priv, 0x6109d4, 0x00000000); 830 }
835 nv_wr32(priv, 0x6101d0, 0x80000000);
836} 831}
837 832
838static void 833static void
839nvd0_display_unk4_handler(struct nv50_disp_priv *priv, u32 head, u32 mask) 834nvd0_disp_intr_unk4_0(struct nv50_disp_priv *priv, int head)
840{ 835{
841 struct dcb_output outp; 836 struct dcb_output outp;
842 int pclk, i; 837 u32 pclk = nv_rd32(priv, 0x660450 + (head * 0x300)) / 1000;
843 838 exec_clkcmp(priv, head, 1, pclk, &outp);
844 pclk = nv_rd32(priv, 0x660450 + (head * 0x300)) / 1000;
845
846 for (i = 0; mask && i < 8; i++) {
847 u32 mcp = nv_rd32(priv, 0x660180 + (i * 0x20));
848 if (mcp & (1 << head))
849 exec_clkcmp(priv, head, i, mcp, 1, pclk, &outp);
850 }
851
852 nv_wr32(priv, 0x6101d4, 0x00000000);
853 nv_wr32(priv, 0x6109d4, 0x00000000);
854 nv_wr32(priv, 0x6101d0, 0x80000000);
855} 839}
856 840
857void 841void
@@ -859,19 +843,50 @@ nvd0_disp_intr_supervisor(struct work_struct *work)
859{ 843{
860 struct nv50_disp_priv *priv = 844 struct nv50_disp_priv *priv =
861 container_of(work, struct nv50_disp_priv, supervisor); 845 container_of(work, struct nv50_disp_priv, supervisor);
862 u32 mask = 0, head = ~0; 846 u32 mask[4];
847 int head;
863 848
864 while (!mask && ++head < priv->head.nr) 849 nv_debug(priv, "supervisor %08x\n", priv->super);
865 mask = nv_rd32(priv, 0x6101d4 + (head * 0x800)); 850 for (head = 0; head < priv->head.nr; head++) {
851 mask[head] = nv_rd32(priv, 0x6101d4 + (head * 0x800));
852 nv_debug(priv, "head %d: 0x%08x\n", head, mask[head]);
853 }
866 854
867 nv_debug(priv, "supervisor %08x %08x %d\n", priv->super, mask, head); 855 if (priv->super & 0x00000001) {
856 for (head = 0; head < priv->head.nr; head++) {
857 if (!(mask[head] & 0x00001000))
858 continue;
859 nvd0_disp_intr_unk1_0(priv, head);
860 }
861 } else
862 if (priv->super & 0x00000002) {
863 for (head = 0; head < priv->head.nr; head++) {
864 if (!(mask[head] & 0x00001000))
865 continue;
866 nvd0_disp_intr_unk2_0(priv, head);
867 }
868 for (head = 0; head < priv->head.nr; head++) {
869 if (!(mask[head] & 0x00010000))
870 continue;
871 nvd0_disp_intr_unk2_1(priv, head);
872 }
873 for (head = 0; head < priv->head.nr; head++) {
874 if (!(mask[head] & 0x00001000))
875 continue;
876 nvd0_disp_intr_unk2_2(priv, head);
877 }
878 } else
879 if (priv->super & 0x00000004) {
880 for (head = 0; head < priv->head.nr; head++) {
881 if (!(mask[head] & 0x00001000))
882 continue;
883 nvd0_disp_intr_unk4_0(priv, head);
884 }
885 }
868 886
869 if (priv->super & 0x00000001) 887 for (head = 0; head < priv->head.nr; head++)
870 nvd0_display_unk1_handler(priv, head, mask); 888 nv_wr32(priv, 0x6101d4 + (head * 0x800), 0x00000000);
871 if (priv->super & 0x00000002) 889 nv_wr32(priv, 0x6101d0, 0x80000000);
872 nvd0_display_unk2_handler(priv, head, mask);
873 if (priv->super & 0x00000004)
874 nvd0_display_unk4_handler(priv, head, mask);
875} 890}
876 891
877void 892void
diff --git a/drivers/gpu/drm/nouveau/nouveau_debugfs.c b/drivers/gpu/drm/nouveau/nouveau_debugfs.c
new file mode 100644
index 000000000000..5392e07edfc6
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nouveau_debugfs.c
@@ -0,0 +1,64 @@
1/*
2 * Copyright (C) 2009 Red Hat <bskeggs@redhat.com>
3 *
4 * Permission is hereby granted, free of charge, to any person obtaining
5 * a copy of this software and associated documentation files (the
6 * "Software"), to deal in the Software without restriction, including
7 * without limitation the rights to use, copy, modify, merge, publish,
8 * distribute, sublicense, and/or sell copies of the Software, and to
9 * permit persons to whom the Software is furnished to do so, subject to
10 * the following conditions:
11 *
12 * The above copyright notice and this permission notice (including the
13 * next paragraph) shall be included in all copies or substantial
14 * portions of the Software.
15 *
16 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
19 * IN NO EVENT SHALL THE COPYRIGHT OWNER(S) AND/OR ITS SUPPLIERS BE
20 * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
21 * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
22 * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
23 *
24 */
25
26/*
27 * Authors:
28 * Ben Skeggs <bskeggs@redhat.com>
29 */
30
31#include "nouveau_debugfs.h"
32#include "nouveau_drm.h"
33
34static int
35nouveau_debugfs_vbios_image(struct seq_file *m, void *data)
36{
37 struct drm_info_node *node = (struct drm_info_node *) m->private;
38 struct nouveau_drm *drm = nouveau_drm(node->minor->dev);
39 int i;
40
41 for (i = 0; i < drm->vbios.length; i++)
42 seq_printf(m, "%c", drm->vbios.data[i]);
43 return 0;
44}
45
46static struct drm_info_list nouveau_debugfs_list[] = {
47 { "vbios.rom", nouveau_debugfs_vbios_image, 0, NULL },
48};
49#define NOUVEAU_DEBUGFS_ENTRIES ARRAY_SIZE(nouveau_debugfs_list)
50
51int
52nouveau_debugfs_init(struct drm_minor *minor)
53{
54 drm_debugfs_create_files(nouveau_debugfs_list, NOUVEAU_DEBUGFS_ENTRIES,
55 minor->debugfs_root, minor);
56 return 0;
57}
58
59void
60nouveau_debugfs_takedown(struct drm_minor *minor)
61{
62 drm_debugfs_remove_files(nouveau_debugfs_list, NOUVEAU_DEBUGFS_ENTRIES,
63 minor);
64}
diff --git a/drivers/gpu/drm/nouveau/nouveau_debugfs.h b/drivers/gpu/drm/nouveau/nouveau_debugfs.h
new file mode 100644
index 000000000000..a62af6fb5f99
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nouveau_debugfs.h
@@ -0,0 +1,22 @@
1#ifndef __NOUVEAU_DEBUGFS_H__
2#define __NOUVEAU_DEBUGFS_H__
3
4#include <drm/drmP.h>
5
6#if defined(CONFIG_DEBUG_FS)
7extern int nouveau_debugfs_init(struct drm_minor *);
8extern void nouveau_debugfs_takedown(struct drm_minor *);
9#else
10static inline int
11nouveau_debugfs_init(struct drm_minor *minor)
12{
13 return 0;
14}
15
16static inline void nouveau_debugfs_takedown(struct drm_minor *minor)
17{
18}
19
20#endif
21
22#endif
diff --git a/drivers/gpu/drm/nouveau/nouveau_drm.c b/drivers/gpu/drm/nouveau/nouveau_drm.c
index ccfe2be3ae38..8a03c58ae988 100644
--- a/drivers/gpu/drm/nouveau/nouveau_drm.c
+++ b/drivers/gpu/drm/nouveau/nouveau_drm.c
@@ -50,6 +50,7 @@
50#include "nouveau_abi16.h" 50#include "nouveau_abi16.h"
51#include "nouveau_fbcon.h" 51#include "nouveau_fbcon.h"
52#include "nouveau_fence.h" 52#include "nouveau_fence.h"
53#include "nouveau_debugfs.h"
53 54
54MODULE_PARM_DESC(config, "option string to pass to driver core"); 55MODULE_PARM_DESC(config, "option string to pass to driver core");
55static char *nouveau_config; 56static char *nouveau_config;
@@ -667,6 +668,11 @@ driver = {
667 .postclose = nouveau_drm_postclose, 668 .postclose = nouveau_drm_postclose,
668 .lastclose = nouveau_vga_lastclose, 669 .lastclose = nouveau_vga_lastclose,
669 670
671#if defined(CONFIG_DEBUG_FS)
672 .debugfs_init = nouveau_debugfs_init,
673 .debugfs_cleanup = nouveau_debugfs_takedown,
674#endif
675
670 .irq_preinstall = nouveau_irq_preinstall, 676 .irq_preinstall = nouveau_irq_preinstall,
671 .irq_postinstall = nouveau_irq_postinstall, 677 .irq_postinstall = nouveau_irq_postinstall,
672 .irq_uninstall = nouveau_irq_uninstall, 678 .irq_uninstall = nouveau_irq_uninstall,
diff --git a/drivers/gpu/drm/nouveau/nv50_display.c b/drivers/gpu/drm/nouveau/nv50_display.c
index 45624c37e29f..a6237c9cbbc3 100644
--- a/drivers/gpu/drm/nouveau/nv50_display.c
+++ b/drivers/gpu/drm/nouveau/nv50_display.c
@@ -1519,9 +1519,6 @@ nv50_dac_disconnect(struct drm_encoder *encoder)
1519 evo_mthd(push, 0x0180 + (or * 0x020), 1); 1519 evo_mthd(push, 0x0180 + (or * 0x020), 1);
1520 evo_data(push, 0x00000000); 1520 evo_data(push, 0x00000000);
1521 } 1521 }
1522
1523 evo_mthd(push, 0x0080, 1);
1524 evo_data(push, 0x00000000);
1525 evo_kick(push, mast); 1522 evo_kick(push, mast);
1526 } 1523 }
1527 } 1524 }
@@ -1735,9 +1732,6 @@ nv50_sor_disconnect(struct drm_encoder *encoder)
1735 evo_mthd(push, 0x0200 + (or * 0x20), 1); 1732 evo_mthd(push, 0x0200 + (or * 0x20), 1);
1736 evo_data(push, 0x00000000); 1733 evo_data(push, 0x00000000);
1737 } 1734 }
1738
1739 evo_mthd(push, 0x0080, 1);
1740 evo_data(push, 0x00000000);
1741 evo_kick(push, mast); 1735 evo_kick(push, mast);
1742 } 1736 }
1743 1737
@@ -2039,9 +2033,6 @@ nv50_pior_disconnect(struct drm_encoder *encoder)
2039 evo_mthd(push, 0x0700 + (or * 0x040), 1); 2033 evo_mthd(push, 0x0700 + (or * 0x040), 1);
2040 evo_data(push, 0x00000000); 2034 evo_data(push, 0x00000000);
2041 } 2035 }
2042
2043 evo_mthd(push, 0x0080, 1);
2044 evo_data(push, 0x00000000);
2045 evo_kick(push, mast); 2036 evo_kick(push, mast);
2046 } 2037 }
2047 } 2038 }