Changeset 3614


Ignore:
Timestamp:
Sep 29, 2008, 8:09:51 PM (7 years ago)
Author:
mjones
Message:

This patch for the AMD K8 allows a single DIMM to be populated in the
ChannelB slot. Previously a DIMM could only be populated in ChannelB
if there was a DIMM already in ChannelA. This patch doesn't allow unmatched
DIMMs to be populate in ChannelA and ChannelB. In an A & B configuration
the DIMM must still be matched.

Signed-off-by: Marc Jones <marc.jones@…>
Acked-by: Stefan Reinauer <stepan@…>

Location:
trunk/coreboot-v2/src/northbridge/amd/amdk8
Files:
3 edited

Legend:

Unmodified
Added
Removed
  • trunk/coreboot-v2/src/northbridge/amd/amdk8/amdk8_f.h

    r2439 r3614  
    482482        uint8_t is_ecc;
    483483        uint8_t is_Width128;
     484        uint8_t is_64MuxMode;
    484485        uint8_t memclk_set; // we need to use this to retrieve the mem param
    485         uint8_t rsv[3];
     486        uint8_t rsv[2];
    486487} __attribute__((packed));
    487488
  • trunk/coreboot-v2/src/northbridge/amd/amdk8/raminit_f.c

    r3586 r3614  
    850850
    851851static void set_dimm_size(const struct mem_controller *ctrl,
    852                          struct dimm_size *sz, unsigned index, int is_Width128)
     852                         struct dimm_size *sz, unsigned index, struct mem_info *meminfo)
    853853{
    854854        uint32_t base0, base1;
     
    873873
    874874        /* Double the size if we are using dual channel memory */
    875         if (is_Width128) {
     875        if (meminfo->is_Width128) {
    876876                base0 = (base0 << 1) | (base0 & 1);
    877877                base1 = (base1 << 1) | (base1 & 1);
     
    882882        base1 &= ~0xe007fffe;
    883883
    884         /* Set the appropriate DIMM base address register */
    885         pci_write_config32(ctrl->f2, DRAM_CSBASE + (((index << 1)+0)<<2), base0);
    886         pci_write_config32(ctrl->f2, DRAM_CSBASE + (((index << 1)+1)<<2), base1);
     884        if (!(meminfo->dimm_mask & 0x0F) && (meminfo->dimm_mask & 0xF0)) { /* channelB only? */
     885                pci_write_config32(ctrl->f2, DRAM_CSBASE + (((index << 1) + 4) << 2), base0);
     886                pci_write_config32(ctrl->f2, DRAM_CSBASE + (((index << 1) + 5) << 2), base1);
     887        } else {
     888                /* Set the appropriate DIMM base address register */
     889                pci_write_config32(ctrl->f2, DRAM_CSBASE + (((index << 1) + 0) << 2), base0);
     890                pci_write_config32(ctrl->f2, DRAM_CSBASE + (((index << 1) + 1) << 2), base1);
    887891#if QRANK_DIMM_SUPPORT == 1
    888         if (sz->rank == 4) {
    889                 pci_write_config32(ctrl->f2, DRAM_CSBASE + (((index << 1)+4)<<2), base0);
    890                 pci_write_config32(ctrl->f2, DRAM_CSBASE + (((index << 1)+5)<<2), base1);
    891         }
    892 #endif
     892                if (sz->rank == 4) {
     893                        pci_write_config32(ctrl->f2, DRAM_CSBASE + (((index << 1) + 4) << 2), base0);
     894                        pci_write_config32(ctrl->f2, DRAM_CSBASE + (((index << 1) + 5) << 2), base1);
     895                }
     896#endif
     897        }
    893898
    894899        /* Enable the memory clocks for this DIMM by Clear the MemClkDis bit*/
     
    904909#endif
    905910
    906                 dword = pci_read_config32(ctrl->f2, DRAM_TIMING_LOW); //Channel A
    907                 dword &= ~(ClkDis0 >> index);
    908 #if QRANK_DIMM_SUPPORT == 1
    909                 if (sz->rank == 4) {
    910                         dword &= ~(ClkDis0 >> (index+2));
    911                 }
    912 #endif
    913                 pci_write_config32(ctrl->f2, DRAM_TIMING_LOW, dword);
    914 
    915                 if (is_Width128) { //Channel B
     911                if (!(meminfo->dimm_mask & 0x0F) && (meminfo->dimm_mask & 0xF0)) { /* channelB only? */
    916912                        dword = pci_read_config32(ctrl->f2, DRAM_CTRL_MISC);
     913                        dword &= ~(ClkDis0 >> index);
     914                        pci_write_config32(ctrl->f2, DRAM_CTRL_MISC, dword);
     915
     916                } else {
     917                        dword = pci_read_config32(ctrl->f2, DRAM_TIMING_LOW); //Channel A
    917918                        dword &= ~(ClkDis0 >> index);
    918919#if QRANK_DIMM_SUPPORT == 1
     
    921922                        }
    922923#endif
    923                         pci_write_config32(ctrl->f2, DRAM_CTRL_MISC, dword);
     924                        pci_write_config32(ctrl->f2, DRAM_TIMING_LOW, dword);
     925
     926                        if (meminfo->is_Width128) { // ChannelA+B
     927                                dword = pci_read_config32(ctrl->f2, DRAM_CTRL_MISC);
     928                                dword &= ~(ClkDis0 >> index);
     929#if QRANK_DIMM_SUPPORT == 1
     930                                if (sz->rank == 4) {
     931                                        dword &= ~(ClkDis0 >> (index+2));
     932                                }
     933#endif
     934                                pci_write_config32(ctrl->f2, DRAM_CTRL_MISC, dword);
     935                        }
    924936                }
    925937
     
    944956
    945957static void set_dimm_cs_map(const struct mem_controller *ctrl,
    946                              struct dimm_size *sz, unsigned index)
     958                             struct dimm_size *sz, unsigned index,
     959                             struct mem_info *meminfo)
    947960{
    948961        static const uint8_t cs_map_aaa[24] = {
     
    962975        uint32_t map;
    963976
     977        if (!(meminfo->dimm_mask & 0x0F) && (meminfo->dimm_mask & 0xF0)) { /* channelB only? */
     978                index += 2;
     979        }
    964980        map = pci_read_config32(ctrl->f2, DRAM_BANK_ADDR_MAP);
    965981        map &= ~(0xf << (index * 4));
     
    9871003
    9881004
    989 static long spd_set_ram_size(const struct mem_controller *ctrl, long dimm_mask,
     1005static long spd_set_ram_size(const struct mem_controller *ctrl,
    9901006                              struct mem_info *meminfo)
    9911007{
     
    9941010        for (i = 0; i < DIMM_SOCKETS; i++) {
    9951011                struct dimm_size *sz = &(meminfo->sz[i]);
    996                 if (!(dimm_mask & (1 << i))) {
    997                         continue;
    998                 }
    999                 spd_get_dimm_size(ctrl->channel0[i], sz);
     1012                u32 spd_device = ctrl->channel0[i];
     1013
     1014                if (!(meminfo->dimm_mask & (1 << i))) {
     1015                        if (meminfo->dimm_mask & (1 << (DIMM_SOCKETS + i))) { /* channelB only? */
     1016                                spd_device = ctrl->channel1[i];
     1017                        } else {
     1018                                continue;
     1019                        }
     1020                }
     1021
     1022                spd_get_dimm_size(spd_device, sz);
    10001023                if (sz->per_rank == 0) {
    10011024                        return -1; /* Report SPD error */
    10021025                }
    1003                 set_dimm_size(ctrl, sz, i, meminfo->is_Width128);
    1004                 set_dimm_cs_map (ctrl, sz, i);
    1005         }
    1006         return dimm_mask;
     1026                set_dimm_size(ctrl, sz, i, meminfo);
     1027                set_dimm_cs_map (ctrl, sz, i, meminfo);
     1028        }
     1029        return meminfo->dimm_mask;
    10071030}
    10081031
     
    12441267                pci_write_config32(ctrl->f2, DRAM_CSBASE + (canidate << 2), csbase);
    12451268                /* Write the new mask register */
    1246                  if ((canidate & 1) == 0) {  //only have 4 CSMASK
    1247                          pci_write_config32(ctrl->f2, DRAM_CSMASK + ((canidate>>1) << 2), csmask);
    1248                  }
     1269                if ((canidate & 1) == 0) {  //only have 4 CSMASK
     1270                        pci_write_config32(ctrl->f2, DRAM_CSMASK + ((canidate >> 1) << 2), csmask);
     1271                }
    12491272
    12501273        }
     
    13001323
    13011324static long disable_dimm(const struct mem_controller *ctrl, unsigned index,
    1302                           long dimm_mask, struct mem_info *meminfo)
     1325                          struct mem_info *meminfo)
    13031326{
    13041327        print_debug("disabling dimm");
    13051328        print_debug_hex8(index);
    13061329        print_debug("\r\n");
    1307         pci_write_config32(ctrl->f2, DRAM_CSBASE + (((index << 1)+0)<<2), 0);
    1308         pci_write_config32(ctrl->f2, DRAM_CSBASE + (((index << 1)+1)<<2), 0);
     1330        if (!(meminfo->dimm_mask & 0x0F) && (meminfo->dimm_mask & 0xF0)) { /* channelB only? */
     1331                pci_write_config32(ctrl->f2, DRAM_CSBASE + (((index << 1) + 4) << 2), 0);
     1332                pci_write_config32(ctrl->f2, DRAM_CSBASE + (((index << 1) + 5) << 2), 0);
     1333        } else {
     1334                pci_write_config32(ctrl->f2, DRAM_CSBASE + (((index << 1) + 0) << 2), 0);
     1335                pci_write_config32(ctrl->f2, DRAM_CSBASE + (((index << 1) + 1) << 2), 0);
    13091336#if QRANK_DIMM_SUPPORT == 1
    1310         if (meminfo->sz[index].rank == 4) {
    1311                 pci_write_config32(ctrl->f2, DRAM_CSBASE + (((index << 1)+4)<<2), 0);
    1312                 pci_write_config32(ctrl->f2, DRAM_CSBASE + (((index << 1)+5)<<2), 0);
    1313         }
    1314 #endif
    1315 
    1316         dimm_mask &= ~(1 << index);
    1317         return dimm_mask;
     1337                if (meminfo->sz[index].rank == 4) {
     1338                        pci_write_config32(ctrl->f2, DRAM_CSBASE + (((index << 1) + 4) << 2), 0);
     1339                        pci_write_config32(ctrl->f2, DRAM_CSBASE + (((index << 1) + 5) << 2), 0);
     1340                }
     1341#endif
     1342        }
     1343
     1344        meminfo->dimm_mask &= ~(1 << index);
     1345        return meminfo->dimm_mask;
    13181346}
    13191347
    13201348
    13211349static long spd_handle_unbuffered_dimms(const struct mem_controller *ctrl,
    1322                                         long dimm_mask, struct mem_info *meminfo)
     1350                                        struct mem_info *meminfo)
    13231351{
    13241352        int i;
     
    13281356        for (i = 0; (i < DIMM_SOCKETS); i++) {
    13291357                int value;
    1330                 if (!(dimm_mask & (1 << i))) {
    1331                         continue;
    1332                 }
    1333 
    1334                 value = spd_read_byte(ctrl->channel0[i], SPD_DIMM_TYPE);
     1358                u32 spd_device = ctrl->channel0[i];
     1359                if (!(meminfo->dimm_mask & (1 << i))) {
     1360                        if (meminfo->dimm_mask & (1 << (DIMM_SOCKETS + i))) { /* channelB only? */
     1361                                spd_device = ctrl->channel1[i];
     1362                        } else {
     1363                                continue;
     1364                        }
     1365                }
     1366                value = spd_read_byte(spd_device, SPD_DIMM_TYPE);
    13351367                if (value < 0) {
    13361368                        return -1;
     
    13391371                /* Registered dimm ? */
    13401372                value &= 0x3f;
    1341                 if ((value == SPD_DIMM_TYPE_RDIMM) ||
    1342                     (value == SPD_DIMM_TYPE_mRDIMM)) {
    1343                         /* check SPD_MOD_ATTRIB to verify it is
    1344                            SPD_MOD_ATTRIB_REGADC (0x11)? */
     1373                if ((value == SPD_DIMM_TYPE_RDIMM) || (value == SPD_DIMM_TYPE_mRDIMM)) {
     1374                        //check SPD_MOD_ATTRIB to verify it is SPD_MOD_ATTRIB_REGADC (0x11)?
    13451375                        registered |= (1<<i);
    13461376                }
     
    13491379        if (is_opteron(ctrl)) {
    13501380#if 0
    1351                 if ( registered != (dimm_mask & ((1<<DIMM_SOCKETS)-1)) ) {
    1352                         dimm_mask &= (registered | (registered << DIMM_SOCKETS) ); //disable unbuffed dimm
     1381                if ( registered != (meminfo->dimm_mask & ((1<<DIMM_SOCKETS)-1)) ) {
     1382                        meminfo->dimm_mask &= (registered | (registered << DIMM_SOCKETS) ); //disable unbuffed dimm
    13531383//                      die("Mixed buffered and registered dimms not supported");
    13541384                }
     
    13771407        }
    13781408#endif
    1379         return dimm_mask;
     1409        return meminfo->dimm_mask;
    13801410}
    13811411
     
    14071437}
    14081438
    1409 
    1410 static long spd_enable_2channels(const struct mem_controller *ctrl, long dimm_mask, struct mem_info *meminfo)
     1439static long spd_enable_2channels(const struct mem_controller *ctrl, struct mem_info *meminfo)
    14111440{
    14121441        int i;
     
    14391468                42,     /* *Minimum Auto Refresh Command Time(Trfc) */
    14401469        };
     1470        u32 dcl, dcm;
     1471
     1472/* S1G1 and AM2 sockets are Mod64BitMux capable. */
     1473#if CPU_SOCKET_TYPE == 0x11 || CPU_SOCKET_TYPE == 0x12
     1474        u8 mux_cap = 1;
     1475#else
     1476        u8 mux_cap = 0;
     1477#endif
     1478
    14411479        /* If the dimms are not in pairs do not do dual channels */
    1442         if ((dimm_mask & ((1 << DIMM_SOCKETS) - 1)) !=
    1443                 ((dimm_mask >> DIMM_SOCKETS) & ((1 << DIMM_SOCKETS) - 1))) {
     1480        if ((meminfo->dimm_mask & ((1 << DIMM_SOCKETS) - 1)) !=
     1481                ((meminfo->dimm_mask >> DIMM_SOCKETS) & ((1 << DIMM_SOCKETS) - 1))) {
    14441482                goto single_channel;
    14451483        }
    1446         /* If the cpu is not capable of doing dual channels
    1447            don't do dual channels */
     1484        /* If the cpu is not capable of doing dual channels don't do dual channels */
    14481485        nbcap = pci_read_config32(ctrl->f3, NORTHBRIDGE_CAP);
    14491486        if (!(nbcap & NBCAP_128Bit)) {
     
    14551492                int j;
    14561493                /* If I don't have a dimm skip this one */
    1457                 if (!(dimm_mask & (1 << i))) {
     1494                if (!(meminfo->dimm_mask & (1 << i))) {
    14581495                        continue;
    14591496                }
     
    14771514        }
    14781515        print_spew("Enabling dual channel memory\r\n");
    1479         uint32_t dcl;
    14801516        dcl = pci_read_config32(ctrl->f2, DRAM_CONFIG_LOW);
    14811517        dcl &= ~DCL_BurstLength32;  /*  32byte mode may be preferred in platforms that include graphics controllers that generate a lot of 32-bytes system memory accesses
     
    14841520        pci_write_config32(ctrl->f2, DRAM_CONFIG_LOW, dcl);
    14851521        meminfo->is_Width128 = 1;
    1486         return dimm_mask;
     1522        return meminfo->dimm_mask;
     1523
    14871524 single_channel:
    1488         dimm_mask &= ~((1 << (DIMM_SOCKETS *2)) - (1 << DIMM_SOCKETS));
    14891525        meminfo->is_Width128 = 0;
    1490         return dimm_mask;
     1526        meminfo->is_64MuxMode = 0;
     1527
     1528        /* single dimm */
     1529        if ((meminfo->dimm_mask & ((1 << DIMM_SOCKETS) - 1)) !=
     1530           ((meminfo->dimm_mask >> DIMM_SOCKETS) & ((1 << DIMM_SOCKETS) - 1))) {
     1531                if (((meminfo->dimm_mask >> DIMM_SOCKETS) & ((1 << DIMM_SOCKETS) - 1))) {
     1532                        /* mux capable and single dimm in channelB */
     1533                        if (mux_cap) {
     1534                                printk_spew("Enable 64MuxMode & BurstLength32\n");
     1535                                dcm = pci_read_config32(ctrl->f2, DRAM_CTRL_MISC);
     1536                                dcm |= DCM_Mode64BitMux;
     1537                                pci_write_config32(ctrl->f2, DRAM_CTRL_MISC, dcm);
     1538                                dcl = pci_read_config32(ctrl->f2, DRAM_CONFIG_LOW);
     1539                                //dcl |= DCL_BurstLength32; /* 32byte mode for channelB only */
     1540                                pci_write_config32(ctrl->f2, DRAM_CONFIG_LOW, dcl);
     1541                                meminfo->is_64MuxMode = 1;
     1542                        } else {
     1543                                meminfo->dimm_mask &= ~((1 << (DIMM_SOCKETS * 2)) - (1 << DIMM_SOCKETS));
     1544                        }
     1545                }
     1546        } else { /* unmatched dual dimms ? */
     1547                /* unmatched dual dimms not supported by meminit code. Use single channelA dimm. */
     1548                meminfo->dimm_mask &= ~((1 << (DIMM_SOCKETS * 2)) - (1 << DIMM_SOCKETS));
     1549                printk_spew("Unmatched dual dimms. Use single channelA dimm.\n");
     1550        }
     1551        return meminfo->dimm_mask;
    14911552}
    14921553
     
    16341695}
    16351696
    1636 static struct spd_set_memclk_result spd_set_memclk(const struct mem_controller *ctrl, long dimm_mask, struct mem_info *meminfo)
     1697static struct spd_set_memclk_result spd_set_memclk(const struct mem_controller *ctrl, struct mem_info *meminfo)
    16371698{
    16381699        /* Compute the minimum cycle time for these dimms */
     
    16711732                int latencies;
    16721733                int latency;
    1673 
    1674                 if (!(dimm_mask & (1 << i))) {
    1675                         continue;
     1734                u32 spd_device = ctrl->channel0[i];
     1735
     1736                print_tx("1.1 dimm_mask:", meminfo->dimm_mask);
     1737                if (!(meminfo->dimm_mask & (1 << i))) {
     1738                        if (meminfo->dimm_mask & (1 << (DIMM_SOCKETS + i))) { /* channelB only? */
     1739                                spd_device = ctrl->channel1[i];
     1740                        } else {
     1741                                continue;
     1742                        }
    16761743                }
    16771744
     
    16861753                new_latency = 6;
    16871754
    1688                 latencies = spd_read_byte(ctrl->channel0[i], SPD_CAS_LAT);
     1755                latencies = spd_read_byte(spd_device, SPD_CAS_LAT);
    16891756                if (latencies <= 0) continue;
    16901757
     
    17011768                                continue;
    17021769                        }
    1703                         value = spd_read_byte(ctrl->channel0[i], latency_indicies[index]);
     1770                        value = spd_read_byte(spd_device, latency_indicies[index]);
    17041771                        if (value < 0) {
    17051772                                goto hw_error;
     
    17541821        print_tx("3 min_latency:", min_latency);
    17551822
    1756         for (i = 0; (i < DIMM_SOCKETS) && (ctrl->channel0[i]); i++) {
     1823        for (i = 0; (i < DIMM_SOCKETS); i++) {
    17571824                int latencies;
    17581825                int latency;
    17591826                int index;
    17601827                int value;
    1761                 if (!(dimm_mask & (1 << i))) {
    1762                         continue;
    1763                 }
    1764 
    1765                 latencies = spd_read_byte(ctrl->channel0[i], SPD_CAS_LAT);
     1828                u32 spd_device = ctrl->channel0[i];
     1829
     1830                if (!(meminfo->dimm_mask & (1 << i))) {
     1831                        if (meminfo->dimm_mask & (1 << (DIMM_SOCKETS + i))) { /* channelB only? */
     1832                                spd_device = ctrl->channel1[i];
     1833                        } else {
     1834                                continue;
     1835                        }
     1836                }
     1837
     1838                latencies = spd_read_byte(spd_device, SPD_CAS_LAT);
    17661839                if (latencies < 0) goto hw_error;
    17671840                if (latencies == 0) {
     
    17861859
    17871860                /* Read the min_cycle_time for this latency */
    1788                 value = spd_read_byte(ctrl->channel0[i], latency_indicies[index]);
     1861                value = spd_read_byte(spd_device, latency_indicies[index]);
    17891862                if (value < 0) goto hw_error;
    17901863
     
    17981871                /* Otherwise I have an error, disable the dimm */
    17991872        dimm_err:
    1800                 dimm_mask = disable_dimm(ctrl, i, dimm_mask, meminfo);
     1873                meminfo->dimm_mask = disable_dimm(ctrl, i, meminfo);
    18011874        }
    18021875
     
    18211894        pci_write_config32(ctrl->f2, DRAM_TIMING_LOW, value);
    18221895
    1823         result.dimm_mask = dimm_mask;
     1896        result.dimm_mask = meminfo->dimm_mask;
    18241897        return result;
    18251898 hw_error:
     
    18381911        return valuex;
    18391912}
    1840 static int update_dimm_Trc(const struct mem_controller *ctrl, const struct mem_param *param, int i)
     1913static int update_dimm_Trc(const struct mem_controller *ctrl,
     1914                            const struct mem_param *param,
     1915                            int i, long dimm_mask)
    18411916{
    18421917        unsigned clocks, old_clocks;
     
    18441919        int value;
    18451920        int value2;
    1846         value = spd_read_byte(ctrl->channel0[i], SPD_TRC);
     1921        u32 spd_device = ctrl->channel0[i];
     1922
     1923        if (!(dimm_mask & (1 << i)) && (dimm_mask & (1 << (DIMM_SOCKETS + i)))) { /* channelB only? */
     1924                spd_device = ctrl->channel1[i];
     1925        }
     1926
     1927        value = spd_read_byte(spd_device, SPD_TRC);
    18471928        if (value < 0) return -1;
    18481929
    1849                 value2 = spd_read_byte(ctrl->channel0[i], SPD_TRC -1);
    1850                 value <<= 2;
    1851                 value += convert_to_1_4(value2>>4);
     1930        value2 = spd_read_byte(spd_device, SPD_TRC -1);
     1931        value <<= 2;
     1932        value += convert_to_1_4(value2>>4);
    18521933
    18531934        value *=10;
     
    18791960        uint32_t dth;
    18801961        int value;
     1962        u8 ch_b = 0;
     1963        u32 spd_device = ctrl->channel0[i];
     1964
     1965        if (!(meminfo->dimm_mask & (1 << i)) && (meminfo->dimm_mask & (1 << (DIMM_SOCKETS + i)))) { /* channelB only? */
     1966                spd_device = ctrl->channel1[i];
     1967                ch_b = 2; /* offset to channelB trfc setting */
     1968        }
    18811969
    18821970        //get the cs_size --> logic dimm size
    1883         value = spd_read_byte(ctrl->channel0[i], SPD_PRI_WIDTH);
     1971        value = spd_read_byte(spd_device, SPD_PRI_WIDTH);
    18841972        if (value < 0) {
    18851973                return -1;
     
    18921980        dth = pci_read_config32(ctrl->f2, DRAM_TIMING_HIGH);
    18931981
    1894         old_clocks = ((dth >> (DTH_TRFC0_SHIFT+i*3)) & DTH_TRFC_MASK);
     1982        old_clocks = ((dth >> (DTH_TRFC0_SHIFT + ((i + ch_b) * 3))) & DTH_TRFC_MASK);
     1983
    18951984        if (old_clocks >= clocks) { // some one did it?
    18961985                return 1;
    18971986        }
    1898         dth &= ~(DTH_TRFC_MASK << (DTH_TRFC0_SHIFT+i*3));
    1899         dth |= clocks  << (DTH_TRFC0_SHIFT+i*3);
     1987        dth &= ~(DTH_TRFC_MASK << (DTH_TRFC0_SHIFT + ((i + ch_b) * 3)));
     1988        dth |= clocks  << (DTH_TRFC0_SHIFT + ((i + ch_b) * 3));
    19001989        pci_write_config32(ctrl->f2, DRAM_TIMING_HIGH, dth);
    19011990        return 1;
    19021991}
    19031992
    1904 static int update_dimm_TT_1_4(const struct mem_controller *ctrl, const struct mem_param *param, int i,
     1993static int update_dimm_TT_1_4(const struct mem_controller *ctrl, const struct mem_param *param, int i, long dimm_mask,
    19051994                                        unsigned TT_REG,
    19061995                                        unsigned SPD_TT, unsigned TT_SHIFT, unsigned TT_MASK, unsigned TT_BASE, unsigned TT_MIN, unsigned TT_MAX )
     
    19091998        uint32_t dtl;
    19101999        int value;
    1911         value = spd_read_byte(ctrl->channel0[i], SPD_TT); //already in 1/4 ns
     2000        u32 spd_device = ctrl->channel0[i];
     2001
     2002        if (!(dimm_mask & (1 << i)) && (dimm_mask & (1 << (DIMM_SOCKETS + i)))) { /* channelB only? */
     2003                spd_device = ctrl->channel1[i];
     2004        }
     2005
     2006        value = spd_read_byte(spd_device, SPD_TT); //already in 1/4 ns
    19122007        if (value < 0) return -1;
    19132008        value *=10;
     
    19182013       
    19192014        if (clocks > TT_MAX) {
    1920                  return 0;
     2015                return 0;
    19212016        }
    19222017
     
    19252020        old_clocks = ((dtl >> TT_SHIFT) & TT_MASK) + TT_BASE;
    19262021        if (old_clocks >= clocks) { //some one did it?
    1927 //      clocks = old_clocks;
     2022//              clocks = old_clocks;
    19282023                return 1;
    19292024        }
     
    19362031
    19372032static int update_dimm_Trcd(const struct mem_controller *ctrl,
    1938                              const struct mem_param *param, int i)
    1939 {
    1940         return update_dimm_TT_1_4(ctrl, param, i, DRAM_TIMING_LOW, SPD_TRCD, DTL_TRCD_SHIFT, DTL_TRCD_MASK, DTL_TRCD_BASE, DTL_TRCD_MIN, DTL_TRCD_MAX);
    1941 }
    1942 
    1943 
    1944 static int update_dimm_Trrd(const struct mem_controller *ctrl, const struct mem_param *param, int i)
    1945 {
    1946         return update_dimm_TT_1_4(ctrl, param, i, DRAM_TIMING_LOW, SPD_TRRD, DTL_TRRD_SHIFT, DTL_TRRD_MASK, DTL_TRRD_BASE, DTL_TRRD_MIN, DTL_TRRD_MAX);
    1947 }
    1948 
    1949 
    1950 static int update_dimm_Tras(const struct mem_controller *ctrl, const struct mem_param *param, int i)
     2033                             const struct mem_param *param, int i, long dimm_mask)
     2034{
     2035        return update_dimm_TT_1_4(ctrl, param, i, dimm_mask, DRAM_TIMING_LOW, SPD_TRCD, DTL_TRCD_SHIFT, DTL_TRCD_MASK, DTL_TRCD_BASE, DTL_TRCD_MIN, DTL_TRCD_MAX);
     2036}
     2037
     2038static int update_dimm_Trrd(const struct mem_controller *ctrl, const struct mem_param *param, int i, long dimm_mask)
     2039{
     2040        return update_dimm_TT_1_4(ctrl, param, i, dimm_mask, DRAM_TIMING_LOW, SPD_TRRD, DTL_TRRD_SHIFT, DTL_TRRD_MASK, DTL_TRRD_BASE, DTL_TRRD_MIN, DTL_TRRD_MAX);
     2041}
     2042
     2043static int update_dimm_Tras(const struct mem_controller *ctrl, const struct mem_param *param, int i, long dimm_mask)
    19512044{
    19522045        unsigned clocks, old_clocks;
    19532046        uint32_t dtl;
    19542047        int value;
    1955         value = spd_read_byte(ctrl->channel0[i], SPD_TRAS); //in 1 ns
     2048        u32 spd_device = ctrl->channel0[i];
     2049
     2050        if (!(dimm_mask & (1 << i)) && (dimm_mask & (1 << (DIMM_SOCKETS + i)))) { /* channelB only? */
     2051                spd_device = ctrl->channel1[i];
     2052        }
     2053
     2054        value = spd_read_byte(spd_device, SPD_TRAS); //in 1 ns
    19562055        if (value < 0) return -1;
    19572056        print_tx("update_dimm_Tras: 0 value=", value);
     
    19862085
    19872086static int update_dimm_Trp(const struct mem_controller *ctrl,
    1988                             const struct mem_param *param, int i)
    1989 {
    1990         return update_dimm_TT_1_4(ctrl, param, i, DRAM_TIMING_LOW, SPD_TRP, DTL_TRP_SHIFT, DTL_TRP_MASK, DTL_TRP_BASE, DTL_TRP_MIN, DTL_TRP_MAX);
     2087                            const struct mem_param *param, int i, long dimm_mask)
     2088{
     2089        return update_dimm_TT_1_4(ctrl, param, i, dimm_mask, DRAM_TIMING_LOW, SPD_TRP, DTL_TRP_SHIFT, DTL_TRP_MASK, DTL_TRP_BASE, DTL_TRP_MIN, DTL_TRP_MAX);
    19912090}
    19922091
     
    20022101                if ((dword &  DCL_BurstLength32)) offset = 0;
    20032102        }
    2004          return update_dimm_TT_1_4(ctrl, param, i, DRAM_TIMING_LOW, SPD_TRTP, DTL_TRTP_SHIFT, DTL_TRTP_MASK, DTL_TRTP_BASE+offset, DTL_TRTP_MIN+offset, DTL_TRTP_MAX+offset);
    2005 }
    2006 
    2007 
    2008 static int update_dimm_Twr(const struct mem_controller *ctrl, const struct mem_param *param, int i)
    2009 {
    2010         return update_dimm_TT_1_4(ctrl, param, i, DRAM_TIMING_LOW, SPD_TWR, DTL_TWR_SHIFT, DTL_TWR_MASK, DTL_TWR_BASE, DTL_TWR_MIN, DTL_TWR_MAX);
     2103        return update_dimm_TT_1_4(ctrl, param, i, meminfo->dimm_mask, DRAM_TIMING_LOW, SPD_TRTP, DTL_TRTP_SHIFT, DTL_TRTP_MASK, DTL_TRTP_BASE+offset, DTL_TRTP_MIN+offset, DTL_TRTP_MAX+offset);
     2104}
     2105
     2106
     2107static int update_dimm_Twr(const struct mem_controller *ctrl, const struct mem_param *param, int i, long dimm_mask)
     2108{
     2109        return update_dimm_TT_1_4(ctrl, param, i, dimm_mask, DRAM_TIMING_LOW, SPD_TWR, DTL_TWR_SHIFT, DTL_TWR_MASK, DTL_TWR_BASE, DTL_TWR_MIN, DTL_TWR_MAX);
    20112110}
    20122111
    20132112
    20142113static int update_dimm_Tref(const struct mem_controller *ctrl,
    2015                              const struct mem_param *param, int i)
     2114                             const struct mem_param *param, int i, long dimm_mask)
    20162115{
    20172116        uint32_t dth, dth_old;
    20182117        int value;
    2019         value = spd_read_byte(ctrl->channel0[i], SPD_TREF); // 0: 15.625us, 1: 3.9us 2: 7.8 us....
     2118        u32 spd_device = ctrl->channel0[i];
     2119
     2120        if (!(dimm_mask & (1 << i)) && (dimm_mask & (1 << (DIMM_SOCKETS + i)))) { /* channelB only? */
     2121                spd_device = ctrl->channel1[i];
     2122        }
     2123
     2124        value = spd_read_byte(spd_device, SPD_TREF); // 0: 15.625us, 1: 3.9us 2: 7.8 us....
    20202125        if (value < 0) return -1;
    20212126
     
    20942199
    20952200        for (i = 0; i < DIMM_SOCKETS; i++) {
     2201                u32 spd_device = ctrl->channel0[i];
    20962202                if (!(dimm_mask & (1 << i))) {
    2097                         continue;
     2203                        if (dimm_mask & (1 << (DIMM_SOCKETS + i))) { /* channelB only? */
     2204                                spd_device = ctrl->channel1[i];
     2205                        } else {
     2206                                continue;
     2207                        }
    20982208                }
    20992209
     
    21072217
    21082218
    2109                 value = spd_read_byte(ctrl->channel0[i], SPD_PRI_WIDTH);
     2219                value = spd_read_byte(spd_device, SPD_PRI_WIDTH);
    21102220
    21112221                #if QRANK_DIMM_SUPPORT == 1
     
    21572267        unsigned index;
    21582268        dimms = 0;
    2159         for (index = 0; index < DIMM_SOCKETS; index++, dimm_mask>>=1) {
     2269        for (index = 0; index < (2 * DIMM_SOCKETS); index++, dimm_mask >>= 1) {
    21602270                if (dimm_mask & 1) {
    21612271                        dimms++;
     
    21952305
    21962306static void set_ecc(const struct mem_controller *ctrl,
    2197         const struct mem_param *param, long dimm_mask, struct mem_info *meminfo)
     2307        const struct mem_param *param, struct mem_info *meminfo)
    21982308{
    21992309        int i;
     
    22192329
    22202330        for (i = 0; i < DIMM_SOCKETS; i++) {
    2221 
    2222                 if (!(dimm_mask & (1 << i))) {
    2223                         continue;
     2331                u32 spd_device = ctrl->channel0[i];
     2332                if (!(meminfo->dimm_mask & (1 << i))) {
     2333                        if (meminfo->dimm_mask & (1 << (DIMM_SOCKETS + i))) { /* channelB only? */
     2334                                spd_device = ctrl->channel1[i];
     2335                                printk_debug("set_ecc spd_device: 0x%x\n", spd_device);
     2336                        } else {
     2337                                continue;
     2338                        }
    22242339                }
    22252340
     
    22382353
    22392354static int update_dimm_Twtr(const struct mem_controller *ctrl,
    2240                              const struct mem_param *param, int i)
    2241 {
    2242 
    2243         return update_dimm_TT_1_4(ctrl, param, i, DRAM_TIMING_HIGH, SPD_TWTR, DTH_TWTR_SHIFT, DTH_TWTR_MASK, DTH_TWTR_BASE, DTH_TWTR_MIN, DTH_TWTR_MAX);
    2244 }
    2245 
     2355                             const struct mem_param *param, int i, long dimm_mask)
     2356{
     2357        return update_dimm_TT_1_4(ctrl, param, i, dimm_mask, DRAM_TIMING_HIGH, SPD_TWTR, DTH_TWTR_SHIFT, DTH_TWTR_MASK, DTH_TWTR_BASE, DTH_TWTR_MIN, DTH_TWTR_MAX);
     2358}
    22462359
    22472360static void set_TT(const struct mem_controller *ctrl,
     
    25112624#endif
    25122625
    2513         /* Program the Output Driver Compensation Control Registers (Function 2:Offset 0x9c, index 0, 0x20) */
    2514         pci_write_config32_index_wait(ctrl->f2, 0x98, 0, dword);
    2515         if (meminfo->is_Width128) {
     2626        if (!(meminfo->dimm_mask & 0x0F) && (meminfo->dimm_mask & 0xF0)) { /* channelB only? */
     2627                /* Program the Output Driver Compensation Control Registers (Function 2:Offset 0x9c, index 0, 0x20) */
    25162628                pci_write_config32_index_wait(ctrl->f2, 0x98, 0x20, dword);
    2517         }
    2518 
    2519         /* Program the Address Timing Control Registers (Function 2:Offset 0x9c, index 4, 0x24) */
    2520         pci_write_config32_index_wait(ctrl->f2, 0x98, 4, dwordx);
    2521         if (meminfo->is_Width128) {
     2629
     2630                /* Program the Address Timing Control Registers (Function 2:Offset 0x9c, index 4, 0x24) */
    25222631                pci_write_config32_index_wait(ctrl->f2, 0x98, 0x24, dwordx);
    2523         }
    2524 
     2632        } else {
     2633                /* Program the Output Driver Compensation Control Registers (Function 2:Offset 0x9c, index 0, 0x20) */
     2634                pci_write_config32_index_wait(ctrl->f2, 0x98, 0, dword);
     2635                if (meminfo->is_Width128) {
     2636                        pci_write_config32_index_wait(ctrl->f2, 0x98, 0x20, dword);
     2637                }
     2638
     2639                /* Program the Address Timing Control Registers (Function 2:Offset 0x9c, index 4, 0x24) */
     2640                pci_write_config32_index_wait(ctrl->f2, 0x98, 4, dwordx);
     2641                if (meminfo->is_Width128) {
     2642                        pci_write_config32_index_wait(ctrl->f2, 0x98, 0x24, dwordx);
     2643                }
     2644        }
    25252645}
    25262646
     
    25652685
    25662686
    2567 static long spd_set_dram_timing(const struct mem_controller *ctrl, const struct mem_param *param, long dimm_mask, struct mem_info *meminfo)
     2687static long spd_set_dram_timing(const struct mem_controller *ctrl,
     2688                                 const struct mem_param *param,
     2689                                 struct mem_info *meminfo)
    25682690{
    25692691        int i;
     
    25712693        for (i = 0; i < DIMM_SOCKETS; i++) {
    25722694                int rc;
    2573                 if (!(dimm_mask & (1 << i))) {
     2695                if (!(meminfo->dimm_mask & (1 << i)) &&
     2696                    !(meminfo->dimm_mask & (1 << (DIMM_SOCKETS + i))) ) {
    25742697                        continue;
    25752698                }
    2576                 print_tx("dimm socket: ", i);
     2699                print_tx("spd_set_dram_timing dimm socket: ", i);
    25772700                /* DRAM Timing Low Register */
    25782701                print_t("\ttrc\r\n");
    2579                 if ((rc = update_dimm_Trc (ctrl, param, i)) <= 0) goto dimm_err;
     2702                if ((rc = update_dimm_Trc (ctrl, param, i, meminfo->dimm_mask)) <= 0) goto dimm_err;
    25802703
    25812704                print_t("\ttrcd\r\n");
    2582                 if ((rc = update_dimm_Trcd(ctrl, param, i)) <= 0) goto dimm_err;
     2705                if ((rc = update_dimm_Trcd(ctrl, param, i, meminfo->dimm_mask)) <= 0) goto dimm_err;
    25832706
    25842707                print_t("\ttrrd\r\n");
    2585                 if ((rc = update_dimm_Trrd(ctrl, param, i)) <= 0) goto dimm_err;
     2708                if ((rc = update_dimm_Trrd(ctrl, param, i, meminfo->dimm_mask)) <= 0) goto dimm_err;
    25862709
    25872710                print_t("\ttras\r\n");
    2588                 if ((rc = update_dimm_Tras(ctrl, param, i)) <= 0) goto dimm_err;
     2711                if ((rc = update_dimm_Tras(ctrl, param, i, meminfo->dimm_mask)) <= 0) goto dimm_err;
    25892712
    25902713                print_t("\ttrp\r\n");
    2591                 if ((rc = update_dimm_Trp (ctrl, param, i)) <= 0) goto dimm_err;
     2714                if ((rc = update_dimm_Trp (ctrl, param, i, meminfo->dimm_mask)) <= 0) goto dimm_err;
    25922715
    25932716                print_t("\ttrtp\r\n");
     
    25952718
    25962719                print_t("\ttwr\r\n");
    2597                 if ((rc = update_dimm_Twr (ctrl, param, i)) <= 0) goto dimm_err;
     2720                if ((rc = update_dimm_Twr (ctrl, param, i, meminfo->dimm_mask)) <= 0) goto dimm_err;
    25982721
    25992722                /* DRAM Timing High Register */
    26002723                print_t("\ttref\r\n");
    2601                 if ((rc = update_dimm_Tref(ctrl, param, i)) <= 0) goto dimm_err;
     2724                if ((rc = update_dimm_Tref(ctrl, param, i, meminfo->dimm_mask)) <= 0) goto dimm_err;
    26022725
    26032726                print_t("\ttwtr\r\n");
    2604                 if ((rc = update_dimm_Twtr(ctrl, param, i)) <= 0) goto dimm_err;
     2727                if ((rc = update_dimm_Twtr(ctrl, param, i, meminfo->dimm_mask)) <= 0) goto dimm_err;
    26052728
    26062729                print_t("\ttrfc\r\n");
     
    26112734                continue;
    26122735        dimm_err:
     2736                printk_debug("spd_set_dram_timing dimm_err!\n");
    26132737                if (rc < 0) {
    26142738                        return -1;
    26152739                }
    2616                 dimm_mask = disable_dimm(ctrl, i, dimm_mask, meminfo);
    2617         }
    2618 
    2619         meminfo->dimm_mask = dimm_mask; // store final dimm_mask
     2740                meminfo->dimm_mask = disable_dimm(ctrl, i, meminfo);
     2741        }
    26202742
    26212743        get_extra_dimm_mask(ctrl, meminfo); // will be used by RDqsEn and dimm_x4
     
    26372759
    26382760        /* DRAM Config Low */
    2639         set_ecc(ctrl, param, dimm_mask, meminfo);
     2761        set_ecc(ctrl, param, meminfo);
    26402762        set_dimm_x4(ctrl, param, meminfo);
    26412763        set_DramTerm(ctrl, param, meminfo);
     
    26452767        set_RdWrQByp(ctrl, param);
    26462768
    2647         return dimm_mask;
     2769        return meminfo->dimm_mask;
    26482770}
    26492771
     
    26552777        struct mem_param paramx;
    26562778        struct mem_info *meminfo;
    2657         long dimm_mask;
    26582779#if 1
    26592780        if (!sysinfo->ctrl_present[ctrl->node_id]) {
     
    26662787
    26672788        activate_spd_rom(ctrl);
    2668         dimm_mask = spd_detect_dimms(ctrl);
    2669         if (!(dimm_mask & ((1 << DIMM_SOCKETS) - 1))) {
     2789        meminfo->dimm_mask = spd_detect_dimms(ctrl);
     2790
     2791        print_tx("sdram_set_spd_registers: dimm_mask=0x%x\n", meminfo->dimm_mask);
     2792
     2793        if (!(meminfo->dimm_mask & ((1 << 2*DIMM_SOCKETS) - 1)))
     2794        {
    26702795                print_debug("No memory for this cpu\r\n");
    26712796                return;
    26722797        }
    2673         dimm_mask = spd_enable_2channels(ctrl, dimm_mask, meminfo);
    2674         if (dimm_mask < 0)
     2798        meminfo->dimm_mask = spd_enable_2channels(ctrl, meminfo);
     2799        print_tx("spd_enable_2channels: dimm_mask=0x%x\n", meminfo->dimm_mask);
     2800        if (meminfo->dimm_mask == -1)
    26752801                goto hw_spd_err;
    2676         dimm_mask = spd_set_ram_size(ctrl , dimm_mask, meminfo);
    2677         if (dimm_mask < 0)
     2802
     2803        meminfo->dimm_mask = spd_set_ram_size(ctrl, meminfo);
     2804        print_tx("spd_set_ram_size: dimm_mask=0x%x\n", meminfo->dimm_mask);
     2805        if (meminfo->dimm_mask == -1)
    26782806                goto hw_spd_err;
    2679         dimm_mask = spd_handle_unbuffered_dimms(ctrl, dimm_mask, meminfo);
    2680         if (dimm_mask < 0)
     2807
     2808        meminfo->dimm_mask = spd_handle_unbuffered_dimms(ctrl, meminfo);
     2809        print_tx("spd_handle_unbuffered_dimms: dimm_mask=0x%x\n", meminfo->dimm_mask);
     2810        if (meminfo->dimm_mask == -1)
    26812811                goto hw_spd_err;
    2682         result = spd_set_memclk(ctrl, dimm_mask, meminfo);
     2812
     2813        result = spd_set_memclk(ctrl, meminfo);
    26832814        param     = result.param;
    2684         dimm_mask = result.dimm_mask;
    2685         if (dimm_mask < 0)
     2815        meminfo->dimm_mask = result.dimm_mask;
     2816        print_tx("spd_set_memclk: dimm_mask=0x%x\n", meminfo->dimm_mask);
     2817        if (meminfo->dimm_mask == -1)
    26862818                goto hw_spd_err;
    26872819
     
    26932825        paramx.divisor = get_exact_divisor(param->dch_memclk, paramx.divisor);
    26942826
    2695         dimm_mask = spd_set_dram_timing(ctrl, &paramx , dimm_mask, meminfo); // dimm_mask will be stored to meminfo->dimm_mask
    2696         if (dimm_mask < 0)
     2827        meminfo->dimm_mask = spd_set_dram_timing(ctrl, &paramx, meminfo);
     2828        print_tx("spd_set_dram_timing: dimm_mask=0x%x\n", meminfo->dimm_mask);
     2829        if (meminfo->dimm_mask == -1)
    26972830                goto hw_spd_err;
    26982831
     
    27022835 hw_spd_err:
    27032836        /* Unrecoverable error reading SPD data */
    2704         print_err("SPD error - reset\r\n");
    2705         hard_reset();
     2837        die("Unrecoverable error reading SPD data. No qualified DIMMs?");
    27062838        return;
    27072839}
  • trunk/coreboot-v2/src/northbridge/amd/amdk8/raminit_f_dqs.c

    r3053 r3614  
    11/*
    2         yhlu 2005.10 dqs training
     2 * This file is part of the coreboot project.
     3 *
     4 * Copyright (C) 2005 YingHai Lu
     5 * Copyright (C) 2008 Advanced Micro Devices, Inc.
     6 *
     7 * This program is free software; you can redistribute it and/or modify
     8 * it under the terms of the GNU General Public License as published by
     9 * the Free Software Foundation; version 2 of the License.
     10 *
     11 * This program is distributed in the hope that it will be useful,
     12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
     13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
     14 * GNU General Public License for more details.
     15 *
     16 * You should have received a copy of the GNU General Public License
     17 * along with this program; if not, write to the Free Software
     18 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301 USA
    319*/
     20
    421//0: mean no debug info
    522#define DQS_TRAIN_DEBUG 0
     
    188205static unsigned RcvrRankEnabled(const struct mem_controller *ctrl, int channel, int cs_idx, unsigned is_Width128, struct sys_info *sysinfo)
    189206{
    190         /* FIXME: process 64Muxed */
    191         if(!is_Width128) {
    192                 if(channel) return 0; // no channel b
    193         }
    194 
    195207        return ChipSelPresent(ctrl, cs_idx, sysinfo);
    196208}
     
    387399        uint32_t dword;
    388400        unsigned index = 0x10;
    389        
     401
     402        dword = pci_read_config32_index_wait(ctrl->f2, 0x98, index);
     403        pci_write_config32_index_wait(ctrl->f2, 0x98, index, dword);
     404
     405        index += 0x20;
    390406        dword = pci_read_config32_index_wait(ctrl->f2, 0x98, index);
    391407        pci_write_config32_index_wait(ctrl->f2, 0x98, index, dword);
     
    505521        unsigned PatternB;
    506522
    507         unsigned TestAddr0, TestAddr0B, TestAddr1, TestAddr1B;
    508 
    509         unsigned CurrRcvrCHADelay;
     523        unsigned TestAddr0, TestAddr0B, TestAddr1, TestAddr1B = 0;
     524
     525        unsigned CurrRcvrCHADelay = 0;
    510526
    511527        unsigned tmp;
     
    576592        /* for each channel */
    577593        CTLRMaxDelay = 0;
    578         for(channel = 0; (channel < 2) && (!Errors); channel++)
     594        channel = 0;
     595
     596        if (!(sysinfo->meminfo[ctrl->node_id].dimm_mask & 0x0F) &&
     597             (sysinfo->meminfo[ctrl->node_id].dimm_mask & 0xF0)) { /* channelB only? */
     598                channel = 1;
     599        }
     600
     601        for ( ; (channel < 2) && (!Errors); channel++)
    579602        {
    580603                print_debug_dqs("\tTrainRcvEn51: channel ",channel, 1);
     
    11051128
    11061129        unsigned LastTest;
    1107         unsigned RnkDlyFilterMax, RnkDlyFilterMin;
    1108         unsigned RnkDlySeqPassMax, RnkDlySeqPassMin;
     1130        unsigned RnkDlyFilterMax, RnkDlyFilterMin = 0;
     1131        unsigned RnkDlySeqPassMax, RnkDlySeqPassMin = 0;
    11091132
    11101133        Errors = 0;
     
    13891412
    13901413        Errors = 0;
    1391 
    13921414        channel = 0;
     1415
     1416        if (!(sysinfo->meminfo[ctrl->node_id].dimm_mask & 0x0F) &&
     1417             (sysinfo->meminfo[ctrl->node_id].dimm_mask & 0xF0)) { /* channelB only? */
     1418                channel = 1;
     1419        }
     1420
    13931421        while( (channel<2) && (!Errors)) {
    13941422                print_debug_dqs("\tTrainDQSRdWrPos: 1 channel ",channel, 1);
Note: See TracChangeset for help on using the changeset viewer.