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