aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/gpu/drm
diff options
context:
space:
mode:
authorBen Skeggs <bskeggs@redhat.com>2013-02-10 18:24:23 -0500
committerBen Skeggs <bskeggs@redhat.com>2013-02-20 01:01:04 -0500
commit476e84e126171d809f9c0b5d97137f5055f95ca8 (patch)
tree1bcabb855c82aa7e42572f4e8a6abe52c37030aa /drivers/gpu/drm
parenta2bc283f3905389ba53962a2bbb05ede0c16193d (diff)
drm/nv50-/disp: initial supervisor support for off-chip encoders
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.c124
-rw-r--r--drivers/gpu/drm/nouveau/core/subdev/bios/init.c9
2 files changed, 100 insertions, 33 deletions
diff --git a/drivers/gpu/drm/nouveau/core/engine/disp/nv50.c b/drivers/gpu/drm/nouveau/core/engine/disp/nv50.c
index 129815319974..314dda6d7cb8 100644
--- a/drivers/gpu/drm/nouveau/core/engine/disp/nv50.c
+++ b/drivers/gpu/drm/nouveau/core/engine/disp/nv50.c
@@ -626,7 +626,7 @@ nv50_disp_base_init(struct nouveau_object *object)
626 nv_wr32(priv, 0x6101e0 + (i * 0x04), tmp); 626 nv_wr32(priv, 0x6101e0 + (i * 0x04), tmp);
627 } 627 }
628 628
629 /* ... EXT caps */ 629 /* ... PIOR caps */
630 for (i = 0; i < 3; i++) { 630 for (i = 0; i < 3; i++) {
631 tmp = nv_rd32(priv, 0x61e000 + (i * 0x800)); 631 tmp = nv_rd32(priv, 0x61e000 + (i * 0x800));
632 nv_wr32(priv, 0x6101f0 + (i * 0x04), tmp); 632 nv_wr32(priv, 0x6101f0 + (i * 0x04), tmp);
@@ -783,8 +783,8 @@ exec_lookup(struct nv50_disp_priv *priv, int head, int outp, u32 ctrl,
783 if (outp < 4) { 783 if (outp < 4) {
784 type = DCB_OUTPUT_ANALOG; 784 type = DCB_OUTPUT_ANALOG;
785 mask = 0; 785 mask = 0;
786 } else { 786 } else
787 outp -= 4; 787 if (outp < 8) {
788 switch (ctrl & 0x00000f00) { 788 switch (ctrl & 0x00000f00) {
789 case 0x00000000: type = DCB_OUTPUT_LVDS; mask = 1; break; 789 case 0x00000000: type = DCB_OUTPUT_LVDS; mask = 1; break;
790 case 0x00000100: type = DCB_OUTPUT_TMDS; mask = 1; break; 790 case 0x00000100: type = DCB_OUTPUT_TMDS; mask = 1; break;
@@ -796,6 +796,17 @@ exec_lookup(struct nv50_disp_priv *priv, int head, int outp, u32 ctrl,
796 nv_error(priv, "unknown SOR mc 0x%08x\n", ctrl); 796 nv_error(priv, "unknown SOR mc 0x%08x\n", ctrl);
797 return 0x0000; 797 return 0x0000;
798 } 798 }
799 outp -= 4;
800 } else {
801 outp = outp - 8;
802 type = 0x0010;
803 mask = 0;
804 switch (ctrl & 0x00000f00) {
805 case 0x00000000: type |= priv->pior.type[outp]; break;
806 default:
807 nv_error(priv, "unknown PIOR mc 0x%08x\n", ctrl);
808 return 0x0000;
809 }
799 } 810 }
800 811
801 mask = 0x00c0 & (mask << 6); 812 mask = 0x00c0 & (mask << 6);
@@ -806,6 +817,10 @@ exec_lookup(struct nv50_disp_priv *priv, int head, int outp, u32 ctrl,
806 if (!data) 817 if (!data)
807 return 0x0000; 818 return 0x0000;
808 819
820 /* off-chip encoders require matching the exact encoder type */
821 if (dcb->location != 0)
822 type |= dcb->extdev << 8;
823
809 return nvbios_outp_match(bios, type, mask, ver, hdr, cnt, len, info); 824 return nvbios_outp_match(bios, type, mask, ver, hdr, cnt, len, info);
810} 825}
811 826
@@ -820,9 +835,11 @@ exec_script(struct nv50_disp_priv *priv, int head, int id)
820 u32 ctrl = 0x00000000; 835 u32 ctrl = 0x00000000;
821 int i; 836 int i;
822 837
838 /* DAC */
823 for (i = 0; !(ctrl & (1 << head)) && i < 3; i++) 839 for (i = 0; !(ctrl & (1 << head)) && i < 3; i++)
824 ctrl = nv_rd32(priv, 0x610b5c + (i * 8)); 840 ctrl = nv_rd32(priv, 0x610b5c + (i * 8));
825 841
842 /* SOR */
826 if (!(ctrl & (1 << head))) { 843 if (!(ctrl & (1 << head))) {
827 if (nv_device(priv)->chipset < 0x90 || 844 if (nv_device(priv)->chipset < 0x90 ||
828 nv_device(priv)->chipset == 0x92 || 845 nv_device(priv)->chipset == 0x92 ||
@@ -837,6 +854,13 @@ exec_script(struct nv50_disp_priv *priv, int head, int id)
837 } 854 }
838 } 855 }
839 856
857 /* PIOR */
858 if (!(ctrl & (1 << head))) {
859 for (i = 0; !(ctrl & (1 << head)) && i < 3; i++)
860 ctrl = nv_rd32(priv, 0x610b84 + (i * 8));
861 i += 8;
862 }
863
840 if (!(ctrl & (1 << head))) 864 if (!(ctrl & (1 << head)))
841 return false; 865 return false;
842 i--; 866 i--;
@@ -870,9 +894,11 @@ exec_clkcmp(struct nv50_disp_priv *priv, int head, int id, u32 pclk,
870 u32 data, conf = ~0; 894 u32 data, conf = ~0;
871 int i; 895 int i;
872 896
897 /* DAC */
873 for (i = 0; !(ctrl & (1 << head)) && i < 3; i++) 898 for (i = 0; !(ctrl & (1 << head)) && i < 3; i++)
874 ctrl = nv_rd32(priv, 0x610b58 + (i * 8)); 899 ctrl = nv_rd32(priv, 0x610b58 + (i * 8));
875 900
901 /* SOR */
876 if (!(ctrl & (1 << head))) { 902 if (!(ctrl & (1 << head))) {
877 if (nv_device(priv)->chipset < 0x90 || 903 if (nv_device(priv)->chipset < 0x90 ||
878 nv_device(priv)->chipset == 0x92 || 904 nv_device(priv)->chipset == 0x92 ||
@@ -887,6 +913,13 @@ exec_clkcmp(struct nv50_disp_priv *priv, int head, int id, u32 pclk,
887 } 913 }
888 } 914 }
889 915
916 /* PIOR */
917 if (!(ctrl & (1 << head))) {
918 for (i = 0; !(ctrl & (1 << head)) && i < 3; i++)
919 ctrl = nv_rd32(priv, 0x610b80 + (i * 8));
920 i += 8;
921 }
922
890 if (!(ctrl & (1 << head))) 923 if (!(ctrl & (1 << head)))
891 return conf; 924 return conf;
892 i--; 925 i--;
@@ -895,22 +928,27 @@ exec_clkcmp(struct nv50_disp_priv *priv, int head, int id, u32 pclk,
895 if (!data) 928 if (!data)
896 return conf; 929 return conf;
897 930
898 switch (outp->type) { 931 if (outp->location == 0) {
899 case DCB_OUTPUT_TMDS: 932 switch (outp->type) {
900 conf = (ctrl & 0x00000f00) >> 8; 933 case DCB_OUTPUT_TMDS:
901 if (pclk >= 165000) 934 conf = (ctrl & 0x00000f00) >> 8;
902 conf |= 0x0100; 935 if (pclk >= 165000)
903 break; 936 conf |= 0x0100;
904 case DCB_OUTPUT_LVDS: 937 break;
905 conf = priv->sor.lvdsconf; 938 case DCB_OUTPUT_LVDS:
906 break; 939 conf = priv->sor.lvdsconf;
907 case DCB_OUTPUT_DP: 940 break;
941 case DCB_OUTPUT_DP:
942 conf = (ctrl & 0x00000f00) >> 8;
943 break;
944 case DCB_OUTPUT_ANALOG:
945 default:
946 conf = 0x00ff;
947 break;
948 }
949 } else {
908 conf = (ctrl & 0x00000f00) >> 8; 950 conf = (ctrl & 0x00000f00) >> 8;
909 break; 951 pclk = pclk / 2;
910 case DCB_OUTPUT_ANALOG:
911 default:
912 conf = 0x00ff;
913 break;
914 } 952 }
915 953
916 data = nvbios_ocfg_match(bios, data, conf, &ver, &hdr, &cnt, &len, &info2); 954 data = nvbios_ocfg_match(bios, data, conf, &ver, &hdr, &cnt, &len, &info2);
@@ -1057,7 +1095,6 @@ static void
1057nv50_disp_intr_unk20(struct nv50_disp_priv *priv, u32 super) 1095nv50_disp_intr_unk20(struct nv50_disp_priv *priv, u32 super)
1058{ 1096{
1059 struct dcb_output outp; 1097 struct dcb_output outp;
1060 u32 addr, mask, data;
1061 int head; 1098 int head;
1062 1099
1063 /* finish detaching encoder? */ 1100 /* finish detaching encoder? */
@@ -1073,14 +1110,14 @@ nv50_disp_intr_unk20(struct nv50_disp_priv *priv, u32 super)
1073 struct nouveau_clock *clk = nouveau_clock(priv); 1110 struct nouveau_clock *clk = nouveau_clock(priv);
1074 clk->pll_set(clk, PLL_VPLL0 + head, pclk); 1111 clk->pll_set(clk, PLL_VPLL0 + head, pclk);
1075 } 1112 }
1076
1077 nv_mask(priv, 0x614200 + head * 0x800, 0x0000000f, 0x00000000);
1078 } 1113 }
1079 1114
1080 /* (re)attach the relevant OR to the head */ 1115 /* (re)attach the relevant OR to the head */
1081 head = ffs((super & 0x00000180) >> 7) - 1; 1116 head = ffs((super & 0x00000180) >> 7) - 1;
1082 if (head >= 0) { 1117 if (head >= 0) {
1083 u32 pclk = nv_rd32(priv, 0x610ad0 + (head * 0x540)) & 0x3fffff; 1118 u32 pclk = nv_rd32(priv, 0x610ad0 + (head * 0x540)) & 0x3fffff;
1119 u32 hval, hreg = 0x614200 + (head * 0x800);
1120 u32 oval, oreg;
1084 u32 conf = exec_clkcmp(priv, head, 0xff, pclk, &outp); 1121 u32 conf = exec_clkcmp(priv, head, 0xff, pclk, &outp);
1085 if (conf != ~0) { 1122 if (conf != ~0) {
1086 if (outp.location == 0 && outp.type == DCB_OUTPUT_DP) { 1123 if (outp.location == 0 && outp.type == DCB_OUTPUT_DP) {
@@ -1103,19 +1140,25 @@ nv50_disp_intr_unk20(struct nv50_disp_priv *priv, u32 super)
1103 1140
1104 exec_clkcmp(priv, head, 0, pclk, &outp); 1141 exec_clkcmp(priv, head, 0, pclk, &outp);
1105 1142
1106 if (outp.type == DCB_OUTPUT_ANALOG) { 1143 if (!outp.location && outp.type == DCB_OUTPUT_ANALOG) {
1107 addr = 0x614280 + (ffs(outp.or) - 1) * 0x800; 1144 oreg = 0x614280 + (ffs(outp.or) - 1) * 0x800;
1108 mask = 0xffffffff; 1145 oval = 0x00000000;
1109 data = 0x00000000; 1146 hval = 0x00000000;
1110 } else { 1147 } else
1148 if (!outp.location) {
1111 if (outp.type == DCB_OUTPUT_DP) 1149 if (outp.type == DCB_OUTPUT_DP)
1112 nv50_disp_intr_unk20_dp(priv, &outp, pclk); 1150 nv50_disp_intr_unk20_dp(priv, &outp, pclk);
1113 addr = 0x614300 + (ffs(outp.or) - 1) * 0x800; 1151 oreg = 0x614300 + (ffs(outp.or) - 1) * 0x800;
1114 mask = 0x00000707; 1152 oval = (conf & 0x0100) ? 0x0101 : 0x0000;
1115 data = (conf & 0x0100) ? 0x0101 : 0x0000; 1153 hval = 0x00000000;
1154 } else {
1155 oreg = 0x614380 + (ffs(outp.or) - 1) * 0x800;
1156 oval = 0x00000001;
1157 hval = 0x00000001;
1116 } 1158 }
1117 1159
1118 nv_mask(priv, addr, mask, data); 1160 nv_mask(priv, hreg, 0x0000000f, hval);
1161 nv_mask(priv, oreg, 0x00000707, oval);
1119 } 1162 }
1120 } 1163 }
1121 1164
@@ -1151,9 +1194,28 @@ nv50_disp_intr_unk40(struct nv50_disp_priv *priv, u32 super)
1151 if (head >= 0) { 1194 if (head >= 0) {
1152 struct dcb_output outp; 1195 struct dcb_output outp;
1153 u32 pclk = nv_rd32(priv, 0x610ad0 + (head * 0x540)) & 0x3fffff; 1196 u32 pclk = nv_rd32(priv, 0x610ad0 + (head * 0x540)) & 0x3fffff;
1154 if (exec_clkcmp(priv, head, 1, pclk, &outp) != ~0) 1197 if (exec_clkcmp(priv, head, 1, pclk, &outp) != ~0) {
1155 if (outp.location == 0 && outp.type == DCB_OUTPUT_TMDS) 1198 if (outp.location == 0 && outp.type == DCB_OUTPUT_TMDS)
1156 nv50_disp_intr_unk40_tmds(priv, &outp); 1199 nv50_disp_intr_unk40_tmds(priv, &outp);
1200 else
1201 if (outp.location == 1 && outp.type == DCB_OUTPUT_DP) {
1202 u32 soff = (ffs(outp.or) - 1) * 0x08;
1203 u32 ctrl = nv_rd32(priv, 0x610b84 + soff);
1204 u32 datarate;
1205
1206 switch ((ctrl & 0x000f0000) >> 16) {
1207 case 6: datarate = pclk * 30 / 8; break;
1208 case 5: datarate = pclk * 24 / 8; break;
1209 case 2:
1210 default:
1211 datarate = pclk * 18 / 8;
1212 break;
1213 }
1214
1215 nouveau_dp_train(&priv->base, priv->pior.dp,
1216 &outp, head, datarate);
1217 }
1218 }
1157 } 1219 }
1158 1220
1159 nv_wr32(priv, 0x610030, 0x80000000); 1221 nv_wr32(priv, 0x610030, 0x80000000);
diff --git a/drivers/gpu/drm/nouveau/core/subdev/bios/init.c b/drivers/gpu/drm/nouveau/core/subdev/bios/init.c
index 7d2ce11cf36a..2cc1e6a5eb6a 100644
--- a/drivers/gpu/drm/nouveau/core/subdev/bios/init.c
+++ b/drivers/gpu/drm/nouveau/core/subdev/bios/init.c
@@ -231,6 +231,11 @@ init_i2c(struct nvbios_init *init, int index)
231 return NULL; 231 return NULL;
232 } 232 }
233 233
234 if (index == -2 && init->outp->location) {
235 index = NV_I2C_TYPE_EXTAUX(init->outp->extdev);
236 return i2c->find_type(i2c, index);
237 }
238
234 index = init->outp->i2c_index; 239 index = init->outp->i2c_index;
235 } 240 }
236 241
@@ -258,7 +263,7 @@ init_wri2cr(struct nvbios_init *init, u8 index, u8 addr, u8 reg, u8 val)
258static int 263static int
259init_rdauxr(struct nvbios_init *init, u32 addr) 264init_rdauxr(struct nvbios_init *init, u32 addr)
260{ 265{
261 struct nouveau_i2c_port *port = init_i2c(init, -1); 266 struct nouveau_i2c_port *port = init_i2c(init, -2);
262 u8 data; 267 u8 data;
263 268
264 if (port && init_exec(init)) { 269 if (port && init_exec(init)) {
@@ -274,7 +279,7 @@ init_rdauxr(struct nvbios_init *init, u32 addr)
274static int 279static int
275init_wrauxr(struct nvbios_init *init, u32 addr, u8 data) 280init_wrauxr(struct nvbios_init *init, u32 addr, u8 data)
276{ 281{
277 struct nouveau_i2c_port *port = init_i2c(init, -1); 282 struct nouveau_i2c_port *port = init_i2c(init, -2);
278 if (port && init_exec(init)) 283 if (port && init_exec(init))
279 return nv_wraux(port, addr, &data, 1); 284 return nv_wraux(port, addr, &data, 1);
280 return -ENODEV; 285 return -ENODEV;