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