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
142
143
144
145
146
147
148
149
150
|
// SPDX-License-Identifier: GPL-2.0+
/*
* Helpers that are commonly used with DW memory controller.
*
* (C) Copyright 2025 Jernej Skrabec <jernej.skrabec@gmail.com>
*
*/
#include <init.h>
#include <asm/arch/dram_dw_helpers.h>
void mctl_auto_detect_rank_width(const struct dram_para *para,
struct dram_config *config)
{
/* this is minimum size that it's supported */
config->cols = 8;
config->rows = 13;
/*
* Strategy here is to test most demanding combination first and least
* demanding last, otherwise HW might not be fully utilized. For
* example, half bus width and rank = 1 combination would also work
* on HW with full bus width and rank = 2, but only 1/4 RAM would be
* visible.
*/
debug("testing 32-bit width, rank = 2\n");
config->bus_full_width = 1;
config->ranks = 2;
if (mctl_core_init(para, config))
return;
debug("testing 32-bit width, rank = 1\n");
config->bus_full_width = 1;
config->ranks = 1;
if (mctl_core_init(para, config))
return;
debug("testing 16-bit width, rank = 2\n");
config->bus_full_width = 0;
config->ranks = 2;
if (mctl_core_init(para, config))
return;
debug("testing 16-bit width, rank = 1\n");
config->bus_full_width = 0;
config->ranks = 1;
if (mctl_core_init(para, config))
return;
panic("This DRAM setup is currently not supported.\n");
}
static void mctl_write_pattern(void)
{
unsigned int i;
u32 *ptr, val;
ptr = (u32 *)CFG_SYS_SDRAM_BASE;
for (i = 0; i < 16; ptr++, i++) {
if (i & 1)
val = ~(ulong)ptr;
else
val = (ulong)ptr;
writel(val, ptr);
}
}
static bool mctl_check_pattern(ulong offset)
{
unsigned int i;
u32 *ptr, val;
ptr = (u32 *)CFG_SYS_SDRAM_BASE;
for (i = 0; i < 16; ptr++, i++) {
if (i & 1)
val = ~(ulong)ptr;
else
val = (ulong)ptr;
if (val != *(ptr + offset / 4))
return false;
}
return true;
}
void mctl_auto_detect_dram_size(const struct dram_para *para,
struct dram_config *config)
{
unsigned int shift, cols, rows;
u32 buffer[16];
/* max. config for columns, but not rows */
config->cols = 11;
config->rows = 13;
mctl_core_init(para, config);
/*
* Store content so it can be restored later. This is important
* if controller was already initialized and holds any data
* which is important for restoring system.
*/
memcpy(buffer, (u32 *)CFG_SYS_SDRAM_BASE, sizeof(buffer));
mctl_write_pattern();
shift = config->bus_full_width + 1;
/* detect column address bits */
for (cols = 8; cols < 11; cols++) {
if (mctl_check_pattern(1ULL << (cols + shift)))
break;
}
debug("detected %u columns\n", cols);
/* restore data */
memcpy((u32 *)CFG_SYS_SDRAM_BASE, buffer, sizeof(buffer));
/* reconfigure to make sure that all active rows are accessible */
config->cols = 8;
config->rows = 17;
mctl_core_init(para, config);
/* store data again as it might be moved */
memcpy(buffer, (u32 *)CFG_SYS_SDRAM_BASE, sizeof(buffer));
mctl_write_pattern();
/* detect row address bits */
shift = config->bus_full_width + 4 + config->cols;
for (rows = 13; rows < 17; rows++) {
if (mctl_check_pattern(1ULL << (rows + shift)))
break;
}
debug("detected %u rows\n", rows);
/* restore data again */
memcpy((u32 *)CFG_SYS_SDRAM_BASE, buffer, sizeof(buffer));
config->cols = cols;
config->rows = rows;
}
unsigned long mctl_calc_size(const struct dram_config *config)
{
u8 width = config->bus_full_width ? 4 : 2;
/* 8 banks */
return (1ULL << (config->cols + config->rows + 3)) * width * config->ranks;
}
|