blob: 21103ae22109ed5b6f9696d198ea07854e27462d [file] [log] [blame]
Stefan Reinauer1c56d9b2012-05-10 11:27:32 -07001/*
2 * (C) Copyright 2010, ucRobotics Inc.
3 * Author: Chong Huang <chuang@ucrobotics.com>
4 * Licensed under the GPL-2 or later.
5 */
6
7#include <stdlib.h>
8#include <spi_flash.h>
9#include "spi_flash_internal.h"
10
11/* EN25Q128-specific commands */
12#define CMD_EN25Q128_WREN 0x06 /* Write Enable */
13#define CMD_EN25Q128_WRDI 0x04 /* Write Disable */
14#define CMD_EN25Q128_RDSR 0x05 /* Read Status Register */
15#define CMD_EN25Q128_WRSR 0x01 /* Write Status Register */
16#define CMD_EN25Q128_READ 0x03 /* Read Data Bytes */
17#define CMD_EN25Q128_FAST_READ 0x0b /* Read Data Bytes at Higher Speed */
18#define CMD_EN25Q128_PP 0x02 /* Page Program */
19#define CMD_EN25Q128_SE 0x20 /* Sector Erase */
20#define CMD_EN25Q128_BE 0xd8 /* Block Erase */
21#define CMD_EN25Q128_DP 0xb9 /* Deep Power-down */
22#define CMD_EN25Q128_RES 0xab /* Release from DP, and Read Signature */
23
24#define EON_ID_EN25Q128 0x18
25
26struct eon_spi_flash_params {
27 u8 idcode1;
28 u16 page_size;
29 u16 pages_per_sector;
30 u16 sectors_per_block;
31 u16 nr_sectors;
32 const char *name;
33};
34
35/* spi_flash needs to be first so upper layers can free() it */
36struct eon_spi_flash {
37 struct spi_flash flash;
38 const struct eon_spi_flash_params *params;
39};
40
41static inline struct eon_spi_flash *to_eon_spi_flash(struct spi_flash *flash)
42{
43 return container_of(flash, struct eon_spi_flash, flash);
44}
45
46static const struct eon_spi_flash_params eon_spi_flash_table[] = {
47 {
48 .idcode1 = EON_ID_EN25Q128,
49 .page_size = 256,
50 .pages_per_sector = 16,
51 .sectors_per_block = 16,
52 .nr_sectors = 4096,
53 .name = "EN25Q128",
54 },
55};
56
57static int eon_write(struct spi_flash *flash,
58 u32 offset, size_t len, const void *buf)
59{
60 struct eon_spi_flash *eon = to_eon_spi_flash(flash);
61 unsigned long page_addr;
62 unsigned long byte_addr;
63 unsigned long page_size;
64 size_t chunk_len;
65 size_t actual;
66 int ret;
67 u8 cmd[4];
68
69 page_size = eon->params->page_size;
70 page_addr = offset / page_size;
71 byte_addr = offset % page_size;
72
Martin Roth3316cf22012-12-05 16:22:54 -070073 flash->spi->rw = SPI_WRITE_FLAG;
Stefan Reinauer1c56d9b2012-05-10 11:27:32 -070074 ret = spi_claim_bus(flash->spi);
75 if (ret) {
76 printk(BIOS_WARNING, "SF: Unable to claim SPI bus\n");
77 return ret;
78 }
79
80 ret = 0;
81 for (actual = 0; actual < len; actual += chunk_len) {
82 chunk_len = min(len - actual, page_size - byte_addr);
83
84 cmd[0] = CMD_EN25Q128_PP;
85 cmd[1] = page_addr >> 8;
86 cmd[2] = page_addr;
87 cmd[3] = byte_addr;
88
Stefan Reinauer5649b082012-05-23 11:03:29 -070089#if CONFIG_DEBUG_SPI_FLASH
Stefan Reinauer1c56d9b2012-05-10 11:27:32 -070090 printk(BIOS_SPEW,
Stefan Reinauer8ea5a342012-05-14 13:52:32 -070091 "PP: 0x%p => cmd = { 0x%02x 0x%02x%02x%02x } chunk_len = %zu\n",
Stefan Reinauer1c56d9b2012-05-10 11:27:32 -070092 buf + actual, cmd[0], cmd[1], cmd[2], cmd[3], chunk_len);
Stefan Reinauer5649b082012-05-23 11:03:29 -070093#endif
Stefan Reinauer1c56d9b2012-05-10 11:27:32 -070094
95 ret = spi_flash_cmd(flash->spi, CMD_EN25Q128_WREN, NULL, 0);
96 if (ret < 0) {
97 printk(BIOS_WARNING, "SF: Enabling Write failed\n");
98 break;
99 }
100
101 ret = spi_flash_cmd_write(flash->spi, cmd, 4,
102 buf + actual, chunk_len);
103 if (ret < 0) {
104 printk(BIOS_WARNING, "SF: EON Page Program failed\n");
105 break;
106 }
107
108 ret = spi_flash_cmd_wait_ready(flash, SPI_FLASH_PROG_TIMEOUT);
109 if (ret)
110 break;
111
112 page_addr++;
113 byte_addr = 0;
114 }
115
Marc Jones747127d2012-12-03 22:16:29 -0700116#if CONFIG_DEBUG_SPI_FLASH
117 printk(BIOS_SPEW, "SF: EON: Successfully programmed %zu bytes @ 0x%x\n",
Stefan Reinauer1c56d9b2012-05-10 11:27:32 -0700118 len, offset);
Marc Jones747127d2012-12-03 22:16:29 -0700119#endif
Stefan Reinauer1c56d9b2012-05-10 11:27:32 -0700120
121 spi_release_bus(flash->spi);
122 return ret;
123}
124
125static int eon_erase(struct spi_flash *flash, u32 offset, size_t len)
126{
127 return spi_flash_cmd_erase(flash, CMD_EN25Q128_BE, offset, len);
128}
129
130struct spi_flash *spi_flash_probe_eon(struct spi_slave *spi, u8 *idcode)
131{
132 const struct eon_spi_flash_params *params;
133 struct eon_spi_flash *eon;
134 unsigned int i;
135
136 for (i = 0; i < ARRAY_SIZE(eon_spi_flash_table); ++i) {
137 params = &eon_spi_flash_table[i];
138 if (params->idcode1 == idcode[2])
139 break;
140 }
141
142 if (i == ARRAY_SIZE(eon_spi_flash_table)) {
143 printk(BIOS_WARNING, "SF: Unsupported EON ID %02x\n", idcode[1]);
144 return NULL;
145 }
146
147 eon = malloc(sizeof(*eon));
148 if (!eon) {
149 printk(BIOS_WARNING, "SF: Failed to allocate memory\n");
150 return NULL;
151 }
152
153 eon->params = params;
154 eon->flash.spi = spi;
155 eon->flash.name = params->name;
156
157 eon->flash.write = eon_write;
158 eon->flash.erase = eon_erase;
159 eon->flash.read = spi_flash_cmd_read_fast;
160 eon->flash.sector_size = params->page_size * params->pages_per_sector
161 * params->sectors_per_block;
162 eon->flash.size = params->page_size * params->pages_per_sector
163 * params->nr_sectors;
164
165 return &eon->flash;
166}