1/* 2 * Firmware loader for ETRAX FS IO-Processor 3 * 4 * Copyright (C) 2004 Axis Communications AB 5 */ 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 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> 20 21#define IOP_TIMEOUT 100 22 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." 25 26static struct device iop_spu_device[2] = { 27 { .init_name = "iop-spu0", }, 28 { .init_name = "iop-spu1", }, 29}; 30 31static struct device iop_mpu_device = { 32 .init_name = "iop-mpu", 33}; 34 35static int wait_mpu_idle(void) 36{ 37 reg_iop_mpu_r_stat mpu_stat; 38 unsigned int timeout = IOP_TIMEOUT; 39 40 do { 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); 43 if (timeout == 0) { 44 printk(KERN_ERR "Timeout waiting for MPU to be idle\n"); 45 return -EBUSY; 46 } 47 return 0; 48} 49 50int iop_fw_load_spu(const unsigned char *fw_name, unsigned int spu_inst) 51{ 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, 55 .size = 4, 56 .cmd = regk_iop_sw_cpu_reg_copy, 57 .keep_owner = regk_iop_sw_cpu_yes 58 }; 59 reg_iop_spu_rw_ctrl spu_ctrl = { 60 .en = regk_iop_spu_no, 61 .fsm = regk_iop_spu_no, 62 }; 63 reg_iop_sw_cpu_r_mc_stat mc_stat; 64 const struct firmware *fw_entry; 65 u32 *data; 66 unsigned int timeout; 67 int retval, i; 68 69 if (spu_inst > 1) 70 return -ENODEV; 71 72 /* get firmware */ 73 retval = request_firmware(&fw_entry, 74 fw_name, 75 &iop_spu_device[spu_inst]); 76 if (retval != 0) 77 { 78 printk(KERN_ERR 79 "iop_load_spu: Failed to load firmware \"%s\"\n", 80 fw_name); 81 return retval; 82 } 83 data = (u32 *) fw_entry->data; 84 85 /* acquire ownership of memory controller */ 86 switch (spu_inst) { 87 case 0: 88 mc_ctrl.wr_spu0_mem = regk_iop_sw_cpu_yes; 89 REG_WR(iop_spu, regi_iop_spu0, rw_ctrl, spu_ctrl); 90 break; 91 case 1: 92 mc_ctrl.wr_spu1_mem = regk_iop_sw_cpu_yes; 93 REG_WR(iop_spu, regi_iop_spu1, rw_ctrl, spu_ctrl); 94 break; 95 } 96 timeout = IOP_TIMEOUT; 97 do { 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); 101 if (timeout == 0) { 102 printk(KERN_ERR "Timeout waiting to acquire MC\n"); 103 retval = -EBUSY; 104 goto out; 105 } 106 107 /* write to SPU memory */ 108 for (i = 0; i < (fw_entry->size/4); i++) { 109 switch (spu_inst) { 110 case 0: 111 REG_WR_INT(iop_spu, regi_iop_spu0, rw_seq_pc, (i*4)); 112 break; 113 case 1: 114 REG_WR_INT(iop_spu, regi_iop_spu1, rw_seq_pc, (i*4)); 115 break; 116 } 117 REG_WR_INT(iop_sw_cpu, regi_iop_sw_cpu, rw_mc_data, *data); 118 data++; 119 } 120 121 /* release ownership of memory controller */ 122 (void) REG_RD(iop_sw_cpu, regi_iop_sw_cpu, rs_mc_data); 123 124 out: 125 release_firmware(fw_entry); 126 return retval; 127} 128 129int iop_fw_load_mpu(unsigned char *fw_name) 130{ 131 const unsigned int start_addr = 0; 132 reg_iop_mpu_rw_ctrl mpu_ctrl; 133 const struct firmware *fw_entry; 134 u32 *data; 135 int retval, i; 136 137 /* get firmware */ 138 retval = request_firmware(&fw_entry, fw_name, &iop_mpu_device); 139 if (retval != 0) 140 { 141 printk(KERN_ERR 142 "iop_load_spu: Failed to load firmware \"%s\"\n", 143 fw_name); 144 return retval; 145 } 146 data = (u32 *) fw_entry->data; 147 148 /* disable MPU */ 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) 155 goto out; 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) 160 goto out; 161 data++; 162 } 163 164 out: 165 release_firmware(fw_entry); 166 return retval; 167} 168 169int iop_start_mpu(unsigned int start_addr) 170{ 171 reg_iop_mpu_rw_ctrl mpu_ctrl = { .en = regk_iop_mpu_yes }; 172 int retval; 173 174 /* disable MPU */ 175 if ((retval = wait_mpu_idle()) != 0) 176 goto out; 177 REG_WR(iop_mpu, regi_iop_mpu, rw_instr, MPU_HALT()); 178 if ((retval = wait_mpu_idle()) != 0) 179 goto out; 180 /* set PC and wait for it to bite */ 181 if ((retval = wait_mpu_idle()) != 0) 182 goto out; 183 REG_WR_INT(iop_mpu, regi_iop_mpu, rw_instr, MPU_BA_I(start_addr)); 184 if ((retval = wait_mpu_idle()) != 0) 185 goto out; 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) 189 goto out; 190 /* enable MPU */ 191 REG_WR(iop_mpu, regi_iop_mpu, rw_ctrl, mpu_ctrl); 192 out: 193 return retval; 194} 195 196static int __init iop_fw_load_init(void) 197{ 198#if 0 199 /* 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. 204 */ 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); 214#endif 215 return 0; 216} 217 218static void __exit iop_fw_load_exit(void) 219{ 220} 221 222module_init(iop_fw_load_init); 223module_exit(iop_fw_load_exit); 224 225MODULE_DESCRIPTION("ETRAX FS IO-Processor Firmware Loader"); 226MODULE_LICENSE("GPL"); 227 228EXPORT_SYMBOL(iop_fw_load_spu); 229EXPORT_SYMBOL(iop_fw_load_mpu); 230EXPORT_SYMBOL(iop_start_mpu); 231