diff options
Diffstat (limited to 'drivers')
-rw-r--r-- | drivers/gpu/drm/nouveau/nouveau_bios.c | 124 |
1 files changed, 124 insertions, 0 deletions
diff --git a/drivers/gpu/drm/nouveau/nouveau_bios.c b/drivers/gpu/drm/nouveau/nouveau_bios.c index abc382a9918b..c11039f90d2e 100644 --- a/drivers/gpu/drm/nouveau/nouveau_bios.c +++ b/drivers/gpu/drm/nouveau/nouveau_bios.c | |||
@@ -26,6 +26,7 @@ | |||
26 | #define NV_DEBUG_NOTRACE | 26 | #define NV_DEBUG_NOTRACE |
27 | #include "nouveau_drv.h" | 27 | #include "nouveau_drv.h" |
28 | #include "nouveau_hw.h" | 28 | #include "nouveau_hw.h" |
29 | #include "nouveau_encoder.h" | ||
29 | 30 | ||
30 | /* these defines are made up */ | 31 | /* these defines are made up */ |
31 | #define NV_CIO_CRE_44_HEADA 0x0 | 32 | #define NV_CIO_CRE_44_HEADA 0x0 |
@@ -1067,6 +1068,126 @@ init_io_flag_condition(struct nvbios *bios, uint16_t offset, | |||
1067 | } | 1068 | } |
1068 | 1069 | ||
1069 | static int | 1070 | static int |
1071 | init_dp_condition(struct nvbios *bios, uint16_t offset, struct init_exec *iexec) | ||
1072 | { | ||
1073 | /* | ||
1074 | * INIT_DP_CONDITION opcode: 0x3A ('') | ||
1075 | * | ||
1076 | * offset (8 bit): opcode | ||
1077 | * offset + 1 (8 bit): "sub" opcode | ||
1078 | * offset + 2 (8 bit): unknown | ||
1079 | * | ||
1080 | */ | ||
1081 | |||
1082 | struct bit_displayport_encoder_table *dpe = NULL; | ||
1083 | struct dcb_entry *dcb = bios->display.output; | ||
1084 | struct drm_device *dev = bios->dev; | ||
1085 | uint8_t cond = bios->data[offset + 1]; | ||
1086 | int dummy; | ||
1087 | |||
1088 | BIOSLOG(bios, "0x%04X: subop 0x%02X\n", offset, cond); | ||
1089 | |||
1090 | if (!iexec->execute) | ||
1091 | return 3; | ||
1092 | |||
1093 | dpe = nouveau_bios_dp_table(dev, dcb, &dummy); | ||
1094 | if (!dpe) { | ||
1095 | NV_ERROR(dev, "0x%04X: INIT_3A: no encoder table!!\n", offset); | ||
1096 | return -EINVAL; | ||
1097 | } | ||
1098 | |||
1099 | switch (cond) { | ||
1100 | case 0: | ||
1101 | { | ||
1102 | struct dcb_connector_table_entry *ent = | ||
1103 | &bios->dcb.connector.entry[dcb->connector]; | ||
1104 | |||
1105 | if (ent->type != DCB_CONNECTOR_eDP) | ||
1106 | iexec->execute = false; | ||
1107 | } | ||
1108 | break; | ||
1109 | case 1: | ||
1110 | case 2: | ||
1111 | if (!(dpe->unknown & cond)) | ||
1112 | iexec->execute = false; | ||
1113 | break; | ||
1114 | case 5: | ||
1115 | { | ||
1116 | struct nouveau_i2c_chan *auxch; | ||
1117 | int ret; | ||
1118 | |||
1119 | auxch = nouveau_i2c_find(dev, bios->display.output->i2c_index); | ||
1120 | if (!auxch) | ||
1121 | return -ENODEV; | ||
1122 | |||
1123 | ret = nouveau_dp_auxch(auxch, 9, 0xd, &cond, 1); | ||
1124 | if (ret) | ||
1125 | return ret; | ||
1126 | |||
1127 | if (cond & 1) | ||
1128 | iexec->execute = false; | ||
1129 | } | ||
1130 | break; | ||
1131 | default: | ||
1132 | NV_WARN(dev, "0x%04X: unknown INIT_3A op: %d\n", offset, cond); | ||
1133 | break; | ||
1134 | } | ||
1135 | |||
1136 | if (iexec->execute) | ||
1137 | BIOSLOG(bios, "0x%04X: continuing to execute\n", offset); | ||
1138 | else | ||
1139 | BIOSLOG(bios, "0x%04X: skipping following commands\n", offset); | ||
1140 | |||
1141 | return 3; | ||
1142 | } | ||
1143 | |||
1144 | static int | ||
1145 | init_op_3b(struct nvbios *bios, uint16_t offset, struct init_exec *iexec) | ||
1146 | { | ||
1147 | /* | ||
1148 | * INIT_3B opcode: 0x3B ('') | ||
1149 | * | ||
1150 | * offset (8 bit): opcode | ||
1151 | * offset + 1 (8 bit): crtc index | ||
1152 | * | ||
1153 | */ | ||
1154 | |||
1155 | uint8_t or = ffs(bios->display.output->or) - 1; | ||
1156 | uint8_t index = bios->data[offset + 1]; | ||
1157 | uint8_t data; | ||
1158 | |||
1159 | if (!iexec->execute) | ||
1160 | return 2; | ||
1161 | |||
1162 | data = bios_idxprt_rd(bios, 0x3d4, index); | ||
1163 | bios_idxprt_wr(bios, 0x3d4, index, data & ~(1 << or)); | ||
1164 | return 2; | ||
1165 | } | ||
1166 | |||
1167 | static int | ||
1168 | init_op_3c(struct nvbios *bios, uint16_t offset, struct init_exec *iexec) | ||
1169 | { | ||
1170 | /* | ||
1171 | * INIT_3C opcode: 0x3C ('') | ||
1172 | * | ||
1173 | * offset (8 bit): opcode | ||
1174 | * offset + 1 (8 bit): crtc index | ||
1175 | * | ||
1176 | */ | ||
1177 | |||
1178 | uint8_t or = ffs(bios->display.output->or) - 1; | ||
1179 | uint8_t index = bios->data[offset + 1]; | ||
1180 | uint8_t data; | ||
1181 | |||
1182 | if (!iexec->execute) | ||
1183 | return 2; | ||
1184 | |||
1185 | data = bios_idxprt_rd(bios, 0x3d4, index); | ||
1186 | bios_idxprt_wr(bios, 0x3d4, index, data | (1 << or)); | ||
1187 | return 2; | ||
1188 | } | ||
1189 | |||
1190 | static int | ||
1070 | init_idx_addr_latched(struct nvbios *bios, uint16_t offset, | 1191 | init_idx_addr_latched(struct nvbios *bios, uint16_t offset, |
1071 | struct init_exec *iexec) | 1192 | struct init_exec *iexec) |
1072 | { | 1193 | { |
@@ -2934,6 +3055,9 @@ static struct init_tbl_entry itbl_entry[] = { | |||
2934 | { "INIT_COPY" , 0x37, init_copy }, | 3055 | { "INIT_COPY" , 0x37, init_copy }, |
2935 | { "INIT_NOT" , 0x38, init_not }, | 3056 | { "INIT_NOT" , 0x38, init_not }, |
2936 | { "INIT_IO_FLAG_CONDITION" , 0x39, init_io_flag_condition }, | 3057 | { "INIT_IO_FLAG_CONDITION" , 0x39, init_io_flag_condition }, |
3058 | { "INIT_DP_CONDITION" , 0x3A, init_dp_condition }, | ||
3059 | { "INIT_OP_3B" , 0x3B, init_op_3b }, | ||
3060 | { "INIT_OP_3C" , 0x3C, init_op_3c }, | ||
2937 | { "INIT_INDEX_ADDRESS_LATCHED" , 0x49, init_idx_addr_latched }, | 3061 | { "INIT_INDEX_ADDRESS_LATCHED" , 0x49, init_idx_addr_latched }, |
2938 | { "INIT_IO_RESTRICT_PLL2" , 0x4A, init_io_restrict_pll2 }, | 3062 | { "INIT_IO_RESTRICT_PLL2" , 0x4A, init_io_restrict_pll2 }, |
2939 | { "INIT_PLL2" , 0x4B, init_pll2 }, | 3063 | { "INIT_PLL2" , 0x4B, init_pll2 }, |