1 /* SPDX-License-Identifier: GPL-2.0-only */
2
3 #include <boot_device.h>
4 #include <symbols.h>
5 #include <console/console.h>
6 #include <assert.h>
7 #include <commonlib/storage/sd_mmc.h>
8 #include <cbfs.h>
9
10 #include <soc/ti/am335x/mmc.h>
11 #include <soc/ti/am335x/header.h>
12
13 // Where the coreboot image is expected to be located on the SD card
14 // Only certain locations are allowed - check the AM335x technical reference
15 // manual for more details.
16 #define COREBOOT_IMAGE_OFFSET (128 * KiB)
17
18 #define SD_BLOCK_SIZE 512
19
20 static struct am335x_mmc_host sd_host;
21 static struct storage_media media;
22
partial_block_read(uint8_t * dest,uint64_t block,uint32_t offset,uint32_t count)23 static size_t partial_block_read(uint8_t *dest, uint64_t block, uint32_t offset, uint32_t count)
24 {
25 static uint8_t overflow_block[SD_BLOCK_SIZE];
26
27 uint64_t blocks_read = storage_block_read(&media, block, 1, &overflow_block);
28
29 if (blocks_read != 1) {
30 printk(BIOS_ERR, "Expected to read 1 block but read: %llu\n", blocks_read);
31 return 0;
32 }
33
34 assert((offset + count) <= SD_BLOCK_SIZE);
35
36 int dest_index = 0;
37 for (int overflow_index = offset; overflow_index < (offset + count); overflow_index++)
38 dest[dest_index++] = overflow_block[overflow_index];
39
40 return count;
41 }
42
43 // This supports reads from a SD card that aren't necessarily aligned to the
44 // sd block size
sd_readat(const struct region_device * rdev,void * dest,size_t offset,size_t count)45 static ssize_t sd_readat(const struct region_device *rdev, void *dest, size_t offset,
46 size_t count)
47 {
48 uint8_t *buffer = (uint8_t *)dest;
49
50 uint64_t block_start = offset / SD_BLOCK_SIZE;
51 uint64_t block_end = (offset + count) / SD_BLOCK_SIZE;
52 uint64_t blocks = block_end - block_start + 1;
53
54 // Read the last first, which might not be aligned on a SD block
55 uint32_t first_block_offset = offset % SD_BLOCK_SIZE;
56 size_t first_block_to_read = MIN(SD_BLOCK_SIZE - first_block_offset, count);
57 size_t bytes_read = partial_block_read(buffer, block_start, first_block_offset,
58 first_block_to_read);
59
60 if (blocks == 1)
61 return bytes_read;
62
63 buffer += bytes_read;
64
65 if (blocks > 2) {
66 // Read all the "whole" blocks between the start and end blocks
67 uint64_t to_read = blocks - 2;
68 uint64_t blocks_read =
69 storage_block_read(&media, block_start + 1, to_read, (void *)buffer);
70
71 if (blocks_read != to_read) {
72 printk(BIOS_ERR, "Expecting to read %llu blocks but only read %llu\n",
73 to_read, blocks_read);
74 return blocks_read * SD_BLOCK_SIZE;
75 }
76
77 buffer += to_read * SD_BLOCK_SIZE;
78 bytes_read += to_read * SD_BLOCK_SIZE;
79 }
80
81 // Read the last block, which might not be aligned on a SD block
82 bytes_read += partial_block_read(buffer, block_end, 0, count - bytes_read);
83
84 return bytes_read;
85 }
86
87 static const struct region_device_ops am335x_sd_ops = {
88 .mmap = mmap_helper_rdev_mmap,
89 .munmap = mmap_helper_rdev_munmap,
90 .readat = sd_readat,
91 };
92
93 extern struct omap_image_headers headers;
94
95 static struct mmap_helper_region_device sd_mdev = MMAP_HELPER_DEV_INIT(
96 &am335x_sd_ops, COREBOOT_IMAGE_OFFSET + sizeof(headers), CONFIG_ROM_SIZE,
97 &cbfs_cache);
98
99 static bool init_done = false;
100
boot_device_init(void)101 void boot_device_init(void)
102 {
103 if (init_done)
104 return;
105
106 sd_host.sd_clock_hz = 96000000;
107 sd_host.reg = (void *)MMCHS0_BASE;
108 am335x_mmc_init_storage(&sd_host);
109 storage_setup_media(&media, &sd_host.sd_mmc_ctrlr);
110 storage_display_setup(&media);
111
112 init_done = true;
113 }
114
boot_device_ro(void)115 const struct region_device *boot_device_ro(void)
116 {
117 return &sd_mdev.rdev;
118 }
119