Add support of Baikal-M SoCs

Information about config values was taken from:

From 804820df7bcb3d53a33ecd074b1eac277e938f24 Mon Sep 17 00:00:00 2001
From: Alexey Sheplyakov <asheplyakov@altlinux.org>
Date: Thu, 4 Feb 2021 19:35:14 +0400
Subject: [PATCH] config-aarch64: adjusted for Baikal-M (MBM1.0 board)

* DW_APB_TIMER=y, DW_APB_TIMER_OF=y: SoC clocks

* SERIAL_8250_DW=y: serial console

* I2C_DESIGNWARE_CORE=y, I2C_DESIGNWARE_PLATFORM=y: BMC (board
  management controller) and RTC (Real Time Clock) are connected
  via I2C.

* GPIO_DWAPB=y: device (PCIe, PHY, etc) reset/configuration

* RTC_DRV_PCF2127=y: RTC compiled in so the kernel automatically
  sets the system time from the hardware clock

* TP_BMC=y: amongst other things handles the power button

* DRM_BAIKAL_VDU=m, DRM_BAIKAL_HDMI=m: video unit and HDMI transmitter

* CMA_SIZE_MBYTES=256: video display unit and GPU use system RAM, hence
  CMA should reserve enough (contiguous) memory.
  Note: CMA reserves memory during very early init, hence the size
  has to be hard-coded into CONFIG

* MALI_MIDGARD=m: GPU driver, kernel side of proprietary mali blob.
  Note: kernel mode code is GPLv2, so it's fine to distribute it.

* SENSORS_BT1_PVT=m: hardware temperature/voltage sensors

* PCI_BAIKAL=m: PCIe root complex. Compiled as a module since takes
  ages (60 seconds or so) to probe the hardware. If compiled in
  substantially increases the boot time, and machine is completely
  unresponsive during probing PCIe. When built as a module probing
  executes concurrently with other boot activities (unless booting
  from a PCIe device)

* STMMAC_ETH=m, STMMAC_PLATFORM=m, DWMAC_BAIKAL=m: Ethernet driver
This commit is contained in:
Mikhail Novosyolov 2021-06-22 16:12:03 +03:00
parent e677098a83
commit 839b6a86b6
27 changed files with 12556 additions and 9 deletions

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,502 @@
From 2e8241aba5add6f768a0876bc11c989681e28817 Mon Sep 17 00:00:00 2001
From: Alexey Sheplyakov <asheplyakov@altlinux.org>
Date: Fri, 20 Mar 2020 13:55:42 +0400
Subject: [PATCH 602/625] Baikal-M: clock driver
(cherry picked from commit acf15020f93d3be658922bb46ee9b4eb84497494)
---
drivers/clk/Makefile | 1 +
drivers/clk/baikal/Makefile | 1 +
drivers/clk/baikal/clk-baikal.c | 459 ++++++++++++++++++++++++++++++++
3 files changed, 461 insertions(+)
create mode 100644 drivers/clk/baikal/Makefile
create mode 100644 drivers/clk/baikal/clk-baikal.c
diff --git a/drivers/clk/Makefile b/drivers/clk/Makefile
index da8fcf147eb1..ab785aca5c8e 100644
--- a/drivers/clk/Makefile
+++ b/drivers/clk/Makefile
@@ -77,6 +77,7 @@ obj-$(CONFIG_COMMON_CLK_AT91) += at91/
obj-$(CONFIG_ARCH_ARTPEC) += axis/
obj-$(CONFIG_ARC_PLAT_AXS10X) += axs10x/
obj-$(CONFIG_CLK_BAIKAL_T1) += baikal-t1/
+obj-$(CONFIG_ARCH_BAIKAL) += baikal/
obj-y += bcm/
obj-$(CONFIG_ARCH_BERLIN) += berlin/
obj-$(CONFIG_ARCH_DAVINCI) += davinci/
diff --git a/drivers/clk/baikal/Makefile b/drivers/clk/baikal/Makefile
new file mode 100644
index 000000000000..56aa4de4081c
--- /dev/null
+++ b/drivers/clk/baikal/Makefile
@@ -0,0 +1 @@
+obj-y += clk-baikal.o
\ No newline at end of file
diff --git a/drivers/clk/baikal/clk-baikal.c b/drivers/clk/baikal/clk-baikal.c
new file mode 100644
index 000000000000..ddf1d328eeaf
--- /dev/null
+++ b/drivers/clk/baikal/clk-baikal.c
@@ -0,0 +1,459 @@
+/*
+ * clk-baikal.c - Baikal Electronics clock driver.
+ *
+ * Copyright (C) 2015,2016 Baikal Electronics JSC
+ *
+ * Author:
+ * Ekaterina Skachko <Ekaterina.Skachko@baikalelectronics.ru>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * 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.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+#include <linux/module.h>
+#include <linux/spinlock.h>
+#include <linux/io.h>
+#include <linux/of.h>
+#include <linux/clk.h>
+#include <linux/clkdev.h>
+#include <linux/clk-provider.h>
+#include <linux/of_address.h>
+#include <linux/platform_device.h>
+#include <linux/delay.h>
+#include <asm/setup.h>
+#include <linux/arm-smccc.h>
+
+#define CMU_PLL_SET_RATE 0
+#define CMU_PLL_GET_RATE 1
+#define CMU_PLL_ENABLE 2
+#define CMU_PLL_DISABLE 3
+#define CMU_PLL_ROUND_RATE 4
+#define CMU_PLL_IS_ENABLED 5
+#define CMU_CLK_CH_SET_RATE 6
+#define CMU_CLK_CH_GET_RATE 7
+#define CMU_CLK_CH_ENABLE 8
+#define CMU_CLK_CH_DISABLE 9
+#define CMU_CLK_CH_ROUND_RATE 10
+#define CMU_CLK_CH_IS_ENABLED 11
+
+
+struct baikal_clk_cmu {
+ struct clk_hw hw;
+ uint32_t cmu_id;
+ unsigned int parent;
+ const char *name;
+ spinlock_t *lock;
+ void __iomem *reg;
+ unsigned int latency; /* ns */
+ unsigned int min, max, step;
+ unsigned int clk_ch_num;
+ uint32_t is_clk_ch;
+};
+
+#define to_baikal_cmu(_hw) container_of(_hw, struct baikal_clk_cmu, hw)
+
+/* Pointer to the place on handling SMC CMU calls in monitor */
+#define BAIKAL_SMC_LCRU_ID 0x82000000
+
+static int baikal_clk_enable(struct clk_hw *hw)
+{
+ struct arm_smccc_res res;
+ struct baikal_clk_cmu *pclk = to_baikal_cmu(hw);
+ uint32_t cmd;
+
+ if (pclk->is_clk_ch){
+ cmd = CMU_CLK_CH_ENABLE;
+ }
+ else {
+ cmd = CMU_PLL_ENABLE;
+ }
+
+ pr_debug("[%s, %x:%d:%s] %s\n",
+ pclk->name,
+ pclk->parent,
+ pclk->cmu_id,
+ pclk->is_clk_ch?"ch":"pll",
+ "enable");
+
+ /* If clock valid */
+ arm_smccc_smc(BAIKAL_SMC_LCRU_ID, pclk->cmu_id, cmd, 0,
+ pclk->parent, 0, 0, 0, &res);
+
+ return res.a0;
+}
+
+static void baikal_clk_disable(struct clk_hw *hw)
+{
+
+ struct arm_smccc_res res;
+ struct baikal_clk_cmu *pclk = to_baikal_cmu(hw);
+ uint32_t cmd;
+
+ if (pclk->is_clk_ch)
+ cmd = CMU_CLK_CH_DISABLE;
+ else
+ cmd = CMU_PLL_DISABLE;
+
+ pr_debug("[%s, %x:%d:%s] %s\n",
+ pclk->name,
+ pclk->parent,
+ pclk->cmu_id,
+ pclk->is_clk_ch?"ch":"pll",
+ "disable");
+
+ /* If clock valid */
+ arm_smccc_smc(BAIKAL_SMC_LCRU_ID, pclk->cmu_id, cmd, 0,
+ pclk->parent, 0, 0, 0, &res);
+}
+
+static int baikal_clk_is_enabled(struct clk_hw *hw)
+{
+ struct arm_smccc_res res;
+ struct baikal_clk_cmu *pclk = to_baikal_cmu(hw);
+ uint32_t cmd;
+
+ if (pclk->is_clk_ch)
+ cmd = CMU_CLK_CH_IS_ENABLED;
+ else
+ cmd = CMU_PLL_IS_ENABLED;
+
+ /* If clock valid */
+ arm_smccc_smc(BAIKAL_SMC_LCRU_ID, pclk->cmu_id, cmd, 0,
+ pclk->parent, 0, 0, 0, &res);
+
+ pr_debug("[%s, %x:%d:%s] %s, %ld\n",
+ pclk->name,
+ pclk->parent,
+ pclk->cmu_id,
+ pclk->is_clk_ch?"ch":"pll",
+ "is enable",
+ res.a0);
+
+ return res.a0;
+}
+
+static unsigned long baikal_clk_recalc_rate(struct clk_hw *hw,
+ unsigned long parent_rate)
+{
+ struct arm_smccc_res res;
+ struct baikal_clk_cmu *pclk = to_baikal_cmu(hw);
+ uint32_t cmd;
+ unsigned long parent;
+
+ if (pclk->is_clk_ch) {
+ cmd = CMU_CLK_CH_GET_RATE;
+ parent = pclk->parent;
+ } else {
+ cmd = CMU_PLL_GET_RATE;
+ parent= parent_rate;
+ }
+
+ /* If clock valid */
+ arm_smccc_smc(BAIKAL_SMC_LCRU_ID, pclk->cmu_id, cmd, 0,
+ parent, 0, 0, 0, &res);
+
+ pr_debug("[%s, %x:%d:%s] %s, %ld\n",
+ pclk->name,
+ parent,
+ pclk->cmu_id,
+ pclk->is_clk_ch?"ch":"pll",
+ "get rate",
+ res.a0);
+
+ /* Return actual freq */
+ return res.a0;
+
+}
+
+static int baikal_clk_set_rate(struct clk_hw *hw, unsigned long rate,
+ unsigned long parent_rate)
+{
+ struct arm_smccc_res res;
+ struct baikal_clk_cmu *pclk = to_baikal_cmu(hw);
+ uint32_t cmd;
+
+ if (pclk->is_clk_ch)
+ cmd = CMU_CLK_CH_SET_RATE;
+ else
+ cmd = CMU_PLL_SET_RATE;
+
+ pr_debug("[%s, %x:%d:%s] %s, %ld\n",
+ pclk->name,
+ pclk->parent,
+ pclk->cmu_id,
+ pclk->is_clk_ch?"ch":"pll",
+ "set rate",
+ rate);
+
+ arm_smccc_smc(BAIKAL_SMC_LCRU_ID, pclk->cmu_id, cmd, rate,
+ pclk->parent, 0, 0, 0, &res);
+
+ return res.a0;
+}
+
+static long baikal_clk_round_rate(struct clk_hw *hw, unsigned long rate,
+ unsigned long *prate)
+{
+ struct arm_smccc_res res;
+ struct baikal_clk_cmu *pclk = to_baikal_cmu(hw);
+ unsigned long parent;
+ uint32_t cmd;
+
+ if (pclk->is_clk_ch) {
+ cmd = CMU_CLK_CH_ROUND_RATE;
+ parent = pclk->parent;
+ } else {
+ cmd = CMU_PLL_ROUND_RATE;
+ parent = *prate;
+ }
+
+
+ /* If clock valid */
+ arm_smccc_smc(BAIKAL_SMC_LCRU_ID, pclk->cmu_id, cmd, rate,
+ parent, 0, 0, 0, &res);
+
+ pr_debug("[%s, %x:%d:%s] %s, %ld\n",
+ pclk->name,
+ pclk->parent,
+ pclk->cmu_id,
+ pclk->is_clk_ch?"ch":"pll",
+ "round rate",
+ res.a0);
+
+ /* Return actual freq */
+ return res.a0;
+}
+
+const struct clk_ops be_clk_pll_ops = {
+ .enable = baikal_clk_enable,
+ .disable = baikal_clk_disable,
+ .is_enabled = baikal_clk_is_enabled,
+ .recalc_rate = baikal_clk_recalc_rate,
+ .set_rate = baikal_clk_set_rate,
+ .round_rate = baikal_clk_round_rate,
+};
+
+
+
+static int baikal_clk_probe(struct platform_device *pdev)
+{
+ struct clk_init_data init;
+ struct clk_init_data *init_ch;
+ struct baikal_clk_cmu *cmu;
+ struct baikal_clk_cmu **cmu_ch;
+ struct device_node *node = pdev->dev.of_node;
+
+ struct clk *clk;
+ struct clk_onecell_data *clk_ch;
+
+ int number, i = 0;
+ u32 rc, index;
+ struct property *prop;
+ const __be32 *p;
+ const char *clk_ch_name;
+ const char *parent_name;
+
+ cmu = kmalloc(sizeof(struct baikal_clk_cmu *), GFP_KERNEL);
+ if (!cmu) {
+ /* Error */
+ pr_err("%s: could not allocate CMU clk\n", __func__);
+ kfree(cmu);
+ return -ENOMEM;
+ }
+
+ of_property_read_string(node, "clock-output-names", &cmu->name);
+ parent_name = of_clk_get_parent_name(node, 0);
+ init.parent_names = &parent_name;
+ init.num_parents = 1;
+ of_property_read_u32(node, "clock-frequency", &cmu->parent);
+ of_property_read_u32(node, "cmu-id", &cmu->cmu_id);
+
+ /* Setup clock init structure */
+ init.name = cmu->name;
+ init.ops = &be_clk_pll_ops;
+ init.flags = CLK_IGNORE_UNUSED;
+
+ cmu->hw.init = &init;
+ cmu->is_clk_ch = 0;
+
+ /* Register the clock */
+ pr_debug("Add %s clock\n", cmu->name);
+ clk = clk_register(NULL, &cmu->hw);
+
+ if (IS_ERR(clk)) {
+ /* Error */
+ pr_err("%s: could not register clk %s\n", __func__, cmu->name);
+ return -ENOMEM;
+ }
+
+ /* Register the clock for lookup */
+ rc = clk_register_clkdev(clk, cmu->name, NULL);
+ if (rc != 0) {
+ /* Error */
+ pr_err("%s: could not register lookup clk %s\n",
+ __func__, cmu->name);
+ }
+
+ /* FIXME We probably SHOULDN'T enable it here */
+ clk_prepare_enable(clk);
+
+ number = of_property_count_u32_elems(node, "clock-indices");
+
+ if (number > 0) {
+ clk_ch = kmalloc(sizeof(struct clk_onecell_data), GFP_KERNEL);
+ if (!clk_ch) {
+ /* Error */
+ pr_err("%s: could not allocate CMU clk channel\n", __func__);
+ kfree(clk_ch);
+ return -ENOMEM;
+ }
+ /* Get the last index to find out max number of children*/
+ of_property_for_each_u32(node, "clock-indices", prop, p, index) {
+ ;
+ }
+ clk_ch->clks = kcalloc(index + 1, sizeof(struct clk *), GFP_KERNEL);
+ clk_ch->clk_num = index + 1;
+ cmu_ch = kcalloc((index + 1 ), sizeof(struct baikal_clk_cmu *), GFP_KERNEL);
+ if (!cmu_ch) {
+ kfree(cmu_ch);
+ kfree(clk_ch);
+ return -ENOMEM;
+ }
+ init_ch = kcalloc((number + 1 ), sizeof(struct clk_init_data), GFP_KERNEL);
+ if (!init_ch){
+ /* Error */
+ pr_err("%s: could not allocate CMU init structure \n", __func__);
+ kfree(init_ch);
+ kfree(cmu_ch);
+ kfree(clk_ch);
+ return -ENOMEM;
+ }
+
+ of_property_for_each_u32(node, "clock-indices", prop, p, index) {
+ of_property_read_string_index(node, "clock-names",
+ i, &clk_ch_name);
+ pr_err("%s index %x name <%s> i %x \n", __func__,index, clk_ch_name, i);
+ cmu_ch[index] = kmalloc(sizeof(struct baikal_clk_cmu), GFP_KERNEL);
+
+ cmu_ch[index]->name = clk_ch_name;
+ cmu_ch[index]->cmu_id = index;
+ cmu_ch[index]->parent = cmu->cmu_id;
+ cmu_ch[index]->is_clk_ch = 1;
+ init_ch[i].parent_names = &cmu->name;
+ init_ch[i].num_parents = 1;
+
+ init_ch[i].name = clk_ch_name;
+ init_ch[i].ops = &be_clk_pll_ops;
+ init_ch[i].flags = CLK_IGNORE_UNUSED;
+
+ cmu_ch[index]->hw.init = &init_ch[i];
+ clk_ch->clks[index] = clk_register(NULL, &cmu_ch[index]->hw);
+
+ if (IS_ERR(clk_ch->clks[index])) {
+ /* Error */
+ pr_err("%s: could not register clk %s\n", __func__, clk_ch_name);
+ }
+ /* Register the clock for lookup */
+ rc = clk_register_clkdev(clk_ch->clks[index], clk_ch_name, NULL);
+ if (rc != 0) {
+ /* Error */
+ pr_err("%s: could not register lookup clk %s\n",
+ __func__, clk_ch_name);
+ }
+ /* FIXME We probably SHOULDN'T enable it here */
+ clk_prepare_enable(clk_ch->clks[index]);
+ i++;
+ }
+ return of_clk_add_provider(pdev->dev.of_node, of_clk_src_onecell_get, clk_ch);
+ } else
+
+ return of_clk_add_provider(pdev->dev.of_node, of_clk_src_simple_get, clk);
+}
+
+static int baikal_clk_remove(struct platform_device *pdev)
+{
+ of_clk_del_provider(pdev->dev.of_node);
+
+ return 0;
+}
+
+static const struct of_device_id baikal_clk_of_match[] = {
+ {.compatible = "baikal,cmu"},
+ { /* sentinel value */ }
+};
+
+static struct platform_driver clk_avlsp_cmu0_driver = {
+ .probe = baikal_clk_probe,
+ .remove = baikal_clk_remove,
+ .driver = {
+ .name = "baikal-avlsp-cmu0",
+ .of_match_table = baikal_clk_of_match,
+ },
+};
+
+static struct platform_driver clk_avlsp_cmu1_driver = {
+ .probe = baikal_clk_probe,
+ .remove = baikal_clk_remove,
+ .driver = {
+ .name = "baikal-avlsp-cmu1",
+ .of_match_table = baikal_clk_of_match,
+ },
+};
+
+static struct platform_driver clk_xgbe_cmu0_driver = {
+ .probe = baikal_clk_probe,
+ .remove = baikal_clk_remove,
+ .driver = {
+ .name = "baikal-xgbe-cmu0",
+ .of_match_table = baikal_clk_of_match,
+ },
+};
+
+static struct platform_driver clk_xgbe_cmu1_driver = {
+ .probe = baikal_clk_probe,
+ .remove = baikal_clk_remove,
+ .driver = {
+ .name = "baikal-xgbe-cmu1",
+ .of_match_table = baikal_clk_of_match,
+ },
+};
+
+static struct platform_driver clk_ca57_cmu_driver = {
+ .probe = baikal_clk_probe,
+ .remove = baikal_clk_remove,
+ .driver = {
+ .name = "baikal-ca57_cmu",
+ .of_match_table = baikal_clk_of_match,
+ },
+};
+
+static struct platform_driver clk_mali_cmu_driver = {
+ .probe = baikal_clk_probe,
+ .remove = baikal_clk_remove,
+ .driver = {
+ .name = "baikal-mali-cmu",
+ .of_match_table = baikal_clk_of_match,
+ },
+};
+
+module_platform_driver(clk_avlsp_cmu0_driver);
+module_platform_driver(clk_avlsp_cmu1_driver);
+module_platform_driver(clk_xgbe_cmu0_driver);
+module_platform_driver(clk_xgbe_cmu1_driver);
+module_platform_driver(clk_mali_cmu_driver);
+module_platform_driver(clk_ca57_cmu_driver);
+
+MODULE_DESCRIPTION("Clkout driver for the Baikal-M");
+MODULE_AUTHOR("Ekaterina Skachko <Ekaterina.Skachko@baikalelectronics.ru>");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:baikal-cmu");
--
2.31.1

View file

@ -0,0 +1,44 @@
From 7b165ef3f844bd6a7f6edb195ba03e33291f0f8d Mon Sep 17 00:00:00 2001
From: Alexey Sheplyakov <asheplyakov@altlinux.org>
Date: Thu, 8 Oct 2020 18:31:28 +0400
Subject: [PATCH 603/625] efi-rtc: avoid calling efi.get_time on Baikal-M
boards
UEFI does NOT provide get_time at the runtime, hence calling it results
in an Oops.
(cherry picked from commit 57a5898a6f7e7c80999cb844ed2f0394b38afcbe)
---
drivers/rtc/rtc-efi.c | 9 +++++++++
1 file changed, 9 insertions(+)
diff --git a/drivers/rtc/rtc-efi.c b/drivers/rtc/rtc-efi.c
index edb64debd173..895bb07a7006 100644
--- a/drivers/rtc/rtc-efi.c
+++ b/drivers/rtc/rtc-efi.c
@@ -17,6 +17,7 @@
#include <linux/platform_device.h>
#include <linux/rtc.h>
#include <linux/efi.h>
+#include <linux/of.h>
#define EFI_ISDST (EFI_TIME_ADJUST_DAYLIGHT|EFI_TIME_IN_DAYLIGHT)
@@ -257,6 +258,14 @@ static int __init efi_rtc_probe(struct platform_device *dev)
efi_time_t eft;
efi_time_cap_t cap;
+#ifdef CONFIG_OF
+ /* efi.get_time is not always safe to call since some UEFI
+ * implementations do not privde get_time at runtime. */
+ if (of_device_is_compatible(of_root, "baikal,baikal-m")) {
+ dev_err(&dev->dev, "Baikal-M UEFI has no get_time\n");
+ return -ENODEV;
+ }
+#endif
/* First check if the RTC is usable */
if (efi.get_time(&eft, &cap) != EFI_SUCCESS)
return -ENODEV;
--
2.31.1

View file

@ -0,0 +1,27 @@
From 33a36bf1bf71c1bffdb0631a09856a24ba3d8165 Mon Sep 17 00:00:00 2001
From: Alexey Sheplyakov <asheplyakov@altlinux.org>
Date: Fri, 20 Mar 2020 17:14:36 +0400
Subject: [PATCH 604/625] efi/arm-runtime: print EFI mapping
(cherry picked from commit 652f76ffabc0e987169934d924d9e34b99b4cca9)
---
drivers/firmware/efi/arm-runtime.c | 3 +++
1 file changed, 3 insertions(+)
diff --git a/drivers/firmware/efi/arm-runtime.c b/drivers/firmware/efi/arm-runtime.c
index 3359ae2adf24..5028cd1605f3 100644
--- a/drivers/firmware/efi/arm-runtime.c
+++ b/drivers/firmware/efi/arm-runtime.c
@@ -71,6 +71,9 @@ static bool __init efi_virtmap_init(void)
pr_warn(" EFI remap %pa: failed to create mapping (%d)\n",
&phys, ret);
return false;
+ } else {
+ pr_info(" EFI remap %pa => %llx\n",
+ &phys, (unsigned long long)md->virt_addr);
}
}
--
2.31.1

View file

@ -0,0 +1,253 @@
From ddbb6264ac1a4216a1b965b4ddc0d7cb31fe3d99 Mon Sep 17 00:00:00 2001
From: Alexey Sheplyakov <asheplyakov@altlinux.org>
Date: Wed, 3 Jun 2020 20:22:29 +0400
Subject: [PATCH 605/625] ethernet: stmmac: made dwmac1000_* DMA functions
available for reuse
Some variants of dwmac hardware (in particular the one in the BE-M1000
SoC) need custom DMA reset, and can reuse other dwmac1000 DMA functions.
(cherry picked from commit f8e6ec3642eb28e7b74c0a7875310d7354895c8a)
---
.../ethernet/stmicro/stmmac/dwmac1000_core.c | 1 +
.../ethernet/stmicro/stmmac/dwmac1000_dma.c | 45 +++++++++++--------
.../ethernet/stmicro/stmmac/dwmac1000_dma.h | 26 +++++++++++
.../net/ethernet/stmicro/stmmac/dwmac_lib.c | 8 ++++
4 files changed, 62 insertions(+), 18 deletions(-)
create mode 100644 drivers/net/ethernet/stmicro/stmmac/dwmac1000_dma.h
diff --git a/drivers/net/ethernet/stmicro/stmmac/dwmac1000_core.c b/drivers/net/ethernet/stmicro/stmmac/dwmac1000_core.c
index fc8759f146c7..bf4f79ef3b22 100644
--- a/drivers/net/ethernet/stmicro/stmmac/dwmac1000_core.c
+++ b/drivers/net/ethernet/stmicro/stmmac/dwmac1000_core.c
@@ -563,3 +563,4 @@ int dwmac1000_setup(struct stmmac_priv *priv)
return 0;
}
+EXPORT_SYMBOL_GPL(dwmac1000_setup);
diff --git a/drivers/net/ethernet/stmicro/stmmac/dwmac1000_dma.c b/drivers/net/ethernet/stmicro/stmmac/dwmac1000_dma.c
index 2bac49b49f73..d27d5292550a 100644
--- a/drivers/net/ethernet/stmicro/stmmac/dwmac1000_dma.c
+++ b/drivers/net/ethernet/stmicro/stmmac/dwmac1000_dma.c
@@ -16,7 +16,7 @@
#include "dwmac1000.h"
#include "dwmac_dma.h"
-static void dwmac1000_dma_axi(void __iomem *ioaddr, struct stmmac_axi *axi)
+void dwmac1000_dma_axi(void __iomem *ioaddr, struct stmmac_axi *axi)
{
u32 value = readl(ioaddr + DMA_AXI_BUS_MODE);
int i;
@@ -69,9 +69,10 @@ static void dwmac1000_dma_axi(void __iomem *ioaddr, struct stmmac_axi *axi)
writel(value, ioaddr + DMA_AXI_BUS_MODE);
}
+EXPORT_SYMBOL_GPL(dwmac1000_dma_axi);
-static void dwmac1000_dma_init(void __iomem *ioaddr,
- struct stmmac_dma_cfg *dma_cfg, int atds)
+void dwmac1000_dma_init(void __iomem *ioaddr,
+ struct stmmac_dma_cfg *dma_cfg, int atds)
{
u32 value = readl(ioaddr + DMA_BUS_MODE);
int txpbl = dma_cfg->txpbl ?: dma_cfg->pbl;
@@ -109,22 +110,25 @@ static void dwmac1000_dma_init(void __iomem *ioaddr,
/* Mask interrupts by writing to CSR7 */
writel(DMA_INTR_DEFAULT_MASK, ioaddr + DMA_INTR_ENA);
}
+EXPORT_SYMBOL_GPL(dwmac1000_dma_init);
-static void dwmac1000_dma_init_rx(void __iomem *ioaddr,
- struct stmmac_dma_cfg *dma_cfg,
- dma_addr_t dma_rx_phy, u32 chan)
+void dwmac1000_dma_init_rx(void __iomem *ioaddr,
+ struct stmmac_dma_cfg *dma_cfg,
+ dma_addr_t dma_rx_phy, u32 chan)
{
/* RX descriptor base address list must be written into DMA CSR3 */
writel(lower_32_bits(dma_rx_phy), ioaddr + DMA_RCV_BASE_ADDR);
}
+EXPORT_SYMBOL_GPL(dwmac1000_dma_init_rx);
-static void dwmac1000_dma_init_tx(void __iomem *ioaddr,
- struct stmmac_dma_cfg *dma_cfg,
- dma_addr_t dma_tx_phy, u32 chan)
+void dwmac1000_dma_init_tx(void __iomem *ioaddr,
+ struct stmmac_dma_cfg *dma_cfg,
+ dma_addr_t dma_tx_phy, u32 chan)
{
/* TX descriptor base address list must be written into DMA CSR4 */
writel(lower_32_bits(dma_tx_phy), ioaddr + DMA_TX_BASE_ADDR);
}
+EXPORT_SYMBOL_GPL(dwmac1000_dma_init_tx);
static u32 dwmac1000_configure_fc(u32 csr6, int rxfifosz)
{
@@ -147,8 +151,8 @@ static u32 dwmac1000_configure_fc(u32 csr6, int rxfifosz)
return csr6;
}
-static void dwmac1000_dma_operation_mode_rx(void __iomem *ioaddr, int mode,
- u32 channel, int fifosz, u8 qmode)
+void dwmac1000_dma_operation_mode_rx(void __iomem *ioaddr, int mode,
+ u32 channel, int fifosz, u8 qmode)
{
u32 csr6 = readl(ioaddr + DMA_CONTROL);
@@ -174,9 +178,10 @@ static void dwmac1000_dma_operation_mode_rx(void __iomem *ioaddr, int mode,
writel(csr6, ioaddr + DMA_CONTROL);
}
+EXPORT_SYMBOL_GPL(dwmac1000_dma_operation_mode_rx);
-static void dwmac1000_dma_operation_mode_tx(void __iomem *ioaddr, int mode,
- u32 channel, int fifosz, u8 qmode)
+void dwmac1000_dma_operation_mode_tx(void __iomem *ioaddr, int mode,
+ u32 channel, int fifosz, u8 qmode)
{
u32 csr6 = readl(ioaddr + DMA_CONTROL);
@@ -207,8 +212,9 @@ static void dwmac1000_dma_operation_mode_tx(void __iomem *ioaddr, int mode,
writel(csr6, ioaddr + DMA_CONTROL);
}
+EXPORT_SYMBOL_GPL(dwmac1000_dma_operation_mode_tx);
-static void dwmac1000_dump_dma_regs(void __iomem *ioaddr, u32 *reg_space)
+void dwmac1000_dump_dma_regs(void __iomem *ioaddr, u32 *reg_space)
{
int i;
@@ -217,9 +223,10 @@ static void dwmac1000_dump_dma_regs(void __iomem *ioaddr, u32 *reg_space)
reg_space[DMA_BUS_MODE / 4 + i] =
readl(ioaddr + DMA_BUS_MODE + i * 4);
}
+EXPORT_SYMBOL_GPL(dwmac1000_dump_dma_regs);
-static void dwmac1000_get_hw_feature(void __iomem *ioaddr,
- struct dma_features *dma_cap)
+void dwmac1000_get_hw_feature(void __iomem *ioaddr,
+ struct dma_features *dma_cap)
{
u32 hw_cap = readl(ioaddr + DMA_HW_FEATURE);
@@ -253,12 +260,14 @@ static void dwmac1000_get_hw_feature(void __iomem *ioaddr,
/* Alternate (enhanced) DESC mode */
dma_cap->enh_desc = (hw_cap & DMA_HW_FEAT_ENHDESSEL) >> 24;
}
+EXPORT_SYMBOL_GPL(dwmac1000_get_hw_feature);
-static void dwmac1000_rx_watchdog(void __iomem *ioaddr, u32 riwt,
- u32 number_chan)
+void dwmac1000_rx_watchdog(void __iomem *ioaddr, u32 riwt,
+ u32 number_chan)
{
writel(riwt, ioaddr + DMA_RX_WATCHDOG);
}
+EXPORT_SYMBOL_GPL(dwmac1000_rx_watchdog);
const struct stmmac_dma_ops dwmac1000_dma_ops = {
.reset = dwmac_dma_reset,
diff --git a/drivers/net/ethernet/stmicro/stmmac/dwmac1000_dma.h b/drivers/net/ethernet/stmicro/stmmac/dwmac1000_dma.h
new file mode 100644
index 000000000000..b1e39a109f31
--- /dev/null
+++ b/drivers/net/ethernet/stmicro/stmmac/dwmac1000_dma.h
@@ -0,0 +1,26 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+
+#ifndef __DWMAC1000_DMA_H__
+#define __DWMAC1000_DMA_H__
+#include "dwmac1000.h"
+
+void dwmac1000_dma_axi(void __iomem *ioaddr, struct stmmac_axi *axi);
+void dwmac1000_dma_init(void __iomem *ioaddr,
+ struct stmmac_dma_cfg *dma_cfg, int atds);
+void dwmac1000_dma_init_rx(void __iomem *ioaddr,
+ struct stmmac_dma_cfg *dma_cfg,
+ dma_addr_t dma_rx_phy, u32 chan);
+void dwmac1000_dma_init_tx(void __iomem *ioaddr,
+ struct stmmac_dma_cfg *dma_cfg,
+ dma_addr_t dma_tx_phy, u32 chan);
+void dwmac1000_dma_operation_mode_rx(void __iomem *ioaddr, int mode,
+ u32 channel, int fifosz, u8 qmode);
+void dwmac1000_dma_operation_mode_tx(void __iomem *ioaddr, int mode,
+ u32 channel, int fifosz, u8 qmode);
+void dwmac1000_dump_dma_regs(void __iomem *ioaddr, u32 *reg_space);
+
+void dwmac1000_get_hw_feature(void __iomem *ioaddr,
+ struct dma_features *dma_cap);
+
+void dwmac1000_rx_watchdog(void __iomem *ioaddr, u32 riwt, u32 number_chan);
+#endif /* __DWMAC1000_DMA_H__ */
diff --git a/drivers/net/ethernet/stmicro/stmmac/dwmac_lib.c b/drivers/net/ethernet/stmicro/stmmac/dwmac_lib.c
index 57a53a600aa5..e391285a2158 100644
--- a/drivers/net/ethernet/stmicro/stmmac/dwmac_lib.c
+++ b/drivers/net/ethernet/stmicro/stmmac/dwmac_lib.c
@@ -31,6 +31,7 @@ void dwmac_enable_dma_transmission(void __iomem *ioaddr)
{
writel(1, ioaddr + DMA_XMT_POLL_DEMAND);
}
+EXPORT_SYMBOL_GPL(dwmac_enable_dma_transmission);
void dwmac_enable_dma_irq(void __iomem *ioaddr, u32 chan, bool rx, bool tx)
{
@@ -43,6 +44,7 @@ void dwmac_enable_dma_irq(void __iomem *ioaddr, u32 chan, bool rx, bool tx)
writel(value, ioaddr + DMA_INTR_ENA);
}
+EXPORT_SYMBOL_GPL(dwmac_enable_dma_irq);
void dwmac_disable_dma_irq(void __iomem *ioaddr, u32 chan, bool rx, bool tx)
{
@@ -55,6 +57,7 @@ void dwmac_disable_dma_irq(void __iomem *ioaddr, u32 chan, bool rx, bool tx)
writel(value, ioaddr + DMA_INTR_ENA);
}
+EXPORT_SYMBOL_GPL(dwmac_disable_dma_irq);
void dwmac_dma_start_tx(void __iomem *ioaddr, u32 chan)
{
@@ -62,6 +65,7 @@ void dwmac_dma_start_tx(void __iomem *ioaddr, u32 chan)
value |= DMA_CONTROL_ST;
writel(value, ioaddr + DMA_CONTROL);
}
+EXPORT_SYMBOL_GPL(dwmac_dma_start_tx);
void dwmac_dma_stop_tx(void __iomem *ioaddr, u32 chan)
{
@@ -69,6 +73,7 @@ void dwmac_dma_stop_tx(void __iomem *ioaddr, u32 chan)
value &= ~DMA_CONTROL_ST;
writel(value, ioaddr + DMA_CONTROL);
}
+EXPORT_SYMBOL_GPL(dwmac_dma_stop_tx);
void dwmac_dma_start_rx(void __iomem *ioaddr, u32 chan)
{
@@ -76,6 +81,7 @@ void dwmac_dma_start_rx(void __iomem *ioaddr, u32 chan)
value |= DMA_CONTROL_SR;
writel(value, ioaddr + DMA_CONTROL);
}
+EXPORT_SYMBOL_GPL(dwmac_dma_start_rx);
void dwmac_dma_stop_rx(void __iomem *ioaddr, u32 chan)
{
@@ -83,6 +89,7 @@ void dwmac_dma_stop_rx(void __iomem *ioaddr, u32 chan)
value &= ~DMA_CONTROL_SR;
writel(value, ioaddr + DMA_CONTROL);
}
+EXPORT_SYMBOL_GPL(dwmac_dma_stop_rx);
#ifdef DWMAC_DMA_DEBUG
static void show_tx_process_state(unsigned int status)
@@ -224,6 +231,7 @@ int dwmac_dma_interrupt(void __iomem *ioaddr,
return ret;
}
+EXPORT_SYMBOL_GPL(dwmac_dma_interrupt);
void dwmac_dma_flush_tx_fifo(void __iomem *ioaddr)
{
--
2.31.1

View file

@ -0,0 +1,278 @@
From 8d0e122d3d4979e32c6ad0d340d8c9b31a8b4d95 Mon Sep 17 00:00:00 2001
From: Alexey Sheplyakov <asheplyakov@altlinux.org>
Date: Fri, 20 Mar 2020 14:00:56 +0400
Subject: [PATCH 606/625] stmmac: Baikal-M dwmac driver
(cherry picked from commit 5fd65e2b57a4873946822e99fb74b07caa73c341)
---
drivers/net/ethernet/stmicro/stmmac/Kconfig | 10 +
drivers/net/ethernet/stmicro/stmmac/Makefile | 1 +
.../ethernet/stmicro/stmmac/dwmac-baikal.c | 223 ++++++++++++++++++
3 files changed, 234 insertions(+)
create mode 100644 drivers/net/ethernet/stmicro/stmmac/dwmac-baikal.c
diff --git a/drivers/net/ethernet/stmicro/stmmac/Kconfig b/drivers/net/ethernet/stmicro/stmmac/Kconfig
index 53f14c5a9e02..26a3f62a36cc 100644
--- a/drivers/net/ethernet/stmicro/stmmac/Kconfig
+++ b/drivers/net/ethernet/stmicro/stmmac/Kconfig
@@ -66,6 +66,16 @@ config DWMAC_ANARION
This selects the Anarion SoC glue layer support for the stmmac driver.
+config DWMAC_BAIKAL
+ tristate "Baikal Electronics DWMAC support"
+ default y if MIPS_BAIKAL || ARCH_BAIKAL
+ depends on OF
+ help
+ Support for Baikal Electronics DWMAC Ethernet.
+
+ This selects the Baikal-T/M SoC glue layer support for the stmmac
+ device driver.
+
config DWMAC_IPQ806X
tristate "QCA IPQ806x DWMAC support"
default ARCH_QCOM
diff --git a/drivers/net/ethernet/stmicro/stmmac/Makefile b/drivers/net/ethernet/stmicro/stmmac/Makefile
index 24e6145d4eae..64970f60f536 100644
--- a/drivers/net/ethernet/stmicro/stmmac/Makefile
+++ b/drivers/net/ethernet/stmicro/stmmac/Makefile
@@ -13,6 +13,7 @@ stmmac-$(CONFIG_STMMAC_SELFTESTS) += stmmac_selftests.o
# Ordering matters. Generic driver must be last.
obj-$(CONFIG_STMMAC_PLATFORM) += stmmac-platform.o
obj-$(CONFIG_DWMAC_ANARION) += dwmac-anarion.o
+obj-$(CONFIG_DWMAC_BAIKAL) += dwmac-baikal.o
obj-$(CONFIG_DWMAC_IPQ806X) += dwmac-ipq806x.o
obj-$(CONFIG_DWMAC_LPC18XX) += dwmac-lpc18xx.o
obj-$(CONFIG_DWMAC_MEDIATEK) += dwmac-mediatek.o
diff --git a/drivers/net/ethernet/stmicro/stmmac/dwmac-baikal.c b/drivers/net/ethernet/stmicro/stmmac/dwmac-baikal.c
new file mode 100644
index 000000000000..646051cd500d
--- /dev/null
+++ b/drivers/net/ethernet/stmicro/stmmac/dwmac-baikal.c
@@ -0,0 +1,223 @@
+/*
+ * Baikal Electronics SoCs DWMAC glue layer
+ *
+ * Copyright (C) 2015,2016 Baikal Electronics JSC
+ * Author:
+ * Dmitry Dunaev <dmitry.dunaev@baikalelectronics.ru>
+ * All bugs by Alexey Sheplyakov <asheplyakov@altlinux.org>
+ *
+ * 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.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <linux/iopoll.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/platform_device.h>
+#include <linux/clk.h>
+
+#include "stmmac.h"
+#include "stmmac_platform.h"
+#include "common.h"
+#include "dwmac_dma.h"
+#include "dwmac1000_dma.h"
+
+#define MAC_GPIO 0x000000e0 /* GPIO register */
+#define MAC_GPIO_GPO0 (1 << 8) /* 0-output port */
+
+struct baikal_dwmac {
+ struct device *dev;
+ struct clk *tx2_clk;
+};
+
+static int baikal_dwmac_dma_reset(void __iomem *ioaddr)
+{
+ int err;
+ u32 value = readl(ioaddr + DMA_BUS_MODE);
+
+ /* DMA SW reset */
+ value |= DMA_BUS_MODE_SFT_RESET;
+ writel(value, ioaddr + DMA_BUS_MODE);
+
+ udelay(10);
+ /* Clear PHY reset */
+ value = readl(ioaddr + MAC_GPIO);
+ value |= MAC_GPIO_GPO0;
+ writel(value, ioaddr + MAC_GPIO);
+ pr_info("PHY re-inited for Baikal DWMAC\n");
+
+ err = readl_poll_timeout(ioaddr + DMA_BUS_MODE, value,
+ !(value & DMA_BUS_MODE_SFT_RESET),
+ 10000, 1000000);
+ if (err)
+ return -EBUSY;
+
+ return 0;
+}
+
+static const struct stmmac_dma_ops baikal_dwmac_dma_ops = {
+ .reset = baikal_dwmac_dma_reset,
+ .init = dwmac1000_dma_init,
+ .init_rx_chan = dwmac1000_dma_init_rx,
+ .init_tx_chan = dwmac1000_dma_init_tx,
+ .axi = dwmac1000_dma_axi,
+ .dump_regs = dwmac1000_dump_dma_regs,
+ .dma_rx_mode = dwmac1000_dma_operation_mode_rx,
+ .dma_tx_mode = dwmac1000_dma_operation_mode_tx,
+ .enable_dma_transmission = dwmac_enable_dma_transmission,
+ .enable_dma_irq = dwmac_enable_dma_irq,
+ .disable_dma_irq = dwmac_disable_dma_irq,
+ .start_tx = dwmac_dma_start_tx,
+ .stop_tx = dwmac_dma_stop_tx,
+ .start_rx = dwmac_dma_start_rx,
+ .stop_rx = dwmac_dma_stop_rx,
+ .dma_interrupt = dwmac_dma_interrupt,
+ .get_hw_feature = dwmac1000_get_hw_feature,
+ .rx_watchdog = dwmac1000_rx_watchdog,
+};
+
+static struct mac_device_info* baikal_dwmac_setup(void *ppriv)
+{
+ struct mac_device_info *mac, *old_mac;
+ struct stmmac_priv *priv = ppriv;
+ int ret;
+
+ mac = devm_kzalloc(priv->device, sizeof(*mac), GFP_KERNEL);
+ if (!mac)
+ return NULL;
+
+ mac->dma = &baikal_dwmac_dma_ops;
+ old_mac = priv->hw;
+ priv->hw = mac;
+ ret = dwmac1000_setup(priv);
+ priv->hw = old_mac;
+ if (ret) {
+ dev_err(priv->device, "dwmac1000_setup: error %d", ret);
+ return NULL;
+ }
+ return mac;
+}
+
+static void baikal_dwmac_fix_mac_speed(void *priv, unsigned int speed)
+{
+ struct baikal_dwmac *dwmac = priv;
+ unsigned long tx2_clk_freq = 0;
+ dev_info(dwmac->dev, "fix_mac_speed new speed %u\n", speed);
+ switch (speed) {
+ case SPEED_1000:
+ tx2_clk_freq = 250000000;
+ break;
+ case SPEED_100:
+ tx2_clk_freq = 50000000;
+ break;
+ case SPEED_10:
+ tx2_clk_freq = 5000000;
+ break;
+ }
+ if (dwmac->tx2_clk && tx2_clk_freq != 0) {
+ dev_info(dwmac->dev, "setting TX2 clock frequency to %lu\n", tx2_clk_freq);
+ clk_set_rate(dwmac->tx2_clk, tx2_clk_freq);
+
+ }
+
+}
+
+
+static int dwmac_baikal_probe(struct platform_device *pdev)
+{
+ struct plat_stmmacenet_data *plat_dat;
+ struct stmmac_resources stmmac_res;
+ struct baikal_dwmac *dwmac;
+ int ret;
+
+ ret = stmmac_get_platform_resources(pdev, &stmmac_res);
+ if (ret)
+ return ret;
+
+ ret = dma_set_mask_and_coherent(&pdev->dev, DMA_BIT_MASK(32));
+ if (ret) {
+ dev_warn(&pdev->dev, "No suitable DMA available\n");
+ return ret;
+ }
+
+ if (pdev->dev.of_node) {
+ plat_dat = stmmac_probe_config_dt(pdev, &stmmac_res.mac);
+ if (IS_ERR(plat_dat)) {
+ dev_err(&pdev->dev, "dt configuration failed\n");
+ return PTR_ERR(plat_dat);
+ }
+ } else {
+ plat_dat = dev_get_platdata(&pdev->dev);
+ if (!plat_dat) {
+ dev_err(&pdev->dev, "no platform data provided\n");
+ return -EINVAL;
+ }
+
+ /* Set default value for multicast hash bins */
+ plat_dat->multicast_filter_bins = HASH_TABLE_SIZE;
+
+ /* Set default value for unicast filter entries */
+ plat_dat->unicast_filter_entries = 1;
+ }
+
+ dwmac = devm_kzalloc(&pdev->dev, sizeof(*dwmac), GFP_KERNEL);
+ if (!dwmac) {
+ ret = -ENOMEM;
+ goto err_remove_config_dt;
+ }
+
+ dwmac->dev = &pdev->dev;
+ dwmac->tx2_clk = devm_clk_get(dwmac->dev, "tx2_clk");
+ if (IS_ERR(dwmac->tx2_clk)) {
+ dev_warn(&pdev->dev, "coldn't get TX2 clock\n");
+ dwmac->tx2_clk = NULL;
+ }
+ plat_dat->fix_mac_speed = baikal_dwmac_fix_mac_speed;
+ plat_dat->bsp_priv = dwmac;
+
+ plat_dat->has_gmac = 1;
+ plat_dat->enh_desc = 1;
+ plat_dat->tx_coe = 1;
+ plat_dat->rx_coe = 1;
+ // TODO: set CSR correct clock in dts!
+ plat_dat->clk_csr = 3;
+ plat_dat->setup = baikal_dwmac_setup;
+
+ dev_info(&pdev->dev, "Baikal Electronics DWMAC glue driver\n");
+
+ ret = stmmac_dvr_probe(&pdev->dev, plat_dat, &stmmac_res);
+ if (ret)
+ goto err_remove_config_dt;
+
+ return 0;
+
+err_remove_config_dt:
+ stmmac_remove_config_dt(pdev, plat_dat);
+
+ return ret;
+}
+
+static const struct of_device_id dwmac_baikal_match[] = {
+ { .compatible = "be,dwmac-3.710"},
+ { .compatible = "be,dwmac"},
+ { }
+};
+MODULE_DEVICE_TABLE(of, dwmac_baikal_match);
+
+static struct platform_driver dwmac_baikal_driver = {
+ .probe = dwmac_baikal_probe,
+ .remove = stmmac_pltfr_remove,
+ .driver = {
+ .name = "baikal-dwmac",
+ .pm = &stmmac_pltfr_pm_ops,
+ .of_match_table = of_match_ptr(dwmac_baikal_match),
+ },
+};
+module_platform_driver(dwmac_baikal_driver);
+
+MODULE_DESCRIPTION("Baikal dwmac glue driver");
+MODULE_LICENSE("GPL v2");
--
2.31.1

View file

@ -0,0 +1,137 @@
From 460b2ff3c8509372228afae9e869aa375b85c319 Mon Sep 17 00:00:00 2001
From: Alexey Sheplyakov <asheplyakov@altlinux.org>
Date: Tue, 10 Nov 2020 19:05:39 +0400
Subject: [PATCH 607/625] Fixed secondary CPUs boot on BE-M1000 SoC
The secure world on BE-M1000 SoC denies execution attempts outside of
the ranges [0x80000000, 0x8FFFFFFF] [0xA0000000, 0xBFFFFFFF]. Thus
PSCI calls to boot secondary CPUs fail unless the kernel image resides
in one of these (physical) address ranges. However BE-M1000's UEFI
PE/COFF loader puts the kernel into the forbidden range. Since the alignment
is good enough EFI stub does not try to relocate the kernel. As a result
secondary CPUs fail to boot.
Relocation to a random address is not going to work either. Therefore
automatically disable kaslr on "known bad" systems (for now only BE-M1000
ones) and forcibly relocate the kernel to a low(er) address.
---
drivers/firmware/efi/libstub/arm64-stub.c | 61 ++++++++++++++++++++++-
1 file changed, 60 insertions(+), 1 deletion(-)
diff --git a/drivers/firmware/efi/libstub/arm64-stub.c b/drivers/firmware/efi/libstub/arm64-stub.c
index 22ece1ad68a8..897708508909 100644
--- a/drivers/firmware/efi/libstub/arm64-stub.c
+++ b/drivers/firmware/efi/libstub/arm64-stub.c
@@ -11,6 +11,7 @@
#include <asm/efi.h>
#include <asm/memory.h>
#include <asm/sections.h>
+#include <linux/libfdt.h>
#include <asm/sysreg.h>
#include "efistub.h"
@@ -34,6 +35,31 @@ efi_status_t check_platform_features(void)
return EFI_SUCCESS;
}
+static const char* machines_need_low_alloc[] = {
+ "baikal,baikal-m",
+};
+
+static bool need_low_alloc(void) {
+ size_t i;
+ const void *fdt;
+ const char *match;
+
+ fdt = get_efi_config_table(DEVICE_TREE_GUID);
+ if (!fdt) {
+ efi_info("failed to retrive FDT from EFI\n");
+ return false;
+ }
+
+ for (i = 0; i < ARRAY_SIZE(machines_need_low_alloc); i++) {
+ match = machines_need_low_alloc[i];
+ if (fdt_node_check_compatible(fdt, 0, match) == 0) {
+ efi_info("machine %s: forcing kernel relocation to low address\n", match);
+ return true;
+ }
+ }
+ return false;
+}
+
/*
* Although relocatable kernels can fix up the misalignment with respect to
* MIN_KIMG_ALIGN, the resulting virtual text addresses are subtly out of
@@ -46,6 +72,19 @@ static u64 min_kimg_align(void)
return efi_nokaslr ? MIN_KIMG_ALIGN : EFI_KIMG_ALIGN;
}
+static inline efi_status_t efi_low_alloc(unsigned long size, unsigned long align,
+ unsigned long *addr)
+{
+ /*
+ * Don't allocate at 0x0. It will confuse code that
+ * checks pointers against NULL. Skip the first 8
+ * bytes so we start at a nice even number.
+ */
+ return efi_low_alloc_above(size, align, addr, 0x8);
+}
+
+
+
efi_status_t handle_kernel_image(unsigned long *image_addr,
unsigned long *image_size,
unsigned long *reserve_addr,
@@ -55,6 +94,13 @@ efi_status_t handle_kernel_image(unsigned long *image_addr,
efi_status_t status;
unsigned long kernel_size, kernel_memsize = 0;
u32 phys_seed = 0;
+ bool force_low_reloc = need_low_alloc();
+ if (force_low_reloc) {
+ if (!efi_nokaslr) {
+ efi_info("booting on a broken firmware, KASLR will be disabled\n");
+ efi_nokaslr = true;
+ }
+ }
if (IS_ENABLED(CONFIG_RANDOMIZE_BASE)) {
if (!efi_nokaslr) {
@@ -69,7 +115,8 @@ efi_status_t handle_kernel_image(unsigned long *image_addr,
efi_nokaslr = true;
}
} else {
- efi_info("KASLR disabled on kernel command line\n");
+ if (!force_low_reloc)
+ efi_info("KASLR disabled on kernel command line\n");
}
}
@@ -91,6 +138,15 @@ efi_status_t handle_kernel_image(unsigned long *image_addr,
status = EFI_OUT_OF_RESOURCES;
}
+ if (force_low_reloc) {
+ status = efi_low_alloc(*reserve_size,
+ min_kimg_align(),
+ reserve_addr);
+ if (status != EFI_SUCCESS) {
+ efi_err("Failed to relocate kernel, expect secondary CPUs boot failure\n");
+ }
+ }
+
if (status != EFI_SUCCESS) {
if (IS_ALIGNED((u64)_text, min_kimg_align())) {
/*
@@ -113,6 +169,9 @@ efi_status_t handle_kernel_image(unsigned long *image_addr,
}
*image_addr = *reserve_addr;
+ if (efi_nokaslr) {
+ efi_info("relocating kernel to 0x%lx\n", *image_addr);
+ }
memcpy((void *)*image_addr, _text, kernel_size);
return EFI_SUCCESS;
--
2.31.1

View file

@ -0,0 +1,175 @@
From 91e33969c0864de65db59308b298d321a5280daa Mon Sep 17 00:00:00 2001
From: Alexey Sheplyakov <asheplyakov@altlinux.org>
Date: Fri, 20 Mar 2020 14:02:43 +0400
Subject: [PATCH 608/625] Baikal-M: USB driver
(cherry picked from commit 136cab54114b2b0b61cf503065d6d547f3d3d5a2)
---
drivers/usb/dwc3/Kconfig | 9 +++
drivers/usb/dwc3/Makefile | 1 +
drivers/usb/dwc3/dwc3-baikal.c | 126 +++++++++++++++++++++++++++++++++
3 files changed, 136 insertions(+)
create mode 100644 drivers/usb/dwc3/dwc3-baikal.c
diff --git a/drivers/usb/dwc3/Kconfig b/drivers/usb/dwc3/Kconfig
index 7a2304565a73..121f8e708d51 100644
--- a/drivers/usb/dwc3/Kconfig
+++ b/drivers/usb/dwc3/Kconfig
@@ -139,4 +139,13 @@ config USB_DWC3_QCOM
for peripheral mode support.
Say 'Y' or 'M' if you have one such device.
+config USB_DWC3_BAIKAL
+ tristate "Baikal Electronics Platforms"
+ depends on OF
+ default USB_DWC3
+ help
+ Baikal Electronics SoCs with one DesignWare Core USB3 IP
+ inside.
+ Say 'Y' or 'M' if you have one such device.
+
endif
diff --git a/drivers/usb/dwc3/Makefile b/drivers/usb/dwc3/Makefile
index ae86da0dc5bd..0dcaf92a43ec 100644
--- a/drivers/usb/dwc3/Makefile
+++ b/drivers/usb/dwc3/Makefile
@@ -51,3 +51,4 @@ obj-$(CONFIG_USB_DWC3_MESON_G12A) += dwc3-meson-g12a.o
obj-$(CONFIG_USB_DWC3_OF_SIMPLE) += dwc3-of-simple.o
obj-$(CONFIG_USB_DWC3_ST) += dwc3-st.o
obj-$(CONFIG_USB_DWC3_QCOM) += dwc3-qcom.o
+obj-$(CONFIG_USB_DWC3_BAIKAL) += dwc3-baikal.o
diff --git a/drivers/usb/dwc3/dwc3-baikal.c b/drivers/usb/dwc3/dwc3-baikal.c
new file mode 100644
index 000000000000..2426dc49bd79
--- /dev/null
+++ b/drivers/usb/dwc3/dwc3-baikal.c
@@ -0,0 +1,126 @@
+/**
+ * dwc3-baikal.c - Baikal Electronics SoCs Specific Glue layer
+ *
+ * Copyright (C) 2015 Baikal Electronics JSC - http://www.baikalelectronics.ru
+ *
+ * Author: Dmitry Dunaev <dmitry.dunaev@baikalelectronics.ru>
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 of
+ * the License 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 <linux/clk.h>
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/interrupt.h>
+#include <linux/platform_device.h>
+#include <linux/dma-mapping.h>
+#include <linux/usb/usb_phy_generic.h>
+#include <linux/io.h>
+#include <linux/of_platform.h>
+
+struct dwc3_baikal {
+ struct device *dev;
+ struct clk *clk;
+};
+
+static int be_dwc3_probe(struct platform_device *pdev)
+{
+ struct device *dev = &pdev->dev;
+ struct device_node *node = pdev->dev.of_node;
+ struct dwc3_baikal *dwc;
+ int ret;
+
+ dwc = devm_kzalloc(dev, sizeof(*dwc), GFP_KERNEL);
+ if (!dwc)
+ return -ENOMEM;
+
+ ret = dma_coerce_mask_and_coherent(dev, DMA_BIT_MASK(64));
+ if (ret) {
+ dev_err(dev, "DMA mask error %d\n", ret);
+ return ret;
+ }
+
+ platform_set_drvdata(pdev, dwc);
+ dwc->dev = dev;
+
+ dwc->clk = devm_clk_get(dwc->dev, "usb");
+ if (IS_ERR(dwc->clk)) {
+ dev_err(dev, "no interface clk specified\n");
+ return -EINVAL;
+ }
+
+ ret = clk_prepare_enable(dwc->clk);
+ if (ret < 0) {
+ dev_err(dwc->dev, "unable to enable usb clock\n");
+ return ret;
+ }
+
+ if (node) {
+ ret = of_platform_populate(node, NULL, NULL, dev);
+ if (ret) {
+ dev_err(&pdev->dev, "failed to create dwc3 core\n");
+ goto __error;
+ }
+ } else {
+ dev_err(dev, "no device node, failed to add dwc3 core\n");
+ ret = -ENODEV;
+ goto __error;
+ }
+
+ return 0;
+
+__error:
+ clk_disable_unprepare(dwc->clk);
+
+ return ret;
+}
+
+static int be_dwc3_remove_core(struct device *dev, void *c)
+{
+ struct platform_device *pdev = to_platform_device(dev);
+
+ platform_device_unregister(pdev);
+
+ return 0;
+}
+
+static int be_dwc3_remove(struct platform_device *pdev)
+{
+ struct dwc3_baikal *dwc = platform_get_drvdata(pdev);
+
+ device_for_each_child(&pdev->dev, NULL, be_dwc3_remove_core);
+ clk_disable_unprepare(dwc->clk);
+
+ platform_set_drvdata(pdev, NULL);
+
+ return 0;
+}
+
+static const struct of_device_id be_dwc3_of_match[] = {
+ { .compatible = "be,baikal-dwc3", },
+ {},
+};
+MODULE_DEVICE_TABLE(of, be_dwc3_of_match);
+
+static struct platform_driver be_dwc3_driver = {
+ .probe = be_dwc3_probe,
+ .remove = be_dwc3_remove,
+ .driver = {
+ .name = "baikal-dwc3",
+ .of_match_table = be_dwc3_of_match,
+ },
+};
+
+module_platform_driver(be_dwc3_driver);
+
+MODULE_ALIAS("platform:baikal-dwc3");
+MODULE_AUTHOR("Dmitry Dunaev <dmitry.dunaev@baikalelectronics.ru>");
+MODULE_LICENSE("GPL v2");
+MODULE_DESCRIPTION("DesignWare USB3 Baikal SoCs Glue Layer");
--
2.31.1

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,810 @@
From 11c1cbda8ed87683a6a058e1991e1bb5f8379d04 Mon Sep 17 00:00:00 2001
From: Alexey Sheplyakov <asheplyakov@altlinux.org>
Date: Tue, 9 Jun 2020 10:37:23 +0400
Subject: [PATCH 610/625] Added Baikal-T1/M BMC driver
The BMC device is responsible for CPU kick-starting, controlling
power button, and a full board poweroff.
(cherry picked from commit 53d167c426d92ca9df319924a107e8cd62cd96b1)
---
drivers/misc/Kconfig | 18 +
drivers/misc/Makefile | 1 +
drivers/misc/tp_bmc.c | 747 ++++++++++++++++++++++++++++++++++++++++++
3 files changed, 766 insertions(+)
create mode 100644 drivers/misc/tp_bmc.c
diff --git a/drivers/misc/Kconfig b/drivers/misc/Kconfig
index fafa8b0d8099..00368637ede0 100644
--- a/drivers/misc/Kconfig
+++ b/drivers/misc/Kconfig
@@ -466,6 +466,24 @@ config HISI_HIKEY_USB
switching between the dual-role USB-C port and the USB-A host ports
using only one USB controller.
+config TP_BMC
+ tristate "T-platforms Baikal-T(1)/M BMC"
+ depends on I2C && SYSFS
+ depends on OF
+ select PINCTRL
+ select GENERIC_PINCONF
+ select SERIO
+ default y if ARCH_BAIKAL
+ help
+ Say Y here if you want to build a driver for T-platforms BMC devices
+ embedded into the boards with Baikal-T(1)/M processors. The device main
+ purpose is the CPU kick-starting as well as some additional side-way
+ functionality like power on/off buttons state tracing and full device
+ powering off.
+
+ If you choose to build module, its name will be tp-bmc. If unsure,
+ say N here.
+
source "drivers/misc/c2port/Kconfig"
source "drivers/misc/eeprom/Kconfig"
source "drivers/misc/cb710/Kconfig"
diff --git a/drivers/misc/Makefile b/drivers/misc/Makefile
index d23231e73330..f60e5079a6fb 100644
--- a/drivers/misc/Makefile
+++ b/drivers/misc/Makefile
@@ -57,3 +57,4 @@ obj-$(CONFIG_HABANA_AI) += habanalabs/
obj-$(CONFIG_UACCE) += uacce/
obj-$(CONFIG_XILINX_SDFEC) += xilinx_sdfec.o
obj-$(CONFIG_HISI_HIKEY_USB) += hisi_hikey_usb.o
+obj-$(CONFIG_TP_BMC) += tp_bmc.o
diff --git a/drivers/misc/tp_bmc.c b/drivers/misc/tp_bmc.c
new file mode 100644
index 000000000000..0b320d3ffae4
--- /dev/null
+++ b/drivers/misc/tp_bmc.c
@@ -0,0 +1,747 @@
+#include <linux/i2c.h>
+#include <linux/bcd.h>
+#include <linux/slab.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/input.h>
+#include <linux/regmap.h>
+#include <linux/delay.h>
+#include <linux/kthread.h>
+#include <linux/pm.h>
+#include <linux/rtc.h>
+#include <linux/serio.h>
+#include <linux/platform_device.h>
+#include <linux/pinctrl/pinctrl.h>
+#include <linux/pinctrl/pinconf.h>
+#include <linux/pinctrl/pinconf-generic.h>
+
+enum I2C_REGS {
+ R_ID1 = 0,
+ R_ID2,
+ R_ID3,
+ R_ID4,
+ R_SOFTOFF_RQ,
+ R_PWROFF_RQ,
+ R_PWRBTN_STATE,
+ R_VERSION1,
+ R_VERSION2,
+ R_BOOTREASON,
+ R_BOOTREASON_ARG,
+ R_SCRATCH1,
+ R_SCRATCH2,
+ R_SCRATCH3,
+ R_SCRATCH4,
+ R_CAP,
+ R_GPIODIR0,
+ R_GPIODIR1,
+ R_GPIODIR2,
+ R_COUNT
+};
+
+#define BMC_ID1_VAL 0x49
+#define BMC_ID2_VAL 0x54
+#define BMC_ID3_VAL 0x58
+#define BMC_ID4_VAL0 0x32
+#define BMC_ID4_VAL1 0x2
+
+#define BMC_VERSION1 0
+#define BMC_VERSION2 2
+#define BMC_VERSION2_3 3
+
+#define BMC_CAP_PWRBTN 0x1
+#define BMC_CAP_TOUCHPAD 0x2
+#define BMC_CAP_RTC 0x4
+#define BMC_CAP_FRU 0x8
+#define BMC_CAP_GPIODIR 0x10
+
+#define BMC_SERIO_BUFSIZE 7
+
+#define POLL_JIFFIES 100
+
+struct bmc_poll_data {
+ struct i2c_client *c;
+};
+
+static struct i2c_client *bmc_i2c;
+static struct i2c_client *rtc_i2c;
+static struct i2c_driver mitx2_bmc_i2c_driver;
+static struct input_dev *button_dev;
+static struct bmc_poll_data poll_data;
+static struct task_struct *polling_task;
+#ifdef CONFIG_SERIO
+static struct i2c_client *serio_i2c;
+static struct task_struct *touchpad_task;
+#endif
+static u8 bmc_proto_version[3];
+static u8 bmc_bootreason[2];
+static u8 bmc_scratch[4];
+static int bmc_cap;
+static const char input_name[] = "BMC input dev";
+static u8 prev_ret;
+
+/* BMC RTC */
+static int
+bmc_rtc_read_time(struct device *dev, struct rtc_time *tm)
+{
+ struct i2c_client *client = to_i2c_client(dev);
+ uint8_t rtc_buf[8];
+ struct i2c_msg msg;
+ int t;
+ int rc;
+
+ msg.addr = client->addr;
+ msg.flags = I2C_M_RD;
+ msg.len = 8;
+ msg.buf = rtc_buf;
+ rc = i2c_transfer(client->adapter, &msg, 1);
+ if (rc != 1) {
+ dev_err(dev, "rtc_read_time: i2c_transfer error %d\n", rc);
+ return rc;
+ }
+
+ tm->tm_sec = bcd2bin(rtc_buf[0] & 0x7f);
+ tm->tm_min = bcd2bin(rtc_buf[1] & 0x7f);
+ tm->tm_hour = bcd2bin(rtc_buf[2] & 0x3f);
+ if (rtc_buf[3] & (1 << 6)) /* PM */
+ tm->tm_hour += 12;
+ tm->tm_mday = bcd2bin(rtc_buf[4] & 0x3f);
+ tm->tm_mon = bcd2bin(rtc_buf[5] & 0x1f);
+ t = rtc_buf[5] >> 5;
+ tm->tm_wday = (t == 7) ? 0 : t;
+ tm->tm_year = bcd2bin(rtc_buf[6]) + 100; /* year since 1900 */
+ tm->tm_yday = rtc_year_days(tm->tm_mday, tm->tm_mon, tm->tm_year);
+ tm->tm_isdst = 0;
+
+ return rtc_valid_tm(tm);
+}
+
+static int
+bmc_rtc_set_time(struct device *dev, struct rtc_time *tm)
+{
+ struct i2c_client *client = to_i2c_client(dev);
+ uint8_t rtc_buf[8];
+ struct i2c_msg msg;
+ int rc;
+ uint8_t seconds, minutes, hours, wday, mday, month, years;
+
+ seconds = bin2bcd(tm->tm_sec);
+ minutes = bin2bcd(tm->tm_min);
+ hours = bin2bcd(tm->tm_hour);
+ wday = tm->tm_wday ? tm->tm_wday : 0x7;
+ mday = bin2bcd(tm->tm_mday);
+ month = bin2bcd(tm->tm_mon);
+ years = bin2bcd(tm->tm_year % 100);
+
+ /* Need sanity check??? */
+ rtc_buf[0] = seconds;
+ rtc_buf[1] = minutes;
+ rtc_buf[2] = hours;
+ rtc_buf[3] = 0;
+ rtc_buf[4] = mday;
+ rtc_buf[5] = month | (wday << 5);
+ rtc_buf[6] = years;
+ rtc_buf[7] = 0;
+
+ msg.addr = client->addr;
+ msg.flags = 0;
+ msg.len = 8;
+ msg.buf = rtc_buf;
+ dev_dbg(dev, "rtc_set_time: %08x-%08x\n", *(uint32_t *)&rtc_buf[0],
+ *(uint32_t *)&rtc_buf[4]);
+ rc = i2c_transfer(client->adapter, &msg, 1);
+ if (rc != 1)
+ dev_err(dev, "i2c write: %d\n", rc);
+
+ return (rc == 1) ? 0 : -EIO;
+}
+
+static const struct rtc_class_ops
+bmc_rtc_ops = {
+ .read_time = bmc_rtc_read_time,
+ .set_time = bmc_rtc_set_time,
+};
+
+#ifdef CONFIG_SERIO
+/* BMC serio (PS/2 touchpad) interface */
+
+static int bmc_serio_write(struct serio *id, unsigned char val)
+{
+ struct i2c_client *client = id->port_data;
+ uint8_t buf[4];
+ struct i2c_msg msg;
+ int rc;
+
+ buf[0] = val;
+ msg.addr = client->addr;
+ msg.flags = 0;
+ msg.len = 1;
+ msg.buf = buf;
+ dev_dbg(&client->dev, "bmc_serio_write: %02x\n", val);
+ rc = i2c_transfer(client->adapter, &msg, 1);
+ if (rc != 1)
+ dev_err(&client->dev, "i2c write: %d\n", rc);
+
+ return (rc == 1) ? 0 : -EIO;
+}
+
+/* returns: -1 on error, +1 if more data available, 0 otherwise */
+static int bmc_serio_read(struct i2c_client *client)
+{
+ struct serio *serio = dev_get_drvdata(&client->dev);
+ int i, rc, cnt;
+ uint8_t buf[BMC_SERIO_BUFSIZE];
+ struct i2c_msg msg;
+
+ msg.addr = client->addr;
+ msg.flags = I2C_M_RD;
+ msg.len = BMC_SERIO_BUFSIZE;
+ msg.buf = buf;
+ rc = i2c_transfer(client->adapter, &msg, 1);
+ if (rc != 1) {
+ dev_err(&client->dev, "bmc_serio_read: i2c_transfer error %d\n", rc);
+ return -1;
+ }
+
+ cnt = buf[0];
+ rc = 0;
+ if (cnt > BMC_SERIO_BUFSIZE - 1) {
+ cnt = BMC_SERIO_BUFSIZE - 1;
+ rc = 1;
+ }
+
+ for (i = 0; i < cnt; i++) {
+ serio_interrupt(serio, buf[i + 1], 0);
+ }
+
+ return 0;
+}
+
+int
+touchpad_poll_fn(void *data) {
+ int ret;
+
+ while (1) {
+ if (kthread_should_stop())
+ break;
+ while ((ret = bmc_serio_read(serio_i2c)) > 0)
+ ;
+ if (ret < 0) {
+ msleep_interruptible(10000);
+ }
+ msleep_interruptible(10);
+ }
+ return 0;
+}
+#endif /* CONFIG_SERIO */
+
+#ifdef CONFIG_PINCTRL
+static uint8_t bmc_pincf_state [3];
+#define BMC_NPINS (sizeof(bmc_pincf_state) * 8)
+
+static struct pinctrl_pin_desc bmc_pin_desc[BMC_NPINS] = {
+ PINCTRL_PIN(0, "P0"),
+ PINCTRL_PIN(1, "P1"),
+ PINCTRL_PIN(2, "P2"),
+ PINCTRL_PIN(3, "P3"),
+ PINCTRL_PIN(4, "P4"),
+ PINCTRL_PIN(5, "P5"),
+ PINCTRL_PIN(6, "P6"),
+ PINCTRL_PIN(7, "P7"),
+ PINCTRL_PIN(8, "P8"),
+ PINCTRL_PIN(9, "P9"),
+ PINCTRL_PIN(10, "P10"),
+ PINCTRL_PIN(11, "P11"),
+ PINCTRL_PIN(12, "P12"),
+ PINCTRL_PIN(13, "P13"),
+ PINCTRL_PIN(14, "P14"),
+ PINCTRL_PIN(15, "P15"),
+ PINCTRL_PIN(16, "P16"),
+ PINCTRL_PIN(17, "P17"),
+ PINCTRL_PIN(18, "P18"),
+ PINCTRL_PIN(19, "P19"),
+ PINCTRL_PIN(20, "P20"),
+ PINCTRL_PIN(21, "P21"),
+ PINCTRL_PIN(22, "P22"),
+ PINCTRL_PIN(23, "P23"),
+};
+
+#define PCTRL_DEV "bmc_pinctrl"
+
+static int bmc_pin_config_get(struct pinctrl_dev *pctldev,
+ unsigned pin,
+ unsigned long *config)
+{
+ int idx, bit;
+
+ if (pin > BMC_NPINS)
+ return -EINVAL;
+
+ idx = pin >> 3;
+ bit = pin & 7;
+
+ *config = !!(bmc_pincf_state[idx] & (1 << bit));
+ return 0;
+}
+
+static int bmc_pin_config_set(struct pinctrl_dev *pctldev,
+ unsigned pin,
+ unsigned long *config,
+ unsigned nc)
+{
+ int idx, bit;
+ enum pin_config_param param;
+ int arg;
+
+ if (pin > BMC_NPINS)
+ return -EINVAL;
+
+ idx = pin >> 3;
+ bit = pin & 7;
+
+ param = pinconf_to_config_param (*config);
+ arg = pinconf_to_config_argument (*config);
+ if (param != PIN_CONFIG_OUTPUT)
+ return -EINVAL;
+
+ if (arg)
+ bmc_pincf_state[idx] |= (1 << bit);
+ else
+ bmc_pincf_state[idx] &= ~(1 << bit);
+dev_dbg(&bmc_i2c->dev, "bmc_pin_config_set: pin %u, dir %lu\n", pin, *config);
+
+ return i2c_smbus_write_byte_data(bmc_i2c, R_GPIODIR0 + idx, bmc_pincf_state[idx]);
+}
+
+void pinconf_generic_dump_config(struct pinctrl_dev *pctldev,
+ struct seq_file *s, unsigned long config);
+
+void pinctrl_utils_free_map(struct pinctrl_dev *pctldev,
+ struct pinctrl_map *map, unsigned num_maps);
+
+static const struct pinconf_ops bmc_confops = {
+ .pin_config_get = bmc_pin_config_get,
+ .pin_config_set = bmc_pin_config_set,
+ .pin_config_config_dbg_show = pinconf_generic_dump_config,
+};
+
+static int bmc_groups_count(struct pinctrl_dev *pctldev)
+{
+ return 0;
+}
+
+static const char *bmc_group_name(struct pinctrl_dev *pctldev,
+ unsigned selector)
+{
+ return NULL;
+}
+
+static const struct pinctrl_ops bmc_ctrl_ops = {
+ .get_groups_count = bmc_groups_count,
+ .get_group_name = bmc_group_name,
+ .dt_node_to_map = pinconf_generic_dt_node_to_map_pin,
+ .dt_free_map = pinctrl_utils_free_map,
+};
+
+static struct pinctrl_desc bmc_pincrtl_desc = {
+ .name = PCTRL_DEV,
+ .pins = bmc_pin_desc,
+ .pctlops = &bmc_ctrl_ops,
+ .npins = BMC_NPINS,
+ .confops = &bmc_confops,
+};
+
+static struct pinctrl_dev *bmc_pinctrl_dev;
+
+static int bmc_pinctrl_register(struct device *dev)
+{
+ struct pinctrl_dev *pctrl_dev;
+ struct platform_device *pbdev;
+
+ pbdev = platform_device_alloc(PCTRL_DEV, -1);
+ pbdev->dev.parent = dev;
+ pbdev->dev.of_node = of_find_node_by_name(dev->of_node, "bmc_pinctrl");
+ platform_device_add(pbdev);
+ pctrl_dev = devm_pinctrl_register(&pbdev->dev, &bmc_pincrtl_desc, NULL);
+ if (IS_ERR(pctrl_dev)) {
+ dev_err(&pbdev->dev, "Can't register pinctrl (%ld)\n", PTR_ERR(pctrl_dev));
+ return PTR_ERR(pctrl_dev);
+ } else {
+ dev_info(&pbdev->dev, "BMC pinctrl registered\n");
+ bmc_pinctrl_dev = pctrl_dev;
+ }
+ /* reset all pins to default state */
+ i2c_smbus_write_byte_data(to_i2c_client(dev), R_GPIODIR0, 0);
+ i2c_smbus_write_byte_data(to_i2c_client(dev), R_GPIODIR1, 0);
+ i2c_smbus_write_byte_data(to_i2c_client(dev), R_GPIODIR2, 0);
+ return 0;
+}
+
+static void bmc_pinctrl_unregister(void)
+{
+ if (bmc_pinctrl_dev)
+ devm_pinctrl_unregister(&bmc_i2c->dev, bmc_pinctrl_dev);
+}
+
+#endif
+
+void
+bmc_pwroff_rq(void) {
+ int ret = 0;
+
+ dev_info(&bmc_i2c->dev, "Write reg R_PWROFF_RQ\n");
+ ret = i2c_smbus_write_byte_data(bmc_i2c, R_PWROFF_RQ, 0x01);
+ dev_info(&bmc_i2c->dev, "ret: %i\n", ret);
+}
+
+int
+pwroff_rq_poll_fn(void *data) {
+ int ret;
+
+ while (1) {
+ if (kthread_should_stop())
+ break;
+ dev_dbg(&poll_data.c->dev, "Polling\n");
+ ret = i2c_smbus_read_byte_data(poll_data.c, R_SOFTOFF_RQ);
+ dev_dbg(&poll_data.c->dev, "Polling returned: %i\n", ret);
+ if (prev_ret != ret) {
+ dev_info(&poll_data.c->dev, "key change [%i]\n", ret);
+ if (ret < 0) {
+ dev_err(&poll_data.c->dev,
+ "Could not read register %x\n",
+ R_SOFTOFF_RQ);
+ return -EIO;
+ } else if (ret != 0) {
+ dev_info(&poll_data.c->dev,
+ "PWROFF \"irq\" detected [%i]\n", ret);
+ input_event(button_dev, EV_KEY, KEY_POWER, 1);
+ } else {
+ input_event(button_dev, EV_KEY, KEY_POWER, 0);
+ }
+ input_sync(button_dev);
+ }
+ prev_ret = ret;
+
+ msleep_interruptible(100);
+ }
+ do_exit(1);
+ return 0;
+}
+
+static int
+mitx2_bmc_validate(struct i2c_client *client) {
+ int ret = 0;
+ int i = 0;
+ static const u8 regs[] = {R_ID1, R_ID2, R_ID3};
+ static const u8 vals[] = {BMC_ID1_VAL, BMC_ID2_VAL, BMC_ID3_VAL};
+
+ bmc_proto_version[0] = 0;
+ bmc_proto_version[1] = 0;
+ bmc_proto_version[2] = 0;
+
+ for (i = 0; i < ARRAY_SIZE(regs); i++) {
+ ret = i2c_smbus_read_byte_data(client, regs[i]);
+ if (ret < 0) {
+ dev_err(&client->dev, "Could not read register %x\n",
+ regs[i]);
+ return -EIO;
+ }
+ if (ret != vals[i]) {
+ dev_err(&client->dev,
+ "Bad value [0x%02x] in register 0x%02x, should be [0x%02x]\n",
+ ret, regs[i], vals[i]);
+
+ return -ENODEV;
+ }
+ }
+ ret = i2c_smbus_read_byte_data(client, R_ID4);
+ if (ret < 0) {
+ dev_err(&client->dev, "Could not read register %x\n", R_ID4);
+ return -EIO;
+ }
+ if (ret == BMC_ID4_VAL0) {
+ bmc_proto_version[0] = 0;
+ } else if (ret == BMC_ID4_VAL1) {
+ bmc_proto_version[0] = 2;
+ ret = i2c_smbus_read_byte_data(client, R_VERSION1);
+ if (ret < 0) {
+ dev_err(&client->dev, "Could not read register %x\n",
+ R_VERSION1);
+ return -EIO;
+ }
+ bmc_proto_version[1] = ret;
+ ret = i2c_smbus_read_byte_data(client, R_VERSION2);
+ if (ret < 0) {
+ dev_err(&client->dev, "Could not read register %x\n",
+ R_VERSION2);
+ return -EIO;
+ }
+ bmc_proto_version[2] = ret;
+ ret = i2c_smbus_read_byte_data(client, R_BOOTREASON);
+ if (ret < 0) {
+ dev_err(&client->dev, "Could not read register %x\n",
+ R_BOOTREASON);
+ return -EIO;
+ }
+ bmc_bootreason[0] = ret;
+ dev_info(&client->dev, "BMC bootreason[0]->%i\n", ret);
+ ret = i2c_smbus_read_byte_data(client, R_BOOTREASON_ARG);
+ if (ret < 0) {
+ dev_err(&client->dev, "Could not read register %x\n",
+ R_BOOTREASON_ARG);
+ return -EIO;
+ }
+ bmc_bootreason[1] = ret;
+ dev_info(&client->dev, "BMC bootreason[1]->%i\n", ret);
+ for (i = R_SCRATCH1; i <= R_SCRATCH4; i++) {
+ ret = i2c_smbus_read_byte_data(client, i);
+ if (ret < 0) {
+ dev_err(&client->dev,
+ "Could not read register %x\n", i);
+ return -EIO;
+ }
+ bmc_scratch[i - R_SCRATCH1] = ret;
+ }
+ if (bmc_proto_version[2] >= BMC_VERSION2_3) {
+ ret = i2c_smbus_read_byte_data(client, R_CAP);
+ if (ret >= 0)
+ bmc_cap = ret;
+ dev_info(&client->dev,
+ "BMC extended capabilities %x\n", bmc_cap);
+ } else {
+ bmc_cap = BMC_CAP_PWRBTN;
+ }
+ } else {
+ dev_err(&client->dev, "Bad value [0x%02x] in register 0x%02x\n",
+ ret, R_ID4);
+ return -ENODEV;
+ }
+ dev_info(&client->dev, "BMC seems to be valid\n");
+ return 0;
+}
+
+static int
+bmc_create_client_devices(struct device *bmc_dev)
+{
+ int ret = 0;
+ struct rtc_device *rtc_dev;
+ struct i2c_client *client = to_i2c_client(bmc_dev);
+ int client_addr = client->addr + 1;
+
+ if (bmc_cap & BMC_CAP_TOUCHPAD) {
+#ifdef CONFIG_SERIO
+ struct serio *serio;
+ serio_i2c = i2c_new_ancillary_device(client,
+ "bmc_serio", client_addr);
+ if (IS_ERR(serio_i2c)) {
+ dev_err(&client->dev, "Can't get serio secondary\n");
+ serio_i2c = NULL;
+ ret = -ENOMEM;
+ goto fail;
+ }
+ serio = devm_kzalloc(&serio_i2c->dev, sizeof(struct serio), GFP_KERNEL);
+ if (!serio) {
+ dev_err(&serio_i2c->dev, "Can't allocate serio\n");
+ ret = -ENOMEM;
+ i2c_unregister_device(serio_i2c);
+ serio_i2c = NULL;
+ goto skip_tp;
+ }
+ serio->write = bmc_serio_write;
+ serio->port_data = serio_i2c;
+ serio->id.type = SERIO_PS_PSTHRU;
+ serio_register_port(serio);
+ dev_set_drvdata(&serio_i2c->dev, serio);
+ touchpad_task = kthread_run(touchpad_poll_fn, NULL, "BMC serio poll task");
+
+skip_tp:
+#endif
+ client_addr++;
+ }
+
+ if (bmc_cap & BMC_CAP_RTC) {
+ rtc_i2c = i2c_new_ancillary_device(client,
+ "bmc_rtc", client_addr);
+ if (IS_ERR(rtc_i2c)) {
+ dev_err(&client->dev, "Can't get RTC secondary\n");
+ rtc_i2c = NULL;
+ ret = -ENOMEM;
+ goto fail;
+ }
+
+ rtc_dev = devm_rtc_device_register(&rtc_i2c->dev, "bmc_rtc",
+ &bmc_rtc_ops, THIS_MODULE);
+ if (IS_ERR(rtc_dev)) {
+ ret = PTR_ERR(rtc_dev);
+ dev_err(&client->dev, "Failed to register RTC device: %d\n",
+ ret);
+ i2c_unregister_device(rtc_i2c);
+ rtc_i2c = NULL;
+ }
+fail:
+ client_addr++;
+ }
+
+#ifdef CONFIG_PINCTRL
+ if (bmc_cap & BMC_CAP_GPIODIR || 1 /*vvv*/)
+ bmc_pinctrl_register(bmc_dev);
+#endif
+
+ return ret;
+}
+
+static int
+mitx2_bmc_i2c_probe(struct i2c_client *client,
+ const struct i2c_device_id *id)
+{
+ int err = 0;
+ int i = 0;
+
+ dev_info(&client->dev, "mitx2 bmc probe\n");
+
+ if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C))
+ return -ENODEV;
+
+ for (i = 0; i < 10; i++) {
+ err = mitx2_bmc_validate(client);
+ if (!err)
+ break;
+ msleep_interruptible(20);
+ }
+ if (err)
+ return err;
+
+ if (bmc_cap & BMC_CAP_PWRBTN) {
+ button_dev = input_allocate_device();
+ if (!button_dev) {
+ dev_err(&client->dev, "Not enough memory\n");
+ return -ENOMEM;
+ }
+
+ button_dev->id.bustype = BUS_I2C;
+ button_dev->dev.parent = &client->dev;
+ button_dev->name = input_name;
+ button_dev->phys = "bmc-input0";
+ button_dev->evbit[0] = BIT_MASK(EV_KEY);
+ button_dev->keybit[BIT_WORD(KEY_POWER)] = BIT_MASK(KEY_POWER);
+
+ err = input_register_device(button_dev);
+ if (err) {
+ dev_err(&client->dev, "Failed to register device\n");
+ input_free_device(button_dev);
+ return err;
+ }
+
+ dev_info(&client->dev, "Starting polling thread\n");
+ poll_data.c = client;
+ polling_task = kthread_run(pwroff_rq_poll_fn, NULL, "BMC poll task");
+ }
+
+ if (bmc_cap || 1 /*vvv*/)
+ err = bmc_create_client_devices(&client->dev);
+
+ bmc_i2c = client;
+ /* register as poweroff handler */
+ pm_power_off = bmc_pwroff_rq;
+
+ return 0;
+}
+
+static int
+mitx2_bmc_i2c_remove(struct i2c_client *client)
+{
+#ifdef CONFIG_SERIO
+ struct serio *serio;
+#endif
+
+ if (button_dev) {
+ kthread_stop(polling_task);
+ input_unregister_device(button_dev);
+ }
+#ifdef CONFIG_SERIO
+ if (serio_i2c) {
+ kthread_stop(touchpad_task);
+ serio = dev_get_drvdata(&serio_i2c->dev);
+ serio_unregister_port(serio);
+ i2c_unregister_device(serio_i2c);
+ }
+#endif
+ if (rtc_i2c)
+ i2c_unregister_device(rtc_i2c);
+#ifdef CONFIG_PINCTRL
+ bmc_pinctrl_unregister();
+#endif
+
+ return 0;
+}
+
+#ifdef CONFIG_OF
+static const struct of_device_id mitx2_bmc_of_match[] = {
+ { .compatible = "tp,mitx2-bmc" },
+ {}
+};
+MODULE_DEVICE_TABLE(of, mitx2_bmc_of_match);
+#endif
+
+static const struct i2c_device_id mitx2_bmc_i2c_id[] = {
+ { "mitx2_bmc", 0 },
+ { }
+};
+MODULE_DEVICE_TABLE(i2c, mitx2_bmc_i2c_id);
+
+static ssize_t
+version_show(struct kobject *kobj, struct kobj_attribute *attr, char *buf)
+{
+ return sprintf(buf, "%i.%i.%i\n", bmc_proto_version[0],
+ bmc_proto_version[1], bmc_proto_version[2]);
+}
+
+static struct kobj_attribute version_attribute =
+ __ATTR(version, 0664, version_show, NULL);
+
+static ssize_t
+bootreason_show(struct kobject *kobj,
+ struct kobj_attribute *attr, char *buf)
+{
+ return sprintf(buf, "%i\n", (bmc_bootreason[0] |
+ (bmc_bootreason[1] << 8)));
+}
+
+static struct kobj_attribute bootreason_attribute =
+ __ATTR(bootreason, 0664, bootreason_show, NULL);
+
+static ssize_t
+scratch_show(struct kobject *kobj,
+ struct kobj_attribute *attr, char *buf)
+{
+ return sprintf(buf, "%i\n", (bmc_scratch[0] | (bmc_scratch[1] << 8) |
+ (bmc_scratch[2] << 16) | (bmc_scratch[3] << 24)));
+}
+
+static struct kobj_attribute scratch_attribute =
+ __ATTR(scratch, 0664, scratch_show, NULL);
+
+static struct attribute *bmc_attrs[] = {
+ &version_attribute.attr,
+ &bootreason_attribute.attr,
+ &scratch_attribute.attr,
+ NULL,
+};
+
+ATTRIBUTE_GROUPS(bmc);
+
+static struct i2c_driver mitx2_bmc_i2c_driver = {
+ .driver = {
+ .name = "mitx2-bmc",
+ .of_match_table = of_match_ptr(mitx2_bmc_of_match),
+ .groups = bmc_groups,
+ },
+ .probe = mitx2_bmc_i2c_probe,
+ .remove = mitx2_bmc_i2c_remove,
+ .id_table = mitx2_bmc_i2c_id,
+};
+module_i2c_driver(mitx2_bmc_i2c_driver);
+
+MODULE_AUTHOR("Konstantin Kirik");
+MODULE_DESCRIPTION("mITX2 BMC driver");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("serial:bmc");
--
2.31.1

View file

@ -0,0 +1,251 @@
From 750bd359f6fff79a3131f89c3bd9ad8a83a6356a Mon Sep 17 00:00:00 2001
From: Alexey Sheplyakov <asheplyakov@altlinux.org>
Date: Wed, 3 Feb 2021 16:58:16 +0400
Subject: [PATCH 611/625] dw-hdmi-ahb-audio: support BE-M1000 SoC
---
.../drm/bridge/synopsys/dw-hdmi-ahb-audio.c | 106 ++++++++++++------
.../gpu/drm/bridge/synopsys/dw-hdmi-audio.h | 1 +
drivers/gpu/drm/bridge/synopsys/dw-hdmi.c | 6 +
3 files changed, 78 insertions(+), 35 deletions(-)
diff --git a/drivers/gpu/drm/bridge/synopsys/dw-hdmi-ahb-audio.c b/drivers/gpu/drm/bridge/synopsys/dw-hdmi-ahb-audio.c
index d0db1acf11d7..3bb652e42718 100644
--- a/drivers/gpu/drm/bridge/synopsys/dw-hdmi-ahb-audio.c
+++ b/drivers/gpu/drm/bridge/synopsys/dw-hdmi-ahb-audio.c
@@ -132,12 +132,45 @@ struct snd_dw_hdmi {
u8 cs[192][8];
};
-static void dw_hdmi_writel(u32 val, void __iomem *ptr)
+static inline void dw_hdmi_writeb_relaxed(u8 value, const struct dw_hdmi_audio_data *data, int offset)
{
- writeb_relaxed(val, ptr);
- writeb_relaxed(val >> 8, ptr + 1);
- writeb_relaxed(val >> 16, ptr + 2);
- writeb_relaxed(val >> 24, ptr + 3);
+ void __iomem *base = data->base;
+ if (data->reg_offset != 0)
+ offset <<= data->reg_offset;
+ writeb_relaxed(value, base + offset);
+}
+
+static inline void dw_hdmi_writeb(u8 value, const struct dw_hdmi_audio_data *data, int offset)
+{
+ void __iomem *base = data->base;
+ if (data->reg_offset != 0)
+ offset <<= data->reg_offset;
+ writeb(value, base + offset);
+}
+
+static inline u8 dw_hdmi_readb(const struct dw_hdmi_audio_data *data, int offset)
+{
+ void __iomem *base = data->base;
+ if (data->reg_offset != 0)
+ offset <<= data->reg_offset;
+ return readb(base + offset);
+
+}
+
+static inline u8 dw_hdmi_readb_relaxed(const struct dw_hdmi_audio_data *data, int offset)
+{
+ void __iomem *base = data->base;
+ if (data->reg_offset != 0)
+ offset <<= data->reg_offset;
+ return readb_relaxed(base + offset);
+}
+
+static void dw_hdmi_writel(u32 val, const struct dw_hdmi_audio_data *data, int offset)
+{
+ dw_hdmi_writeb_relaxed(val, data, offset);
+ dw_hdmi_writeb_relaxed(val >> 8, data, offset + 1);
+ dw_hdmi_writeb_relaxed(val >> 16, data, offset + 2);
+ dw_hdmi_writeb_relaxed(val >> 24, data, offset + 3);
}
/*
@@ -232,7 +265,6 @@ static void dw_hdmi_create_cs(struct snd_dw_hdmi *dw,
static void dw_hdmi_start_dma(struct snd_dw_hdmi *dw)
{
- void __iomem *base = dw->data.base;
unsigned offset = dw->buf_offset;
unsigned period = dw->buf_period;
u32 start, stop;
@@ -240,18 +272,18 @@ static void dw_hdmi_start_dma(struct snd_dw_hdmi *dw)
dw->reformat(dw, offset, period);
/* Clear all irqs before enabling irqs and starting DMA */
- writeb_relaxed(HDMI_IH_AHBDMAAUD_STAT0_ALL,
- base + HDMI_IH_AHBDMAAUD_STAT0);
+ dw_hdmi_writeb_relaxed(HDMI_IH_AHBDMAAUD_STAT0_ALL,
+ &dw->data, HDMI_IH_AHBDMAAUD_STAT0);
start = dw->buf_addr + offset;
stop = start + period - 1;
/* Setup the hardware start/stop addresses */
- dw_hdmi_writel(start, base + HDMI_AHB_DMA_STRADDR0);
- dw_hdmi_writel(stop, base + HDMI_AHB_DMA_STPADDR0);
+ dw_hdmi_writel(start, &dw->data, HDMI_AHB_DMA_STRADDR0);
+ dw_hdmi_writel(stop, &dw->data, HDMI_AHB_DMA_STPADDR0);
- writeb_relaxed((u8)~HDMI_AHB_DMA_MASK_DONE, base + HDMI_AHB_DMA_MASK);
- writeb(HDMI_AHB_DMA_START_START, base + HDMI_AHB_DMA_START);
+ dw_hdmi_writeb_relaxed((u8)~HDMI_AHB_DMA_MASK_DONE, &dw->data, HDMI_AHB_DMA_MASK);
+ dw_hdmi_writeb(HDMI_AHB_DMA_START_START, &dw->data, HDMI_AHB_DMA_START);
offset += period;
if (offset >= dw->buf_size)
@@ -262,8 +294,8 @@ static void dw_hdmi_start_dma(struct snd_dw_hdmi *dw)
static void dw_hdmi_stop_dma(struct snd_dw_hdmi *dw)
{
/* Disable interrupts before disabling DMA */
- writeb_relaxed(~0, dw->data.base + HDMI_AHB_DMA_MASK);
- writeb_relaxed(HDMI_AHB_DMA_STOP_STOP, dw->data.base + HDMI_AHB_DMA_STOP);
+ dw_hdmi_writeb_relaxed(~0, &dw->data, HDMI_AHB_DMA_MASK);
+ dw_hdmi_writeb_relaxed(HDMI_AHB_DMA_STOP_STOP, &dw->data, HDMI_AHB_DMA_STOP);
}
static irqreturn_t snd_dw_hdmi_irq(int irq, void *data)
@@ -272,11 +304,11 @@ static irqreturn_t snd_dw_hdmi_irq(int irq, void *data)
struct snd_pcm_substream *substream;
unsigned stat;
- stat = readb_relaxed(dw->data.base + HDMI_IH_AHBDMAAUD_STAT0);
+ stat = dw_hdmi_readb_relaxed(&dw->data, HDMI_IH_AHBDMAAUD_STAT0);
if (!stat)
return IRQ_NONE;
- writeb_relaxed(stat, dw->data.base + HDMI_IH_AHBDMAAUD_STAT0);
+ dw_hdmi_writeb_relaxed(stat, &dw->data, HDMI_IH_AHBDMAAUD_STAT0);
substream = dw->substream;
if (stat & HDMI_IH_AHBDMAAUD_STAT0_DONE && substream) {
@@ -319,7 +351,6 @@ static int dw_hdmi_open(struct snd_pcm_substream *substream)
{
struct snd_pcm_runtime *runtime = substream->runtime;
struct snd_dw_hdmi *dw = substream->private_data;
- void __iomem *base = dw->data.base;
int ret;
runtime->hw = dw_hdmi_hw;
@@ -345,16 +376,16 @@ static int dw_hdmi_open(struct snd_pcm_substream *substream)
return ret;
/* Clear FIFO */
- writeb_relaxed(HDMI_AHB_DMA_CONF0_SW_FIFO_RST,
- base + HDMI_AHB_DMA_CONF0);
+ dw_hdmi_writeb_relaxed(HDMI_AHB_DMA_CONF0_SW_FIFO_RST,
+ &dw->data, HDMI_AHB_DMA_CONF0);
/* Configure interrupt polarities */
- writeb_relaxed(~0, base + HDMI_AHB_DMA_POL);
- writeb_relaxed(~0, base + HDMI_AHB_DMA_BUFFPOL);
+ dw_hdmi_writeb_relaxed(~0, &dw->data, HDMI_AHB_DMA_POL);
+ dw_hdmi_writeb_relaxed(~0, &dw->data, HDMI_AHB_DMA_BUFFPOL);
/* Keep interrupts masked, and clear any pending */
- writeb_relaxed(~0, base + HDMI_AHB_DMA_MASK);
- writeb_relaxed(~0, base + HDMI_IH_AHBDMAAUD_STAT0);
+ dw_hdmi_writeb_relaxed(~0, &dw->data, HDMI_AHB_DMA_MASK);
+ dw_hdmi_writeb_relaxed(~0, &dw->data, HDMI_IH_AHBDMAAUD_STAT0);
ret = request_irq(dw->data.irq, snd_dw_hdmi_irq, IRQF_SHARED,
"dw-hdmi-audio", dw);
@@ -362,9 +393,9 @@ static int dw_hdmi_open(struct snd_pcm_substream *substream)
return ret;
/* Un-mute done interrupt */
- writeb_relaxed(HDMI_IH_MUTE_AHBDMAAUD_STAT0_ALL &
- ~HDMI_IH_MUTE_AHBDMAAUD_STAT0_DONE,
- base + HDMI_IH_MUTE_AHBDMAAUD_STAT0);
+ dw_hdmi_writeb_relaxed(HDMI_IH_MUTE_AHBDMAAUD_STAT0_ALL &
+ ~HDMI_IH_MUTE_AHBDMAAUD_STAT0_DONE,
+ &dw->data, HDMI_IH_MUTE_AHBDMAAUD_STAT0);
return 0;
}
@@ -374,8 +405,8 @@ static int dw_hdmi_close(struct snd_pcm_substream *substream)
struct snd_dw_hdmi *dw = substream->private_data;
/* Mute all interrupts */
- writeb_relaxed(HDMI_IH_MUTE_AHBDMAAUD_STAT0_ALL,
- dw->data.base + HDMI_IH_MUTE_AHBDMAAUD_STAT0);
+ dw_hdmi_writeb_relaxed(HDMI_IH_MUTE_AHBDMAAUD_STAT0_ALL,
+ &dw->data, HDMI_IH_MUTE_AHBDMAAUD_STAT0);
free_irq(dw->data.irq, dw);
@@ -416,6 +447,11 @@ static int dw_hdmi_prepare(struct snd_pcm_substream *substream)
HDMI_AHB_DMA_CONF0_INCR8;
threshold = 128;
break;
+ case 0x2a: /* this revision is used in Baikal-M SoC */
+ conf0 = HDMI_AHB_DMA_CONF0_BURST_MODE |
+ HDMI_AHB_DMA_CONF0_INCR16;
+ threshold = 128;
+ break;
default:
/* NOTREACHED */
return -EINVAL;
@@ -430,9 +466,9 @@ static int dw_hdmi_prepare(struct snd_pcm_substream *substream)
conf1 = default_hdmi_channel_config[runtime->channels - 2].conf1;
ca = default_hdmi_channel_config[runtime->channels - 2].ca;
- writeb_relaxed(threshold, dw->data.base + HDMI_AHB_DMA_THRSLD);
- writeb_relaxed(conf0, dw->data.base + HDMI_AHB_DMA_CONF0);
- writeb_relaxed(conf1, dw->data.base + HDMI_AHB_DMA_CONF1);
+ dw_hdmi_writeb_relaxed(threshold, &dw->data, HDMI_AHB_DMA_THRSLD);
+ dw_hdmi_writeb_relaxed(conf0, &dw->data, HDMI_AHB_DMA_CONF0);
+ dw_hdmi_writeb_relaxed(conf1, &dw->data, HDMI_AHB_DMA_CONF1);
dw_hdmi_set_channel_count(dw->data.hdmi, runtime->channels);
dw_hdmi_set_channel_allocation(dw->data.hdmi, ca);
@@ -524,10 +560,10 @@ static int snd_dw_hdmi_probe(struct platform_device *pdev)
unsigned revision;
int ret;
- writeb_relaxed(HDMI_IH_MUTE_AHBDMAAUD_STAT0_ALL,
- data->base + HDMI_IH_MUTE_AHBDMAAUD_STAT0);
- revision = readb_relaxed(data->base + HDMI_REVISION_ID);
- if (revision != 0x0a && revision != 0x1a) {
+ dw_hdmi_writeb_relaxed(HDMI_IH_MUTE_AHBDMAAUD_STAT0_ALL,
+ data, HDMI_IH_MUTE_AHBDMAAUD_STAT0);
+ revision = dw_hdmi_readb_relaxed(data, HDMI_REVISION_ID);
+ if (revision != 0x0a && revision != 0x1a && revision != 0x2a) {
dev_err(dev, "dw-hdmi-audio: unknown revision 0x%02x\n",
revision);
return -ENXIO;
diff --git a/drivers/gpu/drm/bridge/synopsys/dw-hdmi-audio.h b/drivers/gpu/drm/bridge/synopsys/dw-hdmi-audio.h
index cb07dc0da5a7..8fb5ebd5a169 100644
--- a/drivers/gpu/drm/bridge/synopsys/dw-hdmi-audio.h
+++ b/drivers/gpu/drm/bridge/synopsys/dw-hdmi-audio.h
@@ -10,6 +10,7 @@ struct dw_hdmi_audio_data {
int irq;
struct dw_hdmi *hdmi;
u8 *eld;
+ unsigned reg_offset;
};
struct dw_hdmi_i2s_audio_data {
diff --git a/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c b/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c
index 0c79a9ba48bb..d0580b7d7430 100644
--- a/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c
+++ b/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c
@@ -3396,6 +3396,12 @@ struct dw_hdmi *dw_hdmi_probe(struct platform_device *pdev,
audio.irq = irq;
audio.hdmi = hdmi;
audio.eld = hdmi->connector.eld;
+ audio.reg_offset = 0;
+ if (of_device_is_compatible(np, "baikal,hdmi")) {
+ audio.reg_offset = 2;
+ dev_info(dev, "setting audio.reg_offset=%d for BE-M1000 SoC\n",
+ audio.reg_offset);
+ }
hdmi->enable_audio = dw_hdmi_ahb_audio_enable;
hdmi->disable_audio = dw_hdmi_ahb_audio_disable;
--
2.31.1

View file

@ -0,0 +1,252 @@
From 5b71a758ddc825759d287b5077c0f36a25c30da6 Mon Sep 17 00:00:00 2001
From: Alexey Sheplyakov <asheplyakov@altlinux.org>
Date: Thu, 3 Dec 2020 19:02:15 +0400
Subject: [PATCH 612/625] bt1-pvt.c: access registers via pvt_{readl,writel}
helper functions
BE-M1000 SoC is equipped with PVT sensors too. However PVT registers are
not directly accessible to kernel. Instead the registers (and clocks)
are managed by the "secure world", so Linux has to call into firmware.
This patch replaces readl/writel with pvt_readl/pvt_writel functions.
No functional changes is intended. Subsequent patch will define pvt_readl
and pvt_writel functions for BE-M1000 SoC.
---
drivers/hwmon/bt1-pvt.c | 85 +++++++++++++++++++++++------------------
1 file changed, 48 insertions(+), 37 deletions(-)
diff --git a/drivers/hwmon/bt1-pvt.c b/drivers/hwmon/bt1-pvt.c
index 3e1d56585b91..c6749585d604 100644
--- a/drivers/hwmon/bt1-pvt.c
+++ b/drivers/hwmon/bt1-pvt.c
@@ -138,12 +138,23 @@ static long pvt_calc_poly(const struct pvt_poly *poly, long data)
return ret / poly->total_divider;
}
-static inline u32 pvt_update(void __iomem *reg, u32 mask, u32 data)
+static inline u32 pvt_readl(struct pvt_hwmon const *pvt, int reg) {
+ return readl(pvt->regs + reg);
+}
+
+static inline u32 pvt_readl_relaxed(struct pvt_hwmon const *pvt, int reg) {
+ return readl_relaxed(pvt->regs + reg);
+}
+
+static inline void pvt_writel(u32 data, struct pvt_hwmon const *pvt, int reg) {
+ writel(data, pvt->regs + reg);
+}
+static inline u32 pvt_update(struct pvt_hwmon *pvt, int reg, u32 mask, u32 data)
{
u32 old;
- old = readl_relaxed(reg);
- writel((old & ~mask) | (data & mask), reg);
+ old = pvt_readl_relaxed(pvt, reg);
+ pvt_writel((old & ~mask) | (data & mask), pvt, reg);
return old & mask;
}
@@ -161,8 +172,8 @@ static inline void pvt_set_mode(struct pvt_hwmon *pvt, u32 mode)
mode = FIELD_PREP(PVT_CTRL_MODE_MASK, mode);
- old = pvt_update(pvt->regs + PVT_CTRL, PVT_CTRL_EN, 0);
- pvt_update(pvt->regs + PVT_CTRL, PVT_CTRL_MODE_MASK | PVT_CTRL_EN,
+ old = pvt_update(pvt, PVT_CTRL, PVT_CTRL_EN, 0);
+ pvt_update(pvt, PVT_CTRL, PVT_CTRL_MODE_MASK | PVT_CTRL_EN,
mode | old);
}
@@ -179,8 +190,8 @@ static inline void pvt_set_trim(struct pvt_hwmon *pvt, u32 trim)
trim = FIELD_PREP(PVT_CTRL_TRIM_MASK, trim);
- old = pvt_update(pvt->regs + PVT_CTRL, PVT_CTRL_EN, 0);
- pvt_update(pvt->regs + PVT_CTRL, PVT_CTRL_TRIM_MASK | PVT_CTRL_EN,
+ old = pvt_update(pvt, PVT_CTRL, PVT_CTRL_EN, 0);
+ pvt_update(pvt, PVT_CTRL, PVT_CTRL_TRIM_MASK | PVT_CTRL_EN,
trim | old);
}
@@ -188,9 +199,9 @@ static inline void pvt_set_tout(struct pvt_hwmon *pvt, u32 tout)
{
u32 old;
- old = pvt_update(pvt->regs + PVT_CTRL, PVT_CTRL_EN, 0);
- writel(tout, pvt->regs + PVT_TTIMEOUT);
- pvt_update(pvt->regs + PVT_CTRL, PVT_CTRL_EN, old);
+ old = pvt_update(pvt, PVT_CTRL, PVT_CTRL_EN, 0);
+ pvt_writel(tout, pvt, PVT_TTIMEOUT);
+ pvt_update(pvt, PVT_CTRL, PVT_CTRL_EN, old);
}
/*
@@ -237,7 +248,7 @@ static irqreturn_t pvt_soft_isr(int irq, void *data)
* status before the next conversion happens. Threshold events will be
* handled a bit later.
*/
- thres_sts = readl(pvt->regs + PVT_RAW_INTR_STAT);
+ thres_sts = pvt_readl(pvt, PVT_RAW_INTR_STAT);
/*
* Then lets recharge the PVT interface with the next sampling mode.
@@ -260,14 +271,14 @@ static irqreturn_t pvt_soft_isr(int irq, void *data)
*/
mutex_lock(&pvt->iface_mtx);
- old = pvt_update(pvt->regs + PVT_INTR_MASK, PVT_INTR_DVALID,
+ old = pvt_update(pvt, PVT_INTR_MASK, PVT_INTR_DVALID,
PVT_INTR_DVALID);
- val = readl(pvt->regs + PVT_DATA);
+ val = pvt_readl(pvt, PVT_DATA);
pvt_set_mode(pvt, pvt_info[pvt->sensor].mode);
- pvt_update(pvt->regs + PVT_INTR_MASK, PVT_INTR_DVALID, old);
+ pvt_update(pvt, PVT_INTR_MASK, PVT_INTR_DVALID, old);
mutex_unlock(&pvt->iface_mtx);
@@ -337,7 +348,7 @@ static int pvt_read_limit(struct pvt_hwmon *pvt, enum pvt_sensor_type type,
u32 data;
/* No need in serialization, since it is just read from MMIO. */
- data = readl(pvt->regs + pvt_info[type].thres_base);
+ data = pvt_readl(pvt, pvt_info[type].thres_base);
if (is_low)
data = FIELD_GET(PVT_THRES_LO_MASK, data);
@@ -372,7 +383,7 @@ static int pvt_write_limit(struct pvt_hwmon *pvt, enum pvt_sensor_type type,
return ret;
/* Make sure the upper and lower ranges don't intersect. */
- limit = readl(pvt->regs + pvt_info[type].thres_base);
+ limit = pvt_readl(pvt, pvt_info[type].thres_base);
if (is_low) {
limit = FIELD_GET(PVT_THRES_HI_MASK, limit);
data = clamp_val(data, PVT_DATA_MIN, limit);
@@ -385,7 +396,7 @@ static int pvt_write_limit(struct pvt_hwmon *pvt, enum pvt_sensor_type type,
mask = PVT_THRES_HI_MASK;
}
- pvt_update(pvt->regs + pvt_info[type].thres_base, mask, data);
+ pvt_update(pvt, pvt_info[type].thres_base, mask, data);
mutex_unlock(&pvt->iface_mtx);
@@ -439,14 +450,14 @@ static irqreturn_t pvt_hard_isr(int irq, void *data)
* Mask the DVALID interrupt so after exiting from the handler a
* repeated conversion wouldn't happen.
*/
- pvt_update(pvt->regs + PVT_INTR_MASK, PVT_INTR_DVALID,
+ pvt_update(pvt, PVT_INTR_MASK, PVT_INTR_DVALID,
PVT_INTR_DVALID);
/*
* Nothing special for alarm-less driver. Just read the data, update
* the cache and notify a waiter of this event.
*/
- val = readl(pvt->regs + PVT_DATA);
+ val = pvt_readl(pvt, PVT_DATA);
if (!(val & PVT_DATA_VALID)) {
dev_err(pvt->dev, "Got IRQ when data isn't valid\n");
return IRQ_HANDLED;
@@ -498,8 +509,8 @@ static int pvt_read_data(struct pvt_hwmon *pvt, enum pvt_sensor_type type,
* Unmask the DVALID interrupt and enable the sensors conversions.
* Do the reverse procedure when conversion is done.
*/
- pvt_update(pvt->regs + PVT_INTR_MASK, PVT_INTR_DVALID, 0);
- pvt_update(pvt->regs + PVT_CTRL, PVT_CTRL_EN, PVT_CTRL_EN);
+ pvt_update(pvt, PVT_INTR_MASK, PVT_INTR_DVALID, 0);
+ pvt_update(pvt, PVT_CTRL, PVT_CTRL_EN, PVT_CTRL_EN);
/*
* Wait with timeout since in case if the sensor is suddenly powered
@@ -510,8 +521,8 @@ static int pvt_read_data(struct pvt_hwmon *pvt, enum pvt_sensor_type type,
timeout = 2 * usecs_to_jiffies(ktime_to_us(pvt->timeout));
ret = wait_for_completion_timeout(&cache->conversion, timeout);
- pvt_update(pvt->regs + PVT_CTRL, PVT_CTRL_EN, 0);
- pvt_update(pvt->regs + PVT_INTR_MASK, PVT_INTR_DVALID,
+ pvt_update(pvt, PVT_CTRL, PVT_CTRL_EN, 0);
+ pvt_update(pvt, PVT_INTR_MASK, PVT_INTR_DVALID,
PVT_INTR_DVALID);
data = READ_ONCE(cache->data);
@@ -637,7 +648,7 @@ static int pvt_read_trim(struct pvt_hwmon *pvt, long *val)
{
u32 data;
- data = readl(pvt->regs + PVT_CTRL);
+ data = pvt_readl(pvt, PVT_CTRL);
*val = FIELD_GET(PVT_CTRL_TRIM_MASK, data) * PVT_TRIM_STEP;
return 0;
@@ -983,21 +994,21 @@ static int pvt_check_pwr(struct pvt_hwmon *pvt)
* conversion. In the later case alas we won't be able to detect the
* problem.
*/
- pvt_update(pvt->regs + PVT_INTR_MASK, PVT_INTR_ALL, PVT_INTR_ALL);
- pvt_update(pvt->regs + PVT_CTRL, PVT_CTRL_EN, PVT_CTRL_EN);
+ pvt_update(pvt, PVT_INTR_MASK, PVT_INTR_ALL, PVT_INTR_ALL);
+ pvt_update(pvt, PVT_CTRL, PVT_CTRL_EN, PVT_CTRL_EN);
pvt_set_tout(pvt, 0);
- readl(pvt->regs + PVT_DATA);
+ pvt_readl(pvt, PVT_DATA);
tout = PVT_TOUT_MIN / NSEC_PER_USEC;
usleep_range(tout, 2 * tout);
- data = readl(pvt->regs + PVT_DATA);
+ data = pvt_readl(pvt, PVT_DATA);
if (!(data & PVT_DATA_VALID)) {
ret = -ENODEV;
dev_err(pvt->dev, "Sensor is powered down\n");
}
- pvt_update(pvt->regs + PVT_CTRL, PVT_CTRL_EN, 0);
+ pvt_update(pvt, PVT_CTRL, PVT_CTRL_EN, 0);
return ret;
}
@@ -1018,10 +1029,10 @@ static int pvt_init_iface(struct pvt_hwmon *pvt)
* accidentally have ISR executed before the driver data is fully
* initialized. Clear the IRQ status as well.
*/
- pvt_update(pvt->regs + PVT_INTR_MASK, PVT_INTR_ALL, PVT_INTR_ALL);
- pvt_update(pvt->regs + PVT_CTRL, PVT_CTRL_EN, 0);
- readl(pvt->regs + PVT_CLR_INTR);
- readl(pvt->regs + PVT_DATA);
+ pvt_update(pvt, PVT_INTR_MASK, PVT_INTR_ALL, PVT_INTR_ALL);
+ pvt_update(pvt, PVT_CTRL, PVT_CTRL_EN, 0);
+ pvt_readl(pvt, PVT_CLR_INTR);
+ pvt_readl(pvt, PVT_DATA);
/* Setup default sensor mode, timeout and temperature trim. */
pvt_set_mode(pvt, pvt_info[pvt->sensor].mode);
@@ -1105,8 +1116,8 @@ static void pvt_disable_iface(void *data)
struct pvt_hwmon *pvt = data;
mutex_lock(&pvt->iface_mtx);
- pvt_update(pvt->regs + PVT_CTRL, PVT_CTRL_EN, 0);
- pvt_update(pvt->regs + PVT_INTR_MASK, PVT_INTR_DVALID,
+ pvt_update(pvt, PVT_CTRL, PVT_CTRL_EN, 0);
+ pvt_update(pvt, PVT_INTR_MASK, PVT_INTR_DVALID,
PVT_INTR_DVALID);
mutex_unlock(&pvt->iface_mtx);
}
@@ -1128,8 +1139,8 @@ static int pvt_enable_iface(struct pvt_hwmon *pvt)
* which theoretically may cause races.
*/
mutex_lock(&pvt->iface_mtx);
- pvt_update(pvt->regs + PVT_INTR_MASK, PVT_INTR_DVALID, 0);
- pvt_update(pvt->regs + PVT_CTRL, PVT_CTRL_EN, PVT_CTRL_EN);
+ pvt_update(pvt, PVT_INTR_MASK, PVT_INTR_DVALID, 0);
+ pvt_update(pvt, PVT_CTRL, PVT_CTRL_EN, PVT_CTRL_EN);
mutex_unlock(&pvt->iface_mtx);
return 0;
--
2.31.1

View file

@ -0,0 +1,87 @@
From bb4383c2491f602cb87e619418cbff9c32a0f0ac Mon Sep 17 00:00:00 2001
From: Alexey Sheplyakov <asheplyakov@altlinux.org>
Date: Thu, 3 Dec 2020 19:13:51 +0400
Subject: [PATCH 613/625] bt1-pvt: define pvt_readl/pvt_writel for BE-M1000 SoC
---
drivers/hwmon/bt1-pvt.c | 23 +++++++++++++++++++++++
drivers/hwmon/bt1-pvt.h | 8 ++++++++
2 files changed, 31 insertions(+)
diff --git a/drivers/hwmon/bt1-pvt.c b/drivers/hwmon/bt1-pvt.c
index c6749585d604..d1f66de6a2cd 100644
--- a/drivers/hwmon/bt1-pvt.c
+++ b/drivers/hwmon/bt1-pvt.c
@@ -29,6 +29,9 @@
#include <linux/seqlock.h>
#include <linux/sysfs.h>
#include <linux/types.h>
+#ifdef CONFIG_ARM64
+#include <linux/arm-smccc.h>
+#endif
#include "bt1-pvt.h"
@@ -138,6 +141,7 @@ static long pvt_calc_poly(const struct pvt_poly *poly, long data)
return ret / poly->total_divider;
}
+#ifdef BT1_PVT_DIRECT_REG_ACCESS
static inline u32 pvt_readl(struct pvt_hwmon const *pvt, int reg) {
return readl(pvt->regs + reg);
}
@@ -149,6 +153,25 @@ static inline u32 pvt_readl_relaxed(struct pvt_hwmon const *pvt, int reg) {
static inline void pvt_writel(u32 data, struct pvt_hwmon const *pvt, int reg) {
writel(data, pvt->regs + reg);
}
+#else
+static inline u32 pvt_readl(struct pvt_hwmon const *pvt, int reg) {
+ struct arm_smccc_res res;
+ arm_smccc_smc(BAIKAL_SMC_PVT_ID, PVT_READ, pvt->pvt_id, reg,
+ 0, 0, 0, 0, &res);
+ return res.a0;
+}
+
+static inline u32 pvt_readl_relaxed(struct pvt_hwmon const *pvt, int reg) {
+ return pvt_readl(pvt, reg);
+}
+
+static inline void pvt_writel(u32 data, struct pvt_hwmon const *pvt, int reg) {
+ struct arm_smccc_res res;
+ arm_smccc_smc(BAIKAL_SMC_PVT_ID, PVT_WRITE, pvt->pvt_id, reg,
+ data, 0, 0, 0, &res);
+}
+#endif
+
static inline u32 pvt_update(struct pvt_hwmon *pvt, int reg, u32 mask, u32 data)
{
u32 old;
diff --git a/drivers/hwmon/bt1-pvt.h b/drivers/hwmon/bt1-pvt.h
index 93b8dd5e7c94..0cea95b01c13 100644
--- a/drivers/hwmon/bt1-pvt.h
+++ b/drivers/hwmon/bt1-pvt.h
@@ -101,6 +101,13 @@
# define PVT_TOUT_DEF 0
#endif
+#define BAIKAL_SMC_PVT_ID 0x82000001
+#define PVT_READ 0
+#define PVT_WRITE 1
+#ifndef CONFIG_ARM64
+#define BT1_PVT_DIRECT_REG_ACCESS
+#endif
+
/*
* enum pvt_sensor_type - Baikal-T1 PVT sensor types (correspond to each PVT
* sampling mode)
@@ -217,6 +224,7 @@ struct pvt_hwmon {
enum pvt_sensor_type sensor;
struct pvt_cache cache[PVT_SENSORS_NUM];
ktime_t timeout;
+ int pvt_id;
};
/*
--
2.31.1

View file

@ -0,0 +1,135 @@
From 1048ea091c614a2514a0e851d6c614de572e1141 Mon Sep 17 00:00:00 2001
From: Alexey Sheplyakov <asheplyakov@altlinux.org>
Date: Thu, 3 Dec 2020 19:22:04 +0400
Subject: [PATCH 614/625] bt1-pvt: adjust probing for BE-M1000 SoC
The registers and clocks are managed by the secure world and can't be
accessed by Linux directly. Therefore skip enabling/disabling clocks
and ioremapping registers on BE-M1000.
Also a sensor is identified by special `pvt_id' instead of registers base
address. pvt_id is initialized from the device tree.
---
drivers/hwmon/Kconfig | 7 ++++---
drivers/hwmon/bt1-pvt.c | 28 ++++++++++++++++++++++++----
2 files changed, 28 insertions(+), 7 deletions(-)
diff --git a/drivers/hwmon/Kconfig b/drivers/hwmon/Kconfig
index a850e4f0e0bd..efaf8ba21e7b 100644
--- a/drivers/hwmon/Kconfig
+++ b/drivers/hwmon/Kconfig
@@ -415,10 +415,11 @@ config SENSORS_ATXP1
will be called atxp1.
config SENSORS_BT1_PVT
- tristate "Baikal-T1 Process, Voltage, Temperature sensor driver"
- depends on MIPS_BAIKAL_T1 || COMPILE_TEST
+ tristate "Baikal-T1/M Process, Voltage, Temperature sensor driver"
+ depends on MIPS_BAIKAL_T1 || ARCH_BAIKAL || COMPILE_TEST
+ default m if MIPS_BAIKAL_T1 || ARCH_BAIKAL
help
- If you say yes here you get support for Baikal-T1 PVT sensor
+ If you say yes here you get support for Baikal-M or Baikal-T1 PVT sensor
embedded into the SoC.
This driver can also be built as a module. If so, the module will be
diff --git a/drivers/hwmon/bt1-pvt.c b/drivers/hwmon/bt1-pvt.c
index d1f66de6a2cd..38774ec33ee1 100644
--- a/drivers/hwmon/bt1-pvt.c
+++ b/drivers/hwmon/bt1-pvt.c
@@ -950,6 +950,7 @@ static int pvt_request_regs(struct pvt_hwmon *pvt)
{
struct platform_device *pdev = to_platform_device(pvt->dev);
struct resource *res;
+ int err = 0;
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
if (!res) {
@@ -957,11 +958,19 @@ static int pvt_request_regs(struct pvt_hwmon *pvt)
return -EINVAL;
}
+#ifdef BT1_PVT_DIRECT_REG_ACCESS
pvt->regs = devm_ioremap_resource(pvt->dev, res);
if (IS_ERR(pvt->regs)) {
dev_err(pvt->dev, "Couldn't map PVT registers\n");
return PTR_ERR(pvt->regs);
}
+#else
+ err = of_property_read_u32(pvt->dev->of_node, "pvt_id", &(pvt->pvt_id));
+ if (err) {
+ dev_err(pvt->dev, "couldn't find pvt_id\n");
+ return err;
+ }
+#endif
return 0;
}
@@ -975,11 +984,12 @@ static void pvt_disable_clks(void *data)
static int pvt_request_clks(struct pvt_hwmon *pvt)
{
- int ret;
+ int ret = 0;
pvt->clks[PVT_CLOCK_APB].id = "pclk";
pvt->clks[PVT_CLOCK_REF].id = "ref";
+#ifdef BT1_PVT_DIRECT_REG_ACCESS
ret = devm_clk_bulk_get(pvt->dev, PVT_CLOCK_NUM, pvt->clks);
if (ret) {
dev_err(pvt->dev, "Couldn't get PVT clocks descriptors\n");
@@ -997,8 +1007,11 @@ static int pvt_request_clks(struct pvt_hwmon *pvt)
dev_err(pvt->dev, "Can't add PVT clocks disable action\n");
return ret;
}
-
- return 0;
+#else
+ pvt->clks[PVT_CLOCK_APB].clk = NULL;
+ pvt->clks[PVT_CLOCK_REF].clk = NULL;
+#endif
+ return ret;
}
static int pvt_check_pwr(struct pvt_hwmon *pvt)
@@ -1038,14 +1051,17 @@ static int pvt_check_pwr(struct pvt_hwmon *pvt)
static int pvt_init_iface(struct pvt_hwmon *pvt)
{
- unsigned long rate;
u32 trim, temp;
+#ifdef BT1_PVT_DIRECT_REG_ACCESS
+ unsigned long rate;
+
rate = clk_get_rate(pvt->clks[PVT_CLOCK_REF].clk);
if (!rate) {
dev_err(pvt->dev, "Invalid reference clock rate\n");
return -ENODEV;
}
+#endif
/*
* Make sure all interrupts and controller are disabled so not to
@@ -1074,6 +1090,7 @@ static int pvt_init_iface(struct pvt_hwmon *pvt)
* polled. In that case the formulae will look a bit different:
* Ttotal = 5 * (N / Fclk + Tmin)
*/
+#if defined(BT1_PVT_DIRECT_REG_ACCESS)
#if defined(CONFIG_SENSORS_BT1_PVT_ALARMS)
pvt->timeout = ktime_set(PVT_SENSORS_NUM * PVT_TOUT_DEF, 0);
pvt->timeout = ktime_divns(pvt->timeout, rate);
@@ -1083,6 +1100,9 @@ static int pvt_init_iface(struct pvt_hwmon *pvt)
pvt->timeout = ktime_divns(pvt->timeout, rate);
pvt->timeout = ktime_add_ns(pvt->timeout, PVT_TOUT_MIN);
#endif
+#else
+ pvt->timeout = ktime_set(0, PVT_TOUT_MIN * PVT_SENSORS_NUM);
+#endif
trim = PVT_TRIM_DEF;
if (!of_property_read_u32(pvt->dev->of_node,
--
2.31.1

View file

@ -0,0 +1,27 @@
From 7028d81bce581b1075c55b34f2596f16ae8686ce Mon Sep 17 00:00:00 2001
From: Alexey Sheplyakov <asheplyakov@altlinux.org>
Date: Thu, 3 Dec 2020 19:24:00 +0400
Subject: [PATCH 615/625] bt1-pvt: added compatible baikal,pvt
So the driver will be loaded on existing BE-M1000 based boards.
X-DONTUPSTREAM
---
drivers/hwmon/bt1-pvt.c | 1 +
1 file changed, 1 insertion(+)
diff --git a/drivers/hwmon/bt1-pvt.c b/drivers/hwmon/bt1-pvt.c
index 38774ec33ee1..585614a384e1 100644
--- a/drivers/hwmon/bt1-pvt.c
+++ b/drivers/hwmon/bt1-pvt.c
@@ -1240,6 +1240,7 @@ static int pvt_probe(struct platform_device *pdev)
static const struct of_device_id pvt_of_match[] = {
{ .compatible = "baikal,bt1-pvt" },
+ { .compatible = "baikal,pvt" },
{ }
};
MODULE_DEVICE_TABLE(of, pvt_of_match);
--
2.31.1

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,861 @@
From 1865253e6f0bd9dd35495cf5c5cc0db1c5df071b Mon Sep 17 00:00:00 2001
From: Alexey Sheplyakov <asheplyakov@altlinux.org>
Date: Thu, 14 Jan 2021 12:25:44 +0400
Subject: [PATCH 617/625] Baikal-M: PCIe driver from SDK-M 4.4
Appears to successfully probe the hardware, lspci -vv output
looks good. No other testing has been done yet.
---
drivers/pci/controller/dwc/Makefile | 2 +-
drivers/pci/controller/dwc/pcie-baikal-v44.c | 826 +++++++++++++++++++
2 files changed, 827 insertions(+), 1 deletion(-)
create mode 100644 drivers/pci/controller/dwc/pcie-baikal-v44.c
diff --git a/drivers/pci/controller/dwc/Makefile b/drivers/pci/controller/dwc/Makefile
index 85e6ad1954e5..dcd23d7d5430 100644
--- a/drivers/pci/controller/dwc/Makefile
+++ b/drivers/pci/controller/dwc/Makefile
@@ -20,7 +20,7 @@ obj-$(CONFIG_PCI_MESON) += pci-meson.o
obj-$(CONFIG_PCIE_TEGRA194) += pcie-tegra194.o
obj-$(CONFIG_PCIE_UNIPHIER) += pcie-uniphier.o
obj-$(CONFIG_PCIE_UNIPHIER_EP) += pcie-uniphier-ep.o
-obj-$(CONFIG_PCI_BAIKAL) += pcie-baikal.o
+obj-$(CONFIG_PCI_BAIKAL) += pcie-baikal.o pcie-baikal-v44.o
# The following drivers are for devices that use the generic ACPI
# pci_root.c driver but don't support standard ECAM config access.
diff --git a/drivers/pci/controller/dwc/pcie-baikal-v44.c b/drivers/pci/controller/dwc/pcie-baikal-v44.c
new file mode 100644
index 000000000000..5e5f0a9e59e2
--- /dev/null
+++ b/drivers/pci/controller/dwc/pcie-baikal-v44.c
@@ -0,0 +1,826 @@
+/*
+ * PCIe root complex driver for Baikal SoCs
+ *
+ * Copyright (C) 2019-2020 Baikal Electronics, JSC
+ * Authors: Pavel Parkhomenko <pavel.parkhomenko@baikalelectronics.ru>
+ * Mikhail Ivanov <michail.ivanov@baikalelectronics.ru>
+ *
+ * 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.
+ */
+
+#include <linux/interrupt.h>
+#include <linux/module.h>
+#include <linux/irqchip/arm-gic-v3.h>
+#include <linux/mfd/baikal/lcru-pcie.h>
+#include <linux/mfd/syscon.h>
+#include <linux/of_address.h>
+#include <linux/of_device.h>
+#include <linux/of_gpio.h>
+#include <linux/pci.h>
+#include <linux/phy/phy.h>
+
+#include "pcie-designware.h"
+
+#ifdef CONFIG_PCI_DEBUG
+#define DEBUG
+#endif
+
+struct baikal_pcie {
+ struct dw_pcie pp;
+ unsigned bus_nr;
+ struct regmap *lcru;
+ struct gpio_desc *reset_gpio;
+ unsigned reset_active_low;
+ char reset_name[32];
+ unsigned retrained;
+ unsigned num_lanes;
+};
+
+#define to_baikal_pcie(x) container_of((x), struct baikal_pcie, pp)
+
+#define PCIE_DEVICE_CONTROL_DEVICE_STATUS_REG 0x78
+#define PCIE_CAP_CORR_ERR_REPORT_EN BIT(0)
+#define PCIE_CAP_NON_FATAL_ERR_REPORT_EN BIT(1)
+#define PCIE_CAP_FATAL_ERR_REPORT_EN BIT(2)
+#define PCIE_CAP_UNSUPPORT_REQ_REP_EN BIT(3)
+
+#define PCIE_LINK_CAPABILITIES_REG 0x7c
+#define PCIE_CAP_MAX_LINK_WIDTH_MASK 0x3f0
+#define PCIE_CAP_MAX_LINK_WIDTH_SHIFT 4
+
+#define PCIE_LINK_CONTROL_LINK_STATUS_REG 0x80
+#define PCIE_CAP_LINK_SPEED_MASK 0xf0000
+#define PCIE_CAP_LINK_SPEED_SHIFT 16
+#define PCIE_CAP_NEGO_LINK_WIDTH_MASK 0x3f00000
+#define PCIE_CAP_NEGO_LINK_WIDTH_SHIFT 20
+#define PCIE_CAP_LINK_TRAINING BIT(27)
+
+#define PCIE_ROOT_CONTROL_ROOT_CAPABILITIES_REG 0x8c
+#define PCIE_CAP_SYS_ERR_ON_CORR_ERR_EN BIT(0)
+#define PCIE_CAP_SYS_ERR_ON_NON_FATAL_ERR_EN BIT(1)
+#define PCIE_CAP_SYS_ERR_ON_FATAL_ERR_EN BIT(2)
+#define PCIE_CAP_PME_INT_EN BIT(3)
+
+#define PCIE_LINK_CONTROL2_LINK_STATUS2_REG 0xa0
+#define PCIE_CAP_TARGET_LINK_SPEED_MASK 0xf
+
+#define PCIE_UNCORR_ERR_STATUS_REG 0x104
+#define PCIE_CORR_ERR_STATUS_REG 0x110
+
+#define PCIE_ROOT_ERR_CMD_REG 0x12c
+#define PCIE_CORR_ERR_REPORTING_EN BIT(0)
+#define PCIE_NON_FATAL_ERR_REPORTING_EN BIT(1)
+#define PCIE_FATAL_ERR_REPORTING_EN BIT(2)
+
+#define PCIE_ROOT_ERR_STATUS_REG 0x130
+
+#define PCIE_GEN2_CTRL_REG 0x80c
+#define PCIE_DIRECT_SPEED_CHANGE BIT(17)
+
+#define PCIE_MSI_CTRL_ADDR_LO_REG 0x820
+#define PCIE_MSI_CTRL_ADDR_HI_REG 0x824
+
+#define PCIE_MISC_CONTROL_1_REG 0x8bc
+#define PCIE_DBI_RO_RW_EN BIT(0)
+
+#define PCIE_IATU_VIEWPORT_REG 0x900
+#define PCIE_IATU_REGION_INBOUND BIT(31)
+#define PCIE_IATU_REGION_OUTBOUND 0
+#define PCIE_IATU_REGION_CTRL_2_REG 0x908
+
+static const struct of_device_id of_baikal_pcie_match[] = {
+ { .compatible = "baikal,pcie-m", },
+ {},
+};
+
+static unsigned baikal_pcie_link_is_training(struct dw_pcie *pp)
+{
+ unsigned long reg;
+ reg = dw_pcie_readl_dbi(pp, PCIE_LINK_CONTROL_LINK_STATUS_REG);
+ return reg & PCIE_CAP_LINK_TRAINING;
+}
+
+static bool baikal_wait_pcie_link_training_done(struct dw_pcie *pp)
+{
+ unsigned long start_jiffies = jiffies;
+ while (baikal_pcie_link_is_training(pp)) {
+ if (time_after(jiffies, start_jiffies + HZ)) {
+ pr_err("%s: link retrained for too long, timeout occured\n", __func__);
+ return false;
+ }
+ udelay(100);
+ }
+ return true;
+}
+
+static void baikal_print_link_status(struct dw_pcie *pp)
+{
+ unsigned long reg;
+ unsigned speed, width;
+
+ reg = dw_pcie_readl_dbi(pp, PCIE_LINK_CONTROL_LINK_STATUS_REG);
+ speed = (reg & PCIE_CAP_LINK_SPEED_MASK) >> PCIE_CAP_LINK_SPEED_SHIFT;
+ width = (reg & PCIE_CAP_NEGO_LINK_WIDTH_MASK) >>
+ PCIE_CAP_NEGO_LINK_WIDTH_SHIFT;
+
+ dev_info(pp->dev, "link status is Gen%u, x%u\n", speed, width);
+}
+
+static void baikal_pcie_link_retrain(struct dw_pcie *pp, int target_speed)
+{
+ unsigned long reg;
+ unsigned long start_jiffies;
+
+ dev_info(pp->dev, "retrain link to Gen%u\n", target_speed);
+
+ /* In case link is already training wait for training to complete */
+ baikal_wait_pcie_link_training_done(pp);
+
+ /* Set desired speed */
+ reg = dw_pcie_readl_dbi(pp, PCIE_LINK_CONTROL2_LINK_STATUS2_REG);
+ reg &= ~PCIE_CAP_TARGET_LINK_SPEED_MASK;
+ reg |= target_speed;
+ dw_pcie_writel_dbi(pp, PCIE_LINK_CONTROL2_LINK_STATUS2_REG, reg);
+
+ /* Set DIRECT_SPEED_CHANGE bit */
+ reg = dw_pcie_readl_dbi(pp, PCIE_GEN2_CTRL_REG);
+ reg &= ~PCIE_DIRECT_SPEED_CHANGE;
+ dw_pcie_writel_dbi(pp, PCIE_GEN2_CTRL_REG, reg);
+ reg |= PCIE_DIRECT_SPEED_CHANGE;
+ dw_pcie_writel_dbi(pp, PCIE_GEN2_CTRL_REG, reg);
+
+ /* Wait for link training begin */
+ start_jiffies = jiffies;
+ while (baikal_pcie_link_is_training(pp) == 0) {
+ if (time_after(jiffies, start_jiffies + HZ)) {
+ pr_err("%s: link retrained for too long, timeout occured\n", __func__);
+ break;
+ }
+ udelay(100);
+ }
+
+ /* Wait for link training end */
+ baikal_wait_pcie_link_training_done(pp);
+
+ if (dw_pcie_wait_for_link(pp) == 0) {
+ baikal_print_link_status(pp);
+ }
+}
+
+static void baikal_pcie_link_speed_fixup(struct pci_dev *pdev)
+{
+ struct pcie_port *portp = pdev->bus->sysdata;
+ struct dw_pcie *pp = to_dw_pcie_from_pp(portp);
+ struct baikal_pcie *pcie = to_baikal_pcie(pp);
+ unsigned dev_lnkcap_speed;
+ unsigned dev_lnkcap_width;
+ unsigned rc_lnkcap_speed;
+ unsigned rc_lnksta_speed;
+ unsigned rc_target_speed;
+ u32 reg;
+
+ /* Skip Root Bridge */
+ if (!pdev->bus->self) {
+ return;
+ }
+
+ /* Skip any devices not directly connected to the RC */
+ if (pdev->bus->self->bus->number != portp->bridge->bus->number) {
+ return;
+ }
+
+ /* Skip if the bus has already been retrained */
+ if (pcie->retrained) {
+ return;
+ }
+
+ reg = dw_pcie_readl_dbi(pp, PCIE_LINK_CAPABILITIES_REG);
+ rc_lnkcap_speed = reg & PCI_EXP_LNKCAP_SLS;
+
+ reg = dw_pcie_readl_dbi(pp, PCIE_LINK_CONTROL_LINK_STATUS_REG);
+ rc_lnksta_speed = (reg & PCIE_CAP_LINK_SPEED_MASK) >>
+ PCIE_CAP_LINK_SPEED_SHIFT;
+
+ rc_target_speed = rc_lnksta_speed < 3? rc_lnksta_speed + 1 : 3;
+
+ pcie_capability_read_dword(pdev, PCI_EXP_LNKCAP, &reg);
+ dev_lnkcap_speed = (reg & PCI_EXP_LNKCAP_SLS);
+ dev_lnkcap_width = (reg & PCI_EXP_LNKCAP_MLW) >> PCI_EXP_LNKSTA_NLW_SHIFT;
+
+ baikal_print_link_status(pp);
+ dev_info(&pdev->dev, "device link capability is Gen%u, x%u\n",
+ dev_lnkcap_speed, dev_lnkcap_width);
+
+ while (rc_target_speed > rc_lnksta_speed &&
+ rc_target_speed <= rc_lnkcap_speed &&
+ rc_target_speed <= dev_lnkcap_speed) {
+ /* Try to change link speed */
+ baikal_pcie_link_retrain(pp, rc_target_speed);
+ reg = dw_pcie_readl_dbi(pp, PCIE_LINK_CONTROL_LINK_STATUS_REG);
+ rc_lnksta_speed = (reg & PCIE_CAP_LINK_SPEED_MASK) >>
+ PCIE_CAP_LINK_SPEED_SHIFT;
+
+ /* Check if the targeted speed has not been reached */
+ if (rc_lnksta_speed < rc_target_speed) {
+ /* Check if the retraining has led to speed regression */
+ if (rc_lnksta_speed < (rc_target_speed - 1)) {
+ /* Fall back to the previous speed */
+ --rc_target_speed;
+ baikal_pcie_link_retrain(pp, rc_target_speed);
+ }
+
+ break;
+ }
+
+ ++rc_target_speed;
+ }
+
+ pcie->retrained = 1;
+}
+
+static void baikal_pcie_retrain_links(const struct pci_bus *bus)
+{
+ struct pci_dev *dev;
+ struct pci_bus *child;
+
+ list_for_each_entry(dev, &bus->devices, bus_list)
+ baikal_pcie_link_speed_fixup(dev);
+
+ list_for_each_entry(dev, &bus->devices, bus_list) {
+ child = dev->subordinate;
+ if (child)
+ baikal_pcie_retrain_links(child);
+ }
+}
+
+static int baikal_pcie_link_up(struct dw_pcie *pp)
+{
+ struct baikal_pcie *pcie = to_baikal_pcie(pp);
+ unsigned long reg;
+
+ reg = baikal_pcie_lcru_readl(pcie->lcru,
+ BAIKAL_LCRU_PCIE_GEN_CTL(pcie->bus_nr));
+
+ if ((reg & BAIKAL_PCIE_LTSSM_ENABLE) == 0) {
+ return 0;
+ }
+
+ reg = baikal_pcie_lcru_readl(pcie->lcru,
+ BAIKAL_LCRU_PCIE_STATUS(pcie->bus_nr));
+
+ return (reg & BAIKAL_PCIE_SMLH_LINKUP) &&
+ (reg & BAIKAL_PCIE_RDLH_LINKUP);
+}
+
+static int baikal_pcie_get_msi(struct baikal_pcie *pcie,
+ struct device_node *msi_node,
+ u64 *msi_addr)
+{
+ struct device *dev = pcie->pp.dev;
+ int ret;
+ struct resource res;
+
+ /*
+ * Check if 'msi-parent' points to ARM GICv3 ITS, which is the only
+ * supported MSI controller.
+ */
+ if (!of_device_is_compatible(msi_node, "arm,gic-v3-its")) {
+ dev_err(dev, "unable to find compatible MSI controller\n");
+ return -ENODEV;
+ }
+
+ /* Derive GITS_TRANSLATER address from GICv3 */
+ ret = of_address_to_resource(msi_node, 0, &res);
+ if (ret < 0) {
+ dev_err(dev, "unable to obtain MSI controller resources\n");
+ return ret;
+ }
+
+ *msi_addr = res.start + GITS_TRANSLATER;
+ return 0;
+}
+
+static int baikal_pcie_msi_steer(struct baikal_pcie *pcie,
+ struct device_node *msi_node)
+{
+ struct dw_pcie *pp = &pcie->pp;
+ struct device *dev = pp->dev;
+ int ret;
+ u64 msi_addr;
+
+ ret = baikal_pcie_get_msi(pcie, msi_node, &msi_addr);
+ if (ret < 0) {
+ dev_err(dev, "MSI steering failed\n");
+ return ret;
+ }
+
+ /* Program the msi_data */
+ dw_pcie_write(pp->dbi_base + PCIE_MSI_CTRL_ADDR_LO_REG, 4,
+ lower_32_bits(msi_addr));
+ dw_pcie_write(pp->dbi_base + PCIE_MSI_CTRL_ADDR_HI_REG, 4,
+ upper_32_bits(msi_addr));
+ return 0;
+}
+
+static int baikal_pcie_msi_enable(struct baikal_pcie *pcie)
+{
+ struct device *dev = pcie->pp.dev;
+ struct device_node *msi_node;
+ int ret;
+
+ /*
+ * The "msi-parent" phandle needs to exist
+ * for us to obtain the MSI node.
+ */
+ msi_node = of_parse_phandle(dev->of_node, "msi-parent", 0);
+ if (!msi_node) {
+ dev_err(dev, "failed to read msi-parent node from FDT\n");
+ return -ENODEV;
+ }
+
+ ret = baikal_pcie_msi_steer(pcie, msi_node);
+ if (ret) {
+ goto out_put_node;
+ }
+
+out_put_node:
+ of_node_put(msi_node);
+ return ret;
+}
+
+static irqreturn_t baikal_pcie_err_irq_handler(int irq, void *priv)
+{
+ struct baikal_pcie *pcie = priv;
+ struct device *dev = pcie->pp.dev;
+ unsigned long corr_err_status;
+ unsigned long dev_ctrl_dev_status;
+ unsigned long root_err_status;
+ unsigned long uncorr_err_status;
+
+ uncorr_err_status = dw_pcie_readl_dbi(&pcie->pp,
+ PCIE_UNCORR_ERR_STATUS_REG);
+ corr_err_status = dw_pcie_readl_dbi(&pcie->pp,
+ PCIE_CORR_ERR_STATUS_REG);
+ root_err_status = dw_pcie_readl_dbi(&pcie->pp,
+ PCIE_ROOT_ERR_STATUS_REG);
+ dev_ctrl_dev_status = dw_pcie_readl_dbi(&pcie->pp,
+ PCIE_DEVICE_CONTROL_DEVICE_STATUS_REG);
+ dev_err(dev,
+ "dev_err:0x%lx root_err:0x%lx uncorr_err:0x%lx corr_err:0x%lx\n",
+ (dev_ctrl_dev_status & 0xf0000) >> 16,
+ root_err_status, uncorr_err_status, corr_err_status);
+
+ dw_pcie_writel_dbi(&pcie->pp,
+ PCIE_UNCORR_ERR_STATUS_REG, uncorr_err_status);
+ dw_pcie_writel_dbi(&pcie->pp,
+ PCIE_CORR_ERR_STATUS_REG, corr_err_status);
+ dw_pcie_writel_dbi(&pcie->pp,
+ PCIE_ROOT_ERR_STATUS_REG, root_err_status);
+ dw_pcie_writel_dbi(&pcie->pp,
+ PCIE_DEVICE_CONTROL_DEVICE_STATUS_REG, dev_ctrl_dev_status);
+
+ return IRQ_HANDLED;
+}
+
+static int baikal_pcie_host_init(struct pcie_port *port)
+{
+ struct dw_pcie* pp = to_dw_pcie_from_pp(port);
+ struct device *dev = pp->dev;
+ struct baikal_pcie *pcie = to_baikal_pcie(pp);
+ int err;
+ int linkup;
+ unsigned idx;
+ unsigned long reg;
+
+ /* Disable access to PHY registers and DBI2 mode */
+ reg = baikal_pcie_lcru_readl(pcie->lcru,
+ BAIKAL_LCRU_PCIE_GEN_CTL(pcie->bus_nr));
+
+ reg &= ~(BAIKAL_PCIE_PHY_MGMT_ENABLE |
+ BAIKAL_PCIE_DBI2_MODE);
+
+ baikal_pcie_lcru_writel(pcie->lcru,
+ BAIKAL_LCRU_PCIE_GEN_CTL(pcie->bus_nr), reg);
+
+ pcie->retrained = 0;
+ linkup = baikal_pcie_link_up(pp);
+
+ /* If link is not established yet, reset the RC */
+ if (!linkup) {
+ /* Disable link training */
+ reg = baikal_pcie_lcru_readl(pcie->lcru,
+ BAIKAL_LCRU_PCIE_GEN_CTL(pcie->bus_nr));
+
+ reg &= ~BAIKAL_PCIE_LTSSM_ENABLE;
+ baikal_pcie_lcru_writel(pcie->lcru,
+ BAIKAL_LCRU_PCIE_GEN_CTL(pcie->bus_nr), reg);
+
+ /* Assert PERST pin */
+ if (pcie->reset_gpio != NULL) {
+ unsigned long gpio_flags;
+
+ if (pcie->reset_active_low) {
+ gpio_flags = GPIOF_ACTIVE_LOW |
+ GPIOF_OUT_INIT_LOW;
+ } else {
+ gpio_flags = GPIOF_OUT_INIT_HIGH;
+ }
+
+ err = devm_gpio_request_one(dev,
+ desc_to_gpio(pcie->reset_gpio),
+ gpio_flags, pcie->reset_name);
+
+ if (err) {
+ dev_err(dev, "request GPIO failed (%d)\n", err);
+ return -ENODEV;
+ }
+ }
+
+ /* Reset the RC */
+ reg = baikal_pcie_lcru_readl(pcie->lcru,
+ BAIKAL_LCRU_PCIE_RESET(pcie->bus_nr));
+
+ reg |= BAIKAL_PCIE_NONSTICKY_RST |
+ BAIKAL_PCIE_STICKY_RST |
+ BAIKAL_PCIE_PWR_RST |
+ BAIKAL_PCIE_CORE_RST |
+ BAIKAL_PCIE_PHY_RESET;
+
+ /* If the RC is PCIe x8, reset PIPE0 and PIPE1 */
+ if (pcie->bus_nr == 2) {
+ reg |= BAIKAL_PCIE_PIPE0_RESET |
+ BAIKAL_PCIE_PIPE1_RESET;
+ } else {
+ reg |= BAIKAL_PCIE_PIPE_RESET;
+ }
+
+ baikal_pcie_lcru_writel(pcie->lcru,
+ BAIKAL_LCRU_PCIE_RESET(pcie->bus_nr), reg);
+
+ usleep_range(20000, 30000);
+
+ if (pcie->reset_gpio != NULL) {
+ /* Deassert PERST pin */
+ gpiod_set_value_cansleep(pcie->reset_gpio, 0);
+ }
+
+ /* Deassert PHY reset */
+ reg = baikal_pcie_lcru_readl(pcie->lcru,
+ BAIKAL_LCRU_PCIE_RESET(pcie->bus_nr));
+
+ reg &= ~BAIKAL_PCIE_PHY_RESET;
+ baikal_pcie_lcru_writel(pcie->lcru,
+ BAIKAL_LCRU_PCIE_RESET(pcie->bus_nr), reg);
+
+ /* Deassert all software controlled resets */
+ reg = baikal_pcie_lcru_readl(pcie->lcru,
+ BAIKAL_LCRU_PCIE_RESET(pcie->bus_nr));
+
+ reg &= ~(BAIKAL_PCIE_ADB_PWRDWN |
+ BAIKAL_PCIE_HOT_RESET |
+ BAIKAL_PCIE_NONSTICKY_RST |
+ BAIKAL_PCIE_STICKY_RST |
+ BAIKAL_PCIE_PWR_RST |
+ BAIKAL_PCIE_CORE_RST |
+ BAIKAL_PCIE_PHY_RESET);
+
+ if (pcie->bus_nr == 2) {
+ reg &= ~(BAIKAL_PCIE_PIPE0_RESET |
+ BAIKAL_PCIE_PIPE1_RESET);
+ } else {
+ reg &= ~BAIKAL_PCIE_PIPE_RESET;
+ }
+
+ baikal_pcie_lcru_writel(pcie->lcru,
+ BAIKAL_LCRU_PCIE_RESET(pcie->bus_nr), reg);
+ }
+
+ /* Deinitialise all iATU regions */
+ for (idx = 0; idx < pp->num_viewport; ++idx) {
+ dw_pcie_writel_dbi(pp, PCIE_IATU_VIEWPORT_REG,
+ PCIE_IATU_REGION_OUTBOUND | idx);
+ dw_pcie_writel_dbi(pp, PCIE_IATU_REGION_CTRL_2_REG, 0);
+ }
+
+ /*
+ * Enable writing to config regs. This is required as the DW driver
+ * changes the class code. That register needs DBI write enable.
+ */
+ reg = dw_pcie_readl_dbi(pp, PCIE_MISC_CONTROL_1_REG);
+ reg |= PCIE_DBI_RO_RW_EN;
+ dw_pcie_writel_dbi(pp, PCIE_MISC_CONTROL_1_REG, reg);
+
+ dw_pcie_setup_rc(port);
+
+ /* Set prog-if = 1 */
+ reg = dw_pcie_readl_dbi(pp, PCI_CLASS_REVISION);
+ reg = (1 << 8) | (reg & 0xffff00ff);
+ dw_pcie_writel_dbi(pp, PCI_CLASS_REVISION, reg);
+
+ /* Set max link width in accordance with 'num-lanes' value */
+ reg = dw_pcie_readl_dbi(pp, PCIE_LINK_CAPABILITIES_REG);
+ reg &= ~PCIE_CAP_MAX_LINK_WIDTH_MASK;
+ reg |= (pcie->num_lanes) << PCIE_CAP_MAX_LINK_WIDTH_SHIFT;
+ dw_pcie_writel_dbi(pp, PCIE_LINK_CAPABILITIES_REG, reg);
+
+ /* Disable writing to config regs */
+ reg = dw_pcie_readl_dbi(pp, PCIE_MISC_CONTROL_1_REG);
+ reg &= ~PCIE_DBI_RO_RW_EN;
+ dw_pcie_writel_dbi(pp, PCIE_MISC_CONTROL_1_REG, reg);
+
+ if (IS_ENABLED(CONFIG_PCI_MSI)) {
+ err = baikal_pcie_msi_enable(pcie);
+ if (err) {
+ dev_err(pp->dev, "failed to initialize MSI\n");
+ return -EIO;
+ }
+ }
+
+ /* Enable error reporting */
+ reg = dw_pcie_readl_dbi(pp, PCIE_ROOT_ERR_CMD_REG);
+ reg |= PCIE_CORR_ERR_REPORTING_EN |
+ PCIE_NON_FATAL_ERR_REPORTING_EN |
+ PCIE_FATAL_ERR_REPORTING_EN;
+ dw_pcie_writel_dbi(pp, PCIE_ROOT_ERR_CMD_REG, reg);
+
+ reg = dw_pcie_readl_dbi(pp, PCIE_DEVICE_CONTROL_DEVICE_STATUS_REG);
+ reg |= PCIE_CAP_CORR_ERR_REPORT_EN |
+ PCIE_CAP_NON_FATAL_ERR_REPORT_EN |
+ PCIE_CAP_FATAL_ERR_REPORT_EN |
+ PCIE_CAP_UNSUPPORT_REQ_REP_EN;
+ dw_pcie_writel_dbi(pp, PCIE_DEVICE_CONTROL_DEVICE_STATUS_REG, reg);
+
+ reg = dw_pcie_readl_dbi(pp, PCIE_ROOT_CONTROL_ROOT_CAPABILITIES_REG);
+ reg |= PCIE_CAP_SYS_ERR_ON_CORR_ERR_EN |
+ PCIE_CAP_SYS_ERR_ON_NON_FATAL_ERR_EN |
+ PCIE_CAP_SYS_ERR_ON_FATAL_ERR_EN |
+ PCIE_CAP_PME_INT_EN;
+ dw_pcie_writel_dbi(pp, PCIE_ROOT_CONTROL_ROOT_CAPABILITIES_REG, reg);
+
+ if (linkup) {
+ dev_info(dev, "link is already up\n");
+ return 0;
+ }
+
+ /* Use Gen1 mode for link establishing */
+ reg = dw_pcie_readl_dbi(pp, PCIE_LINK_CONTROL2_LINK_STATUS2_REG);
+ reg &= ~PCIE_CAP_TARGET_LINK_SPEED_MASK;
+ reg |= 1;
+ dw_pcie_writel_dbi(pp, PCIE_LINK_CONTROL2_LINK_STATUS2_REG, reg);
+
+ /*
+ * Clear DIRECT_SPEED_CHANGE bit. It has been set by dw_pcie_setup_rc.
+ * This bit causes link retraining. However, link retraining should be
+ * performed later by calling a speed fixup function.
+ */
+ reg = dw_pcie_readl_dbi(pp, PCIE_GEN2_CTRL_REG);
+ reg &= ~PCIE_DIRECT_SPEED_CHANGE;
+ dw_pcie_writel_dbi(pp, PCIE_GEN2_CTRL_REG, reg);
+
+ /* Establish link */
+ reg = baikal_pcie_lcru_readl(pcie->lcru,
+ BAIKAL_LCRU_PCIE_GEN_CTL(pcie->bus_nr));
+
+ reg |= BAIKAL_PCIE_LTSSM_ENABLE;
+ baikal_pcie_lcru_writel(pcie->lcru,
+ BAIKAL_LCRU_PCIE_GEN_CTL(pcie->bus_nr), reg);
+
+ dw_pcie_wait_for_link(pp);
+ /* XXX:
+ * - return OK even if the link is down
+ * - on error dw_pcie_wait_for_link prints a warning on its own,
+ * there's no need to print more messages here
+ */
+ return 0;
+}
+
+static int baikal_pcie_msi_host_init(struct pcie_port *pp)
+{
+ struct dw_pcie* pcie = to_dw_pcie_from_pp(pp);
+ struct device *dev = pcie->dev;
+ struct device_node *np = dev->of_node;
+ struct device_node *msi_node;
+
+ /*
+ * The MSI domain is set by the generic of_msi_configure(). This
+ * .msi_host_init() function keeps us from doing the default MSI domain
+ * setup in dw_pcie_host_init() and also enforces the requirement that
+ * "msi-parent" exists.
+ */
+ msi_node = of_parse_phandle(np, "msi-parent", 0);
+ if (!msi_node) {
+ dev_err(dev, "failed to find msi-parent\n");
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+static const struct dw_pcie_host_ops baikal_pcie_host_ops = {
+ .host_init = baikal_pcie_host_init,
+ .msi_host_init = baikal_pcie_msi_host_init,
+};
+
+static const struct dw_pcie_ops baikal_pcie_ops = {
+ .link_up = baikal_pcie_link_up,
+};
+
+static int baikal_add_pcie_port(struct baikal_pcie *pcie,
+ struct platform_device *pdev)
+{
+ struct dw_pcie *dw_pci = &pcie->pp;
+ struct pcie_port *pp = &dw_pci->pp;
+ struct resource *res;
+ int irq;
+ int ret;
+
+ dw_pci->dev = &pdev->dev;
+
+ res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "dbi");
+ if (res) {
+ devm_request_resource(dw_pci->dev, &iomem_resource, res);
+ dw_pci->dbi_base = devm_ioremap_resource(dw_pci->dev, res);
+ if (IS_ERR(dw_pci->dbi_base)) {
+ dev_err(dw_pci->dev, "error with ioremap\n");
+ return -ENOMEM;
+ }
+ } else {
+ dev_err(dw_pci->dev, "missing *dbi* reg space\n");
+ return -EINVAL;
+ }
+
+ irq = platform_get_irq(pdev, 0);
+ if (irq < 0) {
+ dev_err(dw_pci->dev, "missing IRQ resource: %d\n", irq);
+ return irq;
+ }
+
+ ret = devm_request_irq(dw_pci->dev, irq, baikal_pcie_err_irq_handler,
+ IRQF_SHARED | IRQF_NO_THREAD,
+ "baikal-pcie-error-irq", pcie);
+ if (ret) {
+ dev_err(dw_pci->dev, "failed to request IRQ\n");
+ return ret;
+ }
+
+ pp->ops = &baikal_pcie_host_ops;
+ ret = dw_pcie_host_init(pp);
+ if (ret) {
+ dev_err(dw_pci->dev, "failed to initialize host\n");
+ return ret;
+ }
+ baikal_pcie_retrain_links(pp->bridge->bus);
+
+ return 0;
+}
+
+static bool has_incompat_firmware(void) {
+ bool gotcha = false;
+ struct device_node *np = NULL;
+ np = of_find_node_by_path("/soc");
+ if (np) {
+ of_node_put(np);
+ } else {
+ gotcha = true;
+ }
+ return gotcha;
+}
+
+static int baikal_pcie_probe(struct platform_device *pdev)
+{
+ struct device *dev = &pdev->dev;
+ struct baikal_pcie *pcie;
+ int err;
+ u32 index[2];
+ enum of_gpio_flags gpio_flags;
+ int reset_gpio;
+
+ if (has_incompat_firmware()) {
+ dev_err(dev, "detected incompatible firmware, bailing out\n");
+ return -EINVAL;
+ }
+ if (!of_match_device(of_baikal_pcie_match, dev)) {
+ return -EINVAL;
+ }
+
+ pcie = devm_kzalloc(dev, sizeof(*pcie), GFP_KERNEL);
+ if (!pcie) {
+ return -ENOMEM;
+ }
+ pcie->pp.dev = dev;
+ pcie->pp.ops = &baikal_pcie_ops;
+
+ err = of_property_read_u32(dev->of_node, "num-lanes", &pcie->num_lanes);
+ if (err) {
+ dev_err(dev, "property num-lanes isn't found\n");
+ return -EINVAL;
+ }
+ pcie->lcru = syscon_regmap_lookup_by_phandle(dev->of_node,
+ "baikal,pcie-lcru");
+ if (IS_ERR(pcie->lcru)) {
+ dev_err(dev, "No LCRU phandle specified\n");
+ pcie->lcru = NULL;
+ return -EINVAL;
+ }
+
+ if (of_property_read_u32_array(dev->of_node, "baikal,pcie-lcru", index, 2)) {
+ pcie->lcru = NULL;
+ return -EINVAL;
+ }
+
+ pcie->bus_nr = index[1];
+
+ pm_runtime_enable(dev);
+ err = pm_runtime_get_sync(dev);
+ if (err < 0) {
+ dev_err(dev, "pm_runtime_get_sync failed\n");
+ goto err_pm_disable;
+ }
+
+ reset_gpio = of_get_named_gpio_flags(dev->of_node, "reset-gpios", 0,
+ &gpio_flags);
+ if (gpio_is_valid(reset_gpio)) {
+ pcie->reset_gpio = gpio_to_desc(reset_gpio);
+ pcie->reset_active_low = gpio_flags & OF_GPIO_ACTIVE_LOW;
+ snprintf(pcie->reset_name, sizeof pcie->reset_name,
+ "pcie%u-reset", pcie->bus_nr);
+ } else {
+ pcie->reset_gpio = NULL;
+ }
+
+ err = baikal_add_pcie_port(pcie, pdev);
+ if (err < 0) {
+ goto err_pm_put;
+ }
+
+ platform_set_drvdata(pdev, pcie);
+ return 0;
+
+err_pm_put:
+ pm_runtime_put(dev);
+
+err_pm_disable:
+ pm_runtime_disable(dev);
+
+ return err;
+}
+
+#ifdef CONFIG_PM_SLEEP
+static int baikal_pcie_suspend(struct device *dev)
+{
+ struct baikal_pcie *pcie = dev_get_drvdata(dev);
+ struct dw_pcie *pp = &pcie->pp;
+ u32 val;
+
+ /* Clear Memory Space Enable (MSE) bit */
+ val = dw_pcie_readl_dbi(pp, PCI_COMMAND);
+ val &= ~PCI_COMMAND_MEMORY;
+ dw_pcie_writel_dbi(pp, PCI_COMMAND, val);
+ return 0;
+}
+
+static int baikal_pcie_resume(struct device *dev)
+{
+ struct baikal_pcie *pcie = dev_get_drvdata(dev);
+ struct dw_pcie *pp = &pcie->pp;
+ u32 val;
+
+ /* Set Memory Space Enable (MSE) bit */
+ val = dw_pcie_readl_dbi(pp, PCI_COMMAND);
+ val |= PCI_COMMAND_MEMORY;
+ dw_pcie_writel_dbi(pp, PCI_COMMAND, val);
+ return 0;
+}
+
+static int baikal_pcie_suspend_noirq(struct device *dev)
+{
+ return 0;
+}
+
+static int baikal_pcie_resume_noirq(struct device *dev)
+{
+ return 0;
+}
+#endif
+
+static const struct dev_pm_ops baikal_pcie_pm_ops = {
+ SET_SYSTEM_SLEEP_PM_OPS(baikal_pcie_suspend, baikal_pcie_resume)
+ SET_NOIRQ_SYSTEM_SLEEP_PM_OPS(baikal_pcie_suspend_noirq,
+ baikal_pcie_resume_noirq)
+};
+
+static struct platform_driver baikal_pcie_driver = {
+ .driver = {
+ .name = "baikal-pcie-v2",
+ .of_match_table = of_baikal_pcie_match,
+ .suppress_bind_attrs = true,
+ .pm = &baikal_pcie_pm_ops,
+ },
+ .probe = baikal_pcie_probe,
+};
+
+MODULE_DEVICE_TABLE(of, of_baikal_pcie_match);
+module_platform_driver(baikal_pcie_driver);
+MODULE_LICENSE("GPL v2");
--
2.31.1

View file

@ -0,0 +1,223 @@
From 74a27e95a02db904c452f4b06b0e976cbecf113e Mon Sep 17 00:00:00 2001
From: Alexey Sheplyakov <asheplyakov@altlinux.org>
Date: Thu, 28 Jan 2021 18:44:36 +0400
Subject: [PATCH 618/625] baikal_vdu: avoid using SMC calls for updating
framebuffer address
(from SDK-M 4.4)
---
drivers/gpu/drm/baikal/baikal_vdu_drm.h | 16 -----
drivers/gpu/drm/baikal/baikal_vdu_drv.c | 2 -
drivers/gpu/drm/baikal/baikal_vdu_plane.c | 88 ++++++++---------------
3 files changed, 28 insertions(+), 78 deletions(-)
diff --git a/drivers/gpu/drm/baikal/baikal_vdu_drm.h b/drivers/gpu/drm/baikal/baikal_vdu_drm.h
index d049335dab1d..2db3fb73c9e7 100644
--- a/drivers/gpu/drm/baikal/baikal_vdu_drm.h
+++ b/drivers/gpu/drm/baikal/baikal_vdu_drm.h
@@ -22,23 +22,12 @@
#include <drm/drm_gem.h>
#include <drm/drm_simple_kms_helper.h>
-#include <linux/workqueue.h>
struct clk;
struct drm_device;
struct drm_fbdev_cma;
struct drm_panel;
-/*struct baikal_vdu_framebuffer {
- u32 base;
- u32 size;
- u32 index;
- u32 reg_base;
- u32 reg_size;
- u32 reg_width;
- u32 reg_height;
-};*/
-
struct baikal_vdu_drm_connector {
struct drm_connector connector;
struct drm_panel *panel;
@@ -61,8 +50,6 @@ struct baikal_vdu_private {
u32 fb_addr;
u32 fb_end;
-
- struct delayed_work update_work;
};
#define to_baikal_vdu_drm_connector(x) \
@@ -89,7 +76,4 @@ int baikal_vdu_dumb_create(struct drm_file *file_priv,
void baikal_vdu_debugfs_init(struct drm_minor *minor);
-/* Worker functions */
-void baikal_vdu_update_work(struct work_struct *work);
-
#endif /* __BAIKAL_VDU_DRM_H__ */
diff --git a/drivers/gpu/drm/baikal/baikal_vdu_drv.c b/drivers/gpu/drm/baikal/baikal_vdu_drv.c
index 0caa97dcb2e9..5deab510ea57 100644
--- a/drivers/gpu/drm/baikal/baikal_vdu_drv.c
+++ b/drivers/gpu/drm/baikal/baikal_vdu_drv.c
@@ -152,8 +152,6 @@ static int vdu_modeset_init(struct drm_device *dev)
}
arm_smccc_smc(BAIKAL_SMC_SCP_LOG_DISABLE, 0, 0, 0, 0, 0, 0, 0, &res);
- INIT_DEFERRABLE_WORK(&priv->update_work,
- baikal_vdu_update_work);
drm_mode_config_reset(dev);
diff --git a/drivers/gpu/drm/baikal/baikal_vdu_plane.c b/drivers/gpu/drm/baikal/baikal_vdu_plane.c
index 9817af3c6de8..5a047835e154 100644
--- a/drivers/gpu/drm/baikal/baikal_vdu_plane.c
+++ b/drivers/gpu/drm/baikal/baikal_vdu_plane.c
@@ -17,7 +17,6 @@
*
*/
-#include <linux/arm-smccc.h>
#include <linux/clk.h>
#include <linux/clk-provider.h>
#include <linux/delay.h>
@@ -32,42 +31,6 @@
#include "baikal_vdu_drm.h"
#include "baikal_vdu_regs.h"
-#define BAIKAL_SMC_VDU_UPDATE_HDMI 0x82000100
-
-void baikal_vdu_update_work(struct work_struct *work)
-{
- struct arm_smccc_res res;
- unsigned long flags;
- struct baikal_vdu_private *priv = container_of(work, struct baikal_vdu_private,
- update_work.work);
- int count = 0;
- u64 t1, t2;
- t1 = read_sysreg(CNTVCT_EL0);
- spin_lock_irqsave(&priv->lock, flags);
- arm_smccc_smc(BAIKAL_SMC_VDU_UPDATE_HDMI, priv->fb_addr, priv->fb_end, 0, 0, 0, 0, 0, &res);
- spin_unlock_irqrestore(&priv->lock, flags);
- if (res.a0 == -EBUSY)
- priv->counters[15]++;
- else
- priv->counters[16]++;
- while (res.a0 == -EBUSY && count < 10) {
- count++;
- usleep_range(10000, 20000);
- res.a0 = 0;
- spin_lock_irqsave(&priv->lock, flags);
- arm_smccc_smc(BAIKAL_SMC_VDU_UPDATE_HDMI, priv->fb_addr, priv->fb_end, 0, 0, 0, 0, 0, &res);
- spin_unlock_irqrestore(&priv->lock, flags);
- if (res.a0 == -EBUSY)
- priv->counters[15]++;
- else
- priv->counters[16]++;
- }
- t2 = read_sysreg(CNTVCT_EL0);
- priv->counters[17] = t2 - t1;
- priv->counters[18] = count;
- priv->counters[19]++;
-}
-
static int baikal_vdu_primary_plane_atomic_check(struct drm_plane *plane,
struct drm_plane_state *state)
{
@@ -76,6 +39,7 @@ static int baikal_vdu_primary_plane_atomic_check(struct drm_plane *plane,
struct drm_crtc_state *crtc_state;
struct drm_display_mode *mode;
int rate, ret;
+ u32 cntl;
if (!state->crtc)
return 0;
@@ -86,6 +50,9 @@ static int baikal_vdu_primary_plane_atomic_check(struct drm_plane *plane,
if (rate == clk_get_rate(priv->clk))
return 0;
+ /* hold clock domain reset; disable clocking */
+ writel(0, priv->regs + PCTR);
+
if (__clk_is_enabled(priv->clk))
clk_disable_unprepare(priv->clk);
ret = clk_set_rate(priv->clk, rate);
@@ -94,15 +61,23 @@ static int baikal_vdu_primary_plane_atomic_check(struct drm_plane *plane,
if (ret < 0) {
DRM_ERROR("Cannot set desired pixel clock (%d Hz)\n",
rate);
- return -EINVAL;
- }
- clk_prepare_enable(priv->clk);
- if (!__clk_is_enabled(priv->clk)) {
- DRM_ERROR("PLL could not lock at desired frequency (%d Hz)\n",
+ ret = -EINVAL;
+ } else {
+ clk_prepare_enable(priv->clk);
+ if (__clk_is_enabled(priv->clk))
+ ret = 0;
+ else {
+ DRM_ERROR("PLL could not lock at desired frequency (%d Hz)\n",
rate);
- return -EINVAL;
+ ret = -EINVAL;
+ }
}
- return 0;
+
+ /* release clock domain reset; enable clocking */
+ cntl = readl(priv->regs + PCTR);
+ cntl |= PCTR_PCR + PCTR_PCI;
+
+ return ret;
}
static void baikal_vdu_primary_plane_atomic_update(struct drm_plane *plane,
@@ -112,28 +87,13 @@ static void baikal_vdu_primary_plane_atomic_update(struct drm_plane *plane,
struct baikal_vdu_private *priv = dev->dev_private;
struct drm_plane_state *state = plane->state;
struct drm_framebuffer *fb = state->fb;
- struct arm_smccc_res res;
u32 cntl, addr, end;
- unsigned long flags;
if (!fb)
return;
addr = drm_fb_cma_get_gem_addr(fb, state, 0);
- end = ((addr + fb->height * fb->pitches[0] - 1) & MRR_DEAR_MRR_MASK) | MRR_OUTSTND_RQ(4);
-
- spin_lock_irqsave(&priv->lock, flags);
- arm_smccc_smc(BAIKAL_SMC_VDU_UPDATE_HDMI, addr, end, 0, 0, 0, 0, 0, &res);
- spin_unlock_irqrestore(&priv->lock, flags);
-
- if (res.a0 == -EBUSY) {
- priv->counters[15]++;
- priv->fb_addr = addr;
- priv->fb_end = end;
- smp_wmb();
- schedule_delayed_work(&priv->update_work, usecs_to_jiffies(250));
- } else
- priv->counters[16]++;
+ priv->fb_addr = addr & 0xfffffff8;
cntl = readl(priv->regs + CR1);
cntl &= ~CR1_BPP_MASK;
@@ -178,6 +138,14 @@ static void baikal_vdu_primary_plane_atomic_update(struct drm_plane *plane,
break;
}
+ writel(priv->fb_addr, priv->regs + DBAR);
+ end = ((priv->fb_addr + fb->height * fb->pitches[0] - 1) & MRR_DEAR_MRR_MASK) | \
+ MRR_OUTSTND_RQ(4);
+
+ if (priv->fb_end < end) {
+ writel(end, priv->regs + MRR);
+ priv->fb_end = end;
+ }
writel(cntl, priv->regs + CR1);
}
--
2.31.1

View file

@ -0,0 +1,30 @@
From 190b6e5664f8a541f0f38da5dff65d39adf1b549 Mon Sep 17 00:00:00 2001
From: Alexey Sheplyakov <asheplyakov@altlinux.org>
Date: Tue, 16 Feb 2021 17:12:40 +0400
Subject: [PATCH 619/625] panfrost: compatibility with Baikal-M firmware from
SDK-M 4.3
Added .compatible string so the driver can be used on Baikal-M
systems with firmware from SDK-M 4.3.
Note: the driver should be explicitly enabled with
enable_broken_machines=y module parameter
---
drivers/gpu/drm/panfrost/panfrost_drv.c | 1 +
1 file changed, 1 insertion(+)
diff --git a/drivers/gpu/drm/panfrost/panfrost_drv.c b/drivers/gpu/drm/panfrost/panfrost_drv.c
index 689be734ed20..7376b17bc44a 100644
--- a/drivers/gpu/drm/panfrost/panfrost_drv.c
+++ b/drivers/gpu/drm/panfrost/panfrost_drv.c
@@ -681,6 +681,7 @@ static const struct of_device_id dt_match[] = {
{ .compatible = "arm,mali-t860", .data = &default_data, },
{ .compatible = "arm,mali-t880", .data = &default_data, },
{ .compatible = "arm,mali-bifrost", .data = &default_data, },
+ { .compatible = "arm,mali-midgard", .data = &default_data, },
{}
};
MODULE_DEVICE_TABLE(of, dt_match);
--
2.31.1

View file

@ -0,0 +1,136 @@
From 7c3c753e3d32b250467bcc172f5abeb08dead01e Mon Sep 17 00:00:00 2001
From: Alexey Sheplyakov <asheplyakov@altlinux.org>
Date: Fri, 19 Feb 2021 12:55:03 +0400
Subject: [PATCH 620/625] cpufreq-dt: don't load on BE-M1000 SoC
Apparently the driver deadlocks the kernel in a few minutes:
[ 454.690508] rcu: INFO: rcu_preempt detected stalls on CPUs/tasks:
[ 454.696839] (detected by 4, t=26002 jiffies, g=22561, q=15)
[ 454.703017] rcu: All QSes seen, last rcu_preempt kthread activity 25992 (4295121102-4295095110), jiffies_till_next_fqs=3, root ->qsmask 0x0
[ 454.715570] rcu: rcu_preempt kthread starved for 25992 jiffies! g22561 f0x2 RCU_GP_WAIT_FQS(5) ->state=0x200 ->cpu=1
[ 454.726117] rcu: Unless rcu_preempt kthread gets sufficient CPU time, OOM is now expected behavior.
[ 454.735273] rcu: RCU grace-period kthread stack dump:
[ 454.740344] task:rcu_preempt state:R stack: 0 pid: 13 ppid: 2 flags:0x00000028
[ 454.748731] Call trace:
[ 454.751204] __switch_to+0x114/0x170
[ 454.754803] __schedule+0x370/0xa3c
[ 454.758310] schedule+0x50/0x104
[ 454.761557] schedule_timeout+0x9c/0x114
[ 454.765503] rcu_gp_kthread+0x598/0xb50
[ 454.769360] kthread+0x150/0x160
[ 454.772607] ret_from_fork+0x10/0x38
[ 454.778130]
[ 454.779631] ================================
[ 454.783912] WARNING: inconsistent lock state
[ 454.788196] 5.10.17-00041-g454ed3004040-dirty #1 Not tainted
[ 454.793867] --------------------------------
[ 454.798147] inconsistent {IN-HARDIRQ-W} -> {HARDIRQ-ON-W} usage.
[ 454.804168] swapper/4/0 [HC0[0]:SC1[1]:HE0:SE0] takes:
[ 454.809319] ffff800011198498 (rcu_node_0){?.-.}-{2:2}, at: rcu_sched_clock_irq+0x480/0xce0
[ 454.817615] {IN-HARDIRQ-W} state was registered at:
[ 454.822508] __lock_acquire+0xad8/0x2094
[ 454.826530] lock_acquire.part.0+0xfc/0x360
[ 454.830813] lock_acquire+0x68/0x84
[ 454.834399] _raw_spin_lock_irqsave+0x84/0x158
[ 454.838941] rcu_exp_handler+0xcc/0x140
[ 454.842878] flush_smp_call_function_queue+0xec/0x304
[ 454.848029] generic_smp_call_function_single_interrupt+0x20/0x2c
[ 454.854225] ipi_handler+0x1d8/0x39c
[ 454.857899] handle_percpu_devid_fasteoi_ipi+0xb0/0xe0
[ 454.863137] __handle_domain_irq+0xbc/0x13c
[ 454.867419] gic_handle_irq+0xcc/0x14c
[ 454.871265] el1_irq+0xc4/0x180
[ 454.874504] lock_acquire.part.0+0x120/0x360
[ 454.878873] lock_acquire+0x68/0x84
[ 454.882461] lock_page_memcg+0x5c/0x150
[ 454.886399] page_add_file_rmap+0x28/0x27c
[ 454.890595] alloc_set_pte+0xb8/0x5c0
[ 454.894356] filemap_map_pages+0x4a4/0x4c0
[ 454.898551] handle_mm_fault+0xbcc/0xf50
[ 454.902572] do_page_fault+0x14c/0x404
[ 454.906418] do_translation_fault+0xbc/0xd8
[ 454.910701] do_mem_abort+0x4c/0xac
[ 454.914287] el0_ia+0x68/0xcc
[ 454.917351] el0_sync_handler+0x180/0x1b0
[ 454.921458] el0_sync+0x174/0x180
[ 454.924868] irq event stamp: 449729
[ 454.928368] hardirqs last enabled at (449725): [<ffff8000109fcf74>] default_idle_call+0x24/0xdc
[ 454.937171] hardirqs last disabled at (449726): [<ffff8000109f27a0>] enter_el1_irq_or_nmi+0x10/0x20
[ 454.946237] softirqs last enabled at (449728): [<ffff8000100532f0>] _local_bh_enable+0x30/0x54
[ 454.954952] softirqs last disabled at (449729): [<ffff8000100534c4>] __irq_exit_rcu+0x1b0/0x1bc
[ 454.963665]
[ 454.963665] other info that might help us debug this:
[ 454.970206] Possible unsafe locking scenario:
[ 454.970206]
[ 454.976136] CPU0
[ 454.978590] ----
[ 454.981043] lock(rcu_node_0);
[ 454.984198] <Interrupt>
[ 454.986825] lock(rcu_node_0);
[ 454.990155]
[ 454.990155] *** DEADLOCK ***
[ 454.990155]
[ 454.996087] 1 lock held by swapper/4/0:
[ 454.999932] #0: ffff800011198498 (rcu_node_0){?.-.}-{2:2}, at: rcu_sched_clock_irq+0x480/0xce0
[ 455.008662]
[ 455.008662] stack backtrace:
[ 455.013033] CPU: 4 PID: 0 Comm: swapper/4 Not tainted 5.10.17-00041-g454ed3004040-dirty #1
[ 455.021313] Hardware name: Baikal Electronics Baikal-M mitx board (DT)
[ 455.027854] Call trace:
[ 455.030311] dump_backtrace+0x0/0x1e4
[ 455.033985] show_stack+0x24/0x80
[ 455.037312] dump_stack+0xec/0x154
[ 455.040723] print_usage_bug.part.0+0x208/0x22c
[ 455.045265] mark_lock+0x88c/0x934
[ 455.048677] mark_held_locks+0x58/0x90
[ 455.052437] lockdep_hardirqs_on_prepare+0xe4/0x23c
[ 455.057330] trace_hardirqs_on+0x78/0x2e0
[ 455.061350] __do_softirq+0x114/0x6d0
[ 455.065022] __irq_exit_rcu+0x1b0/0x1bc
[ 455.068868] irq_exit+0x1c/0x54
[ 455.072020] __handle_domain_irq+0xc0/0x13c
[ 455.076214] gic_handle_irq+0xcc/0x14c
[ 455.079972] el1_irq+0xc4/0x180
[ 455.083124] arch_cpu_idle+0x18/0x30
[ 455.086710] default_idle_call+0x5c/0xdc
[ 455.090645] do_idle+0x260/0x2e0
[ 455.093883] cpu_startup_entry+0x30/0x8c
[ 455.097818] secondary_start_kernel+0x138/0x184
[ 455.102410] BUG: scheduling while atomic: swapper/4/0/0x00000002
[ 455.108449] INFO: lockdep is turned off.
[ 455.112399] Modules linked in: dm_mod designware_i2s sdhci_of_dwcmshc snd_soc_core sdhci_pltfm dw_hdmi_ahb_audio snd_pcm_dmaengine ac97_bus evdev sdhci snd_pcm at24 panfrost mmc_core snd_timer pcie_baikal_v44 snd pcie_baikal bt1_pvt gpu_sched soundcore cpufreq_dt fuse configfs efivarfs ipv6
[ 455.138295] Preemption disabled at:
[ 455.138305] [<ffff800010028c64>] secondary_start_kernel+0xb4/0x184
[ 455.148020] CPU: 4 PID: 0 Comm: swapper/4 Not tainted 5.10.17-00041-g454ed3004040-dirty #1
[ 455.156299] Hardware name: Baikal Electronics Baikal-M mitx board (DT)
[ 455.162840] Call trace:
[ 455.165296] dump_backtrace+0x0/0x1e4
[ 455.168969] show_stack+0x24/0x80
[ 455.172295] dump_stack+0xec/0x154
[ 455.175711] __schedule_bug+0xcc/0xe0
[ 455.179383] __schedule+0x928/0xa3c
[ 455.182881] schedule_idle+0x34/0x5c
[ 455.186467] do_idle+0x1dc/0x2e0
[ 455.189706] cpu_startup_entry+0x30/0x8c
[ 455.193640] secondary_start_kernel+0x138/0x184
---
drivers/cpufreq/cpufreq-dt-platdev.c | 2 ++
1 file changed, 2 insertions(+)
diff --git a/drivers/cpufreq/cpufreq-dt-platdev.c b/drivers/cpufreq/cpufreq-dt-platdev.c
index 1c192a42f11e..2885ad3779bf 100644
--- a/drivers/cpufreq/cpufreq-dt-platdev.c
+++ b/drivers/cpufreq/cpufreq-dt-platdev.c
@@ -105,6 +105,8 @@ static const struct of_device_id blacklist[] __initconst = {
{ .compatible = "arm,vexpress", },
+ { .compatible = "baikal,baikal-m", },
+
{ .compatible = "calxeda,highbank", },
{ .compatible = "calxeda,ecx-2000", },
--
2.31.1

View file

@ -0,0 +1,38 @@
From 3a2d37d8f2aacdd8711f0f90a4c04d75eccd7a1f Mon Sep 17 00:00:00 2001
From: Alexey Sheplyakov <asheplyakov@altlinux.org>
Date: Fri, 19 Feb 2021 12:38:34 +0400
Subject: [PATCH 621/625] baikal_clk: compatibility with SDK-M 5.1 firmware
Without this patch the kernel seems to locks up within 10 -- 20 seconds
after the boot on a board with firmware from SDK-M 5.1
baikal_clk_set_rate: fixed parent rate calculation (from SDK-M 4.4)
---
drivers/clk/baikal/clk-baikal.c | 8 ++++++--
1 file changed, 6 insertions(+), 2 deletions(-)
diff --git a/drivers/clk/baikal/clk-baikal.c b/drivers/clk/baikal/clk-baikal.c
index ddf1d328eeaf..d9709322b2ee 100644
--- a/drivers/clk/baikal/clk-baikal.c
+++ b/drivers/clk/baikal/clk-baikal.c
@@ -181,11 +181,15 @@ static int baikal_clk_set_rate(struct clk_hw *hw, unsigned long rate,
struct arm_smccc_res res;
struct baikal_clk_cmu *pclk = to_baikal_cmu(hw);
uint32_t cmd;
+ unsigned long parent;
- if (pclk->is_clk_ch)
+ if (pclk->is_clk_ch) {
cmd = CMU_CLK_CH_SET_RATE;
- else
+ parent = pclk->parent;
+ } else {
cmd = CMU_PLL_SET_RATE;
+ parent = parent_rate;
+ }
pr_debug("[%s, %x:%d:%s] %s, %ld\n",
pclk->name,
--
2.31.1

View file

@ -0,0 +1,106 @@
From ae07645b9fa53d7e863dc49998c266333d34906a Mon Sep 17 00:00:00 2001
From: Alexey Sheplyakov <asheplyakov@altlinux.org>
Date: Wed, 24 Feb 2021 13:46:49 +0400
Subject: [PATCH 622/625] stmmac_mdio: implemented reset via MAC GP out pin
BE-M1000 variant of stmmac mdio needs a special reset routine.
Related: #39714
---
.../net/ethernet/stmicro/stmmac/stmmac_mdio.c | 68 ++++++++++++++++++-
1 file changed, 66 insertions(+), 2 deletions(-)
diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac_mdio.c b/drivers/net/ethernet/stmicro/stmmac/stmmac_mdio.c
index b2a707e2ef43..fa7b13e932e3 100644
--- a/drivers/net/ethernet/stmicro/stmmac/stmmac_mdio.c
+++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_mdio.c
@@ -287,6 +287,63 @@ static int stmmac_mdio_write(struct mii_bus *bus, int phyaddr, int phyreg,
100, 10000);
}
+#define MAC_GPIO 0xe0 /* GPIO register */
+#define MAC_GPIO_GPO0 (1 << 8) /* 0-output port */
+
+/**
+ * Reset the MII bus via MAC GP out pin
+ */
+static int stmmac_mdio_reset_gp_out(struct stmmac_priv *priv) {
+#if IS_ENABLED(CONFIG_STMMAC_PLATFORM) && IS_ENABLED(CONFIG_OF)
+ u32 value, high, low;
+ u32 delays[3] = { 0, 0, 0 };
+ bool active_low = false;
+ struct device_node *np = priv->device->of_node;
+
+ if (!np)
+ return -ENODEV;
+
+ if (!of_property_read_bool(np, "snps,reset-gp-out")) {
+ dev_warn(priv->device, "snps,reset-gp-out is not set\n");
+ return -ENODEV;
+ }
+
+ active_low = of_property_read_bool(np, "snsps,reset-active-low");
+ of_property_read_u32_array(np, "snps,reset-delays-us", delays, 3);
+
+ value = readl(priv->ioaddr + MAC_GPIO);
+ if (active_low) {
+ high = value | MAC_GPIO_GPO0;
+ low = value & ~MAC_GPIO_GPO0;
+ } else {
+ high = value & ~MAC_GPIO_GPO0;
+ low = value | MAC_GPIO_GPO0;
+ }
+
+ writel(high, priv->ioaddr + MAC_GPIO);
+ if (delays[0])
+ msleep(DIV_ROUND_UP(delays[0], 1000));
+
+ writel(low, priv->ioaddr + MAC_GPIO);
+ if (delays[1])
+ msleep(DIV_ROUND_UP(delays[1], 1000));
+
+ writel(high, priv->ioaddr + MAC_GPIO);
+ if (delays[2])
+ msleep(DIV_ROUND_UP(delays[2], 1000));
+
+ /* Clear PHY reset */
+ udelay(10);
+ value = readl(priv->ioaddr + MAC_GPIO);
+ value |= MAC_GPIO_GPO0;
+ writel(value, priv->ioaddr + MAC_GPIO);
+ mdelay(1000);
+ dev_info(priv->device, "mdio reset completed\n");
+ return 0;
+#endif
+ return -ENODEV;
+}
+
/**
* stmmac_mdio_reset
* @bus: points to the mii_bus structure
@@ -302,13 +359,20 @@ int stmmac_mdio_reset(struct mii_bus *bus)
#ifdef CONFIG_OF
if (priv->device->of_node) {
struct gpio_desc *reset_gpio;
+ bool need_reset_gp_out;
u32 delays[3] = { 0, 0, 0 };
reset_gpio = devm_gpiod_get_optional(priv->device,
"snps,reset",
GPIOD_OUT_LOW);
- if (IS_ERR(reset_gpio))
- return PTR_ERR(reset_gpio);
+ if (IS_ERR(reset_gpio)) {
+ need_reset_gp_out = of_property_read_bool(priv->device->of_node,
+ "snps,reset-gp-out");
+ if (need_reset_gp_out)
+ return stmmac_mdio_reset_gp_out(priv);
+ else
+ return PTR_ERR(reset_gpio);
+ }
device_property_read_u32_array(priv->device,
"snps,reset-delays-us",
--
2.31.1

View file

@ -0,0 +1,60 @@
From b7110f36a3ea12867eabcd5caeb104d23e1a3f4a Mon Sep 17 00:00:00 2001
From: Alexey Sheplyakov <asheplyakov@altlinux.org>
Date: Wed, 24 Feb 2021 16:45:30 +0400
Subject: [PATCH 623/625] dwmac_baikal: clear PHY reset before calling generic
setup routine
Without this attaching to Micrel PHY fails with the following error:
[ 17.596114] Micrel KSZ9031 Gigabit PHY stmmac-2:03: phy_poll_reset failed: -110
[ 17.603602] baikal-dwmac 30250000.eth1 eth1: no phy at addr -1
[ 17.609468] baikal-dwmac 30250000.eth1 eth1: stmmac_open: Cannot attach to PHY (error: -19)
Closes: #39714
---
.../net/ethernet/stmicro/stmmac/dwmac-baikal.c | 15 +++++++++++----
1 file changed, 11 insertions(+), 4 deletions(-)
diff --git a/drivers/net/ethernet/stmicro/stmmac/dwmac-baikal.c b/drivers/net/ethernet/stmicro/stmmac/dwmac-baikal.c
index 646051cd500d..e706ece9b4f5 100644
--- a/drivers/net/ethernet/stmicro/stmmac/dwmac-baikal.c
+++ b/drivers/net/ethernet/stmicro/stmmac/dwmac-baikal.c
@@ -34,6 +34,14 @@ struct baikal_dwmac {
struct clk *tx2_clk;
};
+static void clear_phy_reset(void __iomem *ioaddr)
+{
+ u32 value;
+ value = readl(ioaddr + MAC_GPIO);
+ value |= MAC_GPIO_GPO0;
+ writel(value, ioaddr + MAC_GPIO);
+}
+
static int baikal_dwmac_dma_reset(void __iomem *ioaddr)
{
int err;
@@ -44,10 +52,7 @@ static int baikal_dwmac_dma_reset(void __iomem *ioaddr)
writel(value, ioaddr + DMA_BUS_MODE);
udelay(10);
- /* Clear PHY reset */
- value = readl(ioaddr + MAC_GPIO);
- value |= MAC_GPIO_GPO0;
- writel(value, ioaddr + MAC_GPIO);
+ clear_phy_reset(ioaddr);
pr_info("PHY re-inited for Baikal DWMAC\n");
err = readl_poll_timeout(ioaddr + DMA_BUS_MODE, value,
@@ -90,6 +95,8 @@ static struct mac_device_info* baikal_dwmac_setup(void *ppriv)
if (!mac)
return NULL;
+ clear_phy_reset(priv->ioaddr);
+
mac->dma = &baikal_dwmac_dma_ops;
old_mac = priv->hw;
priv->hw = mac;
--
2.31.1

View file

@ -0,0 +1,101 @@
From c0b58206fc41cad2dcf7ae9193d69aafdce89173 Mon Sep 17 00:00:00 2001
From: Alexey Sheplyakov <asheplyakov@altlinux.org>
Date: Mon, 29 Mar 2021 12:22:11 +0400
Subject: [PATCH 624/625] (BROKEN) dwc-i2s: support BE-M1000 SoC
* dw_i2s_probe: request all IRQs specified in device tree
* dw_i2s_startup: set the correct DAI clock frequency
Note that the sound frequency is distorted (i.e. playing 440 Hz
sine wave results in 467 Hz), for more details see
https://github.com/edelweiss-tech/kernel/issues/2
---
sound/soc/dwc/dwc-i2s.c | 36 ++++++++++++++++++++++++++----------
sound/soc/dwc/local.h | 1 +
2 files changed, 27 insertions(+), 10 deletions(-)
diff --git a/sound/soc/dwc/dwc-i2s.c b/sound/soc/dwc/dwc-i2s.c
index fd4160289fac..e1efad33b522 100644
--- a/sound/soc/dwc/dwc-i2s.c
+++ b/sound/soc/dwc/dwc-i2s.c
@@ -100,6 +100,7 @@ static inline void i2s_enable_irqs(struct dw_i2s_dev *dev, u32 stream,
static irqreturn_t i2s_irq_handler(int irq, void *dev_id)
{
+ unsigned int rxor_count;
struct dw_i2s_dev *dev = dev_id;
bool irq_valid = false;
u32 isr[4];
@@ -136,9 +137,13 @@ static irqreturn_t i2s_irq_handler(int irq, void *dev_id)
irq_valid = true;
}
- /* Error Handling: TX */
+ /* Error Handling: RX */
if (isr[i] & ISR_RXFO) {
- dev_err(dev->dev, "RX overrun (ch_id=%d)\n", i);
+ rxor_count = READ_ONCE(dev->rx_overrun_count);
+ if (!(rxor_count & 0x3ff))
+ dev_dbg(dev->dev, "RX overrun (ch_id=%d)\n", i);
+ rxor_count++;
+ WRITE_ONCE(dev->rx_overrun_count, rxor_count);
irq_valid = true;
}
}
@@ -622,7 +627,8 @@ static int dw_i2s_probe(struct platform_device *pdev)
const struct i2s_platform_data *pdata = pdev->dev.platform_data;
struct dw_i2s_dev *dev;
struct resource *res;
- int ret, irq;
+ int ret, irq, irq_count;
+ unsigned idx;
struct snd_soc_dai_driver *dw_i2s_dai;
const char *clk_id;
@@ -643,13 +649,23 @@ static int dw_i2s_probe(struct platform_device *pdev)
dev->dev = &pdev->dev;
- irq = platform_get_irq(pdev, 0);
- if (irq >= 0) {
- ret = devm_request_irq(&pdev->dev, irq, i2s_irq_handler, 0,
- pdev->name, dev);
- if (ret < 0) {
- dev_err(&pdev->dev, "failed to request irq\n");
- return ret;
+ irq_count = platform_irq_count(pdev);
+ if (irq_count < 0) /* - EPROBE_DEFER */
+ return irq_count;
+ else if (!irq_count) {
+ dev_err(&pdev->dev, "no IRQs found for device\n");
+ return -ENODEV;
+ }
+
+ for (idx = 0; idx < (unsigned)irq_count; idx++) {
+ irq = platform_get_irq(pdev, idx);
+ if (irq >= 0) {
+ ret = devm_request_irq(&pdev->dev, irq, i2s_irq_handler, 0,
+ pdev->name, dev);
+ if (ret < 0) {
+ dev_err(&pdev->dev, "failed to request irq\n");
+ return ret;
+ }
}
}
diff --git a/sound/soc/dwc/local.h b/sound/soc/dwc/local.h
index 91dc70a826f8..49167d89daae 100644
--- a/sound/soc/dwc/local.h
+++ b/sound/soc/dwc/local.h
@@ -117,6 +117,7 @@ struct dw_i2s_dev {
bool *period_elapsed);
unsigned int tx_ptr;
unsigned int rx_ptr;
+ unsigned int rx_overrun_count;
};
#if IS_ENABLED(CONFIG_SND_DESIGNWARE_PCM)
--
2.31.1

View file

@ -0,0 +1,548 @@
From d38a793e0efeb27e49b1ac0bad855f49f840684b Mon Sep 17 00:00:00 2001
From: Alexey Sheplyakov <asheplyakov@altlinux.org>
Date: Tue, 16 Mar 2021 12:45:43 +0400
Subject: [PATCH 625/625] baikal_vdu_drm: (LVDS) panel support
---
drivers/gpu/drm/baikal/Makefile | 2 -
drivers/gpu/drm/baikal/baikal_vdu_connector.c | 54 ++++++++++++------
drivers/gpu/drm/baikal/baikal_vdu_crtc.c | 55 ++++++++++++++-----
drivers/gpu/drm/baikal/baikal_vdu_drm.h | 32 +++--------
drivers/gpu/drm/baikal/baikal_vdu_drv.c | 42 ++++++++------
drivers/gpu/drm/baikal/baikal_vdu_encoder.c | 51 -----------------
drivers/gpu/drm/baikal/baikal_vdu_gem.c | 37 -------------
drivers/gpu/drm/baikal/baikal_vdu_regs.h | 13 +----
8 files changed, 113 insertions(+), 173 deletions(-)
delete mode 100644 drivers/gpu/drm/baikal/baikal_vdu_encoder.c
delete mode 100644 drivers/gpu/drm/baikal/baikal_vdu_gem.c
diff --git a/drivers/gpu/drm/baikal/Makefile b/drivers/gpu/drm/baikal/Makefile
index 4c3e9e67befb..eb029494e823 100644
--- a/drivers/gpu/drm/baikal/Makefile
+++ b/drivers/gpu/drm/baikal/Makefile
@@ -2,8 +2,6 @@
baikal_vdu_drm-y += baikal_vdu_connector.o \
baikal_vdu_crtc.o \
baikal_vdu_drv.o \
- baikal_vdu_encoder.o \
- baikal_vdu_gem.o \
baikal_vdu_plane.o
baikal_vdu_drm-$(CONFIG_DEBUG_FS) += baikal_vdu_debugfs.o
diff --git a/drivers/gpu/drm/baikal/baikal_vdu_connector.c b/drivers/gpu/drm/baikal/baikal_vdu_connector.c
index ca48e230f174..2f20cf3da627 100644
--- a/drivers/gpu/drm/baikal/baikal_vdu_connector.c
+++ b/drivers/gpu/drm/baikal/baikal_vdu_connector.c
@@ -34,6 +34,9 @@
#include "baikal_vdu_drm.h"
#include "baikal_vdu_regs.h"
+#define to_baikal_vdu_private(x) \
+ container_of(x, struct baikal_vdu_private, connector)
+
static void baikal_vdu_drm_connector_destroy(struct drm_connector *connector)
{
drm_connector_unregister(connector);
@@ -43,10 +46,9 @@ static void baikal_vdu_drm_connector_destroy(struct drm_connector *connector)
static enum drm_connector_status baikal_vdu_drm_connector_detect(
struct drm_connector *connector, bool force)
{
- struct baikal_vdu_drm_connector *vdu_connector =
- to_baikal_vdu_drm_connector(connector);
+ struct baikal_vdu_private *priv = to_baikal_vdu_private(connector);
- return (vdu_connector->panel ?
+ return (priv->panel ?
connector_status_connected :
connector_status_disconnected);
}
@@ -54,24 +56,18 @@ static enum drm_connector_status baikal_vdu_drm_connector_detect(
static int baikal_vdu_drm_connector_helper_get_modes(
struct drm_connector *connector)
{
- struct baikal_vdu_drm_connector *vdu_connector =
- to_baikal_vdu_drm_connector(connector);
+ struct baikal_vdu_private *priv = to_baikal_vdu_private(connector);
- if (!vdu_connector) {
- pr_err("%s: vdu_connector == NULL\n", __func__);
- return 0;
- }
- if (!vdu_connector->panel)
+ if (!priv->panel)
return 0;
- return drm_panel_get_modes(vdu_connector->panel, connector);
+ return drm_panel_get_modes(priv->panel, connector);
}
const struct drm_connector_funcs connector_funcs = {
.fill_modes = drm_helper_probe_single_connector_modes,
.destroy = baikal_vdu_drm_connector_destroy,
.detect = baikal_vdu_drm_connector_detect,
- //.dpms = drm_atomic_helper_connector_dpms, // TODO enable it?
.reset = drm_atomic_helper_connector_reset,
.atomic_duplicate_state = drm_atomic_helper_connector_duplicate_state,
.atomic_destroy_state = drm_atomic_helper_connector_destroy_state,
@@ -85,14 +81,38 @@ static const struct drm_encoder_funcs encoder_funcs = {
.destroy = drm_encoder_cleanup,
};
-int baikal_vdu_connector_create(struct drm_device *dev)
+int baikal_vdu_lvds_connector_create(struct drm_device *dev)
{
struct baikal_vdu_private *priv = dev->dev_private;
- struct baikal_vdu_drm_connector *vdu_connector = &priv->connector;
- struct drm_connector *connector = &vdu_connector->connector;
+ struct drm_connector *connector = &priv->connector;
+ struct drm_encoder *encoder = &priv->encoder;
+ int ret = 0;
- drm_connector_init(dev, connector, &connector_funcs,
+ ret = drm_connector_init(dev, connector, &connector_funcs,
DRM_MODE_CONNECTOR_LVDS);
+ if (ret) {
+ dev_err(dev->dev, "drm_connector_init failed: %d\n", ret);
+ goto out;
+ }
drm_connector_helper_add(connector, &connector_helper_funcs);
- return 0;
+ ret = drm_encoder_init(dev, encoder, &encoder_funcs,
+ DRM_MODE_ENCODER_LVDS, NULL);
+ if (ret) {
+ dev_err(dev->dev, "drm_encoder_init failed: %d\n", ret);
+ goto out;
+ }
+ encoder->crtc = &priv->crtc;
+ encoder->possible_crtcs = drm_crtc_mask(encoder->crtc);
+ ret = drm_connector_attach_encoder(connector, encoder);
+ if (ret) {
+ dev_err(dev->dev, "drm_connector_attach_encoder failed: %d\n", ret);
+ goto out;
+ }
+ ret = drm_connector_register(connector);
+ if (ret) {
+ dev_err(dev->dev, "drm_connector_register failed: %d\n", ret);
+ goto out;
+ }
+out:
+ return ret;
}
diff --git a/drivers/gpu/drm/baikal/baikal_vdu_crtc.c b/drivers/gpu/drm/baikal/baikal_vdu_crtc.c
index 6ef61791e299..d8bc1182bb77 100644
--- a/drivers/gpu/drm/baikal/baikal_vdu_crtc.c
+++ b/drivers/gpu/drm/baikal/baikal_vdu_crtc.c
@@ -134,8 +134,13 @@ static void baikal_vdu_crtc_helper_mode_set_nofb(struct drm_crtc *crtc)
drm_mode_debug_printmodeline(mode);
ppl = mode->hdisplay / 16;
- hsw = mode->hsync_end - mode->hsync_start - 1;
- hfp = mode->hsync_start - mode->hdisplay;
+ if (priv->panel) {
+ hsw = mode->hsync_end - mode->hsync_start;
+ hfp = mode->hsync_start - mode->hdisplay - 1;
+ } else {
+ hsw = mode->hsync_end - mode->hsync_start - 1;
+ hfp = mode->hsync_start - mode->hdisplay;
+ }
hbp = mode->htotal - mode->hsync_end;
lpp = mode->vdisplay;
@@ -188,12 +193,15 @@ static void baikal_vdu_crtc_helper_enable(struct drm_crtc *crtc,
struct drm_crtc_state *old_state)
{
struct baikal_vdu_private *priv = crtc->dev->dev_private;
- u32 cntl;
+ struct drm_panel *panel = priv->panel;
+ struct device_node *panel_node;
+ const char *data_mapping;
+ u32 cntl, gpio;
DRM_DEV_DEBUG_DRIVER(crtc->dev->dev, "enabling pixel clock\n");
clk_prepare_enable(priv->clk);
- drm_panel_prepare(priv->connector.panel);
+ drm_panel_prepare(panel);
writel(ISCR_VSC_VFP, priv->regs + ISCR);
@@ -202,13 +210,37 @@ static void baikal_vdu_crtc_helper_enable(struct drm_crtc *crtc,
cntl |= PCTR_PCR + PCTR_PCI;
writel(cntl, priv->regs + PCTR);
- /* Set 16-word input FIFO watermark and 24-bit LCD interface mode */
+ /* Set 16-word input FIFO watermark */
/* Enable and Power Up */
cntl = readl(priv->regs + CR1);
- cntl |= CR1_LCE + CR1_FDW_16_WORDS + CR1_OPS_LCD24;
+ cntl &= ~CR1_FDW_MASK;
+ cntl |= CR1_LCE + CR1_FDW_16_WORDS;
+
+ if (priv->type == VDU_TYPE_LVDS) {
+ panel_node = panel->dev->of_node;
+ if (of_property_read_string(panel_node, "data-mapping", &data_mapping)) {
+ cntl |= CR1_OPS_LCD18;
+ } else if (strncmp(data_mapping, "vesa-24", 7))
+ cntl |= CR1_OPS_LCD24;
+ else if (strncmp(data_mapping, "jeida-18", 8))
+ cntl |= CR1_OPS_LCD18;
+ else {
+ dev_warn(crtc->dev->dev, "%s data mapping is not supported, vesa-24 is set\n", data_mapping);
+ cntl |= CR1_OPS_LCD24;
+ }
+ gpio = GPIOR_UHD_ENB;
+ if (priv->ep_count == 4)
+ gpio |= GPIOR_UHD_QUAD_PORT;
+ else if (priv->ep_count == 2)
+ gpio |= GPIOR_UHD_DUAL_PORT;
+ else
+ gpio |= GPIOR_UHD_SNGL_PORT;
+ writel(gpio, priv->regs + GPIOR);
+ } else
+ cntl |= CR1_OPS_LCD24;
writel(cntl, priv->regs + CR1);
- drm_panel_enable(priv->connector.panel);
+ drm_panel_enable(priv->panel);
drm_crtc_vblank_on(crtc);
}
@@ -217,12 +249,9 @@ void baikal_vdu_crtc_helper_disable(struct drm_crtc *crtc)
struct baikal_vdu_private *priv = crtc->dev->dev_private;
drm_crtc_vblank_off(crtc);
- drm_panel_disable(priv->connector.panel);
+ drm_panel_disable(priv->panel);
- /* Disable and Power Down */
- //writel(0, priv->regs + CR1);
-
- drm_panel_unprepare(priv->connector.panel);
+ drm_panel_unprepare(priv->panel);
/* Disable clock */
DRM_DEV_DEBUG_DRIVER(crtc->dev->dev, "disabling pixel clock\n");
@@ -250,8 +279,6 @@ static int baikal_vdu_enable_vblank(struct drm_crtc *crtc)
{
struct baikal_vdu_private *priv = crtc->dev->dev_private;
- //clk_prepare_enable(priv->clk);
-
/* clear interrupt status */
writel(0x3ffff, priv->regs + ISR);
diff --git a/drivers/gpu/drm/baikal/baikal_vdu_drm.h b/drivers/gpu/drm/baikal/baikal_vdu_drm.h
index 2db3fb73c9e7..9ab6303a4195 100644
--- a/drivers/gpu/drm/baikal/baikal_vdu_drm.h
+++ b/drivers/gpu/drm/baikal/baikal_vdu_drm.h
@@ -23,22 +23,16 @@
#include <drm/drm_gem.h>
#include <drm/drm_simple_kms_helper.h>
-struct clk;
-struct drm_device;
-struct drm_fbdev_cma;
-struct drm_panel;
-
-struct baikal_vdu_drm_connector {
- struct drm_connector connector;
- struct drm_panel *panel;
-};
+#define VDU_TYPE_HDMI 0
+#define VDU_TYPE_LVDS 1
struct baikal_vdu_private {
struct drm_device *drm;
- struct baikal_vdu_drm_connector connector;
+ struct drm_connector connector;
struct drm_crtc crtc;
struct drm_encoder encoder;
+ struct drm_panel *panel;
struct drm_bridge *bridge;
struct drm_plane primary;
@@ -47,16 +41,12 @@ struct baikal_vdu_private {
spinlock_t lock;
u32 counters[20];
int mode_fixup;
-
+ int type;
+ u32 ep_count;
u32 fb_addr;
u32 fb_end;
};
-#define to_baikal_vdu_drm_connector(x) \
- container_of(x, struct baikal_vdu_drm_connector, connector)
-
-extern const struct drm_encoder_funcs baikal_vdu_encoder_funcs;
-
/* CRTC Functions */
int baikal_vdu_crtc_create(struct drm_device *dev);
irqreturn_t baikal_vdu_irq(int irq, void *data);
@@ -64,15 +54,7 @@ irqreturn_t baikal_vdu_irq(int irq, void *data);
int baikal_vdu_primary_plane_init(struct drm_device *dev);
/* Connector Functions */
-int baikal_vdu_connector_create(struct drm_device *dev);
-
-/* Encoder Functions */
-int baikal_vdu_encoder_init(struct drm_device *dev);
-
-/* GEM Functions */
-int baikal_vdu_dumb_create(struct drm_file *file_priv,
- struct drm_device *dev,
- struct drm_mode_create_dumb *args);
+int baikal_vdu_lvds_connector_create(struct drm_device *dev);
void baikal_vdu_debugfs_init(struct drm_minor *minor);
diff --git a/drivers/gpu/drm/baikal/baikal_vdu_drv.c b/drivers/gpu/drm/baikal/baikal_vdu_drv.c
index 5deab510ea57..8eb9dda7fa01 100644
--- a/drivers/gpu/drm/baikal/baikal_vdu_drv.c
+++ b/drivers/gpu/drm/baikal/baikal_vdu_drv.c
@@ -23,7 +23,6 @@
#include <linux/arm-smccc.h>
#include <linux/irq.h>
#include <linux/clk.h>
-#include <linux/version.h>
#include <linux/shmem_fs.h>
#include <linux/dma-buf.h>
#include <linux/module.h>
@@ -63,6 +62,10 @@ static struct drm_mode_config_funcs mode_config_funcs = {
.atomic_commit = drm_atomic_helper_commit,
};
+static const struct drm_encoder_funcs baikal_vdu_encoder_funcs = {
+ .destroy = drm_encoder_cleanup,
+};
+
static int vdu_modeset_init(struct drm_device *dev)
{
struct drm_mode_config *mode_config;
@@ -94,38 +97,35 @@ static int vdu_modeset_init(struct drm_device *dev)
}
ret = drm_of_find_panel_or_bridge(dev->dev->of_node, -1, -1,
- &priv->connector.panel,
+ &priv->panel,
&priv->bridge);
if (ret == -EPROBE_DEFER) {
dev_info(dev->dev, "Bridge probe deferred\n");
goto out_config;
}
- ret = baikal_vdu_encoder_init(dev);
- if (ret) {
- dev_err(dev->dev, "Failed to create DRM encoder\n");
- goto out_config;
- }
-
if (priv->bridge) {
+ struct drm_encoder *encoder = &priv->encoder;
+ ret = drm_encoder_init(dev, encoder, &baikal_vdu_encoder_funcs,
+ DRM_MODE_ENCODER_NONE, NULL);
+ if (ret) {
+ dev_err(dev->dev, "failed to create DRM encoder\n");
+ goto out_config;
+ }
+ encoder->crtc = &priv->crtc;
+ encoder->possible_crtcs = drm_crtc_mask(encoder->crtc);
priv->bridge->encoder = &priv->encoder;
ret = drm_bridge_attach(&priv->encoder, priv->bridge, NULL, 0);
if (ret) {
dev_err(dev->dev, "Failed to attach DRM bridge %d\n", ret);
goto out_config;
}
- } else if (priv->connector.panel) {
- ret = baikal_vdu_connector_create(dev);
+ } else if (priv->panel) {
+ ret = baikal_vdu_lvds_connector_create(dev);
if (ret) {
dev_err(dev->dev, "Failed to create DRM connector\n");
goto out_config;
}
- ret = drm_connector_attach_encoder(&priv->connector.connector,
- &priv->encoder);
- if (ret != 0) {
- dev_err(dev->dev, "Failed to attach encoder\n");
- goto out_config;
- }
} else
ret = -EINVAL;
@@ -194,7 +194,7 @@ static struct drm_driver vdu_drm_driver = {
.major = 1,
.minor = 0,
.patchlevel = 0,
- .dumb_create = baikal_vdu_dumb_create,
+ .dumb_create = drm_gem_cma_dumb_create,
.gem_create_object = drm_gem_cma_create_object_default_funcs,
.prime_handle_to_fd = drm_gem_prime_handle_to_fd,
.prime_fd_to_handle = drm_gem_prime_fd_to_handle,
@@ -254,6 +254,14 @@ static int baikal_vdu_drm_probe(struct platform_device *pdev)
return ret;
}
+ if (pdev->dev.of_node && of_property_read_bool(pdev->dev.of_node, "lvds-out")) {
+ priv->type = VDU_TYPE_LVDS;
+ if (of_property_read_u32(pdev->dev.of_node, "num-lanes", &priv->ep_count))
+ priv->ep_count = 1;
+ }
+ else
+ priv->type = VDU_TYPE_HDMI;
+
ret = vdu_modeset_init(drm);
if (ret != 0) {
dev_err(dev, "Failed to init modeset\n");
diff --git a/drivers/gpu/drm/baikal/baikal_vdu_encoder.c b/drivers/gpu/drm/baikal/baikal_vdu_encoder.c
deleted file mode 100644
index 9081d196dac3..000000000000
--- a/drivers/gpu/drm/baikal/baikal_vdu_encoder.c
+++ /dev/null
@@ -1,51 +0,0 @@
-/*
- * Copyright (C) 2019-2020 Baikal Electronics JSC
- *
- * Author: Pavel Parkhomenko <Pavel.Parkhomenko@baikalelectronics.ru>
- *
- * Parts of this file were based on sources as follows:
- *
- * Copyright (c) 2006-2008 Intel Corporation
- * Copyright (c) 2007 Dave Airlie <airlied@linux.ie>
- * Copyright (C) 2011 Texas Instruments
- * (C) COPYRIGHT 2012-2013 ARM Limited. All rights reserved.
- *
- * This program is free software and is provided to you under the terms of the
- * GNU General Public License version 2 as published by the Free Software
- * Foundation, and any use by you of this program is subject to the terms of
- * such GNU licence.
- *
- */
-
-/**
- * baikal_vdu_encoder.c
- * Implementation of the encoder functions for Baikal Electronics BE-M1000 VDU driver
- */
-#include <linux/version.h>
-#include <linux/shmem_fs.h>
-#include <linux/dma-buf.h>
-
-#include <drm/drm_crtc_helper.h>
-
-#include "baikal_vdu_drm.h"
-
-const struct drm_encoder_funcs baikal_vdu_encoder_funcs = {
- .destroy = drm_encoder_cleanup,
-};
-
-int baikal_vdu_encoder_init(struct drm_device *dev)
-{
- struct baikal_vdu_private *priv = dev->dev_private;
- struct drm_encoder *encoder = &priv->encoder;
- int ret;
-
- ret = drm_encoder_init(dev, encoder, &baikal_vdu_encoder_funcs,
- DRM_MODE_ENCODER_NONE, NULL);
- if (ret)
- return ret;
-
- encoder->crtc = &priv->crtc;
- encoder->possible_crtcs = BIT(drm_crtc_index(encoder->crtc));
-
- return 0;
-}
diff --git a/drivers/gpu/drm/baikal/baikal_vdu_gem.c b/drivers/gpu/drm/baikal/baikal_vdu_gem.c
deleted file mode 100644
index b07566caf12c..000000000000
--- a/drivers/gpu/drm/baikal/baikal_vdu_gem.c
+++ /dev/null
@@ -1,37 +0,0 @@
-/*
- * Copyright (C) 2019-2020 Baikal Electronics JSC
- *
- * Author: Pavel Parkhomenko <Pavel.Parkhomenko@baikalelectronics.ru>
- *
- * Parts of this file were based on sources as follows:
- *
- * Copyright (c) 2006-2008 Intel Corporation
- * Copyright (c) 2007 Dave Airlie <airlied@linux.ie>
- * Copyright (C) 2011 Texas Instruments
- * (C) COPYRIGHT 2012-2013 ARM Limited. All rights reserved.
- *
- * This program is free software and is provided to you under the terms of the
- * GNU General Public License version 2 as published by the Free Software
- * Foundation, and any use by you of this program is subject to the terms of
- * such GNU licence.
- *
- */
-
-/**
- * baikal_vdu_gem.c
- * Implementation of the GEM functions for Baikal Electronics BE-M1000 VDU driver
- */
-#include <linux/version.h>
-#include <linux/shmem_fs.h>
-#include <linux/dma-buf.h>
-#include <drm/drm_crtc_helper.h>
-#include <drm/drm_gem_cma_helper.h>
-#include "baikal_vdu_drm.h"
-
-int baikal_vdu_dumb_create(struct drm_file *file_priv,
- struct drm_device *dev, struct drm_mode_create_dumb *args)
-{
- args->pitch = DIV_ROUND_UP(args->width * args->bpp, 8);
-
- return drm_gem_cma_dumb_create_internal(file_priv, dev, args);
-}
diff --git a/drivers/gpu/drm/baikal/baikal_vdu_regs.h b/drivers/gpu/drm/baikal/baikal_vdu_regs.h
index a0d8e69eb5e6..5553fcac5fec 100644
--- a/drivers/gpu/drm/baikal/baikal_vdu_regs.h
+++ b/drivers/gpu/drm/baikal/baikal_vdu_regs.h
@@ -1,5 +1,6 @@
+/* SPDX-License-Identifier: GPL-2.0 */
/*
- * Copyright (C) 2019-2020 Baikal Electronics JSC
+ * Copyright (C) 2019-2021 Baikal Electronics JSC
*
* Author: Pavel Parkhomenko <Pavel.Parkhomenko@baikalelectronics.ru>
*
@@ -7,10 +8,6 @@
*
* David A Rusling
* Copyright (C) 2001 ARM Limited
- *
- * This file is subject to the terms and conditions of the GNU General Public
- * License. See the file COPYING in the main directory of this archive
- * for more details.
*/
#ifndef __BAIKAL_VDU_REGS_H__
@@ -50,6 +47,7 @@
#define INTR_FER BIT(4)
#define CR1_FBP BIT(19)
+#define CR1_FDW_MASK GENMASK(17, 16)
#define CR1_FDW_4_WORDS (0 << 16)
#define CR1_FDW_8_WORDS (1 << 16)
#define CR1_FDW_16_WORDS (2 << 16)
@@ -129,15 +127,10 @@
#define HPPLOR_HPPLO(x) ((x) << 0)
#define GPIOR_UHD_MASK GENMASK(23, 16)
-#define GPIOR_UHD_FMT_LDI (0 << 20)
-#define GPIOR_UHD_FMT_VESA (1 << 20)
-#define GPIOR_UHD_FMT_JEIDA (2 << 20)
#define GPIOR_UHD_SNGL_PORT (0 << 18)
#define GPIOR_UHD_DUAL_PORT (1 << 18)
#define GPIOR_UHD_QUAD_PORT (2 << 18)
#define GPIOR_UHD_ENB BIT(17)
-#define GPIOR_UHD_PIX_INTLV (0 << 16)
-#define GPIOR_UHD_PIX_SQNTL (1 << 16)
#define MRR_DEAR_MRR_MASK GENMASK(31, 3)
#define MRR_OUTSTND_RQ_MASK GENMASK(2, 0)
--
2.31.1

View file

@ -1,16 +1,17 @@
#
# Automatically generated file; DO NOT EDIT.
# Linux/arm64 5.10.17 Kernel Configuration
# Linux/arm64 5.10.45 Kernel Configuration
#
CONFIG_CC_VERSION_TEXT="gcc (GCC) 10.2.0 20200723 (ROSA)"
CONFIG_CC_VERSION_TEXT="gcc (GCC) 11.1.0 20210427 (ROSA)"
CONFIG_CC_IS_GCC=y
CONFIG_GCC_VERSION=100200
CONFIG_GCC_VERSION=110100
CONFIG_LD_VERSION=236010000
CONFIG_CLANG_VERSION=0
CONFIG_LLD_VERSION=0
CONFIG_CC_CAN_LINK=y
CONFIG_CC_CAN_LINK_STATIC=y
CONFIG_CC_HAS_ASM_GOTO=y
CONFIG_CC_HAS_ASM_GOTO_OUTPUT=y
CONFIG_CC_HAS_ASM_INLINE=y
CONFIG_IRQ_WORK=y
CONFIG_BUILDTIME_TABLE_SORT=y
@ -221,6 +222,7 @@ CONFIG_USERMODE_DRIVER=y
# CONFIG_BPF_PRELOAD is not set
CONFIG_USERFAULTFD=y
CONFIG_ARCH_HAS_MEMBARRIER_SYNC_CORE=y
CONFIG_KCMP=y
CONFIG_RSEQ=y
# CONFIG_DEBUG_RSEQ is not set
# CONFIG_EMBEDDED is not set
@ -289,6 +291,7 @@ CONFIG_ARCH_ACTIONS=y
CONFIG_ARCH_AGILEX=y
CONFIG_ARCH_SUNXI=y
CONFIG_ARCH_ALPINE=y
CONFIG_ARCH_BAIKAL=y
CONFIG_ARCH_BCM2835=y
CONFIG_ARCH_BCM_IPROC=y
CONFIG_ARCH_BERLIN=y
@ -2111,7 +2114,6 @@ CONFIG_PCIEASPM_DEFAULT=y
CONFIG_PCIE_PME=y
CONFIG_PCIE_DPC=y
CONFIG_PCIE_PTM=y
# CONFIG_PCIE_BW is not set
CONFIG_PCIE_EDR=y
CONFIG_PCI_MSI=y
CONFIG_PCI_MSI_IRQ_DOMAIN=y
@ -2168,6 +2170,7 @@ CONFIG_PCIE_ROCKCHIP_HOST=m
CONFIG_PCIE_ROCKCHIP_EP=y
CONFIG_PCIE_MEDIATEK=m
CONFIG_PCIE_BRCMSTB=m
CONFIG_PCI_BAIKAL=m
CONFIG_PCIE_HISI_ERR=y
#
@ -2632,6 +2635,7 @@ CONFIG_XILINX_SDFEC=m
CONFIG_MISC_RTSX=m
CONFIG_PVPANIC=m
CONFIG_HISI_HIKEY_USB=m
CONFIG_TP_BMC=y
CONFIG_C2PORT=m
#
@ -3478,6 +3482,7 @@ CONFIG_STMMAC_ETH=m
CONFIG_STMMAC_PLATFORM=m
CONFIG_DWMAC_DWC_QOS_ETH=m
CONFIG_DWMAC_GENERIC=m
CONFIG_DWMAC_BAIKAL=m
CONFIG_DWMAC_IPQ806X=m
CONFIG_DWMAC_MEDIATEK=m
CONFIG_DWMAC_MESON=m
@ -4461,7 +4466,7 @@ CONFIG_SERIAL_8250_RSA=y
CONFIG_SERIAL_8250_DWLIB=y
CONFIG_SERIAL_8250_BCM2835AUX=m
CONFIG_SERIAL_8250_FSL=y
CONFIG_SERIAL_8250_DW=m
CONFIG_SERIAL_8250_DW=y
CONFIG_SERIAL_8250_RT288X=y
CONFIG_SERIAL_8250_OMAP=m
CONFIG_SERIAL_8250_MT6577=m
@ -5094,7 +5099,7 @@ CONFIG_GPIO_BCM_XGS_IPROC=m
CONFIG_GPIO_BRCMSTB=m
CONFIG_GPIO_CADENCE=m
CONFIG_GPIO_DAVINCI=y
CONFIG_GPIO_DWAPB=m
CONFIG_GPIO_DWAPB=y
CONFIG_GPIO_EIC_SPRD=m
CONFIG_GPIO_EXAR=m
CONFIG_GPIO_FTGPIO010=y
@ -5383,6 +5388,8 @@ CONFIG_SENSORS_ARM_SCMI=m
CONFIG_SENSORS_ARM_SCPI=m
CONFIG_SENSORS_ASPEED=m
CONFIG_SENSORS_ATXP1=m
CONFIG_SENSORS_BT1_PVT=m
CONFIG_SENSORS_BT1_PVT_ALARMS=y
CONFIG_SENSORS_CORSAIR_CPRO=m
CONFIG_SENSORS_DRIVETEMP=m
CONFIG_SENSORS_DS620=m
@ -6988,6 +6995,7 @@ CONFIG_DRM_MALI_DISPLAY=m
CONFIG_DRM_KOMEDA=m
# end of ARM devices
CONFIG_DRM_BAIKAL_VDU=m
CONFIG_DRM_RADEON=m
# CONFIG_DRM_RADEON_USERPTR is not set
CONFIG_DRM_AMDGPU=m
@ -7168,6 +7176,7 @@ CONFIG_DRM_CHRONTEL_CH7033=m
CONFIG_DRM_DISPLAY_CONNECTOR=m
CONFIG_DRM_LONTIUM_LT9611=m
CONFIG_DRM_LVDS_CODEC=m
CONFIG_DRM_BAIKAL_HDMI=m
CONFIG_DRM_MEGACHIPS_STDPXXXX_GE_B850V3_FW=m
CONFIG_DRM_NWL_MIPI_DSI=m
CONFIG_DRM_NXP_PTN3460=m
@ -8347,6 +8356,7 @@ CONFIG_USB_DWC3_KEYSTONE=m
CONFIG_USB_DWC3_MESON_G12A=m
CONFIG_USB_DWC3_OF_SIMPLE=m
CONFIG_USB_DWC3_QCOM=m
CONFIG_USB_DWC3_BAIKAL=m
CONFIG_USB_DWC2=y
CONFIG_USB_DWC2_HOST=y
@ -9008,7 +9018,7 @@ CONFIG_RTC_I2C_AND_SPI=y
#
CONFIG_RTC_DRV_DS3232=m
CONFIG_RTC_DRV_DS3232_HWMON=y
CONFIG_RTC_DRV_PCF2127=m
CONFIG_RTC_DRV_PCF2127=y
CONFIG_RTC_DRV_RV3029C2=m
CONFIG_RTC_DRV_RV3029_HWMON=y
@ -10955,7 +10965,6 @@ CONFIG_RESET_TEGRA_BPMP=y
CONFIG_GENERIC_PHY=y
CONFIG_GENERIC_PHY_MIPI_DPHY=y
CONFIG_PHY_XGENE=m
CONFIG_USB_LGM_PHY=m
CONFIG_PHY_SUN4I_USB=m
CONFIG_PHY_SUN6I_MIPI_DPHY=m
CONFIG_PHY_SUN9I_USB=m
@ -12117,7 +12126,7 @@ CONFIG_DMA_CMA=y
#
# Default contiguous memory area size:
#
CONFIG_CMA_SIZE_MBYTES=32
CONFIG_CMA_SIZE_MBYTES=256
CONFIG_CMA_SIZE_SEL_MBYTES=y
# CONFIG_CMA_SIZE_SEL_PERCENTAGE is not set
# CONFIG_CMA_SIZE_SEL_MIN is not set
@ -12223,6 +12232,7 @@ CONFIG_KDB_KEYBOARD=y
CONFIG_KDB_CONTINUE_CATASTROPHIC=0
CONFIG_ARCH_HAS_UBSAN_SANITIZE_ALL=y
# CONFIG_UBSAN is not set
CONFIG_HAVE_KCSAN_COMPILER=y
# end of Generic Kernel Debugging Instruments
CONFIG_DEBUG_KERNEL=y

View file

@ -342,6 +342,36 @@ Patch306: 0001-ROSA-ima-allow-to-off-modules-signature-check-dynami.patch
Patch307: le9pf.diff
Patch308: 0001-Revert-kallsyms-unexport-kallsyms_lookup_name-and-ka.patch
# Support SoC with Baikal-M (ARMv8) CPU
# From http://git.altlinux.org/gears/k/kernel-image-std-def.git (many thanks!)
# They are based on sources from official SDK with patched kernel from Baikal Electronics
Patch0601: 0601-Baikal-M-Kconfig-defconfig.patch
Patch0602: 0602-Baikal-M-clock-driver.patch
Patch0603: 0603-efi-rtc-avoid-calling-efi.get_time-on-Baikal-M-board.patch
Patch0604: 0604-efi-arm-runtime-print-EFI-mapping.patch
Patch0605: 0605-ethernet-stmmac-made-dwmac1000_-DMA-functions-availa.patch
Patch0606: 0606-stmmac-Baikal-M-dwmac-driver.patch
Patch0607: 0607-Fixed-secondary-CPUs-boot-on-BE-M1000-SoC.patch
Patch0608: 0608-Baikal-M-USB-driver.patch
# https://bugzilla.altlinux.org/show_bug.cgi?id=40269
Patch0609: 0609-Baikal-M-video-unit-driver.patch
Patch0610: 0610-Added-Baikal-T1-M-BMC-driver.patch
Patch0611: 0611-dw-hdmi-ahb-audio-support-BE-M1000-SoC.patch
Patch0612: 0612-bt1-pvt.c-access-registers-via-pvt_-readl-writel-hel.patch
Patch0613: 0613-bt1-pvt-define-pvt_readl-pvt_writel-for-BE-M1000-SoC.patch
Patch0614: 0614-bt1-pvt-adjust-probing-for-BE-M1000-SoC.patch
Patch0615: 0615-bt1-pvt-added-compatible-baikal-pvt.patch
Patch0616: 0616-Baikal-M-PCIe-driver-from-SDK-M-4.3.patch
Patch0617: 0617-Baikal-M-PCIe-driver-from-SDK-M-4.4.patch
Patch0618: 0618-baikal_vdu-avoid-using-SMC-calls-for-updating-frameb.patch
Patch0619: 0619-panfrost-compatibility-with-Baikal-M-firmware-from-S.patch
Patch0620: 0620-cpufreq-dt-don-t-load-on-BE-M1000-SoC.patch
Patch0621: 0621-baikal_clk-compatibility-with-SDK-M-5.1-firmware.patch
Patch0622: 0622-stmmac_mdio-implemented-reset-via-MAC-GP-out-pin.patch
Patch0623: 0623-dwmac_baikal-clear-PHY-reset-before-calling-generic-.patch
Patch0624: 0624-BROKEN-dwc-i2s-support-BE-M1000-SoC.patch
Patch0625: 0625-baikal_vdu_drm-LVDS-panel-support.patch
# Disable AutoReq
AutoReq: 0
# but keep autoprov for kmod(xxx)