1 /* 2 * atmel_df_pow2.c - convert Atmel Dataflashes to Power of 2 mode 3 * 4 * Copyright 2009 Analog Devices Inc. 5 * 6 * Licensed under the 2-clause BSD. 7 */ 8 9 #include <common.h> 10 #include <exports.h> 11 #include <spi.h> 12 13 #define CMD_ID 0x9f 14 #define CMD_STAT 0xd7 15 #define CMD_CFG 0x3d 16 17 static int flash_cmd(struct spi_slave *slave, uchar cmd, uchar *buf, int len) 18 { 19 buf[0] = cmd; 20 return spi_xfer(slave, 8 * len, buf, buf, SPI_XFER_BEGIN | SPI_XFER_END); 21 } 22 23 static int flash_status(struct spi_slave *slave) 24 { 25 uchar buf[2]; 26 if (flash_cmd(slave, CMD_STAT, buf, sizeof(buf))) 27 return -1; 28 return buf[1]; 29 } 30 31 static int flash_set_pow2(struct spi_slave *slave) 32 { 33 int ret; 34 uchar buf[4]; 35 36 buf[1] = 0x2a; 37 buf[2] = 0x80; 38 buf[3] = 0xa6; 39 40 ret = flash_cmd(slave, CMD_CFG, buf, sizeof(buf)); 41 if (ret) 42 return ret; 43 44 /* wait Tp, or 6 msec */ 45 udelay(6000); 46 47 ret = flash_status(slave); 48 if (ret == -1) 49 return 1; 50 51 return ret & 0x1 ? 0 : 1; 52 } 53 54 static int flash_check(struct spi_slave *slave) 55 { 56 int ret; 57 uchar buf[4]; 58 59 ret = flash_cmd(slave, CMD_ID, buf, sizeof(buf)); 60 if (ret) 61 return ret; 62 63 if (buf[1] != 0x1F) { 64 printf("atmel flash not found (id[0] = %#x)\n", buf[1]); 65 return 1; 66 } 67 68 if ((buf[2] >> 5) != 0x1) { 69 printf("AT45 flash not found (id[0] = %#x)\n", buf[2]); 70 return 2; 71 } 72 73 return 0; 74 } 75 76 static char *getline(void) 77 { 78 static char buffer[100]; 79 char c; 80 size_t i; 81 82 i = 0; 83 while (1) { 84 buffer[i] = '\0'; 85 86 c = getc(); 87 88 switch (c) { 89 case '\r': /* Enter/Return key */ 90 case '\n': 91 puts("\n"); 92 return buffer; 93 94 case 0x03: /* ^C - break */ 95 return NULL; 96 97 case 0x5F: 98 case 0x08: /* ^H - backspace */ 99 case 0x7F: /* DEL - backspace */ 100 if (i) { 101 puts("\b \b"); 102 i--; 103 } 104 break; 105 106 default: 107 /* Ignore control characters */ 108 if (c < 0x20) 109 break; 110 /* Queue up all other characters */ 111 buffer[i++] = c; 112 printf("%c", c); 113 break; 114 } 115 } 116 } 117 118 int atmel_df_pow2(int argc, char * const argv[]) 119 { 120 /* Print the ABI version */ 121 app_startup(argv); 122 if (XF_VERSION != get_version()) { 123 printf("Expects ABI version %d\n", XF_VERSION); 124 printf("Actual U-Boot ABI version %lu\n", get_version()); 125 printf("Can't run\n\n"); 126 return 1; 127 } 128 129 while (1) { 130 struct spi_slave *slave; 131 char *line, *p; 132 int bus, cs, status; 133 134 puts("\nenter the [BUS:]CS of the SPI flash: "); 135 line = getline(); 136 137 /* CTRL+C */ 138 if (!line) 139 return 0; 140 if (line[0] == '\0') 141 continue; 142 143 bus = cs = simple_strtoul(line, &p, 10); 144 if (*p) { 145 if (*p == ':') { 146 ++p; 147 cs = simple_strtoul(p, &p, 10); 148 } 149 if (*p) { 150 puts("invalid format, please try again\n"); 151 continue; 152 } 153 } else 154 bus = 0; 155 156 printf("\ngoing to work with dataflash at %i:%i\n", bus, cs); 157 158 /* use a low speed -- it'll work with all devices, and 159 * speed here doesn't really matter. 160 */ 161 slave = spi_setup_slave(bus, cs, 1000, SPI_MODE_3); 162 if (!slave) { 163 puts("unable to setup slave\n"); 164 continue; 165 } 166 167 if (spi_claim_bus(slave)) { 168 spi_free_slave(slave); 169 continue; 170 } 171 172 if (flash_check(slave)) { 173 puts("no flash found\n"); 174 goto done; 175 } 176 177 status = flash_status(slave); 178 if (status == -1) { 179 puts("unable to read status register\n"); 180 goto done; 181 } 182 if (status & 0x1) { 183 puts("flash is already in power-of-2 mode!\n"); 184 goto done; 185 } 186 187 puts("are you sure you wish to set power-of-2 mode?\n"); 188 puts("this operation is permanent and irreversible\n"); 189 printf("enter YES to continue: "); 190 line = getline(); 191 if (!line || strcmp(line, "YES")) 192 goto done; 193 194 if (flash_set_pow2(slave)) { 195 puts("setting pow2 mode failed\n"); 196 goto done; 197 } 198 199 puts( 200 "Configuration should be updated now. You will have to\n" 201 "power cycle the part in order to finish the conversion.\n" 202 ); 203 204 done: 205 spi_release_bus(slave); 206 spi_free_slave(slave); 207 } 208 } 209