diff options
author | Ben Skeggs <bskeggs@redhat.com> | 2013-02-20 03:56:33 -0500 |
---|---|---|
committer | Ben Skeggs <bskeggs@redhat.com> | 2013-02-20 05:46:21 -0500 |
commit | 16d4c031dd3befa1a85ff4645e28bb173e16ef43 (patch) | |
tree | 0f66d50e24903244790513819f827b07abe1a026 /drivers/gpu/drm | |
parent | a91ed42de25e7e81159c0dd59faf8cac9dfa1d32 (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.c | 226 |
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 | ||
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 |