static void ram_read32(u8 dimm_start, u32 offset) { u32 reg32, base_addr = 32 * 1024 * 1024 * dimm_start; if (offset == 0x55aa55aa) { reg32 = read32(base_addr); PRINTK_DEBUG(" Reading RAM at 0x%08x => 0x%08x\n", base_addr, reg32); PRINTK_DEBUG(" Writing RAM at 0x%08x <= 0x%08x\n", base_addr, offset); write32(base_addr, offset); reg32 = read32(base_addr); PRINTK_DEBUG(" Reading RAM at 0x%08x => 0x%08x\n", base_addr, reg32); } else { PRINTK_DEBUG(" to 0x%08x\n", base_addr + offset); read32(base_addr + offset); } }
static void die_on_spd_error(int spd_return_value) { if (spd_return_value < 0) PRINTK_DEBUG("Error reading SPD info: got %d\n", spd_return_value); /* if (spd_return_value < 0) die("Error reading SPD info\n"); */ }
static void do_ram_command(u32 command) { u32 reg32; /* Configure the RAM command. */ reg32 = pci_read_config32(NORTHBRIDGE, DRC); /* Clear bits 29, 10-8, 6-4. */ reg32 &= 0xdffff88f; reg32 |= command << 4; PRINTK_DEBUG(" Sending RAM command 0x%08x", reg32); pci_write_config32(NORTHBRIDGE, DRC, reg32); }
/** * Calculate the page size for each physical bank of the DIMM: * * log2(page size) = (# columns) + log2(data width) * * NOTE: Page size is the total number of data bits in a row. * * @param dimm_socket_address SMBus address of DIMM socket to interrogate. * @return log2(page size) for each side of the DIMM. */ static struct dimm_size sdram_spd_get_page_size(u8 dimm_socket_address) { uint16_t module_data_width; int value; struct dimm_size pgsz; pgsz.side1 = 0; pgsz.side2 = 0; // Side 1 value = spd_read_byte(dimm_socket_address, SPD_NUM_COLUMNS); die_on_spd_error(value); pgsz.side1 = value & 0xf; // # columns in bank 1 /* Get the module data width and convert it to a power of two */ value = spd_read_byte(dimm_socket_address, SPD_MODULE_DATA_WIDTH_MSB); die_on_spd_error(value); module_data_width = (value & 0xff) << 8; value = spd_read_byte(dimm_socket_address, SPD_MODULE_DATA_WIDTH_LSB); die_on_spd_error(value); module_data_width |= (value & 0xff); pgsz.side1 += log2(module_data_width); /* side two */ value = spd_read_byte(dimm_socket_address, SPD_NUM_DIMM_BANKS); die_on_spd_error(value); /* if (value > 2) die("Bad SPD value\n"); */ if (value > 2) PRINTK_DEBUG("Bad SPD value\n"); if (value == 2) { pgsz.side2 = pgsz.side1; // Assume symmetric banks until we know differently value = spd_read_byte(dimm_socket_address, SPD_NUM_COLUMNS); die_on_spd_error(value); if ((value & 0xf0) != 0) { // Asymmetric banks pgsz.side2 -= value & 0xf; /* Subtract out columns on side 1 */ pgsz.side2 += (value >> 4) & 0xf; /* Add in columns on side 2 */ }
static void initialize_dimm_rows(void) { int i, row; u8 dimm_start, dimm_end; unsigned device; dimm_start = 0; for (row = 0; row < (DIMM_SOCKETS * 2); row++) { switch (row) { case 0: device = DIMM0; break; case 1: device = DIMM0; break; case 2: device = DIMM0 + 1; break; case 3: device = DIMM0 + 1; break; } dimm_end = pci_read_config8(NORTHBRIDGE, DRB + row); if (dimm_end > dimm_start) { printk(BIOS_DEBUG, "Initializing SDRAM Row %u\n", row); /* NOP command */ PRINTK_DEBUG(" NOP\n"); do_ram_command(RAM_COMMAND_NOP); ram_read32(dimm_start, 0); udelay(200); /* Pre-charge all banks (at least 200 us after NOP) */ PRINTK_DEBUG(" Pre-charging all banks\n"); do_ram_command(RAM_COMMAND_PRECHARGE); ram_read32(dimm_start, 0); udelay(1); /* 8 CBR refreshes (Auto Refresh) */ PRINTK_DEBUG(" 8 CBR refreshes\n"); for (i = 0; i < 8; i++) { do_ram_command(RAM_COMMAND_CBR); ram_read32(dimm_start, 0); udelay(1); } /* MRS command */ /* TODO: Set offset 0x1d0 according to DRT values */ PRINTK_DEBUG(" MRS\n"); do_ram_command(RAM_COMMAND_MRS); ram_read32(dimm_start, 0x1d0); udelay(2); /* Set GMCH-M Mode Select bits back to NORMAL operation mode */ PRINTK_DEBUG(" Normal operation mode\n"); do_ram_command(RAM_COMMAND_NORMAL); ram_read32(dimm_start, 0); udelay(1); /* Perform a dummy memory read/write cycle */ PRINTK_DEBUG(" Performing dummy read/write\n"); ram_read32(dimm_start, 0x55aa55aa); udelay(1); } /* Set the start of the next DIMM. */ dimm_start = dimm_end; } }