layerscape: add linux 4.9 support
This patch is to add linux 4.9 support for layerscape. All these kernel patches are from NXP LSDK 1709 release. Signed-off-by: Yangbo Lu <yangbo.lu@nxp.com>
This commit is contained in:
parent
19951bbf57
commit
8fdda1cc10
32 changed files with 251241 additions and 1 deletions
|
@ -9,7 +9,7 @@ include $(TOPDIR)/rules.mk
|
||||||
BOARD:=layerscape
|
BOARD:=layerscape
|
||||||
BOARDNAME:=NXP Layerscape
|
BOARDNAME:=NXP Layerscape
|
||||||
DEVICE_TYPE:=developerboard
|
DEVICE_TYPE:=developerboard
|
||||||
KERNEL_PATCHVER:=4.4
|
KERNEL_PATCHVER:=4.9
|
||||||
FEATURES:=squashfs nand usb pcie gpio
|
FEATURES:=squashfs nand usb pcie gpio
|
||||||
SUBTARGETS:=armv8_64b armv8_32b
|
SUBTARGETS:=armv8_64b armv8_32b
|
||||||
MAINTAINER:=Yangbo Lu <yangbo.lu@nxp.com>
|
MAINTAINER:=Yangbo Lu <yangbo.lu@nxp.com>
|
||||||
|
|
1461
target/linux/layerscape/armv8_32b/config-4.9
Normal file
1461
target/linux/layerscape/armv8_32b/config-4.9
Normal file
File diff suppressed because it is too large
Load diff
1371
target/linux/layerscape/armv8_64b/config-4.9
Normal file
1371
target/linux/layerscape/armv8_64b/config-4.9
Normal file
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
|
||||||
|
|
10085
target/linux/layerscape/patches-4.9/302-dts-support-layercape.patch
Normal file
10085
target/linux/layerscape/patches-4.9/302-dts-support-layercape.patch
Normal file
File diff suppressed because it is too large
Load diff
File diff suppressed because it is too large
Load diff
|
@ -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
|
||||||
|
|
2549
target/linux/layerscape/patches-4.9/601-net-support-layerscape.patch
Normal file
2549
target/linux/layerscape/patches-4.9/601-net-support-layerscape.patch
Normal file
File diff suppressed because it is too large
Load diff
155005
target/linux/layerscape/patches-4.9/701-sdk_dpaa-support-layerscape.patch
Normal file
155005
target/linux/layerscape/patches-4.9/701-sdk_dpaa-support-layerscape.patch
Normal file
File diff suppressed because it is too large
Load diff
2062
target/linux/layerscape/patches-4.9/702-pci-support-layerscape.patch
Normal file
2062
target/linux/layerscape/patches-4.9/702-pci-support-layerscape.patch
Normal file
File diff suppressed because it is too large
Load diff
1776
target/linux/layerscape/patches-4.9/703-phy-support-layerscape.patch
Normal file
1776
target/linux/layerscape/patches-4.9/703-phy-support-layerscape.patch
Normal file
File diff suppressed because it is too large
Load diff
11518
target/linux/layerscape/patches-4.9/704-fsl-mc-layerscape-support.patch
Normal file
11518
target/linux/layerscape/patches-4.9/704-fsl-mc-layerscape-support.patch
Normal file
File diff suppressed because it is too large
Load diff
23027
target/linux/layerscape/patches-4.9/705-dpaa2-support-layerscape.patch
Normal file
23027
target/linux/layerscape/patches-4.9/705-dpaa2-support-layerscape.patch
Normal file
File diff suppressed because it is too large
Load diff
|
@ -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
|
||||||
|
|
26853
target/linux/layerscape/patches-4.9/804-crypto-support-layerscape.patch
Normal file
26853
target/linux/layerscape/patches-4.9/804-crypto-support-layerscape.patch
Normal file
File diff suppressed because it is too large
Load diff
3781
target/linux/layerscape/patches-4.9/805-dma-support-layerscape.patch
Normal file
3781
target/linux/layerscape/patches-4.9/805-dma-support-layerscape.patch
Normal file
File diff suppressed because it is too large
Load diff
|
@ -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
|
||||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -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
|
||||||
|
|
1378
target/linux/layerscape/patches-4.9/813-qe-support-layerscape.patch
Normal file
1378
target/linux/layerscape/patches-4.9/813-qe-support-layerscape.patch
Normal file
File diff suppressed because it is too large
Load diff
|
@ -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, ®val);
|
||||||
|
+ if (ret)
|
||||||
|
+ return ret;
|
||||||
|
+ alarm->enabled = !!(regval & PCF85263_REG_ALM_CTL_ALL_A1E);
|
||||||
|
+
|
||||||
|
+ ret = regmap_read(pcf85263->regmap, PCF85263_REG_FLAGS, ®val);
|
||||||
|
+ 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, ®val);
|
||||||
|
+ 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, ®val);
|
||||||
|
+ 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, ®val);
|
||||||
|
+ 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
|
||||||
|
|
1471
target/linux/layerscape/patches-4.9/817-usb-support-layerscape.patch
Normal file
1471
target/linux/layerscape/patches-4.9/817-usb-support-layerscape.patch
Normal file
File diff suppressed because it is too large
Load diff
File diff suppressed because it is too large
Load diff
Loading…
Reference in a new issue