From patchwork Thu Sep 19 13:52:38 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: =?utf-8?b?SsOpcsO0bWUgUG91aWxsZXI=?= X-Patchwork-Id: 11152439 X-Patchwork-Delegate: johannes@sipsolutions.net Return-Path: Received: from mail.kernel.org (pdx-korg-mail-1.web.codeaurora.org [172.30.200.123]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id 9A32116B1 for ; Thu, 19 Sep 2019 13:54:07 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by mail.kernel.org (Postfix) with ESMTP id 5CC7021D80 for ; Thu, 19 Sep 2019 13:54:07 +0000 (UTC) Authentication-Results: mail.kernel.org; dkim=pass (1024-bit key) header.d=silabs.onmicrosoft.com header.i=@silabs.onmicrosoft.com header.b="VZ8J1LeJ" Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S2390633AbfISNxr (ORCPT ); Thu, 19 Sep 2019 09:53:47 -0400 Received: from mail-eopbgr800072.outbound.protection.outlook.com ([40.107.80.72]:49376 "EHLO NAM03-DM3-obe.outbound.protection.outlook.com" rhost-flags-OK-OK-OK-FAIL) by vger.kernel.org with ESMTP id S2403836AbfISNwu (ORCPT ); Thu, 19 Sep 2019 09:52:50 -0400 ARC-Seal: i=1; a=rsa-sha256; s=arcselector9901; d=microsoft.com; cv=none; b=TyvD0O7w5rRbVA3WSb2N2BYzwwBcpx7xurqZX+Nzs9PefCGHqptrqF3S7m3S9O5Q95SdckHH3dvLxkI6+Jna73wUitGgh1YCdquvvknNJzPrmsLmzTzsK78s42MmZufjpuMCn1X7k1g5hFLQ5Ugr6Oz18TmXgE5+5vkLA03TvLzEdv9S20vkg6sjVwWojPVXQ9V134B3ugznK6SGNK7PkwARVk25rH2IIOrEcEx40e002whZp5tpCqhWWuwyJIanrrsxY3hC3OPTTfkzm0ZgP4NXsffFtGIu7clm4sEwSsy8eSITHGwQr497RHpTr+NwFBnXSXqCuviqmBgdpTDHYg== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=microsoft.com; s=arcselector9901; h=From:Date:Subject:Message-ID:Content-Type:MIME-Version:X-MS-Exchange-SenderADCheck; bh=v+VuhidZiuSFycge8YlvXs/crNTYDKdMRuK0diS96DM=; b=jpMjjCRwZA1r7Htyi2F3gRupPigQXaUcSpDsX1SLBmNyCzQ5LSGA5B1jHNCkjsF95KMAtwXlbY0bprLmGw+Mn7zh1021tP+Tr4agLVN3jHr7ZXumA7MT+NF8+rx0Neq6KYJb32p9S2A79p7FkB2kL7a8ILp868TcynNtawlMywYMJvFjr8Rck2yaNQztnbXKmsR+QBJVBV+87QA6G9vQDIwfkaw/bsqn6MRgjzYYeqJS1SmL0m1lNq0nKjByKUl87n4R/SkO/G56K/XMU8lyhBgPdrGZerMk6GcEKX1MRjK2QTESHBUkk9D4h0qy0ObEZNWw30rolav2Hss2JvlKbA== ARC-Authentication-Results: i=1; mx.microsoft.com 1; spf=pass smtp.mailfrom=silabs.com; dmarc=pass action=none header.from=silabs.com; dkim=pass header.d=silabs.com; arc=none DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=silabs.onmicrosoft.com; s=selector2-silabs-onmicrosoft-com; h=From:Date:Subject:Message-ID:Content-Type:MIME-Version:X-MS-Exchange-SenderADCheck; bh=v+VuhidZiuSFycge8YlvXs/crNTYDKdMRuK0diS96DM=; b=VZ8J1LeJ29TqauOUlAHc7Sw03ep9rPsGQCbgkbVGwHm0tOn3am0uXoXPb6LdAcSx/BIq2AY1l3jakgJX/5AofBqvFRalrhM8K5iPJKVCfyraqg+FmTAIKFWAQCIv/t/TqNhGGw3qpv1yKc1wyqpyr/TznjLZKU0QCNXc6Z2Sd3k= Received: from MN2PR11MB4063.namprd11.prod.outlook.com (20.179.149.217) by MN2PR11MB3871.namprd11.prod.outlook.com (10.255.180.204) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.20.2284.18; Thu, 19 Sep 2019 13:52:39 +0000 Received: from MN2PR11MB4063.namprd11.prod.outlook.com ([fe80::45dc:e073:4446:4bf8]) by MN2PR11MB4063.namprd11.prod.outlook.com ([fe80::45dc:e073:4446:4bf8%3]) with mapi id 15.20.2263.023; Thu, 19 Sep 2019 13:52:39 +0000 From: Jerome Pouiller To: "devel@driverdev.osuosl.org" , "linux-wireless@vger.kernel.org" CC: "netdev@vger.kernel.org" , "linux-kernel@vger.kernel.org" , Greg Kroah-Hartman , Kalle Valo , "David S . Miller" , David Le Goff , Jerome Pouiller Subject: [PATCH v2 14/20] staging: wfx: setup initial chip configuration Thread-Topic: [PATCH v2 14/20] staging: wfx: setup initial chip configuration Thread-Index: AQHVbvF/vmtpAzBNLkK67GdRYRiEXA== Date: Thu, 19 Sep 2019 13:52:38 +0000 Message-ID: <20190919135220.30663-15-Jerome.Pouiller@silabs.com> References: <20190919135220.30663-1-Jerome.Pouiller@silabs.com> In-Reply-To: <20190919135220.30663-1-Jerome.Pouiller@silabs.com> Accept-Language: en-US Content-Language: en-US X-MS-Has-Attach: X-MS-TNEF-Correlator: authentication-results: spf=none (sender IP is ) smtp.mailfrom=Jerome.Pouiller@silabs.com; x-originating-ip: [37.71.187.125] x-ms-publictraffictype: Email x-ms-office365-filtering-correlation-id: 38a544ca-e871-4869-1049-08d73d08a280 x-microsoft-antispam: BCL:0;PCL:0;RULEID:(2390118)(7020095)(4652040)(8989299)(4534185)(4627221)(201703031133081)(201702281549075)(8990200)(5600167)(711020)(4605104)(1401327)(2017052603328)(7193020);SRVR:MN2PR11MB3871; x-ms-traffictypediagnostic: MN2PR11MB3871: x-ms-exchange-purlcount: 1 x-ms-exchange-transport-forked: True x-microsoft-antispam-prvs: x-ms-oob-tlc-oobclassifiers: OLM:494; x-forefront-prvs: 016572D96D x-forefront-antispam-report: SFV:NSPM;SFS:(10009020)(136003)(396003)(376002)(366004)(346002)(39850400004)(199004)(189003)(305945005)(2906002)(71190400001)(186003)(71200400001)(7736002)(91956017)(1076003)(66574012)(25786009)(66476007)(86362001)(66446008)(64756008)(66556008)(6506007)(3846002)(36756003)(2501003)(14444005)(486006)(11346002)(256004)(2616005)(476003)(76116006)(26005)(66946007)(446003)(76176011)(14454004)(8936002)(99286004)(66066001)(478600001)(81166006)(107886003)(5660300002)(102836004)(6116002)(81156014)(8676002)(316002)(966005)(4326008)(54906003)(6486002)(6306002)(110136005)(6512007)(6436002);DIR:OUT;SFP:1101;SCL:1;SRVR:MN2PR11MB3871;H:MN2PR11MB4063.namprd11.prod.outlook.com;FPR:;SPF:None;LANG:en;PTR:InfoNoRecords;A:1;MX:1; received-spf: None (protection.outlook.com: silabs.com does not designate permitted sender hosts) x-ms-exchange-senderadcheck: 1 x-microsoft-antispam-message-info: kjPUaK9JS/lEX88J7FskuGLwT9xC+kV+e01n6KLOiqG0+huhamltJXX4b8FSjqTF5IQse95ceWS28IUNoewB2WR84q3WAOQNsmeyVWetsjtNJS3qsZWClqfDWzm2HQyveGy54pzyjvJ4eH52vATj7DdaIltWBQ/k2TTpHfnTPWUZt8MpROs+8bA6wlpIchzWHm3EY3iWUVTK4/8m9ArNo20pQ/+4Z/pMhTvQ+OwzXZT0D53lZrvbP3ZFEvv1vO84Gs9XCSoE61o48P0ssPUS3YvBIRofBQKtcIin5zbTIh2cX15HGgly7bqdFjUpuzEQLJ7G2JJcV1RthnpXnBrke2Nyv+R3r06d0Od/KI+KTXdq7r8pSFafRt3x0C3q9LylVaddFwL+x1dIhgAnjwBjJb/l9APalIklCDwJ/RuzOe0= Content-ID: <3D155BEFF791FB4E9917E6B1EFFD61D5@namprd11.prod.outlook.com> MIME-Version: 1.0 X-OriginatorOrg: silabs.com X-MS-Exchange-CrossTenant-Network-Message-Id: 38a544ca-e871-4869-1049-08d73d08a280 X-MS-Exchange-CrossTenant-originalarrivaltime: 19 Sep 2019 13:52:38.1144 (UTC) X-MS-Exchange-CrossTenant-fromentityheader: Hosted X-MS-Exchange-CrossTenant-id: 54dbd822-5231-4b20-944d-6f4abcd541fb X-MS-Exchange-CrossTenant-mailboxtype: HOSTED X-MS-Exchange-CrossTenant-userprincipalname: buHeN1pfXUFwGrhkypstwbHHj+p15CGzYr5xtzPaAWOqd7zh1rAvqpVRnRFu+coTuQoyBrWASQI1o//wauXv6g== X-MS-Exchange-Transport-CrossTenantHeadersStamped: MN2PR11MB3871 Sender: linux-wireless-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-wireless@vger.kernel.org From: Jérôme Pouiller A few tasks remain to be done in order to finish chip initial configuration: - configure chip to use multi-tx confirmation (speed up data transfer) - configure chip to use wake-up feature (save power consumption during runtime) - set hardware configuration (clocks, RF, pinout, etc...) using a Platform Data Set (PDS) file On release, driver completely shutdown the chip to save power consumption. Documentation about PDS and PDS data for sample boards are available here[1]. One day, PDS data may find a place in device tree but, currently, PDS is too much linked with firmware to allowing that. This patch also add "send_pds" file in debugfs to be able to dynamically change PDS (only for debug, of course). [1]: https://github.com/SiliconLabs/wfx-firmware/tree/master/PDS Signed-off-by: Jérôme Pouiller --- drivers/staging/wfx/bus_sdio.c | 1 + drivers/staging/wfx/bus_spi.c | 1 + drivers/staging/wfx/debug.c | 29 +++++++++++ drivers/staging/wfx/hif_rx.c | 11 ++++ drivers/staging/wfx/main.c | 94 ++++++++++++++++++++++++++++++++++ drivers/staging/wfx/main.h | 2 + 6 files changed, 138 insertions(+) diff --git a/drivers/staging/wfx/bus_sdio.c b/drivers/staging/wfx/bus_sdio.c index c0c063c3cfc9..05f02c278782 100644 --- a/drivers/staging/wfx/bus_sdio.c +++ b/drivers/staging/wfx/bus_sdio.c @@ -19,6 +19,7 @@ static const struct wfx_platform_data wfx_sdio_pdata = { .file_fw = "wfm_wf200", + .file_pds = "wf200.pds", }; struct wfx_sdio_priv { diff --git a/drivers/staging/wfx/bus_spi.c b/drivers/staging/wfx/bus_spi.c index b7cd82b4e5e7..f65f7d75e731 100644 --- a/drivers/staging/wfx/bus_spi.c +++ b/drivers/staging/wfx/bus_spi.c @@ -29,6 +29,7 @@ MODULE_PARM_DESC(gpio_reset, "gpio number for reset. -1 for none."); static const struct wfx_platform_data wfx_spi_pdata = { .file_fw = "wfm_wf200", + .file_pds = "wf200.pds", .use_rising_clk = true, }; diff --git a/drivers/staging/wfx/debug.c b/drivers/staging/wfx/debug.c index f79693a4be7f..0619c7d1cf79 100644 --- a/drivers/staging/wfx/debug.c +++ b/drivers/staging/wfx/debug.c @@ -10,6 +10,7 @@ #include "debug.h" #include "wfx.h" +#include "main.h" #define CREATE_TRACE_POINTS #include "traces.h" @@ -54,6 +55,33 @@ const char *get_reg_name(unsigned long id) return get_symbol(id, wfx_reg_print_map); } +static ssize_t wfx_send_pds_write(struct file *file, const char __user *user_buf, + size_t count, loff_t *ppos) +{ + struct wfx_dev *wdev = file->private_data; + char *buf; + int ret; + + if (*ppos != 0) { + dev_dbg(wdev->dev, "PDS data must be written in one transaction"); + return -EBUSY; + } + buf = memdup_user(user_buf, count); + if (IS_ERR(buf)) + return PTR_ERR(buf); + *ppos = *ppos + count; + ret = wfx_send_pds(wdev, buf, count); + kfree(buf); + if (ret < 0) + return ret; + return count; +} + +static const struct file_operations wfx_send_pds_fops = { + .open = simple_open, + .write = wfx_send_pds_write, +}; + static ssize_t wfx_burn_slk_key_write(struct file *file, const char __user *user_buf, size_t count, loff_t *ppos) @@ -162,6 +190,7 @@ int wfx_debug_init(struct wfx_dev *wdev) struct dentry *d; d = debugfs_create_dir("wfx", wdev->hw->wiphy->debugfsdir); + debugfs_create_file("send_pds", 0200, d, wdev, &wfx_send_pds_fops); debugfs_create_file("burn_slk_key", 0200, d, wdev, &wfx_burn_slk_key_fops); debugfs_create_file("send_hif_msg", 0600, d, wdev, &wfx_send_hif_msg_fops); diff --git a/drivers/staging/wfx/hif_rx.c b/drivers/staging/wfx/hif_rx.c index dd5f1dea4e85..6b9683d69a3f 100644 --- a/drivers/staging/wfx/hif_rx.c +++ b/drivers/staging/wfx/hif_rx.c @@ -71,6 +71,16 @@ static int hif_startup_indication(struct wfx_dev *wdev, struct hif_msg *hif, voi return 0; } +static int hif_wakeup_indication(struct wfx_dev *wdev, struct hif_msg *hif, void *buf) +{ + if (!wdev->pdata.gpio_wakeup + || !gpiod_get_value(wdev->pdata.gpio_wakeup)) { + dev_warn(wdev->dev, "unexpected wake-up indication\n"); + return -EIO; + } + return 0; +} + static int hif_keys_indication(struct wfx_dev *wdev, struct hif_msg *hif, void *buf) { struct hif_ind_sl_exchange_pub_keys *body = buf; @@ -89,6 +99,7 @@ static const struct { int (*handler)(struct wfx_dev *wdev, struct hif_msg *hif, void *buf); } hif_handlers[] = { { HIF_IND_ID_STARTUP, hif_startup_indication }, + { HIF_IND_ID_WAKEUP, hif_wakeup_indication }, { HIF_IND_ID_SL_EXCHANGE_PUB_KEYS, hif_keys_indication }, }; diff --git a/drivers/staging/wfx/main.c b/drivers/staging/wfx/main.c index 0cfd6b2ec8d1..5b04ea5f4353 100644 --- a/drivers/staging/wfx/main.c +++ b/drivers/staging/wfx/main.c @@ -18,6 +18,7 @@ #include #include #include +#include #include "main.h" #include "wfx.h" @@ -28,9 +29,12 @@ #include "sta.h" #include "debug.h" #include "secure_link.h" +#include "hif_tx_mib.h" #include "hif_api_cmd.h" #include "wfx_version.h" +#define WFX_PDS_MAX_SIZE 1500 + MODULE_DESCRIPTION("Silicon Labs 802.11 Wireless LAN driver for WFx"); MODULE_AUTHOR("Jérôme Pouiller "); MODULE_LICENSE("GPL"); @@ -112,6 +116,69 @@ static void wfx_fill_sl_key(struct device *dev, struct wfx_platform_data *pdata) dev_err(dev, "secure link is not supported by this driver, ignoring provided key\n"); } +/* NOTE: wfx_send_pds() destroy buf */ +int wfx_send_pds(struct wfx_dev *wdev, unsigned char *buf, size_t len) +{ + int ret; + int start, brace_level, i; + + start = 0; + brace_level = 0; + if (buf[0] != '{') { + dev_err(wdev->dev, "valid PDS start with '{'. Did you forget to compress it?\n"); + return -EINVAL; + } + for (i = 1; i < len - 1; i++) { + if (buf[i] == '{') + brace_level++; + if (buf[i] == '}') + brace_level--; + if (buf[i] == '}' && !brace_level) { + i++; + if (i - start + 1 > WFX_PDS_MAX_SIZE) + return -EFBIG; + buf[start] = '{'; + buf[i] = 0; + dev_dbg(wdev->dev, "send PDS '%s}'\n", buf + start); + buf[i] = '}'; + ret = hif_configuration(wdev, buf + start, i - start + 1); + if (ret == HIF_STATUS_FAILURE) { + dev_err(wdev->dev, "PDS bytes %d to %d: invalid data (unsupported options?)\n", start, i); + return -EINVAL; + } + if (ret == -ETIMEDOUT) { + dev_err(wdev->dev, "PDS bytes %d to %d: chip didn't reply (corrupted file?)\n", start, i); + return ret; + } + if (ret) { + dev_err(wdev->dev, "PDS bytes %d to %d: chip returned an unknown error\n", start, i); + return -EIO; + } + buf[i] = ','; + start = i; + } + } + return 0; +} + +static int wfx_send_pdata_pds(struct wfx_dev *wdev) +{ + int ret = 0; + const struct firmware *pds; + unsigned char *tmp_buf; + + ret = request_firmware(&pds, wdev->pdata.file_pds, wdev->dev); + if (ret) { + dev_err(wdev->dev, "can't load PDS file %s\n", wdev->pdata.file_pds); + return ret; + } + tmp_buf = kmemdup(pds->data, pds->size, GFP_KERNEL); + ret = wfx_send_pds(wdev, tmp_buf, pds->size); + kfree(tmp_buf); + release_firmware(pds); + return ret; +} + struct wfx_dev *wfx_init_common(struct device *dev, const struct wfx_platform_data *pdata, const struct hwbus_ops *hwbus_ops, @@ -141,6 +208,8 @@ struct wfx_dev *wfx_init_common(struct device *dev, wdev->hwbus_ops = hwbus_ops; wdev->hwbus_priv = hwbus_priv; memcpy(&wdev->pdata, pdata, sizeof(*pdata)); + of_property_read_string(dev->of_node, "config-file", &wdev->pdata.file_pds); + wdev->pdata.gpio_wakeup = wfx_get_gpio(dev, gpio_wakeup, "wakeup"); wfx_fill_sl_key(dev, &wdev->pdata); init_completion(&wdev->firmware_ready); @@ -159,6 +228,12 @@ int wfx_probe(struct wfx_dev *wdev) int i; int err; const void *macaddr; + struct gpio_desc *gpio_saved; + + // During first part of boot, gpio_wakeup cannot yet been used. So + // prevent bh() to touch it. + gpio_saved = wdev->pdata.gpio_wakeup; + wdev->pdata.gpio_wakeup = NULL; wfx_bh_register(wdev); @@ -202,6 +277,24 @@ int wfx_probe(struct wfx_dev *wdev) goto err1; } + dev_dbg(wdev->dev, "sending configuration file %s\n", wdev->pdata.file_pds); + err = wfx_send_pdata_pds(wdev); + if (err < 0) + goto err1; + + wdev->pdata.gpio_wakeup = gpio_saved; + if (wdev->pdata.gpio_wakeup) { + dev_dbg(wdev->dev, "enable 'quiescent' power mode with gpio %d and PDS file %s\n", + desc_to_gpio(wdev->pdata.gpio_wakeup), wdev->pdata.file_pds); + gpiod_set_value(wdev->pdata.gpio_wakeup, 1); + control_reg_write(wdev, 0); + hif_set_operational_mode(wdev, HIF_OP_POWER_MODE_QUIESCENT); + } else { + hif_set_operational_mode(wdev, HIF_OP_POWER_MODE_DOZE); + } + + hif_use_multi_tx_conf(wdev, true); + for (i = 0; i < ARRAY_SIZE(wdev->addresses); i++) { eth_zero_addr(wdev->addresses[i].addr); macaddr = of_get_mac_address(wdev->dev->of_node); @@ -232,6 +325,7 @@ int wfx_probe(struct wfx_dev *wdev) void wfx_release(struct wfx_dev *wdev) { + hif_shutdown(wdev); wfx_bh_unregister(wdev); wfx_sl_deinit(wdev); } diff --git a/drivers/staging/wfx/main.h b/drivers/staging/wfx/main.h index 2c9c215455ce..f2b07ed1627c 100644 --- a/drivers/staging/wfx/main.h +++ b/drivers/staging/wfx/main.h @@ -21,6 +21,7 @@ struct wfx_dev; struct wfx_platform_data { /* Keyset and ".sec" extention will appended to this string */ const char *file_fw; + const char *file_pds; unsigned char slk_key[API_KEY_VALUE_SIZE]; struct gpio_desc *gpio_wakeup; /* @@ -42,5 +43,6 @@ void wfx_release(struct wfx_dev *wdev); struct gpio_desc *wfx_get_gpio(struct device *dev, int override, const char *label); bool wfx_api_older_than(struct wfx_dev *wdev, int major, int minor); +int wfx_send_pds(struct wfx_dev *wdev, unsigned char *buf, size_t len); #endif