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