summaryrefslogtreecommitdiffstats
path: root/arch/arm/mach-at91/xload-mmc.c
blob: 33e5b203fe905a6076969189b8cbbc68e881506d (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
// SPDX-License-Identifier: GPL-2.0-only

#include <common.h>
#include <mach/xload.h>
#include <mach/sama5_bootsource.h>
#include <mach/hardware.h>
#include <mach/sama5d2_ll.h>
#include <mach/sama5d3_ll.h>
#include <mach/gpio.h>
#include <linux/sizes.h>
#include <asm/cache.h>
#include <pbl/bio.h>

static void at91_fat_start_image(struct pbl_bio *bio,
				 void *buf, unsigned int len,
				 u32 r4)
{
	void __noreturn (*bb)(void);
	int ret;

	ret = pbl_fat_load(bio, "barebox.bin", buf, len);
	if (ret < 0) {
		pr_err("pbl_fat_load: error %d\n", ret);
		return;
	}

	bb = buf;

	sync_caches_for_execution();

	sama5_boot_xload(bb, r4);
}

static const struct sdhci_instance {
	void __iomem *base;
	unsigned id;
	u8 periph;
	s8 pins[15];
} sdhci_instances[] = {
	[0] = {
		.base = SAMA5D2_BASE_SDHC0, .id = SAMA5D2_ID_SDMMC0, .periph = AT91_MUX_PERIPH_A,
		.pins = { 2, 3, 4, 5, 6, 7, 8, 9, 0, 1, 13, 10, 11, 12, -1 }
	},
	[1] = {
		.base = SAMA5D2_BASE_SDHC1, .id = SAMA5D2_ID_SDMMC1, .periph = AT91_MUX_PERIPH_E,
		.pins = { 18, 19, 20, 21, 22, 28, 30, -1 }
	},
};

/**
 * sama5d2_sdhci_start_image - Load and start an image from FAT-formatted SDHCI
 * @r4: value of r4 passed by BootROM
 */
void __noreturn sama5d2_sdhci_start_image(u32 r4)
{
	void *buf = (void *)SAMA5_DDRCS;
	const struct sdhci_instance *instance;
	struct pbl_bio bio;
	const s8 *pin;
	int ret;

	ret = sama5_bootsource_instance(r4);
	if (ret > 1)
		panic("Couldn't determine boot MCI instance\n");

	instance = &sdhci_instances[ret];

	sama5d2_pmc_enable_periph_clock(SAMA5D2_ID_PIOA);
	for (pin = instance->pins; *pin >= 0; pin++) {
		at91_mux_pio4_set_periph(SAMA5D2_BASE_PIOA,
					 BIT(*pin), instance->periph);
	}

	sama5d2_pmc_enable_periph_clock(instance->id);
	sama5d2_pmc_enable_generic_clock(instance->id, AT91_PMC_GCKCSS_UPLL_CLK, 1);

	ret = at91_sdhci_bio_init(&bio, instance->base);
	if (ret)
		goto out_panic;

	/* TODO: eMMC boot partition handling: they are not FAT-formatted */

	at91_fat_start_image(&bio, buf, SZ_16M, r4);

out_panic:
	panic("FAT chainloading failed\n");
}

static const struct atmci_instance {
	void __iomem *base;
	unsigned id;
	u8 periph;
	s8 pins[15];
} sama5d3_atmci_instances[] = {
	[0] = {
		.base = IOMEM(SAMA5D3_BASE_HSMCI0),
		.id = SAMA5D3_ID_HSMCI0,
		.periph = AT91_MUX_PERIPH_A,
		.pins = {
			AT91_PIN_PD0, AT91_PIN_PD1, AT91_PIN_PD2, AT91_PIN_PD3,
			AT91_PIN_PD4, AT91_PIN_PD5, AT91_PIN_PD6, AT91_PIN_PD7,
			AT91_PIN_PD8, AT91_PIN_PD9, -1 }
	},
};

void __noreturn sama5d3_atmci_start_image(u32 boot_src, unsigned int clock,
					  unsigned int slot)
{
	void *buf = (void *)SAMA5_DDRCS;
	const struct atmci_instance *instance;
	struct pbl_bio bio;
	const s8 *pin;
	int ret;

	ret = sama5_bootsource_instance(boot_src);
	if (ret > ARRAY_SIZE(sama5d3_atmci_instances) - 1)
		panic("Couldn't determine boot MCI instance\n");

	instance = &sama5d3_atmci_instances[boot_src];

	sama5d3_pmc_enable_periph_clock(SAMA5D3_ID_PIOD);
	for (pin = instance->pins; *pin >= 0; pin++) {
		at91_mux_pio3_pin(IOMEM(SAMA5D3_BASE_PIOD),
					 pin_to_mask(*pin), instance->periph, 0);
	}

	sama5d3_pmc_enable_periph_clock(instance->id);

	ret = at91_mci_bio_init(&bio, instance->base, clock, slot);
	if (ret)
		goto out_panic;

	at91_fat_start_image(&bio, buf, SZ_16M, boot_src);

out_panic:
	panic("FAT chainloading failed\n");
}