diff options
author | Jesse Barnes <jbarnes@virtuousgeek.org> | 2010-05-20 17:28:11 -0400 |
---|---|---|
committer | Eric Anholt <eric@anholt.net> | 2010-05-26 17:10:01 -0400 |
commit | 7648fa99eb77a2e1a90b7beaa420e07d819b9c11 (patch) | |
tree | 29991eba782a22922441813dcc3a5cbde8377119 /drivers | |
parent | 7a772c492fcfffae812ffca78a628e76fa57fe58 (diff) |
drm/i915: add power monitoring support
Add power monitoring support to the i915 driver for use by the IPS
driver. Export the available power info to the IPS driver through a few
new inter-driver hooks. When used together, the IPS driver and this
patch can significantly increase graphics performance on Ironlake class
chips.
Signed-off-by: Jesse Barnes <jbarnes@virtuousgeek.org>
[anholt: Fixed 32-bit compile. stupid obfuscating div_u64()]
Signed-off-by: Eric Anholt <eric@anholt.net>
Diffstat (limited to 'drivers')
-rw-r--r-- | drivers/gpu/drm/i915/i915_debugfs.c | 56 | ||||
-rw-r--r-- | drivers/gpu/drm/i915/i915_dma.c | 533 | ||||
-rw-r--r-- | drivers/gpu/drm/i915/i915_drv.h | 20 | ||||
-rw-r--r-- | drivers/gpu/drm/i915/i915_irq.c | 28 | ||||
-rw-r--r-- | drivers/gpu/drm/i915/i915_reg.h | 41 | ||||
-rw-r--r-- | drivers/gpu/drm/i915/intel_display.c | 147 |
6 files changed, 772 insertions, 53 deletions
diff --git a/drivers/gpu/drm/i915/i915_debugfs.c b/drivers/gpu/drm/i915/i915_debugfs.c index c864858d5064..eb11e1e049cb 100644 --- a/drivers/gpu/drm/i915/i915_debugfs.c +++ b/drivers/gpu/drm/i915/i915_debugfs.c | |||
@@ -491,11 +491,14 @@ static int i915_cur_delayinfo(struct seq_file *m, void *unused) | |||
491 | struct drm_device *dev = node->minor->dev; | 491 | struct drm_device *dev = node->minor->dev; |
492 | drm_i915_private_t *dev_priv = dev->dev_private; | 492 | drm_i915_private_t *dev_priv = dev->dev_private; |
493 | u16 rgvswctl = I915_READ16(MEMSWCTL); | 493 | u16 rgvswctl = I915_READ16(MEMSWCTL); |
494 | u16 rgvstat = I915_READ16(MEMSTAT_ILK); | ||
494 | 495 | ||
495 | seq_printf(m, "Last command: 0x%01x\n", (rgvswctl >> 13) & 0x3); | 496 | seq_printf(m, "Requested P-state: %d\n", (rgvswctl >> 8) & 0xf); |
496 | seq_printf(m, "Command status: %d\n", (rgvswctl >> 12) & 1); | 497 | seq_printf(m, "Requested VID: %d\n", rgvswctl & 0x3f); |
497 | seq_printf(m, "P%d DELAY 0x%02x\n", (rgvswctl >> 8) & 0xf, | 498 | seq_printf(m, "Current VID: %d\n", (rgvstat & MEMSTAT_VID_MASK) >> |
498 | rgvswctl & 0x3f); | 499 | MEMSTAT_VID_SHIFT); |
500 | seq_printf(m, "Current P-state: %d\n", | ||
501 | (rgvstat & MEMSTAT_PSTATE_MASK) >> MEMSTAT_PSTATE_SHIFT); | ||
499 | 502 | ||
500 | return 0; | 503 | return 0; |
501 | } | 504 | } |
@@ -510,7 +513,8 @@ static int i915_delayfreq_table(struct seq_file *m, void *unused) | |||
510 | 513 | ||
511 | for (i = 0; i < 16; i++) { | 514 | for (i = 0; i < 16; i++) { |
512 | delayfreq = I915_READ(PXVFREQ_BASE + i * 4); | 515 | delayfreq = I915_READ(PXVFREQ_BASE + i * 4); |
513 | seq_printf(m, "P%02dVIDFREQ: 0x%08x\n", i, delayfreq); | 516 | seq_printf(m, "P%02dVIDFREQ: 0x%08x (VID: %d)\n", i, delayfreq, |
517 | (delayfreq & PXVFREQ_PX_MASK) >> PXVFREQ_PX_SHIFT); | ||
514 | } | 518 | } |
515 | 519 | ||
516 | return 0; | 520 | return 0; |
@@ -543,6 +547,8 @@ static int i915_drpc_info(struct seq_file *m, void *unused) | |||
543 | struct drm_device *dev = node->minor->dev; | 547 | struct drm_device *dev = node->minor->dev; |
544 | drm_i915_private_t *dev_priv = dev->dev_private; | 548 | drm_i915_private_t *dev_priv = dev->dev_private; |
545 | u32 rgvmodectl = I915_READ(MEMMODECTL); | 549 | u32 rgvmodectl = I915_READ(MEMMODECTL); |
550 | u32 rstdbyctl = I915_READ(MCHBAR_RENDER_STANDBY); | ||
551 | u16 crstandvid = I915_READ16(CRSTANDVID); | ||
546 | 552 | ||
547 | seq_printf(m, "HD boost: %s\n", (rgvmodectl & MEMMODE_BOOST_EN) ? | 553 | seq_printf(m, "HD boost: %s\n", (rgvmodectl & MEMMODE_BOOST_EN) ? |
548 | "yes" : "no"); | 554 | "yes" : "no"); |
@@ -557,9 +563,13 @@ static int i915_drpc_info(struct seq_file *m, void *unused) | |||
557 | rgvmodectl & MEMMODE_RCLK_GATE ? "yes" : "no"); | 563 | rgvmodectl & MEMMODE_RCLK_GATE ? "yes" : "no"); |
558 | seq_printf(m, "Starting frequency: P%d\n", | 564 | seq_printf(m, "Starting frequency: P%d\n", |
559 | (rgvmodectl & MEMMODE_FSTART_MASK) >> MEMMODE_FSTART_SHIFT); | 565 | (rgvmodectl & MEMMODE_FSTART_MASK) >> MEMMODE_FSTART_SHIFT); |
560 | seq_printf(m, "Max frequency: P%d\n", | 566 | seq_printf(m, "Max P-state: P%d\n", |
561 | (rgvmodectl & MEMMODE_FMAX_MASK) >> MEMMODE_FMAX_SHIFT); | 567 | (rgvmodectl & MEMMODE_FMAX_MASK) >> MEMMODE_FMAX_SHIFT); |
562 | seq_printf(m, "Min frequency: P%d\n", (rgvmodectl & MEMMODE_FMIN_MASK)); | 568 | seq_printf(m, "Min P-state: P%d\n", (rgvmodectl & MEMMODE_FMIN_MASK)); |
569 | seq_printf(m, "RS1 VID: %d\n", (crstandvid & 0x3f)); | ||
570 | seq_printf(m, "RS2 VID: %d\n", ((crstandvid >> 8) & 0x3f)); | ||
571 | seq_printf(m, "Render standby enabled: %s\n", | ||
572 | (rstdbyctl & RCX_SW_EXIT) ? "no" : "yes"); | ||
563 | 573 | ||
564 | return 0; | 574 | return 0; |
565 | } | 575 | } |
@@ -623,6 +633,36 @@ static int i915_sr_status(struct seq_file *m, void *unused) | |||
623 | return 0; | 633 | return 0; |
624 | } | 634 | } |
625 | 635 | ||
636 | static int i915_emon_status(struct seq_file *m, void *unused) | ||
637 | { | ||
638 | struct drm_info_node *node = (struct drm_info_node *) m->private; | ||
639 | struct drm_device *dev = node->minor->dev; | ||
640 | drm_i915_private_t *dev_priv = dev->dev_private; | ||
641 | unsigned long temp, chipset, gfx; | ||
642 | |||
643 | temp = i915_mch_val(dev_priv); | ||
644 | chipset = i915_chipset_val(dev_priv); | ||
645 | gfx = i915_gfx_val(dev_priv); | ||
646 | |||
647 | seq_printf(m, "GMCH temp: %ld\n", temp); | ||
648 | seq_printf(m, "Chipset power: %ld\n", chipset); | ||
649 | seq_printf(m, "GFX power: %ld\n", gfx); | ||
650 | seq_printf(m, "Total power: %ld\n", chipset + gfx); | ||
651 | |||
652 | return 0; | ||
653 | } | ||
654 | |||
655 | static int i915_gfxec(struct seq_file *m, void *unused) | ||
656 | { | ||
657 | struct drm_info_node *node = (struct drm_info_node *) m->private; | ||
658 | struct drm_device *dev = node->minor->dev; | ||
659 | drm_i915_private_t *dev_priv = dev->dev_private; | ||
660 | |||
661 | seq_printf(m, "GFXEC: %ld\n", (unsigned long)I915_READ(0x112f4)); | ||
662 | |||
663 | return 0; | ||
664 | } | ||
665 | |||
626 | static int | 666 | static int |
627 | i915_wedged_open(struct inode *inode, | 667 | i915_wedged_open(struct inode *inode, |
628 | struct file *filp) | 668 | struct file *filp) |
@@ -745,6 +785,8 @@ static struct drm_info_list i915_debugfs_list[] = { | |||
745 | {"i915_delayfreq_table", i915_delayfreq_table, 0}, | 785 | {"i915_delayfreq_table", i915_delayfreq_table, 0}, |
746 | {"i915_inttoext_table", i915_inttoext_table, 0}, | 786 | {"i915_inttoext_table", i915_inttoext_table, 0}, |
747 | {"i915_drpc_info", i915_drpc_info, 0}, | 787 | {"i915_drpc_info", i915_drpc_info, 0}, |
788 | {"i915_emon_status", i915_emon_status, 0}, | ||
789 | {"i915_gfxec", i915_gfxec, 0}, | ||
748 | {"i915_fbc_status", i915_fbc_status, 0}, | 790 | {"i915_fbc_status", i915_fbc_status, 0}, |
749 | {"i915_sr_status", i915_sr_status, 0}, | 791 | {"i915_sr_status", i915_sr_status, 0}, |
750 | }; | 792 | }; |
diff --git a/drivers/gpu/drm/i915/i915_dma.c b/drivers/gpu/drm/i915/i915_dma.c index 1dbed700800e..12e92f2cc3a7 100644 --- a/drivers/gpu/drm/i915/i915_dma.c +++ b/drivers/gpu/drm/i915/i915_dma.c | |||
@@ -1458,14 +1458,11 @@ void i915_master_destroy(struct drm_device *dev, struct drm_master *master) | |||
1458 | master->driver_priv = NULL; | 1458 | master->driver_priv = NULL; |
1459 | } | 1459 | } |
1460 | 1460 | ||
1461 | static void i915_get_mem_freq(struct drm_device *dev) | 1461 | static void i915_pineview_get_mem_freq(struct drm_device *dev) |
1462 | { | 1462 | { |
1463 | drm_i915_private_t *dev_priv = dev->dev_private; | 1463 | drm_i915_private_t *dev_priv = dev->dev_private; |
1464 | u32 tmp; | 1464 | u32 tmp; |
1465 | 1465 | ||
1466 | if (!IS_PINEVIEW(dev)) | ||
1467 | return; | ||
1468 | |||
1469 | tmp = I915_READ(CLKCFG); | 1466 | tmp = I915_READ(CLKCFG); |
1470 | 1467 | ||
1471 | switch (tmp & CLKCFG_FSB_MASK) { | 1468 | switch (tmp & CLKCFG_FSB_MASK) { |
@@ -1496,6 +1493,519 @@ static void i915_get_mem_freq(struct drm_device *dev) | |||
1496 | } | 1493 | } |
1497 | } | 1494 | } |
1498 | 1495 | ||
1496 | static void i915_ironlake_get_mem_freq(struct drm_device *dev) | ||
1497 | { | ||
1498 | drm_i915_private_t *dev_priv = dev->dev_private; | ||
1499 | u16 ddrpll, csipll; | ||
1500 | |||
1501 | ddrpll = I915_READ16(DDRMPLL1); | ||
1502 | csipll = I915_READ16(CSIPLL0); | ||
1503 | |||
1504 | switch (ddrpll & 0xff) { | ||
1505 | case 0xc: | ||
1506 | dev_priv->mem_freq = 800; | ||
1507 | break; | ||
1508 | case 0x10: | ||
1509 | dev_priv->mem_freq = 1066; | ||
1510 | break; | ||
1511 | case 0x14: | ||
1512 | dev_priv->mem_freq = 1333; | ||
1513 | break; | ||
1514 | case 0x18: | ||
1515 | dev_priv->mem_freq = 1600; | ||
1516 | break; | ||
1517 | default: | ||
1518 | DRM_DEBUG_DRIVER("unknown memory frequency 0x%02x\n", | ||
1519 | ddrpll & 0xff); | ||
1520 | dev_priv->mem_freq = 0; | ||
1521 | break; | ||
1522 | } | ||
1523 | |||
1524 | dev_priv->r_t = dev_priv->mem_freq; | ||
1525 | |||
1526 | switch (csipll & 0x3ff) { | ||
1527 | case 0x00c: | ||
1528 | dev_priv->fsb_freq = 3200; | ||
1529 | break; | ||
1530 | case 0x00e: | ||
1531 | dev_priv->fsb_freq = 3733; | ||
1532 | break; | ||
1533 | case 0x010: | ||
1534 | dev_priv->fsb_freq = 4266; | ||
1535 | break; | ||
1536 | case 0x012: | ||
1537 | dev_priv->fsb_freq = 4800; | ||
1538 | break; | ||
1539 | case 0x014: | ||
1540 | dev_priv->fsb_freq = 5333; | ||
1541 | break; | ||
1542 | case 0x016: | ||
1543 | dev_priv->fsb_freq = 5866; | ||
1544 | break; | ||
1545 | case 0x018: | ||
1546 | dev_priv->fsb_freq = 6400; | ||
1547 | break; | ||
1548 | default: | ||
1549 | DRM_DEBUG_DRIVER("unknown fsb frequency 0x%04x\n", | ||
1550 | csipll & 0x3ff); | ||
1551 | dev_priv->fsb_freq = 0; | ||
1552 | break; | ||
1553 | } | ||
1554 | |||
1555 | if (dev_priv->fsb_freq == 3200) { | ||
1556 | dev_priv->c_m = 0; | ||
1557 | } else if (dev_priv->fsb_freq > 3200 && dev_priv->fsb_freq <= 4800) { | ||
1558 | dev_priv->c_m = 1; | ||
1559 | } else { | ||
1560 | dev_priv->c_m = 2; | ||
1561 | } | ||
1562 | } | ||
1563 | |||
1564 | struct v_table { | ||
1565 | u8 vid; | ||
1566 | unsigned long vd; /* in .1 mil */ | ||
1567 | unsigned long vm; /* in .1 mil */ | ||
1568 | u8 pvid; | ||
1569 | }; | ||
1570 | |||
1571 | static struct v_table v_table[] = { | ||
1572 | { 0, 16125, 15000, 0x7f, }, | ||
1573 | { 1, 16000, 14875, 0x7e, }, | ||
1574 | { 2, 15875, 14750, 0x7d, }, | ||
1575 | { 3, 15750, 14625, 0x7c, }, | ||
1576 | { 4, 15625, 14500, 0x7b, }, | ||
1577 | { 5, 15500, 14375, 0x7a, }, | ||
1578 | { 6, 15375, 14250, 0x79, }, | ||
1579 | { 7, 15250, 14125, 0x78, }, | ||
1580 | { 8, 15125, 14000, 0x77, }, | ||
1581 | { 9, 15000, 13875, 0x76, }, | ||
1582 | { 10, 14875, 13750, 0x75, }, | ||
1583 | { 11, 14750, 13625, 0x74, }, | ||
1584 | { 12, 14625, 13500, 0x73, }, | ||
1585 | { 13, 14500, 13375, 0x72, }, | ||
1586 | { 14, 14375, 13250, 0x71, }, | ||
1587 | { 15, 14250, 13125, 0x70, }, | ||
1588 | { 16, 14125, 13000, 0x6f, }, | ||
1589 | { 17, 14000, 12875, 0x6e, }, | ||
1590 | { 18, 13875, 12750, 0x6d, }, | ||
1591 | { 19, 13750, 12625, 0x6c, }, | ||
1592 | { 20, 13625, 12500, 0x6b, }, | ||
1593 | { 21, 13500, 12375, 0x6a, }, | ||
1594 | { 22, 13375, 12250, 0x69, }, | ||
1595 | { 23, 13250, 12125, 0x68, }, | ||
1596 | { 24, 13125, 12000, 0x67, }, | ||
1597 | { 25, 13000, 11875, 0x66, }, | ||
1598 | { 26, 12875, 11750, 0x65, }, | ||
1599 | { 27, 12750, 11625, 0x64, }, | ||
1600 | { 28, 12625, 11500, 0x63, }, | ||
1601 | { 29, 12500, 11375, 0x62, }, | ||
1602 | { 30, 12375, 11250, 0x61, }, | ||
1603 | { 31, 12250, 11125, 0x60, }, | ||
1604 | { 32, 12125, 11000, 0x5f, }, | ||
1605 | { 33, 12000, 10875, 0x5e, }, | ||
1606 | { 34, 11875, 10750, 0x5d, }, | ||
1607 | { 35, 11750, 10625, 0x5c, }, | ||
1608 | { 36, 11625, 10500, 0x5b, }, | ||
1609 | { 37, 11500, 10375, 0x5a, }, | ||
1610 | { 38, 11375, 10250, 0x59, }, | ||
1611 | { 39, 11250, 10125, 0x58, }, | ||
1612 | { 40, 11125, 10000, 0x57, }, | ||
1613 | { 41, 11000, 9875, 0x56, }, | ||
1614 | { 42, 10875, 9750, 0x55, }, | ||
1615 | { 43, 10750, 9625, 0x54, }, | ||
1616 | { 44, 10625, 9500, 0x53, }, | ||
1617 | { 45, 10500, 9375, 0x52, }, | ||
1618 | { 46, 10375, 9250, 0x51, }, | ||
1619 | { 47, 10250, 9125, 0x50, }, | ||
1620 | { 48, 10125, 9000, 0x4f, }, | ||
1621 | { 49, 10000, 8875, 0x4e, }, | ||
1622 | { 50, 9875, 8750, 0x4d, }, | ||
1623 | { 51, 9750, 8625, 0x4c, }, | ||
1624 | { 52, 9625, 8500, 0x4b, }, | ||
1625 | { 53, 9500, 8375, 0x4a, }, | ||
1626 | { 54, 9375, 8250, 0x49, }, | ||
1627 | { 55, 9250, 8125, 0x48, }, | ||
1628 | { 56, 9125, 8000, 0x47, }, | ||
1629 | { 57, 9000, 7875, 0x46, }, | ||
1630 | { 58, 8875, 7750, 0x45, }, | ||
1631 | { 59, 8750, 7625, 0x44, }, | ||
1632 | { 60, 8625, 7500, 0x43, }, | ||
1633 | { 61, 8500, 7375, 0x42, }, | ||
1634 | { 62, 8375, 7250, 0x41, }, | ||
1635 | { 63, 8250, 7125, 0x40, }, | ||
1636 | { 64, 8125, 7000, 0x3f, }, | ||
1637 | { 65, 8000, 6875, 0x3e, }, | ||
1638 | { 66, 7875, 6750, 0x3d, }, | ||
1639 | { 67, 7750, 6625, 0x3c, }, | ||
1640 | { 68, 7625, 6500, 0x3b, }, | ||
1641 | { 69, 7500, 6375, 0x3a, }, | ||
1642 | { 70, 7375, 6250, 0x39, }, | ||
1643 | { 71, 7250, 6125, 0x38, }, | ||
1644 | { 72, 7125, 6000, 0x37, }, | ||
1645 | { 73, 7000, 5875, 0x36, }, | ||
1646 | { 74, 6875, 5750, 0x35, }, | ||
1647 | { 75, 6750, 5625, 0x34, }, | ||
1648 | { 76, 6625, 5500, 0x33, }, | ||
1649 | { 77, 6500, 5375, 0x32, }, | ||
1650 | { 78, 6375, 5250, 0x31, }, | ||
1651 | { 79, 6250, 5125, 0x30, }, | ||
1652 | { 80, 6125, 5000, 0x2f, }, | ||
1653 | { 81, 6000, 4875, 0x2e, }, | ||
1654 | { 82, 5875, 4750, 0x2d, }, | ||
1655 | { 83, 5750, 4625, 0x2c, }, | ||
1656 | { 84, 5625, 4500, 0x2b, }, | ||
1657 | { 85, 5500, 4375, 0x2a, }, | ||
1658 | { 86, 5375, 4250, 0x29, }, | ||
1659 | { 87, 5250, 4125, 0x28, }, | ||
1660 | { 88, 5125, 4000, 0x27, }, | ||
1661 | { 89, 5000, 3875, 0x26, }, | ||
1662 | { 90, 4875, 3750, 0x25, }, | ||
1663 | { 91, 4750, 3625, 0x24, }, | ||
1664 | { 92, 4625, 3500, 0x23, }, | ||
1665 | { 93, 4500, 3375, 0x22, }, | ||
1666 | { 94, 4375, 3250, 0x21, }, | ||
1667 | { 95, 4250, 3125, 0x20, }, | ||
1668 | { 96, 4125, 3000, 0x1f, }, | ||
1669 | { 97, 4125, 3000, 0x1e, }, | ||
1670 | { 98, 4125, 3000, 0x1d, }, | ||
1671 | { 99, 4125, 3000, 0x1c, }, | ||
1672 | { 100, 4125, 3000, 0x1b, }, | ||
1673 | { 101, 4125, 3000, 0x1a, }, | ||
1674 | { 102, 4125, 3000, 0x19, }, | ||
1675 | { 103, 4125, 3000, 0x18, }, | ||
1676 | { 104, 4125, 3000, 0x17, }, | ||
1677 | { 105, 4125, 3000, 0x16, }, | ||
1678 | { 106, 4125, 3000, 0x15, }, | ||
1679 | { 107, 4125, 3000, 0x14, }, | ||
1680 | { 108, 4125, 3000, 0x13, }, | ||
1681 | { 109, 4125, 3000, 0x12, }, | ||
1682 | { 110, 4125, 3000, 0x11, }, | ||
1683 | { 111, 4125, 3000, 0x10, }, | ||
1684 | { 112, 4125, 3000, 0x0f, }, | ||
1685 | { 113, 4125, 3000, 0x0e, }, | ||
1686 | { 114, 4125, 3000, 0x0d, }, | ||
1687 | { 115, 4125, 3000, 0x0c, }, | ||
1688 | { 116, 4125, 3000, 0x0b, }, | ||
1689 | { 117, 4125, 3000, 0x0a, }, | ||
1690 | { 118, 4125, 3000, 0x09, }, | ||
1691 | { 119, 4125, 3000, 0x08, }, | ||
1692 | { 120, 1125, 0, 0x07, }, | ||
1693 | { 121, 1000, 0, 0x06, }, | ||
1694 | { 122, 875, 0, 0x05, }, | ||
1695 | { 123, 750, 0, 0x04, }, | ||
1696 | { 124, 625, 0, 0x03, }, | ||
1697 | { 125, 500, 0, 0x02, }, | ||
1698 | { 126, 375, 0, 0x01, }, | ||
1699 | { 127, 0, 0, 0x00, }, | ||
1700 | }; | ||
1701 | |||
1702 | struct cparams { | ||
1703 | int i; | ||
1704 | int t; | ||
1705 | int m; | ||
1706 | int c; | ||
1707 | }; | ||
1708 | |||
1709 | static struct cparams cparams[] = { | ||
1710 | { 1, 1333, 301, 28664 }, | ||
1711 | { 1, 1066, 294, 24460 }, | ||
1712 | { 1, 800, 294, 25192 }, | ||
1713 | { 0, 1333, 276, 27605 }, | ||
1714 | { 0, 1066, 276, 27605 }, | ||
1715 | { 0, 800, 231, 23784 }, | ||
1716 | }; | ||
1717 | |||
1718 | unsigned long i915_chipset_val(struct drm_i915_private *dev_priv) | ||
1719 | { | ||
1720 | u64 total_count, diff, ret; | ||
1721 | u32 count1, count2, count3, m = 0, c = 0; | ||
1722 | unsigned long now = jiffies_to_msecs(jiffies), diff1; | ||
1723 | int i; | ||
1724 | |||
1725 | diff1 = now - dev_priv->last_time1; | ||
1726 | |||
1727 | count1 = I915_READ(DMIEC); | ||
1728 | count2 = I915_READ(DDREC); | ||
1729 | count3 = I915_READ(CSIEC); | ||
1730 | |||
1731 | total_count = count1 + count2 + count3; | ||
1732 | |||
1733 | /* FIXME: handle per-counter overflow */ | ||
1734 | if (total_count < dev_priv->last_count1) { | ||
1735 | diff = ~0UL - dev_priv->last_count1; | ||
1736 | diff += total_count; | ||
1737 | } else { | ||
1738 | diff = total_count - dev_priv->last_count1; | ||
1739 | } | ||
1740 | |||
1741 | for (i = 0; i < ARRAY_SIZE(cparams); i++) { | ||
1742 | if (cparams[i].i == dev_priv->c_m && | ||
1743 | cparams[i].t == dev_priv->r_t) { | ||
1744 | m = cparams[i].m; | ||
1745 | c = cparams[i].c; | ||
1746 | break; | ||
1747 | } | ||
1748 | } | ||
1749 | |||
1750 | div_u64(diff, diff1); | ||
1751 | ret = ((m * diff) + c); | ||
1752 | div_u64(ret, 10); | ||
1753 | |||
1754 | dev_priv->last_count1 = total_count; | ||
1755 | dev_priv->last_time1 = now; | ||
1756 | |||
1757 | return ret; | ||
1758 | } | ||
1759 | |||
1760 | unsigned long i915_mch_val(struct drm_i915_private *dev_priv) | ||
1761 | { | ||
1762 | unsigned long m, x, b; | ||
1763 | u32 tsfs; | ||
1764 | |||
1765 | tsfs = I915_READ(TSFS); | ||
1766 | |||
1767 | m = ((tsfs & TSFS_SLOPE_MASK) >> TSFS_SLOPE_SHIFT); | ||
1768 | x = I915_READ8(TR1); | ||
1769 | |||
1770 | b = tsfs & TSFS_INTR_MASK; | ||
1771 | |||
1772 | return ((m * x) / 127) - b; | ||
1773 | } | ||
1774 | |||
1775 | static unsigned long pvid_to_extvid(struct drm_i915_private *dev_priv, u8 pxvid) | ||
1776 | { | ||
1777 | unsigned long val = 0; | ||
1778 | int i; | ||
1779 | |||
1780 | for (i = 0; i < ARRAY_SIZE(v_table); i++) { | ||
1781 | if (v_table[i].pvid == pxvid) { | ||
1782 | if (IS_MOBILE(dev_priv->dev)) | ||
1783 | val = v_table[i].vm; | ||
1784 | else | ||
1785 | val = v_table[i].vd; | ||
1786 | } | ||
1787 | } | ||
1788 | |||
1789 | return val; | ||
1790 | } | ||
1791 | |||
1792 | void i915_update_gfx_val(struct drm_i915_private *dev_priv) | ||
1793 | { | ||
1794 | struct timespec now, diff1; | ||
1795 | u64 diff; | ||
1796 | unsigned long diffms; | ||
1797 | u32 count; | ||
1798 | |||
1799 | getrawmonotonic(&now); | ||
1800 | diff1 = timespec_sub(now, dev_priv->last_time2); | ||
1801 | |||
1802 | /* Don't divide by 0 */ | ||
1803 | diffms = diff1.tv_sec * 1000 + diff1.tv_nsec / 1000000; | ||
1804 | if (!diffms) | ||
1805 | return; | ||
1806 | |||
1807 | count = I915_READ(GFXEC); | ||
1808 | |||
1809 | if (count < dev_priv->last_count2) { | ||
1810 | diff = ~0UL - dev_priv->last_count2; | ||
1811 | diff += count; | ||
1812 | } else { | ||
1813 | diff = count - dev_priv->last_count2; | ||
1814 | } | ||
1815 | |||
1816 | dev_priv->last_count2 = count; | ||
1817 | dev_priv->last_time2 = now; | ||
1818 | |||
1819 | /* More magic constants... */ | ||
1820 | diff = diff * 1181; | ||
1821 | div_u64(diff, diffms * 10); | ||
1822 | dev_priv->gfx_power = diff; | ||
1823 | } | ||
1824 | |||
1825 | unsigned long i915_gfx_val(struct drm_i915_private *dev_priv) | ||
1826 | { | ||
1827 | unsigned long t, corr, state1, corr2, state2; | ||
1828 | u32 pxvid, ext_v; | ||
1829 | |||
1830 | pxvid = I915_READ(PXVFREQ_BASE + (dev_priv->cur_delay * 4)); | ||
1831 | pxvid = (pxvid >> 24) & 0x7f; | ||
1832 | ext_v = pvid_to_extvid(dev_priv, pxvid); | ||
1833 | |||
1834 | state1 = ext_v; | ||
1835 | |||
1836 | t = i915_mch_val(dev_priv); | ||
1837 | |||
1838 | /* Revel in the empirically derived constants */ | ||
1839 | |||
1840 | /* Correction factor in 1/100000 units */ | ||
1841 | if (t > 80) | ||
1842 | corr = ((t * 2349) + 135940); | ||
1843 | else if (t >= 50) | ||
1844 | corr = ((t * 964) + 29317); | ||
1845 | else /* < 50 */ | ||
1846 | corr = ((t * 301) + 1004); | ||
1847 | |||
1848 | corr = corr * ((150142 * state1) / 10000 - 78642); | ||
1849 | corr /= 100000; | ||
1850 | corr2 = (corr * dev_priv->corr); | ||
1851 | |||
1852 | state2 = (corr2 * state1) / 10000; | ||
1853 | state2 /= 100; /* convert to mW */ | ||
1854 | |||
1855 | i915_update_gfx_val(dev_priv); | ||
1856 | |||
1857 | return dev_priv->gfx_power + state2; | ||
1858 | } | ||
1859 | |||
1860 | /* Global for IPS driver to get at the current i915 device */ | ||
1861 | static struct drm_i915_private *i915_mch_dev; | ||
1862 | /* | ||
1863 | * Lock protecting IPS related data structures | ||
1864 | * - i915_mch_dev | ||
1865 | * - dev_priv->max_delay | ||
1866 | * - dev_priv->min_delay | ||
1867 | * - dev_priv->fmax | ||
1868 | * - dev_priv->gpu_busy | ||
1869 | */ | ||
1870 | DEFINE_SPINLOCK(mchdev_lock); | ||
1871 | |||
1872 | /** | ||
1873 | * i915_read_mch_val - return value for IPS use | ||
1874 | * | ||
1875 | * Calculate and return a value for the IPS driver to use when deciding whether | ||
1876 | * we have thermal and power headroom to increase CPU or GPU power budget. | ||
1877 | */ | ||
1878 | unsigned long i915_read_mch_val(void) | ||
1879 | { | ||
1880 | struct drm_i915_private *dev_priv; | ||
1881 | unsigned long chipset_val, graphics_val, ret = 0; | ||
1882 | |||
1883 | spin_lock(&mchdev_lock); | ||
1884 | if (!i915_mch_dev) | ||
1885 | goto out_unlock; | ||
1886 | dev_priv = i915_mch_dev; | ||
1887 | |||
1888 | chipset_val = i915_chipset_val(dev_priv); | ||
1889 | graphics_val = i915_gfx_val(dev_priv); | ||
1890 | |||
1891 | ret = chipset_val + graphics_val; | ||
1892 | |||
1893 | out_unlock: | ||
1894 | spin_unlock(&mchdev_lock); | ||
1895 | |||
1896 | return ret; | ||
1897 | } | ||
1898 | EXPORT_SYMBOL_GPL(i915_read_mch_val); | ||
1899 | |||
1900 | /** | ||
1901 | * i915_gpu_raise - raise GPU frequency limit | ||
1902 | * | ||
1903 | * Raise the limit; IPS indicates we have thermal headroom. | ||
1904 | */ | ||
1905 | bool i915_gpu_raise(void) | ||
1906 | { | ||
1907 | struct drm_i915_private *dev_priv; | ||
1908 | bool ret = true; | ||
1909 | |||
1910 | spin_lock(&mchdev_lock); | ||
1911 | if (!i915_mch_dev) { | ||
1912 | ret = false; | ||
1913 | goto out_unlock; | ||
1914 | } | ||
1915 | dev_priv = i915_mch_dev; | ||
1916 | |||
1917 | if (dev_priv->max_delay > dev_priv->fmax) | ||
1918 | dev_priv->max_delay--; | ||
1919 | |||
1920 | out_unlock: | ||
1921 | spin_unlock(&mchdev_lock); | ||
1922 | |||
1923 | return ret; | ||
1924 | } | ||
1925 | EXPORT_SYMBOL_GPL(i915_gpu_raise); | ||
1926 | |||
1927 | /** | ||
1928 | * i915_gpu_lower - lower GPU frequency limit | ||
1929 | * | ||
1930 | * IPS indicates we're close to a thermal limit, so throttle back the GPU | ||
1931 | * frequency maximum. | ||
1932 | */ | ||
1933 | bool i915_gpu_lower(void) | ||
1934 | { | ||
1935 | struct drm_i915_private *dev_priv; | ||
1936 | bool ret = true; | ||
1937 | |||
1938 | spin_lock(&mchdev_lock); | ||
1939 | if (!i915_mch_dev) { | ||
1940 | ret = false; | ||
1941 | goto out_unlock; | ||
1942 | } | ||
1943 | dev_priv = i915_mch_dev; | ||
1944 | |||
1945 | if (dev_priv->max_delay < dev_priv->min_delay) | ||
1946 | dev_priv->max_delay++; | ||
1947 | |||
1948 | out_unlock: | ||
1949 | spin_unlock(&mchdev_lock); | ||
1950 | |||
1951 | return ret; | ||
1952 | } | ||
1953 | EXPORT_SYMBOL_GPL(i915_gpu_lower); | ||
1954 | |||
1955 | /** | ||
1956 | * i915_gpu_busy - indicate GPU business to IPS | ||
1957 | * | ||
1958 | * Tell the IPS driver whether or not the GPU is busy. | ||
1959 | */ | ||
1960 | bool i915_gpu_busy(void) | ||
1961 | { | ||
1962 | struct drm_i915_private *dev_priv; | ||
1963 | bool ret = false; | ||
1964 | |||
1965 | spin_lock(&mchdev_lock); | ||
1966 | if (!i915_mch_dev) | ||
1967 | goto out_unlock; | ||
1968 | dev_priv = i915_mch_dev; | ||
1969 | |||
1970 | ret = dev_priv->busy; | ||
1971 | |||
1972 | out_unlock: | ||
1973 | spin_unlock(&mchdev_lock); | ||
1974 | |||
1975 | return ret; | ||
1976 | } | ||
1977 | EXPORT_SYMBOL_GPL(i915_gpu_busy); | ||
1978 | |||
1979 | /** | ||
1980 | * i915_gpu_turbo_disable - disable graphics turbo | ||
1981 | * | ||
1982 | * Disable graphics turbo by resetting the max frequency and setting the | ||
1983 | * current frequency to the default. | ||
1984 | */ | ||
1985 | bool i915_gpu_turbo_disable(void) | ||
1986 | { | ||
1987 | struct drm_i915_private *dev_priv; | ||
1988 | bool ret = true; | ||
1989 | |||
1990 | spin_lock(&mchdev_lock); | ||
1991 | if (!i915_mch_dev) { | ||
1992 | ret = false; | ||
1993 | goto out_unlock; | ||
1994 | } | ||
1995 | dev_priv = i915_mch_dev; | ||
1996 | |||
1997 | dev_priv->max_delay = dev_priv->fstart; | ||
1998 | |||
1999 | if (!ironlake_set_drps(dev_priv->dev, dev_priv->fstart)) | ||
2000 | ret = false; | ||
2001 | |||
2002 | out_unlock: | ||
2003 | spin_unlock(&mchdev_lock); | ||
2004 | |||
2005 | return ret; | ||
2006 | } | ||
2007 | EXPORT_SYMBOL_GPL(i915_gpu_turbo_disable); | ||
2008 | |||
1499 | /** | 2009 | /** |
1500 | * i915_driver_load - setup chip and create an initial config | 2010 | * i915_driver_load - setup chip and create an initial config |
1501 | * @dev: DRM device | 2011 | * @dev: DRM device |
@@ -1616,7 +2126,10 @@ int i915_driver_load(struct drm_device *dev, unsigned long flags) | |||
1616 | goto out_workqueue_free; | 2126 | goto out_workqueue_free; |
1617 | } | 2127 | } |
1618 | 2128 | ||
1619 | i915_get_mem_freq(dev); | 2129 | if (IS_PINEVIEW(dev)) |
2130 | i915_pineview_get_mem_freq(dev); | ||
2131 | else if (IS_IRONLAKE(dev)) | ||
2132 | i915_ironlake_get_mem_freq(dev); | ||
1620 | 2133 | ||
1621 | /* On the 945G/GM, the chipset reports the MSI capability on the | 2134 | /* On the 945G/GM, the chipset reports the MSI capability on the |
1622 | * integrated graphics even though the support isn't actually there | 2135 | * integrated graphics even though the support isn't actually there |
@@ -1662,6 +2175,12 @@ int i915_driver_load(struct drm_device *dev, unsigned long flags) | |||
1662 | 2175 | ||
1663 | setup_timer(&dev_priv->hangcheck_timer, i915_hangcheck_elapsed, | 2176 | setup_timer(&dev_priv->hangcheck_timer, i915_hangcheck_elapsed, |
1664 | (unsigned long) dev); | 2177 | (unsigned long) dev); |
2178 | |||
2179 | spin_lock(&mchdev_lock); | ||
2180 | i915_mch_dev = dev_priv; | ||
2181 | dev_priv->mchdev_lock = &mchdev_lock; | ||
2182 | spin_unlock(&mchdev_lock); | ||
2183 | |||
1665 | return 0; | 2184 | return 0; |
1666 | 2185 | ||
1667 | out_workqueue_free: | 2186 | out_workqueue_free: |
@@ -1683,6 +2202,10 @@ int i915_driver_unload(struct drm_device *dev) | |||
1683 | 2202 | ||
1684 | i915_destroy_error_state(dev); | 2203 | i915_destroy_error_state(dev); |
1685 | 2204 | ||
2205 | spin_lock(&mchdev_lock); | ||
2206 | i915_mch_dev = NULL; | ||
2207 | spin_unlock(&mchdev_lock); | ||
2208 | |||
1686 | destroy_workqueue(dev_priv->wq); | 2209 | destroy_workqueue(dev_priv->wq); |
1687 | del_timer_sync(&dev_priv->hangcheck_timer); | 2210 | del_timer_sync(&dev_priv->hangcheck_timer); |
1688 | 2211 | ||
diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index 6bc0fc080f2b..91b3a1c20ef8 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h | |||
@@ -619,6 +619,18 @@ typedef struct drm_i915_private { | |||
619 | u8 cur_delay; | 619 | u8 cur_delay; |
620 | u8 min_delay; | 620 | u8 min_delay; |
621 | u8 max_delay; | 621 | u8 max_delay; |
622 | u8 fmax; | ||
623 | u8 fstart; | ||
624 | |||
625 | u64 last_count1; | ||
626 | unsigned long last_time1; | ||
627 | u64 last_count2; | ||
628 | struct timespec last_time2; | ||
629 | unsigned long gfx_power; | ||
630 | int c_m; | ||
631 | int r_t; | ||
632 | u8 corr; | ||
633 | spinlock_t *mchdev_lock; | ||
622 | 634 | ||
623 | enum no_fbc_reason no_fbc_reason; | 635 | enum no_fbc_reason no_fbc_reason; |
624 | 636 | ||
@@ -802,6 +814,11 @@ extern int i915_emit_box(struct drm_device *dev, | |||
802 | struct drm_clip_rect *boxes, | 814 | struct drm_clip_rect *boxes, |
803 | int i, int DR1, int DR4); | 815 | int i, int DR1, int DR4); |
804 | extern int i965_reset(struct drm_device *dev, u8 flags); | 816 | extern int i965_reset(struct drm_device *dev, u8 flags); |
817 | extern unsigned long i915_chipset_val(struct drm_i915_private *dev_priv); | ||
818 | extern unsigned long i915_mch_val(struct drm_i915_private *dev_priv); | ||
819 | extern unsigned long i915_gfx_val(struct drm_i915_private *dev_priv); | ||
820 | extern void i915_update_gfx_val(struct drm_i915_private *dev_priv); | ||
821 | |||
805 | 822 | ||
806 | /* i915_irq.c */ | 823 | /* i915_irq.c */ |
807 | void i915_hangcheck_elapsed(unsigned long data); | 824 | void i915_hangcheck_elapsed(unsigned long data); |
@@ -1005,7 +1022,7 @@ extern void g4x_disable_fbc(struct drm_device *dev); | |||
1005 | extern void intel_disable_fbc(struct drm_device *dev); | 1022 | extern void intel_disable_fbc(struct drm_device *dev); |
1006 | extern void intel_enable_fbc(struct drm_crtc *crtc, unsigned long interval); | 1023 | extern void intel_enable_fbc(struct drm_crtc *crtc, unsigned long interval); |
1007 | extern bool intel_fbc_enabled(struct drm_device *dev); | 1024 | extern bool intel_fbc_enabled(struct drm_device *dev); |
1008 | 1025 | extern bool ironlake_set_drps(struct drm_device *dev, u8 val); | |
1009 | extern void intel_detect_pch (struct drm_device *dev); | 1026 | extern void intel_detect_pch (struct drm_device *dev); |
1010 | extern int intel_trans_dp_port_sel (struct drm_crtc *crtc); | 1027 | extern int intel_trans_dp_port_sel (struct drm_crtc *crtc); |
1011 | 1028 | ||
@@ -1030,6 +1047,7 @@ extern int intel_trans_dp_port_sel (struct drm_crtc *crtc); | |||
1030 | #define I915_WRITE64(reg, val) writeq(val, dev_priv->regs + (reg)) | 1047 | #define I915_WRITE64(reg, val) writeq(val, dev_priv->regs + (reg)) |
1031 | #define I915_READ64(reg) readq(dev_priv->regs + (reg)) | 1048 | #define I915_READ64(reg) readq(dev_priv->regs + (reg)) |
1032 | #define POSTING_READ(reg) (void)I915_READ(reg) | 1049 | #define POSTING_READ(reg) (void)I915_READ(reg) |
1050 | #define POSTING_READ16(reg) (void)I915_READ16(reg) | ||
1033 | 1051 | ||
1034 | #define I915_VERBOSE 0 | 1052 | #define I915_VERBOSE 0 |
1035 | 1053 | ||
diff --git a/drivers/gpu/drm/i915/i915_irq.c b/drivers/gpu/drm/i915/i915_irq.c index 0a3a5806a12e..b5dba4795f6f 100644 --- a/drivers/gpu/drm/i915/i915_irq.c +++ b/drivers/gpu/drm/i915/i915_irq.c | |||
@@ -278,10 +278,9 @@ static void i915_handle_rps_change(struct drm_device *dev) | |||
278 | { | 278 | { |
279 | drm_i915_private_t *dev_priv = dev->dev_private; | 279 | drm_i915_private_t *dev_priv = dev->dev_private; |
280 | u32 busy_up, busy_down, max_avg, min_avg; | 280 | u32 busy_up, busy_down, max_avg, min_avg; |
281 | u16 rgvswctl; | ||
282 | u8 new_delay = dev_priv->cur_delay; | 281 | u8 new_delay = dev_priv->cur_delay; |
283 | 282 | ||
284 | I915_WRITE(MEMINTRSTS, I915_READ(MEMINTRSTS) & ~MEMINT_EVAL_CHG); | 283 | I915_WRITE16(MEMINTRSTS, MEMINT_EVAL_CHG); |
285 | busy_up = I915_READ(RCPREVBSYTUPAVG); | 284 | busy_up = I915_READ(RCPREVBSYTUPAVG); |
286 | busy_down = I915_READ(RCPREVBSYTDNAVG); | 285 | busy_down = I915_READ(RCPREVBSYTDNAVG); |
287 | max_avg = I915_READ(RCBMAXAVG); | 286 | max_avg = I915_READ(RCBMAXAVG); |
@@ -300,27 +299,8 @@ static void i915_handle_rps_change(struct drm_device *dev) | |||
300 | new_delay = dev_priv->min_delay; | 299 | new_delay = dev_priv->min_delay; |
301 | } | 300 | } |
302 | 301 | ||
303 | DRM_DEBUG("rps change requested: %d -> %d\n", | 302 | if (ironlake_set_drps(dev, new_delay)) |
304 | dev_priv->cur_delay, new_delay); | 303 | dev_priv->cur_delay = new_delay; |
305 | |||
306 | rgvswctl = I915_READ(MEMSWCTL); | ||
307 | if (rgvswctl & MEMCTL_CMD_STS) { | ||
308 | DRM_ERROR("gpu busy, RCS change rejected\n"); | ||
309 | return; /* still busy with another command */ | ||
310 | } | ||
311 | |||
312 | /* Program the new state */ | ||
313 | rgvswctl = (MEMCTL_CMD_CHFREQ << MEMCTL_CMD_SHIFT) | | ||
314 | (new_delay << MEMCTL_FREQ_SHIFT) | MEMCTL_SFCAVM; | ||
315 | I915_WRITE(MEMSWCTL, rgvswctl); | ||
316 | POSTING_READ(MEMSWCTL); | ||
317 | |||
318 | rgvswctl |= MEMCTL_CMD_STS; | ||
319 | I915_WRITE(MEMSWCTL, rgvswctl); | ||
320 | |||
321 | dev_priv->cur_delay = new_delay; | ||
322 | |||
323 | DRM_DEBUG("rps changed\n"); | ||
324 | 304 | ||
325 | return; | 305 | return; |
326 | } | 306 | } |
@@ -392,7 +372,7 @@ irqreturn_t ironlake_irq_handler(struct drm_device *dev) | |||
392 | } | 372 | } |
393 | 373 | ||
394 | if (de_iir & DE_PCU_EVENT) { | 374 | if (de_iir & DE_PCU_EVENT) { |
395 | I915_WRITE(MEMINTRSTS, I915_READ(MEMINTRSTS)); | 375 | I915_WRITE16(MEMINTRSTS, I915_READ(MEMINTRSTS)); |
396 | i915_handle_rps_change(dev); | 376 | i915_handle_rps_change(dev); |
397 | } | 377 | } |
398 | 378 | ||
diff --git a/drivers/gpu/drm/i915/i915_reg.h b/drivers/gpu/drm/i915/i915_reg.h index 7a726840efa7..df7224de0aed 100644 --- a/drivers/gpu/drm/i915/i915_reg.h +++ b/drivers/gpu/drm/i915/i915_reg.h | |||
@@ -838,6 +838,12 @@ | |||
838 | #define CLKCFG_MEM_800 (3 << 4) | 838 | #define CLKCFG_MEM_800 (3 << 4) |
839 | #define CLKCFG_MEM_MASK (7 << 4) | 839 | #define CLKCFG_MEM_MASK (7 << 4) |
840 | 840 | ||
841 | #define TR1 0x11006 | ||
842 | #define TSFS 0x11020 | ||
843 | #define TSFS_SLOPE_MASK 0x0000ff00 | ||
844 | #define TSFS_SLOPE_SHIFT 8 | ||
845 | #define TSFS_INTR_MASK 0x000000ff | ||
846 | |||
841 | #define CRSTANDVID 0x11100 | 847 | #define CRSTANDVID 0x11100 |
842 | #define PXVFREQ_BASE 0x11110 /* P[0-15]VIDFREQ (0x1114c) (Ironlake) */ | 848 | #define PXVFREQ_BASE 0x11110 /* P[0-15]VIDFREQ (0x1114c) (Ironlake) */ |
843 | #define PXVFREQ_PX_MASK 0x7f000000 | 849 | #define PXVFREQ_PX_MASK 0x7f000000 |
@@ -976,6 +982,41 @@ | |||
976 | #define MEMSTAT_SRC_CTL_STDBY 3 | 982 | #define MEMSTAT_SRC_CTL_STDBY 3 |
977 | #define RCPREVBSYTUPAVG 0x113b8 | 983 | #define RCPREVBSYTUPAVG 0x113b8 |
978 | #define RCPREVBSYTDNAVG 0x113bc | 984 | #define RCPREVBSYTDNAVG 0x113bc |
985 | #define SDEW 0x1124c | ||
986 | #define CSIEW0 0x11250 | ||
987 | #define CSIEW1 0x11254 | ||
988 | #define CSIEW2 0x11258 | ||
989 | #define PEW 0x1125c | ||
990 | #define DEW 0x11270 | ||
991 | #define MCHAFE 0x112c0 | ||
992 | #define CSIEC 0x112e0 | ||
993 | #define DMIEC 0x112e4 | ||
994 | #define DDREC 0x112e8 | ||
995 | #define PEG0EC 0x112ec | ||
996 | #define PEG1EC 0x112f0 | ||
997 | #define GFXEC 0x112f4 | ||
998 | #define RPPREVBSYTUPAVG 0x113b8 | ||
999 | #define RPPREVBSYTDNAVG 0x113bc | ||
1000 | #define ECR 0x11600 | ||
1001 | #define ECR_GPFE (1<<31) | ||
1002 | #define ECR_IMONE (1<<30) | ||
1003 | #define ECR_CAP_MASK 0x0000001f /* Event range, 0-31 */ | ||
1004 | #define OGW0 0x11608 | ||
1005 | #define OGW1 0x1160c | ||
1006 | #define EG0 0x11610 | ||
1007 | #define EG1 0x11614 | ||
1008 | #define EG2 0x11618 | ||
1009 | #define EG3 0x1161c | ||
1010 | #define EG4 0x11620 | ||
1011 | #define EG5 0x11624 | ||
1012 | #define EG6 0x11628 | ||
1013 | #define EG7 0x1162c | ||
1014 | #define PXW 0x11664 | ||
1015 | #define PXWL 0x11680 | ||
1016 | #define LCFUSE02 0x116c0 | ||
1017 | #define LCFUSE_HIV_MASK 0x000000ff | ||
1018 | #define CSIPLL0 0x12c10 | ||
1019 | #define DDRMPLL1 0X12c20 | ||
979 | #define PEG_BAND_GAP_DATA 0x14d68 | 1020 | #define PEG_BAND_GAP_DATA 0x14d68 |
980 | 1021 | ||
981 | /* | 1022 | /* |
diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index 4c7c151114f7..e94d1db35364 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c | |||
@@ -4459,6 +4459,8 @@ static void intel_idle_update(struct work_struct *work) | |||
4459 | 4459 | ||
4460 | mutex_lock(&dev->struct_mutex); | 4460 | mutex_lock(&dev->struct_mutex); |
4461 | 4461 | ||
4462 | i915_update_gfx_val(dev_priv); | ||
4463 | |||
4462 | if (IS_I945G(dev) || IS_I945GM(dev)) { | 4464 | if (IS_I945G(dev) || IS_I945GM(dev)) { |
4463 | DRM_DEBUG_DRIVER("enable memory self refresh on 945\n"); | 4465 | DRM_DEBUG_DRIVER("enable memory self refresh on 945\n"); |
4464 | I915_WRITE(FW_BLC_SELF, FW_BLC_SELF_EN_MASK | FW_BLC_SELF_EN); | 4466 | I915_WRITE(FW_BLC_SELF, FW_BLC_SELF_EN_MASK | FW_BLC_SELF_EN); |
@@ -5045,10 +5047,32 @@ err_unref: | |||
5045 | return NULL; | 5047 | return NULL; |
5046 | } | 5048 | } |
5047 | 5049 | ||
5050 | bool ironlake_set_drps(struct drm_device *dev, u8 val) | ||
5051 | { | ||
5052 | struct drm_i915_private *dev_priv = dev->dev_private; | ||
5053 | u16 rgvswctl; | ||
5054 | |||
5055 | rgvswctl = I915_READ16(MEMSWCTL); | ||
5056 | if (rgvswctl & MEMCTL_CMD_STS) { | ||
5057 | DRM_DEBUG("gpu busy, RCS change rejected\n"); | ||
5058 | return false; /* still busy with another command */ | ||
5059 | } | ||
5060 | |||
5061 | rgvswctl = (MEMCTL_CMD_CHFREQ << MEMCTL_CMD_SHIFT) | | ||
5062 | (val << MEMCTL_FREQ_SHIFT) | MEMCTL_SFCAVM; | ||
5063 | I915_WRITE16(MEMSWCTL, rgvswctl); | ||
5064 | POSTING_READ16(MEMSWCTL); | ||
5065 | |||
5066 | rgvswctl |= MEMCTL_CMD_STS; | ||
5067 | I915_WRITE16(MEMSWCTL, rgvswctl); | ||
5068 | |||
5069 | return true; | ||
5070 | } | ||
5071 | |||
5048 | void ironlake_enable_drps(struct drm_device *dev) | 5072 | void ironlake_enable_drps(struct drm_device *dev) |
5049 | { | 5073 | { |
5050 | struct drm_i915_private *dev_priv = dev->dev_private; | 5074 | struct drm_i915_private *dev_priv = dev->dev_private; |
5051 | u32 rgvmodectl = I915_READ(MEMMODECTL), rgvswctl; | 5075 | u32 rgvmodectl = I915_READ(MEMMODECTL); |
5052 | u8 fmax, fmin, fstart, vstart; | 5076 | u8 fmax, fmin, fstart, vstart; |
5053 | int i = 0; | 5077 | int i = 0; |
5054 | 5078 | ||
@@ -5067,13 +5091,21 @@ void ironlake_enable_drps(struct drm_device *dev) | |||
5067 | fmin = (rgvmodectl & MEMMODE_FMIN_MASK); | 5091 | fmin = (rgvmodectl & MEMMODE_FMIN_MASK); |
5068 | fstart = (rgvmodectl & MEMMODE_FSTART_MASK) >> | 5092 | fstart = (rgvmodectl & MEMMODE_FSTART_MASK) >> |
5069 | MEMMODE_FSTART_SHIFT; | 5093 | MEMMODE_FSTART_SHIFT; |
5094 | fstart = fmax; | ||
5095 | |||
5070 | vstart = (I915_READ(PXVFREQ_BASE + (fstart * 4)) & PXVFREQ_PX_MASK) >> | 5096 | vstart = (I915_READ(PXVFREQ_BASE + (fstart * 4)) & PXVFREQ_PX_MASK) >> |
5071 | PXVFREQ_PX_SHIFT; | 5097 | PXVFREQ_PX_SHIFT; |
5072 | 5098 | ||
5073 | dev_priv->max_delay = fstart; /* can't go to fmax w/o IPS */ | 5099 | dev_priv->fmax = fstart; /* IPS callback will increase this */ |
5100 | dev_priv->fstart = fstart; | ||
5101 | |||
5102 | dev_priv->max_delay = fmax; | ||
5074 | dev_priv->min_delay = fmin; | 5103 | dev_priv->min_delay = fmin; |
5075 | dev_priv->cur_delay = fstart; | 5104 | dev_priv->cur_delay = fstart; |
5076 | 5105 | ||
5106 | DRM_DEBUG_DRIVER("fmax: %d, fmin: %d, fstart: %d\n", fmax, fmin, | ||
5107 | fstart); | ||
5108 | |||
5077 | I915_WRITE(MEMINTREN, MEMINT_CX_SUPR_EN | MEMINT_EVAL_CHG_EN); | 5109 | I915_WRITE(MEMINTREN, MEMINT_CX_SUPR_EN | MEMINT_EVAL_CHG_EN); |
5078 | 5110 | ||
5079 | /* | 5111 | /* |
@@ -5095,20 +5127,19 @@ void ironlake_enable_drps(struct drm_device *dev) | |||
5095 | } | 5127 | } |
5096 | msleep(1); | 5128 | msleep(1); |
5097 | 5129 | ||
5098 | rgvswctl = (MEMCTL_CMD_CHFREQ << MEMCTL_CMD_SHIFT) | | 5130 | ironlake_set_drps(dev, fstart); |
5099 | (fstart << MEMCTL_FREQ_SHIFT) | MEMCTL_SFCAVM; | ||
5100 | I915_WRITE(MEMSWCTL, rgvswctl); | ||
5101 | POSTING_READ(MEMSWCTL); | ||
5102 | 5131 | ||
5103 | rgvswctl |= MEMCTL_CMD_STS; | 5132 | dev_priv->last_count1 = I915_READ(0x112e4) + I915_READ(0x112e8) + |
5104 | I915_WRITE(MEMSWCTL, rgvswctl); | 5133 | I915_READ(0x112e0); |
5134 | dev_priv->last_time1 = jiffies_to_msecs(jiffies); | ||
5135 | dev_priv->last_count2 = I915_READ(0x112f4); | ||
5136 | getrawmonotonic(&dev_priv->last_time2); | ||
5105 | } | 5137 | } |
5106 | 5138 | ||
5107 | void ironlake_disable_drps(struct drm_device *dev) | 5139 | void ironlake_disable_drps(struct drm_device *dev) |
5108 | { | 5140 | { |
5109 | struct drm_i915_private *dev_priv = dev->dev_private; | 5141 | struct drm_i915_private *dev_priv = dev->dev_private; |
5110 | u32 rgvswctl; | 5142 | u16 rgvswctl = I915_READ16(MEMSWCTL); |
5111 | u8 fstart; | ||
5112 | 5143 | ||
5113 | /* Ack interrupts, disable EFC interrupt */ | 5144 | /* Ack interrupts, disable EFC interrupt */ |
5114 | I915_WRITE(MEMINTREN, I915_READ(MEMINTREN) & ~MEMINT_EVAL_CHG_EN); | 5145 | I915_WRITE(MEMINTREN, I915_READ(MEMINTREN) & ~MEMINT_EVAL_CHG_EN); |
@@ -5118,11 +5149,7 @@ void ironlake_disable_drps(struct drm_device *dev) | |||
5118 | I915_WRITE(DEIMR, I915_READ(DEIMR) | DE_PCU_EVENT); | 5149 | I915_WRITE(DEIMR, I915_READ(DEIMR) | DE_PCU_EVENT); |
5119 | 5150 | ||
5120 | /* Go back to the starting frequency */ | 5151 | /* Go back to the starting frequency */ |
5121 | fstart = (I915_READ(MEMMODECTL) & MEMMODE_FSTART_MASK) >> | 5152 | ironlake_set_drps(dev, dev_priv->fstart); |
5122 | MEMMODE_FSTART_SHIFT; | ||
5123 | rgvswctl = (MEMCTL_CMD_CHFREQ << MEMCTL_CMD_SHIFT) | | ||
5124 | (fstart << MEMCTL_FREQ_SHIFT) | MEMCTL_SFCAVM; | ||
5125 | I915_WRITE(MEMSWCTL, rgvswctl); | ||
5126 | msleep(1); | 5153 | msleep(1); |
5127 | rgvswctl |= MEMCTL_CMD_STS; | 5154 | rgvswctl |= MEMCTL_CMD_STS; |
5128 | I915_WRITE(MEMSWCTL, rgvswctl); | 5155 | I915_WRITE(MEMSWCTL, rgvswctl); |
@@ -5130,6 +5157,92 @@ void ironlake_disable_drps(struct drm_device *dev) | |||
5130 | 5157 | ||
5131 | } | 5158 | } |
5132 | 5159 | ||
5160 | static unsigned long intel_pxfreq(u32 vidfreq) | ||
5161 | { | ||
5162 | unsigned long freq; | ||
5163 | int div = (vidfreq & 0x3f0000) >> 16; | ||
5164 | int post = (vidfreq & 0x3000) >> 12; | ||
5165 | int pre = (vidfreq & 0x7); | ||
5166 | |||
5167 | if (!pre) | ||
5168 | return 0; | ||
5169 | |||
5170 | freq = ((div * 133333) / ((1<<post) * pre)); | ||
5171 | |||
5172 | return freq; | ||
5173 | } | ||
5174 | |||
5175 | void intel_init_emon(struct drm_device *dev) | ||
5176 | { | ||
5177 | struct drm_i915_private *dev_priv = dev->dev_private; | ||
5178 | u32 lcfuse; | ||
5179 | u8 pxw[16]; | ||
5180 | int i; | ||
5181 | |||
5182 | /* Disable to program */ | ||
5183 | I915_WRITE(ECR, 0); | ||
5184 | POSTING_READ(ECR); | ||
5185 | |||
5186 | /* Program energy weights for various events */ | ||
5187 | I915_WRITE(SDEW, 0x15040d00); | ||
5188 | I915_WRITE(CSIEW0, 0x007f0000); | ||
5189 | I915_WRITE(CSIEW1, 0x1e220004); | ||
5190 | I915_WRITE(CSIEW2, 0x04000004); | ||
5191 | |||
5192 | for (i = 0; i < 5; i++) | ||
5193 | I915_WRITE(PEW + (i * 4), 0); | ||
5194 | for (i = 0; i < 3; i++) | ||
5195 | I915_WRITE(DEW + (i * 4), 0); | ||
5196 | |||
5197 | /* Program P-state weights to account for frequency power adjustment */ | ||
5198 | for (i = 0; i < 16; i++) { | ||
5199 | u32 pxvidfreq = I915_READ(PXVFREQ_BASE + (i * 4)); | ||
5200 | unsigned long freq = intel_pxfreq(pxvidfreq); | ||
5201 | unsigned long vid = (pxvidfreq & PXVFREQ_PX_MASK) >> | ||
5202 | PXVFREQ_PX_SHIFT; | ||
5203 | unsigned long val; | ||
5204 | |||
5205 | val = vid * vid; | ||
5206 | val *= (freq / 1000); | ||
5207 | val *= 255; | ||
5208 | val /= (127*127*900); | ||
5209 | if (val > 0xff) | ||
5210 | DRM_ERROR("bad pxval: %ld\n", val); | ||
5211 | pxw[i] = val; | ||
5212 | } | ||
5213 | /* Render standby states get 0 weight */ | ||
5214 | pxw[14] = 0; | ||
5215 | pxw[15] = 0; | ||
5216 | |||
5217 | for (i = 0; i < 4; i++) { | ||
5218 | u32 val = (pxw[i*4] << 24) | (pxw[(i*4)+1] << 16) | | ||
5219 | (pxw[(i*4)+2] << 8) | (pxw[(i*4)+3]); | ||
5220 | I915_WRITE(PXW + (i * 4), val); | ||
5221 | } | ||
5222 | |||
5223 | /* Adjust magic regs to magic values (more experimental results) */ | ||
5224 | I915_WRITE(OGW0, 0); | ||
5225 | I915_WRITE(OGW1, 0); | ||
5226 | I915_WRITE(EG0, 0x00007f00); | ||
5227 | I915_WRITE(EG1, 0x0000000e); | ||
5228 | I915_WRITE(EG2, 0x000e0000); | ||
5229 | I915_WRITE(EG3, 0x68000300); | ||
5230 | I915_WRITE(EG4, 0x42000000); | ||
5231 | I915_WRITE(EG5, 0x00140031); | ||
5232 | I915_WRITE(EG6, 0); | ||
5233 | I915_WRITE(EG7, 0); | ||
5234 | |||
5235 | for (i = 0; i < 8; i++) | ||
5236 | I915_WRITE(PXWL + (i * 4), 0); | ||
5237 | |||
5238 | /* Enable PMON + select events */ | ||
5239 | I915_WRITE(ECR, 0x80000019); | ||
5240 | |||
5241 | lcfuse = I915_READ(LCFUSE02); | ||
5242 | |||
5243 | dev_priv->corr = (lcfuse & LCFUSE_HIV_MASK); | ||
5244 | } | ||
5245 | |||
5133 | void intel_init_clock_gating(struct drm_device *dev) | 5246 | void intel_init_clock_gating(struct drm_device *dev) |
5134 | { | 5247 | { |
5135 | struct drm_i915_private *dev_priv = dev->dev_private; | 5248 | struct drm_i915_private *dev_priv = dev->dev_private; |
@@ -5376,8 +5489,10 @@ void intel_modeset_init(struct drm_device *dev) | |||
5376 | 5489 | ||
5377 | intel_init_clock_gating(dev); | 5490 | intel_init_clock_gating(dev); |
5378 | 5491 | ||
5379 | if (IS_IRONLAKE_M(dev)) | 5492 | if (IS_IRONLAKE_M(dev)) { |
5380 | ironlake_enable_drps(dev); | 5493 | ironlake_enable_drps(dev); |
5494 | intel_init_emon(dev); | ||
5495 | } | ||
5381 | 5496 | ||
5382 | INIT_WORK(&dev_priv->idle_work, intel_idle_update); | 5497 | INIT_WORK(&dev_priv->idle_work, intel_idle_update); |
5383 | setup_timer(&dev_priv->idle_timer, intel_gpu_idle_timer, | 5498 | setup_timer(&dev_priv->idle_timer, intel_gpu_idle_timer, |