2 * Firmware loader for ETRAX FS IO-Processor
4 * Copyright (C) 2004 Axis Communications AB
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>
13 #include <hwregs/reg_rdwr.h>
14 #include <hwregs/reg_map.h>
15 #include <hwregs/iop/iop_reg_space.h>
16 #include <hwregs/iop/iop_mpu_macros.h>
17 #include <hwregs/iop/iop_mpu_defs.h>
18 #include <hwregs/iop/iop_spu_defs.h>
19 #include <hwregs/iop/iop_sw_cpu_defs.h>
21 #define IOP_TIMEOUT 100
23 #error "This driver is broken with regard to its driver core usage."
24 #error "Please contact <greg@kroah.com> for details on how to fix it properly."
26 static struct device iop_spu_device
[2] = {
27 { .init_name
= "iop-spu0", },
28 { .init_name
= "iop-spu1", },
31 static struct device iop_mpu_device
= {
32 .init_name
= "iop-mpu",
35 static int wait_mpu_idle(void)
37 reg_iop_mpu_r_stat mpu_stat
;
38 unsigned int timeout
= IOP_TIMEOUT
;
41 mpu_stat
= REG_RD(iop_mpu
, regi_iop_mpu
, r_stat
);
42 } while (mpu_stat
.instr_reg_busy
== regk_iop_mpu_yes
&& --timeout
> 0);
44 printk(KERN_ERR
"Timeout waiting for MPU to be idle\n");
50 int iop_fw_load_spu(const unsigned char *fw_name
, unsigned int spu_inst
)
52 reg_iop_sw_cpu_rw_mc_ctrl mc_ctrl
= {
53 .wr_spu0_mem
= regk_iop_sw_cpu_no
,
54 .wr_spu1_mem
= regk_iop_sw_cpu_no
,
56 .cmd
= regk_iop_sw_cpu_reg_copy
,
57 .keep_owner
= regk_iop_sw_cpu_yes
59 reg_iop_spu_rw_ctrl spu_ctrl
= {
60 .en
= regk_iop_spu_no
,
61 .fsm
= regk_iop_spu_no
,
63 reg_iop_sw_cpu_r_mc_stat mc_stat
;
64 const struct firmware
*fw_entry
;
73 retval
= request_firmware(&fw_entry
,
75 &iop_spu_device
[spu_inst
]);
79 "iop_load_spu: Failed to load firmware \"%s\"\n",
83 data
= (u32
*) fw_entry
->data
;
85 /* acquire ownership of memory controller */
88 mc_ctrl
.wr_spu0_mem
= regk_iop_sw_cpu_yes
;
89 REG_WR(iop_spu
, regi_iop_spu0
, rw_ctrl
, spu_ctrl
);
92 mc_ctrl
.wr_spu1_mem
= regk_iop_sw_cpu_yes
;
93 REG_WR(iop_spu
, regi_iop_spu1
, rw_ctrl
, spu_ctrl
);
96 timeout
= IOP_TIMEOUT
;
98 REG_WR(iop_sw_cpu
, regi_iop_sw_cpu
, rw_mc_ctrl
, mc_ctrl
);
99 mc_stat
= REG_RD(iop_sw_cpu
, regi_iop_sw_cpu
, r_mc_stat
);
100 } while (mc_stat
.owned_by_cpu
== regk_iop_sw_cpu_no
&& --timeout
> 0);
102 printk(KERN_ERR
"Timeout waiting to acquire MC\n");
107 /* write to SPU memory */
108 for (i
= 0; i
< (fw_entry
->size
/4); i
++) {
111 REG_WR_INT(iop_spu
, regi_iop_spu0
, rw_seq_pc
, (i
*4));
114 REG_WR_INT(iop_spu
, regi_iop_spu1
, rw_seq_pc
, (i
*4));
117 REG_WR_INT(iop_sw_cpu
, regi_iop_sw_cpu
, rw_mc_data
, *data
);
121 /* release ownership of memory controller */
122 (void) REG_RD(iop_sw_cpu
, regi_iop_sw_cpu
, rs_mc_data
);
125 release_firmware(fw_entry
);
129 int iop_fw_load_mpu(unsigned char *fw_name
)
131 const unsigned int start_addr
= 0;
132 reg_iop_mpu_rw_ctrl mpu_ctrl
;
133 const struct firmware
*fw_entry
;
138 retval
= request_firmware(&fw_entry
, fw_name
, &iop_mpu_device
);
142 "iop_load_spu: Failed to load firmware \"%s\"\n",
146 data
= (u32
*) fw_entry
->data
;
149 mpu_ctrl
.en
= regk_iop_mpu_no
;
150 REG_WR(iop_mpu
, regi_iop_mpu
, rw_ctrl
, mpu_ctrl
);
151 /* put start address in R0 */
152 REG_WR_VECT(iop_mpu
, regi_iop_mpu
, rw_r
, 0, start_addr
);
153 /* write to memory by executing 'SWX i, 4, R0' for each word */
154 if ((retval
= wait_mpu_idle()) != 0)
156 REG_WR(iop_mpu
, regi_iop_mpu
, rw_instr
, MPU_SWX_IIR_INSTR(0, 4, 0));
157 for (i
= 0; i
< (fw_entry
->size
/ 4); i
++) {
158 REG_WR_INT(iop_mpu
, regi_iop_mpu
, rw_immediate
, *data
);
159 if ((retval
= wait_mpu_idle()) != 0)
165 release_firmware(fw_entry
);
169 int iop_start_mpu(unsigned int start_addr
)
171 reg_iop_mpu_rw_ctrl mpu_ctrl
= { .en
= regk_iop_mpu_yes
};
175 if ((retval
= wait_mpu_idle()) != 0)
177 REG_WR(iop_mpu
, regi_iop_mpu
, rw_instr
, MPU_HALT());
178 if ((retval
= wait_mpu_idle()) != 0)
180 /* set PC and wait for it to bite */
181 if ((retval
= wait_mpu_idle()) != 0)
183 REG_WR_INT(iop_mpu
, regi_iop_mpu
, rw_instr
, MPU_BA_I(start_addr
));
184 if ((retval
= wait_mpu_idle()) != 0)
186 /* make sure the MPU starts executing with interrupts disabled */
187 REG_WR(iop_mpu
, regi_iop_mpu
, rw_instr
, MPU_DI());
188 if ((retval
= wait_mpu_idle()) != 0)
191 REG_WR(iop_mpu
, regi_iop_mpu
, rw_ctrl
, mpu_ctrl
);
196 static int __init
iop_fw_load_init(void)
200 * static struct devices can not be added directly to sysfs by ignoring
201 * the driver model infrastructure. To fix this properly, please use
202 * the platform_bus to register these devices to be able to properly
203 * use the firmware infrastructure.
205 device_initialize(&iop_spu_device
[0]);
206 kobject_set_name(&iop_spu_device
[0].kobj
, "iop-spu0");
207 kobject_add(&iop_spu_device
[0].kobj
);
208 device_initialize(&iop_spu_device
[1]);
209 kobject_set_name(&iop_spu_device
[1].kobj
, "iop-spu1");
210 kobject_add(&iop_spu_device
[1].kobj
);
211 device_initialize(&iop_mpu_device
);
212 kobject_set_name(&iop_mpu_device
.kobj
, "iop-mpu");
213 kobject_add(&iop_mpu_device
.kobj
);
218 static void __exit
iop_fw_load_exit(void)
222 module_init(iop_fw_load_init
);
223 module_exit(iop_fw_load_exit
);
225 MODULE_DESCRIPTION("ETRAX FS IO-Processor Firmware Loader");
226 MODULE_LICENSE("GPL");
228 EXPORT_SYMBOL(iop_fw_load_spu
);
229 EXPORT_SYMBOL(iop_fw_load_mpu
);
230 EXPORT_SYMBOL(iop_start_mpu
);