Path: blob/master/arch/cris/arch-v32/drivers/iop_fw_load.c
15126 views
/*1* Firmware loader for ETRAX FS IO-Processor2*3* Copyright (C) 2004 Axis Communications AB4*/56#include <linux/module.h>7#include <linux/kernel.h>8#include <linux/init.h>9#include <linux/device.h>10#include <linux/firmware.h>1112#include <hwregs/reg_rdwr.h>13#include <hwregs/reg_map.h>14#include <hwregs/iop/iop_reg_space.h>15#include <hwregs/iop/iop_mpu_macros.h>16#include <hwregs/iop/iop_mpu_defs.h>17#include <hwregs/iop/iop_spu_defs.h>18#include <hwregs/iop/iop_sw_cpu_defs.h>1920#define IOP_TIMEOUT 1002122#error "This driver is broken with regard to its driver core usage."23#error "Please contact <[email protected]> for details on how to fix it properly."2425static struct device iop_spu_device[2] = {26{ .init_name = "iop-spu0", },27{ .init_name = "iop-spu1", },28};2930static struct device iop_mpu_device = {31.init_name = "iop-mpu",32};3334static int wait_mpu_idle(void)35{36reg_iop_mpu_r_stat mpu_stat;37unsigned int timeout = IOP_TIMEOUT;3839do {40mpu_stat = REG_RD(iop_mpu, regi_iop_mpu, r_stat);41} while (mpu_stat.instr_reg_busy == regk_iop_mpu_yes && --timeout > 0);42if (timeout == 0) {43printk(KERN_ERR "Timeout waiting for MPU to be idle\n");44return -EBUSY;45}46return 0;47}4849int iop_fw_load_spu(const unsigned char *fw_name, unsigned int spu_inst)50{51reg_iop_sw_cpu_rw_mc_ctrl mc_ctrl = {52.wr_spu0_mem = regk_iop_sw_cpu_no,53.wr_spu1_mem = regk_iop_sw_cpu_no,54.size = 4,55.cmd = regk_iop_sw_cpu_reg_copy,56.keep_owner = regk_iop_sw_cpu_yes57};58reg_iop_spu_rw_ctrl spu_ctrl = {59.en = regk_iop_spu_no,60.fsm = regk_iop_spu_no,61};62reg_iop_sw_cpu_r_mc_stat mc_stat;63const struct firmware *fw_entry;64u32 *data;65unsigned int timeout;66int retval, i;6768if (spu_inst > 1)69return -ENODEV;7071/* get firmware */72retval = request_firmware(&fw_entry,73fw_name,74&iop_spu_device[spu_inst]);75if (retval != 0)76{77printk(KERN_ERR78"iop_load_spu: Failed to load firmware \"%s\"\n",79fw_name);80return retval;81}82data = (u32 *) fw_entry->data;8384/* acquire ownership of memory controller */85switch (spu_inst) {86case 0:87mc_ctrl.wr_spu0_mem = regk_iop_sw_cpu_yes;88REG_WR(iop_spu, regi_iop_spu0, rw_ctrl, spu_ctrl);89break;90case 1:91mc_ctrl.wr_spu1_mem = regk_iop_sw_cpu_yes;92REG_WR(iop_spu, regi_iop_spu1, rw_ctrl, spu_ctrl);93break;94}95timeout = IOP_TIMEOUT;96do {97REG_WR(iop_sw_cpu, regi_iop_sw_cpu, rw_mc_ctrl, mc_ctrl);98mc_stat = REG_RD(iop_sw_cpu, regi_iop_sw_cpu, r_mc_stat);99} while (mc_stat.owned_by_cpu == regk_iop_sw_cpu_no && --timeout > 0);100if (timeout == 0) {101printk(KERN_ERR "Timeout waiting to acquire MC\n");102retval = -EBUSY;103goto out;104}105106/* write to SPU memory */107for (i = 0; i < (fw_entry->size/4); i++) {108switch (spu_inst) {109case 0:110REG_WR_INT(iop_spu, regi_iop_spu0, rw_seq_pc, (i*4));111break;112case 1:113REG_WR_INT(iop_spu, regi_iop_spu1, rw_seq_pc, (i*4));114break;115}116REG_WR_INT(iop_sw_cpu, regi_iop_sw_cpu, rw_mc_data, *data);117data++;118}119120/* release ownership of memory controller */121(void) REG_RD(iop_sw_cpu, regi_iop_sw_cpu, rs_mc_data);122123out:124release_firmware(fw_entry);125return retval;126}127128int iop_fw_load_mpu(unsigned char *fw_name)129{130const unsigned int start_addr = 0;131reg_iop_mpu_rw_ctrl mpu_ctrl;132const struct firmware *fw_entry;133u32 *data;134int retval, i;135136/* get firmware */137retval = request_firmware(&fw_entry, fw_name, &iop_mpu_device);138if (retval != 0)139{140printk(KERN_ERR141"iop_load_spu: Failed to load firmware \"%s\"\n",142fw_name);143return retval;144}145data = (u32 *) fw_entry->data;146147/* disable MPU */148mpu_ctrl.en = regk_iop_mpu_no;149REG_WR(iop_mpu, regi_iop_mpu, rw_ctrl, mpu_ctrl);150/* put start address in R0 */151REG_WR_VECT(iop_mpu, regi_iop_mpu, rw_r, 0, start_addr);152/* write to memory by executing 'SWX i, 4, R0' for each word */153if ((retval = wait_mpu_idle()) != 0)154goto out;155REG_WR(iop_mpu, regi_iop_mpu, rw_instr, MPU_SWX_IIR_INSTR(0, 4, 0));156for (i = 0; i < (fw_entry->size / 4); i++) {157REG_WR_INT(iop_mpu, regi_iop_mpu, rw_immediate, *data);158if ((retval = wait_mpu_idle()) != 0)159goto out;160data++;161}162163out:164release_firmware(fw_entry);165return retval;166}167168int iop_start_mpu(unsigned int start_addr)169{170reg_iop_mpu_rw_ctrl mpu_ctrl = { .en = regk_iop_mpu_yes };171int retval;172173/* disable MPU */174if ((retval = wait_mpu_idle()) != 0)175goto out;176REG_WR(iop_mpu, regi_iop_mpu, rw_instr, MPU_HALT());177if ((retval = wait_mpu_idle()) != 0)178goto out;179/* set PC and wait for it to bite */180if ((retval = wait_mpu_idle()) != 0)181goto out;182REG_WR_INT(iop_mpu, regi_iop_mpu, rw_instr, MPU_BA_I(start_addr));183if ((retval = wait_mpu_idle()) != 0)184goto out;185/* make sure the MPU starts executing with interrupts disabled */186REG_WR(iop_mpu, regi_iop_mpu, rw_instr, MPU_DI());187if ((retval = wait_mpu_idle()) != 0)188goto out;189/* enable MPU */190REG_WR(iop_mpu, regi_iop_mpu, rw_ctrl, mpu_ctrl);191out:192return retval;193}194195static int __init iop_fw_load_init(void)196{197#if 0198/*199* static struct devices can not be added directly to sysfs by ignoring200* the driver model infrastructure. To fix this properly, please use201* the platform_bus to register these devices to be able to properly202* use the firmware infrastructure.203*/204device_initialize(&iop_spu_device[0]);205kobject_set_name(&iop_spu_device[0].kobj, "iop-spu0");206kobject_add(&iop_spu_device[0].kobj);207device_initialize(&iop_spu_device[1]);208kobject_set_name(&iop_spu_device[1].kobj, "iop-spu1");209kobject_add(&iop_spu_device[1].kobj);210device_initialize(&iop_mpu_device);211kobject_set_name(&iop_mpu_device.kobj, "iop-mpu");212kobject_add(&iop_mpu_device.kobj);213#endif214return 0;215}216217static void __exit iop_fw_load_exit(void)218{219}220221module_init(iop_fw_load_init);222module_exit(iop_fw_load_exit);223224MODULE_DESCRIPTION("ETRAX FS IO-Processor Firmware Loader");225MODULE_LICENSE("GPL");226227EXPORT_SYMBOL(iop_fw_load_spu);228EXPORT_SYMBOL(iop_fw_load_mpu);229EXPORT_SYMBOL(iop_start_mpu);230231232