Setting up repository
[linux-libre-firmware.git] / b43-tools / assembler / initvals.c
1 /*
2  *   Copyright (C) 2007  Michael Buesch <m@bues.ch>
3  *
4  *   This program is free software; you can redistribute it and/or modify
5  *   it under the terms of the GNU General Public License version 2
6  *   as published by the Free Software Foundation.
7  *
8  *   This program is distributed in the hope that it will be useful,
9  *   but WITHOUT ANY WARRANTY; without even the implied warranty of
10  *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
11  *   GNU General Public License for more details.
12  */
13
14 #include "initvals.h"
15 #include "list.h"
16 #include "util.h"
17 #include "args.h"
18
19 #include <stdio.h>
20 #include <stdlib.h>
21 #include <string.h>
22
23
24 struct initval {
25         unsigned int offset;
26         unsigned int size;
27 #define SIZE_16BIT      2
28 #define SIZE_32BIT      4
29         unsigned int value;
30
31         struct list_head list;
32 };
33
34 /* The IV in the binary file */
35 struct initval_raw {
36         be16_t offset_size;
37         union {
38                 be16_t d16;
39                 be32_t d32;
40         } data __attribute__((__packed__));
41 } __attribute__((__packed__));
42
43 #define FW_IV_OFFSET_MASK       0x7FFF
44 #define FW_IV_32BIT             0x8000
45
46
47 struct ivals_context {
48         /* Pointer to the parsed section structure */
49         const struct initvals_sect *sect;
50         /* List of struct initval */
51         struct list_head ivals;
52         /* Number of initvals. */
53         unsigned int ivals_count;
54 };
55
56 #define _msg_helper(type, ctx, msg, x...)       do {            \
57         fprintf(stderr, "InitVals " type);                      \
58         fprintf(stderr, " (Section \"%s\")", ctx->sect->name);  \
59         fprintf(stderr, ":\n  " msg "\n" ,##x);                 \
60                                                 } while (0)
61
62 #define iv_error(ctx, msg, x...)        do {            \
63         _msg_helper("ERROR", ctx, msg ,##x);            \
64         exit(1);                                        \
65                                         } while (0)
66
67 #define iv_warn(ctx, msg, x...) \
68         _msg_helper("warning", ctx, msg ,##x)
69
70 #define iv_info(ctx, msg, x...) \
71         _msg_helper("info", ctx, msg ,##x)
72
73
74 static void assemble_write_mmio(struct ivals_context *ctx,
75                                 unsigned int offset,
76                                 unsigned int size,
77                                 unsigned int value)
78 {
79         struct initval *iv;
80
81         iv = xmalloc(sizeof(struct initval));
82         iv->offset = offset;
83         iv->size = size;
84         iv->value = value;
85         INIT_LIST_HEAD(&iv->list);
86         list_add_tail(&iv->list, &ctx->ivals);
87         ctx->ivals_count++;
88 }
89
90 static void assemble_write_phy(struct ivals_context *ctx,
91                                unsigned int offset,
92                                unsigned int value)
93 {
94         assemble_write_mmio(ctx, 0x3FC, SIZE_16BIT, offset);
95         assemble_write_mmio(ctx, 0x3FE, SIZE_16BIT, value);
96 }
97
98 static void assemble_write_radio(struct ivals_context *ctx,
99                                  unsigned int offset,
100                                  unsigned int value)
101 {
102         assemble_write_mmio(ctx, 0x3F6, SIZE_16BIT, offset);
103         assemble_write_mmio(ctx, 0x3FA, SIZE_16BIT, value);
104 }
105
106 static void shm_control_word(struct ivals_context *ctx,
107                              unsigned int routing,
108                              unsigned int offset)
109 {
110         unsigned int control;
111
112         control = (routing & 0xFFFF);
113         control <<= 16;
114         control |= (offset & 0xFFFF);
115         assemble_write_mmio(ctx, 0x160, SIZE_32BIT, control);
116 }
117
118 static void shm_write32(struct ivals_context *ctx,
119                         unsigned int routing,
120                         unsigned int offset,
121                         unsigned int value)
122 {
123         if ((routing & 0xFF) == 0x01) {
124                 /* Is SHM Shared-memory */
125 //TODO          assert((offset & 0x0001) == 0);
126                 if (offset & 0x0003) {
127                         /* Unaligned access */
128                         shm_control_word(ctx, routing, offset >> 2);
129                         assemble_write_mmio(ctx, 0x166, SIZE_16BIT,
130                                             (value >> 16) & 0xFFFF);
131                         shm_control_word(ctx, routing, (offset >> 2) + 1);
132                         assemble_write_mmio(ctx, 0x164, SIZE_16BIT,
133                                             (value & 0xFFFF));
134                         return;
135                 }
136                 offset >>= 2;
137         }
138         shm_control_word(ctx, routing, offset);
139         assemble_write_mmio(ctx, 0x164, SIZE_32BIT, value);
140 }
141
142 static void shm_write16(struct ivals_context *ctx,
143                         unsigned int routing,
144                         unsigned int offset,
145                         unsigned int value)
146 {
147         if ((routing & 0xFF) == 0x01) {
148                 /* Is SHM Shared-memory */
149 //TODO          assert((offset & 0x0001) == 0);
150                 if (offset & 0x0003) {
151                         /* Unaligned access */
152                         shm_control_word(ctx, routing, offset >> 2);
153                         assemble_write_mmio(ctx, 0x166, SIZE_16BIT,
154                                             value);
155                         return;
156                 }
157                 offset >>= 2;
158         }
159         shm_control_word(ctx, routing, offset);
160         assemble_write_mmio(ctx, 0x164, SIZE_16BIT, value);
161 }
162
163 static void assemble_write_shm(struct ivals_context *ctx,
164                                unsigned int routing,
165                                unsigned int offset,
166                                unsigned int value,
167                                unsigned int size)
168 {
169         switch (routing & 0xFF) {
170         case 0: case 1: case 2: case 3: case 4:
171                 break;
172         default:
173                 //TODO error
174                 break;
175         }
176         //TODO check offset
177
178         //TODO check value
179         switch (size) {
180         case SIZE_16BIT:
181                 shm_write16(ctx, routing, offset, value);
182                 break;
183         case SIZE_32BIT:
184                 shm_write32(ctx, routing, offset, value);
185                 break;
186         default:
187                 fprintf(stderr, "Internal assembler BUG. SHMwrite invalid size\n");
188                 exit(1);
189         }
190 }
191
192 /* Template RAM write */
193 static void assemble_write_tram(struct ivals_context *ctx,
194                                 unsigned int offset,
195                                 unsigned int value)
196 {
197         assemble_write_mmio(ctx, 0x130, SIZE_32BIT, offset);
198         assemble_write_mmio(ctx, 0x134, SIZE_32BIT, value);
199 }
200
201 static void assemble_ival_section(struct ivals_context *ctx,
202                                   const struct initvals_sect *sect)
203 {
204         struct initval_op *op;
205
206         ctx->sect = sect;
207         if (list_empty(&sect->ops)) {
208                 //TODO warning
209                 return;
210         }
211         list_for_each_entry(op, &sect->ops, list) {
212                 switch (op->type) {
213                 case IVAL_W_MMIO16:
214                         assemble_write_mmio(ctx, op->args[1],
215                                             SIZE_16BIT,
216                                             op->args[0]);
217                         break;
218                 case IVAL_W_MMIO32:
219                         assemble_write_mmio(ctx, op->args[1],
220                                             SIZE_32BIT,
221                                             op->args[0]);
222                         break;
223                 case IVAL_W_PHY:
224                         assemble_write_phy(ctx, op->args[1],
225                                            op->args[0]);
226                         break;
227                 case IVAL_W_RADIO:
228                         assemble_write_radio(ctx, op->args[1],
229                                              op->args[0]);
230                         break;
231                 case IVAL_W_SHM16:
232                         assemble_write_shm(ctx, op->args[1],
233                                            op->args[2],
234                                            op->args[0],
235                                            SIZE_16BIT);
236                         break;
237                 case IVAL_W_SHM32:
238                         assemble_write_shm(ctx, op->args[1],
239                                            op->args[2],
240                                            op->args[0],
241                                            SIZE_32BIT);
242                         break;
243                 case IVAL_W_TRAM:
244                         assemble_write_tram(ctx, op->args[1],
245                                             op->args[0]);
246                         break;
247                 }
248         }
249 }
250
251 static unsigned int initval_to_raw(struct ivals_context *ctx,
252                                    struct initval_raw *raw,
253                                    const struct initval *iv)
254 {
255         unsigned int size;
256
257         memset(raw, 0, sizeof(*raw));
258         if (iv->offset & ~FW_IV_OFFSET_MASK) {
259                 iv_error(ctx, "Initval offset 0x%04X too big. "
260                          "Offset must be <= 0x%04X",
261                          iv->offset, FW_IV_OFFSET_MASK);
262         }
263         raw->offset_size = cpu_to_be16(iv->offset);
264
265         switch (iv->size) {
266         case SIZE_16BIT:
267                 raw->data.d16 = cpu_to_be16(iv->value);
268                 size = sizeof(be16_t) + sizeof(be16_t);
269                 break;
270         case SIZE_32BIT:
271                 raw->data.d32 = cpu_to_be32(iv->value);
272                 raw->offset_size |= cpu_to_be16(FW_IV_32BIT);
273                 size = sizeof(be16_t) + sizeof(be32_t);
274                 break;
275         default:
276                 iv_error(ctx, "Internal error. initval_to_raw invalid size.");
277                 break;
278         }
279
280         return size;
281 }
282
283 static void emit_ival_section(struct ivals_context *ctx)
284 {
285         FILE *fd;
286         char *fn;
287         size_t fn_len;
288         struct initval *iv;
289         struct initval_raw raw;
290         struct fw_header hdr;
291         unsigned int size;
292         unsigned int filesize = 0;
293
294         memset(&hdr, 0, sizeof(hdr));
295         hdr.type = FW_TYPE_IV;
296         hdr.ver = FW_HDR_VER;
297         hdr.size = cpu_to_be32(ctx->ivals_count);
298
299         fn_len = strlen(ctx->sect->name) + strlen(cmdargs.initvals_fn_extension ? : "") + 1;
300         fn = xmalloc(fn_len);
301         snprintf(fn, fn_len, "%s%s", ctx->sect->name, cmdargs.initvals_fn_extension ? : "");
302         fd = fopen(fn, "w+");
303         if (!fd) {
304                 fprintf(stderr, "Could not open initval output file \"%s\"\n", fn);
305                 free(fn);
306                 exit(1);
307         }
308
309         if (fwrite(&hdr, sizeof(hdr), 1, fd) != 1) {
310                 fprintf(stderr, "Could not write initvals outfile\n");
311                 exit(1);
312         }
313
314         if (IS_VERBOSE_DEBUG)
315                 fprintf(stderr, "\nInitvals \"%s\":\n", ctx->sect->name);
316         list_for_each_entry(iv, &ctx->ivals, list) {
317                 if (IS_VERBOSE_DEBUG) {
318                         fprintf(stderr, "%04X %u %08X\n",
319                                 iv->offset,
320                                 iv->size,
321                                 iv->value);
322                 }
323                 size = initval_to_raw(ctx, &raw, iv);
324                 if (fwrite(&raw, size, 1, fd) != 1) {
325                         fprintf(stderr, "Could not write initvals outfile\n");
326                         exit(1);
327                 }
328                 filesize += size;
329         }
330
331         if (cmdargs.print_sizes) {
332                 printf("%s:  %d values (%u bytes)\n",
333                        fn, ctx->ivals_count, filesize);
334         }
335
336         fclose(fd);
337         free(fn);
338 }
339
340 void assemble_initvals(void)
341 {
342         struct ivals_context ctx;
343         struct initvals_sect *sect;
344
345         list_for_each_entry(sect, &infile.ivals, list) {
346                 memset(&ctx, 0, sizeof(ctx));
347                 INIT_LIST_HEAD(&ctx.ivals);
348
349                 assemble_ival_section(&ctx, sect);
350                 emit_ival_section(&ctx);
351         }
352 }