aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/gpu/drm/nouveau/nvd0_display.c
diff options
context:
space:
mode:
authorBen Skeggs <bskeggs@redhat.com>2011-07-08 00:34:45 -0400
committerBen Skeggs <bskeggs@redhat.com>2011-09-20 02:07:46 -0400
commitee41779e76fd69168bce3f0530828a67ecb8db5b (patch)
treeb1b5f44117e96e5b409122e3dd7153b62f009ae7 /drivers/gpu/drm/nouveau/nvd0_display.c
parentf20ce9629f820c00e581acc4c9938fbf6e34475d (diff)
drm/nvd0/disp: rewrite irq handler, should be somewhat sturdier now
Signed-off-by: Ben Skeggs <bskeggs@redhat.com>
Diffstat (limited to 'drivers/gpu/drm/nouveau/nvd0_display.c')
-rw-r--r--drivers/gpu/drm/nouveau/nvd0_display.c192
1 files changed, 111 insertions, 81 deletions
diff --git a/drivers/gpu/drm/nouveau/nvd0_display.c b/drivers/gpu/drm/nouveau/nvd0_display.c
index b6a8c6def64c..725ae9983f1c 100644
--- a/drivers/gpu/drm/nouveau/nvd0_display.c
+++ b/drivers/gpu/drm/nouveau/nvd0_display.c
@@ -46,14 +46,7 @@ struct nvd0_display {
46 } evo[1]; 46 } evo[1];
47 47
48 struct tasklet_struct tasklet; 48 struct tasklet_struct tasklet;
49 struct { 49 u32 modeset;
50 struct dcb_entry *dis;
51 struct dcb_entry *ena;
52 u32 modeset;
53 int crtc;
54 int pclk;
55 u16 cfg;
56 } irq;
57}; 50};
58 51
59static struct nvd0_display * 52static struct nvd0_display *
@@ -965,6 +958,23 @@ nvd0_sor_create(struct drm_connector *connector, struct dcb_entry *dcbe)
965/****************************************************************************** 958/******************************************************************************
966 * IRQ 959 * IRQ
967 *****************************************************************************/ 960 *****************************************************************************/
961static void
962debug_irq(struct drm_device *dev, int i)
963{
964 if (drm_debug & (DRM_UT_DRIVER | DRM_UT_KMS)) {
965 NV_INFO(dev, "PDISP: modeset req %d\n", i);
966 NV_INFO(dev, " STAT: 0x%08x 0x%08x 0x%08x\n",
967 nv_rd32(dev, 0x6101d0),
968 nv_rd32(dev, 0x6101d4), nv_rd32(dev, 0x6109d4));
969 for (i = 0; i < 8; i++) {
970 NV_INFO(dev, " %s%d: 0x%08x 0x%08x\n",
971 i < 4 ? "DAC" : "SOR", i,
972 nv_rd32(dev, 0x640180 + (i * 0x20)),
973 nv_rd32(dev, 0x660180 + (i * 0x20)));
974 }
975 }
976}
977
968static struct dcb_entry * 978static struct dcb_entry *
969lookup_dcb(struct drm_device *dev, int id, u32 mc) 979lookup_dcb(struct drm_device *dev, int id, u32 mc)
970{ 980{
@@ -981,6 +991,7 @@ lookup_dcb(struct drm_device *dev, int id, u32 mc)
981 case 0x00000200: type = OUTPUT_TMDS; break; 991 case 0x00000200: type = OUTPUT_TMDS; break;
982 case 0x00000500: type = OUTPUT_TMDS; break; 992 case 0x00000500: type = OUTPUT_TMDS; break;
983 default: 993 default:
994 NV_ERROR(dev, "PDISP: unknown SOR mc 0x%08x\n", mc);
984 return NULL; 995 return NULL;
985 } 996 }
986 997
@@ -993,49 +1004,36 @@ lookup_dcb(struct drm_device *dev, int id, u32 mc)
993 return dcb; 1004 return dcb;
994 } 1005 }
995 1006
996 NV_INFO(dev, "PDISP: DCB for %d/0x%08x not found\n", id, mc); 1007 NV_ERROR(dev, "PDISP: DCB for %d/0x%08x not found\n", id, mc);
997 return NULL; 1008 return NULL;
998} 1009}
999 1010
1000static void 1011static void
1001nvd0_display_unk1_handler(struct drm_device *dev) 1012nvd0_display_unk1_handler(struct drm_device *dev)
1002{ 1013{
1003 struct nvd0_display *disp = nvd0_display(dev);
1004 struct dcb_entry *dcb; 1014 struct dcb_entry *dcb;
1005 u32 unkn, crtc = 0; 1015 u32 mask, crtc;
1006 int i; 1016 int i;
1007 1017
1008 NV_INFO(dev, "PDISP: 1 0x%08x 0x%08x 0x%08x\n", nv_rd32(dev, 0x6101d0), 1018 mask = nv_rd32(dev, 0x6101d4);
1009 nv_rd32(dev, 0x6101d4), nv_rd32(dev, 0x6109d4)); 1019 crtc = 0;
1010 1020 if (!mask) {
1011 unkn = nv_rd32(dev, 0x6101d4); 1021 mask = nv_rd32(dev, 0x6109d4);
1012 if (!unkn) {
1013 unkn = nv_rd32(dev, 0x6109d4);
1014 crtc = 1; 1022 crtc = 1;
1015 } 1023 }
1024 debug_irq(dev, 1);
1016 1025
1017 disp->irq.ena = NULL; 1026 for (i = 0; mask && i < 8; i++) {
1018 disp->irq.dis = NULL;
1019 disp->irq.crtc = crtc;
1020 disp->irq.pclk = nv_rd32(dev, 0x660450 + (disp->irq.crtc * 0x300));
1021 disp->irq.pclk /= 1000;
1022
1023 for (i = 0; i < 8; i++) {
1024 u32 mcc = nv_rd32(dev, 0x640180 + (i * 0x20)); 1027 u32 mcc = nv_rd32(dev, 0x640180 + (i * 0x20));
1025 u32 mcp = nv_rd32(dev, 0x660180 + (i * 0x20)); 1028 if (!(mcc & (1 << crtc)))
1026 1029 continue;
1027 if (mcc & (1 << crtc))
1028 disp->irq.dis = lookup_dcb(dev, i, mcc);
1029 1030
1030 if (mcp & (1 << crtc)) { 1031 dcb = lookup_dcb(dev, i, mcc);
1031 disp->irq.cfg = nv_rd32(dev, 0x660184 + (i * 0x20)); 1032 if (!dcb)
1032 disp->irq.ena = lookup_dcb(dev, i, mcp); 1033 continue;
1033 }
1034 }
1035 1034
1036 dcb = disp->irq.dis;
1037 if (dcb)
1038 nouveau_bios_run_display_table(dev, 0x0000, -1, dcb, crtc); 1035 nouveau_bios_run_display_table(dev, 0x0000, -1, dcb, crtc);
1036 }
1039 1037
1040 nv_wr32(dev, 0x6101d4, 0x00000000); 1038 nv_wr32(dev, 0x6101d4, 0x00000000);
1041 nv_wr32(dev, 0x6109d4, 0x00000000); 1039 nv_wr32(dev, 0x6109d4, 0x00000000);
@@ -1045,49 +1043,70 @@ nvd0_display_unk1_handler(struct drm_device *dev)
1045static void 1043static void
1046nvd0_display_unk2_handler(struct drm_device *dev) 1044nvd0_display_unk2_handler(struct drm_device *dev)
1047{ 1045{
1048 struct nvd0_display *disp = nvd0_display(dev);
1049 struct dcb_entry *dcb; 1046 struct dcb_entry *dcb;
1050 int crtc = disp->irq.crtc; 1047 u32 mask, crtc, pclk;
1051 int pclk = disp->irq.pclk; 1048 u32 or, tmp;
1052 int or; 1049 int i;
1053 u32 tmp; 1050
1051 mask = nv_rd32(dev, 0x6101d4);
1052 crtc = 0;
1053 if (!mask) {
1054 mask = nv_rd32(dev, 0x6109d4);
1055 crtc = 1;
1056 }
1057 debug_irq(dev, 2);
1054 1058
1055 NV_INFO(dev, "PDISP: 2 0x%08x 0x%08x 0x%08x\n", nv_rd32(dev, 0x6101d0), 1059 for (i = 0; mask && i < 8; i++) {
1056 nv_rd32(dev, 0x6101d4), nv_rd32(dev, 0x6109d4)); 1060 u32 mcc = nv_rd32(dev, 0x640180 + (i * 0x20));
1061 if (!(mcc & (1 << crtc)))
1062 continue;
1063
1064 dcb = lookup_dcb(dev, i, mcc);
1065 if (!dcb)
1066 continue;
1057 1067
1058 dcb = disp->irq.dis;
1059 disp->irq.dis = NULL;
1060 if (dcb)
1061 nouveau_bios_run_display_table(dev, 0x0000, -2, dcb, crtc); 1068 nouveau_bios_run_display_table(dev, 0x0000, -2, dcb, crtc);
1069 }
1070
1071 pclk = nv_rd32(dev, 0x660450 + (crtc * 0x300)) / 1000;
1072 if (mask & 0x00010000) {
1073 nv50_crtc_set_clock(dev, crtc, pclk);
1074 }
1062 1075
1063 nv50_crtc_set_clock(dev, crtc, pclk); 1076 for (i = 0; mask && i < 8; i++) {
1077 u32 mcp = nv_rd32(dev, 0x660180 + (i * 0x20));
1078 u32 cfg = nv_rd32(dev, 0x660184 + (i * 0x20));
1079 if (!(mcp & (1 << crtc)))
1080 continue;
1064 1081
1065 dcb = disp->irq.ena; 1082 dcb = lookup_dcb(dev, i, mcp);
1066 if (!dcb) 1083 if (!dcb)
1067 goto ack; 1084 continue;
1068 or = ffs(dcb->or) - 1; 1085 or = ffs(dcb->or) - 1;
1069 1086
1070 nouveau_bios_run_display_table(dev, disp->irq.cfg, pclk, dcb, crtc); 1087 nouveau_bios_run_display_table(dev, cfg, pclk, dcb, crtc);
1071 1088
1072 nv_wr32(dev, 0x612200 + (crtc * 0x800), 0x00000000); 1089 nv_wr32(dev, 0x612200 + (crtc * 0x800), 0x00000000);
1073 switch (dcb->type) { 1090 switch (dcb->type) {
1074 case OUTPUT_ANALOG: 1091 case OUTPUT_ANALOG:
1075 nv_wr32(dev, 0x612280 + (or * 0x800), 0x00000000); 1092 nv_wr32(dev, 0x612280 + (or * 0x800), 0x00000000);
1076 break; 1093 break;
1077 case OUTPUT_TMDS: 1094 case OUTPUT_TMDS:
1078 case OUTPUT_LVDS: 1095 case OUTPUT_LVDS:
1079 if (disp->irq.cfg & 0x00000100) 1096 if (cfg & 0x00000100)
1080 tmp = 0x00000101; 1097 tmp = 0x00000101;
1081 else 1098 else
1082 tmp = 0x00000000; 1099 tmp = 0x00000000;
1100
1101 nv_mask(dev, 0x612300 + (or * 0x800), 0x00000707, tmp);
1102 break;
1103 default:
1104 break;
1105 }
1083 1106
1084 nv_mask(dev, 0x612300 + (or * 0x800), 0x00000707, tmp);
1085 break;
1086 default:
1087 break; 1107 break;
1088 } 1108 }
1089 1109
1090ack:
1091 nv_wr32(dev, 0x6101d4, 0x00000000); 1110 nv_wr32(dev, 0x6101d4, 0x00000000);
1092 nv_wr32(dev, 0x6109d4, 0x00000000); 1111 nv_wr32(dev, 0x6109d4, 0x00000000);
1093 nv_wr32(dev, 0x6101d0, 0x80000000); 1112 nv_wr32(dev, 0x6101d0, 0x80000000);
@@ -1096,22 +1115,33 @@ ack:
1096static void 1115static void
1097nvd0_display_unk4_handler(struct drm_device *dev) 1116nvd0_display_unk4_handler(struct drm_device *dev)
1098{ 1117{
1099 struct nvd0_display *disp = nvd0_display(dev);
1100 struct dcb_entry *dcb; 1118 struct dcb_entry *dcb;
1101 int crtc = disp->irq.crtc; 1119 u32 mask, crtc;
1102 int pclk = disp->irq.pclk; 1120 int pclk, i;
1121
1122 mask = nv_rd32(dev, 0x6101d4);
1123 crtc = 0;
1124 if (!mask) {
1125 mask = nv_rd32(dev, 0x6109d4);
1126 crtc = 1;
1127 }
1128 debug_irq(dev, 4);
1103 1129
1104 NV_INFO(dev, "PDISP: 4 0x%08x 0x%08x 0x%08x\n", nv_rd32(dev, 0x6101d0), 1130 pclk = nv_rd32(dev, 0x660450 + (crtc * 0x300)) / 1000;
1105 nv_rd32(dev, 0x6101d4), nv_rd32(dev, 0x6109d4));
1106 1131
1107 dcb = disp->irq.ena; 1132 for (i = 0; mask && i < 8; i++) {
1108 disp->irq.ena = NULL; 1133 u32 mcp = nv_rd32(dev, 0x660180 + (i * 0x20));
1109 if (!dcb) 1134 u32 cfg = nv_rd32(dev, 0x660184 + (i * 0x20));
1110 goto ack; 1135 if (!(mcp & (1 << crtc)))
1136 continue;
1111 1137
1112 nouveau_bios_run_display_table(dev, disp->irq.cfg, pclk, dcb, crtc); 1138 dcb = lookup_dcb(dev, i, mcp);
1139 if (!dcb)
1140 continue;
1141
1142 nouveau_bios_run_display_table(dev, cfg, -pclk, dcb, crtc);
1143 }
1113 1144
1114ack:
1115 nv_wr32(dev, 0x6101d4, 0x00000000); 1145 nv_wr32(dev, 0x6101d4, 0x00000000);
1116 nv_wr32(dev, 0x6109d4, 0x00000000); 1146 nv_wr32(dev, 0x6109d4, 0x00000000);
1117 nv_wr32(dev, 0x6101d0, 0x80000000); 1147 nv_wr32(dev, 0x6101d0, 0x80000000);
@@ -1123,11 +1153,11 @@ nvd0_display_bh(unsigned long data)
1123 struct drm_device *dev = (struct drm_device *)data; 1153 struct drm_device *dev = (struct drm_device *)data;
1124 struct nvd0_display *disp = nvd0_display(dev); 1154 struct nvd0_display *disp = nvd0_display(dev);
1125 1155
1126 if (disp->irq.modeset & 0x00000001) 1156 if (disp->modeset & 0x00000001)
1127 nvd0_display_unk1_handler(dev); 1157 nvd0_display_unk1_handler(dev);
1128 if (disp->irq.modeset & 0x00000002) 1158 if (disp->modeset & 0x00000002)
1129 nvd0_display_unk2_handler(dev); 1159 nvd0_display_unk2_handler(dev);
1130 if (disp->irq.modeset & 0x00000004) 1160 if (disp->modeset & 0x00000004)
1131 nvd0_display_unk4_handler(dev); 1161 nvd0_display_unk4_handler(dev);
1132} 1162}
1133 1163
@@ -1159,7 +1189,7 @@ nvd0_display_intr(struct drm_device *dev)
1159 u32 stat = nv_rd32(dev, 0x6100ac); 1189 u32 stat = nv_rd32(dev, 0x6100ac);
1160 1190
1161 if (stat & 0x00000007) { 1191 if (stat & 0x00000007) {
1162 disp->irq.modeset = stat; 1192 disp->modeset = stat;
1163 tasklet_schedule(&disp->tasklet); 1193 tasklet_schedule(&disp->tasklet);
1164 1194
1165 nv_wr32(dev, 0x6100ac, (stat & 0x00000007)); 1195 nv_wr32(dev, 0x6100ac, (stat & 0x00000007));