linux/arch/cris/arch-v32/drivers/iop_fw_load.c
<<
>>
Prefs
   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