diff options
author | Dave Airlie <airlied@redhat.com> | 2013-02-20 16:13:17 -0500 |
---|---|---|
committer | Dave Airlie <airlied@redhat.com> | 2013-02-20 16:13:56 -0500 |
commit | e9f211ad7d65b264998928cea822c11c88e5586b (patch) | |
tree | 5d24895f6a9bdb7c8438f405867fc1b61b549fd5 | |
parent | 2e82b5dd47d826baf0f6e34334fe6b899aa6ad1e (diff) | |
parent | 33b903e82873ba9233bd89c44d016b87347ed158 (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/Makefile | 1 | ||||
-rw-r--r-- | drivers/gpu/drm/nouveau/core/engine/disp/nv50.c | 226 | ||||
-rw-r--r-- | drivers/gpu/drm/nouveau/core/engine/disp/nvd0.c | 221 | ||||
-rw-r--r-- | drivers/gpu/drm/nouveau/nouveau_debugfs.c | 64 | ||||
-rw-r--r-- | drivers/gpu/drm/nouveau/nouveau_debugfs.h | 22 | ||||
-rw-r--r-- | drivers/gpu/drm/nouveau/nouveau_drm.c | 6 | ||||
-rw-r--r-- | drivers/gpu/drm/nouveau/nv50_display.c | 9 |
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 | |||
242 | nouveau-$(CONFIG_ACPI) += nouveau_acpi.o | 242 | nouveau-$(CONFIG_ACPI) += nouveau_acpi.o |
243 | endif | 243 | endif |
244 | nouveau-$(CONFIG_DRM_NOUVEAU_BACKLIGHT) += nouveau_backlight.o | 244 | nouveau-$(CONFIG_DRM_NOUVEAU_BACKLIGHT) += nouveau_backlight.o |
245 | nouveau-$(CONFIG_DEBUG_FS) += nouveau_debugfs.o | ||
245 | 246 | ||
246 | obj-$(CONFIG_DRM_NOUVEAU)+= nouveau.o | 247 | obj-$(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 | ||
974 | static void | 974 | static void |
975 | nv50_disp_intr_unk10(struct nv50_disp_priv *priv, u32 super) | 975 | nv50_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); | 980 | static void |
981 | nv50_disp_intr_unk20_0(struct nv50_disp_priv *priv, int head) | ||
982 | { | ||
983 | exec_script(priv, head, 2); | ||
985 | } | 984 | } |
986 | 985 | ||
987 | static void | 986 | static void |
988 | nv50_disp_intr_unk20_dp(struct nv50_disp_priv *priv, | 987 | nv50_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 | |||
995 | static void | ||
996 | nv50_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 | ||
1094 | static void | 1102 | static void |
1095 | nv50_disp_intr_unk20(struct nv50_disp_priv *priv, u32 super) | 1103 | nv50_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 | */ |
1176 | static void | 1161 | static void |
1177 | nv50_disp_intr_unk40_tmds(struct nv50_disp_priv *priv, struct dcb_output *outp) | 1162 | nv50_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 | ||
1190 | static void | 1175 | static void |
1191 | nv50_disp_intr_unk40(struct nv50_disp_priv *priv, u32 super) | 1176 | nv50_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 | ||
1224 | void | 1204 | void |
@@ -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 | ||
1241 | void | 1251 | void |
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 | ||
625 | static bool | 625 | static bool |
626 | exec_script(struct nv50_disp_priv *priv, int head, int outp, u32 ctrl, int id) | 626 | exec_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 | ||
651 | static u32 | 662 | static u32 |
652 | exec_clkcmp(struct nv50_disp_priv *priv, int head, int outp, | 663 | exec_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 | ||
703 | static void | 725 | static void |
704 | nvd0_display_unk1_handler(struct nv50_disp_priv *priv, u32 head, u32 mask) | 726 | nvd0_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++) { | 731 | static void |
709 | u32 mcc = nv_rd32(priv, 0x640180 + (i * 0x20)); | 732 | nvd0_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); | 737 | static void |
715 | nv_wr32(priv, 0x6109d4, 0x00000000); | 738 | nvd0_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 | ||
719 | static void | 747 | static void |
720 | nvd0_display_unk2_calc_tu(struct nv50_disp_priv *priv, int head, int or) | 748 | nvd0_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 | ||
763 | static void | 793 | static void |
764 | nvd0_display_unk2_handler(struct nv50_disp_priv *priv, u32 head, u32 mask) | 794 | nvd0_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 | ||
838 | static void | 833 | static void |
839 | nvd0_display_unk4_handler(struct nv50_disp_priv *priv, u32 head, u32 mask) | 834 | nvd0_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 | ||
857 | void | 841 | void |
@@ -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 | ||
877 | void | 892 | void |
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 | |||
34 | static int | ||
35 | nouveau_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 | |||
46 | static 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 | |||
51 | int | ||
52 | nouveau_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 | |||
59 | void | ||
60 | nouveau_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) | ||
7 | extern int nouveau_debugfs_init(struct drm_minor *); | ||
8 | extern void nouveau_debugfs_takedown(struct drm_minor *); | ||
9 | #else | ||
10 | static inline int | ||
11 | nouveau_debugfs_init(struct drm_minor *minor) | ||
12 | { | ||
13 | return 0; | ||
14 | } | ||
15 | |||
16 | static 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 | ||
54 | MODULE_PARM_DESC(config, "option string to pass to driver core"); | 55 | MODULE_PARM_DESC(config, "option string to pass to driver core"); |
55 | static char *nouveau_config; | 56 | static 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 | } |