layerscape: add linux 4.9 support

This patch is to add linux 4.9 support for layerscape.
All these kernel patches are from NXP LSDK 1709 release.

Signed-off-by: Yangbo Lu <yangbo.lu@nxp.com>
This commit is contained in:
Yangbo Lu 2017-09-27 15:31:31 +08:00 committed by John Crispin
parent 19951bbf57
commit 8fdda1cc10
32 changed files with 251241 additions and 1 deletions

View file

@ -9,7 +9,7 @@ include $(TOPDIR)/rules.mk
BOARD:=layerscape BOARD:=layerscape
BOARDNAME:=NXP Layerscape BOARDNAME:=NXP Layerscape
DEVICE_TYPE:=developerboard DEVICE_TYPE:=developerboard
KERNEL_PATCHVER:=4.4 KERNEL_PATCHVER:=4.9
FEATURES:=squashfs nand usb pcie gpio FEATURES:=squashfs nand usb pcie gpio
SUBTARGETS:=armv8_64b armv8_32b SUBTARGETS:=armv8_64b armv8_32b
MAINTAINER:=Yangbo Lu <yangbo.lu@nxp.com> MAINTAINER:=Yangbo Lu <yangbo.lu@nxp.com>

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,532 @@
From 11edf9c88acea13d1a02901289060263b4027a77 Mon Sep 17 00:00:00 2001
From: Yangbo Lu <yangbo.lu@nxp.com>
Date: Mon, 25 Sep 2017 09:52:26 +0800
Subject: [PATCH] config: support layerscape
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
This is a integrated patch for layerscape config/makefile support.
Signed-off-by: Yuantian Tang <andy.tang@nxp.com>
Signed-off-by: Zhang Ying-22455 <ying.zhang22455@nxp.com>
Signed-off-by: Zhao Qiang <qiang.zhao@nxp.com>
Signed-off-by: Bogdan Purcareata <bogdan.purcareata@nxp.com>
Signed-off-by: Zhao Qiang <qiang.zhao@nxp.com>
Signed-off-by: Horia Geantă <horia.geanta@nxp.com>
Signed-off-by: Yangbo Lu <yangbo.lu@nxp.com>
---
drivers/base/Kconfig | 1 +
drivers/crypto/Makefile | 2 +-
drivers/net/ethernet/freescale/Kconfig | 4 +-
drivers/net/ethernet/freescale/Makefile | 2 +
drivers/ptp/Kconfig | 29 ++++++
drivers/rtc/Kconfig | 8 ++
drivers/rtc/Makefile | 1 +
drivers/soc/Kconfig | 3 +-
drivers/soc/fsl/Kconfig | 22 +++++
drivers/soc/fsl/Kconfig.arm | 16 ++++
drivers/soc/fsl/Makefile | 4 +
drivers/soc/fsl/layerscape/Kconfig | 10 +++
drivers/soc/fsl/layerscape/Makefile | 1 +
drivers/soc/fsl/rcpm.c | 154 ++++++++++++++++++++++++++++++++
drivers/staging/Kconfig | 4 +
drivers/staging/Makefile | 2 +
drivers/staging/fsl-dpaa2/Kconfig | 41 +++++++++
drivers/staging/fsl-dpaa2/Makefile | 9 ++
18 files changed, 309 insertions(+), 4 deletions(-)
create mode 100644 drivers/soc/fsl/Kconfig
create mode 100644 drivers/soc/fsl/Kconfig.arm
create mode 100644 drivers/soc/fsl/layerscape/Kconfig
create mode 100644 drivers/soc/fsl/layerscape/Makefile
create mode 100644 drivers/soc/fsl/rcpm.c
create mode 100644 drivers/staging/fsl-dpaa2/Kconfig
create mode 100644 drivers/staging/fsl-dpaa2/Makefile
diff --git a/drivers/base/Kconfig b/drivers/base/Kconfig
index e1c0e2e0..4211a7fd 100644
--- a/drivers/base/Kconfig
+++ b/drivers/base/Kconfig
@@ -237,6 +237,7 @@ config GENERIC_CPU_AUTOPROBE
config SOC_BUS
bool
+ select GLOB
source "drivers/base/regmap/Kconfig"
diff --git a/drivers/crypto/Makefile b/drivers/crypto/Makefile
index ad7250fa..6d788fd7 100644
--- a/drivers/crypto/Makefile
+++ b/drivers/crypto/Makefile
@@ -3,7 +3,7 @@ obj-$(CONFIG_CRYPTO_DEV_ATMEL_SHA) += atmel-sha.o
obj-$(CONFIG_CRYPTO_DEV_ATMEL_TDES) += atmel-tdes.o
obj-$(CONFIG_CRYPTO_DEV_BFIN_CRC) += bfin_crc.o
obj-$(CONFIG_CRYPTO_DEV_CCP) += ccp/
-obj-$(CONFIG_CRYPTO_DEV_FSL_CAAM) += caam/
+obj-$(CONFIG_CRYPTO_DEV_FSL_CAAM_COMMON) += caam/
obj-$(CONFIG_CRYPTO_DEV_GEODE) += geode-aes.o
obj-$(CONFIG_CRYPTO_DEV_HIFN_795X) += hifn_795x.o
obj-$(CONFIG_CRYPTO_DEV_IMGTEC_HASH) += img-hash.o
diff --git a/drivers/net/ethernet/freescale/Kconfig b/drivers/net/ethernet/freescale/Kconfig
index d1ca45fb..74a2864e 100644
--- a/drivers/net/ethernet/freescale/Kconfig
+++ b/drivers/net/ethernet/freescale/Kconfig
@@ -5,7 +5,7 @@
config NET_VENDOR_FREESCALE
bool "Freescale devices"
default y
- depends on FSL_SOC || QUICC_ENGINE || CPM1 || CPM2 || PPC_MPC512x || \
+ depends on FSL_SOC || (QUICC_ENGINE && PPC32) || CPM1 || CPM2 || PPC_MPC512x || \
M523x || M527x || M5272 || M528x || M520x || M532x || \
ARCH_MXC || ARCH_MXS || (PPC_MPC52xx && PPC_BESTCOMM) || \
ARCH_LAYERSCAPE
@@ -93,4 +93,6 @@ config GIANFAR
and MPC86xx family of chips, the eTSEC on LS1021A and the FEC
on the 8540.
+source "drivers/net/ethernet/freescale/sdk_fman/Kconfig"
+source "drivers/net/ethernet/freescale/sdk_dpaa/Kconfig"
endif # NET_VENDOR_FREESCALE
diff --git a/drivers/net/ethernet/freescale/Makefile b/drivers/net/ethernet/freescale/Makefile
index cbe21dc7..a5d4405f 100644
--- a/drivers/net/ethernet/freescale/Makefile
+++ b/drivers/net/ethernet/freescale/Makefile
@@ -21,4 +21,6 @@ gianfar_driver-objs := gianfar.o \
obj-$(CONFIG_UCC_GETH) += ucc_geth_driver.o
ucc_geth_driver-objs := ucc_geth.o ucc_geth_ethtool.o
+obj-$(if $(CONFIG_FSL_SDK_FMAN),y) += sdk_fman/
+obj-$(if $(CONFIG_FSL_SDK_DPAA_ETH),y) += sdk_dpaa/
obj-$(CONFIG_FSL_FMAN) += fman/
diff --git a/drivers/ptp/Kconfig b/drivers/ptp/Kconfig
index ee3de342..4c45beda 100644
--- a/drivers/ptp/Kconfig
+++ b/drivers/ptp/Kconfig
@@ -39,6 +39,35 @@ config PTP_1588_CLOCK_GIANFAR
To compile this driver as a module, choose M here: the module
will be called gianfar_ptp.
+config PTP_1588_CLOCK_DPAA
+ tristate "Freescale DPAA as PTP clock"
+ depends on FSL_SDK_DPAA_ETH
+ select PTP_1588_CLOCK
+ select FSL_DPAA_TS
+ default n
+ help
+ This driver adds support for using the DPAA 1588 timer module
+ as a PTP clock. This clock is only useful if your PTP programs are
+ getting hardware time stamps on the PTP Ethernet packets
+ using the SO_TIMESTAMPING API.
+
+ To compile this driver as a module, choose M here: the module
+ will be called dpaa_ptp.
+
+config PTP_1588_CLOCK_DPAA2
+ tristate "Freescale DPAA2 as PTP clock"
+ depends on FSL_DPAA2_ETH
+ select PTP_1588_CLOCK
+ default y
+ help
+ This driver adds support for using the DPAA2 1588 timer module
+ as a PTP clock. This clock is only useful if your PTP programs are
+ getting hardware time stamps on the PTP Ethernet packets
+ using the SO_TIMESTAMPING API.
+
+ To compile this driver as a module, choose M here: the module
+ will be called dpaa2-rtc.
+
config PTP_1588_CLOCK_IXP46X
tristate "Intel IXP46x as PTP clock"
depends on IXP4XX_ETH
diff --git a/drivers/rtc/Kconfig b/drivers/rtc/Kconfig
index 0723c97e..df610dcd 100644
--- a/drivers/rtc/Kconfig
+++ b/drivers/rtc/Kconfig
@@ -414,6 +414,14 @@ config RTC_DRV_PCF85063
This driver can also be built as a module. If so, the module
will be called rtc-pcf85063.
+config RTC_DRV_PCF85263
+ tristate "NXP PCF85263"
+ help
+ If you say yes here you get support for the PCF85263 RTC chip
+
+ This driver can also be built as a module. If so, the module
+ will be called rtc-pcf85263.
+
config RTC_DRV_PCF8563
tristate "Philips PCF8563/Epson RTC8564"
help
diff --git a/drivers/rtc/Makefile b/drivers/rtc/Makefile
index 1ac694a3..7675b8a7 100644
--- a/drivers/rtc/Makefile
+++ b/drivers/rtc/Makefile
@@ -111,6 +111,7 @@ obj-$(CONFIG_RTC_DRV_PCF2127) += rtc-pcf2127.o
obj-$(CONFIG_RTC_DRV_PCF50633) += rtc-pcf50633.o
obj-$(CONFIG_RTC_DRV_PCF85063) += rtc-pcf85063.o
obj-$(CONFIG_RTC_DRV_PCF8523) += rtc-pcf8523.o
+obj-$(CONFIG_RTC_DRV_PCF85263) += rtc-pcf85263.o
obj-$(CONFIG_RTC_DRV_PCF8563) += rtc-pcf8563.o
obj-$(CONFIG_RTC_DRV_PCF8583) += rtc-pcf8583.o
obj-$(CONFIG_RTC_DRV_PIC32) += rtc-pic32.o
diff --git a/drivers/soc/Kconfig b/drivers/soc/Kconfig
index e6e90e80..f31bceb6 100644
--- a/drivers/soc/Kconfig
+++ b/drivers/soc/Kconfig
@@ -1,8 +1,7 @@
menu "SOC (System On Chip) specific Drivers"
source "drivers/soc/bcm/Kconfig"
-source "drivers/soc/fsl/qbman/Kconfig"
-source "drivers/soc/fsl/qe/Kconfig"
+source "drivers/soc/fsl/Kconfig"
source "drivers/soc/mediatek/Kconfig"
source "drivers/soc/qcom/Kconfig"
source "drivers/soc/rockchip/Kconfig"
diff --git a/drivers/soc/fsl/Kconfig b/drivers/soc/fsl/Kconfig
new file mode 100644
index 00000000..d4cd25f1
--- /dev/null
+++ b/drivers/soc/fsl/Kconfig
@@ -0,0 +1,22 @@
+#
+# Freescale SOC drivers
+#
+
+source "drivers/soc/fsl/qbman/Kconfig"
+source "drivers/soc/fsl/qe/Kconfig"
+source "drivers/soc/fsl/ls2-console/Kconfig"
+
+config FSL_GUTS
+ bool
+ select SOC_BUS
+ help
+ The global utilities block controls power management, I/O device
+ enabling, power-onreset(POR) configuration monitoring, alternate
+ function selection for multiplexed signals,and clock control.
+ This driver is to manage and access global utilities block.
+ Initially only reading SVR and registering soc device are supported.
+ Other guts accesses, such as reading RCW, should eventually be moved
+ into this driver as well.
+if ARM || ARM64
+source "drivers/soc/fsl/Kconfig.arm"
+endif
diff --git a/drivers/soc/fsl/Kconfig.arm b/drivers/soc/fsl/Kconfig.arm
new file mode 100644
index 00000000..106c9b98
--- /dev/null
+++ b/drivers/soc/fsl/Kconfig.arm
@@ -0,0 +1,16 @@
+#
+# Freescale ARM SOC Drivers
+#
+
+config LS_SOC_DRIVERS
+ bool "Layerscape Soc Drivers"
+ depends on ARCH_LAYERSCAPE || SOC_LS1021A
+ default n
+ help
+ Say y here to enable Freescale Layerscape Soc Device Drivers support.
+ The Soc Drivers provides the device driver that is a specific block
+ or feature on Layerscape platform.
+
+if LS_SOC_DRIVERS
+ source "drivers/soc/fsl/layerscape/Kconfig"
+endif
diff --git a/drivers/soc/fsl/Makefile b/drivers/soc/fsl/Makefile
index 75e1f533..b8708569 100644
--- a/drivers/soc/fsl/Makefile
+++ b/drivers/soc/fsl/Makefile
@@ -5,3 +5,7 @@
obj-$(CONFIG_FSL_DPAA) += qbman/
obj-$(CONFIG_QUICC_ENGINE) += qe/
obj-$(CONFIG_CPM) += qe/
+obj-$(CONFIG_FSL_GUTS) += guts.o
+obj-$(CONFIG_FSL_LS2_CONSOLE) += ls2-console/
+obj-$(CONFIG_SUSPEND) += rcpm.o
+obj-$(CONFIG_LS_SOC_DRIVERS) += layerscape/
diff --git a/drivers/soc/fsl/layerscape/Kconfig b/drivers/soc/fsl/layerscape/Kconfig
new file mode 100644
index 00000000..e1373aa1
--- /dev/null
+++ b/drivers/soc/fsl/layerscape/Kconfig
@@ -0,0 +1,10 @@
+#
+# Layerscape Soc drivers
+#
+config FTM_ALARM
+ bool "FTM alarm driver"
+ default n
+ help
+ Say y here to enable FTM alarm support. The FTM alarm provides
+ alarm functions for wakeup system from deep sleep. There is only
+ one FTM can be used in ALARM(FTM 0).
diff --git a/drivers/soc/fsl/layerscape/Makefile b/drivers/soc/fsl/layerscape/Makefile
new file mode 100644
index 00000000..6299aa1d
--- /dev/null
+++ b/drivers/soc/fsl/layerscape/Makefile
@@ -0,0 +1 @@
+obj-$(CONFIG_FTM_ALARM) += ftm_alarm.o
diff --git a/drivers/soc/fsl/rcpm.c b/drivers/soc/fsl/rcpm.c
new file mode 100644
index 00000000..a6a31c87
--- /dev/null
+++ b/drivers/soc/fsl/rcpm.c
@@ -0,0 +1,154 @@
+/*
+ * Run Control and Power Management (RCPM) driver
+ *
+ * Copyright 2016 NXP
+ *
+ * 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.
+ *
+ */
+#define pr_fmt(fmt) "RCPM: %s: " fmt, __func__
+
+#include <linux/kernel.h>
+#include <linux/io.h>
+#include <linux/of_platform.h>
+#include <linux/of_address.h>
+#include <linux/suspend.h>
+
+/* RCPM register offset */
+#define RCPM_IPPDEXPCR0 0x140
+
+#define RCPM_WAKEUP_CELL_SIZE 2
+
+struct rcpm_config {
+ int ipp_num;
+ int ippdexpcr_offset;
+ u32 ippdexpcr[2];
+ void *rcpm_reg_base;
+};
+
+static struct rcpm_config *rcpm;
+
+static inline void rcpm_reg_write(u32 offset, u32 value)
+{
+ iowrite32be(value, rcpm->rcpm_reg_base + offset);
+}
+
+static inline u32 rcpm_reg_read(u32 offset)
+{
+ return ioread32be(rcpm->rcpm_reg_base + offset);
+}
+
+static void rcpm_wakeup_fixup(struct device *dev, void *data)
+{
+ struct device_node *node = dev ? dev->of_node : NULL;
+ u32 value[RCPM_WAKEUP_CELL_SIZE];
+ int ret, i;
+
+ if (!dev || !node || !device_may_wakeup(dev))
+ return;
+
+ /*
+ * Get the values in the "rcpm-wakeup" property.
+ * Three values are:
+ * The first is a pointer to the RCPM node.
+ * The second is the value of the ippdexpcr0 register.
+ * The third is the value of the ippdexpcr1 register.
+ */
+ ret = of_property_read_u32_array(node, "fsl,rcpm-wakeup",
+ value, RCPM_WAKEUP_CELL_SIZE);
+ if (ret)
+ return;
+
+ pr_debug("wakeup source: the device %s\n", node->full_name);
+
+ for (i = 0; i < rcpm->ipp_num; i++)
+ rcpm->ippdexpcr[i] |= value[i + 1];
+}
+
+static int rcpm_suspend_prepare(void)
+{
+ int i;
+
+ BUG_ON(!rcpm);
+
+ for (i = 0; i < rcpm->ipp_num; i++)
+ rcpm->ippdexpcr[i] = 0;
+
+ dpm_for_each_dev(NULL, rcpm_wakeup_fixup);
+
+ for (i = 0; i < rcpm->ipp_num; i++) {
+ rcpm_reg_write(rcpm->ippdexpcr_offset + 4 * i,
+ rcpm->ippdexpcr[i]);
+ pr_debug("ippdexpcr%d = 0x%x\n", i, rcpm->ippdexpcr[i]);
+ }
+
+ return 0;
+}
+
+static int rcpm_suspend_notifier_call(struct notifier_block *bl,
+ unsigned long state,
+ void *unused)
+{
+ switch (state) {
+ case PM_SUSPEND_PREPARE:
+ rcpm_suspend_prepare();
+ break;
+ }
+
+ return NOTIFY_DONE;
+}
+
+static struct rcpm_config rcpm_default_config = {
+ .ipp_num = 1,
+ .ippdexpcr_offset = RCPM_IPPDEXPCR0,
+};
+
+static const struct of_device_id rcpm_matches[] = {
+ {
+ .compatible = "fsl,qoriq-rcpm-2.1",
+ .data = &rcpm_default_config,
+ },
+ {}
+};
+
+static struct notifier_block rcpm_suspend_notifier = {
+ .notifier_call = rcpm_suspend_notifier_call,
+};
+
+static int __init layerscape_rcpm_init(void)
+{
+ const struct of_device_id *match;
+ struct device_node *np;
+
+ np = of_find_matching_node_and_match(NULL, rcpm_matches, &match);
+ if (!np) {
+ pr_err("Can't find the RCPM node.\n");
+ return -EINVAL;
+ }
+
+ if (match->data)
+ rcpm = (struct rcpm_config *)match->data;
+ else
+ return -EINVAL;
+
+ rcpm->rcpm_reg_base = of_iomap(np, 0);
+ of_node_put(np);
+ if (!rcpm->rcpm_reg_base)
+ return -ENOMEM;
+
+ register_pm_notifier(&rcpm_suspend_notifier);
+
+ pr_info("The RCPM driver initialized.\n");
+
+ return 0;
+}
+
+subsys_initcall(layerscape_rcpm_init);
diff --git a/drivers/staging/Kconfig b/drivers/staging/Kconfig
index 58a7b350..f8e54860 100644
--- a/drivers/staging/Kconfig
+++ b/drivers/staging/Kconfig
@@ -94,6 +94,8 @@ source "drivers/staging/fbtft/Kconfig"
source "drivers/staging/fsl-mc/Kconfig"
+source "drivers/staging/fsl-dpaa2/Kconfig"
+
source "drivers/staging/wilc1000/Kconfig"
source "drivers/staging/most/Kconfig"
@@ -106,4 +108,6 @@ source "drivers/staging/greybus/Kconfig"
source "drivers/staging/vc04_services/Kconfig"
+source "drivers/staging/fsl_qbman/Kconfig"
+
endif # STAGING
diff --git a/drivers/staging/Makefile b/drivers/staging/Makefile
index 2fa9745d..cbd7b089 100644
--- a/drivers/staging/Makefile
+++ b/drivers/staging/Makefile
@@ -36,9 +36,11 @@ obj-$(CONFIG_UNISYSSPAR) += unisys/
obj-$(CONFIG_COMMON_CLK_XLNX_CLKWZRD) += clocking-wizard/
obj-$(CONFIG_FB_TFT) += fbtft/
obj-$(CONFIG_FSL_MC_BUS) += fsl-mc/
+obj-$(CONFIG_FSL_DPAA2) += fsl-dpaa2/
obj-$(CONFIG_WILC1000) += wilc1000/
obj-$(CONFIG_MOST) += most/
obj-$(CONFIG_ISDN_I4L) += i4l/
obj-$(CONFIG_KS7010) += ks7010/
obj-$(CONFIG_GREYBUS) += greybus/
obj-$(CONFIG_BCM2708_VCHIQ) += vc04_services/
+obj-$(CONFIG_FSL_SDK_DPA) += fsl_qbman/
diff --git a/drivers/staging/fsl-dpaa2/Kconfig b/drivers/staging/fsl-dpaa2/Kconfig
new file mode 100644
index 00000000..8042d9cc
--- /dev/null
+++ b/drivers/staging/fsl-dpaa2/Kconfig
@@ -0,0 +1,41 @@
+#
+# Freescale DataPath Acceleration Architecture Gen2 (DPAA2) drivers
+#
+
+config FSL_DPAA2
+ bool "Freescale DPAA2 devices"
+ depends on FSL_MC_BUS
+ ---help---
+ Build drivers for Freescale DataPath Acceleration
+ Architecture (DPAA2) family of SoCs.
+
+config FSL_DPAA2_ETH
+ tristate "Freescale DPAA2 Ethernet"
+ depends on FSL_DPAA2 && FSL_MC_DPIO
+ ---help---
+ Ethernet driver for Freescale DPAA2 SoCs, using the
+ Freescale MC bus driver
+
+if FSL_DPAA2_ETH
+config FSL_DPAA2_ETH_USE_ERR_QUEUE
+ bool "Enable Rx error queue"
+ default n
+ ---help---
+ Allow Rx error frames to be enqueued on an error queue
+ and processed by the driver (by default they are dropped
+ in hardware).
+ This may impact performance, recommended for debugging
+ purposes only.
+
+# QBMAN_DEBUG requires some additional DPIO APIs
+config FSL_DPAA2_ETH_DEBUGFS
+ depends on DEBUG_FS && FSL_QBMAN_DEBUG
+ bool "Enable debugfs support"
+ default n
+ ---help---
+ Enable advanced statistics through debugfs interface.
+endif
+
+source "drivers/staging/fsl-dpaa2/mac/Kconfig"
+source "drivers/staging/fsl-dpaa2/evb/Kconfig"
+source "drivers/staging/fsl-dpaa2/ethsw/Kconfig"
diff --git a/drivers/staging/fsl-dpaa2/Makefile b/drivers/staging/fsl-dpaa2/Makefile
new file mode 100644
index 00000000..cbaa8c20
--- /dev/null
+++ b/drivers/staging/fsl-dpaa2/Makefile
@@ -0,0 +1,9 @@
+#
+# Freescale DataPath Acceleration Architecture Gen2 (DPAA2) drivers
+#
+
+obj-$(CONFIG_FSL_DPAA2_ETH) += ethernet/
+obj-$(CONFIG_FSL_DPAA2_MAC) += mac/
+obj-$(CONFIG_FSL_DPAA2_EVB) += evb/
+obj-$(CONFIG_FSL_DPAA2_ETHSW) += ethsw/
+obj-$(CONFIG_PTP_1588_CLOCK_DPAA2) += rtc/
--
2.14.1

View file

@ -0,0 +1,461 @@
From 7edaf7ed8fbd5fb50950a4fc8067a9c14557d010 Mon Sep 17 00:00:00 2001
From: Yangbo Lu <yangbo.lu@nxp.com>
Date: Mon, 25 Sep 2017 10:03:52 +0800
Subject: [PATCH] arch: support layerscape
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
This is a integrated patch for layerscape arch support.
Signed-off-by: Madalin Bucur <madalin.bucur@nxp.com>
Signed-off-by: Nipun Gupta <nipun.gupta@nxp.com>
Signed-off-by: Zhao Qiang <B45475@freescale.com>
Signed-off-by: Camelia Groza <camelia.groza@nxp.com>
Signed-off-by: Haiying Wang <Haiying.wang@freescale.com>
Signed-off-by: Pan Jiafei <Jiafei.Pan@nxp.com>
Signed-off-by: Po Liu <po.liu@nxp.com>
Signed-off-by: Bharat Bhushan <Bharat.Bhushan@nxp.com>
Signed-off-by: Jianhua Xie <jianhua.xie@nxp.com>
Signed-off-by: Horia Geantă <horia.geanta@nxp.com>
Signed-off-by: Yangbo Lu <yangbo.lu@nxp.com>
---
arch/arm/include/asm/delay.h | 16 +++++++++
arch/arm/include/asm/io.h | 31 ++++++++++++++++++
arch/arm/include/asm/mach/map.h | 4 +--
arch/arm/include/asm/pgtable.h | 7 ++++
arch/arm/kernel/bios32.c | 43 ++++++++++++++++++++++++
arch/arm/mm/dma-mapping.c | 1 +
arch/arm/mm/ioremap.c | 7 ++++
arch/arm/mm/mmu.c | 9 +++++
arch/arm64/include/asm/cache.h | 2 +-
arch/arm64/include/asm/io.h | 2 ++
arch/arm64/include/asm/pci.h | 4 +++
arch/arm64/include/asm/pgtable-prot.h | 1 +
arch/arm64/include/asm/pgtable.h | 5 +++
arch/arm64/kernel/pci.c | 62 +++++++++++++++++++++++++++++++++++
arch/arm64/mm/dma-mapping.c | 6 ++++
15 files changed, 197 insertions(+), 3 deletions(-)
diff --git a/arch/arm/include/asm/delay.h b/arch/arm/include/asm/delay.h
index b1ce037e..1445b0ca 100644
--- a/arch/arm/include/asm/delay.h
+++ b/arch/arm/include/asm/delay.h
@@ -57,6 +57,22 @@ extern void __bad_udelay(void);
__const_udelay((n) * UDELAY_MULT)) : \
__udelay(n))
+#define spin_event_timeout(condition, timeout, delay) \
+({ \
+ typeof(condition) __ret; \
+ int i = 0; \
+ while (!(__ret = (condition)) && (i++ < timeout)) { \
+ if (delay) \
+ udelay(delay); \
+ else \
+ cpu_relax(); \
+ udelay(1); \
+ } \
+ if (!__ret) \
+ __ret = (condition); \
+ __ret; \
+})
+
/* Loop-based definitions for assembly code. */
extern void __loop_delay(unsigned long loops);
extern void __loop_udelay(unsigned long usecs);
diff --git a/arch/arm/include/asm/io.h b/arch/arm/include/asm/io.h
index 021692c6..172a4f2e 100644
--- a/arch/arm/include/asm/io.h
+++ b/arch/arm/include/asm/io.h
@@ -129,6 +129,7 @@ static inline u32 __raw_readl(const volatile void __iomem *addr)
#define MT_DEVICE_NONSHARED 1
#define MT_DEVICE_CACHED 2
#define MT_DEVICE_WC 3
+#define MT_MEMORY_RW_NS 4
/*
* types 4 onwards can be found in asm/mach/map.h and are undefined
* for ioremap
@@ -220,6 +221,34 @@ extern int pci_ioremap_io(unsigned int offset, phys_addr_t phys_addr);
#endif
#endif
+/* access ports */
+#define setbits32(_addr, _v) iowrite32be(ioread32be(_addr) | (_v), (_addr))
+#define clrbits32(_addr, _v) iowrite32be(ioread32be(_addr) & ~(_v), (_addr))
+
+#define setbits16(_addr, _v) iowrite16be(ioread16be(_addr) | (_v), (_addr))
+#define clrbits16(_addr, _v) iowrite16be(ioread16be(_addr) & ~(_v), (_addr))
+
+#define setbits8(_addr, _v) iowrite8(ioread8(_addr) | (_v), (_addr))
+#define clrbits8(_addr, _v) iowrite8(ioread8(_addr) & ~(_v), (_addr))
+
+/* Clear and set bits in one shot. These macros can be used to clear and
+ * set multiple bits in a register using a single read-modify-write. These
+ * macros can also be used to set a multiple-bit bit pattern using a mask,
+ * by specifying the mask in the 'clear' parameter and the new bit pattern
+ * in the 'set' parameter.
+ */
+
+#define clrsetbits_be32(addr, clear, set) \
+ iowrite32be((ioread32be(addr) & ~(clear)) | (set), (addr))
+#define clrsetbits_le32(addr, clear, set) \
+ iowrite32le((ioread32le(addr) & ~(clear)) | (set), (addr))
+#define clrsetbits_be16(addr, clear, set) \
+ iowrite16be((ioread16be(addr) & ~(clear)) | (set), (addr))
+#define clrsetbits_le16(addr, clear, set) \
+ iowrite16le((ioread16le(addr) & ~(clear)) | (set), (addr))
+#define clrsetbits_8(addr, clear, set) \
+ iowrite8((ioread8(addr) & ~(clear)) | (set), (addr))
+
/*
* IO port access primitives
* -------------------------
@@ -408,6 +437,8 @@ void __iomem *ioremap_wc(resource_size_t res_cookie, size_t size);
#define ioremap_wc ioremap_wc
#define ioremap_wt ioremap_wc
+void __iomem *ioremap_cache_ns(resource_size_t res_cookie, size_t size);
+
void iounmap(volatile void __iomem *iomem_cookie);
#define iounmap iounmap
diff --git a/arch/arm/include/asm/mach/map.h b/arch/arm/include/asm/mach/map.h
index 9b7c328f..27f3df7d 100644
--- a/arch/arm/include/asm/mach/map.h
+++ b/arch/arm/include/asm/mach/map.h
@@ -21,9 +21,9 @@ struct map_desc {
unsigned int type;
};
-/* types 0-3 are defined in asm/io.h */
+/* types 0-4 are defined in asm/io.h */
enum {
- MT_UNCACHED = 4,
+ MT_UNCACHED = 5,
MT_CACHECLEAN,
MT_MINICLEAN,
MT_LOW_VECTORS,
diff --git a/arch/arm/include/asm/pgtable.h b/arch/arm/include/asm/pgtable.h
index a8d656d9..4ab57b37 100644
--- a/arch/arm/include/asm/pgtable.h
+++ b/arch/arm/include/asm/pgtable.h
@@ -118,6 +118,13 @@ extern pgprot_t pgprot_s2_device;
#define pgprot_noncached(prot) \
__pgprot_modify(prot, L_PTE_MT_MASK, L_PTE_MT_UNCACHED)
+#define pgprot_cached(prot) \
+ __pgprot_modify(prot, L_PTE_MT_MASK, L_PTE_MT_DEV_CACHED)
+
+#define pgprot_cached_ns(prot) \
+ __pgprot_modify(prot, L_PTE_MT_MASK, L_PTE_MT_DEV_CACHED | \
+ L_PTE_MT_DEV_NONSHARED)
+
#define pgprot_writecombine(prot) \
__pgprot_modify(prot, L_PTE_MT_MASK, L_PTE_MT_BUFFERABLE)
diff --git a/arch/arm/kernel/bios32.c b/arch/arm/kernel/bios32.c
index 2f0e0773..d2f4869a 100644
--- a/arch/arm/kernel/bios32.c
+++ b/arch/arm/kernel/bios32.c
@@ -11,6 +11,8 @@
#include <linux/slab.h>
#include <linux/init.h>
#include <linux/io.h>
+#include <linux/of_irq.h>
+#include <linux/pcieport_if.h>
#include <asm/mach-types.h>
#include <asm/mach/map.h>
@@ -63,6 +65,47 @@ void pcibios_report_status(u_int status_mask, int warn)
pcibios_bus_report_status(bus, status_mask, warn);
}
+/*
+ * Check device tree if the service interrupts are there
+ */
+int pcibios_check_service_irqs(struct pci_dev *dev, int *irqs, int mask)
+{
+ int ret, count = 0;
+ struct device_node *np = NULL;
+
+ if (dev->bus->dev.of_node)
+ np = dev->bus->dev.of_node;
+
+ if (np == NULL)
+ return 0;
+
+ if (!IS_ENABLED(CONFIG_OF_IRQ))
+ return 0;
+
+ /* If root port doesn't support MSI/MSI-X/INTx in RC mode,
+ * request irq for aer
+ */
+ if (mask & PCIE_PORT_SERVICE_AER) {
+ ret = of_irq_get_byname(np, "aer");
+ if (ret > 0) {
+ irqs[PCIE_PORT_SERVICE_AER_SHIFT] = ret;
+ count++;
+ }
+ }
+
+ if (mask & PCIE_PORT_SERVICE_PME) {
+ ret = of_irq_get_byname(np, "pme");
+ if (ret > 0) {
+ irqs[PCIE_PORT_SERVICE_PME_SHIFT] = ret;
+ count++;
+ }
+ }
+
+ /* TODO: add more service interrupts if there it is in the device tree*/
+
+ return count;
+}
+
/*
* We don't use this to fix the device, but initialisation of it.
* It's not the correct use for this, but it works.
diff --git a/arch/arm/mm/dma-mapping.c b/arch/arm/mm/dma-mapping.c
index ab771000..9b5f4465 100644
--- a/arch/arm/mm/dma-mapping.c
+++ b/arch/arm/mm/dma-mapping.c
@@ -2392,6 +2392,7 @@ void arch_setup_dma_ops(struct device *dev, u64 dma_base, u64 size,
set_dma_ops(dev, dma_ops);
}
+EXPORT_SYMBOL(arch_setup_dma_ops);
void arch_teardown_dma_ops(struct device *dev)
{
diff --git a/arch/arm/mm/ioremap.c b/arch/arm/mm/ioremap.c
index ff0eed23..2f2f4269 100644
--- a/arch/arm/mm/ioremap.c
+++ b/arch/arm/mm/ioremap.c
@@ -398,6 +398,13 @@ void __iomem *ioremap_wc(resource_size_t res_cookie, size_t size)
}
EXPORT_SYMBOL(ioremap_wc);
+void __iomem *ioremap_cache_ns(resource_size_t res_cookie, size_t size)
+{
+ return arch_ioremap_caller(res_cookie, size, MT_MEMORY_RW_NS,
+ __builtin_return_address(0));
+}
+EXPORT_SYMBOL(ioremap_cache_ns);
+
/*
* Remap an arbitrary physical address space into the kernel virtual
* address space as memory. Needed when the kernel wants to execute
diff --git a/arch/arm/mm/mmu.c b/arch/arm/mm/mmu.c
index f7c74135..4a2fb704 100644
--- a/arch/arm/mm/mmu.c
+++ b/arch/arm/mm/mmu.c
@@ -313,6 +313,13 @@ static struct mem_type mem_types[] __ro_after_init = {
.prot_sect = PMD_TYPE_SECT | PMD_SECT_AP_WRITE,
.domain = DOMAIN_KERNEL,
},
+ [MT_MEMORY_RW_NS] = {
+ .prot_pte = L_PTE_PRESENT | L_PTE_YOUNG | L_PTE_DIRTY |
+ L_PTE_XN,
+ .prot_l1 = PMD_TYPE_TABLE,
+ .prot_sect = PMD_TYPE_SECT | PMD_SECT_AP_WRITE | PMD_SECT_XN,
+ .domain = DOMAIN_KERNEL,
+ },
[MT_ROM] = {
.prot_sect = PMD_TYPE_SECT,
.domain = DOMAIN_KERNEL,
@@ -644,6 +651,7 @@ static void __init build_mem_type_table(void)
}
kern_pgprot |= PTE_EXT_AF;
vecs_pgprot |= PTE_EXT_AF;
+ mem_types[MT_MEMORY_RW_NS].prot_pte |= PTE_EXT_AF | cp->pte;
/*
* Set PXN for user mappings
@@ -672,6 +680,7 @@ static void __init build_mem_type_table(void)
mem_types[MT_MEMORY_RWX].prot_pte |= kern_pgprot;
mem_types[MT_MEMORY_RW].prot_sect |= ecc_mask | cp->pmd;
mem_types[MT_MEMORY_RW].prot_pte |= kern_pgprot;
+ mem_types[MT_MEMORY_RW_NS].prot_sect |= ecc_mask | cp->pmd;
mem_types[MT_MEMORY_DMA_READY].prot_pte |= kern_pgprot;
mem_types[MT_MEMORY_RWX_NONCACHED].prot_sect |= ecc_mask;
mem_types[MT_ROM].prot_sect |= cp->pmd;
diff --git a/arch/arm64/include/asm/cache.h b/arch/arm64/include/asm/cache.h
index 5082b30b..bde44993 100644
--- a/arch/arm64/include/asm/cache.h
+++ b/arch/arm64/include/asm/cache.h
@@ -18,7 +18,7 @@
#include <asm/cachetype.h>
-#define L1_CACHE_SHIFT 7
+#define L1_CACHE_SHIFT 6
#define L1_CACHE_BYTES (1 << L1_CACHE_SHIFT)
/*
diff --git a/arch/arm64/include/asm/io.h b/arch/arm64/include/asm/io.h
index 0bba427b..36c1fbf3 100644
--- a/arch/arm64/include/asm/io.h
+++ b/arch/arm64/include/asm/io.h
@@ -171,6 +171,8 @@ extern void __iomem *ioremap_cache(phys_addr_t phys_addr, size_t size);
#define ioremap_nocache(addr, size) __ioremap((addr), (size), __pgprot(PROT_DEVICE_nGnRE))
#define ioremap_wc(addr, size) __ioremap((addr), (size), __pgprot(PROT_NORMAL_NC))
#define ioremap_wt(addr, size) __ioremap((addr), (size), __pgprot(PROT_DEVICE_nGnRE))
+#define ioremap_cache_ns(addr, size) __ioremap((addr), (size), \
+ __pgprot(PROT_NORMAL_NS))
#define iounmap __iounmap
/*
diff --git a/arch/arm64/include/asm/pci.h b/arch/arm64/include/asm/pci.h
index b9a7ba9c..8a189159 100644
--- a/arch/arm64/include/asm/pci.h
+++ b/arch/arm64/include/asm/pci.h
@@ -31,6 +31,10 @@ static inline int pci_get_legacy_ide_irq(struct pci_dev *dev, int channel)
return -ENODEV;
}
+#define HAVE_PCI_MMAP
+extern int pci_mmap_page_range(struct pci_dev *dev, struct vm_area_struct *vma,
+ enum pci_mmap_state mmap_state,
+ int write_combine);
static inline int pci_proc_domain(struct pci_bus *bus)
{
return 1;
diff --git a/arch/arm64/include/asm/pgtable-prot.h b/arch/arm64/include/asm/pgtable-prot.h
index 2142c772..cdf8b25d 100644
--- a/arch/arm64/include/asm/pgtable-prot.h
+++ b/arch/arm64/include/asm/pgtable-prot.h
@@ -42,6 +42,7 @@
#define PROT_NORMAL_NC (PROT_DEFAULT | PTE_PXN | PTE_UXN | PTE_DIRTY | PTE_WRITE | PTE_ATTRINDX(MT_NORMAL_NC))
#define PROT_NORMAL_WT (PROT_DEFAULT | PTE_PXN | PTE_UXN | PTE_DIRTY | PTE_WRITE | PTE_ATTRINDX(MT_NORMAL_WT))
#define PROT_NORMAL (PROT_DEFAULT | PTE_PXN | PTE_UXN | PTE_DIRTY | PTE_WRITE | PTE_ATTRINDX(MT_NORMAL))
+#define PROT_NORMAL_NS (PTE_TYPE_PAGE | PTE_AF | PTE_PXN | PTE_UXN | PTE_DIRTY | PTE_WRITE | PTE_ATTRINDX(MT_NORMAL))
#define PROT_SECT_DEVICE_nGnRE (PROT_SECT_DEFAULT | PMD_SECT_PXN | PMD_SECT_UXN | PMD_ATTRINDX(MT_DEVICE_nGnRE))
#define PROT_SECT_NORMAL (PROT_SECT_DEFAULT | PMD_SECT_PXN | PMD_SECT_UXN | PMD_ATTRINDX(MT_NORMAL))
diff --git a/arch/arm64/include/asm/pgtable.h b/arch/arm64/include/asm/pgtable.h
index 61e21401..b8c876fb 100644
--- a/arch/arm64/include/asm/pgtable.h
+++ b/arch/arm64/include/asm/pgtable.h
@@ -356,6 +356,11 @@ static inline int pmd_protnone(pmd_t pmd)
__pgprot_modify(prot, PTE_ATTRINDX_MASK, PTE_ATTRINDX(MT_DEVICE_nGnRnE) | PTE_PXN | PTE_UXN)
#define pgprot_writecombine(prot) \
__pgprot_modify(prot, PTE_ATTRINDX_MASK, PTE_ATTRINDX(MT_NORMAL_NC) | PTE_PXN | PTE_UXN)
+#define pgprot_cached(prot) \
+ __pgprot_modify(prot, PTE_ATTRINDX_MASK, PTE_ATTRINDX(MT_NORMAL) | \
+ PTE_PXN | PTE_UXN)
+#define pgprot_cached_ns(prot) \
+ __pgprot(pgprot_val(pgprot_cached(prot)) ^ PTE_SHARED)
#define pgprot_device(prot) \
__pgprot_modify(prot, PTE_ATTRINDX_MASK, PTE_ATTRINDX(MT_DEVICE_nGnRE) | PTE_PXN | PTE_UXN)
#define __HAVE_PHYS_MEM_ACCESS_PROT
diff --git a/arch/arm64/kernel/pci.c b/arch/arm64/kernel/pci.c
index 409abc45..0568ec3a 100644
--- a/arch/arm64/kernel/pci.c
+++ b/arch/arm64/kernel/pci.c
@@ -17,6 +17,8 @@
#include <linux/mm.h>
#include <linux/of_pci.h>
#include <linux/of_platform.h>
+#include <linux/of_irq.h>
+#include <linux/pcieport_if.h>
#include <linux/pci.h>
#include <linux/pci-acpi.h>
#include <linux/pci-ecam.h>
@@ -54,6 +56,66 @@ int pcibios_alloc_irq(struct pci_dev *dev)
return 0;
}
+/*
+ * Check device tree if the service interrupts are there
+ */
+int pcibios_check_service_irqs(struct pci_dev *dev, int *irqs, int mask)
+{
+ int ret, count = 0;
+ struct device_node *np = NULL;
+
+ if (dev->bus->dev.of_node)
+ np = dev->bus->dev.of_node;
+
+ if (np == NULL)
+ return 0;
+
+ if (!IS_ENABLED(CONFIG_OF_IRQ))
+ return 0;
+
+ /* If root port doesn't support MSI/MSI-X/INTx in RC mode,
+ * request irq for aer
+ */
+ if (mask & PCIE_PORT_SERVICE_AER) {
+ ret = of_irq_get_byname(np, "aer");
+ if (ret > 0) {
+ irqs[PCIE_PORT_SERVICE_AER_SHIFT] = ret;
+ count++;
+ }
+ }
+
+ if (mask & PCIE_PORT_SERVICE_PME) {
+ ret = of_irq_get_byname(np, "pme");
+ if (ret > 0) {
+ irqs[PCIE_PORT_SERVICE_PME_SHIFT] = ret;
+ count++;
+ }
+ }
+
+ /* TODO: add more service interrupts if there it is in the device tree*/
+
+ return count;
+}
+
+int pci_mmap_page_range(struct pci_dev *dev, struct vm_area_struct *vma,
+ enum pci_mmap_state mmap_state, int write_combine)
+{
+ if (mmap_state == pci_mmap_io)
+ return -EINVAL;
+
+ /*
+ * Mark this as IO
+ */
+ vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot);
+
+ if (remap_pfn_range(vma, vma->vm_start, vma->vm_pgoff,
+ vma->vm_end - vma->vm_start,
+ vma->vm_page_prot))
+ return -EAGAIN;
+
+ return 0;
+}
+
/*
* raw_pci_read/write - Platform-specific PCI config space access.
*/
diff --git a/arch/arm64/mm/dma-mapping.c b/arch/arm64/mm/dma-mapping.c
index b5bf46ce..1ef0d6df 100644
--- a/arch/arm64/mm/dma-mapping.c
+++ b/arch/arm64/mm/dma-mapping.c
@@ -30,6 +30,7 @@
#include <linux/swiotlb.h>
#include <asm/cacheflush.h>
+#include <../../../drivers/staging/fsl-mc/include/mc-bus.h>
static int swiotlb __ro_after_init;
@@ -917,6 +918,10 @@ static int __init __iommu_dma_init(void)
#ifdef CONFIG_PCI
if (!ret)
ret = register_iommu_dma_ops_notifier(&pci_bus_type);
+#endif
+#ifdef CONFIG_FSL_MC_BUS
+ if (!ret)
+ ret = register_iommu_dma_ops_notifier(&fsl_mc_bus_type);
#endif
return ret;
}
@@ -971,3 +976,4 @@ void arch_setup_dma_ops(struct device *dev, u64 dma_base, u64 size,
dev->archdata.dma_coherent = coherent;
__iommu_setup_dma_ops(dev, dma_base, size, iommu);
}
+EXPORT_SYMBOL(arch_setup_dma_ops);
--
2.14.1

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,412 @@
From c0e4767d3b26f21e5043fe2d15a24a1958de766e Mon Sep 17 00:00:00 2001
From: Yangbo Lu <yangbo.lu@nxp.com>
Date: Mon, 25 Sep 2017 10:17:28 +0800
Subject: [PATCH] mtd: support layerscape
This is a integrated patch for layerscape ifc-nor-nand support.
Signed-off-by: Alison Wang <b18965@freescale.com>
Signed-off-by: Prabhakar Kushwaha <prabhakar.kushwaha@nxp.com>
Signed-off-by: Yangbo Lu <yangbo.lu@nxp.com>
---
drivers/memory/Kconfig | 2 +-
drivers/memory/fsl_ifc.c | 263 ++++++++++++++++++++++++++++++++++++++++
drivers/mtd/maps/physmap_of.c | 4 +
drivers/mtd/nand/Kconfig | 2 +-
drivers/mtd/nand/fsl_ifc_nand.c | 5 +-
include/linux/fsl_ifc.h | 7 ++
6 files changed, 280 insertions(+), 3 deletions(-)
diff --git a/drivers/memory/Kconfig b/drivers/memory/Kconfig
index 4b4c0c3c..820f5590 100644
--- a/drivers/memory/Kconfig
+++ b/drivers/memory/Kconfig
@@ -115,7 +115,7 @@ config FSL_CORENET_CF
config FSL_IFC
bool
- depends on FSL_SOC || ARCH_LAYERSCAPE
+ depends on FSL_SOC || ARCH_LAYERSCAPE || SOC_LS1021A
config JZ4780_NEMC
bool "Ingenic JZ4780 SoC NEMC driver"
diff --git a/drivers/memory/fsl_ifc.c b/drivers/memory/fsl_ifc.c
index 1b182b11..10d2a5f8 100644
--- a/drivers/memory/fsl_ifc.c
+++ b/drivers/memory/fsl_ifc.c
@@ -24,6 +24,7 @@
#include <linux/compiler.h>
#include <linux/sched.h>
#include <linux/spinlock.h>
+#include <linux/delay.h>
#include <linux/types.h>
#include <linux/slab.h>
#include <linux/io.h>
@@ -37,6 +38,8 @@
struct fsl_ifc_ctrl *fsl_ifc_ctrl_dev;
EXPORT_SYMBOL(fsl_ifc_ctrl_dev);
+#define FSL_IFC_V1_3_0 0x01030000
+#define IFC_TIMEOUT_MSECS 1000 /* 1000ms */
/*
* convert_ifc_address - convert the base address
@@ -311,6 +314,261 @@ static int fsl_ifc_ctrl_probe(struct platform_device *dev)
return ret;
}
+#ifdef CONFIG_PM_SLEEP
+/* save ifc registers */
+static int fsl_ifc_suspend(struct device *dev)
+{
+ struct fsl_ifc_ctrl *ctrl = dev_get_drvdata(dev);
+ struct fsl_ifc_global __iomem *fcm = ctrl->gregs;
+ struct fsl_ifc_runtime __iomem *runtime = ctrl->rregs;
+ __be32 nand_evter_intr_en, cm_evter_intr_en, nor_evter_intr_en,
+ gpcm_evter_intr_en;
+ uint32_t ifc_bank, i;
+
+ ctrl->saved_gregs = kzalloc(sizeof(struct fsl_ifc_global), GFP_KERNEL);
+ if (!ctrl->saved_gregs)
+ return -ENOMEM;
+ ctrl->saved_rregs = kzalloc(sizeof(struct fsl_ifc_runtime), GFP_KERNEL);
+ if (!ctrl->saved_rregs)
+ return -ENOMEM;
+
+ cm_evter_intr_en = ifc_in32(&fcm->cm_evter_intr_en);
+ nand_evter_intr_en = ifc_in32(&runtime->ifc_nand.nand_evter_intr_en);
+ nor_evter_intr_en = ifc_in32(&runtime->ifc_nor.nor_evter_intr_en);
+ gpcm_evter_intr_en = ifc_in32(&runtime->ifc_gpcm.gpcm_evter_intr_en);
+
+/* IFC interrupts disabled */
+
+ ifc_out32(0x0, &fcm->cm_evter_intr_en);
+ ifc_out32(0x0, &runtime->ifc_nand.nand_evter_intr_en);
+ ifc_out32(0x0, &runtime->ifc_nor.nor_evter_intr_en);
+ ifc_out32(0x0, &runtime->ifc_gpcm.gpcm_evter_intr_en);
+
+ if (ctrl->saved_gregs) {
+ for (ifc_bank = 0; ifc_bank < FSL_IFC_BANK_COUNT; ifc_bank++) {
+ ctrl->saved_gregs->cspr_cs[ifc_bank].cspr_ext =
+ ifc_in32(&fcm->cspr_cs[ifc_bank].cspr_ext);
+ ctrl->saved_gregs->cspr_cs[ifc_bank].cspr =
+ ifc_in32(&fcm->cspr_cs[ifc_bank].cspr);
+ ctrl->saved_gregs->amask_cs[ifc_bank].amask =
+ ifc_in32(&fcm->amask_cs[ifc_bank].amask);
+ ctrl->saved_gregs->csor_cs[ifc_bank].csor_ext =
+ ifc_in32(&fcm->csor_cs[ifc_bank].csor_ext);
+ ctrl->saved_gregs->csor_cs[ifc_bank].csor =
+ ifc_in32(&fcm->csor_cs[ifc_bank].csor);
+ for (i = 0; i < 4; i++) {
+ ctrl->saved_gregs->ftim_cs[ifc_bank].ftim[i] =
+ ifc_in32(
+ &fcm->ftim_cs[ifc_bank].ftim[i]);
+ }
+ }
+
+ ctrl->saved_gregs->rb_map = ifc_in32(&fcm->rb_map);
+ ctrl->saved_gregs->wb_map = ifc_in32(&fcm->wb_map);
+ ctrl->saved_gregs->ifc_gcr = ifc_in32(&fcm->ifc_gcr);
+ ctrl->saved_gregs->ddr_ccr_low = ifc_in32(&fcm->ddr_ccr_low);
+ ctrl->saved_gregs->cm_evter_en = ifc_in32(&fcm->cm_evter_en);
+ }
+
+ if (ctrl->saved_rregs) {
+ /* IFC controller NAND machine registers */
+ ctrl->saved_rregs->ifc_nand.ncfgr =
+ ifc_in32(&runtime->ifc_nand.ncfgr);
+ ctrl->saved_rregs->ifc_nand.nand_fcr0 =
+ ifc_in32(&runtime->ifc_nand.nand_fcr0);
+ ctrl->saved_rregs->ifc_nand.nand_fcr1 =
+ ifc_in32(&runtime->ifc_nand.nand_fcr1);
+ ctrl->saved_rregs->ifc_nand.row0 =
+ ifc_in32(&runtime->ifc_nand.row0);
+ ctrl->saved_rregs->ifc_nand.row1 =
+ ifc_in32(&runtime->ifc_nand.row1);
+ ctrl->saved_rregs->ifc_nand.col0 =
+ ifc_in32(&runtime->ifc_nand.col0);
+ ctrl->saved_rregs->ifc_nand.col1 =
+ ifc_in32(&runtime->ifc_nand.col1);
+ ctrl->saved_rregs->ifc_nand.row2 =
+ ifc_in32(&runtime->ifc_nand.row2);
+ ctrl->saved_rregs->ifc_nand.col2 =
+ ifc_in32(&runtime->ifc_nand.col2);
+ ctrl->saved_rregs->ifc_nand.row3 =
+ ifc_in32(&runtime->ifc_nand.row3);
+ ctrl->saved_rregs->ifc_nand.col3 =
+ ifc_in32(&runtime->ifc_nand.col3);
+
+ ctrl->saved_rregs->ifc_nand.nand_fbcr =
+ ifc_in32(&runtime->ifc_nand.nand_fbcr);
+ ctrl->saved_rregs->ifc_nand.nand_fir0 =
+ ifc_in32(&runtime->ifc_nand.nand_fir0);
+ ctrl->saved_rregs->ifc_nand.nand_fir1 =
+ ifc_in32(&runtime->ifc_nand.nand_fir1);
+ ctrl->saved_rregs->ifc_nand.nand_fir2 =
+ ifc_in32(&runtime->ifc_nand.nand_fir2);
+ ctrl->saved_rregs->ifc_nand.nand_csel =
+ ifc_in32(&runtime->ifc_nand.nand_csel);
+ ctrl->saved_rregs->ifc_nand.nandseq_strt =
+ ifc_in32(
+ &runtime->ifc_nand.nandseq_strt);
+ ctrl->saved_rregs->ifc_nand.nand_evter_en =
+ ifc_in32(
+ &runtime->ifc_nand.nand_evter_en);
+ ctrl->saved_rregs->ifc_nand.nanndcr =
+ ifc_in32(&runtime->ifc_nand.nanndcr);
+ ctrl->saved_rregs->ifc_nand.nand_dll_lowcfg0 =
+ ifc_in32(
+ &runtime->ifc_nand.nand_dll_lowcfg0);
+ ctrl->saved_rregs->ifc_nand.nand_dll_lowcfg1 =
+ ifc_in32(
+ &runtime->ifc_nand.nand_dll_lowcfg1);
+
+ /* IFC controller NOR machine registers */
+ ctrl->saved_rregs->ifc_nor.nor_evter_en =
+ ifc_in32(
+ &runtime->ifc_nor.nor_evter_en);
+ ctrl->saved_rregs->ifc_nor.norcr =
+ ifc_in32(&runtime->ifc_nor.norcr);
+
+ /* IFC controller GPCM Machine registers */
+ ctrl->saved_rregs->ifc_gpcm.gpcm_evter_en =
+ ifc_in32(
+ &runtime->ifc_gpcm.gpcm_evter_en);
+ }
+
+/* save the interrupt values */
+ ctrl->saved_gregs->cm_evter_intr_en = cm_evter_intr_en;
+ ctrl->saved_rregs->ifc_nand.nand_evter_intr_en = nand_evter_intr_en;
+ ctrl->saved_rregs->ifc_nor.nor_evter_intr_en = nor_evter_intr_en;
+ ctrl->saved_rregs->ifc_gpcm.gpcm_evter_intr_en = gpcm_evter_intr_en;
+
+ return 0;
+}
+
+/* restore ifc registers */
+static int fsl_ifc_resume(struct device *dev)
+{
+ struct fsl_ifc_ctrl *ctrl = dev_get_drvdata(dev);
+ struct fsl_ifc_global __iomem *fcm = ctrl->gregs;
+ struct fsl_ifc_runtime __iomem *runtime = ctrl->rregs;
+ struct fsl_ifc_global *savd_gregs = ctrl->saved_gregs;
+ struct fsl_ifc_runtime *savd_rregs = ctrl->saved_rregs;
+ uint32_t ver = 0, ncfgr, timeout, ifc_bank, i;
+
+/*
+ * IFC interrupts disabled
+ */
+ ifc_out32(0x0, &fcm->cm_evter_intr_en);
+ ifc_out32(0x0, &runtime->ifc_nand.nand_evter_intr_en);
+ ifc_out32(0x0, &runtime->ifc_nor.nor_evter_intr_en);
+ ifc_out32(0x0, &runtime->ifc_gpcm.gpcm_evter_intr_en);
+
+
+ if (ctrl->saved_gregs) {
+ for (ifc_bank = 0; ifc_bank < FSL_IFC_BANK_COUNT; ifc_bank++) {
+ ifc_out32(savd_gregs->cspr_cs[ifc_bank].cspr_ext,
+ &fcm->cspr_cs[ifc_bank].cspr_ext);
+ ifc_out32(savd_gregs->cspr_cs[ifc_bank].cspr,
+ &fcm->cspr_cs[ifc_bank].cspr);
+ ifc_out32(savd_gregs->amask_cs[ifc_bank].amask,
+ &fcm->amask_cs[ifc_bank].amask);
+ ifc_out32(savd_gregs->csor_cs[ifc_bank].csor_ext,
+ &fcm->csor_cs[ifc_bank].csor_ext);
+ ifc_out32(savd_gregs->csor_cs[ifc_bank].csor,
+ &fcm->csor_cs[ifc_bank].csor);
+ for (i = 0; i < 4; i++) {
+ ifc_out32(savd_gregs->ftim_cs[ifc_bank].ftim[i],
+ &fcm->ftim_cs[ifc_bank].ftim[i]);
+ }
+ }
+ ifc_out32(savd_gregs->rb_map, &fcm->rb_map);
+ ifc_out32(savd_gregs->wb_map, &fcm->wb_map);
+ ifc_out32(savd_gregs->ifc_gcr, &fcm->ifc_gcr);
+ ifc_out32(savd_gregs->ddr_ccr_low, &fcm->ddr_ccr_low);
+ ifc_out32(savd_gregs->cm_evter_en, &fcm->cm_evter_en);
+ }
+
+ if (ctrl->saved_rregs) {
+ /* IFC controller NAND machine registers */
+ ifc_out32(savd_rregs->ifc_nand.ncfgr,
+ &runtime->ifc_nand.ncfgr);
+ ifc_out32(savd_rregs->ifc_nand.nand_fcr0,
+ &runtime->ifc_nand.nand_fcr0);
+ ifc_out32(savd_rregs->ifc_nand.nand_fcr1,
+ &runtime->ifc_nand.nand_fcr1);
+ ifc_out32(savd_rregs->ifc_nand.row0, &runtime->ifc_nand.row0);
+ ifc_out32(savd_rregs->ifc_nand.row1, &runtime->ifc_nand.row1);
+ ifc_out32(savd_rregs->ifc_nand.col0, &runtime->ifc_nand.col0);
+ ifc_out32(savd_rregs->ifc_nand.col1, &runtime->ifc_nand.col1);
+ ifc_out32(savd_rregs->ifc_nand.row2, &runtime->ifc_nand.row2);
+ ifc_out32(savd_rregs->ifc_nand.col2, &runtime->ifc_nand.col2);
+ ifc_out32(savd_rregs->ifc_nand.row3, &runtime->ifc_nand.row3);
+ ifc_out32(savd_rregs->ifc_nand.col3, &runtime->ifc_nand.col3);
+ ifc_out32(savd_rregs->ifc_nand.nand_fbcr,
+ &runtime->ifc_nand.nand_fbcr);
+ ifc_out32(savd_rregs->ifc_nand.nand_fir0,
+ &runtime->ifc_nand.nand_fir0);
+ ifc_out32(savd_rregs->ifc_nand.nand_fir1,
+ &runtime->ifc_nand.nand_fir1);
+ ifc_out32(savd_rregs->ifc_nand.nand_fir2,
+ &runtime->ifc_nand.nand_fir2);
+ ifc_out32(savd_rregs->ifc_nand.nand_csel,
+ &runtime->ifc_nand.nand_csel);
+ ifc_out32(savd_rregs->ifc_nand.nandseq_strt,
+ &runtime->ifc_nand.nandseq_strt);
+ ifc_out32(savd_rregs->ifc_nand.nand_evter_en,
+ &runtime->ifc_nand.nand_evter_en);
+ ifc_out32(savd_rregs->ifc_nand.nanndcr,
+ &runtime->ifc_nand.nanndcr);
+ ifc_out32(savd_rregs->ifc_nand.nand_dll_lowcfg0,
+ &runtime->ifc_nand.nand_dll_lowcfg0);
+ ifc_out32(savd_rregs->ifc_nand.nand_dll_lowcfg1,
+ &runtime->ifc_nand.nand_dll_lowcfg1);
+
+ /* IFC controller NOR machine registers */
+ ifc_out32(savd_rregs->ifc_nor.nor_evter_en,
+ &runtime->ifc_nor.nor_evter_en);
+ ifc_out32(savd_rregs->ifc_nor.norcr, &runtime->ifc_nor.norcr);
+
+ /* IFC controller GPCM Machine registers */
+ ifc_out32(savd_rregs->ifc_gpcm.gpcm_evter_en,
+ &runtime->ifc_gpcm.gpcm_evter_en);
+
+ /* IFC interrupts enabled */
+ ifc_out32(ctrl->saved_gregs->cm_evter_intr_en,
+ &fcm->cm_evter_intr_en);
+ ifc_out32(ctrl->saved_rregs->ifc_nand.nand_evter_intr_en,
+ &runtime->ifc_nand.nand_evter_intr_en);
+ ifc_out32(ctrl->saved_rregs->ifc_nor.nor_evter_intr_en,
+ &runtime->ifc_nor.nor_evter_intr_en);
+ ifc_out32(ctrl->saved_rregs->ifc_gpcm.gpcm_evter_intr_en,
+ &runtime->ifc_gpcm.gpcm_evter_intr_en);
+
+ kfree(ctrl->saved_gregs);
+ kfree(ctrl->saved_rregs);
+ ctrl->saved_gregs = NULL;
+ ctrl->saved_rregs = NULL;
+ }
+
+ ver = ifc_in32(&fcm->ifc_rev);
+ ncfgr = ifc_in32(&runtime->ifc_nand.ncfgr);
+ if (ver >= FSL_IFC_V1_3_0) {
+
+ ifc_out32(ncfgr | IFC_NAND_SRAM_INIT_EN,
+ &runtime->ifc_nand.ncfgr);
+ /* wait for SRAM_INIT bit to be clear or timeout */
+ timeout = 10;
+ while ((ifc_in32(&runtime->ifc_nand.ncfgr) &
+ IFC_NAND_SRAM_INIT_EN) && timeout) {
+ mdelay(IFC_TIMEOUT_MSECS);
+ timeout--;
+ }
+
+ if (!timeout)
+ dev_err(ctrl->dev, "Timeout waiting for IFC SRAM INIT");
+ }
+
+ return 0;
+}
+#endif /* CONFIG_PM_SLEEP */
+
static const struct of_device_id fsl_ifc_match[] = {
{
.compatible = "fsl,ifc",
@@ -318,10 +576,15 @@ static const struct of_device_id fsl_ifc_match[] = {
{},
};
+static const struct dev_pm_ops ifc_pm_ops = {
+ SET_SYSTEM_SLEEP_PM_OPS(fsl_ifc_suspend, fsl_ifc_resume)
+};
+
static struct platform_driver fsl_ifc_ctrl_driver = {
.driver = {
.name = "fsl-ifc",
.of_match_table = fsl_ifc_match,
+ .pm = &ifc_pm_ops,
},
.probe = fsl_ifc_ctrl_probe,
.remove = fsl_ifc_ctrl_remove,
diff --git a/drivers/mtd/maps/physmap_of.c b/drivers/mtd/maps/physmap_of.c
index 11d63046..38b90301 100644
--- a/drivers/mtd/maps/physmap_of.c
+++ b/drivers/mtd/maps/physmap_of.c
@@ -20,6 +20,7 @@
#include <linux/mtd/map.h>
#include <linux/mtd/partitions.h>
#include <linux/mtd/concat.h>
+#include <linux/mtd/cfi_endian.h>
#include <linux/of.h>
#include <linux/of_address.h>
#include <linux/of_platform.h>
@@ -209,6 +210,9 @@ static int of_flash_probe(struct platform_device *dev)
return err;
}
+ if (of_property_read_bool(dp->parent, "big-endian"))
+ info->list[i].map.swap = CFI_BIG_ENDIAN;
+
err = -ENOMEM;
info->list[i].map.virt = ioremap(info->list[i].map.phys,
info->list[i].map.size);
diff --git a/drivers/mtd/nand/Kconfig b/drivers/mtd/nand/Kconfig
index b254090b..961f1aa1 100644
--- a/drivers/mtd/nand/Kconfig
+++ b/drivers/mtd/nand/Kconfig
@@ -438,7 +438,7 @@ config MTD_NAND_FSL_ELBC
config MTD_NAND_FSL_IFC
tristate "NAND support for Freescale IFC controller"
- depends on FSL_SOC || ARCH_LAYERSCAPE
+ depends on FSL_SOC || ARCH_LAYERSCAPE || SOC_LS1021A
select FSL_IFC
select MEMORY
help
diff --git a/drivers/mtd/nand/fsl_ifc_nand.c b/drivers/mtd/nand/fsl_ifc_nand.c
index d1570f51..785e9ee0 100644
--- a/drivers/mtd/nand/fsl_ifc_nand.c
+++ b/drivers/mtd/nand/fsl_ifc_nand.c
@@ -904,9 +904,12 @@ static int fsl_ifc_chip_init(struct fsl_ifc_mtd *priv)
chip->ecc.algo = NAND_ECC_HAMMING;
}
- if (ctrl->version == FSL_IFC_VERSION_1_1_0)
+ if (ctrl->version >= FSL_IFC_VERSION_1_1_0)
fsl_ifc_sram_init(priv);
+ if (ctrl->version >= FSL_IFC_VERSION_2_0_0)
+ priv->bufnum_mask = (priv->bufnum_mask * 2) + 1;
+
return 0;
}
diff --git a/include/linux/fsl_ifc.h b/include/linux/fsl_ifc.h
index c332f0a4..a41d21b6 100644
--- a/include/linux/fsl_ifc.h
+++ b/include/linux/fsl_ifc.h
@@ -274,6 +274,8 @@
*/
/* Auto Boot Mode */
#define IFC_NAND_NCFGR_BOOT 0x80000000
+/* SRAM INIT EN */
+#define IFC_NAND_SRAM_INIT_EN 0x20000000
/* Addressing Mode-ROW0+n/COL0 */
#define IFC_NAND_NCFGR_ADDR_MODE_RC0 0x00000000
/* Addressing Mode-ROW0+n/COL0+n */
@@ -861,6 +863,11 @@ struct fsl_ifc_ctrl {
u32 nand_stat;
wait_queue_head_t nand_wait;
bool little_endian;
+#ifdef CONFIG_PM_SLEEP
+ /*save regs when system goes to deep sleep*/
+ struct fsl_ifc_global *saved_gregs;
+ struct fsl_ifc_runtime *saved_rregs;
+#endif
};
extern struct fsl_ifc_ctrl *fsl_ifc_ctrl_dev;
--
2.14.1

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,149 @@
From 505eb62bdb7a4cc25b13491dd5c68d0741c5d6da Mon Sep 17 00:00:00 2001
From: Yangbo Lu <yangbo.lu@nxp.com>
Date: Mon, 25 Sep 2017 12:21:13 +0800
Subject: [PATCH] ata: support layerscape
This is a integrated patch for layerscape sata support.
Signed-off-by: Tang Yuantian <Yuantian.Tang@nxp.com>
Signed-off-by: Yangbo Lu <yangbo.lu@nxp.com>
---
drivers/ata/ahci_qoriq.c | 63 ++++++++++++++++++++++++++++++++++++++++++------
1 file changed, 56 insertions(+), 7 deletions(-)
diff --git a/drivers/ata/ahci_qoriq.c b/drivers/ata/ahci_qoriq.c
index 1eba8dff..2f30a39f 100644
--- a/drivers/ata/ahci_qoriq.c
+++ b/drivers/ata/ahci_qoriq.c
@@ -1,7 +1,7 @@
/*
* Freescale QorIQ AHCI SATA platform driver
*
- * Copyright 2015 Freescale, Inc.
+ * Copyright (C) 2015 Freescale Semiconductor, Inc.
* Tang Yuantian <Yuantian.Tang@freescale.com>
*
* This program is free software; you can redistribute it and/or modify
@@ -46,23 +46,32 @@
#define LS1021A_AXICC_ADDR 0xC0
#define SATA_ECC_DISABLE 0x00020000
+#define ECC_DIS_ARMV8_CH2 0x80000000
+#define ECC_DIS_LS1088A 0x40000000
enum ahci_qoriq_type {
AHCI_LS1021A,
AHCI_LS1043A,
AHCI_LS2080A,
+ AHCI_LS1046A,
+ AHCI_LS1088A,
+ AHCI_LS2088A,
};
struct ahci_qoriq_priv {
struct ccsr_ahci *reg_base;
enum ahci_qoriq_type type;
void __iomem *ecc_addr;
+ bool is_dmacoherent;
};
static const struct of_device_id ahci_qoriq_of_match[] = {
{ .compatible = "fsl,ls1021a-ahci", .data = (void *)AHCI_LS1021A},
{ .compatible = "fsl,ls1043a-ahci", .data = (void *)AHCI_LS1043A},
{ .compatible = "fsl,ls2080a-ahci", .data = (void *)AHCI_LS2080A},
+ { .compatible = "fsl,ls1046a-ahci", .data = (void *)AHCI_LS1046A},
+ { .compatible = "fsl,ls1088a-ahci", .data = (void *)AHCI_LS1088A},
+ { .compatible = "fsl,ls2088a-ahci", .data = (void *)AHCI_LS2088A},
{},
};
MODULE_DEVICE_TABLE(of, ahci_qoriq_of_match);
@@ -154,6 +163,8 @@ static int ahci_qoriq_phy_init(struct ahci_host_priv *hpriv)
switch (qpriv->type) {
case AHCI_LS1021A:
+ if (!qpriv->ecc_addr)
+ return -EINVAL;
writel(SATA_ECC_DISABLE, qpriv->ecc_addr);
writel(AHCI_PORT_PHY_1_CFG, reg_base + PORT_PHY1);
writel(LS1021A_PORT_PHY2, reg_base + PORT_PHY2);
@@ -161,19 +172,56 @@ static int ahci_qoriq_phy_init(struct ahci_host_priv *hpriv)
writel(LS1021A_PORT_PHY4, reg_base + PORT_PHY4);
writel(LS1021A_PORT_PHY5, reg_base + PORT_PHY5);
writel(AHCI_PORT_TRANS_CFG, reg_base + PORT_TRANS);
- writel(AHCI_PORT_AXICC_CFG, reg_base + LS1021A_AXICC_ADDR);
+ if (qpriv->is_dmacoherent)
+ writel(AHCI_PORT_AXICC_CFG,
+ reg_base + LS1021A_AXICC_ADDR);
break;
case AHCI_LS1043A:
+ if (!qpriv->ecc_addr)
+ return -EINVAL;
+ writel(readl(qpriv->ecc_addr) | ECC_DIS_ARMV8_CH2,
+ qpriv->ecc_addr);
writel(AHCI_PORT_PHY_1_CFG, reg_base + PORT_PHY1);
writel(AHCI_PORT_TRANS_CFG, reg_base + PORT_TRANS);
- writel(AHCI_PORT_AXICC_CFG, reg_base + PORT_AXICC);
+ if (qpriv->is_dmacoherent)
+ writel(AHCI_PORT_AXICC_CFG, reg_base + PORT_AXICC);
break;
case AHCI_LS2080A:
writel(AHCI_PORT_PHY_1_CFG, reg_base + PORT_PHY1);
writel(AHCI_PORT_TRANS_CFG, reg_base + PORT_TRANS);
- writel(AHCI_PORT_AXICC_CFG, reg_base + PORT_AXICC);
+ if (qpriv->is_dmacoherent)
+ writel(AHCI_PORT_AXICC_CFG, reg_base + PORT_AXICC);
+ break;
+
+ case AHCI_LS1046A:
+ if (!qpriv->ecc_addr)
+ return -EINVAL;
+ writel(readl(qpriv->ecc_addr) | ECC_DIS_ARMV8_CH2,
+ qpriv->ecc_addr);
+ writel(AHCI_PORT_PHY_1_CFG, reg_base + PORT_PHY1);
+ writel(AHCI_PORT_TRANS_CFG, reg_base + PORT_TRANS);
+ if (qpriv->is_dmacoherent)
+ writel(AHCI_PORT_AXICC_CFG, reg_base + PORT_AXICC);
+ break;
+
+ case AHCI_LS1088A:
+ if (!qpriv->ecc_addr)
+ return -EINVAL;
+ writel(readl(qpriv->ecc_addr) | ECC_DIS_LS1088A,
+ qpriv->ecc_addr);
+ writel(AHCI_PORT_PHY_1_CFG, reg_base + PORT_PHY1);
+ writel(AHCI_PORT_TRANS_CFG, reg_base + PORT_TRANS);
+ if (qpriv->is_dmacoherent)
+ writel(AHCI_PORT_AXICC_CFG, reg_base + PORT_AXICC);
+ break;
+
+ case AHCI_LS2088A:
+ writel(AHCI_PORT_PHY_1_CFG, reg_base + PORT_PHY1);
+ writel(AHCI_PORT_TRANS_CFG, reg_base + PORT_TRANS);
+ if (qpriv->is_dmacoherent)
+ writel(AHCI_PORT_AXICC_CFG, reg_base + PORT_AXICC);
break;
}
@@ -204,13 +252,14 @@ static int ahci_qoriq_probe(struct platform_device *pdev)
qoriq_priv->type = (enum ahci_qoriq_type)of_id->data;
- if (qoriq_priv->type == AHCI_LS1021A) {
- res = platform_get_resource_byname(pdev, IORESOURCE_MEM,
- "sata-ecc");
+ res = platform_get_resource_byname(pdev, IORESOURCE_MEM,
+ "sata-ecc");
+ if (res) {
qoriq_priv->ecc_addr = devm_ioremap_resource(dev, res);
if (IS_ERR(qoriq_priv->ecc_addr))
return PTR_ERR(qoriq_priv->ecc_addr);
}
+ qoriq_priv->is_dmacoherent = of_dma_is_coherent(np);
rc = ahci_platform_enable_resources(hpriv);
if (rc)
--
2.14.1

View file

@ -0,0 +1,312 @@
From bd3df6d053a28d5aa630524c9087c21def30e764 Mon Sep 17 00:00:00 2001
From: Yangbo Lu <yangbo.lu@nxp.com>
Date: Mon, 25 Sep 2017 12:09:35 +0800
Subject: [PATCH] clk: support layerscape
This is a integrated patch for layerscape clock support.
Signed-off-by: Yuantian Tang <andy.tang@nxp.com>
Signed-off-by: Mingkai Hu <mingkai.hu@nxp.com>
Signed-off-by: Scott Wood <oss@buserror.net>
Signed-off-by: Yangbo Lu <yangbo.lu@nxp.com>
---
drivers/clk/clk-qoriq.c | 170 ++++++++++++++++++++++++++++++++++++++++++++----
1 file changed, 156 insertions(+), 14 deletions(-)
diff --git a/drivers/clk/clk-qoriq.c b/drivers/clk/clk-qoriq.c
index 80ae2a51..0e7de00a 100644
--- a/drivers/clk/clk-qoriq.c
+++ b/drivers/clk/clk-qoriq.c
@@ -12,6 +12,7 @@
#include <linux/clk.h>
#include <linux/clk-provider.h>
+#include <linux/clkdev.h>
#include <linux/fsl/guts.h>
#include <linux/io.h>
#include <linux/kernel.h>
@@ -87,7 +88,7 @@ struct clockgen {
struct device_node *node;
void __iomem *regs;
struct clockgen_chipinfo info; /* mutable copy */
- struct clk *sysclk;
+ struct clk *sysclk, *coreclk;
struct clockgen_pll pll[6];
struct clk *cmux[NUM_CMUX];
struct clk *hwaccel[NUM_HWACCEL];
@@ -266,6 +267,39 @@ static const struct clockgen_muxinfo ls1043a_hwa2 = {
},
};
+static const struct clockgen_muxinfo ls1046a_hwa1 = {
+ {
+ {},
+ {},
+ { CLKSEL_VALID, CGA_PLL1, PLL_DIV2 },
+ { CLKSEL_VALID, CGA_PLL1, PLL_DIV3 },
+ { CLKSEL_VALID, CGA_PLL1, PLL_DIV4 },
+ { CLKSEL_VALID, PLATFORM_PLL, PLL_DIV1 },
+ { CLKSEL_VALID, CGA_PLL2, PLL_DIV2 },
+ { CLKSEL_VALID, CGA_PLL2, PLL_DIV3 },
+ },
+};
+
+static const struct clockgen_muxinfo ls1046a_hwa2 = {
+ {
+ {},
+ { CLKSEL_VALID, CGA_PLL2, PLL_DIV1 },
+ { CLKSEL_VALID, CGA_PLL2, PLL_DIV2 },
+ { CLKSEL_VALID, CGA_PLL2, PLL_DIV3 },
+ {},
+ {},
+ { CLKSEL_VALID, CGA_PLL1, PLL_DIV2 },
+ },
+};
+
+static const struct clockgen_muxinfo ls1012a_cmux = {
+ {
+ [0] = { CLKSEL_VALID, CGA_PLL1, PLL_DIV1 },
+ {},
+ [2] = { CLKSEL_VALID, CGA_PLL1, PLL_DIV2 },
+ }
+};
+
static const struct clockgen_muxinfo t1023_hwa1 = {
{
{},
@@ -488,6 +522,42 @@ static const struct clockgen_chipinfo chipinfo[] = {
.pll_mask = 0x07,
.flags = CG_PLL_8BIT,
},
+ {
+ .compat = "fsl,ls1046a-clockgen",
+ .init_periph = t2080_init_periph,
+ .cmux_groups = {
+ &t1040_cmux
+ },
+ .hwaccel = {
+ &ls1046a_hwa1, &ls1046a_hwa2
+ },
+ .cmux_to_group = {
+ 0, -1
+ },
+ .pll_mask = 0x07,
+ .flags = CG_PLL_8BIT,
+ },
+ {
+ .compat = "fsl,ls1088a-clockgen",
+ .cmux_groups = {
+ &clockgen2_cmux_cga12
+ },
+ .cmux_to_group = {
+ 0, 0, -1
+ },
+ .pll_mask = 0x07,
+ .flags = CG_VER3 | CG_LITTLE_ENDIAN,
+ },
+ {
+ .compat = "fsl,ls1012a-clockgen",
+ .cmux_groups = {
+ &ls1012a_cmux
+ },
+ .cmux_to_group = {
+ 0, -1
+ },
+ .pll_mask = 0x03,
+ },
{
.compat = "fsl,ls2080a-clockgen",
.cmux_groups = {
@@ -846,7 +916,12 @@ static void __init create_muxes(struct clockgen *cg)
static void __init clockgen_init(struct device_node *np);
-/* Legacy nodes may get probed before the parent clockgen node */
+/*
+ * Legacy nodes may get probed before the parent clockgen node.
+ * It is assumed that device trees with legacy nodes will not
+ * contain a "clocks" property -- otherwise the input clocks may
+ * not be initialized at this point.
+ */
static void __init legacy_init_clockgen(struct device_node *np)
{
if (!clockgen.node)
@@ -887,18 +962,13 @@ static struct clk __init
return clk_register_fixed_rate(NULL, name, NULL, 0, rate);
}
-static struct clk *sysclk_from_parent(const char *name)
+static struct clk __init *input_clock(const char *name, struct clk *clk)
{
- struct clk *clk;
- const char *parent_name;
-
- clk = of_clk_get(clockgen.node, 0);
- if (IS_ERR(clk))
- return clk;
+ const char *input_name;
/* Register the input clock under the desired name. */
- parent_name = __clk_get_name(clk);
- clk = clk_register_fixed_factor(NULL, name, parent_name,
+ input_name = __clk_get_name(clk);
+ clk = clk_register_fixed_factor(NULL, name, input_name,
0, 1, 1);
if (IS_ERR(clk))
pr_err("%s: Couldn't register %s: %ld\n", __func__, name,
@@ -907,6 +977,29 @@ static struct clk *sysclk_from_parent(const char *name)
return clk;
}
+static struct clk __init *input_clock_by_name(const char *name,
+ const char *dtname)
+{
+ struct clk *clk;
+
+ clk = of_clk_get_by_name(clockgen.node, dtname);
+ if (IS_ERR(clk))
+ return clk;
+
+ return input_clock(name, clk);
+}
+
+static struct clk __init *input_clock_by_index(const char *name, int idx)
+{
+ struct clk *clk;
+
+ clk = of_clk_get(clockgen.node, 0);
+ if (IS_ERR(clk))
+ return clk;
+
+ return input_clock(name, clk);
+}
+
static struct clk * __init create_sysclk(const char *name)
{
struct device_node *sysclk;
@@ -916,7 +1009,11 @@ static struct clk * __init create_sysclk(const char *name)
if (!IS_ERR(clk))
return clk;
- clk = sysclk_from_parent(name);
+ clk = input_clock_by_name(name, "sysclk");
+ if (!IS_ERR(clk))
+ return clk;
+
+ clk = input_clock_by_index(name, 0);
if (!IS_ERR(clk))
return clk;
@@ -927,7 +1024,27 @@ static struct clk * __init create_sysclk(const char *name)
return clk;
}
- pr_err("%s: No input clock\n", __func__);
+ pr_err("%s: No input sysclk\n", __func__);
+ return NULL;
+}
+
+static struct clk * __init create_coreclk(const char *name)
+{
+ struct clk *clk;
+
+ clk = input_clock_by_name(name, "coreclk");
+ if (!IS_ERR(clk))
+ return clk;
+
+ /*
+ * This indicates a mix of legacy nodes with the new coreclk
+ * mechanism, which should never happen. If this error occurs,
+ * don't use the wrong input clock just because coreclk isn't
+ * ready yet.
+ */
+ if (WARN_ON(PTR_ERR(clk) == -EPROBE_DEFER))
+ return clk;
+
return NULL;
}
@@ -950,11 +1067,19 @@ static void __init create_one_pll(struct clockgen *cg, int idx)
u32 __iomem *reg;
u32 mult;
struct clockgen_pll *pll = &cg->pll[idx];
+ const char *input = "cg-sysclk";
int i;
if (!(cg->info.pll_mask & (1 << idx)))
return;
+ if (cg->coreclk && idx != PLATFORM_PLL) {
+ if (IS_ERR(cg->coreclk))
+ return;
+
+ input = "cg-coreclk";
+ }
+
if (cg->info.flags & CG_VER3) {
switch (idx) {
case PLATFORM_PLL:
@@ -1000,12 +1125,13 @@ static void __init create_one_pll(struct clockgen *cg, int idx)
for (i = 0; i < ARRAY_SIZE(pll->div); i++) {
struct clk *clk;
+ int ret;
snprintf(pll->div[i].name, sizeof(pll->div[i].name),
"cg-pll%d-div%d", idx, i + 1);
clk = clk_register_fixed_factor(NULL,
- pll->div[i].name, "cg-sysclk", 0, mult, i + 1);
+ pll->div[i].name, input, 0, mult, i + 1);
if (IS_ERR(clk)) {
pr_err("%s: %s: register failed %ld\n",
__func__, pll->div[i].name, PTR_ERR(clk));
@@ -1013,6 +1139,11 @@ static void __init create_one_pll(struct clockgen *cg, int idx)
}
pll->div[i].clk = clk;
+ ret = clk_register_clkdev(clk, pll->div[i].name, NULL);
+ if (ret != 0)
+ pr_err("%s: %s: register to lookup table failed %ld\n",
+ __func__, pll->div[i].name, PTR_ERR(clk));
+
}
}
@@ -1142,6 +1273,13 @@ static struct clk *clockgen_clk_get(struct of_phandle_args *clkspec, void *data)
goto bad_args;
clk = pll->div[idx].clk;
break;
+ case 5:
+ if (idx != 0)
+ goto bad_args;
+ clk = cg->coreclk;
+ if (IS_ERR(clk))
+ clk = NULL;
+ break;
default:
goto bad_args;
}
@@ -1253,6 +1391,7 @@ static void __init clockgen_init(struct device_node *np)
clockgen.info.flags |= CG_CMUX_GE_PLAT;
clockgen.sysclk = create_sysclk("cg-sysclk");
+ clockgen.coreclk = create_coreclk("cg-coreclk");
create_plls(&clockgen);
create_muxes(&clockgen);
@@ -1273,8 +1412,11 @@ static void __init clockgen_init(struct device_node *np)
CLK_OF_DECLARE(qoriq_clockgen_1, "fsl,qoriq-clockgen-1.0", clockgen_init);
CLK_OF_DECLARE(qoriq_clockgen_2, "fsl,qoriq-clockgen-2.0", clockgen_init);
+CLK_OF_DECLARE(qoriq_clockgen_ls1012a, "fsl,ls1012a-clockgen", clockgen_init);
CLK_OF_DECLARE(qoriq_clockgen_ls1021a, "fsl,ls1021a-clockgen", clockgen_init);
CLK_OF_DECLARE(qoriq_clockgen_ls1043a, "fsl,ls1043a-clockgen", clockgen_init);
+CLK_OF_DECLARE(qoriq_clockgen_ls1046a, "fsl,ls1046a-clockgen", clockgen_init);
+CLK_OF_DECLARE(qoriq_clockgen_ls1088a, "fsl,ls1088a-clockgen", clockgen_init);
CLK_OF_DECLARE(qoriq_clockgen_ls2080a, "fsl,ls2080a-clockgen", clockgen_init);
/* Legacy nodes */
--
2.14.1

View file

@ -0,0 +1,370 @@
From a9ebdf9fa18fd317a4e97f46e8c5263898094864 Mon Sep 17 00:00:00 2001
From: Yangbo Lu <yangbo.lu@nxp.com>
Date: Mon, 25 Sep 2017 12:20:10 +0800
Subject: [PATCH] cpufreq: support layerscape
This is a integrated patch for layerscape pm support.
Signed-off-by: Tang Yuantian <Yuantian.Tang@nxp.com>
Signed-off-by: Yangbo Lu <yangbo.lu@nxp.com>
---
drivers/cpufreq/Kconfig | 2 +-
drivers/cpufreq/qoriq-cpufreq.c | 176 +++++++++++++++-------------------------
drivers/firmware/psci.c | 12 ++-
3 files changed, 77 insertions(+), 113 deletions(-)
diff --git a/drivers/cpufreq/Kconfig b/drivers/cpufreq/Kconfig
index d8b164a7..bc9264c7 100644
--- a/drivers/cpufreq/Kconfig
+++ b/drivers/cpufreq/Kconfig
@@ -332,7 +332,7 @@ endif
config QORIQ_CPUFREQ
tristate "CPU frequency scaling driver for Freescale QorIQ SoCs"
- depends on OF && COMMON_CLK && (PPC_E500MC || ARM)
+ depends on OF && COMMON_CLK && (PPC_E500MC || ARM || ARM64)
depends on !CPU_THERMAL || THERMAL
select CLK_QORIQ
help
diff --git a/drivers/cpufreq/qoriq-cpufreq.c b/drivers/cpufreq/qoriq-cpufreq.c
index 53d8c3fb..e2ea433a 100644
--- a/drivers/cpufreq/qoriq-cpufreq.c
+++ b/drivers/cpufreq/qoriq-cpufreq.c
@@ -11,6 +11,7 @@
#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
#include <linux/clk.h>
+#include <linux/clk-provider.h>
#include <linux/cpufreq.h>
#include <linux/cpu_cooling.h>
#include <linux/errno.h>
@@ -22,10 +23,6 @@
#include <linux/slab.h>
#include <linux/smp.h>
-#if !defined(CONFIG_ARM)
-#include <asm/smp.h> /* for get_hard_smp_processor_id() in UP configs */
-#endif
-
/**
* struct cpu_data
* @pclk: the parent clock of cpu
@@ -37,73 +34,51 @@ struct cpu_data {
struct thermal_cooling_device *cdev;
};
+/*
+ * Don't use cpufreq on this SoC -- used when the SoC would have otherwise
+ * matched a more generic compatible.
+ */
+#define SOC_BLACKLIST 1
+
/**
* struct soc_data - SoC specific data
- * @freq_mask: mask the disallowed frequencies
- * @flag: unique flags
+ * @flags: SOC_xxx
*/
struct soc_data {
- u32 freq_mask[4];
- u32 flag;
-};
-
-#define FREQ_MASK 1
-/* see hardware specification for the allowed frqeuencies */
-static const struct soc_data sdata[] = {
- { /* used by p2041 and p3041 */
- .freq_mask = {0x8, 0x8, 0x2, 0x2},
- .flag = FREQ_MASK,
- },
- { /* used by p5020 */
- .freq_mask = {0x8, 0x2},
- .flag = FREQ_MASK,
- },
- { /* used by p4080, p5040 */
- .freq_mask = {0},
- .flag = 0,
- },
+ u32 flags;
};
-/*
- * the minimum allowed core frequency, in Hz
- * for chassis v1.0, >= platform frequency
- * for chassis v2.0, >= platform frequency / 2
- */
-static u32 min_cpufreq;
-static const u32 *fmask;
-
-#if defined(CONFIG_ARM)
-static int get_cpu_physical_id(int cpu)
-{
- return topology_core_id(cpu);
-}
-#else
-static int get_cpu_physical_id(int cpu)
-{
- return get_hard_smp_processor_id(cpu);
-}
-#endif
-
static u32 get_bus_freq(void)
{
struct device_node *soc;
u32 sysfreq;
+ struct clk *pltclk;
+ int ret;
+ /* get platform freq by searching bus-frequency property */
soc = of_find_node_by_type(NULL, "soc");
- if (!soc)
- return 0;
-
- if (of_property_read_u32(soc, "bus-frequency", &sysfreq))
- sysfreq = 0;
+ if (soc) {
+ ret = of_property_read_u32(soc, "bus-frequency", &sysfreq);
+ of_node_put(soc);
+ if (!ret)
+ return sysfreq;
+ }
- of_node_put(soc);
+ /* get platform freq by its clock name */
+ pltclk = clk_get(NULL, "cg-pll0-div1");
+ if (IS_ERR(pltclk)) {
+ pr_err("%s: can't get bus frequency %ld\n",
+ __func__, PTR_ERR(pltclk));
+ return PTR_ERR(pltclk);
+ }
- return sysfreq;
+ return clk_get_rate(pltclk);
}
-static struct device_node *cpu_to_clk_node(int cpu)
+static struct clk *cpu_to_clk(int cpu)
{
- struct device_node *np, *clk_np;
+ struct device_node *np;
+ struct clk *clk;
if (!cpu_present(cpu))
return NULL;
@@ -112,37 +87,28 @@ static struct device_node *cpu_to_clk_node(int cpu)
if (!np)
return NULL;
- clk_np = of_parse_phandle(np, "clocks", 0);
- if (!clk_np)
- return NULL;
-
+ clk = of_clk_get(np, 0);
of_node_put(np);
-
- return clk_np;
+ return clk;
}
/* traverse cpu nodes to get cpu mask of sharing clock wire */
static void set_affected_cpus(struct cpufreq_policy *policy)
{
- struct device_node *np, *clk_np;
struct cpumask *dstp = policy->cpus;
+ struct clk *clk;
int i;
- np = cpu_to_clk_node(policy->cpu);
- if (!np)
- return;
-
for_each_present_cpu(i) {
- clk_np = cpu_to_clk_node(i);
- if (!clk_np)
+ clk = cpu_to_clk(i);
+ if (IS_ERR(clk)) {
+ pr_err("%s: no clock for cpu %d\n", __func__, i);
continue;
+ }
- if (clk_np == np)
+ if (clk_is_match(policy->clk, clk))
cpumask_set_cpu(i, dstp);
-
- of_node_put(clk_np);
}
- of_node_put(np);
}
/* reduce the duplicated frequencies in frequency table */
@@ -198,10 +164,11 @@ static void freq_table_sort(struct cpufreq_frequency_table *freq_table,
static int qoriq_cpufreq_cpu_init(struct cpufreq_policy *policy)
{
- struct device_node *np, *pnode;
+ struct device_node *np;
int i, count, ret;
- u32 freq, mask;
+ u32 freq;
struct clk *clk;
+ const struct clk_hw *hwclk;
struct cpufreq_frequency_table *table;
struct cpu_data *data;
unsigned int cpu = policy->cpu;
@@ -221,17 +188,13 @@ static int qoriq_cpufreq_cpu_init(struct cpufreq_policy *policy)
goto err_nomem2;
}
- pnode = of_parse_phandle(np, "clocks", 0);
- if (!pnode) {
- pr_err("%s: could not get clock information\n", __func__);
- goto err_nomem2;
- }
+ hwclk = __clk_get_hw(policy->clk);
+ count = clk_hw_get_num_parents(hwclk);
- count = of_property_count_strings(pnode, "clock-names");
data->pclk = kcalloc(count, sizeof(struct clk *), GFP_KERNEL);
if (!data->pclk) {
pr_err("%s: no memory\n", __func__);
- goto err_node;
+ goto err_nomem2;
}
table = kcalloc(count + 1, sizeof(*table), GFP_KERNEL);
@@ -240,23 +203,11 @@ static int qoriq_cpufreq_cpu_init(struct cpufreq_policy *policy)
goto err_pclk;
}
- if (fmask)
- mask = fmask[get_cpu_physical_id(cpu)];
- else
- mask = 0x0;
-
for (i = 0; i < count; i++) {
- clk = of_clk_get(pnode, i);
+ clk = clk_hw_get_parent_by_index(hwclk, i)->clk;
data->pclk[i] = clk;
freq = clk_get_rate(clk);
- /*
- * the clock is valid if its frequency is not masked
- * and large than minimum allowed frequency.
- */
- if (freq < min_cpufreq || (mask & (1 << i)))
- table[i].frequency = CPUFREQ_ENTRY_INVALID;
- else
- table[i].frequency = freq / 1000;
+ table[i].frequency = freq / 1000;
table[i].driver_data = i;
}
freq_table_redup(table, count);
@@ -282,7 +233,6 @@ static int qoriq_cpufreq_cpu_init(struct cpufreq_policy *policy)
policy->cpuinfo.transition_latency = u64temp + 1;
of_node_put(np);
- of_node_put(pnode);
return 0;
@@ -290,10 +240,7 @@ static int qoriq_cpufreq_cpu_init(struct cpufreq_policy *policy)
kfree(table);
err_pclk:
kfree(data->pclk);
-err_node:
- of_node_put(pnode);
err_nomem2:
- policy->driver_data = NULL;
kfree(data);
err_np:
of_node_put(np);
@@ -357,12 +304,25 @@ static struct cpufreq_driver qoriq_cpufreq_driver = {
.attr = cpufreq_generic_attr,
};
+static const struct soc_data blacklist = {
+ .flags = SOC_BLACKLIST,
+};
+
static const struct of_device_id node_matches[] __initconst = {
- { .compatible = "fsl,p2041-clockgen", .data = &sdata[0], },
- { .compatible = "fsl,p3041-clockgen", .data = &sdata[0], },
- { .compatible = "fsl,p5020-clockgen", .data = &sdata[1], },
- { .compatible = "fsl,p4080-clockgen", .data = &sdata[2], },
- { .compatible = "fsl,p5040-clockgen", .data = &sdata[2], },
+ /* e6500 cannot use cpufreq due to erratum A-008083 */
+ { .compatible = "fsl,b4420-clockgen", &blacklist },
+ { .compatible = "fsl,b4860-clockgen", &blacklist },
+ { .compatible = "fsl,t2080-clockgen", &blacklist },
+ { .compatible = "fsl,t4240-clockgen", &blacklist },
+
+ { .compatible = "fsl,ls1012a-clockgen", },
+ { .compatible = "fsl,ls1021a-clockgen", },
+ { .compatible = "fsl,ls1043a-clockgen", },
+ { .compatible = "fsl,ls1046a-clockgen", },
+ { .compatible = "fsl,ls1088a-clockgen", },
+ { .compatible = "fsl,ls2080a-clockgen", },
+ { .compatible = "fsl,p4080-clockgen", },
+ { .compatible = "fsl,qoriq-clockgen-1.0", },
{ .compatible = "fsl,qoriq-clockgen-2.0", },
{}
};
@@ -380,16 +340,12 @@ static int __init qoriq_cpufreq_init(void)
match = of_match_node(node_matches, np);
data = match->data;
- if (data) {
- if (data->flag)
- fmask = data->freq_mask;
- min_cpufreq = get_bus_freq();
- } else {
- min_cpufreq = get_bus_freq() / 2;
- }
of_node_put(np);
+ if (data && data->flags & SOC_BLACKLIST)
+ return -ENODEV;
+
ret = cpufreq_register_driver(&qoriq_cpufreq_driver);
if (!ret)
pr_info("Freescale QorIQ CPU frequency scaling driver\n");
diff --git a/drivers/firmware/psci.c b/drivers/firmware/psci.c
index 8263429e..323c9fc0 100644
--- a/drivers/firmware/psci.c
+++ b/drivers/firmware/psci.c
@@ -418,8 +418,12 @@ CPUIDLE_METHOD_OF_DECLARE(psci, "psci", &psci_cpuidle_ops);
static int psci_system_suspend(unsigned long unused)
{
- return invoke_psci_fn(PSCI_FN_NATIVE(1_0, SYSTEM_SUSPEND),
- virt_to_phys(cpu_resume), 0, 0);
+ u32 state;
+
+ state = ( 2 << PSCI_0_2_POWER_STATE_AFFL_SHIFT) |
+ (1 << PSCI_0_2_POWER_STATE_TYPE_SHIFT);
+
+ return psci_cpu_suspend(state, virt_to_phys(cpu_resume));
}
static int psci_system_suspend_enter(suspend_state_t state)
@@ -439,6 +443,8 @@ static void __init psci_init_system_suspend(void)
if (!IS_ENABLED(CONFIG_SUSPEND))
return;
+ suspend_set_ops(&psci_suspend_ops);
+
ret = psci_features(PSCI_FN_NATIVE(1_0, SYSTEM_SUSPEND));
if (ret != PSCI_RET_NOT_SUPPORTED)
@@ -516,6 +522,8 @@ static void __init psci_0_2_set_functions(void)
arm_pm_restart = psci_sys_reset;
pm_power_off = psci_sys_poweroff;
+ psci_init_system_suspend();
+ suspend_set_ops(&psci_suspend_ops);
}
/*
--
2.14.1

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,331 @@
From a5b3155b532289af793c26251cb087b4a24d5c15 Mon Sep 17 00:00:00 2001
From: Yangbo Lu <yangbo.lu@nxp.com>
Date: Mon, 25 Sep 2017 12:13:12 +0800
Subject: [PATCH] flextimer: support layerscape
This is a integrated patch for layerscape flextimer support.
Signed-off-by: Wang Dongsheng <dongsheng.wang@nxp.com>
Signed-off-by: Meng Yi <meng.yi@nxp.com>
Signed-off-by: Yangbo Lu <yangbo.lu@nxp.com>
---
drivers/clocksource/fsl_ftm_timer.c | 8 +-
drivers/soc/fsl/layerscape/ftm_alarm.c | 286 +++++++++++++++++++++++++++++++++
2 files changed, 290 insertions(+), 4 deletions(-)
create mode 100644 drivers/soc/fsl/layerscape/ftm_alarm.c
diff --git a/drivers/clocksource/fsl_ftm_timer.c b/drivers/clocksource/fsl_ftm_timer.c
index 738515b8..770bbbca 100644
--- a/drivers/clocksource/fsl_ftm_timer.c
+++ b/drivers/clocksource/fsl_ftm_timer.c
@@ -83,11 +83,11 @@ static inline void ftm_counter_disable(void __iomem *base)
static inline void ftm_irq_acknowledge(void __iomem *base)
{
- u32 val;
+ unsigned int timeout = 100;
- val = ftm_readl(base + FTM_SC);
- val &= ~FTM_SC_TOF;
- ftm_writel(val, base + FTM_SC);
+ while ((FTM_SC_TOF & ftm_readl(base + FTM_SC)) && timeout--)
+ ftm_writel(ftm_readl(base + FTM_SC) & (~FTM_SC_TOF),
+ base + FTM_SC);
}
static inline void ftm_irq_enable(void __iomem *base)
diff --git a/drivers/soc/fsl/layerscape/ftm_alarm.c b/drivers/soc/fsl/layerscape/ftm_alarm.c
new file mode 100644
index 00000000..6f9882ff
--- /dev/null
+++ b/drivers/soc/fsl/layerscape/ftm_alarm.c
@@ -0,0 +1,286 @@
+/*
+ * Freescale FlexTimer Module (FTM) Alarm driver.
+ *
+ * Copyright 2014 Freescale Semiconductor, Inc.
+ *
+ * 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.
+ */
+
+#include <linux/device.h>
+#include <linux/err.h>
+#include <linux/interrupt.h>
+#include <linux/io.h>
+#include <linux/of_address.h>
+#include <linux/of_irq.h>
+#include <linux/platform_device.h>
+
+#define FTM_SC 0x00
+#define FTM_SC_CLK_SHIFT 3
+#define FTM_SC_CLK_MASK (0x3 << FTM_SC_CLK_SHIFT)
+#define FTM_SC_CLK(c) ((c) << FTM_SC_CLK_SHIFT)
+#define FTM_SC_PS_MASK 0x7
+#define FTM_SC_TOIE BIT(6)
+#define FTM_SC_TOF BIT(7)
+
+#define FTM_SC_CLKS_FIXED_FREQ 0x02
+
+#define FTM_CNT 0x04
+#define FTM_MOD 0x08
+#define FTM_CNTIN 0x4C
+
+#define FIXED_FREQ_CLK 32000
+#define MAX_FREQ_DIV (1 << FTM_SC_PS_MASK)
+#define MAX_COUNT_VAL 0xffff
+
+static void __iomem *ftm1_base;
+static void __iomem *rcpm_ftm_addr;
+static u32 alarm_freq;
+static bool big_endian;
+
+static inline u32 ftm_readl(void __iomem *addr)
+{
+ if (big_endian)
+ return ioread32be(addr);
+
+ return ioread32(addr);
+}
+
+static inline void ftm_writel(u32 val, void __iomem *addr)
+{
+ if (big_endian)
+ iowrite32be(val, addr);
+ else
+ iowrite32(val, addr);
+}
+
+static inline void ftm_counter_enable(void __iomem *base)
+{
+ u32 val;
+
+ /* select and enable counter clock source */
+ val = ftm_readl(base + FTM_SC);
+ val &= ~(FTM_SC_PS_MASK | FTM_SC_CLK_MASK);
+ val |= (FTM_SC_PS_MASK | FTM_SC_CLK(FTM_SC_CLKS_FIXED_FREQ));
+ ftm_writel(val, base + FTM_SC);
+}
+
+static inline void ftm_counter_disable(void __iomem *base)
+{
+ u32 val;
+
+ /* disable counter clock source */
+ val = ftm_readl(base + FTM_SC);
+ val &= ~(FTM_SC_PS_MASK | FTM_SC_CLK_MASK);
+ ftm_writel(val, base + FTM_SC);
+}
+
+static inline void ftm_irq_acknowledge(void __iomem *base)
+{
+ unsigned int timeout = 100;
+
+ while ((FTM_SC_TOF & ftm_readl(base + FTM_SC)) && timeout--)
+ ftm_writel(ftm_readl(base + FTM_SC) & (~FTM_SC_TOF),
+ base + FTM_SC);
+}
+
+static inline void ftm_irq_enable(void __iomem *base)
+{
+ u32 val;
+
+ val = ftm_readl(base + FTM_SC);
+ val |= FTM_SC_TOIE;
+ ftm_writel(val, base + FTM_SC);
+}
+
+static inline void ftm_irq_disable(void __iomem *base)
+{
+ u32 val;
+
+ val = ftm_readl(base + FTM_SC);
+ val &= ~FTM_SC_TOIE;
+ ftm_writel(val, base + FTM_SC);
+}
+
+static inline void ftm_reset_counter(void __iomem *base)
+{
+ /*
+ * The CNT register contains the FTM counter value.
+ * Reset clears the CNT register. Writing any value to COUNT
+ * updates the counter with its initial value, CNTIN.
+ */
+ ftm_writel(0x00, base + FTM_CNT);
+}
+
+static u32 time_to_cycle(unsigned long time)
+{
+ u32 cycle;
+
+ cycle = time * alarm_freq;
+ if (cycle > MAX_COUNT_VAL) {
+ pr_err("Out of alarm range.\n");
+ cycle = 0;
+ }
+
+ return cycle;
+}
+
+static u32 cycle_to_time(u32 cycle)
+{
+ return cycle / alarm_freq + 1;
+}
+
+static void ftm_clean_alarm(void)
+{
+ ftm_counter_disable(ftm1_base);
+
+ ftm_writel(0x00, ftm1_base + FTM_CNTIN);
+ ftm_writel(~0U, ftm1_base + FTM_MOD);
+
+ ftm_reset_counter(ftm1_base);
+}
+
+static int ftm_set_alarm(u64 cycle)
+{
+ ftm_irq_disable(ftm1_base);
+
+ /*
+ * The counter increments until the value of MOD is reached,
+ * at which point the counter is reloaded with the value of CNTIN.
+ * The TOF (the overflow flag) bit is set when the FTM counter
+ * changes from MOD to CNTIN. So we should using the cycle - 1.
+ */
+ ftm_writel(cycle - 1, ftm1_base + FTM_MOD);
+
+ ftm_counter_enable(ftm1_base);
+
+ ftm_irq_enable(ftm1_base);
+
+ return 0;
+}
+
+static irqreturn_t ftm_alarm_interrupt(int irq, void *dev_id)
+{
+ ftm_irq_acknowledge(ftm1_base);
+ ftm_irq_disable(ftm1_base);
+ ftm_clean_alarm();
+
+ return IRQ_HANDLED;
+}
+
+static ssize_t ftm_alarm_show(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
+{
+ u32 count, val;
+
+ count = ftm_readl(ftm1_base + FTM_MOD);
+ val = ftm_readl(ftm1_base + FTM_CNT);
+ val = (count & MAX_COUNT_VAL) - val;
+ val = cycle_to_time(val);
+
+ return sprintf(buf, "%u\n", val);
+}
+
+static ssize_t ftm_alarm_store(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ u32 cycle;
+ unsigned long time;
+
+ if (kstrtoul(buf, 0, &time))
+ return -EINVAL;
+
+ ftm_clean_alarm();
+
+ cycle = time_to_cycle(time);
+ if (!cycle)
+ return -EINVAL;
+
+ ftm_set_alarm(cycle);
+
+ return count;
+}
+
+static struct device_attribute ftm_alarm_attributes = __ATTR(ftm_alarm, 0644,
+ ftm_alarm_show, ftm_alarm_store);
+
+static int ftm_alarm_probe(struct platform_device *pdev)
+{
+ struct device_node *np = pdev->dev.of_node;
+ struct resource *r;
+ int irq;
+ int ret;
+ u32 ippdexpcr;
+
+ r = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ if (!r)
+ return -ENODEV;
+
+ ftm1_base = devm_ioremap_resource(&pdev->dev, r);
+ if (IS_ERR(ftm1_base))
+ return PTR_ERR(ftm1_base);
+
+ r = platform_get_resource_byname(pdev, IORESOURCE_MEM, "FlexTimer1");
+ if (r) {
+ rcpm_ftm_addr = devm_ioremap_resource(&pdev->dev, r);
+ if (IS_ERR(rcpm_ftm_addr))
+ return PTR_ERR(rcpm_ftm_addr);
+ ippdexpcr = ioread32be(rcpm_ftm_addr);
+ ippdexpcr |= 0x20000;
+ iowrite32be(ippdexpcr, rcpm_ftm_addr);
+ }
+
+ irq = irq_of_parse_and_map(np, 0);
+ if (irq <= 0) {
+ pr_err("ftm: unable to get IRQ from DT, %d\n", irq);
+ return -EINVAL;
+ }
+
+ big_endian = of_property_read_bool(np, "big-endian");
+
+ ret = devm_request_irq(&pdev->dev, irq, ftm_alarm_interrupt,
+ IRQF_NO_SUSPEND, dev_name(&pdev->dev), NULL);
+ if (ret < 0) {
+ dev_err(&pdev->dev, "failed to request irq\n");
+ return ret;
+ }
+
+ ret = device_create_file(&pdev->dev, &ftm_alarm_attributes);
+ if (ret) {
+ dev_err(&pdev->dev, "create sysfs fail.\n");
+ return ret;
+ }
+
+ alarm_freq = (u32)FIXED_FREQ_CLK / (u32)MAX_FREQ_DIV;
+
+ ftm_clean_alarm();
+
+ device_init_wakeup(&pdev->dev, true);
+
+ return ret;
+}
+
+static const struct of_device_id ftm_alarm_match[] = {
+ { .compatible = "fsl,ftm-alarm", },
+ { .compatible = "fsl,ftm-timer", },
+ { },
+};
+
+static struct platform_driver ftm_alarm_driver = {
+ .probe = ftm_alarm_probe,
+ .driver = {
+ .name = "ftm-alarm",
+ .owner = THIS_MODULE,
+ .of_match_table = ftm_alarm_match,
+ },
+};
+
+static int __init ftm_alarm_init(void)
+{
+ return platform_driver_register(&ftm_alarm_driver);
+}
+device_initcall(ftm_alarm_init);
--
2.14.1

View file

@ -0,0 +1,73 @@
From 4278a546526094dd57bfa3cf7ae2bf34092246db Mon Sep 17 00:00:00 2001
From: Yangbo Lu <yangbo.lu@nxp.com>
Date: Mon, 25 Sep 2017 12:10:01 +0800
Subject: [PATCH] gpu: support layerscape
This is a integrated patch for layerscape dcu support.
Signed-off-by: Alison Wang <b18965@freescale.com>
Signed-off-by: Yangbo Lu <yangbo.lu@nxp.com>
---
drivers/gpu/drm/fsl-dcu/fsl_dcu_drm_drv.c | 18 ++++++++++++++++--
1 file changed, 16 insertions(+), 2 deletions(-)
diff --git a/drivers/gpu/drm/fsl-dcu/fsl_dcu_drm_drv.c b/drivers/gpu/drm/fsl-dcu/fsl_dcu_drm_drv.c
index cc2fde2a..54f60ba1 100644
--- a/drivers/gpu/drm/fsl-dcu/fsl_dcu_drm_drv.c
+++ b/drivers/gpu/drm/fsl-dcu/fsl_dcu_drm_drv.c
@@ -225,7 +225,6 @@ static int fsl_dcu_drm_pm_suspend(struct device *dev)
if (!fsl_dev)
return 0;
- disable_irq(fsl_dev->irq);
drm_kms_helper_poll_disable(fsl_dev->drm);
console_lock();
@@ -243,6 +242,8 @@ static int fsl_dcu_drm_pm_suspend(struct device *dev)
return PTR_ERR(fsl_dev->state);
}
+ disable_irq(fsl_dev->irq);
+
clk_disable_unprepare(fsl_dev->pix_clk);
clk_disable_unprepare(fsl_dev->clk);
@@ -263,6 +264,14 @@ static int fsl_dcu_drm_pm_resume(struct device *dev)
return ret;
}
+ ret = clk_prepare_enable(fsl_dev->pix_clk);
+ if (ret < 0) {
+ dev_err(dev, "failed to enable dcu pix clk\n");
+ return ret;
+ }
+
+ enable_irq(fsl_dev->irq);
+
if (fsl_dev->tcon)
fsl_tcon_bypass_enable(fsl_dev->tcon);
fsl_dcu_drm_init_planes(fsl_dev->drm);
@@ -273,7 +282,6 @@ static int fsl_dcu_drm_pm_resume(struct device *dev)
console_unlock();
drm_kms_helper_poll_enable(fsl_dev->drm);
- enable_irq(fsl_dev->irq);
return 0;
}
@@ -389,6 +397,12 @@ static int fsl_dcu_drm_probe(struct platform_device *pdev)
goto disable_clk;
}
+ ret = clk_prepare_enable(fsl_dev->pix_clk);
+ if (ret < 0) {
+ dev_err(dev, "failed to enable dcu pix clk\n");
+ return ret;
+ }
+
fsl_dev->tcon = fsl_tcon_init(dev);
drm = drm_dev_alloc(driver, dev);
--
2.14.1

View file

@ -0,0 +1,462 @@
From d51e307e4ecf51832c9e3bc30acb5dbd559d5f4d Mon Sep 17 00:00:00 2001
From: Yangbo Lu <yangbo.lu@nxp.com>
Date: Mon, 25 Sep 2017 12:19:34 +0800
Subject: [PATCH] guts: support layerscape
This is a integrated patch for layerscape guts support.
Signed-off-by: Roy Pledge <roy.pledge@nxp.com>
Signed-off-by: Geert Uytterhoeven <geert+renesas@glider.be>
Signed-off-by: Amrita Kumari <amrita.kumari@nxp.com>
Signed-off-by: Yangbo Lu <yangbo.lu@nxp.com>
---
drivers/base/soc.c | 12 ++-
drivers/soc/fsl/guts.c | 238 +++++++++++++++++++++++++++++++++++++++++++++++
include/linux/fsl/guts.h | 125 +++++++++++++++----------
3 files changed, 323 insertions(+), 52 deletions(-)
create mode 100644 drivers/soc/fsl/guts.c
diff --git a/drivers/base/soc.c b/drivers/base/soc.c
index 0c5cf872..0e701e22 100644
--- a/drivers/base/soc.c
+++ b/drivers/base/soc.c
@@ -167,19 +167,23 @@ static int soc_device_match_one(struct device *dev, void *arg)
const struct soc_device_attribute *match = arg;
if (match->machine &&
- !glob_match(match->machine, soc_dev->attr->machine))
+ (!soc_dev->attr->machine ||
+ !glob_match(match->machine, soc_dev->attr->machine)))
return 0;
if (match->family &&
- !glob_match(match->family, soc_dev->attr->family))
+ (!soc_dev->attr->family ||
+ !glob_match(match->family, soc_dev->attr->family)))
return 0;
if (match->revision &&
- !glob_match(match->revision, soc_dev->attr->revision))
+ (!soc_dev->attr->revision ||
+ !glob_match(match->revision, soc_dev->attr->revision)))
return 0;
if (match->soc_id &&
- !glob_match(match->soc_id, soc_dev->attr->soc_id))
+ (!soc_dev->attr->soc_id ||
+ !glob_match(match->soc_id, soc_dev->attr->soc_id)))
return 0;
return 1;
diff --git a/drivers/soc/fsl/guts.c b/drivers/soc/fsl/guts.c
new file mode 100644
index 00000000..7d28784a
--- /dev/null
+++ b/drivers/soc/fsl/guts.c
@@ -0,0 +1,238 @@
+/*
+ * Freescale QorIQ Platforms GUTS Driver
+ *
+ * Copyright (C) 2016 Freescale Semiconductor, Inc.
+ *
+ * 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.
+ */
+
+#include <linux/io.h>
+#include <linux/slab.h>
+#include <linux/module.h>
+#include <linux/of_fdt.h>
+#include <linux/sys_soc.h>
+#include <linux/of_address.h>
+#include <linux/platform_device.h>
+#include <linux/fsl/guts.h>
+
+struct guts {
+ struct ccsr_guts __iomem *regs;
+ bool little_endian;
+};
+
+struct fsl_soc_die_attr {
+ char *die;
+ u32 svr;
+ u32 mask;
+};
+
+static struct guts *guts;
+static struct soc_device_attribute soc_dev_attr;
+static struct soc_device *soc_dev;
+
+
+/* SoC die attribute definition for QorIQ platform */
+static const struct fsl_soc_die_attr fsl_soc_die[] = {
+ /*
+ * Power Architecture-based SoCs T Series
+ */
+
+ /* Die: T4240, SoC: T4240/T4160/T4080 */
+ { .die = "T4240",
+ .svr = 0x82400000,
+ .mask = 0xfff00000,
+ },
+ /* Die: T1040, SoC: T1040/T1020/T1042/T1022 */
+ { .die = "T1040",
+ .svr = 0x85200000,
+ .mask = 0xfff00000,
+ },
+ /* Die: T2080, SoC: T2080/T2081 */
+ { .die = "T2080",
+ .svr = 0x85300000,
+ .mask = 0xfff00000,
+ },
+ /* Die: T1024, SoC: T1024/T1014/T1023/T1013 */
+ { .die = "T1024",
+ .svr = 0x85400000,
+ .mask = 0xfff00000,
+ },
+
+ /*
+ * ARM-based SoCs LS Series
+ */
+
+ /* Die: LS1043A, SoC: LS1043A/LS1023A */
+ { .die = "LS1043A",
+ .svr = 0x87920000,
+ .mask = 0xffff0000,
+ },
+ /* Die: LS2080A, SoC: LS2080A/LS2040A/LS2085A */
+ { .die = "LS2080A",
+ .svr = 0x87010000,
+ .mask = 0xff3f0000,
+ },
+ /* Die: LS1088A, SoC: LS1088A/LS1048A/LS1084A/LS1044A */
+ { .die = "LS1088A",
+ .svr = 0x87030000,
+ .mask = 0xff3f0000,
+ },
+ /* Die: LS1012A, SoC: LS1012A */
+ { .die = "LS1012A",
+ .svr = 0x87040000,
+ .mask = 0xffff0000,
+ },
+ /* Die: LS1046A, SoC: LS1046A/LS1026A */
+ { .die = "LS1046A",
+ .svr = 0x87070000,
+ .mask = 0xffff0000,
+ },
+ /* Die: LS2088A, SoC: LS2088A/LS2048A/LS2084A/LS2044A */
+ { .die = "LS2088A",
+ .svr = 0x87090000,
+ .mask = 0xff3f0000,
+ },
+ /* Die: LS1021A, SoC: LS1021A/LS1020A/LS1022A */
+ { .die = "LS1021A",
+ .svr = 0x87000000,
+ .mask = 0xfff70000,
+ },
+ { },
+};
+
+static const struct fsl_soc_die_attr *fsl_soc_die_match(
+ u32 svr, const struct fsl_soc_die_attr *matches)
+{
+ while (matches->svr) {
+ if (matches->svr == (svr & matches->mask))
+ return matches;
+ matches++;
+ };
+ return NULL;
+}
+
+u32 fsl_guts_get_svr(void)
+{
+ u32 svr = 0;
+
+ if (!guts || !guts->regs)
+ return svr;
+
+ if (guts->little_endian)
+ svr = ioread32(&guts->regs->svr);
+ else
+ svr = ioread32be(&guts->regs->svr);
+
+ return svr;
+}
+EXPORT_SYMBOL(fsl_guts_get_svr);
+
+static int fsl_guts_probe(struct platform_device *pdev)
+{
+ struct device_node *np = pdev->dev.of_node;
+ struct device *dev = &pdev->dev;
+ struct resource *res;
+ const struct fsl_soc_die_attr *soc_die;
+ const char *machine;
+ u32 svr;
+
+ /* Initialize guts */
+ guts = devm_kzalloc(dev, sizeof(*guts), GFP_KERNEL);
+ if (!guts)
+ return -ENOMEM;
+
+ guts->little_endian = of_property_read_bool(np, "little-endian");
+
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ guts->regs = devm_ioremap_resource(dev, res);
+ if (IS_ERR(guts->regs))
+ return PTR_ERR(guts->regs);
+
+ /* Register soc device */
+ machine = of_flat_dt_get_machine_name();
+ if (machine)
+ soc_dev_attr.machine = devm_kstrdup(dev, machine, GFP_KERNEL);
+
+ svr = fsl_guts_get_svr();
+ soc_die = fsl_soc_die_match(svr, fsl_soc_die);
+ if (soc_die) {
+ soc_dev_attr.family = devm_kasprintf(dev, GFP_KERNEL,
+ "QorIQ %s", soc_die->die);
+ } else {
+ soc_dev_attr.family = devm_kasprintf(dev, GFP_KERNEL, "QorIQ");
+ }
+ soc_dev_attr.soc_id = devm_kasprintf(dev, GFP_KERNEL,
+ "svr:0x%08x", svr);
+ soc_dev_attr.revision = devm_kasprintf(dev, GFP_KERNEL, "%d.%d",
+ (svr >> 4) & 0xf, svr & 0xf);
+
+ soc_dev = soc_device_register(&soc_dev_attr);
+ if (IS_ERR(soc_dev))
+ return PTR_ERR(soc_dev);
+
+ pr_info("Machine: %s\n", soc_dev_attr.machine);
+ pr_info("SoC family: %s\n", soc_dev_attr.family);
+ pr_info("SoC ID: %s, Revision: %s\n",
+ soc_dev_attr.soc_id, soc_dev_attr.revision);
+ return 0;
+}
+
+static int fsl_guts_remove(struct platform_device *dev)
+{
+ soc_device_unregister(soc_dev);
+ return 0;
+}
+
+/*
+ * Table for matching compatible strings, for device tree
+ * guts node, for Freescale QorIQ SOCs.
+ */
+static const struct of_device_id fsl_guts_of_match[] = {
+ { .compatible = "fsl,qoriq-device-config-1.0", },
+ { .compatible = "fsl,qoriq-device-config-2.0", },
+ { .compatible = "fsl,p1010-guts", },
+ { .compatible = "fsl,p1020-guts", },
+ { .compatible = "fsl,p1021-guts", },
+ { .compatible = "fsl,p1022-guts", },
+ { .compatible = "fsl,p1023-guts", },
+ { .compatible = "fsl,p2020-guts", },
+ { .compatible = "fsl,bsc9131-guts", },
+ { .compatible = "fsl,bsc9132-guts", },
+ { .compatible = "fsl,mpc8536-guts", },
+ { .compatible = "fsl,mpc8544-guts", },
+ { .compatible = "fsl,mpc8548-guts", },
+ { .compatible = "fsl,mpc8568-guts", },
+ { .compatible = "fsl,mpc8569-guts", },
+ { .compatible = "fsl,mpc8572-guts", },
+ { .compatible = "fsl,ls1021a-dcfg", },
+ { .compatible = "fsl,ls1043a-dcfg", },
+ { .compatible = "fsl,ls1046a-dcfg", },
+ { .compatible = "fsl,ls2080a-dcfg", },
+ { .compatible = "fsl,ls1088a-dcfg", },
+ {}
+};
+MODULE_DEVICE_TABLE(of, fsl_guts_of_match);
+
+static struct platform_driver fsl_guts_driver = {
+ .driver = {
+ .name = "fsl-guts",
+ .of_match_table = fsl_guts_of_match,
+ },
+ .probe = fsl_guts_probe,
+ .remove = fsl_guts_remove,
+};
+
+static int __init fsl_guts_init(void)
+{
+ return platform_driver_register(&fsl_guts_driver);
+}
+core_initcall(fsl_guts_init);
+
+static void __exit fsl_guts_exit(void)
+{
+ platform_driver_unregister(&fsl_guts_driver);
+}
+module_exit(fsl_guts_exit);
diff --git a/include/linux/fsl/guts.h b/include/linux/fsl/guts.h
index 649e9171..3efa3b86 100644
--- a/include/linux/fsl/guts.h
+++ b/include/linux/fsl/guts.h
@@ -29,83 +29,112 @@
* #ifdefs.
*/
struct ccsr_guts {
- __be32 porpllsr; /* 0x.0000 - POR PLL Ratio Status Register */
- __be32 porbmsr; /* 0x.0004 - POR Boot Mode Status Register */
- __be32 porimpscr; /* 0x.0008 - POR I/O Impedance Status and Control Register */
- __be32 pordevsr; /* 0x.000c - POR I/O Device Status Register */
- __be32 pordbgmsr; /* 0x.0010 - POR Debug Mode Status Register */
- __be32 pordevsr2; /* 0x.0014 - POR device status register 2 */
+ u32 porpllsr; /* 0x.0000 - POR PLL Ratio Status Register */
+ u32 porbmsr; /* 0x.0004 - POR Boot Mode Status Register */
+ u32 porimpscr; /* 0x.0008 - POR I/O Impedance Status and
+ * Control Register
+ */
+ u32 pordevsr; /* 0x.000c - POR I/O Device Status Register */
+ u32 pordbgmsr; /* 0x.0010 - POR Debug Mode Status Register */
+ u32 pordevsr2; /* 0x.0014 - POR device status register 2 */
u8 res018[0x20 - 0x18];
- __be32 porcir; /* 0x.0020 - POR Configuration Information Register */
+ u32 porcir; /* 0x.0020 - POR Configuration Information
+ * Register
+ */
u8 res024[0x30 - 0x24];
- __be32 gpiocr; /* 0x.0030 - GPIO Control Register */
+ u32 gpiocr; /* 0x.0030 - GPIO Control Register */
u8 res034[0x40 - 0x34];
- __be32 gpoutdr; /* 0x.0040 - General-Purpose Output Data Register */
+ u32 gpoutdr; /* 0x.0040 - General-Purpose Output Data
+ * Register
+ */
u8 res044[0x50 - 0x44];
- __be32 gpindr; /* 0x.0050 - General-Purpose Input Data Register */
+ u32 gpindr; /* 0x.0050 - General-Purpose Input Data
+ * Register
+ */
u8 res054[0x60 - 0x54];
- __be32 pmuxcr; /* 0x.0060 - Alternate Function Signal Multiplex Control */
- __be32 pmuxcr2; /* 0x.0064 - Alternate function signal multiplex control 2 */
- __be32 dmuxcr; /* 0x.0068 - DMA Mux Control Register */
+ u32 pmuxcr; /* 0x.0060 - Alternate Function Signal
+ * Multiplex Control
+ */
+ u32 pmuxcr2; /* 0x.0064 - Alternate function signal
+ * multiplex control 2
+ */
+ u32 dmuxcr; /* 0x.0068 - DMA Mux Control Register */
u8 res06c[0x70 - 0x6c];
- __be32 devdisr; /* 0x.0070 - Device Disable Control */
+ u32 devdisr; /* 0x.0070 - Device Disable Control */
#define CCSR_GUTS_DEVDISR_TB1 0x00001000
#define CCSR_GUTS_DEVDISR_TB0 0x00004000
- __be32 devdisr2; /* 0x.0074 - Device Disable Control 2 */
+ u32 devdisr2; /* 0x.0074 - Device Disable Control 2 */
u8 res078[0x7c - 0x78];
- __be32 pmjcr; /* 0x.007c - 4 Power Management Jog Control Register */
- __be32 powmgtcsr; /* 0x.0080 - Power Management Status and Control Register */
- __be32 pmrccr; /* 0x.0084 - Power Management Reset Counter Configuration Register */
- __be32 pmpdccr; /* 0x.0088 - Power Management Power Down Counter Configuration Register */
- __be32 pmcdr; /* 0x.008c - 4Power management clock disable register */
- __be32 mcpsumr; /* 0x.0090 - Machine Check Summary Register */
- __be32 rstrscr; /* 0x.0094 - Reset Request Status and Control Register */
- __be32 ectrstcr; /* 0x.0098 - Exception reset control register */
- __be32 autorstsr; /* 0x.009c - Automatic reset status register */
- __be32 pvr; /* 0x.00a0 - Processor Version Register */
- __be32 svr; /* 0x.00a4 - System Version Register */
+ u32 pmjcr; /* 0x.007c - 4 Power Management Jog Control
+ * Register
+ */
+ u32 powmgtcsr; /* 0x.0080 - Power Management Status and
+ * Control Register
+ */
+ u32 pmrccr; /* 0x.0084 - Power Management Reset Counter
+ * Configuration Register
+ */
+ u32 pmpdccr; /* 0x.0088 - Power Management Power Down Counter
+ * Configuration Register
+ */
+ u32 pmcdr; /* 0x.008c - 4Power management clock disable
+ * register
+ */
+ u32 mcpsumr; /* 0x.0090 - Machine Check Summary Register */
+ u32 rstrscr; /* 0x.0094 - Reset Request Status and
+ * Control Register
+ */
+ u32 ectrstcr; /* 0x.0098 - Exception reset control register */
+ u32 autorstsr; /* 0x.009c - Automatic reset status register */
+ u32 pvr; /* 0x.00a0 - Processor Version Register */
+ u32 svr; /* 0x.00a4 - System Version Register */
u8 res0a8[0xb0 - 0xa8];
- __be32 rstcr; /* 0x.00b0 - Reset Control Register */
+ u32 rstcr; /* 0x.00b0 - Reset Control Register */
u8 res0b4[0xc0 - 0xb4];
- __be32 iovselsr; /* 0x.00c0 - I/O voltage select status register
+ u32 iovselsr; /* 0x.00c0 - I/O voltage select status register
Called 'elbcvselcr' on 86xx SOCs */
u8 res0c4[0x100 - 0xc4];
- __be32 rcwsr[16]; /* 0x.0100 - Reset Control Word Status registers
+ u32 rcwsr[16]; /* 0x.0100 - Reset Control Word Status registers
There are 16 registers */
u8 res140[0x224 - 0x140];
- __be32 iodelay1; /* 0x.0224 - IO delay control register 1 */
- __be32 iodelay2; /* 0x.0228 - IO delay control register 2 */
+ u32 iodelay1; /* 0x.0224 - IO delay control register 1 */
+ u32 iodelay2; /* 0x.0228 - IO delay control register 2 */
u8 res22c[0x604 - 0x22c];
- __be32 pamubypenr; /* 0x.604 - PAMU bypass enable register */
+ u32 pamubypenr; /* 0x.604 - PAMU bypass enable register */
u8 res608[0x800 - 0x608];
- __be32 clkdvdr; /* 0x.0800 - Clock Divide Register */
+ u32 clkdvdr; /* 0x.0800 - Clock Divide Register */
u8 res804[0x900 - 0x804];
- __be32 ircr; /* 0x.0900 - Infrared Control Register */
+ u32 ircr; /* 0x.0900 - Infrared Control Register */
u8 res904[0x908 - 0x904];
- __be32 dmacr; /* 0x.0908 - DMA Control Register */
+ u32 dmacr; /* 0x.0908 - DMA Control Register */
u8 res90c[0x914 - 0x90c];
- __be32 elbccr; /* 0x.0914 - eLBC Control Register */
+ u32 elbccr; /* 0x.0914 - eLBC Control Register */
u8 res918[0xb20 - 0x918];
- __be32 ddr1clkdr; /* 0x.0b20 - DDR1 Clock Disable Register */
- __be32 ddr2clkdr; /* 0x.0b24 - DDR2 Clock Disable Register */
- __be32 ddrclkdr; /* 0x.0b28 - DDR Clock Disable Register */
+ u32 ddr1clkdr; /* 0x.0b20 - DDR1 Clock Disable Register */
+ u32 ddr2clkdr; /* 0x.0b24 - DDR2 Clock Disable Register */
+ u32 ddrclkdr; /* 0x.0b28 - DDR Clock Disable Register */
u8 resb2c[0xe00 - 0xb2c];
- __be32 clkocr; /* 0x.0e00 - Clock Out Select Register */
+ u32 clkocr; /* 0x.0e00 - Clock Out Select Register */
u8 rese04[0xe10 - 0xe04];
- __be32 ddrdllcr; /* 0x.0e10 - DDR DLL Control Register */
+ u32 ddrdllcr; /* 0x.0e10 - DDR DLL Control Register */
u8 rese14[0xe20 - 0xe14];
- __be32 lbcdllcr; /* 0x.0e20 - LBC DLL Control Register */
- __be32 cpfor; /* 0x.0e24 - L2 charge pump fuse override register */
+ u32 lbcdllcr; /* 0x.0e20 - LBC DLL Control Register */
+ u32 cpfor; /* 0x.0e24 - L2 charge pump fuse override
+ * register
+ */
u8 rese28[0xf04 - 0xe28];
- __be32 srds1cr0; /* 0x.0f04 - SerDes1 Control Register 0 */
- __be32 srds1cr1; /* 0x.0f08 - SerDes1 Control Register 0 */
+ u32 srds1cr0; /* 0x.0f04 - SerDes1 Control Register 0 */
+ u32 srds1cr1; /* 0x.0f08 - SerDes1 Control Register 0 */
u8 resf0c[0xf2c - 0xf0c];
- __be32 itcr; /* 0x.0f2c - Internal transaction control register */
+ u32 itcr; /* 0x.0f2c - Internal transaction control
+ * register
+ */
u8 resf30[0xf40 - 0xf30];
- __be32 srds2cr0; /* 0x.0f40 - SerDes2 Control Register 0 */
- __be32 srds2cr1; /* 0x.0f44 - SerDes2 Control Register 0 */
+ u32 srds2cr0; /* 0x.0f40 - SerDes2 Control Register 0 */
+ u32 srds2cr1; /* 0x.0f44 - SerDes2 Control Register 0 */
} __attribute__ ((packed));
+u32 fsl_guts_get_svr(void);
/* Alternate function signal multiplex control */
#define MPC85xx_PMUXCR_QE(x) (0x8000 >> (x))
--
2.14.1

View file

@ -0,0 +1,140 @@
From 3c5032fe34f1af50e9e5fe58d40bf93c1717302f Mon Sep 17 00:00:00 2001
From: Yangbo Lu <yangbo.lu@nxp.com>
Date: Mon, 25 Sep 2017 12:19:53 +0800
Subject: [PATCH] i2c: support layerscape
This is a integrated patch for layerscape i2c support.
Signed-off-by: Zhang Ying-22455 <ying.zhang22455@nxp.com>
Signed-off-by: Priyanka Jain <Priyanka.Jain@freescale.com>
Signed-off-by: Yangbo Lu <yangbo.lu@nxp.com>
---
drivers/i2c/busses/i2c-imx.c | 10 ++++++++-
drivers/i2c/muxes/i2c-mux-pca954x.c | 43 +++++++++++++++++++++++++++++++++++++
2 files changed, 52 insertions(+), 1 deletion(-)
diff --git a/drivers/i2c/busses/i2c-imx.c b/drivers/i2c/busses/i2c-imx.c
index 47fc1f1a..a35c366b 100644
--- a/drivers/i2c/busses/i2c-imx.c
+++ b/drivers/i2c/busses/i2c-imx.c
@@ -889,6 +889,14 @@ static int i2c_imx_xfer(struct i2c_adapter *adapter,
dev_dbg(&i2c_imx->adapter.dev, "<%s>\n", __func__);
+ /*
+ * workround for ERR010027: ensure that the I2C BUS is idle
+ * before switching to master mode and attempting a Start cycle
+ */
+ result = i2c_imx_bus_busy(i2c_imx, 0);
+ if (result)
+ goto out;
+
result = pm_runtime_get_sync(i2c_imx->adapter.dev.parent);
if (result < 0)
goto out;
@@ -1100,7 +1108,7 @@ static int i2c_imx_probe(struct platform_device *pdev)
}
/* Request IRQ */
- ret = devm_request_irq(&pdev->dev, irq, i2c_imx_isr, 0,
+ ret = devm_request_irq(&pdev->dev, irq, i2c_imx_isr, IRQF_SHARED,
pdev->name, i2c_imx);
if (ret) {
dev_err(&pdev->dev, "can't claim irq %d\n", irq);
diff --git a/drivers/i2c/muxes/i2c-mux-pca954x.c b/drivers/i2c/muxes/i2c-mux-pca954x.c
index 9c4ac26c..3c27ab84 100644
--- a/drivers/i2c/muxes/i2c-mux-pca954x.c
+++ b/drivers/i2c/muxes/i2c-mux-pca954x.c
@@ -74,6 +74,7 @@ struct pca954x {
u8 last_chan; /* last register value */
u8 deselect;
struct i2c_client *client;
+ u8 disable_mux; /* do not disable mux if val not 0 */
};
/* Provide specs for the PCA954x types we know about */
@@ -196,6 +197,13 @@ static int pca954x_deselect_mux(struct i2c_mux_core *muxc, u32 chan)
if (!(data->deselect & (1 << chan)))
return 0;
+#ifdef CONFIG_ARCH_LAYERSCAPE
+ if (data->disable_mux != 0)
+ data->last_chan = data->chip->nchans;
+ else
+ data->last_chan = 0;
+ return pca954x_reg_write(muxc->parent, client, data->disable_mux);
+#endif
/* Deselect active channel */
data->last_chan = 0;
return pca954x_reg_write(muxc->parent, client, data->last_chan);
@@ -228,6 +236,28 @@ static int pca954x_probe(struct i2c_client *client,
return -ENOMEM;
data = i2c_mux_priv(muxc);
+#ifdef CONFIG_ARCH_LAYERSCAPE
+ /* The point here is that you must not disable a mux if there
+ * are no pullups on the input or you mess up the I2C. This
+ * needs to be put into the DTS really as the kernel cannot
+ * know this otherwise.
+ */
+ match = of_match_device(of_match_ptr(pca954x_of_match), &client->dev);
+ if (match)
+ data->chip = of_device_get_match_data(&client->dev);
+ else
+ data->chip = &chips[id->driver_data];
+
+ data->disable_mux = of_node &&
+ of_property_read_bool(of_node, "i2c-mux-never-disable") &&
+ data->chip->muxtype == pca954x_ismux ?
+ data->chip->enable : 0;
+ /* force the first selection */
+ if (data->disable_mux != 0)
+ data->last_chan = data->chip->nchans;
+ else
+ data->last_chan = 0;
+#endif
i2c_set_clientdata(client, muxc);
data->client = client;
@@ -240,11 +270,16 @@ static int pca954x_probe(struct i2c_client *client,
* that the mux is in fact present. This also
* initializes the mux to disconnected state.
*/
+#ifdef CONFIG_ARCH_LAYERSCAPE
+ if (i2c_smbus_write_byte(client, data->disable_mux) < 0) {
+#else
if (i2c_smbus_write_byte(client, 0) < 0) {
+#endif
dev_warn(&client->dev, "probe failed\n");
return -ENODEV;
}
+#ifndef CONFIG_ARCH_LAYERSCAPE
match = of_match_device(of_match_ptr(pca954x_of_match), &client->dev);
if (match)
data->chip = of_device_get_match_data(&client->dev);
@@ -252,6 +287,7 @@ static int pca954x_probe(struct i2c_client *client,
data->chip = &chips[id->driver_data];
data->last_chan = 0; /* force the first selection */
+#endif
idle_disconnect_dt = of_node &&
of_property_read_bool(of_node, "i2c-mux-idle-disconnect");
@@ -312,6 +348,13 @@ static int pca954x_resume(struct device *dev)
struct i2c_mux_core *muxc = i2c_get_clientdata(client);
struct pca954x *data = i2c_mux_priv(muxc);
+#ifdef CONFIG_ARCH_LAYERSCAPE
+ if (data->disable_mux != 0)
+ data->last_chan = data->chip->nchans;
+ else
+ data->last_chan = 0;
+ return i2c_smbus_write_byte(client, data->disable_mux);
+#endif
data->last_chan = 0;
return i2c_smbus_write_byte(client, 0);
}
--
2.14.1

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,182 @@
From 1d596855b596db88f10b12a1be6fd19e249be170 Mon Sep 17 00:00:00 2001
From: Yangbo Lu <yangbo.lu@nxp.com>
Date: Mon, 25 Sep 2017 12:13:29 +0800
Subject: [PATCH] irqchip: support layerscape
This is a integrated patch for layerscape gic support.
Signed-off-by: Eric Auger <eric.auger@redhat.com>
Signed-off-by: Zhao Qiang <qiang.zhao@nxp.com>
Signed-off-by: Yangbo Lu <yangbo.lu@nxp.com>
---
drivers/irqchip/Makefile | 1 +
drivers/irqchip/irq-gic-v3-its.c | 1 +
include/linux/irqdomain.h | 36 ++++++++++++++++++++++++++++++++++++
kernel/irq/irqdomain.c | 39 +++++++++++++++++++++++++++++++++++++++
kernel/irq/msi.c | 4 ++--
5 files changed, 79 insertions(+), 2 deletions(-)
diff --git a/drivers/irqchip/Makefile b/drivers/irqchip/Makefile
index e4dbfc85..53d2cd54 100644
--- a/drivers/irqchip/Makefile
+++ b/drivers/irqchip/Makefile
@@ -74,3 +74,4 @@ obj-$(CONFIG_LS_SCFG_MSI) += irq-ls-scfg-msi.o
obj-$(CONFIG_EZNPS_GIC) += irq-eznps.o
obj-$(CONFIG_ARCH_ASPEED) += irq-aspeed-vic.o
obj-$(CONFIG_STM32_EXTI) += irq-stm32-exti.o
+obj-$(CONFIG_QUICC_ENGINE) += irq-qeic.o
diff --git a/drivers/irqchip/irq-gic-v3-its.c b/drivers/irqchip/irq-gic-v3-its.c
index acb9d250..2f1c8826 100644
--- a/drivers/irqchip/irq-gic-v3-its.c
+++ b/drivers/irqchip/irq-gic-v3-its.c
@@ -1659,6 +1659,7 @@ static int its_init_domain(struct fwnode_handle *handle, struct its_node *its)
inner_domain->parent = its_parent;
inner_domain->bus_token = DOMAIN_BUS_NEXUS;
+ inner_domain->flags |= IRQ_DOMAIN_FLAG_MSI_REMAP;
info->ops = &its_msi_domain_ops;
info->data = its;
inner_domain->host_data = info;
diff --git a/include/linux/irqdomain.h b/include/linux/irqdomain.h
index ffb84604..188eced6 100644
--- a/include/linux/irqdomain.h
+++ b/include/linux/irqdomain.h
@@ -183,6 +183,12 @@ enum {
/* Irq domain is an IPI domain with single virq */
IRQ_DOMAIN_FLAG_IPI_SINGLE = (1 << 3),
+ /* Irq domain implements MSIs */
+ IRQ_DOMAIN_FLAG_MSI = (1 << 4),
+
+ /* Irq domain implements MSI remapping */
+ IRQ_DOMAIN_FLAG_MSI_REMAP = (1 << 5),
+
/*
* Flags starting from IRQ_DOMAIN_FLAG_NONCORE are reserved
* for implementation specific purposes and ignored by the
@@ -216,6 +222,7 @@ struct irq_domain *irq_domain_add_legacy(struct device_node *of_node,
void *host_data);
extern struct irq_domain *irq_find_matching_fwspec(struct irq_fwspec *fwspec,
enum irq_domain_bus_token bus_token);
+extern bool irq_domain_check_msi_remap(void);
extern void irq_set_default_host(struct irq_domain *host);
extern int irq_domain_alloc_descs(int virq, unsigned int nr_irqs,
irq_hw_number_t hwirq, int node,
@@ -446,6 +453,19 @@ static inline bool irq_domain_is_ipi_single(struct irq_domain *domain)
{
return domain->flags & IRQ_DOMAIN_FLAG_IPI_SINGLE;
}
+
+static inline bool irq_domain_is_msi(struct irq_domain *domain)
+{
+ return domain->flags & IRQ_DOMAIN_FLAG_MSI;
+}
+
+static inline bool irq_domain_is_msi_remap(struct irq_domain *domain)
+{
+ return domain->flags & IRQ_DOMAIN_FLAG_MSI_REMAP;
+}
+
+extern bool irq_domain_hierarchical_is_msi_remap(struct irq_domain *domain);
+
#else /* CONFIG_IRQ_DOMAIN_HIERARCHY */
static inline void irq_domain_activate_irq(struct irq_data *data) { }
static inline void irq_domain_deactivate_irq(struct irq_data *data) { }
@@ -477,6 +497,22 @@ static inline bool irq_domain_is_ipi_single(struct irq_domain *domain)
{
return false;
}
+
+static inline bool irq_domain_is_msi(struct irq_domain *domain)
+{
+ return false;
+}
+
+static inline bool irq_domain_is_msi_remap(struct irq_domain *domain)
+{
+ return false;
+}
+
+static inline bool
+irq_domain_hierarchical_is_msi_remap(struct irq_domain *domain)
+{
+ return false;
+}
#endif /* CONFIG_IRQ_DOMAIN_HIERARCHY */
#else /* CONFIG_IRQ_DOMAIN */
diff --git a/kernel/irq/irqdomain.c b/kernel/irq/irqdomain.c
index b59e6768..31805f23 100644
--- a/kernel/irq/irqdomain.c
+++ b/kernel/irq/irqdomain.c
@@ -277,6 +277,31 @@ struct irq_domain *irq_find_matching_fwspec(struct irq_fwspec *fwspec,
}
EXPORT_SYMBOL_GPL(irq_find_matching_fwspec);
+/**
+ * irq_domain_check_msi_remap - Check whether all MSI irq domains implement
+ * IRQ remapping
+ *
+ * Return: false if any MSI irq domain does not support IRQ remapping,
+ * true otherwise (including if there is no MSI irq domain)
+ */
+bool irq_domain_check_msi_remap(void)
+{
+ struct irq_domain *h;
+ bool ret = true;
+
+ mutex_lock(&irq_domain_mutex);
+ list_for_each_entry(h, &irq_domain_list, link) {
+ if (irq_domain_is_msi(h) &&
+ !irq_domain_hierarchical_is_msi_remap(h)) {
+ ret = false;
+ break;
+ }
+ }
+ mutex_unlock(&irq_domain_mutex);
+ return ret;
+}
+EXPORT_SYMBOL_GPL(irq_domain_check_msi_remap);
+
/**
* irq_set_default_host() - Set a "default" irq domain
* @domain: default domain pointer
@@ -1408,6 +1433,20 @@ static void irq_domain_check_hierarchy(struct irq_domain *domain)
if (domain->ops->alloc)
domain->flags |= IRQ_DOMAIN_FLAG_HIERARCHY;
}
+
+/**
+ * irq_domain_hierarchical_is_msi_remap - Check if the domain or any
+ * parent has MSI remapping support
+ * @domain: domain pointer
+ */
+bool irq_domain_hierarchical_is_msi_remap(struct irq_domain *domain)
+{
+ for (; domain; domain = domain->parent) {
+ if (irq_domain_is_msi_remap(domain))
+ return true;
+ }
+ return false;
+}
#else /* CONFIG_IRQ_DOMAIN_HIERARCHY */
/**
* irq_domain_get_irq_data - Get irq_data associated with @virq and @domain
diff --git a/kernel/irq/msi.c b/kernel/irq/msi.c
index 8a3e8727..2e2b2c45 100644
--- a/kernel/irq/msi.c
+++ b/kernel/irq/msi.c
@@ -272,8 +272,8 @@ struct irq_domain *msi_create_irq_domain(struct fwnode_handle *fwnode,
if (info->flags & MSI_FLAG_USE_DEF_CHIP_OPS)
msi_domain_update_chip_ops(info);
- return irq_domain_create_hierarchy(parent, 0, 0, fwnode,
- &msi_domain_ops, info);
+ return irq_domain_create_hierarchy(parent, IRQ_DOMAIN_FLAG_MSI, 0,
+ fwnode, &msi_domain_ops, info);
}
int msi_domain_prepare_irqs(struct irq_domain *domain, struct device *dev,
--
2.14.1

View file

@ -0,0 +1,611 @@
From b31046c51c72232363711f0c623df08bf28c37e4 Mon Sep 17 00:00:00 2001
From: Yangbo Lu <yangbo.lu@nxp.com>
Date: Mon, 25 Sep 2017 12:21:30 +0800
Subject: [PATCH] mmc: layerscape support
This is a integrated patch for layerscape mmc support.
Adrian Hunter <adrian.hunter@intel.com>
Jaehoon Chung <jh80.chung@samsung.com>
Masahiro Yamada <yamada.masahiro@socionext.com>
Signed-off-by: Yangbo Lu <yangbo.lu@nxp.com>
---
drivers/mmc/host/Kconfig | 1 +
drivers/mmc/host/sdhci-esdhc.h | 52 +++++---
drivers/mmc/host/sdhci-of-esdhc.c | 251 ++++++++++++++++++++++++++++++++++++--
drivers/mmc/host/sdhci.c | 45 ++++---
drivers/mmc/host/sdhci.h | 3 +
5 files changed, 306 insertions(+), 46 deletions(-)
diff --git a/drivers/mmc/host/Kconfig b/drivers/mmc/host/Kconfig
index 5274f503..a1135a92 100644
--- a/drivers/mmc/host/Kconfig
+++ b/drivers/mmc/host/Kconfig
@@ -144,6 +144,7 @@ config MMC_SDHCI_OF_ESDHC
depends on MMC_SDHCI_PLTFM
depends on PPC || ARCH_MXC || ARCH_LAYERSCAPE
select MMC_SDHCI_IO_ACCESSORS
+ select FSL_GUTS
help
This selects the Freescale eSDHC controller support.
diff --git a/drivers/mmc/host/sdhci-esdhc.h b/drivers/mmc/host/sdhci-esdhc.h
index de132e28..98898a30 100644
--- a/drivers/mmc/host/sdhci-esdhc.h
+++ b/drivers/mmc/host/sdhci-esdhc.h
@@ -24,30 +24,46 @@
SDHCI_QUIRK_PIO_NEEDS_DELAY | \
SDHCI_QUIRK_NO_HISPD_BIT)
-#define ESDHC_PROCTL 0x28
-
-#define ESDHC_SYSTEM_CONTROL 0x2c
-#define ESDHC_CLOCK_MASK 0x0000fff0
-#define ESDHC_PREDIV_SHIFT 8
-#define ESDHC_DIVIDER_SHIFT 4
-#define ESDHC_CLOCK_PEREN 0x00000004
-#define ESDHC_CLOCK_HCKEN 0x00000002
-#define ESDHC_CLOCK_IPGEN 0x00000001
-
/* pltfm-specific */
#define ESDHC_HOST_CONTROL_LE 0x20
/*
- * P2020 interpretation of the SDHCI_HOST_CONTROL register
+ * eSDHC register definition
*/
-#define ESDHC_CTRL_4BITBUS (0x1 << 1)
-#define ESDHC_CTRL_8BITBUS (0x2 << 1)
-#define ESDHC_CTRL_BUSWIDTH_MASK (0x3 << 1)
-/* OF-specific */
-#define ESDHC_DMA_SYSCTL 0x40c
-#define ESDHC_DMA_SNOOP 0x00000040
+/* Present State Register */
+#define ESDHC_PRSSTAT 0x24
+#define ESDHC_CLOCK_STABLE 0x00000008
+
+/* Protocol Control Register */
+#define ESDHC_PROCTL 0x28
+#define ESDHC_VOLT_SEL 0x00000400
+#define ESDHC_CTRL_4BITBUS (0x1 << 1)
+#define ESDHC_CTRL_8BITBUS (0x2 << 1)
+#define ESDHC_CTRL_BUSWIDTH_MASK (0x3 << 1)
+#define ESDHC_HOST_CONTROL_RES 0x01
+
+/* System Control Register */
+#define ESDHC_SYSTEM_CONTROL 0x2c
+#define ESDHC_CLOCK_MASK 0x0000fff0
+#define ESDHC_PREDIV_SHIFT 8
+#define ESDHC_DIVIDER_SHIFT 4
+#define ESDHC_CLOCK_SDCLKEN 0x00000008
+#define ESDHC_CLOCK_PEREN 0x00000004
+#define ESDHC_CLOCK_HCKEN 0x00000002
+#define ESDHC_CLOCK_IPGEN 0x00000001
+
+/* Host Controller Capabilities Register 2 */
+#define ESDHC_CAPABILITIES_1 0x114
+
+/* Tuning Block Control Register */
+#define ESDHC_TBCTL 0x120
+#define ESDHC_TB_EN 0x00000004
-#define ESDHC_HOST_CONTROL_RES 0x01
+/* Control Register for DMA transfer */
+#define ESDHC_DMA_SYSCTL 0x40c
+#define ESDHC_PERIPHERAL_CLK_SEL 0x00080000
+#define ESDHC_FLUSH_ASYNC_FIFO 0x00040000
+#define ESDHC_DMA_SNOOP 0x00000040
#endif /* _DRIVERS_MMC_SDHCI_ESDHC_H */
diff --git a/drivers/mmc/host/sdhci-of-esdhc.c b/drivers/mmc/host/sdhci-of-esdhc.c
index 3c27401c..4b0f375b 100644
--- a/drivers/mmc/host/sdhci-of-esdhc.c
+++ b/drivers/mmc/host/sdhci-of-esdhc.c
@@ -16,8 +16,12 @@
#include <linux/err.h>
#include <linux/io.h>
#include <linux/of.h>
+#include <linux/of_address.h>
#include <linux/delay.h>
#include <linux/module.h>
+#include <linux/sys_soc.h>
+#include <linux/clk.h>
+#include <linux/ktime.h>
#include <linux/mmc/host.h>
#include "sdhci-pltfm.h"
#include "sdhci-esdhc.h"
@@ -28,8 +32,12 @@
struct sdhci_esdhc {
u8 vendor_ver;
u8 spec_ver;
+ bool quirk_incorrect_hostver;
+ unsigned int peripheral_clock;
};
+static void esdhc_clock_enable(struct sdhci_host *host, bool enable);
+
/**
* esdhc_read*_fixup - Fixup the value read from incompatible eSDHC register
* to make it compatible with SD spec.
@@ -80,6 +88,17 @@ static u32 esdhc_readl_fixup(struct sdhci_host *host,
return ret;
}
+ /*
+ * DTS properties of mmc host are used to enable each speed mode
+ * according to soc and board capability. So clean up
+ * SDR50/SDR104/DDR50 support bits here.
+ */
+ if (spec_reg == SDHCI_CAPABILITIES_1) {
+ ret = value & (~(SDHCI_SUPPORT_SDR50 | SDHCI_SUPPORT_SDR104 |
+ SDHCI_SUPPORT_DDR50));
+ return ret;
+ }
+
ret = value;
return ret;
}
@@ -87,6 +106,8 @@ static u32 esdhc_readl_fixup(struct sdhci_host *host,
static u16 esdhc_readw_fixup(struct sdhci_host *host,
int spec_reg, u32 value)
{
+ struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
+ struct sdhci_esdhc *esdhc = sdhci_pltfm_priv(pltfm_host);
u16 ret;
int shift = (spec_reg & 0x2) * 8;
@@ -94,6 +115,12 @@ static u16 esdhc_readw_fixup(struct sdhci_host *host,
ret = value & 0xffff;
else
ret = (value >> shift) & 0xffff;
+ /* Workaround for T4240-R1.0-R2.0 eSDHC which has incorrect
+ * vendor version and spec version information.
+ */
+ if ((spec_reg == SDHCI_HOST_VERSION) &&
+ (esdhc->quirk_incorrect_hostver))
+ ret = (VENDOR_V_23 << SDHCI_VENDOR_VER_SHIFT) | SDHCI_SPEC_200;
return ret;
}
@@ -235,7 +262,11 @@ static u32 esdhc_be_readl(struct sdhci_host *host, int reg)
u32 ret;
u32 value;
- value = ioread32be(host->ioaddr + reg);
+ if (reg == SDHCI_CAPABILITIES_1)
+ value = ioread32be(host->ioaddr + ESDHC_CAPABILITIES_1);
+ else
+ value = ioread32be(host->ioaddr + reg);
+
ret = esdhc_readl_fixup(host, reg, value);
return ret;
@@ -246,7 +277,11 @@ static u32 esdhc_le_readl(struct sdhci_host *host, int reg)
u32 ret;
u32 value;
- value = ioread32(host->ioaddr + reg);
+ if (reg == SDHCI_CAPABILITIES_1)
+ value = ioread32(host->ioaddr + ESDHC_CAPABILITIES_1);
+ else
+ value = ioread32(host->ioaddr + reg);
+
ret = esdhc_readl_fixup(host, reg, value);
return ret;
@@ -404,15 +439,25 @@ static int esdhc_of_enable_dma(struct sdhci_host *host)
static unsigned int esdhc_of_get_max_clock(struct sdhci_host *host)
{
struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
+ struct sdhci_esdhc *esdhc = sdhci_pltfm_priv(pltfm_host);
- return pltfm_host->clock;
+ if (esdhc->peripheral_clock)
+ return esdhc->peripheral_clock;
+ else
+ return pltfm_host->clock;
}
static unsigned int esdhc_of_get_min_clock(struct sdhci_host *host)
{
struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
+ struct sdhci_esdhc *esdhc = sdhci_pltfm_priv(pltfm_host);
+ unsigned int clock;
- return pltfm_host->clock / 256 / 16;
+ if (esdhc->peripheral_clock)
+ clock = esdhc->peripheral_clock;
+ else
+ clock = pltfm_host->clock;
+ return clock / 256 / 16;
}
static void esdhc_of_set_clock(struct sdhci_host *host, unsigned int clock)
@@ -421,17 +466,34 @@ static void esdhc_of_set_clock(struct sdhci_host *host, unsigned int clock)
struct sdhci_esdhc *esdhc = sdhci_pltfm_priv(pltfm_host);
int pre_div = 1;
int div = 1;
+ ktime_t timeout;
u32 temp;
host->mmc->actual_clock = 0;
- if (clock == 0)
+ if (clock == 0) {
+ esdhc_clock_enable(host, false);
return;
+ }
/* Workaround to start pre_div at 2 for VNN < VENDOR_V_23 */
if (esdhc->vendor_ver < VENDOR_V_23)
pre_div = 2;
+ /*
+ * Limit SD clock to 167MHz for ls1046a according to its datasheet
+ */
+ if (clock > 167000000 &&
+ of_find_compatible_node(NULL, NULL, "fsl,ls1046a-esdhc"))
+ clock = 167000000;
+
+ /*
+ * Limit SD clock to 125MHz for ls1012a according to its datasheet
+ */
+ if (clock > 125000000 &&
+ of_find_compatible_node(NULL, NULL, "fsl,ls1012a-esdhc"))
+ clock = 125000000;
+
/* Workaround to reduce the clock frequency for p1010 esdhc */
if (of_find_compatible_node(NULL, NULL, "fsl,p1010-esdhc")) {
if (clock > 20000000)
@@ -441,8 +503,8 @@ static void esdhc_of_set_clock(struct sdhci_host *host, unsigned int clock)
}
temp = sdhci_readl(host, ESDHC_SYSTEM_CONTROL);
- temp &= ~(ESDHC_CLOCK_IPGEN | ESDHC_CLOCK_HCKEN | ESDHC_CLOCK_PEREN
- | ESDHC_CLOCK_MASK);
+ temp &= ~(ESDHC_CLOCK_SDCLKEN | ESDHC_CLOCK_IPGEN | ESDHC_CLOCK_HCKEN |
+ ESDHC_CLOCK_PEREN | ESDHC_CLOCK_MASK);
sdhci_writel(host, temp, ESDHC_SYSTEM_CONTROL);
while (host->max_clk / pre_div / 16 > clock && pre_div < 256)
@@ -462,7 +524,20 @@ static void esdhc_of_set_clock(struct sdhci_host *host, unsigned int clock)
| (div << ESDHC_DIVIDER_SHIFT)
| (pre_div << ESDHC_PREDIV_SHIFT));
sdhci_writel(host, temp, ESDHC_SYSTEM_CONTROL);
- mdelay(1);
+
+ /* Wait max 20 ms */
+ timeout = ktime_add_ms(ktime_get(), 20);
+ while (!(sdhci_readl(host, ESDHC_PRSSTAT) & ESDHC_CLOCK_STABLE)) {
+ if (ktime_after(ktime_get(), timeout)) {
+ pr_err("%s: Internal clock never stabilised.\n",
+ mmc_hostname(host->mmc));
+ return;
+ }
+ udelay(10);
+ }
+
+ temp |= ESDHC_CLOCK_SDCLKEN;
+ sdhci_writel(host, temp, ESDHC_SYSTEM_CONTROL);
}
static void esdhc_pltfm_set_bus_width(struct sdhci_host *host, int width)
@@ -487,6 +562,33 @@ static void esdhc_pltfm_set_bus_width(struct sdhci_host *host, int width)
sdhci_writel(host, ctrl, ESDHC_PROCTL);
}
+static void esdhc_clock_enable(struct sdhci_host *host, bool enable)
+{
+ u32 val;
+ ktime_t timeout;
+
+ val = sdhci_readl(host, ESDHC_SYSTEM_CONTROL);
+
+ if (enable)
+ val |= ESDHC_CLOCK_SDCLKEN;
+ else
+ val &= ~ESDHC_CLOCK_SDCLKEN;
+
+ sdhci_writel(host, val, ESDHC_SYSTEM_CONTROL);
+
+ /* Wait max 20 ms */
+ timeout = ktime_add_ms(ktime_get(), 20);
+ val = ESDHC_CLOCK_STABLE;
+ while (!(sdhci_readl(host, ESDHC_PRSSTAT) & val)) {
+ if (ktime_after(ktime_get(), timeout)) {
+ pr_err("%s: Internal clock never stabilised.\n",
+ mmc_hostname(host->mmc));
+ break;
+ }
+ udelay(10);
+ }
+}
+
static void esdhc_reset(struct sdhci_host *host, u8 mask)
{
sdhci_reset(host, mask);
@@ -495,6 +597,95 @@ static void esdhc_reset(struct sdhci_host *host, u8 mask)
sdhci_writel(host, host->ier, SDHCI_SIGNAL_ENABLE);
}
+/* The SCFG, Supplemental Configuration Unit, provides SoC specific
+ * configuration and status registers for the device. There is a
+ * SDHC IO VSEL control register on SCFG for some platforms. It's
+ * used to support SDHC IO voltage switching.
+ */
+static const struct of_device_id scfg_device_ids[] = {
+ { .compatible = "fsl,t1040-scfg", },
+ { .compatible = "fsl,ls1012a-scfg", },
+ { .compatible = "fsl,ls1046a-scfg", },
+ {}
+};
+
+/* SDHC IO VSEL control register definition */
+#define SCFG_SDHCIOVSELCR 0x408
+#define SDHCIOVSELCR_TGLEN 0x80000000
+#define SDHCIOVSELCR_VSELVAL 0x60000000
+#define SDHCIOVSELCR_SDHC_VS 0x00000001
+
+static int esdhc_signal_voltage_switch(struct mmc_host *mmc,
+ struct mmc_ios *ios)
+{
+ struct sdhci_host *host = mmc_priv(mmc);
+ struct device_node *scfg_node;
+ void __iomem *scfg_base = NULL;
+ u32 sdhciovselcr;
+ u32 val;
+
+ /*
+ * Signal Voltage Switching is only applicable for Host Controllers
+ * v3.00 and above.
+ */
+ if (host->version < SDHCI_SPEC_300)
+ return 0;
+
+ val = sdhci_readl(host, ESDHC_PROCTL);
+
+ switch (ios->signal_voltage) {
+ case MMC_SIGNAL_VOLTAGE_330:
+ val &= ~ESDHC_VOLT_SEL;
+ sdhci_writel(host, val, ESDHC_PROCTL);
+ return 0;
+ case MMC_SIGNAL_VOLTAGE_180:
+ scfg_node = of_find_matching_node(NULL, scfg_device_ids);
+ if (scfg_node)
+ scfg_base = of_iomap(scfg_node, 0);
+ if (scfg_base) {
+ sdhciovselcr = SDHCIOVSELCR_TGLEN |
+ SDHCIOVSELCR_VSELVAL;
+ iowrite32be(sdhciovselcr,
+ scfg_base + SCFG_SDHCIOVSELCR);
+
+ val |= ESDHC_VOLT_SEL;
+ sdhci_writel(host, val, ESDHC_PROCTL);
+ mdelay(5);
+
+ sdhciovselcr = SDHCIOVSELCR_TGLEN |
+ SDHCIOVSELCR_SDHC_VS;
+ iowrite32be(sdhciovselcr,
+ scfg_base + SCFG_SDHCIOVSELCR);
+ iounmap(scfg_base);
+ } else {
+ val |= ESDHC_VOLT_SEL;
+ sdhci_writel(host, val, ESDHC_PROCTL);
+ }
+ return 0;
+ default:
+ return 0;
+ }
+}
+
+static int esdhc_execute_tuning(struct mmc_host *mmc, u32 opcode)
+{
+ struct sdhci_host *host = mmc_priv(mmc);
+ u32 val;
+
+ /* Use tuning block for tuning procedure */
+ esdhc_clock_enable(host, false);
+ val = sdhci_readl(host, ESDHC_DMA_SYSCTL);
+ val |= ESDHC_FLUSH_ASYNC_FIFO;
+ sdhci_writel(host, val, ESDHC_DMA_SYSCTL);
+
+ val = sdhci_readl(host, ESDHC_TBCTL);
+ val |= ESDHC_TB_EN;
+ sdhci_writel(host, val, ESDHC_TBCTL);
+ esdhc_clock_enable(host, true);
+
+ return sdhci_execute_tuning(mmc, opcode);
+}
+
#ifdef CONFIG_PM_SLEEP
static u32 esdhc_proctl;
static int esdhc_of_suspend(struct device *dev)
@@ -575,10 +766,19 @@ static const struct sdhci_pltfm_data sdhci_esdhc_le_pdata = {
.ops = &sdhci_esdhc_le_ops,
};
+static struct soc_device_attribute soc_incorrect_hostver[] = {
+ { .family = "QorIQ T4240", .revision = "1.0", },
+ { .family = "QorIQ T4240", .revision = "2.0", },
+ { },
+};
+
static void esdhc_init(struct platform_device *pdev, struct sdhci_host *host)
{
struct sdhci_pltfm_host *pltfm_host;
struct sdhci_esdhc *esdhc;
+ struct device_node *np;
+ struct clk *clk;
+ u32 val;
u16 host_ver;
pltfm_host = sdhci_priv(host);
@@ -588,6 +788,36 @@ static void esdhc_init(struct platform_device *pdev, struct sdhci_host *host)
esdhc->vendor_ver = (host_ver & SDHCI_VENDOR_VER_MASK) >>
SDHCI_VENDOR_VER_SHIFT;
esdhc->spec_ver = host_ver & SDHCI_SPEC_VER_MASK;
+ if (soc_device_match(soc_incorrect_hostver))
+ esdhc->quirk_incorrect_hostver = true;
+ else
+ esdhc->quirk_incorrect_hostver = false;
+
+ np = pdev->dev.of_node;
+ clk = of_clk_get(np, 0);
+ if (!IS_ERR(clk)) {
+ /*
+ * esdhc->peripheral_clock would be assigned with a value
+ * which is eSDHC base clock when use periperal clock.
+ * For ls1046a, the clock value got by common clk API is
+ * peripheral clock while the eSDHC base clock is 1/2
+ * peripheral clock.
+ */
+ if (of_device_is_compatible(np, "fsl,ls1046a-esdhc"))
+ esdhc->peripheral_clock = clk_get_rate(clk) / 2;
+ else
+ esdhc->peripheral_clock = clk_get_rate(clk);
+
+ clk_put(clk);
+ }
+
+ if (esdhc->peripheral_clock) {
+ esdhc_clock_enable(host, false);
+ val = sdhci_readl(host, ESDHC_DMA_SYSCTL);
+ val |= ESDHC_PERIPHERAL_CLK_SEL;
+ sdhci_writel(host, val, ESDHC_DMA_SYSCTL);
+ esdhc_clock_enable(host, true);
+ }
}
static int sdhci_esdhc_probe(struct platform_device *pdev)
@@ -610,6 +840,11 @@ static int sdhci_esdhc_probe(struct platform_device *pdev)
if (IS_ERR(host))
return PTR_ERR(host);
+ host->mmc_host_ops.start_signal_voltage_switch =
+ esdhc_signal_voltage_switch;
+ host->mmc_host_ops.execute_tuning = esdhc_execute_tuning;
+ host->tuning_delay = 1;
+
esdhc_init(pdev, host);
sdhci_get_of_property(pdev);
diff --git a/drivers/mmc/host/sdhci.c b/drivers/mmc/host/sdhci.c
index 7d275e72..099c3bf5 100644
--- a/drivers/mmc/host/sdhci.c
+++ b/drivers/mmc/host/sdhci.c
@@ -1624,26 +1624,24 @@ static void sdhci_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
ctrl = sdhci_readb(host, SDHCI_HOST_CONTROL);
- if ((ios->timing == MMC_TIMING_SD_HS ||
- ios->timing == MMC_TIMING_MMC_HS)
- && !(host->quirks & SDHCI_QUIRK_NO_HISPD_BIT))
- ctrl |= SDHCI_CTRL_HISPD;
- else
- ctrl &= ~SDHCI_CTRL_HISPD;
+ if (!(host->quirks & SDHCI_QUIRK_NO_HISPD_BIT)) {
+ if ((ios->timing == MMC_TIMING_SD_HS ||
+ ios->timing == MMC_TIMING_MMC_HS ||
+ ios->timing == MMC_TIMING_MMC_HS400 ||
+ ios->timing == MMC_TIMING_MMC_HS200 ||
+ ios->timing == MMC_TIMING_MMC_DDR52 ||
+ ios->timing == MMC_TIMING_UHS_SDR50 ||
+ ios->timing == MMC_TIMING_UHS_SDR104 ||
+ ios->timing == MMC_TIMING_UHS_DDR50 ||
+ ios->timing == MMC_TIMING_UHS_SDR25))
+ ctrl |= SDHCI_CTRL_HISPD;
+ else
+ ctrl &= ~SDHCI_CTRL_HISPD;
+ }
if (host->version >= SDHCI_SPEC_300) {
u16 clk, ctrl_2;
- /* In case of UHS-I modes, set High Speed Enable */
- if ((ios->timing == MMC_TIMING_MMC_HS400) ||
- (ios->timing == MMC_TIMING_MMC_HS200) ||
- (ios->timing == MMC_TIMING_MMC_DDR52) ||
- (ios->timing == MMC_TIMING_UHS_SDR50) ||
- (ios->timing == MMC_TIMING_UHS_SDR104) ||
- (ios->timing == MMC_TIMING_UHS_DDR50) ||
- (ios->timing == MMC_TIMING_UHS_SDR25))
- ctrl |= SDHCI_CTRL_HISPD;
-
if (!host->preset_enabled) {
sdhci_writeb(host, ctrl, SDHCI_HOST_CONTROL);
/*
@@ -1956,7 +1954,7 @@ static int sdhci_prepare_hs400_tuning(struct mmc_host *mmc, struct mmc_ios *ios)
return 0;
}
-static int sdhci_execute_tuning(struct mmc_host *mmc, u32 opcode)
+int sdhci_execute_tuning(struct mmc_host *mmc, u32 opcode)
{
struct sdhci_host *host = mmc_priv(mmc);
u16 ctrl;
@@ -2015,6 +2013,9 @@ static int sdhci_execute_tuning(struct mmc_host *mmc, u32 opcode)
return err;
}
+ if (host->tuning_delay < 0)
+ host->tuning_delay = opcode == MMC_SEND_TUNING_BLOCK;
+
ctrl = sdhci_readw(host, SDHCI_HOST_CONTROL2);
ctrl |= SDHCI_CTRL_EXEC_TUNING;
if (host->quirks2 & SDHCI_QUIRK2_TUNING_WORK_AROUND)
@@ -2127,9 +2128,10 @@ static int sdhci_execute_tuning(struct mmc_host *mmc, u32 opcode)
ctrl = sdhci_readw(host, SDHCI_HOST_CONTROL2);
- /* eMMC spec does not require a delay between tuning cycles */
- if (opcode == MMC_SEND_TUNING_BLOCK)
- mdelay(1);
+ /* Spec does not require a delay between tuning cycles */
+ if (host->tuning_delay > 0)
+ mdelay(host->tuning_delay);
+
} while (ctrl & SDHCI_CTRL_EXEC_TUNING);
/*
@@ -2165,6 +2167,7 @@ static int sdhci_execute_tuning(struct mmc_host *mmc, u32 opcode)
spin_unlock_irqrestore(&host->lock, flags);
return err;
}
+EXPORT_SYMBOL_GPL(sdhci_execute_tuning);
static int sdhci_select_drive_strength(struct mmc_card *card,
unsigned int max_dtr, int host_drv,
@@ -2997,6 +3000,8 @@ struct sdhci_host *sdhci_alloc_host(struct device *dev,
host->flags = SDHCI_SIGNALING_330;
+ host->tuning_delay = -1;
+
return host;
}
diff --git a/drivers/mmc/host/sdhci.h b/drivers/mmc/host/sdhci.h
index 2570455b..088bed43 100644
--- a/drivers/mmc/host/sdhci.h
+++ b/drivers/mmc/host/sdhci.h
@@ -524,6 +524,8 @@ struct sdhci_host {
#define SDHCI_TUNING_MODE_1 0
#define SDHCI_TUNING_MODE_2 1
#define SDHCI_TUNING_MODE_3 2
+ /* Delay (ms) between tuning commands */
+ int tuning_delay;
unsigned long private[0] ____cacheline_aligned;
};
@@ -689,6 +691,7 @@ void sdhci_set_power_noreg(struct sdhci_host *host, unsigned char mode,
void sdhci_set_bus_width(struct sdhci_host *host, int width);
void sdhci_reset(struct sdhci_host *host, u8 mask);
void sdhci_set_uhs_signaling(struct sdhci_host *host, unsigned timing);
+int sdhci_execute_tuning(struct mmc_host *mmc, u32 opcode);
#ifdef CONFIG_PM
extern int sdhci_suspend_host(struct sdhci_host *host);
--
2.14.1

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,688 @@
From 7e7944c484954ff7b5d53047194e59bfffd1540a Mon Sep 17 00:00:00 2001
From: Yangbo Lu <yangbo.lu@nxp.com>
Date: Mon, 25 Sep 2017 12:20:55 +0800
Subject: [PATCH] rtc: support layerscape
This is a integrated patch for layerscape rtc support.
Signed-off-by: Zhang Ying-22455 <ying.zhang22455@nxp.com>
Signed-off-by: Yangbo Lu <yangbo.lu@nxp.com>
---
drivers/rtc/rtc-pcf85263.c | 665 +++++++++++++++++++++++++++++++++++++++++++++
1 file changed, 665 insertions(+)
create mode 100644 drivers/rtc/rtc-pcf85263.c
diff --git a/drivers/rtc/rtc-pcf85263.c b/drivers/rtc/rtc-pcf85263.c
new file mode 100644
index 00000000..629c2840
--- /dev/null
+++ b/drivers/rtc/rtc-pcf85263.c
@@ -0,0 +1,665 @@
+/*
+ * rtc-pcf85263 Driver for the NXP PCF85263 RTC
+ * Copyright 2016 Parkeon
+ *
+ * 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/module.h>
+#include <linux/mutex.h>
+#include <linux/rtc.h>
+#include <linux/i2c.h>
+#include <linux/bcd.h>
+#include <linux/of.h>
+#include <linux/of_device.h>
+#include <linux/regmap.h>
+
+
+#define DRV_NAME "rtc-pcf85263"
+
+/* Quartz capacitance */
+#define PCF85263_QUARTZCAP_7pF 0
+#define PCF85263_QUARTZCAP_6pF 1
+#define PCF85263_QUARTZCAP_12p5pF 2
+
+/* Quartz drive strength */
+#define PCF85263_QUARTZDRIVE_NORMAL 0
+#define PCF85263_QUARTZDRIVE_LOW 1
+#define PCF85263_QUARTZDRIVE_HIGH 2
+
+
+#define PCF85263_REG_RTC_SC 0x01 /* Seconds */
+#define PCF85263_REG_RTC_SC_OS BIT(7) /* Oscilator stopped flag */
+
+#define PCF85263_REG_RTC_MN 0x02 /* Minutes */
+#define PCF85263_REG_RTC_HR 0x03 /* Hours */
+#define PCF85263_REG_RTC_DT 0x04 /* Day of month 1-31 */
+#define PCF85263_REG_RTC_DW 0x05 /* Day of week 0-6 */
+#define PCF85263_REG_RTC_MO 0x06 /* Month 1-12 */
+#define PCF85263_REG_RTC_YR 0x07 /* Year 0-99 */
+
+#define PCF85263_REG_ALM1_SC 0x08 /* Seconds */
+#define PCF85263_REG_ALM1_MN 0x09 /* Minutes */
+#define PCF85263_REG_ALM1_HR 0x0a /* Hours */
+#define PCF85263_REG_ALM1_DT 0x0b /* Day of month 1-31 */
+#define PCF85263_REG_ALM1_MO 0x0c /* Month 1-12 */
+
+#define PCF85263_REG_ALM_CTL 0x10
+#define PCF85263_REG_ALM_CTL_ALL_A1E 0x1f /* sec,min,hr,day,mon alarm 1 */
+
+#define PCF85263_REG_OSC 0x25
+#define PCF85263_REG_OSC_CL_MASK (BIT(0) | BIT(1))
+#define PCF85263_REG_OSC_CL_SHIFT 0
+#define PCF85263_REG_OSC_OSCD_MASK (BIT(2) | BIT(3))
+#define PCF85263_REG_OSC_OSCD_SHIFT 2
+#define PCF85263_REG_OSC_LOWJ BIT(4)
+#define PCF85263_REG_OSC_12H BIT(5)
+
+#define PCF85263_REG_PINIO 0x27
+#define PCF85263_REG_PINIO_INTAPM_MASK (BIT(0) | BIT(1))
+#define PCF85263_REG_PINIO_INTAPM_SHIFT 0
+#define PCF85263_INTAPM_INTA (0x2 << PCF85263_REG_PINIO_INTAPM_SHIFT)
+#define PCF85263_INTAPM_HIGHZ (0x3 << PCF85263_REG_PINIO_INTAPM_SHIFT)
+#define PCF85263_REG_PINIO_TSPM_MASK (BIT(2) | BIT(3))
+#define PCF85263_REG_PINIO_TSPM_SHIFT 2
+#define PCF85263_TSPM_DISABLED (0x0 << PCF85263_REG_PINIO_TSPM_SHIFT)
+#define PCF85263_TSPM_INTB (0x1 << PCF85263_REG_PINIO_TSPM_SHIFT)
+#define PCF85263_REG_PINIO_CLKDISABLE BIT(7)
+
+#define PCF85263_REG_FUNCTION 0x28
+#define PCF85263_REG_FUNCTION_COF_MASK 0x7
+#define PCF85263_REG_FUNCTION_COF_OFF 0x7 /* No clock output */
+
+#define PCF85263_REG_INTA_CTL 0x29
+#define PCF85263_REG_INTB_CTL 0x2A
+#define PCF85263_REG_INTx_CTL_A1E BIT(4) /* Alarm 1 */
+#define PCF85263_REG_INTx_CTL_ILP BIT(7) /* 0=pulse, 1=level */
+
+#define PCF85263_REG_FLAGS 0x2B
+#define PCF85263_REG_FLAGS_A1F BIT(5)
+
+#define PCF85263_REG_RAM_BYTE 0x2c
+
+#define PCF85263_REG_STOPENABLE 0x2e
+#define PCF85263_REG_STOPENABLE_STOP BIT(0)
+
+#define PCF85263_REG_RESET 0x2f /* Reset command */
+#define PCF85263_REG_RESET_CMD_CPR 0xa4 /* Clear prescaler */
+
+#define PCF85263_MAX_REG 0x2f
+
+#define PCF85263_HR_PM BIT(5)
+
+enum pcf85263_irqpin {
+ PCF85263_IRQPIN_NONE,
+ PCF85263_IRQPIN_INTA,
+ PCF85263_IRQPIN_INTB
+};
+
+static const char *const pcf85263_irqpin_names[] = {
+ [PCF85263_IRQPIN_NONE] = "None",
+ [PCF85263_IRQPIN_INTA] = "INTA",
+ [PCF85263_IRQPIN_INTB] = "INTB"
+};
+
+struct pcf85263 {
+ struct device *dev;
+ struct rtc_device *rtc;
+ struct regmap *regmap;
+ enum pcf85263_irqpin irq_pin;
+ int irq;
+ bool mode_12h;
+};
+
+/*
+ * Helpers to convert 12h to 24h and vice versa.
+ * Values in register are stored in BCD with a PM flag in bit 5
+ *
+ * 23:00 <=> 11PM <=> 0x31
+ * 00:00 <=> 12AM <=> 0x12
+ * 01:00 <=> 1AM <=> 0x01
+ * 12:00 <=> 12PM <=> 0x32
+ * 13:00 <=> 1PM <=> 0x21
+ */
+static int pcf85263_bcd12h_to_bin24h(int regval)
+{
+ int hr = bcd2bin(regval & 0x1f);
+ bool pm = regval & PCF85263_HR_PM;
+
+ if (hr == 12)
+ return pm ? 12 : 0;
+
+ return pm ? hr + 12 : hr;
+}
+
+static int pcf85263_bin24h_to_bcd12h(int hr24)
+{
+ bool pm = hr24 >= 12;
+ int hr12 = hr24 % 12;
+
+ if (!hr12)
+ hr12++;
+
+ return bin2bcd(hr12) | pm ? 0 : PCF85263_HR_PM;
+}
+
+static int pcf85263_read_time(struct device *dev, struct rtc_time *tm)
+{
+ struct pcf85263 *pcf85263 = dev_get_drvdata(dev);
+ const int first = PCF85263_REG_RTC_SC;
+ const int last = PCF85263_REG_RTC_YR;
+ const int len = last - first + 1;
+ u8 regs[len];
+ u8 hr_reg;
+ int ret;
+
+ ret = regmap_bulk_read(pcf85263->regmap, first, regs, len);
+ if (ret)
+ return ret;
+
+ if (regs[PCF85263_REG_RTC_SC - first] & PCF85263_REG_RTC_SC_OS) {
+ dev_warn(dev, "Oscillator stop detected, date/time is not reliable.\n");
+ return -EINVAL;
+ }
+
+ tm->tm_sec = bcd2bin(regs[PCF85263_REG_RTC_SC - first] & 0x7f);
+ tm->tm_min = bcd2bin(regs[PCF85263_REG_RTC_MN - first] & 0x7f);
+
+ hr_reg = regs[PCF85263_REG_RTC_HR - first];
+ if (pcf85263->mode_12h)
+ tm->tm_hour = pcf85263_bcd12h_to_bin24h(hr_reg);
+ else
+ tm->tm_hour = bcd2bin(hr_reg & 0x3f);
+
+ tm->tm_mday = bcd2bin(regs[PCF85263_REG_RTC_DT - first]);
+ tm->tm_wday = bcd2bin(regs[PCF85263_REG_RTC_DW - first]);
+ tm->tm_mon = bcd2bin(regs[PCF85263_REG_RTC_MO - first]) - 1;
+ tm->tm_year = bcd2bin(regs[PCF85263_REG_RTC_YR - first]);
+
+ tm->tm_year += 100; /* Assume 21st century */
+
+ return 0;
+}
+
+static int pcf85263_set_time(struct device *dev, struct rtc_time *tm)
+{
+ struct pcf85263 *pcf85263 = dev_get_drvdata(dev);
+
+ /*
+ * Before setting time need to stop RTC and disable prescaler
+ * Do this all in a single I2C transaction exploiting wraparound
+ * as described in data sheet.
+ * This means that the array below must be in register order
+ */
+ u8 regs[] = {
+ PCF85263_REG_STOPENABLE_STOP, /* STOP */
+ PCF85263_REG_RESET_CMD_CPR, /* Disable prescaler */
+ /* Wrap around to register 0 (1/100s) */
+ 0, /* 1/100s always zero. */
+ bin2bcd(tm->tm_sec),
+ bin2bcd(tm->tm_min),
+ bin2bcd(tm->tm_hour), /* 24-hour */
+ bin2bcd(tm->tm_mday),
+ bin2bcd(tm->tm_wday + 1),
+ bin2bcd(tm->tm_mon + 1),
+ bin2bcd(tm->tm_year % 100)
+ };
+ int ret;
+
+ ret = regmap_bulk_write(pcf85263->regmap, PCF85263_REG_STOPENABLE,
+ regs, sizeof(regs));
+ if (ret)
+ return ret;
+
+ /* As we have set the time in 24H update the hardware for that */
+ if (pcf85263->mode_12h) {
+ pcf85263->mode_12h = false;
+ ret = regmap_update_bits(pcf85263->regmap, PCF85263_REG_OSC,
+ PCF85263_REG_OSC_12H, 0);
+ if (ret)
+ return ret;
+ }
+
+ /* Start it again */
+ return regmap_write(pcf85263->regmap, PCF85263_REG_STOPENABLE, 0);
+}
+
+static int pcf85263_enable_alarm(struct pcf85263 *pcf85263, bool enable)
+{
+ int reg;
+ int ret;
+
+ ret = regmap_update_bits(pcf85263->regmap, PCF85263_REG_ALM_CTL,
+ PCF85263_REG_ALM_CTL_ALL_A1E,
+ enable ? PCF85263_REG_ALM_CTL_ALL_A1E : 0);
+ if (ret)
+ return ret;
+
+ switch (pcf85263->irq_pin) {
+ case PCF85263_IRQPIN_NONE:
+ return 0;
+
+ case PCF85263_IRQPIN_INTA:
+ reg = PCF85263_REG_INTA_CTL;
+ break;
+
+ case PCF85263_IRQPIN_INTB:
+ reg = PCF85263_REG_INTB_CTL;
+ break;
+
+ default:
+ return -EINVAL;
+ }
+
+ return regmap_update_bits(pcf85263->regmap, reg,
+ PCF85263_REG_INTx_CTL_A1E,
+ enable ? PCF85263_REG_INTx_CTL_A1E : 0);
+}
+
+static int pcf85263_read_alarm(struct device *dev, struct rtc_wkalrm *alarm)
+{
+ struct pcf85263 *pcf85263 = dev_get_drvdata(dev);
+ struct rtc_time *tm = &alarm->time;
+ const int first = PCF85263_REG_ALM1_SC;
+ const int last = PCF85263_REG_ALM1_MO;
+ const int len = last - first + 1;
+ u8 regs[len];
+ u8 hr_reg;
+ unsigned int regval;
+ int ret;
+
+ ret = regmap_bulk_read(pcf85263->regmap, first, regs, len);
+ if (ret)
+ return ret;
+
+ tm->tm_sec = bcd2bin(regs[PCF85263_REG_ALM1_SC - first] & 0x7f);
+ tm->tm_min = bcd2bin(regs[PCF85263_REG_ALM1_MN - first] & 0x7f);
+
+ hr_reg = regs[PCF85263_REG_ALM1_HR - first];
+ if (pcf85263->mode_12h)
+ tm->tm_hour = pcf85263_bcd12h_to_bin24h(hr_reg);
+ else
+ tm->tm_hour = bcd2bin(hr_reg & 0x3f);
+
+ tm->tm_mday = bcd2bin(regs[PCF85263_REG_ALM1_DT - first]);
+ tm->tm_mon = bcd2bin(regs[PCF85263_REG_ALM1_MO - first]) - 1;
+ tm->tm_year = -1;
+ tm->tm_wday = -1;
+
+ ret = regmap_read(pcf85263->regmap, PCF85263_REG_ALM_CTL, &regval);
+ if (ret)
+ return ret;
+ alarm->enabled = !!(regval & PCF85263_REG_ALM_CTL_ALL_A1E);
+
+ ret = regmap_read(pcf85263->regmap, PCF85263_REG_FLAGS, &regval);
+ if (ret)
+ return ret;
+ alarm->pending = !!(regval & PCF85263_REG_FLAGS_A1F);
+
+ return 0;
+}
+
+static int pcf85263_set_alarm(struct device *dev, struct rtc_wkalrm *alarm)
+{
+ struct pcf85263 *pcf85263 = dev_get_drvdata(dev);
+ struct rtc_time *tm = &alarm->time;
+ const int first = PCF85263_REG_ALM1_SC;
+ const int last = PCF85263_REG_ALM1_MO;
+ const int len = last - first + 1;
+ u8 regs[len];
+ int ret;
+
+ /* Disable alarm comparison during update */
+ ret = pcf85263_enable_alarm(pcf85263, false);
+ if (ret)
+ return ret;
+
+ /* Clear any pending alarm (write 0=>clr, 1=>no change) */
+ ret = regmap_write(pcf85263->regmap, PCF85263_REG_FLAGS,
+ (unsigned int)(~PCF85263_REG_FLAGS_A1F));
+ if (ret)
+ return ret;
+
+ /* Set the alarm time registers */
+ regs[PCF85263_REG_ALM1_SC - first] = bin2bcd(tm->tm_sec);
+ regs[PCF85263_REG_ALM1_MN - first] = bin2bcd(tm->tm_min);
+ regs[PCF85263_REG_ALM1_HR - first] = pcf85263->mode_12h ?
+ pcf85263_bin24h_to_bcd12h(tm->tm_hour) :
+ bin2bcd(tm->tm_hour);
+ regs[PCF85263_REG_ALM1_DT - first] = bin2bcd(tm->tm_mday);
+ regs[PCF85263_REG_ALM1_MO - first] = bin2bcd(tm->tm_mon + 1);
+
+ ret = regmap_bulk_write(pcf85263->regmap, first, regs, sizeof(regs));
+ if (ret)
+ return ret;
+
+ if (alarm->enabled)
+ ret = pcf85263_enable_alarm(pcf85263, true);
+
+ return ret;
+}
+
+static int pcf85263_alarm_irq_enable(struct device *dev, unsigned int enable)
+{
+ struct pcf85263 *pcf85263 = dev_get_drvdata(dev);
+
+ return pcf85263_enable_alarm(pcf85263, !!enable);
+}
+
+static irqreturn_t pcf85263_irq(int irq, void *data)
+{
+ struct pcf85263 *pcf85263 = data;
+ unsigned int regval;
+ int ret;
+
+ ret = regmap_read(pcf85263->regmap, PCF85263_REG_FLAGS, &regval);
+ if (ret)
+ return IRQ_NONE;
+
+ if (regval & PCF85263_REG_FLAGS_A1F) {
+ regmap_write(pcf85263->regmap, PCF85263_REG_FLAGS,
+ (unsigned int)(~PCF85263_REG_FLAGS_A1F));
+
+ rtc_update_irq(pcf85263->rtc, 1, RTC_IRQF | RTC_AF);
+
+ return IRQ_HANDLED;
+ }
+
+ return IRQ_NONE;
+}
+
+static int pcf85263_check_osc_stopped(struct pcf85263 *pcf85263)
+{
+ unsigned int regval;
+ int ret;
+
+ ret = regmap_read(pcf85263->regmap, PCF85263_REG_RTC_SC, &regval);
+ if (ret)
+ return ret;
+
+ ret = regval & PCF85263_REG_RTC_SC_OS ? 1 : 0;
+ if (ret)
+ dev_warn(pcf85263->dev, "Oscillator stop detected, date/time is not reliable.\n");
+
+ return ret;
+}
+
+#ifdef CONFIG_RTC_INTF_DEV
+static int pcf85263_ioctl(struct device *dev,
+ unsigned int cmd, unsigned long arg)
+{
+ struct pcf85263 *pcf85263 = dev_get_drvdata(dev);
+ int ret;
+
+ switch (cmd) {
+ case RTC_VL_READ:
+ ret = pcf85263_check_osc_stopped(pcf85263);
+ if (ret < 0)
+ return ret;
+
+ if (copy_to_user((void __user *)arg, &ret, sizeof(int)))
+ return -EFAULT;
+ return 0;
+
+ case RTC_VL_CLR:
+ return regmap_update_bits(pcf85263->regmap,
+ PCF85263_REG_RTC_SC,
+ PCF85263_REG_RTC_SC_OS, 0);
+ default:
+ return -ENOIOCTLCMD;
+ }
+}
+#else
+#define pcf85263_ioctl NULL
+#endif
+
+static int pcf85263_init_hw(struct pcf85263 *pcf85263)
+{
+ struct device_node *np = pcf85263->dev->of_node;
+ unsigned int regval;
+ u32 propval;
+ int ret;
+
+ /* Determine if oscilator has been stopped (probably low power) */
+ ret = pcf85263_check_osc_stopped(pcf85263);
+ if (ret < 0) {
+ /* Log here since this is the first hw access on probe */
+ dev_err(pcf85263->dev, "Unable to read register\n");
+
+ return ret;
+ }
+
+ /* Determine 12/24H mode */
+ ret = regmap_read(pcf85263->regmap, PCF85263_REG_OSC, &regval);
+ if (ret)
+ return ret;
+ pcf85263->mode_12h = !!(regval & PCF85263_REG_OSC_12H);
+
+ /* Set oscilator register */
+ regval &= ~PCF85263_REG_OSC_12H; /* keep current 12/24 h setting */
+
+ propval = PCF85263_QUARTZCAP_12p5pF;
+ of_property_read_u32(np, "quartz-load-capacitance", &propval);
+ regval |= ((propval << PCF85263_REG_OSC_CL_SHIFT)
+ & PCF85263_REG_OSC_CL_MASK);
+
+ propval = PCF85263_QUARTZDRIVE_NORMAL;
+ of_property_read_u32(np, "quartz-drive-strength", &propval);
+ regval |= ((propval << PCF85263_REG_OSC_OSCD_SHIFT)
+ & PCF85263_REG_OSC_OSCD_MASK);
+
+ if (of_property_read_bool(np, "quartz-low-jitter"))
+ regval |= PCF85263_REG_OSC_LOWJ;
+
+ ret = regmap_write(pcf85263->regmap, PCF85263_REG_OSC, regval);
+ if (ret)
+ return ret;
+
+ /* Set function register (RTC mode, 1s tick, clock output static) */
+ ret = regmap_write(pcf85263->regmap, PCF85263_REG_FUNCTION,
+ PCF85263_REG_FUNCTION_COF_OFF);
+ if (ret)
+ return ret;
+
+ /* Set all interrupts to disabled, level mode */
+ ret = regmap_write(pcf85263->regmap, PCF85263_REG_INTA_CTL,
+ PCF85263_REG_INTx_CTL_ILP);
+ if (ret)
+ return ret;
+ ret = regmap_write(pcf85263->regmap, PCF85263_REG_INTB_CTL,
+ PCF85263_REG_INTx_CTL_ILP);
+ if (ret)
+ return ret;
+
+ /* Setup IO pin config register */
+ regval = PCF85263_REG_PINIO_CLKDISABLE;
+ switch (pcf85263->irq_pin) {
+ case PCF85263_IRQPIN_INTA:
+ regval |= (PCF85263_INTAPM_INTA | PCF85263_TSPM_DISABLED);
+ break;
+ case PCF85263_IRQPIN_INTB:
+ regval |= (PCF85263_INTAPM_HIGHZ | PCF85263_TSPM_INTB);
+ break;
+ case PCF85263_IRQPIN_NONE:
+ regval |= (PCF85263_INTAPM_HIGHZ | PCF85263_TSPM_DISABLED);
+ break;
+ }
+ ret = regmap_write(pcf85263->regmap, PCF85263_REG_PINIO, regval);
+
+ return ret;
+}
+
+static const struct rtc_class_ops rtc_ops = {
+ .ioctl = pcf85263_ioctl,
+ .read_time = pcf85263_read_time,
+ .set_time = pcf85263_set_time,
+ .read_alarm = pcf85263_read_alarm,
+ .set_alarm = pcf85263_set_alarm,
+ .alarm_irq_enable = pcf85263_alarm_irq_enable,
+};
+
+static const struct regmap_config pcf85263_regmap_cfg = {
+ .reg_bits = 8,
+ .val_bits = 8,
+ .max_register = PCF85263_MAX_REG,
+};
+
+/*
+ * On some boards the interrupt line may not be wired to the CPU but only to
+ * a power supply circuit.
+ * In that case no interrupt will be specified in the device tree but the
+ * wakeup-source DT property may be used to enable wakeup programming in
+ * sysfs
+ */
+static bool pcf85263_can_wakeup_machine(struct pcf85263 *pcf85263)
+{
+ return pcf85263->irq ||
+ of_property_read_bool(pcf85263->dev->of_node, "wakeup-source");
+}
+
+static int pcf85263_probe(struct i2c_client *client,
+ const struct i2c_device_id *id)
+{
+ struct device *dev = &client->dev;
+ struct pcf85263 *pcf85263;
+ int ret;
+
+ if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C |
+ I2C_FUNC_SMBUS_BYTE_DATA |
+ I2C_FUNC_SMBUS_I2C_BLOCK))
+ return -ENODEV;
+
+ pcf85263 = devm_kzalloc(dev, sizeof(*pcf85263), GFP_KERNEL);
+ if (!pcf85263)
+ return -ENOMEM;
+
+ pcf85263->dev = dev;
+ pcf85263->irq = client->irq;
+ dev_set_drvdata(dev, pcf85263);
+
+ pcf85263->regmap = devm_regmap_init_i2c(client, &pcf85263_regmap_cfg);
+ if (IS_ERR(pcf85263->regmap)) {
+ ret = PTR_ERR(pcf85263->regmap);
+ dev_err(dev, "regmap allocation failed (%d)\n", ret);
+
+ return ret;
+ }
+
+ /* Determine which interrupt pin the board uses */
+ if (pcf85263_can_wakeup_machine(pcf85263)) {
+ if (of_property_match_string(dev->of_node,
+ "interrupt-names", "INTB") >= 0)
+ pcf85263->irq_pin = PCF85263_IRQPIN_INTB;
+ else
+ pcf85263->irq_pin = PCF85263_IRQPIN_INTA;
+ } else {
+ pcf85263->irq_pin = PCF85263_IRQPIN_NONE;
+ }
+
+ ret = pcf85263_init_hw(pcf85263);
+ if (ret)
+ return ret;
+
+ if (pcf85263->irq) {
+ ret = devm_request_threaded_irq(dev, pcf85263->irq, NULL,
+ pcf85263_irq,
+ IRQF_ONESHOT,
+ dev->driver->name, pcf85263);
+ if (ret) {
+ dev_err(dev, "irq %d unavailable (%d)\n",
+ pcf85263->irq, ret);
+ pcf85263->irq = 0;
+ }
+ }
+
+ if (pcf85263_can_wakeup_machine(pcf85263))
+ device_init_wakeup(dev, true);
+
+ pcf85263->rtc = devm_rtc_device_register(dev, dev->driver->name,
+ &rtc_ops, THIS_MODULE);
+ ret = PTR_ERR_OR_ZERO(pcf85263->rtc);
+ if (ret)
+ return ret;
+
+ /* We cannot support UIE mode if we do not have an IRQ line */
+ if (!pcf85263->irq)
+ pcf85263->rtc->uie_unsupported = 1;
+
+ dev_info(pcf85263->dev,
+ "PCF85263 RTC (irqpin=%s irq=%d)\n",
+ pcf85263_irqpin_names[pcf85263->irq_pin],
+ pcf85263->irq);
+
+ return 0;
+}
+
+static int pcf85263_remove(struct i2c_client *client)
+{
+ struct pcf85263 *pcf85263 = i2c_get_clientdata(client);
+
+ if (pcf85263_can_wakeup_machine(pcf85263))
+ device_init_wakeup(pcf85263->dev, false);
+
+ return 0;
+}
+
+#ifdef CONFIG_PM_SLEEP
+static int pcf85263_suspend(struct device *dev)
+{
+ struct pcf85263 *pcf85263 = dev_get_drvdata(dev);
+ int ret = 0;
+
+ if (device_may_wakeup(dev))
+ ret = enable_irq_wake(pcf85263->irq);
+
+ return ret;
+}
+
+static int pcf85263_resume(struct device *dev)
+{
+ struct pcf85263 *pcf85263 = dev_get_drvdata(dev);
+ int ret = 0;
+
+ if (device_may_wakeup(dev))
+ ret = disable_irq_wake(pcf85263->irq);
+
+ return ret;
+}
+
+#endif
+
+static const struct i2c_device_id pcf85263_id[] = {
+ { "pcf85263", 0 },
+ { }
+};
+MODULE_DEVICE_TABLE(i2c, pcf85263_id);
+
+#ifdef CONFIG_OF
+static const struct of_device_id pcf85263_of_match[] = {
+ { .compatible = "nxp,pcf85263" },
+ {}
+};
+MODULE_DEVICE_TABLE(of, pcf85263_of_match);
+#endif
+
+static SIMPLE_DEV_PM_OPS(pcf85263_pm_ops, pcf85263_suspend, pcf85263_resume);
+
+static struct i2c_driver pcf85263_driver = {
+ .driver = {
+ .name = "rtc-pcf85263",
+ .of_match_table = of_match_ptr(pcf85263_of_match),
+ .pm = &pcf85263_pm_ops,
+ },
+ .probe = pcf85263_probe,
+ .remove = pcf85263_remove,
+ .id_table = pcf85263_id,
+};
+
+module_i2c_driver(pcf85263_driver);
+
+MODULE_AUTHOR("Martin Fuzzey <mfuzzey@parkeon.com>");
+MODULE_DESCRIPTION("PCF85263 RTC Driver");
+MODULE_LICENSE("GPL");
+
--
2.14.1

View file

@ -0,0 +1,445 @@
From a12f522b48a8cb637c1c026b46a76b2ef7983f8d Mon Sep 17 00:00:00 2001
From: Yangbo Lu <yangbo.lu@nxp.com>
Date: Mon, 25 Sep 2017 12:12:41 +0800
Subject: [PATCH] spi: support layerscape
This is a integrated patch for layerscape dspi support.
Signed-off-by: Christophe JAILLET <christophe.jaillet@wanadoo.fr>
Signed-off-by: Sanchayan Maity <maitysanchayan@gmail.com>
Signed-off-by: Geert Uytterhoeven <geert@linux-m68k.org>
Signed-off-by: Sanchayan Maity <maitysanchayan@gmail.com>
Signed-off-by: Yangbo Lu <yangbo.lu@nxp.com>
---
drivers/spi/Kconfig | 1 +
drivers/spi/spi-fsl-dspi.c | 309 ++++++++++++++++++++++++++++++++++++++++++++-
2 files changed, 305 insertions(+), 5 deletions(-)
diff --git a/drivers/spi/Kconfig b/drivers/spi/Kconfig
index b7995474..8e281e47 100644
--- a/drivers/spi/Kconfig
+++ b/drivers/spi/Kconfig
@@ -365,6 +365,7 @@ config SPI_FSL_SPI
config SPI_FSL_DSPI
tristate "Freescale DSPI controller"
select REGMAP_MMIO
+ depends on HAS_DMA
depends on SOC_VF610 || SOC_LS1021A || ARCH_LAYERSCAPE || COMPILE_TEST
help
This enables support for the Freescale DSPI controller in master
diff --git a/drivers/spi/spi-fsl-dspi.c b/drivers/spi/spi-fsl-dspi.c
index a67b0ff6..15201645 100644
--- a/drivers/spi/spi-fsl-dspi.c
+++ b/drivers/spi/spi-fsl-dspi.c
@@ -15,6 +15,8 @@
#include <linux/clk.h>
#include <linux/delay.h>
+#include <linux/dmaengine.h>
+#include <linux/dma-mapping.h>
#include <linux/err.h>
#include <linux/errno.h>
#include <linux/interrupt.h>
@@ -40,6 +42,7 @@
#define TRAN_STATE_WORD_ODD_NUM 0x04
#define DSPI_FIFO_SIZE 4
+#define DSPI_DMA_BUFSIZE (DSPI_FIFO_SIZE * 1024)
#define SPI_MCR 0x00
#define SPI_MCR_MASTER (1 << 31)
@@ -72,6 +75,11 @@
#define SPI_SR_TCFQF 0x80000000
#define SPI_SR_CLEAR 0xdaad0000
+#define SPI_RSER_TFFFE BIT(25)
+#define SPI_RSER_TFFFD BIT(24)
+#define SPI_RSER_RFDFE BIT(17)
+#define SPI_RSER_RFDFD BIT(16)
+
#define SPI_RSER 0x30
#define SPI_RSER_EOQFE 0x10000000
#define SPI_RSER_TCFQE 0x80000000
@@ -109,6 +117,8 @@
#define SPI_TCR_TCNT_MAX 0x10000
+#define DMA_COMPLETION_TIMEOUT msecs_to_jiffies(3000)
+
struct chip_data {
u32 mcr_val;
u32 ctar_val;
@@ -118,6 +128,7 @@ struct chip_data {
enum dspi_trans_mode {
DSPI_EOQ_MODE = 0,
DSPI_TCFQ_MODE,
+ DSPI_DMA_MODE,
};
struct fsl_dspi_devtype_data {
@@ -126,7 +137,7 @@ struct fsl_dspi_devtype_data {
};
static const struct fsl_dspi_devtype_data vf610_data = {
- .trans_mode = DSPI_EOQ_MODE,
+ .trans_mode = DSPI_DMA_MODE,
.max_clock_factor = 2,
};
@@ -140,6 +151,23 @@ static const struct fsl_dspi_devtype_data ls2085a_data = {
.max_clock_factor = 8,
};
+struct fsl_dspi_dma {
+ /* Length of transfer in words of DSPI_FIFO_SIZE */
+ u32 curr_xfer_len;
+
+ u32 *tx_dma_buf;
+ struct dma_chan *chan_tx;
+ dma_addr_t tx_dma_phys;
+ struct completion cmd_tx_complete;
+ struct dma_async_tx_descriptor *tx_desc;
+
+ u32 *rx_dma_buf;
+ struct dma_chan *chan_rx;
+ dma_addr_t rx_dma_phys;
+ struct completion cmd_rx_complete;
+ struct dma_async_tx_descriptor *rx_desc;
+};
+
struct fsl_dspi {
struct spi_master *master;
struct platform_device *pdev;
@@ -166,8 +194,11 @@ struct fsl_dspi {
u32 waitflags;
u32 spi_tcnt;
+ struct fsl_dspi_dma *dma;
};
+static u32 dspi_data_to_pushr(struct fsl_dspi *dspi, int tx_word);
+
static inline int is_double_byte_mode(struct fsl_dspi *dspi)
{
unsigned int val;
@@ -177,6 +208,255 @@ static inline int is_double_byte_mode(struct fsl_dspi *dspi)
return ((val & SPI_FRAME_BITS_MASK) == SPI_FRAME_BITS(8)) ? 0 : 1;
}
+static void dspi_tx_dma_callback(void *arg)
+{
+ struct fsl_dspi *dspi = arg;
+ struct fsl_dspi_dma *dma = dspi->dma;
+
+ complete(&dma->cmd_tx_complete);
+}
+
+static void dspi_rx_dma_callback(void *arg)
+{
+ struct fsl_dspi *dspi = arg;
+ struct fsl_dspi_dma *dma = dspi->dma;
+ int rx_word;
+ int i;
+ u16 d;
+
+ rx_word = is_double_byte_mode(dspi);
+
+ if (!(dspi->dataflags & TRAN_STATE_RX_VOID)) {
+ for (i = 0; i < dma->curr_xfer_len; i++) {
+ d = dspi->dma->rx_dma_buf[i];
+ rx_word ? (*(u16 *)dspi->rx = d) :
+ (*(u8 *)dspi->rx = d);
+ dspi->rx += rx_word + 1;
+ }
+ }
+
+ complete(&dma->cmd_rx_complete);
+}
+
+static int dspi_next_xfer_dma_submit(struct fsl_dspi *dspi)
+{
+ struct fsl_dspi_dma *dma = dspi->dma;
+ struct device *dev = &dspi->pdev->dev;
+ int time_left;
+ int tx_word;
+ int i;
+
+ tx_word = is_double_byte_mode(dspi);
+
+ for (i = 0; i < dma->curr_xfer_len; i++) {
+ dspi->dma->tx_dma_buf[i] = dspi_data_to_pushr(dspi, tx_word);
+ if ((dspi->cs_change) && (!dspi->len))
+ dspi->dma->tx_dma_buf[i] &= ~SPI_PUSHR_CONT;
+ }
+
+ dma->tx_desc = dmaengine_prep_slave_single(dma->chan_tx,
+ dma->tx_dma_phys,
+ dma->curr_xfer_len *
+ DMA_SLAVE_BUSWIDTH_4_BYTES,
+ DMA_MEM_TO_DEV,
+ DMA_PREP_INTERRUPT | DMA_CTRL_ACK);
+ if (!dma->tx_desc) {
+ dev_err(dev, "Not able to get desc for DMA xfer\n");
+ return -EIO;
+ }
+
+ dma->tx_desc->callback = dspi_tx_dma_callback;
+ dma->tx_desc->callback_param = dspi;
+ if (dma_submit_error(dmaengine_submit(dma->tx_desc))) {
+ dev_err(dev, "DMA submit failed\n");
+ return -EINVAL;
+ }
+
+ dma->rx_desc = dmaengine_prep_slave_single(dma->chan_rx,
+ dma->rx_dma_phys,
+ dma->curr_xfer_len *
+ DMA_SLAVE_BUSWIDTH_4_BYTES,
+ DMA_DEV_TO_MEM,
+ DMA_PREP_INTERRUPT | DMA_CTRL_ACK);
+ if (!dma->rx_desc) {
+ dev_err(dev, "Not able to get desc for DMA xfer\n");
+ return -EIO;
+ }
+
+ dma->rx_desc->callback = dspi_rx_dma_callback;
+ dma->rx_desc->callback_param = dspi;
+ if (dma_submit_error(dmaengine_submit(dma->rx_desc))) {
+ dev_err(dev, "DMA submit failed\n");
+ return -EINVAL;
+ }
+
+ reinit_completion(&dspi->dma->cmd_rx_complete);
+ reinit_completion(&dspi->dma->cmd_tx_complete);
+
+ dma_async_issue_pending(dma->chan_rx);
+ dma_async_issue_pending(dma->chan_tx);
+
+ time_left = wait_for_completion_timeout(&dspi->dma->cmd_tx_complete,
+ DMA_COMPLETION_TIMEOUT);
+ if (time_left == 0) {
+ dev_err(dev, "DMA tx timeout\n");
+ dmaengine_terminate_all(dma->chan_tx);
+ dmaengine_terminate_all(dma->chan_rx);
+ return -ETIMEDOUT;
+ }
+
+ time_left = wait_for_completion_timeout(&dspi->dma->cmd_rx_complete,
+ DMA_COMPLETION_TIMEOUT);
+ if (time_left == 0) {
+ dev_err(dev, "DMA rx timeout\n");
+ dmaengine_terminate_all(dma->chan_tx);
+ dmaengine_terminate_all(dma->chan_rx);
+ return -ETIMEDOUT;
+ }
+
+ return 0;
+}
+
+static int dspi_dma_xfer(struct fsl_dspi *dspi)
+{
+ struct fsl_dspi_dma *dma = dspi->dma;
+ struct device *dev = &dspi->pdev->dev;
+ int curr_remaining_bytes;
+ int bytes_per_buffer;
+ int word = 1;
+ int ret = 0;
+
+ if (is_double_byte_mode(dspi))
+ word = 2;
+ curr_remaining_bytes = dspi->len;
+ bytes_per_buffer = DSPI_DMA_BUFSIZE / DSPI_FIFO_SIZE;
+ while (curr_remaining_bytes) {
+ /* Check if current transfer fits the DMA buffer */
+ dma->curr_xfer_len = curr_remaining_bytes / word;
+ if (dma->curr_xfer_len > bytes_per_buffer)
+ dma->curr_xfer_len = bytes_per_buffer;
+
+ ret = dspi_next_xfer_dma_submit(dspi);
+ if (ret) {
+ dev_err(dev, "DMA transfer failed\n");
+ goto exit;
+
+ } else {
+ curr_remaining_bytes -= dma->curr_xfer_len * word;
+ if (curr_remaining_bytes < 0)
+ curr_remaining_bytes = 0;
+ }
+ }
+
+exit:
+ return ret;
+}
+
+static int dspi_request_dma(struct fsl_dspi *dspi, phys_addr_t phy_addr)
+{
+ struct fsl_dspi_dma *dma;
+ struct dma_slave_config cfg;
+ struct device *dev = &dspi->pdev->dev;
+ int ret;
+
+ dma = devm_kzalloc(dev, sizeof(*dma), GFP_KERNEL);
+ if (!dma)
+ return -ENOMEM;
+
+ dma->chan_rx = dma_request_slave_channel(dev, "rx");
+ if (!dma->chan_rx) {
+ dev_err(dev, "rx dma channel not available\n");
+ ret = -ENODEV;
+ return ret;
+ }
+
+ dma->chan_tx = dma_request_slave_channel(dev, "tx");
+ if (!dma->chan_tx) {
+ dev_err(dev, "tx dma channel not available\n");
+ ret = -ENODEV;
+ goto err_tx_channel;
+ }
+
+ dma->tx_dma_buf = dma_alloc_coherent(dev, DSPI_DMA_BUFSIZE,
+ &dma->tx_dma_phys, GFP_KERNEL);
+ if (!dma->tx_dma_buf) {
+ ret = -ENOMEM;
+ goto err_tx_dma_buf;
+ }
+
+ dma->rx_dma_buf = dma_alloc_coherent(dev, DSPI_DMA_BUFSIZE,
+ &dma->rx_dma_phys, GFP_KERNEL);
+ if (!dma->rx_dma_buf) {
+ ret = -ENOMEM;
+ goto err_rx_dma_buf;
+ }
+
+ cfg.src_addr = phy_addr + SPI_POPR;
+ cfg.dst_addr = phy_addr + SPI_PUSHR;
+ cfg.src_addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES;
+ cfg.dst_addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES;
+ cfg.src_maxburst = 1;
+ cfg.dst_maxburst = 1;
+
+ cfg.direction = DMA_DEV_TO_MEM;
+ ret = dmaengine_slave_config(dma->chan_rx, &cfg);
+ if (ret) {
+ dev_err(dev, "can't configure rx dma channel\n");
+ ret = -EINVAL;
+ goto err_slave_config;
+ }
+
+ cfg.direction = DMA_MEM_TO_DEV;
+ ret = dmaengine_slave_config(dma->chan_tx, &cfg);
+ if (ret) {
+ dev_err(dev, "can't configure tx dma channel\n");
+ ret = -EINVAL;
+ goto err_slave_config;
+ }
+
+ dspi->dma = dma;
+ init_completion(&dma->cmd_tx_complete);
+ init_completion(&dma->cmd_rx_complete);
+
+ return 0;
+
+err_slave_config:
+ dma_free_coherent(dev, DSPI_DMA_BUFSIZE,
+ dma->rx_dma_buf, dma->rx_dma_phys);
+err_rx_dma_buf:
+ dma_free_coherent(dev, DSPI_DMA_BUFSIZE,
+ dma->tx_dma_buf, dma->tx_dma_phys);
+err_tx_dma_buf:
+ dma_release_channel(dma->chan_tx);
+err_tx_channel:
+ dma_release_channel(dma->chan_rx);
+
+ devm_kfree(dev, dma);
+ dspi->dma = NULL;
+
+ return ret;
+}
+
+static void dspi_release_dma(struct fsl_dspi *dspi)
+{
+ struct fsl_dspi_dma *dma = dspi->dma;
+ struct device *dev = &dspi->pdev->dev;
+
+ if (dma) {
+ if (dma->chan_tx) {
+ dma_unmap_single(dev, dma->tx_dma_phys,
+ DSPI_DMA_BUFSIZE, DMA_TO_DEVICE);
+ dma_release_channel(dma->chan_tx);
+ }
+
+ if (dma->chan_rx) {
+ dma_unmap_single(dev, dma->rx_dma_phys,
+ DSPI_DMA_BUFSIZE, DMA_FROM_DEVICE);
+ dma_release_channel(dma->chan_rx);
+ }
+ }
+}
+
static void hz_to_spi_baud(char *pbr, char *br, int speed_hz,
unsigned long clkrate)
{
@@ -425,6 +705,12 @@ static int dspi_transfer_one_message(struct spi_master *master,
regmap_write(dspi->regmap, SPI_RSER, SPI_RSER_TCFQE);
dspi_tcfq_write(dspi);
break;
+ case DSPI_DMA_MODE:
+ regmap_write(dspi->regmap, SPI_RSER,
+ SPI_RSER_TFFFE | SPI_RSER_TFFFD |
+ SPI_RSER_RFDFE | SPI_RSER_RFDFD);
+ status = dspi_dma_xfer(dspi);
+ break;
default:
dev_err(&dspi->pdev->dev, "unsupported trans_mode %u\n",
trans_mode);
@@ -432,9 +718,13 @@ static int dspi_transfer_one_message(struct spi_master *master,
goto out;
}
- if (wait_event_interruptible(dspi->waitq, dspi->waitflags))
- dev_err(&dspi->pdev->dev, "wait transfer complete fail!\n");
- dspi->waitflags = 0;
+ if (trans_mode != DSPI_DMA_MODE) {
+ if (wait_event_interruptible(dspi->waitq,
+ dspi->waitflags))
+ dev_err(&dspi->pdev->dev,
+ "wait transfer complete fail!\n");
+ dspi->waitflags = 0;
+ }
if (transfer->delay_usecs)
udelay(transfer->delay_usecs);
@@ -712,7 +1002,8 @@ static int dspi_probe(struct platform_device *pdev)
if (IS_ERR(dspi->regmap)) {
dev_err(&pdev->dev, "failed to init regmap: %ld\n",
PTR_ERR(dspi->regmap));
- return PTR_ERR(dspi->regmap);
+ ret = PTR_ERR(dspi->regmap);
+ goto out_master_put;
}
dspi_init(dspi);
@@ -740,6 +1031,13 @@ static int dspi_probe(struct platform_device *pdev)
if (ret)
goto out_master_put;
+ if (dspi->devtype_data->trans_mode == DSPI_DMA_MODE) {
+ if (dspi_request_dma(dspi, res->start)) {
+ dev_err(&pdev->dev, "can't get dma channels\n");
+ goto out_clk_put;
+ }
+ }
+
master->max_speed_hz =
clk_get_rate(dspi->clk) / dspi->devtype_data->max_clock_factor;
@@ -768,6 +1066,7 @@ static int dspi_remove(struct platform_device *pdev)
struct fsl_dspi *dspi = spi_master_get_devdata(master);
/* Disconnect from the SPI framework */
+ dspi_release_dma(dspi);
clk_disable_unprepare(dspi->clk);
spi_unregister_master(dspi->master);
--
2.14.1

View file

@ -0,0 +1,163 @@
From 469daac0faff06209bc1d1390571b860d153a82b Mon Sep 17 00:00:00 2001
From: Yangbo Lu <yangbo.lu@nxp.com>
Date: Wed, 27 Sep 2017 10:33:47 +0800
Subject: [PATCH] tty: serial: support layerscape
This is a integrated patch for layerscape uart support.
Signed-off-by: Nikita Yushchenko <nikita.yoush@cogentembedded.com>
Signed-off-by: Yuan Yao <yao.yuan@nxp.com>
Signed-off-by: Stefan Agner <stefan@agner.ch>
Signed-off-by: Yangbo Lu <yangbo.lu@nxp.com>
---
drivers/tty/serial/fsl_lpuart.c | 66 ++++++++++++++++++++++++++++-------------
1 file changed, 46 insertions(+), 20 deletions(-)
diff --git a/drivers/tty/serial/fsl_lpuart.c b/drivers/tty/serial/fsl_lpuart.c
index 76103f2c..61453820 100644
--- a/drivers/tty/serial/fsl_lpuart.c
+++ b/drivers/tty/serial/fsl_lpuart.c
@@ -231,6 +231,8 @@
#define DEV_NAME "ttyLP"
#define UART_NR 6
+static DECLARE_BITMAP(linemap, UART_NR);
+
struct lpuart_port {
struct uart_port port;
struct clk *clk;
@@ -1348,6 +1350,18 @@ lpuart_set_termios(struct uart_port *port, struct ktermios *termios,
/* ask the core to calculate the divisor */
baud = uart_get_baud_rate(port, termios, old, 50, port->uartclk / 16);
+ /*
+ * Need to update the Ring buffer length according to the selected
+ * baud rate and restart Rx DMA path.
+ *
+ * Since timer function acqures sport->port.lock, need to stop before
+ * acquring same lock because otherwise del_timer_sync() can deadlock.
+ */
+ if (old && sport->lpuart_dma_rx_use) {
+ del_timer_sync(&sport->lpuart_timer);
+ lpuart_dma_rx_free(&sport->port);
+ }
+
spin_lock_irqsave(&sport->port.lock, flags);
sport->port.read_status_mask = 0;
@@ -1397,22 +1411,11 @@ lpuart_set_termios(struct uart_port *port, struct ktermios *termios,
/* restore control register */
writeb(old_cr2, sport->port.membase + UARTCR2);
- /*
- * If new baud rate is set, we will also need to update the Ring buffer
- * length according to the selected baud rate and restart Rx DMA path.
- */
- if (old) {
- if (sport->lpuart_dma_rx_use) {
- del_timer_sync(&sport->lpuart_timer);
- lpuart_dma_rx_free(&sport->port);
- }
-
- if (sport->dma_rx_chan && !lpuart_start_rx_dma(sport)) {
- sport->lpuart_dma_rx_use = true;
+ if (old && sport->lpuart_dma_rx_use) {
+ if (!lpuart_start_rx_dma(sport))
rx_dma_timer_init(sport);
- } else {
+ else
sport->lpuart_dma_rx_use = false;
- }
}
spin_unlock_irqrestore(&sport->port.lock, flags);
@@ -1640,6 +1643,13 @@ lpuart_console_write(struct console *co, const char *s, unsigned int count)
{
struct lpuart_port *sport = lpuart_ports[co->index];
unsigned char old_cr2, cr2;
+ unsigned long flags;
+ int locked = 1;
+
+ if (sport->port.sysrq || oops_in_progress)
+ locked = spin_trylock_irqsave(&sport->port.lock, flags);
+ else
+ spin_lock_irqsave(&sport->port.lock, flags);
/* first save CR2 and then disable interrupts */
cr2 = old_cr2 = readb(sport->port.membase + UARTCR2);
@@ -1654,6 +1664,9 @@ lpuart_console_write(struct console *co, const char *s, unsigned int count)
barrier();
writeb(old_cr2, sport->port.membase + UARTCR2);
+
+ if (locked)
+ spin_unlock_irqrestore(&sport->port.lock, flags);
}
static void
@@ -1661,6 +1674,13 @@ lpuart32_console_write(struct console *co, const char *s, unsigned int count)
{
struct lpuart_port *sport = lpuart_ports[co->index];
unsigned long old_cr, cr;
+ unsigned long flags;
+ int locked = 1;
+
+ if (sport->port.sysrq || oops_in_progress)
+ locked = spin_trylock_irqsave(&sport->port.lock, flags);
+ else
+ spin_lock_irqsave(&sport->port.lock, flags);
/* first save CR2 and then disable interrupts */
cr = old_cr = lpuart32_read(sport->port.membase + UARTCTRL);
@@ -1675,6 +1695,9 @@ lpuart32_console_write(struct console *co, const char *s, unsigned int count)
barrier();
lpuart32_write(old_cr, sport->port.membase + UARTCTRL);
+
+ if (locked)
+ spin_unlock_irqrestore(&sport->port.lock, flags);
}
/*
@@ -1899,9 +1922,13 @@ static int lpuart_probe(struct platform_device *pdev)
ret = of_alias_get_id(np, "serial");
if (ret < 0) {
- dev_err(&pdev->dev, "failed to get alias id, errno %d\n", ret);
- return ret;
+ ret = find_first_zero_bit(linemap, UART_NR);
+ if (ret >= UART_NR) {
+ dev_err(&pdev->dev, "port line is full, add device failed\n");
+ return ret;
+ }
}
+ set_bit(ret, linemap);
sport->port.line = ret;
sport->lpuart32 = of_device_is_compatible(np, "fsl,ls1021a-lpuart");
@@ -1983,6 +2010,7 @@ static int lpuart_remove(struct platform_device *pdev)
struct lpuart_port *sport = platform_get_drvdata(pdev);
uart_remove_one_port(&lpuart_reg, &sport->port);
+ clear_bit(sport->port.line, linemap);
clk_disable_unprepare(sport->clk);
@@ -2067,12 +2095,10 @@ static int lpuart_resume(struct device *dev)
if (sport->lpuart_dma_rx_use) {
if (sport->port.irq_wake) {
- if (!lpuart_start_rx_dma(sport)) {
- sport->lpuart_dma_rx_use = true;
+ if (!lpuart_start_rx_dma(sport))
rx_dma_timer_init(sport);
- } else {
+ else
sport->lpuart_dma_rx_use = false;
- }
}
}
--
2.14.1

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff