From patchwork Thu Sep 19 10:52:41 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: 11152169 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 EB53014DB for ; Thu, 19 Sep 2019 10:55:18 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by mail.kernel.org (Postfix) with ESMTP id AB9CA21924 for ; Thu, 19 Sep 2019 10:55:18 +0000 (UTC) Authentication-Results: mail.kernel.org; dkim=pass (1024-bit key) header.d=silabs.onmicrosoft.com header.i=@silabs.onmicrosoft.com header.b="KZZZdT/h" Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S2389772AbfISKzH (ORCPT ); Thu, 19 Sep 2019 06:55:07 -0400 Received: from mail-eopbgr730082.outbound.protection.outlook.com ([40.107.73.82]:1632 "EHLO NAM05-DM3-obe.outbound.protection.outlook.com" rhost-flags-OK-OK-OK-FAIL) by vger.kernel.org with ESMTP id S2389415AbfISKwr (ORCPT ); Thu, 19 Sep 2019 06:52:47 -0400 ARC-Seal: i=1; a=rsa-sha256; s=arcselector9901; d=microsoft.com; cv=none; b=NOEKMqxnaZC4Ec/Ic76Yuvu2Pf7gaNJfO57/E0sfwW1Dz2XohXKUEWC3CyI/+FFj+Hc5stp9BxuLzLjVUYccfZeSU04oeSRGRDhhhr+UPi9KytKaiLGXWKM7e+TJnTzpB01NpoOuvlx4OfypEpb+961s8FbebDV2r6qHzFgMtBzRQSTO+2PB11ljh86eVt9R4gmbsFZeW7Dyc9Aa/Em0/SCzdvC64Ar5dz0ZSJamuArKBZaf3LRoTisR6gH/6YfW1XnKqA3KODKg0Q4HnyU+SlzVEBQ93tEur7OL8QGWNh1wDBrEL6PB7w9JMXVdEE59Y8w7o4h2gwrkR8rSd3mzsA== 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=GAuEJd1m/W2ssuVkuPzuJbm16vtuvyO128flRB+a6iI=; b=jpcCjLgRrKZkqN4KRhTBNld3T+9LTxEic73z1tzlU5vTBGaYSygUNBYs8HqAN4uogeFvvHGln/F1CdWlTlEhZxCyOywS84Md1o09DDFNUC/5iJAWnaKBdev3uaajhIzdtbWKFyS4YmhDLiP9Z+kKIZWcOBJQmb2PrCCN+nrwnHDvocH8ZWF9viGPC3sq/vlFFOcVBqihVzkd9BTrz8ahEaQM3QQFGQHlr/8QbAyJH+i5X5qq4JPm8OgrbsDBGB97FGlaO93NBy5zIMy+erjm+0GTt3EX+pcNsIloYWxGrV6AxmDCPVWO/wHfdCHN9x3bj9GK+fSI3pT7kJFmYZslHw== 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=GAuEJd1m/W2ssuVkuPzuJbm16vtuvyO128flRB+a6iI=; b=KZZZdT/hVyzd9wjg5LMLMfTx0LDgYGi4WwoEbnt9OP983hC/cMIYerHogziAd/zP7cPhJFetYTB/szZs0SSPddC8Y36Rhd/d77ac2jO1u4RIV0YE4Oj6rpv/21saCSZTjh0IABI5PodpauHvCEbPr4QHx9ZVDE2fwNGQUN4/SFc= Received: from MN2PR11MB4063.namprd11.prod.outlook.com (20.179.149.217) by MN2PR11MB4415.namprd11.prod.outlook.com (52.135.39.95) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.20.2263.17; Thu, 19 Sep 2019 10:52:43 +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 10:52:43 +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 14/20] staging: wfx: setup initial chip configuration Thread-Topic: [PATCH 14/20] staging: wfx: setup initial chip configuration Thread-Index: AQHVbthcHyoij0GWT0m4YSubLjb5JA== Date: Thu, 19 Sep 2019 10:52:41 +0000 Message-ID: <20190919105153.15285-15-Jerome.Pouiller@silabs.com> References: <20190919105153.15285-1-Jerome.Pouiller@silabs.com> In-Reply-To: <20190919105153.15285-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: 9983e75a-1d3e-4edb-be9a-08d73cef7f9c x-microsoft-antispam: BCL:0;PCL:0;RULEID:(2390118)(7020095)(4652040)(8989299)(5600167)(711020)(4605104)(1401327)(4534185)(4627221)(201703031133081)(201702281549075)(8990200)(2017052603328)(7193020);SRVR:MN2PR11MB4415; x-ms-traffictypediagnostic: MN2PR11MB4415: 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)(346002)(396003)(366004)(39850400004)(376002)(136003)(189003)(199004)(14454004)(71190400001)(2906002)(81156014)(81166006)(478600001)(316002)(2501003)(64756008)(76176011)(66476007)(256004)(86362001)(66446008)(99286004)(25786009)(8676002)(66556008)(66946007)(11346002)(6512007)(110136005)(66574012)(5660300002)(54906003)(6436002)(71200400001)(14444005)(76116006)(3846002)(6506007)(91956017)(966005)(1076003)(6116002)(486006)(305945005)(36756003)(2616005)(446003)(4326008)(6306002)(7736002)(8936002)(66066001)(186003)(107886003)(26005)(476003)(6486002)(102836004);DIR:OUT;SFP:1101;SCL:1;SRVR:MN2PR11MB4415;H:MN2PR11MB4063.namprd11.prod.outlook.com;FPR:;SPF:None;LANG:en;PTR:InfoNoRecords;MX:1;A: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: 6gJhdR4ZSvt+/K+ex8/HJVRu5CuOTbKWNsUMtn40g/LUWoICa1DfSlnB2c09kw2YpxoA1c9L+KRP3TQw4RmMuiM/5PVGBmvrNI3qRA3Jorrqov15EznD5+ImnWf9jSwwfnkYEWY67NO2Zm4a6nB/Z5QjDXz1d6sgLEGJRV/Cx0C9G3fpnrBqjAuQ3Jk8pLMQnLVwaZF0AjjGqwE8+A+hl/aoH+JX8YcSbT/DWns9Le2492WiG9OJPdPW06WjHKg79NJphbyMnSKT643hS1UxzUdDree8VggJUEWbgpuAnnUJE3pHXL+TFbfhnZ7P3F94zopBX3mKo+zfnMIK0QxlU2QHEs6fSweiq+PcSuJ8sxxelMP6kSLvJ6RP0yeOGeHAFnScXLRicrDgxiZ52Kk7UEPvJSKWLpT3CKGcbRqCviA= Content-ID: <2614ED3FB5F31642B6561BB79EA5145D@namprd11.prod.outlook.com> MIME-Version: 1.0 X-OriginatorOrg: silabs.com X-MS-Exchange-CrossTenant-Network-Message-Id: 9983e75a-1d3e-4edb-be9a-08d73cef7f9c X-MS-Exchange-CrossTenant-originalarrivaltime: 19 Sep 2019 10:52:41.5672 (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: vUAwRDtkDgdscXFIwhrHuiLb9PEkS8j26yt6Z6GNlXIk0mZ9aAzYlI0zW5m9DILDOCFcYzWppjq95FjF+/eSqA== X-MS-Exchange-Transport-CrossTenantHeadersStamped: MN2PR11MB4415 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 8a9aab3e7384..163342b66a5e 100644 --- a/drivers/staging/wfx/bus_spi.c +++ b/drivers/staging/wfx/bus_spi.c @@ -32,6 +32,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