aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/gpu/drm
diff options
context:
space:
mode:
authorBen Skeggs <bskeggs@redhat.com>2013-02-20 03:56:33 -0500
committerBen Skeggs <bskeggs@redhat.com>2013-02-20 05:46:21 -0500
commit16d4c031dd3befa1a85ff4645e28bb173e16ef43 (patch)
tree0f66d50e24903244790513819f827b07abe1a026 /drivers/gpu/drm
parenta91ed42de25e7e81159c0dd59faf8cac9dfa1d32 (diff)
drm/nv50/disp: handle multiple actions from one set of supervisor intrs
Signed-off-by: Ben Skeggs <bskeggs@redhat.com>
Diffstat (limited to 'drivers/gpu/drm')
-rw-r--r--drivers/gpu/drm/nouveau/core/engine/disp/nv50.c226
1 files changed, 118 insertions, 108 deletions
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