12f01a1f58889fbfeb68b1bc1b52e4197f3333490Kalle Valo/*
280301cdcfe44e3533175be23d7d52a9fc8c3fdb0Kalle Valo * This file is part of wl1251
32f01a1f58889fbfeb68b1bc1b52e4197f3333490Kalle Valo *
42f01a1f58889fbfeb68b1bc1b52e4197f3333490Kalle Valo * Copyright (C) 2009 Nokia Corporation
52f01a1f58889fbfeb68b1bc1b52e4197f3333490Kalle Valo *
62f01a1f58889fbfeb68b1bc1b52e4197f3333490Kalle Valo * This program is free software; you can redistribute it and/or
72f01a1f58889fbfeb68b1bc1b52e4197f3333490Kalle Valo * modify it under the terms of the GNU General Public License
82f01a1f58889fbfeb68b1bc1b52e4197f3333490Kalle Valo * version 2 as published by the Free Software Foundation.
92f01a1f58889fbfeb68b1bc1b52e4197f3333490Kalle Valo *
102f01a1f58889fbfeb68b1bc1b52e4197f3333490Kalle Valo * This program is distributed in the hope that it will be useful, but
112f01a1f58889fbfeb68b1bc1b52e4197f3333490Kalle Valo * WITHOUT ANY WARRANTY; without even the implied warranty of
122f01a1f58889fbfeb68b1bc1b52e4197f3333490Kalle Valo * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
132f01a1f58889fbfeb68b1bc1b52e4197f3333490Kalle Valo * General Public License for more details.
142f01a1f58889fbfeb68b1bc1b52e4197f3333490Kalle Valo *
152f01a1f58889fbfeb68b1bc1b52e4197f3333490Kalle Valo * You should have received a copy of the GNU General Public License
162f01a1f58889fbfeb68b1bc1b52e4197f3333490Kalle Valo * along with this program; if not, write to the Free Software
172f01a1f58889fbfeb68b1bc1b52e4197f3333490Kalle Valo * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
182f01a1f58889fbfeb68b1bc1b52e4197f3333490Kalle Valo * 02110-1301 USA
192f01a1f58889fbfeb68b1bc1b52e4197f3333490Kalle Valo *
202f01a1f58889fbfeb68b1bc1b52e4197f3333490Kalle Valo */
212f01a1f58889fbfeb68b1bc1b52e4197f3333490Kalle Valo
222f01a1f58889fbfeb68b1bc1b52e4197f3333490Kalle Valo#include <linux/kernel.h>
232f01a1f58889fbfeb68b1bc1b52e4197f3333490Kalle Valo#include <linux/module.h>
245a0e3ad6af8660be21ca98a971cd00f331318c05Tejun Heo#include <linux/slab.h>
252f01a1f58889fbfeb68b1bc1b52e4197f3333490Kalle Valo
269bc6772e15d25f58c1be638031280e04514287d4Kalle Valo#include "init.h"
272f01a1f58889fbfeb68b1bc1b52e4197f3333490Kalle Valo#include "wl12xx_80211.h"
289bc6772e15d25f58c1be638031280e04514287d4Kalle Valo#include "acx.h"
299bc6772e15d25f58c1be638031280e04514287d4Kalle Valo#include "cmd.h"
309bc6772e15d25f58c1be638031280e04514287d4Kalle Valo#include "reg.h"
312f01a1f58889fbfeb68b1bc1b52e4197f3333490Kalle Valo
3280301cdcfe44e3533175be23d7d52a9fc8c3fdb0Kalle Valoint wl1251_hw_init_hwenc_config(struct wl1251 *wl)
332f01a1f58889fbfeb68b1bc1b52e4197f3333490Kalle Valo{
342f01a1f58889fbfeb68b1bc1b52e4197f3333490Kalle Valo	int ret;
352f01a1f58889fbfeb68b1bc1b52e4197f3333490Kalle Valo
364d09b5378defd4ef685f9d33e0d35b380109eafaDavid Gnedt	ret = wl1251_acx_feature_cfg(wl, 0);
372f01a1f58889fbfeb68b1bc1b52e4197f3333490Kalle Valo	if (ret < 0) {
3880301cdcfe44e3533175be23d7d52a9fc8c3fdb0Kalle Valo		wl1251_warning("couldn't set feature config");
392f01a1f58889fbfeb68b1bc1b52e4197f3333490Kalle Valo		return ret;
402f01a1f58889fbfeb68b1bc1b52e4197f3333490Kalle Valo	}
412f01a1f58889fbfeb68b1bc1b52e4197f3333490Kalle Valo
4280301cdcfe44e3533175be23d7d52a9fc8c3fdb0Kalle Valo	ret = wl1251_acx_default_key(wl, wl->default_key);
432f01a1f58889fbfeb68b1bc1b52e4197f3333490Kalle Valo	if (ret < 0) {
4480301cdcfe44e3533175be23d7d52a9fc8c3fdb0Kalle Valo		wl1251_warning("couldn't set default key");
452f01a1f58889fbfeb68b1bc1b52e4197f3333490Kalle Valo		return ret;
462f01a1f58889fbfeb68b1bc1b52e4197f3333490Kalle Valo	}
472f01a1f58889fbfeb68b1bc1b52e4197f3333490Kalle Valo
482f01a1f58889fbfeb68b1bc1b52e4197f3333490Kalle Valo	return 0;
492f01a1f58889fbfeb68b1bc1b52e4197f3333490Kalle Valo}
502f01a1f58889fbfeb68b1bc1b52e4197f3333490Kalle Valo
5180301cdcfe44e3533175be23d7d52a9fc8c3fdb0Kalle Valoint wl1251_hw_init_templates_config(struct wl1251 *wl)
522f01a1f58889fbfeb68b1bc1b52e4197f3333490Kalle Valo{
532f01a1f58889fbfeb68b1bc1b52e4197f3333490Kalle Valo	int ret;
542f01a1f58889fbfeb68b1bc1b52e4197f3333490Kalle Valo	u8 partial_vbm[PARTIAL_VBM_MAX];
552f01a1f58889fbfeb68b1bc1b52e4197f3333490Kalle Valo
562f01a1f58889fbfeb68b1bc1b52e4197f3333490Kalle Valo	/* send empty templates for fw memory reservation */
5780301cdcfe44e3533175be23d7d52a9fc8c3fdb0Kalle Valo	ret = wl1251_cmd_template_set(wl, CMD_PROBE_REQ, NULL,
582f01a1f58889fbfeb68b1bc1b52e4197f3333490Kalle Valo				      sizeof(struct wl12xx_probe_req_template));
592f01a1f58889fbfeb68b1bc1b52e4197f3333490Kalle Valo	if (ret < 0)
602f01a1f58889fbfeb68b1bc1b52e4197f3333490Kalle Valo		return ret;
612f01a1f58889fbfeb68b1bc1b52e4197f3333490Kalle Valo
6280301cdcfe44e3533175be23d7d52a9fc8c3fdb0Kalle Valo	ret = wl1251_cmd_template_set(wl, CMD_NULL_DATA, NULL,
632f01a1f58889fbfeb68b1bc1b52e4197f3333490Kalle Valo				      sizeof(struct wl12xx_null_data_template));
642f01a1f58889fbfeb68b1bc1b52e4197f3333490Kalle Valo	if (ret < 0)
652f01a1f58889fbfeb68b1bc1b52e4197f3333490Kalle Valo		return ret;
662f01a1f58889fbfeb68b1bc1b52e4197f3333490Kalle Valo
6780301cdcfe44e3533175be23d7d52a9fc8c3fdb0Kalle Valo	ret = wl1251_cmd_template_set(wl, CMD_PS_POLL, NULL,
682f01a1f58889fbfeb68b1bc1b52e4197f3333490Kalle Valo				      sizeof(struct wl12xx_ps_poll_template));
692f01a1f58889fbfeb68b1bc1b52e4197f3333490Kalle Valo	if (ret < 0)
702f01a1f58889fbfeb68b1bc1b52e4197f3333490Kalle Valo		return ret;
712f01a1f58889fbfeb68b1bc1b52e4197f3333490Kalle Valo
7280301cdcfe44e3533175be23d7d52a9fc8c3fdb0Kalle Valo	ret = wl1251_cmd_template_set(wl, CMD_QOS_NULL_DATA, NULL,
732f01a1f58889fbfeb68b1bc1b52e4197f3333490Kalle Valo				      sizeof
742f01a1f58889fbfeb68b1bc1b52e4197f3333490Kalle Valo				      (struct wl12xx_qos_null_data_template));
752f01a1f58889fbfeb68b1bc1b52e4197f3333490Kalle Valo	if (ret < 0)
762f01a1f58889fbfeb68b1bc1b52e4197f3333490Kalle Valo		return ret;
772f01a1f58889fbfeb68b1bc1b52e4197f3333490Kalle Valo
7880301cdcfe44e3533175be23d7d52a9fc8c3fdb0Kalle Valo	ret = wl1251_cmd_template_set(wl, CMD_PROBE_RESP, NULL,
792f01a1f58889fbfeb68b1bc1b52e4197f3333490Kalle Valo				      sizeof
802f01a1f58889fbfeb68b1bc1b52e4197f3333490Kalle Valo				      (struct wl12xx_probe_resp_template));
812f01a1f58889fbfeb68b1bc1b52e4197f3333490Kalle Valo	if (ret < 0)
822f01a1f58889fbfeb68b1bc1b52e4197f3333490Kalle Valo		return ret;
832f01a1f58889fbfeb68b1bc1b52e4197f3333490Kalle Valo
8480301cdcfe44e3533175be23d7d52a9fc8c3fdb0Kalle Valo	ret = wl1251_cmd_template_set(wl, CMD_BEACON, NULL,
852f01a1f58889fbfeb68b1bc1b52e4197f3333490Kalle Valo				      sizeof
862f01a1f58889fbfeb68b1bc1b52e4197f3333490Kalle Valo				      (struct wl12xx_beacon_template));
872f01a1f58889fbfeb68b1bc1b52e4197f3333490Kalle Valo	if (ret < 0)
882f01a1f58889fbfeb68b1bc1b52e4197f3333490Kalle Valo		return ret;
892f01a1f58889fbfeb68b1bc1b52e4197f3333490Kalle Valo
902f01a1f58889fbfeb68b1bc1b52e4197f3333490Kalle Valo	/* tim templates, first reserve space then allocate an empty one */
912f01a1f58889fbfeb68b1bc1b52e4197f3333490Kalle Valo	memset(partial_vbm, 0, PARTIAL_VBM_MAX);
9280301cdcfe44e3533175be23d7d52a9fc8c3fdb0Kalle Valo	ret = wl1251_cmd_vbm(wl, TIM_ELE_ID, partial_vbm, PARTIAL_VBM_MAX, 0);
932f01a1f58889fbfeb68b1bc1b52e4197f3333490Kalle Valo	if (ret < 0)
942f01a1f58889fbfeb68b1bc1b52e4197f3333490Kalle Valo		return ret;
952f01a1f58889fbfeb68b1bc1b52e4197f3333490Kalle Valo
9680301cdcfe44e3533175be23d7d52a9fc8c3fdb0Kalle Valo	ret = wl1251_cmd_vbm(wl, TIM_ELE_ID, partial_vbm, 1, 0);
972f01a1f58889fbfeb68b1bc1b52e4197f3333490Kalle Valo	if (ret < 0)
982f01a1f58889fbfeb68b1bc1b52e4197f3333490Kalle Valo		return ret;
992f01a1f58889fbfeb68b1bc1b52e4197f3333490Kalle Valo
1002f01a1f58889fbfeb68b1bc1b52e4197f3333490Kalle Valo	return 0;
1012f01a1f58889fbfeb68b1bc1b52e4197f3333490Kalle Valo}
1022f01a1f58889fbfeb68b1bc1b52e4197f3333490Kalle Valo
10380301cdcfe44e3533175be23d7d52a9fc8c3fdb0Kalle Valoint wl1251_hw_init_rx_config(struct wl1251 *wl, u32 config, u32 filter)
1042f01a1f58889fbfeb68b1bc1b52e4197f3333490Kalle Valo{
1052f01a1f58889fbfeb68b1bc1b52e4197f3333490Kalle Valo	int ret;
1062f01a1f58889fbfeb68b1bc1b52e4197f3333490Kalle Valo
10780301cdcfe44e3533175be23d7d52a9fc8c3fdb0Kalle Valo	ret = wl1251_acx_rx_msdu_life_time(wl, RX_MSDU_LIFETIME_DEF);
1082f01a1f58889fbfeb68b1bc1b52e4197f3333490Kalle Valo	if (ret < 0)
1092f01a1f58889fbfeb68b1bc1b52e4197f3333490Kalle Valo		return ret;
1102f01a1f58889fbfeb68b1bc1b52e4197f3333490Kalle Valo
11180301cdcfe44e3533175be23d7d52a9fc8c3fdb0Kalle Valo	ret = wl1251_acx_rx_config(wl, config, filter);
1122f01a1f58889fbfeb68b1bc1b52e4197f3333490Kalle Valo	if (ret < 0)
1132f01a1f58889fbfeb68b1bc1b52e4197f3333490Kalle Valo		return ret;
1142f01a1f58889fbfeb68b1bc1b52e4197f3333490Kalle Valo
1152f01a1f58889fbfeb68b1bc1b52e4197f3333490Kalle Valo	return 0;
1162f01a1f58889fbfeb68b1bc1b52e4197f3333490Kalle Valo}
1172f01a1f58889fbfeb68b1bc1b52e4197f3333490Kalle Valo
11880301cdcfe44e3533175be23d7d52a9fc8c3fdb0Kalle Valoint wl1251_hw_init_phy_config(struct wl1251 *wl)
1192f01a1f58889fbfeb68b1bc1b52e4197f3333490Kalle Valo{
1202f01a1f58889fbfeb68b1bc1b52e4197f3333490Kalle Valo	int ret;
1212f01a1f58889fbfeb68b1bc1b52e4197f3333490Kalle Valo
12280301cdcfe44e3533175be23d7d52a9fc8c3fdb0Kalle Valo	ret = wl1251_acx_pd_threshold(wl);
1232f01a1f58889fbfeb68b1bc1b52e4197f3333490Kalle Valo	if (ret < 0)
1242f01a1f58889fbfeb68b1bc1b52e4197f3333490Kalle Valo		return ret;
1252f01a1f58889fbfeb68b1bc1b52e4197f3333490Kalle Valo
12680301cdcfe44e3533175be23d7d52a9fc8c3fdb0Kalle Valo	ret = wl1251_acx_slot(wl, DEFAULT_SLOT_TIME);
1272f01a1f58889fbfeb68b1bc1b52e4197f3333490Kalle Valo	if (ret < 0)
1282f01a1f58889fbfeb68b1bc1b52e4197f3333490Kalle Valo		return ret;
1292f01a1f58889fbfeb68b1bc1b52e4197f3333490Kalle Valo
1309ed74ba029fc920701cdcada8e25889a6d64a335David Gnedt	ret = wl1251_acx_group_address_tbl(wl, true, NULL, 0);
1312f01a1f58889fbfeb68b1bc1b52e4197f3333490Kalle Valo	if (ret < 0)
1322f01a1f58889fbfeb68b1bc1b52e4197f3333490Kalle Valo		return ret;
1332f01a1f58889fbfeb68b1bc1b52e4197f3333490Kalle Valo
13480301cdcfe44e3533175be23d7d52a9fc8c3fdb0Kalle Valo	ret = wl1251_acx_service_period_timeout(wl);
1352f01a1f58889fbfeb68b1bc1b52e4197f3333490Kalle Valo	if (ret < 0)
1362f01a1f58889fbfeb68b1bc1b52e4197f3333490Kalle Valo		return ret;
1372f01a1f58889fbfeb68b1bc1b52e4197f3333490Kalle Valo
13880301cdcfe44e3533175be23d7d52a9fc8c3fdb0Kalle Valo	ret = wl1251_acx_rts_threshold(wl, RTS_THRESHOLD_DEF);
1392f01a1f58889fbfeb68b1bc1b52e4197f3333490Kalle Valo	if (ret < 0)
1402f01a1f58889fbfeb68b1bc1b52e4197f3333490Kalle Valo		return ret;
1412f01a1f58889fbfeb68b1bc1b52e4197f3333490Kalle Valo
1422f01a1f58889fbfeb68b1bc1b52e4197f3333490Kalle Valo	return 0;
1432f01a1f58889fbfeb68b1bc1b52e4197f3333490Kalle Valo}
1442f01a1f58889fbfeb68b1bc1b52e4197f3333490Kalle Valo
14580301cdcfe44e3533175be23d7d52a9fc8c3fdb0Kalle Valoint wl1251_hw_init_beacon_filter(struct wl1251 *wl)
1462f01a1f58889fbfeb68b1bc1b52e4197f3333490Kalle Valo{
1472f01a1f58889fbfeb68b1bc1b52e4197f3333490Kalle Valo	int ret;
1482f01a1f58889fbfeb68b1bc1b52e4197f3333490Kalle Valo
1496b21a2cd315e2e56a1748bd3ef9d910fe4f2e711Juuso Oikarinen	/* disable beacon filtering at this stage */
1506b21a2cd315e2e56a1748bd3ef9d910fe4f2e711Juuso Oikarinen	ret = wl1251_acx_beacon_filter_opt(wl, false);
1512f01a1f58889fbfeb68b1bc1b52e4197f3333490Kalle Valo	if (ret < 0)
1522f01a1f58889fbfeb68b1bc1b52e4197f3333490Kalle Valo		return ret;
1532f01a1f58889fbfeb68b1bc1b52e4197f3333490Kalle Valo
15480301cdcfe44e3533175be23d7d52a9fc8c3fdb0Kalle Valo	ret = wl1251_acx_beacon_filter_table(wl);
1552f01a1f58889fbfeb68b1bc1b52e4197f3333490Kalle Valo	if (ret < 0)
1562f01a1f58889fbfeb68b1bc1b52e4197f3333490Kalle Valo		return ret;
1572f01a1f58889fbfeb68b1bc1b52e4197f3333490Kalle Valo
1582f01a1f58889fbfeb68b1bc1b52e4197f3333490Kalle Valo	return 0;
1592f01a1f58889fbfeb68b1bc1b52e4197f3333490Kalle Valo}
1602f01a1f58889fbfeb68b1bc1b52e4197f3333490Kalle Valo
16180301cdcfe44e3533175be23d7d52a9fc8c3fdb0Kalle Valoint wl1251_hw_init_pta(struct wl1251 *wl)
1622f01a1f58889fbfeb68b1bc1b52e4197f3333490Kalle Valo{
1632f01a1f58889fbfeb68b1bc1b52e4197f3333490Kalle Valo	int ret;
1642f01a1f58889fbfeb68b1bc1b52e4197f3333490Kalle Valo
16580301cdcfe44e3533175be23d7d52a9fc8c3fdb0Kalle Valo	ret = wl1251_acx_sg_enable(wl);
1662f01a1f58889fbfeb68b1bc1b52e4197f3333490Kalle Valo	if (ret < 0)
1672f01a1f58889fbfeb68b1bc1b52e4197f3333490Kalle Valo		return ret;
1682f01a1f58889fbfeb68b1bc1b52e4197f3333490Kalle Valo
16980301cdcfe44e3533175be23d7d52a9fc8c3fdb0Kalle Valo	ret = wl1251_acx_sg_cfg(wl);
1702f01a1f58889fbfeb68b1bc1b52e4197f3333490Kalle Valo	if (ret < 0)
1712f01a1f58889fbfeb68b1bc1b52e4197f3333490Kalle Valo		return ret;
1722f01a1f58889fbfeb68b1bc1b52e4197f3333490Kalle Valo
1732f01a1f58889fbfeb68b1bc1b52e4197f3333490Kalle Valo	return 0;
1742f01a1f58889fbfeb68b1bc1b52e4197f3333490Kalle Valo}
1752f01a1f58889fbfeb68b1bc1b52e4197f3333490Kalle Valo
17680301cdcfe44e3533175be23d7d52a9fc8c3fdb0Kalle Valoint wl1251_hw_init_energy_detection(struct wl1251 *wl)
1772f01a1f58889fbfeb68b1bc1b52e4197f3333490Kalle Valo{
1782f01a1f58889fbfeb68b1bc1b52e4197f3333490Kalle Valo	int ret;
1792f01a1f58889fbfeb68b1bc1b52e4197f3333490Kalle Valo
18080301cdcfe44e3533175be23d7d52a9fc8c3fdb0Kalle Valo	ret = wl1251_acx_cca_threshold(wl);
1812f01a1f58889fbfeb68b1bc1b52e4197f3333490Kalle Valo	if (ret < 0)
1822f01a1f58889fbfeb68b1bc1b52e4197f3333490Kalle Valo		return ret;
1832f01a1f58889fbfeb68b1bc1b52e4197f3333490Kalle Valo
1842f01a1f58889fbfeb68b1bc1b52e4197f3333490Kalle Valo	return 0;
1852f01a1f58889fbfeb68b1bc1b52e4197f3333490Kalle Valo}
1862f01a1f58889fbfeb68b1bc1b52e4197f3333490Kalle Valo
18780301cdcfe44e3533175be23d7d52a9fc8c3fdb0Kalle Valoint wl1251_hw_init_beacon_broadcast(struct wl1251 *wl)
1882f01a1f58889fbfeb68b1bc1b52e4197f3333490Kalle Valo{
1892f01a1f58889fbfeb68b1bc1b52e4197f3333490Kalle Valo	int ret;
1902f01a1f58889fbfeb68b1bc1b52e4197f3333490Kalle Valo
19180301cdcfe44e3533175be23d7d52a9fc8c3fdb0Kalle Valo	ret = wl1251_acx_bcn_dtim_options(wl);
1922f01a1f58889fbfeb68b1bc1b52e4197f3333490Kalle Valo	if (ret < 0)
1932f01a1f58889fbfeb68b1bc1b52e4197f3333490Kalle Valo		return ret;
1942f01a1f58889fbfeb68b1bc1b52e4197f3333490Kalle Valo
1952f01a1f58889fbfeb68b1bc1b52e4197f3333490Kalle Valo	return 0;
1962f01a1f58889fbfeb68b1bc1b52e4197f3333490Kalle Valo}
1972f01a1f58889fbfeb68b1bc1b52e4197f3333490Kalle Valo
19880301cdcfe44e3533175be23d7d52a9fc8c3fdb0Kalle Valoint wl1251_hw_init_power_auth(struct wl1251 *wl)
1992f01a1f58889fbfeb68b1bc1b52e4197f3333490Kalle Valo{
20080301cdcfe44e3533175be23d7d52a9fc8c3fdb0Kalle Valo	return wl1251_acx_sleep_auth(wl, WL1251_PSM_CAM);
2012f01a1f58889fbfeb68b1bc1b52e4197f3333490Kalle Valo}
2020e71bb084adc4986b9a4be3581897f0ee703cbd5Kalle Valo
2030e71bb084adc4986b9a4be3581897f0ee703cbd5Kalle Valoint wl1251_hw_init_mem_config(struct wl1251 *wl)
2040e71bb084adc4986b9a4be3581897f0ee703cbd5Kalle Valo{
2050e71bb084adc4986b9a4be3581897f0ee703cbd5Kalle Valo	int ret;
2060e71bb084adc4986b9a4be3581897f0ee703cbd5Kalle Valo
2070e71bb084adc4986b9a4be3581897f0ee703cbd5Kalle Valo	ret = wl1251_acx_mem_cfg(wl);
2080e71bb084adc4986b9a4be3581897f0ee703cbd5Kalle Valo	if (ret < 0)
2090e71bb084adc4986b9a4be3581897f0ee703cbd5Kalle Valo		return ret;
2100e71bb084adc4986b9a4be3581897f0ee703cbd5Kalle Valo
2110e71bb084adc4986b9a4be3581897f0ee703cbd5Kalle Valo	wl->target_mem_map = kzalloc(sizeof(struct wl1251_acx_mem_map),
2120e71bb084adc4986b9a4be3581897f0ee703cbd5Kalle Valo					  GFP_KERNEL);
2130e71bb084adc4986b9a4be3581897f0ee703cbd5Kalle Valo	if (!wl->target_mem_map) {
2140e71bb084adc4986b9a4be3581897f0ee703cbd5Kalle Valo		wl1251_error("couldn't allocate target memory map");
2150e71bb084adc4986b9a4be3581897f0ee703cbd5Kalle Valo		return -ENOMEM;
2160e71bb084adc4986b9a4be3581897f0ee703cbd5Kalle Valo	}
2170e71bb084adc4986b9a4be3581897f0ee703cbd5Kalle Valo
2180e71bb084adc4986b9a4be3581897f0ee703cbd5Kalle Valo	/* we now ask for the firmware built memory map */
2190e71bb084adc4986b9a4be3581897f0ee703cbd5Kalle Valo	ret = wl1251_acx_mem_map(wl, wl->target_mem_map,
2200e71bb084adc4986b9a4be3581897f0ee703cbd5Kalle Valo				 sizeof(struct wl1251_acx_mem_map));
2210e71bb084adc4986b9a4be3581897f0ee703cbd5Kalle Valo	if (ret < 0) {
2220e71bb084adc4986b9a4be3581897f0ee703cbd5Kalle Valo		wl1251_error("couldn't retrieve firmware memory map");
2230e71bb084adc4986b9a4be3581897f0ee703cbd5Kalle Valo		kfree(wl->target_mem_map);
2240e71bb084adc4986b9a4be3581897f0ee703cbd5Kalle Valo		wl->target_mem_map = NULL;
2250e71bb084adc4986b9a4be3581897f0ee703cbd5Kalle Valo		return ret;
2260e71bb084adc4986b9a4be3581897f0ee703cbd5Kalle Valo	}
2270e71bb084adc4986b9a4be3581897f0ee703cbd5Kalle Valo
2280e71bb084adc4986b9a4be3581897f0ee703cbd5Kalle Valo	return 0;
2290e71bb084adc4986b9a4be3581897f0ee703cbd5Kalle Valo}
2300e71bb084adc4986b9a4be3581897f0ee703cbd5Kalle Valo
2310e71bb084adc4986b9a4be3581897f0ee703cbd5Kalle Valostatic int wl1251_hw_init_txq_fill(u8 qid,
2320e71bb084adc4986b9a4be3581897f0ee703cbd5Kalle Valo				   struct acx_tx_queue_qos_config *config,
2330e71bb084adc4986b9a4be3581897f0ee703cbd5Kalle Valo				   u32 num_blocks)
2340e71bb084adc4986b9a4be3581897f0ee703cbd5Kalle Valo{
2350e71bb084adc4986b9a4be3581897f0ee703cbd5Kalle Valo	config->qid = qid;
2360e71bb084adc4986b9a4be3581897f0ee703cbd5Kalle Valo
2370e71bb084adc4986b9a4be3581897f0ee703cbd5Kalle Valo	switch (qid) {
2380e71bb084adc4986b9a4be3581897f0ee703cbd5Kalle Valo	case QOS_AC_BE:
2390e71bb084adc4986b9a4be3581897f0ee703cbd5Kalle Valo		config->high_threshold =
2400e71bb084adc4986b9a4be3581897f0ee703cbd5Kalle Valo			(QOS_TX_HIGH_BE_DEF * num_blocks) / 100;
2410e71bb084adc4986b9a4be3581897f0ee703cbd5Kalle Valo		config->low_threshold =
2420e71bb084adc4986b9a4be3581897f0ee703cbd5Kalle Valo			(QOS_TX_LOW_BE_DEF * num_blocks) / 100;
2430e71bb084adc4986b9a4be3581897f0ee703cbd5Kalle Valo		break;
2440e71bb084adc4986b9a4be3581897f0ee703cbd5Kalle Valo	case QOS_AC_BK:
2450e71bb084adc4986b9a4be3581897f0ee703cbd5Kalle Valo		config->high_threshold =
2460e71bb084adc4986b9a4be3581897f0ee703cbd5Kalle Valo			(QOS_TX_HIGH_BK_DEF * num_blocks) / 100;
2470e71bb084adc4986b9a4be3581897f0ee703cbd5Kalle Valo		config->low_threshold =
2480e71bb084adc4986b9a4be3581897f0ee703cbd5Kalle Valo			(QOS_TX_LOW_BK_DEF * num_blocks) / 100;
2490e71bb084adc4986b9a4be3581897f0ee703cbd5Kalle Valo		break;
2500e71bb084adc4986b9a4be3581897f0ee703cbd5Kalle Valo	case QOS_AC_VI:
2510e71bb084adc4986b9a4be3581897f0ee703cbd5Kalle Valo		config->high_threshold =
2520e71bb084adc4986b9a4be3581897f0ee703cbd5Kalle Valo			(QOS_TX_HIGH_VI_DEF * num_blocks) / 100;
2530e71bb084adc4986b9a4be3581897f0ee703cbd5Kalle Valo		config->low_threshold =
2540e71bb084adc4986b9a4be3581897f0ee703cbd5Kalle Valo			(QOS_TX_LOW_VI_DEF * num_blocks) / 100;
2550e71bb084adc4986b9a4be3581897f0ee703cbd5Kalle Valo		break;
2560e71bb084adc4986b9a4be3581897f0ee703cbd5Kalle Valo	case QOS_AC_VO:
2570e71bb084adc4986b9a4be3581897f0ee703cbd5Kalle Valo		config->high_threshold =
2580e71bb084adc4986b9a4be3581897f0ee703cbd5Kalle Valo			(QOS_TX_HIGH_VO_DEF * num_blocks) / 100;
2590e71bb084adc4986b9a4be3581897f0ee703cbd5Kalle Valo		config->low_threshold =
2600e71bb084adc4986b9a4be3581897f0ee703cbd5Kalle Valo			(QOS_TX_LOW_VO_DEF * num_blocks) / 100;
2610e71bb084adc4986b9a4be3581897f0ee703cbd5Kalle Valo		break;
2620e71bb084adc4986b9a4be3581897f0ee703cbd5Kalle Valo	default:
2630e71bb084adc4986b9a4be3581897f0ee703cbd5Kalle Valo		wl1251_error("Invalid TX queue id: %d", qid);
2640e71bb084adc4986b9a4be3581897f0ee703cbd5Kalle Valo		return -EINVAL;
2650e71bb084adc4986b9a4be3581897f0ee703cbd5Kalle Valo	}
2660e71bb084adc4986b9a4be3581897f0ee703cbd5Kalle Valo
2670e71bb084adc4986b9a4be3581897f0ee703cbd5Kalle Valo	return 0;
2680e71bb084adc4986b9a4be3581897f0ee703cbd5Kalle Valo}
2690e71bb084adc4986b9a4be3581897f0ee703cbd5Kalle Valo
2700e71bb084adc4986b9a4be3581897f0ee703cbd5Kalle Valostatic int wl1251_hw_init_tx_queue_config(struct wl1251 *wl)
2710e71bb084adc4986b9a4be3581897f0ee703cbd5Kalle Valo{
2720e71bb084adc4986b9a4be3581897f0ee703cbd5Kalle Valo	struct acx_tx_queue_qos_config *config;
2730e71bb084adc4986b9a4be3581897f0ee703cbd5Kalle Valo	struct wl1251_acx_mem_map *wl_mem_map = wl->target_mem_map;
2740e71bb084adc4986b9a4be3581897f0ee703cbd5Kalle Valo	int ret, i;
2750e71bb084adc4986b9a4be3581897f0ee703cbd5Kalle Valo
2760e71bb084adc4986b9a4be3581897f0ee703cbd5Kalle Valo	wl1251_debug(DEBUG_ACX, "acx tx queue config");
2770e71bb084adc4986b9a4be3581897f0ee703cbd5Kalle Valo
2780e71bb084adc4986b9a4be3581897f0ee703cbd5Kalle Valo	config = kzalloc(sizeof(*config), GFP_KERNEL);
2790e71bb084adc4986b9a4be3581897f0ee703cbd5Kalle Valo	if (!config) {
2800e71bb084adc4986b9a4be3581897f0ee703cbd5Kalle Valo		ret = -ENOMEM;
2810e71bb084adc4986b9a4be3581897f0ee703cbd5Kalle Valo		goto out;
2820e71bb084adc4986b9a4be3581897f0ee703cbd5Kalle Valo	}
2830e71bb084adc4986b9a4be3581897f0ee703cbd5Kalle Valo
2840e71bb084adc4986b9a4be3581897f0ee703cbd5Kalle Valo	for (i = 0; i < MAX_NUM_OF_AC; i++) {
2850e71bb084adc4986b9a4be3581897f0ee703cbd5Kalle Valo		ret = wl1251_hw_init_txq_fill(i, config,
2860e71bb084adc4986b9a4be3581897f0ee703cbd5Kalle Valo					      wl_mem_map->num_tx_mem_blocks);
2870e71bb084adc4986b9a4be3581897f0ee703cbd5Kalle Valo		if (ret < 0)
2880e71bb084adc4986b9a4be3581897f0ee703cbd5Kalle Valo			goto out;
2890e71bb084adc4986b9a4be3581897f0ee703cbd5Kalle Valo
2900e71bb084adc4986b9a4be3581897f0ee703cbd5Kalle Valo		ret = wl1251_cmd_configure(wl, ACX_TX_QUEUE_CFG,
2910e71bb084adc4986b9a4be3581897f0ee703cbd5Kalle Valo					   config, sizeof(*config));
2920e71bb084adc4986b9a4be3581897f0ee703cbd5Kalle Valo		if (ret < 0)
2930e71bb084adc4986b9a4be3581897f0ee703cbd5Kalle Valo			goto out;
2940e71bb084adc4986b9a4be3581897f0ee703cbd5Kalle Valo	}
2950e71bb084adc4986b9a4be3581897f0ee703cbd5Kalle Valo
29686dff7a7955f1e14c1f2c142312462fae70ea7e4Kalle Valo	wl1251_acx_ac_cfg(wl, AC_BE, CWMIN_BE, CWMAX_BE, AIFS_DIFS, TXOP_BE);
29786dff7a7955f1e14c1f2c142312462fae70ea7e4Kalle Valo	wl1251_acx_ac_cfg(wl, AC_BK, CWMIN_BK, CWMAX_BK, AIFS_DIFS, TXOP_BK);
29886dff7a7955f1e14c1f2c142312462fae70ea7e4Kalle Valo	wl1251_acx_ac_cfg(wl, AC_VI, CWMIN_VI, CWMAX_VI, AIFS_DIFS, TXOP_VI);
29986dff7a7955f1e14c1f2c142312462fae70ea7e4Kalle Valo	wl1251_acx_ac_cfg(wl, AC_VO, CWMIN_VO, CWMAX_VO, AIFS_DIFS, TXOP_VO);
30086dff7a7955f1e14c1f2c142312462fae70ea7e4Kalle Valo
3010e71bb084adc4986b9a4be3581897f0ee703cbd5Kalle Valoout:
3020e71bb084adc4986b9a4be3581897f0ee703cbd5Kalle Valo	kfree(config);
3030e71bb084adc4986b9a4be3581897f0ee703cbd5Kalle Valo	return ret;
3040e71bb084adc4986b9a4be3581897f0ee703cbd5Kalle Valo}
3050e71bb084adc4986b9a4be3581897f0ee703cbd5Kalle Valo
3060e71bb084adc4986b9a4be3581897f0ee703cbd5Kalle Valostatic int wl1251_hw_init_data_path_config(struct wl1251 *wl)
3070e71bb084adc4986b9a4be3581897f0ee703cbd5Kalle Valo{
3080e71bb084adc4986b9a4be3581897f0ee703cbd5Kalle Valo	int ret;
3090e71bb084adc4986b9a4be3581897f0ee703cbd5Kalle Valo
3100e71bb084adc4986b9a4be3581897f0ee703cbd5Kalle Valo	/* asking for the data path parameters */
3110e71bb084adc4986b9a4be3581897f0ee703cbd5Kalle Valo	wl->data_path = kzalloc(sizeof(struct acx_data_path_params_resp),
3120e71bb084adc4986b9a4be3581897f0ee703cbd5Kalle Valo				GFP_KERNEL);
3130e71bb084adc4986b9a4be3581897f0ee703cbd5Kalle Valo	if (!wl->data_path) {
3140e71bb084adc4986b9a4be3581897f0ee703cbd5Kalle Valo		wl1251_error("Couldnt allocate data path parameters");
3150e71bb084adc4986b9a4be3581897f0ee703cbd5Kalle Valo		return -ENOMEM;
3160e71bb084adc4986b9a4be3581897f0ee703cbd5Kalle Valo	}
3170e71bb084adc4986b9a4be3581897f0ee703cbd5Kalle Valo
3180e71bb084adc4986b9a4be3581897f0ee703cbd5Kalle Valo	ret = wl1251_acx_data_path_params(wl, wl->data_path);
3190e71bb084adc4986b9a4be3581897f0ee703cbd5Kalle Valo	if (ret < 0) {
3200e71bb084adc4986b9a4be3581897f0ee703cbd5Kalle Valo		kfree(wl->data_path);
3210e71bb084adc4986b9a4be3581897f0ee703cbd5Kalle Valo		wl->data_path = NULL;
3220e71bb084adc4986b9a4be3581897f0ee703cbd5Kalle Valo		return ret;
3230e71bb084adc4986b9a4be3581897f0ee703cbd5Kalle Valo	}
3240e71bb084adc4986b9a4be3581897f0ee703cbd5Kalle Valo
3250e71bb084adc4986b9a4be3581897f0ee703cbd5Kalle Valo	return 0;
3260e71bb084adc4986b9a4be3581897f0ee703cbd5Kalle Valo}
3270e71bb084adc4986b9a4be3581897f0ee703cbd5Kalle Valo
3280e71bb084adc4986b9a4be3581897f0ee703cbd5Kalle Valo
3290e71bb084adc4986b9a4be3581897f0ee703cbd5Kalle Valoint wl1251_hw_init(struct wl1251 *wl)
3300e71bb084adc4986b9a4be3581897f0ee703cbd5Kalle Valo{
3310e71bb084adc4986b9a4be3581897f0ee703cbd5Kalle Valo	struct wl1251_acx_mem_map *wl_mem_map;
3320e71bb084adc4986b9a4be3581897f0ee703cbd5Kalle Valo	int ret;
3330e71bb084adc4986b9a4be3581897f0ee703cbd5Kalle Valo
3340e71bb084adc4986b9a4be3581897f0ee703cbd5Kalle Valo	ret = wl1251_hw_init_hwenc_config(wl);
3350e71bb084adc4986b9a4be3581897f0ee703cbd5Kalle Valo	if (ret < 0)
3360e71bb084adc4986b9a4be3581897f0ee703cbd5Kalle Valo		return ret;
3370e71bb084adc4986b9a4be3581897f0ee703cbd5Kalle Valo
3380e71bb084adc4986b9a4be3581897f0ee703cbd5Kalle Valo	/* Template settings */
3390e71bb084adc4986b9a4be3581897f0ee703cbd5Kalle Valo	ret = wl1251_hw_init_templates_config(wl);
3400e71bb084adc4986b9a4be3581897f0ee703cbd5Kalle Valo	if (ret < 0)
3410e71bb084adc4986b9a4be3581897f0ee703cbd5Kalle Valo		return ret;
3420e71bb084adc4986b9a4be3581897f0ee703cbd5Kalle Valo
3430e71bb084adc4986b9a4be3581897f0ee703cbd5Kalle Valo	/* Default memory configuration */
3440e71bb084adc4986b9a4be3581897f0ee703cbd5Kalle Valo	ret = wl1251_hw_init_mem_config(wl);
3450e71bb084adc4986b9a4be3581897f0ee703cbd5Kalle Valo	if (ret < 0)
3460e71bb084adc4986b9a4be3581897f0ee703cbd5Kalle Valo		return ret;
3470e71bb084adc4986b9a4be3581897f0ee703cbd5Kalle Valo
3480e71bb084adc4986b9a4be3581897f0ee703cbd5Kalle Valo	/* Default data path configuration  */
3490e71bb084adc4986b9a4be3581897f0ee703cbd5Kalle Valo	ret = wl1251_hw_init_data_path_config(wl);
3500e71bb084adc4986b9a4be3581897f0ee703cbd5Kalle Valo	if (ret < 0)
3510e71bb084adc4986b9a4be3581897f0ee703cbd5Kalle Valo		goto out_free_memmap;
3520e71bb084adc4986b9a4be3581897f0ee703cbd5Kalle Valo
3530e71bb084adc4986b9a4be3581897f0ee703cbd5Kalle Valo	/* RX config */
3540e71bb084adc4986b9a4be3581897f0ee703cbd5Kalle Valo	ret = wl1251_hw_init_rx_config(wl,
3550e71bb084adc4986b9a4be3581897f0ee703cbd5Kalle Valo				       RX_CFG_PROMISCUOUS | RX_CFG_TSF,
3560e71bb084adc4986b9a4be3581897f0ee703cbd5Kalle Valo				       RX_FILTER_OPTION_DEF);
3570e71bb084adc4986b9a4be3581897f0ee703cbd5Kalle Valo	/* RX_CONFIG_OPTION_ANY_DST_ANY_BSS,
3580e71bb084adc4986b9a4be3581897f0ee703cbd5Kalle Valo	   RX_FILTER_OPTION_FILTER_ALL); */
3590e71bb084adc4986b9a4be3581897f0ee703cbd5Kalle Valo	if (ret < 0)
3600e71bb084adc4986b9a4be3581897f0ee703cbd5Kalle Valo		goto out_free_data_path;
3610e71bb084adc4986b9a4be3581897f0ee703cbd5Kalle Valo
3620e71bb084adc4986b9a4be3581897f0ee703cbd5Kalle Valo	/* TX queues config */
3630e71bb084adc4986b9a4be3581897f0ee703cbd5Kalle Valo	ret = wl1251_hw_init_tx_queue_config(wl);
3640e71bb084adc4986b9a4be3581897f0ee703cbd5Kalle Valo	if (ret < 0)
3650e71bb084adc4986b9a4be3581897f0ee703cbd5Kalle Valo		goto out_free_data_path;
3660e71bb084adc4986b9a4be3581897f0ee703cbd5Kalle Valo
3670e71bb084adc4986b9a4be3581897f0ee703cbd5Kalle Valo	/* PHY layer config */
3680e71bb084adc4986b9a4be3581897f0ee703cbd5Kalle Valo	ret = wl1251_hw_init_phy_config(wl);
3690e71bb084adc4986b9a4be3581897f0ee703cbd5Kalle Valo	if (ret < 0)
3700e71bb084adc4986b9a4be3581897f0ee703cbd5Kalle Valo		goto out_free_data_path;
3710e71bb084adc4986b9a4be3581897f0ee703cbd5Kalle Valo
372474c48c9f2118e637477b3b1c70003cb5cbda983Juuso Oikarinen	/* Initialize connection monitoring thresholds */
373474c48c9f2118e637477b3b1c70003cb5cbda983Juuso Oikarinen	ret = wl1251_acx_conn_monit_params(wl);
374474c48c9f2118e637477b3b1c70003cb5cbda983Juuso Oikarinen	if (ret < 0)
375474c48c9f2118e637477b3b1c70003cb5cbda983Juuso Oikarinen		goto out_free_data_path;
376474c48c9f2118e637477b3b1c70003cb5cbda983Juuso Oikarinen
3770e71bb084adc4986b9a4be3581897f0ee703cbd5Kalle Valo	/* Beacon filtering */
3780e71bb084adc4986b9a4be3581897f0ee703cbd5Kalle Valo	ret = wl1251_hw_init_beacon_filter(wl);
3790e71bb084adc4986b9a4be3581897f0ee703cbd5Kalle Valo	if (ret < 0)
3800e71bb084adc4986b9a4be3581897f0ee703cbd5Kalle Valo		goto out_free_data_path;
3810e71bb084adc4986b9a4be3581897f0ee703cbd5Kalle Valo
3820e71bb084adc4986b9a4be3581897f0ee703cbd5Kalle Valo	/* Bluetooth WLAN coexistence */
3830e71bb084adc4986b9a4be3581897f0ee703cbd5Kalle Valo	ret = wl1251_hw_init_pta(wl);
3840e71bb084adc4986b9a4be3581897f0ee703cbd5Kalle Valo	if (ret < 0)
3850e71bb084adc4986b9a4be3581897f0ee703cbd5Kalle Valo		goto out_free_data_path;
3860e71bb084adc4986b9a4be3581897f0ee703cbd5Kalle Valo
3870e71bb084adc4986b9a4be3581897f0ee703cbd5Kalle Valo	/* Energy detection */
3880e71bb084adc4986b9a4be3581897f0ee703cbd5Kalle Valo	ret = wl1251_hw_init_energy_detection(wl);
3890e71bb084adc4986b9a4be3581897f0ee703cbd5Kalle Valo	if (ret < 0)
3900e71bb084adc4986b9a4be3581897f0ee703cbd5Kalle Valo		goto out_free_data_path;
3910e71bb084adc4986b9a4be3581897f0ee703cbd5Kalle Valo
3920e71bb084adc4986b9a4be3581897f0ee703cbd5Kalle Valo	/* Beacons and boradcast settings */
3930e71bb084adc4986b9a4be3581897f0ee703cbd5Kalle Valo	ret = wl1251_hw_init_beacon_broadcast(wl);
3940e71bb084adc4986b9a4be3581897f0ee703cbd5Kalle Valo	if (ret < 0)
3950e71bb084adc4986b9a4be3581897f0ee703cbd5Kalle Valo		goto out_free_data_path;
3960e71bb084adc4986b9a4be3581897f0ee703cbd5Kalle Valo
3979281691fb2e48f0853bb986a9049e5d9c8bf1578David Gnedt	/* Enable rx data path */
3989281691fb2e48f0853bb986a9049e5d9c8bf1578David Gnedt	ret = wl1251_cmd_data_path_rx(wl, wl->channel, 1);
3999281691fb2e48f0853bb986a9049e5d9c8bf1578David Gnedt	if (ret < 0)
4009281691fb2e48f0853bb986a9049e5d9c8bf1578David Gnedt		goto out_free_data_path;
4019281691fb2e48f0853bb986a9049e5d9c8bf1578David Gnedt
4029281691fb2e48f0853bb986a9049e5d9c8bf1578David Gnedt	/* Enable tx data path */
4039281691fb2e48f0853bb986a9049e5d9c8bf1578David Gnedt	ret = wl1251_cmd_data_path_tx(wl, wl->channel, 1);
4040e71bb084adc4986b9a4be3581897f0ee703cbd5Kalle Valo	if (ret < 0)
4050e71bb084adc4986b9a4be3581897f0ee703cbd5Kalle Valo		goto out_free_data_path;
4060e71bb084adc4986b9a4be3581897f0ee703cbd5Kalle Valo
4070e71bb084adc4986b9a4be3581897f0ee703cbd5Kalle Valo	/* Default power state */
4080e71bb084adc4986b9a4be3581897f0ee703cbd5Kalle Valo	ret = wl1251_hw_init_power_auth(wl);
4090e71bb084adc4986b9a4be3581897f0ee703cbd5Kalle Valo	if (ret < 0)
4100e71bb084adc4986b9a4be3581897f0ee703cbd5Kalle Valo		goto out_free_data_path;
4110e71bb084adc4986b9a4be3581897f0ee703cbd5Kalle Valo
4120e71bb084adc4986b9a4be3581897f0ee703cbd5Kalle Valo	wl_mem_map = wl->target_mem_map;
4130e71bb084adc4986b9a4be3581897f0ee703cbd5Kalle Valo	wl1251_info("%d tx blocks at 0x%x, %d rx blocks at 0x%x",
4140e71bb084adc4986b9a4be3581897f0ee703cbd5Kalle Valo		    wl_mem_map->num_tx_mem_blocks,
4150e71bb084adc4986b9a4be3581897f0ee703cbd5Kalle Valo		    wl->data_path->tx_control_addr,
4160e71bb084adc4986b9a4be3581897f0ee703cbd5Kalle Valo		    wl_mem_map->num_rx_mem_blocks,
4170e71bb084adc4986b9a4be3581897f0ee703cbd5Kalle Valo		    wl->data_path->rx_control_addr);
4180e71bb084adc4986b9a4be3581897f0ee703cbd5Kalle Valo
4190e71bb084adc4986b9a4be3581897f0ee703cbd5Kalle Valo	return 0;
4200e71bb084adc4986b9a4be3581897f0ee703cbd5Kalle Valo
4210e71bb084adc4986b9a4be3581897f0ee703cbd5Kalle Valo out_free_data_path:
4220e71bb084adc4986b9a4be3581897f0ee703cbd5Kalle Valo	kfree(wl->data_path);
4230e71bb084adc4986b9a4be3581897f0ee703cbd5Kalle Valo
4240e71bb084adc4986b9a4be3581897f0ee703cbd5Kalle Valo out_free_memmap:
4250e71bb084adc4986b9a4be3581897f0ee703cbd5Kalle Valo	kfree(wl->target_mem_map);
4260e71bb084adc4986b9a4be3581897f0ee703cbd5Kalle Valo
4270e71bb084adc4986b9a4be3581897f0ee703cbd5Kalle Valo	return ret;
4280e71bb084adc4986b9a4be3581897f0ee703cbd5Kalle Valo}
429