1 // SPDX-License-Identifier: GPL-2.0+ 2 /* 3 * (C) Copyright 2000 4 * Wolfgang Denk, DENX Software Engineering, wd (at) denx.de. 5 */ 6 7 /* #define DEBUG */ 8 9 #include <common.h> 10 #include <flash.h> 11 12 #include <mtd/cfi_flash.h> 13 14 extern flash_info_t flash_info[]; /* info for FLASH chips */ 15 16 /*----------------------------------------------------------------------- 17 * Functions 18 */ 19 20 /*----------------------------------------------------------------------- 21 * Set protection status for monitor sectors 22 * 23 * The monitor is always located in the _first_ Flash bank. 24 * If necessary you have to map the second bank at lower addresses. 25 */ 26 void 27 flash_protect (int flag, ulong from, ulong to, flash_info_t *info) 28 { 29 ulong b_end; 30 short s_end; 31 int i; 32 33 /* Do nothing if input data is bad. */ 34 if (!info || info->sector_count == 0 || info->size == 0 || to < from) { 35 return; 36 } 37 38 s_end = info->sector_count - 1; /* index of last sector */ 39 b_end = info->start[0] + info->size - 1; /* bank end address */ 40 41 debug ("flash_protect %s: from 0x%08lX to 0x%08lX\n", 42 (flag & FLAG_PROTECT_SET) ? "ON" : 43 (flag & FLAG_PROTECT_CLEAR) ? "OFF" : "???", 44 from, to); 45 46 /* There is nothing to do if we have no data about the flash 47 * or the protect range and flash range don't overlap. 48 */ 49 if (info->flash_id == FLASH_UNKNOWN || 50 to < info->start[0] || from > b_end) { 51 return; 52 } 53 54 for (i=0; i<info->sector_count; ++i) { 55 ulong end; /* last address in current sect */ 56 57 end = (i == s_end) ? b_end : info->start[i + 1] - 1; 58 59 /* Update protection if any part of the sector 60 * is in the specified range. 61 */ 62 if (from <= end && to >= info->start[i]) { 63 if (flag & FLAG_PROTECT_CLEAR) { 64 #if defined(CONFIG_SYS_FLASH_PROTECTION) 65 flash_real_protect(info, i, 0); 66 #else 67 info->protect[i] = 0; 68 #endif /* CONFIG_SYS_FLASH_PROTECTION */ 69 debug ("protect off %d\n", i); 70 } 71 else if (flag & FLAG_PROTECT_SET) { 72 #if defined(CONFIG_SYS_FLASH_PROTECTION) 73 flash_real_protect(info, i, 1); 74 #else 75 info->protect[i] = 1; 76 #endif /* CONFIG_SYS_FLASH_PROTECTION */ 77 debug ("protect on %d\n", i); 78 } 79 } 80 } 81 } 82 83 /*----------------------------------------------------------------------- 84 */ 85 86 flash_info_t * 87 addr2info (ulong addr) 88 { 89 flash_info_t *info; 90 int i; 91 92 for (i=0, info = &flash_info[0]; i<CONFIG_SYS_MAX_FLASH_BANKS; ++i, ++info) { 93 if (info->flash_id != FLASH_UNKNOWN && 94 addr >= info->start[0] && 95 /* WARNING - The '- 1' is needed if the flash 96 * is at the end of the address space, since 97 * info->start[0] + info->size wraps back to 0. 98 * Please don't change this unless you understand this. 99 */ 100 addr <= info->start[0] + info->size - 1) { 101 return (info); 102 } 103 } 104 105 return (NULL); 106 } 107 108 /*----------------------------------------------------------------------- 109 * Copy memory to flash. 110 * Make sure all target addresses are within Flash bounds, 111 * and no protected sectors are hit. 112 * Returns: 113 * ERR_OK 0 - OK 114 * ERR_TIMEOUT 1 - write timeout 115 * ERR_NOT_ERASED 2 - Flash not erased 116 * ERR_PROTECTED 4 - target range includes protected sectors 117 * ERR_INVAL 8 - target address not in Flash memory 118 * ERR_ALIGN 16 - target address not aligned on boundary 119 * (only some targets require alignment) 120 */ 121 int 122 flash_write (char *src, ulong addr, ulong cnt) 123 { 124 int i; 125 ulong end = addr + cnt - 1; 126 flash_info_t *info_first = addr2info (addr); 127 flash_info_t *info_last = addr2info (end ); 128 flash_info_t *info; 129 __maybe_unused char *src_orig = src; 130 __maybe_unused char *addr_orig = (char *)addr; 131 __maybe_unused ulong cnt_orig = cnt; 132 133 if (cnt == 0) { 134 return (ERR_OK); 135 } 136 137 if (!info_first || !info_last) { 138 return (ERR_INVAL); 139 } 140 141 for (info = info_first; info <= info_last; ++info) { 142 ulong b_end = info->start[0] + info->size; /* bank end addr */ 143 short s_end = info->sector_count - 1; 144 for (i=0; i<info->sector_count; ++i) { 145 ulong e_addr = (i == s_end) ? b_end : info->start[i + 1]; 146 147 if ((end >= info->start[i]) && (addr < e_addr) && 148 (info->protect[i] != 0) ) { 149 return (ERR_PROTECTED); 150 } 151 } 152 } 153 154 /* finally write data to flash */ 155 for (info = info_first; info <= info_last && cnt>0; ++info) { 156 ulong len; 157 158 len = info->start[0] + info->size - addr; 159 if (len > cnt) 160 len = cnt; 161 if ((i = write_buff(info, (uchar *)src, addr, len)) != 0) { 162 return (i); 163 } 164 cnt -= len; 165 addr += len; 166 src += len; 167 } 168 169 #if defined(CONFIG_FLASH_VERIFY) 170 if (memcmp(src_orig, addr_orig, cnt_orig)) { 171 printf("\nVerify failed!\n"); 172 return ERR_PROG_ERROR; 173 } 174 #endif /* CONFIG_SYS_FLASH_VERIFY_AFTER_WRITE */ 175 176 return (ERR_OK); 177 } 178 179 /*----------------------------------------------------------------------- 180 */ 181 182 void flash_perror (int err) 183 { 184 switch (err) { 185 case ERR_OK: 186 break; 187 case ERR_TIMEOUT: 188 puts ("Timeout writing to Flash\n"); 189 break; 190 case ERR_NOT_ERASED: 191 puts ("Flash not Erased\n"); 192 break; 193 case ERR_PROTECTED: 194 puts ("Can't write to protected Flash sectors\n"); 195 break; 196 case ERR_INVAL: 197 puts ("Outside available Flash\n"); 198 break; 199 case ERR_ALIGN: 200 puts ("Start and/or end address not on sector boundary\n"); 201 break; 202 case ERR_UNKNOWN_FLASH_VENDOR: 203 puts ("Unknown Vendor of Flash\n"); 204 break; 205 case ERR_UNKNOWN_FLASH_TYPE: 206 puts ("Unknown Type of Flash\n"); 207 break; 208 case ERR_PROG_ERROR: 209 puts ("General Flash Programming Error\n"); 210 break; 211 case ERR_ABORTED: 212 puts("Flash Programming Aborted\n"); 213 break; 214 default: 215 printf ("%s[%d] FIXME: rc=%d\n", __FILE__, __LINE__, err); 216 break; 217 } 218 } 219