Changeset 5194


Ignore:
Timestamp:
Mar 6, 2010, 7:16:25 PM (5 years ago)
Author:
uwe
Message:

440BX: Do not hardcode DIMM number + size anymore.

The code currently assumes a 4-DIMM-slots board, this will be fixed soon.

Signed-off-by: Keith Hui <buurin@…>
Acked-by: Uwe Hermann <uwe@…>

Location:
trunk/src/northbridge/intel/i440bx
Files:
2 edited

Legend:

Unmodified
Added
Removed
  • trunk/src/northbridge/intel/i440bx/i440bx.h

    r3052 r5194  
    3333 * Reserved or Intel Reserved and should not be touched.
    3434 */
     35
    3536#define NBXCFG  0x50 /* 440BX Configuration (0x0000:00S0_0000_000S_0S00b). */
    3637#define DRAMC   0x57 /* DRAM Control (00S0_0000b). */
    3738#define DRAMT   0x58 /* DRAM Timing (0x03). */
    3839#define PAM     0x59 /* Programmable Attribute Map, 7 registers (0x00). */
     40#define PAM0    0x59
     41#define PAM1    0x5a
     42#define PAM2    0x5b
     43#define PAM3    0x5c
     44#define PAM4    0x5d
     45#define PAM5    0x5e
     46#define PAM6    0x5f
    3947#define DRB     0x60 /* DRAM Row Boundary, 8 registers (0x01). */
     48#define DRB0    0x60
     49#define DRB1    0x61
     50#define DRB2    0x62
     51#define DRB3    0x63
     52#define DRB4    0x64
     53#define DRB5    0x65
     54#define DRB6    0x66
     55#define DRB7    0x67
    4056#define FDHC    0x68 /* Fixed SDRAM Hole Control (0x00). */
    4157#define MBSC    0x69 /* Memory Buffer Strength Control (0x0000-0000-0000). */
     
    5167#define ERRSTS  0x91 /* Error Status (0x0000). */
    5268// TODO: AGP stuff.
     69#define ACAPID  0xa0 /* AGP Capability Identifier (0x00100002 or 0x00000000) */
     70#define AGPSTAT 0xa4 /* AGP Status Register (0x1f000203, read only) */
     71#define AGPCMD  0xa8 /* AGP Command Register (0x00000000) */
     72#define AGPCTRL 0xb0 /* AGP Control Register (0x00000000) */
     73#define APSIZE  0xb4 /* Aperture Size Control Register (0x00) */
     74#define ATTBASE 0xb8 /* Aperture Translation Table (0x00000000) */
     75 
    5376#define MBFS    0xca /* Memory Buffer Frequency Select (0x000000). */
    5477#define BSPAD   0xd0 /* BIOS Scratch Pad (0x000..000). */
     78#define BSPAD0  0xd0 /* These are free for our use. */
     79#define BSPAD1  0xd1
     80#define BSPAD2  0xd2
     81#define BSPAD3  0xd3
     82#define BSPAD4  0xd4
     83#define BSPAD5  0xd5
     84#define BSPAD6  0xd6
     85#define BSPAD7  0xd7
    5586#define DWTC    0xe0 /* DRAM Write Thermal Throttling Control (0x000..000). */
    5687#define DRTC    0xe8 /* DRAM Read Thermal Throttling Control (0x000..000). */
    5788#define BUFFC   0xf0 /* Buffer Control Register (0x0000). */
    5889
    59 /* For convenience: */
    60 #define DRB0    0x60
    61 #define DRB1    0x61
    62 #define DRB2    0x62
    63 #define DRB3    0x63
    64 #define DRB4    0x64
    65 #define DRB5    0x65
    66 #define DRB6    0x66
    67 #define DRB7    0x67
    68 
    69 #define PAM0    0x59
    70 #define PAM1    0x5a
    71 #define PAM2    0x5b
    72 #define PAM3    0x5c
    73 #define PAM4    0x5d
    74 #define PAM5    0x5e
    75 #define PAM6    0x5f
    76 
  • trunk/src/northbridge/intel/i440bx/raminit.c

    r5185 r5194  
    33 *
    44 * Copyright (C) 2007-2008 Uwe Hermann <uwe@hermann-uwe.de>
     5 * Copyright (C) 2010 Keith Hui <buurin@gmail.com>
    56 *
    67 * This program is free software; you can redistribute it and/or modify
     
    2425#include <stdlib.h>
    2526#include "i440bx.h"
     27#include "raminit.h"
    2628
    2729/*-----------------------------------------------------------------------------
     
    186188         * 11 = Read/Write (all access goes to DRAM)
    187189         */
    188         // TODO
    189         PAM0, 0x00, 0x00,
    190         PAM1, 0x00, 0x00,
    191         PAM2, 0x00, 0x00,
    192         PAM3, 0x00, 0x00,
    193         PAM4, 0x00, 0x00,
    194         PAM5, 0x00, 0x00,
    195         PAM6, 0x00, 0x00,
     190
     191        /*
     192         * Map all legacy regions to RAM (read/write). This is required if
     193         * you want to use the RAM area from 768 KB - 1 MB. If the PAM
     194         * registers are not set here appropriately, the RAM in that region
     195         * will not be accessible, thus a RAM check of it will also fail.
     196         *
     197         * TODO: This was set in sdram_set_spd_registers().
     198         * Test if it still works when set here.
     199         */
     200        PAM0, 0x00, 0x30,
     201        PAM1, 0x00, 0x33,
     202        PAM2, 0x00, 0x33,
     203        PAM3, 0x00, 0x33,
     204        PAM4, 0x00, 0x33,
     205        PAM5, 0x00, 0x33,
     206        PAM6, 0x00, 0x33,
    196207
    197208        /* DRB[0:7] - DRAM Row Boundary Registers
     
    341352        // PMCR, 0x00, 0x10,
    342353        PMCR, 0x00, 0x00,
     354
     355        /* Enable SCRR.SRRAEN and let BX choose the SRR. */
     356        SCRR + 1, 0x00, 0x10,
    343357};
    344358
     
    375389        dimm_start = 0;
    376390        for (i = 0; i < (DIMM_SOCKETS * 2); i++) {
    377                 addr_offset = 0;
    378                 caslatency = 3; /* TODO: Dynamically get CAS latency later. */
     391                addr_offset = 0;
     392                caslatency = 3; /* TODO: Dynamically get CAS latency later. */
    379393                if (command == RAM_COMMAND_MRS) {
    380394                        /*
     
    412426}
    413427
     428static void set_dram_buffer_strength(void)
     429{
     430        /* TODO: This needs to be set according to the DRAM tech
     431         * (x8, x16, or x32). Argh, Intel provides no docs on this!
     432         * Currently, it needs to be pulled from the output of
     433         * lspci -xxx Rx92
     434         *
     435         * Relevant registers: MBSC, MBFS, BUFFC.
     436         */
     437
     438        pci_write_config8(NB, MBSC, 0x03);
     439}
     440
    414441/*-----------------------------------------------------------------------------
    415442DIMM-independant configuration functions.
     
    459486                reg |= register_values[i + 2] & ~(register_values[i + 1]);
    460487                pci_write_config8(NB, register_values[i], reg);
    461 
     488#if 0
    462489                PRINT_DEBUG("    Set register 0x");
    463490                PRINT_DEBUG_HEX8(register_values[i]);
     
    465492                PRINT_DEBUG_HEX8(reg);
    466493                PRINT_DEBUG("\r\n");
     494#endif
    467495        }
    468496}
    469497
     498struct dimm_size {
     499        unsigned long side1;
     500        unsigned long side2;
     501};
     502
     503static struct dimm_size spd_get_dimm_size(unsigned int device)
     504{
     505        struct dimm_size sz;
     506        int i, module_density, dimm_banks;
     507        sz.side1 = 0;
     508        module_density = spd_read_byte(device, SPD_DENSITY_OF_EACH_ROW_ON_MODULE);
     509        dimm_banks = spd_read_byte(device, SPD_NUM_DIMM_BANKS);
     510
     511        /* Find the size of side1. */
     512        /* Find the larger value. The larger value is always side1. */
     513        for (i = 512; i >= 0; i >>= 1) {
     514                if ((module_density & i) == i) {
     515                        sz.side1 = i;
     516                        break;
     517                }
     518        }
     519
     520        /* Set to 0 in case it's single sided. */
     521        sz.side2 = 0;
     522
     523        /* Test if it's a dual-sided DIMM. */
     524        if (dimm_banks > 1) {
     525                /* Test if there's a second value. If so it's asymmetrical. */
     526                if (module_density != i) {
     527                        /*
     528                         * Find second value, picking up where we left off.
     529                         * i >>= 1 done initially to make sure we don't get
     530                         * the same value again.
     531                         */
     532                        for (i >>= 1; i >= 0; i >>= 1) {
     533                                if (module_density == (sz.side1 | i)) {
     534                                        sz.side2 = i;
     535                                        break;
     536                                }
     537                        }
     538                        /* If not, it's symmetrical. */
     539                } else {
     540                        sz.side2 = sz.side1;
     541                }
     542        }
     543
     544        /*
     545         * SPD byte 31 is the memory size divided by 4 so we
     546         * need to muliply by 4 to get the total size.
     547         */
     548        sz.side1 *= 4;
     549        sz.side2 *= 4;
     550
     551        return sz;
     552}
     553/*
     554 * Sets DRAM attributes one DIMM at a time, based on SPD data.
     555 * Northbridge settings that are set: NBXCFG[31:24], DRB0-DRB7, RPS, DRAMC.
     556 */
     557static void set_dram_row_attributes(void)
     558{
     559        int i, dra, drb, col, width, value, rps, edosd, ecc, nbxecc;
     560        u8 bpr; /* Top 8 bits of PGPOL */
     561
     562        edosd = 0;
     563        rps = 0;
     564        drb = 0;
     565        bpr = 0;
     566        nbxecc = 0xff;
     567
     568        for (i = 0; i < DIMM_SOCKETS; i++) {
     569                unsigned int device;
     570                device = DIMM_SPD_BASE + i;
     571                bpr >>= 2;
     572
     573                /* First check if a DIMM is actually present. */
     574                value = spd_read_byte(device, SPD_MEMORY_TYPE);
     575                /* This is 440BX! We do EDO too! */
     576                if (value == SPD_MEMORY_TYPE_EDO
     577                        || value == SPD_MEMORY_TYPE_SDRAM) {
     578
     579                        PRINT_DEBUG("Found ");
     580                        if (value == SPD_MEMORY_TYPE_EDO) {
     581                                edosd |= 0x02;
     582                        } else if (value == SPD_MEMORY_TYPE_SDRAM) {
     583                                edosd |= 0x04;
     584                        }
     585                        PRINT_DEBUG("DIMM in slot ");
     586                        PRINT_DEBUG_HEX8(i);
     587                        PRINT_DEBUG("\r\n");
     588
     589                        if (edosd == 0x06) {
     590                                print_err("Mixing EDO/SDRAM unsupported!\r\n");
     591                                die("HALT\r\n");
     592                        }
     593
     594                        /* "DRA" is our RPS for the two rows on this DIMM. */
     595                        dra = 0;
     596
     597                        /* Columns */
     598                        col = spd_read_byte(device, SPD_NUM_COLUMNS);
     599
     600                        /*
     601                         * Is this an ECC DIMM? Actually will be a 2 if so.
     602                         * TODO: Other register than NBXCFG also needs this
     603                         * ECC information.
     604                         */
     605                        ecc = spd_read_byte(device, SPD_DIMM_CONFIG_TYPE);
     606
     607                        /* Data width */
     608                        width = spd_read_byte(device, SPD_MODULE_DATA_WIDTH_LSB);
     609                       
     610                        /* Exclude error checking data width from page size calculations */
     611                        if (ecc) {
     612                                value = spd_read_byte(device,
     613                                        SPD_ERROR_CHECKING_SDRAM_WIDTH);
     614                                width -= value;
     615                                /* ### ECC */
     616                                /* Clear top 2 bits to help set up NBXCFG. */
     617                                ecc &= 0x3f;
     618                        } else {
     619                                /* Without ECC, top 2 bits should be 11. */
     620                                ecc |= 0xc0;
     621                        }
     622
     623                        /* Calculate page size in bits. */
     624                        value = ((1 << col) * width);
     625
     626                        /* Convert to KB. */
     627                        dra = (value >> 13);
     628
     629                        /* Number of banks of DIMM (single or double sided). */
     630                        value = spd_read_byte(device, SPD_NUM_DIMM_BANKS);
     631
     632                        /* Once we have dra, col is done and can be reused.
     633                         * So it's reused for number of banks.
     634                         */
     635                        col = spd_read_byte(device, SPD_NUM_BANKS_PER_SDRAM);
     636
     637                        if (value == 1) {
     638                                /*
     639                                 * Second bank of 1-bank DIMMs "doesn't have
     640                                 * ECC" - or anything.
     641                                 */
     642                                ecc |= 0x80;
     643                                if (dra == 2) {
     644                                        dra = 0x0; /* 2KB */
     645                                } else if (dra == 4) {
     646                                        dra = 0x1; /* 4KB */
     647                                } else if (dra == 8) {
     648                                        dra = 0x2; /* 8KB */
     649                                } else {
     650                                        dra = -1;
     651                                }
     652                                /*
     653                                 * Sets a flag in PGPOL[BPR] if this DIMM has
     654                                 * 4 banks per row.
     655                                 */
     656                                if (col == 4)
     657                                        bpr |= 0x40;
     658                        } else if (value == 2) {
     659                                if (dra == 2) {
     660                                        dra = 0x0; /* 2KB */
     661                                } else if (dra == 4) {
     662                                        dra = 0x05; /* 4KB */
     663                                } else if (dra == 8) {
     664                                        dra = 0x0a; /* 8KB */
     665                                } else {
     666                                        dra = -1;
     667                                }
     668                                /* Ditto */
     669                                if (col == 4)
     670                                        bpr |= 0xc0;
     671                        } else {
     672                                print_err("# of banks of DIMM unsupported!\r\n");
     673                                die("HALT\r\n");
     674                        }
     675                        if (dra == -1) {
     676                                print_err("Page size not supported\r\n");
     677                                die("HALT\r\n");
     678                        }
     679
     680                        /*
     681                         * 440BX supports asymmetrical dual-sided DIMMs,
     682                         * but can't handle DIMMs smaller than 8MB per
     683                         * side or larger than 128MB per side.
     684                         */
     685                        struct dimm_size sz = spd_get_dimm_size(device);
     686                        if ((sz.side1 < 8)) {
     687                                print_err("DIMMs smaller than 8MB per side\r\n"
     688                                          "are not supported on this NB.\r\n");
     689                                die("HALT\r\n");
     690                        }
     691                        if ((sz.side1 > 128)) {
     692                                print_err ("DIMMs > 128MB per side\r\n"
     693                                           "are not supported on this NB\r\n");
     694                                die("HALT\r\n");
     695                        }
     696
     697                        /* Divide size by 8 to set up the DRB registers. */
     698                        drb += (sz.side1 / 8);
     699
     700                        /*
     701                         * Build the DRB for the next row in MSB so it gets
     702                         * placed in DRB[n+1] where it belongs when written
     703                         * as a 16-bit word.
     704                         */
     705                        drb &= 0xff;
     706                        drb |= (drb + (sz.side2 / 8)) << 8;
     707                } else {
     708#if 0
     709                        PRINT_DEBUG("No DIMM found in slot ");
     710                        PRINT_DEBUG_HEX8(i);
     711                        PRINT_DEBUG("\r\n");
     712#endif
     713
     714                        /* If there's no DIMM in the slot, set dra to 0x00. */
     715                        dra = 0x00;
     716                        ecc = 0xc0;
     717                        /* Still have to propagate DRB over. */
     718                        drb &= 0xff;
     719                        drb |= (drb << 8);
     720                }
     721
     722                pci_write_config16(NB, DRB + (2 * i), drb);
     723#if 0
     724                PRINT_DEBUG("DRB has been set to 0x");
     725                PRINT_DEBUG_HEX16(drb);
     726                PRINT_DEBUG("\r\n");
     727#endif
     728
     729                /* Brings the upper DRB back down to be base for
     730                 * DRB calculations for the next two rows.
     731                 */
     732                drb >>= 8;
     733
     734                rps |= (dra & 0x0f) << (i * 4);
     735                nbxecc = (nbxecc >> 2) | (ecc & 0xc0);
     736        }
     737
     738        /* Set paging policy register. */
     739        pci_write_config8(NB, PGPOL + 1, bpr);
     740        PRINT_DEBUG("PGPOL[BPR] has been set to 0x");
     741        PRINT_DEBUG_HEX8(bpr);
     742        PRINT_DEBUG("\r\n");
     743
     744        /* Set DRAM row page size register. */
     745        pci_write_config16(NB, RPS, rps);
     746        PRINT_DEBUG("RPS has been set to 0x");
     747        PRINT_DEBUG_HEX16(rps);
     748        PRINT_DEBUG("\r\n");
     749
     750        /* ### ECC */
     751        pci_write_config8(NB, NBXCFG + 3, nbxecc);
     752        PRINT_DEBUG("NBXECC[31:24] has been set to 0x");
     753        PRINT_DEBUG_HEX8(nbxecc);
     754        PRINT_DEBUG("\r\n");
     755
     756        /* Set DRAMC[4:3] to proper memory type (EDO/SDRAM).
     757         * TODO: Registered SDRAM support.
     758         */
     759        edosd &= 0x07;
     760        if (edosd & 0x02) {
     761                edosd |= 0x00;
     762        } else if (edosd & 0x04) {
     763                edosd |= 0x08;
     764        }
     765        edosd &= 0x18;
     766
     767        /* edosd is now in the form needed for DRAMC[4:3]. */
     768        value = pci_read_config8(NB, DRAMC) & 0xe7;
     769        value |= edosd;
     770        pci_write_config8(NB, DRAMC, value);
     771        PRINT_DEBUG("DRAMC has been set to 0x");
     772        PRINT_DEBUG_HEX8(value);
     773        PRINT_DEBUG("\r\n");
     774}
     775
    470776static void sdram_set_spd_registers(void)
    471777{
    472         /* TODO: Don't hardcode the values here, get info via SPD. */
    473 
    474         /* Map all legacy regions to RAM (read/write). This is required if
    475          * you want to use the RAM area from 768 KB - 1 MB. If the PAM
    476          * registers are not set here appropriately, the RAM in that region
    477          * will not be accessible, thus a RAM check of it will also fail.
    478          */
    479         pci_write_config8(NB, PAM0, 0x30);
    480         pci_write_config8(NB, PAM1, 0x33);
    481         pci_write_config8(NB, PAM2, 0x33);
    482         pci_write_config8(NB, PAM3, 0x33);
    483         pci_write_config8(NB, PAM4, 0x33);
    484         pci_write_config8(NB, PAM5, 0x33);
    485         pci_write_config8(NB, PAM6, 0x33);
    486 
    487         /* TODO: Set DRB0-DRB7. */
    488         /* Currently this is hardcoded to one 64 MB DIMM in slot 0. */
    489         pci_write_config8(NB, DRB0, 0x08);
    490         pci_write_config8(NB, DRB1, 0x08);
    491         pci_write_config8(NB, DRB2, 0x08);
    492         pci_write_config8(NB, DRB3, 0x08);
    493         pci_write_config8(NB, DRB4, 0x08);
    494         pci_write_config8(NB, DRB5, 0x08);
    495         pci_write_config8(NB, DRB6, 0x08);
    496         pci_write_config8(NB, DRB7, 0x08);
    497 
    498         /* TODO: Set DRAMC. Don't enable refresh for now. */
    499         pci_write_config8(NB, DRAMC, 0x08);
    500 
    501         /* TODO: Set RPS. Needs to be fixed for multiple DIMM support. */
    502         pci_write_config16(NB, RPS, 0x0001);
     778        /* Setup DRAM row boundary registers and other attributes. */
     779        set_dram_row_attributes();
    503780
    504781        /* TODO: Set SDRAMC. */
    505782        pci_write_config16(NB, SDRAMC, 0x0010); /* SDRAMPWR=1: 4 DIMM config */
    506783
    507         /* TODO: Set PGPOL. */
    508         // pci_write_config16(NB, PGPOL, 0x0107);
    509         pci_write_config16(NB, PGPOL, 0x0123);
    510 
    511         /* TODO: Set NBXCFG. */
    512         // pci_write_config32(NB, NBXCFG, 0x0100220c); // FIXME?
    513         pci_write_config32(NB, NBXCFG, 0xff00800c);
     784        /* TODO */
     785        set_dram_buffer_strength();
    514786
    515787        /* TODO: Set PMCR? */
     
    518790
    519791        /* TODO? */
    520         pci_write_config8(NB, PCI_LATENCY_TIMER, 0x40);
    521792        pci_write_config8(NB, DRAMT, 0x03);
    522         pci_write_config8(NB, MBSC, 0x03);
    523         pci_write_config8(NB, SCRR, 0x38);
    524793}
    525794
Note: See TracChangeset for help on using the changeset viewer.