summaryrefslogtreecommitdiffstats
path: root/arch/arm/boards/edb93xx/sdram_cfg.c
blob: 8342d446b37c08ba74fa0c3716c6ed81e1dff654 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
/*
 * Copyright (C) 2009 Matthias Kaehlcke <matthias@kaehlcke.net>
 *
 * Copyright (C) 2006 Dominic Rath <Dominic.Rath@gmx.de>
 *
 * See file CREDITS for list of people who contributed to this
 * project.
 *
 * 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., 59 Temple Place, Suite 330, Boston,
 * MA 02111-1307 USA
 */

#include <common.h>
#include <io.h>
#include "sdram_cfg.h"
#include "early_udelay.h"

#define PROGRAM_MODE_REG(bank)		(*(volatile uint32_t *)		\
		(SDRAM_BASE_ADDR | SDRAM_BANK_SEL_##bank | SDRAM_MODE_REG_VAL))

#define PRECHARGE_BANK(bank)		(*(volatile uint32_t *)	\
		(SDRAM_BASE_ADDR | SDRAM_BANK_SEL_##bank)) = 0

static void precharge_all_banks(void);
static void setup_refresh_timer(void);
static void program_mode_registers(void);

void sdram_cfg(void)
{
	struct sdram_regs *sdram = (struct sdram_regs *)SDRAM_BASE;

	writel(SDRAM_DEVCFG_VAL, &sdram->SDRAM_DEVCFG_REG);

	/* Issue continous NOP commands */
	writel(GLCONFIG_INIT | GLCONFIG_MRS | GLCONFIG_CKE, &sdram->glconfig);

	early_udelay(200);

	precharge_all_banks();

	setup_refresh_timer();

	program_mode_registers();

	/* Select normal operation mode */
	writel(GLCONFIG_CKE, &sdram->glconfig);
}

static void precharge_all_banks(void)
{
	struct sdram_regs *sdram = (struct sdram_regs *)SDRAM_BASE;

	/* Issue PRECHARGE ALL commands */
	writel(GLCONFIG_INIT | GLCONFIG_CKE, &sdram->glconfig);

	/*
	 * Errata of most EP93xx revisions say that PRECHARGE ALL isn't always
	 * issued.
	 *
	 *  Cirrus proposes a workaround which consists in performing a read from
	 * each bank to force the precharge. This causes some boards to hang.
	 * Writing to the SDRAM banks instead of reading has the same
	 * side-effect (the SDRAM controller issues the necessary precharges),
	 * but is known to work on all supported boards
	 */

	PRECHARGE_BANK(0);

#if (CONFIG_EP93XX_SDRAM_NUM_BANKS >= 2)
	PRECHARGE_BANK(1);
#endif

#if (CONFIG_EP93XX_SDRAM_NUM_BANKS >= 3)
	PRECHARGE_BANK(2);
#endif

#if (CONFIG_EP93XX_SDRAM_NUM_BANKS == 4)
	PRECHARGE_BANK(3);
#endif
}

static void setup_refresh_timer(void)
{
	struct sdram_regs *sdram = (struct sdram_regs *)SDRAM_BASE;

	/* Load refresh timer with 10 to issue refresh every 10 cycles */
	writel(0x0a, &sdram->refrshtimr);

	/*
	 * Wait at least 80 clock cycles to provide 8 refresh cycles
	 * to all SDRAMs
	 */
	early_udelay(1);

	/*
	 * Program refresh timer with normal value
	 * We need 8192 refresh cycles every 64ms
	 * at 15ns (HCLK >= 66MHz) per cycle:
	 * 64ms / 8192 = 7.8125us
	 * 7.8125us / 15ns = 520 (0x208)
	 */
	/*
	 * TODO: redboot uses 0x1e0 for the slowest possible device
	 * but i don't understand how this value is calculated
	 */
	writel(0x208, &sdram->refrshtimr);
}

static void program_mode_registers(void)
{
	struct sdram_regs *sdram = (struct sdram_regs *)SDRAM_BASE;

	/* Select mode register update mode */
	writel(GLCONFIG_MRS | GLCONFIG_CKE, &sdram->glconfig);

	PROGRAM_MODE_REG(0);

#if (CONFIG_EP93XX_SDRAM_NUM_BANKS >= 2)
	PROGRAM_MODE_REG(1);
#endif

#if (CONFIG_EP93XX_SDRAM_NUM_BANKS >= 3)
	PROGRAM_MODE_REG(2);
#endif

#if (CONFIG_EP93XX_SDRAM_NUM_BANKS == 4)
	PROGRAM_MODE_REG(3);
#endif
}