]> git.kernelconcepts.de Git - karo-tx-linux.git/blob - drivers/uwb/i1480/dfu/phy.c
Merge branches 'acpi-spcr', 'acpi-osi', 'acpi-bus', 'acpi-scan' and 'acpi-misc'
[karo-tx-linux.git] / drivers / uwb / i1480 / dfu / phy.c
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  */
51 static
52 int 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         }
74 out:
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  */
99 static
100 int 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                 goto out;
130         }
131         for (cnt = 0; cnt < size; cnt++) {
132                 if (reply->data[cnt].page != (srcaddr + cnt) >> 8)
133                         dev_err(i1480->dev, "MPI-READ: page inconsistency at "
134                                 "index %u: expected 0x%02x, got 0x%02x\n", cnt,
135                                 (srcaddr + cnt) >> 8, reply->data[cnt].page);
136                 if (reply->data[cnt].offset != ((srcaddr + cnt) & 0x00ff))
137                         dev_err(i1480->dev, "MPI-READ: offset inconsistency at "
138                                 "index %u: expected 0x%02x, got 0x%02x\n", cnt,
139                                 (srcaddr + cnt) & 0x00ff,
140                                 reply->data[cnt].offset);
141                 data[cnt] = reply->data[cnt].value;
142         }
143         result = 0;
144 out:
145         return result;
146 }
147
148
149 /**
150  * Upload a PHY firmware, wait for it to start
151  *
152  * @i1480:     Device instance
153  * @fw_name: Name of the file that contains the firmware
154  *
155  * We assume the MAC fw is up and running. This means we can use the
156  * MPI interface to write the PHY firmware. Once done, we issue an
157  * MBOA Reset, which will force the MAC to reset and reinitialize the
158  * PHY. If that works, we are ready to go.
159  *
160  * Max packet size for the MPI write is 512, so the max buffer is 480
161  * (which gives us 160 byte triads of MSB, LSB and VAL for the data).
162  */
163 int i1480_phy_fw_upload(struct i1480 *i1480)
164 {
165         int result;
166         const struct firmware *fw;
167         const char *data_itr, *data_top;
168         const size_t MAX_BLK_SIZE = 480;        /* 160 triads */
169         size_t data_size;
170         u8 phy_stat;
171
172         result = request_firmware(&fw, i1480->phy_fw_name, i1480->dev);
173         if (result < 0)
174                 goto out;
175         /* Loop writing data in chunks as big as possible until done. */
176         for (data_itr = fw->data, data_top = data_itr + fw->size;
177              data_itr < data_top; data_itr += MAX_BLK_SIZE) {
178                 data_size = min(MAX_BLK_SIZE, (size_t) (data_top - data_itr));
179                 result = i1480_mpi_write(i1480, data_itr, data_size);
180                 if (result < 0)
181                         goto error_mpi_write;
182         }
183         /* Read MPI page 0, offset 6; if 0, PHY was initialized correctly. */
184         result = i1480_mpi_read(i1480, &phy_stat, 0x0006, 1);
185         if (result < 0) {
186                 dev_err(i1480->dev, "PHY: can't get status: %d\n", result);
187                 goto error_mpi_status;
188         }
189         if (phy_stat != 0) {
190                 result = -ENODEV;
191                 dev_info(i1480->dev, "error, PHY not ready: %u\n", phy_stat);
192                 goto error_phy_status;
193         }
194         dev_info(i1480->dev, "PHY fw '%s': uploaded\n", i1480->phy_fw_name);
195 error_phy_status:
196 error_mpi_status:
197 error_mpi_write:
198         release_firmware(fw);
199         if (result < 0)
200                 dev_err(i1480->dev, "PHY fw '%s': failed to upload (%d), "
201                         "power cycle device\n", i1480->phy_fw_name, result);
202 out:
203         return result;
204 }