coreboot/util/romcc/tests/linux_test5.c
<<
>>
Prefs
   1#include "linux_syscall.h"
   2#include "linux_console.h"
   3
   4inline int log2(int value)
   5{
   6        /* __builtin_bsr is a exactly equivalent to the x86 machine
   7         * instruction with the exception that it returns -1
   8         * when the value presented to it is zero.
   9         * Otherwise __builtin_bsr returns the zero based index of
  10         * the highest bit set.
  11         */
  12        return __builtin_bsr(value);
  13}
  14
  15
  16static int smbus_read_byte(unsigned device, unsigned address)
  17{
  18        static const unsigned char dimm[] = {
  190x80, 0x08, 0x07, 0x0d, 0x0a, 0x02, 0x48, 0x00, 0x04, 0x60, 0x70, 0x02, 0x82, 0x08, 0x08, 0x01,
  200x0e, 0x04, 0x0c, 0x01, 0x02, 0x20, 0x00, 0x75, 0x70, 0x00, 0x00, 0x48, 0x30, 0x48, 0x2a, 0x40,
  210x80, 0x80, 0x45, 0x45, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  220x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x33,
  230xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
  240xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
  250xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
  260xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
  270xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
  280xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
  290xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
  300xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
  310xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
  320xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
  330xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
  340xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
  35
  360x80, 0x08, 0x07, 0x0d, 0x0a, 0x02, 0x48, 0x00, 0x04, 0x60, 0x70, 0x02, 0x82, 0x08, 0x08, 0x01,
  370x0e, 0x04, 0x0c, 0x01, 0x02, 0x20, 0x00, 0x75, 0x70, 0x00, 0x00, 0x48, 0x30, 0x48, 0x2a, 0x40,
  380x80, 0x80, 0x45, 0x45, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  390x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x33,
  400xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
  410xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
  420xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
  430xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
  440xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
  450xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
  460xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
  470xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
  480xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
  490xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
  500xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
  510xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
  52        };
  53        return dimm[(device << 8) + address];
  54}
  55
  56#define SMBUS_MEM_DEVICE_START 0x00
  57#define SMBUS_MEM_DEVICE_END   0x01
  58#define SMBUS_MEM_DEVICE_INC   1
  59
  60/* Function 2 */
  61#define DRAM_CONFIG_HIGH   0x94
  62#define  DCH_MEMCLK_SHIFT  20
  63#define  DCH_MEMCLK_MASK   7
  64#define  DCH_MEMCLK_100MHZ 0
  65#define  DCH_MEMCLK_133MHZ 2
  66#define  DCH_MEMCLK_166MHZ 5
  67#define  DCH_MEMCLK_200MHZ 7
  68
  69/* Function 3 */
  70#define NORTHBRIDGE_CAP    0xE8
  71#define  NBCAP_128Bit         0x0001
  72#define  NBCAP_MP             0x0002
  73#define  NBCAP_BIG_MP         0x0004
  74#define  NBCAP_ECC            0x0004
  75#define  NBCAP_CHIPKILL_ECC   0x0010
  76#define  NBCAP_MEMCLK_SHIFT   5
  77#define  NBCAP_MEMCLK_MASK    3
  78#define  NBCAP_MEMCLK_100MHZ  3
  79#define  NBCAP_MEMCLK_133MHZ  2
  80#define  NBCAP_MEMCLK_166MHZ  1
  81#define  NBCAP_MEMCLK_200MHZ  0
  82#define  NBCAP_MEMCTRL        0x0100
  83
  84typedef unsigned char uint8_t;
  85typedef unsigned int uint32_t;
  86
  87static unsigned spd_to_dimm(unsigned device)
  88{
  89        return (device - SMBUS_MEM_DEVICE_START);
  90}
  91
  92static void disable_dimm(unsigned index)
  93{
  94        print_debug("disabling dimm");
  95        print_debug_hex8(index);
  96        print_debug("\r\n");
  97#if 0
  98        pci_write_config32(PCI_DEV(0, 0x18, 2), DRAM_CSBASE + (((index << 1)+0)<<2), 0);
  99        pci_write_config32(PCI_DEV(0, 0x18, 2), DRAM_CSBASE + (((index << 1)+1)<<2), 0);
 100#endif
 101}
 102
 103
 104struct mem_param {
 105        uint8_t cycle_time;
 106        uint32_t dch_memclk;
 107};
 108
 109static const struct mem_param *get_mem_param(unsigned min_cycle_time)
 110{
 111        static const struct mem_param speed[] = {
 112                {
 113                        .cycle_time = 0xa0,
 114                        .dch_memclk = DCH_MEMCLK_100MHZ << DCH_MEMCLK_SHIFT,
 115                },
 116                {
 117                        .cycle_time = 0x75,
 118                        .dch_memclk = DCH_MEMCLK_133MHZ << DCH_MEMCLK_SHIFT,
 119                },
 120                {
 121                        .cycle_time = 0x60,
 122                        .dch_memclk = DCH_MEMCLK_166MHZ << DCH_MEMCLK_SHIFT,
 123                },
 124                {
 125                        .cycle_time = 0x50,
 126                        .dch_memclk = DCH_MEMCLK_200MHZ << DCH_MEMCLK_SHIFT,
 127                },
 128                {
 129                        .cycle_time = 0x00,
 130                },
 131        };
 132        const struct mem_param *param;
 133        for(param = &speed[0]; param->cycle_time ; param++) {
 134                if (min_cycle_time > (param+1)->cycle_time) {
 135                        break;
 136                }
 137        }
 138        if (!param->cycle_time) {
 139                die("min_cycle_time to low");
 140        }
 141        return param;
 142}
 143
 144#if 1
 145static void debug(int c)
 146{
 147        print_debug_char(c);
 148        print_debug_char('\r');
 149        print_debug_char('\n');
 150}
 151#endif
 152static const struct mem_param *spd_set_memclk(void)
 153{
 154        /* Compute the minimum cycle time for these dimms */
 155        const struct mem_param *param;
 156        unsigned min_cycle_time, min_latency;
 157        unsigned device;
 158        uint32_t value;
 159
 160        static const int latency_indicies[] = { 26, 23, 9 };
 161        static const unsigned char min_cycle_times[] = {
 162                [NBCAP_MEMCLK_200MHZ] = 0x50, /* 5ns */
 163                [NBCAP_MEMCLK_166MHZ] = 0x60, /* 6ns */
 164                [NBCAP_MEMCLK_133MHZ] = 0x75, /* 7.5ns */
 165                [NBCAP_MEMCLK_100MHZ] = 0xa0, /* 10ns */
 166        };
 167
 168
 169#if 0
 170        value = pci_read_config32(PCI_DEV(0, 0x18, 3), NORTHBRIDGE_CAP);
 171#else
 172        value = 0x50;
 173#endif
 174        min_cycle_time = min_cycle_times[(value >> NBCAP_MEMCLK_SHIFT) & NBCAP_MEMCLK_MASK];
 175        min_latency = 2;
 176
 177#if 1
 178        print_debug("min_cycle_time: ");
 179        print_debug_hex8(min_cycle_time);
 180        print_debug(" min_latency: ");
 181        print_debug_hex8(min_latency);
 182        print_debug("\r\n");
 183#endif
 184
 185        /* Compute the least latency with the fastest clock supported
 186         * by both the memory controller and the dimms.
 187         */
 188        for(device = SMBUS_MEM_DEVICE_START;
 189                device <= SMBUS_MEM_DEVICE_END;
 190                device += SMBUS_MEM_DEVICE_INC)
 191        {
 192                int new_cycle_time, new_latency;
 193                int index;
 194                int latencies;
 195                int latency;
 196
 197                debug('A');
 198                /* First find the supported CAS latencies
 199                 * Byte 18 for DDR SDRAM is interpreted:
 200                 * bit 0 == CAS Latency = 1.0
 201                 * bit 1 == CAS Latency = 1.5
 202                 * bit 2 == CAS Latency = 2.0
 203                 * bit 3 == CAS Latency = 2.5
 204                 * bit 4 == CAS Latency = 3.0
 205                 * bit 5 == CAS Latency = 3.5
 206                 * bit 6 == TBD
 207                 * bit 7 == TBD
 208                 */
 209                new_cycle_time = 0xa0;
 210                new_latency = 5;
 211
 212                latencies = smbus_read_byte(device, 18);
 213                if (latencies <= 0) continue;
 214
 215                debug('B');
 216                /* Compute the lowest cas latency supported */
 217                latency = log2(latencies) -2;
 218
 219                /* Loop through and find a fast clock with a low latency */
 220                for(index = 0; index < 3; index++, latency++) {
 221                        int value;
 222                        debug('C');
 223                        if ((latency < 2) || (latency > 4) ||
 224                                (!(latencies & (1 << latency)))) {
 225                                continue;
 226                        }
 227                        debug('D');
 228                        value = smbus_read_byte(device, latency_indicies[index]);
 229                        if (value < 0) continue;
 230
 231                        debug('E');
 232                        /* Only increase the latency if we decreas the clock */
 233                        if ((value >= min_cycle_time) && (value < new_cycle_time)) {
 234                                new_cycle_time = value;
 235                                new_latency = latency;
 236#if 1
 237                                print_debug("device: ");
 238                                print_debug_hex8(device);
 239                                print_debug(" new_cycle_time: ");
 240                                print_debug_hex8(new_cycle_time);
 241                                print_debug(" new_latency: ");
 242                                print_debug_hex8(new_latency);
 243                                print_debug("\r\n");
 244#endif
 245                        }
 246                        debug('G');
 247                }
 248                debug('H');
 249#if 1
 250                print_debug("device: ");
 251                print_debug_hex8(device);
 252                print_debug(" new_cycle_time: ");
 253                print_debug_hex8(new_cycle_time);
 254                print_debug(" new_latency: ");
 255                print_debug_hex8(new_latency);
 256                print_debug("\r\n");
 257#endif
 258                if (new_latency > 4){
 259                        continue;
 260                }
 261                debug('I');
 262                /* Does min_latency need to be increased? */
 263                if (new_cycle_time > min_cycle_time) {
 264                        min_cycle_time = new_cycle_time;
 265                }
 266                /* Does min_cycle_time need to be increased? */
 267                if (new_latency > min_latency) {
 268                        min_latency = new_latency;
 269                }
 270#if 1
 271                print_debug("device: ");
 272                print_debug_hex8(device);
 273                print_debug(" min_cycle_time: ");
 274                print_debug_hex8(min_cycle_time);
 275                print_debug(" min_latency: ");
 276                print_debug_hex8(min_latency);
 277                print_debug("\r\n");
 278#endif
 279        }
 280        /* Make a second pass through the dimms and disable
 281         * any that cannot support the selected memclk and cas latency.
 282         */
 283        for(device = SMBUS_MEM_DEVICE_START;
 284                device <= SMBUS_MEM_DEVICE_END;
 285                device += SMBUS_MEM_DEVICE_INC)
 286        {
 287                int latencies;
 288                int latency;
 289                int index;
 290                int value;
 291                int dimm;
 292                latencies = smbus_read_byte(device, 18);
 293                if (latencies <= 0) {
 294                        goto dimm_err;
 295                }
 296
 297                /* Compute the lowest cas latency supported */
 298                latency = log2(latencies) -2;
 299
 300                /* Walk through searching for the selected latency */
 301                for(index = 0; index < 3; index++, latency++) {
 302                        if (!(latencies & (1 << latency))) {
 303                                continue;
 304                        }
 305                        if (latency == min_latency)
 306                                break;
 307                }
 308                /* If I can't find the latency or my index is bad error */
 309                if ((latency != min_latency) || (index >= 3)) {
 310                        goto dimm_err;
 311                }
 312
 313                /* Read the min_cycle_time for this latency */
 314                value = smbus_read_byte(device, latency_indicies[index]);
 315
 316                /* All is good if the selected clock speed
 317                 * is what I need or slower.
 318                 */
 319                if (value <= min_cycle_time) {
 320                        continue;
 321                }
 322                /* Otherwise I have an error, disable the dimm */
 323        dimm_err:
 324                disable_dimm(spd_to_dimm(device));
 325        }
 326#if 1
 327        print_debug("min_cycle_time: ");
 328        print_debug_hex8(min_cycle_time);
 329        print_debug(" min_latency: ");
 330        print_debug_hex8(min_latency);
 331        print_debug("\r\n");
 332#endif
 333        /* Now that I know the minimum cycle time lookup the memory parameters */
 334        param = get_mem_param(min_cycle_time);
 335
 336#if 0
 337        /* Update DRAM Config High with our selected memory speed */
 338        value = pci_read_config32(PCI_DEV(0, 0x18, 2), DRAM_CONFIG_HIGH);
 339        value &= ~(DCH_MEMCLK_MASK << DCH_MEMCLK_SHIFT);
 340        value |= param->dch_memclk;
 341        pci_write_config32(PCI_DEV(0, 0x18, 2), DRAM_CONFIG_HIGH, value);
 342
 343        static const unsigned latencies[] = { 1, 5, 2 };
 344        /* Update DRAM Timing Low wiht our selected cas latency */
 345        value = pci_read_config32(PCI_DEV(0, 0x18, 2), DRAM_CONFIG_LOW);
 346        value &= ~7;
 347        value |= latencies[min_latency - 2];
 348        pci_write_config32(PCI_DEV(0, 0x18, 2), DRAM_CONFIG_LOW, value);
 349#endif
 350
 351        return param;
 352}
 353
 354static void main(void)
 355{
 356        const struct mem_param *param;
 357        param = spd_set_memclk();
 358        _exit(0);
 359}
 360
lxr.linux.no kindly hosted by Redpill Linpro AS, provider of Linux consulting and operations services since 1995.