--- /dev/null
+From patchwork Wed Nov 11 10:06:05 2020
+Content-Type: text/plain; charset="utf-8"
+MIME-Version: 1.0
+Content-Transfer-Encoding: 7bit
+X-Patchwork-Id: 11898191
+Return-Path:
+ <SRS0=XU8h=ER=lists.infradead.org=linux-riscv-bounces+patchwork-linux-riscv=patchwork.kernel.org@kernel.org>
+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 65B0A1391
+ Wed, 11 Nov 2020 16:47:21 +0000 (UTC)
+Received: from merlin.infradead.org (merlin.infradead.org [205.233.59.134])
+ (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits))
+ (No client certificate requested)
+ by mail.kernel.org (Postfix) with ESMTPS id D7F48206FB
+ Wed, 11 Nov 2020 16:47:20 +0000 (UTC)
+Authentication-Results: mail.kernel.org;
+ dkim=pass (2048-bit key) header.d=lists.infradead.org
+ dkim=fail reason="signature verification failed" (2048-bit key)
+DMARC-Filter: OpenDMARC Filter v1.3.2 mail.kernel.org D7F48206FB
+Authentication-Results: mail.kernel.org;
+ dmarc=none (p=none dis=none) header.from=sifive.com
+Authentication-Results: mail.kernel.org;
+ spf=none
+ smtp.mailfrom=linux-riscv-bounces+patchwork-linux-riscv=patchwork.kernel.org@lists.infradead.org
+DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed;
+ d=lists.infradead.org; s=merlin.20170209; h=Sender:Content-Transfer-Encoding:
+ Content-Type:Cc:List-Subscribe:List-Help:List-Post:List-Archive:
+ List-Unsubscribe:List-Id:MIME-Version:References:In-Reply-To:Message-Id:Date:
+ Subject:To:From:Reply-To:Content-ID:Content-Description:Resent-Date:
+ Resent-From:Resent-Sender:Resent-To:Resent-Cc:Resent-Message-ID:List-Owner;
+ bh=mXnSFZXMGisE2lDMkTUOOvUC/Kyr45NVjphI8tYXLzM=; b=Y/a4oqWEq/yUVKeLqi8reTYUM
+ EAsnXe1PUAgkUYK5Q0sp5Cc/cOtbLCZn0W6+B4kmJdYiIejGvc9Iz+1prVXtBw9AQYtamNp+Gtwjn
+ rnDLa1TL9UxJr8Tc2kACZNvkN7OLbuMTucdaKmudxS9LPgBDHZpUR58P2ptp83fr48x/FQbn1XoOz
+ xdFGekeIxgN7crqG2MkDZz5TqJWLNqY2za551mzNTN4rc9wMFWg4SEMx4CqPmLmwWsxwTWWb9BLhi
+ W6p6id/YvHglypggoP8zRIBWKPUly1eJVTFL67ODGaTtcFlrUSSpw8yHacwPpzU8nsAw7U/uh6xym
+ gTi/XcNmA==;
+Received: from localhost ([::1] helo=merlin.infradead.org)
+ by merlin.infradead.org with esmtp (Exim 4.92.3 #3 (Red Hat Linux))
+ id 1kctGq-0000D2-PT; Wed, 11 Nov 2020 16:46:56 +0000
+Received: from mail-pg1-x542.google.com ([2607:f8b0:4864:20::542])
+ by merlin.infradead.org with esmtps (Exim 4.92.3 #3 (Red Hat Linux))
+ id 1kcn18-0001JE-Vr
+Received: by mail-pg1-x542.google.com with SMTP id f18so1134899pgi.8
+DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=sifive.com; s=google;
+ h=from:to:cc:subject:date:message-id:in-reply-to:references
+ :mime-version:content-transfer-encoding;
+ bh=jL0tNU5hYFb7CUkP07ONQLx8L/T/xIAB3EAjS9DXImE=;
+ b=AFj9tIwIOmVUroqhyJd02VjhXIiSoSRxNL4OpbvnCjJRF/0vbs5I0JSaeJ7WvkBzZR
+ 3G0jDsBWbRX0zskB8JJEpepnElnvxLhfE+pPLf1pM/kucT9jYG6DyDZV/NtLl6ByppdO
+ NATEr+3GJISSuZ9myc7i3mpPkaIXOilTRYG46fcp17hbEbVyto+AD0WlByCSxxKbrr7Q
+ 4Yd2Ot3N7zyUVG+CaiTRFEgbgo8jMOyWS+mCGSgxtEsvyukg4v32KryY0kAaR9q/qBFw
+ He9p9S43OPStloEwi6JoxNu3o/5K1zw6c8mdTkD+17fTTABpUhm+MI94D0C/cVyHBQNa
+ V+Tw==
+X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed;
+ d=1e100.net; s=20161025;
+ h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to
+ :references:mime-version:content-transfer-encoding;
+ bh=jL0tNU5hYFb7CUkP07ONQLx8L/T/xIAB3EAjS9DXImE=;
+ b=IyojVq+ov6yc6UGaulkTn2AtRqjerTeTbLN3m/6yzbf1SbhNaFU5VMCgxxGhspnpoy
+ OUM84DRBMPX16h7/y1E1c3gylb7UNx7qdzG5AA/GzFghmsikTJKqTNifC+gvvfnkJJFO
+ LIx5nc+fQSXV6wQ2ppy8mfjZS2p/4vc2gGsebpj/8QKz6jkw8Dhd1QxNPGhu+W23kFla
+ /bYoBC6B/fIcetWBt7Bhwe5FQ/erh7ULiSQlObnkWKiZbR2HFKUJ7VQQckBBcLGrUjDg
+ aa3bDJnCR9DHvQwYs0I0KmPJG67TG9YvOgWyTkEGi0A+aa/wPSg4lF388+CpnYNK6azG
+ TdkQ==
+X-Gm-Message-State: AOAM530Uxpk8eMOmjXxbBdooCEyI6LvqPd7SKQ0MNdvLz+ubFKdGuSGA
+ x3rqGyCiTIqVI7qErEKZpQhV71fxtBcaYQ==
+X-Google-Smtp-Source:
+ ABdhPJzR6NhJ3vRp8GB36lz7N/OocbSO0kByZ0JnlUQayrXj7eA5KOHRgUv//OPPs35/ef72XIjb0A==
+X-Received: by 2002:a63:e612:: with SMTP id
+ g18mr20277608pgh.388.1605089176158;
+ Wed, 11 Nov 2020 02:06:16 -0800 (PST)
+Received: from hsinchu02.internal.sifive.com
+ (114-34-229-221.HINET-IP.hinet.net. [114.34.229.221])
+ by smtp.gmail.com with ESMTPSA id u22sm1872801pgf.24.2020.11.11.02.06.13
+ (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256);
+ Wed, 11 Nov 2020 02:06:15 -0800 (PST)
+Subject: [PATCH v4 1/4] clk: sifive: Extract prci core to common base
+Date: Wed, 11 Nov 2020 18:06:05 +0800
+X-Mailer: git-send-email 2.29.2
+MIME-Version: 1.0
+X-CRM114-Version: 20100106-BlameMichelson ( TRE 0.8.0 (BSD) ) MR-646709E3
+X-CRM114-CacheID: sfid-20201111_050619_330980_6A671390
+X-CRM114-Status: GOOD ( 27.34 )
+X-Spam-Score: -0.2 (/)
+X-Spam-Report: SpamAssassin version 3.4.4 on merlin.infradead.org summary:
+ Content analysis details: (-0.2 points)
+ pts rule name description
+ ---- ----------------------
+ --------------------------------------------------
+ -0.0 RCVD_IN_DNSWL_NONE RBL: Sender listed at https://www.dnswl.org/,
+ no trust [2607:f8b0:4864:20:0:0:0:542 listed in]
+ [list.dnswl.org]
+ -0.0 SPF_PASS SPF: sender matches SPF record
+ 0.0 SPF_HELO_NONE SPF: HELO does not publish an SPF Record
+ 0.1 DKIM_SIGNED Message has a DKIM or DK signature,
+ not necessarily
+ valid
+ -0.1 DKIM_VALID Message has at least one valid DKIM or DK signature
+ -0.1 DKIM_VALID_AU Message has a valid DKIM or DK signature from
+ author's domain
+ -0.1 DKIM_VALID_EF Message has a valid DKIM or DK signature from
+ envelope-from domain
+X-Mailman-Approved-At: Wed, 11 Nov 2020 11:46:52 -0500
+X-Mailman-Version: 2.1.29
+Precedence: list
+List-Id: <linux-riscv.lists.infradead.org>
+List-Unsubscribe: <http://lists.infradead.org/mailman/options/linux-riscv>,
+List-Archive: <http://lists.infradead.org/pipermail/linux-riscv/>
+List-Subscribe: <http://lists.infradead.org/mailman/listinfo/linux-riscv>,
+Errors-To:
+ linux-riscv-bounces+patchwork-linux-riscv=patchwork.kernel.org@lists.infradead.org
+
+Extract common core of prci driver to an independent file, it could
+allow other chips to reuse it. Separate SoCs-dependent code 'fu540'
+from prci core, then we can easily add 'fu740' later.
+
+Almost these changes are code movement. The different is adding the
+private data for each SoC use, so it needs to get match data in probe
+callback function, then use the data for initialization.
+
+---
+ drivers/clk/sifive/Makefile | 2 +
+ drivers/clk/sifive/fu540-prci.c | 586 +-----------------
+ drivers/clk/sifive/fu540-prci.h | 21 +
+ .../sifive/{fu540-prci.c => sifive-prci.c} | 381 +++---------
+ drivers/clk/sifive/sifive-prci.h | 201 ++++++
+ 5 files changed, 323 insertions(+), 868 deletions(-)
+ create mode 100644 drivers/clk/sifive/fu540-prci.h
+ copy drivers/clk/sifive/{fu540-prci.c => sifive-prci.c} (45%)
+ create mode 100644 drivers/clk/sifive/sifive-prci.h
+
+diff --git a/drivers/clk/sifive/Makefile b/drivers/clk/sifive/Makefile
+index 0797f14fef6b..627effe2ece1 100644
+--- a/drivers/clk/sifive/Makefile
++++ b/drivers/clk/sifive/Makefile
+@@ -1,2 +1,4 @@
+ # SPDX-License-Identifier: GPL-2.0-only
++obj-y += sifive-prci.o
++
+ obj-$(CONFIG_CLK_SIFIVE_FU540_PRCI) += fu540-prci.o
+diff --git a/drivers/clk/sifive/fu540-prci.c b/drivers/clk/sifive/fu540-prci.c
+index a8901f90a61a..840b97bfff85 100644
+--- a/drivers/clk/sifive/fu540-prci.c
++++ b/drivers/clk/sifive/fu540-prci.c
+@@ -3,6 +3,7 @@
+ * Copyright (C) 2018-2019 SiFive, Inc.
+ * Wesley Terpstra
+ * Paul Walmsley
++ * Zong Li
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+@@ -13,475 +14,48 @@
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+- * The FU540 PRCI implements clock and reset control for the SiFive
+- * FU540-C000 chip. This driver assumes that it has sole control
+- * over all PRCI resources.
+- *
+- * This driver is based on the PRCI driver written by Wesley Terpstra:
+- * https://github.com/riscv/riscv-linux/commit/999529edf517ed75b56659d456d221b2ee56bb60
+- *
+ * References:
+ * - SiFive FU540-C000 manual v1p0, Chapter 7 "Clocking and Reset"
+ */
+
+ #include <dt-bindings/clock/sifive-fu540-prci.h>
+-#include <linux/clkdev.h>
+-#include <linux/clk-provider.h>
+-#include <linux/clk/analogbits-wrpll-cln28hpc.h>
+-#include <linux/delay.h>
+-#include <linux/err.h>
+-#include <linux/io.h>
+ #include <linux/module.h>
+-#include <linux/of.h>
+-#include <linux/of_clk.h>
+-#include <linux/platform_device.h>
+-#include <linux/slab.h>
+-
+-/*
+- * EXPECTED_CLK_PARENT_COUNT: how many parent clocks this driver expects:
+- * hfclk and rtcclk
+- */
+-#define EXPECTED_CLK_PARENT_COUNT 2
+-
+-/*
+- * Register offsets and bitmasks
+- */
+-
+-/* COREPLLCFG0 */
+-#define PRCI_COREPLLCFG0_OFFSET 0x4
+-# define PRCI_COREPLLCFG0_DIVR_SHIFT 0
+-# define PRCI_COREPLLCFG0_DIVR_MASK (0x3f << PRCI_COREPLLCFG0_DIVR_SHIFT)
+-# define PRCI_COREPLLCFG0_DIVF_SHIFT 6
+-# define PRCI_COREPLLCFG0_DIVF_MASK (0x1ff << PRCI_COREPLLCFG0_DIVF_SHIFT)
+-# define PRCI_COREPLLCFG0_DIVQ_SHIFT 15
+-# define PRCI_COREPLLCFG0_DIVQ_MASK (0x7 << PRCI_COREPLLCFG0_DIVQ_SHIFT)
+-# define PRCI_COREPLLCFG0_RANGE_SHIFT 18
+-# define PRCI_COREPLLCFG0_RANGE_MASK (0x7 << PRCI_COREPLLCFG0_RANGE_SHIFT)
+-# define PRCI_COREPLLCFG0_BYPASS_SHIFT 24
+-# define PRCI_COREPLLCFG0_BYPASS_MASK (0x1 << PRCI_COREPLLCFG0_BYPASS_SHIFT)
+-# define PRCI_COREPLLCFG0_FSE_SHIFT 25
+-# define PRCI_COREPLLCFG0_FSE_MASK (0x1 << PRCI_COREPLLCFG0_FSE_SHIFT)
+-# define PRCI_COREPLLCFG0_LOCK_SHIFT 31
+-# define PRCI_COREPLLCFG0_LOCK_MASK (0x1 << PRCI_COREPLLCFG0_LOCK_SHIFT)
+-
+-/* DDRPLLCFG0 */
+-#define PRCI_DDRPLLCFG0_OFFSET 0xc
+-# define PRCI_DDRPLLCFG0_DIVR_SHIFT 0
+-# define PRCI_DDRPLLCFG0_DIVR_MASK (0x3f << PRCI_DDRPLLCFG0_DIVR_SHIFT)
+-# define PRCI_DDRPLLCFG0_DIVF_SHIFT 6
+-# define PRCI_DDRPLLCFG0_DIVF_MASK (0x1ff << PRCI_DDRPLLCFG0_DIVF_SHIFT)
+-# define PRCI_DDRPLLCFG0_DIVQ_SHIFT 15
+-# define PRCI_DDRPLLCFG0_DIVQ_MASK (0x7 << PRCI_DDRPLLCFG0_DIVQ_SHIFT)
+-# define PRCI_DDRPLLCFG0_RANGE_SHIFT 18
+-# define PRCI_DDRPLLCFG0_RANGE_MASK (0x7 << PRCI_DDRPLLCFG0_RANGE_SHIFT)
+-# define PRCI_DDRPLLCFG0_BYPASS_SHIFT 24
+-# define PRCI_DDRPLLCFG0_BYPASS_MASK (0x1 << PRCI_DDRPLLCFG0_BYPASS_SHIFT)
+-# define PRCI_DDRPLLCFG0_FSE_SHIFT 25
+-# define PRCI_DDRPLLCFG0_FSE_MASK (0x1 << PRCI_DDRPLLCFG0_FSE_SHIFT)
+-# define PRCI_DDRPLLCFG0_LOCK_SHIFT 31
+-# define PRCI_DDRPLLCFG0_LOCK_MASK (0x1 << PRCI_DDRPLLCFG0_LOCK_SHIFT)
++#include "sifive-prci.h"
+
+-/* DDRPLLCFG1 */
+-#define PRCI_DDRPLLCFG1_OFFSET 0x10
+-# define PRCI_DDRPLLCFG1_CKE_SHIFT 24
+-# define PRCI_DDRPLLCFG1_CKE_MASK (0x1 << PRCI_DDRPLLCFG1_CKE_SHIFT)
++/* PRCI integration data for each WRPLL instance */
+
+-/* GEMGXLPLLCFG0 */
+-#define PRCI_GEMGXLPLLCFG0_OFFSET 0x1c
+-# define PRCI_GEMGXLPLLCFG0_DIVR_SHIFT 0
+-# define PRCI_GEMGXLPLLCFG0_DIVR_MASK (0x3f << PRCI_GEMGXLPLLCFG0_DIVR_SHIFT)
+-# define PRCI_GEMGXLPLLCFG0_DIVF_SHIFT 6
+-# define PRCI_GEMGXLPLLCFG0_DIVF_MASK (0x1ff << PRCI_GEMGXLPLLCFG0_DIVF_SHIFT)
+-# define PRCI_GEMGXLPLLCFG0_DIVQ_SHIFT 15
+-# define PRCI_GEMGXLPLLCFG0_DIVQ_MASK (0x7 << PRCI_GEMGXLPLLCFG0_DIVQ_SHIFT)
+-# define PRCI_GEMGXLPLLCFG0_RANGE_SHIFT 18
+-# define PRCI_GEMGXLPLLCFG0_RANGE_MASK (0x7 << PRCI_GEMGXLPLLCFG0_RANGE_SHIFT)
+-# define PRCI_GEMGXLPLLCFG0_BYPASS_SHIFT 24
+-# define PRCI_GEMGXLPLLCFG0_BYPASS_MASK (0x1 << PRCI_GEMGXLPLLCFG0_BYPASS_SHIFT)
+-# define PRCI_GEMGXLPLLCFG0_FSE_SHIFT 25
+-# define PRCI_GEMGXLPLLCFG0_FSE_MASK (0x1 << PRCI_GEMGXLPLLCFG0_FSE_SHIFT)
+-# define PRCI_GEMGXLPLLCFG0_LOCK_SHIFT 31
+-# define PRCI_GEMGXLPLLCFG0_LOCK_MASK (0x1 << PRCI_GEMGXLPLLCFG0_LOCK_SHIFT)
+-
+-/* GEMGXLPLLCFG1 */
+-#define PRCI_GEMGXLPLLCFG1_OFFSET 0x20
+-# define PRCI_GEMGXLPLLCFG1_CKE_SHIFT 24
+-# define PRCI_GEMGXLPLLCFG1_CKE_MASK (0x1 << PRCI_GEMGXLPLLCFG1_CKE_SHIFT)
+-
+-/* CORECLKSEL */
+-#define PRCI_CORECLKSEL_OFFSET 0x24
+-# define PRCI_CORECLKSEL_CORECLKSEL_SHIFT 0
+-# define PRCI_CORECLKSEL_CORECLKSEL_MASK (0x1 << PRCI_CORECLKSEL_CORECLKSEL_SHIFT)
+-
+-/* DEVICESRESETREG */
+-#define PRCI_DEVICESRESETREG_OFFSET 0x28
+-# define PRCI_DEVICESRESETREG_DDR_CTRL_RST_N_SHIFT 0
+-# define PRCI_DEVICESRESETREG_DDR_CTRL_RST_N_MASK (0x1 << PRCI_DEVICESRESETREG_DDR_CTRL_RST_N_SHIFT)
+-# define PRCI_DEVICESRESETREG_DDR_AXI_RST_N_SHIFT 1
+-# define PRCI_DEVICESRESETREG_DDR_AXI_RST_N_MASK (0x1 << PRCI_DEVICESRESETREG_DDR_AXI_RST_N_SHIFT)
+-# define PRCI_DEVICESRESETREG_DDR_AHB_RST_N_SHIFT 2
+-# define PRCI_DEVICESRESETREG_DDR_AHB_RST_N_MASK (0x1 << PRCI_DEVICESRESETREG_DDR_AHB_RST_N_SHIFT)
+-# define PRCI_DEVICESRESETREG_DDR_PHY_RST_N_SHIFT 3
+-# define PRCI_DEVICESRESETREG_DDR_PHY_RST_N_MASK (0x1 << PRCI_DEVICESRESETREG_DDR_PHY_RST_N_SHIFT)
+-# define PRCI_DEVICESRESETREG_GEMGXL_RST_N_SHIFT 5
+-# define PRCI_DEVICESRESETREG_GEMGXL_RST_N_MASK (0x1 << PRCI_DEVICESRESETREG_GEMGXL_RST_N_SHIFT)
+-
+-/* CLKMUXSTATUSREG */
+-#define PRCI_CLKMUXSTATUSREG_OFFSET 0x2c
+-# define PRCI_CLKMUXSTATUSREG_TLCLKSEL_STATUS_SHIFT 1
+-# define PRCI_CLKMUXSTATUSREG_TLCLKSEL_STATUS_MASK (0x1 << PRCI_CLKMUXSTATUSREG_TLCLKSEL_STATUS_SHIFT)
+-
+-/*
+- * Private structures
+- */
+-
+-/**
+- * struct __prci_data - per-device-instance data
+- * @va: base virtual address of the PRCI IP block
+- * @hw_clks: encapsulates struct clk_hw records
+- *
+- * PRCI per-device instance data
+- */
+-struct __prci_data {
+- void __iomem *va;
+- struct clk_hw_onecell_data hw_clks;
++static struct __prci_wrpll_data __prci_corepll_data = {
++ .cfg0_offs = PRCI_COREPLLCFG0_OFFSET,
++ .enable_bypass = sifive_prci_coreclksel_use_hfclk,
++ .disable_bypass = sifive_prci_coreclksel_use_corepll,
+ };
+
+-/**
+- * struct __prci_wrpll_data - WRPLL configuration and integration data
+- * @c: WRPLL current configuration record
+- * @enable_bypass: fn ptr to code to bypass the WRPLL (if applicable; else NULL)
+- * @disable_bypass: fn ptr to code to not bypass the WRPLL (or NULL)
+- * @cfg0_offs: WRPLL CFG0 register offset (in bytes) from the PRCI base address
+- *
+- * @enable_bypass and @disable_bypass are used for WRPLL instances
+- * that contain a separate external glitchless clock mux downstream
+- * from the PLL. The WRPLL internal bypass mux is not glitchless.
+- */
+-struct __prci_wrpll_data {
+- struct wrpll_cfg c;
+- void (*enable_bypass)(struct __prci_data *pd);
+- void (*disable_bypass)(struct __prci_data *pd);
+- u8 cfg0_offs;
++static struct __prci_wrpll_data __prci_ddrpll_data = {
++ .cfg0_offs = PRCI_DDRPLLCFG0_OFFSET,
+ };
+
+-/**
+- * struct __prci_clock - describes a clock device managed by PRCI
+- * @name: user-readable clock name string - should match the manual
+- * @parent_name: parent name for this clock
+- * @ops: struct clk_ops for the Linux clock framework to use for control
+- * @hw: Linux-private clock data
+- * @pwd: WRPLL-specific data, associated with this clock (if not NULL)
+- * @pd: PRCI-specific data associated with this clock (if not NULL)
+- *
+- * PRCI clock data. Used by the PRCI driver to register PRCI-provided
+- * clocks to the Linux clock infrastructure.
+- */
+-struct __prci_clock {
+- const char *name;
+- const char *parent_name;
+- const struct clk_ops *ops;
+- struct clk_hw hw;
+- struct __prci_wrpll_data *pwd;
+- struct __prci_data *pd;
++static struct __prci_wrpll_data __prci_gemgxlpll_data = {
++ .cfg0_offs = PRCI_GEMGXLPLLCFG0_OFFSET,
+ };
+
+-#define clk_hw_to_prci_clock(pwd) container_of(pwd, struct __prci_clock, hw)
+-
+-/*
+- * Private functions
+- */
+-
+-/**
+- * __prci_readl() - read from a PRCI register
+- * @pd: PRCI context
+- * @offs: register offset to read from (in bytes, from PRCI base address)
+- *
+- * Read the register located at offset @offs from the base virtual
+- * address of the PRCI register target described by @pd, and return
+- * the value to the caller.
+- *
+- * Context: Any context.
+- *
+- * Return: the contents of the register described by @pd and @offs.
+- */
+-static u32 __prci_readl(struct __prci_data *pd, u32 offs)
+-{
+- return readl_relaxed(pd->va + offs);
+-}
+-
+-static void __prci_writel(u32 v, u32 offs, struct __prci_data *pd)
+-{
+- writel_relaxed(v, pd->va + offs);
+-}
+-
+-/* WRPLL-related private functions */
+-
+-/**
+- * __prci_wrpll_unpack() - unpack WRPLL configuration registers into parameters
+- * @c: ptr to a struct wrpll_cfg record to write config into
+- * @r: value read from the PRCI PLL configuration register
+- *
+- * Given a value @r read from an FU540 PRCI PLL configuration register,
+- * split it into fields and populate it into the WRPLL configuration record
+- * pointed to by @c.
+- *
+- * The COREPLLCFG0 macros are used below, but the other *PLLCFG0 macros
+- * have the same register layout.
+- *
+- * Context: Any context.
+- */
+-static void __prci_wrpll_unpack(struct wrpll_cfg *c, u32 r)
+-{
+- u32 v;
+-
+- v = r & PRCI_COREPLLCFG0_DIVR_MASK;
+- v >>= PRCI_COREPLLCFG0_DIVR_SHIFT;
+- c->divr = v;
+-
+- v = r & PRCI_COREPLLCFG0_DIVF_MASK;
+- v >>= PRCI_COREPLLCFG0_DIVF_SHIFT;
+- c->divf = v;
+-
+- v = r & PRCI_COREPLLCFG0_DIVQ_MASK;
+- v >>= PRCI_COREPLLCFG0_DIVQ_SHIFT;
+- c->divq = v;
+-
+- v = r & PRCI_COREPLLCFG0_RANGE_MASK;
+- v >>= PRCI_COREPLLCFG0_RANGE_SHIFT;
+- c->range = v;
+-
+- c->flags &= (WRPLL_FLAGS_INT_FEEDBACK_MASK |
+- WRPLL_FLAGS_EXT_FEEDBACK_MASK);
+-
+- /* external feedback mode not supported */
+- c->flags |= WRPLL_FLAGS_INT_FEEDBACK_MASK;
+-}
+-
+-/**
+- * __prci_wrpll_pack() - pack PLL configuration parameters into a register value
+- * @c: pointer to a struct wrpll_cfg record containing the PLL's cfg
+- *
+- * Using a set of WRPLL configuration values pointed to by @c,
+- * assemble a PRCI PLL configuration register value, and return it to
+- * the caller.
+- *
+- * Context: Any context. Caller must ensure that the contents of the
+- * record pointed to by @c do not change during the execution
+- * of this function.
+- *
+- * Returns: a value suitable for writing into a PRCI PLL configuration
+- * register
+- */
+-static u32 __prci_wrpll_pack(const struct wrpll_cfg *c)
+-{
+- u32 r = 0;
+-
+- r |= c->divr << PRCI_COREPLLCFG0_DIVR_SHIFT;
+- r |= c->divf << PRCI_COREPLLCFG0_DIVF_SHIFT;
+- r |= c->divq << PRCI_COREPLLCFG0_DIVQ_SHIFT;
+- r |= c->range << PRCI_COREPLLCFG0_RANGE_SHIFT;
+-
+- /* external feedback mode not supported */
+- r |= PRCI_COREPLLCFG0_FSE_MASK;
+-
+- return r;
+-}
+-
+-/**
+- * __prci_wrpll_read_cfg() - read the WRPLL configuration from the PRCI
+- * @pd: PRCI context
+- * @pwd: PRCI WRPLL metadata
+- *
+- * Read the current configuration of the PLL identified by @pwd from
+- * the PRCI identified by @pd, and store it into the local configuration
+- * cache in @pwd.
+- *
+- * Context: Any context. Caller must prevent the records pointed to by
+- * @pd and @pwd from changing during execution.
+- */
+-static void __prci_wrpll_read_cfg(struct __prci_data *pd,
+- struct __prci_wrpll_data *pwd)
+-{
+- __prci_wrpll_unpack(&pwd->c, __prci_readl(pd, pwd->cfg0_offs));
+-}
+-
+-/**
+- * __prci_wrpll_write_cfg() - write WRPLL configuration into the PRCI
+- * @pd: PRCI context
+- * @pwd: PRCI WRPLL metadata
+- * @c: WRPLL configuration record to write
+- *
+- * Write the WRPLL configuration described by @c into the WRPLL
+- * configuration register identified by @pwd in the PRCI instance
+- * described by @c. Make a cached copy of the WRPLL's current
+- * configuration so it can be used by other code.
+- *
+- * Context: Any context. Caller must prevent the records pointed to by
+- * @pd and @pwd from changing during execution.
+- */
+-static void __prci_wrpll_write_cfg(struct __prci_data *pd,
+- struct __prci_wrpll_data *pwd,
+- struct wrpll_cfg *c)
+-{
+- __prci_writel(__prci_wrpll_pack(c), pwd->cfg0_offs, pd);
+-
+- memcpy(&pwd->c, c, sizeof(*c));
+-}
+-
+-/* Core clock mux control */
+-
+-/**
+- * __prci_coreclksel_use_hfclk() - switch the CORECLK mux to output HFCLK
+- * @pd: struct __prci_data * for the PRCI containing the CORECLK mux reg
+- *
+- * Switch the CORECLK mux to the HFCLK input source; return once complete.
+- *
+- * Context: Any context. Caller must prevent concurrent changes to the
+- * PRCI_CORECLKSEL_OFFSET register.
+- */
+-static void __prci_coreclksel_use_hfclk(struct __prci_data *pd)
+-{
+- u32 r;
+-
+- r = __prci_readl(pd, PRCI_CORECLKSEL_OFFSET);
+- r |= PRCI_CORECLKSEL_CORECLKSEL_MASK;
+- __prci_writel(r, PRCI_CORECLKSEL_OFFSET, pd);
+-
+- r = __prci_readl(pd, PRCI_CORECLKSEL_OFFSET); /* barrier */
+-}
+-
+-/**
+- * __prci_coreclksel_use_corepll() - switch the CORECLK mux to output COREPLL
+- * @pd: struct __prci_data * for the PRCI containing the CORECLK mux reg
+- *
+- * Switch the CORECLK mux to the PLL output clock; return once complete.
+- *
+- * Context: Any context. Caller must prevent concurrent changes to the
+- * PRCI_CORECLKSEL_OFFSET register.
+- */
+-static void __prci_coreclksel_use_corepll(struct __prci_data *pd)
+-{
+- u32 r;
+-
+- r = __prci_readl(pd, PRCI_CORECLKSEL_OFFSET);
+- r &= ~PRCI_CORECLKSEL_CORECLKSEL_MASK;
+- __prci_writel(r, PRCI_CORECLKSEL_OFFSET, pd);
+-
+- r = __prci_readl(pd, PRCI_CORECLKSEL_OFFSET); /* barrier */
+-}
+-
+-/*
+- * Linux clock framework integration
+- *
+- * See the Linux clock framework documentation for more information on
+- * these functions.
+- */
+-
+-static unsigned long sifive_fu540_prci_wrpll_recalc_rate(struct clk_hw *hw,
+- unsigned long parent_rate)
+-{
+- struct __prci_clock *pc = clk_hw_to_prci_clock(hw);
+- struct __prci_wrpll_data *pwd = pc->pwd;
+-
+- return wrpll_calc_output_rate(&pwd->c, parent_rate);
+-}
+-
+-static long sifive_fu540_prci_wrpll_round_rate(struct clk_hw *hw,
+- unsigned long rate,
+- unsigned long *parent_rate)
+-{
+- struct __prci_clock *pc = clk_hw_to_prci_clock(hw);
+- struct __prci_wrpll_data *pwd = pc->pwd;
+- struct wrpll_cfg c;
+-
+- memcpy(&c, &pwd->c, sizeof(c));
+-
+- wrpll_configure_for_rate(&c, rate, *parent_rate);
+-
+- return wrpll_calc_output_rate(&c, *parent_rate);
+-}
+-
+-static int sifive_fu540_prci_wrpll_set_rate(struct clk_hw *hw,
+- unsigned long rate,
+- unsigned long parent_rate)
+-{
+- struct __prci_clock *pc = clk_hw_to_prci_clock(hw);
+- struct __prci_wrpll_data *pwd = pc->pwd;
+- struct __prci_data *pd = pc->pd;
+- int r;
+-
+- r = wrpll_configure_for_rate(&pwd->c, rate, parent_rate);
+- if (r)
+- return r;
+-
+- if (pwd->enable_bypass)
+- pwd->enable_bypass(pd);
+-
+- __prci_wrpll_write_cfg(pd, pwd, &pwd->c);
+-
+- udelay(wrpll_calc_max_lock_us(&pwd->c));
+-
+- if (pwd->disable_bypass)
+- pwd->disable_bypass(pd);
+-
+- return 0;
+-}
++/* Linux clock framework integration */
+
+ static const struct clk_ops sifive_fu540_prci_wrpll_clk_ops = {
+- .set_rate = sifive_fu540_prci_wrpll_set_rate,
+- .round_rate = sifive_fu540_prci_wrpll_round_rate,
+- .recalc_rate = sifive_fu540_prci_wrpll_recalc_rate,
++ .set_rate = sifive_prci_wrpll_set_rate,
++ .round_rate = sifive_prci_wrpll_round_rate,
++ .recalc_rate = sifive_prci_wrpll_recalc_rate,
+ };
+
+ static const struct clk_ops sifive_fu540_prci_wrpll_ro_clk_ops = {
+- .recalc_rate = sifive_fu540_prci_wrpll_recalc_rate,
++ .recalc_rate = sifive_prci_wrpll_recalc_rate,
+ };
+
+-/* TLCLKSEL clock integration */
+-
+-static unsigned long sifive_fu540_prci_tlclksel_recalc_rate(struct clk_hw *hw,
+- unsigned long parent_rate)
+-{
+- struct __prci_clock *pc = clk_hw_to_prci_clock(hw);
+- struct __prci_data *pd = pc->pd;
+- u32 v;
+- u8 div;
+-
+- v = __prci_readl(pd, PRCI_CLKMUXSTATUSREG_OFFSET);
+- v &= PRCI_CLKMUXSTATUSREG_TLCLKSEL_STATUS_MASK;
+- div = v ? 1 : 2;
+-
+- return div_u64(parent_rate, div);
+-}
+-
+ static const struct clk_ops sifive_fu540_prci_tlclksel_clk_ops = {
+- .recalc_rate = sifive_fu540_prci_tlclksel_recalc_rate,
+-};
+-
+-/*
+- * PRCI integration data for each WRPLL instance
+- */
+-
+-static struct __prci_wrpll_data __prci_corepll_data = {
+- .cfg0_offs = PRCI_COREPLLCFG0_OFFSET,
+- .enable_bypass = __prci_coreclksel_use_hfclk,
+- .disable_bypass = __prci_coreclksel_use_corepll,
+-};
+-
+-static struct __prci_wrpll_data __prci_ddrpll_data = {
+- .cfg0_offs = PRCI_DDRPLLCFG0_OFFSET,
++ .recalc_rate = sifive_prci_tlclksel_recalc_rate,
+ };
+
+-static struct __prci_wrpll_data __prci_gemgxlpll_data = {
+- .cfg0_offs = PRCI_GEMGXLPLLCFG0_OFFSET,
+-};
+-
+-/*
+- * List of clock controls provided by the PRCI
+- */
+-
+-static struct __prci_clock __prci_init_clocks[] = {
++/* List of clock controls provided by the PRCI */
++struct __prci_clock __prci_init_clocks_fu540[] = {
+ [PRCI_CLK_COREPLL] = {
+ .name = "corepll",
+ .parent_name = "hfclk",
+@@ -506,125 +80,3 @@ static struct __prci_clock __prci_init_clocks[] = {
+ .ops = &sifive_fu540_prci_tlclksel_clk_ops,
+ },
+ };
+-
+-/**
+- * __prci_register_clocks() - register clock controls in the PRCI with Linux
+- * @dev: Linux struct device *
+- *
+- * Register the list of clock controls described in __prci_init_plls[] with
+- * the Linux clock framework.
+- *
+- * Return: 0 upon success or a negative error code upon failure.
+- */
+-static int __prci_register_clocks(struct device *dev, struct __prci_data *pd)
+-{
+- struct clk_init_data init = { };
+- struct __prci_clock *pic;
+- int parent_count, i, r;
+-
+- parent_count = of_clk_get_parent_count(dev->of_node);
+- if (parent_count != EXPECTED_CLK_PARENT_COUNT) {
+- dev_err(dev, "expected only two parent clocks, found %d\n",
+- parent_count);
+- return -EINVAL;
+- }
+-
+- /* Register PLLs */
+- for (i = 0; i < ARRAY_SIZE(__prci_init_clocks); ++i) {
+- pic = &__prci_init_clocks[i];
+-
+- init.name = pic->name;
+- init.parent_names = &pic->parent_name;
+- init.num_parents = 1;
+- init.ops = pic->ops;
+- pic->hw.init = &init;
+-
+- pic->pd = pd;
+-
+- if (pic->pwd)
+- __prci_wrpll_read_cfg(pd, pic->pwd);
+-
+- r = devm_clk_hw_register(dev, &pic->hw);
+- if (r) {
+- dev_warn(dev, "Failed to register clock %s: %d\n",
+- init.name, r);
+- return r;
+- }
+-
+- r = clk_hw_register_clkdev(&pic->hw, pic->name, dev_name(dev));
+- if (r) {
+- dev_warn(dev, "Failed to register clkdev for %s: %d\n",
+- init.name, r);
+- return r;
+- }
+-
+- pd->hw_clks.hws[i] = &pic->hw;
+- }
+-
+- pd->hw_clks.num = i;
+-
+- r = devm_of_clk_add_hw_provider(dev, of_clk_hw_onecell_get,
+- &pd->hw_clks);
+- if (r) {
+- dev_err(dev, "could not add hw_provider: %d\n", r);
+- return r;
+- }
+-
+- return 0;
+-}
+-
+-/*
+- * Linux device model integration
+- *
+- * See the Linux device model documentation for more information about
+- * these functions.
+- */
+-static int sifive_fu540_prci_probe(struct platform_device *pdev)
+-{
+- struct device *dev = &pdev->dev;
+- struct resource *res;
+- struct __prci_data *pd;
+- int r;
+-
+- pd = devm_kzalloc(dev,
+- struct_size(pd, hw_clks.hws,
+- ARRAY_SIZE(__prci_init_clocks)),
+- GFP_KERNEL);
+- if (!pd)
+- return -ENOMEM;
+-
+- res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+- pd->va = devm_ioremap_resource(dev, res);
+- if (IS_ERR(pd->va))
+- return PTR_ERR(pd->va);
+-
+- r = __prci_register_clocks(dev, pd);
+- if (r) {
+- dev_err(dev, "could not register clocks: %d\n", r);
+- return r;
+- }
+-
+- dev_dbg(dev, "SiFive FU540 PRCI probed\n");
+-
+- return 0;
+-}
+-
+-static const struct of_device_id sifive_fu540_prci_of_match[] = {
+- { .compatible = "sifive,fu540-c000-prci", },
+- {}
+-};
+-MODULE_DEVICE_TABLE(of, sifive_fu540_prci_of_match);
+-
+-static struct platform_driver sifive_fu540_prci_driver = {
+- .driver = {
+- .name = "sifive-fu540-prci",
+- .of_match_table = sifive_fu540_prci_of_match,
+- },
+- .probe = sifive_fu540_prci_probe,
+-};
+-
+-static int __init sifive_fu540_prci_init(void)
+-{
+- return platform_driver_register(&sifive_fu540_prci_driver);
+-}
+-core_initcall(sifive_fu540_prci_init);
+diff --git a/drivers/clk/sifive/fu540-prci.h b/drivers/clk/sifive/fu540-prci.h
+new file mode 100644
+index 000000000000..c8271efa7bdc
+--- /dev/null
++++ b/drivers/clk/sifive/fu540-prci.h
+@@ -0,0 +1,21 @@
++/* SPDX-License-Identifier: GPL-2.0 */
++/*
++ * Copyright (C) 2020 SiFive, Inc.
++ * Zong Li
++ */
++
++#ifndef __SIFIVE_CLK_FU540_PRCI_H
++#define __SIFIVE_CLK_FU540_PRCI_H
++
++#include "sifive-prci.h"
++
++#define NUM_CLOCK_FU540 4
++
++extern struct __prci_clock __prci_init_clocks_fu540[NUM_CLOCK_FU540];
++
++static const struct prci_clk_desc prci_clk_fu540 = {
++ .clks = __prci_init_clocks_fu540,
++ .num_clks = ARRAY_SIZE(__prci_init_clocks_fu540),
++};
++
++#endif /* __SIFIVE_CLK_FU540_PRCI_H */
+diff --git a/drivers/clk/sifive/fu540-prci.c b/drivers/clk/sifive/sifive-prci.c
+similarity index 45%
+copy from drivers/clk/sifive/fu540-prci.c
+copy to drivers/clk/sifive/sifive-prci.c
+index a8901f90a61a..0ac729eeb71b 100644
+--- a/drivers/clk/sifive/fu540-prci.c
++++ b/drivers/clk/sifive/sifive-prci.c
+@@ -3,6 +3,7 @@
+ * Copyright (C) 2018-2019 SiFive, Inc.
+ * Wesley Terpstra
+ * Paul Walmsley
++ * Zong Li
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+@@ -13,180 +14,19 @@
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+- * The FU540 PRCI implements clock and reset control for the SiFive
+- * FU540-C000 chip. This driver assumes that it has sole control
+- * over all PRCI resources.
++ * The PRCI implements clock and reset control for the SiFive chip.
++ * This driver assumes that it has sole control over all PRCI resources.
+ *
+ * This driver is based on the PRCI driver written by Wesley Terpstra:
+ * https://github.com/riscv/riscv-linux/commit/999529edf517ed75b56659d456d221b2ee56bb60
+- *
+- * References:
+- * - SiFive FU540-C000 manual v1p0, Chapter 7 "Clocking and Reset"
+ */
+
+-#include <dt-bindings/clock/sifive-fu540-prci.h>
+ #include <linux/clkdev.h>
+-#include <linux/clk-provider.h>
+-#include <linux/clk/analogbits-wrpll-cln28hpc.h>
+ #include <linux/delay.h>
+-#include <linux/err.h>
+ #include <linux/io.h>
+-#include <linux/module.h>
+-#include <linux/of.h>
+-#include <linux/of_clk.h>
+-#include <linux/platform_device.h>
+-#include <linux/slab.h>
+-
+-/*
+- * EXPECTED_CLK_PARENT_COUNT: how many parent clocks this driver expects:
+- * hfclk and rtcclk
+- */
+-#define EXPECTED_CLK_PARENT_COUNT 2
+-
+-/*
+- * Register offsets and bitmasks
+- */
+-
+-/* COREPLLCFG0 */
+-#define PRCI_COREPLLCFG0_OFFSET 0x4
+-# define PRCI_COREPLLCFG0_DIVR_SHIFT 0
+-# define PRCI_COREPLLCFG0_DIVR_MASK (0x3f << PRCI_COREPLLCFG0_DIVR_SHIFT)
+-# define PRCI_COREPLLCFG0_DIVF_SHIFT 6
+-# define PRCI_COREPLLCFG0_DIVF_MASK (0x1ff << PRCI_COREPLLCFG0_DIVF_SHIFT)
+-# define PRCI_COREPLLCFG0_DIVQ_SHIFT 15
+-# define PRCI_COREPLLCFG0_DIVQ_MASK (0x7 << PRCI_COREPLLCFG0_DIVQ_SHIFT)
+-# define PRCI_COREPLLCFG0_RANGE_SHIFT 18
+-# define PRCI_COREPLLCFG0_RANGE_MASK (0x7 << PRCI_COREPLLCFG0_RANGE_SHIFT)
+-# define PRCI_COREPLLCFG0_BYPASS_SHIFT 24
+-# define PRCI_COREPLLCFG0_BYPASS_MASK (0x1 << PRCI_COREPLLCFG0_BYPASS_SHIFT)
+-# define PRCI_COREPLLCFG0_FSE_SHIFT 25
+-# define PRCI_COREPLLCFG0_FSE_MASK (0x1 << PRCI_COREPLLCFG0_FSE_SHIFT)
+-# define PRCI_COREPLLCFG0_LOCK_SHIFT 31
+-# define PRCI_COREPLLCFG0_LOCK_MASK (0x1 << PRCI_COREPLLCFG0_LOCK_SHIFT)
+-
+-/* DDRPLLCFG0 */
+-#define PRCI_DDRPLLCFG0_OFFSET 0xc
+-# define PRCI_DDRPLLCFG0_DIVR_SHIFT 0
+-# define PRCI_DDRPLLCFG0_DIVR_MASK (0x3f << PRCI_DDRPLLCFG0_DIVR_SHIFT)
+-# define PRCI_DDRPLLCFG0_DIVF_SHIFT 6
+-# define PRCI_DDRPLLCFG0_DIVF_MASK (0x1ff << PRCI_DDRPLLCFG0_DIVF_SHIFT)
+-# define PRCI_DDRPLLCFG0_DIVQ_SHIFT 15
+-# define PRCI_DDRPLLCFG0_DIVQ_MASK (0x7 << PRCI_DDRPLLCFG0_DIVQ_SHIFT)
+-# define PRCI_DDRPLLCFG0_RANGE_SHIFT 18
+-# define PRCI_DDRPLLCFG0_RANGE_MASK (0x7 << PRCI_DDRPLLCFG0_RANGE_SHIFT)
+-# define PRCI_DDRPLLCFG0_BYPASS_SHIFT 24
+-# define PRCI_DDRPLLCFG0_BYPASS_MASK (0x1 << PRCI_DDRPLLCFG0_BYPASS_SHIFT)
+-# define PRCI_DDRPLLCFG0_FSE_SHIFT 25
+-# define PRCI_DDRPLLCFG0_FSE_MASK (0x1 << PRCI_DDRPLLCFG0_FSE_SHIFT)
+-# define PRCI_DDRPLLCFG0_LOCK_SHIFT 31
+-# define PRCI_DDRPLLCFG0_LOCK_MASK (0x1 << PRCI_DDRPLLCFG0_LOCK_SHIFT)
+-
+-/* DDRPLLCFG1 */
+-#define PRCI_DDRPLLCFG1_OFFSET 0x10
+-# define PRCI_DDRPLLCFG1_CKE_SHIFT 24
+-# define PRCI_DDRPLLCFG1_CKE_MASK (0x1 << PRCI_DDRPLLCFG1_CKE_SHIFT)
+-
+-/* GEMGXLPLLCFG0 */
+-#define PRCI_GEMGXLPLLCFG0_OFFSET 0x1c
+-# define PRCI_GEMGXLPLLCFG0_DIVR_SHIFT 0
+-# define PRCI_GEMGXLPLLCFG0_DIVR_MASK (0x3f << PRCI_GEMGXLPLLCFG0_DIVR_SHIFT)
+-# define PRCI_GEMGXLPLLCFG0_DIVF_SHIFT 6
+-# define PRCI_GEMGXLPLLCFG0_DIVF_MASK (0x1ff << PRCI_GEMGXLPLLCFG0_DIVF_SHIFT)
+-# define PRCI_GEMGXLPLLCFG0_DIVQ_SHIFT 15
+-# define PRCI_GEMGXLPLLCFG0_DIVQ_MASK (0x7 << PRCI_GEMGXLPLLCFG0_DIVQ_SHIFT)
+-# define PRCI_GEMGXLPLLCFG0_RANGE_SHIFT 18
+-# define PRCI_GEMGXLPLLCFG0_RANGE_MASK (0x7 << PRCI_GEMGXLPLLCFG0_RANGE_SHIFT)
+-# define PRCI_GEMGXLPLLCFG0_BYPASS_SHIFT 24
+-# define PRCI_GEMGXLPLLCFG0_BYPASS_MASK (0x1 << PRCI_GEMGXLPLLCFG0_BYPASS_SHIFT)
+-# define PRCI_GEMGXLPLLCFG0_FSE_SHIFT 25
+-# define PRCI_GEMGXLPLLCFG0_FSE_MASK (0x1 << PRCI_GEMGXLPLLCFG0_FSE_SHIFT)
+-# define PRCI_GEMGXLPLLCFG0_LOCK_SHIFT 31
+-# define PRCI_GEMGXLPLLCFG0_LOCK_MASK (0x1 << PRCI_GEMGXLPLLCFG0_LOCK_SHIFT)
+-
+-/* GEMGXLPLLCFG1 */
+-#define PRCI_GEMGXLPLLCFG1_OFFSET 0x20
+-# define PRCI_GEMGXLPLLCFG1_CKE_SHIFT 24
+-# define PRCI_GEMGXLPLLCFG1_CKE_MASK (0x1 << PRCI_GEMGXLPLLCFG1_CKE_SHIFT)
+-
+-/* CORECLKSEL */
+-#define PRCI_CORECLKSEL_OFFSET 0x24
+-# define PRCI_CORECLKSEL_CORECLKSEL_SHIFT 0
+-# define PRCI_CORECLKSEL_CORECLKSEL_MASK (0x1 << PRCI_CORECLKSEL_CORECLKSEL_SHIFT)
+-
+-/* DEVICESRESETREG */
+-#define PRCI_DEVICESRESETREG_OFFSET 0x28
+-# define PRCI_DEVICESRESETREG_DDR_CTRL_RST_N_SHIFT 0
+-# define PRCI_DEVICESRESETREG_DDR_CTRL_RST_N_MASK (0x1 << PRCI_DEVICESRESETREG_DDR_CTRL_RST_N_SHIFT)
+-# define PRCI_DEVICESRESETREG_DDR_AXI_RST_N_SHIFT 1
+-# define PRCI_DEVICESRESETREG_DDR_AXI_RST_N_MASK (0x1 << PRCI_DEVICESRESETREG_DDR_AXI_RST_N_SHIFT)
+-# define PRCI_DEVICESRESETREG_DDR_AHB_RST_N_SHIFT 2
+-# define PRCI_DEVICESRESETREG_DDR_AHB_RST_N_MASK (0x1 << PRCI_DEVICESRESETREG_DDR_AHB_RST_N_SHIFT)
+-# define PRCI_DEVICESRESETREG_DDR_PHY_RST_N_SHIFT 3
+-# define PRCI_DEVICESRESETREG_DDR_PHY_RST_N_MASK (0x1 << PRCI_DEVICESRESETREG_DDR_PHY_RST_N_SHIFT)
+-# define PRCI_DEVICESRESETREG_GEMGXL_RST_N_SHIFT 5
+-# define PRCI_DEVICESRESETREG_GEMGXL_RST_N_MASK (0x1 << PRCI_DEVICESRESETREG_GEMGXL_RST_N_SHIFT)
+-
+-/* CLKMUXSTATUSREG */
+-#define PRCI_CLKMUXSTATUSREG_OFFSET 0x2c
+-# define PRCI_CLKMUXSTATUSREG_TLCLKSEL_STATUS_SHIFT 1
+-# define PRCI_CLKMUXSTATUSREG_TLCLKSEL_STATUS_MASK (0x1 << PRCI_CLKMUXSTATUSREG_TLCLKSEL_STATUS_SHIFT)
+-
+-/*
+- * Private structures
+- */
+-
+-/**
+- * struct __prci_data - per-device-instance data
+- * @va: base virtual address of the PRCI IP block
+- * @hw_clks: encapsulates struct clk_hw records
+- *
+- * PRCI per-device instance data
+- */
+-struct __prci_data {
+- void __iomem *va;
+- struct clk_hw_onecell_data hw_clks;
+-};
+-
+-/**
+- * struct __prci_wrpll_data - WRPLL configuration and integration data
+- * @c: WRPLL current configuration record
+- * @enable_bypass: fn ptr to code to bypass the WRPLL (if applicable; else NULL)
+- * @disable_bypass: fn ptr to code to not bypass the WRPLL (or NULL)
+- * @cfg0_offs: WRPLL CFG0 register offset (in bytes) from the PRCI base address
+- *
+- * @enable_bypass and @disable_bypass are used for WRPLL instances
+- * that contain a separate external glitchless clock mux downstream
+- * from the PLL. The WRPLL internal bypass mux is not glitchless.
+- */
+-struct __prci_wrpll_data {
+- struct wrpll_cfg c;
+- void (*enable_bypass)(struct __prci_data *pd);
+- void (*disable_bypass)(struct __prci_data *pd);
+- u8 cfg0_offs;
+-};
+-
+-/**
+- * struct __prci_clock - describes a clock device managed by PRCI
+- * @name: user-readable clock name string - should match the manual
+- * @parent_name: parent name for this clock
+- * @ops: struct clk_ops for the Linux clock framework to use for control
+- * @hw: Linux-private clock data
+- * @pwd: WRPLL-specific data, associated with this clock (if not NULL)
+- * @pd: PRCI-specific data associated with this clock (if not NULL)
+- *
+- * PRCI clock data. Used by the PRCI driver to register PRCI-provided
+- * clocks to the Linux clock infrastructure.
+- */
+-struct __prci_clock {
+- const char *name;
+- const char *parent_name;
+- const struct clk_ops *ops;
+- struct clk_hw hw;
+- struct __prci_wrpll_data *pwd;
+- struct __prci_data *pd;
+-};
+-
+-#define clk_hw_to_prci_clock(pwd) container_of(pwd, struct __prci_clock, hw)
++#include <linux/of_device.h>
++#include "sifive-prci.h"
++#include "fu540-prci.h"
+
+ /*
+ * Private functions
+@@ -222,7 +62,7 @@ static void __prci_writel(u32 v, u32 offs, struct __prci_data *pd)
+ * @c: ptr to a struct wrpll_cfg record to write config into
+ * @r: value read from the PRCI PLL configuration register
+ *
+- * Given a value @r read from an FU540 PRCI PLL configuration register,
++ * Given a value @r read from an FU740 PRCI PLL configuration register,
+ * split it into fields and populate it into the WRPLL configuration record
+ * pointed to by @c.
+ *
+@@ -251,8 +91,8 @@ static void __prci_wrpll_unpack(struct wrpll_cfg *c, u32 r)
+ v >>= PRCI_COREPLLCFG0_RANGE_SHIFT;
+ c->range = v;
+
+- c->flags &= (WRPLL_FLAGS_INT_FEEDBACK_MASK |
+- WRPLL_FLAGS_EXT_FEEDBACK_MASK);
++ c->flags &=
++ (WRPLL_FLAGS_INT_FEEDBACK_MASK | WRPLL_FLAGS_EXT_FEEDBACK_MASK);
+
+ /* external feedback mode not supported */
+ c->flags |= WRPLL_FLAGS_INT_FEEDBACK_MASK;
+@@ -329,48 +169,6 @@ static void __prci_wrpll_write_cfg(struct __prci_data *pd,
+ memcpy(&pwd->c, c, sizeof(*c));
+ }
+
+-/* Core clock mux control */
+-
+-/**
+- * __prci_coreclksel_use_hfclk() - switch the CORECLK mux to output HFCLK
+- * @pd: struct __prci_data * for the PRCI containing the CORECLK mux reg
+- *
+- * Switch the CORECLK mux to the HFCLK input source; return once complete.
+- *
+- * Context: Any context. Caller must prevent concurrent changes to the
+- * PRCI_CORECLKSEL_OFFSET register.
+- */
+-static void __prci_coreclksel_use_hfclk(struct __prci_data *pd)
+-{
+- u32 r;
+-
+- r = __prci_readl(pd, PRCI_CORECLKSEL_OFFSET);
+- r |= PRCI_CORECLKSEL_CORECLKSEL_MASK;
+- __prci_writel(r, PRCI_CORECLKSEL_OFFSET, pd);
+-
+- r = __prci_readl(pd, PRCI_CORECLKSEL_OFFSET); /* barrier */
+-}
+-
+-/**
+- * __prci_coreclksel_use_corepll() - switch the CORECLK mux to output COREPLL
+- * @pd: struct __prci_data * for the PRCI containing the CORECLK mux reg
+- *
+- * Switch the CORECLK mux to the PLL output clock; return once complete.
+- *
+- * Context: Any context. Caller must prevent concurrent changes to the
+- * PRCI_CORECLKSEL_OFFSET register.
+- */
+-static void __prci_coreclksel_use_corepll(struct __prci_data *pd)
+-{
+- u32 r;
+-
+- r = __prci_readl(pd, PRCI_CORECLKSEL_OFFSET);
+- r &= ~PRCI_CORECLKSEL_CORECLKSEL_MASK;
+- __prci_writel(r, PRCI_CORECLKSEL_OFFSET, pd);
+-
+- r = __prci_readl(pd, PRCI_CORECLKSEL_OFFSET); /* barrier */
+-}
+-
+ /*
+ * Linux clock framework integration
+ *
+@@ -378,8 +176,8 @@ static void __prci_coreclksel_use_corepll(struct __prci_data *pd)
+ * these functions.
+ */
+
+-static unsigned long sifive_fu540_prci_wrpll_recalc_rate(struct clk_hw *hw,
+- unsigned long parent_rate)
++unsigned long sifive_prci_wrpll_recalc_rate(struct clk_hw *hw,
++ unsigned long parent_rate)
+ {
+ struct __prci_clock *pc = clk_hw_to_prci_clock(hw);
+ struct __prci_wrpll_data *pwd = pc->pwd;
+@@ -387,9 +185,9 @@ static unsigned long sifive_fu540_prci_wrpll_recalc_rate(struct clk_hw *hw,
+ return wrpll_calc_output_rate(&pwd->c, parent_rate);
+ }
+
+-static long sifive_fu540_prci_wrpll_round_rate(struct clk_hw *hw,
+- unsigned long rate,
+- unsigned long *parent_rate)
++long sifive_prci_wrpll_round_rate(struct clk_hw *hw,
++ unsigned long rate,
++ unsigned long *parent_rate)
+ {
+ struct __prci_clock *pc = clk_hw_to_prci_clock(hw);
+ struct __prci_wrpll_data *pwd = pc->pwd;
+@@ -402,9 +200,8 @@ static long sifive_fu540_prci_wrpll_round_rate(struct clk_hw *hw,
+ return wrpll_calc_output_rate(&c, *parent_rate);
+ }
+
+-static int sifive_fu540_prci_wrpll_set_rate(struct clk_hw *hw,
+- unsigned long rate,
+- unsigned long parent_rate)
++int sifive_prci_wrpll_set_rate(struct clk_hw *hw,
++ unsigned long rate, unsigned long parent_rate)
+ {
+ struct __prci_clock *pc = clk_hw_to_prci_clock(hw);
+ struct __prci_wrpll_data *pwd = pc->pwd;
+@@ -428,20 +225,10 @@ static int sifive_fu540_prci_wrpll_set_rate(struct clk_hw *hw,
+ return 0;
+ }
+
+-static const struct clk_ops sifive_fu540_prci_wrpll_clk_ops = {
+- .set_rate = sifive_fu540_prci_wrpll_set_rate,
+- .round_rate = sifive_fu540_prci_wrpll_round_rate,
+- .recalc_rate = sifive_fu540_prci_wrpll_recalc_rate,
+-};
+-
+-static const struct clk_ops sifive_fu540_prci_wrpll_ro_clk_ops = {
+- .recalc_rate = sifive_fu540_prci_wrpll_recalc_rate,
+-};
+-
+ /* TLCLKSEL clock integration */
+
+-static unsigned long sifive_fu540_prci_tlclksel_recalc_rate(struct clk_hw *hw,
+- unsigned long parent_rate)
++unsigned long sifive_prci_tlclksel_recalc_rate(struct clk_hw *hw,
++ unsigned long parent_rate)
+ {
+ struct __prci_clock *pc = clk_hw_to_prci_clock(hw);
+ struct __prci_data *pd = pc->pd;
+@@ -455,68 +242,62 @@ static unsigned long sifive_fu540_prci_tlclksel_recalc_rate(struct clk_hw *hw,
+ return div_u64(parent_rate, div);
+ }
+
+-static const struct clk_ops sifive_fu540_prci_tlclksel_clk_ops = {
+- .recalc_rate = sifive_fu540_prci_tlclksel_recalc_rate,
+-};
+-
+ /*
+- * PRCI integration data for each WRPLL instance
++ * Core clock mux control
+ */
+
+-static struct __prci_wrpll_data __prci_corepll_data = {
+- .cfg0_offs = PRCI_COREPLLCFG0_OFFSET,
+- .enable_bypass = __prci_coreclksel_use_hfclk,
+- .disable_bypass = __prci_coreclksel_use_corepll,
+-};
++/**
++ * sifive_prci_coreclksel_use_hfclk() - switch the CORECLK mux to output HFCLK
++ * @pd: struct __prci_data * for the PRCI containing the CORECLK mux reg
++ *
++ * Switch the CORECLK mux to the HFCLK input source; return once complete.
++ *
++ * Context: Any context. Caller must prevent concurrent changes to the
++ * PRCI_CORECLKSEL_OFFSET register.
++ */
++void sifive_prci_coreclksel_use_hfclk(struct __prci_data *pd)
++{
++ u32 r;
+
+-static struct __prci_wrpll_data __prci_ddrpll_data = {
+- .cfg0_offs = PRCI_DDRPLLCFG0_OFFSET,
+-};
++ r = __prci_readl(pd, PRCI_CORECLKSEL_OFFSET);
++ r |= PRCI_CORECLKSEL_CORECLKSEL_MASK;
++ __prci_writel(r, PRCI_CORECLKSEL_OFFSET, pd);
+
+-static struct __prci_wrpll_data __prci_gemgxlpll_data = {
+- .cfg0_offs = PRCI_GEMGXLPLLCFG0_OFFSET,
+-};
++ r = __prci_readl(pd, PRCI_CORECLKSEL_OFFSET); /* barrier */
++}
+
+-/*
+- * List of clock controls provided by the PRCI
++/**
++ * sifive_prci_coreclksel_use_corepll() - switch the CORECLK mux to output
++ * COREPLL
++ * @pd: struct __prci_data * for the PRCI containing the CORECLK mux reg
++ *
++ * Switch the CORECLK mux to the COREPLL output clock; return once complete.
++ *
++ * Context: Any context. Caller must prevent concurrent changes to the
++ * PRCI_CORECLKSEL_OFFSET register.
+ */
++void sifive_prci_coreclksel_use_corepll(struct __prci_data *pd)
++{
++ u32 r;
+
+-static struct __prci_clock __prci_init_clocks[] = {
+- [PRCI_CLK_COREPLL] = {
+- .name = "corepll",
+- .parent_name = "hfclk",
+- .ops = &sifive_fu540_prci_wrpll_clk_ops,
+- .pwd = &__prci_corepll_data,
+- },
+- [PRCI_CLK_DDRPLL] = {
+- .name = "ddrpll",
+- .parent_name = "hfclk",
+- .ops = &sifive_fu540_prci_wrpll_ro_clk_ops,
+- .pwd = &__prci_ddrpll_data,
+- },
+- [PRCI_CLK_GEMGXLPLL] = {
+- .name = "gemgxlpll",
+- .parent_name = "hfclk",
+- .ops = &sifive_fu540_prci_wrpll_clk_ops,
+- .pwd = &__prci_gemgxlpll_data,
+- },
+- [PRCI_CLK_TLCLK] = {
+- .name = "tlclk",
+- .parent_name = "corepll",
+- .ops = &sifive_fu540_prci_tlclksel_clk_ops,
+- },
+-};
++ r = __prci_readl(pd, PRCI_CORECLKSEL_OFFSET);
++ r &= ~PRCI_CORECLKSEL_CORECLKSEL_MASK;
++ __prci_writel(r, PRCI_CORECLKSEL_OFFSET, pd);
++
++ r = __prci_readl(pd, PRCI_CORECLKSEL_OFFSET); /* barrier */
++}
+
+ /**
+- * __prci_register_clocks() - register clock controls in the PRCI with Linux
++ * __prci_register_clocks() - register clock controls in the PRCI
+ * @dev: Linux struct device *
+ *
+- * Register the list of clock controls described in __prci_init_plls[] with
++ * Register the list of clock controls described in __prci_init_clocks[] with
+ * the Linux clock framework.
+ *
+ * Return: 0 upon success or a negative error code upon failure.
+ */
+-static int __prci_register_clocks(struct device *dev, struct __prci_data *pd)
++static int __prci_register_clocks(struct device *dev, struct __prci_data *pd,
++ const struct prci_clk_desc *desc)
+ {
+ struct clk_init_data init = { };
+ struct __prci_clock *pic;
+@@ -530,8 +311,8 @@ static int __prci_register_clocks(struct device *dev, struct __prci_data *pd)
+ }
+
+ /* Register PLLs */
+- for (i = 0; i < ARRAY_SIZE(__prci_init_clocks); ++i) {
+- pic = &__prci_init_clocks[i];
++ for (i = 0; i < desc->num_clks; ++i) {
++ pic = &(desc->clks[i]);
+
+ init.name = pic->name;
+ init.parent_names = &pic->parent_name;
+@@ -573,23 +354,22 @@ static int __prci_register_clocks(struct device *dev, struct __prci_data *pd)
+ return 0;
+ }
+
+-/*
+- * Linux device model integration
++/**
++ * sifive_prci_init() - initialize prci data and check parent count
+ *
+- * See the Linux device model documentation for more information about
+- * these functions.
++ * Return: 0 upon success or a negative error code upon failure.
+ */
+-static int sifive_fu540_prci_probe(struct platform_device *pdev)
++static int sifive_prci_probe(struct platform_device *pdev)
+ {
+ struct device *dev = &pdev->dev;
+ struct resource *res;
+ struct __prci_data *pd;
++ const struct prci_clk_desc *desc;
+ int r;
+
+- pd = devm_kzalloc(dev,
+- struct_size(pd, hw_clks.hws,
+- ARRAY_SIZE(__prci_init_clocks)),
+- GFP_KERNEL);
++ desc = of_device_get_match_data(&pdev->dev);
++
++ pd = devm_kzalloc(dev, struct_size(pd, hw_clks.hws, desc->num_clks), GFP_KERNEL);
+ if (!pd)
+ return -ENOMEM;
+
+@@ -598,33 +378,32 @@ static int sifive_fu540_prci_probe(struct platform_device *pdev)
+ if (IS_ERR(pd->va))
+ return PTR_ERR(pd->va);
+
+- r = __prci_register_clocks(dev, pd);
++ r = __prci_register_clocks(dev, pd, desc);
+ if (r) {
+ dev_err(dev, "could not register clocks: %d\n", r);
+ return r;
+ }
+
+- dev_dbg(dev, "SiFive FU540 PRCI probed\n");
++ dev_dbg(dev, "SiFive PRCI probed\n");
+
+ return 0;
+ }
+
+-static const struct of_device_id sifive_fu540_prci_of_match[] = {
+- { .compatible = "sifive,fu540-c000-prci", },
++static const struct of_device_id sifive_prci_of_match[] = {
++ {.compatible = "sifive,fu540-c000-prci", .data = &prci_clk_fu540},
+ {}
+ };
+-MODULE_DEVICE_TABLE(of, sifive_fu540_prci_of_match);
+
+-static struct platform_driver sifive_fu540_prci_driver = {
+- .driver = {
+- .name = "sifive-fu540-prci",
+- .of_match_table = sifive_fu540_prci_of_match,
++static struct platform_driver sifive_prci_driver = {
++ .driver = {
++ .name = "sifive-clk-prci",
++ .of_match_table = sifive_prci_of_match,
+ },
+- .probe = sifive_fu540_prci_probe,
++ .probe = sifive_prci_probe,
+ };
+
+-static int __init sifive_fu540_prci_init(void)
++static int __init sifive_prci_init(void)
+ {
+- return platform_driver_register(&sifive_fu540_prci_driver);
++ return platform_driver_register(&sifive_prci_driver);
+ }
+-core_initcall(sifive_fu540_prci_init);
++core_initcall(sifive_prci_init);
+diff --git a/drivers/clk/sifive/sifive-prci.h b/drivers/clk/sifive/sifive-prci.h
+new file mode 100644
+index 000000000000..025f717bc053
+--- /dev/null
++++ b/drivers/clk/sifive/sifive-prci.h
+@@ -0,0 +1,201 @@
++/* SPDX-License-Identifier: GPL-2.0 */
++/*
++ * Copyright (C) 2018-2019 SiFive, Inc.
++ * Wesley Terpstra
++ * Paul Walmsley
++ * Zong Li
++ */
++
++#ifndef __SIFIVE_CLK_SIFIVE_PRCI_H
++#define __SIFIVE_CLK_SIFIVE_PRCI_H
++
++#include <linux/clk/analogbits-wrpll-cln28hpc.h>
++#include <linux/clk-provider.h>
++#include <linux/platform_device.h>
++
++/*
++ * EXPECTED_CLK_PARENT_COUNT: how many parent clocks this driver expects:
++ * hfclk and rtcclk
++ */
++#define EXPECTED_CLK_PARENT_COUNT 2
++
++/*
++ * Register offsets and bitmasks
++ */
++
++/* COREPLLCFG0 */
++#define PRCI_COREPLLCFG0_OFFSET 0x4
++#define PRCI_COREPLLCFG0_DIVR_SHIFT 0
++#define PRCI_COREPLLCFG0_DIVR_MASK (0x3f << PRCI_COREPLLCFG0_DIVR_SHIFT)
++#define PRCI_COREPLLCFG0_DIVF_SHIFT 6
++#define PRCI_COREPLLCFG0_DIVF_MASK (0x1ff << PRCI_COREPLLCFG0_DIVF_SHIFT)
++#define PRCI_COREPLLCFG0_DIVQ_SHIFT 15
++#define PRCI_COREPLLCFG0_DIVQ_MASK (0x7 << PRCI_COREPLLCFG0_DIVQ_SHIFT)
++#define PRCI_COREPLLCFG0_RANGE_SHIFT 18
++#define PRCI_COREPLLCFG0_RANGE_MASK (0x7 << PRCI_COREPLLCFG0_RANGE_SHIFT)
++#define PRCI_COREPLLCFG0_BYPASS_SHIFT 24
++#define PRCI_COREPLLCFG0_BYPASS_MASK (0x1 << PRCI_COREPLLCFG0_BYPASS_SHIFT)
++#define PRCI_COREPLLCFG0_FSE_SHIFT 25
++#define PRCI_COREPLLCFG0_FSE_MASK (0x1 << PRCI_COREPLLCFG0_FSE_SHIFT)
++#define PRCI_COREPLLCFG0_LOCK_SHIFT 31
++#define PRCI_COREPLLCFG0_LOCK_MASK (0x1 << PRCI_COREPLLCFG0_LOCK_SHIFT)
++
++/* DDRPLLCFG0 */
++#define PRCI_DDRPLLCFG0_OFFSET 0xc
++#define PRCI_DDRPLLCFG0_DIVR_SHIFT 0
++#define PRCI_DDRPLLCFG0_DIVR_MASK (0x3f << PRCI_DDRPLLCFG0_DIVR_SHIFT)
++#define PRCI_DDRPLLCFG0_DIVF_SHIFT 6
++#define PRCI_DDRPLLCFG0_DIVF_MASK (0x1ff << PRCI_DDRPLLCFG0_DIVF_SHIFT)
++#define PRCI_DDRPLLCFG0_DIVQ_SHIFT 15
++#define PRCI_DDRPLLCFG0_DIVQ_MASK (0x7 << PRCI_DDRPLLCFG0_DIVQ_SHIFT)
++#define PRCI_DDRPLLCFG0_RANGE_SHIFT 18
++#define PRCI_DDRPLLCFG0_RANGE_MASK (0x7 << PRCI_DDRPLLCFG0_RANGE_SHIFT)
++#define PRCI_DDRPLLCFG0_BYPASS_SHIFT 24
++#define PRCI_DDRPLLCFG0_BYPASS_MASK (0x1 << PRCI_DDRPLLCFG0_BYPASS_SHIFT)
++#define PRCI_DDRPLLCFG0_FSE_SHIFT 25
++#define PRCI_DDRPLLCFG0_FSE_MASK (0x1 << PRCI_DDRPLLCFG0_FSE_SHIFT)
++#define PRCI_DDRPLLCFG0_LOCK_SHIFT 31
++#define PRCI_DDRPLLCFG0_LOCK_MASK (0x1 << PRCI_DDRPLLCFG0_LOCK_SHIFT)
++
++/* DDRPLLCFG1 */
++#define PRCI_DDRPLLCFG1_OFFSET 0x10
++#define PRCI_DDRPLLCFG1_CKE_SHIFT 24
++#define PRCI_DDRPLLCFG1_CKE_MASK (0x1 << PRCI_DDRPLLCFG1_CKE_SHIFT)
++
++/* GEMGXLPLLCFG0 */
++#define PRCI_GEMGXLPLLCFG0_OFFSET 0x1c
++#define PRCI_GEMGXLPLLCFG0_DIVR_SHIFT 0
++#define PRCI_GEMGXLPLLCFG0_DIVR_MASK (0x3f << PRCI_GEMGXLPLLCFG0_DIVR_SHIFT)
++#define PRCI_GEMGXLPLLCFG0_DIVF_SHIFT 6
++#define PRCI_GEMGXLPLLCFG0_DIVF_MASK (0x1ff << PRCI_GEMGXLPLLCFG0_DIVF_SHIFT)
++#define PRCI_GEMGXLPLLCFG0_DIVQ_SHIFT 15
++#define PRCI_GEMGXLPLLCFG0_DIVQ_MASK (0x7 << PRCI_GEMGXLPLLCFG0_DIVQ_SHIFT)
++#define PRCI_GEMGXLPLLCFG0_RANGE_SHIFT 18
++#define PRCI_GEMGXLPLLCFG0_RANGE_MASK (0x7 << PRCI_GEMGXLPLLCFG0_RANGE_SHIFT)
++#define PRCI_GEMGXLPLLCFG0_BYPASS_SHIFT 24
++#define PRCI_GEMGXLPLLCFG0_BYPASS_MASK (0x1 << PRCI_GEMGXLPLLCFG0_BYPASS_SHIFT)
++#define PRCI_GEMGXLPLLCFG0_FSE_SHIFT 25
++#define PRCI_GEMGXLPLLCFG0_FSE_MASK (0x1 << PRCI_GEMGXLPLLCFG0_FSE_SHIFT)
++#define PRCI_GEMGXLPLLCFG0_LOCK_SHIFT 31
++#define PRCI_GEMGXLPLLCFG0_LOCK_MASK (0x1 << PRCI_GEMGXLPLLCFG0_LOCK_SHIFT)
++
++/* GEMGXLPLLCFG1 */
++#define PRCI_GEMGXLPLLCFG1_OFFSET 0x20
++#define RCI_GEMGXLPLLCFG1_CKE_SHIFT 24
++#define PRCI_GEMGXLPLLCFG1_CKE_MASK (0x1 << PRCI_GEMGXLPLLCFG1_CKE_SHIFT)
++
++/* CORECLKSEL */
++#define PRCI_CORECLKSEL_OFFSET 0x24
++#define PRCI_CORECLKSEL_CORECLKSEL_SHIFT 0
++#define PRCI_CORECLKSEL_CORECLKSEL_MASK \
++ (0x1 << PRCI_CORECLKSEL_CORECLKSEL_SHIFT)
++
++/* DEVICESRESETREG */
++#define PRCI_DEVICESRESETREG_OFFSET 0x28
++#define PRCI_DEVICESRESETREG_DDR_CTRL_RST_N_SHIFT 0
++#define PRCI_DEVICESRESETREG_DDR_CTRL_RST_N_MASK \
++ (0x1 << PRCI_DEVICESRESETREG_DDR_CTRL_RST_N_SHIFT)
++#define PRCI_DEVICESRESETREG_DDR_AXI_RST_N_SHIFT 1
++#define PRCI_DEVICESRESETREG_DDR_AXI_RST_N_MASK \
++ (0x1 << PRCI_DEVICESRESETREG_DDR_AXI_RST_N_SHIFT)
++#define PRCI_DEVICESRESETREG_DDR_AHB_RST_N_SHIFT 2
++#define PRCI_DEVICESRESETREG_DDR_AHB_RST_N_MASK \
++ (0x1 << PRCI_DEVICESRESETREG_DDR_AHB_RST_N_SHIFT)
++#define PRCI_DEVICESRESETREG_DDR_PHY_RST_N_SHIFT 3
++#define PRCI_DEVICESRESETREG_DDR_PHY_RST_N_MASK \
++ (0x1 << PRCI_DEVICESRESETREG_DDR_PHY_RST_N_SHIFT)
++#define PRCI_DEVICESRESETREG_GEMGXL_RST_N_SHIFT 5
++#define PRCI_DEVICESRESETREG_GEMGXL_RST_N_MASK \
++ (0x1 << PRCI_DEVICESRESETREG_GEMGXL_RST_N_SHIFT)
++#define PRCI_DEVICESRESETREG_CHIPLINK_RST_N_SHIFT 6
++#define PRCI_DEVICESRESETREG_CHIPLINK_RST_N_MASK \
++ (0x1 << PRCI_DEVICESRESETREG_CHIPLINK_RST_N_SHIFT)
++
++/* CLKMUXSTATUSREG */
++#define PRCI_CLKMUXSTATUSREG_OFFSET 0x2c
++#define PRCI_CLKMUXSTATUSREG_TLCLKSEL_STATUS_SHIFT 1
++#define PRCI_CLKMUXSTATUSREG_TLCLKSEL_STATUS_MASK \
++ (0x1 << PRCI_CLKMUXSTATUSREG_TLCLKSEL_STATUS_SHIFT)
++
++/*
++ * Private structures
++ */
++
++/**
++ * struct __prci_data - per-device-instance data
++ * @va: base virtual address of the PRCI IP block
++ * @hw_clks: encapsulates struct clk_hw records
++ *
++ * PRCI per-device instance data
++ */
++struct __prci_data {
++ void __iomem *va;
++ struct clk_hw_onecell_data hw_clks;
++};
++
++/**
++ * struct __prci_wrpll_data - WRPLL configuration and integration data
++ * @c: WRPLL current configuration record
++ * @enable_bypass: fn ptr to code to bypass the WRPLL (if applicable; else NULL)
++ * @disable_bypass: fn ptr to code to not bypass the WRPLL (or NULL)
++ * @cfg0_offs: WRPLL CFG0 register offset (in bytes) from the PRCI base address
++ *
++ * @enable_bypass and @disable_bypass are used for WRPLL instances
++ * that contain a separate external glitchless clock mux downstream
++ * from the PLL. The WRPLL internal bypass mux is not glitchless.
++ */
++struct __prci_wrpll_data {
++ struct wrpll_cfg c;
++ void (*enable_bypass)(struct __prci_data *pd);
++ void (*disable_bypass)(struct __prci_data *pd);
++ u8 cfg0_offs;
++};
++
++/**
++ * struct __prci_clock - describes a clock device managed by PRCI
++ * @name: user-readable clock name string - should match the manual
++ * @parent_name: parent name for this clock
++ * @ops: struct clk_ops for the Linux clock framework to use for control
++ * @hw: Linux-private clock data
++ * @pwd: WRPLL-specific data, associated with this clock (if not NULL)
++ * @pd: PRCI-specific data associated with this clock (if not NULL)
++ *
++ * PRCI clock data. Used by the PRCI driver to register PRCI-provided
++ * clocks to the Linux clock infrastructure.
++ */
++struct __prci_clock {
++ const char *name;
++ const char *parent_name;
++ const struct clk_ops *ops;
++ struct clk_hw hw;
++ struct __prci_wrpll_data *pwd;
++ struct __prci_data *pd;
++};
++
++#define clk_hw_to_prci_clock(pwd) container_of(pwd, struct __prci_clock, hw)
++
++/*
++ * struct prci_clk_desc - describes the information of clocks of each SoCs
++ * @clks: point to a array of __prci_clock
++ * @num_clks: the number of element of clks
++ */
++struct prci_clk_desc {
++ struct __prci_clock *clks;
++ size_t num_clks;
++};
++
++/* Core clock mux control */
++void sifive_prci_coreclksel_use_hfclk(struct __prci_data *pd);
++void sifive_prci_coreclksel_use_corepll(struct __prci_data *pd);
++
++/* Linux clock framework integration */
++long sifive_prci_wrpll_round_rate(struct clk_hw *hw, unsigned long rate,
++ unsigned long *parent_rate);
++int sifive_prci_wrpll_set_rate(struct clk_hw *hw, unsigned long rate,
++ unsigned long parent_rate);
++unsigned long sifive_prci_wrpll_recalc_rate(struct clk_hw *hw,
++ unsigned long parent_rate);
++unsigned long sifive_prci_tlclksel_recalc_rate(struct clk_hw *hw,
++ unsigned long parent_rate);
++
++#endif /* __SIFIVE_CLK_SIFIVE_PRCI_H */
+
+From patchwork Wed Nov 11 10:06:06 2020
+Content-Type: text/plain; charset="utf-8"
+MIME-Version: 1.0
+Content-Transfer-Encoding: 7bit
+X-Patchwork-Id: 11897343
+Return-Path:
+ <SRS0=XU8h=ER=lists.infradead.org=linux-riscv-bounces+patchwork-linux-riscv=patchwork.kernel.org@kernel.org>
+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 A1FFB139F
+ Wed, 11 Nov 2020 10:06:41 +0000 (UTC)
+Received: from merlin.infradead.org (merlin.infradead.org [205.233.59.134])
+ (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits))
+ (No client certificate requested)
+ by mail.kernel.org (Postfix) with ESMTPS id 4C7A420674
+ Wed, 11 Nov 2020 10:06:41 +0000 (UTC)
+Authentication-Results: mail.kernel.org;
+ dkim=pass (2048-bit key) header.d=lists.infradead.org
+ dkim=fail reason="signature verification failed" (2048-bit key)
+DMARC-Filter: OpenDMARC Filter v1.3.2 mail.kernel.org 4C7A420674
+Authentication-Results: mail.kernel.org;
+ dmarc=none (p=none dis=none) header.from=sifive.com
+Authentication-Results: mail.kernel.org;
+ spf=none
+ smtp.mailfrom=linux-riscv-bounces+patchwork-linux-riscv=patchwork.kernel.org@lists.infradead.org
+DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed;
+ d=lists.infradead.org; s=merlin.20170209; h=Sender:Content-Transfer-Encoding:
+ Content-Type:Cc:List-Subscribe:List-Help:List-Post:List-Archive:
+ List-Unsubscribe:List-Id:MIME-Version:References:In-Reply-To:Message-Id:Date:
+ Subject:To:From:Reply-To:Content-ID:Content-Description:Resent-Date:
+ Resent-From:Resent-Sender:Resent-To:Resent-Cc:Resent-Message-ID:List-Owner;
+ bh=8M31xTWIfUttsrqEIOFkLkkyiFCsznYAXX4jpceXv4A=; b=qBw7oS3mwfu033UCPMmqQoIpb
+ 2vAv10HZmtsPiax38/U81wtjBg4Prf+wINDCyMfFA14jB9t6/x4k9OcO0u88m3qtvCxA2vv0j/u7d
+ pyBT39UMr2TpTP0YPjAfe5Myl6ocXBR7SS2fxa2rwa6KzdGSMPOnjjPUtgiU2ymt5rDFCPT0SaS2T
+ FoLBk0SJQFfGu50k7NlCZkQhNsmWdgkM54WUn+ZnjTlHxEXPuMNN88H30OHs3AHVulXszS5bG3SSF
+ xKe8wds85aA3Q0xFFNL12ydnrEQVCoFcq4MONORy7b+XXqCl2a++jSSU31FSMA/XhxJhR8qObW7T2
+ syj36oKsQ==;
+Received: from localhost ([::1] helo=merlin.infradead.org)
+ by merlin.infradead.org with esmtp (Exim 4.92.3 #3 (Red Hat Linux))
+ id 1kcn1F-0001Lp-3C; Wed, 11 Nov 2020 10:06:25 +0000
+Received: from mail-pg1-x543.google.com ([2607:f8b0:4864:20::543])
+ by merlin.infradead.org with esmtps (Exim 4.92.3 #3 (Red Hat Linux))
+ id 1kcn1B-0001Ju-Md
+Received: by mail-pg1-x543.google.com with SMTP id h6so1153275pgk.4
+DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=sifive.com; s=google;
+ h=from:to:cc:subject:date:message-id:in-reply-to:references
+ :mime-version:content-transfer-encoding;
+ bh=jUzLpOLCCQxDI0oXwDQj4vn2ea5xlcrxx/Uo+2NUKPY=;
+ b=GC+wCOZXigNUTzVyZoZ5sQt0B+qGYQ1rxmobkqe9PjmIvCc/rsn/BC8H3SYZc1hh7I
+ ccETM+g3YzkfkhlvzwnMVXtFwOcS9ucDcp9DLB0k6R0WOAdnNzMABEvcf5WqS0Im3vSN
+ Q8DKnOqwENJeRcYAZBFf2Cm/JpxjIZlkTedy2/RlgQ0hj60kJk9yTI6lvt4enmm9Rhhq
+ 00HHbUlbR28KDigrln9y4ub2QAB8IT1RoQdrVL8NlXWcUK/g1VPzGDK9B1xJ0dx8NrNO
+ 0WrqDqiHfe0ve9o60xGs5YrUO4zAbx/BYypBao5sHykIa0P47nR/r9/I5PDEpjN94jxC
+ sPuw==
+X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed;
+ d=1e100.net; s=20161025;
+ h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to
+ :references:mime-version:content-transfer-encoding;
+ bh=jUzLpOLCCQxDI0oXwDQj4vn2ea5xlcrxx/Uo+2NUKPY=;
+ b=qpt+M+z3gzNH3+8gmx03oWa43xIXEC5PTMslEd6R5Sl7l1rVS7HOPJt/XzUyfQXh/k
+ MQJPZxGh8zyZFR6V9zMFXbL04yHowZaDdn8SJZ9A7QPc/Z2MM3XxzIHXWtgBwDXPqICD
+ 0ku+Z8LEQDuATbKcNJUlF8dhXub/sK4MNMPTNJYh86UXqymHHUNaXgWSG8nHpvUyaKWA
+ q11d27V29oreOq7kK+1VDMIbMRPBXdS1Ra4rJuviWOb02GLLSqVgLWVuYcoocJbRsEqE
+ fk/jhVIOy7AKX26bE34/lEWTmXaHwzz3zLIgdgT8nUKq0WzlPHiqgGY4GD1k8DZmbp4D
+ A3YQ==
+X-Gm-Message-State: AOAM530gEeGE8OMORL33Vr/vtRwFsN1QjnQM5BPR+3Rn9/uySLb3uYjl
+ 54lBbM0xgBN1yrC6kUnjgcpNLA==
+X-Google-Smtp-Source:
+ ABdhPJzaTSpLq60xMn+cJpFbOkkYXEhNYIOqlqrtQTK0CvD4ZUtz6woJa+U319CNjyJImvVsb89P1A==
+X-Received: by 2002:a63:e650:: with SMTP id
+ p16mr20477838pgj.295.1605089179165;
+ Wed, 11 Nov 2020 02:06:19 -0800 (PST)
+Received: from hsinchu02.internal.sifive.com
+ (114-34-229-221.HINET-IP.hinet.net. [114.34.229.221])
+ by smtp.gmail.com with ESMTPSA id u22sm1872801pgf.24.2020.11.11.02.06.16
+ (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256);
+ Wed, 11 Nov 2020 02:06:18 -0800 (PST)
+Subject: [PATCH v4 2/4] clk: sifive: Use common name for prci configuration
+Date: Wed, 11 Nov 2020 18:06:06 +0800
+X-Mailer: git-send-email 2.29.2
+MIME-Version: 1.0
+X-CRM114-Version: 20100106-BlameMichelson ( TRE 0.8.0 (BSD) ) MR-646709E3
+X-CRM114-CacheID: sfid-20201111_050621_742564_129A155B
+X-CRM114-Status: GOOD ( 11.99 )
+X-Spam-Score: -0.2 (/)
+X-Spam-Report: SpamAssassin version 3.4.4 on merlin.infradead.org summary:
+ Content analysis details: (-0.2 points)
+ pts rule name description
+ ---- ----------------------
+ --------------------------------------------------
+ -0.0 RCVD_IN_DNSWL_NONE RBL: Sender listed at https://www.dnswl.org/,
+ no trust [2607:f8b0:4864:20:0:0:0:543 listed in]
+ [list.dnswl.org]
+ -0.0 SPF_PASS SPF: sender matches SPF record
+ 0.0 SPF_HELO_NONE SPF: HELO does not publish an SPF Record
+ 0.1 DKIM_SIGNED Message has a DKIM or DK signature,
+ not necessarily
+ valid
+ -0.1 DKIM_VALID Message has at least one valid DKIM or DK signature
+ -0.1 DKIM_VALID_AU Message has a valid DKIM or DK signature from
+ author's domain
+ -0.1 DKIM_VALID_EF Message has a valid DKIM or DK signature from
+ envelope-from domain
+X-Mailman-Version: 2.1.29
+Precedence: list
+List-Id: <linux-riscv.lists.infradead.org>
+List-Unsubscribe: <http://lists.infradead.org/mailman/options/linux-riscv>,
+List-Archive: <http://lists.infradead.org/pipermail/linux-riscv/>
+List-Subscribe: <http://lists.infradead.org/mailman/listinfo/linux-riscv>,
+Errors-To:
+ linux-riscv-bounces+patchwork-linux-riscv=patchwork.kernel.org@lists.infradead.org
+
+Use generic name CLK_SIFIVE_PRCI instead of CLK_SIFIVE_FU540_PRCI. This
+patch is prepared for fu740 support.
+
+---
+ arch/riscv/Kconfig.socs | 2 +-
+ drivers/clk/sifive/Kconfig | 6 +++---
+ drivers/clk/sifive/Makefile | 2 +-
+ 3 files changed, 5 insertions(+), 5 deletions(-)
+
+diff --git a/arch/riscv/Kconfig.socs b/arch/riscv/Kconfig.socs
+index 8a55f6156661..3284d5c291be 100644
+--- a/arch/riscv/Kconfig.socs
++++ b/arch/riscv/Kconfig.socs
+@@ -5,7 +5,7 @@ config SOC_SIFIVE
+ select SERIAL_SIFIVE if TTY
+ select SERIAL_SIFIVE_CONSOLE if TTY
+ select CLK_SIFIVE
+- select CLK_SIFIVE_FU540_PRCI
++ select CLK_SIFIVE_PRCI
+ select SIFIVE_PLIC
+ help
+ This enables support for SiFive SoC platform hardware.
+diff --git a/drivers/clk/sifive/Kconfig b/drivers/clk/sifive/Kconfig
+index f3b4eb9cb0f5..ab48cf7e0105 100644
+--- a/drivers/clk/sifive/Kconfig
++++ b/drivers/clk/sifive/Kconfig
+@@ -8,12 +8,12 @@ menuconfig CLK_SIFIVE
+
+ if CLK_SIFIVE
+
+-config CLK_SIFIVE_FU540_PRCI
+- bool "PRCI driver for SiFive FU540 SoCs"
++config CLK_SIFIVE_PRCI
++ bool "PRCI driver for SiFive SoCs"
+ select CLK_ANALOGBITS_WRPLL_CLN28HPC
+ help
+ Supports the Power Reset Clock interface (PRCI) IP block found in
+- FU540 SoCs. If this kernel is meant to run on a SiFive FU540 SoC,
++ FU540 SoCs. If this kernel is meant to run on a SiFive FU540 SoC,
+ enable this driver.
+
+ endif
+diff --git a/drivers/clk/sifive/Makefile b/drivers/clk/sifive/Makefile
+index 627effe2ece1..fe3e2cb4c4d8 100644
+--- a/drivers/clk/sifive/Makefile
++++ b/drivers/clk/sifive/Makefile
+@@ -1,4 +1,4 @@
+ # SPDX-License-Identifier: GPL-2.0-only
+ obj-y += sifive-prci.o
+
+-obj-$(CONFIG_CLK_SIFIVE_FU540_PRCI) += fu540-prci.o
++obj-$(CONFIG_CLK_SIFIVE_PRCI) += fu540-prci.o
+
+From patchwork Wed Nov 11 10:06:07 2020
+Content-Type: text/plain; charset="utf-8"
+MIME-Version: 1.0
+Content-Transfer-Encoding: 7bit
+X-Patchwork-Id: 11897347
+Return-Path:
+ <SRS0=XU8h=ER=lists.infradead.org=linux-riscv-bounces+patchwork-linux-riscv=patchwork.kernel.org@kernel.org>
+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 CB2CB16C1
+ Wed, 11 Nov 2020 10:06:45 +0000 (UTC)
+Received: from merlin.infradead.org (merlin.infradead.org [205.233.59.134])
+ (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits))
+ (No client certificate requested)
+ by mail.kernel.org (Postfix) with ESMTPS id 5EA7020756
+ Wed, 11 Nov 2020 10:06:45 +0000 (UTC)
+Authentication-Results: mail.kernel.org;
+ dkim=pass (2048-bit key) header.d=lists.infradead.org
+ dkim=fail reason="signature verification failed" (2048-bit key)
+DMARC-Filter: OpenDMARC Filter v1.3.2 mail.kernel.org 5EA7020756
+Authentication-Results: mail.kernel.org;
+ dmarc=none (p=none dis=none) header.from=sifive.com
+Authentication-Results: mail.kernel.org;
+ spf=none
+ smtp.mailfrom=linux-riscv-bounces+patchwork-linux-riscv=patchwork.kernel.org@lists.infradead.org
+DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed;
+ d=lists.infradead.org; s=merlin.20170209; h=Sender:Content-Transfer-Encoding:
+ Content-Type:Cc:List-Subscribe:List-Help:List-Post:List-Archive:
+ List-Unsubscribe:List-Id:MIME-Version:References:In-Reply-To:Message-Id:Date:
+ Subject:To:From:Reply-To:Content-ID:Content-Description:Resent-Date:
+ Resent-From:Resent-Sender:Resent-To:Resent-Cc:Resent-Message-ID:List-Owner;
+ bh=lVhQgWcRK8t+icobc320Mvw2SK2pa6BityQVJ8tOZ44=; b=t946ymQkXiy0CVBWstEyQ1Iv4
+ CMq9F3UMDuPInkASSB1F/j+7tdXjKJ03wTyuqnLGkIUt11JFYR6nvZFGbaAWvHbRmjqFKOzTH+4eh
+ aCzv/PLkRmr+nlttEybZ7IwalGjbt9iC3udKjjZ8acr8AdVXg/VrEcJFht4ZPZHmQa0mw7oaCGzPi
+ otXN80S8tunksRvUbRAmvN8THK563yWX65Siucg/BSGOQRAa8HLKlcJDRho28eLaeEHXIjiFD0Qt8
+ y09HUFPwyCLutKEvb0hSKVClHmCzQJ05EXHioc8rXxtX4dUJ/8XMkLCWyN/PX4GU9md7jHFQ3mN0y
+ 1qBlXZesA==;
+Received: from localhost ([::1] helo=merlin.infradead.org)
+ by merlin.infradead.org with esmtp (Exim 4.92.3 #3 (Red Hat Linux))
+ id 1kcn1I-0001Nc-Ui; Wed, 11 Nov 2020 10:06:28 +0000
+Received: from mail-pl1-x641.google.com ([2607:f8b0:4864:20::641])
+ by merlin.infradead.org with esmtps (Exim 4.92.3 #3 (Red Hat Linux))
+ id 1kcn1E-0001Kp-IL
+Received: by mail-pl1-x641.google.com with SMTP id b3so710408pls.11
+DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=sifive.com; s=google;
+ h=from:to:cc:subject:date:message-id:in-reply-to:references
+ :mime-version:content-transfer-encoding;
+ bh=A3BlQc2MRybB5FiAx2c+SYK+EYdvwk/XU5ETgPyL/wo=;
+ b=RiuGW/pZdiApo0EHoEoRg45i8IdvCrf5jJh5UtuNQHC0Q5czsccHssCZnZPedAp82F
+ zXlCG5FYVq0tw7zRvDrjWwQ+3d3JhVL21KLXFkhIL0D0qFc6FXQY8eKkjmUFtBtzarIo
+ A7BzBRkRctw7K2nCGMLrO7doquccZ+RpIKOjzzxWZcPoD9G7U8oBpJ/tC1ItLnBj/kmp
+ VEz76o8vXe5xe1+BY9bm+SGRoYx4z5s++qXYOmZv9lWlOw/Cvo+9m9LGpZLk4R67Tvux
+ /SZYwcHJo0Ljp8pSo47HtdApGwrw8NjhefAmMRIvUg/gMVnu5kc3ZZWrl8dwVut5q+Hg
+ Y/fw==
+X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed;
+ d=1e100.net; s=20161025;
+ h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to
+ :references:mime-version:content-transfer-encoding;
+ bh=A3BlQc2MRybB5FiAx2c+SYK+EYdvwk/XU5ETgPyL/wo=;
+ b=HacOL1rHKTeNifDz8nzY5Zax4zXuoS62ZJSP8cdEWe5jwlUncU5Mz2/Ji+T46T87LN
+ ug2pPq8YkQvo5mAawUFmAWTMnfiaY2woj1JmM/KVnQS/Yy4+q3kY3vbBJaKHoADoRIN+
+ bHirNo0vW5Z3wQfc6dwkZXZ60k4BgdPlbc9Dnquw0SUJGsX62SBzX2pJANKs+9+puGHj
+ ZKKl4N4X23ueD6sbslC2R3WDzu/xF5BuVvWmg+l8g0Q8g2PVbY1FuUEnIQTtXAQaQ9EY
+ JkmwA+x/hEv+f+poqj60vzpmcxKv0mqmXEc4q2TT9B5K7FFOvGJ9nhuQs0PAlJPwJYx/
+ TS2g==
+X-Gm-Message-State: AOAM5309joyTx8wVWXyuyzu51vBS6RfWmH2pgM6NkUtihJVV/BuT3lXy
+ tqSd2TfNKGEYrA3s9XKAwTZDsw==
+X-Google-Smtp-Source:
+ ABdhPJwxRk/wVkQDxS/Mw8BxslnAIh64ghgND8BjM79JF2E4Tx+1u+PP6NaDddejbfJt4j1Vvz5cZQ==
+X-Received: by 2002:a17:902:d386:b029:d7:c6c4:b128 with SMTP id
+ e6-20020a170902d386b02900d7c6c4b128mr19757740pld.70.1605089182337;
+ Wed, 11 Nov 2020 02:06:22 -0800 (PST)
+Received: from hsinchu02.internal.sifive.com
+ (114-34-229-221.HINET-IP.hinet.net. [114.34.229.221])
+ by smtp.gmail.com with ESMTPSA id u22sm1872801pgf.24.2020.11.11.02.06.19
+ (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256);
+ Wed, 11 Nov 2020 02:06:21 -0800 (PST)
+Subject: [PATCH v4 3/4] clk: sifive: Add a driver for the SiFive FU740 PRCI IP
+ block
+Date: Wed, 11 Nov 2020 18:06:07 +0800
+X-Mailer: git-send-email 2.29.2
+MIME-Version: 1.0
+X-CRM114-Version: 20100106-BlameMichelson ( TRE 0.8.0 (BSD) ) MR-646709E3
+X-CRM114-CacheID: sfid-20201111_050624_696105_7EAC376D
+X-CRM114-Status: GOOD ( 27.29 )
+X-Spam-Score: -0.2 (/)
+X-Spam-Report: SpamAssassin version 3.4.4 on merlin.infradead.org summary:
+ Content analysis details: (-0.2 points)
+ pts rule name description
+ ---- ----------------------
+ --------------------------------------------------
+ -0.0 RCVD_IN_DNSWL_NONE RBL: Sender listed at https://www.dnswl.org/,
+ no trust [2607:f8b0:4864:20:0:0:0:641 listed in]
+ [list.dnswl.org]
+ -0.0 SPF_PASS SPF: sender matches SPF record
+ 0.0 SPF_HELO_NONE SPF: HELO does not publish an SPF Record
+ 0.1 DKIM_SIGNED Message has a DKIM or DK signature,
+ not necessarily
+ valid
+ -0.1 DKIM_VALID Message has at least one valid DKIM or DK signature
+ -0.1 DKIM_VALID_AU Message has a valid DKIM or DK signature from
+ author's domain
+ -0.1 DKIM_VALID_EF Message has a valid DKIM or DK signature from
+ envelope-from domain
+X-Mailman-Version: 2.1.29
+Precedence: list
+List-Id: <linux-riscv.lists.infradead.org>
+List-Unsubscribe: <http://lists.infradead.org/mailman/options/linux-riscv>,
+List-Archive: <http://lists.infradead.org/pipermail/linux-riscv/>
+List-Subscribe: <http://lists.infradead.org/mailman/listinfo/linux-riscv>,
+Errors-To:
+ linux-riscv-bounces+patchwork-linux-riscv=patchwork.kernel.org@lists.infradead.org
+
+Add driver code for the SiFive FU740 PRCI IP block. This IP block
+handles reset and clock control for the SiFive FU740 device and
+implements SoC-level clock tree controls and dividers.
+
+This driver contains bug fixes and contributions from
+
+---
+ drivers/clk/sifive/Kconfig | 4 +-
+ drivers/clk/sifive/Makefile | 1 +
+ drivers/clk/sifive/fu740-prci.c | 122 ++++++++++++++++++
+ drivers/clk/sifive/fu740-prci.h | 21 +++
+ drivers/clk/sifive/sifive-prci.c | 120 +++++++++++++++++
+ drivers/clk/sifive/sifive-prci.h | 88 +++++++++++++
+ include/dt-bindings/clock/sifive-fu740-prci.h | 23 ++++
+ 7 files changed, 377 insertions(+), 2 deletions(-)
+ create mode 100644 drivers/clk/sifive/fu740-prci.c
+ create mode 100644 drivers/clk/sifive/fu740-prci.h
+ create mode 100644 include/dt-bindings/clock/sifive-fu740-prci.h
+
+diff --git a/drivers/clk/sifive/Kconfig b/drivers/clk/sifive/Kconfig
+index ab48cf7e0105..1c14eb20c066 100644
+--- a/drivers/clk/sifive/Kconfig
++++ b/drivers/clk/sifive/Kconfig
+@@ -13,7 +13,7 @@ config CLK_SIFIVE_PRCI
+ select CLK_ANALOGBITS_WRPLL_CLN28HPC
+ help
+ Supports the Power Reset Clock interface (PRCI) IP block found in
+- FU540 SoCs. If this kernel is meant to run on a SiFive FU540 SoC,
+- enable this driver.
++ FU540/FU740 SoCs. If this kernel is meant to run on a SiFive FU540/
++ FU740 SoCs, enable this driver.
+
+ endif
+diff --git a/drivers/clk/sifive/Makefile b/drivers/clk/sifive/Makefile
+index fe3e2cb4c4d8..2c05798e4ba4 100644
+--- a/drivers/clk/sifive/Makefile
++++ b/drivers/clk/sifive/Makefile
+@@ -2,3 +2,4 @@
+ obj-y += sifive-prci.o
+
+ obj-$(CONFIG_CLK_SIFIVE_PRCI) += fu540-prci.o
++obj-$(CONFIG_CLK_SIFIVE_PRCI) += fu740-prci.o
+diff --git a/drivers/clk/sifive/fu740-prci.c b/drivers/clk/sifive/fu740-prci.c
+new file mode 100644
+index 000000000000..3b87e273c3eb
+--- /dev/null
++++ b/drivers/clk/sifive/fu740-prci.c
+@@ -0,0 +1,122 @@
++// SPDX-License-Identifier: GPL-2.0
++/*
++ * Copyright (C) 2018-2019 SiFive, Inc.
++ * Wesley Terpstra
++ * Paul Walmsley
++ * Zong Li
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License version 2 as
++ * published by the Free Software Foundation.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
++ * GNU General Public License for more details.
++ */
++
++#include <dt-bindings/clock/sifive-fu740-prci.h>
++#include <linux/module.h>
++#include "sifive-prci.h"
++
++/* PRCI integration data for each WRPLL instance */
++
++static struct __prci_wrpll_data __prci_corepll_data = {
++ .cfg0_offs = PRCI_COREPLLCFG0_OFFSET,
++ .enable_bypass = sifive_prci_coreclksel_use_hfclk,
++ .disable_bypass = sifive_prci_coreclksel_use_final_corepll,
++};
++
++static struct __prci_wrpll_data __prci_ddrpll_data = {
++ .cfg0_offs = PRCI_DDRPLLCFG0_OFFSET,
++};
++
++static struct __prci_wrpll_data __prci_gemgxlpll_data = {
++ .cfg0_offs = PRCI_GEMGXLPLLCFG0_OFFSET,
++};
++
++static struct __prci_wrpll_data __prci_dvfscorepll_data = {
++ .cfg0_offs = PRCI_DVFSCOREPLLCFG0_OFFSET,
++ .enable_bypass = sifive_prci_corepllsel_use_corepll,
++ .disable_bypass = sifive_prci_corepllsel_use_dvfscorepll,
++};
++
++static struct __prci_wrpll_data __prci_hfpclkpll_data = {
++ .cfg0_offs = PRCI_HFPCLKPLLCFG0_OFFSET,
++ .enable_bypass = sifive_prci_hfpclkpllsel_use_hfclk,
++ .disable_bypass = sifive_prci_hfpclkpllsel_use_hfpclkpll,
++};
++
++static struct __prci_wrpll_data __prci_cltxpll_data = {
++ .cfg0_offs = PRCI_CLTXPLLCFG0_OFFSET,
++};
++
++/* Linux clock framework integration */
++
++static const struct clk_ops sifive_fu740_prci_wrpll_clk_ops = {
++ .set_rate = sifive_prci_wrpll_set_rate,
++ .round_rate = sifive_prci_wrpll_round_rate,
++ .recalc_rate = sifive_prci_wrpll_recalc_rate,
++};
++
++static const struct clk_ops sifive_fu740_prci_wrpll_ro_clk_ops = {
++ .recalc_rate = sifive_prci_wrpll_recalc_rate,
++};
++
++static const struct clk_ops sifive_fu740_prci_tlclksel_clk_ops = {
++ .recalc_rate = sifive_prci_tlclksel_recalc_rate,
++};
++
++static const struct clk_ops sifive_fu740_prci_hfpclkplldiv_clk_ops = {
++ .recalc_rate = sifive_prci_hfpclkplldiv_recalc_rate,
++};
++
++/* List of clock controls provided by the PRCI */
++struct __prci_clock __prci_init_clocks_fu740[] = {
++ [PRCI_CLK_COREPLL] = {
++ .name = "corepll",
++ .parent_name = "hfclk",
++ .ops = &sifive_fu740_prci_wrpll_clk_ops,
++ .pwd = &__prci_corepll_data,
++ },
++ [PRCI_CLK_DDRPLL] = {
++ .name = "ddrpll",
++ .parent_name = "hfclk",
++ .ops = &sifive_fu740_prci_wrpll_ro_clk_ops,
++ .pwd = &__prci_ddrpll_data,
++ },
++ [PRCI_CLK_GEMGXLPLL] = {
++ .name = "gemgxlpll",
++ .parent_name = "hfclk",
++ .ops = &sifive_fu740_prci_wrpll_clk_ops,
++ .pwd = &__prci_gemgxlpll_data,
++ },
++ [PRCI_CLK_DVFSCOREPLL] = {
++ .name = "dvfscorepll",
++ .parent_name = "hfclk",
++ .ops = &sifive_fu740_prci_wrpll_clk_ops,
++ .pwd = &__prci_dvfscorepll_data,
++ },
++ [PRCI_CLK_HFPCLKPLL] = {
++ .name = "hfpclkpll",
++ .parent_name = "hfclk",
++ .ops = &sifive_fu740_prci_wrpll_clk_ops,
++ .pwd = &__prci_hfpclkpll_data,
++ },
++ [PRCI_CLK_CLTXPLL] = {
++ .name = "cltxpll",
++ .parent_name = "hfclk",
++ .ops = &sifive_fu740_prci_wrpll_clk_ops,
++ .pwd = &__prci_cltxpll_data,
++ },
++ [PRCI_CLK_TLCLK] = {
++ .name = "tlclk",
++ .parent_name = "corepll",
++ .ops = &sifive_fu740_prci_tlclksel_clk_ops,
++ },
++ [PRCI_CLK_PCLK] = {
++ .name = "pclk",
++ .parent_name = "hfpclkpll",
++ .ops = &sifive_fu740_prci_hfpclkplldiv_clk_ops,
++ },
++};
+diff --git a/drivers/clk/sifive/fu740-prci.h b/drivers/clk/sifive/fu740-prci.h
+new file mode 100644
+index 000000000000..13ef971f7764
+--- /dev/null
++++ b/drivers/clk/sifive/fu740-prci.h
+@@ -0,0 +1,21 @@
++/* SPDX-License-Identifier: GPL-2.0 */
++/*
++ * Copyright (C) 2020 SiFive, Inc.
++ * Zong Li
++ */
++
++#ifndef __SIFIVE_CLK_FU740_PRCI_H
++#define __SIFIVE_CLK_FU740_PRCI_H
++
++#include "sifive-prci.h"
++
++#define NUM_CLOCK_FU740 8
++
++extern struct __prci_clock __prci_init_clocks_fu740[NUM_CLOCK_FU740];
++
++static const struct prci_clk_desc prci_clk_fu740 = {
++ .clks = __prci_init_clocks_fu740,
++ .num_clks = ARRAY_SIZE(__prci_init_clocks_fu740),
++};
++
++#endif /* __SIFIVE_CLK_FU740_PRCI_H */
+diff --git a/drivers/clk/sifive/sifive-prci.c b/drivers/clk/sifive/sifive-prci.c
+index 0ac729eeb71b..4098dbc5881a 100644
+--- a/drivers/clk/sifive/sifive-prci.c
++++ b/drivers/clk/sifive/sifive-prci.c
+@@ -27,6 +27,7 @@
+ #include <linux/of_device.h>
+ #include "sifive-prci.h"
+ #include "fu540-prci.h"
++#include "fu740-prci.h"
+
+ /*
+ * Private functions
+@@ -242,6 +243,18 @@ unsigned long sifive_prci_tlclksel_recalc_rate(struct clk_hw *hw,
+ return div_u64(parent_rate, div);
+ }
+
++/* HFPCLK clock integration */
++
++unsigned long sifive_prci_hfpclkplldiv_recalc_rate(struct clk_hw *hw,
++ unsigned long parent_rate)
++{
++ struct __prci_clock *pc = clk_hw_to_prci_clock(hw);
++ struct __prci_data *pd = pc->pd;
++ u32 div = __prci_readl(pd, PRCI_HFPCLKPLLDIV_OFFSET);
++
++ return div_u64(parent_rate, div + 2);
++}
++
+ /*
+ * Core clock mux control
+ */
+@@ -287,6 +300,112 @@ void sifive_prci_coreclksel_use_corepll(struct __prci_data *pd)
+ r = __prci_readl(pd, PRCI_CORECLKSEL_OFFSET); /* barrier */
+ }
+
++/**
++ * sifive_prci_coreclksel_use_final_corepll() - switch the CORECLK mux to output
++ * FINAL_COREPLL
++ * @pd: struct __prci_data * for the PRCI containing the CORECLK mux reg
++ *
++ * Switch the CORECLK mux to the final COREPLL output clock; return once
++ * complete.
++ *
++ * Context: Any context. Caller must prevent concurrent changes to the
++ * PRCI_CORECLKSEL_OFFSET register.
++ */
++void sifive_prci_coreclksel_use_final_corepll(struct __prci_data *pd)
++{
++ u32 r;
++
++ r = __prci_readl(pd, PRCI_CORECLKSEL_OFFSET);
++ r &= ~PRCI_CORECLKSEL_CORECLKSEL_MASK;
++ __prci_writel(r, PRCI_CORECLKSEL_OFFSET, pd);
++
++ r = __prci_readl(pd, PRCI_CORECLKSEL_OFFSET); /* barrier */
++}
++
++/**
++ * sifive_prci_corepllsel_use_dvfscorepll() - switch the COREPLL mux to
++ * output DVFS_COREPLL
++ * @pd: struct __prci_data * for the PRCI containing the COREPLL mux reg
++ *
++ * Switch the COREPLL mux to the DVFSCOREPLL output clock; return once complete.
++ *
++ * Context: Any context. Caller must prevent concurrent changes to the
++ * PRCI_COREPLLSEL_OFFSET register.
++ */
++void sifive_prci_corepllsel_use_dvfscorepll(struct __prci_data *pd)
++{
++ u32 r;
++
++ r = __prci_readl(pd, PRCI_COREPLLSEL_OFFSET);
++ r |= PRCI_COREPLLSEL_COREPLLSEL_MASK;
++ __prci_writel(r, PRCI_COREPLLSEL_OFFSET, pd);
++
++ r = __prci_readl(pd, PRCI_COREPLLSEL_OFFSET); /* barrier */
++}
++
++/**
++ * sifive_prci_corepllsel_use_corepll() - switch the COREPLL mux to
++ * output COREPLL
++ * @pd: struct __prci_data * for the PRCI containing the COREPLL mux reg
++ *
++ * Switch the COREPLL mux to the COREPLL output clock; return once complete.
++ *
++ * Context: Any context. Caller must prevent concurrent changes to the
++ * PRCI_COREPLLSEL_OFFSET register.
++ */
++void sifive_prci_corepllsel_use_corepll(struct __prci_data *pd)
++{
++ u32 r;
++
++ r = __prci_readl(pd, PRCI_COREPLLSEL_OFFSET);
++ r &= ~PRCI_COREPLLSEL_COREPLLSEL_MASK;
++ __prci_writel(r, PRCI_COREPLLSEL_OFFSET, pd);
++
++ r = __prci_readl(pd, PRCI_COREPLLSEL_OFFSET); /* barrier */
++}
++
++/**
++ * sifive_prci_hfpclkpllsel_use_hfclk() - switch the HFPCLKPLL mux to
++ * output HFCLK
++ * @pd: struct __prci_data * for the PRCI containing the HFPCLKPLL mux reg
++ *
++ * Switch the HFPCLKPLL mux to the HFCLK input source; return once complete.
++ *
++ * Context: Any context. Caller must prevent concurrent changes to the
++ * PRCI_HFPCLKPLLSEL_OFFSET register.
++ */
++void sifive_prci_hfpclkpllsel_use_hfclk(struct __prci_data *pd)
++{
++ u32 r;
++
++ r = __prci_readl(pd, PRCI_HFPCLKPLLSEL_OFFSET);
++ r |= PRCI_HFPCLKPLLSEL_HFPCLKPLLSEL_MASK;
++ __prci_writel(r, PRCI_HFPCLKPLLSEL_OFFSET, pd);
++
++ r = __prci_readl(pd, PRCI_HFPCLKPLLSEL_OFFSET); /* barrier */
++}
++
++/**
++ * sifive_prci_hfpclkpllsel_use_hfpclkpll() - switch the HFPCLKPLL mux to
++ * output HFPCLKPLL
++ * @pd: struct __prci_data * for the PRCI containing the HFPCLKPLL mux reg
++ *
++ * Switch the HFPCLKPLL mux to the HFPCLKPLL output clock; return once complete.
++ *
++ * Context: Any context. Caller must prevent concurrent changes to the
++ * PRCI_HFPCLKPLLSEL_OFFSET register.
++ */
++void sifive_prci_hfpclkpllsel_use_hfpclkpll(struct __prci_data *pd)
++{
++ u32 r;
++
++ r = __prci_readl(pd, PRCI_HFPCLKPLLSEL_OFFSET);
++ r &= ~PRCI_HFPCLKPLLSEL_HFPCLKPLLSEL_MASK;
++ __prci_writel(r, PRCI_HFPCLKPLLSEL_OFFSET, pd);
++
++ r = __prci_readl(pd, PRCI_HFPCLKPLLSEL_OFFSET); /* barrier */
++}
++
+ /**
+ * __prci_register_clocks() - register clock controls in the PRCI
+ * @dev: Linux struct device *
+@@ -391,6 +510,7 @@ static int sifive_prci_probe(struct platform_device *pdev)
+
+ static const struct of_device_id sifive_prci_of_match[] = {
+ {.compatible = "sifive,fu540-c000-prci", .data = &prci_clk_fu540},
++ {.compatible = "sifive,fu740-c000-prci", .data = &prci_clk_fu740},
+ {}
+ };
+
+diff --git a/drivers/clk/sifive/sifive-prci.h b/drivers/clk/sifive/sifive-prci.h
+index 025f717bc053..802fc8fb9c09 100644
+--- a/drivers/clk/sifive/sifive-prci.h
++++ b/drivers/clk/sifive/sifive-prci.h
+@@ -117,6 +117,87 @@
+ #define PRCI_CLKMUXSTATUSREG_TLCLKSEL_STATUS_MASK \
+ (0x1 << PRCI_CLKMUXSTATUSREG_TLCLKSEL_STATUS_SHIFT)
+
++/* CLTXPLLCFG0 */
++#define PRCI_CLTXPLLCFG0_OFFSET 0x30
++#define PRCI_CLTXPLLCFG0_DIVR_SHIFT 0
++#define PRCI_CLTXPLLCFG0_DIVR_MASK (0x3f << PRCI_CLTXPLLCFG0_DIVR_SHIFT)
++#define PRCI_CLTXPLLCFG0_DIVF_SHIFT 6
++#define PRCI_CLTXPLLCFG0_DIVF_MASK (0x1ff << PRCI_CLTXPLLCFG0_DIVF_SHIFT)
++#define PRCI_CLTXPLLCFG0_DIVQ_SHIFT 15
++#define PRCI_CLTXPLLCFG0_DIVQ_MASK (0x7 << PRCI_CLTXPLLCFG0_DIVQ_SHIFT)
++#define PRCI_CLTXPLLCFG0_RANGE_SHIFT 18
++#define PRCI_CLTXPLLCFG0_RANGE_MASK (0x7 << PRCI_CLTXPLLCFG0_RANGE_SHIFT)
++#define PRCI_CLTXPLLCFG0_BYPASS_SHIFT 24
++#define PRCI_CLTXPLLCFG0_BYPASS_MASK (0x1 << PRCI_CLTXPLLCFG0_BYPASS_SHIFT)
++#define PRCI_CLTXPLLCFG0_FSE_SHIFT 25
++#define PRCI_CLTXPLLCFG0_FSE_MASK (0x1 << PRCI_CLTXPLLCFG0_FSE_SHIFT)
++#define PRCI_CLTXPLLCFG0_LOCK_SHIFT 31
++#define PRCI_CLTXPLLCFG0_LOCK_MASK (0x1 << PRCI_CLTXPLLCFG0_LOCK_SHIFT)
++
++/* CLTXPLLCFG1 */
++#define PRCI_CLTXPLLCFG1_OFFSET 0x34
++#define PRCI_CLTXPLLCFG1_CKE_SHIFT 31
++#define PRCI_CLTXPLLCFG1_CKE_MASK (0x1 << PRCI_CLTXPLLCFG1_CKE_SHIFT)
++
++/* DVFSCOREPLLCFG0 */
++#define PRCI_DVFSCOREPLLCFG0_OFFSET 0x38
++
++/* DVFSCOREPLLCFG1 */
++#define PRCI_DVFSCOREPLLCFG1_OFFSET 0x3c
++#define PRCI_DVFSCOREPLLCFG1_CKE_SHIFT 31
++#define PRCI_DVFSCOREPLLCFG1_CKE_MASK (0x1 << PRCI_DVFSCOREPLLCFG1_CKE_SHIFT)
++
++/* COREPLLSEL */
++#define PRCI_COREPLLSEL_OFFSET 0x40
++#define PRCI_COREPLLSEL_COREPLLSEL_SHIFT 0
++#define PRCI_COREPLLSEL_COREPLLSEL_MASK \
++ (0x1 << PRCI_COREPLLSEL_COREPLLSEL_SHIFT)
++
++/* HFPCLKPLLCFG0 */
++#define PRCI_HFPCLKPLLCFG0_OFFSET 0x50
++#define PRCI_HFPCLKPLL_CFG0_DIVR_SHIFT 0
++#define PRCI_HFPCLKPLL_CFG0_DIVR_MASK \
++ (0x3f << PRCI_HFPCLKPLLCFG0_DIVR_SHIFT)
++#define PRCI_HFPCLKPLL_CFG0_DIVF_SHIFT 6
++#define PRCI_HFPCLKPLL_CFG0_DIVF_MASK \
++ (0x1ff << PRCI_HFPCLKPLLCFG0_DIVF_SHIFT)
++#define PRCI_HFPCLKPLL_CFG0_DIVQ_SHIFT 15
++#define PRCI_HFPCLKPLL_CFG0_DIVQ_MASK \
++ (0x7 << PRCI_HFPCLKPLLCFG0_DIVQ_SHIFT)
++#define PRCI_HFPCLKPLL_CFG0_RANGE_SHIFT 18
++#define PRCI_HFPCLKPLL_CFG0_RANGE_MASK \
++ (0x7 << PRCI_HFPCLKPLLCFG0_RANGE_SHIFT)
++#define PRCI_HFPCLKPLL_CFG0_BYPASS_SHIFT 24
++#define PRCI_HFPCLKPLL_CFG0_BYPASS_MASK \
++ (0x1 << PRCI_HFPCLKPLLCFG0_BYPASS_SHIFT)
++#define PRCI_HFPCLKPLL_CFG0_FSE_SHIFT 25
++#define PRCI_HFPCLKPLL_CFG0_FSE_MASK \
++ (0x1 << PRCI_HFPCLKPLLCFG0_FSE_SHIFT)
++#define PRCI_HFPCLKPLL_CFG0_LOCK_SHIFT 31
++#define PRCI_HFPCLKPLL_CFG0_LOCK_MASK \
++ (0x1 << PRCI_HFPCLKPLLCFG0_LOCK_SHIFT)
++
++/* HFPCLKPLLCFG1 */
++#define PRCI_HFPCLKPLLCFG1_OFFSET 0x54
++#define PRCI_HFPCLKPLLCFG1_CKE_SHIFT 31
++#define PRCI_HFPCLKPLLCFG1_CKE_MASK \
++ (0x1 << PRCI_HFPCLKPLLCFG1_CKE_SHIFT)
++
++/* HFPCLKPLLSEL */
++#define PRCI_HFPCLKPLLSEL_OFFSET 0x58
++#define PRCI_HFPCLKPLLSEL_HFPCLKPLLSEL_SHIFT 0
++#define PRCI_HFPCLKPLLSEL_HFPCLKPLLSEL_MASK \
++ (0x1 << PRCI_HFPCLKPLLSEL_HFPCLKPLLSEL_SHIFT)
++
++/* HFPCLKPLLDIV */
++#define PRCI_HFPCLKPLLDIV_OFFSET 0x5c
++
++/* PRCIPLL */
++#define PRCI_PRCIPLL_OFFSET 0xe0
++
++/* PROCMONCFG */
++#define PRCI_PROCMONCFG_OFFSET 0xf0
++
+ /*
+ * Private structures
+ */
+@@ -187,6 +268,11 @@ struct prci_clk_desc {
+ /* Core clock mux control */
+ void sifive_prci_coreclksel_use_hfclk(struct __prci_data *pd);
+ void sifive_prci_coreclksel_use_corepll(struct __prci_data *pd);
++void sifive_prci_coreclksel_use_final_corepll(struct __prci_data *pd);
++void sifive_prci_corepllsel_use_dvfscorepll(struct __prci_data *pd);
++void sifive_prci_corepllsel_use_corepll(struct __prci_data *pd);
++void sifive_prci_hfpclkpllsel_use_hfclk(struct __prci_data *pd);
++void sifive_prci_hfpclkpllsel_use_hfpclkpll(struct __prci_data *pd);
+
+ /* Linux clock framework integration */
+ long sifive_prci_wrpll_round_rate(struct clk_hw *hw, unsigned long rate,
+@@ -197,5 +283,7 @@ unsigned long sifive_prci_wrpll_recalc_rate(struct clk_hw *hw,
+ unsigned long parent_rate);
+ unsigned long sifive_prci_tlclksel_recalc_rate(struct clk_hw *hw,
+ unsigned long parent_rate);
++unsigned long sifive_prci_hfpclkplldiv_recalc_rate(struct clk_hw *hw,
++ unsigned long parent_rate);
+
+ #endif /* __SIFIVE_CLK_SIFIVE_PRCI_H */
+diff --git a/include/dt-bindings/clock/sifive-fu740-prci.h b/include/dt-bindings/clock/sifive-fu740-prci.h
+new file mode 100644
+index 000000000000..cd7706ea5677
+--- /dev/null
++++ b/include/dt-bindings/clock/sifive-fu740-prci.h
+@@ -0,0 +1,23 @@
++/* SPDX-License-Identifier: (GPL-2.0 OR MIT) */
++/*
++ * Copyright (C) 2019 SiFive, Inc.
++ * Wesley Terpstra
++ * Paul Walmsley
++ * Zong Li
++ */
++
++#ifndef __DT_BINDINGS_CLOCK_SIFIVE_FU740_PRCI_H
++#define __DT_BINDINGS_CLOCK_SIFIVE_FU740_PRCI_H
++
++/* Clock indexes for use by Device Tree data and the PRCI driver */
++
++#define PRCI_CLK_COREPLL 0
++#define PRCI_CLK_DDRPLL 1
++#define PRCI_CLK_GEMGXLPLL 2
++#define PRCI_CLK_DVFSCOREPLL 3
++#define PRCI_CLK_HFPCLKPLL 4
++#define PRCI_CLK_CLTXPLL 5
++#define PRCI_CLK_TLCLK 6
++#define PRCI_CLK_PCLK 7
++
++#endif /* __DT_BINDINGS_CLOCK_SIFIVE_FU740_PRCI_H */
+
+From patchwork Wed Nov 11 10:06:08 2020
+Content-Type: text/plain; charset="utf-8"
+MIME-Version: 1.0
+Content-Transfer-Encoding: 7bit
+X-Patchwork-Id: 11897345
+Return-Path:
+ <SRS0=XU8h=ER=lists.infradead.org=linux-riscv-bounces+patchwork-linux-riscv=patchwork.kernel.org@kernel.org>
+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 C81D7921
+ Wed, 11 Nov 2020 10:06:45 +0000 (UTC)
+Received: from merlin.infradead.org (merlin.infradead.org [205.233.59.134])
+ (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits))
+ (No client certificate requested)
+ by mail.kernel.org (Postfix) with ESMTPS id 5D73E20674
+ Wed, 11 Nov 2020 10:06:45 +0000 (UTC)
+Authentication-Results: mail.kernel.org;
+ dkim=pass (2048-bit key) header.d=lists.infradead.org
+ dkim=fail reason="signature verification failed" (2048-bit key)
+DMARC-Filter: OpenDMARC Filter v1.3.2 mail.kernel.org 5D73E20674
+Authentication-Results: mail.kernel.org;
+ dmarc=none (p=none dis=none) header.from=sifive.com
+Authentication-Results: mail.kernel.org;
+ spf=none
+ smtp.mailfrom=linux-riscv-bounces+patchwork-linux-riscv=patchwork.kernel.org@lists.infradead.org
+DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed;
+ d=lists.infradead.org; s=merlin.20170209; h=Sender:Content-Transfer-Encoding:
+ Content-Type:Cc:List-Subscribe:List-Help:List-Post:List-Archive:
+ List-Unsubscribe:List-Id:MIME-Version:References:In-Reply-To:Message-Id:Date:
+ Subject:To:From:Reply-To:Content-ID:Content-Description:Resent-Date:
+ Resent-From:Resent-Sender:Resent-To:Resent-Cc:Resent-Message-ID:List-Owner;
+ bh=Iews4m/vXSIqqkrhG9iaPa7cWeSAQe21FZQymVbjsek=; b=n3HMvSwOSedTdvwm4hsUJQn4J
+ LMx/juTx/k+vS98k9FAGRpif02amIkwVzJqzx0DwyzZyrIOWtAElnhs//2qkI6cypy145twFMcNJ1
+ VwSP2z+13zR6wJoaxL6GoyE7oKCDc5nuVJYgtF5p7Xnt7CfSm3mTufIrP22q6o1tvcL4rVICrXfcs
+ 4c5qmrRP0dJhLna/LyehaPS2NilAd3iHikmA4WEP3/4mXYrPqcy2LMIsfKCyIFIONgautnQBaCqiP
+ qE3M+PtaL5B+IkXATvHgq2ElUBGlrs+ApmEQg3HFJxBQ+BK7sLGRyKb1mbAjMSCcg4tfigDBJsqCj
+ Stj5xG5ZQ==;
+Received: from localhost ([::1] helo=merlin.infradead.org)
+ by merlin.infradead.org with esmtp (Exim 4.92.3 #3 (Red Hat Linux))
+ id 1kcn1J-0001O2-Vw; Wed, 11 Nov 2020 10:06:30 +0000
+Received: from mail-pl1-x641.google.com ([2607:f8b0:4864:20::641])
+ by merlin.infradead.org with esmtps (Exim 4.92.3 #3 (Red Hat Linux))
+ id 1kcn1G-0001M8-M3
+Received: by mail-pl1-x641.google.com with SMTP id t18so741935plo.0
+DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=sifive.com; s=google;
+ h=from:to:cc:subject:date:message-id:in-reply-to:references
+ :mime-version:content-transfer-encoding;
+ bh=ZNKLbQTe0EJyIiECa6jG2QS24SEV6zzCe3D1RGbycgk=;
+ b=PeekuDgz0P2oQrbgHf0FCJsHiFPz2BZ5Cv0EpubvZV33MfWN9TBmNIoMvevKzpAKwl
+ 7LJeN/GGuGZ1R8SpAyvdx9PV6YbcoggRDY0x4w9xPXzQGeKz4WnDAw06gmxneyOgmKhA
+ /lAFxcltub4Uf/tXXaz4ZpsXGpLrCoyGmwQFdiISsmB4SgURGnWWwnYgNloUH1NuXD4I
+ fVbamNCDjQnkK9gW1s3b1+yDDha0yEI92ND4/KzlrlG4VVgfF5U6OOfUgRj2uq9OGYl7
+ 8ZzoZiJQdd8CKeidNnJUbHDKXKybBKhey4LHDnjRvLwKZchOpPaIBJl5Llx+6ySZtwDi
+ Ww/g==
+X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed;
+ d=1e100.net; s=20161025;
+ h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to
+ :references:mime-version:content-transfer-encoding;
+ bh=ZNKLbQTe0EJyIiECa6jG2QS24SEV6zzCe3D1RGbycgk=;
+ b=SWpgmTh3mw2jAC1m2kFTI+MTPWGdATCrm7BeHr8h1itmKaar496vqFFosmLa8W2Zu2
+ 3bmEUpTRpqbU4csrwJ08+o6g6iRy05FrUbCY5OC8mbGdKFImjlzq2l5DHewQtc1u+dAk
+ g29Rbuq3HsOXZCahBqdf6RGGr5aG9Abqb7HPiLUKt3eObcwpyfFcQvuC2IuG058oFlS/
+ HiOUBFTlM+LpAXVTzSft+WUtuve9Ygg2eFcEM+KW76DIU0YPap437NMquK5i5Z3/+e91
+ NbDca+1mYv10N1y1lZkWfCQV684IsbDonNEbVWeaqua6Cz2NgJV91CSqh4lTrW/1I/fB
+ 4NHA==
+X-Gm-Message-State: AOAM531SY0ngV//lj1q8qfNb19tAN6GloaUG8Oe2G9K2D7ZgjhIgLIzj
+ CfyzHRvEm76GevoBY2v6m0YSRA==
+X-Google-Smtp-Source:
+ ABdhPJyXKkTB6t7sDQgeqfdIEFT0KtFRUawfjJ4kwO8HBmsgEDtvRVY0BcyIF6ftITFc/IHnSOKd3Q==
+X-Received: by 2002:a17:902:d3d4:b029:d7:e936:7651 with SMTP id
+ w20-20020a170902d3d4b02900d7e9367651mr10846937plb.57.1605089185026;
+ Wed, 11 Nov 2020 02:06:25 -0800 (PST)
+Received: from hsinchu02.internal.sifive.com
+ (114-34-229-221.HINET-IP.hinet.net. [114.34.229.221])
+ by smtp.gmail.com with ESMTPSA id u22sm1872801pgf.24.2020.11.11.02.06.22
+ (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256);
+ Wed, 11 Nov 2020 02:06:24 -0800 (PST)
+Subject: [PATCH v4 4/4] clk: sifive: Fix the wrong bit field shift
+Date: Wed, 11 Nov 2020 18:06:08 +0800
+X-Mailer: git-send-email 2.29.2
+MIME-Version: 1.0
+X-CRM114-Version: 20100106-BlameMichelson ( TRE 0.8.0 (BSD) ) MR-646709E3
+X-CRM114-CacheID: sfid-20201111_050626_820934_FD67C5E9
+X-CRM114-Status: GOOD ( 10.51 )
+X-Spam-Score: -0.2 (/)
+X-Spam-Report: SpamAssassin version 3.4.4 on merlin.infradead.org summary:
+ Content analysis details: (-0.2 points)
+ pts rule name description
+ ---- ----------------------
+ --------------------------------------------------
+ -0.0 RCVD_IN_DNSWL_NONE RBL: Sender listed at https://www.dnswl.org/,
+ no trust [2607:f8b0:4864:20:0:0:0:641 listed in]
+ [list.dnswl.org]
+ -0.0 SPF_PASS SPF: sender matches SPF record
+ 0.0 SPF_HELO_NONE SPF: HELO does not publish an SPF Record
+ 0.1 DKIM_SIGNED Message has a DKIM or DK signature,
+ not necessarily
+ valid
+ -0.1 DKIM_VALID Message has at least one valid DKIM or DK signature
+ -0.1 DKIM_VALID_AU Message has a valid DKIM or DK signature from
+ author's domain
+ -0.1 DKIM_VALID_EF Message has a valid DKIM or DK signature from
+ envelope-from domain
+X-Mailman-Version: 2.1.29
+Precedence: list
+List-Id: <linux-riscv.lists.infradead.org>
+List-Unsubscribe: <http://lists.infradead.org/mailman/options/linux-riscv>,
+List-Archive: <http://lists.infradead.org/pipermail/linux-riscv/>
+List-Subscribe: <http://lists.infradead.org/mailman/listinfo/linux-riscv>,
+Errors-To:
+ linux-riscv-bounces+patchwork-linux-riscv=patchwork.kernel.org@lists.infradead.org
+
+The clk enable bit should be 31 instead of 24.
+
+---
+ drivers/clk/sifive/sifive-prci.h | 4 ++--
+ 1 file changed, 2 insertions(+), 2 deletions(-)
+
+diff --git a/drivers/clk/sifive/sifive-prci.h b/drivers/clk/sifive/sifive-prci.h
+index 802fc8fb9c09..da7be9103d4d 100644
+--- a/drivers/clk/sifive/sifive-prci.h
++++ b/drivers/clk/sifive/sifive-prci.h
+@@ -59,7 +59,7 @@
+
+ /* DDRPLLCFG1 */
+ #define PRCI_DDRPLLCFG1_OFFSET 0x10
+-#define PRCI_DDRPLLCFG1_CKE_SHIFT 24
++#define PRCI_DDRPLLCFG1_CKE_SHIFT 31
+ #define PRCI_DDRPLLCFG1_CKE_MASK (0x1 << PRCI_DDRPLLCFG1_CKE_SHIFT)
+
+ /* GEMGXLPLLCFG0 */
+@@ -81,7 +81,7 @@
+
+ /* GEMGXLPLLCFG1 */
+ #define PRCI_GEMGXLPLLCFG1_OFFSET 0x20
+-#define RCI_GEMGXLPLLCFG1_CKE_SHIFT 24
++#define RCI_GEMGXLPLLCFG1_CKE_SHIFT 31
+ #define PRCI_GEMGXLPLLCFG1_CKE_MASK (0x1 << PRCI_GEMGXLPLLCFG1_CKE_SHIFT)
+
+ /* CORECLKSEL */
--- /dev/null
+From patchwork Mon Oct 26 23:02:49 2020
+Content-Type: text/plain; charset="utf-8"
+MIME-Version: 1.0
+Content-Transfer-Encoding: 7bit
+X-Patchwork-Id: 11858967
+Return-Path:
+ <SRS0=2xBv=EB=lists.infradead.org=linux-riscv-bounces+patchwork-linux-riscv=patchwork.kernel.org@kernel.org>
+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 4BD05697
+ Mon, 26 Oct 2020 23:03:54 +0000 (UTC)
+Received: from merlin.infradead.org (merlin.infradead.org [205.233.59.134])
+ (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits))
+ (No client certificate requested)
+ by mail.kernel.org (Postfix) with ESMTPS id 1C98220708
+ Mon, 26 Oct 2020 23:03:54 +0000 (UTC)
+Authentication-Results: mail.kernel.org;
+ dkim=pass (2048-bit key) header.d=lists.infradead.org
+ dkim=fail reason="signature verification failed" (2048-bit key)
+DMARC-Filter: OpenDMARC Filter v1.3.2 mail.kernel.org 1C98220708
+Authentication-Results: mail.kernel.org;
+ dmarc=fail (p=none dis=none) header.from=wdc.com
+Authentication-Results: mail.kernel.org;
+ spf=none
+ smtp.mailfrom=linux-riscv-bounces+patchwork-linux-riscv=patchwork.kernel.org@lists.infradead.org
+DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed;
+ d=lists.infradead.org; s=merlin.20170209; h=Sender:Content-Transfer-Encoding:
+ Content-Type:Cc:List-Subscribe:List-Help:List-Post:List-Archive:
+ List-Unsubscribe:List-Id:MIME-Version:References:In-Reply-To:Message-Id:Date:
+ Subject:To:From:Reply-To:Content-ID:Content-Description:Resent-Date:
+ Resent-From:Resent-Sender:Resent-To:Resent-Cc:Resent-Message-ID:List-Owner;
+ bh=wX4g/n6Z4vxFkVtoaai8oo26/fP6F8kk0A+XsmapyyU=; b=td8C3JZ+t42jYE9JYqpuhrzG4
+ mf/Cyo+A34YAryyjJ0WDmJm+tlQtkguSCgdrAi0i9m5xvsxFET+HAp02yWKh4dNV1x1FSRYvzS4/h
+ eLBjlmfQ3qmmCW7AOqwHU0JtVkosQDjljJPFBvpo9PPSGHRXUAwC8L1Jdk9jTxselPR8xSnRWZiJz
+ PM2YlEJvLc7D1eMDhuD3w16L86NeGguAdgOVRf9zRyy1pdWtr6zLzXIcpObNv1LnfQ557Idrq83EV
+ dRnIUFsIvavBFOWvmCvPeoscvnVkj1crBbLS7OrJUVO3/OU0WFY9zDvp3RcFq+dTxdqVptvB17q95
+ LjIWwpkyA==;
+Received: from localhost ([::1] helo=merlin.infradead.org)
+ by merlin.infradead.org with esmtp (Exim 4.92.3 #3 (Red Hat Linux))
+ id 1kXBWV-0004Hv-KO; Mon, 26 Oct 2020 23:03:31 +0000
+Received: from esa6.hgst.iphmx.com ([216.71.154.45])
+ by merlin.infradead.org with esmtps (Exim 4.92.3 #3 (Red Hat Linux))
+ id 1kXBWS-0004FU-Ay
+DKIM-Signature: v=1; a=rsa-sha256; c=simple/simple;
+ t=1603753408; x=1635289408;
+ h=from:to:cc:subject:date:message-id:in-reply-to:
+ references:mime-version:content-transfer-encoding;
+ bh=Qmlk0Pnoc73PLeMzxCGZ41KUAZ0XJ8ZZaWUmbVJfPT0=;
+ b=nGr05oxDAK6SRe7L7o1giKU1GJuN/1wDt6UpyPcYMwzGiDbNCVn3Jas8
+ C7rWDC0lAKjCVjADONzoQTYpDq5AUGTNYO+dhqbDNJBsApSIv8jvsg1ZL
+ RU3/nobD5FMZ2k3NJwx1BEde/T9oy5Gfq5OThiRZwe6cSGSoKCH+WXQda
+ 2kPPEDzScTwjpc2hMdq7+reRiFHvtVgaBg7FM4IXejGhxVN0SwEsVG6z2
+ o3SSsreUZvNH8XtK83CNdDidTNESY/VNJHnP7lt23/8LIe6fgXwhVjC+g
+ A6+Cml40M8I34uazxz9OngDliKt61AZr1YuXRQsOAfQ+GpvwabO8ZjIWp A==;
+IronPort-SDR:
+ JybhKPbwUi/q9fGONsYOeF/38aYwXWBa5uJtb/Y1EvUxqi+u/0Y2wm/lhLJgB4UR2aiwBOv4vW
+ l3ApnDplRsZZx+azT1MoIzF+XCBslSC+ay04xht2qVX7bx3MSjjOIEnmE86rzQFSgx+GoEkQRs
+ RttASlhJq4ZZ8RsyaRJRI0uxRXOmxkoajSiY5dMfebzmp7PTLBY84j8c1WzH28wekiXAwbmUB1
+ H6hF2AahkCfeVbWPNAIjPwy/qWb3Fe52LbS3baXCDuiY0fjR3gAtZFfc4CTknO2ITlDcxRbIbq
+ QtI=
+X-IronPort-AV: E=Sophos;i="5.77,421,1596470400"; d="scan'208";a="152152906"
+Received: from h199-255-45-15.hgst.com (HELO uls-op-cesaep02.wdc.com)
+ ([199.255.45.15])
+ by ob1.hgst.iphmx.com with ESMTP; 27 Oct 2020 07:03:23 +0800
+IronPort-SDR:
+ Tpcus0rX16e4qgtbXcdZdBeFOG1T6Zg8N83jXFLUk3LPYmFifOthq2plK4SHViNbDmZQ6i1Lh8
+ LUQCBq6AtyWkG4vl1cO1s/n8422erEiTSRrgtK60jzcY35aOrbaNASElmyzB+XB0rYFn7/C45Z
+ qyoJhhP2uu+D+bCiyp8yea7M+ZZg15R1jhtXx0s7WGu26muiQfQAHWRe29m/cxwIsTbloNQkx9
+ 5jgejPdPMcAg6jW+VZNpy83oy9KALuxI6bnHbH+1nTUXijsxw1AyV1pZGy1wh23Gg+xqL7/VuT
+ ZZ9sOmrtOa+0MTbHhXA4fcfz
+Received: from uls-op-cesaip02.wdc.com ([10.248.3.37])
+ by uls-op-cesaep02.wdc.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384;
+ 26 Oct 2020 15:48:34 -0700
+IronPort-SDR:
+ w0qKrqk4Ps76VXo2fhQqnJ3FzMjkvDA5n76UhstySma3ZkkQkkND11NhJZJe1RlXHu/OQkarV/
+ 5eJJS29Zjj//2bfffUYVZXW2/yuSD0isOWFHbB8RAWw1+v7/ODIlLVksfre4BHHKG/C4su00sv
+ EAC/XmNixR8peOtynxZ0tW4ZofnRxUZ5ok6zjykyuVEQPSkyAFY4IZSWqNz+XVT+JZAK6I8bpi
+ YWP1fNPizwdXJD1KYcY1PiwAqN04YYwkFs6RUTz+WYH+vwTMz3OLF7cwaI9wldwepnoJKem0cx
+ 6Ho=
+WDCIronportException: Internal
+Received: from 8223p12.ad.shared (HELO jedi-01.hgst.com) ([10.86.60.110])
+ by uls-op-cesaip02.wdc.com with ESMTP; 26 Oct 2020 16:03:24 -0700
+Subject: [PATCH v2 1/6] RISC-V: Move __start_kernel to .head.text
+Date: Mon, 26 Oct 2020 16:02:49 -0700
+X-Mailer: git-send-email 2.25.1
+MIME-Version: 1.0
+X-CRM114-Version: 20100106-BlameMichelson ( TRE 0.8.0 (BSD) ) MR-646709E3
+X-CRM114-CacheID: sfid-20201026_190328_503890_B35AEB06
+X-CRM114-Status: GOOD ( 13.15 )
+X-Spam-Score: -2.5 (--)
+X-Spam-Report: SpamAssassin version 3.4.4 on merlin.infradead.org summary:
+ Content analysis details: (-2.5 points)
+ pts rule name description
+ ---- ----------------------
+ --------------------------------------------------
+ -2.3 RCVD_IN_DNSWL_MED RBL: Sender listed at https://www.dnswl.org/,
+ medium trust [216.71.154.45 listed in list.dnswl.org]
+ -0.0 SPF_PASS SPF: sender matches SPF record
+ -0.0 SPF_HELO_PASS SPF: HELO matches SPF record
+ -0.1 DKIM_VALID_EF Message has a valid DKIM or DK signature from
+ envelope-from domain
+ 0.1 DKIM_SIGNED Message has a DKIM or DK signature,
+ not necessarily
+ valid
+ -0.1 DKIM_VALID Message has at least one valid DKIM or DK signature
+ -0.1 DKIM_VALID_AU Message has a valid DKIM or DK signature from
+ author's domain
+X-Mailman-Version: 2.1.29
+Precedence: list
+List-Id: <linux-riscv.lists.infradead.org>
+List-Unsubscribe: <http://lists.infradead.org/mailman/options/linux-riscv>,
+List-Archive: <http://lists.infradead.org/pipermail/linux-riscv/>
+List-Subscribe: <http://lists.infradead.org/mailman/listinfo/linux-riscv>,
+Errors-To:
+ linux-riscv-bounces+patchwork-linux-riscv=patchwork.kernel.org@lists.infradead.org
+
+Currently, __start_kernel is kept in _init while _start is in head section.
+This may result in "relocation truncated to fit error" if _init section is
+moved far from head. It also makes sense to keep entire head.S in one
+section.
+
+Keep __start_kernel in head section rather than _init.
+
+---
+ arch/riscv/kernel/head.S | 1 -
+ 1 file changed, 1 deletion(-)
+
+diff --git a/arch/riscv/kernel/head.S b/arch/riscv/kernel/head.S
+index 11e2a4fe66e0..45dbdae930bf 100644
+--- a/arch/riscv/kernel/head.S
++++ b/arch/riscv/kernel/head.S
+@@ -177,7 +177,6 @@ setup_trap_vector:
+
+ END(_start)
+
+- __INIT
+ ENTRY(_start_kernel)
+ /* Mask all interrupts */
+ csrw CSR_IE, zero
+
+From patchwork Mon Oct 26 23:02:50 2020
+Content-Type: text/plain; charset="utf-8"
+MIME-Version: 1.0
+Content-Transfer-Encoding: 7bit
+X-Patchwork-Id: 11858963
+Return-Path:
+ <SRS0=2xBv=EB=lists.infradead.org=linux-riscv-bounces+patchwork-linux-riscv=patchwork.kernel.org@kernel.org>
+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 4E41514C0
+ Mon, 26 Oct 2020 23:03:51 +0000 (UTC)
+Received: from merlin.infradead.org (merlin.infradead.org [205.233.59.134])
+ (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits))
+ (No client certificate requested)
+ by mail.kernel.org (Postfix) with ESMTPS id 12B3620780
+ Mon, 26 Oct 2020 23:03:50 +0000 (UTC)
+Authentication-Results: mail.kernel.org;
+ dkim=pass (2048-bit key) header.d=lists.infradead.org
+ dkim=fail reason="signature verification failed" (2048-bit key)
+DMARC-Filter: OpenDMARC Filter v1.3.2 mail.kernel.org 12B3620780
+Authentication-Results: mail.kernel.org;
+ dmarc=fail (p=none dis=none) header.from=wdc.com
+Authentication-Results: mail.kernel.org;
+ spf=none
+ smtp.mailfrom=linux-riscv-bounces+patchwork-linux-riscv=patchwork.kernel.org@lists.infradead.org
+DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed;
+ d=lists.infradead.org; s=merlin.20170209; h=Sender:Content-Transfer-Encoding:
+ Content-Type:Cc:List-Subscribe:List-Help:List-Post:List-Archive:
+ List-Unsubscribe:List-Id:MIME-Version:References:In-Reply-To:Message-Id:Date:
+ Subject:To:From:Reply-To:Content-ID:Content-Description:Resent-Date:
+ Resent-From:Resent-Sender:Resent-To:Resent-Cc:Resent-Message-ID:List-Owner;
+ bh=jItsVKgw3M8EfidQQEWfLINsB65ulKh31mJBLTzxhDI=; b=R2N4oQv042pLH7TrdlwNl7i50
+ JjJy5OvLFC7t//03XjlRdVlWhM7FNziOhNkUx4TR4LRsdhYbQzg1uMxn7yAmZXSXldhIR6W2JsZTO
+ jEOLLZl8TALQpLU/nc9Hx27O2pnp9vVLtXNjp0bi1hXSf09zSdDG99wlmmlgTwsxi58Z8opCAtLlc
+ b5eYKGc/KQEhrPrF8/K3XPpKjb/ubPyDnL4Pe2wxp1arN3ruor691TL7rSFM9u9RbJUiSaE0C4H52
+ +5ywoRk22VlNHevpvSo7+Ciak7INBHIQGNvR6n69NNMsPvEHvhzlw/63bQ/dm8p6jMNjN6vCogORd
+ SDruDBTMw==;
+Received: from localhost ([::1] helo=merlin.infradead.org)
+ by merlin.infradead.org with esmtp (Exim 4.92.3 #3 (Red Hat Linux))
+ id 1kXBWX-0004Ij-0J; Mon, 26 Oct 2020 23:03:33 +0000
+Received: from esa6.hgst.iphmx.com ([216.71.154.45])
+ by merlin.infradead.org with esmtps (Exim 4.92.3 #3 (Red Hat Linux))
+ id 1kXBWS-0004G3-NQ
+DKIM-Signature: v=1; a=rsa-sha256; c=simple/simple;
+ t=1603753408; x=1635289408;
+ h=from:to:cc:subject:date:message-id:in-reply-to:
+ references:mime-version:content-transfer-encoding;
+ bh=AVRSSDssQdWbrcRKwBjC+hUtmkwJEL8J+eqHnYnc5QE=;
+ b=JXSoMBF4ncwPVXLxewMSTeYsKp0BzDGS31RbupMBJvpJXzJAd/M1iJmL
+ TBSJVfuyzHcCdd1Il/SovevTs8tWGJHiD5H6/jgM9WngeEiBJfRRrAJEi
+ zz2z/CTcvEF8uUNS/NeXxi9zHprzolNuwagt8HIJQ4im6++Z+V4MYBBFa
+ rIwOLsRyNRuPQd+uavq+ecYDaII6BW0AQgMPlbBFs20+h4l9ug/5r8lvq
+ vkaGEWWmHJy+Y7uFf/H59nyE+YyVgl5VWIXxeq+lTsBLThebrhcfNR5rF
+ mX+GKYLwKesukjd5kivkf/O4bChtj+Zk5mjygV0JXnu8/qKTgdKGgFb2c g==;
+IronPort-SDR:
+ 4YNJctnRQh5CAun/n5enQjM7oquvPrOE3nkGFW+C5QqyuTdTfMuPC9ObswJdNtZwfXOZSP5M47
+ iBPtDJ5kPm5b5SYNOuUKAQ4oE8q8nZ2FxIJT8P6gv9OeHvvG5/KH6gbbwAscyn4o7xOmg7CKr0
+ jtoKxdwABk51IwBt/KNR8GAxr+yFheq2GxCKokyowKQ7NR10DGS87oI72liz3W2KnjsAvP2g2P
+ zQWDZ1IVj6vcGosiDETTFL931i534FP9dlQ6Qj75JQ8WbRCsmrMJkEqLHGdpQpPCOjvKI/c+F5
+ vTk=
+X-IronPort-AV: E=Sophos;i="5.77,421,1596470400"; d="scan'208";a="152152907"
+Received: from h199-255-45-15.hgst.com (HELO uls-op-cesaep02.wdc.com)
+ ([199.255.45.15])
+ by ob1.hgst.iphmx.com with ESMTP; 27 Oct 2020 07:03:24 +0800
+IronPort-SDR:
+ rJJ/C8JZke0ThawF2PuVIjlUTsSDKbnB73s5tnzsxw/p0QX5zEUP6q14uvBl6dU4RoaituDCkX
+ n8z2GJl3XoFXVFB9aMQAACJSppt4l3VQkYp+g4VAc9icZSGARojUqMHmfIZ2GUtB9AoDv5tyj0
+ q2xQFgoW//H8fhLERqeSoNYn04PByFAqa6rpWjZc2LLmNIyjNFqnHY5Pt/73yZyqdvLYuwrNUC
+ olBFQjlaaXPsankbmZBSYN4NJX37cZjcNTKQ2CpkOEMM+CinKrHXsShQEx6J5FIysSY33/fvhQ
+ ypYbSqAvYJ5rr0SpmaSNGvdH
+Received: from uls-op-cesaip02.wdc.com ([10.248.3.37])
+ by uls-op-cesaep02.wdc.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384;
+ 26 Oct 2020 15:48:35 -0700
+IronPort-SDR:
+ 3Ij9aVJeppLgiNBWU3i6/X2lSE43Hhk1vz4ATQcxpjVCxcKhKrhmo10TYjsLHqnNpODk0WtNen
+ Jk3krrwCqPcL89Wud7ibOl0NwE8tiPXGwsV+VOBu7+XKdtCGk/wxHi26nHu4oq3DgH1BoSgD/M
+ yerK255lPug90GLaMc/tBilGkgTn2lyb38VH4Cd9zyBbfIniEjmkrpqFWHyXEDr+ZTPAFpzKMm
+ x+t6xCJh33r7HlknIojBzHJXHJZ+dw0Lj9+d9N04W6lg2IfrWFFKMUVNhjjU6p4QVZ/yqZzPjo
+ I/U=
+WDCIronportException: Internal
+Received: from 8223p12.ad.shared (HELO jedi-01.hgst.com) ([10.86.60.110])
+ by uls-op-cesaip02.wdc.com with ESMTP; 26 Oct 2020 16:03:24 -0700
+Subject: [PATCH v2 2/6] RISC-V: Initialize SBI early
+Date: Mon, 26 Oct 2020 16:02:50 -0700
+X-Mailer: git-send-email 2.25.1
+MIME-Version: 1.0
+X-CRM114-Version: 20100106-BlameMichelson ( TRE 0.8.0 (BSD) ) MR-646709E3
+X-CRM114-CacheID: sfid-20201026_190328_882682_FE50A426
+X-CRM114-Status: GOOD ( 12.31 )
+X-Spam-Score: -2.5 (--)
+X-Spam-Report: SpamAssassin version 3.4.4 on merlin.infradead.org summary:
+ Content analysis details: (-2.5 points)
+ pts rule name description
+ ---- ----------------------
+ --------------------------------------------------
+ -2.3 RCVD_IN_DNSWL_MED RBL: Sender listed at https://www.dnswl.org/,
+ medium trust [216.71.154.45 listed in list.dnswl.org]
+ -0.0 SPF_PASS SPF: sender matches SPF record
+ -0.0 SPF_HELO_PASS SPF: HELO matches SPF record
+ -0.1 DKIM_VALID_EF Message has a valid DKIM or DK signature from
+ envelope-from domain
+ 0.1 DKIM_SIGNED Message has a DKIM or DK signature,
+ not necessarily
+ valid
+ -0.1 DKIM_VALID Message has at least one valid DKIM or DK signature
+ -0.1 DKIM_VALID_AU Message has a valid DKIM or DK signature from
+ author's domain
+X-Mailman-Version: 2.1.29
+Precedence: list
+List-Id: <linux-riscv.lists.infradead.org>
+List-Unsubscribe: <http://lists.infradead.org/mailman/options/linux-riscv>,
+List-Archive: <http://lists.infradead.org/pipermail/linux-riscv/>
+List-Subscribe: <http://lists.infradead.org/mailman/listinfo/linux-riscv>,
+Errors-To:
+ linux-riscv-bounces+patchwork-linux-riscv=patchwork.kernel.org@lists.infradead.org
+
+Currently, SBI is initialized towards the end of arch setup. This prevents
+the set memory operations to be invoked earlier as it requires a full tlb
+flush.
+
+Initialize SBI as early as possible.
+
+---
+ arch/riscv/kernel/setup.c | 7 +++----
+ 1 file changed, 3 insertions(+), 4 deletions(-)
+
+diff --git a/arch/riscv/kernel/setup.c b/arch/riscv/kernel/setup.c
+index c424cc6dd833..7d6a04ae3929 100644
+--- a/arch/riscv/kernel/setup.c
++++ b/arch/riscv/kernel/setup.c
+@@ -89,6 +89,9 @@ void __init setup_arch(char **cmdline_p)
+ pr_err("No DTB found in kernel mappings\n");
+ #endif
+
++#if IS_ENABLED(CONFIG_RISCV_SBI)
++ sbi_init();
++#endif
+ #ifdef CONFIG_SWIOTLB
+ swiotlb_init(1);
+ #endif
+@@ -97,10 +100,6 @@ void __init setup_arch(char **cmdline_p)
+ kasan_init();
+ #endif
+
+-#if IS_ENABLED(CONFIG_RISCV_SBI)
+- sbi_init();
+-#endif
+-
+ #ifdef CONFIG_SMP
+ setup_smp();
+ #endif
+
+From patchwork Mon Oct 26 23:02:51 2020
+Content-Type: text/plain; charset="utf-8"
+MIME-Version: 1.0
+Content-Transfer-Encoding: 7bit
+X-Patchwork-Id: 11858961
+Return-Path:
+ <SRS0=2xBv=EB=lists.infradead.org=linux-riscv-bounces+patchwork-linux-riscv=patchwork.kernel.org@kernel.org>
+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 E03AC697
+ Mon, 26 Oct 2020 23:03:50 +0000 (UTC)
+Received: from merlin.infradead.org (merlin.infradead.org [205.233.59.134])
+ (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits))
+ (No client certificate requested)
+ by mail.kernel.org (Postfix) with ESMTPS id 9E26520780
+ Mon, 26 Oct 2020 23:03:50 +0000 (UTC)
+Authentication-Results: mail.kernel.org;
+ dkim=pass (2048-bit key) header.d=lists.infradead.org
+ dkim=fail reason="signature verification failed" (2048-bit key)
+DMARC-Filter: OpenDMARC Filter v1.3.2 mail.kernel.org 9E26520780
+Authentication-Results: mail.kernel.org;
+ dmarc=fail (p=none dis=none) header.from=wdc.com
+Authentication-Results: mail.kernel.org;
+ spf=none
+ smtp.mailfrom=linux-riscv-bounces+patchwork-linux-riscv=patchwork.kernel.org@lists.infradead.org
+DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed;
+ d=lists.infradead.org; s=merlin.20170209; h=Sender:Content-Transfer-Encoding:
+ Content-Type:Cc:List-Subscribe:List-Help:List-Post:List-Archive:
+ List-Unsubscribe:List-Id:MIME-Version:References:In-Reply-To:Message-Id:Date:
+ Subject:To:From:Reply-To:Content-ID:Content-Description:Resent-Date:
+ Resent-From:Resent-Sender:Resent-To:Resent-Cc:Resent-Message-ID:List-Owner;
+ bh=LLvjP6UUF+mN2NFHQ/w8mCLk894u/K6BT448BmhIzQ4=; b=xYC8KiamK0TAM3BY6T9hRqDcY
+ wB95sKdyXf2pP404bJ28keqaeUu59O9F12gNLiMlaDSXue16RKAyMMcv91I0NOptDVGZZsOEC5q5e
+ zF2nqG23tJt41TlS7tm/muslXV3klrPXdtdWyMWbNMn5yzKEUozzBfqDJ8/l4J5RI09A3eI3N2iHd
+ rKoweCxhcX3fgQwwHpcmS+lWa+zvBMr4TDQJpKG3IbWMJiMuc1HwIBfoIVJNE/S0CaH4aFslFFYWV
+ dNwCUzN/Y2iQdsb0gxaLHWXD8duKjsagaZj0Pubwqjvz8RjdfdzyRVOA9z7oOSvRWik1T2Q/doFJo
+ SsgbTSlNg==;
+Received: from localhost ([::1] helo=merlin.infradead.org)
+ by merlin.infradead.org with esmtp (Exim 4.92.3 #3 (Red Hat Linux))
+ id 1kXBWY-0004J6-7l; Mon, 26 Oct 2020 23:03:34 +0000
+Received: from esa6.hgst.iphmx.com ([216.71.154.45])
+ by merlin.infradead.org with esmtps (Exim 4.92.3 #3 (Red Hat Linux))
+ id 1kXBWT-0004FU-At
+DKIM-Signature: v=1; a=rsa-sha256; c=simple/simple;
+ t=1603753409; x=1635289409;
+ h=from:to:cc:subject:date:message-id:in-reply-to:
+ references:mime-version:content-transfer-encoding;
+ bh=rpPh1ri27/mV4Lq6GihXSvX59Cmyy4U53NNqLUWVVFg=;
+ b=IGlvH/HeG+LtRaV9YRN/VJ92x3cba2Xbt5IlgvhW6e+2kqLjoheazKa4
+ sW1k4tE7X3IClbO8GZrCFtEWXWaw9Z10Up+X6W49lJYIho/4KKBhLxPr2
+ +SCivaneKgpreYsC5Y8azdPya3U/n+E6tRaDB0Ng+h9KlEA4yLVQqFKuW
+ 5EV34s13VQxzRapuie7tGx1zyifO+6Q5LDaThml/ORK27gZ6YyBj0KtL6
+ GHRilGu/kY2wjPWoyrDcf4iHq4r9f1cDqC8idZ7XZfadax/iMkDzWSvxc
+ h3S4iEtcZS0Q5No2RWoGmOeTp52XEQEbzIpu4vPsmBPYFAqNY7Yvtel/0 w==;
+IronPort-SDR:
+ upmBvvWfa2b8MmYHtzqu/BqkOl1YAZk4qwb3OWmRVkBz8Q8KNLXxZyJtY64PG/zF08rvh/1ZYP
+ eovKyM4rqIXsWEQeZSixcDrHE288ygjSxu/f+cXPkVfHxCPMN9tpkTqQgBIfsHe8Y0BHaCOc8/
+ H1knVJMdHIOeCfezAL5il2HBu/Vym8HSP4WMEa6m622CDWZS5oefiHvEmWwI65GZcaPoKObN4B
+ GJY7amcMkWsk0AGmo7dnQY0jxcqcEaGcsiKs8/iV8DsGM6MhpQ3Cgu/fZbCNR/A83dQTFTtHi9
+ w90=
+X-IronPort-AV: E=Sophos;i="5.77,421,1596470400"; d="scan'208";a="152152909"
+Received: from h199-255-45-15.hgst.com (HELO uls-op-cesaep02.wdc.com)
+ ([199.255.45.15])
+ by ob1.hgst.iphmx.com with ESMTP; 27 Oct 2020 07:03:24 +0800
+IronPort-SDR:
+ LUcWKsGyxMhMy14zInqMDnSWvfLodcW3JZm43fD96zVbcHRGq/jkMyPQqmKawb3/LQH2EKNkH6
+ 68itcHUR8Xwwv5Vo/ao/+1tgsmQFo+r8v44sW7uMNA0ifzfNDS5w5hhrR4yQGlaxdrzwim8RBe
+ bIu9SGubi5/WfG5pmuBdctXpWGyr3ahj7O4Z/z3AzIvgp9VndisL9xZGGOrv1Pc82IALWjlrDX
+ wSvQpsoUO/jqBe5rRTNxSiGlVEu2VVYYkXXfaRrnHfol12PqMWCBve/MdFLrLdrbM2gHsPxczG
+ cRcC19KGip4DdpqeSITONqGB
+Received: from uls-op-cesaip02.wdc.com ([10.248.3.37])
+ by uls-op-cesaep02.wdc.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384;
+ 26 Oct 2020 15:48:35 -0700
+IronPort-SDR:
+ rriut/QXTurmMnXEV+/wkdh18jeVeIaUuF5OpX2DpiAjha4uQ2m8xvQ2+CYVPztIlri/dGG9Fx
+ sn4DjUGAMl9xld4i92d4WY0ChJTrDHbpMX+/nWTBiwVYjSvhmt8dWvvRfITcAe8aHbsJflfw31
+ X7bMdmMoJiKhs3WflXZAL19ePomMnN9ectpJbqja3ffpDKFD6UTBM+ZaybUNAdN7ZoQ4QlFV6l
+ 1tP01QkDPJPYD5O1x+9fKaT5edDaRfBK6oaYcjCM8Jv0VUQ424prp5C290AGcHQRTt2fhXTuUe
+ LPU=
+WDCIronportException: Internal
+Received: from 8223p12.ad.shared (HELO jedi-01.hgst.com) ([10.86.60.110])
+ by uls-op-cesaip02.wdc.com with ESMTP; 26 Oct 2020 16:03:25 -0700
+Subject: [PATCH v2 3/6] RISC-V: Enforce protections for kernel sections early
+Date: Mon, 26 Oct 2020 16:02:51 -0700
+X-Mailer: git-send-email 2.25.1
+MIME-Version: 1.0
+X-CRM114-Version: 20100106-BlameMichelson ( TRE 0.8.0 (BSD) ) MR-646709E3
+X-CRM114-CacheID: sfid-20201026_190329_555710_AE8BAB41
+X-CRM114-Status: GOOD ( 16.68 )
+X-Spam-Score: -2.5 (--)
+X-Spam-Report: SpamAssassin version 3.4.4 on merlin.infradead.org summary:
+ Content analysis details: (-2.5 points)
+ pts rule name description
+ ---- ----------------------
+ --------------------------------------------------
+ -2.3 RCVD_IN_DNSWL_MED RBL: Sender listed at https://www.dnswl.org/,
+ medium trust [216.71.154.45 listed in list.dnswl.org]
+ -0.0 SPF_PASS SPF: sender matches SPF record
+ -0.0 SPF_HELO_PASS SPF: HELO matches SPF record
+ -0.1 DKIM_VALID_EF Message has a valid DKIM or DK signature from
+ envelope-from domain
+ 0.1 DKIM_SIGNED Message has a DKIM or DK signature,
+ not necessarily
+ valid
+ -0.1 DKIM_VALID Message has at least one valid DKIM or DK signature
+ -0.1 DKIM_VALID_AU Message has a valid DKIM or DK signature from
+ author's domain
+X-Mailman-Version: 2.1.29
+Precedence: list
+List-Id: <linux-riscv.lists.infradead.org>
+List-Unsubscribe: <http://lists.infradead.org/mailman/options/linux-riscv>,
+List-Archive: <http://lists.infradead.org/pipermail/linux-riscv/>
+List-Subscribe: <http://lists.infradead.org/mailman/listinfo/linux-riscv>,
+Errors-To:
+ linux-riscv-bounces+patchwork-linux-riscv=patchwork.kernel.org@lists.infradead.org
+
+Currently, all memblocks are mapped with PAGE_KERNEL_EXEC and the strict
+permissions are only enforced after /init starts. This leaves the kernel
+vulnerable from possible buggy built-in modules.
+
+Apply permissions to individual sections as early as possible.
+
+---
+ arch/riscv/include/asm/set_memory.h | 2 ++
+ arch/riscv/kernel/setup.c | 2 ++
+ arch/riscv/mm/init.c | 11 +++++++++--
+ 3 files changed, 13 insertions(+), 2 deletions(-)
+
+diff --git a/arch/riscv/include/asm/set_memory.h b/arch/riscv/include/asm/set_memory.h
+index 4c5bae7ca01c..4cc3a4e2afd3 100644
+--- a/arch/riscv/include/asm/set_memory.h
++++ b/arch/riscv/include/asm/set_memory.h
+@@ -15,11 +15,13 @@ int set_memory_ro(unsigned long addr, int numpages);
+ int set_memory_rw(unsigned long addr, int numpages);
+ int set_memory_x(unsigned long addr, int numpages);
+ int set_memory_nx(unsigned long addr, int numpages);
++void protect_kernel_text_data(void);
+ #else
+ static inline int set_memory_ro(unsigned long addr, int numpages) { return 0; }
+ static inline int set_memory_rw(unsigned long addr, int numpages) { return 0; }
+ static inline int set_memory_x(unsigned long addr, int numpages) { return 0; }
+ static inline int set_memory_nx(unsigned long addr, int numpages) { return 0; }
++static inline void protect_kernel_text_data(void) {};
+ #endif
+
+ int set_direct_map_invalid_noflush(struct page *page);
+diff --git a/arch/riscv/kernel/setup.c b/arch/riscv/kernel/setup.c
+index 7d6a04ae3929..b722c5bf892c 100644
+--- a/arch/riscv/kernel/setup.c
++++ b/arch/riscv/kernel/setup.c
+@@ -22,6 +22,7 @@
+ #include <asm/cpu_ops.h>
+ #include <asm/early_ioremap.h>
+ #include <asm/setup.h>
++#include <asm/set_memory.h>
+ #include <asm/sections.h>
+ #include <asm/sbi.h>
+ #include <asm/tlbflush.h>
+@@ -92,6 +93,7 @@ void __init setup_arch(char **cmdline_p)
+ #if IS_ENABLED(CONFIG_RISCV_SBI)
+ sbi_init();
+ #endif
++ protect_kernel_text_data();
+ #ifdef CONFIG_SWIOTLB
+ swiotlb_init(1);
+ #endif
+diff --git a/arch/riscv/mm/init.c b/arch/riscv/mm/init.c
+index ea933b789a88..5f196f8158d4 100644
+--- a/arch/riscv/mm/init.c
++++ b/arch/riscv/mm/init.c
+@@ -608,7 +608,7 @@ static inline void setup_vm_final(void)
+ #endif /* CONFIG_MMU */
+
+ #ifdef CONFIG_STRICT_KERNEL_RWX
+-void mark_rodata_ro(void)
++void protect_kernel_text_data(void)
+ {
+ unsigned long text_start = (unsigned long)_text;
+ unsigned long text_end = (unsigned long)_etext;
+@@ -617,9 +617,16 @@ void mark_rodata_ro(void)
+ unsigned long max_low = (unsigned long)(__va(PFN_PHYS(max_low_pfn)));
+
+ set_memory_ro(text_start, (text_end - text_start) >> PAGE_SHIFT);
+- set_memory_ro(rodata_start, (data_start - rodata_start) >> PAGE_SHIFT);
+ set_memory_nx(rodata_start, (data_start - rodata_start) >> PAGE_SHIFT);
+ set_memory_nx(data_start, (max_low - data_start) >> PAGE_SHIFT);
++}
++
++void mark_rodata_ro(void)
++{
++ unsigned long rodata_start = (unsigned long)__start_rodata;
++ unsigned long data_start = (unsigned long)_data;
++
++ set_memory_ro(rodata_start, (data_start - rodata_start) >> PAGE_SHIFT);
+
+ debug_checkwx();
+ }
+
+From patchwork Mon Oct 26 23:02:52 2020
+Content-Type: text/plain; charset="utf-8"
+MIME-Version: 1.0
+Content-Transfer-Encoding: 7bit
+X-Patchwork-Id: 11858957
+Return-Path:
+ <SRS0=2xBv=EB=lists.infradead.org=linux-riscv-bounces+patchwork-linux-riscv=patchwork.kernel.org@kernel.org>
+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 02FB2697
+ Mon, 26 Oct 2020 23:03:38 +0000 (UTC)
+Received: from merlin.infradead.org (merlin.infradead.org [205.233.59.134])
+ (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits))
+ (No client certificate requested)
+ by mail.kernel.org (Postfix) with ESMTPS id A5CAE20708
+ Mon, 26 Oct 2020 23:03:37 +0000 (UTC)
+Authentication-Results: mail.kernel.org;
+ dkim=pass (2048-bit key) header.d=lists.infradead.org
+ dkim=fail reason="signature verification failed" (2048-bit key)
+DMARC-Filter: OpenDMARC Filter v1.3.2 mail.kernel.org A5CAE20708
+Authentication-Results: mail.kernel.org;
+ dmarc=fail (p=none dis=none) header.from=wdc.com
+Authentication-Results: mail.kernel.org;
+ spf=none
+ smtp.mailfrom=linux-riscv-bounces+patchwork-linux-riscv=patchwork.kernel.org@lists.infradead.org
+DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed;
+ d=lists.infradead.org; s=merlin.20170209; h=Sender:Content-Transfer-Encoding:
+ Content-Type:Cc:List-Subscribe:List-Help:List-Post:List-Archive:
+ List-Unsubscribe:List-Id:MIME-Version:References:In-Reply-To:Message-Id:Date:
+ Subject:To:From:Reply-To:Content-ID:Content-Description:Resent-Date:
+ Resent-From:Resent-Sender:Resent-To:Resent-Cc:Resent-Message-ID:List-Owner;
+ bh=K4aClDeRkTGSHM6Q3W9Eo4LL84FjDanPKTlxKTMYT2Y=; b=X0mvMGeVLhaZowgqwRF0Oy00W
+ Ro3DTyI28iAxiYsgQk7tOKFm6yRviAAo61fD4CxEw0kAPfJGvb2M95clzrlSGqoJejHLAMO33adTG
+ WzEJi2IwBvyKp0jyWLDkXQVeXiXA3fXO2Fdf40zfHtdT7iaNSu7soNx9r0g9RwD0XtCEe0iWXYDCy
+ VYekhBN4Fw2wC4eplt45X+fkkuE3+0tF41fE6RupWyY7GQUxknVYOAdyLwNWiBCZAHnTUQfmeiFwO
+ uJGDjjkmP20pBxhl9RJJaYWtr+NA0KJF8Lz94t4taxRSf6lJ+VMb32ZlXsCufd4x+h9vJjOLs35ef
+ rTVgylhTg==;
+Received: from localhost ([::1] helo=merlin.infradead.org)
+ by merlin.infradead.org with esmtp (Exim 4.92.3 #3 (Red Hat Linux))
+ id 1kXBWZ-0004Jf-BW; Mon, 26 Oct 2020 23:03:35 +0000
+Received: from esa6.hgst.iphmx.com ([216.71.154.45])
+ by merlin.infradead.org with esmtps (Exim 4.92.3 #3 (Red Hat Linux))
+ id 1kXBWT-0004G3-Pa
+DKIM-Signature: v=1; a=rsa-sha256; c=simple/simple;
+ t=1603753409; x=1635289409;
+ h=from:to:cc:subject:date:message-id:in-reply-to:
+ references:mime-version:content-transfer-encoding;
+ bh=BXRrXHASEZw+q5AEH6JXn4IG5K15cGG21TkLjxF25TY=;
+ b=URJjjHRLy8KmQfGlwj/WBLzTx4gHsfdUY8YsCSHPkMnU6I/nuYRNK6Ga
+ bFb3AWymzww5MFphpcpliqhWOgO7o5ggmA/PU54Lw0bMOPZCA+rynjwXo
+ 3S+KsjpSiGmSEq4q8fjZfKa2ErdI+J5zImh2i5Z1BSB+TnBH9I45lN6AP
+ EaBFxk2EkIUlP/6LoKRzLmneYZf5HJVBOKW7pRcr48ZJbX1nj95w972SA
+ FMJjzWioIkGlR3K+L4I9r0w+HJgzqTJHIS+DZnLF3LQWEoRJaPGrzgi1+
+ 80pshfjh4GMd0a9tcSQj/wSS17P3kJQ49XhDYEw61qpuk61DCWKl4XwXz A==;
+IronPort-SDR:
+ QJtG6KvnHciweTON41ovUFASCfAMlNSE35baDpF5gZo80LXmQZYFWDxGQuqCn75wzVDRu9qTha
+ OVLwC/ghV4iZnQszcl4+JLFqr+xcefARIea4vQbe+lD+SBXej8h1etv6Sn/BGlDI4z218G7Ies
+ gd0hxcq0cfi9vgrb1zOrwHQ3BNrmw1FOuOApx6fEUAqtSs9ucezKvJJyeyy4ZszU3ckY0J9G4I
+ rZTBTHkd6wGgYuvcq+3IiRVQtXPfxkXXzpIkQfnrpQpkW9rJ6S8VzSZ3Su4XpXi4pT/fHmnS9y
+ bsg=
+X-IronPort-AV: E=Sophos;i="5.77,421,1596470400"; d="scan'208";a="152152912"
+Received: from h199-255-45-15.hgst.com (HELO uls-op-cesaep02.wdc.com)
+ ([199.255.45.15])
+ by ob1.hgst.iphmx.com with ESMTP; 27 Oct 2020 07:03:25 +0800
+IronPort-SDR:
+ oz9iIUPO41YXmSe5lIg1FWt9CkcMbjZjMOQWhQN3Eu+YCvga4haAmUvFUzr/dCRkEcGOibXBfo
+ eM/I7m5DAnRSaeBbbs1FXY8Pmgw/I4NoLQ7/N5vBqPpbV6i20QzmfCUhUoleEfOnhjpM7M5NKq
+ GcrT+a43FwhHMDO3722Gh76G8hGmXJ/TQpNUrJLD6d6F2rao3fIRtOs4X6DwAsP3T4TKHwjDaT
+ 8s8oMKCFFJGKKBsgvzcRbxR8SYhbYY+IoKN5H3LmowqOqe/EqvmOOs8j862dIJx/SQsGrd5KNW
+ OJ+6YOzCjCoSwS47k5WebISH
+Received: from uls-op-cesaip02.wdc.com ([10.248.3.37])
+ by uls-op-cesaep02.wdc.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384;
+ 26 Oct 2020 15:48:36 -0700
+IronPort-SDR:
+ nc5o0tmxjzldhTvYndCLRMxDkR7DVB0Qk9xsu3nOE77OHiF++vF7uzB8dkN6FOL63EaQPgW6vg
+ 32Ps9rMRe6NjHIcHRp5jbx3Fek2i+PHg9bgM/sHhvhKm4Md89MmIf3oyZeyDszhniw1Vs1X25M
+ OlI0GIJkCqeeclxiq3vzCN9bZC15BwvNL5vcbuD1e7UMTO2rDsIYlNsUJfTOQ3loffL7C1jBXK
+ u9QjFn66K/qD/FBZsbsXUkxk7teb0SZUKmIJ96W9LgSUVq77xPrfBzq/ABINxmwTYilVzPaYOF
+ RYQ=
+WDCIronportException: Internal
+Received: from 8223p12.ad.shared (HELO jedi-01.hgst.com) ([10.86.60.110])
+ by uls-op-cesaip02.wdc.com with ESMTP; 26 Oct 2020 16:03:25 -0700
+Subject: [PATCH v2 4/6] RISC-V: Align the .init.text section
+Date: Mon, 26 Oct 2020 16:02:52 -0700
+X-Mailer: git-send-email 2.25.1
+MIME-Version: 1.0
+X-CRM114-Version: 20100106-BlameMichelson ( TRE 0.8.0 (BSD) ) MR-646709E3
+X-CRM114-CacheID: sfid-20201026_190330_004554_38C54A71
+X-CRM114-Status: GOOD ( 14.66 )
+X-Spam-Score: -2.5 (--)
+X-Spam-Report: SpamAssassin version 3.4.4 on merlin.infradead.org summary:
+ Content analysis details: (-2.5 points)
+ pts rule name description
+ ---- ----------------------
+ --------------------------------------------------
+ -2.3 RCVD_IN_DNSWL_MED RBL: Sender listed at https://www.dnswl.org/,
+ medium trust [216.71.154.45 listed in list.dnswl.org]
+ -0.0 SPF_PASS SPF: sender matches SPF record
+ -0.0 SPF_HELO_PASS SPF: HELO matches SPF record
+ -0.1 DKIM_VALID_EF Message has a valid DKIM or DK signature from
+ envelope-from domain
+ 0.1 DKIM_SIGNED Message has a DKIM or DK signature,
+ not necessarily
+ valid
+ -0.1 DKIM_VALID Message has at least one valid DKIM or DK signature
+ -0.1 DKIM_VALID_AU Message has a valid DKIM or DK signature from
+ author's domain
+X-Mailman-Version: 2.1.29
+Precedence: list
+List-Id: <linux-riscv.lists.infradead.org>
+List-Unsubscribe: <http://lists.infradead.org/mailman/options/linux-riscv>,
+List-Archive: <http://lists.infradead.org/pipermail/linux-riscv/>
+List-Subscribe: <http://lists.infradead.org/mailman/listinfo/linux-riscv>,
+Errors-To:
+ linux-riscv-bounces+patchwork-linux-riscv=patchwork.kernel.org@lists.infradead.org
+
+In order to improve kernel text protection, we need separate .init.text/
+.init.data/.text in separate sections. However, RISC-V linker relaxation
+code is not aware of any alignment between sections. As a result, it may
+relax any RISCV_CALL relocations between sections to JAL without realizing
+that an inter section alignment may move the address farther. That may
+lead to a relocation truncated fit error. However, linker relaxation code
+is aware of the individual section alignments.
+
+The detailed discussion on this issue can be found here.
+https://github.com/riscv/riscv-gnu-toolchain/issues/738
+
+Keep the .init.text section aligned so that linker relaxation will take
+that as a hint while relaxing inter section calls.
+Here are the code size changes for each section because of this change.
+
+section change in size (in bytes)
+ .head.text +4
+ .text +40
+ .init.text +6530
+ .exit.text +84
+
+The only significant increase in size happened for .init.text because
+all intra relocations also use 2MB alignment.
+
+---
+ arch/riscv/kernel/vmlinux.lds.S | 8 +++++++-
+ 1 file changed, 7 insertions(+), 1 deletion(-)
+
+diff --git a/arch/riscv/kernel/vmlinux.lds.S b/arch/riscv/kernel/vmlinux.lds.S
+index 3ffbd6cbdb86..cacd7898ba7f 100644
+--- a/arch/riscv/kernel/vmlinux.lds.S
++++ b/arch/riscv/kernel/vmlinux.lds.S
+@@ -30,7 +30,13 @@ SECTIONS
+ . = ALIGN(PAGE_SIZE);
+
+ __init_begin = .;
+- INIT_TEXT_SECTION(PAGE_SIZE)
++ __init_text_begin = .;
++ .init.text : AT(ADDR(.init.text) - LOAD_OFFSET) ALIGN(SECTION_ALIGN) { \
++ _sinittext = .; \
++ INIT_TEXT \
++ _einittext = .; \
++ }
++
+ . = ALIGN(8);
+ __soc_early_init_table : {
+ __soc_early_init_table_start = .;
+
+From patchwork Mon Oct 26 23:02:53 2020
+Content-Type: text/plain; charset="utf-8"
+MIME-Version: 1.0
+Content-Transfer-Encoding: 7bit
+X-Patchwork-Id: 11858965
+Return-Path:
+ <SRS0=2xBv=EB=lists.infradead.org=linux-riscv-bounces+patchwork-linux-riscv=patchwork.kernel.org@kernel.org>
+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 CEAA592C
+ Mon, 26 Oct 2020 23:03:51 +0000 (UTC)
+Received: from merlin.infradead.org (merlin.infradead.org [205.233.59.134])
+ (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits))
+ (No client certificate requested)
+ by mail.kernel.org (Postfix) with ESMTPS id 984E420708
+ Mon, 26 Oct 2020 23:03:51 +0000 (UTC)
+Authentication-Results: mail.kernel.org;
+ dkim=pass (2048-bit key) header.d=lists.infradead.org
+ dkim=fail reason="signature verification failed" (2048-bit key)
+DMARC-Filter: OpenDMARC Filter v1.3.2 mail.kernel.org 984E420708
+Authentication-Results: mail.kernel.org;
+ dmarc=fail (p=none dis=none) header.from=wdc.com
+Authentication-Results: mail.kernel.org;
+ spf=none
+ smtp.mailfrom=linux-riscv-bounces+patchwork-linux-riscv=patchwork.kernel.org@lists.infradead.org
+DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed;
+ d=lists.infradead.org; s=merlin.20170209; h=Sender:Content-Transfer-Encoding:
+ Content-Type:Cc:List-Subscribe:List-Help:List-Post:List-Archive:
+ List-Unsubscribe:List-Id:MIME-Version:References:In-Reply-To:Message-Id:Date:
+ Subject:To:From:Reply-To:Content-ID:Content-Description:Resent-Date:
+ Resent-From:Resent-Sender:Resent-To:Resent-Cc:Resent-Message-ID:List-Owner;
+ bh=oywE//1iXDBCyZMx/g2q51Gaz+jyhPQi+ZXU++cKzDw=; b=tormdiD4MrtCitBw7gI19k1yX
+ QoRXXSgmXFbYBSCnc/8iMMZfO9Pqq19sern8kdCtQfMSKoBHmyHpdRBDtf5HX8gbZAlyfrHivX0wm
+ zkpY7xzgZ0OHlaoFladcnJPJSojoMl+0gUeqV0bIlmBRFngaGP3j0Owje1pHFagZTsqi7g5+r3gd7
+ ISEhANtyxlX301o1K28/yYIdBq652NzL0QSBGqhs1vNVJ0OrPhxuBQNRXLbh/l6q144HKBmBLfklM
+ LOHVxqzca6fYMg7AA4XMaO8Pr3ov3xDYHtqmtjCKxEsovZf2SC8BX2f1MoGNWIVVI8nitiQVuE4Vv
+ pVqjtr42Q==;
+Received: from localhost ([::1] helo=merlin.infradead.org)
+ by merlin.infradead.org with esmtp (Exim 4.92.3 #3 (Red Hat Linux))
+ id 1kXBWa-0004KB-4Y; Mon, 26 Oct 2020 23:03:36 +0000
+Received: from esa6.hgst.iphmx.com ([216.71.154.45])
+ by merlin.infradead.org with esmtps (Exim 4.92.3 #3 (Red Hat Linux))
+ id 1kXBWU-0004H6-Er
+DKIM-Signature: v=1; a=rsa-sha256; c=simple/simple;
+ t=1603753410; x=1635289410;
+ h=from:to:cc:subject:date:message-id:in-reply-to:
+ references:mime-version:content-transfer-encoding;
+ bh=iPUv/PUCUw9poafNmoCWlV7tTLouxKtDuq6y3HZQDjc=;
+ b=TINKrKy1j7UvdoiLMTeHUQ/tMBzQuLtdTEH/fWFrgO6GS+tfZcEZ8JHu
+ Cl2FOprdMaFJ02crvI0iY3uM/H++1sZNJlYKC81UfIWEROxDKgp0pdDI4
+ I6QBWtOpDcvdfYolhms30rt3tqELl2JP1csmhLb78lJbIgcwbZkAu0D0M
+ 0hblQSEchmVhvcSFc3cket/LBv6gEqdvViw+5WKkCsT5sKuBEmjZ5N8Mo
+ 6BaHAosKbWj4CtithfGsVHfyhVkX0czQFMHbgAWBkfUNdLyj+svAGcBaF
+ /L1NRhojdJC+/A7+0TRv7wF65E3xRBRVb1jPZdwTp024gNcjRa6N//K/Z Q==;
+IronPort-SDR:
+ CsILWxdqzjyqU2FwYLjPK+jZdSUoiFWfCLCK+zomYaBEEBdHYGDeaNr7VvK9zze/GpA6btdait
+ F1JdnNzUJfawMwtwWVtbM80tYohxjLjTkce7af85Ed+TPHgSzENYmGcC6ODWnQ8/RUXMWmX19Z
+ sHcoBfNu6L8r42mWepVbU0Iwl9uNPRG3jHzlJ8w8gSj+DWbjwfR8WWgSnONL6BjmJA88gqBS1q
+ M/Bwcdr2OMD5ks7Gp2TfMj/7ykp/9agc8yDoViH+z7+v/8XjJohC59tKu6NIkStZgO3jdA79cN
+ fMM=
+X-IronPort-AV: E=Sophos;i="5.77,421,1596470400"; d="scan'208";a="152152914"
+Received: from h199-255-45-15.hgst.com (HELO uls-op-cesaep02.wdc.com)
+ ([199.255.45.15])
+ by ob1.hgst.iphmx.com with ESMTP; 27 Oct 2020 07:03:25 +0800
+IronPort-SDR:
+ 3u2+d01NfPNLyJepvSU9gqztIqwBrsJhqYka2NFJ9fpUx5JTnhNRJABKy6ymocr+VACsvFbW0b
+ 6IrLWS8PlkhTEoMNENQpQZY/Dg3kkiMoplXxpCudshL4S7UCtXcY4cloLua+RDS0oHtpSFbVzU
+ Y+X7uqSvXZrCUQOkIV5UCjT224FgPTw2OAhCeEAyTTPpgudiMZjzE9YrQNgG4A+BLF2tUVsuBR
+ BImVlogyHkN9O4t2kyVGoYGTNHNi5bqZhvUwAY1RNzRvcA+vQD0w7T2SoaguxxMPOwTACcF/d3
+ Z+sMS87NekBWHXBRqTecgl0W
+Received: from uls-op-cesaip02.wdc.com ([10.248.3.37])
+ by uls-op-cesaep02.wdc.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384;
+ 26 Oct 2020 15:48:36 -0700
+IronPort-SDR:
+ ey/+IpD7q+PZFkntsCEL5kRkGMghTUQ92D4aSwCY0hicm+MUionuNfl6dBlx3Gh91OzXB6oKuq
+ FIrt8TuWoscWKGL5FZGzu4oj0jqXFxfqAjrHGnQLM0h4LD3Er1WjUcaV2wAoJI00VcLs3/mXyS
+ /Prep/fH4qGRAmABa+qjbQbvBrGkfszca5mZUfa2SOTn3Nb0sYaGlEKe6wEY2Vo3ZSHVRn7fll
+ 21NHZZZaa3XJN3YV/d0MMiVrPYSdIbcOhg7XGcbFSgMmsM0NEy7Y5E1i8priVbwPj6Z7qmOgj+
+ tBg=
+WDCIronportException: Internal
+Received: from 8223p12.ad.shared (HELO jedi-01.hgst.com) ([10.86.60.110])
+ by uls-op-cesaip02.wdc.com with ESMTP; 26 Oct 2020 16:03:26 -0700
+Subject: [PATCH v2 5/6] RISC-V: Protect .init.text & .init.data
+Date: Mon, 26 Oct 2020 16:02:53 -0700
+X-Mailer: git-send-email 2.25.1
+MIME-Version: 1.0
+X-CRM114-Version: 20100106-BlameMichelson ( TRE 0.8.0 (BSD) ) MR-646709E3
+X-CRM114-CacheID: sfid-20201026_190330_837440_84C45BC2
+X-CRM114-Status: GOOD ( 19.16 )
+X-Spam-Score: -2.5 (--)
+X-Spam-Report: SpamAssassin version 3.4.4 on merlin.infradead.org summary:
+ Content analysis details: (-2.5 points)
+ pts rule name description
+ ---- ----------------------
+ --------------------------------------------------
+ -2.3 RCVD_IN_DNSWL_MED RBL: Sender listed at https://www.dnswl.org/,
+ medium trust [216.71.154.45 listed in list.dnswl.org]
+ -0.0 SPF_PASS SPF: sender matches SPF record
+ -0.0 SPF_HELO_PASS SPF: HELO matches SPF record
+ -0.1 DKIM_VALID_EF Message has a valid DKIM or DK signature from
+ envelope-from domain
+ 0.1 DKIM_SIGNED Message has a DKIM or DK signature,
+ not necessarily
+ valid
+ -0.1 DKIM_VALID Message has at least one valid DKIM or DK signature
+ -0.1 DKIM_VALID_AU Message has a valid DKIM or DK signature from
+ author's domain
+X-Mailman-Version: 2.1.29
+Precedence: list
+List-Id: <linux-riscv.lists.infradead.org>
+List-Unsubscribe: <http://lists.infradead.org/mailman/options/linux-riscv>,
+List-Archive: <http://lists.infradead.org/pipermail/linux-riscv/>
+List-Subscribe: <http://lists.infradead.org/mailman/listinfo/linux-riscv>,
+Errors-To:
+ linux-riscv-bounces+patchwork-linux-riscv=patchwork.kernel.org@lists.infradead.org
+
+Currently, .init.text & .init.data are intermixed which makes it impossible
+apply different permissions to them. .init.data shouldn't need exec
+permissions while .init.text shouldn't have write permission.
+
+Keep them in separate sections so that different permissions are applied to
+each section. This improves the kernel protection under
+CONFIG_STRICT_KERNEL_RWX. We also need to restore the permissions for the
+entire _init section after it is freed so that those pages can be used for
+other purpose.
+
+---
+ arch/riscv/include/asm/sections.h | 2 ++
+ arch/riscv/include/asm/set_memory.h | 2 ++
+ arch/riscv/kernel/setup.c | 9 +++++
+ arch/riscv/kernel/vmlinux.lds.S | 51 ++++++++++++++++-------------
+ arch/riscv/mm/init.c | 8 ++++-
+ arch/riscv/mm/pageattr.c | 6 ++++
+ 6 files changed, 54 insertions(+), 24 deletions(-)
+
+diff --git a/arch/riscv/include/asm/sections.h b/arch/riscv/include/asm/sections.h
+index 3a9971b1210f..1595c5b60cfd 100644
+--- a/arch/riscv/include/asm/sections.h
++++ b/arch/riscv/include/asm/sections.h
+@@ -9,5 +9,7 @@
+
+ extern char _start[];
+ extern char _start_kernel[];
++extern char __init_data_begin[], __init_data_end[];
++extern char __init_text_begin[], __init_text_end[];
+
+ #endif /* __ASM_SECTIONS_H */
+diff --git a/arch/riscv/include/asm/set_memory.h b/arch/riscv/include/asm/set_memory.h
+index 4cc3a4e2afd3..913429c9c1ae 100644
+--- a/arch/riscv/include/asm/set_memory.h
++++ b/arch/riscv/include/asm/set_memory.h
+@@ -15,6 +15,7 @@ int set_memory_ro(unsigned long addr, int numpages);
+ int set_memory_rw(unsigned long addr, int numpages);
+ int set_memory_x(unsigned long addr, int numpages);
+ int set_memory_nx(unsigned long addr, int numpages);
++int set_memory_default(unsigned long addr, int numpages);
+ void protect_kernel_text_data(void);
+ #else
+ static inline int set_memory_ro(unsigned long addr, int numpages) { return 0; }
+@@ -22,6 +23,7 @@ static inline int set_memory_rw(unsigned long addr, int numpages) { return 0; }
+ static inline int set_memory_x(unsigned long addr, int numpages) { return 0; }
+ static inline int set_memory_nx(unsigned long addr, int numpages) { return 0; }
+ static inline void protect_kernel_text_data(void) {};
++static inline int set_memory_default(unsigned long addr, int numpages) { return 0; }
+ #endif
+
+ int set_direct_map_invalid_noflush(struct page *page);
+diff --git a/arch/riscv/kernel/setup.c b/arch/riscv/kernel/setup.c
+index b722c5bf892c..abfbdc8cfef3 100644
+--- a/arch/riscv/kernel/setup.c
++++ b/arch/riscv/kernel/setup.c
+@@ -123,3 +123,12 @@ static int __init topology_init(void)
+ return 0;
+ }
+ subsys_initcall(topology_init);
++
++void free_initmem(void)
++{
++ unsigned long init_begin = (unsigned long)__init_begin;
++ unsigned long init_end = (unsigned long)__init_end;
++
++ set_memory_default(init_begin, (init_end - init_begin) >> PAGE_SHIFT);
++ free_initmem_default(POISON_FREE_INITMEM);
++}
+diff --git a/arch/riscv/kernel/vmlinux.lds.S b/arch/riscv/kernel/vmlinux.lds.S
+index cacd7898ba7f..0a1874e48e8a 100644
+--- a/arch/riscv/kernel/vmlinux.lds.S
++++ b/arch/riscv/kernel/vmlinux.lds.S
+@@ -29,6 +29,26 @@ SECTIONS
+ HEAD_TEXT_SECTION
+ . = ALIGN(PAGE_SIZE);
+
++ .text : {
++ _text = .;
++ _stext = .;
++ TEXT_TEXT
++ SCHED_TEXT
++ CPUIDLE_TEXT
++ LOCK_TEXT
++ KPROBES_TEXT
++ ENTRY_TEXT
++ IRQENTRY_TEXT
++ SOFTIRQENTRY_TEXT
++ *(.fixup)
++ _etext = .;
++ }
++
++#ifdef CONFIG_EFI
++ . = ALIGN(PECOFF_SECTION_ALIGNMENT);
++ __pecoff_text_end = .;
++#endif
++ . = ALIGN(SECTION_ALIGN);
+ __init_begin = .;
+ __init_text_begin = .;
+ .init.text : AT(ADDR(.init.text) - LOAD_OFFSET) ALIGN(SECTION_ALIGN) { \
+@@ -53,35 +73,20 @@ SECTIONS
+ {
+ EXIT_TEXT
+ }
++
++ __init_text_end = .;
++ . = ALIGN(SECTION_ALIGN);
++ /* Start of init data section */
++ __init_data_begin = .;
++ INIT_DATA_SECTION(16)
+ .exit.data :
+ {
+ EXIT_DATA
+ }
+ PERCPU_SECTION(L1_CACHE_BYTES)
+- __init_end = .;
+
+- . = ALIGN(SECTION_ALIGN);
+- .text : {
+- _text = .;
+- _stext = .;
+- TEXT_TEXT
+- SCHED_TEXT
+- CPUIDLE_TEXT
+- LOCK_TEXT
+- KPROBES_TEXT
+- ENTRY_TEXT
+- IRQENTRY_TEXT
+- SOFTIRQENTRY_TEXT
+- *(.fixup)
+- _etext = .;
+- }
+-
+-#ifdef CONFIG_EFI
+- . = ALIGN(PECOFF_SECTION_ALIGNMENT);
+- __pecoff_text_end = .;
+-#endif
+-
+- INIT_DATA_SECTION(16)
++ __init_data_end = .;
++ __init_end = .;
+
+ /* Start of data section */
+ _sdata = .;
+diff --git a/arch/riscv/mm/init.c b/arch/riscv/mm/init.c
+index 5f196f8158d4..1bb3821d81d5 100644
+--- a/arch/riscv/mm/init.c
++++ b/arch/riscv/mm/init.c
+@@ -610,13 +610,19 @@ static inline void setup_vm_final(void)
+ #ifdef CONFIG_STRICT_KERNEL_RWX
+ void protect_kernel_text_data(void)
+ {
+- unsigned long text_start = (unsigned long)_text;
++ unsigned long text_start = (unsigned long)_start;
+ unsigned long text_end = (unsigned long)_etext;
++ unsigned long init_text_start = (unsigned long)__init_text_begin;
++ unsigned long init_text_end = (unsigned long)__init_text_end;
++ unsigned long init_data_start = (unsigned long)__init_data_begin;
++ unsigned long init_data_end = (unsigned long)__init_data_end;
+ unsigned long rodata_start = (unsigned long)__start_rodata;
+ unsigned long data_start = (unsigned long)_data;
+ unsigned long max_low = (unsigned long)(__va(PFN_PHYS(max_low_pfn)));
+
++ set_memory_ro(init_text_start, (init_text_end - init_text_start) >> PAGE_SHIFT);
+ set_memory_ro(text_start, (text_end - text_start) >> PAGE_SHIFT);
++ set_memory_nx(init_data_start, (init_data_end - init_data_start) >> PAGE_SHIFT);
+ set_memory_nx(rodata_start, (data_start - rodata_start) >> PAGE_SHIFT);
+ set_memory_nx(data_start, (max_low - data_start) >> PAGE_SHIFT);
+ }
+diff --git a/arch/riscv/mm/pageattr.c b/arch/riscv/mm/pageattr.c
+index 19fecb362d81..04f3fc16aa9c 100644
+--- a/arch/riscv/mm/pageattr.c
++++ b/arch/riscv/mm/pageattr.c
+@@ -128,6 +128,12 @@ static int __set_memory(unsigned long addr, int numpages, pgprot_t set_mask,
+ return ret;
+ }
+
++int set_memory_default(unsigned long addr, int numpages)
++{
++ return __set_memory(addr, numpages, __pgprot(_PAGE_KERNEL),
++ __pgprot(_PAGE_EXEC));
++}
++
+ int set_memory_ro(unsigned long addr, int numpages)
+ {
+ return __set_memory(addr, numpages, __pgprot(_PAGE_READ),
+
+From patchwork Mon Oct 26 23:02:54 2020
+Content-Type: text/plain; charset="utf-8"
+MIME-Version: 1.0
+Content-Transfer-Encoding: 7bit
+X-Patchwork-Id: 11858959
+Return-Path:
+ <SRS0=2xBv=EB=lists.infradead.org=linux-riscv-bounces+patchwork-linux-riscv=patchwork.kernel.org@kernel.org>
+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 CA26E697
+ Mon, 26 Oct 2020 23:03:38 +0000 (UTC)
+Received: from merlin.infradead.org (merlin.infradead.org [205.233.59.134])
+ (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits))
+ (No client certificate requested)
+ by mail.kernel.org (Postfix) with ESMTPS id 738AA20708
+ Mon, 26 Oct 2020 23:03:38 +0000 (UTC)
+Authentication-Results: mail.kernel.org;
+ dkim=pass (2048-bit key) header.d=lists.infradead.org
+ dkim=fail reason="signature verification failed" (2048-bit key)
+DMARC-Filter: OpenDMARC Filter v1.3.2 mail.kernel.org 738AA20708
+Authentication-Results: mail.kernel.org;
+ dmarc=fail (p=none dis=none) header.from=wdc.com
+Authentication-Results: mail.kernel.org;
+ spf=none
+ smtp.mailfrom=linux-riscv-bounces+patchwork-linux-riscv=patchwork.kernel.org@lists.infradead.org
+DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed;
+ d=lists.infradead.org; s=merlin.20170209; h=Sender:Content-Transfer-Encoding:
+ Content-Type:Cc:List-Subscribe:List-Help:List-Post:List-Archive:
+ List-Unsubscribe:List-Id:MIME-Version:References:In-Reply-To:Message-Id:Date:
+ Subject:To:From:Reply-To:Content-ID:Content-Description:Resent-Date:
+ Resent-From:Resent-Sender:Resent-To:Resent-Cc:Resent-Message-ID:List-Owner;
+ bh=fXVyYS2t9va4G58pC03VA4d9ZBiDIWidqr+XRUr8uOM=; b=0aEtXH3VAgmEBQKzqXhgabfRE
+ V2/Yqid/iy8LtCw6WoK+IVDI0gOLkgqLP2ChmPXt/RfAxTA+A3xxvMKazG/ygUYBu1vPG3HUQz/de
+ bcSLaUFmCBulOt7OZR90WhPVW0D8wAdA/xmh6FX8AwRnN6My2vAB54m9VcZ00hokRdPWtSF8kzQNY
+ 2H/DkxGNMtg8XXR/w/9+i13bwLOrTP3sj5oJxGkMjrzESGKfJU65gkd8/EuLSbTq+If+fmG5nBq52
+ BXgpz9qxiE1Fju1w5btn8AE1Y97YALESFOPRdOm7uZIEmXlm/OayEkYwZMCQZMW6MyUxcagLM+Sib
+ /7oyW5gOg==;
+Received: from localhost ([::1] helo=merlin.infradead.org)
+ by merlin.infradead.org with esmtp (Exim 4.92.3 #3 (Red Hat Linux))
+ id 1kXBWa-0004Ka-Lz; Mon, 26 Oct 2020 23:03:36 +0000
+Received: from esa6.hgst.iphmx.com ([216.71.154.45])
+ by merlin.infradead.org with esmtps (Exim 4.92.3 #3 (Red Hat Linux))
+ id 1kXBWV-0004FU-0j
+DKIM-Signature: v=1; a=rsa-sha256; c=simple/simple;
+ t=1603753411; x=1635289411;
+ h=from:to:cc:subject:date:message-id:in-reply-to:
+ references:mime-version:content-transfer-encoding;
+ bh=ySjO0ROtxsgulKuASejfUOnFI2wPdTDF4D2jhNgjeiY=;
+ b=P7imCxg+9oBiw8aBtRk+L6Zz8THT17cCHNj7XjaKdrZmC2+KBGDAvFWO
+ 5V/fRypY/s9wxrudt5RjyPOp87Ob7g+gSuRQ9v2Ickh6Dl0cg/bmflozp
+ nlSCPgJUH0uCTqgckGDx9Kg+EdFOUmnUNTFlItmvIOJIYmaDjqe58y+HC
+ ej8tpDrRJdN3oAN6uc5hYyO5kMWuiFVJibm/bKr+5oJgimJ9DsG2bA4f+
+ jKvLQRQCI5MidMbWd1/oj0QSwCNghHSUahIwFeQjZjwy0Do2Wn7AyjwHz
+ Pimf0/AVzQYqo8BacBX5cUK7OXAkBRsTu6BUIu/h6VPuvV/t7ZwQp9z8R Q==;
+IronPort-SDR:
+ PT0RiwbgnnB9A6wwG+sCRTPlsjfPISJwc8M+pA4S6cjb6g/gX+CxZDF5bjLlqnkTWQiYX2pzM7
+ oy40QCbgnrOmeGDuoRhTSdYyZ4yxn/8MGgWB7Mo7ASVn/rRoeSGkcUjDsDZ1i3vGEcW3It9BJJ
+ xoamU0sMqFCB/KXU9pOVY7ZWo9e/fTAAl59xrdy9nnLDHTSmOxqnxIugOPx36qVNglEGPVoRp3
+ PcLgXDjtPzOvLJp0XI9G/dGNZ0zs2mZyt2jKX6+XcufPL6perAaPdrPzUAa5YOsoImLBpZsT5d
+ ogU=
+X-IronPort-AV: E=Sophos;i="5.77,421,1596470400"; d="scan'208";a="152152918"
+Received: from h199-255-45-15.hgst.com (HELO uls-op-cesaep02.wdc.com)
+ ([199.255.45.15])
+ by ob1.hgst.iphmx.com with ESMTP; 27 Oct 2020 07:03:26 +0800
+IronPort-SDR:
+ ZbbpiJxajYyqZgq/FisScuJrRZsjrqlKTSHhQnmaz5I2bxr8Q/Q13rQQ+52de0CtGTdgnVXive
+ f7e/l3eRWTzARcycqNkGjCUHbg25Lr5CkXXYOeafY1cnnz3cLPy1D53MkmPQ9RDajUYFYvhxJq
+ /LDSLVmZiWjquoJBfjk4NUyfaczNQ7Ttnee0ZhyENiPr0n9B2fhJa07FPYS9R1t7ReBR/TZydI
+ UKxgygabdrP3YNvguDZCWoy6tI9mvzSWi0cMxM5SA6Uv9Qq3W1TqnD7rxSnMUDViRrpoS/F7gU
+ WcKtaoA+nEMc+wxCU8YiHZdf
+Received: from uls-op-cesaip02.wdc.com ([10.248.3.37])
+ by uls-op-cesaep02.wdc.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384;
+ 26 Oct 2020 15:48:37 -0700
+IronPort-SDR:
+ ZIK6pBlHow57hiV8D7ho7M4zJo6JZXmXc68rJru36zg2zepGnFLYfk0rMM063VRf2xcII5Vlm6
+ k22KEvndaC4UkvZdmPy7PsVD3hmZnU/emkdOcOh9ZfogHtkgStZuny0fTzU6a6UKM//grYrAnu
+ g2DxU2TKr9SHf2reP/hg81Iij6L7dTzG1xKtuyPaToFyfsS8Ud3UlSpzrBY8RZEc9935R2b6nJ
+ OLPJbTTgczk/7d57STXaSaoAVH2omOc9iwiC6afLAGgmwM3l5XwA5ZkyLRltkHkbZ7/aPO0BEN
+ FHg=
+WDCIronportException: Internal
+Received: from 8223p12.ad.shared (HELO jedi-01.hgst.com) ([10.86.60.110])
+ by uls-op-cesaip02.wdc.com with ESMTP; 26 Oct 2020 16:03:26 -0700
+Subject: [PATCH v2 6/6] RISC-V: Move dynamic relocation section under __init
+Date: Mon, 26 Oct 2020 16:02:54 -0700
+X-Mailer: git-send-email 2.25.1
+MIME-Version: 1.0
+X-CRM114-Version: 20100106-BlameMichelson ( TRE 0.8.0 (BSD) ) MR-646709E3
+X-CRM114-CacheID: sfid-20201026_190331_505428_453BB9CC
+X-CRM114-Status: GOOD ( 12.45 )
+X-Spam-Score: -2.5 (--)
+X-Spam-Report: SpamAssassin version 3.4.4 on merlin.infradead.org summary:
+ Content analysis details: (-2.5 points)
+ pts rule name description
+ ---- ----------------------
+ --------------------------------------------------
+ -2.3 RCVD_IN_DNSWL_MED RBL: Sender listed at https://www.dnswl.org/,
+ medium trust [216.71.154.45 listed in list.dnswl.org]
+ -0.0 SPF_PASS SPF: sender matches SPF record
+ -0.0 SPF_HELO_PASS SPF: HELO matches SPF record
+ -0.1 DKIM_VALID_EF Message has a valid DKIM or DK signature from
+ envelope-from domain
+ 0.1 DKIM_SIGNED Message has a DKIM or DK signature,
+ not necessarily
+ valid
+ -0.1 DKIM_VALID Message has at least one valid DKIM or DK signature
+ -0.1 DKIM_VALID_AU Message has a valid DKIM or DK signature from
+ author's domain
+X-Mailman-Version: 2.1.29
+Precedence: list
+List-Id: <linux-riscv.lists.infradead.org>
+List-Unsubscribe: <http://lists.infradead.org/mailman/options/linux-riscv>,
+List-Archive: <http://lists.infradead.org/pipermail/linux-riscv/>
+List-Subscribe: <http://lists.infradead.org/mailman/listinfo/linux-riscv>,
+Errors-To:
+ linux-riscv-bounces+patchwork-linux-riscv=patchwork.kernel.org@lists.infradead.org
+
+Dynamic relocation section are only required during boot. Those sections
+can be freed after init. Thus, it can be moved to __init section.
+
+---
+ arch/riscv/kernel/vmlinux.lds.S | 8 ++++----
+ 1 file changed, 4 insertions(+), 4 deletions(-)
+
+diff --git a/arch/riscv/kernel/vmlinux.lds.S b/arch/riscv/kernel/vmlinux.lds.S
+index 0a1874e48e8a..64c5e74008b7 100644
+--- a/arch/riscv/kernel/vmlinux.lds.S
++++ b/arch/riscv/kernel/vmlinux.lds.S
+@@ -85,6 +85,10 @@ SECTIONS
+ }
+ PERCPU_SECTION(L1_CACHE_BYTES)
+
++ .rel.dyn : {
++ *(.rel.dyn*)
++ }
++
+ __init_data_end = .;
+ __init_end = .;
+
+@@ -116,10 +120,6 @@ SECTIONS
+
+ BSS_SECTION(PAGE_SIZE, PAGE_SIZE, 0)
+
+- .rel.dyn : {
+- *(.rel.dyn*)
+- }
+-
+ #ifdef CONFIG_EFI
+ . = ALIGN(PECOFF_SECTION_ALIGNMENT);
+ __pecoff_data_virt_size = ABSOLUTE(. - __pecoff_text_end);
--- /dev/null
+From 621dd9aa125dbd597ac51a0b2a466ef49562d561 Mon Sep 17 00:00:00 2001
+Date: Tue, 8 Dec 2020 10:25:39 +0530
+Subject: [PATCH 04/28] riscv: dts: add initial support for the SiFive
+ FU740-C000 SoC
+
+Add initial support for the SiFive FU540-C000 SoC. FU740-C000 is built
+around the SiFIve U7 Core Complex and a TileLink interconnect.
+
+This file is expected to grow as more device drivers are added to the
+kernel.
+
+---
+ arch/riscv/boot/dts/sifive/fu740-c000.dtsi | 293 +++++++++++++++++++++++++++++
+ 1 file changed, 293 insertions(+)
+ create mode 100644 arch/riscv/boot/dts/sifive/fu740-c000.dtsi
+
+diff --git a/arch/riscv/boot/dts/sifive/fu740-c000.dtsi b/arch/riscv/boot/dts/sifive/fu740-c000.dtsi
+new file mode 100644
+index 00000000..eeb4f8c3
+--- /dev/null
++++ b/arch/riscv/boot/dts/sifive/fu740-c000.dtsi
+@@ -0,0 +1,293 @@
++// SPDX-License-Identifier: (GPL-2.0 OR MIT)
++/* Copyright (c) 2020 SiFive, Inc */
++
++/dts-v1/;
++
++#include <dt-bindings/clock/sifive-fu740-prci.h>
++
++/ {
++ #address-cells = <2>;
++ #size-cells = <2>;
++ compatible = "sifive,fu740-c000", "sifive,fu740";
++
++ aliases {
++ serial0 = &uart0;
++ serial1 = &uart1;
++ ethernet0 = ð0;
++ };
++
++ chosen {
++ };
++
++ cpus {
++ #address-cells = <1>;
++ #size-cells = <0>;
++ cpu0: cpu@0 {
++ compatible = "sifive,bullet0", "riscv";
++ device_type = "cpu";
++ i-cache-block-size = <64>;
++ i-cache-sets = <128>;
++ i-cache-size = <16384>;
++ next-level-cache = <&ccache>;
++ reg = <0x0>;
++ riscv,isa = "rv64imac";
++ status = "disabled";
++ cpu0_intc: interrupt-controller {
++ #interrupt-cells = <1>;
++ compatible = "riscv,cpu-intc";
++ interrupt-controller;
++ };
++ };
++ cpu1: cpu@1 {
++ compatible = "sifive,bullet0", "riscv";
++ d-cache-block-size = <64>;
++ d-cache-sets = <64>;
++ d-cache-size = <32768>;
++ d-tlb-sets = <1>;
++ d-tlb-size = <40>;
++ device_type = "cpu";
++ i-cache-block-size = <64>;
++ i-cache-sets = <128>;
++ i-cache-size = <32768>;
++ i-tlb-sets = <1>;
++ i-tlb-size = <40>;
++ mmu-type = "riscv,sv39";
++ next-level-cache = <&ccache>;
++ reg = <0x1>;
++ riscv,isa = "rv64imafdc";
++ tlb-split;
++ cpu1_intc: interrupt-controller {
++ #interrupt-cells = <1>;
++ compatible = "riscv,cpu-intc";
++ interrupt-controller;
++ };
++ };
++ cpu2: cpu@2 {
++ compatible = "sifive,bullet0", "riscv";
++ d-cache-block-size = <64>;
++ d-cache-sets = <64>;
++ d-cache-size = <32768>;
++ d-tlb-sets = <1>;
++ d-tlb-size = <40>;
++ device_type = "cpu";
++ i-cache-block-size = <64>;
++ i-cache-sets = <128>;
++ i-cache-size = <32768>;
++ i-tlb-sets = <1>;
++ i-tlb-size = <40>;
++ mmu-type = "riscv,sv39";
++ next-level-cache = <&ccache>;
++ reg = <0x2>;
++ riscv,isa = "rv64imafdc";
++ tlb-split;
++ cpu2_intc: interrupt-controller {
++ #interrupt-cells = <1>;
++ compatible = "riscv,cpu-intc";
++ interrupt-controller;
++ };
++ };
++ cpu3: cpu@3 {
++ compatible = "sifive,bullet0", "riscv";
++ d-cache-block-size = <64>;
++ d-cache-sets = <64>;
++ d-cache-size = <32768>;
++ d-tlb-sets = <1>;
++ d-tlb-size = <40>;
++ device_type = "cpu";
++ i-cache-block-size = <64>;
++ i-cache-sets = <128>;
++ i-cache-size = <32768>;
++ i-tlb-sets = <1>;
++ i-tlb-size = <40>;
++ mmu-type = "riscv,sv39";
++ next-level-cache = <&ccache>;
++ reg = <0x3>;
++ riscv,isa = "rv64imafdc";
++ tlb-split;
++ cpu3_intc: interrupt-controller {
++ #interrupt-cells = <1>;
++ compatible = "riscv,cpu-intc";
++ interrupt-controller;
++ };
++ };
++ cpu4: cpu@4 {
++ compatible = "sifive,bullet0", "riscv";
++ d-cache-block-size = <64>;
++ d-cache-sets = <64>;
++ d-cache-size = <32768>;
++ d-tlb-sets = <1>;
++ d-tlb-size = <40>;
++ device_type = "cpu";
++ i-cache-block-size = <64>;
++ i-cache-sets = <128>;
++ i-cache-size = <32768>;
++ i-tlb-sets = <1>;
++ i-tlb-size = <40>;
++ mmu-type = "riscv,sv39";
++ next-level-cache = <&ccache>;
++ reg = <0x4>;
++ riscv,isa = "rv64imafdc";
++ tlb-split;
++ cpu4_intc: interrupt-controller {
++ #interrupt-cells = <1>;
++ compatible = "riscv,cpu-intc";
++ interrupt-controller;
++ };
++ };
++ };
++ soc {
++ #address-cells = <2>;
++ #size-cells = <2>;
++ compatible = "simple-bus";
++ ranges;
++ plic0: interrupt-controller@c000000 {
++ #interrupt-cells = <1>;
++ #address-cells = <0>;
++ compatible = "sifive,fu540-c000-plic", "sifive,plic-1.0.0";
++ reg = <0x0 0xc000000 0x0 0x4000000>;
++ riscv,ndev = <69>;
++ interrupt-controller;
++ interrupts-extended = <
++ &cpu0_intc 0xffffffff
++ &cpu1_intc 0xffffffff &cpu1_intc 9
++ &cpu2_intc 0xffffffff &cpu2_intc 9
++ &cpu3_intc 0xffffffff &cpu3_intc 9
++ &cpu4_intc 0xffffffff &cpu4_intc 9>;
++ };
++ prci: clock-controller@10000000 {
++ compatible = "sifive,fu740-c000-prci";
++ reg = <0x0 0x10000000 0x0 0x1000>;
++ clocks = <&hfclk>, <&rtcclk>;
++ #clock-cells = <1>;
++ };
++ uart0: serial@10010000 {
++ compatible = "sifive,fu740-c000-uart", "sifive,uart0";
++ reg = <0x0 0x10010000 0x0 0x1000>;
++ interrupt-parent = <&plic0>;
++ interrupts = <39>;
++ clocks = <&prci PRCI_CLK_PCLK>;
++ status = "disabled";
++ };
++ uart1: serial@10011000 {
++ compatible = "sifive,fu740-c000-uart", "sifive,uart0";
++ reg = <0x0 0x10011000 0x0 0x1000>;
++ interrupt-parent = <&plic0>;
++ interrupts = <40>;
++ clocks = <&prci PRCI_CLK_PCLK>;
++ status = "disabled";
++ };
++ i2c0: i2c@10030000 {
++ compatible = "sifive,fu740-c000-i2c", "sifive,i2c0";
++ reg = <0x0 0x10030000 0x0 0x1000>;
++ interrupt-parent = <&plic0>;
++ interrupts = <52>;
++ clocks = <&prci PRCI_CLK_PCLK>;
++ reg-shift = <2>;
++ reg-io-width = <1>;
++ #address-cells = <1>;
++ #size-cells = <0>;
++ status = "disabled";
++ };
++ i2c1: i2c@10031000 {
++ compatible = "sifive,fu740-c000-i2c", "sifive,i2c0";
++ reg = <0x0 0x10031000 0x0 0x1000>;
++ interrupt-parent = <&plic0>;
++ interrupts = <53>;
++ clocks = <&prci PRCI_CLK_PCLK>;
++ reg-shift = <2>;
++ reg-io-width = <1>;
++ #address-cells = <1>;
++ #size-cells = <0>;
++ status = "disabled";
++ };
++ qspi0: spi@10040000 {
++ compatible = "sifive,fu740-c000-spi", "sifive,spi0";
++ reg = <0x0 0x10040000 0x0 0x1000>,
++ <0x0 0x20000000 0x0 0x10000000>;
++ interrupt-parent = <&plic0>;
++ interrupts = <41>;
++ clocks = <&prci PRCI_CLK_PCLK>;
++ #address-cells = <1>;
++ #size-cells = <0>;
++ status = "disabled";
++ };
++ qspi1: spi@10041000 {
++ compatible = "sifive,fu740-c000-spi", "sifive,spi0";
++ reg = <0x0 0x10041000 0x0 0x1000>,
++ <0x0 0x30000000 0x0 0x10000000>;
++ interrupt-parent = <&plic0>;
++ interrupts = <42>;
++ clocks = <&prci PRCI_CLK_PCLK>;
++ #address-cells = <1>;
++ #size-cells = <0>;
++ status = "disabled";
++ };
++ spi0: spi@10050000 {
++ compatible = "sifive,fu740-c000-spi", "sifive,spi0";
++ reg = <0x0 0x10050000 0x0 0x1000>;
++ interrupt-parent = <&plic0>;
++ interrupts = <43>;
++ clocks = <&prci PRCI_CLK_PCLK>;
++ #address-cells = <1>;
++ #size-cells = <0>;
++ status = "disabled";
++ };
++ eth0: ethernet@10090000 {
++ compatible = "sifive,fu540-c000-gem";
++ interrupt-parent = <&plic0>;
++ interrupts = <55>;
++ reg = <0x0 0x10090000 0x0 0x2000>,
++ <0x0 0x100a0000 0x0 0x1000>;
++ local-mac-address = [00 00 00 00 00 00];
++ clock-names = "pclk", "hclk";
++ clocks = <&prci PRCI_CLK_GEMGXLPLL>,
++ <&prci PRCI_CLK_GEMGXLPLL>;
++ #address-cells = <1>;
++ #size-cells = <0>;
++ status = "disabled";
++ };
++ pwm0: pwm@10020000 {
++ compatible = "sifive,fu740-c000-pwm", "sifive,pwm0";
++ reg = <0x0 0x10020000 0x0 0x1000>;
++ interrupt-parent = <&plic0>;
++ interrupts = <44>, <45>, <46>, <47>;
++ clocks = <&prci PRCI_CLK_PCLK>;
++ #pwm-cells = <3>;
++ status = "disabled";
++ };
++ pwm1: pwm@10021000 {
++ compatible = "sifive,fu740-c000-pwm", "sifive,pwm0";
++ reg = <0x0 0x10021000 0x0 0x1000>;
++ interrupt-parent = <&plic0>;
++ interrupts = <48>, <49>, <50>, <51>;
++ clocks = <&prci PRCI_CLK_PCLK>;
++ #pwm-cells = <3>;
++ status = "disabled";
++ };
++ ccache: cache-controller@2010000 {
++ compatible = "sifive,fu740-c000-ccache", "cache";
++ cache-block-size = <64>;
++ cache-level = <2>;
++ cache-sets = <2048>;
++ cache-size = <2097152>;
++ cache-unified;
++ interrupt-parent = <&plic0>;
++ interrupts = <19 20 21 22>;
++ reg = <0x0 0x2010000 0x0 0x1000>;
++ };
++ gpio: gpio@10060000 {
++ compatible = "sifive,fu740-c000-gpio", "sifive,gpio0";
++ interrupt-parent = <&plic0>;
++ interrupts = <23>, <24>, <25>, <26>, <27>, <28>, <29>,
++ <30>, <31>, <32>, <33>, <34>, <35>, <36>,
++ <37>, <38>;
++ reg = <0x0 0x10060000 0x0 0x1000>;
++ gpio-controller;
++ #gpio-cells = <2>;
++ interrupt-controller;
++ #interrupt-cells = <2>;
++ clocks = <&prci PRCI_CLK_PCLK>;
++ status = "disabled";
++ };
++ };
++};
+--
+2.7.4
+
--- /dev/null
+From 4c3ea0f7a7ff303c83273c66b10fe62eed86a7c8 Mon Sep 17 00:00:00 2001
+Date: Tue, 8 Dec 2020 10:25:41 +0530
+Subject: [PATCH 06/28] riscv: dts: add initial board data for the SiFive
+ HiFive Unmatched
+
+Add initial board data for the SiFive HiFive Unmatched A00.
+This patch is dependent on Zong's Patchset[0].
+
+
+---
+ arch/riscv/boot/dts/sifive/Makefile | 3 +-
+ .../riscv/boot/dts/sifive/hifive-unmatched-a00.dts | 253 +++++++++++++++++++++
+ 2 files changed, 255 insertions(+), 1 deletion(-)
+ create mode 100644 arch/riscv/boot/dts/sifive/hifive-unmatched-a00.dts
+
+diff --git a/arch/riscv/boot/dts/sifive/Makefile b/arch/riscv/boot/dts/sifive/Makefile
+index 6d6189e..74c47fe 100644
+--- a/arch/riscv/boot/dts/sifive/Makefile
++++ b/arch/riscv/boot/dts/sifive/Makefile
+@@ -1,2 +1,3 @@
+ # SPDX-License-Identifier: GPL-2.0
+-dtb-$(CONFIG_SOC_SIFIVE) += hifive-unleashed-a00.dtb
++dtb-$(CONFIG_SOC_SIFIVE) += hifive-unleashed-a00.dtb \
++ hifive-unmatched-a00.dtb
+diff --git a/arch/riscv/boot/dts/sifive/hifive-unmatched-a00.dts b/arch/riscv/boot/dts/sifive/hifive-unmatched-a00.dts
+new file mode 100644
+index 00000000..b1c3c59
+--- /dev/null
++++ b/arch/riscv/boot/dts/sifive/hifive-unmatched-a00.dts
+@@ -0,0 +1,253 @@
++// SPDX-License-Identifier: (GPL-2.0 OR MIT)
++/* Copyright (c) 2020 SiFive, Inc */
++
++#include "fu740-c000.dtsi"
++#include <dt-bindings/interrupt-controller/irq.h>
++
++/* Clock frequency (in Hz) of the PCB crystal for rtcclk */
++#define RTCCLK_FREQ 1000000
++
++/ {
++ #address-cells = <2>;
++ #size-cells = <2>;
++ model = "SiFive HiFive Unmatched A00";
++ compatible = "sifive,hifive-unmatched-a00", "sifive,fu740-c000",
++ "sifive,fu740";
++
++ chosen {
++ stdout-path = "serial0";
++ };
++
++ cpus {
++ timebase-frequency = <RTCCLK_FREQ>;
++ };
++
++ memory@80000000 {
++ device_type = "memory";
++ reg = <0x0 0x80000000 0x2 0x00000000>;
++ };
++
++ soc {
++ };
++
++ hfclk: hfclk {
++ #clock-cells = <0>;
++ compatible = "fixed-clock";
++ clock-frequency = <26000000>;
++ clock-output-names = "hfclk";
++ };
++
++ rtcclk: rtcclk {
++ #clock-cells = <0>;
++ compatible = "fixed-clock";
++ clock-frequency = <RTCCLK_FREQ>;
++ clock-output-names = "rtcclk";
++ };
++};
++
++&uart0 {
++ status = "okay";
++};
++
++&uart1 {
++ status = "okay";
++};
++
++&i2c0 {
++ status = "okay";
++
++ temperature-sensor@4c {
++ compatible = "ti,tmp451";
++ reg = <0x4c>;
++ interrupt-parent = <&gpio>;
++ interrupts = <6 IRQ_TYPE_LEVEL_LOW>;
++ };
++
++ pmic@58 {
++ compatible = "dlg,da9063";
++ reg = <0x58>;
++ interrupt-parent = <&gpio>;
++ interrupts = <1 IRQ_TYPE_LEVEL_LOW>;
++ interrupt-controller;
++
++ regulators {
++ vdd_bcore1: bcore1 {
++ regulator-min-microvolt = <900000>;
++ regulator-max-microvolt = <900000>;
++ regulator-min-microamp = <5000000>;
++ regulator-max-microamp = <5000000>;
++ regulator-always-on;
++ };
++
++ vdd_bcore2: bcore2 {
++ regulator-min-microvolt = <900000>;
++ regulator-max-microvolt = <900000>;
++ regulator-min-microamp = <5000000>;
++ regulator-max-microamp = <5000000>;
++ regulator-always-on;
++ };
++
++ vdd_bpro: bpro {
++ regulator-min-microvolt = <1800000>;
++ regulator-max-microvolt = <1800000>;
++ regulator-min-microamp = <2500000>;
++ regulator-max-microamp = <2500000>;
++ regulator-always-on;
++ };
++
++ vdd_bperi: bperi {
++ regulator-min-microvolt = <1050000>;
++ regulator-max-microvolt = <1050000>;
++ regulator-min-microamp = <1500000>;
++ regulator-max-microamp = <1500000>;
++ regulator-always-on;
++ };
++
++ vdd_bmem: bmem {
++ regulator-min-microvolt = <1200000>;
++ regulator-max-microvolt = <1200000>;
++ regulator-min-microamp = <3000000>;
++ regulator-max-microamp = <3000000>;
++ regulator-always-on;
++ };
++
++ vdd_bio: bio {
++ regulator-min-microvolt = <1200000>;
++ regulator-max-microvolt = <1200000>;
++ regulator-min-microamp = <3000000>;
++ regulator-max-microamp = <3000000>;
++ regulator-always-on;
++ };
++
++ vdd_ldo1: ldo1 {
++ regulator-min-microvolt = <1800000>;
++ regulator-max-microvolt = <1800000>;
++ regulator-min-microamp = <100000>;
++ regulator-max-microamp = <100000>;
++ regulator-always-on;
++ };
++
++ vdd_ldo2: ldo2 {
++ regulator-min-microvolt = <1800000>;
++ regulator-max-microvolt = <1800000>;
++ regulator-min-microamp = <200000>;
++ regulator-max-microamp = <200000>;
++ regulator-always-on;
++ };
++
++ vdd_ldo3: ldo3 {
++ regulator-min-microvolt = <1800000>;
++ regulator-max-microvolt = <1800000>;
++ regulator-min-microamp = <200000>;
++ regulator-max-microamp = <200000>;
++ regulator-always-on;
++ };
++
++ vdd_ldo4: ldo4 {
++ regulator-min-microvolt = <1800000>;
++ regulator-max-microvolt = <1800000>;
++ regulator-min-microamp = <200000>;
++ regulator-max-microamp = <200000>;
++ regulator-always-on;
++ };
++
++ vdd_ldo5: ldo5 {
++ regulator-min-microvolt = <1800000>;
++ regulator-max-microvolt = <1800000>;
++ regulator-min-microamp = <100000>;
++ regulator-max-microamp = <100000>;
++ regulator-always-on;
++ };
++
++ vdd_ldo6: ldo6 {
++ regulator-min-microvolt = <3300000>;
++ regulator-max-microvolt = <3300000>;
++ regulator-min-microamp = <200000>;
++ regulator-max-microamp = <200000>;
++ regulator-always-on;
++ };
++
++ vdd_ldo7: ldo7 {
++ regulator-min-microvolt = <1800000>;
++ regulator-max-microvolt = <1800000>;
++ regulator-min-microamp = <200000>;
++ regulator-max-microamp = <200000>;
++ regulator-always-on;
++ };
++
++ vdd_ldo8: ldo8 {
++ regulator-min-microvolt = <1800000>;
++ regulator-max-microvolt = <1800000>;
++ regulator-min-microamp = <200000>;
++ regulator-max-microamp = <200000>;
++ regulator-always-on;
++ };
++
++ vdd_ld09: ldo9 {
++ regulator-min-microvolt = <1050000>;
++ regulator-max-microvolt = <1050000>;
++ regulator-min-microamp = <200000>;
++ regulator-max-microamp = <200000>;
++ };
++
++ vdd_ldo10: ldo10 {
++ regulator-min-microvolt = <1000000>;
++ regulator-max-microvolt = <1000000>;
++ regulator-min-microamp = <300000>;
++ regulator-max-microamp = <300000>;
++ };
++
++ vdd_ldo11: ldo11 {
++ regulator-min-microvolt = <2500000>;
++ regulator-max-microvolt = <2500000>;
++ regulator-min-microamp = <300000>;
++ regulator-max-microamp = <300000>;
++ regulator-always-on;
++ };
++ };
++ };
++};
++
++&qspi0 {
++ status = "okay";
++ flash@0 {
++ compatible = "issi,is25wp256", "jedec,spi-nor";
++ reg = <0>;
++ spi-max-frequency = <50000000>;
++ m25p,fast-read;
++ spi-tx-bus-width = <4>;
++ spi-rx-bus-width = <4>;
++ };
++};
++
++&spi0 {
++ status = "okay";
++ mmc@0 {
++ compatible = "mmc-spi-slot";
++ reg = <0>;
++ spi-max-frequency = <20000000>;
++ voltage-ranges = <3300 3300>;
++ disable-wp;
++ };
++};
++
++ð0 {
++ status = "okay";
++ phy-mode = "gmii";
++ phy-handle = <&phy0>;
++ phy0: ethernet-phy@0 {
++ reg = <0>;
++ };
++};
++
++&pwm0 {
++ status = "okay";
++};
++
++&pwm1 {
++ status = "okay";
++};
++
++&gpio {
++ status = "okay";
++};
+--
+2.7.4
+
--- /dev/null
+From c6ed58c46436731279045a01c3611251a8ebd76b Mon Sep 17 00:00:00 2001
+Date: Thu, 10 Dec 2020 15:58:03 +0530
+Subject: [PATCH 08/28] RISC-V: sifive_l2_cache: Update L2 cache driver to
+ support SiFive FU740
+
+SiFive FU740 has 4 ECC interrupt sources as compared to 3 in FU540.
+Update the L2 cache controller driver to support this additional
+interrupt in case of FU740-C000 chip.
+
+---
+ drivers/soc/sifive/sifive_l2_cache.c | 27 ++++++++++++++++++++++++---
+ 1 file changed, 24 insertions(+), 3 deletions(-)
+
+diff --git a/drivers/soc/sifive/sifive_l2_cache.c b/drivers/soc/sifive/sifive_l2_cache.c
+index 44d7e1951..59640a1 100644
+--- a/drivers/soc/sifive/sifive_l2_cache.c
++++ b/drivers/soc/sifive/sifive_l2_cache.c
+@@ -17,6 +17,10 @@
+ #define SIFIVE_L2_DIRECCFIX_HIGH 0x104
+ #define SIFIVE_L2_DIRECCFIX_COUNT 0x108
+
++#define SIFIVE_L2_DIRECCFAIL_LOW 0x120
++#define SIFIVE_L2_DIRECCFAIL_HIGH 0x124
++#define SIFIVE_L2_DIRECCFAIL_COUNT 0x128
++
+ #define SIFIVE_L2_DATECCFIX_LOW 0x140
+ #define SIFIVE_L2_DATECCFIX_HIGH 0x144
+ #define SIFIVE_L2_DATECCFIX_COUNT 0x148
+@@ -29,7 +33,7 @@
+ #define SIFIVE_L2_WAYENABLE 0x08
+ #define SIFIVE_L2_ECCINJECTERR 0x40
+
+-#define SIFIVE_L2_MAX_ECCINTR 3
++#define SIFIVE_L2_MAX_ECCINTR 4
+
+ static void __iomem *l2_base;
+ static int g_irq[SIFIVE_L2_MAX_ECCINTR];
+@@ -39,6 +43,7 @@ enum {
+ DIR_CORR = 0,
+ DATA_CORR,
+ DATA_UNCORR,
++ DIR_UNCORR,
+ };
+
+ #ifdef CONFIG_DEBUG_FS
+@@ -93,6 +98,7 @@ static void l2_config_read(void)
+
+ static const struct of_device_id sifive_l2_ids[] = {
+ { .compatible = "sifive,fu540-c000-ccache" },
++ { .compatible = "sifive,fu740-c000-ccache" },
+ { /* end of table */ },
+ };
+
+@@ -155,6 +161,15 @@ static irqreturn_t l2_int_handler(int irq, void *device)
+ atomic_notifier_call_chain(&l2_err_chain, SIFIVE_L2_ERR_TYPE_CE,
+ "DirECCFix");
+ }
++ if (irq == g_irq[DIR_UNCORR]) {
++ add_h = readl(l2_base + SIFIVE_L2_DIRECCFAIL_HIGH);
++ add_l = readl(l2_base + SIFIVE_L2_DIRECCFAIL_LOW);
++ /* Reading this register clears the DirFail interrupt sig */
++ readl(l2_base + SIFIVE_L2_DIRECCFAIL_COUNT);
++ atomic_notifier_call_chain(&l2_err_chain, SIFIVE_L2_ERR_TYPE_UE,
++ "DirECCFail");
++ panic("L2CACHE: DirFail @ 0x%08X.%08X\n", add_h, add_l);
++ }
+ if (irq == g_irq[DATA_CORR]) {
+ add_h = readl(l2_base + SIFIVE_L2_DATECCFIX_HIGH);
+ add_l = readl(l2_base + SIFIVE_L2_DATECCFIX_LOW);
+@@ -181,7 +196,7 @@ static int __init sifive_l2_init(void)
+ {
+ struct device_node *np;
+ struct resource res;
+- int i, rc;
++ int i, rc, intr_num;
+
+ np = of_find_matching_node(NULL, sifive_l2_ids);
+ if (!np)
+@@ -194,7 +209,13 @@ static int __init sifive_l2_init(void)
+ if (!l2_base)
+ return -ENOMEM;
+
+- for (i = 0; i < SIFIVE_L2_MAX_ECCINTR; i++) {
++ intr_num = of_property_count_u32_elems(np, "interrupts");
++ if (!intr_num) {
++ pr_err("L2CACHE: no interrupts property\n");
++ return -ENODEV;
++ }
++
++ for (i = 0; i < intr_num; i++) {
+ g_irq[i] = irq_of_parse_and_map(np, i);
+ rc = request_irq(g_irq[i], l2_int_handler, 0, "l2_ecc", NULL);
+ if (rc) {
+--
+2.7.4
+
--- /dev/null
+From bc7576ad8540ac5fd49c38eae072f561ee6ed8fa Mon Sep 17 00:00:00 2001
+Date: Wed, 3 Feb 2021 07:00:15 -0800
+Subject: [PATCH 09/28] riscv: dts: fu740: fix cache-controller interrupts
+
+The order of interrupt numbers is incorrect.
+
+The order for FU740 is: DirError, DataError, DataFail, DirFail
+
+From SiFive FU740-C000 Manual:
+19 - L2 Cache DirError
+20 - L2 Cache DirFail
+21 - L2 Cache DataError
+22 - L2 Cache DataFail
+
+---
+ arch/riscv/boot/dts/sifive/fu740-c000.dtsi | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+diff --git a/arch/riscv/boot/dts/sifive/fu740-c000.dtsi b/arch/riscv/boot/dts/sifive/fu740-c000.dtsi
+index eeb4f8c3..d0d206c 100644
+--- a/arch/riscv/boot/dts/sifive/fu740-c000.dtsi
++++ b/arch/riscv/boot/dts/sifive/fu740-c000.dtsi
+@@ -272,7 +272,7 @@
+ cache-size = <2097152>;
+ cache-unified;
+ interrupt-parent = <&plic0>;
+- interrupts = <19 20 21 22>;
++ interrupts = <19 21 22 20>;
+ reg = <0x0 0x2010000 0x0 0x1000>;
+ };
+ gpio: gpio@10060000 {
+--
+2.7.4
+
--- /dev/null
+From aae0bd387f1c3a81bfa1108dfa3fcd7a631ef482 Mon Sep 17 00:00:00 2001
+Date: Wed, 17 Feb 2021 06:06:14 -0800
+Subject: [PATCH 10/28] riscv: sifive: fu740: cpu{1,2,3,4} set compatible to
+ sifive,u74-mc
+
+---
+ arch/riscv/boot/dts/sifive/fu740-c000.dtsi | 8 ++++----
+ 1 file changed, 4 insertions(+), 4 deletions(-)
+
+diff --git a/arch/riscv/boot/dts/sifive/fu740-c000.dtsi b/arch/riscv/boot/dts/sifive/fu740-c000.dtsi
+index d0d206c..cd9cc02 100644
+--- a/arch/riscv/boot/dts/sifive/fu740-c000.dtsi
++++ b/arch/riscv/boot/dts/sifive/fu740-c000.dtsi
+@@ -39,7 +39,7 @@
+ };
+ };
+ cpu1: cpu@1 {
+- compatible = "sifive,bullet0", "riscv";
++ compatible = "sifive,u74-mc", "sifive,bullet0", "riscv";
+ d-cache-block-size = <64>;
+ d-cache-sets = <64>;
+ d-cache-size = <32768>;
+@@ -63,7 +63,7 @@
+ };
+ };
+ cpu2: cpu@2 {
+- compatible = "sifive,bullet0", "riscv";
++ compatible = "sifive,u74-mc", "sifive,bullet0", "riscv";
+ d-cache-block-size = <64>;
+ d-cache-sets = <64>;
+ d-cache-size = <32768>;
+@@ -87,7 +87,7 @@
+ };
+ };
+ cpu3: cpu@3 {
+- compatible = "sifive,bullet0", "riscv";
++ compatible = "sifive,u74-mc", "sifive,bullet0", "riscv";
+ d-cache-block-size = <64>;
+ d-cache-sets = <64>;
+ d-cache-size = <32768>;
+@@ -111,7 +111,7 @@
+ };
+ };
+ cpu4: cpu@4 {
+- compatible = "sifive,bullet0", "riscv";
++ compatible = "sifive,u74-mc", "sifive,bullet0", "riscv";
+ d-cache-block-size = <64>;
+ d-cache-sets = <64>;
+ d-cache-size = <32768>;
+--
+2.7.4
+
--- /dev/null
+From e0fc0af6df9f5a1c9835d73e649b88c8a533db0c Mon Sep 17 00:00:00 2001
+Date: Mon, 22 Feb 2021 01:33:52 -0800
+Subject: [PATCH 11/28] riscv: sifive: unmatched: update for 16GB rev3
+
+---
+ .../riscv/boot/dts/sifive/hifive-unmatched-a00.dts | 34 +++++++++++-----------
+ 1 file changed, 17 insertions(+), 17 deletions(-)
+
+diff --git a/arch/riscv/boot/dts/sifive/hifive-unmatched-a00.dts b/arch/riscv/boot/dts/sifive/hifive-unmatched-a00.dts
+index b1c3c59..e026f60 100644
+--- a/arch/riscv/boot/dts/sifive/hifive-unmatched-a00.dts
++++ b/arch/riscv/boot/dts/sifive/hifive-unmatched-a00.dts
+@@ -24,7 +24,7 @@
+
+ memory@80000000 {
+ device_type = "memory";
+- reg = <0x0 0x80000000 0x2 0x00000000>;
++ reg = <0x0 0x80000000 0x4 0x00000000>;
+ };
+
+ soc {
+@@ -72,16 +72,16 @@
+
+ regulators {
+ vdd_bcore1: bcore1 {
+- regulator-min-microvolt = <900000>;
+- regulator-max-microvolt = <900000>;
++ regulator-min-microvolt = <1050000>;
++ regulator-max-microvolt = <1050000>;
+ regulator-min-microamp = <5000000>;
+ regulator-max-microamp = <5000000>;
+ regulator-always-on;
+ };
+
+ vdd_bcore2: bcore2 {
+- regulator-min-microvolt = <900000>;
+- regulator-max-microvolt = <900000>;
++ regulator-min-microvolt = <1050000>;
++ regulator-max-microvolt = <1050000>;
+ regulator-min-microamp = <5000000>;
+ regulator-max-microamp = <5000000>;
+ regulator-always-on;
+@@ -136,48 +136,48 @@
+ };
+
+ vdd_ldo3: ldo3 {
+- regulator-min-microvolt = <1800000>;
+- regulator-max-microvolt = <1800000>;
++ regulator-min-microvolt = <3300000>;
++ regulator-max-microvolt = <3300000>;
+ regulator-min-microamp = <200000>;
+ regulator-max-microamp = <200000>;
+ regulator-always-on;
+ };
+
+ vdd_ldo4: ldo4 {
+- regulator-min-microvolt = <1800000>;
+- regulator-max-microvolt = <1800000>;
++ regulator-min-microvolt = <2500000>;
++ regulator-max-microvolt = <2500000>;
+ regulator-min-microamp = <200000>;
+ regulator-max-microamp = <200000>;
+ regulator-always-on;
+ };
+
+ vdd_ldo5: ldo5 {
+- regulator-min-microvolt = <1800000>;
+- regulator-max-microvolt = <1800000>;
++ regulator-min-microvolt = <3300000>;
++ regulator-max-microvolt = <3300000>;
+ regulator-min-microamp = <100000>;
+ regulator-max-microamp = <100000>;
+ regulator-always-on;
+ };
+
+ vdd_ldo6: ldo6 {
+- regulator-min-microvolt = <3300000>;
+- regulator-max-microvolt = <3300000>;
++ regulator-min-microvolt = <1800000>;
++ regulator-max-microvolt = <1800000>;
+ regulator-min-microamp = <200000>;
+ regulator-max-microamp = <200000>;
+ regulator-always-on;
+ };
+
+ vdd_ldo7: ldo7 {
+- regulator-min-microvolt = <1800000>;
+- regulator-max-microvolt = <1800000>;
++ regulator-min-microvolt = <3300000>;
++ regulator-max-microvolt = <3300000>;
+ regulator-min-microamp = <200000>;
+ regulator-max-microamp = <200000>;
+ regulator-always-on;
+ };
+
+ vdd_ldo8: ldo8 {
+- regulator-min-microvolt = <1800000>;
+- regulator-max-microvolt = <1800000>;
++ regulator-min-microvolt = <3300000>;
++ regulator-max-microvolt = <3300000>;
+ regulator-min-microamp = <200000>;
+ regulator-max-microamp = <200000>;
+ regulator-always-on;
+--
+2.7.4
+
--- /dev/null
+From 1707c6daff527d1661de60a9279b72d22265fd4b Mon Sep 17 00:00:00 2001
+Date: Mon, 22 Mar 2021 22:26:02 +0800
+Subject: [PATCH 12/28] riscv: Add 3 SBI wrapper functions to get cpu
+ manufacturer information
+
+Add 3 wrapper functions to get vendor id, architecture id and implement id
+from M-mode
+
+---
+ arch/riscv/include/asm/sbi.h | 3 +++
+ arch/riscv/kernel/sbi.c | 15 +++++++++++++++
+ 2 files changed, 18 insertions(+)
+
+diff --git a/arch/riscv/include/asm/sbi.h b/arch/riscv/include/asm/sbi.h
+index c0fdb05..072c91f 100644
+--- a/arch/riscv/include/asm/sbi.h
++++ b/arch/riscv/include/asm/sbi.h
+@@ -97,6 +97,9 @@ struct sbiret sbi_ecall(int ext, int fid, unsigned long arg0,
+
+ void sbi_console_putchar(int ch);
+ int sbi_console_getchar(void);
++long sbi_get_mvendorid(void);
++long sbi_get_marchid(void);
++long sbi_get_mimpid(void);
+ void sbi_set_timer(uint64_t stime_value);
+ void sbi_shutdown(void);
+ void sbi_clear_ipi(void);
+diff --git a/arch/riscv/kernel/sbi.c b/arch/riscv/kernel/sbi.c
+index 226ccce..51a4e5f 100644
+--- a/arch/riscv/kernel/sbi.c
++++ b/arch/riscv/kernel/sbi.c
+@@ -547,6 +547,21 @@ static inline long sbi_get_firmware_version(void)
+ return __sbi_base_ecall(SBI_EXT_BASE_GET_IMP_VERSION);
+ }
+
++long sbi_get_mvendorid(void)
++{
++ return __sbi_base_ecall(SBI_EXT_BASE_GET_MVENDORID);
++}
++
++long sbi_get_marchid(void)
++{
++ return __sbi_base_ecall(SBI_EXT_BASE_GET_MARCHID);
++}
++
++long sbi_get_mimpid(void)
++{
++ return __sbi_base_ecall(SBI_EXT_BASE_GET_MIMPID);
++}
++
+ static void sbi_send_cpumask_ipi(const struct cpumask *target)
+ {
+ struct cpumask hartid_mask;
+--
+2.7.4
+
--- /dev/null
+From 5c0093a1e2b8ef676d413576b2f74f4b6b7c1c51 Mon Sep 17 00:00:00 2001
+Date: Mon, 22 Mar 2021 22:26:03 +0800
+Subject: [PATCH 13/28] riscv: Introduce alternative mechanism to apply errata
+ solution
+
+Introduce the "alternative" mechanism from ARM64 and x86 to apply the CPU
+vendors' errata solution at runtime. The main purpose of this patch is
+to provide a framework. Therefore, the implementation is quite basic for
+now so that some scenarios could not use this schemei, such as patching
+code to a module, relocating the patching code and heterogeneous CPU
+topology.
+
+Users could use the macro ALTERNATIVE to apply an errata to the existing
+code flow. In the macro ALTERNATIVE, users need to specify the manufacturer
+information(vendorid, archid, and impid) for this errata. Therefore, kernel
+will know this errata is suitable for which CPU core. During the booting
+procedure, kernel will select the errata required by the CPU core and then
+patch it. It means that the kernel only applies the errata to the specified
+CPU core. In this case, the vendor's errata does not affect each other at
+runtime. The above patching procedure only occurs during the booting phase,
+so we only take the overhead of the "alternative" mechanism once.
+
+This "alternative" mechanism is enabled by default to ensure that all
+required errata will be applied. However, users can disable this feature by
+the Kconfig "CONFIG_RISCV_ERRATA_ALTERNATIVE".
+
+---
+ arch/riscv/Kconfig | 1 +
+ arch/riscv/Kconfig.erratas | 12 +++
+ arch/riscv/Makefile | 1 +
+ arch/riscv/errata/Makefile | 1 +
+ arch/riscv/errata/alternative.c | 69 ++++++++++++++
+ arch/riscv/include/asm/alternative-macros.h | 142 ++++++++++++++++++++++++++++
+ arch/riscv/include/asm/alternative.h | 36 +++++++
+ arch/riscv/include/asm/asm.h | 1 +
+ arch/riscv/include/asm/csr.h | 3 +
+ arch/riscv/include/asm/errata_list.h | 12 +++
+ arch/riscv/include/asm/sections.h | 1 +
+ arch/riscv/include/asm/vendorid_list.h | 10 ++
+ arch/riscv/kernel/smpboot.c | 4 +
+ arch/riscv/kernel/vmlinux.lds.S | 7 ++
+ 14 files changed, 300 insertions(+)
+ create mode 100644 arch/riscv/Kconfig.erratas
+ create mode 100644 arch/riscv/errata/Makefile
+ create mode 100644 arch/riscv/errata/alternative.c
+ create mode 100644 arch/riscv/include/asm/alternative-macros.h
+ create mode 100644 arch/riscv/include/asm/alternative.h
+ create mode 100644 arch/riscv/include/asm/errata_list.h
+ create mode 100644 arch/riscv/include/asm/vendorid_list.h
+
+diff --git a/arch/riscv/Kconfig b/arch/riscv/Kconfig
+index e6d569a..3c66957 100644
+--- a/arch/riscv/Kconfig
++++ b/arch/riscv/Kconfig
+@@ -195,6 +195,7 @@ config LOCKDEP_SUPPORT
+ def_bool y
+
+ source "arch/riscv/Kconfig.socs"
++source "arch/riscv/Kconfig.erratas"
+
+ menu "Platform type"
+
+diff --git a/arch/riscv/Kconfig.erratas b/arch/riscv/Kconfig.erratas
+new file mode 100644
+index 00000000..4d0bafc
+--- /dev/null
++++ b/arch/riscv/Kconfig.erratas
+@@ -0,0 +1,12 @@
++menu "CPU errata selection"
++
++config RISCV_ERRATA_ALTERNATIVE
++ bool "RISC-V alternative scheme"
++ default y
++ help
++ This Kconfig allows the kernel to automatically patch the
++ errata required by the execution platform at run time. The
++ code patching is performed once in the boot stages. It means
++ that the overhead from this mechanism is just taken once.
++
++endmenu
+diff --git a/arch/riscv/Makefile b/arch/riscv/Makefile
+index 8c29e55..2bff64c 100644
+--- a/arch/riscv/Makefile
++++ b/arch/riscv/Makefile
+@@ -75,6 +75,7 @@ KBUILD_IMAGE := $(boot)/Image.gz
+ head-y := arch/riscv/kernel/head.o
+
+ core-y += arch/riscv/
++core-$(CONFIG_RISCV_ERRATA_ALTERNATIVE) += arch/riscv/errata/
+
+ libs-y += arch/riscv/lib/
+ libs-$(CONFIG_EFI_STUB) += $(objtree)/drivers/firmware/efi/libstub/lib.a
+diff --git a/arch/riscv/errata/Makefile b/arch/riscv/errata/Makefile
+new file mode 100644
+index 00000000..43e6d54
+--- /dev/null
++++ b/arch/riscv/errata/Makefile
+@@ -0,0 +1 @@
++obj-y += alternative.o
+diff --git a/arch/riscv/errata/alternative.c b/arch/riscv/errata/alternative.c
+new file mode 100644
+index 00000000..8efa60a
+--- /dev/null
++++ b/arch/riscv/errata/alternative.c
+@@ -0,0 +1,69 @@
++// SPDX-License-Identifier: GPL-2.0-only
++/*
++ * alternative runtime patching
++ * inspired by the ARM64 and x86 version
++ *
++ * Copyright (C) 2021 Sifive.
++ */
++
++#include <linux/init.h>
++#include <linux/cpu.h>
++#include <linux/uaccess.h>
++#include <asm/alternative.h>
++#include <asm/sections.h>
++#include <asm/vendorid_list.h>
++#include <asm/sbi.h>
++#include <asm/csr.h>
++
++static struct cpu_manufacturer_info_t {
++ unsigned long vendor_id;
++ unsigned long arch_id;
++ unsigned long imp_id;
++} cpu_mfr_info;
++
++static void (*vendor_patch_func)(struct alt_entry *begin, struct alt_entry *end,
++ unsigned long archid, unsigned long impid);
++
++static inline void __init riscv_fill_cpu_mfr_info(void)
++{
++#ifdef CONFIG_RISCV_M_MODE
++ cpu_mfr_info.vendor_id = csr_read(CSR_MVENDORID);
++ cpu_mfr_info.arch_id = csr_read(CSR_MARCHID);
++ cpu_mfr_info.imp_id = csr_read(CSR_MIMPID);
++#else
++ cpu_mfr_info.vendor_id = sbi_get_mvendorid();
++ cpu_mfr_info.arch_id = sbi_get_marchid();
++ cpu_mfr_info.imp_id = sbi_get_mimpid();
++#endif
++}
++
++static void __init init_alternative(void)
++{
++ riscv_fill_cpu_mfr_info();
++
++ switch (cpu_mfr_info.vendor_id) {
++ default:
++ vendor_patch_func = NULL;
++ }
++}
++
++/*
++ * This is called very early in the boot process (directly after we run
++ * a feature detect on the boot CPU). No need to worry about other CPUs
++ * here.
++ */
++void __init apply_boot_alternatives(void)
++{
++ /* If called on non-boot cpu things could go wrong */
++ WARN_ON(smp_processor_id() != 0);
++
++ init_alternative();
++
++ if (!vendor_patch_func)
++ return;
++
++ vendor_patch_func((struct alt_entry *)__alt_start,
++ (struct alt_entry *)__alt_end,
++ cpu_mfr_info.arch_id, cpu_mfr_info.imp_id);
++}
++
+diff --git a/arch/riscv/include/asm/alternative-macros.h b/arch/riscv/include/asm/alternative-macros.h
+new file mode 100644
+index 00000000..88c0870
+--- /dev/null
++++ b/arch/riscv/include/asm/alternative-macros.h
+@@ -0,0 +1,142 @@
++/* SPDX-License-Identifier: GPL-2.0 */
++#ifndef __ASM_ALTERNATIVE_MACROS_H
++#define __ASM_ALTERNATIVE_MACROS_H
++
++#ifdef CONFIG_RISCV_ERRATA_ALTERNATIVE
++
++#ifdef __ASSEMBLY__
++
++.macro ALT_ENTRY oldptr newptr vendor_id errata_id new_len
++ RISCV_PTR \oldptr
++ RISCV_PTR \newptr
++ REG_ASM \vendor_id
++ REG_ASM \new_len
++ .word \errata_id
++.endm
++
++.macro ALT_NEW_CONTENT vendor_id, errata_id, enable = 1, new_c : vararg
++ .if \enable
++ .pushsection .alternative, "a"
++ ALT_ENTRY 886b, 888f, \vendor_id, \errata_id, 889f - 888f
++ .popsection
++ .subsection 1
++888 :
++ \new_c
++889 :
++ .previous
++ .org . - (889b - 888b) + (887b - 886b)
++ .org . - (887b - 886b) + (889b - 888b)
++ .endif
++.endm
++
++.macro __ALTERNATIVE_CFG old_c, new_c, vendor_id, errata_id, enable
++886 :
++ \old_c
++887 :
++ ALT_NEW_CONTENT \vendor_id, \errata_id, \enable, \new_c
++.endm
++
++#define _ALTERNATIVE_CFG(old_c, new_c, vendor_id, errata_id, CONFIG_k) \
++ __ALTERNATIVE_CFG old_c, new_c, vendor_id, errata_id, IS_ENABLED(CONFIG_k)
++
++#else /* !__ASSEMBLY__ */
++
++#include <asm/asm.h>
++#include <linux/stringify.h>
++
++#define ALT_ENTRY(oldptr, newptr, vendor_id, errata_id, newlen) \
++ RISCV_PTR " " oldptr "\n" \
++ RISCV_PTR " " newptr "\n" \
++ REG_ASM " " vendor_id "\n" \
++ REG_ASM " " newlen "\n" \
++ ".word " errata_id "\n"
++
++#define ALT_NEW_CONSTENT(vendor_id, errata_id, enable, new_c) \
++ ".if " __stringify(enable) " == 1\n" \
++ ".pushsection .alternative, \"a\"\n" \
++ ALT_ENTRY("886b", "888f", __stringify(vendor_id), __stringify(errata_id), "889f - 888f") \
++ ".popsection\n" \
++ ".subsection 1\n" \
++ "888 :\n" \
++ new_c "\n" \
++ "889 :\n" \
++ ".previous\n" \
++ ".org . - (887b - 886b) + (889b - 888b)\n" \
++ ".org . - (889b - 888b) + (887b - 886b)\n" \
++ ".endif\n"
++
++#define __ALTERNATIVE_CFG(old_c, new_c, vendor_id, errata_id, enable) \
++ "886 :\n" \
++ old_c "\n" \
++ "887 :\n" \
++ ALT_NEW_CONSTENT(vendor_id, errata_id, enable, new_c)
++
++#define _ALTERNATIVE_CFG(old_c, new_c, vendor_id, errata_id, CONFIG_k) \
++ __ALTERNATIVE_CFG(old_c, new_c, vendor_id, errata_id, IS_ENABLED(CONFIG_k))
++
++#endif /* __ASSEMBLY__ */
++
++#else /* !CONFIG_RISCV_ERRATA_ALTERNATIVE*/
++#ifdef __ASSEMBLY__
++
++.macro __ALTERNATIVE_CFG old_c
++ \old_c
++.endm
++
++#define _ALTERNATIVE_CFG(old_c, new_c, vendor_id, errata_id, CONFIG_k) \
++ __ALTERNATIVE_CFG old_c
++
++#else /* !__ASSEMBLY__ */
++
++#define __ALTERNATIVE_CFG(old_c) \
++ old_c "\n"
++
++#define _ALTERNATIVE_CFG(old_c, new_c, vendor_id, errata_id, CONFIG_k) \
++ __ALTERNATIVE_CFG(old_c)
++
++#endif /* __ASSEMBLY__ */
++#endif /* CONFIG_RISCV_ERRATA_ALTERNATIVE */
++/*
++ * Usage:
++ * ALTERNATIVE(old_content, new_content, vendor_id, errata_id, CONFIG_k)
++ * in the assembly code. Otherwise,
++ * asm(ALTERNATIVE(old_content, new_content, vendor_id, errata_id, CONFIG_k));
++ *
++ * old_content: The old content which is probably replaced with new content.
++ * new_content: The new content.
++ * vendor_id: The CPU vendor ID.
++ * errata_id: The errata ID.
++ * CONFIG_k: The Kconfig of this errata. When Kconfig is disabled, the old
++ * content will alwyas be executed.
++ */
++#define ALTERNATIVE(old_content, new_content, vendor_id, errata_id, CONFIG_k) \
++ _ALTERNATIVE_CFG(old_content, new_content, vendor_id, errata_id, CONFIG_k)
++
++/*
++ * A vendor wants to replace an old_content, but another vendor has used
++ * ALTERNATIVE() to patch its customized content at the same location. In
++ * this case, this vendor can create a new macro ALTERNATIVE_2() based
++ * on the following sample code and then replace ALTERNATIVE() with
++ * ALTERNATIVE_2() to append its customized content.
++ *
++ * .macro __ALTERNATIVE_CFG_2 old_c, new_c_1, vendor_id_1, errata_id_1, enable_1, \
++ * new_c_2, vendor_id_2, errata_id_2, enable_2
++ * 886 :
++ * \old_c
++ * 887 :
++ * ALT_NEW_CONTENT \vendor_id_1, \errata_id_1, \enable_1, \new_c_1
++ * ALT_NEW_CONTENT \vendor_id_2, \errata_id_2, \enable_2, \new_c_2
++ * .endm
++ *
++ * #define _ALTERNATIVE_CFG_2(old_c, new_c_1, vendor_id_1, errata_id_1, CONFIG_k_1, \
++ * new_c_2, vendor_id_2, errata_id_2, CONFIG_k_2) \
++ * __ALTERNATIVE_CFG_2 old_c, new_c_1, vendor_id_1, errata_id_1, IS_ENABLED(CONFIG_k_1), \
++ * new_c_2, vendor_id_2, errata_id_2, IS_ENABLED(CONFIG_k_2) \
++ *
++ * #define ALTERNATIVE_2(old_content, new_content_1, vendor_id_1, errata_id_1, CONFIG_k_1, \
++ * new_content_2, vendor_id_2, errata_id_2, CONFIG_k_2) \
++ * _ALTERNATIVE_CFG_2(old_content, new_content_1, vendor_id_1, errata_id_1, CONFIG_k_1, \
++ * new_content_2, vendor_id_2, errata_id_2, CONFIG_k_2)
++ *
++ */
++#endif
+diff --git a/arch/riscv/include/asm/alternative.h b/arch/riscv/include/asm/alternative.h
+new file mode 100644
+index 00000000..430bc4f
+--- /dev/null
++++ b/arch/riscv/include/asm/alternative.h
+@@ -0,0 +1,36 @@
++/* SPDX-License-Identifier: GPL-2.0-only */
++/*
++ * Copyright (C) 2021 Sifive.
++ */
++
++#ifndef __ASM_ALTERNATIVE_H
++#define __ASM_ALTERNATIVE_H
++
++#define ERRATA_STRING_LENGTH_MAX 32
++
++#include <asm/alternative-macros.h>
++
++#ifndef __ASSEMBLY__
++
++#include <linux/init.h>
++#include <linux/types.h>
++#include <linux/stddef.h>
++#include <asm/hwcap.h>
++
++void __init apply_boot_alternatives(void);
++
++struct alt_entry {
++ void *old_ptr; /* address of original instruciton or data */
++ void *alt_ptr; /* address of replacement instruction or data */
++ unsigned long vendor_id; /* cpu vendor id */
++ unsigned long alt_len; /* The replacement size */
++ unsigned int errata_id; /* The errata id */
++} __packed;
++
++struct errata_checkfunc_id {
++ unsigned long vendor_id;
++ bool (*func)(struct alt_entry *alt);
++};
++
++#endif
++#endif
+diff --git a/arch/riscv/include/asm/asm.h b/arch/riscv/include/asm/asm.h
+index 9c992a8..618d7c5 100644
+--- a/arch/riscv/include/asm/asm.h
++++ b/arch/riscv/include/asm/asm.h
+@@ -23,6 +23,7 @@
+ #define REG_L __REG_SEL(ld, lw)
+ #define REG_S __REG_SEL(sd, sw)
+ #define REG_SC __REG_SEL(sc.d, sc.w)
++#define REG_ASM __REG_SEL(.dword, .word)
+ #define SZREG __REG_SEL(8, 4)
+ #define LGREG __REG_SEL(3, 2)
+
+diff --git a/arch/riscv/include/asm/csr.h b/arch/riscv/include/asm/csr.h
+index cec462e..076beb9 100644
+--- a/arch/riscv/include/asm/csr.h
++++ b/arch/riscv/include/asm/csr.h
+@@ -109,6 +109,9 @@
+ #define CSR_MIP 0x344
+ #define CSR_PMPCFG0 0x3a0
+ #define CSR_PMPADDR0 0x3b0
++#define CSR_MVENDORID 0xf11
++#define CSR_MARCHID 0xf12
++#define CSR_MIMPID 0xf13
+ #define CSR_MHARTID 0xf14
+
+ #ifdef CONFIG_RISCV_M_MODE
+diff --git a/arch/riscv/include/asm/errata_list.h b/arch/riscv/include/asm/errata_list.h
+new file mode 100644
+index 00000000..1b56131
+--- /dev/null
++++ b/arch/riscv/include/asm/errata_list.h
+@@ -0,0 +1,12 @@
++/* SPDX-License-Identifier: GPL-2.0-only */
++/*
++ * Copyright (C) 2021 Sifive.
++ */
++#ifndef ASM_ERRATA_LIST_H
++#define ASM_ERRATA_LIST_H
++
++#ifdef CONFIG_ERRATA_SIFIVE
++#define ERRATA_SIFIVE_NUMBER 0
++#endif
++
++#endif
+diff --git a/arch/riscv/include/asm/sections.h b/arch/riscv/include/asm/sections.h
+index 1595c5b..8a303fb 100644
+--- a/arch/riscv/include/asm/sections.h
++++ b/arch/riscv/include/asm/sections.h
+@@ -11,5 +11,6 @@ extern char _start[];
+ extern char _start_kernel[];
+ extern char __init_data_begin[], __init_data_end[];
+ extern char __init_text_begin[], __init_text_end[];
++extern char __alt_start[], __alt_end[];
+
+ #endif /* __ASM_SECTIONS_H */
+diff --git a/arch/riscv/include/asm/vendorid_list.h b/arch/riscv/include/asm/vendorid_list.h
+new file mode 100644
+index 00000000..9d93421
+--- /dev/null
++++ b/arch/riscv/include/asm/vendorid_list.h
+@@ -0,0 +1,10 @@
++/* SPDX-License-Identifier: GPL-2.0-only */
++/*
++ * Copyright (C) 2021 SiFive
++ */
++#ifndef ASM_VENDOR_LIST_H
++#define ASM_VENDOR_LIST_H
++
++#define SIFIVE_VENDOR_ID 0x489
++
++#endif
+diff --git a/arch/riscv/kernel/smpboot.c b/arch/riscv/kernel/smpboot.c
+index 96167d5..79788d2 100644
+--- a/arch/riscv/kernel/smpboot.c
++++ b/arch/riscv/kernel/smpboot.c
+@@ -31,6 +31,7 @@
+ #include <asm/sections.h>
+ #include <asm/sbi.h>
+ #include <asm/smp.h>
++#include <asm/alternative.h>
+
+ #include "head.h"
+
+@@ -39,6 +40,9 @@ static DECLARE_COMPLETION(cpu_running);
+ void __init smp_prepare_boot_cpu(void)
+ {
+ init_cpu_topology();
++#ifdef CONFIG_RISCV_ERRATA_ALTERNATIVE
++ apply_boot_alternatives();
++#endif
+ }
+
+ void __init smp_prepare_cpus(unsigned int max_cpus)
+diff --git a/arch/riscv/kernel/vmlinux.lds.S b/arch/riscv/kernel/vmlinux.lds.S
+index de03cb2..7e61bc1 100644
+--- a/arch/riscv/kernel/vmlinux.lds.S
++++ b/arch/riscv/kernel/vmlinux.lds.S
+@@ -90,6 +90,13 @@ SECTIONS
+ }
+
+ __init_data_end = .;
++
++ . = ALIGN(8);
++ .alternative : {
++ __alt_start = .;
++ *(.alternative)
++ __alt_end = .;
++ }
+ __init_end = .;
+
+ /* Start of data section */
+--
+2.7.4
+
--- /dev/null
+From a56d45ca5b618c553be90591d883747e4cee30e3 Mon Sep 17 00:00:00 2001
+Date: Mon, 22 Mar 2021 22:26:04 +0800
+Subject: [PATCH 14/28] riscv: sifive: Add SiFive alternative ports
+
+Add required ports of the Alternative scheme for SiFive.
+
+---
+ arch/riscv/Kconfig.erratas | 10 ++++++
+ arch/riscv/Kconfig.socs | 1 +
+ arch/riscv/errata/Makefile | 1 +
+ arch/riscv/errata/alternative.c | 5 +++
+ arch/riscv/errata/sifive/Makefile | 1 +
+ arch/riscv/errata/sifive/errata.c | 68 ++++++++++++++++++++++++++++++++++++
+ arch/riscv/include/asm/alternative.h | 3 ++
+ 7 files changed, 89 insertions(+)
+ create mode 100644 arch/riscv/errata/sifive/Makefile
+ create mode 100644 arch/riscv/errata/sifive/errata.c
+
+diff --git a/arch/riscv/Kconfig.erratas b/arch/riscv/Kconfig.erratas
+index 4d0bafc..302e746 100644
+--- a/arch/riscv/Kconfig.erratas
++++ b/arch/riscv/Kconfig.erratas
+@@ -9,4 +9,14 @@ config RISCV_ERRATA_ALTERNATIVE
+ code patching is performed once in the boot stages. It means
+ that the overhead from this mechanism is just taken once.
+
++config ERRATA_SIFIVE
++ bool "SiFive errata"
++ depends on RISCV_ERRATA_ALTERNATIVE
++ help
++ All SiFive errata Kconfig depend on this Kconfig. Disabling
++ this Kconfig will disable all SiFive errata. Please say "Y"
++ here if your platform uses SiFive CPU cores.
++
++ Otherwise, please say "N" here to avoid unnecessary overhead.
++
+ endmenu
+diff --git a/arch/riscv/Kconfig.socs b/arch/riscv/Kconfig.socs
+index 3284d5c..77d18f2 100644
+--- a/arch/riscv/Kconfig.socs
++++ b/arch/riscv/Kconfig.socs
+@@ -7,6 +7,7 @@ config SOC_SIFIVE
+ select CLK_SIFIVE
+ select CLK_SIFIVE_PRCI
+ select SIFIVE_PLIC
++ select ERRATA_SIFIVE
+ help
+ This enables support for SiFive SoC platform hardware.
+
+diff --git a/arch/riscv/errata/Makefile b/arch/riscv/errata/Makefile
+index 43e6d54..b8f8740 100644
+--- a/arch/riscv/errata/Makefile
++++ b/arch/riscv/errata/Makefile
+@@ -1 +1,2 @@
+ obj-y += alternative.o
++obj-$(CONFIG_ERRATA_SIFIVE) += sifive/
+diff --git a/arch/riscv/errata/alternative.c b/arch/riscv/errata/alternative.c
+index 8efa60a..3b15885d 100644
+--- a/arch/riscv/errata/alternative.c
++++ b/arch/riscv/errata/alternative.c
+@@ -42,6 +42,11 @@ static void __init init_alternative(void)
+ riscv_fill_cpu_mfr_info();
+
+ switch (cpu_mfr_info.vendor_id) {
++#ifdef CONFIG_ERRATA_SIFIVE
++ case SIFIVE_VENDOR_ID:
++ vendor_patch_func = sifive_errata_patch_func;
++ break;
++#endif
+ default:
+ vendor_patch_func = NULL;
+ }
+diff --git a/arch/riscv/errata/sifive/Makefile b/arch/riscv/errata/sifive/Makefile
+new file mode 100644
+index 00000000..2d644e1
+--- /dev/null
++++ b/arch/riscv/errata/sifive/Makefile
+@@ -0,0 +1 @@
++obj-y += errata.o
+diff --git a/arch/riscv/errata/sifive/errata.c b/arch/riscv/errata/sifive/errata.c
+new file mode 100644
+index 00000000..826cd39
+--- /dev/null
++++ b/arch/riscv/errata/sifive/errata.c
+@@ -0,0 +1,68 @@
++// SPDX-License-Identifier: GPL-2.0-only
++/*
++ * Copyright (C) 2021 Sifive.
++ */
++
++#include <linux/kernel.h>
++#include <linux/string.h>
++#include <linux/bug.h>
++#include <asm/patch.h>
++#include <asm/alternative.h>
++#include <asm/vendorid_list.h>
++#include <asm/errata_list.h>
++
++struct errata_info_t {
++ char name[ERRATA_STRING_LENGTH_MAX];
++ bool (*check_func)(unsigned long arch_id, unsigned long impid);
++};
++
++static u32 __init sifive_errata_probe(unsigned long archid, unsigned long impid)
++{
++ int idx;
++ u32 cpu_req_errata = 0;
++
++ for (idx = 0; idx < ERRATA_SIFIVE_NUMBER; idx++)
++ if (errata_list[idx].check_func(archid, impid))
++ cpu_req_errata |= (1U << idx);
++
++ return cpu_req_errata;
++}
++
++static void __init warn_miss_errata(u32 miss_errata)
++{
++ int i;
++
++ pr_warn("----------------------------------------------------------------\n");
++ pr_warn("WARNING: Missing the following errata may cause potential issues\n");
++ for (i = 0; i < ERRATA_SIFIVE_NUMBER; i++)
++ if (miss_errata & 0x1 << i)
++ pr_warn("\tSiFive Errata[%d]:%s\n", i, errata_list[i].name);
++ pr_warn("Please enable the corresponding Kconfig to apply them\n");
++ pr_warn("----------------------------------------------------------------\n");
++}
++
++void __init sifive_errata_patch_func(struct alt_entry *begin, struct alt_entry *end,
++ unsigned long archid, unsigned long impid)
++{
++ struct alt_entry *alt;
++ u32 cpu_req_errata = sifive_errata_probe(archid, impid);
++ u32 cpu_apply_errata = 0;
++ u32 tmp;
++
++ for (alt = begin; alt < end; alt++) {
++ if (alt->vendor_id != SIFIVE_VENDOR_ID)
++ continue;
++ if (alt->errata_id >= ERRATA_SIFIVE_NUMBER) {
++ WARN(1, "This errata id:%d is not in kernel errata list", alt->errata_id);
++ continue;
++ }
++
++ tmp = (1U << alt->errata_id);
++ if (cpu_req_errata & tmp) {
++ patch_text_nosync(alt->old_ptr, alt->alt_ptr, alt->alt_len);
++ cpu_apply_errata |= tmp;
++ }
++ }
++ if (cpu_apply_errata != cpu_req_errata)
++ warn_miss_errata(cpu_req_errata - cpu_apply_errata);
++}
+diff --git a/arch/riscv/include/asm/alternative.h b/arch/riscv/include/asm/alternative.h
+index 430bc4f..e625d3ca 100644
+--- a/arch/riscv/include/asm/alternative.h
++++ b/arch/riscv/include/asm/alternative.h
+@@ -32,5 +32,8 @@ struct errata_checkfunc_id {
+ bool (*func)(struct alt_entry *alt);
+ };
+
++void sifive_errata_patch_func(struct alt_entry *begin, struct alt_entry *end,
++ unsigned long archid, unsigned long impid);
++
+ #endif
+ #endif
+--
+2.7.4
+
--- /dev/null
+From ef3d7fb53eff4d043a011bf10e07a77e8ed92736 Mon Sep 17 00:00:00 2001
+Date: Mon, 22 Mar 2021 22:26:05 +0800
+Subject: [PATCH 15/28] riscv: sifive: Apply errata "cip-453" patch
+
+Add sign extension to the $badaddr before addressing the instruction page
+fault and instruction access fault to workaround the issue "cip-453".
+
+To avoid affecting the existing code sequence, this patch will creates two
+trampolines to add sign extension to the $badaddr. By the "alternative"
+mechanism, these two trampolines will replace the original exception
+handler of instruction page fault and instruction access fault in the
+excp_vect_table. In this case, only the specific SiFive CPU core jumps to
+the do_page_fault and do_trap_insn_fault through these two trampolines.
+Other CPUs are not affected.
+
+---
+ arch/riscv/Kconfig.erratas | 11 +++++++++
+ arch/riscv/errata/sifive/Makefile | 1 +
+ arch/riscv/errata/sifive/errata.c | 20 ++++++++++++++++
+ arch/riscv/errata/sifive/errata_cip_453.S | 38 +++++++++++++++++++++++++++++++
+ arch/riscv/include/asm/errata_list.h | 21 ++++++++++++++++-
+ arch/riscv/kernel/entry.S | 6 +++--
+ 6 files changed, 94 insertions(+), 3 deletions(-)
+ create mode 100644 arch/riscv/errata/sifive/errata_cip_453.S
+
+diff --git a/arch/riscv/Kconfig.erratas b/arch/riscv/Kconfig.erratas
+index 302e746..b4146dc 100644
+--- a/arch/riscv/Kconfig.erratas
++++ b/arch/riscv/Kconfig.erratas
+@@ -19,4 +19,15 @@ config ERRATA_SIFIVE
+
+ Otherwise, please say "N" here to avoid unnecessary overhead.
+
++config ERRATA_SIFIVE_CIP_453
++ bool "Apply SiFive errata CIP-453"
++ depends on ERRATA_SIFIVE
++ default y
++ help
++ This will apply the SiFive CIP-453 errata to add sign extension
++ to the $badaddr when exception type is instruction page fault
++ and instruction access fault.
++
++ If you don't know what to do here, say "Y".
++
+ endmenu
+diff --git a/arch/riscv/errata/sifive/Makefile b/arch/riscv/errata/sifive/Makefile
+index 2d644e1..bdd5fc8 100644
+--- a/arch/riscv/errata/sifive/Makefile
++++ b/arch/riscv/errata/sifive/Makefile
+@@ -1 +1,2 @@
++obj-y += errata_cip_453.o
+ obj-y += errata.o
+diff --git a/arch/riscv/errata/sifive/errata.c b/arch/riscv/errata/sifive/errata.c
+index 826cd39..e273918 100644
+--- a/arch/riscv/errata/sifive/errata.c
++++ b/arch/riscv/errata/sifive/errata.c
+@@ -16,6 +16,26 @@ struct errata_info_t {
+ bool (*check_func)(unsigned long arch_id, unsigned long impid);
+ };
+
++static bool errata_cip_453_check_func(unsigned long arch_id, unsigned long impid)
++{
++ /*
++ * Affected cores:
++ * Architecture ID: 0x8000000000000007
++ * Implement ID: 0x20181004 <= impid <= 0x20191105
++ */
++ if (arch_id != 0x8000000000000007 ||
++ (impid < 0x20181004 || impid > 0x20191105))
++ return false;
++ return true;
++}
++
++static struct errata_info_t errata_list[ERRATA_SIFIVE_NUMBER] = {
++ {
++ .name = "cip-453",
++ .check_func = errata_cip_453_check_func
++ },
++};
++
+ static u32 __init sifive_errata_probe(unsigned long archid, unsigned long impid)
+ {
+ int idx;
+diff --git a/arch/riscv/errata/sifive/errata_cip_453.S b/arch/riscv/errata/sifive/errata_cip_453.S
+new file mode 100644
+index 00000000..f1b9623
+--- /dev/null
++++ b/arch/riscv/errata/sifive/errata_cip_453.S
+@@ -0,0 +1,38 @@
++/* SPDX-License-Identifier: GPL-2.0-only */
++/*
++ * Copyright (C) 2021 SiFive
++ */
++
++#include <linux/linkage.h>
++#include <asm/asm.h>
++#include <asm/asm-offsets.h>
++#include <asm/alternative.h>
++
++.macro ADD_SIGN_EXT pt_reg badaddr tmp_reg
++ REG_L \badaddr, PT_BADADDR(\pt_reg)
++ li \tmp_reg,1
++ slli \tmp_reg,\tmp_reg,0x26
++ and \tmp_reg,\tmp_reg,\badaddr
++ beqz \tmp_reg, 1f
++ li \tmp_reg,-1
++ slli \tmp_reg,\tmp_reg,0x27
++ or \badaddr,\tmp_reg,\badaddr
++ REG_S \badaddr, PT_BADADDR(\pt_reg)
++1:
++.endm
++
++ENTRY(sifive_cip_453_page_fault_trp)
++ ADD_SIGN_EXT a0, t0, t1
++#ifdef CONFIG_MMU
++ la t0, do_page_fault
++#else
++ la t0, do_trap_unknown
++#endif
++ jr t0
++END(sifive_cip_453_page_fault_trp)
++
++ENTRY(sifive_cip_453_insn_fault_trp)
++ ADD_SIGN_EXT a0, t0, t1
++ la t0, do_trap_insn_fault
++ jr t0
++END(sifive_cip_453_insn_fault_trp)
+diff --git a/arch/riscv/include/asm/errata_list.h b/arch/riscv/include/asm/errata_list.h
+index 1b56131..6148d34 100644
+--- a/arch/riscv/include/asm/errata_list.h
++++ b/arch/riscv/include/asm/errata_list.h
+@@ -5,8 +5,27 @@
+ #ifndef ASM_ERRATA_LIST_H
+ #define ASM_ERRATA_LIST_H
+
++#include <asm/alternative.h>
++#include <asm/vendorid_list.h>
++
+ #ifdef CONFIG_ERRATA_SIFIVE
+-#define ERRATA_SIFIVE_NUMBER 0
++#define ERRATA_SIFIVE_CIP_453 0
++#define ERRATA_SIFIVE_NUMBER 1
+ #endif
+
++#ifdef __ASSEMBLY__
++
++#define ALT_INSN_FAULT(x) \
++ALTERNATIVE(__stringify(RISCV_PTR do_trap_insn_fault), \
++ __stringify(RISCV_PTR sifive_cip_453_insn_fault_trp), \
++ SIFIVE_VENDOR_ID, ERRATA_SIFIVE_CIP_453, \
++ CONFIG_ERRATA_SIFIVE_CIP_453)
++
++#define ALT_PAGE_FAULT(x) \
++ALTERNATIVE(__stringify(RISCV_PTR do_page_fault), \
++ __stringify(RISCV_PTR sifive_cip_453_page_fault_trp), \
++ SIFIVE_VENDOR_ID, ERRATA_SIFIVE_CIP_453, \
++ CONFIG_ERRATA_SIFIVE_CIP_453)
++#endif /* __ASSEMBLY__ */
++
+ #endif
+diff --git a/arch/riscv/kernel/entry.S b/arch/riscv/kernel/entry.S
+index 744f320..60d0a2f 100644
+--- a/arch/riscv/kernel/entry.S
++++ b/arch/riscv/kernel/entry.S
+@@ -12,6 +12,7 @@
+ #include <asm/unistd.h>
+ #include <asm/thread_info.h>
+ #include <asm/asm-offsets.h>
++#include <asm/errata_list.h>
+
+ #if !IS_ENABLED(CONFIG_PREEMPTION)
+ .set resume_kernel, restore_all
+@@ -450,7 +451,7 @@ ENDPROC(__switch_to)
+ /* Exception vector table */
+ ENTRY(excp_vect_table)
+ RISCV_PTR do_trap_insn_misaligned
+- RISCV_PTR do_trap_insn_fault
++ ALT_INSN_FAULT(RISCV_PTR do_trap_insn_fault)
+ RISCV_PTR do_trap_insn_illegal
+ RISCV_PTR do_trap_break
+ RISCV_PTR do_trap_load_misaligned
+@@ -461,7 +462,8 @@ ENTRY(excp_vect_table)
+ RISCV_PTR do_trap_ecall_s
+ RISCV_PTR do_trap_unknown
+ RISCV_PTR do_trap_ecall_m
+- RISCV_PTR do_page_fault /* instruction page fault */
++ /* instruciton page fault */
++ ALT_PAGE_FAULT(RISCV_PTR do_page_fault)
+ RISCV_PTR do_page_fault /* load page fault */
+ RISCV_PTR do_trap_unknown
+ RISCV_PTR do_page_fault /* store page fault */
+--
+2.7.4
+
--- /dev/null
+From 00238b2b634a61b51f7aa1433786d1f8473fa94e Mon Sep 17 00:00:00 2001
+Date: Mon, 22 Mar 2021 22:26:06 +0800
+Subject: [PATCH 16/28] riscv: sifive: Apply errata "cip-1200" patch
+
+For certain SiFive CPUs, "sfence.vma addr" cannot exactly flush addr
+from TLB in the particular cases. The details could be found here:
+https://sifive.cdn.prismic.io/sifive/167a1a56-03f4-4615-a79e-b2a86153148f_FU740_errata_20210205.pdf
+In order to ensure the functionality, this patch uses the Alternative
+scheme to replace all "sfence.vma addr" with "sfence.vma" at runtime.
+
+---
+ arch/riscv/Kconfig.erratas | 11 +++++++++++
+ arch/riscv/errata/sifive/errata.c | 18 ++++++++++++++++++
+ arch/riscv/include/asm/errata_list.h | 10 +++++++++-
+ arch/riscv/include/asm/tlbflush.h | 3 ++-
+ 4 files changed, 40 insertions(+), 2 deletions(-)
+
+diff --git a/arch/riscv/Kconfig.erratas b/arch/riscv/Kconfig.erratas
+index b4146dc..d5d03ae 100644
+--- a/arch/riscv/Kconfig.erratas
++++ b/arch/riscv/Kconfig.erratas
+@@ -30,4 +30,15 @@ config ERRATA_SIFIVE_CIP_453
+
+ If you don't know what to do here, say "Y".
+
++config ERRATA_SIFIVE_CIP_1200
++ bool "Apply SiFive errata CIP-1200"
++ depends on ERRATA_SIFIVE
++ default y
++ help
++ This will apply the SiFive CIP-1200 errata to repalce all
++ "sfence.vma addr" with "sfence.vma" to ensure that the addr
++ has been flushed from TLB.
++
++ If you don't know what to do here, say "Y".
++
+ endmenu
+diff --git a/arch/riscv/errata/sifive/errata.c b/arch/riscv/errata/sifive/errata.c
+index e273918..f5e5ae7 100644
+--- a/arch/riscv/errata/sifive/errata.c
++++ b/arch/riscv/errata/sifive/errata.c
+@@ -29,11 +29,29 @@ static bool errata_cip_453_check_func(unsigned long arch_id, unsigned long impi
+ return true;
+ }
+
++static bool errata_cip_1200_check_func(unsigned long arch_id, unsigned long impid)
++{
++ /*
++ * Affected cores:
++ * Architecture ID: 0x8000000000000007 or 0x1
++ * Implement ID: mimpid[23:0] <= 0x200630 and mimpid != 0x01200626
++ */
++ if (arch_id != 0x8000000000000007 && arch_id != 0x1)
++ return false;
++ if ((impid & 0xffffff) > 0x200630 || impid == 0x1200626)
++ return false;
++ return true;
++}
++
+ static struct errata_info_t errata_list[ERRATA_SIFIVE_NUMBER] = {
+ {
+ .name = "cip-453",
+ .check_func = errata_cip_453_check_func
+ },
++ {
++ .name = "cip-1200",
++ .check_func = errata_cip_1200_check_func
++ },
+ };
+
+ static u32 __init sifive_errata_probe(unsigned long archid, unsigned long impid)
+diff --git a/arch/riscv/include/asm/errata_list.h b/arch/riscv/include/asm/errata_list.h
+index 6148d34..5f1046e 100644
+--- a/arch/riscv/include/asm/errata_list.h
++++ b/arch/riscv/include/asm/errata_list.h
+@@ -10,7 +10,8 @@
+
+ #ifdef CONFIG_ERRATA_SIFIVE
+ #define ERRATA_SIFIVE_CIP_453 0
+-#define ERRATA_SIFIVE_NUMBER 1
++#define ERRATA_SIFIVE_CIP_1200 1
++#define ERRATA_SIFIVE_NUMBER 2
+ #endif
+
+ #ifdef __ASSEMBLY__
+@@ -26,6 +27,13 @@ ALTERNATIVE(__stringify(RISCV_PTR do_page_fault), \
+ __stringify(RISCV_PTR sifive_cip_453_page_fault_trp), \
+ SIFIVE_VENDOR_ID, ERRATA_SIFIVE_CIP_453, \
+ CONFIG_ERRATA_SIFIVE_CIP_453)
++#else /* !__ASSEMBLY__ */
++
++#define ALT_FLUSH_TLB_PAGE(x) \
++asm(ALTERNATIVE("sfence.vma %0", "sfence.vma", SIFIVE_VENDOR_ID, \
++ ERRATA_SIFIVE_CIP_1200, CONFIG_ERRATA_SIFIVE_CIP_1200) \
++ : : "r" (addr) : "memory")
++
+ #endif /* __ASSEMBLY__ */
+
+ #endif
+diff --git a/arch/riscv/include/asm/tlbflush.h b/arch/riscv/include/asm/tlbflush.h
+index 394cfbc..c84218a 100644
+--- a/arch/riscv/include/asm/tlbflush.h
++++ b/arch/riscv/include/asm/tlbflush.h
+@@ -9,6 +9,7 @@
+
+ #include <linux/mm_types.h>
+ #include <asm/smp.h>
++#include <asm/errata_list.h>
+
+ #ifdef CONFIG_MMU
+ static inline void local_flush_tlb_all(void)
+@@ -19,7 +20,7 @@ static inline void local_flush_tlb_all(void)
+ /* Flush one page from local TLB */
+ static inline void local_flush_tlb_page(unsigned long addr)
+ {
+- __asm__ __volatile__ ("sfence.vma %0" : : "r" (addr) : "memory");
++ ALT_FLUSH_TLB_PAGE(__asm__ __volatile__ ("sfence.vma %0" : : "r" (addr) : "memory"));
+ }
+ #else /* CONFIG_MMU */
+ #define local_flush_tlb_all() do { } while (0)
+--
+2.7.4
+
--- /dev/null
+From 1b27caf83ab572e422069caa8217391f7fbcb7e3 Mon Sep 17 00:00:00 2001
+Date: Tue, 6 Apr 2021 17:26:29 +0800
+Subject: [PATCH 17/28] clk: sifive: Add pcie_aux clock in prci driver for PCIe
+ driver
+
+We add pcie_aux clock in this patch so that pcie driver can use
+clk_prepare_enable() and clk_disable_unprepare() to enable and disable
+pcie_aux clock.
+
+---
+ drivers/clk/sifive/fu740-prci.c | 11 +++++++
+ drivers/clk/sifive/fu740-prci.h | 2 +-
+ drivers/clk/sifive/sifive-prci.c | 41 +++++++++++++++++++++++++++
+ drivers/clk/sifive/sifive-prci.h | 9 ++++++
+ include/dt-bindings/clock/sifive-fu740-prci.h | 1 +
+ 5 files changed, 63 insertions(+), 1 deletion(-)
+
+diff --git a/drivers/clk/sifive/fu740-prci.c b/drivers/clk/sifive/fu740-prci.c
+index 764d109..53f6e00 100644
+--- a/drivers/clk/sifive/fu740-prci.c
++++ b/drivers/clk/sifive/fu740-prci.c
+@@ -72,6 +72,12 @@ static const struct clk_ops sifive_fu740_prci_hfpclkplldiv_clk_ops = {
+ .recalc_rate = sifive_prci_hfpclkplldiv_recalc_rate,
+ };
+
++static const struct clk_ops sifive_fu740_prci_pcie_aux_clk_ops = {
++ .enable = sifive_prci_pcie_aux_clock_enable,
++ .disable = sifive_prci_pcie_aux_clock_disable,
++ .is_enabled = sifive_prci_pcie_aux_clock_is_enabled,
++};
++
+ /* List of clock controls provided by the PRCI */
+ struct __prci_clock __prci_init_clocks_fu740[] = {
+ [PRCI_CLK_COREPLL] = {
+@@ -120,4 +126,9 @@ struct __prci_clock __prci_init_clocks_fu740[] = {
+ .parent_name = "hfpclkpll",
+ .ops = &sifive_fu740_prci_hfpclkplldiv_clk_ops,
+ },
++ [PRCI_CLK_PCIE_AUX] = {
++ .name = "pcie_aux",
++ .parent_name = "hfclk",
++ .ops = &sifive_fu740_prci_pcie_aux_clk_ops,
++ },
+ };
+diff --git a/drivers/clk/sifive/fu740-prci.h b/drivers/clk/sifive/fu740-prci.h
+index 13ef971f7..511a0bf 100644
+--- a/drivers/clk/sifive/fu740-prci.h
++++ b/drivers/clk/sifive/fu740-prci.h
+@@ -9,7 +9,7 @@
+
+ #include "sifive-prci.h"
+
+-#define NUM_CLOCK_FU740 8
++#define NUM_CLOCK_FU740 9
+
+ extern struct __prci_clock __prci_init_clocks_fu740[NUM_CLOCK_FU740];
+
+diff --git a/drivers/clk/sifive/sifive-prci.c b/drivers/clk/sifive/sifive-prci.c
+index c78b042..8fdba5d 100644
+--- a/drivers/clk/sifive/sifive-prci.c
++++ b/drivers/clk/sifive/sifive-prci.c
+@@ -448,6 +448,47 @@ void sifive_prci_hfpclkpllsel_use_hfpclkpll(struct __prci_data *pd)
+ r = __prci_readl(pd, PRCI_HFPCLKPLLSEL_OFFSET); /* barrier */
+ }
+
++/* PCIE AUX clock APIs for enable, disable. */
++int sifive_prci_pcie_aux_clock_is_enabled(struct clk_hw *hw)
++{
++ struct __prci_clock *pc = clk_hw_to_prci_clock(hw);
++ struct __prci_data *pd = pc->pd;
++ u32 r;
++
++ r = __prci_readl(pd, PRCI_PCIE_AUX_OFFSET);
++
++ if (r & PRCI_PCIE_AUX_EN_MASK)
++ return 1;
++ else
++ return 0;
++}
++
++int sifive_prci_pcie_aux_clock_enable(struct clk_hw *hw)
++{
++ struct __prci_clock *pc = clk_hw_to_prci_clock(hw);
++ struct __prci_data *pd = pc->pd;
++ u32 r __maybe_unused;
++
++ if (sifive_prci_pcie_aux_clock_is_enabled(hw))
++ return 0;
++
++ __prci_writel(1, PRCI_PCIE_AUX_OFFSET, pd);
++ r = __prci_readl(pd, PRCI_PCIE_AUX_OFFSET); /* barrier */
++
++ return 0;
++}
++
++void sifive_prci_pcie_aux_clock_disable(struct clk_hw *hw)
++{
++ struct __prci_clock *pc = clk_hw_to_prci_clock(hw);
++ struct __prci_data *pd = pc->pd;
++ u32 r __maybe_unused;
++
++ __prci_writel(0, PRCI_PCIE_AUX_OFFSET, pd);
++ r = __prci_readl(pd, PRCI_PCIE_AUX_OFFSET); /* barrier */
++
++}
++
+ /**
+ * __prci_register_clocks() - register clock controls in the PRCI
+ * @dev: Linux struct device
+diff --git a/drivers/clk/sifive/sifive-prci.h b/drivers/clk/sifive/sifive-prci.h
+index dbdbd17..022c67c 100644
+--- a/drivers/clk/sifive/sifive-prci.h
++++ b/drivers/clk/sifive/sifive-prci.h
+@@ -67,6 +67,11 @@
+ #define PRCI_DDRPLLCFG1_CKE_SHIFT 31
+ #define PRCI_DDRPLLCFG1_CKE_MASK (0x1 << PRCI_DDRPLLCFG1_CKE_SHIFT)
+
++/* PCIEAUX */
++#define PRCI_PCIE_AUX_OFFSET 0x14
++#define PRCI_PCIE_AUX_EN_SHIFT 0
++#define PRCI_PCIE_AUX_EN_MASK (0x1 << PRCI_PCIE_AUX_EN_SHIFT)
++
+ /* GEMGXLPLLCFG0 */
+ #define PRCI_GEMGXLPLLCFG0_OFFSET 0x1c
+ #define PRCI_GEMGXLPLLCFG0_DIVR_SHIFT 0
+@@ -296,4 +301,8 @@ unsigned long sifive_prci_tlclksel_recalc_rate(struct clk_hw *hw,
+ unsigned long sifive_prci_hfpclkplldiv_recalc_rate(struct clk_hw *hw,
+ unsigned long parent_rate);
+
++int sifive_prci_pcie_aux_clock_is_enabled(struct clk_hw *hw);
++int sifive_prci_pcie_aux_clock_enable(struct clk_hw *hw);
++void sifive_prci_pcie_aux_clock_disable(struct clk_hw *hw);
++
+ #endif /* __SIFIVE_CLK_SIFIVE_PRCI_H */
+diff --git a/include/dt-bindings/clock/sifive-fu740-prci.h b/include/dt-bindings/clock/sifive-fu740-prci.h
+index cd7706e..7899b7f 100644
+--- a/include/dt-bindings/clock/sifive-fu740-prci.h
++++ b/include/dt-bindings/clock/sifive-fu740-prci.h
+@@ -19,5 +19,6 @@
+ #define PRCI_CLK_CLTXPLL 5
+ #define PRCI_CLK_TLCLK 6
+ #define PRCI_CLK_PCLK 7
++#define PRCI_CLK_PCIE_AUX 8
+
+ #endif /* __DT_BINDINGS_CLOCK_SIFIVE_FU740_PRCI_H */
+--
+2.7.4
+
--- /dev/null
+From e52c5adad77711186c6d8a0e972ec3302bb69d63 Mon Sep 17 00:00:00 2001
+Date: Tue, 6 Apr 2021 17:26:30 +0800
+Subject: [PATCH 18/28] clk: sifive: Use reset-simple in prci driver for PCIe
+ driver
+
+We use reset-simple in this patch so that pcie driver can use
+devm_reset_control_get() to get this reset data structure and use
+reset_control_deassert() to deassert pcie_power_up_rst_n.
+
+---
+ drivers/clk/sifive/Kconfig | 2 ++
+ drivers/clk/sifive/sifive-prci.c | 13 +++++++++++++
+ drivers/clk/sifive/sifive-prci.h | 4 ++++
+ drivers/reset/Kconfig | 1 +
+ 4 files changed, 20 insertions(+)
+
+diff --git a/drivers/clk/sifive/Kconfig b/drivers/clk/sifive/Kconfig
+index 1c14eb2..9132c3c 100644
+--- a/drivers/clk/sifive/Kconfig
++++ b/drivers/clk/sifive/Kconfig
+@@ -10,6 +10,8 @@ if CLK_SIFIVE
+
+ config CLK_SIFIVE_PRCI
+ bool "PRCI driver for SiFive SoCs"
++ select RESET_CONTROLLER
++ select RESET_SIMPLE
+ select CLK_ANALOGBITS_WRPLL_CLN28HPC
+ help
+ Supports the Power Reset Clock interface (PRCI) IP block found in
+diff --git a/drivers/clk/sifive/sifive-prci.c b/drivers/clk/sifive/sifive-prci.c
+index 8fdba5d..0704fdd 100644
+--- a/drivers/clk/sifive/sifive-prci.c
++++ b/drivers/clk/sifive/sifive-prci.c
+@@ -583,6 +583,19 @@ static int sifive_prci_probe(struct platform_device *pdev)
+ if (IS_ERR(pd->va))
+ return PTR_ERR(pd->va);
+
++ pd->reset.rcdev.owner = THIS_MODULE;
++ pd->reset.rcdev.nr_resets = PRCI_RST_NR;
++ pd->reset.rcdev.ops = &reset_simple_ops;
++ pd->reset.rcdev.of_node = pdev->dev.of_node;
++ pd->reset.active_low = true;
++ pd->reset.membase = pd->va + PRCI_DEVICESRESETREG_OFFSET;
++ spin_lock_init(&pd->reset.lock);
++
++ r = devm_reset_controller_register(&pdev->dev, &pd->reset.rcdev);
++ if (r) {
++ dev_err(dev, "could not register reset controller: %d\n", r);
++ return r;
++ }
+ r = __prci_register_clocks(dev, pd, desc);
+ if (r) {
+ dev_err(dev, "could not register clocks: %d\n", r);
+diff --git a/drivers/clk/sifive/sifive-prci.h b/drivers/clk/sifive/sifive-prci.h
+index 022c67c..91658a8 100644
+--- a/drivers/clk/sifive/sifive-prci.h
++++ b/drivers/clk/sifive/sifive-prci.h
+@@ -11,6 +11,7 @@
+
+ #include <linux/clk/analogbits-wrpll-cln28hpc.h>
+ #include <linux/clk-provider.h>
++#include <linux/reset/reset-simple.h>
+ #include <linux/platform_device.h>
+
+ /*
+@@ -121,6 +122,8 @@
+ #define PRCI_DEVICESRESETREG_CHIPLINK_RST_N_MASK \
+ (0x1 << PRCI_DEVICESRESETREG_CHIPLINK_RST_N_SHIFT)
+
++#define PRCI_RST_NR 7
++
+ /* CLKMUXSTATUSREG */
+ #define PRCI_CLKMUXSTATUSREG_OFFSET 0x2c
+ #define PRCI_CLKMUXSTATUSREG_TLCLKSEL_STATUS_SHIFT 1
+@@ -221,6 +224,7 @@
+ */
+ struct __prci_data {
+ void __iomem *va;
++ struct reset_simple_data reset;
+ struct clk_hw_onecell_data hw_clks;
+ };
+
+diff --git a/drivers/reset/Kconfig b/drivers/reset/Kconfig
+index 71ab75a..d0f5d0a 100644
+--- a/drivers/reset/Kconfig
++++ b/drivers/reset/Kconfig
+@@ -187,6 +187,7 @@ config RESET_SIMPLE
+ - RCC reset controller in STM32 MCUs
+ - Allwinner SoCs
+ - ZTE's zx2967 family
++ - SiFive FU740 SoCs
+
+ config RESET_STM32MP157
+ bool "STM32MP157 Reset Driver" if COMPILE_TEST
+--
+2.7.4
+
--- /dev/null
+From e59df5889b82f239eb324e81599108ae75584438 Mon Sep 17 00:00:00 2001
+Date: Tue, 6 Apr 2021 17:26:33 +0800
+Subject: [PATCH 21/28] PCI: fu740: Add SiFive FU740 PCIe host controller
+ driver
+
+Add driver for the SiFive FU740 PCIe host controller.
+This controller is based on the DesignWare PCIe core.
+
+---
+ drivers/pci/controller/dwc/Kconfig | 9 +
+ drivers/pci/controller/dwc/Makefile | 1 +
+ drivers/pci/controller/dwc/pcie-fu740.c | 308 ++++++++++++++++++++++++++++++++
+ 3 files changed, 318 insertions(+)
+ create mode 100644 drivers/pci/controller/dwc/pcie-fu740.c
+
+diff --git a/drivers/pci/controller/dwc/Kconfig b/drivers/pci/controller/dwc/Kconfig
+index 22c5529..0a37d21 100644
+--- a/drivers/pci/controller/dwc/Kconfig
++++ b/drivers/pci/controller/dwc/Kconfig
+@@ -318,4 +318,13 @@ config PCIE_AL
+ required only for DT-based platforms. ACPI platforms with the
+ Annapurna Labs PCIe controller don't need to enable this.
+
++config PCIE_FU740
++ bool "SiFive FU740 PCIe host controller"
++ depends on PCI_MSI_IRQ_DOMAIN
++ depends on SOC_SIFIVE || COMPILE_TEST
++ select PCIE_DW_HOST
++ help
++ Say Y here if you want PCIe controller support for the SiFive
++ FU740.
++
+ endmenu
+diff --git a/drivers/pci/controller/dwc/Makefile b/drivers/pci/controller/dwc/Makefile
+index a751553..625f6aa 100644
+--- a/drivers/pci/controller/dwc/Makefile
++++ b/drivers/pci/controller/dwc/Makefile
+@@ -5,6 +5,7 @@ obj-$(CONFIG_PCIE_DW_EP) += pcie-designware-ep.o
+ obj-$(CONFIG_PCIE_DW_PLAT) += pcie-designware-plat.o
+ obj-$(CONFIG_PCI_DRA7XX) += pci-dra7xx.o
+ obj-$(CONFIG_PCI_EXYNOS) += pci-exynos.o
++obj-$(CONFIG_PCIE_FU740) += pcie-fu740.o
+ obj-$(CONFIG_PCI_IMX6) += pci-imx6.o
+ obj-$(CONFIG_PCIE_SPEAR13XX) += pcie-spear13xx.o
+ obj-$(CONFIG_PCI_KEYSTONE) += pci-keystone.o
+diff --git a/drivers/pci/controller/dwc/pcie-fu740.c b/drivers/pci/controller/dwc/pcie-fu740.c
+new file mode 100644
+index 00000000..f8abb08
+--- /dev/null
++++ b/drivers/pci/controller/dwc/pcie-fu740.c
+@@ -0,0 +1,308 @@
++// SPDX-License-Identifier: GPL-2.0
++/*
++ * FU740 DesignWare PCIe Controller integration
++ * Copyright (C) 2019-2021 SiFive, Inc.
++ * Paul Walmsley
++ * Greentime Hu
++ *
++ * Based in part on the i.MX6 PCIe host controller shim which is:
++ *
++ * Copyright (C) 2013 Kosagi
++ * https://www.kosagi.com
++ */
++
++#include <linux/clk.h>
++#include <linux/delay.h>
++#include <linux/gpio.h>
++#include <linux/kernel.h>
++#include <linux/mfd/syscon.h>
++#include <linux/module.h>
++#include <linux/pci.h>
++#include <linux/platform_device.h>
++#include <linux/regulator/consumer.h>
++#include <linux/resource.h>
++#include <linux/types.h>
++#include <linux/interrupt.h>
++#include <linux/iopoll.h>
++#include <linux/reset.h>
++
++#include "pcie-designware.h"
++
++#define to_fu740_pcie(x) dev_get_drvdata((x)->dev)
++
++struct fu740_pcie {
++ struct dw_pcie pci;
++ void __iomem *mgmt_base;
++ struct gpio_desc *reset;
++ struct gpio_desc *pwren;
++ struct clk *pcie_aux;
++ struct reset_control *rst;
++};
++
++#define SIFIVE_DEVICESRESETREG 0x28
++
++#define PCIEX8MGMT_PERST_N 0x0
++#define PCIEX8MGMT_APP_LTSSM_ENABLE 0x10
++#define PCIEX8MGMT_APP_HOLD_PHY_RST 0x18
++#define PCIEX8MGMT_DEVICE_TYPE 0x708
++#define PCIEX8MGMT_PHY0_CR_PARA_ADDR 0x860
++#define PCIEX8MGMT_PHY0_CR_PARA_RD_EN 0x870
++#define PCIEX8MGMT_PHY0_CR_PARA_RD_DATA 0x878
++#define PCIEX8MGMT_PHY0_CR_PARA_SEL 0x880
++#define PCIEX8MGMT_PHY0_CR_PARA_WR_DATA 0x888
++#define PCIEX8MGMT_PHY0_CR_PARA_WR_EN 0x890
++#define PCIEX8MGMT_PHY0_CR_PARA_ACK 0x898
++#define PCIEX8MGMT_PHY1_CR_PARA_ADDR 0x8a0
++#define PCIEX8MGMT_PHY1_CR_PARA_RD_EN 0x8b0
++#define PCIEX8MGMT_PHY1_CR_PARA_RD_DATA 0x8b8
++#define PCIEX8MGMT_PHY1_CR_PARA_SEL 0x8c0
++#define PCIEX8MGMT_PHY1_CR_PARA_WR_DATA 0x8c8
++#define PCIEX8MGMT_PHY1_CR_PARA_WR_EN 0x8d0
++#define PCIEX8MGMT_PHY1_CR_PARA_ACK 0x8d8
++
++#define PCIEX8MGMT_PHY_CDR_TRACK_EN BIT(0)
++#define PCIEX8MGMT_PHY_LOS_THRSHLD BIT(5)
++#define PCIEX8MGMT_PHY_TERM_EN BIT(9)
++#define PCIEX8MGMT_PHY_TERM_ACDC BIT(10)
++#define PCIEX8MGMT_PHY_EN BIT(11)
++#define PCIEX8MGMT_PHY_INIT_VAL (PCIEX8MGMT_PHY_CDR_TRACK_EN|\
++ PCIEX8MGMT_PHY_LOS_THRSHLD|\
++ PCIEX8MGMT_PHY_TERM_EN|\
++ PCIEX8MGMT_PHY_TERM_ACDC|\
++ PCIEX8MGMT_PHY_EN)
++
++#define PCIEX8MGMT_PHY_LANEN_DIG_ASIC_RX_OVRD_IN_3 0x1008
++#define PCIEX8MGMT_PHY_LANE_OFF 0x100
++#define PCIEX8MGMT_PHY_LANE0_BASE (PCIEX8MGMT_PHY_LANEN_DIG_ASIC_RX_OVRD_IN_3 + 0x100 * 0)
++#define PCIEX8MGMT_PHY_LANE1_BASE (PCIEX8MGMT_PHY_LANEN_DIG_ASIC_RX_OVRD_IN_3 + 0x100 * 1)
++#define PCIEX8MGMT_PHY_LANE2_BASE (PCIEX8MGMT_PHY_LANEN_DIG_ASIC_RX_OVRD_IN_3 + 0x100 * 2)
++#define PCIEX8MGMT_PHY_LANE3_BASE (PCIEX8MGMT_PHY_LANEN_DIG_ASIC_RX_OVRD_IN_3 + 0x100 * 3)
++
++static void fu740_pcie_assert_reset(struct fu740_pcie *afp)
++{
++ /* Assert PERST_N GPIO */
++ gpiod_set_value_cansleep(afp->reset, 0);
++ /* Assert controller PERST_N */
++ writel_relaxed(0x0, afp->mgmt_base + PCIEX8MGMT_PERST_N);
++}
++
++static void fu740_pcie_deassert_reset(struct fu740_pcie *afp)
++{
++ /* Deassert controller PERST_N */
++ writel_relaxed(0x1, afp->mgmt_base + PCIEX8MGMT_PERST_N);
++ /* Deassert PERST_N GPIO */
++ gpiod_set_value_cansleep(afp->reset, 1);
++}
++
++static void fu740_pcie_power_on(struct fu740_pcie *afp)
++{
++ gpiod_set_value_cansleep(afp->pwren, 1);
++ /*
++ * Ensure that PERST has been asserted for at least 100 ms.
++ * Section 2.2 of PCI Express Card Electromechanical Specification
++ * Revision 3.0
++ */
++ msleep(100);
++}
++
++static void fu740_pcie_drive_reset(struct fu740_pcie *afp)
++{
++ fu740_pcie_assert_reset(afp);
++ fu740_pcie_power_on(afp);
++ fu740_pcie_deassert_reset(afp);
++}
++
++static void fu740_phyregwrite(const uint8_t phy, const uint16_t addr,
++ const uint16_t wrdata, struct fu740_pcie *afp)
++{
++ struct device *dev = afp->pci.dev;
++ void __iomem *phy_cr_para_addr;
++ void __iomem *phy_cr_para_wr_data;
++ void __iomem *phy_cr_para_wr_en;
++ void __iomem *phy_cr_para_ack;
++ int ret, val;
++
++ /* Setup */
++ if (phy) {
++ phy_cr_para_addr = afp->mgmt_base + PCIEX8MGMT_PHY1_CR_PARA_ADDR;
++ phy_cr_para_wr_data = afp->mgmt_base + PCIEX8MGMT_PHY1_CR_PARA_WR_DATA;
++ phy_cr_para_wr_en = afp->mgmt_base + PCIEX8MGMT_PHY1_CR_PARA_WR_EN;
++ phy_cr_para_ack = afp->mgmt_base + PCIEX8MGMT_PHY1_CR_PARA_ACK;
++ } else {
++ phy_cr_para_addr = afp->mgmt_base + PCIEX8MGMT_PHY0_CR_PARA_ADDR;
++ phy_cr_para_wr_data = afp->mgmt_base + PCIEX8MGMT_PHY0_CR_PARA_WR_DATA;
++ phy_cr_para_wr_en = afp->mgmt_base + PCIEX8MGMT_PHY0_CR_PARA_WR_EN;
++ phy_cr_para_ack = afp->mgmt_base + PCIEX8MGMT_PHY0_CR_PARA_ACK;
++ }
++
++ writel_relaxed(addr, phy_cr_para_addr);
++ writel_relaxed(wrdata, phy_cr_para_wr_data);
++ writel_relaxed(1, phy_cr_para_wr_en);
++
++ /* Wait for wait_idle */
++ ret = readl_poll_timeout(phy_cr_para_ack, val, val, 10, 5000);
++ if (ret)
++ dev_warn(dev, "Wait for wait_idle state failed!\n");
++
++ /* Clear */
++ writel_relaxed(0, phy_cr_para_wr_en);
++
++ /* Wait for ~wait_idle */
++ ret = readl_poll_timeout(phy_cr_para_ack, val, !val, 10, 5000);
++ if (ret)
++ dev_warn(dev, "Wait for !wait_idle state failed!\n");
++}
++
++static void fu740_pcie_init_phy(struct fu740_pcie *afp)
++{
++ /* Enable phy cr_para_sel interfaces */
++ writel_relaxed(0x1, afp->mgmt_base + PCIEX8MGMT_PHY0_CR_PARA_SEL);
++ writel_relaxed(0x1, afp->mgmt_base + PCIEX8MGMT_PHY1_CR_PARA_SEL);
++
++ /*
++ * Wait 10 cr_para cycles to guarantee that the registers are ready
++ * to be edited.
++ */
++ ndelay(10);
++
++ /* Set PHY AC termination mode */
++ fu740_phyregwrite(0, PCIEX8MGMT_PHY_LANE0_BASE, PCIEX8MGMT_PHY_INIT_VAL, afp);
++ fu740_phyregwrite(0, PCIEX8MGMT_PHY_LANE1_BASE, PCIEX8MGMT_PHY_INIT_VAL, afp);
++ fu740_phyregwrite(0, PCIEX8MGMT_PHY_LANE2_BASE, PCIEX8MGMT_PHY_INIT_VAL, afp);
++ fu740_phyregwrite(0, PCIEX8MGMT_PHY_LANE3_BASE, PCIEX8MGMT_PHY_INIT_VAL, afp);
++ fu740_phyregwrite(1, PCIEX8MGMT_PHY_LANE0_BASE, PCIEX8MGMT_PHY_INIT_VAL, afp);
++ fu740_phyregwrite(1, PCIEX8MGMT_PHY_LANE1_BASE, PCIEX8MGMT_PHY_INIT_VAL, afp);
++ fu740_phyregwrite(1, PCIEX8MGMT_PHY_LANE2_BASE, PCIEX8MGMT_PHY_INIT_VAL, afp);
++ fu740_phyregwrite(1, PCIEX8MGMT_PHY_LANE3_BASE, PCIEX8MGMT_PHY_INIT_VAL, afp);
++}
++
++static int fu740_pcie_start_link(struct dw_pcie *pci)
++{
++ struct device *dev = pci->dev;
++ struct fu740_pcie *afp = dev_get_drvdata(dev);
++
++ /* Enable LTSSM */
++ writel_relaxed(0x1, afp->mgmt_base + PCIEX8MGMT_APP_LTSSM_ENABLE);
++ return 0;
++}
++
++static int fu740_pcie_host_init(struct pcie_port *pp)
++{
++ struct dw_pcie *pci = to_dw_pcie_from_pp(pp);
++ struct fu740_pcie *afp = to_fu740_pcie(pci);
++ struct device *dev = pci->dev;
++ int ret;
++
++ /* Power on reset */
++ fu740_pcie_drive_reset(afp);
++
++ /* Enable pcieauxclk */
++ ret = clk_prepare_enable(afp->pcie_aux);
++ if (ret) {
++ dev_err(dev, "unable to enable pcie_aux clock\n");
++ return ret;
++ }
++
++ /*
++ * Assert hold_phy_rst (hold the controller LTSSM in reset after
++ * power_up_rst_n for register programming with cr_para)
++ */
++ writel_relaxed(0x1, afp->mgmt_base + PCIEX8MGMT_APP_HOLD_PHY_RST);
++
++ /* Deassert power_up_rst_n */
++ ret = reset_control_deassert(afp->rst);
++ if (ret) {
++ dev_err(dev, "unable to deassert pcie_power_up_rst_n\n");
++ return ret;
++ }
++
++ fu740_pcie_init_phy(afp);
++
++ /* Disable pcieauxclk */
++ clk_disable_unprepare(afp->pcie_aux);
++ /* Clear hold_phy_rst */
++ writel_relaxed(0x0, afp->mgmt_base + PCIEX8MGMT_APP_HOLD_PHY_RST);
++ /* Enable pcieauxclk */
++ ret = clk_prepare_enable(afp->pcie_aux);
++ /* Set RC mode */
++ writel_relaxed(0x4, afp->mgmt_base + PCIEX8MGMT_DEVICE_TYPE);
++
++ return 0;
++}
++
++static const struct dw_pcie_host_ops fu740_pcie_host_ops = {
++ .host_init = fu740_pcie_host_init,
++};
++
++static const struct dw_pcie_ops dw_pcie_ops = {
++ .start_link = fu740_pcie_start_link,
++};
++
++static int fu740_pcie_probe(struct platform_device *pdev)
++{
++ struct device *dev = &pdev->dev;
++ struct dw_pcie *pci;
++ struct fu740_pcie *afp;
++
++ afp = devm_kzalloc(dev, sizeof(*afp), GFP_KERNEL);
++ if (!afp)
++ return -ENOMEM;
++ pci = &afp->pci;
++ pci->dev = dev;
++ pci->ops = &dw_pcie_ops;
++ pci->pp.ops = &fu740_pcie_host_ops;
++
++ /* SiFive specific region: mgmt */
++ afp->mgmt_base = devm_platform_ioremap_resource_byname(pdev, "mgmt");
++ if (IS_ERR(afp->mgmt_base))
++ return PTR_ERR(afp->mgmt_base);
++
++ /* Fetch GPIOs */
++ afp->reset = devm_gpiod_get_optional(dev, "reset-gpios", GPIOD_OUT_LOW);
++ if (IS_ERR(afp->reset))
++ return dev_err_probe(dev, PTR_ERR(afp->reset), "unable to get reset-gpios\n");
++
++ afp->pwren = devm_gpiod_get_optional(dev, "pwren-gpios", GPIOD_OUT_LOW);
++ if (IS_ERR(afp->pwren))
++ return dev_err_probe(dev, PTR_ERR(afp->pwren), "unable to get pwren-gpios\n");
++
++ /* Fetch clocks */
++ afp->pcie_aux = devm_clk_get(dev, "pcie_aux");
++ if (IS_ERR(afp->pcie_aux))
++ return dev_err_probe(dev, PTR_ERR(afp->pcie_aux),
++ "pcie_aux clock source missing or invalid\n");
++
++ /* Fetch reset */
++ afp->rst = devm_reset_control_get_exclusive(dev, NULL);
++ if (IS_ERR(afp->rst))
++ return dev_err_probe(dev, PTR_ERR(afp->rst), "unable to get reset\n");
++
++ platform_set_drvdata(pdev, afp);
++
++ return dw_pcie_host_init(&pci->pp);
++}
++
++static void fu740_pcie_shutdown(struct platform_device *pdev)
++{
++ struct fu740_pcie *afp = platform_get_drvdata(pdev);
++
++ /* Bring down link, so bootloader gets clean state in case of reboot */
++ fu740_pcie_assert_reset(afp);
++}
++
++static const struct of_device_id fu740_pcie_of_match[] = {
++ { .compatible = "sifive,fu740-pcie", },
++ {},
++};
++
++static struct platform_driver fu740_pcie_driver = {
++ .driver = {
++ .name = "fu740-pcie",
++ .of_match_table = fu740_pcie_of_match,
++ .suppress_bind_attrs = true,
++ },
++ .probe = fu740_pcie_probe,
++ .shutdown = fu740_pcie_shutdown,
++};
++
++builtin_platform_driver(fu740_pcie_driver);
+--
+2.7.4
+
--- /dev/null
+From 54c43398c4bc7cdedbabe3d40105c2e6e9d09c98 Mon Sep 17 00:00:00 2001
+Date: Tue, 6 Apr 2021 17:26:34 +0800
+Subject: [PATCH 22/28] riscv: dts: Add PCIe support for the SiFive FU740-C000
+ SoC
+
+---
+ arch/riscv/boot/dts/sifive/fu740-c000.dtsi | 33 ++++++++++++++++++++++++++++++
+ 1 file changed, 33 insertions(+)
+
+diff --git a/arch/riscv/boot/dts/sifive/fu740-c000.dtsi b/arch/riscv/boot/dts/sifive/fu740-c000.dtsi
+index cd9cc02..3095d82 100644
+--- a/arch/riscv/boot/dts/sifive/fu740-c000.dtsi
++++ b/arch/riscv/boot/dts/sifive/fu740-c000.dtsi
+@@ -159,6 +159,7 @@
+ reg = <0x0 0x10000000 0x0 0x1000>;
+ clocks = <&hfclk>, <&rtcclk>;
+ #clock-cells = <1>;
++ #reset-cells = <1>;
+ };
+ uart0: serial@10010000 {
+ compatible = "sifive,fu740-c000-uart", "sifive,uart0";
+@@ -289,5 +290,37 @@
+ clocks = <&prci PRCI_CLK_PCLK>;
+ status = "disabled";
+ };
++ pcie@e00000000 {
++ compatible = "sifive,fu740-pcie";
++ #address-cells = <3>;
++ #size-cells = <2>;
++ #interrupt-cells = <1>;
++ reg = <0xe 0x00000000 0x0 0x80000000>,
++ <0xd 0xf0000000 0x0 0x10000000>,
++ <0x0 0x100d0000 0x0 0x1000>;
++ reg-names = "dbi", "config", "mgmt";
++ device_type = "pci";
++ dma-coherent;
++ bus-range = <0x0 0xff>;
++ ranges = <0x81000000 0x0 0x60080000 0x0 0x60080000 0x0 0x10000>, /* I/O */
++ <0x82000000 0x0 0x60090000 0x0 0x60090000 0x0 0xff70000>, /* mem */
++ <0x82000000 0x0 0x70000000 0x0 0x70000000 0x0 0x1000000>, /* mem */
++ <0xc3000000 0x20 0x00000000 0x20 0x00000000 0x20 0x00000000>; /* mem prefetchable */
++ num-lanes = <0x8>;
++ interrupts = <56>, <57>, <58>, <59>, <60>, <61>, <62>, <63>, <64>;
++ interrupt-names = "msi", "inta", "intb", "intc", "intd";
++ interrupt-parent = <&plic0>;
++ interrupt-map-mask = <0x0 0x0 0x0 0x7>;
++ interrupt-map = <0x0 0x0 0x0 0x1 &plic0 57>,
++ <0x0 0x0 0x0 0x2 &plic0 58>,
++ <0x0 0x0 0x0 0x3 &plic0 59>,
++ <0x0 0x0 0x0 0x4 &plic0 60>;
++ clock-names = "pcie_aux";
++ clocks = <&prci PRCI_CLK_PCIE_AUX>;
++ pwren-gpios = <&gpio 5 0>;
++ reset-gpios = <&gpio 8 0>;
++ resets = <&prci 4>;
++ status = "okay";
++ };
+ };
+ };
+--
+2.7.4
+
--- /dev/null
+From ce24ba4d603a19690548b986d87ae2d9af26d015 Mon Sep 17 00:00:00 2001
+Date: Thu, 25 Mar 2021 04:34:52 -0700
+Subject: [PATCH 23/28] riscv: sifive: unmatched: add D12 PWM LED
+
+---
+ arch/riscv/boot/dts/sifive/hifive-unmatched-a00.dts | 12 ++++++++++++
+ 1 file changed, 12 insertions(+)
+
+diff --git a/arch/riscv/boot/dts/sifive/hifive-unmatched-a00.dts b/arch/riscv/boot/dts/sifive/hifive-unmatched-a00.dts
+index e026f60..8461b33 100644
+--- a/arch/riscv/boot/dts/sifive/hifive-unmatched-a00.dts
++++ b/arch/riscv/boot/dts/sifive/hifive-unmatched-a00.dts
+@@ -3,6 +3,7 @@
+
+ #include "fu740-c000.dtsi"
+ #include <dt-bindings/interrupt-controller/irq.h>
++#include <dt-bindings/pwm/pwm.h>
+
+ /* Clock frequency (in Hz) of the PCB crystal for rtcclk */
+ #define RTCCLK_FREQ 1000000
+@@ -30,6 +31,17 @@
+ soc {
+ };
+
++ pwmleds {
++ compatible = "pwm-leds";
++ d12 {
++ label = "green:d12";
++ pwms = <&pwm0 0 7812500 PWM_POLARITY_INVERTED>;
++ active-low = <1>;
++ max-brightness = <255>;
++ linux,default-trigger = "none";
++ };
++ };
++
+ hfclk: hfclk {
+ #clock-cells = <0>;
+ compatible = "fixed-clock";
+--
+2.7.4
+
--- /dev/null
+From f19634daf24481664cdc89dc0b5abd9b622718f5 Mon Sep 17 00:00:00 2001
+Date: Thu, 25 Mar 2021 04:37:20 -0700
+Subject: [PATCH 24/28] riscv: sifive: unmatched: add gpio-poweroff node
+
+---
+ arch/riscv/boot/dts/sifive/hifive-unmatched-a00.dts | 6 ++++++
+ 1 file changed, 6 insertions(+)
+
+diff --git a/arch/riscv/boot/dts/sifive/hifive-unmatched-a00.dts b/arch/riscv/boot/dts/sifive/hifive-unmatched-a00.dts
+index 8461b33..9a7fa9b 100644
+--- a/arch/riscv/boot/dts/sifive/hifive-unmatched-a00.dts
++++ b/arch/riscv/boot/dts/sifive/hifive-unmatched-a00.dts
+@@ -2,6 +2,7 @@
+ /* Copyright (c) 2020 SiFive, Inc */
+
+ #include "fu740-c000.dtsi"
++#include <dt-bindings/gpio/gpio.h>
+ #include <dt-bindings/interrupt-controller/irq.h>
+ #include <dt-bindings/pwm/pwm.h>
+
+@@ -55,6 +56,11 @@
+ clock-frequency = <RTCCLK_FREQ>;
+ clock-output-names = "rtcclk";
+ };
++
++ gpio-poweroff {
++ compatible = "gpio-poweroff";
++ gpios = <&gpio 2 GPIO_ACTIVE_LOW>;
++ };
+ };
+
+ &uart0 {
+--
+2.7.4
+
--- /dev/null
+From 2d375478fd6b5eeea711d081502cc8fd1a22987d Mon Sep 17 00:00:00 2001
+Date: Fri, 2 Apr 2021 06:31:07 -0700
+Subject: [PATCH 25/28] riscv: sifive: unmatched: add D2 RGB LED
+
+---
+ .../riscv/boot/dts/sifive/hifive-unmatched-a00.dts | 26 +++++++++++++++++++++-
+ 1 file changed, 25 insertions(+), 1 deletion(-)
+
+diff --git a/arch/riscv/boot/dts/sifive/hifive-unmatched-a00.dts b/arch/riscv/boot/dts/sifive/hifive-unmatched-a00.dts
+index 9a7fa9b..235f78a 100644
+--- a/arch/riscv/boot/dts/sifive/hifive-unmatched-a00.dts
++++ b/arch/riscv/boot/dts/sifive/hifive-unmatched-a00.dts
+@@ -34,13 +34,37 @@
+
+ pwmleds {
+ compatible = "pwm-leds";
+- d12 {
++ green-d12 {
+ label = "green:d12";
+ pwms = <&pwm0 0 7812500 PWM_POLARITY_INVERTED>;
+ active-low = <1>;
+ max-brightness = <255>;
+ linux,default-trigger = "none";
+ };
++
++ green-d2 {
++ label = "green:d2";
++ pwms = <&pwm0 1 7812500 PWM_POLARITY_INVERTED>;
++ active-low = <1>;
++ max-brightness = <255>;
++ linux,default-trigger = "none";
++ };
++
++ red-d2 {
++ label = "red:d2";
++ pwms = <&pwm0 2 7812500 PWM_POLARITY_INVERTED>;
++ active-low = <1>;
++ max-brightness = <255>;
++ linux,default-trigger = "none";
++ };
++
++ blue-d2 {
++ label = "blue:d2";
++ pwms = <&pwm0 3 7812500 PWM_POLARITY_INVERTED>;
++ active-low = <1>;
++ max-brightness = <255>;
++ linux,default-trigger = "none";
++ };
+ };
+
+ hfclk: hfclk {
+--
+2.7.4
+
--- /dev/null
+From 45ed220373844f72e9ddb05ef0a8f2bd391e0980 Mon Sep 17 00:00:00 2001
+Date: Tue, 6 Apr 2021 05:00:11 -0700
+Subject: [PATCH 26/28] riscv: sifive: unmatched: remove "A00" from model
+
+---
+ arch/riscv/boot/dts/sifive/hifive-unmatched-a00.dts | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+diff --git a/arch/riscv/boot/dts/sifive/hifive-unmatched-a00.dts b/arch/riscv/boot/dts/sifive/hifive-unmatched-a00.dts
+index 235f78a..5fdd183 100644
+--- a/arch/riscv/boot/dts/sifive/hifive-unmatched-a00.dts
++++ b/arch/riscv/boot/dts/sifive/hifive-unmatched-a00.dts
+@@ -12,7 +12,7 @@
+ / {
+ #address-cells = <2>;
+ #size-cells = <2>;
+- model = "SiFive HiFive Unmatched A00";
++ model = "SiFive HiFive Unmatched";
+ compatible = "sifive,hifive-unmatched-a00", "sifive,fu740-c000",
+ "sifive,fu740";
+
+--
+2.7.4
+
--- /dev/null
+From 665297adfa377a3682b261b23f2a6f3ec56daa8b Mon Sep 17 00:00:00 2001
+Date: Wed, 7 Apr 2021 06:08:33 -0700
+Subject: [PATCH 27/28] riscv: sifive: unmatched: define LEDs color
+
+---
+ arch/riscv/boot/dts/sifive/hifive-unmatched-a00.dts | 5 +++++
+ 1 file changed, 5 insertions(+)
+
+diff --git a/arch/riscv/boot/dts/sifive/hifive-unmatched-a00.dts b/arch/riscv/boot/dts/sifive/hifive-unmatched-a00.dts
+index 5fdd183..9be0564 100644
+--- a/arch/riscv/boot/dts/sifive/hifive-unmatched-a00.dts
++++ b/arch/riscv/boot/dts/sifive/hifive-unmatched-a00.dts
+@@ -4,6 +4,7 @@
+ #include "fu740-c000.dtsi"
+ #include <dt-bindings/gpio/gpio.h>
+ #include <dt-bindings/interrupt-controller/irq.h>
++#include <dt-bindings/leds/common.h>
+ #include <dt-bindings/pwm/pwm.h>
+
+ /* Clock frequency (in Hz) of the PCB crystal for rtcclk */
+@@ -36,6 +37,7 @@
+ compatible = "pwm-leds";
+ green-d12 {
+ label = "green:d12";
++ color = <LED_COLOR_ID_GREEN>;
+ pwms = <&pwm0 0 7812500 PWM_POLARITY_INVERTED>;
+ active-low = <1>;
+ max-brightness = <255>;
+@@ -44,6 +46,7 @@
+
+ green-d2 {
+ label = "green:d2";
++ color = <LED_COLOR_ID_GREEN>;
+ pwms = <&pwm0 1 7812500 PWM_POLARITY_INVERTED>;
+ active-low = <1>;
+ max-brightness = <255>;
+@@ -52,6 +55,7 @@
+
+ red-d2 {
+ label = "red:d2";
++ color = <LED_COLOR_ID_RED>;
+ pwms = <&pwm0 2 7812500 PWM_POLARITY_INVERTED>;
+ active-low = <1>;
+ max-brightness = <255>;
+@@ -60,6 +64,7 @@
+
+ blue-d2 {
+ label = "blue:d2";
++ color = <LED_COLOR_ID_BLUE>;
+ pwms = <&pwm0 3 7812500 PWM_POLARITY_INVERTED>;
+ active-low = <1>;
+ max-brightness = <255>;
+--
+2.7.4
+
--- /dev/null
+From 63d7d0e6553ed2990fec51b3f449e50153461650 Mon Sep 17 00:00:00 2001
+Date: Mon, 12 Apr 2021 13:10:12 +0200
+Subject: [PATCH 28/28] riscv: enable generic PCI resource mapping
+
+Enable the PCI resource mapping on RISC-V using the generic framework.
+This allows userspace applications to mmap PCI resources using
+/sys/devices/pci*/*/resource* interface.
+The mmap has been tested with Intel x520-DA2 NIC card on a HiFive
+Unmatched board (SiFive FU740 SoC).
+
+---
+ arch/riscv/include/asm/pci.h | 2 ++
+ 1 file changed, 2 insertions(+)
+
+diff --git a/arch/riscv/include/asm/pci.h b/arch/riscv/include/asm/pci.h
+index 1c473a1..46e844f 100644
+--- a/arch/riscv/include/asm/pci.h
++++ b/arch/riscv/include/asm/pci.h
+@@ -18,6 +18,8 @@
+ /* RISC-V shim does not initialize PCI bus */
+ #define pcibios_assign_all_busses() 1
+
++#define ARCH_GENERIC_PCI_MMAP_RESOURCE 1
++
+ extern int isa_dma_bridge_buggy;
+
+ #ifdef CONFIG_PCI
+--
+2.7.4
+
--- /dev/null
+From 35f046065b988ea1b29df78728f5dbb6877aadc4 Mon Sep 17 00:00:00 2001
+Date: Tue, 28 Jan 2020 02:55:56 -0800
+Subject: [PATCH 4/7] SiFive Unleashed CPUFreq
+
+Source: https://github.com/sifive/riscv-linux/commits/dev/paulw/cpufreq-dt-aloe-v5.3-rc4
+
+Upstream-Status: Not posted for a review
+---
+ arch/riscv/Kconfig | 8 +++++
+ arch/riscv/boot/dts/sifive/fu540-c000.dtsi | 5 ++++
+ .../riscv/boot/dts/sifive/hifive-unleashed-a00.dts | 34 ++++++++++++++++++++++
+ arch/riscv/configs/defconfig | 5 ++++
+ 4 files changed, 52 insertions(+)
+
+diff --git a/arch/riscv/Kconfig b/arch/riscv/Kconfig
+index fa7dc03..73b1138 100644
+--- a/arch/riscv/Kconfig
++++ b/arch/riscv/Kconfig
+@@ -356,6 +356,14 @@ endchoice
+
+ endmenu
+
++menu "CPU Power Management"
++
++source "drivers/cpuidle/Kconfig"
++
++source "drivers/cpufreq/Kconfig"
++
++endmenu
++
+ menu "Power management options"
+
+ source "kernel/power/Kconfig"
+diff --git a/arch/riscv/boot/dts/sifive/fu540-c000.dtsi b/arch/riscv/boot/dts/sifive/fu540-c000.dtsi
+index a2e3d54..a380bc7 100644
+--- a/arch/riscv/boot/dts/sifive/fu540-c000.dtsi
++++ b/arch/riscv/boot/dts/sifive/fu540-c000.dtsi
+@@ -30,6 +30,7 @@
+ i-cache-size = <16384>;
+ reg = <0>;
+ riscv,isa = "rv64imac";
++ clocks = <&prci PRCI_CLK_COREPLL>;
+ status = "disabled";
+ cpu0_intc: interrupt-controller {
+ #interrupt-cells = <1>;
+@@ -54,6 +55,7 @@
+ reg = <1>;
+ riscv,isa = "rv64imafdc";
+ tlb-split;
++ clocks = <&prci PRCI_CLK_COREPLL>;
+ next-level-cache = <&l2cache>;
+ cpu1_intc: interrupt-controller {
+ #interrupt-cells = <1>;
+@@ -78,6 +80,7 @@
+ reg = <2>;
+ riscv,isa = "rv64imafdc";
+ tlb-split;
++ clocks = <&prci PRCI_CLK_COREPLL>;
+ next-level-cache = <&l2cache>;
+ cpu2_intc: interrupt-controller {
+ #interrupt-cells = <1>;
+@@ -102,6 +105,7 @@
+ reg = <3>;
+ riscv,isa = "rv64imafdc";
+ tlb-split;
++ clocks = <&prci PRCI_CLK_COREPLL>;
+ next-level-cache = <&l2cache>;
+ cpu3_intc: interrupt-controller {
+ #interrupt-cells = <1>;
+@@ -126,6 +130,7 @@
+ reg = <4>;
+ riscv,isa = "rv64imafdc";
+ tlb-split;
++ clocks = <&prci PRCI_CLK_COREPLL>;
+ next-level-cache = <&l2cache>;
+ cpu4_intc: interrupt-controller {
+ #interrupt-cells = <1>;
+diff --git a/arch/riscv/boot/dts/sifive/hifive-unleashed-a00.dts b/arch/riscv/boot/dts/sifive/hifive-unleashed-a00.dts
+index 88cfcb9..e1724e3 100644
+--- a/arch/riscv/boot/dts/sifive/hifive-unleashed-a00.dts
++++ b/arch/riscv/boot/dts/sifive/hifive-unleashed-a00.dts
+@@ -41,6 +41,40 @@
+ clock-frequency = <RTCCLK_FREQ>;
+ clock-output-names = "rtcclk";
+ };
++
++ fu540_c000_opp_table: opp-table {
++ compatible = "operating-points-v2";
++ opp-shared;
++
++ opp-350000000 {
++ opp-hz = /bits/ 64 <350000000>;
++ };
++ opp-700000000 {
++ opp-hz = /bits/ 64 <700000000>;
++ };
++ opp-999999999 {
++ opp-hz = /bits/ 64 <999999999>;
++ };
++ opp-1400000000 {
++ opp-hz = /bits/ 64 <1400000000>;
++ };
++ };
++};
++
++&cpu0 {
++ operating-points-v2 = <&fu540_c000_opp_table>;
++};
++&cpu1 {
++ operating-points-v2 = <&fu540_c000_opp_table>;
++};
++&cpu2 {
++ operating-points-v2 = <&fu540_c000_opp_table>;
++};
++&cpu3 {
++ operating-points-v2 = <&fu540_c000_opp_table>;
++};
++&cpu4 {
++ operating-points-v2 = <&fu540_c000_opp_table>;
+ };
+
+ &uart0 {
+diff --git a/arch/riscv/configs/defconfig b/arch/riscv/configs/defconfig
+index e2ff95c..a2fb392 100644
+--
+2.7.4
+
--- /dev/null
+From c1c831af223931219b7bf9158b1306b500116167 Mon Sep 17 00:00:00 2001
+Date: Fri, 5 Jun 2020 07:02:10 +0000
+Subject: [PATCH] SiFive HiFive Unleashed: Add PWM LEDs (D1, D2, D3, D4)
+
+By default no functions are assigned to LEDs. It's up to user/distribution
+to provide udev rules to configure them.
+
+---
+ .../riscv/boot/dts/sifive/hifive-unleashed-a00.dts | 32 ++++++++++++++++++++++
+ 1 file changed, 32 insertions(+)
+
+diff --git a/arch/riscv/boot/dts/sifive/hifive-unleashed-a00.dts b/arch/riscv/boot/dts/sifive/hifive-unleashed-a00.dts
+index 6dd6fa4..c8a47bf 100644
+--- a/arch/riscv/boot/dts/sifive/hifive-unleashed-a00.dts
++++ b/arch/riscv/boot/dts/sifive/hifive-unleashed-a00.dts
+@@ -3,6 +3,7 @@
+
+ #include "fu540-c000.dtsi"
+ #include <dt-bindings/gpio/gpio.h>
++#include <dt-bindings/pwm/pwm.h>
+
+ /* Clock frequency (in Hz) of the PCB crystal for rtcclk */
+ #define RTCCLK_FREQ 1000000
+@@ -27,6 +28,37 @@
+ };
+
+ soc {
++ pwmleds {
++ compatible = "pwm-leds";
++ d1 {
++ label = "green:d1";
++ pwms = <&pwm0 0 7812500 PWM_POLARITY_INVERTED>;
++ active-low = <1>;
++ max-brightness = <255>;
++ linux,default-trigger = "none";
++ };
++ d2 {
++ label = "green:d2";
++ pwms = <&pwm0 1 7812500 PWM_POLARITY_INVERTED>;
++ active-low = <1>;
++ max-brightness = <255>;
++ linux,default-trigger = "none";
++ };
++ d3 {
++ label = "green:d3";
++ pwms = <&pwm0 2 7812500 PWM_POLARITY_INVERTED>;
++ active-low = <1>;
++ max-brightness = <255>;
++ linux,default-trigger = "none";
++ };
++ d4 {
++ label = "green:d4";
++ pwms = <&pwm0 3 7812500 PWM_POLARITY_INVERTED>;
++ active-low = <1>;
++ max-brightness = <255>;
++ linux,default-trigger = "none";
++ };
++ };
+ };
+
+ hfclk: hfclk {
+--
+2.7.4
+