Linux Audio

Check our new training course

Loading...
  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}