linux/drivers/uwb/i1480/dfu/phy.c
<<
>>
Prefs
   1/*
   2 * Intel Wireless UWB Link 1480
   3 * PHY parameters upload
   4 *
   5 * Copyright (C) 2005-2006 Intel Corporation
   6 * Inaky Perez-Gonzalez <inaky.perez-gonzalez@intel.com>
   7 *
   8 * This program is free software; you can redistribute it and/or
   9 * modify it under the terms of the GNU General Public License version
  10 * 2 as published by the Free Software Foundation.
  11 *
  12 * This program is distributed in the hope that it will be useful,
  13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
  14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  15 * GNU General Public License for more details.
  16 *
  17 * You should have received a copy of the GNU General Public License
  18 * along with this program; if not, write to the Free Software
  19 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
  20 * 02110-1301, USA.
  21 *
  22 *
  23 * Code for uploading the PHY parameters to the PHY through the UWB
  24 * Radio Control interface.
  25 *
  26 * We just send the data through the MPI interface using HWA-like
  27 * commands and then reset the PHY to make sure it is ok.
  28 */
  29#include <linux/delay.h>
  30#include <linux/device.h>
  31#include <linux/firmware.h>
  32#include <linux/usb/wusb.h>
  33#include "i1480-dfu.h"
  34
  35
  36/**
  37 * Write a value array to an address of the MPI interface
  38 *
  39 * @i1480:      Device descriptor
  40 * @data:       Data array to write
  41 * @size:       Size of the data array
  42 * @returns:    0 if ok, < 0 errno code on error.
  43 *
  44 * The data array is organized into pairs:
  45 *
  46 * ADDRESS VALUE
  47 *
  48 * ADDRESS is BE 16 bit unsigned, VALUE 8 bit unsigned. Size thus has
  49 * to be a multiple of three.
  50 */
  51static
  52int i1480_mpi_write(struct i1480 *i1480, const void *data, size_t size)
  53{
  54        int result;
  55        struct i1480_cmd_mpi_write *cmd = i1480->cmd_buf;
  56        struct i1480_evt_confirm *reply = i1480->evt_buf;
  57
  58        BUG_ON(size > 480);
  59        result = -ENOMEM;
  60        cmd->rccb.bCommandType = i1480_CET_VS1;
  61        cmd->rccb.wCommand = cpu_to_le16(i1480_CMD_MPI_WRITE);
  62        cmd->size = cpu_to_le16(size);
  63        memcpy(cmd->data, data, size);
  64        reply->rceb.bEventType = i1480_CET_VS1;
  65        reply->rceb.wEvent = i1480_CMD_MPI_WRITE;
  66        result = i1480_cmd(i1480, "MPI-WRITE", sizeof(*cmd) + size, sizeof(*reply));
  67        if (result < 0)
  68                goto out;
  69        if (reply->bResultCode != UWB_RC_RES_SUCCESS) {
  70                dev_err(i1480->dev, "MPI-WRITE: command execution failed: %d\n",
  71                        reply->bResultCode);
  72                result = -EIO;
  73        }
  74out:
  75        return result;
  76}
  77
  78
  79/**
  80 * Read a value array to from an address of the MPI interface
  81 *
  82 * @i1480:      Device descriptor
  83 * @data:       where to place the read array
  84 * @srcaddr:    Where to read from
  85 * @size:       Size of the data read array
  86 * @returns:    0 if ok, < 0 errno code on error.
  87 *
  88 * The command data array is organized into pairs ADDR0 ADDR1..., and
  89 * the returned data in ADDR0 VALUE0 ADDR1 VALUE1...
  90 *
  91 * We generate the command array to be a sequential read and then
  92 * rearrange the result.
  93 *
  94 * We use the i1480->cmd_buf for the command, i1480->evt_buf for the reply.
  95 *
  96 * As the reply has to fit in 512 bytes (i1480->evt_buffer), the max amount
  97 * of values we can read is (512 - sizeof(*reply)) / 3
  98 */
  99static
 100int i1480_mpi_read(struct i1480 *i1480, u8 *data, u16 srcaddr, size_t size)
 101{
 102        int result;
 103        struct i1480_cmd_mpi_read *cmd = i1480->cmd_buf;
 104        struct i1480_evt_mpi_read *reply = i1480->evt_buf;
 105        unsigned cnt;
 106
 107        memset(i1480->cmd_buf, 0x69, 512);
 108        memset(i1480->evt_buf, 0x69, 512);
 109
 110        BUG_ON(size > (i1480->buf_size - sizeof(*reply)) / 3);
 111        result = -ENOMEM;
 112        cmd->rccb.bCommandType = i1480_CET_VS1;
 113        cmd->rccb.wCommand = cpu_to_le16(i1480_CMD_MPI_READ);
 114        cmd->size = cpu_to_le16(3*size);
 115        for (cnt = 0; cnt < size; cnt++) {
 116                cmd->data[cnt].page = (srcaddr + cnt) >> 8;
 117                cmd->data[cnt].offset = (srcaddr + cnt) & 0xff;
 118        }
 119        reply->rceb.bEventType = i1480_CET_VS1;
 120        reply->rceb.wEvent = i1480_CMD_MPI_READ;
 121        result = i1480_cmd(i1480, "MPI-READ", sizeof(*cmd) + 2*size,
 122                        sizeof(*reply) + 3*size);
 123        if (result < 0)
 124                goto out;
 125        if (reply->bResultCode != UWB_RC_RES_SUCCESS) {
 126                dev_err(i1480->dev, "MPI-READ: command execution failed: %d\n",
 127                        reply->bResultCode);
 128                result = -EIO;
 129        }
 130        for (cnt = 0; cnt < size; cnt++) {
 131                if (reply->data[cnt].page != (srcaddr + cnt) >> 8)
 132                        dev_err(i1480->dev, "MPI-READ: page inconsistency at "
 133                                "index %u: expected 0x%02x, got 0x%02x\n", cnt,
 134                                (srcaddr + cnt) >> 8, reply->data[cnt].page);
 135                if (reply->data[cnt].offset != ((srcaddr + cnt) & 0x00ff))
 136                        dev_err(i1480->dev, "MPI-READ: offset inconsistency at "
 137                                "index %u: expected 0x%02x, got 0x%02x\n", cnt,
 138                                (srcaddr + cnt) & 0x00ff,
 139                                reply->data[cnt].offset);
 140                data[cnt] = reply->data[cnt].value;
 141        }
 142        result = 0;
 143out:
 144        return result;
 145}
 146
 147
 148/**
 149 * Upload a PHY firmware, wait for it to start
 150 *
 151 * @i1480:     Device instance
 152 * @fw_name: Name of the file that contains the firmware
 153 *
 154 * We assume the MAC fw is up and running. This means we can use the
 155 * MPI interface to write the PHY firmware. Once done, we issue an
 156 * MBOA Reset, which will force the MAC to reset and reinitialize the
 157 * PHY. If that works, we are ready to go.
 158 *
 159 * Max packet size for the MPI write is 512, so the max buffer is 480
 160 * (which gives us 160 byte triads of MSB, LSB and VAL for the data).
 161 */
 162int i1480_phy_fw_upload(struct i1480 *i1480)
 163{
 164        int result;
 165        const struct firmware *fw;
 166        const char *data_itr, *data_top;
 167        const size_t MAX_BLK_SIZE = 480;        /* 160 triads */
 168        size_t data_size;
 169        u8 phy_stat;
 170
 171        result = request_firmware(&fw, i1480->phy_fw_name, i1480->dev);
 172        if (result < 0)
 173                goto out;
 174        /* Loop writing data in chunks as big as possible until done. */
 175        for (data_itr = fw->data, data_top = data_itr + fw->size;
 176             data_itr < data_top; data_itr += MAX_BLK_SIZE) {
 177                data_size = min(MAX_BLK_SIZE, (size_t) (data_top - data_itr));
 178                result = i1480_mpi_write(i1480, data_itr, data_size);
 179                if (result < 0)
 180                        goto error_mpi_write;
 181        }
 182        /* Read MPI page 0, offset 6; if 0, PHY was initialized correctly. */
 183        result = i1480_mpi_read(i1480, &phy_stat, 0x0006, 1);
 184        if (result < 0) {
 185                dev_err(i1480->dev, "PHY: can't get status: %d\n", result);
 186                goto error_mpi_status;
 187        }
 188        if (phy_stat != 0) {
 189                result = -ENODEV;
 190                dev_info(i1480->dev, "error, PHY not ready: %u\n", phy_stat);
 191                goto error_phy_status;
 192        }
 193        dev_info(i1480->dev, "PHY fw '%s': uploaded\n", i1480->phy_fw_name);
 194error_phy_status:
 195error_mpi_status:
 196error_mpi_write:
 197        release_firmware(fw);
 198        if (result < 0)
 199                dev_err(i1480->dev, "PHY fw '%s': failed to upload (%d), "
 200                        "power cycle device\n", i1480->phy_fw_name, result);
 201out:
 202        return result;
 203}
 204