hi,
as promised the ram init routine for the intel 430fx chipset. completely untested yet, but seems to compile without errors (at least those i could have typed in ;))
the datasheet for the chipset is here: http://download.intel.com/design/chipsets/datashts/29051801.pdf
the routine does the following: 1. disable all caches 2. set ram size to 0 3. take one row and set its ram size to the maximum value and its type to edo 4. write some data in the row 5. enable edo detection 6. read the data back 7. if the data read is the data written it is edo 8. if the data read is NOT the data written, write some more data 9. read the data back (without edo detection) 10. if the data read is the data written it is fpm 11. if the data read is NOT the data written, the row is empty 12. detect the real size of the row and the dram technology (i'll write some more about that tomorrow, sorry, it's late already :)) 13. clear all settings for the current row 14. restart at 3. as long as not all rows have been processed 15. write the size and type (edo/fpm) of all rows 16. turn the caches back on ;)
the routine isn't doing any tests on dram timings yet. this COULD be implemented or we should ask the user to enter something useful. upto now the slowest dram timings are used which is not that nice but still it should work. anyway, i could implement some more chipset settings regarding pci performance and behaviour but i guess it doesn't belong in the raminit.c, does it? now have a look at the code and try to understand it ;) Holger
/* * This file is part of the LinuxBIOS project. * * Copyright (C) * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */
#include <delay.h> #include <device/device.h> #include "raminit.h"
/*----------------------------------------------------------------------------- Macros and definitions. -----------------------------------------------------------------------------*/
/* Uncomment this to enable debugging output. */ #define DEBUG_RAM_SETUP 1
/* Debugging macros. */ #if defined(DEBUG_RAM_SETUP) #define PRINT_DEBUG(x) print_debug(x) #define PRINT_DEBUG_HEX8(x) print_debug_hex8(x) #define PRINT_DEBUG_HEX16(x) print_debug_hex16(x) #define PRINT_DEBUG_HEX32(x) print_debug_hex32(x) #define DUMPNORTH() dump_pci_device(PCI_DEV(0, 0, 0)) #else #define PRINT_DEBUG_(x) #define PRINT_DEBUG_HEX8(x) #define PRINT_DEBUG_HEX16(x) #define PRINT_DEBUG_HEX32(x) #define DUMPNORTH() #endif
/*----------------------------------------------------------------------------- EDO/FP/SDRAM detection routine. ----------------------------------------------------------------------------*/
/** * Initializes a row before it can be checked for DRAM */ static void initialize_row(const struct mem_controller* ctrl, const uint8_t u8_row) {
uint8_t u8_DRAMSize = 0; uint8_t u8_DRAMType = 1;
/* Initialize the current row to EDO and 32MB (maximum size) */ u8_DRAMType <<= u8_row; u8_DRAMSize == SIMM_ROW_SIZE_MAX / SIMM_GRANULARITY;
pci_write_config8(ctrl->d0, ((uint8_t)e_DRAM_ROW_BOUNDARY_BASE) + u8_row, u8_DRAMSize);
pci_write_config8(ctrl->d0, ((uint8_t)e_DRAM_ROW_TYPE), u8_DRAMType); }
/** * Clears a row after it has been checked for DRAM */ static void clear_row(const struct mem_controller* ctrl, const uint8_t u8_row) {
uint8_t u8_DRAMSize = 0;
pci_write_config8(ctrl->d0, ((uint8_t)e_DRAM_ROW_BOUNDARY_BASE) + u8_row, u8_DRAMSize); }
/** * Detects the type of RAM in the current row */ static void detect_type(const struct mem_controller* ctrl, uint8_t* pu8_DRAMSize, uint8_t* pu8_DRAMType, const uint8_t u8_row) {
uint8_t u8_DRAMC = 0; uint32_t u32_AA0 = 0x0; uint32_t u32_AA8 = 0x8; uint32_t u32_DD1 = 0xAAAAAAAAUL; uint32_t u32_DD2 = 0x55555555UL; uint32_t u32_DD3 = 0; uint32_t u32_DD4 = 0;
/* Write some data */ dimm_write32(u32_AA0, u32_DD1); dimm_write32(u32_AA8, u32_DD2);
/* Enable EDO detection mode */ u8_DRAMC = pci_read_config8(ctrl->d0, ((uint8_t)e_DRAM_CONTROL));
u8_DRAMC |= ((uint8_t)e_DRAMC_EDO_DETECT); pci_write_config8(ctrl->d0, ((uint8_t)e_DRAM_CONTROL), u8_DRAMC);
/* Read the data back */ dimm_read32(u32_AA0, u32_DD3); dimm_read32(u32_AA8, u32_DD4);
/* Disable EDO detection mode */ u8_DRAMC &= ~((uint8_t)e_DRAMC_EDO_DETECT); pci_write_config8(ctrl->d0, ((uint8_t)e_DRAM_CONTROL), u8_DRAMC);
if(u32_DD3 != u32_DD1 || u32_DD4 != u32_DD2) { /* No EDO RAM. Test FPM next */
/* Set the current bank to FPM */ pci_write_config8(ctrl->d0, ((uint8_t)e_DRAM_ROW_TYPE), 0x00);
/* Write some data */ dimm_write32(u32_AA0, u32_DD1); dimm_write32(u32_AA8, u32_DD2);
/* Read the data back */ dimm_read32(u32_AA0, u32_DD3); dimm_read32(u32_AA8, u32_DD4);
if(u32_DD3 != u32_DD1 || u32_DD4 != u32_DD2) { /* No FPM RAM. No RAM at all! */ *(pu8_DRAMSize) = 0; } else { *(pu8_DRAMType) &= ~(1 << u8_row); } } else { /* EDO found */ *(pu8_DRAMType) |= (1 << u8_row); } }
/** * Detects DRAM row size */ static void detect_size(const struct mem_controller* ctrl, uint8_t* au8_DRAMSize, const uint8_t u8_row) { uint32_t u32_AA0 = 0x0; uint32_t u32_AA8 = 1; uint32_t u32_DD1 = 0x55555555UL; uint32_t u32_DD2 = 0xAAAAAAAAUL; uint32_t u32_DD3 = 0xFEDCBA98UL; uint32_t u32_DD4 = 0; uint8_t u8_size_detected = 0; uint8_t u8_type = 0;
for(;;) { /* Write some data */ dimm_write32(u32_AA0, u32_DD1);
switch (au8_DRAMSize[u8_row]) { case e_4MB : { for(u8_type = 0; u8_type < RCA_8MB_TYPES; u8_type++) { /* Prepare the first address */ u32_AA8 = (1 << s_DRAMT8MB[u8_type].u8_ColumnAddress);
/* Write some more data */ dimm_write32(u32_AA8, u32_DD2);
/* Write even more data to yet another address for asymetric DRAM */ if(s_DRAMT8MB[u8_type].u8_ColumnAddress != s_DRAMT8MB[u8_type].u8_RowAddress) { /* Prepare the second address */ u32_AA8 = (1 << s_DRAMT8MB[u8_type].u8_RowAddress);
/* Write even more data */ dimm_write32(u32_AA8, u32_DD3); }
/* Read data back */ dimm_read32(u32_AA0, u32_DD4);
if(u32_DD1 == u32_DD4) { /* Found DRAM with correct size and technology */ au8_DRAMSize[u8_row] = ((uint8_t)e_4MB); u8_size_detected = 1; break; } }
/* No DRAM was found! */ if(u8_size_detected == 0) { au8_DRAMSize[u8_row] = ((uint8_t)e_EMPTY);
/* FIXME: Not sure if this is really needed */ pci_write_config8(ctrl->d0, ((uint8_t)e_DRAM_ROW_BOUNDARY_BASE) + u8_row, au8_DRAMSize[u8_row]); }
break; }
case e_8MB : { for(u8_type = 0; u8_type < RCA_8MB_TYPES; u8_type++) { /* Prepare the first address */ u32_AA8 = (1 << s_DRAMT8MB[u8_type].u8_ColumnAddress);
/* Write some more data */ dimm_write32(u32_AA8, u32_DD2);
/* Write even more data to yet another address for asymetric DRAM */ if(s_DRAMT8MB[u8_type].u8_ColumnAddress != s_DRAMT8MB[u8_type].u8_RowAddress) { /* Prepare the second address */ u32_AA8 = (1 << s_DRAMT8MB[u8_type].u8_RowAddress);
/* Write even more data */ dimm_write32(u32_AA8, u32_DD3); }
/* Read data back */ dimm_read32(u32_AA0, u32_DD4);
if(u32_DD1 == u32_DD4) { /* Found DRAM with correct size and technology */ au8_DRAMSize[u8_row] = ((uint8_t)e_8MB); u8_size_detected = 1; break; } }
/* Test for 4MB next if no 8MB DRAM was found */ if(u8_size_detected == 0) { au8_DRAMSize[u8_row] = ((uint8_t)e_4MB);
/* FIXME: Not sure if this is really needed */ pci_write_config8(ctrl->d0, ((uint8_t)e_DRAM_ROW_BOUNDARY_BASE) + u8_row, au8_DRAMSize[u8_row]); }
break; }
case e_16MB : { for(u8_type = 0; u8_type < RCA_16MB_TYPES; u8_type++) { /* Prepare the first address */ u32_AA8 = (1 << s_DRAMT16MB[u8_type].u8_ColumnAddress);
/* Write some more data */ dimm_write32(u32_AA8, u32_DD2);
/* Write even more data to yet another address for asymetric DRAM */ if(s_DRAMT16MB[u8_type].u8_ColumnAddress != s_DRAMT16MB[u8_type].u8_RowAddress) { /* Prepare the second address */ u32_AA8 = (1 << s_DRAMT16MB[u8_type].u8_RowAddress);
/* Write even more data */ dimm_write32(u32_AA8, u32_DD3); }
/* Read data back */ dimm_read32(u32_AA0, u32_DD4);
if(u32_DD1 == u32_DD4) { /* Found DRAM with correct size and technology */ au8_DRAMSize[u8_row] = ((uint8_t)e_16MB); u8_size_detected = 1; break; } }
/* Test for 8MB next if no 16MB DRAM was found */ if(u8_size_detected == 0) { au8_DRAMSize[u8_row] = ((uint8_t)e_8MB);
/* FIXME: Not sure if this is really needed */ pci_write_config8(ctrl->d0, ((uint8_t)e_DRAM_ROW_BOUNDARY_BASE) + u8_row, au8_DRAMSize[u8_row]); }
break; }
case e_32MB : { for(u8_type = 0; u8_type < RCA_32MB_TYPES; u8_type++) { /* Prepare the first address */ u32_AA8 = (1 << s_DRAMT32MB[u8_type].u8_ColumnAddress);
/* Write some more data */ dimm_write32(u32_AA8, u32_DD2);
/* Write even more data to yet another address for asymetric DRAM */ if(s_DRAMT32MB[u8_type].u8_ColumnAddress != s_DRAMT32MB[u8_type].u8_RowAddress) { /* Prepare the second address */ u32_AA8 = (1 << s_DRAMT32MB[u8_type].u8_RowAddress);
/* Write even more data */ dimm_write32(u32_AA8, u32_DD3); }
/* Read data back */ dimm_read32(u32_AA0, u32_DD4);
if(u32_DD1 == u32_DD4) { /* Found DRAM with correct size and technology */ au8_DRAMSize[u8_row] = ((uint8_t)e_32MB); u8_size_detected = 1; break; } }
/* Test for 16MB next if no 32MB DRAM was found */ if(u8_size_detected == 0) { au8_DRAMSize[u8_row] = ((uint8_t)e_16MB);
/* FIXME: Not sure if this is really needed */ pci_write_config8(ctrl->d0, ((uint8_t)e_DRAM_ROW_BOUNDARY_BASE) + u8_row, au8_DRAMSize[u8_row]); }
break; }
default : { /* Unknown DRAM size */ au8_DRAMSize[u8_row] = ((uint8_t)e_EMPTY);
/* FIXME: Not sure if this is really needed */ pci_write_config8(ctrl->d0, ((uint8_t)e_DRAM_ROW_BOUNDARY_BASE) + u8_row, au8_DRAMSize[u8_row]); break; } }
/* Quit if the size of the current row was detected or an error occured */ if((u8_size_detected != 0) || au8_DRAMSize[u8_row] == ((uint8_t)e_EMPTY)){ break; } } }
static void ram_detection(const struct mem_controller* ctrl) {
uint8_t u8_row = 0; uint8_t au8_DRAMSize[SIMM_SOCKETS]; uint8_t u8_DRAMType = 0; uint8_t u8_DRAMBoundary = 0; uint8_t u8_CacheControl = 0; uint8_t u8_CacheOff = 0;
/* Turn off cache (L1 & L2) */ u8_CacheControl = pci_read_config8(ctrl->d0, ((uint8_t)e_CACHE_CONTROL));
u8_CacheOff = u8_CacheControl & (~(e_CC_FIRST_CACHE_ENABLE) & ~(e_CC_SECONDARY_CACHE_SIZE) & ~(e_CC_SECONDARY_CACHE_MISS));
pci_write_config8(ctrl->d0, ((uint8_t)e_CACHE_CONTROL), u8_CacheOff);
/* Set size of DRAM to 0 for all rows */ for(u8_row = 0; u8_row < SIMM_SOCKETS; u8_row++) { au8_DRAMSize[u8_row] = 0; pci_write_config8(ctrl->d0, ((uint8_t)e_DRAM_ROW_BOUNDARY_BASE) + u8_row, au8_DRAMSize); }
/* Detect RAM presence and type in all rows */ for(u8_row = 0; u8_row < SIMM_SOCKETS; u8_row++) {
/* Start of DRAM type detection */ /* Initialize the current row */ initialize_row(ctrl, u8_row);
/* Detect type of ram in the current row */ detect_type(ctrl, au8_DRAMSize, &u8_DRAMType, u8_row);
/* Check if any DRAM was found in this row */ if(au8_DRAMSize[u8_row] == 0) { /* No DRAM found. Skip the rest. */ continue; }
/* Detect column address type and the size of the current row */ detect_size(ctrl, au8_DRAMSize, u8_row);
/* Clear all settings made for the current row */ clear_row(ctrl, u8_row); }
/* Turn L1 and L2 caches back on */ pci_write_config8(ctrl->d0, ((uint8_t)e_CACHE_CONTROL), u8_CacheControl);
/* Set the type of all detected DRAM rows */ pci_write_config8(ctrl->d0, ((uint8_t)e_DRAM_ROW_TYPE), u8_DRAMType);
/* Set the DRAM row boundaries */ for(u8_row = 0; u8_row < SIMM_SOCKETS; u8_row++) { u8_DRAMBoundary += au8_DRAMSize[u8_row];
pci_write_config8(ctrl->d0, ((uint8_t)e_DRAM_ROW_BOUNDARY_BASE) + u8_row, u8_DRAMBoundary); } }
/* * This file is part of the LinuxBIOS project. * * Copyright (C) * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */
#ifndef RAMINIT_H #define RAMINIT_H
#define SIMM_SOCKETS 5 #define SIMM_ROW_SIZE_MAX 32 #define SIMM_GRANULARITY 4
enum E_DRAM_SIZE { e_EMPTY = 0, e_4MB = 1, e_8MB = 2, e_16MB = 4, e_32MB = 8 };
enum E_REGISTERS { e_CACHE_CONTROL = 0x52, e_DRAM_CONTROL = 0x57, e_DRAM_ROW_BOUNDARY_BASE = 0x60, e_DRAM_ROW_TYPE = 0x68 };
enum E_CACHE_CONTROL_MASKS { e_CC_SECONDARY_CACHE_SIZE = 0xC0, e_CC_SRAM_TYPE = 0x30, e_CC_NA_DISABLE = 0x04, e_CC_SECONDARY_CACHE_MISS = 0x02, e_CC_FIRST_CACHE_ENABLE = 0x01 };
enum E_DRAM_CONTROL_MASKS { e_DRAMC_HOLE_ENABLE = 0xC0, e_DRAMC_EDO_DETECT = 0x08, e_DRAMC_HOST_BUS_FREQUENCY = 0x07 };
enum E_DRAM_ROW_BOUNDARY_MASKS { e_DRB_ROW_BOUNDARY = 0x2F };
enum E_DRAM_ROW_TYPE_MASKS { e_DRT_ROW_TYPE = 0x1F };
#define RCA_32MB_TYPES 2 #define RCA_16MB_TYPES 1 #define RCA_8MB_TYPES 1 #define RCA_4MB_TYPES 1
struct S_DRAMTechnology { uint8_t u8_RowAddress; uint8_t u8_ColumnAddress; };
/** * row x col - DRAM size * 12 x 10 - 32MB * 11 x 11 - 32MB */
static struct S_DRAMTechnology s_DRAMT32MB[] = { {24, 22}, {23, 24} };
/** * row x col - DRAM size * 11 x 10 - 16MB */ struct S_DRAMTechnology s_DRAMT16MB[] = { {23, 22} };
/** * row x col - DRAM size * 10 x 10 - 8MB */ struct S_DRAMTechnology s_DRAMT8MB[] = { {21, 22} };
/** * row x col - DRAM size * 10 x 9 - 4MB */ struct S_DRAMTechnology s_DRAMT4MB[] = { {21, 11} };
struct mem_controller { device_t d0; uint16_t channel0[SIMM_SOCKETS]; };
#endif /* RAMINIT_H */
On Fri, Aug 10, 2007 at 12:09:36AM +0200, popkonserve wrote:
/*
- This file is part of the LinuxBIOS project.
- Copyright (C)
Please add 2007 Holger Yourlastname
static void initialize_row(const struct mem_controller* ctrl, const uint8_t u8_row) {
uint8_t u8_DRAMSize = 0; uint8_t u8_DRAMType = 1;
/* Initialize the current row to EDO and 32MB (maximum size) */ u8_DRAMType <<= u8_row; u8_DRAMSize == SIMM_ROW_SIZE_MAX / SIMM_GRANULARITY;
Typo == instead of = ?
pci_write_config8(ctrl->d0, ((uint8_t)e_DRAM_ROW_BOUNDARY_BASE) + u8_row, u8_DRAMSize);
..will always write 0 otherwise.
pci_write_config8(ctrl->d0, ((uint8_t)e_DRAM_ROW_TYPE), u8_DRAMType);
Does this want to be a set_row_type() function?
/* Enable EDO detection mode */ u8_DRAMC = pci_read_config8(ctrl->d0, ((uint8_t)e_DRAM_CONTROL));
u8_DRAMC |= ((uint8_t)e_DRAMC_EDO_DETECT); pci_write_config8(ctrl->d0, ((uint8_t)e_DRAM_CONTROL), u8_DRAMC);
Maybe also candidate for a separate function?
static void detect_size(const struct mem_controller* ctrl,
[..]
for(;;) {
[..]
/* Quit if the size of the current row was detected or an error occured */ if((u8_size_detected != 0) || au8_DRAMSize[u8_row] == ((uint8_t)e_EMPTY)){ break; }
}
Please change the for() into do {} while(); to improve readability.
/* Turn off cache (L1 & L2) */
Isn't there a function for this already? If not, should there be?
/* Set size of DRAM to 0 for all rows */ for(u8_row = 0; u8_row < SIMM_SOCKETS; u8_row++) { au8_DRAMSize[u8_row] = 0; pci_write_config8(ctrl->d0, ((uint8_t)e_DRAM_ROW_BOUNDARY_BASE) + u8_row, au8_DRAMSize); }
/* Detect RAM presence and type in all rows */ for(u8_row = 0; u8_row < SIMM_SOCKETS; u8_row++) {
All rows need to be zeroed first to make this reliable?
/* Detect type of ram in the current row */ detect_type(ctrl, au8_DRAMSize, &u8_DRAMType, u8_row); /* Check if any DRAM was found in this row */ if(au8_DRAMSize[u8_row] == 0) { /* No DRAM found. Skip the rest. */ continue; }
A bit unexpected to have detect_type() return meaningful data in a Size parameter.
Maybe a return value from detect_type() would be nicer?
Looks good! :)
//Peter
- This file is part of the LinuxBIOS project.
- Copyright (C)
Please add 2007 Holger Yourlastname
fixed. left it out as it isn't tested at all..and shouldn't be used as long as it isn't.
Typo == instead of = ?
fixed, too :)
pci_write_config8(ctrl->d0, ((uint8_t)e_DRAM_ROW_TYPE), u8_DRAMType);
Does this want to be a set_row_type() function?
hmm, wouldn't make much sense here i guess. the register that stores the type of drams used is a single register for all rows. so the only thing the function would do would be a single write to the same register for all rows. only the data would change.
/* Enable EDO detection mode */
Maybe also candidate for a separate function?
then i would have to write a disable_edo_detection, too. and again all they would to is to write one special register. both calls are alread inside a function that is called detect_type and that's where they belong :)
Please change the for() into do {} while(); to improve readability.
done.
/* Turn off cache (L1 & L2) */
Isn't there a function for this already? If not, should there be?
there should be..i didn't look. while L1 cache could be switched off on socket 7 processors, the L2 cache is controlled by the chipset. i don't know if there's a 'disable L2 cache' pin on socket 7 processors that would tell the chipset to ignore its L2 cache. so i used the chipset's function rather than leaving it as TODO.
/* Set size of DRAM to 0 for all rows */ for(u8_row = 0; u8_row < SIMM_SOCKETS; u8_row++) { au8_DRAMSize[u8_row] = 0; pci_write_config8(ctrl->d0, ((uint8_t)e_DRAM_ROW_BOUNDARY_BASE) + u8_row, au8_DRAMSize); }
/* Detect RAM presence and type in all rows */ for(u8_row = 0; u8_row < SIMM_SOCKETS; u8_row++) {
All rows need to be zeroed first to make this reliable?
well, there are two kind answers: yes and no. if i do not set all rows to zero, the writes in the type and size detection routines would have to be recalculated for each row. they would have to take into account that there already is ram in front of them and they would have to write to ex. OFFSET + AA0 just to avoid some more mind breaking calculation i decided to set the ram size to zero for all rows before the detection starts and set it back to zero for the current row when the detection is over. if there's a problem with that i could rewrite the functions to use offsets, too.
/* Detect type of ram in the current row */ detect_type(ctrl, au8_DRAMSize, &u8_DRAMType, u8_row);
/* Check if any DRAM was found in this row */ if(au8_DRAMSize[u8_row] == 0) { /* No DRAM found. Skip the rest. */ continue; }
A bit unexpected to have detect_type() return meaningful data in a Size parameter.
i use the size parameter as indication if the row is populated at all and thus skipping the rest of the detection process (why trying to detect anything else if there's no ram in there?).
Maybe a return value from detect_type() would be nicer?
yes, maybe. no problem to change it if the others agree on this one. i would want to reuse the code for the other socket 7 chipsets, too. even with a return parameter reuseability wouldn't be hurt at all. Holger
Hi,
On Fri, Aug 10, 2007 at 12:09:36AM +0200, popkonserve wrote:
the routine does the following:
- disable all caches
- set ram size to 0
- take one row and set its ram size to the maximum value and its type to
edo 4. write some data in the row 5. enable edo detection 6. read the data back 7. if the data read is the data written it is edo 8. if the data read is NOT the data written, write some more data 9. read the data back (without edo detection) 10. if the data read is the data written it is fpm 11. if the data read is NOT the data written, the row is empty 12. detect the real size of the row and the dram technology (i'll write some more about that tomorrow, sorry, it's late already :)) 13. clear all settings for the current row 14. restart at 3. as long as not all rows have been processed 15. write the size and type (edo/fpm) of all rows 16. turn the caches back on ;)
Please add this documentation to the source code as a (Doygen) comment.
/*----------------------------------------------------------------------------- EDO/FP/SDRAM detection routine. ----------------------------------------------------------------------------*/
/**
- Initializes a row before it can be checked for DRAM
*/ static void initialize_row(const struct mem_controller* ctrl, const uint8_t u8_row) {
Please don't encode type information in variable names. "row" is fine.
uint8_t u8_DRAMSize = 0; uint8_t u8_DRAMType = 1;
Use all-lowercase variable and function names, please. There are many other coding style issues in the code, please read
http://linuxbios.org/Development_Guidelines#Coding_Guidelines http://lxr.linux.no/source/Documentation/CodingStyle
and fix the code to use the Linux kernel coding style.
/* Initialize the current row to EDO and 32MB (maximum size) */ u8_DRAMType <<= u8_row; u8_DRAMSize == SIMM_ROW_SIZE_MAX / SIMM_GRANULARITY;
pci_write_config8(ctrl->d0, ((uint8_t)e_DRAM_ROW_BOUNDARY_BASE) + u8_row,
Is the (uint8_t) cast really needed? Otherwise please drop it.
u8_DRAMSize);
pci_write_config8(ctrl->d0, ((uint8_t)e_DRAM_ROW_TYPE), u8_DRAMType); }
/**
- Clears a row after it has been checked for DRAM
*/ static void clear_row(const struct mem_controller* ctrl, const uint8_t u8_row) {
I think the 'const' for u8_row is not needed (not needed for integer types in general, I think).
/**
- Detects DRAM row size
*/ static void detect_size(const struct mem_controller* ctrl, uint8_t* au8_DRAMSize, const uint8_t u8_row) { uint32_t u32_AA0 = 0x0; uint32_t u32_AA8 = 1; uint32_t u32_DD1 = 0x55555555UL; uint32_t u32_DD2 = 0xAAAAAAAAUL; uint32_t u32_DD3 = 0xFEDCBA98UL; uint32_t u32_DD4 = 0; uint8_t u8_size_detected = 0; uint8_t u8_type = 0;
for(;;) { /* Write some data */ dimm_write32(u32_AA0, u32_DD1);
switch (au8_DRAMSize[u8_row]) { case e_4MB : {
[...]
case e_8MB : {
[...]
case e_16MB : {
The code here looks pretty similar, can it be generalized in a common function?
static struct S_DRAMTechnology s_DRAMT32MB[] = {
You can make this static const struct S_DRAMTechnology s_DRAMT32MB[] for structs with purely constant content.
{24, 22}, {23, 24} };
Uwe.
the routine does the following: [...]
Please add this documentation to the source code as a (Doygen) comment.
i don't think that this belongs into the source code. i would rather put it into a separate document that describes the general sizing algorithm. or even in a document that describes the code used for the 430FX.
here is an article on memory sizing: http://www.rcollins.org/articles/memsize/MemSizing.html (please note: the MA table is different for almost every chipset :( and please ignore the bank switching stuff..)
i did fix some more errors in the code btw. and beautified it to fit the coding rules. i'll post a diff or a complete version (depends on the number of changes) soon. Holger
On Sat, Aug 11, 2007 at 12:42:57PM +0200, popkonserve wrote:
the routine does the following: [...]
Please add this documentation to the source code as a (Doygen) comment.
i don't think that this belongs into the source code. i would rather put it into a separate document that describes the general sizing algorithm.
I like doxygen too.
or even in a document that describes the code used for the 430FX.
Well, but then we would end up with 100s of documents like that..
Of course, any documentation effort on the wiki would be most welcome, but that's a whole new project in itself...
//Peter
i tried another approach, looks way nicer now. any comments? let me know :) Holger
/* IN RAMINIT.H */ enum E_DRAM_TYPE { DRT_SYMMETRIC = 0, DRT_ASYMMETRIC = 1 };
struct S_DRAMTechnology { uint8_t row_address; uint8_t column_address; uint16_t row_size; enum E_DRAM_TYPE type; };
static const struct S_DRAMTechnology dram_technology[] = { { 0, 24, 32, DRT_SYMMETRIC}, {24, 22, 32, DRT_ASYMMETRIC}, {23, 22, 16, DRT_ASYMMETRIC}, { 0, 22, 8, DRT_SYMMETRIC}, {21, 11, 4, DRT_ASYMMETRIC}, { 0, 0, 0, DRT_SYMMETRIC} };
/* IN RAMINIT.C */ static void detect_size(const struct mem_controller* ctrl, uint8_t* dram_size, const uint8_t row) { uint32_t address0 = 0x0; uint32_t address8 = 1; uint32_t data1 = 0x55555555UL; uint32_t data2 = 0xAAAAAAAAUL; uint32_t data3 = 0xFEDCBA98UL; uint32_t data4 = 0; uint8_t detected = 0; uint8_t index = 0;
do { /* FIXME: Not sure if this is really needed */ pci_write_config8(ctrl->d0, CR_DRAM_ROW_BOUNDARY_BASE + row, dram_technology[index].row_size / SIMM_GRANULARITY);
/* Write some data */ dimm_write32(address0, data1);
/* Prepare the first address */ address8 = (1 << dram_technology[index].column_address);
/* Write some more data */ dimm_write32(address8, data2);
/* Write even more data to yet another address for asymmetric DRAM */ if(dram_technology[index].type == DRT_ASYMMETRIC) { /* Prepare the second address */ address8 = (1 << dram_technology[index].row_address);
/* Write even more data */ dimm_write32(address8, data3); }
/* Read data back */ dimm_read32(address0, data4);
if(data1 == data4) { /* Found DRAM with correct size and technology */ dram_size[row] = dram_technology[index].row_address / SIMM_GRANULARITY; detected = 1; break; } else { /* No RAM found yet. Try next addressing scheme. */ index++; } } while(detected == 0 || dram_technology[index].row_size != 0);
if(detected == 0) { dram_size[row] = DRAM_EMPTY; } }