1// SPDX-License-Identifier: GPL-2.0+ 2/* 3 * (c) Copyright 2011 by Tigris Elektronik GmbH 4 * 5 * Author: 6 * Maximilian Schwerin <mvs@tigris.de> 7 */ 8 9#include <common.h> 10#include <command.h> 11#include <env.h> 12#include <env_internal.h> 13#include <part.h> 14#include <malloc.h> 15#include <memalign.h> 16#include <search.h> 17#include <errno.h> 18#include <fat.h> 19#include <mmc.h> 20#include <scsi.h> 21#include <virtio.h> 22#include <asm/cache.h> 23#include <asm/global_data.h> 24#include <linux/stddef.h> 25 26#ifdef CONFIG_SPL_BUILD 27/* TODO(sjg@chromium.org): Figure out why this is needed */ 28# if !defined(CONFIG_TARGET_AM335X_EVM) || defined(CONFIG_SPL_OS_BOOT) 29# define LOADENV 30# endif 31#else 32# define LOADENV 33#endif 34 35DECLARE_GLOBAL_DATA_PTR; 36 37__weak const char *env_fat_get_intf(void) 38{ 39 return (const char *)CONFIG_ENV_FAT_INTERFACE; 40} 41 42__weak char *env_fat_get_dev_part(void) 43{ 44#ifdef CONFIG_MMC 45 static char *part_str; 46 47 if (!part_str) { 48 part_str = CONFIG_ENV_FAT_DEVICE_AND_PART; 49 if (!strcmp(CONFIG_ENV_FAT_INTERFACE, "mmc") && part_str[0] == ':') { 50 part_str = "0" CONFIG_ENV_FAT_DEVICE_AND_PART; 51 part_str[0] += mmc_get_env_dev(); 52 } 53 } 54 55 return part_str; 56#else 57 return CONFIG_ENV_FAT_DEVICE_AND_PART; 58#endif 59} 60 61static int env_fat_save(void) 62{ 63 env_t __aligned(ARCH_DMA_MINALIGN) env_new; 64 struct blk_desc *dev_desc = NULL; 65 struct disk_partition info; 66 const char *file = CONFIG_ENV_FAT_FILE; 67 int dev, part; 68 int err; 69 loff_t size; 70 const char *ifname = env_fat_get_intf(); 71 const char *dev_and_part = env_fat_get_dev_part(); 72 73 err = env_export(&env_new); 74 if (err) 75 return err; 76 77 part = blk_get_device_part_str(ifname, dev_and_part, 78 &dev_desc, &info, 1); 79 if (part < 0) 80 return 1; 81 82 dev = dev_desc->devnum; 83 if (fat_set_blk_dev(dev_desc, &info) != 0) { 84 /* 85 * This printf is embedded in the messages from env_save that 86 * will calling it. The missing \n is intentional. 87 */ 88 printf("Unable to use %s %d:%d...\n", ifname, dev, part); 89 return 1; 90 } 91 92#ifdef CONFIG_SYS_REDUNDAND_ENVIRONMENT 93 if (gd->env_valid == ENV_VALID) 94 file = CONFIG_ENV_FAT_FILE_REDUND; 95#endif 96 97 err = file_fat_write(file, (void *)&env_new, 0, sizeof(env_t), &size); 98 if (err == -1) { 99 /* 100 * This printf is embedded in the messages from env_save that 101 * will calling it. The missing \n is intentional. 102 */ 103 printf("Unable to write \"%s\" from %s%d:%d...\n", file, ifname, dev, part); 104 return 1; 105 } 106 107#ifdef CONFIG_SYS_REDUNDAND_ENVIRONMENT 108 gd->env_valid = (gd->env_valid == ENV_REDUND) ? ENV_VALID : ENV_REDUND; 109#endif 110 111 return 0; 112} 113 114#ifdef LOADENV 115static int env_fat_load(void) 116{ 117 ALLOC_CACHE_ALIGN_BUFFER(char, buf1, CONFIG_ENV_SIZE); 118#ifdef CONFIG_SYS_REDUNDAND_ENVIRONMENT 119 ALLOC_CACHE_ALIGN_BUFFER(char, buf2, CONFIG_ENV_SIZE); 120 int err2; 121#endif 122 struct blk_desc *dev_desc = NULL; 123 struct disk_partition info; 124 int dev, part; 125 int err1; 126 const char *ifname = env_fat_get_intf(); 127 const char *dev_and_part = env_fat_get_dev_part(); 128 129#ifdef CONFIG_MMC 130 if (!strcmp(ifname, "mmc")) 131 mmc_initialize(NULL); 132#endif 133#ifndef CONFIG_SPL_BUILD 134#if defined(CONFIG_AHCI) || defined(CONFIG_SCSI) 135 if (!strcmp(CONFIG_ENV_FAT_INTERFACE, "scsi")) 136 scsi_scan(true); 137#endif 138#if defined(CONFIG_VIRTIO) 139 if (!strcmp(ifname, "virtio")) 140 virtio_init(); 141#endif 142#endif 143 part = blk_get_device_part_str(ifname, dev_and_part, 144 &dev_desc, &info, 1); 145 if (part < 0) 146 goto err_env_relocate; 147 148 dev = dev_desc->devnum; 149 if (fat_set_blk_dev(dev_desc, &info) != 0) { 150 /* 151 * This printf is embedded in the messages from env_save that 152 * will calling it. The missing \n is intentional. 153 */ 154 printf("Unable to use %s %d:%d...\n", ifname, dev, part); 155 goto err_env_relocate; 156 } 157 158 err1 = file_fat_read(CONFIG_ENV_FAT_FILE, buf1, CONFIG_ENV_SIZE); 159#ifdef CONFIG_SYS_REDUNDAND_ENVIRONMENT 160 err2 = file_fat_read(CONFIG_ENV_FAT_FILE_REDUND, buf2, CONFIG_ENV_SIZE); 161 162 err1 = (err1 >= 0) ? 0 : -1; 163 err2 = (err2 >= 0) ? 0 : -1; 164 return env_import_redund(buf1, err1, buf2, err2, H_EXTERNAL); 165#else 166 if (err1 < 0) { 167 /* 168 * This printf is embedded in the messages from env_save that 169 * will calling it. The missing \n is intentional. 170 */ 171 printf("Unable to read \"%s\" from %s%d:%d... \n", 172 CONFIG_ENV_FAT_FILE, ifname, dev, part); 173 goto err_env_relocate; 174 } 175 176 return env_import(buf1, 1, H_EXTERNAL); 177#endif 178 179err_env_relocate: 180 env_set_default(NULL, 0); 181 182 return -EIO; 183} 184#endif /* LOADENV */ 185 186U_BOOT_ENV_LOCATION(fat) = { 187 .location = ENVL_FAT, 188 ENV_NAME("FAT") 189#ifdef LOADENV 190 .load = env_fat_load, 191#endif 192 .save = ENV_SAVE_PTR(env_fat_save), 193}; 194