Linux Audio

Check our new training course

Linux kernel drivers training

Mar 31-Apr 9, 2025, special US time zones
Register
Loading...
Note: File does not exist in v6.8.
  1/*
  2
  3  Broadcom B43 wireless driver
  4  IEEE 802.11n HT-PHY support
  5
  6  This program is free software; you can redistribute it and/or modify
  7  it under the terms of the GNU General Public License as published by
  8  the Free Software Foundation; either version 2 of the License, or
  9  (at your option) any later version.
 10
 11  This program is distributed in the hope that it will be useful,
 12  but WITHOUT ANY WARRANTY; without even the implied warranty of
 13  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 14  GNU General Public License for more details.
 15
 16  You should have received a copy of the GNU General Public License
 17  along with this program; see the file COPYING.  If not, write to
 18  the Free Software Foundation, Inc., 51 Franklin Steet, Fifth Floor,
 19  Boston, MA 02110-1301, USA.
 20
 21*/
 22
 23#include <linux/slab.h>
 24
 25#include "b43.h"
 26#include "phy_ht.h"
 27#include "tables_phy_ht.h"
 28#include "radio_2059.h"
 29#include "main.h"
 30
 31/**************************************************
 32 * Radio 2059.
 33 **************************************************/
 34
 35static void b43_radio_2059_channel_setup(struct b43_wldev *dev,
 36			const struct b43_phy_ht_channeltab_e_radio2059 *e)
 37{
 38	u8 i;
 39	u16 routing;
 40
 41	b43_radio_write(dev, 0x16, e->radio_syn16);
 42	b43_radio_write(dev, 0x17, e->radio_syn17);
 43	b43_radio_write(dev, 0x22, e->radio_syn22);
 44	b43_radio_write(dev, 0x25, e->radio_syn25);
 45	b43_radio_write(dev, 0x27, e->radio_syn27);
 46	b43_radio_write(dev, 0x28, e->radio_syn28);
 47	b43_radio_write(dev, 0x29, e->radio_syn29);
 48	b43_radio_write(dev, 0x2c, e->radio_syn2c);
 49	b43_radio_write(dev, 0x2d, e->radio_syn2d);
 50	b43_radio_write(dev, 0x37, e->radio_syn37);
 51	b43_radio_write(dev, 0x41, e->radio_syn41);
 52	b43_radio_write(dev, 0x43, e->radio_syn43);
 53	b43_radio_write(dev, 0x47, e->radio_syn47);
 54	b43_radio_write(dev, 0x4a, e->radio_syn4a);
 55	b43_radio_write(dev, 0x58, e->radio_syn58);
 56	b43_radio_write(dev, 0x5a, e->radio_syn5a);
 57	b43_radio_write(dev, 0x6a, e->radio_syn6a);
 58	b43_radio_write(dev, 0x6d, e->radio_syn6d);
 59	b43_radio_write(dev, 0x6e, e->radio_syn6e);
 60	b43_radio_write(dev, 0x92, e->radio_syn92);
 61	b43_radio_write(dev, 0x98, e->radio_syn98);
 62
 63	for (i = 0; i < 2; i++) {
 64		routing = i ? R2059_RXRX1 : R2059_TXRX0;
 65		b43_radio_write(dev, routing | 0x4a, e->radio_rxtx4a);
 66		b43_radio_write(dev, routing | 0x58, e->radio_rxtx58);
 67		b43_radio_write(dev, routing | 0x5a, e->radio_rxtx5a);
 68		b43_radio_write(dev, routing | 0x6a, e->radio_rxtx6a);
 69		b43_radio_write(dev, routing | 0x6d, e->radio_rxtx6d);
 70		b43_radio_write(dev, routing | 0x6e, e->radio_rxtx6e);
 71		b43_radio_write(dev, routing | 0x92, e->radio_rxtx92);
 72		b43_radio_write(dev, routing | 0x98, e->radio_rxtx98);
 73	}
 74
 75	udelay(50);
 76
 77	/* Calibration */
 78	b43_radio_mask(dev, 0x2b, ~0x1);
 79	b43_radio_mask(dev, 0x2e, ~0x4);
 80	b43_radio_set(dev, 0x2e, 0x4);
 81	b43_radio_set(dev, 0x2b, 0x1);
 82
 83	udelay(300);
 84}
 85
 86static void b43_radio_2059_init(struct b43_wldev *dev)
 87{
 88	const u16 routing[] = { R2059_SYN, R2059_TXRX0, R2059_RXRX1 };
 89	const u16 radio_values[3][2] = {
 90		{ 0x61, 0xE9 }, { 0x69, 0xD5 }, { 0x73, 0x99 },
 91	};
 92	u16 i, j;
 93
 94	b43_radio_write(dev, R2059_ALL | 0x51, 0x0070);
 95	b43_radio_write(dev, R2059_ALL | 0x5a, 0x0003);
 96
 97	for (i = 0; i < ARRAY_SIZE(routing); i++)
 98		b43_radio_set(dev, routing[i] | 0x146, 0x3);
 99
100	b43_radio_set(dev, 0x2e, 0x0078);
101	b43_radio_set(dev, 0xc0, 0x0080);
102	msleep(2);
103	b43_radio_mask(dev, 0x2e, ~0x0078);
104	b43_radio_mask(dev, 0xc0, ~0x0080);
105
106	if (1) { /* FIXME */
107		b43_radio_set(dev, R2059_RXRX1 | 0x4, 0x1);
108		udelay(10);
109		b43_radio_set(dev, R2059_RXRX1 | 0x0BF, 0x1);
110		b43_radio_maskset(dev, R2059_RXRX1 | 0x19B, 0x3, 0x2);
111
112		b43_radio_set(dev, R2059_RXRX1 | 0x4, 0x2);
113		udelay(100);
114		b43_radio_mask(dev, R2059_RXRX1 | 0x4, ~0x2);
115
116		for (i = 0; i < 10000; i++) {
117			if (b43_radio_read(dev, R2059_RXRX1 | 0x145) & 1) {
118				i = 0;
119				break;
120			}
121			udelay(100);
122		}
123		if (i)
124			b43err(dev->wl, "radio 0x945 timeout\n");
125
126		b43_radio_mask(dev, R2059_RXRX1 | 0x4, ~0x1);
127		b43_radio_set(dev, 0xa, 0x60);
128
129		for (i = 0; i < 3; i++) {
130			b43_radio_write(dev, 0x17F, radio_values[i][0]);
131			b43_radio_write(dev, 0x13D, 0x6E);
132			b43_radio_write(dev, 0x13E, radio_values[i][1]);
133			b43_radio_write(dev, 0x13C, 0x55);
134
135			for (j = 0; j < 10000; j++) {
136				if (b43_radio_read(dev, 0x140) & 2) {
137					j = 0;
138					break;
139				}
140				udelay(500);
141			}
142			if (j)
143				b43err(dev->wl, "radio 0x140 timeout\n");
144
145			b43_radio_write(dev, 0x13C, 0x15);
146		}
147
148		b43_radio_mask(dev, 0x17F, ~0x1);
149	}
150
151	b43_radio_mask(dev, 0x11, ~0x0008);
152}
153
154/**************************************************
155 * Channel switching ops.
156 **************************************************/
157
158static void b43_phy_ht_channel_setup(struct b43_wldev *dev,
159				const struct b43_phy_ht_channeltab_e_phy *e,
160				struct ieee80211_channel *new_channel)
161{
162	bool old_band_5ghz;
163	u8 i;
164
165	old_band_5ghz = b43_phy_read(dev, B43_PHY_HT_BANDCTL) & 0; /* FIXME */
166	if (new_channel->band == IEEE80211_BAND_5GHZ && !old_band_5ghz) {
167		/* TODO */
168	} else if (new_channel->band == IEEE80211_BAND_2GHZ && old_band_5ghz) {
169		/* TODO */
170	}
171
172	b43_phy_write(dev, B43_PHY_HT_BW1, e->bw1);
173	b43_phy_write(dev, B43_PHY_HT_BW2, e->bw2);
174	b43_phy_write(dev, B43_PHY_HT_BW3, e->bw3);
175	b43_phy_write(dev, B43_PHY_HT_BW4, e->bw4);
176	b43_phy_write(dev, B43_PHY_HT_BW5, e->bw5);
177	b43_phy_write(dev, B43_PHY_HT_BW6, e->bw6);
178
179	/* TODO: some ops on PHY regs 0x0B0 and 0xC0A */
180
181	/* TODO: separated function? */
182	for (i = 0; i < 3; i++) {
183		u16 mask;
184		u32 tmp = b43_httab_read(dev, B43_HTTAB32(26, 0xE8));
185
186		if (0) /* FIXME */
187			mask = 0x2 << (i * 4);
188		else
189			mask = 0;
190		b43_phy_mask(dev, B43_PHY_EXTG(0x108), mask);
191
192		b43_httab_write(dev, B43_HTTAB16(7, 0x110 + i), tmp >> 16);
193		b43_httab_write(dev, B43_HTTAB8(13, 0x63 + (i * 4)),
194				tmp & 0xFF);
195		b43_httab_write(dev, B43_HTTAB8(13, 0x73 + (i * 4)),
196				tmp & 0xFF);
197	}
198
199	b43_phy_write(dev, 0x017e, 0x3830);
200}
201
202static int b43_phy_ht_set_channel(struct b43_wldev *dev,
203				  struct ieee80211_channel *channel,
204				  enum nl80211_channel_type channel_type)
205{
206	struct b43_phy *phy = &dev->phy;
207
208	const struct b43_phy_ht_channeltab_e_radio2059 *chent_r2059 = NULL;
209
210	if (phy->radio_ver == 0x2059) {
211		chent_r2059 = b43_phy_ht_get_channeltab_e_r2059(dev,
212							channel->center_freq);
213		if (!chent_r2059)
214			return -ESRCH;
215	} else {
216		return -ESRCH;
217	}
218
219	/* TODO: In case of N-PHY some bandwidth switching goes here */
220
221	if (phy->radio_ver == 0x2059) {
222		b43_radio_2059_channel_setup(dev, chent_r2059);
223		b43_phy_ht_channel_setup(dev, &(chent_r2059->phy_regs),
224					 channel);
225	} else {
226		return -ESRCH;
227	}
228
229	return 0;
230}
231
232/**************************************************
233 * Basic PHY ops.
234 **************************************************/
235
236static int b43_phy_ht_op_allocate(struct b43_wldev *dev)
237{
238	struct b43_phy_ht *phy_ht;
239
240	phy_ht = kzalloc(sizeof(*phy_ht), GFP_KERNEL);
241	if (!phy_ht)
242		return -ENOMEM;
243	dev->phy.ht = phy_ht;
244
245	return 0;
246}
247
248static void b43_phy_ht_op_prepare_structs(struct b43_wldev *dev)
249{
250	struct b43_phy *phy = &dev->phy;
251	struct b43_phy_ht *phy_ht = phy->ht;
252
253	memset(phy_ht, 0, sizeof(*phy_ht));
254}
255
256static int b43_phy_ht_op_init(struct b43_wldev *dev)
257{
258	b43_phy_ht_tables_init(dev);
259
260	return 0;
261}
262
263static void b43_phy_ht_op_free(struct b43_wldev *dev)
264{
265	struct b43_phy *phy = &dev->phy;
266	struct b43_phy_ht *phy_ht = phy->ht;
267
268	kfree(phy_ht);
269	phy->ht = NULL;
270}
271
272/* http://bcm-v4.sipsolutions.net/802.11/Radio/Switch%20Radio */
273static void b43_phy_ht_op_software_rfkill(struct b43_wldev *dev,
274					bool blocked)
275{
276	if (b43_read32(dev, B43_MMIO_MACCTL) & B43_MACCTL_ENABLED)
277		b43err(dev->wl, "MAC not suspended\n");
278
279	/* In the following PHY ops we copy wl's dummy behaviour.
280	 * TODO: Find out if reads (currently hidden in masks/masksets) are
281	 * needed and replace following ops with just writes or w&r.
282	 * Note: B43_PHY_HT_RF_CTL1 register is tricky, wrong operation can
283	 * cause delayed (!) machine lock up. */
284	if (blocked) {
285		b43_phy_mask(dev, B43_PHY_HT_RF_CTL1, 0);
286	} else {
287		b43_phy_mask(dev, B43_PHY_HT_RF_CTL1, 0);
288		b43_phy_maskset(dev, B43_PHY_HT_RF_CTL1, 0, 0x1);
289		b43_phy_mask(dev, B43_PHY_HT_RF_CTL1, 0);
290		b43_phy_maskset(dev, B43_PHY_HT_RF_CTL1, 0, 0x2);
291
292		if (dev->phy.radio_ver == 0x2059)
293			b43_radio_2059_init(dev);
294		else
295			B43_WARN_ON(1);
296
297		b43_switch_channel(dev, dev->phy.channel);
298	}
299}
300
301static void b43_phy_ht_op_switch_analog(struct b43_wldev *dev, bool on)
302{
303	if (on) {
304		b43_phy_write(dev, B43_PHY_HT_AFE_CTL2, 0x00cd);
305		b43_phy_write(dev, B43_PHY_HT_AFE_CTL1, 0x0000);
306		b43_phy_write(dev, B43_PHY_HT_AFE_CTL4, 0x00cd);
307		b43_phy_write(dev, B43_PHY_HT_AFE_CTL3, 0x0000);
308		b43_phy_write(dev, B43_PHY_HT_AFE_CTL6, 0x00cd);
309		b43_phy_write(dev, B43_PHY_HT_AFE_CTL5, 0x0000);
310	} else {
311		b43_phy_write(dev, B43_PHY_HT_AFE_CTL1, 0x07ff);
312		b43_phy_write(dev, B43_PHY_HT_AFE_CTL2, 0x00fd);
313		b43_phy_write(dev, B43_PHY_HT_AFE_CTL3, 0x07ff);
314		b43_phy_write(dev, B43_PHY_HT_AFE_CTL4, 0x00fd);
315		b43_phy_write(dev, B43_PHY_HT_AFE_CTL5, 0x07ff);
316		b43_phy_write(dev, B43_PHY_HT_AFE_CTL6, 0x00fd);
317	}
318}
319
320static int b43_phy_ht_op_switch_channel(struct b43_wldev *dev,
321					unsigned int new_channel)
322{
323	struct ieee80211_channel *channel = dev->wl->hw->conf.channel;
324	enum nl80211_channel_type channel_type = dev->wl->hw->conf.channel_type;
325
326	if (b43_current_band(dev->wl) == IEEE80211_BAND_2GHZ) {
327		if ((new_channel < 1) || (new_channel > 14))
328			return -EINVAL;
329	} else {
330		return -EINVAL;
331	}
332
333	return b43_phy_ht_set_channel(dev, channel, channel_type);
334}
335
336static unsigned int b43_phy_ht_op_get_default_chan(struct b43_wldev *dev)
337{
338	if (b43_current_band(dev->wl) == IEEE80211_BAND_2GHZ)
339		return 11;
340	return 36;
341}
342
343/**************************************************
344 * R/W ops.
345 **************************************************/
346
347static u16 b43_phy_ht_op_read(struct b43_wldev *dev, u16 reg)
348{
349	b43_write16(dev, B43_MMIO_PHY_CONTROL, reg);
350	return b43_read16(dev, B43_MMIO_PHY_DATA);
351}
352
353static void b43_phy_ht_op_write(struct b43_wldev *dev, u16 reg, u16 value)
354{
355	b43_write16(dev, B43_MMIO_PHY_CONTROL, reg);
356	b43_write16(dev, B43_MMIO_PHY_DATA, value);
357}
358
359static void b43_phy_ht_op_maskset(struct b43_wldev *dev, u16 reg, u16 mask,
360				 u16 set)
361{
362	b43_write16(dev, B43_MMIO_PHY_CONTROL, reg);
363	b43_write16(dev, B43_MMIO_PHY_DATA,
364		    (b43_read16(dev, B43_MMIO_PHY_DATA) & mask) | set);
365}
366
367static u16 b43_phy_ht_op_radio_read(struct b43_wldev *dev, u16 reg)
368{
369	/* HT-PHY needs 0x200 for read access */
370	reg |= 0x200;
371
372	b43_write16(dev, B43_MMIO_RADIO24_CONTROL, reg);
373	return b43_read16(dev, B43_MMIO_RADIO24_DATA);
374}
375
376static void b43_phy_ht_op_radio_write(struct b43_wldev *dev, u16 reg,
377				      u16 value)
378{
379	b43_write16(dev, B43_MMIO_RADIO24_CONTROL, reg);
380	b43_write16(dev, B43_MMIO_RADIO24_DATA, value);
381}
382
383static enum b43_txpwr_result
384b43_phy_ht_op_recalc_txpower(struct b43_wldev *dev, bool ignore_tssi)
385{
386	return B43_TXPWR_RES_DONE;
387}
388
389static void b43_phy_ht_op_adjust_txpower(struct b43_wldev *dev)
390{
391}
392
393/**************************************************
394 * PHY ops struct.
395 **************************************************/
396
397const struct b43_phy_operations b43_phyops_ht = {
398	.allocate		= b43_phy_ht_op_allocate,
399	.free			= b43_phy_ht_op_free,
400	.prepare_structs	= b43_phy_ht_op_prepare_structs,
401	.init			= b43_phy_ht_op_init,
402	.phy_read		= b43_phy_ht_op_read,
403	.phy_write		= b43_phy_ht_op_write,
404	.phy_maskset		= b43_phy_ht_op_maskset,
405	.radio_read		= b43_phy_ht_op_radio_read,
406	.radio_write		= b43_phy_ht_op_radio_write,
407	.software_rfkill	= b43_phy_ht_op_software_rfkill,
408	.switch_analog		= b43_phy_ht_op_switch_analog,
409	.switch_channel		= b43_phy_ht_op_switch_channel,
410	.get_default_chan	= b43_phy_ht_op_get_default_chan,
411	.recalc_txpower		= b43_phy_ht_op_recalc_txpower,
412	.adjust_txpower		= b43_phy_ht_op_adjust_txpower,
413};