i know it's been a while, but finally i found time to almost finish the
dram detection for the ALi Aladdin Pro II (M1621) as found on the
PcChips M726/M727/M729. the multibanking detetion is still missing and
i've not bothered about any ram timings or other northbridge
(performance) settings yet. and i haven't compiled the source yet, it
may be still full of typing errors..
anyway, i included the important files just if someone wants to have a
quick glance on the code. oh, and please excuse the horrible size
detection monster..i'll try to beautify it later.
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 <spd.h>
#include <sdram_mode.h>
#include <delay.h>
#include "m1621.h"
/*-----------------------------------------------------------------------------
Macros and definitions.
-----------------------------------------------------------------------------*/
/* Uncomment this to enable debugging output. */
#define DEBUG_RAM_SETUP 1
#define REFRESH_66 0x0411
#define REFRESH_75 0x0493;
#define REFRESH_83 0x0516;
#define REFRESH_100 0x0618;
/* 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 configuration functions.
-----------------------------------------------------------------------------*/
/**
* Routine for the RAM detection
*/
static void ram_detection(const struct mem_controller* ctrl)
{
uint8_t u8_fsb100 = 0;
uint16_t u16_reg;
uint32_t u32_reg;
uint32_t au32_dram_row[DIMM_SOCKETS * DIMM_ROWS];
/* Detect Host Clock Bus Frequency */
u32_reg = pci_read_config(ctrl->d0, CR_MRNG);
u8_fsb100 = (uint8_t)(u32_reg >> 30);
/* Turn off cache (L1 & L2) */
//TODO
/* Disable DRAM ECC function */
u32_reg = pci_read_config32(ctrl->d0, CR_MCMD);
u32_reg &= ~((uint32_t)e_MEMORY_PROTECTION);
/* Enable DRAM refresh and set the refresh cycle counter */
u32_reg &= ((uint32_t)e_DRAM_REFRESH_ENABLE);
u32_reg &= ~((uint32_t)e_DRAM_REFRESH_CYCLE);
if(u8_fsb100) {
u32_reg |= ((uint32_t)REFRESH_100);
}
else {
/* TODO determine the real fsb by cpu core speed / multiplier */
u32_reg |= ((uint32_t)REFRESH_66);
}
pci_write_config32(ctrl->d0, CR_MCMD, u32_reg);
/* Disable remapping & shadow */
// TODO
/* Set CAS layout topology as cross-bar */
u16_reg = pci_read_config16(ctrl->d0, CR_HCFG);
u16_reg |= 0x80000000;
pci_write_config(ctrl->d0, CR_HCFG, u16_reg);
/* Detect RAM presence and type RAM in all rows */
for(uint8 u8_row = 0; u8_row < DIMM_SOCKETS*DIMM_ROWS; u8_row++) {
/* Start of DRAM type detection */
/* Initialize the current row */
initialize_row(ctrl, au32_dram_row[u8_row], u8_row);
/* Detect type of ram in the current row */
detect_type(ctrl, au32_dram_row[u8_row], u8_row);
/* Check if types of the two rows of a bank match */
if((u8_row & 0x01) && (au32_dram_row[u8_row] & e_2ND_ROW) != 0)) {
/* Scratch the type detection results if they don't match */
if((au32_dram_row[u8.row] & e_DRAM_TYPE) != (au32_dram_row[u8.row - 1] & e_DRAM_TYPE)) {
au32_dram_row[u8.row] & ~(e_2ND_ROW);
}
}
/* Detect column address type and size of the current row if there's RAM in it */
if((au32_dram_row[u8_row] & e_1ST_ROW) != 0 || (au32_dram_row[u8_row] & e_2ND_ROW) != 0) {
detect_ca_size(ctrl, au32_dram_row[u8_row], u8_row);
}
}
}
/**
* Initializes a row before it can be checked for DRAM
*/
static void initialize_row(const struct mem_controller* ctrl, uint32_t* u32_dram_row uint8_t u8_row)
{
uint8_t u8_bank = u8_row >> 1;
u32_dram_row[u8_row] = pci_read_config32(ctrl->d0, ((uint8_t)CR_MROW + u8_bank));
/* Initialize the current bank to ... */
/* ... EDO ... */
u32_dram_row[u8_row] &= ~((uint32_t)e_DRAM_TYPE);
u32_dram_row[u8_row] |= ((uint32_t)e_EDO);
if(u8_row & 0x01) {
/* ... 2nd Row present ... */
u32_dram_row[u8_row] &= (uint32_t)e_2ND_ROW;
}
else {
/* ... 1st Row present ... */
u32_dram_row[u8_row] &= (uint32_t)e_1ST_ROW;
}
/* ... row size 256MB ... */
u32_dram_row[u8_row] &= ~((uint32_t)e_ROW_SIZE);
u32_dram_row[u8_row] |= ((uint32_t)e_256MB);
/* and column address 12bit */
u32_dram_row[u8_row] &= ~((uint32_t)e_COLUMN_ADDRESS_TYPE);
u32_dram_row[u8_row] |= ((uint32_t)e_12BIT);
pci_write_config32(ctrl->d0, ((uint8_t)CR_MROW + u8_bank), u32_dram_row[u8_row]);
}
/**
* Detects type of RAM
*/
static void detect_type(const struct mem_controller* ctrl, uint32_t* u32_dram_row, uint8_t u8_row)
{
uint32_t u32_reg = 0;
uint8_t u8_match_found = 0;
uint8_t u8_bank = u8_row >> 1;
uint32_t u32_AA0 = 0x0;
unit32_t u32_AA8 = 0x8;
uint64_t u64_DD1 = 0x5555555555555555;
unit64_t u64_DD2 = 0xAAAAAAAAAAAAAAAA;
uint64_t u64_DD3 = 0;
uint64_t u64_DD4 = 0;
for(;;) {
switch(u32_dram_row[u8_row]) {
case e_EDO: {
/* Write some data */
dimm_write64(u32_AA0, u64_DD1);
dimm_write64(u32_AA8, u64_DD2);
/* Enable EDO detection mode */
u32_reg = pci_read_config32(ctrl->d0, CR_MCMD);
u32_reg &= ((uint32_t)e_EDO_DETECT_MODE);
pci_write_config32(ctrl->d0, CR_MCMD, u32_reg);
/* Read the data back */
dimm_read64(u32_AA0, u64_DD3);
dimm_read64(u32_AA8, u64_DD4);
/* Disable EDO detection mode */
u32_reg = pci_read_config32(ctrl->d0, CR_MCMD);
u32_reg &= ~((uint32_t)e_EDO_DETECT_MODE);
pci_write_config32(ctrl->d0, CR_MCMD, u32_reg);
if(u64_DD3 != u64_DD1 || u64_DD4 != u64_DD2) {
/* No EDO RAM. Test FPM next */
u32_dram_row[u8_row] &= ~(e_DRAM_TYPE);
u32_dram_row[u8_row] = e_FPM;
/* Set the current bank to FPM */
pci_write_config32(ctrl->d0, ((uint8_t)CR_MROW + u8_bank), u32_dram_row[u8_row]);
}
else {
/* EDO found */
u8_match_found = 1;
}
break;
}
case e_FPM: {
/* Write some data */
dimm_write64(u32_AA0, u64_DD1);
dimm_write64(u32_AA8, u64_DD2);
/* Read the data back */
dimm_read64(u32_AA0, u64_DD3);
dimm_read64(u32_AA8, u64_DD4);
if(u64_DD3 != u64_DD1 || u64_DD4 != u64_DD2) {
/* No FPM RAM. Test SDR next */
u32_dram_row[u8_row] &= ~(e_DRAM_TYPE);
u32_dram_row[u8_row] = e_SDR;
/* Set the current bank to SDR */
pci_write_config32(ctrl->d0, ((uint8_t)CR_MROW + u8_bank), u32_dram_row[u8_row]);
}
else {
/* FPM found */
u8_match_found = 1;
}
break;
}
case e_SDR: {
/* Disable DRAM refresh */
u32_reg = pci_read_config32(ctrl->d0, CR_MCMD);
u32_reg &= ~((uint32_t)e_DRAM_REFRESH_ENABLE);
pci_write_config32(ctrl->d0, CR_MCMD, u32_reg);
/* Wait for 5µS */
udelay(5);
/* Enable DRAM refresh */
u32_reg = pci_read_config32(ctrl->d0, CR_MCMD);
u32_reg &= ((uint32_t)e_DRAM_REFRESH_ENABLE);
pci_write_config32(ctrl->d0, CR_MCMD, u32_reg);
/* Write some data */
dimm_write64(u32_AA0, u64_DD1);
dimm_write64(u32_AA8, u64_DD2);
/* Read the data back */
dimm_read64(u32_AA0, u64_DD3);
dimm_read64(u32_AA8, u64_DD4);
if(u64_DD3 != u64_DD1 || u64_DD4 != u64_DD2) {
/* No SDR RAM. No RAM at all found! */
u32_dram_row[u8_row] &= ~(e_DRAM_TYPE);
/* Clear the row presence status */
if(u8_row &= 0x01) {
u32_dram_row[u8_row] &= ~(e_2ND_ROW);
}
else {
u32_dram_row[u8_row] &= ~(e_1ST_ROW);
}
}
else {
/* SDR found */
u8_match_found = 1;
}
break;
}
default : {
break;
}
}
/* Quit type detection if a match was found or the row is empty */
if((u8_match_found != 0) ||
((u32_dram_row[u8_row] & ~(e_1ST_ROW) == 0) && (u32_dram_row[u8_row] & ~(e_2ND_ROW) == 0))) {
break;
}
}
/**
* Detects column address type and size of RAM
*/
static void detect_ca_size(const struct mem_controller* ctrl, uint32_t* u32_dram_row, uint8_t u8_row)
{
uint8_t u8_ca_detected = 0;
uint8_t u8_error_detecting_ca = 0;
uint8_t u8_size_detected = 0;
uint8_t u8_error_detecting_size = 0;
uint8_t u8_bank = u8_row >> 1;
uint32_t u32_AA0 = 0x0;
unit32_t u32_AA8 = 0;
uint64_t u64_DD1 = 0x5555555555555555;
unit64_t u64_DD2 = 0xAAAAAAAAAAAAAAAA;
uint64_t u64_DD3 = 0;
u32_dram_row[u8_row] = pci_read_config32(ctrl->d0, ((uint8_t)CR_MROW + u8_bank));
/* Set 10bit column address for SDR */
if((u32_dram_row[u8_row] & e_DRAM_TYPE) == e_SDR) {
u32_dram_row[u8_row] &= ~(e_COLUMN_ADDRESS_TYPE);
u32_dram_row[u8_row] |= e_10BIT;
pci_write_config32(ctrl->d0, ((uint8_t)CR_MROW + u8_bank), u32_dram_row[u8_row]);
}
/* Detect the column address type */
for(;;) {
/* Write some data */
dimm_write64(u32_AA0, u64_DD1);
switch(u32_dram_row[u8_row] & e_COLUMN_ADDRESS_TYPE) {
case e_8BIT : {
u32_AA8 = 0x00000200;
/* Write some more data */
dimm_write64(u32_AA8, u64_DD2);
/* Read data back */
dimm_read64(u32_AA0, u64_DD3);
if(u64_DD3 == u64_DD1) {
/* 8bit column address ram found */
u8_ca_detected = 1;
}
else {
/* User defined column address detection next */
u32_dram_row[u8_row] &= ~(e_COLUMN_ADDRESS_TYPE);
u32_dram_row[u8_row] |= e_USER_DEFINED;
}
break;
}
case e_9BIT : {
u32_AA8 = 0x00000800;
/* Write some more data */
dimm_write64(u32_AA8, u64_DD2);
/* Read data back */
dimm_read64(u32_AA0, u64_DD3);
if(u64_DD3 == u64_DD1) {
/* 9bit column address ram found */
u8_ca_detected = 1;
}
else if (u64_DD3 == u64_DD2) {
/* 8bit column address detection next */
u32_dram_row[u8_row] &= ~(e_COLUMN_ADDRESS_TYPE);
u32_dram_row[u8_row] |= e_8BIT;
}
else {
/* Error detecting column address mode */
u8_error_detecting_ca = 1;
}
break;
}
case e_10BIT : {
u32_AA8 = 0x00001000;
/* Write some more data */
dimm_write64(u32_AA8, u64_DD2);
/* Read data back */
dimm_read64(u32_AA0, u64_DD3);
if(u64_DD3 == u64_DD1) {
/* 10bit column address ram found */
u8_ca_detected = 1;
}
else if (u64_DD3 == u64_DD2) {
/* 9bit column address detection next */
u32_dram_row[u8_row] &= ~(e_COLUMN_ADDRESS_TYPE);
u32_dram_row[u8_row] |= e_9BIT;
}
else {
/* Error detecting column address mode */
u8_error_detecting_ca = 1;
}
break;
}
case e_11BIT : {
u32_AA8 = 0x00002000;
/* Write some more data */
dimm_write64(u32_AA8, u64_DD2);
/* Read data back */
dimm_read64(u32_AA0, u64_DD3);
if(u64_DD3 == u64_DD1) {
/* 11bit column address ram found */
u8_ca_detected = 1;
}
else if (u64_DD3 == u64_DD2) {
/* 10bit column address detection next */
u32_dram_row[u8_row] &= ~(e_COLUMN_ADDRESS_TYPE);
u32_dram_row[u8_row] |= e_10BIT;
}
else {
/* Error detecting column address mode */
u8_error_detecting_ca = 1;
}
break;
}
case e_12BIT : {
u32_AA8 = 0x04000000;
/* Write some more data */
dimm_write64(u32_AA8, u64_DD2);
/* Read data back */
dimm_read64(u32_AA0, u64_DD3);
if(u64_DD3 == u64_DD1) {
/* 12bit column address ram found */
u8_ca_detected = 1;
}
else if (u64_DD3 == u64_DD2) {
/* 11bit column address detection next */
u32_dram_row[u8_row] &= ~(e_COLUMN_ADDRESS_TYPE);
u32_dram_row[u8_row] |= e_11BIT;
}
else {
/* Error detecting column address mode */
u8_error_detecting_ca = 1;
}
break;
}
case e_USER_DEFINED : {
u32_AA8 = 0x00002000;
if((u32_dram_row[u8_row] & e_DRAM_TYPE) != e_SDR) {
/* Error detecting column address mode */
u8_error_detecting_ca = 1;
}
else {
// TODO : ADJUST REGISTERS F0-FCh
/* Write some more data */
dimm_write64(u32_AA8, u64_DD2);
/* Read data back */
dimm_read64(u32_AA0, u64_DD3);
if(u64_DD3 == u64_DD1) {
/* User defined column address ram found */
u8_ca_detected = 1;
}
else {
/* SDRAM type not supported */
u8_error_detecting_ca = 1;
}
}
break;
}
default : {
/* Undefined column address type */
u8_error_detecting_ca = 1;
break;
}
}
/* Quit column address type detection if a column address was found or an error occured */
if(u8_error_detecting_ca != 0 || u8_ca_detected != 0) {
break;
}
}
/* Quit column address type and size detection if an error occured */
if(u8_error_detecting_ca != 0 || u8_ca_detected != 0) {
/* Clear the row presence status */
if(u8_row &= 0x01) {
u32_dram_row[u8_row] &= ~(e_2ND_ROW);
}
else {
u32_dram_row[u8_row] &= ~(e_1ST_ROW);
}
break;
}
/* Set the detected column address type */
pci_write_config32(ctrl->d0, ((uint8_t)CR_MROW + u8_bank), u32_dram_row[u8_row]);
/* Detect size of the current row */
switch (u32_dram_row[u8_row] & e_COLUMN_ADDRESS_TYPE) {
case e_8BIT : {
/* Set the maximum row size to 64MB */
u32_dram_row[u8_row] &= ~(e_ROW_SIZE);
u32_dram_row[u8_row] |= e_64MB;
for(;;) {
/* Write some data */
dimm_write64(u32_AA0, u64_DD1);
switch(u32_dram_row[u8_row] & e_ROW_SIZE){
case e_4MB : {
u32_AA8 = 0x00200000;
/* Write some more data */
dimm_write64(u32_AA8, u64_DD2);
/* Read data back */
dimm_read64(u32_AA0, u64_DD3);
if(u64_DD3 == u64_DD1) {
/* 4MB found */
u8_size_detected = 1;
}
else {
/* Error detecting size */
u8_error_detecting_size = 1;
}
break;
}
case e_8MB : {
u32_AA8 = 0x00400000;
/* Write some more data */
dimm_write64(u32_AA8, u64_DD2);
/* Read data back */
dimm_read64(u32_AA0, u64_DD3);
if(u64_DD3 == u64_DD1) {
/* 8MB found */
u8_size_detected = 1;
}
else if (u64_DD3 == u64_DD2) {
/* 4MB detection next */
u32_dram_row[u8_row] &= ~(e_ROW_SIZE);
u32_dram_row[u8_row] |= e_4MB;
}
else {
/* Error detecting size */
u8_error_detecting_size = 1;
}
break;
}
case e_16MB : {
u32_AA8 = 0x00800000;
/* Write some more data */
dimm_write64(u32_AA8, u64_DD2);
/* Read data back */
dimm_read64(u32_AA0, u64_DD3);
if(u64_DD3 == u64_DD1) {
/* 16MB found */
u8_size_detected = 1;
}
else if (u64_DD3 == u64_DD2) {
/* 8MB detection next */
u32_dram_row[u8_row] &= ~(e_ROW_SIZE);
u32_dram_row[u8_row] |= e_8MB;
}
else {
/* Error detecting size */
u8_error_detecting_size = 1;
}
break;
}
case e_32MB : {
u32_AA8 = 0x01000000;
/* Write some more data */
dimm_write64(u32_AA8, u64_DD2);
/* Read data back */
dimm_read64(u32_AA0, u64_DD3);
if(u64_DD3 == u64_DD1) {
/* 32MB found */
u8_size_detected = 1;
}
else if (u64_DD3 == u64_DD2) {
/* 16MB detection next */
u32_dram_row[u8_row] &= ~(e_ROW_SIZE);
u32_dram_row[u8_row] |= e_16MB;
}
else {
/* Error detecting size */
u8_error_detecting_size = 1;
}
break;
}
case e_64MB : {
u32_AA8 = 0x02000000;
/* Write some more data */
dimm_write64(u32_AA8, u64_DD2);
/* Read data back */
dimm_read64(u32_AA0, u64_DD3);
if(u64_DD3 == u64_DD1) {
/* 64MB found */
u8_size_detected = 1;
}
else if (u64_DD3 == u64_DD2) {
/* 32MB detection next */
u32_dram_row[u8_row] &= ~(e_ROW_SIZE);
u32_dram_row[u8_row] |= e_32MB;
}
else {
/* Error detecting size */
u8_error_detecting_size = 1;
}
break;
}
default : {
/* RAM size not supported in 8bit column address mode */
u8_error_detecting_size = 1;
break;
}
}
/* Quit if the size of the current row was detected or an error occured */
if((u8_size_detected != 0) || (u8_error_detecting_size != 0))
break;
}
break;
}
case e_9BIT : {
/* Set the maximum row size to 128MB */
u32_dram_row[u8_row] &= ~(e_ROW_SIZE);
u32_dram_row[u8_row] |= e_128MB;
for(;;) {
/* Write some data */
dimm_write64(u32_AA0, u64_DD1);
switch(u32_dram_row[u8_row] & e_ROW_SIZE){
case e_4MB : {
u32_AA8 = 0x00200000;
/* Write some more data */
dimm_write64(u32_AA8, u64_DD2);
/* Read data back */
dimm_read64(u32_AA0, u64_DD3);
if(u64_DD3 == u64_DD1) {
/* 4MB found */
u8_size_detected = 1;
}
else {
/* Error detecting size */
u8_error_detecting_size = 1;
}
break;
}
case e_8MB : {
u32_AA8 = 0x00400000;
/* Write some more data */
dimm_write64(u32_AA8, u64_DD2);
/* Read data back */
dimm_read64(u32_AA0, u64_DD3);
if(u64_DD3 == u64_DD1) {
/* 8MB found */
u8_size_detected = 1;
}
else if (u64_DD3 == u64_DD2) {
/* 4MB detection next */
u32_dram_row[u8_row] &= ~(e_ROW_SIZE);
u32_dram_row[u8_row] |= e_4MB;
}
else {
/* Error detecting size */
u8_error_detecting_size = 1;
}
break;
}
case e_16MB : {
u32_AA8 = 0x00800000;
/* Write some more data */
dimm_write64(u32_AA8, u64_DD2);
/* Read data back */
dimm_read64(u32_AA0, u64_DD3);
if(u64_DD3 == u64_DD1) {
/* 16MB found */
u8_size_detected = 1;
}
else if (u64_DD3 == u64_DD2) {
/* 8MB detection next */
u32_dram_row[u8_row] &= ~(e_ROW_SIZE);
u32_dram_row[u8_row] |= e_8MB;
}
else {
/* Error detecting size */
u8_error_detecting_size = 1;
}
break;
}
case e_32MB : {
u32_AA8 = 0x01000000;
/* Write some more data */
dimm_write64(u32_AA8, u64_DD2);
/* Read data back */
dimm_read64(u32_AA0, u64_DD3);
if(u64_DD3 == u64_DD1) {
/* 32MB found */
u8_size_detected = 1;
}
else if (u64_DD3 == u64_DD2) {
/* 16MB detection next */
u32_dram_row[u8_row] &= ~(e_ROW_SIZE);
u32_dram_row[u8_row] |= e_16MB;
}
else {
/* Error detecting size */
u8_error_detecting_size = 1;
}
break;
}
case e_64MB : {
u32_AA8 = 0x02000000;
/* Write some more data */
dimm_write64(u32_AA8, u64_DD2);
/* Read data back */
dimm_read64(u32_AA0, u64_DD3);
if(u64_DD3 == u64_DD1) {
/* 64MB found */
u8_size_detected = 1;
}
else if (u64_DD3 == u64_DD2) {
/* 32MB detection next */
u32_dram_row[u8_row] &= ~(e_ROW_SIZE);
u32_dram_row[u8_row] |= e_32MB;
}
else {
/* Error detecting size */
u8_error_detecting_size = 1;
}
break;
}
case e_128MB : {
u32_AA8 = 0x04000000;
/* Write some more data */
dimm_write64(u32_AA8, u64_DD2);
/* Read data back */
dimm_read64(u32_AA0, u64_DD3);
if(u64_DD3 == u64_DD1) {
/* 128MB found */
u8_size_detected = 1;
}
else if (u64_DD3 == u64_DD2) {
/* 64MB detection next */
u32_dram_row[u8_row] &= ~(e_ROW_SIZE);
u32_dram_row[u8_row] |= e_64MB;
}
else {
/* Error detecting size */
u8_error_detecting_size = 1;
}
break;
}
default : {
/* RAM size not supported in 9bit column address mode */
u8_error_detecting_size = 1;
break;
}
}
/* Quit if the size of the current row was detected or an error occured */
if((u8_size_detected != 0) || (u8_error_detecting_size != 0))
break;
}
break;
}
case e_10BIT : {
for(;;) {
/* Write some data */
dimm_write64(u32_AA0, u64_DD1);
switch(u32_dram_row[u8_row] & e_ROW_SIZE){
case e_8MB : {
u32_AA8 = 0x00200000;
/* Write some more data */
dimm_write64(u32_AA8, u64_DD2);
/* Read data back */
dimm_read64(u32_AA0, u64_DD3);
if(u64_DD3 == u64_DD1) {
/* 8MB found */
u8_size_detected = 1;
}
else {
/* Error detecting size */
u8_error_detecting_size = 1;
}
break;
}
case e_16MB : {
u32_AA8 = 0x00800000;
/* Write some more data */
dimm_write64(u32_AA8, u64_DD2);
/* Read data back */
dimm_read64(u32_AA0, u64_DD3);
if(u64_DD3 == u64_DD1) {
/* 16MB found */
u8_size_detected = 1;
}
else if (u64_DD3 == u64_DD2) {
/* 8MB detection next */
u32_dram_row[u8_row] &= ~(e_ROW_SIZE);
u32_dram_row[u8_row] |= e_8MB;
}
else {
/* Error detecting size */
u8_error_detecting_size = 1;
}
break;
}
case e_32MB : {
u32_AA8 = 0x01000000;
/* Write some more data */
dimm_write64(u32_AA8, u64_DD2);
/* Read data back */
dimm_read64(u32_AA0, u64_DD3);
if(u64_DD3 == u64_DD1) {
/* 32MB found */
u8_size_detected = 1;
}
else if (u64_DD3 == u64_DD2) {
/* 16MB detection next */
u32_dram_row[u8_row] &= ~(e_ROW_SIZE);
u32_dram_row[u8_row] |= e_16MB;
}
else {
/* Error detecting size */
u8_error_detecting_size = 1;
}
break;
}
case e_64MB : {
u32_AA8 = 0x02000000;
/* Write some more data */
dimm_write64(u32_AA8, u64_DD2);
/* Read data back */
dimm_read64(u32_AA0, u64_DD3);
if(u64_DD3 == u64_DD1) {
/* 64MB found */
u8_size_detected = 1;
}
else if (u64_DD3 == u64_DD2) {
/* 32MB detection next */
u32_dram_row[u8_row] &= ~(e_ROW_SIZE);
u32_dram_row[u8_row] |= e_32MB;
}
else {
/* Error detecting size */
u8_error_detecting_size = 1;
}
break;
}
case e_128MB : {
u32_AA8 = 0x04000000;
/* Write some more data */
dimm_write64(u32_AA8, u64_DD2);
/* Read data back */
dimm_read64(u32_AA0, u64_DD3);
if(u64_DD3 == u64_DD1) {
/* 128MB found */
u8_size_detected = 1;
}
else if (u64_DD3 == u64_DD2) {
/* 64MB detection next */
u32_dram_row[u8_row] &= ~(e_ROW_SIZE);
u32_dram_row[u8_row] |= e_64MB;
}
else {
/* Error detecting size */
u8_error_detecting_size = 1;
}
break;
}
case e_256MB : {
u32_AA8 = 0x08000000;
/* Write some more data */
dimm_write64(u32_AA8, u64_DD2);
/* Read data back */
dimm_read64(u32_AA0, u64_DD3);
if(u64_DD3 == u64_DD1) {
/* 256MB found */
u8_size_detected = 1;
}
else if (u64_DD3 == u64_DD2) {
/* 128MB detection next */
u32_dram_row[u8_row] &= ~(e_ROW_SIZE);
u32_dram_row[u8_row] |= e_128MB;
}
else {
/* Error detecting size */
u8_error_detecting_size = 1;
}
break;
}
default : {
/* RAM size not supported in 10bit column address mode */
u8_error_detecting_size = 1;
break;
}
}
/* Quit if the size of the current row was detected or an error occured */
if((u8_size_detected != 0) || (u8_error_detecting_size != 0))
break;
}
break;
}
case e_11BIT : {
for(;;) {
/* Write some data */
dimm_write64(u32_AA0, u64_DD1);
switch(u32_dram_row[u8_row] & e_ROW_SIZE){
case e_32MB : {
u32_AA8 = 0x00800000;
/* Write some more data */
dimm_write64(u32_AA8, u64_DD2);
/* Read data back */
dimm_read64(u32_AA0, u64_DD3);
if(u64_DD3 == u64_DD1) {
/* 32MB found */
u8_size_detected = 1;
}
else {
/* Error detecting size */
u8_error_detecting_size = 1;
}
break;
}
case e_64MB : {
u32_AA8 = 0x02000000;
/* Write some more data */
dimm_write64(u32_AA8, u64_DD2);
/* Read data back */
dimm_read64(u32_AA0, u64_DD3);
if(u64_DD3 == u64_DD1) {
/* 64MB found */
u8_size_detected = 1;
}
else if (u64_DD3 == u64_DD2) {
/* 32MB detection next */
u32_dram_row[u8_row] &= ~(e_ROW_SIZE);
u32_dram_row[u8_row] |= e_32MB;
}
else {
/* Error detecting size */
u8_error_detecting_size = 1;
}
break;
}
case e_128MB : {
u32_AA8 = 0x04000000;
/* Write some more data */
dimm_write64(u32_AA8, u64_DD2);
/* Read data back */
dimm_read64(u32_AA0, u64_DD3);
if(u64_DD3 == u64_DD1) {
/* 128MB found */
u8_size_detected = 1;
}
else if (u64_DD3 == u64_DD2) {
/* 64MB detection next */
u32_dram_row[u8_row] &= ~(e_ROW_SIZE);
u32_dram_row[u8_row] |= e_64MB;
}
else {
/* Error detecting size */
u8_error_detecting_size = 1;
}
break;
}
case e_256MB : {
u32_AA8 = 0x08000000;
/* Write some more data */
dimm_write64(u32_AA8, u64_DD2);
/* Read data back */
dimm_read64(u32_AA0, u64_DD3);
if(u64_DD3 == u64_DD1) {
/* 256MB found */
u8_size_detected = 1;
}
else if (u64_DD3 == u64_DD2) {
/* 128MB detection next */
u32_dram_row[u8_row] &= ~(e_ROW_SIZE);
u32_dram_row[u8_row] |= e_128MB;
}
else {
/* Error detecting size */
u8_error_detecting_size = 1;
}
break;
}
default : {
/* RAM size not supported in 11bit column address mode */
u8_error_detecting_size = 1;
break;
}
}
/* Quit if the size of the current row was detected or an error occured */
if((u8_size_detected != 0) || (u8_error_detecting_size != 0))
break;
}
break;
}
case e_12BIT : {
for(;;) {
/* Write some data */
dimm_write64(u32_AA0, u64_DD1);
switch(u32_dram_row[u8_row] & e_ROW_SIZE){
case e_128MB : {
u32_AA8 = 0x02000000;
/* Write some more data */
dimm_write64(u32_AA8, u64_DD2);
/* Read data back */
dimm_read64(u32_AA0, u64_DD3);
if(u64_DD3 == u64_DD1) {
/* 128MB found */
u8_size_detected = 1;
}
else {
/* Error detecting size */
u8_error_detecting_size = 1;
}
break;
}
case e_256MB : {
u32_AA8 = 0x08000000;
/* Write some more data */
dimm_write64(u32_AA8, u64_DD2);
/* Read data back */
dimm_read64(u32_AA0, u64_DD3);
if(u64_DD3 == u64_DD1) {
/* 256MB found */
u8_size_detected = 1;
}
else if (u64_DD3 == u64_DD2) {
/* 128MB detection next */
u32_dram_row[u8_row] &= ~(e_ROW_SIZE);
u32_dram_row[u8_row] |= e_128MB;
}
else {
/* Error detecting size */
u8_error_detecting_size = 1;
}
break;
}
default : {
/* RAM size not supported in 12bit column address mode */
u8_error_detecting_size = 1;
break;
}
}
/* Quit if the size of the current row was detected or an error occured */
if((u8_size_detected != 0) || (u8_error_detecting_size != 0))
break;
}
break;
}
case e_USER_DEFINED : {
// TODO
break;
}
default : {
/* Unknown column address type */
break;
}
}
}
/*
* 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
/* The ALi Aladdin-Pro II supports up to four DIMMs with 2 rows each. */
#define DIMM_SOCKETS 4
#define DIMM_ROWS 2
enum E_CR_MROW_MASKS {
e_MA_ASSERTATION 0x80000000,
e_PAGE_HIT_WAIT_STATE 0x40000000,
e_EDO_SR_SDR_CL 0x20000000,
e_DRAM_TYPE 0x18000000,
e_1ST_ROW 0x06000000,
e_2ND_ROW 0x01800000,
e_ROW_SIZE 0x00700000,
e_COLUMN_ADDRESS_TYPE 0x000F0000,
e_EDO_ASR_SDR_CSQ 0x00008000,
e_EDO_RAH_SDR_BANK 0x00006000,
e_EDO_ASC_SDR_BANK 0x00001800,
e_EDO_RCAS 0x00000600,
e_EDO_WCAS 0x00000180,
e_EDO_CP_SDR_REG 0x00000040,
e_EDO_CSH_SDR_RCD_RP 0x00000030,
e_EDO_RAS_SDR_BANK 0x0000000C,
e_EDO_RP_SDR_BANK 0x00000003
};
enum E_CR_MCMD_MASKS {
e_MEMORY_PROTECTION 0xC0000000,
e_MWB_ALLOCATION 0x30000000,
e_REF_QUEUE_DEPTH 0x08000000,
e_REF_START_CONTROL 0x07000000,
e_AF_START_CONTROL 0x00C00000,
e_DRAM_REFRESH_ENV 0x00200000,
e_EDO_DETECT_MODE 0x00100000,
e_DRAM_REFRESH_ENABLE 0x00080000,
e_DRAM_REF_CASL_RASL 0x00040000,
e_DRAM_REF_RAS 0x00030000,
e_DRAM_REF_RP 0x0000C000,
e_DRAM_REFRESH_CYCLE 0x00003FFF,
};
enum E_DRAM_TYPE {
e_FPM = 0x00000000,
e_EDO = 0x08000000,
e_SDR = 0x10000000,
};
enum E_DRAM_ROW_SIZE {
e_4MB = 0x00000000,
e_8MB = 0x00100000,
e_16MB = 0x00200000,
e_32MB = 0x00300000,
e_64MB = 0x00400000,
e_128MB = 0x00500000,
e_256MB = 0x00600000
};
enum E_DRAM_CA {
e_8BIT = 0x00000000,
e_9BIT = 0x00010000,
e_10BIT = 0x00020000,
e_11BIT = 0x00030000,
e_12BIT = 0x00040000,
e_USER_DEFINED = 0x000F0000
};
uint32_t au32_DRAM[DIMM_SOCKETS];
/* The ALi Aladdin-Pro II memory controller has one channel only. */
struct mem_controller {
device_t d0;
uint16_t channel0[DIMM_SOCKETS];
};
#endif /* RAMINIT_H */
/*
* 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
*/
/*
* Datasheet:
* - Name: Acer Laboratories Inc. - Aladdin-Pro II M1621 North Bridge
*/
/*
* Host-to-PCI Bridge Registers.
* The values in parenthesis are the default values as per datasheet.
* Any addresses between 0x00 and 0xff not listed below are reserved.
*/
#define CR_VID 0x00 /* Vendor Identification (0x10B9). */
#define CR_DID 0x02 /* Device Identification (0x1621). */
#define CR_CMD 0x04 /* PCI Command Register (0x006). */
#define CR_STAS 0x06 /* PCI Status Register (0x0410). */
#define CR_RID 0x08 /* Revision Identification (0x01). */
#define CR_SRLP 0x09 /* Specific Register-level Programming Register (0x00). */
#define CR_SCC 0x0A /* Sub-Class Code (0x00). */
#define CR_BCC 0x0B /* Base Class Code (0x06). */
#define CR_BAR 0x10 /* Base Address Register (0x00000008). */
#define CR_CPR 0x34 /* Capabilities Pointer Register (0xB0) */
#define CR_FC3PCI 0x40 /* Flushing Counter for USWC Posted Write to 33PCI (0x0C) */
#define CR_FC6PCI 0x41 /* Flushing Counter for USWC Posted Write to 66PCI (0x0C) */
#define CR_PIOW1 0x42 /* First I/O Address for Posted I/O Write (0x0000) */
#define CR_PIOW2 0x44 /* Second I/O Address for Posted I/O Write (0x0000) */
#define CR_PIOW3 0x46 /* Third I/O Address for Posted I/O Write (0x0000) */
#define CR_PIOW4 0x48 /* Fourth I/O Address for Posted I/O Write (0x0000) */
#define CR_IOPWCNT 0x4A /* Control Register for I/O Posted Write Cycles (0x00) */
#define CR_CRSPCNF 0x4B /* Control Register for Special & Configuration Cycles (0x00) */
#define CR_CFDT3P 0x4C /* Counter for 33 PCI Delay Transaction (0x04) */
#define CR_CFDT6P 0x4D /* Counter for 66 PCI Delay Transaction (0x04) */
#define CR_PPM1 0x4E /* Power Management for 33 and 66 PCI Block (0x7F) */
#define CR_PPM2 0x4F /* Power Management for Host Block (0x7F) */
#define CR_HWGEN 0x50 /* Host to AGP Memory-Write Enhancement Register (0x0C) */
#define CR_GPMFW 0x51 /* 66 PCI Master Device Pre-Fetch & Post-Write Control Register (0x00) */
#define CR_GPCMD 0x52 /* 66 PCI Bridge Command Register (0x00) */
#define CR_GPBRC 0x53 /* 66 PCI Bridge Retry Counter Register (0x02) */
#define CR_GPBECR 0x54 /* 66 PCI Bridge Error Command Register (0x0000) */
#define CR_GPBESR 0x56 /* 66 PCI Bridge Error Status Register (0x00) */
#define CR_GPBER 0x57 /* AGP Arbiter Control Register (0x00) */
#define CR_GPMDMT 0x58 /* 66 PCI Master Device Multiple Transaction Timer (0x00) */
#define CR_GPBMT 0x59 /* 66 PCI Bridge Multiple Transaction Timer (0x00) */
#define CR_P2PRPC 0x5A /* P2P Bridge Retry Counter Register (0x02) */
#define CR_PCLKRUN 0x5C /* PCI CLKRUN Control Register (0x00) */
#define CR_HWEN 0x60 /* Host to PCI Memory-Write Enhancement Register (0x00) */
#define CR_PMFW 0x61 /* PCI Master Device Pre-Fetch & Post-Write Control Register (0x00) */
#define CR_PCMD 0x62 /* PCI Bridge Command Register (0x00) */
#define CR_PBRC 0x63 /* PCI Bridge Retry Counter Register (0x02) */
#define CR_PBECR 0x64 /* PCI Bridge Error Command Register (0x0000) */
#define CR_PBESR 0x66 /* PCI Bridge Error Status Register (0x00) */
#define CR_PACR 0x67 /* PCI Arbiter Control Register (0x00) */
#define CR_PMDMT 0x68 /* PCI Master Device Multiple Transaction Timer (0x00) */
#define CR_PBMT 0x69 /* PCI Master Device Multiple Transaction Timer (0x00) */
#define CR_MROW 0x6C /* Memory Bank 0 Register (0xE600FFFF) */
//#define CR_MROW1 0x70 /* Memory Bank 1 Register (0xE000FFFF) */
//#define CR_MROW2 0x74 /* Memory Bank 2 Register (0xE000FFFF) */
//#define CR_MROW3 0x78 /* Memory Bank 3 Register (0xE000FFFF) */
#define CR_MCMD 0x7C /* Memory Command Register (0x00C7C411) */
#define CR_HCFG 0x80 /* Host Interface Configuration Register (0x0C01) */
#define CR_PDEC 0x82 /* PCI Decode Mode Register (0x00) */
#define CR_MSMM 0x83 /* A/B Page and SMM Range Register (0x08) */
#define CR_MPAM 0x84 /* Memory Attribute Register (0x00000000) */
#define CR_HRNG 0x88 /* Memory Gap Range Register (0x00000000) */
#define CR_USWC 0x8C /* USWC Gap Range Register (0x00010000) */
#define CR_ECCST 0x90 /* Memory ECC Error Status Register (0x0000) */
#define CR_SPR1 0x94 /* Spare Register #1 (0x00000000) */
#define CR_SPR2 0x98 /* Spare Register #2 (0x00000000) */
#define CR_SPR3 0x9C /* Spare Register #3 (0x00000000) */
#define CR_PMC2 0xA0 /* Power Management Control Block #2 (0x00000020) */
#define CR_AGPCI 0xB0 /* AGP Capability Identifier Register (0x00800002) */
#define CR_AGPSTA 0xB4 /* AGP Status Register (0x20000203) */
#define CR_AGPCMD 0xB8 /* AGP Command Register (0x80000101) */
#define CR_NLVMCTL 0xBC /* AGP NLVM Control Register (0x00000000) */
#define CR_TGCLR 0xC0 /* AGP TAG Clear Register (0x00000080) */
#define CR_AGPCR1 0xC4 /* AGP Control Register One (0x00000000) */
#define CR_AGPCR2 0xC8 /* AGP Control Register Two (0x00002400) */
#define CR_AGPCR3 0xCC /* AGP Control Register Three (0x00000000) */
#define CR_AGPCR4 0xD0 /* AGP Control Register Four (0x00000000) */
#define CR_AGPCR5 0xD4 /* AGP Control Register Five (0x00000000) */
#define CR_RCA0 0xF0 /* User-Defined Row/Column Address Mapping Register 0 (0x43214320) */
#define CR_RCA1 0xF4 /* User-Defined Row/Column Address Mapping Register 0 (0x43214320) */
#define CR_RCA2 0xF8 /* User-Defined Row/Column Address Mapping Register 0 (0x43214320) */
#define CR_RCA3 0xFC /* User-Defined Row/Column Address Mapping Register 0 (0x43214320) */