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
|
/* SPDX-License-Identifier: GPL-2.0-only */
#include <boot_device.h>
#include <symbols.h>
#include <console/console.h>
#include <assert.h>
#include <commonlib/storage/sd_mmc.h>
#include <cbfs.h>
#include <soc/ti/am335x/mmc.h>
#include <soc/ti/am335x/header.h>
// Where the coreboot image is expected to be located on the SD card
// Only certain locations are allowed - check the AM335x technical reference
// manual for more details.
#define COREBOOT_IMAGE_OFFSET (128 * KiB)
#define SD_BLOCK_SIZE 512
static struct am335x_mmc_host sd_host;
static struct storage_media media;
static size_t partial_block_read(uint8_t *dest, uint64_t block, uint32_t offset, uint32_t count)
{
static uint8_t overflow_block[SD_BLOCK_SIZE];
uint64_t blocks_read = storage_block_read(&media, block, 1, &overflow_block);
if (blocks_read != 1) {
printk(BIOS_ERR, "Expected to read 1 block but read: %llu\n", blocks_read);
return 0;
}
assert((offset + count) <= SD_BLOCK_SIZE);
int dest_index = 0;
for (int overflow_index = offset; overflow_index < (offset + count); overflow_index++)
dest[dest_index++] = overflow_block[overflow_index];
return count;
}
// This supports reads from a SD card that aren't necessarily aligned to the
// sd block size
static ssize_t sd_readat(const struct region_device *rdev, void *dest, size_t offset,
size_t count)
{
uint8_t *buffer = (uint8_t *)dest;
uint64_t block_start = offset / SD_BLOCK_SIZE;
uint64_t block_end = (offset + count) / SD_BLOCK_SIZE;
uint64_t blocks = block_end - block_start + 1;
// Read the last first, which might not be aligned on a SD block
uint32_t first_block_offset = offset % SD_BLOCK_SIZE;
size_t first_block_to_read = MIN(SD_BLOCK_SIZE - first_block_offset, count);
size_t bytes_read = partial_block_read(buffer, block_start, first_block_offset,
first_block_to_read);
if (blocks == 1)
return bytes_read;
buffer += bytes_read;
if (blocks > 2) {
// Read all the "whole" blocks between the start and end blocks
uint64_t to_read = blocks - 2;
uint64_t blocks_read =
storage_block_read(&media, block_start + 1, to_read, (void *)buffer);
if (blocks_read != to_read) {
printk(BIOS_ERR, "Expecting to read %llu blocks but only read %llu\n",
to_read, blocks_read);
return blocks_read * SD_BLOCK_SIZE;
}
buffer += to_read * SD_BLOCK_SIZE;
bytes_read += to_read * SD_BLOCK_SIZE;
}
// Read the last block, which might not be aligned on a SD block
bytes_read += partial_block_read(buffer, block_end, 0, count - bytes_read);
return bytes_read;
}
static const struct region_device_ops am335x_sd_ops = {
.mmap = mmap_helper_rdev_mmap,
.munmap = mmap_helper_rdev_munmap,
.readat = sd_readat,
};
extern struct omap_image_headers headers;
static struct mmap_helper_region_device sd_mdev = MMAP_HELPER_DEV_INIT(
&am335x_sd_ops, COREBOOT_IMAGE_OFFSET + sizeof(headers), CONFIG_ROM_SIZE,
&cbfs_cache);
static bool init_done = false;
void boot_device_init(void)
{
if (init_done)
return;
sd_host.sd_clock_hz = 96000000;
sd_host.reg = (void *)MMCHS0_BASE;
am335x_mmc_init_storage(&sd_host);
storage_setup_media(&media, &sd_host.sd_mmc_ctrlr);
storage_display_setup(&media);
init_done = true;
}
const struct region_device *boot_device_ro(void)
{
return &sd_mdev.rdev;
}
|