aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/gpu/drm/nouveau
diff options
context:
space:
mode:
authorBen Skeggs <bskeggs@redhat.com>2012-03-10 10:28:48 -0500
committerBen Skeggs <bskeggs@redhat.com>2012-03-13 03:15:04 -0400
commit6e83fda2c055f17780b2feef404f06803a49a261 (patch)
treed736720740ef69addd8911060629d987d1822705 /drivers/gpu/drm/nouveau
parentf14d9a4dda65439d74326694db727c6d2a5df0ce (diff)
drm/nvd0/disp: initial implementation of displayport
Signed-off-by: Ben Skeggs <bskeggs@redhat.com>
Diffstat (limited to 'drivers/gpu/drm/nouveau')
-rw-r--r--drivers/gpu/drm/nouveau/nouveau_dp.c6
-rw-r--r--drivers/gpu/drm/nouveau/nvd0_display.c169
2 files changed, 171 insertions, 4 deletions
diff --git a/drivers/gpu/drm/nouveau/nouveau_dp.c b/drivers/gpu/drm/nouveau/nouveau_dp.c
index 7be4e06e8438..b3644651d89b 100644
--- a/drivers/gpu/drm/nouveau/nouveau_dp.c
+++ b/drivers/gpu/drm/nouveau/nouveau_dp.c
@@ -364,10 +364,8 @@ dp_set_downspread(struct drm_device *dev, struct dp_state *dp, bool enable)
364 u8 *entry, *table = nouveau_dp_bios_data(dev, dp->dcb, &entry); 364 u8 *entry, *table = nouveau_dp_bios_data(dev, dp->dcb, &entry);
365 if (table) { 365 if (table) {
366 if (table[0] >= 0x20 && table[0] <= 0x30) { 366 if (table[0] >= 0x20 && table[0] <= 0x30) {
367 if (enable) 367 if (enable) script = ROM16(entry[12]);
368 script = ROM16(entry[12]); 368 else script = ROM16(entry[14]);
369 else
370 script = ROM16(entry[14]);
371 } 369 }
372 } 370 }
373 371
diff --git a/drivers/gpu/drm/nouveau/nvd0_display.c b/drivers/gpu/drm/nouveau/nvd0_display.c
index 296f205249fc..1723733ad9fa 100644
--- a/drivers/gpu/drm/nouveau/nvd0_display.c
+++ b/drivers/gpu/drm/nouveau/nvd0_display.c
@@ -1183,6 +1183,143 @@ nvd0_hdmi_disconnect(struct drm_encoder *encoder)
1183/****************************************************************************** 1183/******************************************************************************
1184 * SOR 1184 * SOR
1185 *****************************************************************************/ 1185 *****************************************************************************/
1186static inline u32
1187nvd0_sor_dp_lane_map(struct drm_device *dev, struct dcb_entry *dcb, u8 lane)
1188{
1189 static const u8 nvd0[] = { 16, 8, 0, 24 };
1190 return nvd0[lane];
1191}
1192
1193static void
1194nvd0_sor_dp_train_set(struct drm_device *dev, struct dcb_entry *dcb, u8 pattern)
1195{
1196 const u32 or = ffs(dcb->or) - 1, link = !(dcb->sorconf.link & 1);
1197 const u32 loff = (or * 0x800) + (link * 0x80);
1198 nv_mask(dev, 0x61c110 + loff, 0x0f0f0f0f, 0x01010101 * pattern);
1199}
1200
1201static void
1202nvd0_sor_dp_train_adj(struct drm_device *dev, struct dcb_entry *dcb,
1203 u8 lane, u8 swing, u8 preem)
1204{
1205 const u32 or = ffs(dcb->or) - 1, link = !(dcb->sorconf.link & 1);
1206 const u32 loff = (or * 0x800) + (link * 0x80);
1207 u32 shift = nvd0_sor_dp_lane_map(dev, dcb, lane);
1208 u32 mask = 0x000000ff << shift;
1209 u8 *table, *entry, *config = NULL;
1210
1211 switch (swing) {
1212 case 0: preem += 0; break;
1213 case 1: preem += 4; break;
1214 case 2: preem += 7; break;
1215 case 3: preem += 9; break;
1216 }
1217
1218 table = nouveau_dp_bios_data(dev, dcb, &entry);
1219 if (table) {
1220 if (table[0] == 0x30) {
1221 config = entry + table[4];
1222 config += table[5] * preem;
1223 }
1224 }
1225
1226 if (!config) {
1227 NV_ERROR(dev, "PDISP: unsupported DP table for chipset\n");
1228 return;
1229 }
1230
1231 nv_mask(dev, 0x61c118 + loff, mask, config[1] << shift);
1232 nv_mask(dev, 0x61c120 + loff, mask, config[2] << shift);
1233 nv_mask(dev, 0x61c130 + loff, 0x0000ff00, config[3] << 8);
1234 nv_mask(dev, 0x61c13c + loff, 0x00000000, 0x00000000);
1235}
1236
1237static void
1238nvd0_sor_dp_link_set(struct drm_device *dev, struct dcb_entry *dcb, int crtc,
1239 int link_nr, u32 link_bw, bool enhframe)
1240{
1241 const u32 or = ffs(dcb->or) - 1, link = !(dcb->sorconf.link & 1);
1242 const u32 loff = (or * 0x800) + (link * 0x80);
1243 const u32 soff = (or * 0x800);
1244 u32 dpctrl = nv_rd32(dev, 0x61c10c + loff) & ~0x001f4000;
1245 u32 clksor = nv_rd32(dev, 0x612300 + soff) & ~0x007c0000;
1246 u32 script = 0x0000, lane_mask = 0;
1247 u8 *table, *entry;
1248 int i;
1249
1250 link_bw /= 27000;
1251
1252 table = nouveau_dp_bios_data(dev, dcb, &entry);
1253 if (table) {
1254 if (table[0] == 0x30) entry = ROMPTR(dev, entry[10]);
1255 else entry = NULL;
1256
1257 while (entry) {
1258 if (entry[0] >= link_bw)
1259 break;
1260 entry += 3;
1261 }
1262
1263 nouveau_bios_run_init_table(dev, script, dcb, crtc);
1264 }
1265
1266 clksor |= link_bw << 18;
1267 dpctrl |= ((1 << link_nr) - 1) << 16;
1268 if (enhframe)
1269 dpctrl |= 0x00004000;
1270
1271 for (i = 0; i < link_nr; i++)
1272 lane_mask |= 1 << (nvd0_sor_dp_lane_map(dev, dcb, i) >> 3);
1273
1274 nv_wr32(dev, 0x612300 + soff, clksor);
1275 nv_wr32(dev, 0x61c10c + loff, dpctrl);
1276 nv_mask(dev, 0x61c130 + loff, 0x0000000f, lane_mask);
1277}
1278
1279static void
1280nvd0_sor_dp_link_get(struct drm_device *dev, struct dcb_entry *dcb,
1281 u32 *link_nr, u32 *link_bw)
1282{
1283 const u32 or = ffs(dcb->or) - 1, link = !(dcb->sorconf.link & 1);
1284 const u32 loff = (or * 0x800) + (link * 0x80);
1285 const u32 soff = (or * 0x800);
1286 u32 dpctrl = nv_rd32(dev, 0x61c10c + loff) & 0x000f0000;
1287 u32 clksor = nv_rd32(dev, 0x612300 + soff);
1288
1289 if (dpctrl > 0x00030000) *link_nr = 4;
1290 else if (dpctrl > 0x00010000) *link_nr = 2;
1291 else *link_nr = 1;
1292
1293 *link_bw = (clksor & 0x007c0000) >> 18;
1294 *link_bw *= 27000;
1295}
1296
1297static void
1298nvd0_sor_dp_calc_tu(struct drm_device *dev, struct dcb_entry *dcb,
1299 u32 crtc, u32 datarate)
1300{
1301 const u32 symbol = 100000;
1302 const u32 TU = 64;
1303 u32 link_nr, link_bw;
1304 u64 ratio, value;
1305
1306 nvd0_sor_dp_link_get(dev, dcb, &link_nr, &link_bw);
1307
1308 ratio = datarate;
1309 ratio *= symbol;
1310 do_div(ratio, link_nr * link_bw);
1311
1312 value = (symbol - ratio) * TU;
1313 value *= ratio;
1314 do_div(value, symbol);
1315 do_div(value, symbol);
1316
1317 value += 5;
1318 value |= 0x08000000;
1319
1320 nv_wr32(dev, 0x616610 + (crtc * 0x800), value);
1321}
1322
1186static void 1323static void
1187nvd0_sor_dpms(struct drm_encoder *encoder, int mode) 1324nvd0_sor_dpms(struct drm_encoder *encoder, int mode)
1188{ 1325{
@@ -1215,6 +1352,16 @@ nvd0_sor_dpms(struct drm_encoder *encoder, int mode)
1215 nv_mask(dev, 0x61c004 + (or * 0x0800), 0x80000001, dpms_ctrl); 1352 nv_mask(dev, 0x61c004 + (or * 0x0800), 0x80000001, dpms_ctrl);
1216 nv_wait(dev, 0x61c004 + (or * 0x0800), 0x80000000, 0x00000000); 1353 nv_wait(dev, 0x61c004 + (or * 0x0800), 0x80000000, 0x00000000);
1217 nv_wait(dev, 0x61c030 + (or * 0x0800), 0x10000000, 0x00000000); 1354 nv_wait(dev, 0x61c030 + (or * 0x0800), 0x10000000, 0x00000000);
1355
1356 if (nv_encoder->dcb->type == OUTPUT_DP) {
1357 struct dp_train_func func = {
1358 .link_set = nvd0_sor_dp_link_set,
1359 .train_set = nvd0_sor_dp_train_set,
1360 .train_adj = nvd0_sor_dp_train_adj
1361 };
1362
1363 nouveau_dp_dpms(encoder, mode, nv_encoder->dp.datarate, &func);
1364 }
1218} 1365}
1219 1366
1220static bool 1367static bool
@@ -1306,6 +1453,19 @@ nvd0_sor_mode_set(struct drm_encoder *encoder, struct drm_display_mode *umode,
1306 1453
1307 } 1454 }
1308 break; 1455 break;
1456 case OUTPUT_DP:
1457 if (nv_connector->base.display_info.bpc == 6)
1458 nv_encoder->dp.datarate = mode->clock * 18 / 8;
1459 else
1460 nv_encoder->dp.datarate = mode->clock * 24 / 8;
1461
1462 if (nv_encoder->dcb->sorconf.link & 1)
1463 mode_ctrl |= 0x00000800;
1464 else
1465 mode_ctrl |= 0x00000900;
1466
1467 or_config = (mode_ctrl & 0x00000f00) >> 8;
1468 break;
1309 default: 1469 default:
1310 BUG_ON(1); 1470 BUG_ON(1);
1311 break; 1471 break;
@@ -1313,6 +1473,11 @@ nvd0_sor_mode_set(struct drm_encoder *encoder, struct drm_display_mode *umode,
1313 1473
1314 nvd0_sor_dpms(encoder, DRM_MODE_DPMS_ON); 1474 nvd0_sor_dpms(encoder, DRM_MODE_DPMS_ON);
1315 1475
1476 if (nv_encoder->dcb->type == OUTPUT_DP) {
1477 nvd0_sor_dp_calc_tu(dev, nv_encoder->dcb, nv_crtc->index,
1478 nv_encoder->dp.datarate);
1479 }
1480
1316 push = evo_wait(dev, EVO_MASTER, 4); 1481 push = evo_wait(dev, EVO_MASTER, 4);
1317 if (push) { 1482 if (push) {
1318 evo_mthd(push, 0x0200 + (nv_encoder->or * 0x20), 2); 1483 evo_mthd(push, 0x0200 + (nv_encoder->or * 0x20), 2);
@@ -1413,6 +1578,8 @@ lookup_dcb(struct drm_device *dev, int id, u32 mc)
1413 case 0x00000100: type = OUTPUT_TMDS; break; 1578 case 0x00000100: type = OUTPUT_TMDS; break;
1414 case 0x00000200: type = OUTPUT_TMDS; break; 1579 case 0x00000200: type = OUTPUT_TMDS; break;
1415 case 0x00000500: type = OUTPUT_TMDS; break; 1580 case 0x00000500: type = OUTPUT_TMDS; break;
1581 case 0x00000800: type = OUTPUT_DP; break;
1582 case 0x00000900: type = OUTPUT_DP; break;
1416 default: 1583 default:
1417 NV_ERROR(dev, "PDISP: unknown SOR mc 0x%08x\n", mc); 1584 NV_ERROR(dev, "PDISP: unknown SOR mc 0x%08x\n", mc);
1418 return NULL; 1585 return NULL;
@@ -1498,6 +1665,7 @@ nvd0_display_unk2_handler(struct drm_device *dev, u32 crtc, u32 mask)
1498 break; 1665 break;
1499 case OUTPUT_TMDS: 1666 case OUTPUT_TMDS:
1500 case OUTPUT_LVDS: 1667 case OUTPUT_LVDS:
1668 case OUTPUT_DP:
1501 if (cfg & 0x00000100) 1669 if (cfg & 0x00000100)
1502 tmp = 0x00000101; 1670 tmp = 0x00000101;
1503 else 1671 else
@@ -1798,6 +1966,7 @@ nvd0_display_create(struct drm_device *dev)
1798 switch (dcbe->type) { 1966 switch (dcbe->type) {
1799 case OUTPUT_TMDS: 1967 case OUTPUT_TMDS:
1800 case OUTPUT_LVDS: 1968 case OUTPUT_LVDS:
1969 case OUTPUT_DP:
1801 nvd0_sor_create(connector, dcbe); 1970 nvd0_sor_create(connector, dcbe);
1802 break; 1971 break;
1803 case OUTPUT_ANALOG: 1972 case OUTPUT_ANALOG: