Angel Pons | 230e4f9d | 2020-04-05 15:47:14 +0200 | [diff] [blame] | 1 | /* SPDX-License-Identifier: GPL-2.0-only */ |
Lee Leahy | 16bc9ba | 2017-04-01 20:33:58 -0700 | [diff] [blame] | 2 | |
Kyösti Mälkki | f1b58b7 | 2019-03-01 13:43:02 +0200 | [diff] [blame] | 3 | #include <device/pci_ops.h> |
Lee Leahy | 16bc9ba | 2017-04-01 20:33:58 -0700 | [diff] [blame] | 4 | #include <assert.h> |
| 5 | #include <cbmem.h> |
Lee Leahy | 48dbc66 | 2017-05-08 16:56:03 -0700 | [diff] [blame] | 6 | #include <commonlib/sdhci.h> |
| 7 | #include <commonlib/storage.h> |
Lee Leahy | 16bc9ba | 2017-04-01 20:33:58 -0700 | [diff] [blame] | 8 | #include <console/console.h> |
Lee Leahy | 16bc9ba | 2017-04-01 20:33:58 -0700 | [diff] [blame] | 9 | #include <lib.h> |
| 10 | #include <soc/iomap.h> |
| 11 | #include <soc/pci_devs.h> |
| 12 | #include <soc/storage_test.h> |
Elyes HAOUAS | add76f9 | 2019-03-21 09:55:49 +0100 | [diff] [blame] | 13 | #include <timer.h> |
Lee Leahy | 16bc9ba | 2017-04-01 20:33:58 -0700 | [diff] [blame] | 14 | #include <string.h> |
| 15 | |
Julius Werner | cd49cce | 2019-03-05 16:53:33 -0800 | [diff] [blame] | 16 | #if CONFIG(STORAGE_LOG) |
Arthur Heymans | 84e22e3 | 2019-05-25 09:57:27 +0200 | [diff] [blame] | 17 | struct log_entry log[LOG_ENTRIES]; |
| 18 | uint8_t log_index; |
| 19 | int log_full; |
| 20 | long log_start_time; |
Lee Leahy | 16bc9ba | 2017-04-01 20:33:58 -0700 | [diff] [blame] | 21 | #endif |
Kyösti Mälkki | f30123b | 2019-02-01 06:44:07 +0200 | [diff] [blame] | 22 | |
Arthur Heymans | 84e22e3 | 2019-05-25 09:57:27 +0200 | [diff] [blame] | 23 | static uint8_t drivers_storage[256]; |
Lee Leahy | 16bc9ba | 2017-04-01 20:33:58 -0700 | [diff] [blame] | 24 | |
| 25 | #define STORAGE_DEBUG BIOS_DEBUG |
Julius Werner | cd49cce | 2019-03-05 16:53:33 -0800 | [diff] [blame] | 26 | #define LOG_DEBUG (CONFIG(STORAGE_LOG) ? STORAGE_DEBUG : BIOS_NEVER) |
Lee Leahy | 16bc9ba | 2017-04-01 20:33:58 -0700 | [diff] [blame] | 27 | |
Elyes HAOUAS | 6f01f43 | 2018-12-05 10:56:30 +0100 | [diff] [blame] | 28 | #ifdef __SIMPLE_DEVICE__ |
| 29 | uint32_t storage_test_init(pci_devfn_t dev, uint32_t *previous_bar, |
Lee Leahy | 16bc9ba | 2017-04-01 20:33:58 -0700 | [diff] [blame] | 30 | uint16_t *previous_command) |
Elyes HAOUAS | 6f01f43 | 2018-12-05 10:56:30 +0100 | [diff] [blame] | 31 | #else |
| 32 | uint32_t storage_test_init(struct device *dev, uint32_t *previous_bar, |
| 33 | uint16_t *previous_command) |
| 34 | #endif |
Lee Leahy | 16bc9ba | 2017-04-01 20:33:58 -0700 | [diff] [blame] | 35 | { |
| 36 | uint32_t bar; |
| 37 | |
| 38 | /* Display the vendor/device IDs */ |
| 39 | printk(LOG_DEBUG, "Vendor ID: 0x%04x, Device ID: 0x%04x\n", |
| 40 | pci_read_config16(dev, PCI_VENDOR_ID), |
| 41 | pci_read_config16(dev, PCI_DEVICE_ID)); |
| 42 | |
| 43 | /* Set the temporary base address */ |
| 44 | bar = pci_read_config32(dev, PCI_BASE_ADDRESS_0); |
| 45 | *previous_bar = bar; |
| 46 | bar &= ~PCI_BASE_ADDRESS_MEM_ATTR_MASK; |
| 47 | if (!bar) { |
| 48 | bar = SD_BASE_ADDRESS; |
| 49 | pci_write_config32(dev, PCI_BASE_ADDRESS_0, bar); |
| 50 | } |
| 51 | |
| 52 | /* Enable the SD/MMC controller */ |
| 53 | *previous_command = pci_read_config16(dev, PCI_COMMAND); |
| 54 | pci_write_config16(dev, PCI_COMMAND, *previous_command |
| 55 | | PCI_COMMAND_MEMORY); |
| 56 | |
| 57 | /* Return the controller address */ |
| 58 | return bar; |
| 59 | } |
| 60 | |
Elyes HAOUAS | 6f01f43 | 2018-12-05 10:56:30 +0100 | [diff] [blame] | 61 | #ifdef __SIMPLE_DEVICE__ |
| 62 | void storage_test_complete(pci_devfn_t dev, uint32_t previous_bar, |
Lee Leahy | 16bc9ba | 2017-04-01 20:33:58 -0700 | [diff] [blame] | 63 | uint16_t previous_command) |
Elyes HAOUAS | 6f01f43 | 2018-12-05 10:56:30 +0100 | [diff] [blame] | 64 | #else |
| 65 | void storage_test_complete(struct device *dev, uint32_t previous_bar, |
| 66 | uint16_t previous_command) |
| 67 | #endif |
Lee Leahy | 16bc9ba | 2017-04-01 20:33:58 -0700 | [diff] [blame] | 68 | { |
| 69 | pci_write_config16(dev, PCI_COMMAND, previous_command); |
| 70 | pci_write_config32(dev, PCI_BASE_ADDRESS_0, previous_bar); |
| 71 | } |
| 72 | |
| 73 | #if !ENV_BOOTBLOCK |
| 74 | static void display_log(void) |
| 75 | { |
| 76 | /* Determine the array bounds */ |
Julius Werner | cd49cce | 2019-03-05 16:53:33 -0800 | [diff] [blame] | 77 | if (CONFIG(STORAGE_LOG)) { |
Lee Leahy | 16bc9ba | 2017-04-01 20:33:58 -0700 | [diff] [blame] | 78 | long delta; |
| 79 | uint8_t end; |
| 80 | uint8_t index; |
| 81 | uint8_t start; |
| 82 | |
| 83 | end = log_index; |
| 84 | start = log_full ? log_index : 0; |
| 85 | for (index = start; (log_full || (index != end)); index++) { |
| 86 | log_full = 0; |
| 87 | delta = log[index].time.microseconds - log_start_time; |
| 88 | printk(BIOS_DEBUG, "%3ld.%03ld mSec, cmd: %2d 0x%08x%s", |
| 89 | delta / 1000, delta % 1000, |
| 90 | log[index].cmd.cmdidx, |
| 91 | log[index].cmd.cmdarg, |
| 92 | log[index].cmd_issued ? "" : "(not issued)"); |
| 93 | if (log[index].response_entries == 1) |
| 94 | printk(BIOS_DEBUG, ", rsp: 0x%08x", |
| 95 | log[index].response[0]); |
| 96 | else if (log[index].response_entries == 4) |
| 97 | printk(BIOS_DEBUG, |
| 98 | ", rsp: 0x%08x.%08x.%08x.%08x", |
| 99 | log[index].response[3], |
| 100 | log[index].response[2], |
| 101 | log[index].response[1], |
| 102 | log[index].response[0]); |
| 103 | printk(BIOS_DEBUG, ", ret: %d\n", log[index].ret); |
| 104 | } |
| 105 | } |
| 106 | } |
| 107 | |
| 108 | void sdhc_log_command(struct mmc_command *cmd) |
| 109 | { |
Julius Werner | cd49cce | 2019-03-05 16:53:33 -0800 | [diff] [blame] | 110 | if (CONFIG(STORAGE_LOG)) { |
Lee Leahy | 16bc9ba | 2017-04-01 20:33:58 -0700 | [diff] [blame] | 111 | timer_monotonic_get(&log[log_index].time); |
| 112 | log[log_index].cmd = *cmd; |
| 113 | log[log_index].cmd_issued = 0; |
| 114 | log[log_index].response_entries = 0; |
| 115 | if ((log_index == 0) && (!log_full)) |
| 116 | log_start_time = log[0].time.microseconds; |
| 117 | } |
| 118 | } |
| 119 | |
| 120 | void sdhc_log_command_issued(void) |
| 121 | { |
Julius Werner | cd49cce | 2019-03-05 16:53:33 -0800 | [diff] [blame] | 122 | if (CONFIG(STORAGE_LOG)) { |
Lee Leahy | 16bc9ba | 2017-04-01 20:33:58 -0700 | [diff] [blame] | 123 | log[log_index].cmd_issued = 1; |
| 124 | } |
| 125 | } |
| 126 | |
| 127 | void sdhc_log_response(uint32_t entries, uint32_t *response) |
| 128 | { |
| 129 | unsigned int entry; |
| 130 | |
Julius Werner | cd49cce | 2019-03-05 16:53:33 -0800 | [diff] [blame] | 131 | if (CONFIG(STORAGE_LOG)) { |
Lee Leahy | 16bc9ba | 2017-04-01 20:33:58 -0700 | [diff] [blame] | 132 | log[log_index].response_entries = entries; |
| 133 | for (entry = 0; entry < entries; entry++) |
| 134 | log[log_index].response[entry] = response[entry]; |
| 135 | } |
| 136 | } |
| 137 | |
| 138 | void sdhc_log_ret(int ret) |
| 139 | { |
Julius Werner | cd49cce | 2019-03-05 16:53:33 -0800 | [diff] [blame] | 140 | if (CONFIG(STORAGE_LOG)) { |
Lee Leahy | 16bc9ba | 2017-04-01 20:33:58 -0700 | [diff] [blame] | 141 | log[log_index].ret = ret; |
| 142 | if (++log_index == 0) |
| 143 | log_full = 1; |
| 144 | } |
| 145 | } |
| 146 | |
| 147 | void storage_test(uint32_t bar, int full_initialization) |
| 148 | { |
| 149 | uint64_t blocks_read; |
| 150 | uint8_t buffer[512]; |
| 151 | int err; |
| 152 | struct storage_media *media; |
| 153 | const char *name; |
| 154 | unsigned int partition; |
| 155 | unsigned int previous_partition; |
| 156 | struct sdhci_ctrlr *sdhci_ctrlr; |
| 157 | |
Kyösti Mälkki | f30123b | 2019-02-01 06:44:07 +0200 | [diff] [blame] | 158 | ASSERT(sizeof(struct sdhci_ctrlr) <= sizeof(drivers_storage)); |
| 159 | |
Lee Leahy | 16bc9ba | 2017-04-01 20:33:58 -0700 | [diff] [blame] | 160 | /* Get the structure addresses */ |
| 161 | media = NULL; |
Kyösti Mälkki | fa3bc04 | 2022-03-31 07:40:10 +0300 | [diff] [blame] | 162 | if (ENV_CREATES_CBMEM) |
Arthur Heymans | 84e22e3 | 2019-05-25 09:57:27 +0200 | [diff] [blame] | 163 | media = (struct storage_media *)drivers_storage; |
Lee Leahy | 16bc9ba | 2017-04-01 20:33:58 -0700 | [diff] [blame] | 164 | else |
| 165 | media = cbmem_find(CBMEM_ID_STORAGE_DATA); |
| 166 | sdhci_ctrlr = (void *)(((uintptr_t)(media + 1) + 0x7) & ~7); |
Lee Leahy | 16bc9ba | 2017-04-01 20:33:58 -0700 | [diff] [blame] | 167 | media->ctrlr = (struct sd_mmc_ctrlr *)sdhci_ctrlr; |
| 168 | sdhci_ctrlr->ioaddr = (void *)bar; |
| 169 | |
| 170 | /* Initialize the controller */ |
| 171 | if (!full_initialization) { |
| 172 | /* Perform fast initialization */ |
| 173 | sdhci_update_pointers(sdhci_ctrlr); |
| 174 | sdhci_display_setup(sdhci_ctrlr); |
| 175 | storage_display_setup(media); |
| 176 | } else { |
| 177 | /* Initialize the log */ |
Julius Werner | cd49cce | 2019-03-05 16:53:33 -0800 | [diff] [blame] | 178 | if (CONFIG(STORAGE_LOG)) { |
Lee Leahy | 16bc9ba | 2017-04-01 20:33:58 -0700 | [diff] [blame] | 179 | log_index = 0; |
| 180 | log_full = 0; |
| 181 | } |
| 182 | |
| 183 | printk(LOG_DEBUG, "Initializing the SD/MMC controller\n"); |
| 184 | err = sdhci_controller_init(sdhci_ctrlr, (void *)bar); |
| 185 | if (err) { |
| 186 | display_log(); |
Elyes HAOUAS | 9d28899 | 2022-02-04 19:59:20 +0100 | [diff] [blame] | 187 | printk(BIOS_ERR, "Controller failed to initialize, err = %d\n", |
Lee Leahy | 16bc9ba | 2017-04-01 20:33:58 -0700 | [diff] [blame] | 188 | err); |
| 189 | return; |
| 190 | } |
| 191 | |
| 192 | /* Initialize the SD/MMC/eMMC card or device */ |
| 193 | printk(LOG_DEBUG, "Initializing the device\n"); |
| 194 | err = storage_setup_media(media, &sdhci_ctrlr->sd_mmc_ctrlr); |
| 195 | if (err) { |
| 196 | display_log(); |
Julius Werner | e966595 | 2022-01-21 17:06:20 -0800 | [diff] [blame] | 197 | printk(BIOS_ERR, "Device failed to initialize, err = %d\n", |
Lee Leahy | 16bc9ba | 2017-04-01 20:33:58 -0700 | [diff] [blame] | 198 | err); |
| 199 | return; |
| 200 | } |
| 201 | display_log(); |
| 202 | } |
| 203 | |
| 204 | /* Save the current partition */ |
| 205 | previous_partition = storage_get_current_partition(media); |
| 206 | |
| 207 | /* Read block 0 from each partition */ |
| 208 | for (partition = 0; partition < ARRAY_SIZE(media->capacity); |
| 209 | partition++) { |
| 210 | if (media->capacity[partition] == 0) |
| 211 | continue; |
| 212 | name = storage_partition_name(media, partition); |
| 213 | printk(STORAGE_DEBUG, "%s%sReading block 0\n", name, |
| 214 | name[0] ? ": " : ""); |
| 215 | err = storage_set_partition(media, partition); |
| 216 | if (err) |
| 217 | continue; |
| 218 | blocks_read = storage_block_read(media, 0, 1, &buffer); |
| 219 | if (blocks_read) |
| 220 | hexdump(buffer, sizeof(buffer)); |
| 221 | } |
| 222 | |
| 223 | /* Restore the previous partition */ |
| 224 | storage_set_partition(media, previous_partition); |
| 225 | } |
| 226 | #endif |
| 227 | |
Lee Leahy | 16bc9ba | 2017-04-01 20:33:58 -0700 | [diff] [blame] | 228 | static void copy_storage_structures(int is_recovery) |
| 229 | { |
| 230 | struct storage_media *media; |
| 231 | struct sdhci_ctrlr *sdhci_ctrlr; |
Kyösti Mälkki | f30123b | 2019-02-01 06:44:07 +0200 | [diff] [blame] | 232 | size_t size = sizeof(drivers_storage); |
Lee Leahy | 16bc9ba | 2017-04-01 20:33:58 -0700 | [diff] [blame] | 233 | |
| 234 | /* Locate the data structures in CBMEM */ |
Lee Leahy | 16bc9ba | 2017-04-01 20:33:58 -0700 | [diff] [blame] | 235 | media = cbmem_add(CBMEM_ID_STORAGE_DATA, size); |
| 236 | ASSERT(media != NULL); |
| 237 | sdhci_ctrlr = (void *)(((uintptr_t)(media + 1) + 0x7) & ~7); |
Lee Leahy | 16bc9ba | 2017-04-01 20:33:58 -0700 | [diff] [blame] | 238 | |
| 239 | /* Migrate the data into CBMEM */ |
Arthur Heymans | 84e22e3 | 2019-05-25 09:57:27 +0200 | [diff] [blame] | 240 | memcpy(media, drivers_storage, size); |
Lee Leahy | 16bc9ba | 2017-04-01 20:33:58 -0700 | [diff] [blame] | 241 | media->ctrlr = &sdhci_ctrlr->sd_mmc_ctrlr; |
| 242 | } |
| 243 | |
Kyösti Mälkki | fa3bc04 | 2022-03-31 07:40:10 +0300 | [diff] [blame] | 244 | CBMEM_CREATION_HOOK(copy_storage_structures); |