NuBusFPGA/nubus-to-ztex-gateware/DeclROM/NuBusFPGAPrimaryInit_RamInit.c
2023-01-27 22:25:12 +01:00

651 lines
18 KiB
C

#include "NuBusFPGADrvr.h"
#define CONFIG_CSR_DATA_WIDTH 32
#include "../nubusfpga_csr_ddrphy.h"
#include "../nubusfpga_csr_sdram.h"
/* auto-generated sdram_phy.h + sc */
#define DFII_CONTROL_SEL 0x01
#define DFII_CONTROL_CKE 0x02
#define DFII_CONTROL_ODT 0x04
#define DFII_CONTROL_RESET_N 0x08
#define DFII_COMMAND_CS 0x01
#define DFII_COMMAND_WE 0x02
#define DFII_COMMAND_CAS 0x04
#define DFII_COMMAND_RAS 0x08
#define DFII_COMMAND_WRDATA 0x10
#define DFII_COMMAND_RDDATA 0x20
#define SDRAM_PHY_A7DDRPHY
#define SDRAM_PHY_XDR 2
#define SDRAM_PHY_DATABITS 16
#define SDRAM_PHY_PHASES 4
#define SDRAM_PHY_CL 6
#define SDRAM_PHY_CWL 5
#define SDRAM_PHY_CMD_LATENCY 0
#define SDRAM_PHY_RDPHASE 2
#define SDRAM_PHY_WRPHASE 3
#define SDRAM_PHY_WRITE_LATENCY_CALIBRATION_CAPABLE
#define SDRAM_PHY_READ_LEVELING_CAPABLE
#define SDRAM_PHY_MODULES SDRAM_PHY_DATABITS/8
#define SDRAM_PHY_DELAYS 32
#define SDRAM_PHY_BITSLIPS 8
__attribute__ ((section (".text.primary"))) static void cdelay(int i);
__attribute__ ((section (".text.primary"))) static void
sdram_read_leveling_rst_delay (uint32_t a32, int module);
__attribute__ ((section (".text.primary"))) static void
sdram_read_leveling_inc_delay (uint32_t a32, int module);
__attribute__ ((section (".text.primary"))) static inline void command_p0(uint32_t a32, int cmd)
{
sdram_dfii_pi0_command_write(a32, cmd);
sdram_dfii_pi0_command_issue_write(a32, 1);
}
__attribute__ ((section (".text.primary"))) static inline void command_p1(uint32_t a32, int cmd)
{
sdram_dfii_pi1_command_write(a32, cmd);
sdram_dfii_pi1_command_issue_write(a32, 1);
}
__attribute__ ((section (".text.primary"))) static inline void command_p2(uint32_t a32, int cmd)
{
sdram_dfii_pi2_command_write(a32, cmd);
sdram_dfii_pi2_command_issue_write(a32, 1);
}
__attribute__ ((section (".text.primary"))) static inline void command_p3(uint32_t a32, int cmd)
{
sdram_dfii_pi3_command_write(a32, cmd);
sdram_dfii_pi3_command_issue_write(a32, 1);
}
#define DFII_PIX_DATA_SIZE CSR_SDRAM_DFII_PI0_WRDATA_SIZE
__attribute__ ((section (".text.primary"))) static inline unsigned long sdram_dfii_pix_wrdata_addr(int phase)
{
switch (phase) {
case 0: return CSR_SDRAM_DFII_PI0_WRDATA_ADDR;
case 1: return CSR_SDRAM_DFII_PI1_WRDATA_ADDR;
case 2: return CSR_SDRAM_DFII_PI2_WRDATA_ADDR;
case 3: return CSR_SDRAM_DFII_PI3_WRDATA_ADDR;
default: return 0;
}
}
__attribute__ ((section (".text.primary"))) static inline unsigned long sdram_dfii_pix_rddata_addr(int phase)
{
switch (phase) {
case 0: return CSR_SDRAM_DFII_PI0_RDDATA_ADDR;
case 1: return CSR_SDRAM_DFII_PI1_RDDATA_ADDR;
case 2: return CSR_SDRAM_DFII_PI2_RDDATA_ADDR;
case 3: return CSR_SDRAM_DFII_PI3_RDDATA_ADDR;
default: return 0;
}
}
#define DDRX_MR_WRLVL_ADDRESS 1
#define DDRX_MR_WRLVL_RESET 6
#define DDRX_MR_WRLVL_BIT 7
__attribute__ ((section (".text.primary"))) static inline void init_sequence(uint32_t a32)
{
/* Release reset */
sdram_dfii_pi0_address_write(a32, 0x0);
sdram_dfii_pi0_baddress_write(a32, 0);
sdram_dfii_control_write(a32, DFII_CONTROL_ODT|DFII_CONTROL_RESET_N);
cdelay(50000);
/* Bring CKE high */
sdram_dfii_pi0_address_write(a32, 0x0);
sdram_dfii_pi0_baddress_write(a32, 0);
sdram_dfii_control_write(a32, DFII_CONTROL_CKE|DFII_CONTROL_ODT|DFII_CONTROL_RESET_N);
cdelay(10000);
/* Load Mode Register 2, CWL=5 */
sdram_dfii_pi0_address_write(a32, 0x200);
sdram_dfii_pi0_baddress_write(a32, 2);
command_p0(a32, DFII_COMMAND_RAS|DFII_COMMAND_CAS|DFII_COMMAND_WE|DFII_COMMAND_CS);
/* Load Mode Register 3 */
sdram_dfii_pi0_address_write(a32, 0x0);
sdram_dfii_pi0_baddress_write(a32, 3);
command_p0(a32, DFII_COMMAND_RAS|DFII_COMMAND_CAS|DFII_COMMAND_WE|DFII_COMMAND_CS);
/* Load Mode Register 1 */
sdram_dfii_pi0_address_write(a32, 0x6);
sdram_dfii_pi0_baddress_write(a32, 1);
command_p0(a32, DFII_COMMAND_RAS|DFII_COMMAND_CAS|DFII_COMMAND_WE|DFII_COMMAND_CS);
/* Load Mode Register 0, CL=6, BL=8 */
sdram_dfii_pi0_address_write(a32, 0x920);
sdram_dfii_pi0_baddress_write(a32, 0);
command_p0(a32, DFII_COMMAND_RAS|DFII_COMMAND_CAS|DFII_COMMAND_WE|DFII_COMMAND_CS);
cdelay(200);
/* ZQ Calibration */
sdram_dfii_pi0_address_write(a32, 0x400);
sdram_dfii_pi0_baddress_write(a32, 0);
command_p0(a32, DFII_COMMAND_WE|DFII_COMMAND_CS);
cdelay(200);
}
#include "nubusfpga_csr_common.h"
/* sdram.c from liblitedram, preprocessed for our case, + sc */
__attribute__ ((section (".text.primary"))) static inline unsigned long
lfsr (unsigned long bits, unsigned long prev)
{
/*static*/ const unsigned long long lfsr_taps[] = {
0x0L,
0x0L,
0x3L,
0x6L,
0xcL,
0x14L,
0x30L,
0x60L,
0xb8L,
0x110L,
0x240L,
0x500L,
0x829L,
0x100dL,
0x2015L,
0x6000L,
0xd008L,
0x12000L,
0x20400L,
0x40023L,
0x90000L,
0x140000L,
0x300000L,
0x420000L,
0xe10000L,
0x1200000L,
0x2000023L,
0x4000013L,
0x9000000L,
0x14000000L,
0x20000029L,
0x48000000L,
0x80200003L,
0x100080000L,
0x204000003L,
0x500000000L,
0x801000000L,
0x100000001fL,
0x2000000031L,
0x4400000000L,
0xa000140000L,
0x12000000000L,
0x300000c0000L,
0x63000000000L,
0xc0000030000L,
0x1b0000000000L,
0x300003000000L,
0x420000000000L,
0xc00000180000L,
0x1008000000000L,
0x3000000c00000L,
0x6000c00000000L,
0x9000000000000L,
0x18003000000000L,
0x30000000030000L,
0x40000040000000L,
0xc0000600000000L,
0x102000000000000L,
0x200004000000000L,
0x600003000000000L,
0xc00000000000000L,
0x1800300000000000L,
0x3000000000000030L,
0x6000000000000000L,
0x800000000000000dL
};
unsigned long lsb = prev & 1;
prev >>= 1;
prev ^= (-lsb) & lfsr_taps[bits];
return prev;
}
__attribute__ ((section (".text.primary")))
static void cdelay (int i)
{
//i >>= 2;
while (i > 0) {
__asm__ volatile ("");
i--;
}
}
__attribute__ ((section (".text.primary"))) static unsigned char
sdram_dfii_get_rdphase(uint32_t a32)
{
return ddrphy_rdphase_read(a32);
}
__attribute__ ((section (".text.primary"))) static unsigned char
sdram_dfii_get_wrphase(uint32_t a32)
{
return ddrphy_wrphase_read(a32);
}
__attribute__ ((section (".text.primary"))) static void
sdram_dfii_pix_address_write(uint32_t a32, unsigned char phase, unsigned int value)
{
switch (phase) {
case 3:
sdram_dfii_pi3_address_write(a32, value);
break;
case 2:
sdram_dfii_pi2_address_write(a32, value);
break;
case 1:
sdram_dfii_pi1_address_write(a32, value);
break;
default:
sdram_dfii_pi0_address_write(a32, value);
}
}
__attribute__ ((section (".text.primary"))) static void
sdram_dfii_pird_address_write(uint32_t a32, unsigned int value)
{
unsigned char rdphase = sdram_dfii_get_rdphase(a32);
sdram_dfii_pix_address_write(a32, rdphase, value);
}
__attribute__ ((section (".text.primary"))) static void
sdram_dfii_piwr_address_write(uint32_t a32, unsigned int value)
{
unsigned char wrphase = sdram_dfii_get_wrphase(a32);
sdram_dfii_pix_address_write(a32, wrphase, value);
}
__attribute__ ((section (".text.primary"))) static void
sdram_dfii_pix_baddress_write(uint32_t a32, unsigned char phase, unsigned int value)
{
switch (phase) {
case 3:
sdram_dfii_pi3_baddress_write(a32, value);
break;
case 2:
sdram_dfii_pi2_baddress_write(a32, value);
break;
case 1:
sdram_dfii_pi1_baddress_write(a32, value);
break;
default:
sdram_dfii_pi0_baddress_write(a32, value);
}
}
__attribute__ ((section (".text.primary"))) static void
sdram_dfii_pird_baddress_write(uint32_t a32, unsigned int value)
{
unsigned char rdphase = sdram_dfii_get_rdphase(a32);
sdram_dfii_pix_baddress_write(a32, rdphase, value);
}
__attribute__ ((section (".text.primary"))) static void
sdram_dfii_piwr_baddress_write(uint32_t a32, unsigned int value)
{
unsigned char wrphase = sdram_dfii_get_wrphase(a32);
sdram_dfii_pix_baddress_write(a32, wrphase, value);
}
__attribute__ ((section (".text.primary"))) static void
command_px(uint32_t a32, unsigned char phase, unsigned int value)
{
switch (phase) {
case 3:
command_p3(a32, value);
break;
case 2:
command_p2(a32, value);
break;
case 1:
command_p1(a32, value);
break;
default:
command_p0(a32, value);
}
}
__attribute__ ((section (".text.primary"))) static void
command_prd(uint32_t a32, unsigned int value)
{
unsigned char rdphase = sdram_dfii_get_rdphase(a32);
command_px(a32, rdphase, value);
}
__attribute__ ((section (".text.primary"))) static void
command_pwr (uint32_t a32, unsigned int value)
{
unsigned char wrphase = sdram_dfii_get_wrphase(a32);
command_px(a32, wrphase, value);
}
__attribute__ ((section (".text.primary"))) static void
sdram_software_control_on(uint32_t a32)
{
unsigned int previous;
previous = sdram_dfii_control_read(a32);
if (previous != (0x02 | 0x04 | 0x08)) {
sdram_dfii_control_write(a32, (0x02 | 0x04 | 0x08));
}
}
__attribute__ ((section (".text.primary"))) static void
sdram_software_control_off(uint32_t a32)
{
unsigned int previous;
previous = sdram_dfii_control_read(a32);
if (previous != (0x01)) {
sdram_dfii_control_write(a32, (0x01));
}
}
__attribute__ ((section (".text.primary"))) static void
sdram_mode_register_write(uint32_t a32, char reg, int value)
{
sdram_dfii_pi0_address_write(a32, value);
sdram_dfii_pi0_baddress_write(a32, reg);
command_p0(a32, 0x08 | 0x04 | 0x02 | 0x01);
}
//typedef void (*delay_callback) (uint32_t a32, int module);
__attribute__ ((section (".text.primary"))) static void
sdram_activate_test_row(uint32_t a32)
{
sdram_dfii_pi0_address_write(a32, 0);
sdram_dfii_pi0_baddress_write(a32, 0);
command_p0(a32, 0x08 | 0x01);
cdelay (15);
}
__attribute__ ((section (".text.primary"))) static void
sdram_precharge_test_row(uint32_t a32)
{
sdram_dfii_pi0_address_write(a32, 0);
sdram_dfii_pi0_baddress_write(a32, 0);
command_p0(a32, 0x08 | 0x02 | 0x01);
cdelay (15);
}
__attribute__ ((section (".text.primary"))) static unsigned int
popcount (unsigned int x)
{
x -= ((x >> 1) & 0x55555555);
x = (x & 0x33333333) + ((x >> 2) & 0x33333333);
x = (x + (x >> 4)) & 0x0F0F0F0F;
x += (x >> 8);
x += (x >> 16);
return x & 0x0000003F;
}
__attribute__ ((section (".text.primary"))) static unsigned int
sdram_write_read_check_test_pattern (uint32_t a32, int module, unsigned int seed)
{
int p, i;
unsigned int errors;
unsigned int prv;
unsigned char tst[1 * 32 / 8];
unsigned char prs[4][1 * 32 / 8];
prv = seed;
for (p = 0; p < 4; p++) {
for (i = 0; i < 1 * 32 / 8; i++) {
prv = lfsr (32, prv);
prs[p][i] = prv;
}
}
sdram_activate_test_row(a32);
for (p = 0; p < 4; p++)
csr_wr_buf_uint8(a32, (sdram_dfii_pix_wrdata_addr (p)/* - CSR_SDRAM_BASE*/), prs[p], 1 * 32 / 8); /* cleanme */
sdram_dfii_piwr_address_write(a32, 0);
sdram_dfii_piwr_baddress_write(a32, 0);
command_pwr(a32, 0x04 | 0x02 | 0x01 | 0x10);
cdelay (15);
sdram_dfii_pird_address_write(a32, 0);
sdram_dfii_pird_baddress_write(a32, 0);
command_prd(a32, 0x04 | 0x01 | 0x20);
cdelay (15);
sdram_precharge_test_row(a32);
errors = 0;
for (p = 0; p < 4; p++) {
csr_rd_buf_uint8(a32, (sdram_dfii_pix_rddata_addr (p)/* - CSR_SDRAM_BASE*/), tst, 1 * 32 / 8); /* cleanme */
errors +=
popcount (prs[p][16 / 8 - 1 - module] ^ tst[16 / 8 - 1 - module]);
errors +=
popcount (prs[p][2 * 16 / 8 - 1 - module] ^
tst[2 * 16 / 8 - 1 - module]);
}
return errors;
}
__attribute__ ((section (".text.primary"))) static void
sdram_leveling_center_module (uint32_t a32, int module, int show_short, int show_long)
/* ,
delay_callback rst_delay,
delay_callback inc_delay) */
{
int i;
int show;
int working;
unsigned int errors;
int delay, delay_mid, delay_range;
int delay_min = -1, delay_max = -1;
delay = 0;
//rst_delay(a32, module);
sdram_read_leveling_rst_delay(a32, module);
while (1) {
errors = sdram_write_read_check_test_pattern(a32, module, 42);
errors += sdram_write_read_check_test_pattern(a32, module, 84);
working = errors == 0;
show = show_long;
if (working && delay_min < 0) {
delay_min = delay;
break;
}
delay++;
if (delay >= 32)
break;
//inc_delay(a32, module);
sdram_read_leveling_inc_delay(a32, module);
}
delay++;
//inc_delay(a32, module);
sdram_read_leveling_inc_delay(a32, module);
while (1) {
errors = sdram_write_read_check_test_pattern(a32, module, 42);
errors += sdram_write_read_check_test_pattern(a32, module, 84);
working = errors == 0;
show = show_long;
if (!working && delay_max < 0) {
delay_max = delay;
}
delay++;
if (delay >= 32)
break;
//inc_delay(a32, module);
sdram_read_leveling_inc_delay(a32, module);
}
if (delay_max < 0) {
delay_max = delay;
}
delay_mid = (delay_min + delay_max) / 2 % 32;
delay_range = (delay_max - delay_min) / 2;
//delay_mid = 25;
//rst_delay(a32, module);
sdram_read_leveling_rst_delay(a32, module);
cdelay (100);
for (i = 0; i < delay_mid; i++) {
//inc_delay(a32, module);
sdram_read_leveling_inc_delay(a32, module);
cdelay (100);
}
}
//__attribute__ ((section (".data.primary"))) int _sdram_write_leveling_bitslips[16];
__attribute__ ((section (".text.primary"))) static void
sdram_read_leveling_rst_delay (uint32_t a32, int module)
{
ddrphy_dly_sel_write(a32, 1 << module);
ddrphy_rdly_dq_rst_write(a32, 1);
ddrphy_dly_sel_write(a32, 0);
}
__attribute__ ((section (".text.primary"))) static void
sdram_read_leveling_inc_delay (uint32_t a32, int module)
{
ddrphy_dly_sel_write(a32, 1 << module);
ddrphy_rdly_dq_inc_write(a32, 1);
ddrphy_dly_sel_write(a32, 0);
}
__attribute__ ((section (".text.primary"))) static void
sdram_read_leveling_rst_bitslip (uint32_t a32, char m)
{
ddrphy_dly_sel_write(a32, 1 << m);
ddrphy_rdly_dq_bitslip_rst_write(a32, 1);
ddrphy_dly_sel_write(a32, 0);
}
__attribute__ ((section (".text.primary"))) static void
sdram_read_leveling_inc_bitslip (uint32_t a32, char m)
{
ddrphy_dly_sel_write(a32, 1 << m);
ddrphy_rdly_dq_bitslip_write(a32, 1);
ddrphy_dly_sel_write(a32, 0);
}
__attribute__ ((section (".text.primary"))) static unsigned int
sdram_read_leveling_scan_module (uint32_t a32, int module, int bitslip, int show)
{
const unsigned int max_errors = 2 * (4 * 2 * 32);
int i;
unsigned int score;
unsigned int errors;
score = 0;
sdram_read_leveling_rst_delay(a32, module);
for (i = 0; i < 32; i++) {
int working;
int _show = show;
errors = sdram_write_read_check_test_pattern(a32, module, 42);
errors += sdram_write_read_check_test_pattern(a32, module, 84);
working = (errors == 0) ? 1 : 0;
score += (working * max_errors * 32) + (max_errors - errors);
sdram_read_leveling_inc_delay(a32, module);
}
return score;
}
__attribute__ ((section (".text.primary"))) static void
sdram_read_leveling(uint32_t a32)
{
int module;
int bitslip;
unsigned int score;
unsigned int best_score;
int best_bitslip;
for (module = 0; module < 16 / 8; module++) {
best_score = 0;
best_bitslip = 0;
sdram_read_leveling_rst_bitslip(a32, module);
for (bitslip = 0; bitslip < 8; bitslip++) {
score = sdram_read_leveling_scan_module(a32, module, bitslip, 1);
sdram_leveling_center_module(a32, module, 1, 0);
/*,
sdram_read_leveling_rst_delay,
sdram_read_leveling_inc_delay);*/
if (score > best_score) {
best_bitslip = bitslip;
best_score = score;
}
if (bitslip == 8 - 1)
break;
sdram_read_leveling_inc_bitslip(a32, module);
}
//best_bitslip = 1;
sdram_read_leveling_rst_bitslip(a32, module);
for (bitslip = 0; bitslip < best_bitslip; bitslip++)
sdram_read_leveling_inc_bitslip(a32, module);
sdram_leveling_center_module(a32, module, 1, 0);
/*,
sdram_read_leveling_rst_delay,
sdram_read_leveling_inc_delay);*/
}
}
__attribute__ ((section (".text.primary"))) static void
sdram_write_latency_calibration(uint32_t a32)
{
int i;
int module;
int bitslip;
unsigned int score;
unsigned int subscore;
unsigned int best_score;
int best_bitslip;
int _sdram_write_leveling_bitslips[16] = {0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0 };
for (module = 0; module < 16 / 8; module++) {
best_score = 0;
best_bitslip = -1;
for (bitslip = 0; bitslip < 8; bitslip += 2) {
score = 0;
ddrphy_dly_sel_write(a32, 1 << module);
ddrphy_wdly_dq_bitslip_rst_write(a32, 1);
for (i = 0; i < bitslip; i++) {
ddrphy_wdly_dq_bitslip_write(a32, 1);
}
ddrphy_dly_sel_write(a32, 0);
score = 0;
sdram_read_leveling_rst_bitslip(a32, module);
for (i = 0; i < 8; i++) {
subscore = sdram_read_leveling_scan_module(a32, module, i, 0);
score = subscore > score ? subscore : score;
sdram_read_leveling_inc_bitslip(a32, module);
}
if (score > best_score) {
best_bitslip = bitslip;
best_score = score;
}
}
if (_sdram_write_leveling_bitslips[module] < 0)
bitslip = best_bitslip;
else
bitslip = _sdram_write_leveling_bitslips[module];
//bitslip = 0;
ddrphy_dly_sel_write(a32, 1 << module);
ddrphy_wdly_dq_bitslip_rst_write(a32, 1);
for (i = 0; i < bitslip; i++) {
ddrphy_wdly_dq_bitslip_write(a32, 1);
}
ddrphy_dly_sel_write(a32, 0);
}
}
__attribute__ ((section (".text.primary"))) static int
sdram_leveling(uint32_t a32)
{
int module;
sdram_software_control_on(a32);
for (module = 0; module < 16 / 8; module++) {
sdram_read_leveling_rst_delay(a32, module);
sdram_read_leveling_rst_bitslip(a32, module);
}
sdram_write_latency_calibration(a32);
sdram_read_leveling(a32);
sdram_software_control_off(a32);
return 1;
}
int
sdram_init(uint32_t a32) // // attribute in header file
{
ddrphy_rdphase_write(a32, 2);
ddrphy_wrphase_write(a32, 3);
sdram_software_control_on(a32);
ddrphy_rst_write(a32, 1);
cdelay (1000);
ddrphy_rst_write(a32, 0);
cdelay (1000);
init_sequence(a32);
sdram_leveling(a32);
sdram_software_control_off(a32);
return 1;
}