init.c 41 KB
Newer Older
Kalle Valo's avatar
Kalle Valo committed
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17

/*
 * Copyright (c) 2011 Atheros Communications Inc.
 *
 * Permission to use, copy, modify, and/or distribute this software for any
 * purpose with or without fee is hereby granted, provided that the above
 * copyright notice and this permission notice appear in all copies.
 *
 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
 */

18
#include <linux/moduleparam.h>
19
#include <linux/errno.h>
Kalle Valo's avatar
Kalle Valo committed
20
#include <linux/export.h>
21
#include <linux/of.h>
Kalle Valo's avatar
Kalle Valo committed
22
#include <linux/mmc/sdio_func.h>
Kalle Valo's avatar
Kalle Valo committed
23

Kalle Valo's avatar
Kalle Valo committed
24
25
26
27
28
29
#include "core.h"
#include "cfg80211.h"
#include "target.h"
#include "debug.h"
#include "hif-ops.h"

30
31
static const struct ath6kl_hw hw_list[] = {
	{
32
		.id				= AR6003_HW_2_0_VERSION,
33
		.name				= "ar6003 hw 2.0",
34
35
36
37
		.dataset_patch_addr		= 0x57e884,
		.app_load_addr			= 0x543180,
		.board_ext_data_addr		= 0x57e500,
		.reserved_ram_size		= 6912,
38
39
		.refclk_hz			= 26000000,
		.uarttx_pin			= 8,
40
41
42

		/* hw2.0 needs override address hardcoded */
		.app_start_override_addr	= 0x944C00,
43

44
45
46
47
48
49
50
51
		.fw = {
			.dir		= AR6003_HW_2_0_FW_DIR,
			.otp		= AR6003_HW_2_0_OTP_FILE,
			.fw		= AR6003_HW_2_0_FIRMWARE_FILE,
			.tcmd		= AR6003_HW_2_0_TCMD_FIRMWARE_FILE,
			.patch		= AR6003_HW_2_0_PATCH_FILE,
		},

52
53
		.fw_board		= AR6003_HW_2_0_BOARD_DATA_FILE,
		.fw_default_board	= AR6003_HW_2_0_DEFAULT_BOARD_DATA_FILE,
54
55
	},
	{
56
		.id				= AR6003_HW_2_1_1_VERSION,
57
		.name				= "ar6003 hw 2.1.1",
58
59
60
61
		.dataset_patch_addr		= 0x57ff74,
		.app_load_addr			= 0x1234,
		.board_ext_data_addr		= 0x542330,
		.reserved_ram_size		= 512,
62
63
		.refclk_hz			= 26000000,
		.uarttx_pin			= 8,
64
		.testscript_addr		= 0x57ef74,
65

66
67
68
69
70
71
		.fw = {
			.dir		= AR6003_HW_2_1_1_FW_DIR,
			.otp		= AR6003_HW_2_1_1_OTP_FILE,
			.fw		= AR6003_HW_2_1_1_FIRMWARE_FILE,
			.tcmd		= AR6003_HW_2_1_1_TCMD_FIRMWARE_FILE,
			.patch		= AR6003_HW_2_1_1_PATCH_FILE,
72
73
			.utf		= AR6003_HW_2_1_1_UTF_FIRMWARE_FILE,
			.testscript	= AR6003_HW_2_1_1_TESTSCRIPT_FILE,
74
75
		},

76
77
		.fw_board		= AR6003_HW_2_1_1_BOARD_DATA_FILE,
		.fw_default_board	= AR6003_HW_2_1_1_DEFAULT_BOARD_DATA_FILE,
78
79
	},
	{
80
		.id				= AR6004_HW_1_0_VERSION,
81
		.name				= "ar6004 hw 1.0",
82
83
84
85
		.dataset_patch_addr		= 0x57e884,
		.app_load_addr			= 0x1234,
		.board_ext_data_addr		= 0x437000,
		.reserved_ram_size		= 19456,
86
		.board_addr			= 0x433900,
87
88
		.refclk_hz			= 26000000,
		.uarttx_pin			= 11,
89

90
91
92
93
94
		.fw = {
			.dir		= AR6004_HW_1_0_FW_DIR,
			.fw		= AR6004_HW_1_0_FIRMWARE_FILE,
		},

95
96
		.fw_board		= AR6004_HW_1_0_BOARD_DATA_FILE,
		.fw_default_board	= AR6004_HW_1_0_DEFAULT_BOARD_DATA_FILE,
97
98
	},
	{
99
		.id				= AR6004_HW_1_1_VERSION,
100
		.name				= "ar6004 hw 1.1",
101
102
103
104
		.dataset_patch_addr		= 0x57e884,
		.app_load_addr			= 0x1234,
		.board_ext_data_addr		= 0x437000,
		.reserved_ram_size		= 11264,
105
		.board_addr			= 0x43d400,
106
107
		.refclk_hz			= 40000000,
		.uarttx_pin			= 11,
108

109
110
111
112
113
		.fw = {
			.dir		= AR6004_HW_1_1_FW_DIR,
			.fw		= AR6004_HW_1_1_FIRMWARE_FILE,
		},

114
115
		.fw_board		= AR6004_HW_1_1_BOARD_DATA_FILE,
		.fw_default_board	= AR6004_HW_1_1_DEFAULT_BOARD_DATA_FILE,
116
117
118
	},
};

Kalle Valo's avatar
Kalle Valo committed
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
/*
 * Include definitions here that can be used to tune the WLAN module
 * behavior. Different customers can tune the behavior as per their needs,
 * here.
 */

/*
 * This configuration item enable/disable keepalive support.
 * Keepalive support: In the absence of any data traffic to AP, null
 * frames will be sent to the AP at periodic interval, to keep the association
 * active. This configuration item defines the periodic interval.
 * Use value of zero to disable keepalive support
 * Default: 60 seconds
 */
#define WLAN_CONFIG_KEEP_ALIVE_INTERVAL 60

/*
 * This configuration item sets the value of disconnect timeout
 * Firmware delays sending the disconnec event to the host for this
 * timeout after is gets disconnected from the current AP.
 * If the firmware successly roams within the disconnect timeout
 * it sends a new connect event
 */
#define WLAN_CONFIG_DISCONNECT_TIMEOUT 10


#define ATH6KL_DATA_OFFSET    64
struct sk_buff *ath6kl_buf_alloc(int size)
{
	struct sk_buff *skb;
	u16 reserved;

	/* Add chacheline space at front and back of buffer */
	reserved = (2 * L1_CACHE_BYTES) + ATH6KL_DATA_OFFSET +
153
		   sizeof(struct htc_packet) + ATH6KL_HTC_ALIGN_BYTES;
Kalle Valo's avatar
Kalle Valo committed
154
155
156
157
158
159
160
	skb = dev_alloc_skb(size + reserved);

	if (skb)
		skb_reserve(skb, reserved - L1_CACHE_BYTES);
	return skb;
}

161
void ath6kl_init_profile_info(struct ath6kl_vif *vif)
Kalle Valo's avatar
Kalle Valo committed
162
{
163
164
165
166
167
168
169
170
171
	vif->ssid_len = 0;
	memset(vif->ssid, 0, sizeof(vif->ssid));

	vif->dot11_auth_mode = OPEN_AUTH;
	vif->auth_mode = NONE_AUTH;
	vif->prwise_crypto = NONE_CRYPT;
	vif->prwise_crypto_len = 0;
	vif->grp_crypto = NONE_CRYPT;
	vif->grp_crypto_len = 0;
172
	memset(vif->wep_key_list, 0, sizeof(vif->wep_key_list));
173
174
	memset(vif->req_bssid, 0, sizeof(vif->req_bssid));
	memset(vif->bssid, 0, sizeof(vif->bssid));
175
	vif->bss_ch = 0;
Kalle Valo's avatar
Kalle Valo committed
176
177
178
179
180
181
182
183
184
185
}

static int ath6kl_set_host_app_area(struct ath6kl *ar)
{
	u32 address, data;
	struct host_app_area host_app_area;

	/* Fetch the address of the host_app_area_s
	 * instance in the host interest area */
	address = ath6kl_get_hi_item_addr(ar, HI_ITEM(hi_app_host_interest));
186
	address = TARG_VTOP(ar->target_type, address);
Kalle Valo's avatar
Kalle Valo committed
187

188
	if (ath6kl_diag_read32(ar, address, &data))
Kalle Valo's avatar
Kalle Valo committed
189
190
		return -EIO;

191
	address = TARG_VTOP(ar->target_type, data);
192
	host_app_area.wmi_protocol_ver = cpu_to_le32(WMI_PROTOCOL_VERSION);
193
194
	if (ath6kl_diag_write(ar, address, (u8 *) &host_app_area,
			      sizeof(struct host_app_area)))
Kalle Valo's avatar
Kalle Valo committed
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
		return -EIO;

	return 0;
}

static inline void set_ac2_ep_map(struct ath6kl *ar,
				  u8 ac,
				  enum htc_endpoint_id ep)
{
	ar->ac2ep_map[ac] = ep;
	ar->ep2ac_map[ep] = ac;
}

/* connect to a service */
static int ath6kl_connectservice(struct ath6kl *ar,
				 struct htc_service_connect_req  *con_req,
				 char *desc)
{
	int status;
	struct htc_service_connect_resp response;

	memset(&response, 0, sizeof(response));

218
	status = ath6kl_htc_conn_service(ar->htc_target, con_req, &response);
Kalle Valo's avatar
Kalle Valo committed
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
	if (status) {
		ath6kl_err("failed to connect to %s service status:%d\n",
			   desc, status);
		return status;
	}

	switch (con_req->svc_id) {
	case WMI_CONTROL_SVC:
		if (test_bit(WMI_ENABLED, &ar->flag))
			ath6kl_wmi_set_control_ep(ar->wmi, response.endpoint);
		ar->ctrl_ep = response.endpoint;
		break;
	case WMI_DATA_BE_SVC:
		set_ac2_ep_map(ar, WMM_AC_BE, response.endpoint);
		break;
	case WMI_DATA_BK_SVC:
		set_ac2_ep_map(ar, WMM_AC_BK, response.endpoint);
		break;
	case WMI_DATA_VI_SVC:
		set_ac2_ep_map(ar, WMM_AC_VI, response.endpoint);
		break;
	case WMI_DATA_VO_SVC:
		set_ac2_ep_map(ar, WMM_AC_VO, response.endpoint);
		break;
	default:
		ath6kl_err("service id is not mapped %d\n", con_req->svc_id);
		return -EINVAL;
	}

	return 0;
}

static int ath6kl_init_service_ep(struct ath6kl *ar)
{
	struct htc_service_connect_req connect;

	memset(&connect, 0, sizeof(connect));

	/* these fields are the same for all service endpoints */
	connect.ep_cb.rx = ath6kl_rx;
	connect.ep_cb.rx_refill = ath6kl_rx_refill;
	connect.ep_cb.tx_full = ath6kl_tx_queue_full;

	/*
	 * Set the max queue depth so that our ath6kl_tx_queue_full handler
	 * gets called.
	*/
	connect.max_txq_depth = MAX_DEFAULT_SEND_QUEUE_DEPTH;
	connect.ep_cb.rx_refill_thresh = ATH6KL_MAX_RX_BUFFERS / 4;
	if (!connect.ep_cb.rx_refill_thresh)
		connect.ep_cb.rx_refill_thresh++;

	/* connect to control service */
	connect.svc_id = WMI_CONTROL_SVC;
	if (ath6kl_connectservice(ar, &connect, "WMI CONTROL"))
		return -EIO;

	connect.flags |= HTC_FLGS_TX_BNDL_PAD_EN;

	/*
	 * Limit the HTC message size on the send path, although e can
	 * receive A-MSDU frames of 4K, we will only send ethernet-sized
	 * (802.3) frames on the send path.
	 */
	connect.max_rxmsg_sz = WMI_MAX_TX_DATA_FRAME_LENGTH;

	/*
	 * To reduce the amount of committed memory for larger A_MSDU
	 * frames, use the recv-alloc threshold mechanism for larger
	 * packets.
	 */
	connect.ep_cb.rx_alloc_thresh = ATH6KL_BUFFER_SIZE;
	connect.ep_cb.rx_allocthresh = ath6kl_alloc_amsdu_rxbuf;

	/*
	 * For the remaining data services set the connection flag to
	 * reduce dribbling, if configured to do so.
	 */
	connect.conn_flags |= HTC_CONN_FLGS_REDUCE_CRED_DRIB;
	connect.conn_flags &= ~HTC_CONN_FLGS_THRESH_MASK;
	connect.conn_flags |= HTC_CONN_FLGS_THRESH_LVL_HALF;

	connect.svc_id = WMI_DATA_BE_SVC;

	if (ath6kl_connectservice(ar, &connect, "WMI DATA BE"))
		return -EIO;

	/* connect to back-ground map this to WMI LOW_PRI */
	connect.svc_id = WMI_DATA_BK_SVC;
	if (ath6kl_connectservice(ar, &connect, "WMI DATA BK"))
		return -EIO;

	/* connect to Video service, map this to to HI PRI */
	connect.svc_id = WMI_DATA_VI_SVC;
	if (ath6kl_connectservice(ar, &connect, "WMI DATA VI"))
		return -EIO;

	/*
	 * Connect to VO service, this is currently not mapped to a WMI
	 * priority stream due to historical reasons. WMI originally
	 * defined 3 priorities over 3 mailboxes We can change this when
	 * WMI is reworked so that priorities are not dependent on
	 * mailboxes.
	 */
	connect.svc_id = WMI_DATA_VO_SVC;
	if (ath6kl_connectservice(ar, &connect, "WMI DATA VO"))
		return -EIO;

	return 0;
}

330
void ath6kl_init_control_info(struct ath6kl_vif *vif)
Kalle Valo's avatar
Kalle Valo committed
331
{
332
	ath6kl_init_profile_info(vif);
333
	vif->def_txkey_index = 0;
334
	memset(vif->wep_key_list, 0, sizeof(vif->wep_key_list));
335
	vif->ch_hint = 0;
Kalle Valo's avatar
Kalle Valo committed
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
}

/*
 * Set HTC/Mbox operational parameters, this can only be called when the
 * target is in the BMI phase.
 */
static int ath6kl_set_htc_params(struct ath6kl *ar, u32 mbox_isr_yield_val,
				 u8 htc_ctrl_buf)
{
	int status;
	u32 blk_size;

	blk_size = ar->mbox_info.block_size;

	if (htc_ctrl_buf)
		blk_size |=  ((u32)htc_ctrl_buf) << 16;

	/* set the host interest area for the block size */
	status = ath6kl_bmi_write(ar,
			ath6kl_get_hi_item_addr(ar,
			HI_ITEM(hi_mbox_io_block_sz)),
			(u8 *)&blk_size,
			4);
	if (status) {
		ath6kl_err("bmi_write_memory for IO block size failed\n");
		goto out;
	}

	ath6kl_dbg(ATH6KL_DBG_TRC, "block size set: %d (target addr:0x%X)\n",
		   blk_size,
		   ath6kl_get_hi_item_addr(ar, HI_ITEM(hi_mbox_io_block_sz)));

	if (mbox_isr_yield_val) {
		/* set the host interest area for the mbox ISR yield limit */
		status = ath6kl_bmi_write(ar,
				ath6kl_get_hi_item_addr(ar,
				HI_ITEM(hi_mbox_isr_yield_limit)),
				(u8 *)&mbox_isr_yield_val,
				4);
		if (status) {
			ath6kl_err("bmi_write_memory for yield limit failed\n");
			goto out;
		}
	}

out:
	return status;
}

385
static int ath6kl_target_config_wlan_params(struct ath6kl *ar, int idx)
Kalle Valo's avatar
Kalle Valo committed
386
387
{
	int status = 0;
388
	int ret;
Kalle Valo's avatar
Kalle Valo committed
389
390
391
392
393
394

	/*
	 * Configure the device for rx dot11 header rules. "0,0" are the
	 * default values. Required if checksum offload is needed. Set
	 * RxMetaVersion to 2.
	 */
395
	if (ath6kl_wmi_set_rx_frame_format_cmd(ar->wmi, idx,
Kalle Valo's avatar
Kalle Valo committed
396
397
398
399
400
401
					       ar->rx_meta_ver, 0, 0)) {
		ath6kl_err("unable to set the rx frame format\n");
		status = -EIO;
	}

	if (ar->conf_flags & ATH6KL_CONF_IGNORE_PS_FAIL_EVT_IN_SCAN)
402
		if ((ath6kl_wmi_pmparams_cmd(ar->wmi, idx, 0, 1, 0, 0, 1,
Kalle Valo's avatar
Kalle Valo committed
403
404
405
406
407
408
		     IGNORE_POWER_SAVE_FAIL_EVENT_DURING_SCAN)) != 0) {
			ath6kl_err("unable to set power save fail event policy\n");
			status = -EIO;
		}

	if (!(ar->conf_flags & ATH6KL_CONF_IGNORE_ERP_BARKER))
409
		if ((ath6kl_wmi_set_lpreamble_cmd(ar->wmi, idx, 0,
Kalle Valo's avatar
Kalle Valo committed
410
411
412
413
414
		     WMI_DONOT_IGNORE_BARKER_IN_ERP)) != 0) {
			ath6kl_err("unable to set barker preamble policy\n");
			status = -EIO;
		}

415
	if (ath6kl_wmi_set_keepalive_cmd(ar->wmi, idx,
Kalle Valo's avatar
Kalle Valo committed
416
417
418
419
420
			WLAN_CONFIG_KEEP_ALIVE_INTERVAL)) {
		ath6kl_err("unable to set keep alive interval\n");
		status = -EIO;
	}

421
	if (ath6kl_wmi_disctimeout_cmd(ar->wmi, idx,
Kalle Valo's avatar
Kalle Valo committed
422
423
424
425
426
427
			WLAN_CONFIG_DISCONNECT_TIMEOUT)) {
		ath6kl_err("unable to set disconnect timeout\n");
		status = -EIO;
	}

	if (!(ar->conf_flags & ATH6KL_CONF_ENABLE_TX_BURST))
428
		if (ath6kl_wmi_set_wmm_txop(ar->wmi, idx, WMI_TXOP_DISABLED)) {
Kalle Valo's avatar
Kalle Valo committed
429
430
431
432
			ath6kl_err("unable to set txop bursting\n");
			status = -EIO;
		}

433
	if (ar->p2p && (ar->vif_max == 1 || idx)) {
434
		ret = ath6kl_wmi_info_req_cmd(ar->wmi, idx,
435
436
437
438
439
440
441
					      P2P_FLAG_CAPABILITIES_REQ |
					      P2P_FLAG_MACADDR_REQ |
					      P2P_FLAG_HMODEL_REQ);
		if (ret) {
			ath6kl_dbg(ATH6KL_DBG_TRC, "failed to request P2P "
				   "capabilities (%d) - assuming P2P not "
				   "supported\n", ret);
442
			ar->p2p = false;
443
444
445
		}
	}

446
	if (ar->p2p && (ar->vif_max == 1 || idx)) {
447
		/* Enable Probe Request reporting for P2P */
448
		ret = ath6kl_wmi_probe_report_req_cmd(ar->wmi, idx, true);
449
450
451
452
		if (ret) {
			ath6kl_dbg(ATH6KL_DBG_TRC, "failed to enable Probe "
				   "Request reporting (%d)\n", ret);
		}
453
454
	}

Kalle Valo's avatar
Kalle Valo committed
455
456
457
458
459
460
	return status;
}

int ath6kl_configure_target(struct ath6kl *ar)
{
	u32 param, ram_reserved_size;
461
	u8 fw_iftype, fw_mode = 0, fw_submode = 0;
462
	int i, status;
Kalle Valo's avatar
Kalle Valo committed
463

464
	param = !!(ar->conf_flags & ATH6KL_CONF_UART_DEBUG);
465
466
467
468
469
470
	if (ath6kl_bmi_write(ar, ath6kl_get_hi_item_addr(ar,
			     HI_ITEM(hi_serial_enable)), (u8 *)&param, 4)) {
		ath6kl_err("bmi_write_memory for uart debug failed\n");
		return -EIO;
	}

471
472
473
474
475
476
477
478
	/*
	 * Note: Even though the firmware interface type is
	 * chosen as BSS_STA for all three interfaces, can
	 * be configured to IBSS/AP as long as the fw submode
	 * remains normal mode (0 - AP, STA and IBSS). But
	 * due to an target assert in firmware only one interface is
	 * configured for now.
	 */
479
	fw_iftype = HI_OPTION_FW_MODE_BSS_STA;
Kalle Valo's avatar
Kalle Valo committed
480

481
	for (i = 0; i < ar->vif_max; i++)
482
483
484
		fw_mode |= fw_iftype << (i * HI_OPTION_FW_MODE_BITS);

	/*
485
486
487
488
	 * By default, submodes :
	 *		vif[0] - AP/STA/IBSS
	 *		vif[1] - "P2P dev"/"P2P GO"/"P2P Client"
	 *		vif[2] - "P2P dev"/"P2P GO"/"P2P Client"
489
	 */
490
491
492
493
494

	for (i = 0; i < ar->max_norm_iface; i++)
		fw_submode |= HI_OPTION_FW_SUBMODE_NONE <<
			      (i * HI_OPTION_FW_SUBMODE_BITS);

495
	for (i = ar->max_norm_iface; i < ar->vif_max; i++)
496
497
		fw_submode |= HI_OPTION_FW_SUBMODE_P2PDEV <<
			      (i * HI_OPTION_FW_SUBMODE_BITS);
498

499
	if (ar->p2p && ar->vif_max == 1)
500
501
		fw_submode = HI_OPTION_FW_SUBMODE_P2PDEV;

Kalle Valo's avatar
Kalle Valo committed
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
	param = HTC_PROTOCOL_VERSION;
	if (ath6kl_bmi_write(ar,
			     ath6kl_get_hi_item_addr(ar,
			     HI_ITEM(hi_app_host_interest)),
			     (u8 *)&param, 4) != 0) {
		ath6kl_err("bmi_write_memory for htc version failed\n");
		return -EIO;
	}

	/* set the firmware mode to STA/IBSS/AP */
	param = 0;

	if (ath6kl_bmi_read(ar,
			    ath6kl_get_hi_item_addr(ar,
			    HI_ITEM(hi_option_flag)),
			    (u8 *)&param, 4) != 0) {
		ath6kl_err("bmi_read_memory for setting fwmode failed\n");
		return -EIO;
	}

522
	param |= (ar->vif_max << HI_OPTION_NUM_DEV_SHIFT);
523
524
525
	param |= fw_mode << HI_OPTION_FW_MODE_SHIFT;
	param |= fw_submode << HI_OPTION_FW_SUBMODE_SHIFT;

Kalle Valo's avatar
Kalle Valo committed
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
	param |= (0 << HI_OPTION_MAC_ADDR_METHOD_SHIFT);
	param |= (0 << HI_OPTION_FW_BRIDGE_SHIFT);

	if (ath6kl_bmi_write(ar,
			     ath6kl_get_hi_item_addr(ar,
			     HI_ITEM(hi_option_flag)),
			     (u8 *)&param,
			     4) != 0) {
		ath6kl_err("bmi_write_memory for setting fwmode failed\n");
		return -EIO;
	}

	ath6kl_dbg(ATH6KL_DBG_TRC, "firmware mode set\n");

	/*
	 * Hardcode the address use for the extended board data
	 * Ideally this should be pre-allocate by the OS at boot time
	 * But since it is a new feature and board data is loaded
	 * at init time, we have to workaround this from host.
	 * It is difficult to patch the firmware boot code,
	 * but possible in theory.
	 */

549
550
	param = ar->hw.board_ext_data_addr;
	ram_reserved_size = ar->hw.reserved_ram_size;
Kalle Valo's avatar
Kalle Valo committed
551

552
553
554
555
556
557
558
559
560
561
562
563
	if (ath6kl_bmi_write(ar, ath6kl_get_hi_item_addr(ar,
					HI_ITEM(hi_board_ext_data)),
			     (u8 *)&param, 4) != 0) {
		ath6kl_err("bmi_write_memory for hi_board_ext_data failed\n");
		return -EIO;
	}

	if (ath6kl_bmi_write(ar, ath6kl_get_hi_item_addr(ar,
					HI_ITEM(hi_end_ram_reserve_sz)),
			     (u8 *)&ram_reserved_size, 4) != 0) {
		ath6kl_err("bmi_write_memory for hi_end_ram_reserve_sz failed\n");
		return -EIO;
Kalle Valo's avatar
Kalle Valo committed
564
565
566
567
568
569
570
	}

	/* set the block size for the target */
	if (ath6kl_set_htc_params(ar, MBOX_YIELD_LIMIT, 0))
		/* use default number of control buffers */
		return -EIO;

571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
	/* Configure GPIO AR600x UART */
	param = ar->hw.uarttx_pin;
	status = ath6kl_bmi_write(ar,
				ath6kl_get_hi_item_addr(ar,
				HI_ITEM(hi_dbg_uart_txpin)),
				(u8 *)&param, 4);
	if (status)
		return status;

	/* Configure target refclk_hz */
	param =  ar->hw.refclk_hz;
	status = ath6kl_bmi_write(ar,
				ath6kl_get_hi_item_addr(ar,
				HI_ITEM(hi_refclk_hz)),
				(u8 *)&param, 4);
	if (status)
		return status;

Kalle Valo's avatar
Kalle Valo committed
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
	return 0;
}

/* firmware upload */
static int ath6kl_get_fw(struct ath6kl *ar, const char *filename,
			 u8 **fw, size_t *fw_len)
{
	const struct firmware *fw_entry;
	int ret;

	ret = request_firmware(&fw_entry, filename, ar->dev);
	if (ret)
		return ret;

	*fw_len = fw_entry->size;
	*fw = kmemdup(fw_entry->data, fw_entry->size, GFP_KERNEL);

	if (*fw == NULL)
		ret = -ENOMEM;

	release_firmware(fw_entry);

	return ret;
}

614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
#ifdef CONFIG_OF
/*
 * Check the device tree for a board-id and use it to construct
 * the pathname to the firmware file.  Used (for now) to find a
 * fallback to the "bdata.bin" file--typically a symlink to the
 * appropriate board-specific file.
 */
static bool check_device_tree(struct ath6kl *ar)
{
	static const char *board_id_prop = "atheros,board-id";
	struct device_node *node;
	char board_filename[64];
	const char *board_id;
	int ret;

	for_each_compatible_node(node, NULL, "atheros,ath6kl") {
		board_id = of_get_property(node, board_id_prop, NULL);
		if (board_id == NULL) {
			ath6kl_warn("No \"%s\" property on %s node.\n",
				    board_id_prop, node->name);
			continue;
		}
		snprintf(board_filename, sizeof(board_filename),
637
			 "%s/bdata.%s.bin", ar->hw.fw.dir, board_id);
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656

		ret = ath6kl_get_fw(ar, board_filename, &ar->fw_board,
				    &ar->fw_board_len);
		if (ret) {
			ath6kl_err("Failed to get DT board file %s: %d\n",
				   board_filename, ret);
			continue;
		}
		return true;
	}
	return false;
}
#else
static bool check_device_tree(struct ath6kl *ar)
{
	return false;
}
#endif /* CONFIG_OF */

Kalle Valo's avatar
Kalle Valo committed
657
658
659
660
661
static int ath6kl_fetch_board_file(struct ath6kl *ar)
{
	const char *filename;
	int ret;

662
663
664
	if (ar->fw_board != NULL)
		return 0;

665
666
667
668
	if (WARN_ON(ar->hw.fw_board == NULL))
		return -EINVAL;

	filename = ar->hw.fw_board;
Kalle Valo's avatar
Kalle Valo committed
669
670
671
672
673
674
675
676

	ret = ath6kl_get_fw(ar, filename, &ar->fw_board,
			    &ar->fw_board_len);
	if (ret == 0) {
		/* managed to get proper board file */
		return 0;
	}

677
678
679
680
681
	if (check_device_tree(ar)) {
		/* got board file from device tree */
		return 0;
	}

Kalle Valo's avatar
Kalle Valo committed
682
683
684
685
	/* there was no proper board file, try to use default instead */
	ath6kl_warn("Failed to get board file %s (%d), trying to find default board file.\n",
		    filename, ret);

686
	filename = ar->hw.fw_default_board;
Kalle Valo's avatar
Kalle Valo committed
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701

	ret = ath6kl_get_fw(ar, filename, &ar->fw_board,
			    &ar->fw_board_len);
	if (ret) {
		ath6kl_err("Failed to get default board file %s: %d\n",
			   filename, ret);
		return ret;
	}

	ath6kl_warn("WARNING! No proper board file was not found, instead using a default board file.\n");
	ath6kl_warn("Most likely your hardware won't work as specified. Install correct board file!\n");

	return 0;
}

702
703
static int ath6kl_fetch_otp_file(struct ath6kl *ar)
{
704
	char filename[100];
705
706
707
708
709
	int ret;

	if (ar->fw_otp != NULL)
		return 0;

710
	if (ar->hw.fw.otp == NULL) {
711
712
		ath6kl_dbg(ATH6KL_DBG_BOOT,
			   "no OTP file configured for this hw\n");
713
714
715
		return 0;
	}

716
717
	snprintf(filename, sizeof(filename), "%s/%s",
		 ar->hw.fw.dir, ar->hw.fw.otp);
718

719
720
721
722
723
724
725
726
727
728
729
	ret = ath6kl_get_fw(ar, filename, &ar->fw_otp,
			    &ar->fw_otp_len);
	if (ret) {
		ath6kl_err("Failed to get OTP file %s: %d\n",
			   filename, ret);
		return ret;
	}

	return 0;
}

730
static int ath6kl_fetch_testmode_file(struct ath6kl *ar)
731
{
732
	char filename[100];
733
734
	int ret;

735
	if (ar->testmode == 0)
736
737
		return 0;

738
	ath6kl_dbg(ATH6KL_DBG_BOOT, "testmode %d\n", ar->testmode);
739

740
741
742
743
744
	if (ar->testmode == 2) {
		if (ar->hw.fw.utf == NULL) {
			ath6kl_warn("testmode 2 not supported\n");
			return -EOPNOTSUPP;
		}
745

746
747
748
749
750
751
		snprintf(filename, sizeof(filename), "%s/%s",
			 ar->hw.fw.dir, ar->hw.fw.utf);
	} else {
		if (ar->hw.fw.tcmd == NULL) {
			ath6kl_warn("testmode 1 not supported\n");
			return -EOPNOTSUPP;
752
		}
753

754
755
		snprintf(filename, sizeof(filename), "%s/%s",
			 ar->hw.fw.dir, ar->hw.fw.tcmd);
756
757
	}

758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
	set_bit(TESTMODE, &ar->flag);

	ret = ath6kl_get_fw(ar, filename, &ar->fw, &ar->fw_len);
	if (ret) {
		ath6kl_err("Failed to get testmode %d firmware file %s: %d\n",
			   ar->testmode, filename, ret);
		return ret;
	}

	return 0;
}

static int ath6kl_fetch_fw_file(struct ath6kl *ar)
{
	char filename[100];
	int ret;

	if (ar->fw != NULL)
		return 0;

778
779
	/* FIXME: remove WARN_ON() as we won't support FW API 1 for long */
	if (WARN_ON(ar->hw.fw.fw == NULL))
780
781
		return -EINVAL;

782
783
	snprintf(filename, sizeof(filename), "%s/%s",
		 ar->hw.fw.dir, ar->hw.fw.fw);
784
785
786
787
788
789
790
791
792
793
794
795
796

	ret = ath6kl_get_fw(ar, filename, &ar->fw, &ar->fw_len);
	if (ret) {
		ath6kl_err("Failed to get firmware file %s: %d\n",
			   filename, ret);
		return ret;
	}

	return 0;
}

static int ath6kl_fetch_patch_file(struct ath6kl *ar)
{
797
	char filename[100];
798
799
	int ret;

800
	if (ar->fw_patch != NULL)
801
802
		return 0;

803
	if (ar->hw.fw.patch == NULL)
804
805
		return 0;

806
807
	snprintf(filename, sizeof(filename), "%s/%s",
		 ar->hw.fw.dir, ar->hw.fw.patch);
808
809
810
811
812
813
814

	ret = ath6kl_get_fw(ar, filename, &ar->fw_patch,
			    &ar->fw_patch_len);
	if (ret) {
		ath6kl_err("Failed to get patch file %s: %d\n",
			   filename, ret);
		return ret;
815
816
817
818
819
	}

	return 0;
}

820
821
822
823
824
static int ath6kl_fetch_testscript_file(struct ath6kl *ar)
{
	char filename[100];
	int ret;

825
	if (ar->testmode != 2)
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
		return 0;

	if (ar->fw_testscript != NULL)
		return 0;

	if (ar->hw.fw.testscript == NULL)
		return 0;

	snprintf(filename, sizeof(filename), "%s/%s",
		ar->hw.fw.dir, ar->hw.fw.testscript);

	ret = ath6kl_get_fw(ar, filename, &ar->fw_testscript,
				&ar->fw_testscript_len);
	if (ret) {
		ath6kl_err("Failed to get testscript file %s: %d\n",
			filename, ret);
		return ret;
	}

	return 0;
}

848
static int ath6kl_fetch_fw_api1(struct ath6kl *ar)
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
{
	int ret;

	ret = ath6kl_fetch_otp_file(ar);
	if (ret)
		return ret;

	ret = ath6kl_fetch_fw_file(ar);
	if (ret)
		return ret;

	ret = ath6kl_fetch_patch_file(ar);
	if (ret)
		return ret;

864
865
866
867
	ret = ath6kl_fetch_testscript_file(ar);
	if (ret)
		return ret;

868
869
	return 0;
}
Kalle Valo's avatar
Kalle Valo committed
870

Kalle Valo's avatar
Kalle Valo committed
871
static int ath6kl_fetch_fw_apin(struct ath6kl *ar, const char *name)
872
873
874
875
{
	size_t magic_len, len, ie_len;
	const struct firmware *fw;
	struct ath6kl_fw_ie *hdr;
876
	char filename[100];
877
	const u8 *data;
878
	int ret, ie_id, i, index, bit;
879
	__le32 *val;
880

Kalle Valo's avatar
Kalle Valo committed
881
	snprintf(filename, sizeof(filename), "%s/%s", ar->hw.fw.dir, name);
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923

	ret = request_firmware(&fw, filename, ar->dev);
	if (ret)
		return ret;

	data = fw->data;
	len = fw->size;

	/* magic also includes the null byte, check that as well */
	magic_len = strlen(ATH6KL_FIRMWARE_MAGIC) + 1;

	if (len < magic_len) {
		ret = -EINVAL;
		goto out;
	}

	if (memcmp(data, ATH6KL_FIRMWARE_MAGIC, magic_len) != 0) {
		ret = -EINVAL;
		goto out;
	}

	len -= magic_len;
	data += magic_len;

	/* loop elements */
	while (len > sizeof(struct ath6kl_fw_ie)) {
		/* hdr is unaligned! */
		hdr = (struct ath6kl_fw_ie *) data;

		ie_id = le32_to_cpup(&hdr->id);
		ie_len = le32_to_cpup(&hdr->len);

		len -= sizeof(*hdr);
		data += sizeof(*hdr);

		if (len < ie_len) {
			ret = -EINVAL;
			goto out;
		}

		switch (ie_id) {
		case ATH6KL_FW_IE_OTP_IMAGE:
924
			ath6kl_dbg(ATH6KL_DBG_BOOT, "found otp image ie (%zd B)\n",
925
926
				ie_len);

927
928
929
930
931
932
933
934
935
936
			ar->fw_otp = kmemdup(data, ie_len, GFP_KERNEL);

			if (ar->fw_otp == NULL) {
				ret = -ENOMEM;
				goto out;
			}

			ar->fw_otp_len = ie_len;
			break;
		case ATH6KL_FW_IE_FW_IMAGE:
937
			ath6kl_dbg(ATH6KL_DBG_BOOT, "found fw image ie (%zd B)\n",
938
939
				ie_len);

940
941
942
943
			/* in testmode we already might have a fw file */
			if (ar->fw != NULL)
				break;

944
945
946
947
948
949
950
951
952
953
			ar->fw = kmemdup(data, ie_len, GFP_KERNEL);

			if (ar->fw == NULL) {
				ret = -ENOMEM;
				goto out;
			}

			ar->fw_len = ie_len;
			break;
		case ATH6KL_FW_IE_PATCH_IMAGE:
954
			ath6kl_dbg(ATH6KL_DBG_BOOT, "found patch image ie (%zd B)\n",
955
956
				ie_len);

957
958
959
960
961
962
963
964
965
			ar->fw_patch = kmemdup(data, ie_len, GFP_KERNEL);

			if (ar->fw_patch == NULL) {
				ret = -ENOMEM;
				goto out;
			}

			ar->fw_patch_len = ie_len;
			break;
966
967
968
		case ATH6KL_FW_IE_RESERVED_RAM_SIZE:
			val = (__le32 *) data;
			ar->hw.reserved_ram_size = le32_to_cpup(val);
969
970
971
972

			ath6kl_dbg(ATH6KL_DBG_BOOT,
				   "found reserved ram size ie 0x%d\n",
				   ar->hw.reserved_ram_size);
973
			break;
974
		case ATH6KL_FW_IE_CAPABILITIES:
975
976
977
			if (ie_len < DIV_ROUND_UP(ATH6KL_FW_CAPABILITY_MAX, 8))
				break;

978
			ath6kl_dbg(ATH6KL_DBG_BOOT,
979
				   "found firmware capabilities ie (%zd B)\n",
980
981
				   ie_len);

982
			for (i = 0; i < ATH6KL_FW_CAPABILITY_MAX; i++) {
983
				index = i / 8;
984
985
986
987
988
				bit = i % 8;

				if (data[index] & (1 << bit))
					__set_bit(i, ar->fw_capabilities);
			}
989
990
991
992

			ath6kl_dbg_dump(ATH6KL_DBG_BOOT, "capabilities", "",
					ar->fw_capabilities,
					sizeof(ar->fw_capabilities));
993
			break;
994
995
996
997
998
999
		case ATH6KL_FW_IE_PATCH_ADDR:
			if (ie_len != sizeof(*val))
				break;

			val = (__le32 *) data;
			ar->hw.dataset_patch_addr = le32_to_cpup(val);
1000
1001

			ath6kl_dbg(ATH6KL_DBG_BOOT,
1002
				   "found patch address ie 0x%x\n",
1003
				   ar->hw.dataset_patch_addr);
1004
			break;
1005
1006
1007
1008
1009
1010
1011
1012
1013
1014
1015
		case ATH6KL_FW_IE_BOARD_ADDR:
			if (ie_len != sizeof(*val))
				break;

			val = (__le32 *) data;
			ar->hw.board_addr = le32_to_cpup(val);

			ath6kl_dbg(ATH6KL_DBG_BOOT,
				   "found board address ie 0x%x\n",
				   ar->hw.board_addr);
			break;
1016
1017
1018
1019
1020
1021
1022
1023
		case ATH6KL_FW_IE_VIF_MAX:
			if (ie_len != sizeof(*val))
				break;

			val = (__le32 *) data;
			ar->vif_max = min_t(unsigned int, le32_to_cpup(val),
					    ATH6KL_VIF_MAX);

1024
1025
1026
			if (ar->vif_max > 1 && !ar->p2p)
				ar->max_norm_iface = 2;

1027
1028
1029
			ath6kl_dbg(ATH6KL_DBG_BOOT,
				   "found vif max ie %d\n", ar->vif_max);
			break;
1030
		default:
1031
			ath6kl_dbg(ATH6KL_DBG_BOOT, "Unknown fw ie: %u\n",
1032
1033
1034
1035
1036
1037
1038
1039
1040
1041
1042
1043
1044
1045
1046
				   le32_to_cpup(&hdr->id));
			break;
		}

		len -= ie_len;
		data += ie_len;
	};

	ret = 0;
out:
	release_firmware(fw);

	return ret;
}

Kalle Valo's avatar
Kalle Valo committed
1047
int ath6kl_init_fetch_firmwares(struct ath6kl *ar)
1048
1049
1050
1051
1052
1053
1054
{
	int ret;

	ret = ath6kl_fetch_board_file(ar);
	if (ret)
		return ret;

1055
1056
1057
1058
	ret = ath6kl_fetch_testmode_file(ar);
	if (ret)
		return ret;

Kalle Valo's avatar
Kalle Valo committed
1059
	ret = ath6kl_fetch_fw_apin(ar, ATH6KL_FW_API3_FILE);
1060
	if (ret == 0) {
Kalle Valo's avatar
Kalle Valo committed
1061
1062
1063
1064
1065
1066
1067
1068
		ar->fw_api = 3;
		goto out;
	}

	ret = ath6kl_fetch_fw_apin(ar, ATH6KL_FW_API2_FILE);
	if (ret == 0) {
		ar->fw_api = 2;
		goto out;
1069
	}
1070
1071
1072
1073
1074

	ret = ath6kl_fetch_fw_api1(ar);
	if (ret)
		return ret;

Kalle Valo's avatar
Kalle Valo committed
1075
1076
1077
1078
	ar->fw_api = 1;

out:
	ath6kl_dbg(ATH6KL_DBG_BOOT, "using fw api %d\n", ar->fw_api);
1079

1080
1081
1082
	return 0;
}

Kalle Valo's avatar
Kalle Valo committed
1083
1084
1085
static int ath6kl_upload_board_file(struct ath6kl *ar)
{
	u32 board_address, board_ext_address, param;
1086
	u32 board_data_size, board_ext_data_size;
Kalle Valo's avatar
Kalle Valo committed
1087
1088
	int ret;

1089
1090
	if (WARN_ON(ar->fw_board == NULL))
		return -ENOENT;
Kalle Valo's avatar
Kalle Valo committed
1091

1092
1093
1094
1095
1096
	/*
	 * Determine where in Target RAM to write Board Data.
	 * For AR6004, host determine Target RAM address for
	 * writing board data.
	 */
1097
1098
	if (ar->hw.board_addr != 0) {
		board_address = ar->hw.board_addr;
1099
1100
1101
1102
1103
1104
1105
1106
1107
1108
1109
		ath6kl_bmi_write(ar,
				ath6kl_get_hi_item_addr(ar,
				HI_ITEM(hi_board_data)),
				(u8 *) &board_address, 4);
	} else {
		ath6kl_bmi_read(ar,
				ath6kl_get_hi_item_addr(ar,
				HI_ITEM(hi_board_data)),
				(u8 *) &board_address, 4);
	}

Kalle Valo's avatar
Kalle Valo committed
1110
1111
1112
1113
1114
1115
	/* determine where in target ram to write extended board data */
	ath6kl_bmi_read(ar,
			ath6kl_get_hi_item_addr(ar,
			HI_ITEM(hi_board_ext_data)),
			(u8 *) &board_ext_address, 4);

1116
1117
	if (ar->target_type == TARGET_TYPE_AR6003 &&
	    board_ext_address == 0) {
Kalle Valo's avatar
Kalle Valo committed
1118
1119
1120
1121
		ath6kl_err("Failed to get board file target address.\n");
		return -EINVAL;
	}

1122
1123
1124
1125
1126
1127
1128
1129
1130
1131
1132
1133
1134
1135
1136
	switch (ar->target_type) {
	case TARGET_TYPE_AR6003:
		board_data_size = AR6003_BOARD_DATA_SZ;
		board_ext_data_size = AR6003_BOARD_EXT_DATA_SZ;
		break;
	case TARGET_TYPE_AR6004:
		board_data_size = AR6004_BOARD_DATA_SZ;
		board_ext_data_size = AR6004_BOARD_EXT_DATA_SZ;
		break;
	default:
		WARN_ON(1);
		return -EINVAL;
		break;
	}

1137
1138
	if (board_ext_address &&
	    ar->fw_board_len == (board_data_size + board_ext_data_size)) {
1139

Kalle Valo's avatar
Kalle Valo committed
1140
		/* write extended board data */
1141
1142
1143
1144
		ath6kl_dbg(ATH6KL_DBG_BOOT,
			   "writing extended board data to 0x%x (%d B)\n",
			   board_ext_address, board_ext_data_size);

Kalle Valo's avatar
Kalle Valo committed
1145
		ret = ath6kl_bmi_write(ar, board_ext_address,
1146
1147
				       ar->fw_board + board_data_size,
				       board_ext_data_size);
Kalle Valo's avatar
Kalle Valo committed
1148
1149
1150
1151
1152
1153
1154
		if (ret) {
			ath6kl_err("Failed to write extended board data: %d\n",
				   ret);
			return ret;
		}

		/* record that extended board data is initialized */
1155
1156
		param = (board_ext_data_size << 16) | 1;

Kalle Valo's avatar
Kalle Valo committed
1157
1158
1159
1160
1161
1162
		ath6kl_bmi_write(ar,
				 ath6kl_get_hi_item_addr(ar,
				 HI_ITEM(hi_board_ext_data_config)),
				 (unsigned char *) &param, 4);
	}

1163
	if (ar->fw_board_len < board_data_size) {
Kalle Valo's avatar
Kalle Valo committed
1164
1165
1166
1167
1168
		ath6kl_err("Too small board file: %zu\n", ar->fw_board_len);
		ret = -EINVAL;
		return ret;
	}

1169
1170
1171
	ath6kl_dbg(ATH6KL_DBG_BOOT, "writing board file to 0x%x (%d B)\n",
		   board_address, board_data_size);

Kalle Valo's avatar
Kalle Valo committed
1172
	ret = ath6kl_bmi_write(ar, board_address, ar->fw_board,
1173
			       board_data_size);
Kalle Valo's avatar
Kalle Valo committed
1174
1175
1176
1177
1178
1179
1180
1181
1182
1183
1184
1185
1186
1187
1188
1189
1190
1191
1192

	if (ret) {
		ath6kl_err("Board file bmi write failed: %d\n", ret);
		return ret;
	}

	/* record the fact that Board Data IS initialized */
	param = 1;
	ath6kl_bmi_write(ar,
			 ath6kl_get_hi_item_addr(ar,
			 HI_ITEM(hi_board_data_initialized)),
			 (u8 *)&param, 4);

	return ret;
}

static int ath6kl_upload_otp(struct ath6kl *ar)
{
	u32 address, param;
1193
	bool from_hw = false;
Kalle Valo's avatar
Kalle Valo committed
1194
1195
	int ret;

1196
1197
	if (ar->fw_otp == NULL)
		return 0;
Kalle Valo's avatar
Kalle Valo committed
1198

1199
	address = ar->hw.app_load_addr;
Kalle Valo's avatar
Kalle Valo committed
1200

1201
	ath6kl_dbg(ATH6KL_DBG_BOOT, "writing otp to 0x%x (%zd B)\n", address,
1202
1203
		   ar->fw_otp_len);

Kalle Valo's avatar
Kalle Valo committed
1204
1205
1206
1207
1208
1209
1210
	ret = ath6kl_bmi_fast_download(ar, address, ar->fw_otp,
				       ar->fw_otp_len);
	if (ret) {
		ath6kl_err("Failed to upload OTP file: %d\n", ret);
		return ret;
	}

1211
1212
1213
1214
1215
1216
1217
1218
1219
1220
1221
	/* read firmware start address */
	ret = ath6kl_bmi_read(ar,
			      ath6kl_get_hi_item_addr(ar,
						      HI_ITEM(hi_app_start)),
			      (u8 *) &address, sizeof(address));

	if (ret) {
		ath6kl_err("Failed to read hi_app_start: %d\n", ret);
		return ret;
	}

1222
1223
1224
1225
	if (ar->hw.app_start_override_addr == 0) {
		ar->hw.app_start_override_addr = address;
		from_hw = true;
	}
1226

1227
1228
	ath6kl_dbg(ATH6KL_DBG_BOOT, "app_start_override_addr%s 0x%x\n",
		   from_hw ? " (from hw)" : "",
1229
1230
		   ar->hw.app_start_override_addr);

Kalle Valo's avatar
Kalle Valo committed
1231
	/* execute the OTP code */
1232
1233
	ath6kl_dbg(ATH6KL_DBG_BOOT, "executing OTP at 0x%x\n",
		   ar->hw.app_start_override_addr);
Kalle Valo's avatar
Kalle Valo committed
1234
	param = 0;
1235
	ath6kl_bmi_execute(ar, ar->hw.app_start_override_addr, &param);
Kalle Valo's avatar
Kalle Valo committed
1236
1237
1238
1239
1240
1241
1242
1243
1244

	return ret;
}

static int ath6kl_upload_firmware(struct ath6kl *ar)
{
	u32 address;
	int ret;

1245
	if (WARN_ON(ar->fw == NULL))
1246
		return 0;
Kalle Valo's avatar
Kalle Valo committed
1247

1248
	address = ar->hw.app_load_addr;
Kalle Valo's avatar
Kalle Valo committed
1249

1250
	ath6kl_dbg(ATH6KL_DBG_BOOT, "writing firmware to 0x%x (%zd B)\n",
1251
1252
		   address, ar->fw_len);

Kalle Valo's avatar
Kalle Valo committed
1253
1254
1255
1256
1257
1258
1259
	ret = ath6kl_bmi_fast_download(ar, address, ar->fw, ar->fw_len);

	if (ret) {
		ath6kl_err("Failed to write firmware: %d\n", ret);
		return ret;
	}

1260
1261
1262
1263
1264
	/*
	 * Set starting address for firmware
	 * Don't need to setup app_start override addr on AR6004
	 */
	if (ar->target_type != TARGET_TYPE_AR6004) {
1265
		address = ar->hw.app_start_override_addr;
1266
1267
		ath6kl_bmi_set_app_start(ar, address);
	}
Kalle Valo's avatar
Kalle Valo committed
1268
1269
1270
1271
1272
1273
1274
1275
	return ret;
}

static int ath6kl_upload_patch(struct ath6kl *ar)
{
	u32 address, param;
	int ret;

1276
1277
	if (ar->fw_patch == NULL)
		return 0;
Kalle Valo's avatar
Kalle Valo committed
1278

1279
	address = ar->hw.dataset_patch_addr;
Kalle Valo's avatar
Kalle Valo committed
1280

1281
	ath6kl_dbg(ATH6KL_DBG_BOOT, "writing patch to 0x%x (%zd B)\n",
1282
1283
		   address, ar->fw_patch_len);

Kalle Valo's avatar
Kalle Valo committed
1284
1285
1286
1287
1288
1289
1290
1291
1292
1293
1294
1295
1296
1297
1298
	ret = ath6kl_bmi_write(ar, address, ar->fw_patch, ar->fw_patch_len);
	if (ret) {
		ath6kl_err("Failed to write patch file: %d\n", ret);
		return ret;
	}

	param = address;
	ath6kl_bmi_write(ar,
			 ath6kl_get_hi_item_addr(ar,
			 HI_ITEM(hi_dset_list_head)),
			 (unsigned char *) &param, 4);

	return 0;
}

1299
1300
1301
1302
1303
static int ath6kl_upload_testscript(struct ath6kl *ar)
{
	u32 address, param;
	int ret;

1304
	if (ar->testmode != 2)
1305
1306
1307
1308
1309
1310
1311
1312
1313
1314
1315
1316
1317
1318
1319
1320
1321
1322
1323
1324
1325
1326
1327
1328
1329
1330
1331
1332
1333
1334
1335
1336
1337
1338
1339
1340
1341
1342
		return 0;

	if (ar->fw_testscript == NULL)
		return 0;

	address = ar->hw.testscript_addr;

	ath6kl_dbg(ATH6KL_DBG_BOOT, "writing testscript to 0x%x (%zd B)\n",
		address, ar->fw_testscript_len);

	ret = ath6kl_bmi_write(ar, address, ar->fw_testscript,
		ar->fw_testscript_len);
	if (ret) {
		ath6kl_err("Failed to write testscript file: %d\n", ret);
		return ret;
	}

	param = address;
	ath6kl_bmi_write(ar,
			ath6kl_get_hi_item_addr(ar,
			HI_ITEM(hi_ota_testscript)),
			(unsigned char *) &param, 4);

	param = 4096;
	ath6kl_bmi_write(ar,
			ath6kl_get_hi_item_addr(ar,
			HI_ITEM(hi_end_ram_reserve_sz)),
			(unsigned char *) &param, 4);

	param = 1;
	ath6kl_bmi_write(ar,
			ath6kl_get_hi_item_addr(ar,
			HI_ITEM(hi_test_apps_related)),
			(unsigned char *) &param, 4);

	return 0;
}

Kalle Valo's avatar
Kalle Valo committed
1343
1344
1345
1346
1347
static int ath6kl_init_upload(struct ath6kl *ar)
{
	u32 param, options, sleep, address;
	int status = 0;

1348
1349
	if (ar->target_type != TARGET_TYPE_AR6003 &&
		ar->target_type != TARGET_TYPE_AR6004)
Kalle Valo's avatar
Kalle Valo committed
1350
1351
1352
1353
1354
1355
1356
1357
1358
1359
1360
1361
1362
1363
1364
1365
1366
1367
1368
1369
1370
1371
1372
1373
1374
1375
1376
1377
1378
1379
1380
		return -EINVAL;

	/* temporarily disable system sleep */
	address = MBOX_BASE_ADDRESS + LOCAL_SCRATCH_ADDRESS;
	status = ath6kl_bmi_reg_read(ar, address, &param);
	if (status)
		return status;

	options = param;

	param |= ATH6KL_OPTION_SLEEP_DISABLE;
	status = ath6kl_bmi_reg_write(ar, address, param);
	if (status)
		return status;

	address = RTC_BASE_ADDRESS + SYSTEM_SLEEP_ADDRESS;
	status = ath6kl_bmi_reg_read(ar, address, &param);
	if (status)
		return status;

	sleep = param;

	param |= SM(SYSTEM_SLEEP_DISABLE, 1);
	status = ath6kl_bmi_reg_write(ar, address, param);
	if (status)
		return status;

	ath6kl_dbg(ATH6KL_DBG_TRC, "old options: %d, old sleep: %d\n",
		   options, sleep);

	/* program analog PLL register */
1381
1382
1383
1384
	/* no need to control 40/44MHz clock on AR6004 */
	if (ar->target_type != TARGET_TYPE_AR6004) {
		status = ath6kl_bmi_reg_write(ar, ATH6KL_ANALOG_PLL_REGISTER,
					      0xF9104001);
Kalle Valo's avatar
Kalle Valo committed
1385

1386
1387
		if (status)
			return status;
Kalle Valo's avatar
Kalle Valo committed
1388

1389
1390
1391
1392
1393
1394
1395
1396
		/* Run at 80/88MHz by default */
		param = SM(CPU_CLOCK_STANDARD, 1);

		address = RTC_BASE_ADDRESS + CPU_CLOCK_ADDRESS;
		status = ath6kl_bmi_reg_write(ar, address, param);
		if (status)
			return status;
	}
Kalle Valo's avatar
Kalle Valo committed
1397
1398
1399
1400
1401
1402
1403
1404
1405

	param = 0;
	address = RTC_BASE_ADDRESS + LPO_CAL_ADDRESS;
	param = SM(LPO_CAL_ENABLE, 1);
	status = ath6kl_bmi_reg_write(ar, address, param);
	if (status)
		return status;

	/* WAR to avoid SDIO CRC err */
1406
	if (ar->version.target_ver == AR6003_HW_2_0_VERSION) {
Kalle Valo's avatar
Kalle Valo committed
1407
1408
1409
1410
1411
1412
1413
1414
1415
1416
1417
1418
1419
1420
1421
1422
1423
1424
1425
1426
1427
1428
1429
1430
1431
1432
1433
1434
1435
1436
1437
1438
1439
1440
1441
1442
1443
1444
1445
1446
1447
1448
1449
1450
		ath6kl_err("temporary war to avoid sdio crc error\n");

		param = 0x20;

		address = GPIO_BASE_ADDRESS + GPIO_PIN10_ADDRESS;
		status = ath6kl_bmi_reg_write(ar, address, param);
		if (status)
			return status;

		address = GPIO_BASE_ADDRESS + GPIO_PIN11_ADDRESS;
		status = ath6kl_bmi_reg_write(ar, address, param);
		if (status)
			return status;

		address = GPIO_BASE_ADDRESS + GPIO_PIN12_ADDRESS;
		status = ath6kl_bmi_reg_write(ar, address, param);
		if (status)
			return status;

		address = GPIO_BASE_ADDRESS + GPIO_PIN13_ADDRESS;
		status = ath6kl_bmi_reg_write(ar, address, param);
		if (status)
			return status;
	}

	/* write EEPROM data to Target RAM */
	status = ath6kl_upload_board_file(ar);
	if (status)
		return status;

	/* transfer One time Programmable data */
	status = ath6kl_upload_otp(ar);
	if (status)
		return status;

	/* Download Target firmware */
	status = ath6kl_upload_firmware(ar);
	if (status)
		return status;

	status = ath6kl_upload_patch(ar);
	if (status)
		return status;

1451
1452
1453
1454
1455
	/* Download the test script */
	status = ath6kl_upload_testscript(ar);
	if (status)
		return status;

Kalle Valo's avatar
Kalle Valo committed
1456
1457
1458
1459
1460
1461
1462
1463
1464
1465
1466
1467
1468
1469
1470
	/* Restore system sleep */
	address = RTC_BASE_ADDRESS + SYSTEM_SLEEP_ADDRESS;
	status = ath6kl_bmi_reg_write(ar, address, sleep);
	if (status)
		return status;

	address = MBOX_BASE_ADDRESS + LOCAL_SCRATCH_ADDRESS;
	param = options | 0x20;
	status = ath6kl_bmi_reg_write(ar, address, param);
	if (status)
		return status;

	return status;
}

Kalle Valo's avatar
Kalle Valo committed
1471
int ath6kl_init_hw_params(struct ath6kl *ar)
1472
{
1473
	const struct ath6kl_hw *uninitialized_var(hw);
1474
	int i;
1475

1476
1477
	for (i = 0; i < ARRAY_SIZE(hw_list); i++) {
		hw = &hw_list[i];
1478

1479
1480
1481
1482
1483
		if (hw->id == ar->version.target_ver)
			break;
	}

	if (i == ARRAY_SIZE(hw_list)) {
1484
1485
1486
1487
1488
		ath6kl_err("Unsupported hardware version: 0x%x\n",
			   ar->version.target_ver);
		return -EINVAL;
	}

1489
1490
	ar->hw = *hw;

1491
1492
1493
1494
1495
1496
1497
1498
	ath6kl_dbg(ATH6KL_DBG_BOOT,
		   "target_ver 0x%x target_type 0x%x dataset_patch 0x%x app_load_addr 0x%x\n",
		   ar->version.target_ver, ar->target_type,
		   ar->hw.dataset_patch_addr, ar->hw.app_load_addr);
	ath6kl_dbg(ATH6KL_DBG_BOOT,
		   "app_start_override_addr 0x%x board_ext_data_addr 0x%x reserved_ram_size 0x%x",
		   ar->hw.app_start_override_addr, ar->hw.board_ext_data_addr,
		   ar->hw.reserved_ram_size);
1499
1500
1501
	ath6kl_dbg(ATH6KL_DBG_BOOT,
		   "refclk_hz %d uarttx_pin %d",
		   ar->hw.refclk_hz, ar->hw.uarttx_pin);
1502

1503
1504
1505
	return 0;
}