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 spi_init(); 130 131 while (1) { 132 struct spi_slave *slave; 133 char *line, *p; 134 int bus, cs, status; 135 136 puts("\nenter the [BUS:]CS of the SPI flash: "); 137 line = getline(); 138 139 /* CTRL+C */ 140 if (!line) 141 return 0; 142 if (line[0] == '\0') 143 continue; 144 145 bus = cs = simple_strtoul(line, &p, 10); 146 if (*p) { 147 if (*p == ':') { 148 ++p; 149 cs = simple_strtoul(p, &p, 10); 150 } 151 if (*p) { 152 puts("invalid format, please try again\n"); 153 continue; 154 } 155 } else 156 bus = 0; 157 158 printf("\ngoing to work with dataflash at %i:%i\n", bus, cs); 159 160 /* use a low speed -- it'll work with all devices, and 161 * speed here doesn't really matter. 162 */ 163 slave = spi_setup_slave(bus, cs, 1000, SPI_MODE_3); 164 if (!slave) { 165 puts("unable to setup slave\n"); 166 continue; 167 } 168 169 if (spi_claim_bus(slave)) { 170 spi_free_slave(slave); 171 continue; 172 } 173 174 if (flash_check(slave)) { 175 puts("no flash found\n"); 176 goto done; 177 } 178 179 status = flash_status(slave); 180 if (status == -1) { 181 puts("unable to read status register\n"); 182 goto done; 183 } 184 if (status & 0x1) { 185 puts("flash is already in power-of-2 mode!\n"); 186 goto done; 187 } 188 189 puts("are you sure you wish to set power-of-2 mode?\n"); 190 puts("this operation is permanent and irreversible\n"); 191 printf("enter YES to continue: "); 192 line = getline(); 193 if (!line || strcmp(line, "YES")) 194 goto done; 195 196 if (flash_set_pow2(slave)) { 197 puts("setting pow2 mode failed\n"); 198 goto done; 199 } 200 201 puts( 202 "Configuration should be updated now. You will have to\n" 203 "power cycle the part in order to finish the conversion.\n" 204 ); 205 206 done: 207 spi_release_bus(slave); 208 spi_free_slave(slave); 209 } 210 } 211