Skip to content

Commit 00a7cfe

Browse files
committed
a4092: mfgtool: link against spi.c instead of duplicating SPI code
mfgtool.c copy-pasted ~250 lines of low-level SPI code that already existed in spi.c: nibble word packing, MMIO helpers, SPI byte-level tx/rx, status register access, write enable, block protection, erase, page program, and streaming read/write/erase functions. Remove the duplicated code and link mfgtool against spi.c directly. To support this: - spi.h: expose spi_read_sr1(), spi_read_sr2(), spi_read_unique_id(), and move SR1/SR2 bit defines from spi.c to the header - spi.c: make spi_read_sr1() and spi_read_sr2() non-static; add spi_read_unique_id(); add progress callback to spi_erase_range_blocks() (existing callers pass NULL) - mfgtool.c: include spi.h, drop all duplicated SPI code, update spi_write_buf_pagewise() calls for the progress parameter, add 'uid' command using the now-shared spi_read_unique_id() - Makefile: add spi.c to the mfgtool link line The mfgtool-specific settle-poll logic in spi_wait_wip_clear() (which waited for WIP to first appear SET before polling for clear) is dropped in favor of spi.c's simpler poll-for-clear. The settle-poll was a manufacturing debug aid and is not essential.
1 parent 27f3ad3 commit 00a7cfe

File tree

4 files changed

+56
-280
lines changed

4 files changed

+56
-280
lines changed

util/a4092flash/Makefile

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -50,9 +50,9 @@ a4092flash: $(SRCS) *.h
5050
$(QUIET)$(CC) $(CFLAGS) -o $@ $(SRCS) $(LDLIBS)
5151
$(QUIET)$(STRIP) -s $@
5252

53-
mfgtool: mfgtool.c mfg_flash.h
53+
mfgtool: mfgtool.c mfg_flash.h spi.c spi.h nibble_word.h
5454
@echo Building $@
55-
$(QUIET)$(CC) $(CFLAGS) -o $@ mfgtool.c $(LDLIBS)
55+
$(QUIET)$(CC) $(CFLAGS) -o $@ mfgtool.c spi.c $(LDLIBS)
5656

5757
test:
5858
@echo Building NVRAM tests

util/a4092flash/mfgtool.c

Lines changed: 18 additions & 264 deletions
Original file line numberDiff line numberDiff line change
@@ -37,16 +37,7 @@
3737
#include <proto/alib.h>
3838
#include <dos/dosextens.h>
3939
#include "../../ndkcompat.h"
40-
41-
/* Use mirrored addresses for writes to work around 68030 write-allocation bug.
42-
* The MMU must be configured to make the write-mirror non-cacheable.
43-
* For now however, we disable write-allocation instead of using different
44-
* addresses.
45-
*/
46-
#define SPI_PORT_READ_HOLD_OFFS 0x7FFFE0
47-
#define SPI_PORT_READ_END_OFFS 0x7FFFF0
48-
#define SPI_PORT_WRITE_HOLD_OFFS 0x7FFFC0
49-
#define SPI_PORT_WRITE_END_OFFS 0x7FFFD0
40+
#include "spi.h"
5041

5142
/* A4092 board identification (matches main.c) */
5243
#define MANUF_ID_COMMODORE_BRAUNSCHWEIG 513
@@ -64,256 +55,6 @@ struct ConfigDev* FindConfigDev(struct ConfigDev*, LONG, LONG);
6455

6556
#define MAX_TRANSFER_SIZE (8 * 1024 * 1024)
6657

67-
static inline uint32_t pack_nibble_word(uint8_t b)
68-
{
69-
uint32_t hi = ((uint32_t)((b >> 4) & 0x0F)) << 28; /* bits 28..31 */
70-
uint32_t lo = ((uint32_t)( b & 0x0F)) << 12; /* bits 12..15 */
71-
return hi | lo;
72-
}
73-
static inline uint8_t unpack_nibble_word(uint32_t w)
74-
{
75-
uint8_t hi = (uint8_t)((w >> 28) & 0x0F);
76-
uint8_t lo = (uint8_t)((w >> 12) & 0x0F);
77-
return (uint8_t)((hi << 4) | lo);
78-
}
79-
static inline void mmio_write_hold(uint32_t base, uint8_t v)
80-
{
81-
volatile uint32_t *p = (volatile uint32_t *)(uintptr_t)(base + SPI_PORT_WRITE_HOLD_OFFS);
82-
*p = pack_nibble_word(v);
83-
}
84-
static inline void mmio_write_end(uint32_t base, uint8_t v)
85-
{
86-
volatile uint32_t *p = (volatile uint32_t *)(uintptr_t)(base + SPI_PORT_WRITE_END_OFFS);
87-
*p = pack_nibble_word(v);
88-
}
89-
static inline uint8_t mmio_read_hold(uint32_t base)
90-
{
91-
volatile uint32_t *p = (volatile uint32_t *)(uintptr_t)(base + SPI_PORT_READ_HOLD_OFFS);
92-
uint32_t w = *p;
93-
return unpack_nibble_word(w);
94-
}
95-
static inline uint8_t mmio_read_end(uint32_t base)
96-
{
97-
volatile uint32_t *p = (volatile uint32_t *)(uintptr_t)(base + SPI_PORT_READ_END_OFFS);
98-
uint32_t w = *p;
99-
return unpack_nibble_word(w);
100-
}
101-
102-
/* ===== SPI commands / constants ===== */
103-
enum {
104-
SPI_CMD_WREN = 0x06,
105-
SPI_CMD_RDSR1 = 0x05,
106-
SPI_CMD_WRSR = 0x01,
107-
SPI_CMD_RDSR2 = 0x35,
108-
SPI_CMD_RDID = 0x9F,
109-
SPI_CMD_READ = 0x03,
110-
SPI_CMD_PP = 0x02,
111-
SPI_CMD_SE_4K = 0x20,
112-
SPI_CMD_BE64K = 0xD8,
113-
};
114-
115-
#define SR1_WIP 0x01
116-
#define SR1_WEL 0x02
117-
#define SR1_BP_MASK 0x1C
118-
119-
#define SR2_QE 0x02
120-
121-
#define SPI_PAGE_SIZE 256u
122-
#define SPI_BLOCK_SIZE 65536u
123-
124-
/* ===== low-level bytewise helpers ===== */
125-
static inline void spi_tx_hold(uint32_t base, uint8_t v) { mmio_write_hold(base, v); }
126-
static inline void spi_tx_end (uint32_t base, uint8_t v) {
127-
mmio_write_end (base, v);
128-
//for (volatile int i = 0; i < 200; i++);
129-
}
130-
static inline uint8_t spi_rx_hold(uint32_t base) {
131-
return mmio_read_hold(base);
132-
}
133-
static inline uint8_t spi_rx_end (uint32_t base) {
134-
return mmio_read_end (base);
135-
}
136-
137-
/* ===== status / waits ===== */
138-
static void spi_write_enable(uint32_t base)
139-
{
140-
spi_tx_end(base, SPI_CMD_WREN);
141-
}
142-
static uint8_t spi_read_sr1(uint32_t base)
143-
{
144-
spi_tx_hold(base, SPI_CMD_RDSR1);
145-
return spi_rx_end(base);
146-
}
147-
static uint8_t spi_read_sr2(uint32_t base)
148-
{
149-
spi_tx_hold(base, SPI_CMD_RDSR2);
150-
return spi_rx_end(base);
151-
}
152-
static bool spi_wait_wip_clear(uint32_t base, uint32_t max_iters)
153-
{
154-
const uint32_t settle_polls = 4096;
155-
bool saw_wip = false;
156-
157-
/* Allow the SPI engine to finish clocking the opcode before polling aggressively. */
158-
for (uint32_t i = 0; i < settle_polls; ++i) {
159-
uint8_t sr = spi_read_sr1(base);
160-
if (sr & SR1_WIP) {
161-
saw_wip = true;
162-
break;
163-
}
164-
}
165-
166-
if (!saw_wip) {
167-
fprintf(stderr, "SPI: command never asserted WIP (SR1=%02X)\n", spi_read_sr1(base));
168-
return false;
169-
}
170-
171-
for (uint32_t i = 0; i < max_iters; ++i) {
172-
if ((spi_read_sr1(base) & SR1_WIP) == 0) {
173-
return true;
174-
}
175-
}
176-
177-
fprintf(stderr, "SPI: timeout waiting for WIP clear (SR1=%02X)\n", spi_read_sr1(base));
178-
return false;
179-
}
180-
static bool spi_wait_wel_set(uint32_t base, uint32_t max_iters)
181-
{
182-
while (max_iters--) {
183-
if (spi_read_sr1(base) & SR1_WEL) {
184-
return true;
185-
}
186-
}
187-
return false;
188-
}
189-
190-
static bool spi_write_status(uint32_t base, uint8_t sr1, uint8_t sr2)
191-
{
192-
spi_write_enable(base);
193-
if (!spi_wait_wel_set(base, 1000)) {
194-
fprintf(stderr, "ERROR: WEL not set before status write\n");
195-
return false;
196-
}
197-
spi_tx_hold(base, SPI_CMD_WRSR);
198-
spi_tx_hold(base, sr1);
199-
spi_tx_end(base, sr2);
200-
if (!spi_wait_wip_clear(base, 100000)) {
201-
fprintf(stderr, "ERROR: status register write timed out\n");
202-
return false;
203-
}
204-
return true;
205-
}
206-
207-
static bool spi_clear_block_protect(uint32_t base)
208-
{
209-
uint8_t sr1 = spi_read_sr1(base);
210-
uint8_t sr2 = spi_read_sr2(base);
211-
if ((sr1 & SR1_BP_MASK) == 0) {
212-
return true;
213-
}
214-
uint8_t new_sr1 = sr1 & (uint8_t)~SR1_BP_MASK;
215-
printf("SPI flash reports block protection (SR1=%02X SR2=%02X); clearing BP bits...\n", sr1, sr2);
216-
if (!spi_write_status(base, new_sr1, sr2)) {
217-
fprintf(stderr, "ERROR: failed to clear block protection bits\n");
218-
return false;
219-
}
220-
uint8_t verify1 = spi_read_sr1(base);
221-
uint8_t verify2 = spi_read_sr2(base);
222-
if (verify1 & SR1_BP_MASK) {
223-
fprintf(stderr, "ERROR: block protection bits still set (SR1=%02X SR2=%02X). Check WP# pin.\n", verify1, verify2);
224-
return false;
225-
}
226-
return true;
227-
}
228-
229-
/* ===== single ops ===== */
230-
static void spi_read_id(uint32_t base, uint8_t *mfg, uint8_t *type, uint8_t *cap)
231-
{
232-
spi_tx_hold(base, SPI_CMD_RDID);
233-
if (mfg) *mfg = spi_rx_hold(base);
234-
if (type) *type = spi_rx_hold(base);
235-
if (cap) *cap = spi_rx_end(base);
236-
}
237-
static bool spi_block_erase(uint32_t base, uint32_t baddr)
238-
{
239-
spi_write_enable(base);
240-
if (!spi_wait_wel_set(base, 1000)) {
241-
fprintf(stderr, "ERROR: WEL not set before erase at 0x%08lX\n", (unsigned long)baddr);
242-
return false;
243-
}
244-
spi_tx_hold(base, SPI_CMD_BE64K);
245-
spi_tx_hold(base, (baddr >> 16) & 0xFF);
246-
spi_tx_hold(base, (baddr >> 8) & 0xFF);
247-
spi_tx_end (base, baddr & 0xFF);
248-
return spi_wait_wip_clear(base, 2000000);
249-
}
250-
static bool spi_sector_erase_4k(uint32_t base, uint32_t baddr)
251-
{
252-
spi_write_enable(base);
253-
if (!spi_wait_wel_set(base, 1000)) {
254-
fprintf(stderr, "ERROR: WEL not set before 4K erase at 0x%08lX\n", (unsigned long)baddr);
255-
return false;
256-
}
257-
spi_tx_hold(base, SPI_CMD_SE_4K);
258-
spi_tx_hold(base, (baddr >> 16) & 0xFF);
259-
spi_tx_hold(base, (baddr >> 8) & 0xFF);
260-
spi_tx_end (base, baddr & 0xFF);
261-
return spi_wait_wip_clear(base, 2000000);
262-
}
263-
264-
static bool spi_page_program(uint32_t base, uint32_t addr, const uint8_t *data, size_t len)
265-
{
266-
if (!len || len > SPI_PAGE_SIZE) return false;
267-
spi_write_enable(base);
268-
if (!spi_wait_wel_set(base, 1000)) {
269-
fprintf(stderr, "ERROR: WEL not set before program at 0x%08lX\n", (unsigned long)addr);
270-
return false;
271-
}
272-
spi_tx_hold(base, SPI_CMD_PP);
273-
spi_tx_hold(base, (addr >> 16) & 0xFF);
274-
spi_tx_hold(base, (addr >> 8) & 0xFF);
275-
spi_tx_hold(base, addr & 0xFF);
276-
for (size_t i=0; i+1<len; ++i) spi_tx_hold(base, data[i]);
277-
spi_tx_end(base, data[len-1]);
278-
return spi_wait_wip_clear(base, 100000);
279-
}
280-
281-
/* ===== streaming helpers ===== */
282-
static bool spi_read_buf(uint32_t base, uint32_t addr, uint8_t *out, size_t len)
283-
{
284-
if (!len) return true;
285-
spi_tx_hold(base, SPI_CMD_READ);
286-
spi_tx_hold(base, (addr >> 16) & 0xFF);
287-
spi_tx_hold(base, (addr >> 8) & 0xFF);
288-
spi_tx_hold(base, addr & 0xFF);
289-
for (size_t i=0; i+1<len; ++i) out[i] = spi_rx_hold(base);
290-
out[len-1] = spi_rx_end(base);
291-
return true;
292-
}
293-
static bool spi_write_buf_pagewise(uint32_t base, uint32_t addr, const uint8_t *in, size_t len)
294-
{
295-
while (len) {
296-
uint32_t page_off = addr & (SPI_PAGE_SIZE-1);
297-
uint32_t page_room = SPI_PAGE_SIZE - page_off;
298-
size_t chunk = len < page_room ? len : page_room;
299-
if (!spi_page_program(base, addr, in, chunk)) return false;
300-
addr += chunk; in += chunk; len -= chunk;
301-
}
302-
return true;
303-
}
304-
static bool spi_erase_range_blocks(uint32_t base, uint32_t addr, size_t len,
305-
void (*progress)(size_t done, size_t total))
306-
{
307-
uint32_t start = (addr / SPI_BLOCK_SIZE) * SPI_BLOCK_SIZE;
308-
uint32_t end = ((addr + (uint32_t)len - 1) / SPI_BLOCK_SIZE) * SPI_BLOCK_SIZE;
309-
size_t total = (end - start) / SPI_BLOCK_SIZE + 1, k = 0;
310-
for (uint32_t b = start; b <= end; b += SPI_BLOCK_SIZE, ++k) {
311-
if (progress) progress(k, total);
312-
if (!spi_block_erase(base, b)) return false;
313-
}
314-
if (progress) progress(total, total);
315-
return true;
316-
}
31758
static bool spi_verify_buf(uint32_t base, uint32_t addr, const uint8_t *ref, size_t len,
31859
void (*progress)(size_t done, size_t total))
31960
{
@@ -806,6 +547,7 @@ static void usage(const char *argv0)
806547
printf(
807548
"Usage:\n"
808549
" %s id\n"
550+
" %s uid\n"
809551
" %s read <addr> <len> <outfile>\n"
810552
" %s erase <addr> <len> [--verify]\n"
811553
" %s write <addr> <infile> [--verify]\n"
@@ -823,7 +565,7 @@ static void usage(const char *argv0)
823565
" - 'writemfg' programs manufacturing data from a config file.\n"
824566
" - 'readmfg' reads manufacturing data from flash to a config file.\n"
825567
" - 'dumpmfg' displays manufacturing data on the console.\n"
826-
, argv0, argv0, argv0, argv0, argv0, argv0, argv0, argv0, argv0, argv0);
568+
, argv0, argv0, argv0, argv0, argv0, argv0, argv0, argv0, argv0, argv0, argv0);
827569
}
828570

829571
/* parse CSV of hex bytes for 'patch' */
@@ -891,6 +633,15 @@ static int cmd_id(uint32_t base)
891633
return 0;
892634
}
893635

636+
static int cmd_uid(uint32_t base)
637+
{
638+
uint8_t id[8];
639+
spi_read_unique_id(base, id);
640+
printf("Unique ID: %02X-%02X-%02X-%02X-%02X-%02X-%02X-%02X\n",
641+
id[0], id[1], id[2], id[3], id[4], id[5], id[6], id[7]);
642+
return 0;
643+
}
644+
894645
static int cmd_read(uint32_t base, uint32_t addr, size_t len, const char *outfile)
895646
{
896647
if (len > MAX_TRANSFER_SIZE) { fprintf(stderr,"len too large (max %d)\n", MAX_TRANSFER_SIZE); return 2; }
@@ -932,7 +683,7 @@ static int cmd_write(uint32_t base, const char *saddr, const char *infile, bool
932683
size_t done=0;
933684
while (done<len) {
934685
size_t chunk = (len-done) > 4096 ? 4096 : (len-done);
935-
if (!spi_write_buf_pagewise(base, addr+done, img+done, chunk)) {
686+
if (!spi_write_buf_pagewise(base, addr+done, img+done, chunk, NULL)) {
936687
fprintf(stderr,"program failed at +0x%zx\n", done);
937688
free(img); return 3;
938689
}
@@ -970,7 +721,7 @@ static int cmd_patch(uint32_t base, const char *saddr, const char *hexlist)
970721
if (!parse_hexbytes(hexlist, &bytes, &n) || n==0) { free(bytes); fprintf(stderr,"bad hex bytes\n"); return 2; }
971722
if (!spi_clear_block_protect(base)) { free(bytes); return 3; }
972723
printf("Patching %zu byte(s) at 0x%08lX (assumes erased)...\n", n, (unsigned long)addr);
973-
bool ok = spi_write_buf_pagewise(base, addr, bytes, n);
724+
bool ok = spi_write_buf_pagewise(base, addr, bytes, n, NULL);
974725
free(bytes);
975726
if (!ok) { fprintf(stderr,"patch failed\n"); return 3; }
976727
printf("Patch OK\n"); return 0;
@@ -1039,7 +790,7 @@ static int cmd_writemfg(uint32_t base, const char *config_file)
1039790
}
1040791

1041792
/* Write 256 bytes */
1042-
if (!spi_write_buf_pagewise(base, MFG_FLASH_OFFSET, (const uint8_t *)&mfg, sizeof(mfg))) {
793+
if (!spi_write_buf_pagewise(base, MFG_FLASH_OFFSET, (const uint8_t *)&mfg, sizeof(mfg), NULL)) {
1043794
fprintf(stderr, "ERROR: flash write failed\n");
1044795
return 3;
1045796
}
@@ -1154,6 +905,9 @@ int main(int argc, char **argv)
1154905
if (strcmp(cmd,"id")==0) {
1155906
return cmd_id(base);
1156907
}
908+
else if (strcmp(cmd,"uid")==0) {
909+
return cmd_uid(base);
910+
}
1157911
else if (strcmp(cmd,"read")==0) {
1158912
if (argi+2 >= argc) { usage(argv[0]); return 1; }
1159913
uint32_t addr; size_t len;

0 commit comments

Comments
 (0)