xref: /aosp_15_r20/external/coreboot/src/mainboard/ti/beaglebone/sd_media.c (revision b9411a12aaaa7e1e6a6fb7c5e057f44ee179a49c)
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