initvals.c 8.1 KB

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