Ticket #12716: 0001-intel_extreme-Rewrite-PLL-calculations.patch

File 0001-intel_extreme-Rewrite-PLL-calculations.patch, 21.5 KB (added by kallisti5, 9 years ago)

Any chance you could test this patch? It's a monster and I don't have the hardware.

  • src/add-ons/accelerants/intel_extreme/Pipes.cpp

    From 8d0e424f94628ba1a03125af10bd6eea5cc9f140 Mon Sep 17 00:00:00 2001
    From: Alexander von Gluck IV <kallisti5@unixzen.com>
    Date: Tue, 12 Apr 2016 01:11:30 -0500
    Subject: [PATCH] intel_extreme: Rewrite PLL calculations
    
    * More like linux, improved G4x calculations
    * Reduce un-needed pll limit complexity
    * Improved pll limits on ports based on type
    ---
     src/add-ons/accelerants/intel_extreme/Pipes.cpp |  19 +-
     src/add-ons/accelerants/intel_extreme/Ports.cpp |   4 +-
     src/add-ons/accelerants/intel_extreme/pll.cpp   | 456 ++++++++++++++++--------
     src/add-ons/accelerants/intel_extreme/pll.h     |  10 +-
     4 files changed, 324 insertions(+), 165 deletions(-)
    
    diff --git a/src/add-ons/accelerants/intel_extreme/Pipes.cpp b/src/add-ons/accelerants/intel_extreme/Pipes.cpp
    index 4f36f62..b5705ad 100644
    a b Pipe::ConfigureClocks(const pll_divisors& divisors, uint32 pixelClock,  
    233233    float refFreq = gInfo->shared_info->pll_info.reference_frequency / 1000.0f;
    234234
    235235    if (gInfo->shared_info->device_type.InGroup(INTEL_GROUP_96x)) {
    236         float adjusted = ((refFreq * divisors.m) / divisors.n)  / divisors.post;
     236        float adjusted = ((refFreq * divisors.m) / divisors.n)  / divisors.p;
    237237        uint32 pixelMultiply = uint32(adjusted  / (pixelClock / 1000.0f));
    238238        write32(pllMD, (0 << 24) | ((pixelMultiply - 1) << 8));
    239239    }
    Pipe::ConfigureClocks(const pll_divisors& divisors, uint32 pixelClock,  
    267267    uint32 pll = DISPLAY_PLL_ENABLED | DISPLAY_PLL_NO_VGA_CONTROL | extraFlags;
    268268
    269269    if (gInfo->shared_info->device_type.Generation() >= 3) {
    270         // post1 divisor << 1 , 1-8
     270        // p1 divisor << 1 , 1-8
    271271        if (gInfo->shared_info->device_type.InGroup(INTEL_GROUP_PIN)) {
    272             pll |= ((1 << (divisors.post1 - 1))
     272            pll |= ((1 << (divisors.p1 - 1))
    273273                    << DISPLAY_PLL_IGD_POST1_DIVISOR_SHIFT)
    274274                & DISPLAY_PLL_IGD_POST1_DIVISOR_MASK;
    275275        } else {
    276             pll |= ((1 << (divisors.post1 - 1))
     276            pll |= ((1 << (divisors.p1 - 1))
    277277                    << DISPLAY_PLL_POST1_DIVISOR_SHIFT)
    278278                & DISPLAY_PLL_9xx_POST1_DIVISOR_MASK;
    279         //  pll |= ((divisors.post1 - 1) << DISPLAY_PLL_POST1_DIVISOR_SHIFT)
     279        //  pll |= ((divisors.p1 - 1) << DISPLAY_PLL_POST1_DIVISOR_SHIFT)
    280280        //      & DISPLAY_PLL_9xx_POST1_DIVISOR_MASK;
    281281        }
    282282
    283         // p2 clock divider. 5 or 7 high
    284         if (divisors.post2_high)
     283        if (divisors.p2 == 5 || divisors.p2 == 7)
    285284            pll |= DISPLAY_PLL_DIVIDE_HIGH;
    286285
    287286        if (gInfo->shared_info->device_type.InGroup(INTEL_GROUP_96x))
    288287            pll |= 6 << DISPLAY_PLL_PULSE_PHASE_SHIFT;
    289288    } else {
    290         if (!divisors.post2_high)
     289        if (divisors.p2 != 5 && divisors.p2 != 7)
    291290            pll |= DISPLAY_PLL_DIVIDE_4X;
    292291
    293292        pll |= DISPLAY_PLL_2X_CLOCK;
    294293
    295294        // TODO: Is this supposed to be DISPLAY_PLL_IGD_POST1_DIVISOR_MASK??
    296         if (divisors.post1 > 2) {
    297             pll |= ((divisors.post1 - 2) << DISPLAY_PLL_POST1_DIVISOR_SHIFT)
     295        if (divisors.p1 > 2) {
     296            pll |= ((divisors.p1 - 2) << DISPLAY_PLL_POST1_DIVISOR_SHIFT)
    298297                & DISPLAY_PLL_POST1_DIVISOR_MASK;
    299298        } else
    300299            pll |= DISPLAY_PLL_POST1_DIVIDE_2;
  • src/add-ons/accelerants/intel_extreme/Ports.cpp

    diff --git a/src/add-ons/accelerants/intel_extreme/Ports.cpp b/src/add-ons/accelerants/intel_extreme/Ports.cpp
    index f5a5d45..4ea1c8c 100644
    a b LVDSPort::SetDisplayMode(display_mode* target, uint32 colorMode)  
    497497        dpll |= (1 << (divisors.post1 - 1))
    498498            << DISPLAY_PLL_POST1_DIVISOR_SHIFT;
    499499    }
    500     switch (divisors.post2) {
     500    switch (divisors.p2) {
    501501        case 5:
    502502        case 7:
    503503            dpll |= DISPLAY_PLL_DIVIDE_HIGH;
    LVDSPort::SetDisplayMode(display_mode* target, uint32 colorMode)  
    547547
    548548    // Set the B0-B3 data pairs corresponding to whether we're going to
    549549    // set the DPLLs for dual-channel mode or not.
    550     if (divisors.post2_high) {
     550    if (divisors.p2 == 5 || divisors.p2 == 7) {
    551551        TRACE("LVDS: dual channel\n");
    552552        lvds |= LVDS_B0B3_POWER_UP | LVDS_CLKB_POWER_UP;
    553553    } else {
  • src/add-ons/accelerants/intel_extreme/pll.cpp

    diff --git a/src/add-ons/accelerants/intel_extreme/pll.cpp b/src/add-ons/accelerants/intel_extreme/pll.cpp
    index f6126d7..f7ac865 100644
    a b  
    11/*
    2  * Copyright 2006-2015, Haiku, Inc. All Rights Reserved.
     2 * Copyright 2006-2016, Haiku, Inc. All Rights Reserved.
    33 * Distributed under the terms of the MIT License.
    44 *
    55 * Authors:
     
    3838#define CALLED(x...) TRACE("CALLED %s\n", __PRETTY_FUNCTION__)
    3939
    4040
    41 void
    42 get_pll_limits(pll_limits* limits, bool isLVDS)
    43 {
    44     // Note, the limits are taken from the X driver; they have not yet been
    45     // tested
    46 
    47     // TODO: Breakout BXT
    48 
    49     if (gInfo->shared_info->device_type.InGroup(INTEL_GROUP_CHV)) {
    50         pll_limits kLimits = {
    51             // p, p1, p2, high,   n,   m, m1, m2
    52             {  5,  2, 14, false,  1,  79, 2,  24 << 22},    // min
    53             { 80,  4,  1, true,   1, 127, 2,  175 << 22},   // max
    54             225000, 4800000, 6480000
    55         };
    56         memcpy(limits, &kLimits, sizeof(pll_limits));
    57     } else if (gInfo->shared_info->device_type.InGroup(INTEL_GROUP_VLV)) {
    58         pll_limits kLimits = {
    59             // p, p1, p2, high,   n,   m, m1, m2
    60             {  5,  2, 20, false,  1,  79, 2,  11},  // min
    61             { 80,  3,  2, true,   7, 127, 3,  156}, // max
    62             225000, 4000000, 6000000
    63         };
    64         memcpy(limits, &kLimits, sizeof(pll_limits));
    65     } else if (gInfo->shared_info->device_type.InFamily(INTEL_FAMILY_SER5)
    66         || gInfo->shared_info->device_type.InGroup(INTEL_GROUP_BXT)) {
    67         pll_limits kLimits = {
    68             // p, p1, p2, high,   n,   m, m1, m2
    69             {  5,  1, 10, false,  1,  79, 12,  5},  // min
    70             { 80,  8,  5, true,   5, 127, 22,  9},  // max
    71             225000, 1760000, 3510000
    72         };
    73         // TODO: validate these LVDS dividers!
    74         if (isLVDS) {
    75             kLimits.min.post = 7;
    76             kLimits.max.post = 98;
    77             kLimits.min.post2 = 14;
    78             kLimits.max.post2 = 7;
    79         }
    80         memcpy(limits, &kLimits, sizeof(pll_limits));
    81     } else if (gInfo->shared_info->device_type.InFamily(INTEL_FAMILY_9xx)) {
    82         pll_limits kLimits = {
    83             // p, p1, p2, high,   n,   m, m1, m2
    84             {  5,  1, 10, false,  1,  70, 8,  3},   // min
    85             { 80,  8,  5, true,   6, 120, 18, 7},   // max
    86             200000, 1400000, 2800000
    87         };
    88         if (isLVDS) {
    89             kLimits.min.post = 7;
    90             kLimits.max.post = 98;
    91             kLimits.min.post2 = 14;
    92             kLimits.max.post2 = 7;
    93         }
    94         memcpy(limits, &kLimits, sizeof(pll_limits));
    95     } else if (gInfo->shared_info->device_type.InGroup(INTEL_GROUP_G4x)) {
    96         pll_limits kLimits = {
    97             // p, p1, p2, high,   n,   m, m1, m2
    98             { 10,  1, 10, false,  1, 104, 17,  5},  // min
    99             { 30,  3, 10, true,   4, 138, 23, 11},  // max
    100             270000, 1750000, 3500000
    101         };
    102         // TODO: validate these LVDS dividers!
    103         if (isLVDS) {
    104             kLimits.min.post = 7;
    105             kLimits.max.post = 98;
    106             kLimits.min.post2 = 14;
    107             kLimits.max.post2 = 7;
    108         }
    109         memcpy(limits, &kLimits, sizeof(pll_limits));
    110     } else if (gInfo->shared_info->device_type.InGroup(INTEL_GROUP_PIN)) {
    111         // m1 is reserved and must be 0
    112         pll_limits kLimits = {
    113             // p, p1, p2, high,   n,   m, m1,  m2
    114             {  5,  1, 10, false,  3,   2,  0,   2}, // min
    115             { 80,  8,  5, true,   6, 256,  0, 254}, // max
    116             200000, 1700000, 3500000
    117         };
    118         if (isLVDS) {
    119             kLimits.min.post = 7;
    120             kLimits.max.post = 112;
    121             kLimits.min.post2 = 14;
    122             kLimits.max.post2 = 14;
    123         }
    124         memcpy(limits, &kLimits, sizeof(pll_limits));
    125     } else {
    126         static pll_limits kLimits = {
    127             // p, p1, p2, high,   n,   m, m1, m2
    128             {  4,  2,  4, false,  5,  96, 20,  8},
    129             {128, 33,  2, true,  18, 140, 28, 18},
    130             165000, 930000, 1400000
    131         };
    132         // TODO: Validate these LVDS dividers!
    133         if (isLVDS) {
    134             kLimits.min.post = 7;
    135             kLimits.max.post = 98;
    136             kLimits.min.post2 = 14;
    137             kLimits.max.post2 = 7;
    138         }
    139         memcpy(limits, &kLimits, sizeof(pll_limits));
    140     }
     41// Static pll limits taken from Linux kernel KMS
     42
     43static pll_limits kLimitsIlkDac = {
     44    // p, p1, p2, n,   m, m1, m2
     45    {  5,  2, 14, 1,  79, 12,  5}, // min
     46    { 80,  8, 14, 3, 118, 22,  9}, // max
     47    225000, 1760000, 3510000
     48};
     49
     50static pll_limits kLimitsIlkLvdsSingle = {
     51    // p, p1, p2, n,   m, m1, m2
     52    { 28,  2, 14, 1,  79, 12,  5}, // min
     53    {112,  8, 14, 3, 118, 22,  9}, // max
     54    225000, 1760000, 3510000
     55};
     56
     57static pll_limits kLimitsIlkLvdsDual = {
     58    // p, p1, p2, n,   m, m1, m2
     59    { 14,  2,  7, 1,  79, 12,  5}, // min
     60    { 56,  8,  7, 3, 127, 22,  9}, // max
     61    225000, 1760000, 3510000
     62};
     63
     64// 100Mhz RefClock
     65static pll_limits kLimitsIlkLvdsSingle100 = {
     66    // p, p1, p2, n,   m, m1, m2
     67    { 28,  2, 14, 1,  79, 12,  5}, // min
     68    {112,  8, 14, 2, 126, 22,  9}, // max
     69    225000, 1760000, 3510000
     70};
     71
     72static pll_limits kLimitsIlkLvdsDual100 = {
     73    // p, p1, p2, n,   m, m1, m2
     74    { 14,  2,  7, 1,  79, 12,  5}, // min
     75    { 42,  6,  7, 3, 126, 22,  9}, // max
     76    225000, 1760000, 3510000
     77};
     78
     79#if 0
     80static pll_limits kLimitsChv = {
     81    // p, p1, p2, n,   m, m1, m2
     82    {  0,  2, 14, 1,  79, 2,   24 << 22}, // min
     83    {  0,  4,  1, 1, 127, 2,  175 << 22}, // max
     84    0, 4800000, 6480000
     85};
     86
     87static pll_limits kLimitsVlv = {
     88    // p, p1, p2, n,   m, m1, m2
     89    {  0,  2, 20, 1,  79, 2,   11}, // min
     90    {  0,  3,  2, 7, 127, 3,  156}, // max
     91    0, 4000000, 6000000
     92};
     93
     94static pll_limits kLimitsBxt = {
     95    // p, p1, p2, n,  m, m1, m2
     96    {  0,  2,  1, 1,  0,  2,   2 << 22}, // min
     97    {  0,  4, 20, 1,  0,  2, 255 << 22}, // max
     98    0, 4800000, 6700000
     99};
     100#endif
    141101
    142     TRACE("PLL limits, min: p %" B_PRId32 " (p1 %" B_PRId32 ", "
    143         "p2 %" B_PRId32 "), n %" B_PRId32 ", m %" B_PRId32 " "
    144         "(m1 %" B_PRId32 ", m2 %" B_PRId32 ")\n", limits->min.post,
    145         limits->min.post1, limits->min.post2, limits->min.n, limits->min.m,
    146         limits->min.m1, limits->min.m2);
    147     TRACE("PLL limits, max: p %" B_PRId32 " (p1 %" B_PRId32 ", "
    148         "p2 %" B_PRId32 "), n %" B_PRId32 ", m %" B_PRId32 " "
    149         "(m1 %" B_PRId32 ", m2 %" B_PRId32 ")\n", limits->max.post,
    150         limits->max.post1, limits->max.post2, limits->max.n, limits->max.m,
    151         limits->max.m1, limits->max.m2);
    152 }
     102static pll_limits kLimits9xxSdvo = {
     103    // p, p1, p2,  n,   m, m1, m2
     104    {  5,  1, 10,  5,  70, 12,  7}, // min
     105    { 80,  8,  5, 10, 120, 22, 11}, // max
     106    200000, 1400000, 2800000
     107};
     108
     109static pll_limits kLimits9xxLvds = {
     110    // p, p1, p2,  n,   m, m1, m2
     111    {  7,  1, 14,  1,  70,  8,  3}, // min
     112    { 98,  8,  7,  6, 120, 18,  7}, // max
     113    112000, 1400000, 2800000
     114};
     115
     116static pll_limits kLimitsG4xSdvo = {
     117    // p, p1, p2, n,   m, m1, m2
     118    { 10,  1, 10, 1, 104, 17,  5},  // min
     119    { 30,  3, 10, 4, 138, 23, 11},  // max
     120    270000, 1750000, 3500000
     121};
     122
     123#if 0
     124static pll_limits kLimitsG4xHdmi = {
     125    // p, p1, p2, n,   m, m1, m2
     126    {  5,  1, 10, 1, 104, 16,  5},  // min
     127    { 80,  8,  5, 4, 138, 23, 11},  // max
     128    165000, 1750000, 3500000
     129};
     130#endif
     131
     132static pll_limits kLimitsG4xLvdsSingle = {
     133    // p,  p1, p2, n,   m, m1, m2
     134    { 28,   2, 14, 1, 104, 17,  5}, // min
     135    { 112,  8, 14, 3, 138, 23, 11}, // max
     136    0, 1750000, 3500000
     137};
     138
     139static pll_limits kLimitsG4xLvdsDual = {
     140    // p, p1, p2, n,   m, m1, m2
     141    { 14,  2,  7, 1, 104, 17,  5},  // min
     142    { 42,  6,  7, 3, 138, 23, 11},  // max
     143    0, 1750000, 3500000
     144};
     145
     146static pll_limits kLimitsPinSdvo = {
     147    // p, p1, p2, n,   m, m1,  m2
     148    {  5,  1, 10, 3,   2,  0,   0}, // min
     149    { 80,  8,  5, 6, 256,  0, 254}, // max
     150    200000, 1700000, 3500000
     151};
     152
     153static pll_limits kLimitsPinLvds = {
     154    // p, p1, p2, n,   m, m1,  m2
     155    {  7,  1, 14, 3,   2,  0,   0}, // min
     156    {112,  8, 14, 6, 256,  0, 254}, // max
     157    112000, 1700000, 3500000
     158};
     159
     160#if 0
     161static pll_limits kLimits = {
     162    // p, p1, p2,  n,   m, m1, m2
     163    {  4,  2,  4,  5,  96, 20,  8},
     164    {128, 33,  2, 18, 140, 28, 18},
     165    165000, 930000, 1400000
     166};
     167#endif
     168
     169
     170static bool
     171lvds_dual_link(display_mode* current)
     172{
     173    float requestedPixelClock = current->timing.pixel_clock / 1000.0f;
     174    if (requestedPixelClock > 112.999)
     175        return true;
    153176
     177    // TODO: Force dual link on MacBookPro6,2  MacBookPro8,2  MacBookPro9,1
    154178
     179    return ((read32(INTEL_DIGITAL_LVDS_PORT) & LVDS_CLKB_POWER_MASK)
     180        == LVDS_CLKB_POWER_UP);
     181}
     182   
    155183bool
    156184valid_pll_divisors(pll_divisors* divisors, pll_limits* limits)
    157185{
    158186    pll_info &info = gInfo->shared_info->pll_info;
    159187    uint32 vco = info.reference_frequency * divisors->m / divisors->n;
    160     uint32 frequency = vco / divisors->post;
     188    uint32 frequency = vco / divisors->p;
    161189
    162     if (divisors->post < limits->min.post || divisors->post > limits->max.post
     190    if (divisors->p < limits->min.p || divisors->p > limits->max.p
    163191        || divisors->m < limits->min.m || divisors->m > limits->max.m
    164192        || vco < limits->min_vco || vco > limits->max_vco
    165193        || frequency < info.min_frequency || frequency > info.max_frequency)
    valid_pll_divisors(pll_divisors* divisors, pll_limits* limits)  
    169197}
    170198
    171199
     200static void
     201compute_pll_p2(display_mode* current, pll_divisors* divisors,
     202    pll_limits* limits, bool isLVDS)
     203{
     204    if (isLVDS) {
     205        if (lvds_dual_link(current)) {
     206            // fast DAC timing via 2 channels (dual link LVDS)
     207            divisors->p2 = limits->max.p2;
     208        } else {
     209            // slow DAC timing
     210            divisors->p2 = limits->min.p2;
     211        }
     212    } else {
     213        if (current->timing.pixel_clock < limits->dot_limit) {
     214            // slow DAC timing
     215            divisors->p2 = limits->min.p2;
     216        } else {
     217            // fast DAC timing
     218            divisors->p2 = limits->max.p2;
     219        }
     220    }
     221}
     222
     223
    172224static uint32
    173225compute_pll_m(pll_divisors* divisors)
    174226{
    compute_pll_m(pll_divisors* divisors)  
    194246static uint32
    195247compute_pll_p(pll_divisors* divisors)
    196248{
    197     return divisors->post1 * divisors->post2;
     249    return divisors->p1 * divisors->p2;
    198250}
    199251
    200252
    201 void
    202 compute_pll_divisors(display_mode* current, pll_divisors* divisors,
    203     bool isLVDS)
     253static void
     254compute_dpll_g4x(display_mode* current, pll_divisors* divisors, bool isLVDS)
    204255{
    205256    float requestedPixelClock = current->timing.pixel_clock / 1000.0f;
    206257    float referenceClock
    207258        = gInfo->shared_info->pll_info.reference_frequency / 1000.0f;
    208     pll_limits limits;
    209     get_pll_limits(&limits, isLVDS);
    210259
    211260    TRACE("%s: required MHz: %g\n", __func__, requestedPixelClock);
    212261
    213     // Calculate p2
    214     if (isLVDS) {
    215         if (requestedPixelClock > 112.999
    216             || (read32(INTEL_DIGITAL_LVDS_PORT) & LVDS_CLKB_POWER_MASK)
    217                 == LVDS_CLKB_POWER_UP) {
    218             // fast DAC timing via 2 channels
    219             divisors->post2 = limits.max.post2;
    220             divisors->post2_high = limits.max.post2_high;
    221         } else {
    222             // slow DAC timing
    223             divisors->post2 = limits.min.post2;
    224             divisors->post2_high = limits.min.post2_high;
    225         }
     262    pll_limits limits;
     263    if (gInfo->shared_info->device_type.InGroup(INTEL_GROUP_G4x)) {
     264        // TODO: Single vs Double LVDS
     265        if (isLVDS) {
     266            if (lvds_dual_link(current))
     267                memcpy(&limits, &kLimitsG4xLvdsDual, sizeof(pll_limits));
     268            else
     269                memcpy(&limits, &kLimitsG4xLvdsSingle, sizeof(pll_limits));
     270        //} else if (type == INTEL_PORT_TYPE_HDMI) {
     271        //  memcpy(&limits, &kLimitsG4xHdmi, sizeof(pll_limits));
     272        } else
     273            memcpy(&limits, &kLimitsG4xSdvo, sizeof(pll_limits));
    226274    } else {
    227         if (current->timing.pixel_clock < limits.min_post2_frequency) {
    228             // slow DAC timing
    229             divisors->post2 = limits.min.post2;
    230             divisors->post2_high = limits.min.post2_high;
     275        if (isLVDS) {
     276            if (lvds_dual_link(current)) {
     277                if (referenceClock == 100.0)
     278                    memcpy(&limits, &kLimitsIlkLvdsDual100, sizeof(pll_limits));
     279                else
     280                    memcpy(&limits, &kLimitsIlkLvdsDual, sizeof(pll_limits));
     281            } else {
     282                if (referenceClock == 100.0) {
     283                    memcpy(&limits, &kLimitsIlkLvdsSingle100,
     284                        sizeof(pll_limits));
     285                } else {
     286                    memcpy(&limits, &kLimitsIlkLvdsSingle, sizeof(pll_limits));
     287                }
     288            }
    231289        } else {
    232             // fast DAC timing
    233             divisors->post2 = limits.max.post2;
    234             divisors->post2_high = limits.max.post2_high;
     290            memcpy(&limits, &kLimitsIlkDac, sizeof(pll_limits));
    235291        }
    236292    }
    237293
     294    compute_pll_p2(current, divisors, &limits, isLVDS);
     295
     296    TRACE("PLL limits, min: p %" B_PRId32 " (p1 %" B_PRId32 ", "
     297        "p2 %" B_PRId32 "), n %" B_PRId32 ", m %" B_PRId32 " "
     298        "(m1 %" B_PRId32 ", m2 %" B_PRId32 ")\n", limits.min.p,
     299        limits.min.p1, limits.min.p2, limits.min.n, limits.min.m,
     300        limits.min.m1, limits.min.m2);
     301    TRACE("PLL limits, max: p %" B_PRId32 " (p1 %" B_PRId32 ", "
     302        "p2 %" B_PRId32 "), n %" B_PRId32 ", m %" B_PRId32 " "
     303        "(m1 %" B_PRId32 ", m2 %" B_PRId32 ")\n", limits.max.p,
     304        limits.max.p1, limits.max.p2, limits.max.n, limits.max.m,
     305        limits.max.m1, limits.max.m2);
     306
    238307    float best = requestedPixelClock;
    239308    pll_divisors bestDivisors;
    240309
     310    uint32 maxn = limits.max.n;
     311    for (divisors->n = limits.min.n; divisors->n <= maxn; divisors->n++) {
     312        for (divisors->m1 = limits.max.m1; divisors->m1 >= limits.min.m1;
     313                divisors->m1--) {
     314            for (divisors->m2 = limits.max.m2; divisors->m2 >= limits.min.m2;
     315                    divisors->m2--) {
     316                for (divisors->p1 = limits.max.p1;
     317                        divisors->p1 >= limits.max.p1; divisors->p1--) {
     318                    divisors->m = compute_pll_m(divisors);
     319                    divisors->p = compute_pll_p(divisors);
     320
     321                    if (!valid_pll_divisors(divisors, &limits))
     322                        continue;
     323
     324                    float error = fabs(requestedPixelClock
     325                        - ((referenceClock * divisors->m) / divisors->n)
     326                        / divisors->p);
     327                    if (error < best) {
     328                        best = error;
     329                        bestDivisors = *divisors;
     330                        maxn = divisors->n;
     331
     332                        if (error == 0)
     333                            break;
     334                    }
     335                }
     336            }
     337        }
     338    }
     339    *divisors = bestDivisors;
     340    TRACE("%s: best MHz: %g (error: %g)\n", __func__,
     341        ((referenceClock * divisors->m) / divisors->n) / divisors->p,
     342        best);
     343}
     344
     345
     346static void
     347compute_dpll_9xx(display_mode* current, pll_divisors* divisors, bool isLVDS)
     348{
     349    float requestedPixelClock = current->timing.pixel_clock / 1000.0f;
     350    float referenceClock
     351        = gInfo->shared_info->pll_info.reference_frequency / 1000.0f;
     352
     353    TRACE("%s: required MHz: %g\n", __func__, requestedPixelClock);
     354
     355    pll_limits limits;
     356    if (gInfo->shared_info->device_type.InGroup(INTEL_GROUP_PIN)) {
     357        if (isLVDS)
     358            memcpy(&limits, &kLimitsPinLvds, sizeof(pll_limits));
     359        else
     360            memcpy(&limits, &kLimitsPinSdvo, sizeof(pll_limits));
     361    } else {
     362        if (isLVDS)
     363            memcpy(&limits, &kLimits9xxLvds, sizeof(pll_limits));
     364        else
     365            memcpy(&limits, &kLimits9xxSdvo, sizeof(pll_limits));
     366    }
     367
     368    compute_pll_p2(current, divisors, &limits, isLVDS);
     369
     370    TRACE("PLL limits, min: p %" B_PRId32 " (p1 %" B_PRId32 ", "
     371        "p2 %" B_PRId32 "), n %" B_PRId32 ", m %" B_PRId32 " "
     372        "(m1 %" B_PRId32 ", m2 %" B_PRId32 ")\n", limits.min.p,
     373        limits.min.p1, limits.min.p2, limits.min.n, limits.min.m,
     374        limits.min.m1, limits.min.m2);
     375    TRACE("PLL limits, max: p %" B_PRId32 " (p1 %" B_PRId32 ", "
     376        "p2 %" B_PRId32 "), n %" B_PRId32 ", m %" B_PRId32 " "
     377        "(m1 %" B_PRId32 ", m2 %" B_PRId32 ")\n", limits.max.p,
     378        limits.max.p1, limits.max.p2, limits.max.n, limits.max.m,
     379        limits.max.m1, limits.max.m2);
     380
    241381    bool is_pine = gInfo->shared_info->device_type.InGroup(INTEL_GROUP_PIN);
     382
     383    float best = requestedPixelClock;
     384    pll_divisors bestDivisors;
     385
    242386    for (divisors->m1 = limits.min.m1; divisors->m1 <= limits.max.m1;
    243387            divisors->m1++) {
    244388        for (divisors->m2 = limits.min.m2; divisors->m2 <= limits.max.m2
    245389                && ((divisors->m2 < divisors->m1) || is_pine); divisors->m2++) {
    246390            for (divisors->n = limits.min.n; divisors->n <= limits.max.n;
    247391                    divisors->n++) {
    248                 for (divisors->post1 = limits.min.post1;
    249                         divisors->post1 <= limits.max.post1; divisors->post1++) {
     392                for (divisors->p1 = limits.min.p1;
     393                        divisors->p1 <= limits.max.p1; divisors->p1++) {
    250394                    divisors->m = compute_pll_m(divisors);
    251                     divisors->post = compute_pll_p(divisors);
     395                    divisors->p = compute_pll_p(divisors);
    252396
    253397                    if (!valid_pll_divisors(divisors, &limits))
    254398                        continue;
    255399
    256400                    float error = fabs(requestedPixelClock
    257401                        - ((referenceClock * divisors->m) / divisors->n)
    258                         / divisors->post);
     402                        / divisors->p);
    259403                    if (error < best) {
    260404                        best = error;
    261405                        bestDivisors = *divisors;
    compute_pll_divisors(display_mode* current, pll_divisors* divisors,  
    270414
    271415    *divisors = bestDivisors;
    272416
    273     TRACE("%s: found: %g MHz, p = %" B_PRId32 " (p1 = %" B_PRId32 ", "
     417    TRACE("%s: best MHz: %g (error: %g)\n", __func__,
     418        ((referenceClock * divisors->m) / divisors->n) / divisors->p,
     419        best);
     420}
     421
     422
     423void
     424compute_pll_divisors(display_mode* current, pll_divisors* divisors, bool isLVDS)
     425{
     426    if (gInfo->shared_info->device_type.InGroup(INTEL_GROUP_G4x)
     427        || gInfo->shared_info->device_type.HasPlatformControlHub()) {
     428        compute_dpll_g4x(current, divisors, isLVDS);
     429    } else if (gInfo->shared_info->device_type.InGroup(INTEL_GROUP_CHV)) {
     430        // TODO: CherryView
     431    } else if (gInfo->shared_info->device_type.InGroup(INTEL_GROUP_VLV)) {
     432        // TODO: VallyView
     433    } else
     434        compute_dpll_9xx(current, divisors, isLVDS);
     435
     436    TRACE("%s: found: p = %" B_PRId32 " (p1 = %" B_PRId32 ", "
    274437        "p2 = %" B_PRId32 "), n = %" B_PRId32 ", m = %" B_PRId32 " "
    275438        "(m1 = %" B_PRId32 ", m2 = %" B_PRId32 ")\n", __func__,
    276         ((referenceClock * divisors->m) / divisors->n) / divisors->post,
    277         divisors->post, divisors->post1, divisors->post2, divisors->n,
     439        divisors->p, divisors->p1, divisors->p2, divisors->n,
    278440        divisors->m, divisors->m1, divisors->m2);
    279441}
  • src/add-ons/accelerants/intel_extreme/pll.h

    diff --git a/src/add-ons/accelerants/intel_extreme/pll.h b/src/add-ons/accelerants/intel_extreme/pll.h
    index bc243a5..88253f4 100644
    a b  
    1414
    1515
    1616struct pll_divisors {
    17     uint32  post;
    18     uint32  post1;
    19     uint32  post2;
    20     bool    post2_high;
     17    uint32  p;
     18    uint32  p1;
     19    uint32  p2;
    2120    uint32  n;
    2221    uint32  m;
    2322    uint32  m1;
    struct pll_divisors {  
    2726struct pll_limits {
    2827    pll_divisors    min;
    2928    pll_divisors    max;
    30     uint32          min_post2_frequency;
     29    uint32          dot_limit;
    3130    uint32          min_vco;
    3231    uint32          max_vco;
    3332};
    3433
    3534
    36 void get_pll_limits(pll_limits* limits, bool isLVDS);
    3735bool valid_pll_divisors(pll_divisors* divisors, pll_limits* limits);
    3836void compute_pll_divisors(display_mode* current, pll_divisors* divisors,
    3937    bool isLVDS);