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>
master
Yangbo Lu 7 years ago committed by John Crispin
parent 19951bbf57
commit 8fdda1cc10
  1. 2
      target/linux/layerscape/Makefile
  2. 1461
      target/linux/layerscape/armv8_32b/config-4.9
  3. 1371
      target/linux/layerscape/armv8_64b/config-4.9
  4. 532
      target/linux/layerscape/patches-4.9/201-config-support-layerscape.patch
  5. 461
      target/linux/layerscape/patches-4.9/301-arch-support-layerscape.patch
  6. 10085
      target/linux/layerscape/patches-4.9/302-dts-support-layercape.patch
  7. 1042
      target/linux/layerscape/patches-4.9/401-mtd-spi-nor-support-layerscape.patch
  8. 412
      target/linux/layerscape/patches-4.9/402-mtd-support-layerscape.patch
  9. 2549
      target/linux/layerscape/patches-4.9/601-net-support-layerscape.patch
  10. 155005
      target/linux/layerscape/patches-4.9/701-sdk_dpaa-support-layerscape.patch
  11. 2062
      target/linux/layerscape/patches-4.9/702-pci-support-layerscape.patch
  12. 1776
      target/linux/layerscape/patches-4.9/703-phy-support-layerscape.patch
  13. 11518
      target/linux/layerscape/patches-4.9/704-fsl-mc-layerscape-support.patch
  14. 23027
      target/linux/layerscape/patches-4.9/705-dpaa2-support-layerscape.patch
  15. 149
      target/linux/layerscape/patches-4.9/801-ata-support-layerscape.patch
  16. 312
      target/linux/layerscape/patches-4.9/802-clk-support-layerscape.patch
  17. 370
      target/linux/layerscape/patches-4.9/803-cpufreq-support-layerscape.patch
  18. 26853
      target/linux/layerscape/patches-4.9/804-crypto-support-layerscape.patch
  19. 3781
      target/linux/layerscape/patches-4.9/805-dma-support-layerscape.patch
  20. 331
      target/linux/layerscape/patches-4.9/806-flextimer-support-layerscape.patch
  21. 73
      target/linux/layerscape/patches-4.9/807-gpu-support-layerscape.patch
  22. 462
      target/linux/layerscape/patches-4.9/808-guts-support-layerscape.patch
  23. 140
      target/linux/layerscape/patches-4.9/809-i2c-support-layerscape.patch
  24. 1338
      target/linux/layerscape/patches-4.9/810-iommu-support-layerscape.patch
  25. 182
      target/linux/layerscape/patches-4.9/811-irqchip-support-layerscape.patch
  26. 611
      target/linux/layerscape/patches-4.9/812-mmc-layerscape-support.patch
  27. 1378
      target/linux/layerscape/patches-4.9/813-qe-support-layerscape.patch
  28. 688
      target/linux/layerscape/patches-4.9/814-rtc-support-layerscape.patch
  29. 445
      target/linux/layerscape/patches-4.9/815-spi-support-layerscape.patch
  30. 163
      target/linux/layerscape/patches-4.9/816-tty-serial-support-layerscape.patch
  31. 1471
      target/linux/layerscape/patches-4.9/817-usb-support-layerscape.patch
  32. 1192
      target/linux/layerscape/patches-4.9/818-vfio-support-layerscape.patch

@ -9,7 +9,7 @@ include $(TOPDIR)/rules.mk
BOARD:=layerscape
BOARDNAME:=NXP Layerscape
DEVICE_TYPE:=developerboard
KERNEL_PATCHVER:=4.4
KERNEL_PATCHVER:=4.9
FEATURES:=squashfs nand usb pcie gpio
SUBTARGETS:=armv8_64b armv8_32b
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

@ -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

@ -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

@ -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

@ -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

@ -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

@ -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

@ -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

@ -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

@ -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

@ -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

@ -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

@ -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

@ -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

@ -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

@ -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
Loading…
Cancel
Save