| /* | |
| * atmel_df_pow2.c - convert Atmel Dataflashes to Power of 2 mode | |
| * | |
| * Copyright 2009 Analog Devices Inc. | |
| * | |
| * Licensed under the 2-clause BSD. | |
| */ | |
| #include <common.h> | |
| #include <exports.h> | |
| #define CMD_ID 0x9f | |
| #define CMD_STAT 0xd7 | |
| #define CMD_CFG 0x3d | |
| static int flash_cmd(struct spi_slave *slave, uchar cmd, uchar *buf, int len) | |
| { | |
| buf[0] = cmd; | |
| return spi_xfer(slave, 8 * len, buf, buf, SPI_XFER_BEGIN | SPI_XFER_END); | |
| } | |
| static int flash_status(struct spi_slave *slave) | |
| { | |
| uchar buf[2]; | |
| if (flash_cmd(slave, CMD_STAT, buf, sizeof(buf))) | |
| return -1; | |
| return buf[1]; | |
| } | |
| static int flash_set_pow2(struct spi_slave *slave) | |
| { | |
| int ret; | |
| uchar buf[4]; | |
| buf[1] = 0x2a; | |
| buf[2] = 0x80; | |
| buf[3] = 0xa6; | |
| ret = flash_cmd(slave, CMD_CFG, buf, sizeof(buf)); | |
| if (ret) | |
| return ret; | |
| /* wait Tp, or 6 msec */ | |
| udelay(6000); | |
| ret = flash_status(slave); | |
| if (ret == -1) | |
| return 1; | |
| return ret & 0x1 ? 0 : 1; | |
| } | |
| static int flash_check(struct spi_slave *slave) | |
| { | |
| int ret; | |
| uchar buf[4]; | |
| ret = flash_cmd(slave, CMD_ID, buf, sizeof(buf)); | |
| if (ret) | |
| return ret; | |
| if (buf[1] != 0x1F) { | |
| printf("atmel flash not found (id[0] = %#x)\n", buf[1]); | |
| return 1; | |
| } | |
| if ((buf[2] >> 5) != 0x1) { | |
| printf("AT45 flash not found (id[0] = %#x)\n", buf[2]); | |
| return 2; | |
| } | |
| return 0; | |
| } | |
| static char *getline(void) | |
| { | |
| static char buffer[100]; | |
| char c; | |
| size_t i; | |
| i = 0; | |
| while (1) { | |
| buffer[i] = '\0'; | |
| c = getc(); | |
| switch (c) { | |
| case '\r': /* Enter/Return key */ | |
| case '\n': | |
| puts("\n"); | |
| return buffer; | |
| case 0x03: /* ^C - break */ | |
| return NULL; | |
| case 0x5F: | |
| case 0x08: /* ^H - backspace */ | |
| case 0x7F: /* DEL - backspace */ | |
| if (i) { | |
| puts("\b \b"); | |
| i--; | |
| } | |
| break; | |
| default: | |
| /* Ignore control characters */ | |
| if (c < 0x20) | |
| break; | |
| /* Queue up all other characters */ | |
| buffer[i++] = c; | |
| printf("%c", c); | |
| break; | |
| } | |
| } | |
| } | |
| int atmel_df_pow2(int argc, char * const argv[]) | |
| { | |
| /* Print the ABI version */ | |
| app_startup(argv); | |
| if (XF_VERSION != get_version()) { | |
| printf("Expects ABI version %d\n", XF_VERSION); | |
| printf("Actual U-Boot ABI version %lu\n", get_version()); | |
| printf("Can't run\n\n"); | |
| return 1; | |
| } | |
| spi_init(); | |
| while (1) { | |
| struct spi_slave *slave; | |
| char *line, *p; | |
| int bus, cs, status; | |
| puts("\nenter the [BUS:]CS of the SPI flash: "); | |
| line = getline(); | |
| /* CTRL+C */ | |
| if (!line) | |
| return 0; | |
| if (line[0] == '\0') | |
| continue; | |
| bus = cs = simple_strtoul(line, &p, 10); | |
| if (*p) { | |
| if (*p == ':') { | |
| ++p; | |
| cs = simple_strtoul(p, &p, 10); | |
| } | |
| if (*p) { | |
| puts("invalid format, please try again\n"); | |
| continue; | |
| } | |
| } else | |
| bus = 0; | |
| printf("\ngoing to work with dataflash at %i:%i\n", bus, cs); | |
| /* use a low speed -- it'll work with all devices, and | |
| * speed here doesn't really matter. | |
| */ | |
| slave = spi_setup_slave(bus, cs, 1000, SPI_MODE_3); | |
| if (!slave) { | |
| puts("unable to setup slave\n"); | |
| continue; | |
| } | |
| if (spi_claim_bus(slave)) { | |
| spi_free_slave(slave); | |
| continue; | |
| } | |
| if (flash_check(slave)) { | |
| puts("no flash found\n"); | |
| goto done; | |
| } | |
| status = flash_status(slave); | |
| if (status == -1) { | |
| puts("unable to read status register\n"); | |
| goto done; | |
| } | |
| if (status & 0x1) { | |
| puts("flash is already in power-of-2 mode!\n"); | |
| goto done; | |
| } | |
| puts("are you sure you wish to set power-of-2 mode?\n"); | |
| puts("this operation is permanent and irreversible\n"); | |
| printf("enter YES to continue: "); | |
| line = getline(); | |
| if (!line || strcmp(line, "YES")) | |
| goto done; | |
| if (flash_set_pow2(slave)) { | |
| puts("setting pow2 mode failed\n"); | |
| goto done; | |
| } | |
| puts( | |
| "Configuration should be updated now. You will have to\n" | |
| "power cycle the part in order to finish the conversion.\n" | |
| ); | |
| done: | |
| spi_release_bus(slave); | |
| spi_free_slave(slave); | |
| } | |
| } |