Received: by 2002:a05:6358:d09b:b0:dc:cd0c:909e with SMTP id jc27csp3637503rwb; Tue, 8 Nov 2022 06:51:04 -0800 (PST) X-Google-Smtp-Source: AMsMyM6Xt9LkziHf/RKaWqX9HMyKoXSG3GmYmykPx+7FSgpB29SLG/KmLjxD4qaMRCYPUNmbhT3m X-Received: by 2002:a17:906:eecb:b0:73c:5bcb:8eb3 with SMTP id wu11-20020a170906eecb00b0073c5bcb8eb3mr54155828ejb.284.1667919064451; Tue, 08 Nov 2022 06:51:04 -0800 (PST) ARC-Seal: i=1; a=rsa-sha256; t=1667919064; cv=none; d=google.com; s=arc-20160816; b=svitikypzgbwY1lmOaxJhl32HAw9z1E9QUJrg9DVhc7ZQN2yQFMIKn0Zp8e/mRrwhz e7QamUOKp71aVAWJmp9pUUQj2383ADk3z5oPDXxoC8Wp5DYgiN5xc9etcBWfrlliL8UI xc61AWrWNUIEzP+Vx+wuiZ97Pu0gG8kvMPdVlIkBzMcV9J4Pos5j4WEpelf7HocCYxFS 0Fnyh3m63TVrHptkLkX20TlYtHOe6sPUmooGZKWXebPBH2pjsEj3jUowRCb4NCZmVCbK A1oZitZQLz8sDcHWtepoYcLXZho+Xh2NfqiTnAqPP84R3rWYF606+TxJHUwUx7/pbWdy jvyA== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=list-id:precedence:content-transfer-encoding:mime-version :references:in-reply-to:message-id:date:subject:cc:to:from :dkim-signature; bh=Wsi4sWm0Fi+JDO4vS780L2O4U8t/mPxFxWNZptVtp0E=; b=CdKukWbPpc3KlVdUOhqwV0iAdZ6bxSof3MClWH/RQdZ4N6zMKwMeNxS827Ob13RhxU Q5Of6PUdWcVHK+WQdSV2jl3VRYYy9P3NcZEWk4XMZC9FOwGJIGuNiDPQ6tlm5c/4kNMz 0nRMCuJgJ2LGPl4aax8/0R5DXAr3HW7g032Tzp0mWnmlSkrhxscW1tjeoAPHvowigL0U l9m0yj/rlT/PCZEOkXUwO3ce7cxKz0AlQemy1V0JnDj8ejgQ20BCg4R2Fv//uxZ0kKP8 dVRmA12pyZlVN2JovCF09xYioj74A4CFVpOfoM6svZo7ajoCQfmiLgvtrDLC6SnqN7gy egIQ== ARC-Authentication-Results: i=1; mx.google.com; dkim=pass header.i=@intel.com header.s=Intel header.b=iaQECidl; spf=pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 2620:137:e000::1:20 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org; dmarc=pass (p=NONE sp=NONE dis=NONE) header.from=intel.com Return-Path: Received: from out1.vger.email (out1.vger.email. [2620:137:e000::1:20]) by mx.google.com with ESMTP id bu7-20020a170906a14700b0078b0865d468si9718709ejb.549.2022.11.08.06.50.42; Tue, 08 Nov 2022 06:51:04 -0800 (PST) Received-SPF: pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 2620:137:e000::1:20 as permitted sender) client-ip=2620:137:e000::1:20; Authentication-Results: mx.google.com; dkim=pass header.i=@intel.com header.s=Intel header.b=iaQECidl; spf=pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 2620:137:e000::1:20 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org; dmarc=pass (p=NONE sp=NONE dis=NONE) header.from=intel.com Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S234768AbiKHOpk (ORCPT + 91 others); Tue, 8 Nov 2022 09:45:40 -0500 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:48740 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S234287AbiKHOoc (ORCPT ); Tue, 8 Nov 2022 09:44:32 -0500 Received: from mga03.intel.com (mga03.intel.com [134.134.136.65]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 7A39ED7; Tue, 8 Nov 2022 06:44:30 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=intel.com; i=@intel.com; q=dns/txt; s=Intel; t=1667918670; x=1699454670; h=from:to:cc:subject:date:message-id:in-reply-to: references:mime-version:content-transfer-encoding; bh=ID4oavSOTy5whIdfy9Y1ZaAXvT9qG1s+ToxFzrU0jZY=; b=iaQECidlfbz36MPwv5clZ9rIuLmN9Q/z9du7GF91srIyDwYc1TT5TQQf xvZ33zUVPzIyC0edqu8Q0fN1gnP8a8Kkcm/+o7hxZGoKU6K3bYFxMsTIO GPydmsf6muE6I1uv0zK7v0hJljDH1WRMD479gHkULveC+XM3RPIjnl0CG DF4bSir5H4vgHFI827u/hV2rbd4jkjR3rnOcHDMkmbaoWaZ6IDu1x1CtV LH1DCnpScSVnSgbC/HRDQ4kHwd6vjE9sLYOIESGvi8INfnaerrKQgMo0o Ale1rEAzQZwDdffC4QZDT+mqGL9j7cHkRSrF0AxgKKMVjKhXrmywirjoW Q==; X-IronPort-AV: E=McAfee;i="6500,9779,10525"; a="312497985" X-IronPort-AV: E=Sophos;i="5.96,148,1665471600"; d="scan'208";a="312497985" Received: from fmsmga007.fm.intel.com ([10.253.24.52]) by orsmga103.jf.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 08 Nov 2022 06:43:59 -0800 X-IronPort-AV: E=McAfee;i="6500,9779,10525"; a="638809842" X-IronPort-AV: E=Sophos;i="5.96,148,1665471600"; d="scan'208";a="638809842" Received: from ppkrause-mobl.ger.corp.intel.com (HELO ijarvine-MOBL2.ger.corp.intel.com) ([10.249.44.73]) by fmsmga007-auth.fm.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 08 Nov 2022 06:43:55 -0800 From: =?UTF-8?q?Ilpo=20J=C3=A4rvinen?= To: linux-fpga@vger.kernel.org, Xu Yilun , Wu Hao , Tom Rix , Moritz Fischer , Lee Jones , Matthew Gerlach , Russ Weight , Tianfei zhang , Mark Brown , Greg KH , "Rafael J. Wysocki" , linux-kernel@vger.kernel.org Cc: =?UTF-8?q?Ilpo=20J=C3=A4rvinen?= Subject: [PATCH 08/12] regmap: indirect: Add indirect regmap support Date: Tue, 8 Nov 2022 16:43:01 +0200 Message-Id: <20221108144305.45424-9-ilpo.jarvinen@linux.intel.com> X-Mailer: git-send-email 2.30.2 In-Reply-To: <20221108144305.45424-1-ilpo.jarvinen@linux.intel.com> References: <20221108144305.45424-1-ilpo.jarvinen@linux.intel.com> MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit X-Spam-Status: No, score=-4.3 required=5.0 tests=BAYES_00,DKIMWL_WL_HIGH, DKIM_SIGNED,DKIM_VALID,DKIM_VALID_EF,RCVD_IN_DNSWL_MED,SPF_HELO_NONE, SPF_NONE autolearn=ham autolearn_force=no version=3.4.6 X-Spam-Checker-Version: SpamAssassin 3.4.6 (2021-04-09) on lindbergh.monkeyblade.net Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org Add support for indirect register access via a regmap interface. Indirect register access is a generic way to access registers directly. One use case is accessing registers on Intel FPGA IPs with e.g. PMCI or HSSI. Co-developed-by: Matthew Gerlach Signed-off-by: Matthew Gerlach Signed-off-by: Ilpo Järvinen --- drivers/base/regmap/Kconfig | 3 + drivers/base/regmap/Makefile | 1 + drivers/base/regmap/regmap-indirect.c | 128 ++++++++++++++++++++++++++ include/linux/regmap.h | 55 +++++++++++ 4 files changed, 187 insertions(+) create mode 100644 drivers/base/regmap/regmap-indirect.c diff --git a/drivers/base/regmap/Kconfig b/drivers/base/regmap/Kconfig index 159bac6c5046..94e5ca5434cf 100644 --- a/drivers/base/regmap/Kconfig +++ b/drivers/base/regmap/Kconfig @@ -65,3 +65,6 @@ config REGMAP_I3C config REGMAP_SPI_AVMM tristate depends on SPI + +config REGMAP_INDIRECT + tristate diff --git a/drivers/base/regmap/Makefile b/drivers/base/regmap/Makefile index 11facb32a027..6221a4740806 100644 --- a/drivers/base/regmap/Makefile +++ b/drivers/base/regmap/Makefile @@ -20,3 +20,4 @@ obj-$(CONFIG_REGMAP_SCCB) += regmap-sccb.o obj-$(CONFIG_REGMAP_I3C) += regmap-i3c.o obj-$(CONFIG_REGMAP_SPI_AVMM) += regmap-spi-avmm.o obj-$(CONFIG_REGMAP_MDIO) += regmap-mdio.o +obj-$(CONFIG_REGMAP_INDIRECT) += regmap-indirect.o diff --git a/drivers/base/regmap/regmap-indirect.c b/drivers/base/regmap/regmap-indirect.c new file mode 100644 index 000000000000..3ceb0c044c7c --- /dev/null +++ b/drivers/base/regmap/regmap-indirect.c @@ -0,0 +1,128 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Indirect Register Access. + * + * Copyright (C) 2020-2022 Intel Corporation, Inc. + */ +#include +#include +#include +#include +#include +#include +#include + +struct indirect_ctx { + void __iomem *base; + struct device *dev; + const struct regmap_indirect_cfg *indirect_cfg; +}; + +static int indirect_bus_idle_cmd(struct indirect_ctx *ctx) +{ + unsigned int cmd; + int ret; + + writel(ctx->indirect_cfg->idle_cmd, ctx->base + ctx->indirect_cfg->cmd_offset); + + ret = readl_poll_timeout(ctx->base + ctx->indirect_cfg->cmd_offset, cmd, + cmd == ctx->indirect_cfg->idle_cmd, + ctx->indirect_cfg->sleep_us, ctx->indirect_cfg->timeout_us); + if (ret) + dev_err(ctx->dev, "timed out waiting idle cmd (residual cmd=0x%x)\n", cmd); + + return ret; +} + +static int indirect_bus_reg_read(void *context, unsigned int reg, + unsigned int *val) +{ + struct indirect_ctx *ctx = context; + unsigned int cmd, ack, tmpval; + int ret; + + cmd = readl(ctx->base + ctx->indirect_cfg->cmd_offset); + if (cmd != ctx->indirect_cfg->idle_cmd) + dev_warn(ctx->dev, "residual cmd 0x%x on read entry\n", cmd); + + writel(reg, ctx->base + ctx->indirect_cfg->addr_offset); + writel(ctx->indirect_cfg->read_cmd, ctx->base + ctx->indirect_cfg->cmd_offset); + + ret = readl_poll_timeout(ctx->base + ctx->indirect_cfg->ack_offset, ack, + (ack & ctx->indirect_cfg->ack_mask) == ctx->indirect_cfg->ack_mask, + ctx->indirect_cfg->sleep_us, ctx->indirect_cfg->timeout_us); + if (ret) { + dev_err(ctx->dev, "read timed out on reg 0x%x ack 0x%x\n", reg, ack); + goto out; + } + + tmpval = readl(ctx->base + ctx->indirect_cfg->read_offset); + + if (indirect_bus_idle_cmd(ctx)) { + if (!ret) + ret = -ETIMEDOUT; + goto out; + } + + *val = tmpval; +out: + return ret; +} + +static int indirect_bus_reg_write(void *context, unsigned int reg, + unsigned int val) +{ + struct indirect_ctx *ctx = context; + unsigned int cmd, ack; + int ret; + + cmd = readl(ctx->base + ctx->indirect_cfg->cmd_offset); + if (cmd != ctx->indirect_cfg->idle_cmd) + dev_warn(ctx->dev, "residual cmd 0x%x on write entry\n", cmd); + + writel(val, ctx->base + ctx->indirect_cfg->write_offset); + writel(reg, ctx->base + ctx->indirect_cfg->addr_offset); + writel(ctx->indirect_cfg->write_cmd, ctx->base + ctx->indirect_cfg->cmd_offset); + + ret = readl_poll_timeout(ctx->base + ctx->indirect_cfg->ack_offset, ack, + (ack & ctx->indirect_cfg->ack_mask) == ctx->indirect_cfg->ack_mask, + ctx->indirect_cfg->sleep_us, ctx->indirect_cfg->timeout_us); + if (ret) + dev_err(ctx->dev, "write timed out on reg 0x%x ack 0x%x\n", reg, ack); + + if (indirect_bus_idle_cmd(ctx)) { + if (!ret) + ret = -ETIMEDOUT; + } + + return ret; +} + +static const struct regmap_bus indirect_bus = { + .reg_write = indirect_bus_reg_write, + .reg_read = indirect_bus_reg_read, +}; + +struct regmap *__devm_regmap_init_indirect(struct device *dev, + void __iomem *base, + struct regmap_config *cfg, + struct lock_class_key *lock_key, + const char *lock_name) +{ + struct indirect_ctx *ctx; + + ctx = devm_kzalloc(dev, sizeof(*ctx), GFP_KERNEL); + if (!ctx) + return NULL; + + ctx->base = base; + ctx->dev = dev; + ctx->indirect_cfg = cfg->indirect_cfg; + + return __devm_regmap_init(dev, &indirect_bus, ctx, cfg, lock_key, lock_name); +} +EXPORT_SYMBOL_GPL(__devm_regmap_init_indirect); + +MODULE_DESCRIPTION("Indirect Register Access"); +MODULE_AUTHOR("Intel Corporation"); +MODULE_LICENSE("GPL"); diff --git a/include/linux/regmap.h b/include/linux/regmap.h index ca3434dca3a0..adaa7bca4f60 100644 --- a/include/linux/regmap.h +++ b/include/linux/regmap.h @@ -190,6 +190,41 @@ enum regmap_endian { REGMAP_ENDIAN_NATIVE, }; +/** + * struct regmap_indirect_cfg - A configuration for indirect register access + * + * @cmd_offset: Command register offset + * @idle_cmd: Idle command + * @read_cmd: Read command + * @write_cmd: Write command + * + * @ack_offset: Command acknowledgment register offset + * @ack_mask: Command acknowledgment bit mask + * + * @addr_offset: Address register offset + * @read_offset: Read register offset + * @write_offset: Write register offset + * + * @sleep_us: Command wait sleep (usecs) + * @timeout_us: Command timeout (usecs) + */ +struct regmap_indirect_cfg { + unsigned int cmd_offset; + u32 idle_cmd; + u32 read_cmd; + u32 write_cmd; + + unsigned int ack_offset; + u32 ack_mask; + + unsigned int addr_offset; + unsigned int read_offset; + unsigned int write_offset; + + unsigned long sleep_us; + unsigned long timeout_us; +}; + /** * struct regmap_range - A register range, used for access related checks * (readable/writeable/volatile/precious checks) @@ -431,6 +466,8 @@ struct regmap_config { const struct regmap_range_cfg *ranges; unsigned int num_ranges; + const struct regmap_indirect_cfg *indirect_cfg; + bool use_hwlock; bool use_raw_spinlock; unsigned int hwlock_id; @@ -693,6 +730,12 @@ struct regmap *__devm_regmap_init_spi_avmm(struct spi_device *spi, const struct regmap_config *config, struct lock_class_key *lock_key, const char *lock_name); +struct regmap *__devm_regmap_init_indirect(struct device *dev, + void __iomem *base, + struct regmap_config *cfg, + struct lock_class_key *lock_key, + const char *lock_name); + /* * Wrapper for regmap_init macros to include a unique lockdep key and name * for each call. No-op if CONFIG_LOCKDEP is not set. @@ -1148,6 +1191,18 @@ bool regmap_ac97_default_volatile(struct device *dev, unsigned int reg); __regmap_lockdep_wrapper(__devm_regmap_init_spi_avmm, #config, \ spi, config) +/** + * devm_regmap_init_indirect - create a regmap for indirect register access + * @dev: device creating the regmap + * @base: __iomem point to base of memory with mailbox + * @cfg: regmap_config describing interface + * + * Return: 0 on success, negative error code otherwise. + */ +#define devm_regmap_init_indirect(dev, base, config) \ + __regmap_lockdep_wrapper(__devm_regmap_init_indirect, #config, \ + dev, base, config) + int regmap_mmio_attach_clk(struct regmap *map, struct clk *clk); void regmap_mmio_detach_clk(struct regmap *map); void regmap_exit(struct regmap *map); -- 2.30.2