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