aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/gpu/drm/i915/intel_pm.c
diff options
context:
space:
mode:
authorDaniel Vetter <daniel.vetter@ffwll.ch>2012-04-26 17:28:12 -0400
committerDaniel Vetter <daniel.vetter@ffwll.ch>2012-05-03 05:18:29 -0400
commiteb48eb005098cc6f845d281dd079baea7573f54c (patch)
tree18eef2f8743a764c34d6ea0cc0f202f2321fba0b /drivers/gpu/drm/i915/intel_pm.c
parent6ebebc9206fca1d20d90edec4873e819cc4051d0 (diff)
drm/i915: move the ips code to intel_pm.c
We now have a nice home for power management code, so let's use it! v2: Resolve conflict agains "Only enable IPS polling for gen5" Acked-by: Jesse Barnes <jbarnes@virtuousgeek.org> Signed-off-by: Daniel Vetter <daniel.vetter@ffwll.ch>
Diffstat (limited to 'drivers/gpu/drm/i915/intel_pm.c')
-rw-r--r--drivers/gpu/drm/i915/intel_pm.c481
1 files changed, 481 insertions, 0 deletions
diff --git a/drivers/gpu/drm/i915/intel_pm.c b/drivers/gpu/drm/i915/intel_pm.c
index 0a3699908fdf..e0f016c24dce 100644
--- a/drivers/gpu/drm/i915/intel_pm.c
+++ b/drivers/gpu/drm/i915/intel_pm.c
@@ -28,6 +28,8 @@
28#include <linux/cpufreq.h> 28#include <linux/cpufreq.h>
29#include "i915_drv.h" 29#include "i915_drv.h"
30#include "intel_drv.h" 30#include "intel_drv.h"
31#include "../../../platform/x86/intel_ips.h"
32#include <linux/module.h>
31 33
32/* FBC, or Frame Buffer Compression, is a technique employed to compress the 34/* FBC, or Frame Buffer Compression, is a technique employed to compress the
33 * framebuffer contents in-memory, aiming at reducing the required bandwidth 35 * framebuffer contents in-memory, aiming at reducing the required bandwidth
@@ -2508,6 +2510,485 @@ static unsigned long intel_pxfreq(u32 vidfreq)
2508 return freq; 2510 return freq;
2509} 2511}
2510 2512
2513static const struct cparams {
2514 u16 i;
2515 u16 t;
2516 u16 m;
2517 u16 c;
2518} cparams[] = {
2519 { 1, 1333, 301, 28664 },
2520 { 1, 1066, 294, 24460 },
2521 { 1, 800, 294, 25192 },
2522 { 0, 1333, 276, 27605 },
2523 { 0, 1066, 276, 27605 },
2524 { 0, 800, 231, 23784 },
2525};
2526
2527unsigned long i915_chipset_val(struct drm_i915_private *dev_priv)
2528{
2529 u64 total_count, diff, ret;
2530 u32 count1, count2, count3, m = 0, c = 0;
2531 unsigned long now = jiffies_to_msecs(jiffies), diff1;
2532 int i;
2533
2534 diff1 = now - dev_priv->last_time1;
2535
2536 /* Prevent division-by-zero if we are asking too fast.
2537 * Also, we don't get interesting results if we are polling
2538 * faster than once in 10ms, so just return the saved value
2539 * in such cases.
2540 */
2541 if (diff1 <= 10)
2542 return dev_priv->chipset_power;
2543
2544 count1 = I915_READ(DMIEC);
2545 count2 = I915_READ(DDREC);
2546 count3 = I915_READ(CSIEC);
2547
2548 total_count = count1 + count2 + count3;
2549
2550 /* FIXME: handle per-counter overflow */
2551 if (total_count < dev_priv->last_count1) {
2552 diff = ~0UL - dev_priv->last_count1;
2553 diff += total_count;
2554 } else {
2555 diff = total_count - dev_priv->last_count1;
2556 }
2557
2558 for (i = 0; i < ARRAY_SIZE(cparams); i++) {
2559 if (cparams[i].i == dev_priv->c_m &&
2560 cparams[i].t == dev_priv->r_t) {
2561 m = cparams[i].m;
2562 c = cparams[i].c;
2563 break;
2564 }
2565 }
2566
2567 diff = div_u64(diff, diff1);
2568 ret = ((m * diff) + c);
2569 ret = div_u64(ret, 10);
2570
2571 dev_priv->last_count1 = total_count;
2572 dev_priv->last_time1 = now;
2573
2574 dev_priv->chipset_power = ret;
2575
2576 return ret;
2577}
2578
2579unsigned long i915_mch_val(struct drm_i915_private *dev_priv)
2580{
2581 unsigned long m, x, b;
2582 u32 tsfs;
2583
2584 tsfs = I915_READ(TSFS);
2585
2586 m = ((tsfs & TSFS_SLOPE_MASK) >> TSFS_SLOPE_SHIFT);
2587 x = I915_READ8(TR1);
2588
2589 b = tsfs & TSFS_INTR_MASK;
2590
2591 return ((m * x) / 127) - b;
2592}
2593
2594static u16 pvid_to_extvid(struct drm_i915_private *dev_priv, u8 pxvid)
2595{
2596 static const struct v_table {
2597 u16 vd; /* in .1 mil */
2598 u16 vm; /* in .1 mil */
2599 } v_table[] = {
2600 { 0, 0, },
2601 { 375, 0, },
2602 { 500, 0, },
2603 { 625, 0, },
2604 { 750, 0, },
2605 { 875, 0, },
2606 { 1000, 0, },
2607 { 1125, 0, },
2608 { 4125, 3000, },
2609 { 4125, 3000, },
2610 { 4125, 3000, },
2611 { 4125, 3000, },
2612 { 4125, 3000, },
2613 { 4125, 3000, },
2614 { 4125, 3000, },
2615 { 4125, 3000, },
2616 { 4125, 3000, },
2617 { 4125, 3000, },
2618 { 4125, 3000, },
2619 { 4125, 3000, },
2620 { 4125, 3000, },
2621 { 4125, 3000, },
2622 { 4125, 3000, },
2623 { 4125, 3000, },
2624 { 4125, 3000, },
2625 { 4125, 3000, },
2626 { 4125, 3000, },
2627 { 4125, 3000, },
2628 { 4125, 3000, },
2629 { 4125, 3000, },
2630 { 4125, 3000, },
2631 { 4125, 3000, },
2632 { 4250, 3125, },
2633 { 4375, 3250, },
2634 { 4500, 3375, },
2635 { 4625, 3500, },
2636 { 4750, 3625, },
2637 { 4875, 3750, },
2638 { 5000, 3875, },
2639 { 5125, 4000, },
2640 { 5250, 4125, },
2641 { 5375, 4250, },
2642 { 5500, 4375, },
2643 { 5625, 4500, },
2644 { 5750, 4625, },
2645 { 5875, 4750, },
2646 { 6000, 4875, },
2647 { 6125, 5000, },
2648 { 6250, 5125, },
2649 { 6375, 5250, },
2650 { 6500, 5375, },
2651 { 6625, 5500, },
2652 { 6750, 5625, },
2653 { 6875, 5750, },
2654 { 7000, 5875, },
2655 { 7125, 6000, },
2656 { 7250, 6125, },
2657 { 7375, 6250, },
2658 { 7500, 6375, },
2659 { 7625, 6500, },
2660 { 7750, 6625, },
2661 { 7875, 6750, },
2662 { 8000, 6875, },
2663 { 8125, 7000, },
2664 { 8250, 7125, },
2665 { 8375, 7250, },
2666 { 8500, 7375, },
2667 { 8625, 7500, },
2668 { 8750, 7625, },
2669 { 8875, 7750, },
2670 { 9000, 7875, },
2671 { 9125, 8000, },
2672 { 9250, 8125, },
2673 { 9375, 8250, },
2674 { 9500, 8375, },
2675 { 9625, 8500, },
2676 { 9750, 8625, },
2677 { 9875, 8750, },
2678 { 10000, 8875, },
2679 { 10125, 9000, },
2680 { 10250, 9125, },
2681 { 10375, 9250, },
2682 { 10500, 9375, },
2683 { 10625, 9500, },
2684 { 10750, 9625, },
2685 { 10875, 9750, },
2686 { 11000, 9875, },
2687 { 11125, 10000, },
2688 { 11250, 10125, },
2689 { 11375, 10250, },
2690 { 11500, 10375, },
2691 { 11625, 10500, },
2692 { 11750, 10625, },
2693 { 11875, 10750, },
2694 { 12000, 10875, },
2695 { 12125, 11000, },
2696 { 12250, 11125, },
2697 { 12375, 11250, },
2698 { 12500, 11375, },
2699 { 12625, 11500, },
2700 { 12750, 11625, },
2701 { 12875, 11750, },
2702 { 13000, 11875, },
2703 { 13125, 12000, },
2704 { 13250, 12125, },
2705 { 13375, 12250, },
2706 { 13500, 12375, },
2707 { 13625, 12500, },
2708 { 13750, 12625, },
2709 { 13875, 12750, },
2710 { 14000, 12875, },
2711 { 14125, 13000, },
2712 { 14250, 13125, },
2713 { 14375, 13250, },
2714 { 14500, 13375, },
2715 { 14625, 13500, },
2716 { 14750, 13625, },
2717 { 14875, 13750, },
2718 { 15000, 13875, },
2719 { 15125, 14000, },
2720 { 15250, 14125, },
2721 { 15375, 14250, },
2722 { 15500, 14375, },
2723 { 15625, 14500, },
2724 { 15750, 14625, },
2725 { 15875, 14750, },
2726 { 16000, 14875, },
2727 { 16125, 15000, },
2728 };
2729 if (dev_priv->info->is_mobile)
2730 return v_table[pxvid].vm;
2731 else
2732 return v_table[pxvid].vd;
2733}
2734
2735void i915_update_gfx_val(struct drm_i915_private *dev_priv)
2736{
2737 struct timespec now, diff1;
2738 u64 diff;
2739 unsigned long diffms;
2740 u32 count;
2741
2742 if (dev_priv->info->gen != 5)
2743 return;
2744
2745 getrawmonotonic(&now);
2746 diff1 = timespec_sub(now, dev_priv->last_time2);
2747
2748 /* Don't divide by 0 */
2749 diffms = diff1.tv_sec * 1000 + diff1.tv_nsec / 1000000;
2750 if (!diffms)
2751 return;
2752
2753 count = I915_READ(GFXEC);
2754
2755 if (count < dev_priv->last_count2) {
2756 diff = ~0UL - dev_priv->last_count2;
2757 diff += count;
2758 } else {
2759 diff = count - dev_priv->last_count2;
2760 }
2761
2762 dev_priv->last_count2 = count;
2763 dev_priv->last_time2 = now;
2764
2765 /* More magic constants... */
2766 diff = diff * 1181;
2767 diff = div_u64(diff, diffms * 10);
2768 dev_priv->gfx_power = diff;
2769}
2770
2771unsigned long i915_gfx_val(struct drm_i915_private *dev_priv)
2772{
2773 unsigned long t, corr, state1, corr2, state2;
2774 u32 pxvid, ext_v;
2775
2776 pxvid = I915_READ(PXVFREQ_BASE + (dev_priv->cur_delay * 4));
2777 pxvid = (pxvid >> 24) & 0x7f;
2778 ext_v = pvid_to_extvid(dev_priv, pxvid);
2779
2780 state1 = ext_v;
2781
2782 t = i915_mch_val(dev_priv);
2783
2784 /* Revel in the empirically derived constants */
2785
2786 /* Correction factor in 1/100000 units */
2787 if (t > 80)
2788 corr = ((t * 2349) + 135940);
2789 else if (t >= 50)
2790 corr = ((t * 964) + 29317);
2791 else /* < 50 */
2792 corr = ((t * 301) + 1004);
2793
2794 corr = corr * ((150142 * state1) / 10000 - 78642);
2795 corr /= 100000;
2796 corr2 = (corr * dev_priv->corr);
2797
2798 state2 = (corr2 * state1) / 10000;
2799 state2 /= 100; /* convert to mW */
2800
2801 i915_update_gfx_val(dev_priv);
2802
2803 return dev_priv->gfx_power + state2;
2804}
2805
2806/* Global for IPS driver to get at the current i915 device */
2807static struct drm_i915_private *i915_mch_dev;
2808/*
2809 * Lock protecting IPS related data structures
2810 * - i915_mch_dev
2811 * - dev_priv->max_delay
2812 * - dev_priv->min_delay
2813 * - dev_priv->fmax
2814 * - dev_priv->gpu_busy
2815 */
2816static DEFINE_SPINLOCK(mchdev_lock);
2817
2818/**
2819 * i915_read_mch_val - return value for IPS use
2820 *
2821 * Calculate and return a value for the IPS driver to use when deciding whether
2822 * we have thermal and power headroom to increase CPU or GPU power budget.
2823 */
2824unsigned long i915_read_mch_val(void)
2825{
2826 struct drm_i915_private *dev_priv;
2827 unsigned long chipset_val, graphics_val, ret = 0;
2828
2829 spin_lock(&mchdev_lock);
2830 if (!i915_mch_dev)
2831 goto out_unlock;
2832 dev_priv = i915_mch_dev;
2833
2834 chipset_val = i915_chipset_val(dev_priv);
2835 graphics_val = i915_gfx_val(dev_priv);
2836
2837 ret = chipset_val + graphics_val;
2838
2839out_unlock:
2840 spin_unlock(&mchdev_lock);
2841
2842 return ret;
2843}
2844EXPORT_SYMBOL_GPL(i915_read_mch_val);
2845
2846/**
2847 * i915_gpu_raise - raise GPU frequency limit
2848 *
2849 * Raise the limit; IPS indicates we have thermal headroom.
2850 */
2851bool i915_gpu_raise(void)
2852{
2853 struct drm_i915_private *dev_priv;
2854 bool ret = true;
2855
2856 spin_lock(&mchdev_lock);
2857 if (!i915_mch_dev) {
2858 ret = false;
2859 goto out_unlock;
2860 }
2861 dev_priv = i915_mch_dev;
2862
2863 if (dev_priv->max_delay > dev_priv->fmax)
2864 dev_priv->max_delay--;
2865
2866out_unlock:
2867 spin_unlock(&mchdev_lock);
2868
2869 return ret;
2870}
2871EXPORT_SYMBOL_GPL(i915_gpu_raise);
2872
2873/**
2874 * i915_gpu_lower - lower GPU frequency limit
2875 *
2876 * IPS indicates we're close to a thermal limit, so throttle back the GPU
2877 * frequency maximum.
2878 */
2879bool i915_gpu_lower(void)
2880{
2881 struct drm_i915_private *dev_priv;
2882 bool ret = true;
2883
2884 spin_lock(&mchdev_lock);
2885 if (!i915_mch_dev) {
2886 ret = false;
2887 goto out_unlock;
2888 }
2889 dev_priv = i915_mch_dev;
2890
2891 if (dev_priv->max_delay < dev_priv->min_delay)
2892 dev_priv->max_delay++;
2893
2894out_unlock:
2895 spin_unlock(&mchdev_lock);
2896
2897 return ret;
2898}
2899EXPORT_SYMBOL_GPL(i915_gpu_lower);
2900
2901/**
2902 * i915_gpu_busy - indicate GPU business to IPS
2903 *
2904 * Tell the IPS driver whether or not the GPU is busy.
2905 */
2906bool i915_gpu_busy(void)
2907{
2908 struct drm_i915_private *dev_priv;
2909 bool ret = false;
2910
2911 spin_lock(&mchdev_lock);
2912 if (!i915_mch_dev)
2913 goto out_unlock;
2914 dev_priv = i915_mch_dev;
2915
2916 ret = dev_priv->busy;
2917
2918out_unlock:
2919 spin_unlock(&mchdev_lock);
2920
2921 return ret;
2922}
2923EXPORT_SYMBOL_GPL(i915_gpu_busy);
2924
2925/**
2926 * i915_gpu_turbo_disable - disable graphics turbo
2927 *
2928 * Disable graphics turbo by resetting the max frequency and setting the
2929 * current frequency to the default.
2930 */
2931bool i915_gpu_turbo_disable(void)
2932{
2933 struct drm_i915_private *dev_priv;
2934 bool ret = true;
2935
2936 spin_lock(&mchdev_lock);
2937 if (!i915_mch_dev) {
2938 ret = false;
2939 goto out_unlock;
2940 }
2941 dev_priv = i915_mch_dev;
2942
2943 dev_priv->max_delay = dev_priv->fstart;
2944
2945 if (!ironlake_set_drps(dev_priv->dev, dev_priv->fstart))
2946 ret = false;
2947
2948out_unlock:
2949 spin_unlock(&mchdev_lock);
2950
2951 return ret;
2952}
2953EXPORT_SYMBOL_GPL(i915_gpu_turbo_disable);
2954
2955/**
2956 * Tells the intel_ips driver that the i915 driver is now loaded, if
2957 * IPS got loaded first.
2958 *
2959 * This awkward dance is so that neither module has to depend on the
2960 * other in order for IPS to do the appropriate communication of
2961 * GPU turbo limits to i915.
2962 */
2963static void
2964ips_ping_for_i915_load(void)
2965{
2966 void (*link)(void);
2967
2968 link = symbol_get(ips_link_to_i915_driver);
2969 if (link) {
2970 link();
2971 symbol_put(ips_link_to_i915_driver);
2972 }
2973}
2974
2975void intel_gpu_ips_init(struct drm_i915_private *dev_priv)
2976{
2977 spin_lock(&mchdev_lock);
2978 i915_mch_dev = dev_priv;
2979 dev_priv->mchdev_lock = &mchdev_lock;
2980 spin_unlock(&mchdev_lock);
2981
2982 ips_ping_for_i915_load();
2983}
2984
2985void intel_gpu_ips_teardown(void)
2986{
2987 spin_lock(&mchdev_lock);
2988 i915_mch_dev = NULL;
2989 spin_unlock(&mchdev_lock);
2990}
2991
2511void intel_init_emon(struct drm_device *dev) 2992void intel_init_emon(struct drm_device *dev)
2512{ 2993{
2513 struct drm_i915_private *dev_priv = dev->dev_private; 2994 struct drm_i915_private *dev_priv = dev->dev_private;