summaryrefslogtreecommitdiffstats
path: root/arch/arm/mach-stm32mp/ddrctrl.c
blob: 31bddba764ed9e3bc89fe366243d4fade1ae498b (plain) (blame)
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
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
// SPDX-License-Identifier: GPL-2.0
/*
 * Copyright (c) 2019 Ahmad Fatoum <a.fatoum@pengutronix.de>
 */

#include <common.h>
#include <init.h>
#include <mach/ddr_regs.h>
#include <mach/entry.h>
#include <mach/stm32.h>
#include <mach/revision.h>
#include <asm/barebox-arm.h>
#include <asm/memory.h>
#include <pbl.h>
#include <io.h>

#define ADDRMAP1_BANK_B0	GENMASK( 5,  0)
#define ADDRMAP1_BANK_B1	GENMASK(13,  8)
#define ADDRMAP1_BANK_B2	GENMASK(21, 16)

#define ADDRMAP2_COL_B2		GENMASK( 3,  0)
#define ADDRMAP2_COL_B3		GENMASK(11,  8)
#define ADDRMAP2_COL_B4		GENMASK(19, 16)
#define ADDRMAP2_COL_B5		GENMASK(27, 24)

#define ADDRMAP3_COL_B6		GENMASK( 3,  0)
#define ADDRMAP3_COL_B7		GENMASK(11,  8)
#define ADDRMAP3_COL_B8		GENMASK(19, 16)
#define ADDRMAP3_COL_B9		GENMASK(27, 24)

#define ADDRMAP4_COL_B10	GENMASK( 3,  0)
#define ADDRMAP4_COL_B11	GENMASK(11,  8)

#define ADDRMAP5_ROW_B0		GENMASK( 3,  0)
#define ADDRMAP5_ROW_B1		GENMASK(11,  8)
#define ADDRMAP5_ROW_B2_10	GENMASK(19, 16)
#define ADDRMAP5_ROW_B11	GENMASK(27, 24)

#define ADDRMAP6_ROW_B12	GENMASK( 3,  0)
#define ADDRMAP6_ROW_B13	GENMASK(11,  8)
#define ADDRMAP6_ROW_B14	GENMASK(19, 16)
#define ADDRMAP6_ROW_B15	GENMASK(27, 24)

#define ADDRMAP9_ROW_B2		GENMASK( 3,  0)
#define ADDRMAP9_ROW_B3		GENMASK(11,  8)
#define ADDRMAP9_ROW_B4		GENMASK(19, 16)
#define ADDRMAP9_ROW_B5		GENMASK(27, 24)

#define ADDRMAP10_ROW_B6	GENMASK( 3,  0)
#define ADDRMAP10_ROW_B7	GENMASK(11,  8)
#define ADDRMAP10_ROW_B8	GENMASK(19, 16)
#define ADDRMAP10_ROW_B9	GENMASK(27, 24)

#define ADDRMAP11_ROW_B10	GENMASK( 3, 0)

#define LINE_UNUSED(reg, mask) (((reg) & (mask)) == (mask))

enum ddrctrl_buswidth {
	BUSWIDTH_FULL = 0,
	BUSWIDTH_HALF = 1,
	BUSWIDTH_QUARTER = 2
};

static unsigned long ddrctrl_addrmap_ramsize(struct stm32mp1_ddrctl __iomem *d,
					     enum ddrctrl_buswidth buswidth,
					     unsigned nb_bytes)
{
	unsigned banks = 3, cols = 12, rows = 16;
	u32 reg;

	cols += buswidth;

	reg = readl(&d->addrmap1);
	if (LINE_UNUSED(reg, ADDRMAP1_BANK_B2)) banks--;
	if (LINE_UNUSED(reg, ADDRMAP1_BANK_B1)) banks--;
	if (LINE_UNUSED(reg, ADDRMAP1_BANK_B0)) banks--;

	reg = readl(&d->addrmap2);
	if (LINE_UNUSED(reg, ADDRMAP2_COL_B5)) cols--;
	if (LINE_UNUSED(reg, ADDRMAP2_COL_B4)) cols--;
	if (LINE_UNUSED(reg, ADDRMAP2_COL_B3)) cols--;
	if (LINE_UNUSED(reg, ADDRMAP2_COL_B2)) cols--;

	reg = readl(&d->addrmap3);
	if (LINE_UNUSED(reg, ADDRMAP3_COL_B9)) cols--;
	if (LINE_UNUSED(reg, ADDRMAP3_COL_B8)) cols--;
	if (LINE_UNUSED(reg, ADDRMAP3_COL_B7)) cols--;
	if (LINE_UNUSED(reg, ADDRMAP3_COL_B6)) cols--;

	reg = readl(&d->addrmap4);
	if (LINE_UNUSED(reg, ADDRMAP4_COL_B11)) cols--;
	if (LINE_UNUSED(reg, ADDRMAP4_COL_B10)) cols--;

	reg = readl(&d->addrmap5);
	if (LINE_UNUSED(reg, ADDRMAP5_ROW_B11)) rows--;

	reg = readl(&d->addrmap6);
	if (LINE_UNUSED(reg, ADDRMAP6_ROW_B15)) rows--;
	if (LINE_UNUSED(reg, ADDRMAP6_ROW_B14)) rows--;
	if (LINE_UNUSED(reg, ADDRMAP6_ROW_B13)) rows--;
	if (LINE_UNUSED(reg, ADDRMAP6_ROW_B12)) rows--;

	return memory_sdram_size(cols, rows, BIT(banks),
				 DIV_ROUND_UP(nb_bytes, BIT(buswidth)));
}

static inline unsigned ddrctrl_ramsize(void __iomem *base, unsigned nb_bytes)
{
	struct stm32mp1_ddrctl __iomem *ddrctl = base;
	unsigned buswidth = readl(&ddrctl->mstr) & DDRCTRL_MSTR_DATA_BUS_WIDTH_MASK;
	buswidth >>= DDRCTRL_MSTR_DATA_BUS_WIDTH_SHIFT;

	return ddrctrl_addrmap_ramsize(ddrctl, buswidth, nb_bytes);
}

static inline unsigned stm32mp1_ddrctrl_ramsize(void)
{
	u32 nb_bytes = 4;

	if (cpu_stm32_is_stm32mp13())
		nb_bytes /= 2;

	return ddrctrl_ramsize(IOMEM(STM32_DDRCTL_BASE), nb_bytes);
}

void __noreturn stm32mp1_barebox_entry(void *boarddata)
{
	barebox_arm_entry(STM32_DDR_BASE, stm32mp1_ddrctrl_ramsize(), boarddata);
}


static int stm32mp1_ddr_probe(struct device_d *dev)
{
	struct resource *iores;
	void __iomem *base;
	unsigned long nb_bytes;

	iores = dev_request_mem_resource(dev, 0);
	if (IS_ERR(iores))
		return PTR_ERR(iores);
	base = IOMEM(iores->start);

	nb_bytes = (unsigned long)device_get_match_data(dev);

	return arm_add_mem_device("ram0", STM32_DDR_BASE,
				  ddrctrl_ramsize(base, nb_bytes));
}

static __maybe_unused struct of_device_id stm32mp1_ddr_dt_ids[] = {
	{ .compatible = "st,stm32mp1-ddr", .data = (void *)4 },
	{ .compatible = "st,stm32mp13-ddr", .data = (void *)2 },
	{ /* sentinel */ }
};

static struct driver_d stm32mp1_ddr_driver = {
	.name   = "stm32mp1-ddr",
	.probe  = stm32mp1_ddr_probe,
	.of_compatible = DRV_OF_COMPAT(stm32mp1_ddr_dt_ids),
};

static int stm32mp1_ddr_init(void)
{
	int ret;

	ret = platform_driver_register(&stm32mp1_ddr_driver);
	if (ret)
		return ret;

	return of_devices_ensure_probed_by_dev_id(stm32mp1_ddr_dt_ids);
}
mem_initcall(stm32mp1_ddr_init);