What's the status of the code below?

Carl-Daniel

On 30.05.2007 04:36, Alfred Wanga wrote:
> Apologies everyone... I meant to tweak it after the feedback, but never
> could seem to get around to it. Here is the original patch again.
> 
> Signed-off-by: Alfred Wanga <[EMAIL PROTECTED]>
> 
> 
> Uwe Hermann wrote:
>> Hi,
>>
>> thanks for your patch. However, please sign-off all patches you submit,
>> otherwise we cannot commit them.
>>
>> http://linuxbios.org/Development_Guidelines#Sign-off_Procedure
>>
>> Please re-send this patch with a sign-off.
>>
>>
>> On Mon, Apr 30, 2007 at 10:47:42AM -0400, Alfred Wanga wrote:
>>> * PMCR - When should it be updated?
>>> Looking at the assembly, it seems as though it's ok to just set the
>>> final value before the RAM refresh code instead of waiting until
>>> afterwards, but I don't know for sure, so I left the original code
>>> alone.
>>
>> Yeah, I'm not sure either. Will look into that later...
>>
>>
>>> * sdram_enable delays
>>> I changed all the RAM timing delays (tRP, tRC, tMRD) to 1usec, since
>>> the timings are on the order of hundreds of nanoseconds (according to
>>> SPD values) and the smallest resolution timer available seems to be
>>> udelay() anyway. It should work for any SDRAM, and shaves a few
>>> milliseconds off previous code.
>>
>> Yep, when everything is working fine (or maybe even before) we'll lower
>> the delays. I set them quite high to make sure that it's definately not
>> a too short delay which is causing problems...
>>
>> If you want you can submit an extra patch with just the delay-fixes. I'll
>> test that on my hardware and commit if it still works with shorter
>> delays.
>>
>>
>>> Anyway, enough verbosity... take a look and see what you think.
>>> Unfortunately, besides testing the SPD code on memory dumps, I haven't
>>> tested the image.
>>
>> It doesn't compile, but that's not a problem in your code, but rather a
>> limitation of romcc ("too few registers").
>>
>> I'll try to move the 440BX code over to Cache as RAM, that'll be
>> needed for
>> LinuxBIOSv3 anyways. Expect a patch soonish...
>>
>>
>> After a few quick tests (after ripping out lots of code and debug
>> statements so that romcc compiles the code) it didn't seem to work on
>> my board. That may have lots of reasons (after all, I had to remove lots
>> of code and replace it with hardcoded values), but I'll look into it
>> in more detail.
>>
>>
>> Anyway, on the long run I don't want to merge this code as is (not a
>> pure translation of the v1 assembler code), but rather create a generic
>> framework for the RAM init on 440BX-ish chipsets.
>>
>> It should be possible to share most of the code for, e.g.
>>  - 440BX/ZX/FX/...
>>  - 430TX/...
>>  - and maybe more such (probably quite similar) chipsets.
>>
>> Thus, no spd_set_pgpol() etc., but more generic code (as far as
>> possible).
>>
>> But please re-send your patch with a sign-off, I think we can merge at
>> least some parts of it.
>>
>>
>>> Index: src/northbridge/intel/i440bx/raminit.c
>>> ===================================================================
>>> --- src/northbridge/intel/i440bx/raminit.c    (revision 2621)
>>> +++ src/northbridge/intel/i440bx/raminit.c    (working copy)
>>> @@ -377,7 +377,348 @@
>>>  DIMM-independant configuration functions.
>>>  
>>> -----------------------------------------------------------------------------*/
>>>
>>>  
>>> +/* Performs Bit Scan Right (MSB) Function (for SPD code) */
>>> +static inline uint8_t bsr(uint16_t val)
>>> +{
>>> +#if ASSEMBLY
>>> +    __asm__ __volatile__ ("bsr %1, %%ax;" : "=a"(val) : "a"(val));
>>
>> No assembler, please. Apart from the very early stuff which _has_ to be
>> written in assembler, LinuxBIOS should be written completely in C.
>>
>>
>>>      /* 2. Precharge all. Wait tRP. */
>>>      PRINT_DEBUG("RAM Enable 2: Precharge all\r\n");
>>> -    do_ram_command(ctrl, RAM_COMMAND_PRECHARGE, 0);
>>> -    mdelay(10);
>>> +    do_ram_command(ctrl, RAM_COMMAND_PRECHARGE, 0x2000);
>>
>> Why 0x2000 here?
>>
>>
>> Uwe.
> 
> 
> ------------------------------------------------------------------------
> 
> Index: src/northbridge/intel/i440bx/raminit.c
> ===================================================================
> --- src/northbridge/intel/i440bx/raminit.c    (revision 2621)
> +++ src/northbridge/intel/i440bx/raminit.c    (working copy)
> @@ -377,7 +377,348 @@
>  DIMM-independant configuration functions.
>  
> -----------------------------------------------------------------------------*/
>  
> +/* Performs Bit Scan Right (MSB) Function (for SPD code) */
> +static inline uint8_t bsr(uint16_t val)
> +{
> +#if ASSEMBLY
> +     __asm__ __volatile__ ("bsr %1, %%ax;" : "=a"(val) : "a"(val));
> +
> +     return (uint8_t)val;
> +#else
> +     uint8_t i;
> +
> +     for (i = 15; i > 0; i--)
> +     {
> +             if (val & 0x8000) break;
> +             val <<= 1;
> +     }
> +     return i;
> +#endif
> +}
> +
> +
>  /**
> + * Set the DRAM Row Boundary Registers for all DIMMs.
> + *
> + * @param Memory controller
> + */
> +static void spd_set_drb(const struct mem_controller *ctrl)
> +{
> +     uint8_t i, size = 0, addr = 0;
> +     uint16_t tmp;
> +
> +     for( i = 0; i < DIMM_SOCKETS; i++ )
> +     {
> +             size = (smbus_read_byte(ctrl->channel0[i], SPD_NUM_ROWS) & 0xf);
> +             size += (smbus_read_byte(ctrl->channel0[i], 
> +                     SPD_NUM_COLUMNS) & 0xf);
> +
> +             /* Skip calculations if SPD returns undefined data */
> +             if (size)
> +             {
> +                     tmp = smbus_read_byte(ctrl->channel0[i], 
> +                             SPD_NUM_BANKS_PER_SDRAM) & 0xff;
> +                     size += bsr(tmp);
> +
> +                     /* Get the module data width and convert it 
> +                      * to a power of two */
> +                     tmp = (smbus_read_byte(ctrl->channel0[i], 
> +                             SPD_MODULE_DATA_WIDTH_MSB) << 8) | 
> +                             (smbus_read_byte(ctrl->channel0[i], 
> +                              SPD_MODULE_DATA_WIDTH_LSB) & 0xff);
> +                     size += bsr(tmp);
> +
> +                     /* Now we have ram size as a power of two (less 1) */
> +                     /* 2^23 = 8MBit: seems like it should be MBits not MB */
> +                     size -= (23 - 1); /* Make it multiples of 8MBits */
> +             }
> +             addr += (size << 1);
> +
> +             PRINT_DEBUG("DRB");
> +             PRINT_DEBUG_HEX8(i<<1);
> +             PRINT_DEBUG(": ");
> +             PRINT_DEBUG_HEX8(addr);
> +             PRINT_DEBUG("\r\n");
> +
> +             /* Ignore the dimm if it is over 2GB */
> +             if (size >= 8)
> +                     pci_write_config8(ctrl->d0, DRB+(i<<1), 0);
> +             else
> +                     pci_write_config8(ctrl->d0, DRB+(i<<1), addr);
> +
> +
> +             /* side two */
> +             if (smbus_read_byte(ctrl->channel0[i], SPD_NUM_DIMM_BANKS) > 1)
> +             {
> +
> +#if 0                        /* Asymmetric code doesn't seem to work */
> +                     size = (smbus_read_byte(ctrl->channel0[i], 
> +                             SPD_NUM_ROWS) & 0xf0) >> 4;
> +                     size += (smbus_read_byte(ctrl->channel0[i], 
> +                             SPD_NUM_COLUMNS) & 0xf0) >> 4;
> +
> +                     if (size)
> +                     {
> +                             tmp = smbus_read_byte(ctrl->channel0[i], 
> +                                     SPD_NUM_BANKS_PER_SDRAM) & 0xff;
> +                             size += bsr(tmp);
> +
> +                             /* Get the module data width and convert it 
> +                              * to a power of two */
> +                             tmp = (smbus_read_byte(ctrl->channel0[i], 
> +                                     SPD_MODULE_DATA_WIDTH_MSB) << 8) |
> +                                     (smbus_read_byte(ctrl->channel0[i], 
> +                                      SPD_MODULE_DATA_WIDTH_LSB) & 0x1f);
> +                             size += bsr(tmp);
> +
> +                             /* Make it multiples of 8MBits */
> +                             size -= (23 - 1);
> +                     }
> +#endif
> +                     addr += (size << 1);
> +
> +                     PRINT_DEBUG("DRB");
> +                     PRINT_DEBUG_HEX8((i<<1)+1);
> +                     PRINT_DEBUG(": ");
> +                     PRINT_DEBUG_HEX8(addr);
> +                     PRINT_DEBUG("\r\n");
> +
> +                     /* Ignore the dimm if it is over 2GB (possible?) */
> +                     if (size >= 8)
> +                             pci_write_config8(ctrl->d0, DRB+(i<<1)+1, 0);
> +                     else
> +                             pci_write_config8(ctrl->d0, DRB+(i<<1)+1, addr);
> +             }
> +
> +     }
> +}
> +
> +/**
> + * Set the DRAM Control Register.
> + *
> + * @param Memory controller
> + */
> +static void spd_set_dramc(const struct mem_controller *ctrl)
> +{
> +     uint8_t i, memid;
> +     uint8_t dram_reg = 0;
> +
> +     /* Auto detect if RAM is registered or not. */
> +     /* The DRAMC register also controls the refresh rate but we can't
> +      * set that here because we must leave refresh disabled.
> +      */
> +
> +     /* Find the first dimm and assume the rest are the same (dangerous?) */
> +     for (i = 0; i < DIMM_SOCKETS; i++) 
> +     {
> +             /* This was changed from SPD_MODULE_ATTRIBUTES because
> +              * it can be equal to zero for an existing DIMM */
> +             memid = smbus_read_byte(ctrl->channel0[i], SPD_MEMORY_TYPE);
> +
> +             if (memid == SPD_MEMORY_TYPE_SDRAM) break;
> +     }
> +
> +     if (memid != SPD_MEMORY_TYPE_SDRAM)
> +     {
> +             /* no SDRAM memory! */
> +             die("No memory found!");
> +     }
> +
> +     memid = smbus_read_byte(ctrl->channel0[i], SPD_MODULE_ATTRIBUTES);
> +
> +     if (memid & 0x12)
> +             dram_reg |= 0x10; /* registered DRAM */
> +     else
> +             dram_reg |= 0x08; /* unregistered DRAM */
> +
> +     /* Write DRAM control register (without refresh) */
> +     PRINT_DEBUG("DRAMC: ");
> +     PRINT_DEBUG_HEX8(dram_reg);
> +     PRINT_DEBUG("\r\n");
> +     pci_write_config8(ctrl->d0, DRAMC, dram_reg);
> +}
> +
> +/**
> + * Set the SDRAM Row Page Size Register.
> + *
> + * @param Memory controller
> + */
> +static void spd_set_rps(const struct mem_controller *ctrl)
> +{
> +     uint16_t page, reg = 0;
> +     uint8_t i, cnt = 0;
> +
> +     /* The RPS register holds the size of a "page" of DRAM on each DIMM */
> +     /* default all page sizes to 2KB */
> +     for (i = 0; i < DIMM_SOCKETS; i++ )
> +     {
> +             page = (smbus_read_byte(ctrl->channel0[i], 
> +                     SPD_NUM_COLUMNS) & 0xf);
> +
> +             /* FIXME: do something with page sizes greater than 8KB!! */
> +             /* This workaround seems to generate valid values */
> +             if (page > 8) page = 8;
> +
> +             if (page <= 8)
> +             {
> +                     page <<= cnt;
> +                     reg |= page & 0xf;
> +
> +                     /* Only handling the symmetric case */
> +                     if ( smbus_read_byte(ctrl->channel0[i], 
> +                             SPD_NUM_DIMM_BANKS) > 1)
> +                             reg |= ((page & 0xf) << 4);
> +             }
> +             cnt += 4;
> +     }
> +
> +     /* Next block is for Ron's attempt to get registered to work.
> +      * We have just verified that we have to have this code. It appears that
> +      * the registered SDRAMs do indeed set the RPS wrong. Sheesh.
> +      *
> +      * We have verified that for registered DRAM the values are
> +      * 1/2 the size they should be. So we test for registered
> +      * and then double the sizes if needed.
> +      */
> +
> +     if (pci_read_config8(ctrl->d0, DRAMC) & 0x10)
> +     {
> +             /* BIOS makes weird page size for registered!
> +              * what we have found is you need to set the EVEN banks to
> +              * twice the size. Fortunately there is a very easy way to
> +              * do this. First, read the WORD value of the RPS register
> +              * and double the size of the EVEN banks we only need to add 1
> +              * because the size is log2
> +              */
> +             reg += 0x1111;
> +     }
> +
> +     /* now write that final value into RPS register */
> +     PRINT_DEBUG("RPS: ");
> +     PRINT_DEBUG_HEX16(reg);
> +     PRINT_DEBUG("\r\n");
> +     pci_write_config16(ctrl->d0, RPS, reg);
> +}
> +
> +/**
> + * Set the Paging Policy Register.
> + *
> + * @param Memory controller
> + */
> +static void spd_set_pgpol(const struct mem_controller *ctrl)
> +{
> +     uint16_t policy = 0;
> +     uint8_t i, cnt = 0;
> +
> +     /* The PGPOL register stores the number of logical banks per DIMM,
> +      * and number of clocks the DRAM controller waits in the idle
> +      * state.
> +      */
> +     for (i = 0; i < DIMM_SOCKETS; i++ )
> +     {
> +             if (smbus_read_byte(ctrl->channel0[i], 
> +                     SPD_NUM_BANKS_PER_SDRAM) >= 4)
> +             {
> +                     policy |= (0x1 << cnt);
> +
> +                     /* for now only handle the symmtrical case */
> +                     if (smbus_read_byte(ctrl->channel0[i], 
> +                             SPD_NUM_DIMM_BANKS) > 1)
> +                             policy |= (0x2 << cnt);
> +             }
> +             cnt += 2;
> +     }
> +
> +     /* 32 clocks DRAM idle time (change back to 0 after MRS?) */
> +     policy = (policy << 8) | 0x7;
> +
> +     PRINT_DEBUG("PGPOL: ");
> +     PRINT_DEBUG_HEX16(policy);
> +     PRINT_DEBUG("\r\n");
> +     pci_write_config16(ctrl->d0, PGPOL, policy);
> +}
> +
> +/**
> + * Set the SDRAM Control Register.
> + *
> + * @param Memory controller
> + */
> +static void spd_set_sdramc(const struct mem_controller *ctrl)
> +{
> +     uint8_t i;
> +     uint16_t reg = 0x0100;
> +
> +     for (i = 0; i < DIMM_SOCKETS; i++ )
> +     {
> +             /* Default settings are OK if only CAS=3 is supported */
> +             if (smbus_read_byte(ctrl->channel0[i], 
> +                     SPD_ACCEPTABLE_CAS_LATENCIES) & 0x2)
> +             {
> +                     PRINT_DEBUG("DIMM bank ");
> +                     PRINT_DEBUG_HEX8(i);
> +                     PRINT_DEBUG(" supports CAS=2\r\n");
> +                     pci_write_config8(ctrl->d0, SDRAMC, reg | 0x4);
> +                     break;
> +             }
> +     }
> +}
> +
> +/**
> + * Set the NBX Configuration Register.
> + *
> + * @param Memory controller
> + */
> +static inline void spd_set_nbxcfg(const struct mem_controller *ctrl)
> +{
> +     uint8_t i, cnt = 24;
> +     uint32_t reg;
> +
> +     /* Say all dimms have no ECC support */
> +     reg = pci_read_config32(ctrl->d0, NBXCFG) | 0xff000000;
> +
> +     for (i = 0; i < DIMM_SOCKETS; i++)
> +     {
> +             /* Module error correction type: 
> +              * 0 == None, 1 == Parity, 2 == ECC */
> +             if (smbus_read_byte(ctrl->channel0[i], 
> +                     SPD_DIMM_CONFIG_TYPE) & 0x2)
> +             {
> +                     reg ^= (0x1 << cnt);
> +
> +                     /* TODO: Set Data Integrity Mode for ECC Mode */
> +                     /* Is this right? What about other EC modes? */
> +                     /* reg |= 0x10; */
> +
> +                     if (smbus_read_byte(ctrl->channel0[i], 
> +                             SPD_NUM_DIMM_BANKS) > 1)
> +                     {
> +                             /* only the symmetric case is possible */
> +                             reg ^= (0x2 << cnt);
> +                     }
> +             }
> +             cnt += 2;
> +     }
> +
> +     /* set correct DRAM bus speed */
> +     for (i = 0; i < DIMM_SOCKETS; i++)
> +     {
> +             /* set to 66MHz if at least one DIMM is 66MHz only */
> +             if (smbus_read_byte(ctrl->channel0[i], 
> +                     SPD_INTEL_SPEC_FOR_FREQUENCY) == 0x66)
> +             {
> +                     /* TODO: need to handle?: 66Mhz->CL2 / 100MHz->CL3 */
> +                     reg |= 0x2000;
> +                     break;
> +             }
> +     }
> +
> +     PRINT_DEBUG("NBXCFG: ");
> +     PRINT_DEBUG_HEX32(reg);
> +     PRINT_DEBUG("\r\n");
> +     pci_write_config32(ctrl->d0, NBXCFG, reg);
> +}
> +
> +/**
>   * TODO.
>   *
>   * @param Memory controller
> @@ -387,6 +728,9 @@
>       int i, value;
>       uint8_t reg;
>  
> +     /* Set DRAM idle time to 0 after MRS (needed?) */
> +     pci_write_config8(ctrl->d0, PGPOL, 0);
> +
>       reg = pci_read_config8(ctrl->d0, DRAMC);
>  
>       for (i = 0; i < DIMM_SOCKETS; i++) {
> @@ -446,32 +790,25 @@
>   */
>  static void sdram_set_spd_registers(const struct mem_controller *ctrl)
>  {
> -     /* TODO: Don't hardcode the values here, get info via SPD. */
> +     PRINT_DEBUG("Reading SPD Registers...\r\n");
>  
> -     /* TODO: Set DRB0-DRB7. */
> -     pci_write_config8(ctrl->d0, DRB0, 0x08);
> -     pci_write_config8(ctrl->d0, DRB1, 0x08);
> -     pci_write_config8(ctrl->d0, DRB2, 0x08);
> -     pci_write_config8(ctrl->d0, DRB3, 0x08);
> -     pci_write_config8(ctrl->d0, DRB4, 0x08);
> -     pci_write_config8(ctrl->d0, DRB5, 0x08);
> -     pci_write_config8(ctrl->d0, DRB6, 0x08);
> -     pci_write_config8(ctrl->d0, DRB7, 0x08);
> +     /* Set DRB0-DRB7. */
> +     spd_set_drb(ctrl);
>  
> -     /* TODO: Set DRAMC. Don't enable refresh for now. */
> -     pci_write_config8(ctrl->d0, DRAMC, 0x08);
> +     /* Set DRAMC. Don't enable refresh for now. */
> +     spd_set_dramc(ctrl);
>  
> -     /* TODO: Set RPS. */
> -     pci_write_config16(ctrl->d0, RPS, 0x0001);
> +     /* Set RPS. */
> +     spd_set_rps(ctrl);
>  
> -     /* TODO: Set SDRAMC. */
> -     // pci_write_config16(ctrl->d0, SDRAMC, 0x0000);
> +     /* Set SDRAMC. */
> +     spd_set_sdramc(ctrl);
>  
> -     /* TODO: Set PGPOL. */
> -     pci_write_config16(ctrl->d0, PGPOL, 0x0107);
> +     /* Set PGPOL. */
> +     spd_set_pgpol(ctrl);
>  
> -     /* TODO: Set NBXCFG. */
> -     // pci_write_config32(ctrl->d0, NBXCFG, 0x0100220c);
> +     /* Set NBXCFG. */
> +     spd_set_nbxcfg(ctrl);
>  
>       /* TODO: Set PMCR? */
>       // pci_write_config8(ctrl->d0, PMCR, 0x14);
> @@ -495,45 +832,51 @@
>       int i;
>  
>       /* TODO: Use a delay here? Needed? */
> -     mdelay(200);
> +     /* Wait at least 1msec after device deselect (when is that?) */
> +     mdelay(1);
>  
> -     /* TODO: How long should the delays be? Fix later. */
> +     /* RAM Timings (tRP, tRC, tMRD) from SPD are on the order or 
> +      * nanoseconds (max=255ns) so 1usec should be more than enough 
> +      * time for any given SDRAM. */
>  
>       /* 1. Apply NOP. */
>       PRINT_DEBUG("RAM Enable 1: Apply NOP\r\n");
>       do_ram_command(ctrl, RAM_COMMAND_NOP, 0);
> -     mdelay(10);
> +     udelay(200); /* minimum pause of 200usec after the NOP */
>  
>       /* 2. Precharge all. Wait tRP. */
>       PRINT_DEBUG("RAM Enable 2: Precharge all\r\n");
> -     do_ram_command(ctrl, RAM_COMMAND_PRECHARGE, 0);
> -     mdelay(10);
> +     do_ram_command(ctrl, RAM_COMMAND_PRECHARGE, 0x2000);
> +     udelay(1);
>  
>       /* 3. Perform 8 refresh cycles. Wait tRC each time. */
>       PRINT_DEBUG("RAM Enable 3: CBR\r\n");
>       for (i = 0; i < 8; i++) {
>               do_ram_command(ctrl, RAM_COMMAND_CBR, 0);
> -             mdelay(10);
> +             udelay(1);
>       }
>  
>       /* 4. Mode register set. Wait two memory cycles. */
>       PRINT_DEBUG("RAM Enable 4: Mode register set\r\n");
> -     do_ram_command(ctrl, RAM_COMMAND_MRS, 0x1d0);
> -     // TODO: Is 0x1d0 correct?
> -     // do_ram_command(ctrl, RAM_COMMAND_MRS, 0x1d0000);
> -     mdelay(10);
> -     mdelay(10);
> +     /* Compute MRS Opcode (Burst length = 4, Interleaved) */
> +     i = 0x2a;
> +     /* If CAS = 3, modify opcode */
> +     if (pci_read_config8(ctrl->d0, SDRAMC) & 0x4 == 0) 
> +             i |= 0x10;
> +     i <<= 3;
> +     do_ram_command(ctrl, RAM_COMMAND_MRS, i); //0x1d0
> +     udelay(1);
>  
>       /* 5. Normal operation. */
>       PRINT_DEBUG("RAM Enable 5: Normal operation\r\n");
>       do_ram_command(ctrl, RAM_COMMAND_NORMAL, 0);
> -     mdelay(10);
> +     udelay(1);
>  
>       /* 6. Finally enable refresh. */
>       PRINT_DEBUG("RAM Enable 6: Enable refresh\r\n");
>       // pci_write_config8(ctrl->d0, PMCR, 0x10);
>       spd_enable_refresh(ctrl);
> -     mdelay(10);
> +     udelay(1);
>  
>       PRINT_DEBUG("Northbridge following SDRAM init:\r\n");
>       DUMPNORTH();
> 


-- 
http://www.hailfinger.org/


-- 
linuxbios mailing list
[email protected]
http://www.linuxbios.org/mailman/listinfo/linuxbios

Reply via email to