blob: 2215a74d8acaa4839638565f2ab9d6dff1eeaeea [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
73 ret = spi_claim_bus(flash->spi);
74 if (ret) {
75 printk(BIOS_WARNING, "SF: Unable to claim SPI bus\n");
76 return ret;
77 }
78
79 ret = 0;
80 for (actual = 0; actual < len; actual += chunk_len) {
81 chunk_len = min(len - actual, page_size - byte_addr);
82
83 cmd[0] = CMD_EN25Q128_PP;
84 cmd[1] = page_addr >> 8;
85 cmd[2] = page_addr;
86 cmd[3] = byte_addr;
87
Stefan Reinauer5649b082012-05-23 11:03:29 -070088#if CONFIG_DEBUG_SPI_FLASH
Stefan Reinauer1c56d9b2012-05-10 11:27:32 -070089 printk(BIOS_SPEW,
Stefan Reinauer8ea5a342012-05-14 13:52:32 -070090 "PP: 0x%p => cmd = { 0x%02x 0x%02x%02x%02x } chunk_len = %zu\n",
Stefan Reinauer1c56d9b2012-05-10 11:27:32 -070091 buf + actual, cmd[0], cmd[1], cmd[2], cmd[3], chunk_len);
Stefan Reinauer5649b082012-05-23 11:03:29 -070092#endif
Stefan Reinauer1c56d9b2012-05-10 11:27:32 -070093
94 ret = spi_flash_cmd(flash->spi, CMD_EN25Q128_WREN, NULL, 0);
95 if (ret < 0) {
96 printk(BIOS_WARNING, "SF: Enabling Write failed\n");
97 break;
98 }
99
100 ret = spi_flash_cmd_write(flash->spi, cmd, 4,
101 buf + actual, chunk_len);
102 if (ret < 0) {
103 printk(BIOS_WARNING, "SF: EON Page Program failed\n");
104 break;
105 }
106
107 ret = spi_flash_cmd_wait_ready(flash, SPI_FLASH_PROG_TIMEOUT);
108 if (ret)
109 break;
110
111 page_addr++;
112 byte_addr = 0;
113 }
114
Marc Jones747127d2012-12-03 22:16:29 -0700115#if CONFIG_DEBUG_SPI_FLASH
116 printk(BIOS_SPEW, "SF: EON: Successfully programmed %zu bytes @ 0x%x\n",
Stefan Reinauer1c56d9b2012-05-10 11:27:32 -0700117 len, offset);
Marc Jones747127d2012-12-03 22:16:29 -0700118#endif
Stefan Reinauer1c56d9b2012-05-10 11:27:32 -0700119
120 spi_release_bus(flash->spi);
121 return ret;
122}
123
124static int eon_erase(struct spi_flash *flash, u32 offset, size_t len)
125{
126 return spi_flash_cmd_erase(flash, CMD_EN25Q128_BE, offset, len);
127}
128
129struct spi_flash *spi_flash_probe_eon(struct spi_slave *spi, u8 *idcode)
130{
131 const struct eon_spi_flash_params *params;
132 struct eon_spi_flash *eon;
133 unsigned int i;
134
135 for (i = 0; i < ARRAY_SIZE(eon_spi_flash_table); ++i) {
136 params = &eon_spi_flash_table[i];
137 if (params->idcode1 == idcode[2])
138 break;
139 }
140
141 if (i == ARRAY_SIZE(eon_spi_flash_table)) {
142 printk(BIOS_WARNING, "SF: Unsupported EON ID %02x\n", idcode[1]);
143 return NULL;
144 }
145
146 eon = malloc(sizeof(*eon));
147 if (!eon) {
148 printk(BIOS_WARNING, "SF: Failed to allocate memory\n");
149 return NULL;
150 }
151
152 eon->params = params;
153 eon->flash.spi = spi;
154 eon->flash.name = params->name;
155
156 eon->flash.write = eon_write;
157 eon->flash.erase = eon_erase;
158 eon->flash.read = spi_flash_cmd_read_fast;
159 eon->flash.sector_size = params->page_size * params->pages_per_sector
160 * params->sectors_per_block;
161 eon->flash.size = params->page_size * params->pages_per_sector
162 * params->nr_sectors;
163
164 return &eon->flash;
165}