diff options
author | Ben Skeggs <bskeggs@redhat.com> | 2014-05-20 21:39:07 -0400 |
---|---|---|
committer | Ben Skeggs <bskeggs@redhat.com> | 2014-06-11 02:10:45 -0400 |
commit | 2bd651ea4323e7fd1379593b701dd25289c68193 (patch) | |
tree | 85b7e96a14d4be5c848b45e6d44968adcadd73d5 /drivers/gpu/drm/nouveau | |
parent | 415f12efc1b2308411b2cbc3e82666b3db8a7758 (diff) |
drm/gf119/disp: start removing direct vbios parsing from supervisor
Signed-off-by: Ben Skeggs <bskeggs@redhat.com>
Diffstat (limited to 'drivers/gpu/drm/nouveau')
-rw-r--r-- | drivers/gpu/drm/nouveau/core/engine/disp/nvd0.c | 158 |
1 files changed, 83 insertions, 75 deletions
diff --git a/drivers/gpu/drm/nouveau/core/engine/disp/nvd0.c b/drivers/gpu/drm/nouveau/core/engine/disp/nvd0.c index e5f5e425e3e2..27ec9954a70b 100644 --- a/drivers/gpu/drm/nouveau/core/engine/disp/nvd0.c +++ b/drivers/gpu/drm/nouveau/core/engine/disp/nvd0.c | |||
@@ -915,19 +915,20 @@ nvd0_disp_sclass[] = { | |||
915 | * Display engine implementation | 915 | * Display engine implementation |
916 | ******************************************************************************/ | 916 | ******************************************************************************/ |
917 | 917 | ||
918 | static u16 | 918 | static struct nvkm_output * |
919 | exec_lookup(struct nv50_disp_priv *priv, int head, int outp, u32 ctrl, | 919 | exec_lookup(struct nv50_disp_priv *priv, int head, int or, u32 ctrl, |
920 | struct dcb_output *dcb, u8 *ver, u8 *hdr, u8 *cnt, u8 *len, | 920 | u32 *data, u8 *ver, u8 *hdr, u8 *cnt, u8 *len, |
921 | struct nvbios_outp *info) | 921 | struct nvbios_outp *info) |
922 | { | 922 | { |
923 | struct nouveau_bios *bios = nouveau_bios(priv); | 923 | struct nouveau_bios *bios = nouveau_bios(priv); |
924 | u16 mask, type, data; | 924 | struct nvkm_output *outp; |
925 | u16 mask, type; | ||
925 | 926 | ||
926 | if (outp < 4) { | 927 | if (or < 4) { |
927 | type = DCB_OUTPUT_ANALOG; | 928 | type = DCB_OUTPUT_ANALOG; |
928 | mask = 0; | 929 | mask = 0; |
929 | } else { | 930 | } else { |
930 | outp -= 4; | 931 | or -= 4; |
931 | switch (ctrl & 0x00000f00) { | 932 | switch (ctrl & 0x00000f00) { |
932 | case 0x00000000: type = DCB_OUTPUT_LVDS; mask = 1; break; | 933 | case 0x00000000: type = DCB_OUTPUT_LVDS; mask = 1; break; |
933 | case 0x00000100: type = DCB_OUTPUT_TMDS; mask = 1; break; | 934 | case 0x00000100: type = DCB_OUTPUT_TMDS; mask = 1; break; |
@@ -939,47 +940,53 @@ exec_lookup(struct nv50_disp_priv *priv, int head, int outp, u32 ctrl, | |||
939 | nv_error(priv, "unknown SOR mc 0x%08x\n", ctrl); | 940 | nv_error(priv, "unknown SOR mc 0x%08x\n", ctrl); |
940 | return 0x0000; | 941 | return 0x0000; |
941 | } | 942 | } |
942 | dcb->sorconf.link = mask; | ||
943 | } | 943 | } |
944 | 944 | ||
945 | mask = 0x00c0 & (mask << 6); | 945 | mask = 0x00c0 & (mask << 6); |
946 | mask |= 0x0001 << outp; | 946 | mask |= 0x0001 << or; |
947 | mask |= 0x0100 << head; | 947 | mask |= 0x0100 << head; |
948 | 948 | ||
949 | data = dcb_outp_match(bios, type, mask, ver, hdr, dcb); | 949 | list_for_each_entry(outp, &priv->base.outp, head) { |
950 | if (!data) | 950 | if ((outp->info.hasht & 0xff) == type && |
951 | return 0x0000; | 951 | (outp->info.hashm & mask) == mask) { |
952 | *data = nvbios_outp_match(bios, outp->info.hasht, | ||
953 | outp->info.hashm, | ||
954 | ver, hdr, cnt, len, info); | ||
955 | if (!*data) | ||
956 | return NULL; | ||
957 | return outp; | ||
958 | } | ||
959 | } | ||
952 | 960 | ||
953 | return nvbios_outp_match(bios, type, mask, ver, hdr, cnt, len, info); | 961 | return NULL; |
954 | } | 962 | } |
955 | 963 | ||
956 | static bool | 964 | static bool |
957 | exec_script(struct nv50_disp_priv *priv, int head, int id) | 965 | exec_script(struct nv50_disp_priv *priv, int head, int id) |
958 | { | 966 | { |
959 | struct nouveau_bios *bios = nouveau_bios(priv); | 967 | struct nouveau_bios *bios = nouveau_bios(priv); |
968 | struct nvkm_output *outp; | ||
960 | struct nvbios_outp info; | 969 | struct nvbios_outp info; |
961 | struct dcb_output dcb; | ||
962 | u8 ver, hdr, cnt, len; | 970 | u8 ver, hdr, cnt, len; |
963 | u32 ctrl = 0x00000000; | 971 | u32 data, ctrl = 0; |
964 | u16 data; | 972 | int or; |
965 | int outp; | ||
966 | 973 | ||
967 | for (outp = 0; !(ctrl & (1 << head)) && outp < 8; outp++) { | 974 | for (or = 0; !(ctrl & (1 << head)) && or < 8; or++) { |
968 | ctrl = nv_rd32(priv, 0x640180 + (outp * 0x20)); | 975 | ctrl = nv_rd32(priv, 0x640180 + (or * 0x20)); |
969 | if (ctrl & (1 << head)) | 976 | if (ctrl & (1 << head)) |
970 | break; | 977 | break; |
971 | } | 978 | } |
972 | 979 | ||
973 | if (outp == 8) | 980 | if (or == 8) |
974 | return false; | 981 | return false; |
975 | 982 | ||
976 | data = exec_lookup(priv, head, outp, ctrl, &dcb, &ver, &hdr, &cnt, &len, &info); | 983 | outp = exec_lookup(priv, head, or, ctrl, &data, &ver, &hdr, &cnt, &len, &info); |
977 | if (data) { | 984 | if (outp) { |
978 | struct nvbios_init init = { | 985 | struct nvbios_init init = { |
979 | .subdev = nv_subdev(priv), | 986 | .subdev = nv_subdev(priv), |
980 | .bios = bios, | 987 | .bios = bios, |
981 | .offset = info.script[id], | 988 | .offset = info.script[id], |
982 | .outp = &dcb, | 989 | .outp = &outp->info, |
983 | .crtc = head, | 990 | .crtc = head, |
984 | .execute = 1, | 991 | .execute = 1, |
985 | }; | 992 | }; |
@@ -990,50 +997,49 @@ exec_script(struct nv50_disp_priv *priv, int head, int id) | |||
990 | return false; | 997 | return false; |
991 | } | 998 | } |
992 | 999 | ||
993 | static u32 | 1000 | static struct nvkm_output * |
994 | exec_clkcmp(struct nv50_disp_priv *priv, int head, int id, | 1001 | exec_clkcmp(struct nv50_disp_priv *priv, int head, int id, u32 pclk, u32 *conf) |
995 | u32 pclk, struct dcb_output *dcb) | ||
996 | { | 1002 | { |
997 | struct nouveau_bios *bios = nouveau_bios(priv); | 1003 | struct nouveau_bios *bios = nouveau_bios(priv); |
1004 | struct nvkm_output *outp; | ||
998 | struct nvbios_outp info1; | 1005 | struct nvbios_outp info1; |
999 | struct nvbios_ocfg info2; | 1006 | struct nvbios_ocfg info2; |
1000 | u8 ver, hdr, cnt, len; | 1007 | u8 ver, hdr, cnt, len; |
1001 | u32 ctrl = 0x00000000; | 1008 | u32 data, ctrl = 0; |
1002 | u32 data, conf = ~0; | 1009 | int or; |
1003 | int outp; | ||
1004 | 1010 | ||
1005 | for (outp = 0; !(ctrl & (1 << head)) && outp < 8; outp++) { | 1011 | for (or = 0; !(ctrl & (1 << head)) && or < 8; or++) { |
1006 | ctrl = nv_rd32(priv, 0x660180 + (outp * 0x20)); | 1012 | ctrl = nv_rd32(priv, 0x660180 + (or * 0x20)); |
1007 | if (ctrl & (1 << head)) | 1013 | if (ctrl & (1 << head)) |
1008 | break; | 1014 | break; |
1009 | } | 1015 | } |
1010 | 1016 | ||
1011 | if (outp == 8) | 1017 | if (or == 8) |
1012 | return conf; | 1018 | return NULL; |
1013 | 1019 | ||
1014 | data = exec_lookup(priv, head, outp, ctrl, dcb, &ver, &hdr, &cnt, &len, &info1); | 1020 | outp = exec_lookup(priv, head, or, ctrl, &data, &ver, &hdr, &cnt, &len, &info1); |
1015 | if (data == 0x0000) | 1021 | if (!outp) |
1016 | return conf; | 1022 | return NULL; |
1017 | 1023 | ||
1018 | switch (dcb->type) { | 1024 | switch (outp->info.type) { |
1019 | case DCB_OUTPUT_TMDS: | 1025 | case DCB_OUTPUT_TMDS: |
1020 | conf = (ctrl & 0x00000f00) >> 8; | 1026 | *conf = (ctrl & 0x00000f00) >> 8; |
1021 | if (pclk >= 165000) | 1027 | if (pclk >= 165000) |
1022 | conf |= 0x0100; | 1028 | *conf |= 0x0100; |
1023 | break; | 1029 | break; |
1024 | case DCB_OUTPUT_LVDS: | 1030 | case DCB_OUTPUT_LVDS: |
1025 | conf = priv->sor.lvdsconf; | 1031 | *conf = priv->sor.lvdsconf; |
1026 | break; | 1032 | break; |
1027 | case DCB_OUTPUT_DP: | 1033 | case DCB_OUTPUT_DP: |
1028 | conf = (ctrl & 0x00000f00) >> 8; | 1034 | *conf = (ctrl & 0x00000f00) >> 8; |
1029 | break; | 1035 | break; |
1030 | case DCB_OUTPUT_ANALOG: | 1036 | case DCB_OUTPUT_ANALOG: |
1031 | default: | 1037 | default: |
1032 | conf = 0x00ff; | 1038 | *conf = 0x00ff; |
1033 | break; | 1039 | break; |
1034 | } | 1040 | } |
1035 | 1041 | ||
1036 | data = nvbios_ocfg_match(bios, data, conf, &ver, &hdr, &cnt, &len, &info2); | 1042 | data = nvbios_ocfg_match(bios, data, *conf, &ver, &hdr, &cnt, &len, &info2); |
1037 | if (data && id < 0xff) { | 1043 | if (data && id < 0xff) { |
1038 | data = nvbios_oclk_match(bios, info2.clkcmp[id], pclk); | 1044 | data = nvbios_oclk_match(bios, info2.clkcmp[id], pclk); |
1039 | if (data) { | 1045 | if (data) { |
@@ -1041,7 +1047,7 @@ exec_clkcmp(struct nv50_disp_priv *priv, int head, int id, | |||
1041 | .subdev = nv_subdev(priv), | 1047 | .subdev = nv_subdev(priv), |
1042 | .bios = bios, | 1048 | .bios = bios, |
1043 | .offset = data, | 1049 | .offset = data, |
1044 | .outp = dcb, | 1050 | .outp = &outp->info, |
1045 | .crtc = head, | 1051 | .crtc = head, |
1046 | .execute = 1, | 1052 | .execute = 1, |
1047 | }; | 1053 | }; |
@@ -1050,7 +1056,7 @@ exec_clkcmp(struct nv50_disp_priv *priv, int head, int id, | |||
1050 | } | 1056 | } |
1051 | } | 1057 | } |
1052 | 1058 | ||
1053 | return conf; | 1059 | return outp; |
1054 | } | 1060 | } |
1055 | 1061 | ||
1056 | static void | 1062 | static void |
@@ -1124,49 +1130,51 @@ nvd0_disp_intr_unk2_2_tu(struct nv50_disp_priv *priv, int head, | |||
1124 | static void | 1130 | static void |
1125 | nvd0_disp_intr_unk2_2(struct nv50_disp_priv *priv, int head) | 1131 | nvd0_disp_intr_unk2_2(struct nv50_disp_priv *priv, int head) |
1126 | { | 1132 | { |
1127 | struct dcb_output outp; | 1133 | struct nvkm_output *outp; |
1128 | u32 pclk = nv_rd32(priv, 0x660450 + (head * 0x300)) / 1000; | 1134 | u32 pclk = nv_rd32(priv, 0x660450 + (head * 0x300)) / 1000; |
1129 | u32 conf = exec_clkcmp(priv, head, 0xff, pclk, &outp); | 1135 | u32 conf, addr, data; |
1130 | if (conf != ~0) { | 1136 | |
1131 | u32 addr, data; | 1137 | outp = exec_clkcmp(priv, head, 0xff, pclk, &conf); |
1132 | 1138 | if (!outp) | |
1133 | if (outp.type == DCB_OUTPUT_DP) { | 1139 | return; |
1134 | u32 sync = nv_rd32(priv, 0x660404 + (head * 0x300)); | 1140 | |
1135 | switch ((sync & 0x000003c0) >> 6) { | 1141 | if (outp->info.type == DCB_OUTPUT_DP) { |
1136 | case 6: pclk = pclk * 30 / 8; break; | 1142 | u32 sync = nv_rd32(priv, 0x660404 + (head * 0x300)); |
1137 | case 5: pclk = pclk * 24 / 8; break; | 1143 | switch ((sync & 0x000003c0) >> 6) { |
1138 | case 2: | 1144 | case 6: pclk = pclk * 30 / 8; break; |
1139 | default: | 1145 | case 5: pclk = pclk * 24 / 8; break; |
1140 | pclk = pclk * 18 / 8; | 1146 | case 2: |
1141 | break; | 1147 | default: |
1142 | } | 1148 | pclk = pclk * 18 / 8; |
1143 | 1149 | break; | |
1144 | nouveau_dp_train(&priv->base, priv->sor.dp, | ||
1145 | &outp, head, pclk); | ||
1146 | } | 1150 | } |
1147 | 1151 | ||
1148 | exec_clkcmp(priv, head, 0, pclk, &outp); | 1152 | nouveau_dp_train(&priv->base, priv->sor.dp, |
1153 | &outp->info, head, pclk); | ||
1154 | } | ||
1149 | 1155 | ||
1150 | if (outp.type == DCB_OUTPUT_ANALOG) { | 1156 | exec_clkcmp(priv, head, 0, pclk, &conf); |
1151 | addr = 0x612280 + (ffs(outp.or) - 1) * 0x800; | ||
1152 | data = 0x00000000; | ||
1153 | } else { | ||
1154 | if (outp.type == DCB_OUTPUT_DP) | ||
1155 | nvd0_disp_intr_unk2_2_tu(priv, head, &outp); | ||
1156 | addr = 0x612300 + (ffs(outp.or) - 1) * 0x800; | ||
1157 | data = (conf & 0x0100) ? 0x00000101 : 0x00000000; | ||
1158 | } | ||
1159 | 1157 | ||
1160 | nv_mask(priv, addr, 0x00000707, data); | 1158 | if (outp->info.type == DCB_OUTPUT_ANALOG) { |
1159 | addr = 0x612280 + (ffs(outp->info.or) - 1) * 0x800; | ||
1160 | data = 0x00000000; | ||
1161 | } else { | ||
1162 | if (outp->info.type == DCB_OUTPUT_DP) | ||
1163 | nvd0_disp_intr_unk2_2_tu(priv, head, &outp->info); | ||
1164 | addr = 0x612300 + (ffs(outp->info.or) - 1) * 0x800; | ||
1165 | data = (conf & 0x0100) ? 0x00000101 : 0x00000000; | ||
1161 | } | 1166 | } |
1167 | |||
1168 | nv_mask(priv, addr, 0x00000707, data); | ||
1162 | } | 1169 | } |
1163 | 1170 | ||
1164 | static void | 1171 | static void |
1165 | nvd0_disp_intr_unk4_0(struct nv50_disp_priv *priv, int head) | 1172 | nvd0_disp_intr_unk4_0(struct nv50_disp_priv *priv, int head) |
1166 | { | 1173 | { |
1167 | struct dcb_output outp; | ||
1168 | u32 pclk = nv_rd32(priv, 0x660450 + (head * 0x300)) / 1000; | 1174 | u32 pclk = nv_rd32(priv, 0x660450 + (head * 0x300)) / 1000; |
1169 | exec_clkcmp(priv, head, 1, pclk, &outp); | 1175 | u32 conf; |
1176 | |||
1177 | exec_clkcmp(priv, head, 1, pclk, &conf); | ||
1170 | } | 1178 | } |
1171 | 1179 | ||
1172 | void | 1180 | void |