diff options
Diffstat (limited to 'drivers/gpu/drm/i915/intel_pm.c')
-rw-r--r-- | drivers/gpu/drm/i915/intel_pm.c | 481 |
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 | ||
2513 | static 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 | |||
2527 | unsigned 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 | |||
2579 | unsigned 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 | |||
2594 | static 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 | |||
2735 | void 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 | |||
2771 | unsigned 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 */ | ||
2807 | static 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 | */ | ||
2816 | static 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 | */ | ||
2824 | unsigned 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 | |||
2839 | out_unlock: | ||
2840 | spin_unlock(&mchdev_lock); | ||
2841 | |||
2842 | return ret; | ||
2843 | } | ||
2844 | EXPORT_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 | */ | ||
2851 | bool 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 | |||
2866 | out_unlock: | ||
2867 | spin_unlock(&mchdev_lock); | ||
2868 | |||
2869 | return ret; | ||
2870 | } | ||
2871 | EXPORT_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 | */ | ||
2879 | bool 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 | |||
2894 | out_unlock: | ||
2895 | spin_unlock(&mchdev_lock); | ||
2896 | |||
2897 | return ret; | ||
2898 | } | ||
2899 | EXPORT_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 | */ | ||
2906 | bool 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 | |||
2918 | out_unlock: | ||
2919 | spin_unlock(&mchdev_lock); | ||
2920 | |||
2921 | return ret; | ||
2922 | } | ||
2923 | EXPORT_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 | */ | ||
2931 | bool 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 | |||
2948 | out_unlock: | ||
2949 | spin_unlock(&mchdev_lock); | ||
2950 | |||
2951 | return ret; | ||
2952 | } | ||
2953 | EXPORT_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 | */ | ||
2963 | static void | ||
2964 | ips_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 | |||
2975 | void 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 | |||
2985 | void intel_gpu_ips_teardown(void) | ||
2986 | { | ||
2987 | spin_lock(&mchdev_lock); | ||
2988 | i915_mch_dev = NULL; | ||
2989 | spin_unlock(&mchdev_lock); | ||
2990 | } | ||
2991 | |||
2511 | void intel_init_emon(struct drm_device *dev) | 2992 | void 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; |