From patchwork Thu Sep 19 14:25:44 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: 11152689 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 76C4814ED for ; Thu, 19 Sep 2019 14:27:29 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by mail.kernel.org (Postfix) with ESMTP id 3D95B218AF for ; Thu, 19 Sep 2019 14:27:29 +0000 (UTC) Authentication-Results: mail.kernel.org; dkim=pass (1024-bit key) header.d=silabs.onmicrosoft.com header.i=@silabs.onmicrosoft.com header.b="SQlO6vJW" Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S2389387AbfISOZw (ORCPT ); Thu, 19 Sep 2019 10:25:52 -0400 Received: from mail-eopbgr780053.outbound.protection.outlook.com ([40.107.78.53]:38626 "EHLO NAM03-BY2-obe.outbound.protection.outlook.com" rhost-flags-OK-OK-OK-FAIL) by vger.kernel.org with ESMTP id S2389228AbfISOZw (ORCPT ); Thu, 19 Sep 2019 10:25:52 -0400 ARC-Seal: i=1; a=rsa-sha256; s=arcselector9901; d=microsoft.com; cv=none; b=gKy9MnIzelyX+jEs76Cwl9CgWMEB5zx40jI6mAN15iLwxRUSngNInGzY3ozC117adR6IAVy1YY6cyNBrYJounom32EvJRgK+nDK5diy8ZYbEfwSqem4bQTE6Mi/PY91jovYjGLVSUtbojgo+XdOZRjUJ8qQqabTPxOAC0HShcbyo8W9hTyuMyq6kVJM+3+TG7bTM8SAleWniOMNqvVy5OeHk1Dpj67JbdQOIdYtWRkaatpgd881kIVx01YmXFKuA8CWnlML7UASfRarUnnh+ZLiCLQBgixmDsJCrWiE9QAz2SPRYNIshEVTUWNiuIH2cYlYdfiHq927PUtxPoHsx1Q== 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=oSLn5avm1Vu1EDeV4UZmeH7/3EjaQmWl5CASCPiu9CqScANKU8hfHYnOAoiGpH5lhOj5GMKcnZ0FoBtpyQNm+PkXP7NLCJe5L87rS3GzDZfJlIG9+V3QtaUqTr63D5YNN4M8sZ8FxslrQHn/eNz/IPHkcqQVUOn/WbruZKKqwhVa2GyuqnfX7maaIJg+GcDyKh6ZkBxruRLeux7fyUgJhynO9HnsGemDNBzSTizgD9OFEqq1+XB0JhB5uvGVlqN2A6PpFQivH/WgGXzrA3xHNsjgDOzXGXI2DDeNdk8/zQVivZW7oT+7mUq23FJdjIusgYc/BTnRcWEMygKZNILL/w== 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=SQlO6vJWEn1e1O9nHwlNHc/2HFtweCTKC5Qy3tS57ASqFFhC091pPAi+HkR+kQsVkrsn/4swlKGxRxbPj7DhwepodrNbNfDPc6l91cbDKivynA3f5nckBBVOJz295kE5XPN5qmYtPBoTjbZDjeAhUQQ6zILJYiOCvDDJNlv5sRg= Received: from MN2PR11MB4063.namprd11.prod.outlook.com (20.179.149.217) by MN2PR11MB4144.namprd11.prod.outlook.com (20.179.150.210) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.20.2284.20; Thu, 19 Sep 2019 14:25:45 +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 14:25:45 +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 v3 14/20] staging: wfx: setup initial chip configuration Thread-Topic: [PATCH v3 14/20] staging: wfx: setup initial chip configuration Thread-Index: AQHVbvYfjPLXWFSNEUGDWVMYRf0ngA== Date: Thu, 19 Sep 2019 14:25:44 +0000 Message-ID: <20190919142527.31797-15-Jerome.Pouiller@silabs.com> References: <20190919142527.31797-1-Jerome.Pouiller@silabs.com> In-Reply-To: <20190919142527.31797-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: 61cee6eb-1b2e-4eb5-c601-08d73d0d4277 x-microsoft-antispam: BCL:0;PCL:0;RULEID:(2390118)(7020095)(4652040)(8989299)(4534185)(4627221)(201703031133081)(201702281549075)(8990200)(5600167)(711020)(4605104)(1401327)(2017052603328)(7193020);SRVR:MN2PR11MB4144; x-ms-traffictypediagnostic: MN2PR11MB4144: 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)(39850400004)(346002)(199004)(189003)(86362001)(66066001)(66574012)(2616005)(14454004)(478600001)(54906003)(8676002)(71190400001)(966005)(36756003)(71200400001)(7736002)(316002)(305945005)(110136005)(6436002)(256004)(81156014)(14444005)(6486002)(6512007)(6306002)(186003)(11346002)(91956017)(486006)(446003)(26005)(2501003)(99286004)(66446008)(66946007)(76176011)(476003)(66556008)(64756008)(66476007)(4326008)(102836004)(6506007)(107886003)(5660300002)(76116006)(25786009)(81166006)(1076003)(8936002)(2906002)(3846002)(6116002);DIR:OUT;SFP:1101;SCL:1;SRVR:MN2PR11MB4144;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: pAG0gvMy9UkA7zgCNLVEpmt91Wpv4fRLdvHN8A5ZNc6Jlkxr9ZF8RcLNaTSggh+WgLMOVcfaLbAMijeuEC4x+ZeDzFMRn9GB8OqJgAApndPcKGef/yNKLmGU0TMRVn5CtLD87URtbEu21g4d5pINnjXAa1a7ODLnjFXQ89wNy8/+t2J3ZJ0juc0UEgVbCsEx3wssQH9i60w7XoYJHqDs1zAiDBnQKLGkwM68Wym0OJsnBg6VGHQAeuoeCo/VqKCwAUudVC5sStBMc0mhAuSrO8+kXlyEG15kK9ipv+La+MvL4LVYTscAhtPzfWMedS9u66bWTwWc1R7SoDRZS1PMbrJahJgWcgMm9o2pHMd2aHrVD7gYq8UzBWdWvo3NRI0/Df2h5+xin9XJ8OGMIJAqXLKkq0SNYD3Vk78jgxQYoiM= Content-ID: MIME-Version: 1.0 X-OriginatorOrg: silabs.com X-MS-Exchange-CrossTenant-Network-Message-Id: 61cee6eb-1b2e-4eb5-c601-08d73d0d4277 X-MS-Exchange-CrossTenant-originalarrivaltime: 19 Sep 2019 14:25:44.4135 (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: mtRaVMmVJhoqCJ4hp2pzEnW4B6teDAcdfFrPfanP91OYP9qIEOls4m5pDldUsPmK1gLJ/uctHZezDlZvbftLmw== X-MS-Exchange-Transport-CrossTenantHeadersStamped: MN2PR11MB4144 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