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