iop_fw_load.c 5.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219
  1. /* $Id: iop_fw_load.c,v 1.4 2005/04/07 09:27:46 larsv Exp $
  2. *
  3. * Firmware loader for ETRAX FS IO-Processor
  4. *
  5. * Copyright (C) 2004 Axis Communications AB
  6. */
  7. #include <linux/module.h>
  8. #include <linux/kernel.h>
  9. #include <linux/init.h>
  10. #include <linux/device.h>
  11. #include <linux/firmware.h>
  12. #include <asm/arch/hwregs/reg_map.h>
  13. #include <asm/arch/hwregs/iop/iop_reg_space.h>
  14. #include <asm/arch/hwregs/iop/iop_mpu_macros.h>
  15. #include <asm/arch/hwregs/iop/iop_mpu_defs.h>
  16. #include <asm/arch/hwregs/iop/iop_spu_defs.h>
  17. #include <asm/arch/hwregs/iop/iop_sw_cpu_defs.h>
  18. #define IOP_TIMEOUT 100
  19. static struct device iop_spu_device[2] = {
  20. { .bus_id = "iop-spu0", },
  21. { .bus_id = "iop-spu1", },
  22. };
  23. static struct device iop_mpu_device = {
  24. .bus_id = "iop-mpu",
  25. };
  26. static int wait_mpu_idle(void)
  27. {
  28. reg_iop_mpu_r_stat mpu_stat;
  29. unsigned int timeout = IOP_TIMEOUT;
  30. do {
  31. mpu_stat = REG_RD(iop_mpu, regi_iop_mpu, r_stat);
  32. } while (mpu_stat.instr_reg_busy == regk_iop_mpu_yes && --timeout > 0);
  33. if (timeout == 0) {
  34. printk(KERN_ERR "Timeout waiting for MPU to be idle\n");
  35. return -EBUSY;
  36. }
  37. return 0;
  38. }
  39. int iop_fw_load_spu(const unsigned char *fw_name, unsigned int spu_inst)
  40. {
  41. reg_iop_sw_cpu_rw_mc_ctrl mc_ctrl = {
  42. .wr_spu0_mem = regk_iop_sw_cpu_no,
  43. .wr_spu1_mem = regk_iop_sw_cpu_no,
  44. .size = 4,
  45. .cmd = regk_iop_sw_cpu_reg_copy,
  46. .keep_owner = regk_iop_sw_cpu_yes
  47. };
  48. reg_iop_spu_rw_ctrl spu_ctrl = {
  49. .en = regk_iop_spu_no,
  50. .fsm = regk_iop_spu_no,
  51. };
  52. reg_iop_sw_cpu_r_mc_stat mc_stat;
  53. const struct firmware *fw_entry;
  54. u32 *data;
  55. unsigned int timeout;
  56. int retval, i;
  57. if (spu_inst > 1)
  58. return -ENODEV;
  59. /* get firmware */
  60. retval = request_firmware(&fw_entry,
  61. fw_name,
  62. &iop_spu_device[spu_inst]);
  63. if (retval != 0)
  64. {
  65. printk(KERN_ERR
  66. "iop_load_spu: Failed to load firmware \"%s\"\n",
  67. fw_name);
  68. return retval;
  69. }
  70. data = (u32 *) fw_entry->data;
  71. /* acquire ownership of memory controller */
  72. switch (spu_inst) {
  73. case 0:
  74. mc_ctrl.wr_spu0_mem = regk_iop_sw_cpu_yes;
  75. REG_WR(iop_spu, regi_iop_spu0, rw_ctrl, spu_ctrl);
  76. break;
  77. case 1:
  78. mc_ctrl.wr_spu1_mem = regk_iop_sw_cpu_yes;
  79. REG_WR(iop_spu, regi_iop_spu1, rw_ctrl, spu_ctrl);
  80. break;
  81. }
  82. timeout = IOP_TIMEOUT;
  83. do {
  84. REG_WR(iop_sw_cpu, regi_iop_sw_cpu, rw_mc_ctrl, mc_ctrl);
  85. mc_stat = REG_RD(iop_sw_cpu, regi_iop_sw_cpu, r_mc_stat);
  86. } while (mc_stat.owned_by_cpu == regk_iop_sw_cpu_no && --timeout > 0);
  87. if (timeout == 0) {
  88. printk(KERN_ERR "Timeout waiting to acquire MC\n");
  89. retval = -EBUSY;
  90. goto out;
  91. }
  92. /* write to SPU memory */
  93. for (i = 0; i < (fw_entry->size/4); i++) {
  94. switch (spu_inst) {
  95. case 0:
  96. REG_WR_INT(iop_spu, regi_iop_spu0, rw_seq_pc, (i*4));
  97. break;
  98. case 1:
  99. REG_WR_INT(iop_spu, regi_iop_spu1, rw_seq_pc, (i*4));
  100. break;
  101. }
  102. REG_WR_INT(iop_sw_cpu, regi_iop_sw_cpu, rw_mc_data, *data);
  103. data++;
  104. }
  105. /* release ownership of memory controller */
  106. (void) REG_RD(iop_sw_cpu, regi_iop_sw_cpu, rs_mc_data);
  107. out:
  108. release_firmware(fw_entry);
  109. return retval;
  110. }
  111. int iop_fw_load_mpu(unsigned char *fw_name)
  112. {
  113. const unsigned int start_addr = 0;
  114. reg_iop_mpu_rw_ctrl mpu_ctrl;
  115. const struct firmware *fw_entry;
  116. u32 *data;
  117. int retval, i;
  118. /* get firmware */
  119. retval = request_firmware(&fw_entry, fw_name, &iop_mpu_device);
  120. if (retval != 0)
  121. {
  122. printk(KERN_ERR
  123. "iop_load_spu: Failed to load firmware \"%s\"\n",
  124. fw_name);
  125. return retval;
  126. }
  127. data = (u32 *) fw_entry->data;
  128. /* disable MPU */
  129. mpu_ctrl.en = regk_iop_mpu_no;
  130. REG_WR(iop_mpu, regi_iop_mpu, rw_ctrl, mpu_ctrl);
  131. /* put start address in R0 */
  132. REG_WR_VECT(iop_mpu, regi_iop_mpu, rw_r, 0, start_addr);
  133. /* write to memory by executing 'SWX i, 4, R0' for each word */
  134. if ((retval = wait_mpu_idle()) != 0)
  135. goto out;
  136. REG_WR(iop_mpu, regi_iop_mpu, rw_instr, MPU_SWX_IIR_INSTR(0, 4, 0));
  137. for (i = 0; i < (fw_entry->size / 4); i++) {
  138. REG_WR_INT(iop_mpu, regi_iop_mpu, rw_immediate, *data);
  139. if ((retval = wait_mpu_idle()) != 0)
  140. goto out;
  141. data++;
  142. }
  143. out:
  144. release_firmware(fw_entry);
  145. return retval;
  146. }
  147. int iop_start_mpu(unsigned int start_addr)
  148. {
  149. reg_iop_mpu_rw_ctrl mpu_ctrl = { .en = regk_iop_mpu_yes };
  150. int retval;
  151. /* disable MPU */
  152. if ((retval = wait_mpu_idle()) != 0)
  153. goto out;
  154. REG_WR(iop_mpu, regi_iop_mpu, rw_instr, MPU_HALT());
  155. if ((retval = wait_mpu_idle()) != 0)
  156. goto out;
  157. /* set PC and wait for it to bite */
  158. if ((retval = wait_mpu_idle()) != 0)
  159. goto out;
  160. REG_WR_INT(iop_mpu, regi_iop_mpu, rw_instr, MPU_BA_I(start_addr));
  161. if ((retval = wait_mpu_idle()) != 0)
  162. goto out;
  163. /* make sure the MPU starts executing with interrupts disabled */
  164. REG_WR(iop_mpu, regi_iop_mpu, rw_instr, MPU_DI());
  165. if ((retval = wait_mpu_idle()) != 0)
  166. goto out;
  167. /* enable MPU */
  168. REG_WR(iop_mpu, regi_iop_mpu, rw_ctrl, mpu_ctrl);
  169. out:
  170. return retval;
  171. }
  172. static int __init iop_fw_load_init(void)
  173. {
  174. device_initialize(&iop_spu_device[0]);
  175. kobject_set_name(&iop_spu_device[0].kobj, "iop-spu0");
  176. kobject_add(&iop_spu_device[0].kobj);
  177. device_initialize(&iop_spu_device[1]);
  178. kobject_set_name(&iop_spu_device[1].kobj, "iop-spu1");
  179. kobject_add(&iop_spu_device[1].kobj);
  180. device_initialize(&iop_mpu_device);
  181. kobject_set_name(&iop_mpu_device.kobj, "iop-mpu");
  182. kobject_add(&iop_mpu_device.kobj);
  183. return 0;
  184. }
  185. static void __exit iop_fw_load_exit(void)
  186. {
  187. }
  188. module_init(iop_fw_load_init);
  189. module_exit(iop_fw_load_exit);
  190. MODULE_DESCRIPTION("ETRAX FS IO-Processor Firmware Loader");
  191. MODULE_LICENSE("GPL");
  192. EXPORT_SYMBOL(iop_fw_load_spu);
  193. EXPORT_SYMBOL(iop_fw_load_mpu);
  194. EXPORT_SYMBOL(iop_start_mpu);