1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
|
// SPDX-License-Identifier: GPL-2.0-or-later
/*
* Support for Digigram AlpX PCI-e boards
*
* Copyright (c) 2024 Digigram Digital (info@digigram.com)
*/
#include "alpx_mtd.h"
#include "alpx.h"
#include "alpx_reg.h"
static const u32 ALPX_FLASH_ERASED_AREA_VALUE = 0xFFFFFFFF;
int alpx_mtd_read(struct mtd_info *mtd, loff_t from, size_t len,
size_t *retlen, u_char *buf)
{
struct alpx_device *alpx_dev = mtd->priv;
size_t size;
u32 page_index;
u32 offset;
u32 cmd;
int ret;
page_index = from >> ALPX_FLASH_SECTOR_SHIFT;
offset = from & (ALPX_FLASH_SECTOR_SIZE-1);
while (len) {
if ((offset + len) > ALPX_FLASH_SECTOR_SIZE)
size = ALPX_FLASH_SECTOR_SIZE - offset;
else
size = len;
cmd = ALP_PROC_COMMAND_MAKE_P16(
ALP_PROC_CMD_READ_FLASH_SECTOR, page_index);
dev_dbg(alpx_dev->dev,"Reading %zu bytes Flash sector 0x%x.\n", size, page_index);
mutex_lock(&alpx_dev->proc_mutex);
ret = alpx_proc_cmd(alpx_dev, cmd);
if (ret) {
mutex_unlock(&alpx_dev->proc_mutex);
dev_err(alpx_dev->dev,
"cmd(CMD_READ_FLASH_SECTOR, 0x%x) failed (%d)\n",
page_index, ret);
return ret;
}
memcpy_fromio(buf, ALPX_AREA(alpx_dev, ALP, SHARED) + offset,
size);
mutex_unlock(&alpx_dev->proc_mutex);
if (retlen)
*retlen += size;
buf += size;
len -= size;
offset = 0;
page_index++;
}
return 0;
}
int alpx_mtd_write(struct mtd_info *mtd, loff_t to, size_t len,
size_t *retlen, const u_char *buf)
{
struct alpx_device *alpx_dev = mtd->priv;
size_t size;
u32 page_index;
u32 offset;
u32 cmd;
int ret;
page_index = to >> ALPX_FLASH_SECTOR_SHIFT;
offset = to & (ALPX_FLASH_SECTOR_SIZE-1);
while (len) {
if ((offset + len) > ALPX_FLASH_SECTOR_SIZE)
size = ALPX_FLASH_SECTOR_SIZE - offset;
else
size = len;
dev_dbg(alpx_dev->dev,"Writing %zu bytes to sector 0x%x.\n", size, page_index);
mutex_lock(&alpx_dev->proc_mutex);
if (size != ALPX_FLASH_SECTOR_SIZE) {
/* Partial page write -> read modify write*/
cmd = ALP_PROC_COMMAND_MAKE_P16(
ALP_PROC_CMD_READ_FLASH_SECTOR, page_index);
ret = alpx_proc_cmd(alpx_dev, cmd);
if (ret) {
mutex_unlock(&alpx_dev->proc_mutex);
dev_err(alpx_dev->dev,
"cmd(CMD_READ_FLASH_SECTOR, 0x%x) failed (%d)\n",
page_index, ret);
return ret;
}
}
memcpy_toio(ALPX_AREA(alpx_dev, ALP, SHARED) + offset, buf,
size);
cmd = ALP_PROC_COMMAND_MAKE_P16(
ALP_PROC_CMD_WRITE_FLASH_SECTOR, page_index);
ret = alpx_proc_cmd(alpx_dev, cmd);
if (ret) {
mutex_unlock(&alpx_dev->proc_mutex);
dev_err(alpx_dev->dev,
"cmd(CMD_WRITE_FLASH_SECTOR, 0x%x) failed (%d)\n",
page_index, ret);
return ret;
}
mutex_unlock(&alpx_dev->proc_mutex);
if (retlen)
*retlen += size;
buf += size;
len -= size;
offset = 0;
page_index++;
}
return 0;
}
int alpx_mtd_probe(struct alpx_device *alpx_dev, const struct mtd_partition* partitions, u32 partitions_size)
{
struct mtd_info *mtd = &alpx_dev->mtd_info;
/* Setup the MTD structure */
mtd->type = MTD_RAM;
mtd->flags = MTD_WRITEABLE | MTD_NO_ERASE;
mtd->size = ALPX_FLASH_CHIP_SIZE;
mtd->writesize = ALPX_FLASH_SECTOR_SIZE;
mtd->writebufsize = mtd->writesize;
mtd->priv = alpx_dev;
mtd->owner = THIS_MODULE;
mtd->dev.parent = alpx_dev->dev;
mtd->_read = alpx_mtd_read;
mtd->_write = alpx_mtd_write;
return mtd_device_register(mtd, partitions,
partitions_size);
}
int alpx_mtd_remove(struct alpx_device *alpx_dev)
{
return alpx_dev->variant->flash_partitions.qty ? mtd_device_unregister(&alpx_dev->mtd_info) : 0;
}
/* Read one Flash's page into the shared area NO LOCK DONE !!*/
static int alpx_mtd_load_one_page_into_shared_area(struct alpx_device* alpx_dev, u32 from)
{
u32 page_index = from >> ALPX_FLASH_SECTOR_SHIFT;
u32 cmd = ALP_PROC_COMMAND_MAKE_P16(
ALP_PROC_CMD_READ_FLASH_SECTOR, page_index);
size_t size = ALPX_FLASH_SECTOR_SIZE;
int ret;
/* Check requested length below FLASH sector's size, TODO check page_index too TODO check form is aligned on page */
if (from % ALPX_FLASH_SECTOR_SIZE != 0)
return -EINVAL;
dev_dbg(alpx_dev->dev,"Reading %zu bytes Flash sector 0x%x (0x%x).\n", size, page_index, from);
ret = alpx_proc_cmd(alpx_dev, cmd);
if (ret) {
dev_err(alpx_dev->dev,
"cmd(CMD_READ_FLASH_SECTOR, 0x%x) failed (%d)\n",
page_index, ret);
return ret;
}
print_hex_dump_bytes("LOADED Shared area :", DUMP_PREFIX_NONE, ALPX_AREA(alpx_dev, ALP, SHARED), 32);
return ret;
}
/* Store the shared area into the Flash at the to address. NO LOCK DONE */
static int alpx_mtd_store_one_page_into_shared_area(struct alpx_device* alpx_dev, u32 to)
{
u32 page_index = to >> ALPX_FLASH_SECTOR_SHIFT;
u32 cmd = ALP_PROC_COMMAND_MAKE_P16(
ALP_PROC_CMD_WRITE_FLASH_SECTOR, page_index);
size_t size = ALPX_FLASH_SECTOR_SIZE;
int ret;
print_hex_dump_bytes("STORED Shared area :", DUMP_PREFIX_NONE, ALPX_AREA(alpx_dev, ALP, SHARED), 32);
/* Check requested length below FLASH sector's size, TODO check page_index too TODO check form is aligned on page */
if (to % ALPX_FLASH_SECTOR_SIZE != 0)
return -EINVAL;
dev_dbg(alpx_dev->dev,"Storing %zu bytes to Flash sector 0x%x.\n", size, page_index);
ret = alpx_proc_cmd(alpx_dev, cmd);
if (ret) {
dev_err(alpx_dev->dev,
"cmd(ALP_PROC_CMD_WRITE_FLASH_SECTOR, 0x%x) failed (%d)\n",
page_index, ret);
return ret;
}
return ret;
}
int alpx_mtd_is_golden_prod_area_valid(struct alpx_device* alpx_dev)
{
int ret = 0;
mutex_lock(&alpx_dev->proc_mutex);
ret = alpx_mtd_load_one_page_into_shared_area(alpx_dev, alpx_dev->variant->flash_golden_production_base);
if (!ret) {
//Now check Production area validity per se : something set in and not in erased state
ret = (*(u32*)ALPX_AREA(alpx_dev, ALP, SHARED)) != ALPX_FLASH_ERASED_AREA_VALUE;
}
else {
dev_err(alpx_dev->dev, "Error %d when loading shared area from flash.\n", ret);
}
mutex_unlock(&alpx_dev->proc_mutex);
return ret;
}
int alpx_mtd_replicate_prod_area(struct alpx_device* alpx_dev)
{
/* Read the USER's Production area and then write it to the GOLDEN'sProduction area */
//Read User
int ret = 0;
mutex_lock(&alpx_dev->proc_mutex);
ret= alpx_mtd_load_one_page_into_shared_area(alpx_dev,
alpx_dev->variant->flash_partitions.partitions[ALPX_FLASH_PARTITION_PRODUCTION_ID].offset);
if (!ret) {
//Write it to the GOLDEN's area
ret = alpx_mtd_store_one_page_into_shared_area(alpx_dev, alpx_dev->variant->flash_golden_production_base);
if (ret) {
dev_err(alpx_dev->dev,"Error %d when storing the USER's Production area into GOLDEN.\n", ret);
}
}
else {
dev_err(alpx_dev->dev,"Error %d when reading the USER's Production area.\n", ret);
}
mutex_unlock(&alpx_dev->proc_mutex);
return ret;
}
int alpx_mtd_read_from(struct alpx_device* alpx_dev,
uint32_t from,
unsigned char* to,
unsigned int length)
{
int ret = 0;
//Check : never read more than SHARE area length
if (length > ALP_SHARED_SIZE)
return -EINVAL;
mutex_lock(&alpx_dev->proc_mutex);
//Load the PRODUCTION into the shared AREA, then extract the Serial Number
ret= alpx_mtd_load_one_page_into_shared_area(alpx_dev, from);
if (!ret) {
unsigned int idx = 0;
//NO memcpy() when dealing with SHARED Area
for (idx = 0 ; idx < length; ++idx) {
to[idx] = *(((unsigned char*)ALPX_AREA(alpx_dev, ALP, SHARED))+idx);
}
print_hex_dump_bytes("READ:", DUMP_PREFIX_NONE, to, length);
} else {
dev_err(alpx_dev->dev, " Error 0x%x when reading Flash memory at %d.\n", ret, from);
}
mutex_unlock(&alpx_dev->proc_mutex);
return ret;
}
int alpx_mtd_load_shared_from(struct alpx_device* alpx_dev, uint32_t from)
{
//Only one page at the moment, must be ALP_SHARED_SIZE bytes after.
return alpx_mtd_load_one_page_into_shared_area(alpx_dev, from);
}
int alpx_mtd_read_shared(struct alpx_device* alpx_dev,
uint32_t at,
unsigned char* to,
unsigned int length)
{
unsigned int idx;
//NO memcpy() when dealing with SHARED Area
for (idx = 0 ; idx < length; ++idx) {
to[idx] = *(((unsigned char*)ALPX_AREA(alpx_dev, ALP, SHARED))+idx + at);
}
print_hex_dump_bytes("READ:", DUMP_PREFIX_NONE, to, length);
return 0;
}
int alpx_mtd_clean_shared(struct alpx_device* alpx_dev)
{
unsigned int idx;
//NO memcpy() when dealing with SHARED Area
for (idx = 0 ; idx < (ALPX_FLASH_SECTOR_SIZE / sizeof(unsigned int)); ++idx) {
*(unsigned int*)(ALPX_AREA(alpx_dev, ALP, SHARED)+idx) = 0;
}
return 0;
}
int alpx_mtd_is_available(struct alpx_device* alpx_dev)
{
//DANTE : no MTD available yet
return alpx_dev->variant->model != ALPX_VARIANT_MODEL_ALPDANTE;
}
|