Add kernel for stm32mp machine

Kernel lts 4.19

Signed-off-by: Christophe Priouzeau <christophe.priouzeau@st.com>
This commit is contained in:
Christophe Priouzeau 2019-02-05 11:20:59 +01:00
parent 3fef5201b0
commit b5ef9c5a74
70 changed files with 57707 additions and 0 deletions

View File

@ -0,0 +1,81 @@
COMPATIBLE_MACHINE = "(stm32mpcommon)"
inherit kernel
DEPENDS += "openssl-native util-linux-native"
B = "${WORKDIR}/linux-${MACHINE}-standard-build"
# Configure build dir for externalsrc class usage through devtool
EXTERNALSRC_BUILD_pn-${PN} = "${WORKDIR}/linux-${MACHINE}-standard-build"
# To share config fragments between layers
FILESEXTRAPATHS_prepend := "${THISDIR}:"
# -------------------------------------------------------------
# Do not deploy kernel module with specfic tarball
MODULE_TARBALL_DEPLOY = "0"
# ---------------------------------------------------------------------
# Defconfig
#
#If the defconfig is contained on the kernel tree (arch/${ARCH}/configs)
#you must use the following line
do_configure_prepend() {
unset CFLAGS CPPFLAGS CXXFLAGS LDFLAGS MACHINE
if [ ! -z ${KERNEL_DEFCONFIG} ];
then
bbnote "Kernel customized: configuration of linux STM by using DEFCONFIG: ${KERNEL_DEFCONFIG}"
oe_runmake ${PARALLEL_MAKE} -C ${S} O=${B} CC="${KERNEL_CC}" LD="${KERNEL_LD}" ${KERNEL_DEFCONFIG}
else
if [ ! -z ${KERNEL_EXTERNAL_DEFCONFIG} ];
then
bbnote "Kernel customized: configuration of linux STM by using external DEFCONFIG"
install -m 0644 ${WORKDIR}/${KERNEL_EXTERNAL_DEFCONFIG} ${B}/.config
oe_runmake -C ${S} O=${B} CC="${KERNEL_CC}" LD="${KERNEL_LD}" oldconfig
else
bbwarn "You must specify KERNEL_DEFCONFIG or KERNEL_EXTERNAL_DEFCONFIG"
die "NO DEFCONFIG SPECIFIED"
fi
fi
if [ ! -z "${KERNEL_CONFIG_FRAGMENTS}" ]
then
for f in ${KERNEL_CONFIG_FRAGMENTS}
do
bbnote "file = $f"
# Check if the config fragment was copied into the WORKDIR from
# the OE meta data
if [ ! -e "$f" ]
then
echo "Could not find kernel config fragment $f"
exit 1
fi
done
bbnote "${S}/scripts/kconfig/merge_config.sh -m -r -O ${B} ${B}/.config ${KERNEL_CONFIG_FRAGMENTS} 1>&2"
# Now that all the fragments are located merge them.
(${S}/scripts/kconfig/merge_config.sh -m -r -O ${B} ${B}/.config ${KERNEL_CONFIG_FRAGMENTS} 1>&2 )
fi
yes '' | oe_runmake -C ${S} O=${B} CC="${KERNEL_CC}" LD="${KERNEL_LD}" oldconfig
#oe_runmake -C ${S} O=${B} savedefconfig && cp ${B}/defconfig ${WORKDIR}/defconfig.saved
}
# ---------------------------------------------------------------------
do_install_append() {
# Install KERNEL_IMAGETYPE for kernel-imagebootfs package
install -m 0644 ${KERNEL_OUTPUT_DIR}/${KERNEL_IMAGETYPE} ${D}/${KERNEL_IMAGEDEST}
}
# ---------------------------------------------------------------------
# Support checking the kernel load address parameter: expecting proper value for ST kernel.
#
python do_loadaddrcheck() {
if not d.getVar('ST_KERNEL_LOADADDR'):
bb.fatal('Missing ST_KERNEL_LOADADDR value for ST kernel build: please define it in your machine.')
}
PACKAGES =+ "${KERNEL_PACKAGE_NAME}-headers ${KERNEL_PACKAGE_NAME}-imagebootfs"
FILES_${KERNEL_PACKAGE_NAME}-headers = "${exec_prefix}/src/linux*"
FILES_${KERNEL_PACKAGE_NAME}-image += "boot/ ${KERNEL_IMAGEDEST}"
FILES_${KERNEL_PACKAGE_NAME}-imagebootfs = "boot/*.dtb boot/${KERNEL_IMAGETYPE}"

View File

@ -0,0 +1,47 @@
From 07a8a17983431bcc47ef52be1370f156e56119ce Mon Sep 17 00:00:00 2001
From: Romuald JEANNE <romuald.jeanne@st.com>
Date: Tue, 13 Nov 2018 12:14:29 +0100
Subject: [PATCH 01/52] ARM: stm32mp1-r0-rc1: MACHINE
---
arch/arm/mach-stm32/Kconfig | 5 +----
1 file changed, 1 insertion(+), 4 deletions(-)
diff --git a/arch/arm/mach-stm32/Kconfig b/arch/arm/mach-stm32/Kconfig
index 713c068..651bdf4 100644
--- a/arch/arm/mach-stm32/Kconfig
+++ b/arch/arm/mach-stm32/Kconfig
@@ -4,6 +4,7 @@ menuconfig ARCH_STM32
select HAVE_ARM_ARCH_TIMER if ARCH_MULTI_V7
select ARM_GIC if ARCH_MULTI_V7
select ARM_PSCI if ARCH_MULTI_V7
+ select ARM_AMBA
select ARCH_HAS_RESET_CONTROLLER
select CLKSRC_STM32
select PINCTRL
@@ -18,22 +19,18 @@ if ARM_SINGLE_ARMV7M
config MACH_STM32F429
bool "STMicroelectronics STM32F429"
- select ARM_AMBA
default y
config MACH_STM32F469
bool "STMicroelectronics STM32F469"
- select ARM_AMBA
default y
config MACH_STM32F746
bool "STMicroelectronics STM32F746"
- select ARM_AMBA
default y
config MACH_STM32F769
bool "STMicroelectronics STM32F769"
- select ARM_AMBA
default y
config MACH_STM32H743
--
2.7.4

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,638 @@
From 656c7df3520f4422b871a4e69c68e6a9daf7ba61 Mon Sep 17 00:00:00 2001
From: Romuald JEANNE <romuald.jeanne@st.com>
Date: Tue, 13 Nov 2018 12:18:06 +0100
Subject: [PATCH 04/52] ARM: stm32mp1-r0-rc1: I2C
---
drivers/i2c/busses/i2c-stm32f7.c | 369 +++++++++++++++++++++++++++++++++------
1 file changed, 320 insertions(+), 49 deletions(-)
diff --git a/drivers/i2c/busses/i2c-stm32f7.c b/drivers/i2c/busses/i2c-stm32f7.c
index 62d023e..c1cbf93 100644
--- a/drivers/i2c/busses/i2c-stm32f7.c
+++ b/drivers/i2c/busses/i2c-stm32f7.c
@@ -21,12 +21,17 @@
#include <linux/interrupt.h>
#include <linux/io.h>
#include <linux/iopoll.h>
+#include <linux/mfd/syscon.h>
#include <linux/module.h>
#include <linux/of.h>
#include <linux/of_address.h>
#include <linux/of_irq.h>
#include <linux/of_platform.h>
#include <linux/platform_device.h>
+#include <linux/pinctrl/consumer.h>
+#include <linux/pm_runtime.h>
+#include <linux/pm_wakeirq.h>
+#include <linux/regmap.h>
#include <linux/reset.h>
#include <linux/slab.h>
@@ -46,6 +51,7 @@
/* STM32F7 I2C control 1 */
#define STM32F7_I2C_CR1_PECEN BIT(23)
+#define STM32F7_I2C_CR1_WUPEN BIT(18)
#define STM32F7_I2C_CR1_SBC BIT(16)
#define STM32F7_I2C_CR1_RXDMAEN BIT(15)
#define STM32F7_I2C_CR1_TXDMAEN BIT(14)
@@ -163,6 +169,26 @@
#define STM32F7_SCLH_MAX BIT(8)
#define STM32F7_SCLL_MAX BIT(8)
+#define STM32F7_AUTOSUSPEND_DELAY (HZ / 100)
+
+/**
+ * struct stm32f7_i2c_regs - i2c f7 registers backup
+ * @cr1: Control register 1
+ * @cr2: Control register 2
+ * @oar1: Own address 1 register
+ * @oar2: Own address 2 register
+ * @pecr: PEC register
+ * @timingr: Timing register
+ */
+struct stm32f7_i2c_regs {
+ u32 cr1;
+ u32 cr2;
+ u32 oar1;
+ u32 oar2;
+ u32 pecr;
+ u32 tmgr;
+};
+
/**
* struct stm32f7_i2c_spec - private i2c specification timing
* @rate: I2C bus speed (Hz)
@@ -259,6 +285,8 @@ struct stm32f7_i2c_msg {
* struct stm32f7_i2c_dev - private data of the controller
* @adap: I2C adapter for this controller
* @dev: device for this controller
+ * @irq_event: interrupt event line for the controller
+ * @irq_wakeup: interrupt wakeup line for the controller
* @base: virtual memory area
* @complete: completion of I2C message
* @clk: hw i2c clock
@@ -276,11 +304,14 @@ struct stm32f7_i2c_msg {
* slave)
* @dma: dma data
* @use_dma: boolean to know if dma is used in the current transfer
+ * @regmap: holds SYSCFG phandle for Fast Mode Plus bits
*/
struct stm32f7_i2c_dev {
struct i2c_adapter adap;
struct device *dev;
void __iomem *base;
+ int irq_event;
+ int irq_wakeup;
struct completion complete;
struct clk *clk;
int speed;
@@ -292,10 +323,12 @@ struct stm32f7_i2c_dev {
struct stm32f7_i2c_timings timing;
struct i2c_client *slave[STM32F7_I2C_MAX_SLAVE];
struct i2c_client *slave_running;
+ struct stm32f7_i2c_regs regs;
u32 slave_dir;
bool master_mode;
struct stm32_i2c_dma *dma;
bool use_dma;
+ struct regmap *regmap;
};
/**
@@ -1545,15 +1578,13 @@ static int stm32f7_i2c_xfer(struct i2c_adapter *i2c_adap,
i2c_dev->msg_id = 0;
f7_msg->smbus = false;
- ret = clk_enable(i2c_dev->clk);
- if (ret) {
- dev_err(i2c_dev->dev, "Failed to enable clock\n");
+ ret = pm_runtime_get_sync(i2c_dev->dev);
+ if (ret < 0)
return ret;
- }
ret = stm32f7_i2c_wait_free_bus(i2c_dev);
if (ret)
- goto clk_free;
+ goto pm_free;
stm32f7_i2c_xfer_msg(i2c_dev, msgs);
@@ -1569,8 +1600,9 @@ static int stm32f7_i2c_xfer(struct i2c_adapter *i2c_adap,
ret = -ETIMEDOUT;
}
-clk_free:
- clk_disable(i2c_dev->clk);
+pm_free:
+ pm_runtime_mark_last_busy(i2c_dev->dev);
+ pm_runtime_put_autosuspend(i2c_dev->dev);
return (ret < 0) ? ret : num;
}
@@ -1592,39 +1624,37 @@ static int stm32f7_i2c_smbus_xfer(struct i2c_adapter *adapter, u16 addr,
f7_msg->read_write = read_write;
f7_msg->smbus = true;
- ret = clk_enable(i2c_dev->clk);
- if (ret) {
- dev_err(i2c_dev->dev, "Failed to enable clock\n");
+ ret = pm_runtime_get_sync(dev);
+ if (ret < 0)
return ret;
- }
ret = stm32f7_i2c_wait_free_bus(i2c_dev);
if (ret)
- goto clk_free;
+ goto pm_free;
ret = stm32f7_i2c_smbus_xfer_msg(i2c_dev, flags, command, data);
if (ret)
- goto clk_free;
+ goto pm_free;
timeout = wait_for_completion_timeout(&i2c_dev->complete,
i2c_dev->adap.timeout);
ret = f7_msg->result;
if (ret)
- goto clk_free;
+ goto pm_free;
if (!timeout) {
dev_dbg(dev, "Access to slave 0x%x timed out\n", f7_msg->addr);
if (i2c_dev->use_dma)
dmaengine_terminate_all(dma->chan_using);
ret = -ETIMEDOUT;
- goto clk_free;
+ goto pm_free;
}
/* Check PEC */
if ((flags & I2C_CLIENT_PEC) && size != I2C_SMBUS_QUICK && read_write) {
ret = stm32f7_i2c_smbus_check_pec(i2c_dev);
if (ret)
- goto clk_free;
+ goto pm_free;
}
if (read_write && size != I2C_SMBUS_QUICK) {
@@ -1649,11 +1679,15 @@ static int stm32f7_i2c_smbus_xfer(struct i2c_adapter *adapter, u16 addr,
}
}
-clk_free:
- clk_disable(i2c_dev->clk);
+pm_free:
+ pm_runtime_mark_last_busy(dev);
+ pm_runtime_put_autosuspend(dev);
return ret;
}
+static void stm32f7_i2c_enable_wakeup(struct stm32f7_i2c_dev *i2c_dev,
+ bool enable);
+
static int stm32f7_i2c_reg_slave(struct i2c_client *slave)
{
struct stm32f7_i2c_dev *i2c_dev = i2c_get_adapdata(slave->adapter);
@@ -1676,13 +1710,12 @@ static int stm32f7_i2c_reg_slave(struct i2c_client *slave)
if (ret)
return ret;
- if (!(stm32f7_i2c_is_slave_registered(i2c_dev))) {
- ret = clk_enable(i2c_dev->clk);
- if (ret) {
- dev_err(dev, "Failed to enable clock\n");
- return ret;
- }
- }
+ ret = pm_runtime_get_sync(dev);
+ if (ret < 0)
+ return ret;
+
+ if (!stm32f7_i2c_is_slave_registered(i2c_dev))
+ stm32f7_i2c_enable_wakeup(i2c_dev, true);
if (id == 0) {
/* Configure Own Address 1 */
@@ -1703,7 +1736,7 @@ static int stm32f7_i2c_reg_slave(struct i2c_client *slave)
oar2 &= ~STM32F7_I2C_OAR2_MASK;
if (slave->flags & I2C_CLIENT_TEN) {
ret = -EOPNOTSUPP;
- goto exit;
+ goto pm_free;
}
oar2 |= STM32F7_I2C_OAR2_OA2_7(slave->addr);
@@ -1712,7 +1745,7 @@ static int stm32f7_i2c_reg_slave(struct i2c_client *slave)
writel_relaxed(oar2, i2c_dev->base + STM32F7_I2C_OAR2);
} else {
ret = -ENODEV;
- goto exit;
+ goto pm_free;
}
/* Enable ACK */
@@ -1723,11 +1756,13 @@ static int stm32f7_i2c_reg_slave(struct i2c_client *slave)
STM32F7_I2C_CR1_PE;
stm32f7_i2c_set_bits(base + STM32F7_I2C_CR1, mask);
- return 0;
+ ret = 0;
+pm_free:
+ if (!stm32f7_i2c_is_slave_registered(i2c_dev))
+ stm32f7_i2c_enable_wakeup(i2c_dev, false);
-exit:
- if (!(stm32f7_i2c_is_slave_registered(i2c_dev)))
- clk_disable(i2c_dev->clk);
+ pm_runtime_mark_last_busy(dev);
+ pm_runtime_put_autosuspend(dev);
return ret;
}
@@ -1745,6 +1780,10 @@ static int stm32f7_i2c_unreg_slave(struct i2c_client *slave)
WARN_ON(!i2c_dev->slave[id]);
+ ret = pm_runtime_get_sync(i2c_dev->dev);
+ if (ret < 0)
+ return ret;
+
if (id == 0) {
mask = STM32F7_I2C_OAR1_OA1EN;
stm32f7_i2c_clr_bits(base + STM32F7_I2C_OAR1, mask);
@@ -1755,14 +1794,56 @@ static int stm32f7_i2c_unreg_slave(struct i2c_client *slave)
i2c_dev->slave[id] = NULL;
- if (!(stm32f7_i2c_is_slave_registered(i2c_dev))) {
+ if (!stm32f7_i2c_is_slave_registered(i2c_dev)) {
stm32f7_i2c_disable_irq(i2c_dev, STM32F7_I2C_ALL_IRQ_MASK);
- clk_disable(i2c_dev->clk);
+ stm32f7_i2c_enable_wakeup(i2c_dev, false);
}
+ pm_runtime_mark_last_busy(i2c_dev->dev);
+ pm_runtime_put_autosuspend(i2c_dev->dev);
+
return 0;
}
+static int stm32f7_i2c_setup_wakeup(struct stm32f7_i2c_dev *i2c_dev)
+{
+ int ret;
+
+ device_init_wakeup(i2c_dev->dev, true);
+ ret = dev_pm_set_dedicated_wake_irq(i2c_dev->dev, i2c_dev->irq_wakeup);
+ if (ret) {
+ device_init_wakeup(i2c_dev->dev, false);
+ dev_warn(i2c_dev->dev, "failed to set up wakeup irq");
+ return ret;
+ }
+
+ return device_set_wakeup_enable(i2c_dev->dev, false);
+}
+
+static int stm32f7_i2c_setup_fm_plus_bits(struct platform_device *pdev,
+ struct stm32f7_i2c_dev *i2c_dev)
+{
+ struct device_node *np = pdev->dev.of_node;
+ int ret;
+ u32 reg, mask;
+
+ i2c_dev->regmap = syscon_regmap_lookup_by_phandle(np, "st,syscfg-fmp");
+ if (IS_ERR(i2c_dev->regmap)) {
+ /* Optional */
+ return 0;
+ }
+
+ ret = of_property_read_u32_index(np, "st,syscfg-fmp", 1, &reg);
+ if (ret)
+ return ret;
+
+ ret = of_property_read_u32_index(np, "st,syscfg-fmp", 2, &mask);
+ if (ret)
+ return ret;
+
+ return regmap_update_bits(i2c_dev->regmap, reg, mask, mask);
+}
+
static u32 stm32f7_i2c_func(struct i2c_adapter *adap)
{
return I2C_FUNC_I2C | I2C_FUNC_10BIT_ADDR | I2C_FUNC_SLAVE |
@@ -1786,7 +1867,7 @@ static int stm32f7_i2c_probe(struct platform_device *pdev)
struct stm32f7_i2c_dev *i2c_dev;
const struct stm32f7_i2c_setup *setup;
struct resource *res;
- u32 irq_error, irq_event, clk_rate, rise_time, fall_time;
+ u32 irq_error, clk_rate, rise_time, fall_time;
struct i2c_adapter *adap;
struct reset_control *rst;
dma_addr_t phy_addr;
@@ -1802,13 +1883,13 @@ static int stm32f7_i2c_probe(struct platform_device *pdev)
return PTR_ERR(i2c_dev->base);
phy_addr = (dma_addr_t)res->start;
- irq_event = irq_of_parse_and_map(np, 0);
- if (!irq_event) {
+ i2c_dev->irq_event = of_irq_get_byname(np, "event");
+ if (!i2c_dev->irq_event) {
dev_err(&pdev->dev, "IRQ event missing or invalid\n");
return -EINVAL;
}
- irq_error = irq_of_parse_and_map(np, 1);
+ irq_error = of_irq_get_byname(np, "error");
if (!irq_error) {
dev_err(&pdev->dev, "IRQ error missing or invalid\n");
return -EINVAL;
@@ -1819,6 +1900,7 @@ static int stm32f7_i2c_probe(struct platform_device *pdev)
dev_err(&pdev->dev, "Error: Missing controller clock\n");
return PTR_ERR(i2c_dev->clk);
}
+
ret = clk_prepare_enable(i2c_dev->clk);
if (ret) {
dev_err(&pdev->dev, "Failed to prepare_enable clock\n");
@@ -1828,12 +1910,16 @@ static int stm32f7_i2c_probe(struct platform_device *pdev)
i2c_dev->speed = STM32_I2C_SPEED_STANDARD;
ret = device_property_read_u32(&pdev->dev, "clock-frequency",
&clk_rate);
- if (!ret && clk_rate >= 1000000)
+ if (!ret && clk_rate >= 1000000) {
i2c_dev->speed = STM32_I2C_SPEED_FAST_PLUS;
- else if (!ret && clk_rate >= 400000)
+ ret = stm32f7_i2c_setup_fm_plus_bits(pdev, i2c_dev);
+ if (ret)
+ goto clk_free;
+ } else if (!ret && clk_rate >= 400000) {
i2c_dev->speed = STM32_I2C_SPEED_FAST;
- else if (!ret && clk_rate >= 100000)
+ } else if (!ret && clk_rate >= 100000) {
i2c_dev->speed = STM32_I2C_SPEED_STANDARD;
+ }
rst = devm_reset_control_get(&pdev->dev, NULL);
if (IS_ERR(rst)) {
@@ -1847,14 +1933,14 @@ static int stm32f7_i2c_probe(struct platform_device *pdev)
i2c_dev->dev = &pdev->dev;
- ret = devm_request_threaded_irq(&pdev->dev, irq_event,
+ ret = devm_request_threaded_irq(&pdev->dev, i2c_dev->irq_event,
stm32f7_i2c_isr_event,
stm32f7_i2c_isr_event_thread,
IRQF_ONESHOT,
pdev->name, i2c_dev);
if (ret) {
dev_err(&pdev->dev, "Failed to request irq event %i\n",
- irq_event);
+ i2c_dev->irq_event);
goto clk_free;
}
@@ -1888,8 +1974,6 @@ static int stm32f7_i2c_probe(struct platform_device *pdev)
if (ret)
goto clk_free;
- stm32f7_i2c_hw_config(i2c_dev);
-
adap = &i2c_dev->adap;
i2c_set_adapdata(adap, i2c_dev);
snprintf(adap->name, sizeof(adap->name), "STM32F7 I2C(%pa)",
@@ -1908,18 +1992,45 @@ static int stm32f7_i2c_probe(struct platform_device *pdev)
STM32F7_I2C_TXDR,
STM32F7_I2C_RXDR);
- ret = i2c_add_adapter(adap);
- if (ret)
- goto clk_free;
+ i2c_dev->irq_wakeup = of_irq_get_byname(np, "wakeup");
+ if (i2c_dev->irq_wakeup > 0) {
+ ret = stm32f7_i2c_setup_wakeup(i2c_dev);
+ if (ret)
+ goto clk_free;
+ }
platform_set_drvdata(pdev, i2c_dev);
- clk_disable(i2c_dev->clk);
+ pm_runtime_set_autosuspend_delay(i2c_dev->dev,
+ STM32F7_AUTOSUSPEND_DELAY);
+ pm_runtime_use_autosuspend(i2c_dev->dev);
+ pm_runtime_set_active(i2c_dev->dev);
+ pm_runtime_enable(i2c_dev->dev);
+
+ pm_runtime_get_noresume(&pdev->dev);
+
+ stm32f7_i2c_hw_config(i2c_dev);
+
+ ret = i2c_add_adapter(adap);
+ if (ret)
+ goto pm_disable;
dev_info(i2c_dev->dev, "STM32F7 I2C-%d bus adapter\n", adap->nr);
+ pm_runtime_mark_last_busy(i2c_dev->dev);
+ pm_runtime_put_autosuspend(i2c_dev->dev);
+
return 0;
+pm_disable:
+ dev_pm_clear_wake_irq(i2c_dev->dev);
+ device_init_wakeup(i2c_dev->dev, false);
+
+ pm_runtime_put_noidle(i2c_dev->dev);
+ pm_runtime_disable(i2c_dev->dev);
+ pm_runtime_set_suspended(i2c_dev->dev);
+ pm_runtime_dont_use_autosuspend(i2c_dev->dev);
+
clk_free:
clk_disable_unprepare(i2c_dev->clk);
@@ -1936,11 +2047,170 @@ static int stm32f7_i2c_remove(struct platform_device *pdev)
}
i2c_del_adapter(&i2c_dev->adap);
+ pm_runtime_get_sync(i2c_dev->dev);
+
+ dev_pm_clear_wake_irq(i2c_dev->dev);
+ device_init_wakeup(i2c_dev->dev, false);
- clk_unprepare(i2c_dev->clk);
+ clk_disable_unprepare(i2c_dev->clk);
+
+ pm_runtime_put_noidle(i2c_dev->dev);
+ pm_runtime_disable(i2c_dev->dev);
+ pm_runtime_set_suspended(i2c_dev->dev);
+ pm_runtime_dont_use_autosuspend(i2c_dev->dev);
+
+ return 0;
+}
+
+#ifdef CONFIG_PM
+static int stm32f7_i2c_runtime_suspend(struct device *dev)
+{
+ struct stm32f7_i2c_dev *i2c_dev = dev_get_drvdata(dev);
+
+ if (!stm32f7_i2c_is_slave_registered(i2c_dev))
+ clk_disable_unprepare(i2c_dev->clk);
+
+ return 0;
+}
+
+static int stm32f7_i2c_runtime_resume(struct device *dev)
+{
+ struct stm32f7_i2c_dev *i2c_dev = dev_get_drvdata(dev);
+ int ret;
+
+ if (!stm32f7_i2c_is_slave_registered(i2c_dev)) {
+ ret = clk_prepare_enable(i2c_dev->clk);
+ if (ret) {
+ dev_err(dev, "failed to prepare_enable clock\n");
+ return ret;
+ }
+ }
return 0;
}
+#endif
+
+#ifdef CONFIG_PM_SLEEP
+static int stm32f7_i2c_regs_backup(struct stm32f7_i2c_dev *i2c_dev)
+{
+ int ret;
+
+ ret = pm_runtime_get_sync(i2c_dev->dev);
+ if (ret < 0)
+ return ret;
+
+ i2c_dev->regs.cr1 = readl_relaxed(i2c_dev->base + STM32F7_I2C_CR1);
+ i2c_dev->regs.cr2 = readl_relaxed(i2c_dev->base + STM32F7_I2C_CR2);
+ i2c_dev->regs.oar1 = readl_relaxed(i2c_dev->base + STM32F7_I2C_OAR1);
+ i2c_dev->regs.oar2 = readl_relaxed(i2c_dev->base + STM32F7_I2C_OAR2);
+ i2c_dev->regs.pecr = readl_relaxed(i2c_dev->base + STM32F7_I2C_PECR);
+ i2c_dev->regs.tmgr = readl_relaxed(i2c_dev->base + STM32F7_I2C_TIMINGR);
+
+ pm_runtime_put_sync(i2c_dev->dev);
+
+ return ret;
+}
+
+static int stm32f7_i2c_regs_restore(struct stm32f7_i2c_dev *i2c_dev)
+{
+ u32 cr1;
+ int ret;
+
+ ret = pm_runtime_get_sync(i2c_dev->dev);
+ if (ret < 0)
+ return ret;
+
+ cr1 = readl_relaxed(i2c_dev->base + STM32F7_I2C_CR1);
+ if (cr1 & STM32F7_I2C_CR1_PE)
+ stm32f7_i2c_clr_bits(i2c_dev->base + STM32F7_I2C_CR1,
+ STM32F7_I2C_CR1_PE);
+
+ writel_relaxed(i2c_dev->regs.tmgr, i2c_dev->base + STM32F7_I2C_TIMINGR);
+ writel_relaxed(i2c_dev->regs.cr1 & ~STM32F7_I2C_CR1_PE,
+ i2c_dev->base + STM32F7_I2C_CR1);
+ if (i2c_dev->regs.cr1 & STM32F7_I2C_CR1_PE)
+ stm32f7_i2c_set_bits(i2c_dev->base + STM32F7_I2C_CR1,
+ STM32F7_I2C_CR1_PE);
+ writel_relaxed(i2c_dev->regs.cr2, i2c_dev->base + STM32F7_I2C_CR2);
+ writel_relaxed(i2c_dev->regs.oar1, i2c_dev->base + STM32F7_I2C_OAR1);
+ writel_relaxed(i2c_dev->regs.oar2, i2c_dev->base + STM32F7_I2C_OAR2);
+ writel_relaxed(i2c_dev->regs.pecr, i2c_dev->base + STM32F7_I2C_PECR);
+
+ pm_runtime_put_sync(i2c_dev->dev);
+
+ return ret;
+}
+
+static void stm32f7_i2c_enable_wakeup(struct stm32f7_i2c_dev *i2c_dev,
+ bool enable)
+{
+ void __iomem *base = i2c_dev->base;
+ u32 mask = STM32F7_I2C_CR1_WUPEN;
+
+ if (i2c_dev->irq_wakeup <= 0)
+ return;
+
+ if (enable) {
+ device_set_wakeup_enable(i2c_dev->dev, true);
+ enable_irq_wake(i2c_dev->irq_wakeup);
+ enable_irq_wake(i2c_dev->irq_event);
+ stm32f7_i2c_set_bits(base + STM32F7_I2C_CR1, mask);
+ readl_relaxed(i2c_dev->base + STM32F7_I2C_CR1);
+ } else {
+ disable_irq_wake(i2c_dev->irq_wakeup);
+ disable_irq_wake(i2c_dev->irq_event);
+ device_set_wakeup_enable(i2c_dev->dev, false);
+ stm32f7_i2c_clr_bits(base + STM32F7_I2C_CR1, mask);
+ }
+}
+
+static int stm32f7_i2c_suspend(struct device *dev)
+{
+ struct stm32f7_i2c_dev *i2c_dev = dev_get_drvdata(dev);
+ int ret;
+
+ ret = stm32f7_i2c_regs_backup(i2c_dev);
+ if (ret < 0)
+ return ret;
+
+ if (!stm32f7_i2c_is_slave_registered(i2c_dev)) {
+ pinctrl_pm_select_sleep_state(dev);
+ pm_runtime_force_suspend(dev);
+ }
+
+ return 0;
+}
+
+static int stm32f7_i2c_resume(struct device *dev)
+{
+ struct stm32f7_i2c_dev *i2c_dev = dev_get_drvdata(dev);
+ int ret;
+
+ if (!stm32f7_i2c_is_slave_registered(i2c_dev)) {
+ ret = pm_runtime_force_resume(dev);
+ if (ret < 0)
+ return ret;
+ pinctrl_pm_select_default_state(dev);
+ }
+
+ ret = stm32f7_i2c_regs_restore(i2c_dev);
+ if (ret < 0)
+ return ret;
+
+ return 0;
+}
+#else
+static void stm32f7_i2c_enable_wakeup(struct stm32f7_i2c_dev *i2c_dev,
+ bool enable)
+{
+}
+#endif
+
+static const struct dev_pm_ops stm32f7_i2c_pm_ops = {
+ SET_RUNTIME_PM_OPS(stm32f7_i2c_runtime_suspend,
+ stm32f7_i2c_runtime_resume, NULL)
+ SET_SYSTEM_SLEEP_PM_OPS(stm32f7_i2c_suspend, stm32f7_i2c_resume)
+};
static const struct of_device_id stm32f7_i2c_match[] = {
{ .compatible = "st,stm32f7-i2c", .data = &stm32f7_setup},
@@ -1952,6 +2222,7 @@ static struct platform_driver stm32f7_i2c_driver = {
.driver = {
.name = "stm32f7-i2c",
.of_match_table = stm32f7_i2c_match,
+ .pm = &stm32f7_i2c_pm_ops,
},
.probe = stm32f7_i2c_probe,
.remove = stm32f7_i2c_remove,
--
2.7.4

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,154 @@
From 358a1325502b2362a6fb74af3027f3f165684375 Mon Sep 17 00:00:00 2001
From: Romuald JEANNE <romuald.jeanne@st.com>
Date: Tue, 13 Nov 2018 12:19:47 +0100
Subject: [PATCH 06/52] ARM: stm32mp1-r0-rc1: IRQ Mailbox
---
drivers/irqchip/irq-stm32-exti.c | 23 ++++++++++++++++++-----
drivers/mailbox/mailbox-test.c | 26 ++++++++++++++------------
drivers/mailbox/stm32-ipcc.c | 4 ++--
3 files changed, 34 insertions(+), 19 deletions(-)
diff --git a/drivers/irqchip/irq-stm32-exti.c b/drivers/irqchip/irq-stm32-exti.c
index 0a2088e..e185ed8 100644
--- a/drivers/irqchip/irq-stm32-exti.c
+++ b/drivers/irqchip/irq-stm32-exti.c
@@ -650,11 +650,6 @@ stm32_exti_chip_data *stm32_exti_chip_init(struct stm32_exti_host_data *h_data,
*/
writel_relaxed(0, base + stm32_bank->imr_ofst);
writel_relaxed(0, base + stm32_bank->emr_ofst);
- writel_relaxed(0, base + stm32_bank->rtsr_ofst);
- writel_relaxed(0, base + stm32_bank->ftsr_ofst);
- writel_relaxed(~0UL, base + stm32_bank->rpr_ofst);
- if (stm32_bank->fpr_ofst != UNDEF_REG)
- writel_relaxed(~0UL, base + stm32_bank->fpr_ofst);
pr_info("%s: bank%d, External IRQs available:%#x\n",
node->full_name, bank_idx, irqs_mask);
@@ -735,9 +730,27 @@ static int __init stm32_exti_init(const struct stm32_exti_drv_data *drv_data,
return ret;
}
+static int stm32_exti_h_translate(struct irq_domain *d,
+ struct irq_fwspec *fwspec,
+ unsigned long *out_hwirq,
+ unsigned int *out_type)
+{
+ if (is_of_node(fwspec->fwnode)) {
+ if (fwspec->param_count != 2)
+ return -EINVAL;
+
+ *out_hwirq = fwspec->param[0];
+ *out_type = fwspec->param[1] & IRQ_TYPE_SENSE_MASK;
+ return 0;
+ }
+
+ return -EINVAL;
+}
+
static const struct irq_domain_ops stm32_exti_h_domain_ops = {
.alloc = stm32_exti_h_domain_alloc,
.free = irq_domain_free_irqs_common,
+ .translate = stm32_exti_h_translate,
};
static int
diff --git a/drivers/mailbox/mailbox-test.c b/drivers/mailbox/mailbox-test.c
index 58bfafc..4e4ac4b 100644
--- a/drivers/mailbox/mailbox-test.c
+++ b/drivers/mailbox/mailbox-test.c
@@ -31,7 +31,6 @@
(MBOX_MAX_MSG_LEN / MBOX_BYTES_PER_LINE))
static bool mbox_data_ready;
-static struct dentry *root_debugfs_dir;
struct mbox_test_device {
struct device *dev;
@@ -45,6 +44,7 @@ struct mbox_test_device {
spinlock_t lock;
wait_queue_head_t waitq;
struct fasync_struct *async_queue;
+ struct dentry *root_debugfs_dir;
};
static ssize_t mbox_test_signal_write(struct file *filp,
@@ -262,16 +262,16 @@ static int mbox_test_add_debugfs(struct platform_device *pdev,
if (!debugfs_initialized())
return 0;
- root_debugfs_dir = debugfs_create_dir("mailbox", NULL);
- if (!root_debugfs_dir) {
+ tdev->root_debugfs_dir = debugfs_create_dir(dev_name(&pdev->dev), NULL);
+ if (!tdev->root_debugfs_dir) {
dev_err(&pdev->dev, "Failed to create Mailbox debugfs\n");
return -EINVAL;
}
- debugfs_create_file("message", 0600, root_debugfs_dir,
+ debugfs_create_file("message", 0600, tdev->root_debugfs_dir,
tdev, &mbox_test_message_ops);
- debugfs_create_file("signal", 0200, root_debugfs_dir,
+ debugfs_create_file("signal", 0200, tdev->root_debugfs_dir,
tdev, &mbox_test_signal_ops);
return 0;
@@ -363,22 +363,24 @@ static int mbox_test_probe(struct platform_device *pdev)
/* It's okay for MMIO to be NULL */
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
- size = resource_size(res);
tdev->tx_mmio = devm_ioremap_resource(&pdev->dev, res);
- if (PTR_ERR(tdev->tx_mmio) == -EBUSY)
+ if (PTR_ERR(tdev->tx_mmio) == -EBUSY) {
/* if reserved area in SRAM, try just ioremap */
+ size = resource_size(res);
tdev->tx_mmio = devm_ioremap(&pdev->dev, res->start, size);
- else if (IS_ERR(tdev->tx_mmio))
+ } else if (IS_ERR(tdev->tx_mmio)) {
tdev->tx_mmio = NULL;
+ }
/* If specified, second reg entry is Rx MMIO */
res = platform_get_resource(pdev, IORESOURCE_MEM, 1);
- size = resource_size(res);
tdev->rx_mmio = devm_ioremap_resource(&pdev->dev, res);
- if (PTR_ERR(tdev->rx_mmio) == -EBUSY)
+ if (PTR_ERR(tdev->rx_mmio) == -EBUSY) {
+ size = resource_size(res);
tdev->rx_mmio = devm_ioremap(&pdev->dev, res->start, size);
- else if (IS_ERR(tdev->rx_mmio))
+ } else if (IS_ERR(tdev->rx_mmio)) {
tdev->rx_mmio = tdev->tx_mmio;
+ }
tdev->tx_channel = mbox_test_request_channel(pdev, "tx");
tdev->rx_channel = mbox_test_request_channel(pdev, "rx");
@@ -416,7 +418,7 @@ static int mbox_test_remove(struct platform_device *pdev)
{
struct mbox_test_device *tdev = platform_get_drvdata(pdev);
- debugfs_remove_recursive(root_debugfs_dir);
+ debugfs_remove_recursive(tdev->root_debugfs_dir);
if (tdev->tx_channel)
mbox_free_channel(tdev->tx_channel);
diff --git a/drivers/mailbox/stm32-ipcc.c b/drivers/mailbox/stm32-ipcc.c
index 533b0da..cd5ceca 100644
--- a/drivers/mailbox/stm32-ipcc.c
+++ b/drivers/mailbox/stm32-ipcc.c
@@ -276,8 +276,8 @@ static int stm32_ipcc_probe(struct platform_device *pdev)
dev_err(dev, "Failed to set wake up irq\n");
goto err_init_wkp;
}
- } else {
- device_init_wakeup(dev, false);
+ /* disable the wakeup source, let the user enable it or not */
+ device_set_wakeup_enable(dev, false);
}
/* mailbox controller */
--
2.7.4

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,78 @@
From 82c6107d054adcc906e43190ef150840876c2618 Mon Sep 17 00:00:00 2001
From: Romuald JEANNE <romuald.jeanne@st.com>
Date: Tue, 13 Nov 2018 12:23:50 +0100
Subject: [PATCH 10/52] ARM: stm32mp1-r0-rc1: ETH
---
drivers/net/ethernet/stmicro/stmmac/dwmac-stm32.c | 30 ++++++++++++++++++++++-
1 file changed, 29 insertions(+), 1 deletion(-)
diff --git a/drivers/net/ethernet/stmicro/stmmac/dwmac-stm32.c b/drivers/net/ethernet/stmicro/stmmac/dwmac-stm32.c
index 7e2e79d..d1cf145 100644
--- a/drivers/net/ethernet/stmicro/stmmac/dwmac-stm32.c
+++ b/drivers/net/ethernet/stmicro/stmmac/dwmac-stm32.c
@@ -42,6 +42,7 @@ struct stm32_dwmac {
struct clk *clk_ethstp;
struct clk *syscfg_clk;
bool int_phyclk; /* Clock from RCC to drive PHY */
+ int irq_pwr_wakeup;
u32 mode_reg; /* MAC glue-logic mode register */
struct regmap *regmap;
u32 speed;
@@ -232,7 +233,9 @@ static int stm32_dwmac_parse_data(struct stm32_dwmac *dwmac,
static int stm32mp1_parse_data(struct stm32_dwmac *dwmac,
struct device *dev)
{
+ struct platform_device *pdev = to_platform_device(dev);
struct device_node *np = dev->of_node;
+ int err = 0;
dwmac->int_phyclk = of_property_read_bool(np, "st,int-phyclk");
@@ -260,7 +263,26 @@ static int stm32mp1_parse_data(struct stm32_dwmac *dwmac,
return PTR_ERR(dwmac->syscfg_clk);
}
- return 0;
+ /* Get IRQ information early to have an ability to ask for deferred
+ * probe if needed before we went too far with resource allocation.
+ */
+ dwmac->irq_pwr_wakeup = platform_get_irq_byname(pdev,
+ "stm32_pwr_wakeup");
+ if (!dwmac->int_phyclk && dwmac->irq_pwr_wakeup >= 0) {
+ err = device_init_wakeup(&pdev->dev, true);
+ if (err) {
+ dev_err(&pdev->dev, "Failed to init wake up irq\n");
+ return err;
+ }
+ err = dev_pm_set_dedicated_wake_irq(&pdev->dev,
+ dwmac->irq_pwr_wakeup);
+ if (err) {
+ dev_err(&pdev->dev, "Failed to set wake up irq\n");
+ device_init_wakeup(&pdev->dev, false);
+ }
+ device_set_wakeup_enable(&pdev->dev, false);
+ }
+ return err;
}
static int stm32_dwmac_probe(struct platform_device *pdev)
@@ -326,9 +348,15 @@ static int stm32_dwmac_remove(struct platform_device *pdev)
struct net_device *ndev = platform_get_drvdata(pdev);
struct stmmac_priv *priv = netdev_priv(ndev);
int ret = stmmac_dvr_remove(&pdev->dev);
+ struct stm32_dwmac *dwmac = priv->plat->bsp_priv;
stm32_dwmac_clk_disable(priv->plat->bsp_priv);
+ if (dwmac->irq_pwr_wakeup >= 0) {
+ dev_pm_clear_wake_irq(&pdev->dev);
+ device_init_wakeup(&pdev->dev, false);
+ }
+
return ret;
}
--
2.7.4

View File

@ -0,0 +1,335 @@
From a38a0eadf1db60bd8d1ff084c2ddc8016432b4fb Mon Sep 17 00:00:00 2001
From: Romuald JEANNE <romuald.jeanne@st.com>
Date: Tue, 13 Nov 2018 12:25:05 +0100
Subject: [PATCH 11/52] ARM: stm32mp1-r0-rc1: NVMEM
---
drivers/nvmem/Kconfig | 10 ++
drivers/nvmem/Makefile | 2 +
drivers/nvmem/core.c | 37 ++++++++
drivers/nvmem/stm32-romem.c | 205 +++++++++++++++++++++++++++++++++++++++++
include/linux/nvmem-consumer.h | 7 ++
5 files changed, 261 insertions(+)
create mode 100644 drivers/nvmem/stm32-romem.c
diff --git a/drivers/nvmem/Kconfig b/drivers/nvmem/Kconfig
index 0a7a470e..f398b18 100644
--- a/drivers/nvmem/Kconfig
+++ b/drivers/nvmem/Kconfig
@@ -113,6 +113,16 @@ config NVMEM_BCM_OCOTP
This driver can also be built as a module. If so, the module
will be called nvmem-bcm-ocotp.
+config NVMEM_STM32_ROMEM
+ tristate "STMicroelectronics STM32 factory-programmed memory support"
+ depends on ARCH_STM32 || COMPILE_TEST
+ help
+ Say y here to enable read-only access for STMicroelectronics STM32
+ factory-programmed memory area.
+
+ This driver can also be built as a module. If so, the module
+ will be called nvmem-stm32-romem.
+
config NVMEM_SUNXI_SID
tristate "Allwinner SoCs SID support"
depends on ARCH_SUNXI
diff --git a/drivers/nvmem/Makefile b/drivers/nvmem/Makefile
index 4e8c616..e85c946 100644
--- a/drivers/nvmem/Makefile
+++ b/drivers/nvmem/Makefile
@@ -26,6 +26,8 @@ nvmem_qfprom-y := qfprom.o
obj-$(CONFIG_ROCKCHIP_EFUSE) += nvmem_rockchip_efuse.o
nvmem_rockchip_efuse-y := rockchip-efuse.o
obj-$(CONFIG_NVMEM_SUNXI_SID) += nvmem_sunxi_sid.o
+nvmem_stm32_romem-y := stm32-romem.o
+obj-$(CONFIG_NVMEM_STM32_ROMEM) += nvmem_stm32_romem.o
nvmem_sunxi_sid-y := sunxi_sid.o
obj-$(CONFIG_UNIPHIER_EFUSE) += nvmem-uniphier-efuse.o
nvmem-uniphier-efuse-y := uniphier-efuse.o
diff --git a/drivers/nvmem/core.c b/drivers/nvmem/core.c
index 7c530c8..60dacd7 100644
--- a/drivers/nvmem/core.c
+++ b/drivers/nvmem/core.c
@@ -1234,6 +1234,43 @@ int nvmem_cell_read_u32(struct device *dev, const char *cell_id, u32 *val)
EXPORT_SYMBOL_GPL(nvmem_cell_read_u32);
/**
+ * nvmem_cell_read_u16() - Read a cell value as an u16
+ *
+ * @dev: Device that requests the nvmem cell.
+ * @cell_id: Name of nvmem cell to read.
+ * @val: pointer to output value.
+ *
+ * Return: 0 on success or negative errno.
+ */
+int nvmem_cell_read_u16(struct device *dev, const char *cell_id, u16 *val)
+{
+ struct nvmem_cell *cell;
+ void *buf;
+ size_t len;
+
+ cell = nvmem_cell_get(dev, cell_id);
+ if (IS_ERR(cell))
+ return PTR_ERR(cell);
+
+ buf = nvmem_cell_read(cell, &len);
+ if (IS_ERR(buf)) {
+ nvmem_cell_put(cell);
+ return PTR_ERR(buf);
+ }
+ if (len != sizeof(*val)) {
+ kfree(buf);
+ nvmem_cell_put(cell);
+ return -EINVAL;
+ }
+ memcpy(val, buf, sizeof(*val));
+ kfree(buf);
+ nvmem_cell_put(cell);
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(nvmem_cell_read_u16);
+
+/**
* nvmem_device_cell_read() - Read a given nvmem device and cell
*
* @nvmem: nvmem device to read from.
diff --git a/drivers/nvmem/stm32-romem.c b/drivers/nvmem/stm32-romem.c
new file mode 100644
index 0000000..198872f
--- /dev/null
+++ b/drivers/nvmem/stm32-romem.c
@@ -0,0 +1,205 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * STM32 Factory-programmed memory read access driver
+ *
+ * Copyright (C) 2017, STMicroelectronics - All Rights Reserved
+ * Author: Fabrice Gasnier <fabrice.gasnier@st.com> for STMicroelectronics.
+ */
+
+#include <linux/arm-smccc.h>
+#include <linux/io.h>
+#include <linux/module.h>
+#include <linux/nvmem-provider.h>
+#include <linux/of_device.h>
+
+/* BSEC secure service access from non-secure */
+#define STM32_SMC_BSEC 0x82001003
+#define STM32_SMC_READ_SHADOW 0x01
+#define STM32_SMC_PROG_OTP 0x02
+#define STM32_SMC_WRITE_SHADOW 0x03
+#define STM32_SMC_READ_OTP 0x04
+
+struct stm32_romem_cfg {
+ int size;
+};
+
+struct stm32_romem_priv {
+ void __iomem *base;
+ struct nvmem_config cfg;
+ struct device *dev;
+};
+
+static int stm32_romem_read(void *context, unsigned int offset, void *buf,
+ size_t bytes)
+{
+ struct stm32_romem_priv *priv = context;
+ u8 *buf8 = buf;
+ int i;
+
+ for (i = offset; i < offset + bytes; i++)
+ *buf8++ = readb_relaxed(priv->base + i);
+
+ return 0;
+}
+
+static int stm32_bsec_smc(u8 op, u32 otp, u32 data, u32 *result)
+{
+#if IS_ENABLED(CONFIG_HAVE_ARM_SMCCC)
+ struct arm_smccc_res res;
+
+ arm_smccc_smc(STM32_SMC_BSEC, op, otp, data, 0, 0, 0, 0, &res);
+ if (res.a0)
+ return -EIO;
+
+ if (result)
+ *result = (u32)res.a1;
+
+ return 0;
+#else
+ return -ENXIO;
+#endif
+}
+
+static int stm32_bsec_read(void *context, unsigned int offset, void *buf,
+ size_t bytes)
+{
+ struct stm32_romem_priv *priv = context;
+ u32 roffset, rbytes, val;
+ u8 *buf8 = buf, *val8 = (u8 *)&val;
+ int i, j = 0, ret, skip_bytes, size;
+
+ /* Round unaligned access to 32-bits */
+ roffset = rounddown(offset, 4);
+ skip_bytes = offset & 0x3;
+ rbytes = roundup(bytes + skip_bytes, 4);
+
+ if (roffset + rbytes > priv->cfg.size)
+ return -EINVAL;
+
+ for (i = roffset; (i < roffset + rbytes); i += 4) {
+ ret = stm32_bsec_smc(STM32_SMC_READ_OTP, i >> 2, 0, &val);
+ if (ret) {
+ dev_err(priv->dev, "Failed to read data%d (%d)\n",
+ i >> 2, ret);
+ return ret;
+ }
+
+ /* skip first bytes in case of unaligned read */
+ if (skip_bytes)
+ size = min(bytes, (size_t)(4 - skip_bytes));
+ else
+ size = min(bytes, (size_t)4);
+ memcpy(&buf8[j], &val8[skip_bytes], size);
+ bytes -= size;
+ j += size;
+ skip_bytes = 0;
+ }
+
+ return 0;
+}
+
+static int stm32_bsec_write(void *context, unsigned int offset, void *buf,
+ size_t bytes)
+{
+ struct stm32_romem_priv *priv = context;
+ u32 *buf32 = buf;
+ int ret, i;
+
+ /* Allow only writing complete 32-bits aligned words */
+ if ((bytes % 4) || (offset % 4))
+ return -EINVAL;
+
+ for (i = offset; i < offset + bytes; i += 4) {
+ ret = stm32_bsec_smc(STM32_SMC_PROG_OTP, i >> 2, *buf32++,
+ NULL);
+ if (ret) {
+ dev_err(priv->dev, "Failed to write data%d (%d)\n",
+ i >> 2, ret);
+ return ret;
+ }
+ }
+
+ return 0;
+}
+
+static int stm32_romem_probe(struct platform_device *pdev)
+{
+ const struct stm32_romem_cfg *cfg;
+ struct device *dev = &pdev->dev;
+ struct stm32_romem_priv *priv;
+ struct nvmem_device *nvmem;
+ struct resource *res;
+
+ priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL);
+ if (!priv)
+ return -ENOMEM;
+
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ priv->base = devm_ioremap_resource(&pdev->dev, res);
+ if (IS_ERR(priv->base))
+ return PTR_ERR(priv->base);
+
+ priv->dev = dev;
+ priv->cfg.name = "stm32-romem";
+ priv->cfg.word_size = 1;
+ priv->cfg.stride = 1;
+ priv->cfg.dev = &pdev->dev;
+ priv->cfg.priv = priv;
+ priv->cfg.owner = THIS_MODULE;
+
+ cfg = (const struct stm32_romem_cfg *)
+ of_match_device(dev->driver->of_match_table, dev)->data;
+ if (!cfg) {
+ priv->cfg.read_only = true;
+ priv->cfg.size = resource_size(res);
+ priv->cfg.reg_read = stm32_romem_read;
+ } else {
+ priv->cfg.read_only = false;
+ priv->cfg.size = cfg->size;
+ priv->cfg.reg_read = stm32_bsec_read;
+ priv->cfg.reg_write = stm32_bsec_write;
+ }
+
+ nvmem = nvmem_register(&priv->cfg);
+ if (IS_ERR(nvmem))
+ return PTR_ERR(nvmem);
+
+ platform_set_drvdata(pdev, nvmem);
+
+ return 0;
+}
+
+static int stm32_romem_remove(struct platform_device *pdev)
+{
+ struct nvmem_device *nvmem = platform_get_drvdata(pdev);
+
+ return nvmem_unregister(nvmem);
+}
+
+static const struct stm32_romem_cfg stm32mp15_bsec_cfg = {
+ .size = 384, /* 96 x 32-bits data words */
+};
+
+static const struct of_device_id stm32_romem_of_match[] = {
+ { .compatible = "st,stm32-romem", }, {
+ .compatible = "st,stm32mp15-bsec",
+ .data = (void *)&stm32mp15_bsec_cfg,
+ }, {
+ },
+};
+MODULE_DEVICE_TABLE(of, stm32_romem_of_match);
+
+static struct platform_driver stm32_romem_driver = {
+ .probe = stm32_romem_probe,
+ .remove = stm32_romem_remove,
+ .driver = {
+ .name = "stm32-romem",
+ .of_match_table = of_match_ptr(stm32_romem_of_match),
+ },
+};
+module_platform_driver(stm32_romem_driver);
+
+MODULE_AUTHOR("Fabrice Gasnier <fabrice.gasnier@st.com>");
+MODULE_DESCRIPTION("STMicroelectronics STM32 RO-MEM");
+MODULE_ALIAS("platform:nvmem-stm32-romem");
+MODULE_LICENSE("GPL v2");
diff --git a/include/linux/nvmem-consumer.h b/include/linux/nvmem-consumer.h
index 4e85447..f303008 100644
--- a/include/linux/nvmem-consumer.h
+++ b/include/linux/nvmem-consumer.h
@@ -39,6 +39,7 @@ void devm_nvmem_cell_put(struct device *dev, struct nvmem_cell *cell);
void *nvmem_cell_read(struct nvmem_cell *cell, size_t *len);
int nvmem_cell_write(struct nvmem_cell *cell, void *buf, size_t len);
int nvmem_cell_read_u32(struct device *dev, const char *cell_id, u32 *val);
+int nvmem_cell_read_u16(struct device *dev, const char *cell_id, u16 *val);
/* direct nvmem device read/write interface */
struct nvmem_device *nvmem_device_get(struct device *dev, const char *name);
@@ -95,6 +96,12 @@ static inline int nvmem_cell_read_u32(struct device *dev,
return -ENOSYS;
}
+static inline int nvmem_cell_read_u16(struct device *dev,
+ const char *cell_id, u16 *val)
+{
+ return -ENOSYS;
+}
+
static inline struct nvmem_device *nvmem_device_get(struct device *dev,
const char *name)
{
--
2.7.4

View File

@ -0,0 +1,192 @@
From 0d162ed61018cda930bb77680ab88b63633d5ce0 Mon Sep 17 00:00:00 2001
From: Romuald JEANNE <romuald.jeanne@st.com>
Date: Tue, 13 Nov 2018 12:29:27 +0100
Subject: [PATCH 14/52] ARM: stm32mp1-r0-rc1: WATCHDOG
---
drivers/watchdog/Kconfig | 12 ++++
drivers/watchdog/Makefile | 1 +
drivers/watchdog/stpmic1_wdt.c | 139 +++++++++++++++++++++++++++++++++++++++++
3 files changed, 152 insertions(+)
create mode 100644 drivers/watchdog/stpmic1_wdt.c
diff --git a/drivers/watchdog/Kconfig b/drivers/watchdog/Kconfig
index 5ea8909..6d2ffef 100644
--- a/drivers/watchdog/Kconfig
+++ b/drivers/watchdog/Kconfig
@@ -806,6 +806,18 @@ config STM32_WATCHDOG
To compile this driver as a module, choose M here: the
module will be called stm32_iwdg.
+config STPMIC1_WATCHDOG
+ tristate "STPMIC1 PMIC watchdog support"
+ depends on MFD_STPMIC1
+ select WATCHDOG_CORE
+ help
+ Say Y here to include watchdog support embedded into STPMIC1 PMIC.
+ If the watchdog timer expires, stpmic1 will shut down all its power
+ supplies.
+
+ To compile this driver as a module, choose M here: the
+ module will be called spmic1_wdt.
+
config UNIPHIER_WATCHDOG
tristate "UniPhier watchdog support"
depends on ARCH_UNIPHIER || COMPILE_TEST
diff --git a/drivers/watchdog/Makefile b/drivers/watchdog/Makefile
index bf92e7b..2649cf3 100644
--- a/drivers/watchdog/Makefile
+++ b/drivers/watchdog/Makefile
@@ -217,3 +217,4 @@ obj-$(CONFIG_SOFT_WATCHDOG) += softdog.o
obj-$(CONFIG_MENF21BMC_WATCHDOG) += menf21bmc_wdt.o
obj-$(CONFIG_MENZ069_WATCHDOG) += menz69_wdt.o
obj-$(CONFIG_RAVE_SP_WATCHDOG) += rave-sp-wdt.o
+obj-$(CONFIG_STPMIC1_WATCHDOG) += stpmic1_wdt.o
diff --git a/drivers/watchdog/stpmic1_wdt.c b/drivers/watchdog/stpmic1_wdt.c
new file mode 100644
index 0000000..a6cbc27
--- /dev/null
+++ b/drivers/watchdog/stpmic1_wdt.c
@@ -0,0 +1,139 @@
+// SPDX-License-Identifier: GPL-2.0
+// Copyright (C) STMicroelectronics 2018
+// Author: Pascal Paillet <p.paillet@st.com> for STMicroelectronics.
+
+#include <linux/kernel.h>
+#include <linux/mfd/stpmic1.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/of.h>
+#include <linux/regmap.h>
+#include <linux/slab.h>
+#include <linux/watchdog.h>
+
+/* WATCHDOG CONTROL REGISTER bit */
+#define WDT_START BIT(0)
+#define WDT_PING BIT(1)
+#define WDT_START_MASK BIT(0)
+#define WDT_PING_MASK BIT(1)
+#define WDT_STOP 0
+
+#define PMIC_WDT_MIN_TIMEOUT 1
+#define PMIC_WDT_MAX_TIMEOUT 256
+#define PMIC_WDT_DEFAULT_TIMEOUT 30
+
+static bool nowayout = WATCHDOG_NOWAYOUT;
+module_param(nowayout, bool, 0);
+MODULE_PARM_DESC(nowayout,
+ "Watchdog cannot be stopped once started (default="
+ __MODULE_STRING(WATCHDOG_NOWAYOUT) ")");
+
+struct stpmic1_wdt {
+ struct stpmic1 *pmic;
+ struct watchdog_device wdtdev;
+};
+
+static int pmic_wdt_start(struct watchdog_device *wdd)
+{
+ struct stpmic1_wdt *wdt = watchdog_get_drvdata(wdd);
+
+ return regmap_update_bits(wdt->pmic->regmap,
+ WCHDG_CR, WDT_START_MASK, WDT_START);
+}
+
+static int pmic_wdt_stop(struct watchdog_device *wdd)
+{
+ struct stpmic1_wdt *wdt = watchdog_get_drvdata(wdd);
+
+ return regmap_update_bits(wdt->pmic->regmap,
+ WCHDG_CR, WDT_START_MASK, WDT_STOP);
+}
+
+static int pmic_wdt_ping(struct watchdog_device *wdd)
+{
+ struct stpmic1_wdt *wdt = watchdog_get_drvdata(wdd);
+
+ return regmap_update_bits(wdt->pmic->regmap,
+ WCHDG_CR, WDT_PING_MASK, WDT_PING);
+}
+
+static int pmic_wdt_set_timeout(struct watchdog_device *wdd,
+ unsigned int timeout)
+{
+ struct stpmic1_wdt *wdt = watchdog_get_drvdata(wdd);
+
+ wdd->timeout = timeout;
+ /* timeout is equal to register value + 1 */
+ return regmap_write(wdt->pmic->regmap, WCHDG_TIMER_CR, timeout - 1);
+}
+
+static const struct watchdog_info pmic_watchdog_info = {
+ .options = WDIOF_SETTIMEOUT | WDIOF_KEEPALIVEPING | WDIOF_MAGICCLOSE,
+ .identity = "STPMIC1 PMIC Watchdog",
+};
+
+static const struct watchdog_ops pmic_watchdog_ops = {
+ .owner = THIS_MODULE,
+ .start = pmic_wdt_start,
+ .stop = pmic_wdt_stop,
+ .ping = pmic_wdt_ping,
+ .set_timeout = pmic_wdt_set_timeout,
+};
+
+static int pmic_wdt_probe(struct platform_device *pdev)
+{
+ int ret;
+ struct stpmic1 *pmic;
+ struct stpmic1_wdt *wdt;
+
+ if (!pdev->dev.parent)
+ return -EINVAL;
+
+ pmic = dev_get_drvdata(pdev->dev.parent);
+ if (!pmic)
+ return -EINVAL;
+
+ wdt = devm_kzalloc(&pdev->dev, sizeof(struct stpmic1_wdt), GFP_KERNEL);
+ if (!wdt)
+ return -ENOMEM;
+
+ wdt->pmic = pmic;
+
+ wdt->wdtdev.info = &pmic_watchdog_info;
+ wdt->wdtdev.ops = &pmic_watchdog_ops;
+ wdt->wdtdev.min_timeout = PMIC_WDT_MIN_TIMEOUT;
+ wdt->wdtdev.max_timeout = PMIC_WDT_MAX_TIMEOUT;
+
+ wdt->wdtdev.timeout = PMIC_WDT_DEFAULT_TIMEOUT;
+ watchdog_init_timeout(&wdt->wdtdev, 0, &pdev->dev);
+
+ watchdog_set_nowayout(&wdt->wdtdev, nowayout);
+ watchdog_set_drvdata(&wdt->wdtdev, wdt);
+
+ ret = devm_watchdog_register_device(&pdev->dev, &wdt->wdtdev);
+ if (ret)
+ return ret;
+
+ dev_dbg(wdt->pmic->dev, "PMIC Watchdog driver probed\n");
+ return 0;
+}
+
+static const struct of_device_id of_pmic_wdt_match[] = {
+ { .compatible = "st,stpmic1-wdt" },
+ { },
+};
+
+MODULE_DEVICE_TABLE(of, of_pmic_wdt_match);
+
+static struct platform_driver stpmic1_wdt_driver = {
+ .probe = pmic_wdt_probe,
+ .driver = {
+ .name = "stpmic1-wdt",
+ .of_match_table = of_pmic_wdt_match,
+ },
+};
+module_platform_driver(stpmic1_wdt_driver);
+
+MODULE_DESCRIPTION("Watchdog driver for STPMIC1 device");
+MODULE_AUTHOR("Pascal Paillet <p.paillet@st.com>");
+MODULE_LICENSE("GPL v2");
--
2.7.4

View File

@ -0,0 +1,901 @@
From 535343fc0142b45ec82958a4cbea41945d4d93c9 Mon Sep 17 00:00:00 2001
From: Romuald JEANNE <romuald.jeanne@st.com>
Date: Tue, 13 Nov 2018 12:30:43 +0100
Subject: [PATCH 15/52] ARM: stm32mp1-r0-rc1: MISC
---
arch/arm/mach-integrator/integrator_cp.c | 2 -
arch/arm/mach-versatile/versatile_dt.c | 4 -
drivers/soc/Kconfig | 1 +
drivers/soc/Makefile | 1 +
drivers/soc/st/Kconfig | 9 +
drivers/soc/st/Makefile | 1 +
drivers/soc/st/stm32_pm_domain.c | 212 ++++++++++++
drivers/spi/Kconfig | 9 +
drivers/spi/Makefile | 1 +
drivers/spi/spi-stm32-qspi.c | 541 +++++++++++++++++++++++++++++++
10 files changed, 775 insertions(+), 6 deletions(-)
create mode 100644 drivers/soc/st/Kconfig
create mode 100644 drivers/soc/st/Makefile
create mode 100644 drivers/soc/st/stm32_pm_domain.c
create mode 100644 drivers/spi/spi-stm32-qspi.c
diff --git a/arch/arm/mach-integrator/integrator_cp.c b/arch/arm/mach-integrator/integrator_cp.c
index 772a7cf..976ded5 100644
--- a/arch/arm/mach-integrator/integrator_cp.c
+++ b/arch/arm/mach-integrator/integrator_cp.c
@@ -80,8 +80,6 @@ static unsigned int mmc_status(struct device *dev)
static struct mmci_platform_data mmc_data = {
.ocr_mask = MMC_VDD_32_33|MMC_VDD_33_34,
.status = mmc_status,
- .gpio_wp = -1,
- .gpio_cd = -1,
};
static u64 notrace intcp_read_sched_clock(void)
diff --git a/arch/arm/mach-versatile/versatile_dt.c b/arch/arm/mach-versatile/versatile_dt.c
index 3c8d39c..e9d6068 100644
--- a/arch/arm/mach-versatile/versatile_dt.c
+++ b/arch/arm/mach-versatile/versatile_dt.c
@@ -89,15 +89,11 @@ unsigned int mmc_status(struct device *dev)
static struct mmci_platform_data mmc0_plat_data = {
.ocr_mask = MMC_VDD_32_33|MMC_VDD_33_34,
.status = mmc_status,
- .gpio_wp = -1,
- .gpio_cd = -1,
};
static struct mmci_platform_data mmc1_plat_data = {
.ocr_mask = MMC_VDD_32_33|MMC_VDD_33_34,
.status = mmc_status,
- .gpio_wp = -1,
- .gpio_cd = -1,
};
/*
diff --git a/drivers/soc/Kconfig b/drivers/soc/Kconfig
index c07b4a8..f2bd1ce 100644
--- a/drivers/soc/Kconfig
+++ b/drivers/soc/Kconfig
@@ -11,6 +11,7 @@ source "drivers/soc/qcom/Kconfig"
source "drivers/soc/renesas/Kconfig"
source "drivers/soc/rockchip/Kconfig"
source "drivers/soc/samsung/Kconfig"
+source "drivers/soc/st/Kconfig"
source "drivers/soc/sunxi/Kconfig"
source "drivers/soc/tegra/Kconfig"
source "drivers/soc/ti/Kconfig"
diff --git a/drivers/soc/Makefile b/drivers/soc/Makefile
index 113e884..a16f673 100644
--- a/drivers/soc/Makefile
+++ b/drivers/soc/Makefile
@@ -18,6 +18,7 @@ obj-y += qcom/
obj-y += renesas/
obj-$(CONFIG_ARCH_ROCKCHIP) += rockchip/
obj-$(CONFIG_SOC_SAMSUNG) += samsung/
+obj-$(CONFIG_ARCH_STM32) += st/
obj-$(CONFIG_ARCH_SUNXI) += sunxi/
obj-$(CONFIG_ARCH_TEGRA) += tegra/
obj-$(CONFIG_SOC_TI) += ti/
diff --git a/drivers/soc/st/Kconfig b/drivers/soc/st/Kconfig
new file mode 100644
index 0000000..82ee423
--- /dev/null
+++ b/drivers/soc/st/Kconfig
@@ -0,0 +1,9 @@
+if ARCH_STM32
+
+config STM32_PM_DOMAINS
+ bool "STM32 PM domains"
+ depends on MACH_STM32MP157
+ select PM_GENERIC_DOMAINS
+ default y if MACH_STM32MP157
+
+endif # ARCH_STM32
diff --git a/drivers/soc/st/Makefile b/drivers/soc/st/Makefile
new file mode 100644
index 0000000..8d7f291
--- /dev/null
+++ b/drivers/soc/st/Makefile
@@ -0,0 +1 @@
+obj-$(CONFIG_STM32_PM_DOMAINS) += stm32_pm_domain.o
diff --git a/drivers/soc/st/stm32_pm_domain.c b/drivers/soc/st/stm32_pm_domain.c
new file mode 100644
index 0000000..0386624
--- /dev/null
+++ b/drivers/soc/st/stm32_pm_domain.c
@@ -0,0 +1,212 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (C) STMicroelectronics 2018 - All Rights Reserved
+ * Author: Alexandre Torgue <alexandre.torgue@st.com> for STMicroelectronics.
+ * Author: Olivier Bideau <olivier.bideau@st.com> for STMicroelectronics.
+ */
+
+#include <linux/arm-smccc.h>
+#include <linux/err.h>
+#include <linux/io.h>
+#include <linux/of.h>
+#include <linux/of_platform.h>
+#include <linux/pm_domain.h>
+#include <linux/printk.h>
+#include <linux/slab.h>
+
+#define SMC(domain, state) \
+{ \
+ struct arm_smccc_res res; \
+ arm_smccc_smc(0x82001008, domain, state, 0, \
+ 0, 0, 0, 0, &res); \
+}
+
+#define STM32_SMC_PD_DOMAIN_ON 0
+#define STM32_SMC_PD_DOMAIN_OFF 1
+
+struct stm32_pm_domain {
+ struct device *dev;
+ struct generic_pm_domain genpd;
+ int id;
+};
+
+static int stm32_pd_power_off(struct generic_pm_domain *domain)
+{
+ struct stm32_pm_domain *priv = container_of(domain,
+ struct stm32_pm_domain,
+ genpd);
+
+ SMC(priv->id, STM32_SMC_PD_DOMAIN_OFF);
+
+ dev_dbg(priv->dev, "%s OFF\n", domain->name);
+
+ return 0;
+}
+
+static int stm32_pd_power_on(struct generic_pm_domain *domain)
+{
+ struct stm32_pm_domain *priv = container_of(domain,
+ struct stm32_pm_domain,
+ genpd);
+
+ SMC(priv->id, STM32_SMC_PD_DOMAIN_ON);
+
+ dev_dbg(priv->dev, "%s ON\n", domain->name);
+
+ return 0;
+}
+
+static void stm32_pm_domain_remove(struct stm32_pm_domain *domain)
+{
+ int ret;
+
+ ret = pm_genpd_remove(&domain->genpd);
+ if (ret)
+ dev_err(domain->dev, "failed to remove PM domain %s: %d\n",
+ domain->genpd.name, ret);
+}
+
+static int stm32_pm_domain_add(struct stm32_pm_domain *domain,
+ struct device *dev,
+ struct device_node *np)
+{
+ int ret;
+
+ domain->dev = dev;
+ domain->genpd.name = np->name;
+ domain->genpd.power_off = stm32_pd_power_off;
+ domain->genpd.power_on = stm32_pd_power_on;
+ domain->genpd.flags |= GENPD_FLAG_ACTIVE_WAKEUP;
+
+ ret = of_property_read_u32(np, "reg", &domain->id);
+ if (ret) {
+ dev_err(domain->dev, "no domain ID\n");
+ return ret;
+ }
+
+ ret = pm_genpd_init(&domain->genpd, NULL, 0);
+ if (ret < 0) {
+ dev_err(domain->dev, "failed to initialise PM domain %s: %d\n",
+ np->name, ret);
+ return ret;
+ }
+
+ ret = of_genpd_add_provider_simple(np, &domain->genpd);
+ if (ret < 0) {
+ dev_err(domain->dev, "failed to register PM domain %s: %d\n",
+ np->name, ret);
+ stm32_pm_domain_remove(domain);
+ return ret;
+ }
+
+ dev_info(domain->dev, "domain %s registered\n", np->name);
+
+ return 0;
+}
+
+static void stm32_pm_subdomain_add(struct stm32_pm_domain *domain,
+ struct device *dev,
+ struct device_node *np)
+{
+ struct device_node *np_child;
+ int ret;
+
+ for_each_child_of_node(np, np_child) {
+ struct stm32_pm_domain *sub_domain;
+
+ sub_domain = devm_kzalloc(dev, sizeof(*sub_domain), GFP_KERNEL);
+ if (!sub_domain)
+ continue;
+
+ sub_domain->dev = dev;
+ sub_domain->genpd.name = np_child->name;
+ sub_domain->genpd.power_off = stm32_pd_power_off;
+ sub_domain->genpd.power_on = stm32_pd_power_on;
+ sub_domain->genpd.flags |= GENPD_FLAG_ACTIVE_WAKEUP;
+
+ ret = of_property_read_u32(np_child, "reg", &sub_domain->id);
+ if (ret) {
+ dev_err(sub_domain->dev, "no domain ID\n");
+ devm_kfree(dev, sub_domain);
+ continue;
+ }
+
+ ret = pm_genpd_init(&sub_domain->genpd, NULL, 0);
+ if (ret < 0) {
+ dev_err(sub_domain->dev, "failed to initialise PM domain %s: %d\n"
+ , np_child->name, ret);
+ devm_kfree(dev, sub_domain);
+ continue;
+ }
+
+ ret = of_genpd_add_provider_simple(np_child,
+ &sub_domain->genpd);
+ if (ret < 0) {
+ dev_err(sub_domain->dev, "failed to register PM domain %s: %d\n"
+ , np_child->name, ret);
+ stm32_pm_domain_remove(sub_domain);
+ devm_kfree(dev, sub_domain);
+ continue;
+ }
+
+ ret = pm_genpd_add_subdomain(&domain->genpd,
+ &sub_domain->genpd);
+
+ if (ret < 0) {
+ dev_err(sub_domain->dev, "failed to add Sub PM domain %s: %d\n"
+ , np_child->name, ret);
+ stm32_pm_domain_remove(sub_domain);
+ devm_kfree(dev, sub_domain);
+ continue;
+ }
+
+ dev_info(sub_domain->dev, "subdomain %s registered\n",
+ np_child->name);
+ }
+}
+
+static int stm32_pm_domain_probe(struct platform_device *pdev)
+{
+ struct device *dev = &pdev->dev;
+ struct device_node *np = dev->of_node, *child_np;
+ int ret;
+
+ for_each_child_of_node(np, child_np) {
+ struct stm32_pm_domain *domain;
+
+ domain = devm_kzalloc(dev, sizeof(*domain), GFP_KERNEL);
+ if (!domain)
+ continue;
+
+ ret = stm32_pm_domain_add(domain, dev, child_np);
+ if (ret) {
+ devm_kfree(dev, domain);
+ continue;
+ }
+
+ stm32_pm_subdomain_add(domain, dev, child_np);
+ }
+
+ dev_info(dev, "domains probed\n");
+
+ return 0;
+}
+
+static const struct of_device_id stm32_pm_domain_matches[] = {
+ { .compatible = "st,stm32mp157c-pd", },
+ { },
+};
+
+static struct platform_driver stm32_pm_domains_driver = {
+ .probe = stm32_pm_domain_probe,
+ .driver = {
+ .name = "stm32-pm-domain",
+ .of_match_table = stm32_pm_domain_matches,
+ },
+};
+
+static int __init stm32_pm_domains_init(void)
+{
+ return platform_driver_register(&stm32_pm_domains_driver);
+}
+core_initcall(stm32_pm_domains_init);
diff --git a/drivers/spi/Kconfig b/drivers/spi/Kconfig
index 671d078..448d441 100644
--- a/drivers/spi/Kconfig
+++ b/drivers/spi/Kconfig
@@ -613,6 +613,15 @@ config SPI_STM32
is not available, the driver automatically falls back to
PIO mode.
+config SPI_STM32_QSPI
+ tristate "STMicroelectronics STM32 QUAD SPI controller"
+ depends on ARCH_STM32 || COMPILE_TEST
+ depends on OF
+ help
+ This enables support for the Quad SPI controller in master mode.
+ This driver does not support generic SPI. The implementation only
+ supports spi-mem interface.
+
config SPI_ST_SSC4
tristate "STMicroelectronics SPI SSC-based driver"
depends on ARCH_STI || COMPILE_TEST
diff --git a/drivers/spi/Makefile b/drivers/spi/Makefile
index a90d559..68a3c4e 100644
--- a/drivers/spi/Makefile
+++ b/drivers/spi/Makefile
@@ -90,6 +90,7 @@ obj-$(CONFIG_SPI_SH_SCI) += spi-sh-sci.o
obj-$(CONFIG_SPI_SIRF) += spi-sirf.o
obj-$(CONFIG_SPI_SPRD_ADI) += spi-sprd-adi.o
obj-$(CONFIG_SPI_STM32) += spi-stm32.o
+obj-$(CONFIG_SPI_STM32_QSPI) += spi-stm32-qspi.o
obj-$(CONFIG_SPI_ST_SSC4) += spi-st-ssc4.o
obj-$(CONFIG_SPI_SUN4I) += spi-sun4i.o
obj-$(CONFIG_SPI_SUN6I) += spi-sun6i.o
diff --git a/drivers/spi/spi-stm32-qspi.c b/drivers/spi/spi-stm32-qspi.c
new file mode 100644
index 0000000..3e8ca10
--- /dev/null
+++ b/drivers/spi/spi-stm32-qspi.c
@@ -0,0 +1,541 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (C) STMicroelectronics 2018 - All Rights Reserved
+ * Author: Ludovic Barre <ludovic.barre@st.com> for STMicroelectronics.
+ */
+#include <linux/bitfield.h>
+#include <linux/clk.h>
+#include <linux/errno.h>
+#include <linux/io.h>
+#include <linux/iopoll.h>
+#include <linux/interrupt.h>
+#include <linux/module.h>
+#include <linux/mutex.h>
+#include <linux/of.h>
+#include <linux/of_device.h>
+#include <linux/pinctrl/consumer.h>
+#include <linux/platform_device.h>
+#include <linux/reset.h>
+#include <linux/sizes.h>
+#include <linux/spi/spi-mem.h>
+
+#define QSPI_CR 0x00
+#define CR_EN BIT(0)
+#define CR_ABORT BIT(1)
+#define CR_DMAEN BIT(2)
+#define CR_TCEN BIT(3)
+#define CR_SSHIFT BIT(4)
+#define CR_DFM BIT(6)
+#define CR_FSEL BIT(7)
+#define CR_FTHRES_MASK GENMASK(12, 8)
+#define CR_TEIE BIT(16)
+#define CR_TCIE BIT(17)
+#define CR_FTIE BIT(18)
+#define CR_SMIE BIT(19)
+#define CR_TOIE BIT(20)
+#define CR_PRESC_MASK GENMASK(31, 24)
+
+#define QSPI_DCR 0x04
+#define DCR_FSIZE_MASK GENMASK(20, 16)
+
+#define QSPI_SR 0x08
+#define SR_TEF BIT(0)
+#define SR_TCF BIT(1)
+#define SR_FTF BIT(2)
+#define SR_SMF BIT(3)
+#define SR_TOF BIT(4)
+#define SR_BUSY BIT(5)
+#define SR_FLEVEL_MASK GENMASK(13, 8)
+
+#define QSPI_FCR 0x0c
+#define FCR_CTEF BIT(0)
+#define FCR_CTCF BIT(1)
+
+#define QSPI_DLR 0x10
+
+#define QSPI_CCR 0x14
+#define CCR_INST_MASK GENMASK(7, 0)
+#define CCR_IMODE_MASK GENMASK(9, 8)
+#define CCR_ADMODE_MASK GENMASK(11, 10)
+#define CCR_ADSIZE_MASK GENMASK(13, 12)
+#define CCR_DCYC_MASK GENMASK(22, 18)
+#define CCR_DMODE_MASK GENMASK(25, 24)
+#define CCR_FMODE_MASK GENMASK(27, 26)
+#define CCR_FMODE_INDW (0U << 26)
+#define CCR_FMODE_INDR (1U << 26)
+#define CCR_FMODE_APM (2U << 26)
+#define CCR_FMODE_MM (3U << 26)
+#define CCR_BUSWIDTH_0 0x0
+#define CCR_BUSWIDTH_1 0x1
+#define CCR_BUSWIDTH_2 0x2
+#define CCR_BUSWIDTH_4 0x3
+
+#define QSPI_AR 0x18
+#define QSPI_ABR 0x1c
+#define QSPI_DR 0x20
+#define QSPI_PSMKR 0x24
+#define QSPI_PSMAR 0x28
+#define QSPI_PIR 0x2c
+#define QSPI_LPTR 0x30
+
+#define STM32_QSPI_MAX_MMAP_SZ SZ_256M
+#define STM32_QSPI_MAX_NORCHIP 2
+
+#define STM32_FIFO_TIMEOUT_US 30000
+#define STM32_BUSY_TIMEOUT_US 100000
+#define STM32_ABT_TIMEOUT_US 100000
+
+struct stm32_qspi_flash {
+ struct stm32_qspi *qspi;
+ u32 cs;
+ u32 presc;
+};
+
+struct stm32_qspi {
+ struct device *dev;
+ void __iomem *io_base;
+ void __iomem *mm_base;
+ resource_size_t mm_size;
+ struct clk *clk;
+ u32 clk_rate;
+ struct stm32_qspi_flash flash[STM32_QSPI_MAX_NORCHIP];
+ struct completion data_completion;
+ u32 fmode;
+
+ u32 cr_reg;
+ u32 dcr_reg;
+
+ /*
+ * to protect device configuration, could be different between
+ * 2 flash access (bk1, bk2)
+ */
+ struct mutex lock;
+};
+
+static irqreturn_t stm32_qspi_irq(int irq, void *dev_id)
+{
+ struct stm32_qspi *qspi = (struct stm32_qspi *)dev_id;
+ u32 cr, sr;
+
+ sr = readl_relaxed(qspi->io_base + QSPI_SR);
+
+ if (sr & (SR_TEF | SR_TCF)) {
+ /* disable irq */
+ cr = readl_relaxed(qspi->io_base + QSPI_CR);
+ cr &= ~CR_TCIE & ~CR_TEIE;
+ writel_relaxed(cr, qspi->io_base + QSPI_CR);
+ complete(&qspi->data_completion);
+ }
+
+ return IRQ_HANDLED;
+}
+
+static void stm32_qspi_read_fifo(u8 *val, void __iomem *addr)
+{
+ *val = readb_relaxed(addr);
+}
+
+static void stm32_qspi_write_fifo(u8 *val, void __iomem *addr)
+{
+ writeb_relaxed(*val, addr);
+}
+
+static int stm32_qspi_tx_poll(struct stm32_qspi *qspi,
+ const struct spi_mem_op *op)
+{
+ void (*tx_fifo)(u8 *val, void __iomem *addr);
+ u32 len = op->data.nbytes, sr;
+ u8 *buf;
+ int ret;
+
+ if (op->data.dir == SPI_MEM_DATA_IN) {
+ tx_fifo = stm32_qspi_read_fifo;
+ buf = op->data.buf.in;
+
+ } else {
+ tx_fifo = stm32_qspi_write_fifo;
+ buf = (u8 *)op->data.buf.out;
+ }
+
+ while (len--) {
+ ret = readl_relaxed_poll_timeout_atomic(qspi->io_base + QSPI_SR,
+ sr, (sr & SR_FTF), 1,
+ STM32_FIFO_TIMEOUT_US);
+ if (ret) {
+ dev_err(qspi->dev, "fifo timeout (len:%d stat:%#x)\n",
+ len, sr);
+ return ret;
+ }
+ tx_fifo(buf++, qspi->io_base + QSPI_DR);
+ }
+
+ return 0;
+}
+
+static int stm32_qspi_tx_mm(struct stm32_qspi *qspi,
+ const struct spi_mem_op *op)
+{
+ memcpy_fromio(op->data.buf.in, qspi->mm_base + op->addr.val,
+ op->data.nbytes);
+ return 0;
+}
+
+static int stm32_qspi_tx(struct stm32_qspi *qspi, const struct spi_mem_op *op)
+{
+ if (!op->data.nbytes)
+ return 0;
+
+ if (qspi->fmode == CCR_FMODE_MM)
+ return stm32_qspi_tx_mm(qspi, op);
+
+ return stm32_qspi_tx_poll(qspi, op);
+}
+
+static int stm32_qspi_wait_nobusy(struct stm32_qspi *qspi)
+{
+ u32 sr;
+
+ return readl_relaxed_poll_timeout_atomic(qspi->io_base + QSPI_SR, sr,
+ !(sr & SR_BUSY), 1,
+ STM32_BUSY_TIMEOUT_US);
+}
+
+static int stm32_qspi_wait_cmd(struct stm32_qspi *qspi,
+ const struct spi_mem_op *op)
+{
+ u32 cr, sr;
+ int err = 0;
+
+ if (!op->data.nbytes)
+ return stm32_qspi_wait_nobusy(qspi);
+
+ if (readl_relaxed(qspi->io_base + QSPI_SR) & SR_TCF)
+ goto out;
+
+ reinit_completion(&qspi->data_completion);
+ cr = readl_relaxed(qspi->io_base + QSPI_CR);
+ writel_relaxed(cr | CR_TCIE | CR_TEIE, qspi->io_base + QSPI_CR);
+
+ if (!wait_for_completion_interruptible_timeout(&qspi->data_completion,
+ msecs_to_jiffies(1000))) {
+ err = -ETIMEDOUT;
+ } else {
+ sr = readl_relaxed(qspi->io_base + QSPI_SR);
+ if (sr & SR_TEF)
+ err = -EIO;
+ }
+
+out:
+ /* clear flags */
+ writel_relaxed(FCR_CTCF | FCR_CTEF, qspi->io_base + QSPI_FCR);
+
+ return err;
+}
+
+static int stm32_qspi_get_mode(struct stm32_qspi *qspi, u8 buswidth)
+{
+ if (buswidth == 4)
+ return CCR_BUSWIDTH_4;
+
+ return buswidth;
+}
+
+static int stm32_qspi_send(struct spi_mem *mem, const struct spi_mem_op *op)
+{
+ struct stm32_qspi *qspi = spi_controller_get_devdata(mem->spi->master);
+ struct stm32_qspi_flash *flash = &qspi->flash[mem->spi->chip_select];
+ u32 ccr, cr, addr_max;
+ int timeout, err = 0;
+
+ dev_dbg(qspi->dev, "cmd:%#x mode:%d.%d.%d.%d addr:%#llx len:%#x\n",
+ op->cmd.opcode, op->cmd.buswidth, op->addr.buswidth,
+ op->dummy.buswidth, op->data.buswidth,
+ op->addr.val, op->data.nbytes);
+
+ err = stm32_qspi_wait_nobusy(qspi);
+ if (err)
+ goto abort;
+
+ addr_max = op->addr.val + op->data.nbytes + 1;
+
+ if (op->data.dir == SPI_MEM_DATA_IN) {
+ if (addr_max < qspi->mm_size &&
+ op->addr.buswidth)
+ qspi->fmode = CCR_FMODE_MM;
+ else
+ qspi->fmode = CCR_FMODE_INDR;
+ } else {
+ qspi->fmode = CCR_FMODE_INDW;
+ }
+
+ cr = readl_relaxed(qspi->io_base + QSPI_CR);
+ cr &= ~CR_PRESC_MASK & ~CR_FSEL;
+ cr |= FIELD_PREP(CR_PRESC_MASK, flash->presc);
+ cr |= FIELD_PREP(CR_FSEL, flash->cs);
+ writel_relaxed(cr, qspi->io_base + QSPI_CR);
+
+ if (op->data.nbytes)
+ writel_relaxed(op->data.nbytes - 1,
+ qspi->io_base + QSPI_DLR);
+ else
+ qspi->fmode = CCR_FMODE_INDW;
+
+ ccr = qspi->fmode;
+ ccr |= FIELD_PREP(CCR_INST_MASK, op->cmd.opcode);
+ ccr |= FIELD_PREP(CCR_IMODE_MASK,
+ stm32_qspi_get_mode(qspi, op->cmd.buswidth));
+
+ if (op->addr.nbytes) {
+ ccr |= FIELD_PREP(CCR_ADMODE_MASK,
+ stm32_qspi_get_mode(qspi, op->addr.buswidth));
+ ccr |= FIELD_PREP(CCR_ADSIZE_MASK, op->addr.nbytes - 1);
+ }
+
+ if (op->dummy.buswidth && op->dummy.nbytes)
+ ccr |= FIELD_PREP(CCR_DCYC_MASK,
+ op->dummy.nbytes * 8 / op->dummy.buswidth);
+
+ if (op->data.nbytes) {
+ ccr |= FIELD_PREP(CCR_DMODE_MASK,
+ stm32_qspi_get_mode(qspi, op->data.buswidth));
+ }
+
+ writel_relaxed(ccr, qspi->io_base + QSPI_CCR);
+
+ if (op->addr.nbytes && qspi->fmode != CCR_FMODE_MM)
+ writel_relaxed(op->addr.val, qspi->io_base + QSPI_AR);
+
+ err = stm32_qspi_tx(qspi, op);
+
+ /*
+ * Abort in:
+ * -error case
+ * -read memory map: prefetching must be stopped if we read the last
+ * byte of device (device size - fifo size). like device size is not
+ * knows, the prefetching is always stop.
+ */
+ if (err || qspi->fmode == CCR_FMODE_MM)
+ goto abort;
+
+ /* wait end of tx in indirect mode */
+ err = stm32_qspi_wait_cmd(qspi, op);
+ if (err)
+ goto abort;
+
+ return 0;
+
+abort:
+ cr = readl_relaxed(qspi->io_base + QSPI_CR) | CR_ABORT;
+ writel_relaxed(cr, qspi->io_base + QSPI_CR);
+
+ /* wait clear of abort bit by hw */
+ timeout = readl_relaxed_poll_timeout_atomic(qspi->io_base + QSPI_CR,
+ cr, !(cr & CR_ABORT), 1,
+ STM32_ABT_TIMEOUT_US);
+
+ writel_relaxed(FCR_CTCF, qspi->io_base + QSPI_FCR);
+
+ if (err || timeout)
+ dev_err(qspi->dev, "%s err:%d abort timeout:%d\n",
+ __func__, err, timeout);
+
+ return err;
+}
+
+static int stm32_qspi_exec_op(struct spi_mem *mem, const struct spi_mem_op *op)
+{
+ struct stm32_qspi *qspi = spi_controller_get_devdata(mem->spi->master);
+ int ret;
+
+ mutex_lock(&qspi->lock);
+ ret = stm32_qspi_send(mem, op);
+ mutex_unlock(&qspi->lock);
+
+ return ret;
+}
+
+static int stm32_qspi_setup(struct spi_device *spi)
+{
+ struct spi_controller *ctrl = spi->master;
+ struct stm32_qspi *qspi = spi_controller_get_devdata(ctrl);
+ struct stm32_qspi_flash *flash;
+ u32 presc;
+
+ if (ctrl->busy)
+ return -EBUSY;
+
+ if (!spi->max_speed_hz)
+ return -EINVAL;
+
+ presc = DIV_ROUND_UP(qspi->clk_rate, spi->max_speed_hz) - 1;
+
+ flash = &qspi->flash[spi->chip_select];
+ flash->qspi = qspi;
+ flash->cs = spi->chip_select;
+ flash->presc = presc;
+
+ mutex_lock(&qspi->lock);
+ qspi->cr_reg = FIELD_PREP(CR_FTHRES_MASK, 3) | CR_SSHIFT | CR_EN;
+ writel_relaxed(qspi->cr_reg, qspi->io_base + QSPI_CR);
+
+ /* set dcr fsize to max address */
+ qspi->dcr_reg = DCR_FSIZE_MASK;
+ writel_relaxed(qspi->dcr_reg, qspi->io_base + QSPI_DCR);
+ mutex_unlock(&qspi->lock);
+
+ return 0;
+}
+
+/*
+ * no special host constraint, so use default spi_mem_default_supports_op
+ * to check supported mode.
+ */
+static const struct spi_controller_mem_ops stm32_qspi_mem_ops = {
+ .exec_op = stm32_qspi_exec_op,
+};
+
+static void stm32_qspi_release(struct stm32_qspi *qspi)
+{
+ /* disable qspi */
+ writel_relaxed(0, qspi->io_base + QSPI_CR);
+ mutex_destroy(&qspi->lock);
+ clk_disable_unprepare(qspi->clk);
+}
+
+static int stm32_qspi_probe(struct platform_device *pdev)
+{
+ struct device *dev = &pdev->dev;
+ struct spi_controller *ctrl;
+ struct reset_control *rstc;
+ struct stm32_qspi *qspi;
+ struct resource *res;
+ int ret, irq;
+
+ ctrl = spi_alloc_master(dev, sizeof(*qspi));
+ if (!ctrl)
+ return -ENOMEM;
+
+ qspi = spi_controller_get_devdata(ctrl);
+
+ res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "qspi");
+ qspi->io_base = devm_ioremap_resource(dev, res);
+ if (IS_ERR(qspi->io_base))
+ return PTR_ERR(qspi->io_base);
+
+ res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "qspi_mm");
+ qspi->mm_base = devm_ioremap_resource(dev, res);
+ if (IS_ERR(qspi->mm_base))
+ return PTR_ERR(qspi->mm_base);
+
+ qspi->mm_size = resource_size(res);
+ if (qspi->mm_size > STM32_QSPI_MAX_MMAP_SZ)
+ return -EINVAL;
+
+ irq = platform_get_irq(pdev, 0);
+ ret = devm_request_irq(dev, irq, stm32_qspi_irq, 0,
+ dev_name(dev), qspi);
+ if (ret) {
+ dev_err(dev, "failed to request irq\n");
+ return ret;
+ }
+
+ init_completion(&qspi->data_completion);
+
+ qspi->clk = devm_clk_get(dev, NULL);
+ if (IS_ERR(qspi->clk))
+ return PTR_ERR(qspi->clk);
+
+ qspi->clk_rate = clk_get_rate(qspi->clk);
+ if (!qspi->clk_rate)
+ return -EINVAL;
+
+ ret = clk_prepare_enable(qspi->clk);
+ if (ret) {
+ dev_err(dev, "can not enable the clock\n");
+ return ret;
+ }
+
+ rstc = devm_reset_control_get_exclusive(dev, NULL);
+ if (!IS_ERR(rstc)) {
+ reset_control_assert(rstc);
+ udelay(2);
+ reset_control_deassert(rstc);
+ }
+
+ qspi->dev = dev;
+ platform_set_drvdata(pdev, qspi);
+ mutex_init(&qspi->lock);
+
+ ctrl->mode_bits = SPI_RX_DUAL | SPI_RX_QUAD
+ | SPI_TX_DUAL | SPI_TX_QUAD;
+ ctrl->setup = stm32_qspi_setup;
+ ctrl->bus_num = -1;
+ ctrl->mem_ops = &stm32_qspi_mem_ops;
+ ctrl->num_chipselect = STM32_QSPI_MAX_NORCHIP;
+ ctrl->dev.of_node = dev->of_node;
+
+ ret = devm_spi_register_master(dev, ctrl);
+ if (ret)
+ goto err_spi_register;
+
+ return 0;
+
+err_spi_register:
+ stm32_qspi_release(qspi);
+
+ return ret;
+}
+
+static int stm32_qspi_remove(struct platform_device *pdev)
+{
+ struct stm32_qspi *qspi = platform_get_drvdata(pdev);
+
+ stm32_qspi_release(qspi);
+ return 0;
+}
+
+static int __maybe_unused stm32_qspi_suspend(struct device *dev)
+{
+ struct stm32_qspi *qspi = dev_get_drvdata(dev);
+
+ clk_disable_unprepare(qspi->clk);
+ pinctrl_pm_select_sleep_state(dev);
+
+ return 0;
+}
+
+static int __maybe_unused stm32_qspi_resume(struct device *dev)
+{
+ struct stm32_qspi *qspi = dev_get_drvdata(dev);
+
+ pinctrl_pm_select_default_state(dev);
+ clk_prepare_enable(qspi->clk);
+
+ writel_relaxed(qspi->cr_reg, qspi->io_base + QSPI_CR);
+ writel_relaxed(qspi->dcr_reg, qspi->io_base + QSPI_DCR);
+
+ return 0;
+}
+
+SIMPLE_DEV_PM_OPS(stm32_qspi_pm_ops, stm32_qspi_suspend, stm32_qspi_resume);
+
+static const struct of_device_id stm32_qspi_match[] = {
+ {.compatible = "st,stm32f469-qspi"},
+ {}
+};
+MODULE_DEVICE_TABLE(of, stm32_qspi_match);
+
+static struct platform_driver stm32_qspi_driver = {
+ .probe = stm32_qspi_probe,
+ .remove = stm32_qspi_remove,
+ .driver = {
+ .name = "stm32-qspi",
+ .of_match_table = stm32_qspi_match,
+ .pm = &stm32_qspi_pm_ops,
+ },
+};
+module_platform_driver(stm32_qspi_driver);
+
+MODULE_AUTHOR("Ludovic Barre <ludovic.barre@st.com>");
+MODULE_DESCRIPTION("STMicroelectronics STM32 quad spi driver");
+MODULE_LICENSE("GPL v2");
--
2.7.4

View File

@ -0,0 +1,558 @@
From ae7d85a994c77d68e3e6a20a24160a5010ba42cc Mon Sep 17 00:00:00 2001
From: Romuald JEANNE <romuald.jeanne@st.com>
Date: Tue, 13 Nov 2018 12:32:03 +0100
Subject: [PATCH 17/52] ARM: stm32mp1-r0-rc1: DEFCONFIG
---
.../arm/configs/fragment-01-multiv7_cleanup.config | 69 +++
arch/arm/configs/fragment-02-multiv7_addons.config | 462 +++++++++++++++++++++
2 files changed, 531 insertions(+)
create mode 100644 arch/arm/configs/fragment-01-multiv7_cleanup.config
create mode 100644 arch/arm/configs/fragment-02-multiv7_addons.config
diff --git a/arch/arm/configs/fragment-01-multiv7_cleanup.config b/arch/arm/configs/fragment-01-multiv7_cleanup.config
new file mode 100644
index 0000000..22f6ffb
--- /dev/null
+++ b/arch/arm/configs/fragment-01-multiv7_cleanup.config
@@ -0,0 +1,69 @@
+#
+# CPU Core family selection
+#
+# CONFIG_ARCH_VIRT is not set
+# CONFIG_ARCH_MVEBU is not set
+# CONFIG_ARCH_ALPINE is not set
+# CONFIG_ARCH_ARTPEC is not set
+# CONFIG_ARCH_AT91 is not set
+# CONFIG_ARCH_BCM is not set
+# CONFIG_ARCH_BERLIN is not set
+# CONFIG_ARCH_DIGICOLOR is not set
+# CONFIG_ARCH_HIGHBANK is not set
+# CONFIG_ARCH_HISI is not set
+# CONFIG_ARCH_KEYSTONE is not set
+# CONFIG_ARCH_MESON is not set
+# CONFIG_ARCH_MXC is not set
+# CONFIG_ARCH_MEDIATEK is not set
+
+#
+# TI OMAP/AM/DM/DRA Family
+#
+# CONFIG_ARCH_OMAP3 is not set
+# CONFIG_ARCH_OMAP4 is not set
+# CONFIG_SOC_OMAP5 is not set
+# CONFIG_SOC_AM33XX is not set
+# CONFIG_SOC_AM43XX is not set
+# CONFIG_SOC_DRA7XX is not set
+# CONFIG_ARCH_MMP is not set
+# CONFIG_ARCH_QCOM is not set
+# CONFIG_ARCH_REALVIEW is not set
+# CONFIG_ARCH_ROCKCHIP is not set
+# CONFIG_ARCH_SOCFPGA is not set
+# CONFIG_PLAT_SPEAR is not set
+# CONFIG_ARCH_STI is not set
+# CONFIG_ARCH_S5PV210 is not set
+# CONFIG_ARCH_EXYNOS is not set
+# CONFIG_ARCH_RENESAS is not set
+# CONFIG_ARCH_SUNXI is not set
+# CONFIG_ARCH_SIRF is not set
+# CONFIG_ARCH_TANGO is not set
+# CONFIG_ARCH_TEGRA is not set
+# CONFIG_ARCH_UNIPHIER is not set
+# CONFIG_ARCH_U8500 is not set
+# CONFIG_ARCH_VEXPRESS is not set
+# CONFIG_ARCH_WM8850 is not set
+# CONFIG_ARCH_ZX is not set
+# CONFIG_ARCH_ZYNQ is not set
+
+# CONFIG_CAN_RCAR is not set
+# CONFIG_GPIO_PCA953X is not set
+# CONFIG_GPIO_PCF857X is not set
+# CONFIG_STAGING is not set
+# CONFIG_CHROME_PLATFORMS is not set
+# CONFIG_SOC_BRCMSTB is not set
+# CONFIG_SUNXI_SRAM is not set
+# CONFIG_SOC_TI is not set
+# CONFIG_PM_DEVFREQ is not set
+# CONFIG_EXTCON is not set
+# CONFIG_MEMORY is not set
+# CONFIG_ENABLE_WARN_DEPRECATED is not set
+# CONFIG_ENABLE_MUST_CHECK is not set
+# CONFIG_SECTION_MISMATCH_WARN_ONLY is not set
+# CONFIG_LOCKUP_DETECTOR is not set
+# CONFIG_DETECT_HUNG_TASK is not set
+
+
+
+
+
diff --git a/arch/arm/configs/fragment-02-multiv7_addons.config b/arch/arm/configs/fragment-02-multiv7_addons.config
new file mode 100644
index 0000000..c91840c
--- /dev/null
+++ b/arch/arm/configs/fragment-02-multiv7_addons.config
@@ -0,0 +1,462 @@
+#
+# General setup
+#
+CONFIG_POSIX_MQUEUE=y
+CONFIG_USELIB=y
+
+#
+# RCU Subsystem
+#
+# allow user to access kernel config through /proc/config.gz
+CONFIG_IKCONFIG=y
+CONFIG_IKCONFIG_PROC=y
+CONFIG_LOG_BUF_SHIFT=16
+CONFIG_MEMCG=y
+CONFIG_NAMESPACES=y
+
+#
+# Kernel Performance Events And Counters
+#
+CONFIG_PROFILING=y
+
+#
+# CPU Core family selection
+#
+
+#
+# Processor Features
+#
+# CONFIG_CACHE_L2X0 is not set
+
+#
+# Bus support
+#
+# CONFIG_PCI is not set
+# CONFIG_PCI_DOMAINS_GENERIC is not set
+# CONFIG_PCI_SYSCALL is not set
+
+#
+# Kernel Features
+#
+CONFIG_MCPM=y
+CONFIG_NR_CPUS=4
+# CONFIG_PREEMPT_NONE is not set
+CONFIG_PREEMPT=y
+CONFIG_PREEMPT_COUNT=y
+CONFIG_AEABI=y
+CONFIG_HIGHMEM=y
+CONFIG_FORCE_MAX_ZONEORDER=12
+
+#
+# Boot options
+#
+# CONFIG_ATAGS is not set
+CONFIG_ZBOOT_ROM_TEXT=0x0
+CONFIG_ZBOOT_ROM_BSS=0x0
+# CONFIG_KEXEC is not set
+# CONFIG_EFI is not set
+
+#
+# CPU Power Management
+#
+
+#
+# CPU Frequency scaling
+#
+# CONFIG_CPU_FREQ is not set
+
+#
+# CPU Idle
+#
+# CONFIG_CPU_IDLE is not set
+
+#
+# Floating point emulation
+#
+CONFIG_VFP=y
+
+#
+# Networking options
+#
+CONFIG_DNS_RESOLVER=y
+
+#
+# CAN Device Drivers
+#
+CONFIG_CAN_M_CAN=y
+
+#
+# CAN SPI interfaces
+#
+# CONFIG_CAN_MCP251X is not set
+
+#
+# CAN USB interfaces
+#
+
+#
+# Bluetooth device drivers
+#
+
+#
+# Device Drivers
+#
+
+#
+# Generic Driver Options
+#
+CONFIG_FW_LOADER_USER_HELPER_FALLBACK=y
+
+#
+# Default contiguous memory area size:
+#
+CONFIG_CMA_SIZE_MBYTES=128
+
+#
+# Disk-On-Chip Device Drivers
+#
+
+#
+# LPDDR & LPDDR2 PCM memory drivers
+#
+CONFIG_OF_RESOLVE=y
+CONFIG_OF_OVERLAY=y
+CONFIG_OF_CONFIGFS=y
+
+#
+# Misc devices
+#
+CONFIG_SRAM=y
+
+#
+# SCSI support type (disk, tape, CD-ROM)
+#
+CONFIG_CHR_DEV_SG=y
+
+#
+# MII PHY device drivers
+#
+# CONFIG_REALTEK_PHY is not set
+
+#
+# Input Device Drivers
+#
+
+#
+# Character devices
+#
+CONFIG_SERIAL_NONSTANDARD=y
+
+#
+# Serial drivers
+#
+# CONFIG_SERIAL_8250 is not set
+
+#
+# Non-8250 serial port support
+#
+# CONFIG_SERIAL_BCM63XX is not set
+# CONFIG_SERIAL_XILINX_PS_UART is not set
+# CONFIG_SERIAL_FSL_LPUART is not set
+# CONFIG_SERIAL_CONEXANT_DIGICOLOR is not set
+# CONFIG_SERIAL_ST_ASC is not set
+# CONFIG_VIRTIO_CONSOLE is not set
+
+#
+# I2C Hardware Bus support
+#
+# CONFIG_I2C_DESIGNWARE_PLATFORM is not set
+# CONFIG_I2C_EMEV2 is not set
+# CONFIG_I2C_GPIO is not set
+# CONFIG_I2C_RK3X is not set
+# CONFIG_I2C_XILINX is not set
+
+#
+# Other I2C/SMBus bus drivers
+#
+# CONFIG_I2C_SLAVE_EEPROM is not set
+
+#
+# SPI Master Controller Drivers
+#
+CONFIG_SPI_STM32_QSPI=y
+
+#
+# Pin controllers
+#
+CONFIG_PINCTRL_STMFX=y
+
+#
+# Memory mapped GPIO drivers
+#
+
+#
+# USB GPIO expanders
+#
+# CONFIG_POWER_AVS is not set
+CONFIG_POWER_RESET=y
+CONFIG_POWER_RESET_SYSCON=y
+CONFIG_SYSCON_REBOOT_MODE=y
+# CONFIG_POWER_SUPPLY is not set
+
+#
+# Native drivers
+#
+CONFIG_SENSORS_IIO_HWMON=y
+CONFIG_THERMAL=y
+
+#
+# STMicroelectronics thermal drivers
+#
+
+
+
+#
+# Watchdog Device Drivers
+#
+
+
+#
+# Sonics Silicon Backplane
+#
+
+#
+# Multifunction device drivers
+#
+CONFIG_PROTECTION_CONSUMER=y
+
+#
+# STMicroelectronics STMPE Interface Drivers
+#
+# CONFIG_REGULATOR_WM8994 is not set
+
+#
+# Multimedia core support
+#
+
+#
+# USB HDMI CEC adapters
+#
+
+#
+# Media ancillary drivers (tuners, sensors, i2c, spi, frontends)
+#
+# CONFIG_MEDIA_SUBDRV_AUTOSELECT is not set
+
+#
+# Camera sensor devices
+#
+
+#
+# Graphics support
+#
+# to solve issue on DK2 screen
+# CONFIG_DRM_FBDEV_EMULATION is not set
+# CONFIG_DRM_LOAD_EDID_FIRMWARE is not set
+
+#
+# Sub-drivers
+#
+
+#
+# Display Panels
+#
+
+#
+# Display Interface Bridges
+#
+
+#
+# Frame buffer hardware drivers
+#
+
+#
+# Console display driver support
+#
+
+#
+# HD-Audio
+#
+
+#
+# CODEC drivers
+#
+
+
+#
+# USB Device Class drivers
+#
+
+#
+# also be needed; see USB_STORAGE Help for more info
+#
+
+#
+# USB Imaging devices
+#
+# CONFIG_USB_MUSB_HDRC is not set
+# CONFIG_USB_DWC3 is not set
+
+#
+# Gadget/Dual-role mode requires USB Gadget support to be enabled
+#
+
+#
+# USB Physical Layer drivers
+#
+
+#
+# Platform Support
+#
+
+#
+# Virtio drivers
+#
+
+#
+# Clock Source drivers
+#
+
+#
+# Rpmsg drivers
+#
+
+#
+# File systems
+#
+CONFIG_OVERLAY_FS=y
+
+#
+# Pseudo filesystems
+#
+CONFIG_TMPFS=y
+
+#
+# Kernel hacking
+#
+
+#
+# printk and dmesg options
+#
+CONFIG_DYNAMIC_DEBUG=y
+
+#
+# Compile-time checks and compiler options
+#
+CONFIG_DEBUG_INFO=y
+CONFIG_GDB_SCRIPTS=y
+CONFIG_DEBUG_SECTION_MISMATCH=y
+
+#
+# Debug Lockups and Hangs
+#
+# CONFIG_SCHED_DEBUG is not set
+CONFIG_DEBUG_PREEMPT=y
+
+#
+# Runtime Testing
+#
+
+# Security options
+#
+CONFIG_KEYS=y
+
+
+#
+# Library routines
+#
+CONFIG_CRC_ITU_T=m
+
+#
+# STM32 PWR
+#
+CONFIG_MFD_STM32MP1_PWR=y
+CONFIG_REGULATOR_STM32_PWR=y
+
+#
+# STPMIC1
+#
+CONFIG_MFD_STPMIC1=y
+CONFIG_REGULATOR_STPMIC1=y
+CONFIG_STPMIC1_WATCHDOG=y
+CONFIG_INPUT_STPMIC1_ONKEY=y
+
+#
+# STM32 TIMER
+#
+CONFIG_MFD_STM32_TIMERS=y
+CONFIG_IIO_STM32_TIMER_TRIGGER=y
+CONFIG_PWM_STM32=y
+
+#
+# STM32 LPTIMER
+#
+CONFIG_MFD_STM32_LPTIMER=y
+CONFIG_PWM_STM32_LP=y
+CONFIG_IIO_STM32_LPTIMER_TRIGGER=y
+CONFIG_STM32_LPTIMER_CNT=y
+
+#
+# STM32 DFSDM
+#
+CONFIG_SD_ADC_MODULATOR=y
+CONFIG_STM32_DFSDM_ADC=y
+
+#
+# FMC2
+#
+CONFIG_MTD_NAND_STM32_FMC2=y
+
+#
+# STM32 VREFBUF
+#
+CONFIG_REGULATOR_STM32_VREFBUF=y
+
+#
+# STM32 BSEC NVMEM
+#
+CONFIG_NVMEM_STM32_ROMEM=y
+
+#
+# STM32 IPCC
+#
+CONFIG_STM32_IPCC=y
+
+#
+# RPMSG_TTY
+#
+CONFIG_RPMSG_VIRTIO=y
+CONFIG_RPMSG_TTY=y
+
+#
+# RPMSG client sample
+#
+CONFIG_SAMPLES=y
+CONFIG_SAMPLE_RPMSG_CLIENT=m
+
+#
+# STM32 RPROC
+#
+# CONFIG_MAILBOX is not set
+CONFIG_REMOTEPROC=y
+CONFIG_STM32_RPROC=y
+CONFIG_RPMSG_VIRTIO=y
+
+#
+# Cryptographic
+#
+CONFIG_CRYPTO_DEV_STM32_CRC=y
+CONFIG_CRYPTO_DEV_STM32_HASH=y
+CONFIG_CRYPTO_DEV_STM32_CRYP=y
+
+#
+# STM32 ADC
+#
+CONFIG_STM32_ADC_CORE=y
+CONFIG_STM32_ADC=y
+CONFIG_STM32_ADC_TEMP=y
+
+#
+# STM32 DAC
+#
+CONFIG_STM32_DAC=y
--
2.7.4

View File

@ -0,0 +1,984 @@
From 8f36e7dd830ff5d93e240a62da54ea2afc580cca Mon Sep 17 00:00:00 2001
From: Christophe Priouzeau <christophe.priouzeau@st.com>
Date: Mon, 26 Nov 2018 14:39:57 +0100
Subject: [PATCH 20/52] ARM-stm32mp1-r0-rc2-MEDIA
---
.../devicetree/bindings/media/video-interfaces.txt | 2 +
drivers/media/i2c/ov5640.c | 663 ++++++++++++---------
drivers/media/platform/stm32/stm32-dcmi.c | 41 +-
drivers/media/v4l2-core/v4l2-fwnode.c | 3 +
include/media/v4l2-fwnode.h | 2 +
5 files changed, 413 insertions(+), 298 deletions(-)
diff --git a/Documentation/devicetree/bindings/media/video-interfaces.txt b/Documentation/devicetree/bindings/media/video-interfaces.txt
index baf9d97..fa4c112 100644
--- a/Documentation/devicetree/bindings/media/video-interfaces.txt
+++ b/Documentation/devicetree/bindings/media/video-interfaces.txt
@@ -147,6 +147,8 @@ Optional endpoint properties
as 0 (normal). This property is valid for serial busses only.
- strobe: Whether the clock signal is used as clock (0) or strobe (1). Used
with CCP2, for instance.
+- pclk-max-frequency: maximum pixel clock frequency admissible by video
+ host interface.
Example
-------
diff --git a/drivers/media/i2c/ov5640.c b/drivers/media/i2c/ov5640.c
index 30b15e9..27b75e7 100644
--- a/drivers/media/i2c/ov5640.c
+++ b/drivers/media/i2c/ov5640.c
@@ -66,6 +66,7 @@
#define OV5640_REG_TIMING_VTS 0x380e
#define OV5640_REG_TIMING_TC_REG20 0x3820
#define OV5640_REG_TIMING_TC_REG21 0x3821
+#define OV5640_REG_DVP_PCLK_DIVIDER 0x3824
#define OV5640_REG_AEC_CTRL00 0x3a00
#define OV5640_REG_AEC_B50_STEP 0x3a08
#define OV5640_REG_AEC_B60_STEP 0x3a0a
@@ -261,8 +262,8 @@ static inline struct v4l2_subdev *ctrl_to_sd(struct v4l2_ctrl *ctrl)
static const struct reg_value ov5640_init_setting_30fps_VGA[] = {
{0x3103, 0x11, 0, 0}, {0x3008, 0x82, 0, 5}, {0x3008, 0x42, 0, 0},
{0x3103, 0x03, 0, 0}, {0x3017, 0x00, 0, 0}, {0x3018, 0x00, 0, 0},
- {0x3034, 0x18, 0, 0}, {0x3035, 0x14, 0, 0}, {0x3036, 0x38, 0, 0},
- {0x3037, 0x13, 0, 0}, {0x3630, 0x36, 0, 0},
+ {0x3034, 0x18, 0, 0},
+ {0x3630, 0x36, 0, 0},
{0x3631, 0x0e, 0, 0}, {0x3632, 0xe2, 0, 0}, {0x3633, 0x12, 0, 0},
{0x3621, 0xe0, 0, 0}, {0x3704, 0xa0, 0, 0}, {0x3703, 0x5a, 0, 0},
{0x3715, 0x78, 0, 0}, {0x3717, 0x01, 0, 0}, {0x370b, 0x60, 0, 0},
@@ -344,85 +345,8 @@ static const struct reg_value ov5640_init_setting_30fps_VGA[] = {
{0x3a1f, 0x14, 0, 0}, {0x3008, 0x02, 0, 0}, {0x3c00, 0x04, 0, 300},
};
-static const struct reg_value ov5640_setting_30fps_VGA_640_480[] = {
- {0x3035, 0x14, 0, 0}, {0x3036, 0x38, 0, 0}, {0x3c07, 0x08, 0, 0},
- {0x3c09, 0x1c, 0, 0}, {0x3c0a, 0x9c, 0, 0}, {0x3c0b, 0x40, 0, 0},
- {0x3814, 0x31, 0, 0},
- {0x3815, 0x31, 0, 0}, {0x3800, 0x00, 0, 0}, {0x3801, 0x00, 0, 0},
- {0x3802, 0x00, 0, 0}, {0x3803, 0x04, 0, 0}, {0x3804, 0x0a, 0, 0},
- {0x3805, 0x3f, 0, 0}, {0x3806, 0x07, 0, 0}, {0x3807, 0x9b, 0, 0},
- {0x3810, 0x00, 0, 0},
- {0x3811, 0x10, 0, 0}, {0x3812, 0x00, 0, 0}, {0x3813, 0x06, 0, 0},
- {0x3618, 0x00, 0, 0}, {0x3612, 0x29, 0, 0}, {0x3708, 0x64, 0, 0},
- {0x3709, 0x52, 0, 0}, {0x370c, 0x03, 0, 0}, {0x3a02, 0x03, 0, 0},
- {0x3a03, 0xd8, 0, 0}, {0x3a08, 0x01, 0, 0}, {0x3a09, 0x0e, 0, 0},
- {0x3a0a, 0x00, 0, 0}, {0x3a0b, 0xf6, 0, 0}, {0x3a0e, 0x03, 0, 0},
- {0x3a0d, 0x04, 0, 0}, {0x3a14, 0x03, 0, 0}, {0x3a15, 0xd8, 0, 0},
- {0x4001, 0x02, 0, 0}, {0x4004, 0x02, 0, 0}, {0x4713, 0x03, 0, 0},
- {0x4407, 0x04, 0, 0}, {0x460b, 0x35, 0, 0}, {0x460c, 0x22, 0, 0},
- {0x3824, 0x02, 0, 0}, {0x5001, 0xa3, 0, 0}, {0x3503, 0x00, 0, 0},
-};
-
-static const struct reg_value ov5640_setting_15fps_VGA_640_480[] = {
- {0x3035, 0x22, 0, 0}, {0x3036, 0x38, 0, 0}, {0x3c07, 0x08, 0, 0},
- {0x3c09, 0x1c, 0, 0}, {0x3c0a, 0x9c, 0, 0}, {0x3c0b, 0x40, 0, 0},
- {0x3814, 0x31, 0, 0},
- {0x3815, 0x31, 0, 0}, {0x3800, 0x00, 0, 0}, {0x3801, 0x00, 0, 0},
- {0x3802, 0x00, 0, 0}, {0x3803, 0x04, 0, 0}, {0x3804, 0x0a, 0, 0},
- {0x3805, 0x3f, 0, 0}, {0x3806, 0x07, 0, 0}, {0x3807, 0x9b, 0, 0},
- {0x3810, 0x00, 0, 0},
- {0x3811, 0x10, 0, 0}, {0x3812, 0x00, 0, 0}, {0x3813, 0x06, 0, 0},
- {0x3618, 0x00, 0, 0}, {0x3612, 0x29, 0, 0}, {0x3708, 0x64, 0, 0},
- {0x3709, 0x52, 0, 0}, {0x370c, 0x03, 0, 0}, {0x3a02, 0x03, 0, 0},
- {0x3a03, 0xd8, 0, 0}, {0x3a08, 0x01, 0, 0}, {0x3a09, 0x27, 0, 0},
- {0x3a0a, 0x00, 0, 0}, {0x3a0b, 0xf6, 0, 0}, {0x3a0e, 0x03, 0, 0},
- {0x3a0d, 0x04, 0, 0}, {0x3a14, 0x03, 0, 0}, {0x3a15, 0xd8, 0, 0},
- {0x4001, 0x02, 0, 0}, {0x4004, 0x02, 0, 0}, {0x4713, 0x03, 0, 0},
- {0x4407, 0x04, 0, 0}, {0x460b, 0x35, 0, 0}, {0x460c, 0x22, 0, 0},
- {0x3824, 0x02, 0, 0}, {0x5001, 0xa3, 0, 0},
-};
-
-static const struct reg_value ov5640_setting_30fps_XGA_1024_768[] = {
- {0x3035, 0x14, 0, 0}, {0x3036, 0x38, 0, 0}, {0x3c07, 0x08, 0, 0},
- {0x3c09, 0x1c, 0, 0}, {0x3c0a, 0x9c, 0, 0}, {0x3c0b, 0x40, 0, 0},
- {0x3814, 0x31, 0, 0},
- {0x3815, 0x31, 0, 0}, {0x3800, 0x00, 0, 0}, {0x3801, 0x00, 0, 0},
- {0x3802, 0x00, 0, 0}, {0x3803, 0x04, 0, 0}, {0x3804, 0x0a, 0, 0},
- {0x3805, 0x3f, 0, 0}, {0x3806, 0x07, 0, 0}, {0x3807, 0x9b, 0, 0},
- {0x3810, 0x00, 0, 0},
- {0x3811, 0x10, 0, 0}, {0x3812, 0x00, 0, 0}, {0x3813, 0x06, 0, 0},
- {0x3618, 0x00, 0, 0}, {0x3612, 0x29, 0, 0}, {0x3708, 0x64, 0, 0},
- {0x3709, 0x52, 0, 0}, {0x370c, 0x03, 0, 0}, {0x3a02, 0x03, 0, 0},
- {0x3a03, 0xd8, 0, 0}, {0x3a08, 0x01, 0, 0}, {0x3a09, 0x0e, 0, 0},
- {0x3a0a, 0x00, 0, 0}, {0x3a0b, 0xf6, 0, 0}, {0x3a0e, 0x03, 0, 0},
- {0x3a0d, 0x04, 0, 0}, {0x3a14, 0x03, 0, 0}, {0x3a15, 0xd8, 0, 0},
- {0x4001, 0x02, 0, 0}, {0x4004, 0x02, 0, 0}, {0x4713, 0x03, 0, 0},
- {0x4407, 0x04, 0, 0}, {0x460b, 0x35, 0, 0}, {0x460c, 0x22, 0, 0},
- {0x3824, 0x02, 0, 0}, {0x5001, 0xa3, 0, 0}, {0x3503, 0x00, 0, 0},
- {0x3035, 0x12, 0, 0},
-};
-
-static const struct reg_value ov5640_setting_15fps_XGA_1024_768[] = {
- {0x3035, 0x22, 0, 0}, {0x3036, 0x38, 0, 0}, {0x3c07, 0x08, 0, 0},
- {0x3c09, 0x1c, 0, 0}, {0x3c0a, 0x9c, 0, 0}, {0x3c0b, 0x40, 0, 0},
- {0x3814, 0x31, 0, 0},
- {0x3815, 0x31, 0, 0}, {0x3800, 0x00, 0, 0}, {0x3801, 0x00, 0, 0},
- {0x3802, 0x00, 0, 0}, {0x3803, 0x04, 0, 0}, {0x3804, 0x0a, 0, 0},
- {0x3805, 0x3f, 0, 0}, {0x3806, 0x07, 0, 0}, {0x3807, 0x9b, 0, 0},
- {0x3810, 0x00, 0, 0},
- {0x3811, 0x10, 0, 0}, {0x3812, 0x00, 0, 0}, {0x3813, 0x06, 0, 0},
- {0x3618, 0x00, 0, 0}, {0x3612, 0x29, 0, 0}, {0x3708, 0x64, 0, 0},
- {0x3709, 0x52, 0, 0}, {0x370c, 0x03, 0, 0}, {0x3a02, 0x03, 0, 0},
- {0x3a03, 0xd8, 0, 0}, {0x3a08, 0x01, 0, 0}, {0x3a09, 0x27, 0, 0},
- {0x3a0a, 0x00, 0, 0}, {0x3a0b, 0xf6, 0, 0}, {0x3a0e, 0x03, 0, 0},
- {0x3a0d, 0x04, 0, 0}, {0x3a14, 0x03, 0, 0}, {0x3a15, 0xd8, 0, 0},
- {0x4001, 0x02, 0, 0}, {0x4004, 0x02, 0, 0}, {0x4713, 0x03, 0, 0},
- {0x4407, 0x04, 0, 0}, {0x460b, 0x35, 0, 0}, {0x460c, 0x22, 0, 0},
- {0x3824, 0x02, 0, 0}, {0x5001, 0xa3, 0, 0},
-};
-
-static const struct reg_value ov5640_setting_30fps_QVGA_320_240[] = {
- {0x3035, 0x14, 0, 0}, {0x3036, 0x38, 0, 0}, {0x3c07, 0x08, 0, 0},
+static const struct reg_value ov5640_setting_VGA_640_480[] = {
+ {0x3c07, 0x08, 0, 0},
{0x3c09, 0x1c, 0, 0}, {0x3c0a, 0x9c, 0, 0}, {0x3c0b, 0x40, 0, 0},
{0x3814, 0x31, 0, 0},
{0x3815, 0x31, 0, 0}, {0x3800, 0x00, 0, 0}, {0x3801, 0x00, 0, 0},
@@ -436,12 +360,12 @@ static const struct reg_value ov5640_setting_30fps_QVGA_320_240[] = {
{0x3a0a, 0x00, 0, 0}, {0x3a0b, 0xf6, 0, 0}, {0x3a0e, 0x03, 0, 0},
{0x3a0d, 0x04, 0, 0}, {0x3a14, 0x03, 0, 0}, {0x3a15, 0xd8, 0, 0},
{0x4001, 0x02, 0, 0}, {0x4004, 0x02, 0, 0}, {0x4713, 0x03, 0, 0},
- {0x4407, 0x04, 0, 0}, {0x460b, 0x35, 0, 0}, {0x460c, 0x22, 0, 0},
- {0x3824, 0x02, 0, 0}, {0x5001, 0xa3, 0, 0},
+ {0x4407, 0x04, 0, 0},
+ {0x5001, 0xa3, 0, 0},
};
-static const struct reg_value ov5640_setting_15fps_QVGA_320_240[] = {
- {0x3035, 0x22, 0, 0}, {0x3036, 0x38, 0, 0}, {0x3c07, 0x08, 0, 0},
+static const struct reg_value ov5640_setting_XGA_1024_768[] = {
+ {0x3c07, 0x08, 0, 0},
{0x3c09, 0x1c, 0, 0}, {0x3c0a, 0x9c, 0, 0}, {0x3c0b, 0x40, 0, 0},
{0x3814, 0x31, 0, 0},
{0x3815, 0x31, 0, 0}, {0x3800, 0x00, 0, 0}, {0x3801, 0x00, 0, 0},
@@ -455,12 +379,11 @@ static const struct reg_value ov5640_setting_15fps_QVGA_320_240[] = {
{0x3a0a, 0x00, 0, 0}, {0x3a0b, 0xf6, 0, 0}, {0x3a0e, 0x03, 0, 0},
{0x3a0d, 0x04, 0, 0}, {0x3a14, 0x03, 0, 0}, {0x3a15, 0xd8, 0, 0},
{0x4001, 0x02, 0, 0}, {0x4004, 0x02, 0, 0}, {0x4713, 0x03, 0, 0},
- {0x4407, 0x04, 0, 0}, {0x460b, 0x35, 0, 0}, {0x460c, 0x22, 0, 0},
- {0x3824, 0x02, 0, 0}, {0x5001, 0xa3, 0, 0},
+ {0x4407, 0x04, 0, 0}, {0x5001, 0xa3, 0, 0},
};
-static const struct reg_value ov5640_setting_30fps_QCIF_176_144[] = {
- {0x3035, 0x14, 0, 0}, {0x3036, 0x38, 0, 0}, {0x3c07, 0x08, 0, 0},
+static const struct reg_value ov5640_setting_QVGA_320_240[] = {
+ {0x3c07, 0x08, 0, 0},
{0x3c09, 0x1c, 0, 0}, {0x3c0a, 0x9c, 0, 0}, {0x3c0b, 0x40, 0, 0},
{0x3814, 0x31, 0, 0},
{0x3815, 0x31, 0, 0}, {0x3800, 0x00, 0, 0}, {0x3801, 0x00, 0, 0},
@@ -474,12 +397,11 @@ static const struct reg_value ov5640_setting_30fps_QCIF_176_144[] = {
{0x3a0a, 0x00, 0, 0}, {0x3a0b, 0xf6, 0, 0}, {0x3a0e, 0x03, 0, 0},
{0x3a0d, 0x04, 0, 0}, {0x3a14, 0x03, 0, 0}, {0x3a15, 0xd8, 0, 0},
{0x4001, 0x02, 0, 0}, {0x4004, 0x02, 0, 0}, {0x4713, 0x03, 0, 0},
- {0x4407, 0x04, 0, 0}, {0x460b, 0x35, 0, 0}, {0x460c, 0x22, 0, 0},
- {0x3824, 0x02, 0, 0}, {0x5001, 0xa3, 0, 0},
+ {0x4407, 0x04, 0, 0}, {0x5001, 0xa3, 0, 0},
};
-static const struct reg_value ov5640_setting_15fps_QCIF_176_144[] = {
- {0x3035, 0x22, 0, 0}, {0x3036, 0x38, 0, 0}, {0x3c07, 0x08, 0, 0},
+static const struct reg_value ov5640_setting_QCIF_176_144[] = {
+ {0x3c07, 0x08, 0, 0},
{0x3c09, 0x1c, 0, 0}, {0x3c0a, 0x9c, 0, 0}, {0x3c0b, 0x40, 0, 0},
{0x3814, 0x31, 0, 0},
{0x3815, 0x31, 0, 0}, {0x3800, 0x00, 0, 0}, {0x3801, 0x00, 0, 0},
@@ -493,12 +415,11 @@ static const struct reg_value ov5640_setting_15fps_QCIF_176_144[] = {
{0x3a0a, 0x00, 0, 0}, {0x3a0b, 0xf6, 0, 0}, {0x3a0e, 0x03, 0, 0},
{0x3a0d, 0x04, 0, 0}, {0x3a14, 0x03, 0, 0}, {0x3a15, 0xd8, 0, 0},
{0x4001, 0x02, 0, 0}, {0x4004, 0x02, 0, 0}, {0x4713, 0x03, 0, 0},
- {0x4407, 0x04, 0, 0}, {0x460b, 0x35, 0, 0}, {0x460c, 0x22, 0, 0},
- {0x3824, 0x02, 0, 0}, {0x5001, 0xa3, 0, 0},
+ {0x4407, 0x04, 0, 0}, {0x5001, 0xa3, 0, 0},
};
-static const struct reg_value ov5640_setting_30fps_NTSC_720_480[] = {
- {0x3035, 0x12, 0, 0}, {0x3036, 0x38, 0, 0}, {0x3c07, 0x08, 0, 0},
+static const struct reg_value ov5640_setting_NTSC_720_480[] = {
+ {0x3c07, 0x08, 0, 0},
{0x3c09, 0x1c, 0, 0}, {0x3c0a, 0x9c, 0, 0}, {0x3c0b, 0x40, 0, 0},
{0x3814, 0x31, 0, 0},
{0x3815, 0x31, 0, 0}, {0x3800, 0x00, 0, 0}, {0x3801, 0x00, 0, 0},
@@ -512,31 +433,11 @@ static const struct reg_value ov5640_setting_30fps_NTSC_720_480[] = {
{0x3a0a, 0x00, 0, 0}, {0x3a0b, 0xf6, 0, 0}, {0x3a0e, 0x03, 0, 0},
{0x3a0d, 0x04, 0, 0}, {0x3a14, 0x03, 0, 0}, {0x3a15, 0xd8, 0, 0},
{0x4001, 0x02, 0, 0}, {0x4004, 0x02, 0, 0}, {0x4713, 0x03, 0, 0},
- {0x4407, 0x04, 0, 0}, {0x460b, 0x35, 0, 0}, {0x460c, 0x22, 0, 0},
- {0x3824, 0x02, 0, 0}, {0x5001, 0xa3, 0, 0},
+ {0x4407, 0x04, 0, 0}, {0x5001, 0xa3, 0, 0},
};
-static const struct reg_value ov5640_setting_15fps_NTSC_720_480[] = {
- {0x3035, 0x22, 0, 0}, {0x3036, 0x38, 0, 0}, {0x3c07, 0x08, 0, 0},
- {0x3c09, 0x1c, 0, 0}, {0x3c0a, 0x9c, 0, 0}, {0x3c0b, 0x40, 0, 0},
- {0x3814, 0x31, 0, 0},
- {0x3815, 0x31, 0, 0}, {0x3800, 0x00, 0, 0}, {0x3801, 0x00, 0, 0},
- {0x3802, 0x00, 0, 0}, {0x3803, 0x04, 0, 0}, {0x3804, 0x0a, 0, 0},
- {0x3805, 0x3f, 0, 0}, {0x3806, 0x07, 0, 0}, {0x3807, 0x9b, 0, 0},
- {0x3810, 0x00, 0, 0},
- {0x3811, 0x10, 0, 0}, {0x3812, 0x00, 0, 0}, {0x3813, 0x3c, 0, 0},
- {0x3618, 0x00, 0, 0}, {0x3612, 0x29, 0, 0}, {0x3708, 0x64, 0, 0},
- {0x3709, 0x52, 0, 0}, {0x370c, 0x03, 0, 0}, {0x3a02, 0x03, 0, 0},
- {0x3a03, 0xd8, 0, 0}, {0x3a08, 0x01, 0, 0}, {0x3a09, 0x27, 0, 0},
- {0x3a0a, 0x00, 0, 0}, {0x3a0b, 0xf6, 0, 0}, {0x3a0e, 0x03, 0, 0},
- {0x3a0d, 0x04, 0, 0}, {0x3a14, 0x03, 0, 0}, {0x3a15, 0xd8, 0, 0},
- {0x4001, 0x02, 0, 0}, {0x4004, 0x02, 0, 0}, {0x4713, 0x03, 0, 0},
- {0x4407, 0x04, 0, 0}, {0x460b, 0x35, 0, 0}, {0x460c, 0x22, 0, 0},
- {0x3824, 0x02, 0, 0}, {0x5001, 0xa3, 0, 0},
-};
-
-static const struct reg_value ov5640_setting_30fps_PAL_720_576[] = {
- {0x3035, 0x12, 0, 0}, {0x3036, 0x38, 0, 0}, {0x3c07, 0x08, 0, 0},
+static const struct reg_value ov5640_setting_PAL_720_576[] = {
+ {0x3c07, 0x08, 0, 0},
{0x3c09, 0x1c, 0, 0}, {0x3c0a, 0x9c, 0, 0}, {0x3c0b, 0x40, 0, 0},
{0x3814, 0x31, 0, 0},
{0x3815, 0x31, 0, 0}, {0x3800, 0x00, 0, 0}, {0x3801, 0x00, 0, 0},
@@ -550,52 +451,11 @@ static const struct reg_value ov5640_setting_30fps_PAL_720_576[] = {
{0x3a0a, 0x00, 0, 0}, {0x3a0b, 0xf6, 0, 0}, {0x3a0e, 0x03, 0, 0},
{0x3a0d, 0x04, 0, 0}, {0x3a14, 0x03, 0, 0}, {0x3a15, 0xd8, 0, 0},
{0x4001, 0x02, 0, 0}, {0x4004, 0x02, 0, 0}, {0x4713, 0x03, 0, 0},
- {0x4407, 0x04, 0, 0}, {0x460b, 0x35, 0, 0}, {0x460c, 0x22, 0, 0},
- {0x3824, 0x02, 0, 0}, {0x5001, 0xa3, 0, 0},
+ {0x4407, 0x04, 0, 0}, {0x5001, 0xa3, 0, 0},
};
-static const struct reg_value ov5640_setting_15fps_PAL_720_576[] = {
- {0x3035, 0x22, 0, 0}, {0x3036, 0x38, 0, 0}, {0x3c07, 0x08, 0, 0},
- {0x3c09, 0x1c, 0, 0}, {0x3c0a, 0x9c, 0, 0}, {0x3c0b, 0x40, 0, 0},
- {0x3814, 0x31, 0, 0},
- {0x3815, 0x31, 0, 0}, {0x3800, 0x00, 0, 0}, {0x3801, 0x00, 0, 0},
- {0x3802, 0x00, 0, 0}, {0x3803, 0x04, 0, 0}, {0x3804, 0x0a, 0, 0},
- {0x3805, 0x3f, 0, 0}, {0x3806, 0x07, 0, 0}, {0x3807, 0x9b, 0, 0},
- {0x3810, 0x00, 0, 0},
- {0x3811, 0x38, 0, 0}, {0x3812, 0x00, 0, 0}, {0x3813, 0x06, 0, 0},
- {0x3618, 0x00, 0, 0}, {0x3612, 0x29, 0, 0}, {0x3708, 0x64, 0, 0},
- {0x3709, 0x52, 0, 0}, {0x370c, 0x03, 0, 0}, {0x3a02, 0x03, 0, 0},
- {0x3a03, 0xd8, 0, 0}, {0x3a08, 0x01, 0, 0}, {0x3a09, 0x27, 0, 0},
- {0x3a0a, 0x00, 0, 0}, {0x3a0b, 0xf6, 0, 0}, {0x3a0e, 0x03, 0, 0},
- {0x3a0d, 0x04, 0, 0}, {0x3a14, 0x03, 0, 0}, {0x3a15, 0xd8, 0, 0},
- {0x4001, 0x02, 0, 0}, {0x4004, 0x02, 0, 0}, {0x4713, 0x03, 0, 0},
- {0x4407, 0x04, 0, 0}, {0x460b, 0x35, 0, 0}, {0x460c, 0x22, 0, 0},
- {0x3824, 0x02, 0, 0}, {0x5001, 0xa3, 0, 0},
-};
-
-static const struct reg_value ov5640_setting_30fps_720P_1280_720[] = {
- {0x3008, 0x42, 0, 0},
- {0x3035, 0x21, 0, 0}, {0x3036, 0x54, 0, 0}, {0x3c07, 0x07, 0, 0},
- {0x3c09, 0x1c, 0, 0}, {0x3c0a, 0x9c, 0, 0}, {0x3c0b, 0x40, 0, 0},
- {0x3814, 0x31, 0, 0},
- {0x3815, 0x31, 0, 0}, {0x3800, 0x00, 0, 0}, {0x3801, 0x00, 0, 0},
- {0x3802, 0x00, 0, 0}, {0x3803, 0xfa, 0, 0}, {0x3804, 0x0a, 0, 0},
- {0x3805, 0x3f, 0, 0}, {0x3806, 0x06, 0, 0}, {0x3807, 0xa9, 0, 0},
- {0x3810, 0x00, 0, 0},
- {0x3811, 0x10, 0, 0}, {0x3812, 0x00, 0, 0}, {0x3813, 0x04, 0, 0},
- {0x3618, 0x00, 0, 0}, {0x3612, 0x29, 0, 0}, {0x3708, 0x64, 0, 0},
- {0x3709, 0x52, 0, 0}, {0x370c, 0x03, 0, 0}, {0x3a02, 0x02, 0, 0},
- {0x3a03, 0xe4, 0, 0}, {0x3a08, 0x01, 0, 0}, {0x3a09, 0xbc, 0, 0},
- {0x3a0a, 0x01, 0, 0}, {0x3a0b, 0x72, 0, 0}, {0x3a0e, 0x01, 0, 0},
- {0x3a0d, 0x02, 0, 0}, {0x3a14, 0x02, 0, 0}, {0x3a15, 0xe4, 0, 0},
- {0x4001, 0x02, 0, 0}, {0x4004, 0x02, 0, 0}, {0x4713, 0x02, 0, 0},
- {0x4407, 0x04, 0, 0}, {0x460b, 0x37, 0, 0}, {0x460c, 0x20, 0, 0},
- {0x3824, 0x04, 0, 0}, {0x5001, 0x83, 0, 0}, {0x4005, 0x1a, 0, 0},
- {0x3008, 0x02, 0, 0}, {0x3503, 0, 0, 0},
-};
-
-static const struct reg_value ov5640_setting_15fps_720P_1280_720[] = {
- {0x3035, 0x41, 0, 0}, {0x3036, 0x54, 0, 0}, {0x3c07, 0x07, 0, 0},
+static const struct reg_value ov5640_setting_720P_1280_720[] = {
+ {0x3c07, 0x07, 0, 0},
{0x3c09, 0x1c, 0, 0}, {0x3c0a, 0x9c, 0, 0}, {0x3c0b, 0x40, 0, 0},
{0x3814, 0x31, 0, 0},
{0x3815, 0x31, 0, 0}, {0x3800, 0x00, 0, 0}, {0x3801, 0x00, 0, 0},
@@ -608,47 +468,13 @@ static const struct reg_value ov5640_setting_15fps_720P_1280_720[] = {
{0x3a03, 0xe4, 0, 0}, {0x3a08, 0x01, 0, 0}, {0x3a09, 0xbc, 0, 0},
{0x3a0a, 0x01, 0, 0}, {0x3a0b, 0x72, 0, 0}, {0x3a0e, 0x01, 0, 0},
{0x3a0d, 0x02, 0, 0}, {0x3a14, 0x02, 0, 0}, {0x3a15, 0xe4, 0, 0},
- {0x4001, 0x02, 0, 0}, {0x4004, 0x02, 0, 0}, {0x4713, 0x02, 0, 0},
- {0x4407, 0x04, 0, 0}, {0x460b, 0x37, 0, 0}, {0x460c, 0x20, 0, 0},
- {0x3824, 0x04, 0, 0}, {0x5001, 0x83, 0, 0},
-};
-
-static const struct reg_value ov5640_setting_30fps_1080P_1920_1080[] = {
- {0x3008, 0x42, 0, 0},
- {0x3035, 0x21, 0, 0}, {0x3036, 0x54, 0, 0}, {0x3c07, 0x08, 0, 0},
- {0x3c09, 0x1c, 0, 0}, {0x3c0a, 0x9c, 0, 0}, {0x3c0b, 0x40, 0, 0},
- {0x3814, 0x11, 0, 0},
- {0x3815, 0x11, 0, 0}, {0x3800, 0x00, 0, 0}, {0x3801, 0x00, 0, 0},
- {0x3802, 0x00, 0, 0}, {0x3803, 0x00, 0, 0}, {0x3804, 0x0a, 0, 0},
- {0x3805, 0x3f, 0, 0}, {0x3806, 0x07, 0, 0}, {0x3807, 0x9f, 0, 0},
- {0x3810, 0x00, 0, 0},
- {0x3811, 0x10, 0, 0}, {0x3812, 0x00, 0, 0}, {0x3813, 0x04, 0, 0},
- {0x3618, 0x04, 0, 0}, {0x3612, 0x29, 0, 0}, {0x3708, 0x21, 0, 0},
- {0x3709, 0x12, 0, 0}, {0x370c, 0x00, 0, 0}, {0x3a02, 0x03, 0, 0},
- {0x3a03, 0xd8, 0, 0}, {0x3a08, 0x01, 0, 0}, {0x3a09, 0x27, 0, 0},
- {0x3a0a, 0x00, 0, 0}, {0x3a0b, 0xf6, 0, 0}, {0x3a0e, 0x03, 0, 0},
- {0x3a0d, 0x04, 0, 0}, {0x3a14, 0x03, 0, 0}, {0x3a15, 0xd8, 0, 0},
- {0x4001, 0x02, 0, 0}, {0x4004, 0x06, 0, 0}, {0x4713, 0x03, 0, 0},
- {0x4407, 0x04, 0, 0}, {0x460b, 0x35, 0, 0}, {0x460c, 0x22, 0, 0},
- {0x3824, 0x02, 0, 0}, {0x5001, 0x83, 0, 0}, {0x3035, 0x11, 0, 0},
- {0x3036, 0x54, 0, 0}, {0x3c07, 0x07, 0, 0}, {0x3c08, 0x00, 0, 0},
- {0x3c09, 0x1c, 0, 0}, {0x3c0a, 0x9c, 0, 0}, {0x3c0b, 0x40, 0, 0},
- {0x3800, 0x01, 0, 0}, {0x3801, 0x50, 0, 0}, {0x3802, 0x01, 0, 0},
- {0x3803, 0xb2, 0, 0}, {0x3804, 0x08, 0, 0}, {0x3805, 0xef, 0, 0},
- {0x3806, 0x05, 0, 0}, {0x3807, 0xf1, 0, 0},
- {0x3612, 0x2b, 0, 0}, {0x3708, 0x64, 0, 0},
- {0x3a02, 0x04, 0, 0}, {0x3a03, 0x60, 0, 0}, {0x3a08, 0x01, 0, 0},
- {0x3a09, 0x50, 0, 0}, {0x3a0a, 0x01, 0, 0}, {0x3a0b, 0x18, 0, 0},
- {0x3a0e, 0x03, 0, 0}, {0x3a0d, 0x04, 0, 0}, {0x3a14, 0x04, 0, 0},
- {0x3a15, 0x60, 0, 0}, {0x4713, 0x02, 0, 0}, {0x4407, 0x04, 0, 0},
- {0x460b, 0x37, 0, 0}, {0x460c, 0x20, 0, 0}, {0x3824, 0x04, 0, 0},
- {0x4005, 0x1a, 0, 0}, {0x3008, 0x02, 0, 0},
- {0x3503, 0, 0, 0},
+ {0x4001, 0x02, 0, 0}, {0x4004, 0x02, 0, 0}, {0x4713, 0x03, 0, 0},
+ {0x4407, 0x04, 0, 0}, {0x5001, 0xa3, 0, 0},
};
-static const struct reg_value ov5640_setting_15fps_1080P_1920_1080[] = {
+static const struct reg_value ov5640_setting_1080P_1920_1080[] = {
{0x3008, 0x42, 0, 0},
- {0x3035, 0x21, 0, 0}, {0x3036, 0x54, 0, 0}, {0x3c07, 0x08, 0, 0},
+ {0x3c07, 0x08, 0, 0},
{0x3c09, 0x1c, 0, 0}, {0x3c0a, 0x9c, 0, 0}, {0x3c0b, 0x40, 0, 0},
{0x3814, 0x11, 0, 0},
{0x3815, 0x11, 0, 0}, {0x3800, 0x00, 0, 0}, {0x3801, 0x00, 0, 0},
@@ -662,9 +488,9 @@ static const struct reg_value ov5640_setting_15fps_1080P_1920_1080[] = {
{0x3a0a, 0x00, 0, 0}, {0x3a0b, 0xf6, 0, 0}, {0x3a0e, 0x03, 0, 0},
{0x3a0d, 0x04, 0, 0}, {0x3a14, 0x03, 0, 0}, {0x3a15, 0xd8, 0, 0},
{0x4001, 0x02, 0, 0}, {0x4004, 0x06, 0, 0}, {0x4713, 0x03, 0, 0},
- {0x4407, 0x04, 0, 0}, {0x460b, 0x35, 0, 0}, {0x460c, 0x22, 0, 0},
- {0x3824, 0x02, 0, 0}, {0x5001, 0x83, 0, 0}, {0x3035, 0x21, 0, 0},
- {0x3036, 0x54, 0, 1}, {0x3c07, 0x07, 0, 0}, {0x3c08, 0x00, 0, 0},
+ {0x4407, 0x04, 0, 0},
+ {0x5001, 0x83, 0, 0},
+ {0x3c07, 0x07, 0, 0}, {0x3c08, 0x00, 0, 0},
{0x3c09, 0x1c, 0, 0}, {0x3c0a, 0x9c, 0, 0}, {0x3c0b, 0x40, 0, 0},
{0x3800, 0x01, 0, 0}, {0x3801, 0x50, 0, 0}, {0x3802, 0x01, 0, 0},
{0x3803, 0xb2, 0, 0}, {0x3804, 0x08, 0, 0}, {0x3805, 0xef, 0, 0},
@@ -674,12 +500,11 @@ static const struct reg_value ov5640_setting_15fps_1080P_1920_1080[] = {
{0x3a09, 0x50, 0, 0}, {0x3a0a, 0x01, 0, 0}, {0x3a0b, 0x18, 0, 0},
{0x3a0e, 0x03, 0, 0}, {0x3a0d, 0x04, 0, 0}, {0x3a14, 0x04, 0, 0},
{0x3a15, 0x60, 0, 0}, {0x4713, 0x02, 0, 0}, {0x4407, 0x04, 0, 0},
- {0x460b, 0x37, 0, 0}, {0x460c, 0x20, 0, 0}, {0x3824, 0x04, 0, 0},
{0x4005, 0x1a, 0, 0}, {0x3008, 0x02, 0, 0}, {0x3503, 0, 0, 0},
};
-static const struct reg_value ov5640_setting_15fps_QSXGA_2592_1944[] = {
- {0x3035, 0x21, 0, 0}, {0x3036, 0x54, 0, 0}, {0x3c07, 0x08, 0, 0},
+static const struct reg_value ov5640_setting_QSXGA_2592_1944[] = {
+ {0x3c07, 0x08, 0, 0},
{0x3c09, 0x1c, 0, 0}, {0x3c0a, 0x9c, 0, 0}, {0x3c0b, 0x40, 0, 0},
{0x3814, 0x11, 0, 0},
{0x3815, 0x11, 0, 0}, {0x3800, 0x00, 0, 0}, {0x3801, 0x00, 0, 0},
@@ -693,8 +518,8 @@ static const struct reg_value ov5640_setting_15fps_QSXGA_2592_1944[] = {
{0x3a0a, 0x00, 0, 0}, {0x3a0b, 0xf6, 0, 0}, {0x3a0e, 0x03, 0, 0},
{0x3a0d, 0x04, 0, 0}, {0x3a14, 0x03, 0, 0}, {0x3a15, 0xd8, 0, 0},
{0x4001, 0x02, 0, 0}, {0x4004, 0x06, 0, 0}, {0x4713, 0x03, 0, 0},
- {0x4407, 0x04, 0, 0}, {0x460b, 0x35, 0, 0}, {0x460c, 0x22, 0, 0},
- {0x3824, 0x02, 0, 0}, {0x5001, 0x83, 0, 70},
+ {0x4407, 0x04, 0, 0},
+ {0x5001, 0x83, 0, 70},
};
/* power-on sensor init reg table */
@@ -705,79 +530,43 @@ static const struct ov5640_mode_info ov5640_mode_init_data = {
};
static const struct ov5640_mode_info
-ov5640_mode_data[OV5640_NUM_FRAMERATES][OV5640_NUM_MODES] = {
- {
- {OV5640_MODE_QCIF_176_144, SUBSAMPLING,
- 176, 1896, 144, 984,
- ov5640_setting_15fps_QCIF_176_144,
- ARRAY_SIZE(ov5640_setting_15fps_QCIF_176_144)},
- {OV5640_MODE_QVGA_320_240, SUBSAMPLING,
- 320, 1896, 240, 984,
- ov5640_setting_15fps_QVGA_320_240,
- ARRAY_SIZE(ov5640_setting_15fps_QVGA_320_240)},
- {OV5640_MODE_VGA_640_480, SUBSAMPLING,
- 640, 1896, 480, 1080,
- ov5640_setting_15fps_VGA_640_480,
- ARRAY_SIZE(ov5640_setting_15fps_VGA_640_480)},
- {OV5640_MODE_NTSC_720_480, SUBSAMPLING,
- 720, 1896, 480, 984,
- ov5640_setting_15fps_NTSC_720_480,
- ARRAY_SIZE(ov5640_setting_15fps_NTSC_720_480)},
- {OV5640_MODE_PAL_720_576, SUBSAMPLING,
- 720, 1896, 576, 984,
- ov5640_setting_15fps_PAL_720_576,
- ARRAY_SIZE(ov5640_setting_15fps_PAL_720_576)},
- {OV5640_MODE_XGA_1024_768, SUBSAMPLING,
- 1024, 1896, 768, 1080,
- ov5640_setting_15fps_XGA_1024_768,
- ARRAY_SIZE(ov5640_setting_15fps_XGA_1024_768)},
- {OV5640_MODE_720P_1280_720, SUBSAMPLING,
- 1280, 1892, 720, 740,
- ov5640_setting_15fps_720P_1280_720,
- ARRAY_SIZE(ov5640_setting_15fps_720P_1280_720)},
- {OV5640_MODE_1080P_1920_1080, SCALING,
- 1920, 2500, 1080, 1120,
- ov5640_setting_15fps_1080P_1920_1080,
- ARRAY_SIZE(ov5640_setting_15fps_1080P_1920_1080)},
- {OV5640_MODE_QSXGA_2592_1944, SCALING,
- 2592, 2844, 1944, 1968,
- ov5640_setting_15fps_QSXGA_2592_1944,
- ARRAY_SIZE(ov5640_setting_15fps_QSXGA_2592_1944)},
- }, {
- {OV5640_MODE_QCIF_176_144, SUBSAMPLING,
- 176, 1896, 144, 984,
- ov5640_setting_30fps_QCIF_176_144,
- ARRAY_SIZE(ov5640_setting_30fps_QCIF_176_144)},
- {OV5640_MODE_QVGA_320_240, SUBSAMPLING,
- 320, 1896, 240, 984,
- ov5640_setting_30fps_QVGA_320_240,
- ARRAY_SIZE(ov5640_setting_30fps_QVGA_320_240)},
- {OV5640_MODE_VGA_640_480, SUBSAMPLING,
- 640, 1896, 480, 1080,
- ov5640_setting_30fps_VGA_640_480,
- ARRAY_SIZE(ov5640_setting_30fps_VGA_640_480)},
- {OV5640_MODE_NTSC_720_480, SUBSAMPLING,
- 720, 1896, 480, 984,
- ov5640_setting_30fps_NTSC_720_480,
- ARRAY_SIZE(ov5640_setting_30fps_NTSC_720_480)},
- {OV5640_MODE_PAL_720_576, SUBSAMPLING,
- 720, 1896, 576, 984,
- ov5640_setting_30fps_PAL_720_576,
- ARRAY_SIZE(ov5640_setting_30fps_PAL_720_576)},
- {OV5640_MODE_XGA_1024_768, SUBSAMPLING,
- 1024, 1896, 768, 1080,
- ov5640_setting_30fps_XGA_1024_768,
- ARRAY_SIZE(ov5640_setting_30fps_XGA_1024_768)},
- {OV5640_MODE_720P_1280_720, SUBSAMPLING,
- 1280, 1892, 720, 740,
- ov5640_setting_30fps_720P_1280_720,
- ARRAY_SIZE(ov5640_setting_30fps_720P_1280_720)},
- {OV5640_MODE_1080P_1920_1080, SCALING,
- 1920, 2500, 1080, 1120,
- ov5640_setting_30fps_1080P_1920_1080,
- ARRAY_SIZE(ov5640_setting_30fps_1080P_1920_1080)},
- {OV5640_MODE_QSXGA_2592_1944, -1, 0, 0, 0, 0, NULL, 0},
- },
+ov5640_mode_data[OV5640_NUM_MODES] = {
+ {OV5640_MODE_QCIF_176_144, SUBSAMPLING,
+ 176, 1896, 144, 984,
+ ov5640_setting_QCIF_176_144,
+ ARRAY_SIZE(ov5640_setting_QCIF_176_144)},
+ {OV5640_MODE_QVGA_320_240, SUBSAMPLING,
+ 320, 1896, 240, 984,
+ ov5640_setting_QVGA_320_240,
+ ARRAY_SIZE(ov5640_setting_QVGA_320_240)},
+ {OV5640_MODE_VGA_640_480, SUBSAMPLING,
+ 640, 1896, 480, 1080,
+ ov5640_setting_VGA_640_480,
+ ARRAY_SIZE(ov5640_setting_VGA_640_480)},
+ {OV5640_MODE_NTSC_720_480, SUBSAMPLING,
+ 720, 1896, 480, 984,
+ ov5640_setting_NTSC_720_480,
+ ARRAY_SIZE(ov5640_setting_NTSC_720_480)},
+ {OV5640_MODE_PAL_720_576, SUBSAMPLING,
+ 720, 1896, 576, 984,
+ ov5640_setting_PAL_720_576,
+ ARRAY_SIZE(ov5640_setting_PAL_720_576)},
+ {OV5640_MODE_XGA_1024_768, SUBSAMPLING,
+ 1024, 1896, 768, 1080,
+ ov5640_setting_XGA_1024_768,
+ ARRAY_SIZE(ov5640_setting_XGA_1024_768)},
+ {OV5640_MODE_720P_1280_720, SUBSAMPLING,
+ 1280, 1892, 720, 740,
+ ov5640_setting_720P_1280_720,
+ ARRAY_SIZE(ov5640_setting_720P_1280_720)},
+ {OV5640_MODE_1080P_1920_1080, SCALING,
+ 1920, 2500, 1080, 1120,
+ ov5640_setting_1080P_1920_1080,
+ ARRAY_SIZE(ov5640_setting_1080P_1920_1080)},
+ {OV5640_MODE_QSXGA_2592_1944, SCALING,
+ 2592, 2844, 1944, 1968,
+ ov5640_setting_QSXGA_2592_1944,
+ ARRAY_SIZE(ov5640_setting_QSXGA_2592_1944)},
};
static int ov5640_init_slave_id(struct ov5640_dev *sensor)
@@ -909,6 +698,272 @@ static int ov5640_mod_reg(struct ov5640_dev *sensor, u16 reg,
return ov5640_write_reg(sensor, reg, val);
}
+/*
+ * After spending way too much time trying the various combinations, I
+ * believe the clock tree is as follows:
+ *
+ * +--------------+
+ * | Oscillator |
+ * +------+-------+
+ * |
+ * +------+-------+
+ * | System clock | - reg 0x3035, bits 4-7
+ * +------+-------+
+ * |
+ * +------+-------+ - reg 0x3036, for the multiplier
+ * | PLL | - reg 0x3037, bits 4 for the root divider
+ * +------+-------+ - reg 0x3037, bits 0-3 for the pre-divider
+ * |
+ * +------+-------+
+ * | SCLK | - reg 0x3108, bits 0-1 for the root divider
+ * +------+-------+
+ * |
+ * +------+-------+
+ * | PCLK | - reg 0x3108, bits 4-5 for the root divider
+ * +--------------+
+ *
+ * This is deviating from the datasheet at least for the register
+ * 0x3108, since it's said here that the PCLK would be clocked from
+ * the PLL. However, changing the SCLK divider value has a direct
+ * effect on the PCLK rate, which wouldn't be the case if both PCLK
+ * and SCLK were to be sourced from the PLL.
+ *
+ * These parameters also match perfectly the rate that is output by
+ * the sensor, so we shouldn't have too much factors missing (or they
+ * would be set to 1).
+ */
+
+/*
+ * FIXME: This is supposed to be ranging from 1 to 16, but the value
+ * is always set to either 1 or 2 in the vendor kernels.
+ *
+ * Moreover issues are seen with SYSDIV set to 1:
+ * Strange behaviour is observed when requesting 75MHz pixel clock output
+ * for 1280x720 (1892x740) resolution, pixel clock is about 100MHz with
+ * blanking (register values: 0x3035=0x11 and 0x3036=0x13).
+ * When forcing system clock divider to 2, pixel clock is 75Mhz continuous
+ * as expected (register values: 0x3035=0x21 and 0x3036=0x26).
+ */
+#define OV5640_SYSDIV_MIN 2
+#define OV5640_SYSDIV_MAX 2
+
+static unsigned long ov5640_calc_sysclk(struct ov5640_dev *sensor,
+ unsigned long rate,
+ u8 *sysdiv)
+{
+ unsigned long best = ~0;
+ u8 best_sysdiv = 1;
+ u8 _sysdiv;
+
+ for (_sysdiv = OV5640_SYSDIV_MIN;
+ _sysdiv <= OV5640_SYSDIV_MAX;
+ _sysdiv++) {
+ unsigned long tmp;
+
+ tmp = sensor->xclk_freq / _sysdiv;
+ if (abs(rate - tmp) < abs(rate - best)) {
+ best = tmp;
+ best_sysdiv = _sysdiv;
+ }
+
+ if (tmp == rate)
+ goto out;
+ }
+
+out:
+ *sysdiv = best_sysdiv;
+ return best;
+}
+
+/*
+ * FIXME: This is supposed to be ranging from 1 to 8, but the value is
+ * always set to 3 in the vendor kernels.
+ */
+#define OV5640_PLL_PREDIV_MIN 3
+#define OV5640_PLL_PREDIV_MAX 3
+
+/*
+ * FIXME: This is supposed to be ranging from 1 to 2, but the value is
+ * always set to 1 in the vendor kernels.
+ */
+#define OV5640_PLL_ROOT_DIV_MIN 1
+#define OV5640_PLL_ROOT_DIV_MAX 1
+
+#define OV5640_PLL_MULT_MIN 4
+#define OV5640_PLL_MULT_MAX 252
+
+static unsigned long ov5640_calc_pll(struct ov5640_dev *sensor,
+ unsigned long rate,
+ u8 *sysdiv, u8 *prediv, u8 *rdiv, u8 *mult)
+{
+ unsigned long best = ~0;
+ u8 best_sysdiv = 1, best_prediv = 1, best_mult = 1, best_rdiv = 1;
+ u8 _prediv, _mult, _rdiv;
+
+ for (_prediv = OV5640_PLL_PREDIV_MIN;
+ _prediv <= OV5640_PLL_PREDIV_MAX;
+ _prediv++) {
+ for (_mult = OV5640_PLL_MULT_MIN;
+ _mult <= OV5640_PLL_MULT_MAX;
+ _mult++) {
+ for (_rdiv = OV5640_PLL_ROOT_DIV_MIN;
+ _rdiv <= OV5640_PLL_ROOT_DIV_MAX;
+ _rdiv++) {
+ unsigned long pll;
+ unsigned long sysclk;
+ u8 _sysdiv;
+
+ /*
+ * The PLL multiplier cannot be odd if
+ * above 127.
+ */
+ if (_mult > 127 && !(_mult % 2))
+ continue;
+
+ sysclk = rate * _prediv * _rdiv / _mult;
+ sysclk = ov5640_calc_sysclk(sensor, sysclk,
+ &_sysdiv);
+
+ pll = sysclk / _rdiv / _prediv * _mult;
+ if (abs(rate - pll) < abs(rate - best)) {
+ best = pll;
+ best_sysdiv = _sysdiv;
+ best_prediv = _prediv;
+ best_mult = _mult;
+ best_rdiv = _rdiv;
+ }
+
+ if (pll == rate)
+ goto out;
+ }
+ }
+ }
+
+out:
+ *sysdiv = best_sysdiv;
+ *prediv = best_prediv;
+ *mult = best_mult;
+ *rdiv = best_rdiv;
+
+ return best;
+}
+
+/*
+ * FIXME: This is supposed to be ranging from 1 to 8, but the value is
+ * always set to 1 in the vendor kernels.
+ */
+#define OV5640_PCLK_ROOT_DIV_MIN 1
+#define OV5640_PCLK_ROOT_DIV_MAX 1
+
+static unsigned long ov5640_calc_pclk(struct ov5640_dev *sensor,
+ unsigned long rate,
+ u8 *sysdiv, u8 *prediv, u8 *pll_rdiv,
+ u8 *mult, u8 *pclk_rdiv)
+{
+ unsigned long best = ~0;
+ u8 best_sysdiv = 1, best_prediv = 1, best_mult = 1, best_pll_rdiv = 1;
+ u8 best_pclk_rdiv = 1;
+ u8 _pclk_rdiv;
+
+ for (_pclk_rdiv = OV5640_PCLK_ROOT_DIV_MIN;
+ _pclk_rdiv <= OV5640_PCLK_ROOT_DIV_MAX;
+ _pclk_rdiv <<= 1) {
+ unsigned long pll, pclk;
+ u8 sysdiv, prediv, mult, pll_rdiv;
+
+ pll = rate * OV5640_SCLK_ROOT_DIVIDER_DEFAULT * _pclk_rdiv;
+ pll = ov5640_calc_pll(sensor, pll, &sysdiv, &prediv, &pll_rdiv,
+ &mult);
+
+ pclk = pll / OV5640_SCLK_ROOT_DIVIDER_DEFAULT / _pclk_rdiv;
+ if (abs(rate - pclk) < abs(rate - best)) {
+ best = pclk;
+ best_sysdiv = sysdiv;
+ best_prediv = prediv;
+ best_pll_rdiv = pll_rdiv;
+ best_pclk_rdiv = _pclk_rdiv;
+ best_mult = mult;
+ }
+
+ if (pclk == rate)
+ goto out;
+ }
+
+out:
+ *sysdiv = best_sysdiv;
+ *prediv = best_prediv;
+ *pll_rdiv = best_pll_rdiv;
+ *mult = best_mult;
+ *pclk_rdiv = best_pclk_rdiv;
+ return best;
+}
+
+static int ov5640_set_dvp_pclk(struct ov5640_dev *sensor,
+ const struct ov5640_mode_info *mode,
+ unsigned long rate)
+{
+ u8 sysdiv, prediv, mult, pll_rdiv, pclk_rdiv;
+ int ret;
+ struct i2c_client *client = sensor->i2c_client;
+ u8 dvp_pclk_divider = mode->hact < 1024 ? 2 : 1;//FIXME
+ unsigned int pclk_freq, max_pclk_freq;
+
+ ret = ov5640_write_reg(sensor, OV5640_REG_DVP_PCLK_DIVIDER,
+ dvp_pclk_divider);
+ if (ret)
+ return ret;
+ pclk_freq = rate / dvp_pclk_divider;
+ max_pclk_freq = sensor->ep.bus.parallel.pclk_max_frequency;
+
+ /* clip rate according to optional maximum pixel clock limit */
+ if (max_pclk_freq && (pclk_freq > max_pclk_freq)) {
+ rate = max_pclk_freq * dvp_pclk_divider;
+ dev_dbg(&client->dev, "DVP pixel clock too high (%d > %d Hz), reducing rate...\n",
+ pclk_freq, max_pclk_freq);
+ }
+
+ ov5640_calc_pclk(sensor, rate, &sysdiv, &prediv, &pll_rdiv, &mult,
+ &pclk_rdiv);
+ ret = ov5640_mod_reg(sensor, OV5640_REG_SC_PLL_CTRL1,
+ 0xf0, sysdiv << 4);
+ if (ret)
+ return ret;
+
+ ret = ov5640_mod_reg(sensor, OV5640_REG_SC_PLL_CTRL2,
+ 0xff, mult);
+ if (ret)
+ return ret;
+
+ ret = ov5640_mod_reg(sensor, OV5640_REG_SC_PLL_CTRL3,
+ 0xff, prediv | ((pll_rdiv - 1) << 4));
+ if (ret)
+ return ret;
+
+ return ov5640_mod_reg(sensor, OV5640_REG_SYS_ROOT_DIVIDER,
+ 0x30, ilog2(pclk_rdiv) << 4);
+}
+
+static int ov5640_set_mipi_pclk(struct ov5640_dev *sensor, unsigned long rate)
+{
+ u8 sysdiv, prediv, mult, pll_rdiv, pclk_rdiv;
+ int ret;
+
+ ov5640_calc_pclk(sensor, rate, &sysdiv, &prediv, &pll_rdiv, &mult,
+ &pclk_rdiv);
+ ret = ov5640_write_reg(sensor, OV5640_REG_SC_PLL_CTRL1,
+ (sysdiv << 4) | pclk_rdiv);
+ if (ret)
+ return ret;
+
+ ret = ov5640_mod_reg(sensor, OV5640_REG_SC_PLL_CTRL2,
+ 0xff, mult);
+ if (ret)
+ return ret;
+
+ return ov5640_mod_reg(sensor, OV5640_REG_SC_PLL_CTRL3,
+ 0xff, prediv | ((pll_rdiv - 1) << 4));
+}
+
/* download ov5640 settings to sensor through i2c */
static int ov5640_set_timings(struct ov5640_dev *sensor,
const struct ov5640_mode_info *mode)
@@ -1444,8 +1499,8 @@ ov5640_find_mode(struct ov5640_dev *sensor, enum ov5640_frame_rate fr,
{
const struct ov5640_mode_info *mode;
- mode = v4l2_find_nearest_size(ov5640_mode_data[fr],
- ARRAY_SIZE(ov5640_mode_data[fr]),
+ mode = v4l2_find_nearest_size(ov5640_mode_data,
+ ARRAY_SIZE(ov5640_mode_data),
hact, vact,
width, height);
@@ -1637,8 +1692,12 @@ static int ov5640_set_mode(struct ov5640_dev *sensor)
enum ov5640_downsize_mode dn_mode, orig_dn_mode;
bool auto_gain = sensor->ctrls.auto_gain->val == 1;
bool auto_exp = sensor->ctrls.auto_exp->val == V4L2_EXPOSURE_AUTO;
+ unsigned long rate;
int ret;
+ if (!orig_mode)
+ orig_mode = mode;
+
dn_mode = mode->dn_mode;
orig_dn_mode = orig_mode->dn_mode;
@@ -1655,6 +1714,24 @@ static int ov5640_set_mode(struct ov5640_dev *sensor)
goto restore_auto_gain;
}
+ /*
+ * All the formats we support have 2 bytes per pixel, except for JPEG
+ * which is 1 byte per pixel, but JPEG requires the same rate
+ * than YUV (horizontal lines blanking).
+ */
+ rate = mode->vtot * mode->htot * 2;
+ rate *= ov5640_framerates[sensor->current_fr];
+
+ if (sensor->ep.bus_type == V4L2_MBUS_CSI2) {
+ rate = rate / sensor->ep.bus.mipi_csi2.num_data_lanes;
+ ret = ov5640_set_mipi_pclk(sensor, rate);
+ } else {
+ ret = ov5640_set_dvp_pclk(sensor, mode, rate);
+ }
+
+ if (ret < 0)
+ return 0;
+
if ((dn_mode == SUBSAMPLING && orig_dn_mode == SCALING) ||
(dn_mode == SCALING && orig_dn_mode == SUBSAMPLING)) {
/*
@@ -2502,10 +2579,10 @@ static int ov5640_enum_frame_size(struct v4l2_subdev *sd,
return -EINVAL;
fse->min_width =
- ov5640_mode_data[0][fse->index].hact;
+ ov5640_mode_data[fse->index].hact;
fse->max_width = fse->min_width;
fse->min_height =
- ov5640_mode_data[0][fse->index].vact;
+ ov5640_mode_data[fse->index].vact;
fse->max_height = fse->min_height;
return 0;
@@ -2573,8 +2650,6 @@ static int ov5640_s_frame_interval(struct v4l2_subdev *sd,
if (frame_rate < 0)
frame_rate = OV5640_15_FPS;
- sensor->current_fr = frame_rate;
- sensor->frame_interval = fi->interval;
mode = ov5640_find_mode(sensor, frame_rate, mode->hact,
mode->vact, true);
if (!mode) {
@@ -2582,7 +2657,10 @@ static int ov5640_s_frame_interval(struct v4l2_subdev *sd,
goto out;
}
- if (mode != sensor->current_mode) {
+ if (mode != sensor->current_mode ||
+ (frame_rate != sensor->current_fr)) {
+ sensor->current_fr = frame_rate;
+ sensor->frame_interval = fi->interval;
sensor->current_mode = mode;
sensor->pending_mode_change = true;
}
@@ -2613,7 +2691,8 @@ static int ov5640_s_stream(struct v4l2_subdev *sd, int enable)
if (sensor->streaming == !enable) {
if (enable && sensor->pending_mode_change) {
- ret = ov5640_set_mode(sensor);
+ ret = ov5640_set_mode(sensor, sensor->last_mode);
+
if (ret)
goto out;
}
@@ -2735,7 +2814,7 @@ static int ov5640_probe(struct i2c_client *client,
sensor->frame_interval.denominator = ov5640_framerates[OV5640_30_FPS];
sensor->current_fr = OV5640_30_FPS;
sensor->current_mode =
- &ov5640_mode_data[OV5640_30_FPS][OV5640_MODE_VGA_640_480];
+ &ov5640_mode_data[OV5640_MODE_VGA_640_480];
sensor->last_mode = sensor->current_mode;
sensor->ae_target = 52;
diff --git a/drivers/media/platform/stm32/stm32-dcmi.c b/drivers/media/platform/stm32/stm32-dcmi.c
index 7215641..49849e6 100644
--- a/drivers/media/platform/stm32/stm32-dcmi.c
+++ b/drivers/media/platform/stm32/stm32-dcmi.c
@@ -95,6 +95,9 @@ enum state {
#define MIN_HEIGHT 16U
#define MAX_HEIGHT 2592U
+/* DMA can sustain YUV 720p@15fps max */
+#define MAX_DMA_BANDWIDTH (1280 * 720 * 2 * 15)
+
#define TIMEOUT_MS 1000
struct dcmi_graph_entity {
@@ -570,9 +573,9 @@ static int dcmi_start_streaming(struct vb2_queue *vq, unsigned int count)
int ret;
ret = pm_runtime_get_sync(dcmi->dev);
- if (ret) {
- dev_err(dcmi->dev, "%s: Failed to start streaming, cannot get sync\n",
- __func__);
+ if (ret < 0) {
+ dev_err(dcmi->dev, "%s: Failed to start streaming, cannot get sync (%d)\n",
+ __func__, ret);
goto err_release_buffers;
}
@@ -621,8 +624,31 @@ static int dcmi_start_streaming(struct vb2_queue *vq, unsigned int count)
dcmi_set_crop(dcmi);
/* Enable jpeg capture */
- if (dcmi->sd_format->fourcc == V4L2_PIX_FMT_JPEG)
- reg_set(dcmi->regs, DCMI_CR, CR_CM);/* Snapshot mode */
+ if (dcmi->sd_format->fourcc == V4L2_PIX_FMT_JPEG) {
+ unsigned int rate;
+ struct v4l2_streamparm p = {
+ .type = V4L2_BUF_TYPE_VIDEO_CAPTURE
+ };
+ struct v4l2_fract frame_interval = {1, 30};
+
+ ret = v4l2_g_parm_cap(dcmi->vdev, dcmi->entity.subdev, &p);
+ if (!ret)
+ frame_interval = p.parm.capture.timeperframe;
+
+ rate = dcmi->fmt.fmt.pix.sizeimage *
+ frame_interval.denominator / frame_interval.numerator;
+
+ /*
+ * If rate exceed DMA capabilities, switch to snapshot mode
+ * to ensure that current DMA transfer is elapsed before
+ * capturing a new JPEG.
+ */
+ if (rate > MAX_DMA_BANDWIDTH) {
+ reg_set(dcmi->regs, DCMI_CR, CR_CM);/* Snapshot mode */
+ dev_dbg(dcmi->dev, "Capture rate is too high for continuous mode (%d > %d bytes/s), switch to snapshot mode\n",
+ rate, MAX_DMA_BANDWIDTH);
+ }
+ }
/* Enable dcmi */
reg_set(dcmi->regs, DCMI_CR, CR_ENABLE);
@@ -659,7 +685,10 @@ static int dcmi_start_streaming(struct vb2_queue *vq, unsigned int count)
}
/* Enable interruptions */
- reg_set(dcmi->regs, DCMI_IER, IT_FRAME | IT_OVR | IT_ERR);
+ if (dcmi->sd_format->fourcc == V4L2_PIX_FMT_JPEG)
+ reg_set(dcmi->regs, DCMI_IER, IT_FRAME | IT_OVR | IT_ERR);
+ else
+ reg_set(dcmi->regs, DCMI_IER, IT_OVR | IT_ERR);
return 0;
diff --git a/drivers/media/v4l2-core/v4l2-fwnode.c b/drivers/media/v4l2-core/v4l2-fwnode.c
index 169bdbb..505338e 100644
--- a/drivers/media/v4l2-core/v4l2-fwnode.c
+++ b/drivers/media/v4l2-core/v4l2-fwnode.c
@@ -158,6 +158,9 @@ static void v4l2_fwnode_endpoint_parse_parallel_bus(
flags |= v ? V4L2_MBUS_DATA_ENABLE_HIGH :
V4L2_MBUS_DATA_ENABLE_LOW;
+ if (!fwnode_property_read_u32(fwnode, "pclk-max-frequency", &v))
+ bus->pclk_max_frequency = v;
+
bus->flags = flags;
}
diff --git a/include/media/v4l2-fwnode.h b/include/media/v4l2-fwnode.h
index 9cccab6..946b48d 100644
--- a/include/media/v4l2-fwnode.h
+++ b/include/media/v4l2-fwnode.h
@@ -52,11 +52,13 @@ struct v4l2_fwnode_bus_mipi_csi2 {
* @flags: media bus (V4L2_MBUS_*) flags
* @bus_width: bus width in bits
* @data_shift: data shift in bits
+ * @max_pclk_frequency: maximum pixel clock in hertz
*/
struct v4l2_fwnode_bus_parallel {
unsigned int flags;
unsigned char bus_width;
unsigned char data_shift;
+ unsigned int pclk_max_frequency;
};
/**
--
2.7.4

View File

@ -0,0 +1,288 @@
From 85d48072cfb2e491d10a235c4ade2460e3bbc93a Mon Sep 17 00:00:00 2001
From: Christophe Priouzeau <christophe.priouzeau@st.com>
Date: Mon, 26 Nov 2018 14:40:42 +0100
Subject: [PATCH 21/52] ARM-stm32mp1-r0-rc2-PINCTRL
---
.../bindings/pinctrl/st,stm32-pinctrl.txt | 1 +
drivers/pinctrl/core.c | 15 +----
drivers/pinctrl/pinctrl-stmfx.c | 8 +++
drivers/pinctrl/stm32/pinctrl-stm32.c | 71 +++++++++++++++++++++-
include/linux/pinctrl/pinctrl.h | 2 +
5 files changed, 83 insertions(+), 14 deletions(-)
diff --git a/Documentation/devicetree/bindings/pinctrl/st,stm32-pinctrl.txt b/Documentation/devicetree/bindings/pinctrl/st,stm32-pinctrl.txt
index 286c981..1a5d1e2 100644
--- a/Documentation/devicetree/bindings/pinctrl/st,stm32-pinctrl.txt
+++ b/Documentation/devicetree/bindings/pinctrl/st,stm32-pinctrl.txt
@@ -58,6 +58,7 @@ Optional properties:
used to select GPIOs as interrupts).
- st,package: Indicates the SOC package used.
More details in include/dt-bindings/pinctrl/stm32-pinfunc.h
+ - hwlocks: reference to a phandle of a hardware spinlock provider node.
Example 1:
#include <dt-bindings/pinctrl/stm32f429-pinfunc.h>
diff --git a/drivers/pinctrl/core.c b/drivers/pinctrl/core.c
index a3dd777..0220d43 100644
--- a/drivers/pinctrl/core.c
+++ b/drivers/pinctrl/core.c
@@ -1992,7 +1992,7 @@ pinctrl_init_controller(struct pinctrl_desc *pctldesc, struct device *dev,
return ERR_PTR(ret);
}
-static int pinctrl_claim_hogs(struct pinctrl_dev *pctldev)
+int pinctrl_claim_hogs(struct pinctrl_dev *pctldev)
{
pctldev->p = create_pinctrl(pctldev->dev, pctldev);
if (PTR_ERR(pctldev->p) == -ENODEV) {
@@ -2030,21 +2030,10 @@ static int pinctrl_claim_hogs(struct pinctrl_dev *pctldev)
return 0;
}
+EXPORT_SYMBOL_GPL(pinctrl_claim_hogs);
int pinctrl_enable(struct pinctrl_dev *pctldev)
{
- int error;
-
- error = pinctrl_claim_hogs(pctldev);
- if (error) {
- dev_err(pctldev->dev, "could not claim hogs: %i\n",
- error);
- mutex_destroy(&pctldev->mutex);
- kfree(pctldev);
-
- return error;
- }
-
mutex_lock(&pinctrldev_list_mutex);
list_add_tail(&pctldev->node, &pinctrldev_list);
mutex_unlock(&pinctrldev_list_mutex);
diff --git a/drivers/pinctrl/pinctrl-stmfx.c b/drivers/pinctrl/pinctrl-stmfx.c
index e253ed1..15d5757 100644
--- a/drivers/pinctrl/pinctrl-stmfx.c
+++ b/drivers/pinctrl/pinctrl-stmfx.c
@@ -663,6 +663,14 @@ static int stmfx_pinctrl_probe(struct platform_device *pdev)
if (ret)
return ret;
+ /*
+ * Claim hogs after enabling gpio function, otherwise pin
+ * configuration will not apply
+ */
+ ret = pinctrl_claim_hogs(pctl->pctl_dev);
+ if (ret)
+ return ret;
+
pctl->irq_chip.name = dev_name(pctl->dev);
pctl->irq_chip.irq_mask = stmfx_pinctrl_irq_mask;
pctl->irq_chip.irq_unmask = stmfx_pinctrl_irq_unmask;
diff --git a/drivers/pinctrl/stm32/pinctrl-stm32.c b/drivers/pinctrl/stm32/pinctrl-stm32.c
index e25917f..914bee4 100644
--- a/drivers/pinctrl/stm32/pinctrl-stm32.c
+++ b/drivers/pinctrl/stm32/pinctrl-stm32.c
@@ -8,6 +8,7 @@
*/
#include <linux/clk.h>
#include <linux/gpio/driver.h>
+#include <linux/hwspinlock.h>
#include <linux/io.h>
#include <linux/irq.h>
#include <linux/mfd/syscon.h>
@@ -64,6 +65,8 @@
#define gpio_range_to_bank(chip) \
container_of(chip, struct stm32_gpio_bank, range)
+#define HWSPINLOCK_TIMEOUT 5 /* msec */
+
static const char * const stm32_gpio_functions[] = {
"gpio", "af0", "af1",
"af2", "af3", "af4",
@@ -111,6 +114,7 @@ struct stm32_pinctrl {
u32 npins;
u32 pkg;
u32 pin_base_shift;
+ struct hwspinlock *hwlock;
};
static inline int stm32_gpio_pin(int gpio)
@@ -598,14 +602,24 @@ static int stm32_pmx_get_func_groups(struct pinctrl_dev *pctldev,
static void stm32_pmx_set_mode(struct stm32_gpio_bank *bank,
int pin, u32 mode, u32 alt)
{
+ struct stm32_pinctrl *pctl = dev_get_drvdata(bank->gpio_chip.parent);
u32 val;
int alt_shift = (pin % 8) * 4;
int alt_offset = STM32_GPIO_AFRL + (pin / 8) * 4;
unsigned long flags;
+ int err = 0;
clk_enable(bank->clk);
spin_lock_irqsave(&bank->lock, flags);
+ if (pctl->hwlock)
+ err = hwspin_lock_timeout(pctl->hwlock, HWSPINLOCK_TIMEOUT);
+
+ if (err) {
+ dev_err(pctl->dev, "Can't get hwspinlock\n");
+ goto unlock;
+ }
+
val = readl_relaxed(bank->base + alt_offset);
val &= ~GENMASK(alt_shift + 3, alt_shift);
val |= (alt << alt_shift);
@@ -618,6 +632,10 @@ static void stm32_pmx_set_mode(struct stm32_gpio_bank *bank,
stm32_gpio_backup_mode(bank, pin, mode, alt);
+ if (pctl->hwlock)
+ hwspin_unlock(pctl->hwlock);
+
+unlock:
spin_unlock_irqrestore(&bank->lock, flags);
clk_disable(bank->clk);
}
@@ -707,12 +725,22 @@ static const struct pinmux_ops stm32_pmx_ops = {
static void stm32_pconf_set_driving(struct stm32_gpio_bank *bank,
unsigned offset, u32 drive)
{
+ struct stm32_pinctrl *pctl = dev_get_drvdata(bank->gpio_chip.parent);
unsigned long flags;
u32 val;
+ int err = 0;
clk_enable(bank->clk);
spin_lock_irqsave(&bank->lock, flags);
+ if (pctl->hwlock)
+ err = hwspin_lock_timeout(pctl->hwlock, HWSPINLOCK_TIMEOUT);
+
+ if (err) {
+ dev_err(pctl->dev, "Can't get hwspinlock\n");
+ goto unlock;
+ }
+
val = readl_relaxed(bank->base + STM32_GPIO_TYPER);
val &= ~BIT(offset);
val |= drive << offset;
@@ -720,6 +748,10 @@ static void stm32_pconf_set_driving(struct stm32_gpio_bank *bank,
stm32_gpio_backup_driving(bank, offset, drive);
+ if (pctl->hwlock)
+ hwspin_unlock(pctl->hwlock);
+
+unlock:
spin_unlock_irqrestore(&bank->lock, flags);
clk_disable(bank->clk);
}
@@ -745,12 +777,22 @@ static u32 stm32_pconf_get_driving(struct stm32_gpio_bank *bank,
static void stm32_pconf_set_speed(struct stm32_gpio_bank *bank,
unsigned offset, u32 speed)
{
+ struct stm32_pinctrl *pctl = dev_get_drvdata(bank->gpio_chip.parent);
unsigned long flags;
u32 val;
+ int err = 0;
clk_enable(bank->clk);
spin_lock_irqsave(&bank->lock, flags);
+ if (pctl->hwlock)
+ err = hwspin_lock_timeout(pctl->hwlock, HWSPINLOCK_TIMEOUT);
+
+ if (err) {
+ dev_err(pctl->dev, "Can't get hwspinlock\n");
+ goto unlock;
+ }
+
val = readl_relaxed(bank->base + STM32_GPIO_SPEEDR);
val &= ~GENMASK(offset * 2 + 1, offset * 2);
val |= speed << (offset * 2);
@@ -758,6 +800,10 @@ static void stm32_pconf_set_speed(struct stm32_gpio_bank *bank,
stm32_gpio_backup_speed(bank, offset, speed);
+ if (pctl->hwlock)
+ hwspin_unlock(pctl->hwlock);
+
+unlock:
spin_unlock_irqrestore(&bank->lock, flags);
clk_disable(bank->clk);
}
@@ -783,12 +829,22 @@ static u32 stm32_pconf_get_speed(struct stm32_gpio_bank *bank,
static void stm32_pconf_set_bias(struct stm32_gpio_bank *bank,
unsigned offset, u32 bias)
{
+ struct stm32_pinctrl *pctl = dev_get_drvdata(bank->gpio_chip.parent);
unsigned long flags;
u32 val;
+ int err = 0;
clk_enable(bank->clk);
spin_lock_irqsave(&bank->lock, flags);
+ if (pctl->hwlock)
+ err = hwspin_lock_timeout(pctl->hwlock, HWSPINLOCK_TIMEOUT);
+
+ if (err) {
+ dev_err(pctl->dev, "Can't get hwspinlock\n");
+ goto unlock;
+ }
+
val = readl_relaxed(bank->base + STM32_GPIO_PUPDR);
val &= ~GENMASK(offset * 2 + 1, offset * 2);
val |= bias << (offset * 2);
@@ -796,6 +852,10 @@ static void stm32_pconf_set_bias(struct stm32_gpio_bank *bank,
stm32_gpio_backup_bias(bank, offset, bias);
+ if (pctl->hwlock)
+ hwspin_unlock(pctl->hwlock);
+
+unlock:
spin_unlock_irqrestore(&bank->lock, flags);
clk_disable(bank->clk);
}
@@ -1206,7 +1266,7 @@ int stm32_pctl_probe(struct platform_device *pdev)
struct device *dev = &pdev->dev;
struct stm32_pinctrl *pctl;
struct pinctrl_pin_desc *pins;
- int i, ret, banks = 0;
+ int i, ret, hwlock_id, banks = 0;
if (!np)
return -EINVAL;
@@ -1226,6 +1286,15 @@ int stm32_pctl_probe(struct platform_device *pdev)
platform_set_drvdata(pdev, pctl);
+ /* hwspinlock is optional */
+ hwlock_id = of_hwspin_lock_get_id(pdev->dev.of_node, 0);
+ if (hwlock_id < 0) {
+ if (hwlock_id == -EPROBE_DEFER)
+ return hwlock_id;
+ } else {
+ pctl->hwlock = hwspin_lock_request_specific(hwlock_id);
+ }
+
pctl->dev = dev;
pctl->match_data = match->data;
diff --git a/include/linux/pinctrl/pinctrl.h b/include/linux/pinctrl/pinctrl.h
index 8f5dbb8..bbeaa29 100644
--- a/include/linux/pinctrl/pinctrl.h
+++ b/include/linux/pinctrl/pinctrl.h
@@ -148,6 +148,8 @@ extern int pinctrl_register_and_init(struct pinctrl_desc *pctldesc,
struct pinctrl_dev **pctldev);
extern int pinctrl_enable(struct pinctrl_dev *pctldev);
+extern int pinctrl_claim_hogs(struct pinctrl_dev *pctldev);
+
/* Please use pinctrl_register_and_init() and pinctrl_enable() instead */
extern struct pinctrl_dev *pinctrl_register(struct pinctrl_desc *pctldesc,
struct device *dev, void *driver_data);
--
2.7.4

View File

@ -0,0 +1,781 @@
From aed35270f0be1c5c61a028d7c183e60269f3abe3 Mon Sep 17 00:00:00 2001
From: Christophe Priouzeau <christophe.priouzeau@st.com>
Date: Mon, 26 Nov 2018 14:41:37 +0100
Subject: [PATCH 22/52] ARM-stm32mp1-r0-rc2-MFD-IRQ
---
.../interrupt-controller/st,stm32-exti.txt | 34 +++++-
.../devicetree/bindings/mfd/st,stpmic1.txt | 2 +-
Documentation/devicetree/bindings/mfd/syscon.txt | 1 +
drivers/irqchip/irq-stm32-exti.c | 133 ++++++++++++++++++---
drivers/mfd/stm32-pwr.c | 131 +++++++++-----------
drivers/mfd/stpmic1.c | 16 +--
drivers/mfd/syscon.c | 19 +++
drivers/mfd/wm8994-core.c | 15 +++
include/linux/mfd/stpmic1.h | 1 -
9 files changed, 247 insertions(+), 105 deletions(-)
diff --git a/Documentation/devicetree/bindings/interrupt-controller/st,stm32-exti.txt b/Documentation/devicetree/bindings/interrupt-controller/st,stm32-exti.txt
index 6a36bf6..abcf816 100644
--- a/Documentation/devicetree/bindings/interrupt-controller/st,stm32-exti.txt
+++ b/Documentation/devicetree/bindings/interrupt-controller/st,stm32-exti.txt
@@ -14,7 +14,23 @@ Required properties:
(only needed for exti controller with multiple exti under
same parent interrupt: st,stm32-exti and st,stm32h7-exti)
-Example:
+Optional properties:
+
+- hwlocks: reference to a phandle of a hardware spinlock provider node.
+
+Exti could have several parent interrupt controllers. In this case child nodes
+are used to describe those "extra" parent controllers. Properties to use are:
+
+- interrupt-controller: Indentifies the node as an interrupt controller
+- #interrupt-cells: Specifies the number of cells to encode an interrupt
+ specifier, shall be 2
+- interrupt-parent: Phandle to the interrupt parent node.
+- st,irq-number: Interrupt number mapped on the parent.
+
+See example 2.
+
+
+Example 1:
exti: interrupt-controller@40013c00 {
compatible = "st,stm32-exti";
@@ -23,3 +39,19 @@ exti: interrupt-controller@40013c00 {
reg = <0x40013C00 0x400>;
interrupts = <1>, <2>, <3>, <6>, <7>, <8>, <9>, <10>, <23>, <40>, <41>, <42>, <62>, <76>;
};
+
+Example 2:
+
+exti: interrupt-controller@5000d000 {
+ compatible = "st,stm32mp1-exti", "syscon";
+ interrupt-controller;
+ #interrupt-cells = <2>;
+ reg = <0x5000d000 0x400>;
+
+ exti_pwr: exti-pwr {
+ interrupt-controller;
+ #interrupt-cells = <2>;
+ interrupt-parent = <&pwr>;
+ st,irq-number = <6>;
+ };
+};
diff --git a/Documentation/devicetree/bindings/mfd/st,stpmic1.txt b/Documentation/devicetree/bindings/mfd/st,stpmic1.txt
index 54b64e2..0fab08a 100644
--- a/Documentation/devicetree/bindings/mfd/st,stpmic1.txt
+++ b/Documentation/devicetree/bindings/mfd/st,stpmic1.txt
@@ -4,7 +4,6 @@ Required parent device properties:
- compatible: "st,stpmic1"
- reg: The I2C slave address for the STPMIC1 chip.
- interrupts: The interrupt lines the device is connected to.
- The second interrupt is used for wake-up.
- #interrupt-cells: Should be 2.
- interrupt-controller: Describes the STPMIC1 as an interrupt
controller (has its own domain). Interrupt number are the following:
@@ -81,6 +80,7 @@ Optional parent device properties:
-bit 5: SW_OUT discharge is enabled
-bit 6: VBUS_OTG detection is enabled
-bit 7: BOOST_OVP is disabled
+- wakeup-source: bool flag to indicate this device has wakeup capabilities
STPMIC1 consists in a varied group of sub-devices.
Each sub-device binding is be described in own documentation file.
diff --git a/Documentation/devicetree/bindings/mfd/syscon.txt b/Documentation/devicetree/bindings/mfd/syscon.txt
index 25d9e9c..a9aaa51 100644
--- a/Documentation/devicetree/bindings/mfd/syscon.txt
+++ b/Documentation/devicetree/bindings/mfd/syscon.txt
@@ -17,6 +17,7 @@ Optional property:
- reg-io-width: the size (in bytes) of the IO accesses that should be
performed on the device.
- hwlocks: reference to a phandle of a hardware spinlock provider node.
+- clocks: phandle to the syscon clock
Examples:
gpr: iomuxc-gpr@20e0000 {
diff --git a/drivers/irqchip/irq-stm32-exti.c b/drivers/irqchip/irq-stm32-exti.c
index e185ed8..9cc15f1 100644
--- a/drivers/irqchip/irq-stm32-exti.c
+++ b/drivers/irqchip/irq-stm32-exti.c
@@ -6,6 +6,7 @@
*/
#include <linux/bitops.h>
+#include <linux/hwspinlock.h>
#include <linux/interrupt.h>
#include <linux/io.h>
#include <linux/irq.h>
@@ -20,6 +21,8 @@
#define IRQS_PER_BANK 32
+#define HWSPINLOCK_TIMEOUT 5 /* msec */
+
struct stm32_exti_bank {
u32 imr_ofst;
u32 emr_ofst;
@@ -47,6 +50,7 @@ struct stm32_exti_drv_data {
struct stm32_exti_chip_data {
struct stm32_exti_host_data *host_data;
const struct stm32_exti_bank *reg_bank;
+ struct hwspinlock *hwlock;
struct raw_spinlock rlock;
u32 wake_active;
u32 mask_cache;
@@ -275,25 +279,34 @@ static int stm32_irq_set_type(struct irq_data *d, unsigned int type)
struct stm32_exti_chip_data *chip_data = gc->private;
const struct stm32_exti_bank *stm32_bank = chip_data->reg_bank;
u32 rtsr, ftsr;
- int err;
+ int err = 0;
irq_gc_lock(gc);
+ if (chip_data->hwlock)
+ err = hwspin_lock_timeout(chip_data->hwlock,
+ HWSPINLOCK_TIMEOUT);
+
+ if (err)
+ goto unlock;
+
rtsr = irq_reg_readl(gc, stm32_bank->rtsr_ofst);
ftsr = irq_reg_readl(gc, stm32_bank->ftsr_ofst);
err = stm32_exti_set_type(d, type, &rtsr, &ftsr);
- if (err) {
- irq_gc_unlock(gc);
- return err;
- }
+ if (err)
+ goto unspinlock;
irq_reg_writel(gc, rtsr, stm32_bank->rtsr_ofst);
irq_reg_writel(gc, ftsr, stm32_bank->ftsr_ofst);
+unspinlock:
+ if (chip_data->hwlock)
+ hwspin_unlock(chip_data->hwlock);
+unlock:
irq_gc_unlock(gc);
- return 0;
+ return err;
}
static void stm32_chip_suspend(struct stm32_exti_chip_data *chip_data,
@@ -457,22 +470,36 @@ static int stm32_exti_h_set_type(struct irq_data *d, unsigned int type)
const struct stm32_exti_bank *stm32_bank = chip_data->reg_bank;
void __iomem *base = chip_data->host_data->base;
u32 rtsr, ftsr;
- int err;
+ int err = 0;
raw_spin_lock(&chip_data->rlock);
+
+ if (chip_data->hwlock)
+ err = hwspin_lock_timeout(chip_data->hwlock,
+ HWSPINLOCK_TIMEOUT);
+
+ if (err)
+ goto unlock;
+
rtsr = readl_relaxed(base + stm32_bank->rtsr_ofst);
ftsr = readl_relaxed(base + stm32_bank->ftsr_ofst);
err = stm32_exti_set_type(d, type, &rtsr, &ftsr);
- if (err) {
- raw_spin_unlock(&chip_data->rlock);
- return err;
- }
+ if (err)
+ goto unspinlock;
writel_relaxed(rtsr, base + stm32_bank->rtsr_ofst);
writel_relaxed(ftsr, base + stm32_bank->ftsr_ofst);
+
+unspinlock:
+ if (chip_data->hwlock)
+ hwspin_unlock(chip_data->hwlock);
+unlock:
raw_spin_unlock(&chip_data->rlock);
+ if (d->parent_data->chip)
+ irq_chip_set_type_parent(d, type);
+
return 0;
}
@@ -490,6 +517,9 @@ static int stm32_exti_h_set_wake(struct irq_data *d, unsigned int on)
raw_spin_unlock(&chip_data->rlock);
+ if (d->parent_data->chip)
+ irq_chip_set_wake_parent(d, on);
+
return 0;
}
@@ -502,6 +532,12 @@ static int stm32_exti_h_set_affinity(struct irq_data *d,
return -EINVAL;
}
+static void stm32_exti_h_ack(struct irq_data *d)
+{
+ if (d->parent_data->chip)
+ irq_chip_ack_parent(d);
+}
+
#ifdef CONFIG_PM
static int stm32_exti_h_suspend(void)
{
@@ -547,6 +583,7 @@ static inline void stm32_exti_h_syscore_init(void) {}
static struct irq_chip stm32_exti_h_chip = {
.name = "stm32-exti-h",
.irq_eoi = stm32_exti_h_eoi,
+ .irq_ack = stm32_exti_h_ack,
.irq_mask = stm32_exti_h_mask,
.irq_unmask = stm32_exti_h_unmask,
.irq_retrigger = irq_chip_retrigger_hierarchy,
@@ -574,15 +611,29 @@ static int stm32_exti_h_domain_alloc(struct irq_domain *dm,
irq_domain_set_hwirq_and_chip(dm, virq, hwirq,
&stm32_exti_h_chip, chip_data);
- p_irq = stm32_exti_to_irq(host_data->drv_data, hwirq);
- if (p_irq >= 0) {
+ /*
+ * EXTI 55 to 60 are mapped to PWR interrupt controller.
+ * The hwirq translation is done diferently than for GIC.
+ */
+ if (hwirq >= 55 && hwirq <= 60) {
p_fwspec.fwnode = dm->parent->fwnode;
- p_fwspec.param_count = 3;
- p_fwspec.param[0] = GIC_SPI;
- p_fwspec.param[1] = p_irq;
- p_fwspec.param[2] = IRQ_TYPE_LEVEL_HIGH;
+ p_fwspec.param_count = 2;
+ p_fwspec.param[0] = hwirq - 55;
+ p_fwspec.param[1] = fwspec->param[1];
return irq_domain_alloc_irqs_parent(dm, virq, 1, &p_fwspec);
+ } else {
+ p_irq = stm32_exti_to_irq(host_data->drv_data, hwirq);
+ if (p_irq >= 0) {
+ p_fwspec.fwnode = dm->parent->fwnode;
+ p_fwspec.param_count = 3;
+ p_fwspec.param[0] = GIC_SPI;
+ p_fwspec.param[1] = p_irq;
+ p_fwspec.param[2] = IRQ_TYPE_LEVEL_HIGH;
+
+ return irq_domain_alloc_irqs_parent(dm, virq, 1,
+ &p_fwspec);
+ }
}
return 0;
@@ -665,6 +716,7 @@ static int __init stm32_exti_init(const struct stm32_exti_drv_data *drv_data,
int nr_irqs, ret, i;
struct irq_chip_generic *gc;
struct irq_domain *domain;
+ struct hwspinlock *hwlock = NULL;
host_data = stm32_exti_host_init(drv_data, node);
if (!host_data)
@@ -687,12 +739,22 @@ static int __init stm32_exti_init(const struct stm32_exti_drv_data *drv_data,
goto out_free_domain;
}
+ /* hwspinlock is optional */
+ ret = of_hwspin_lock_get_id(node, 0);
+ if (ret < 0) {
+ if (ret == -EPROBE_DEFER)
+ goto out_free_domain;
+ } else {
+ hwlock = hwspin_lock_request_specific(ret);
+ }
+
for (i = 0; i < drv_data->bank_nr; i++) {
const struct stm32_exti_bank *stm32_bank;
struct stm32_exti_chip_data *chip_data;
stm32_bank = drv_data->exti_banks[i];
chip_data = stm32_exti_chip_init(host_data, i, node);
+ chip_data->hwlock = hwlock;
gc = irq_get_domain_generic_chip(domain, i * IRQS_PER_BANK);
@@ -760,11 +822,12 @@ __init stm32_exti_hierarchy_init(const struct stm32_exti_drv_data *drv_data,
{
struct irq_domain *parent_domain, *domain;
struct stm32_exti_host_data *host_data;
+ struct device_node *child;
int ret, i;
parent_domain = irq_find_host(parent);
if (!parent_domain) {
- pr_err("interrupt-parent not found\n");
+ pr_err("GIC interrupt-parent not found\n");
return -EINVAL;
}
@@ -786,6 +849,40 @@ __init stm32_exti_hierarchy_init(const struct stm32_exti_drv_data *drv_data,
goto out_unmap;
}
+ for_each_child_of_node(node, child) {
+ struct device_node *parent_node;
+ u32 nirqs;
+
+ parent_node = of_irq_find_parent(child);
+ parent_domain = irq_find_host(parent_node);
+
+ if (!parent_domain) {
+ pr_err("%s: child interrupt-parent not found\n",
+ child->name);
+ ret = -EINVAL;
+ goto out_unmap;
+ }
+
+ ret = of_property_read_u32(child, "st,irq-number", &nirqs);
+ if (ret != 0 || nirqs == 0) {
+ pr_err("%s: Missing or bad irq-number property\n"
+ , __func__);
+ ret = -EINVAL;
+ goto out_unmap;
+ }
+
+ domain = irq_domain_add_hierarchy(parent_domain, 0, nirqs,
+ child,
+ &stm32_exti_h_domain_ops,
+ host_data);
+ if (!domain) {
+ pr_err("%s: Could not register exti domain.\n",
+ node->name);
+ ret = -ENOMEM;
+ goto out_unmap;
+ }
+ }
+
stm32_exti_h_syscore_init();
return 0;
diff --git a/drivers/mfd/stm32-pwr.c b/drivers/mfd/stm32-pwr.c
index 377e2f5..206a933 100644
--- a/drivers/mfd/stm32-pwr.c
+++ b/drivers/mfd/stm32-pwr.c
@@ -5,7 +5,9 @@
*/
#include <linux/arm-smccc.h>
+#include <linux/irqchip.h>
#include <linux/irqchip/chained_irq.h>
+#include <linux/of_address.h>
#include <linux/of_irq.h>
#include <linux/platform_device.h>
#include <asm/exception.h>
@@ -45,7 +47,6 @@ enum wkup_pull_setting {
} \
struct stm32_pwr_data {
- struct device *dev; /* self device */
void __iomem *base; /* IO Memory base address */
struct irq_domain *domain; /* Domain for this controller */
int irq; /* Parent interrupt */
@@ -53,25 +54,19 @@ struct stm32_pwr_data {
static void stm32_pwr_irq_ack(struct irq_data *d)
{
- struct stm32_pwr_data *priv = d->domain->host_data;
-
- dev_dbg(priv->dev, "irq:%lu\n", d->hwirq);
+ pr_debug("irq:%lu\n", d->hwirq);
SMC(STM32_SVC_PWR, STM32_SET_BITS, WKUPCR, BIT(d->hwirq));
}
static void stm32_pwr_irq_mask(struct irq_data *d)
{
- struct stm32_pwr_data *priv = d->domain->host_data;
-
- dev_dbg(priv->dev, "irq:%lu\n", d->hwirq);
+ pr_debug("irq:%lu\n", d->hwirq);
SMC(STM32_SVC_PWR, STM32_CLEAR_BITS, MPUWKUPENR, BIT(d->hwirq));
}
static void stm32_pwr_irq_unmask(struct irq_data *d)
{
- struct stm32_pwr_data *priv = d->domain->host_data;
-
- dev_dbg(priv->dev, "irq:%lu\n", d->hwirq);
+ pr_debug("irq:%lu\n", d->hwirq);
SMC(STM32_SVC_PWR, STM32_SET_BITS, MPUWKUPENR, BIT(d->hwirq));
}
@@ -79,7 +74,7 @@ static int stm32_pwr_irq_set_wake(struct irq_data *d, unsigned int on)
{
struct stm32_pwr_data *priv = d->domain->host_data;
- dev_dbg(priv->dev, "irq:%lu on:%d\n", d->hwirq, on);
+ pr_debug("irq:%lu on:%d\n", d->hwirq, on);
if (on)
enable_irq_wake(priv->irq);
else
@@ -95,7 +90,7 @@ static int stm32_pwr_irq_set_type(struct irq_data *d, unsigned int flow_type)
u32 wkupcr;
int en;
- dev_dbg(priv->dev, "irq:%lu\n", d->hwirq);
+ pr_debug("irq:%lu\n", d->hwirq);
en = readl_relaxed(priv->base + MPUWKUPENR) & BIT(pin_id);
/* reference manual request to disable the wakeup pin while
@@ -115,6 +110,7 @@ static int stm32_pwr_irq_set_type(struct irq_data *d, unsigned int flow_type)
default:
return -EINVAL;
}
+
SMC(STM32_SVC_PWR, STM32_WRITE, WKUPCR, wkupcr);
if (en)
@@ -124,7 +120,7 @@ static int stm32_pwr_irq_set_type(struct irq_data *d, unsigned int flow_type)
}
static struct irq_chip stm32_pwr_irq_chip = {
- .name = "stm32_pwr-irq",
+ .name = "stm32-pwr-irq",
.irq_ack = stm32_pwr_irq_ack,
.irq_mask = stm32_pwr_irq_mask,
.irq_unmask = stm32_pwr_irq_unmask,
@@ -132,29 +128,23 @@ static struct irq_chip stm32_pwr_irq_chip = {
.irq_set_wake = stm32_pwr_irq_set_wake,
};
-static int stm32_pwr_irq_map(struct irq_domain *h, unsigned int virq,
- irq_hw_number_t hw)
-{
- irq_set_chip_and_handler(virq, &stm32_pwr_irq_chip, handle_edge_irq);
- return 0;
-}
-
static int stm32_pwr_irq_set_pull_config(struct irq_domain *d, int pin_id,
enum wkup_pull_setting config)
{
struct stm32_pwr_data *priv = d->host_data;
u32 wkupcr;
- dev_dbg(priv->dev, "irq:%d pull config:0x%x\n", pin_id, config);
+ pr_debug("irq:%d pull config:0x%x\n", pin_id, config);
if (config >= WKUP_PULL_RESERVED) {
- dev_err(priv->dev, "%s: bad irq pull config\n", __func__);
+ pr_err("%s: bad irq pull config\n", __func__);
return -EINVAL;
}
wkupcr = readl_relaxed(priv->base + WKUPCR);
wkupcr &= ~((WKUP_PULL_MASK) << (WKUP_PULL_SHIFT + pin_id * 2));
wkupcr |= (config & WKUP_PULL_MASK) << (WKUP_PULL_SHIFT + pin_id * 2);
+
SMC(STM32_SVC_PWR, STM32_WRITE, WKUPCR, wkupcr);
return 0;
@@ -164,10 +154,8 @@ static int stm32_pwr_xlate(struct irq_domain *d, struct device_node *ctrlr,
const u32 *intspec, unsigned int intsize,
irq_hw_number_t *out_hwirq, unsigned int *out_type)
{
- struct stm32_pwr_data *priv = d->host_data;
-
if (WARN_ON(intsize < 3)) {
- dev_err(priv->dev, "%s: bad irq config parameters\n", __func__);
+ pr_err("%s: bad irq config parameters\n", __func__);
return -EINVAL;
}
@@ -177,9 +165,23 @@ static int stm32_pwr_xlate(struct irq_domain *d, struct device_node *ctrlr,
return stm32_pwr_irq_set_pull_config(d, intspec[0], intspec[2]);
}
+static int stm32_pwr_alloc(struct irq_domain *d, unsigned int virq,
+ unsigned int nr_irqs, void *data)
+{
+ struct irq_fwspec *fwspec = data;
+ irq_hw_number_t hwirq;
+
+ hwirq = fwspec->param[0];
+ irq_domain_set_info(d, virq, hwirq, &stm32_pwr_irq_chip, d->host_data,
+ handle_edge_irq, NULL, NULL);
+
+ return 0;
+}
+
static const struct irq_domain_ops stm32_pwr_irq_domain_ops = {
- .map = stm32_pwr_irq_map,
+ .alloc = stm32_pwr_alloc,
.xlate = stm32_pwr_xlate,
+ .free = irq_domain_free_irqs_common,
};
/*
@@ -195,9 +197,10 @@ static void stm32_pwr_handle_irq(struct irq_desc *desc)
wkupfr = readl_relaxed(priv->base + WKUPFR);
wkupenr = readl_relaxed(priv->base + MPUWKUPENR);
+
for (i = 0; i < NB_WAKEUPPINS; i++) {
if ((wkupfr & BIT(i)) && (wkupenr & BIT(i))) {
- dev_dbg(priv->dev, "handle wkup irq:%d\n", i);
+ pr_debug("handle wkup irq:%d\n", i);
generic_handle_irq(irq_find_mapping(priv->domain, i));
}
}
@@ -205,27 +208,21 @@ static void stm32_pwr_handle_irq(struct irq_desc *desc)
chained_irq_exit(chip, desc);
}
-static int stm32_pwr_probe(struct platform_device *pdev)
+static int __init stm32_pwr_init(struct device_node *np,
+ struct device_node *parent)
{
- struct device *dev = &pdev->dev;
- struct device_node *np = pdev->dev.of_node;
struct stm32_pwr_data *priv;
-
- struct resource *res;
int ret;
- priv = devm_kzalloc(dev, sizeof(struct stm32_pwr_data), GFP_KERNEL);
+ priv = kzalloc(sizeof(*priv), GFP_KERNEL);
if (!priv)
return -ENOMEM;
- platform_set_drvdata(pdev, priv);
- priv->dev = dev;
-
- res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
- priv->base = devm_ioremap_resource(&pdev->dev, res);
+ priv->base = of_iomap(np, 0);
if (IS_ERR(priv->base)) {
- dev_err(dev, "%s: Unable to map IO memory\n", __func__);
- return PTR_ERR(priv->base);
+ pr_err("%s: Unable to map IO memory\n", __func__);
+ ret = PTR_ERR(priv->base);
+ goto out_free;
}
/* Disable all wake-up pins */
@@ -236,52 +233,38 @@ static int stm32_pwr_probe(struct platform_device *pdev)
priv->domain = irq_domain_add_linear(np, NB_WAKEUPPINS,
&stm32_pwr_irq_domain_ops, priv);
if (!priv->domain) {
- dev_err(dev, "%s: Unable to add irq domain!\n", __func__);
- goto out;
+ pr_err("%s: Unable to add irq domain!\n", __func__);
+ ret = -ENOMEM;
+ goto out_unmap;
}
- ret = platform_get_irq(pdev, 0);
- if (ret < 0) {
- dev_err(dev, "failed to get PWR IRQ\n");
- goto err;
+ priv->irq = irq_of_parse_and_map(np, 0);
+ if (priv->irq < 0) {
+ pr_err("failed to get PWR IRQ\n");
+ ret = priv->irq;
+ goto out_domain;
}
- priv->irq = ret;
irq_set_chained_handler_and_data(priv->irq,
stm32_pwr_handle_irq, priv);
-out:
+ of_node_clear_flag(np, OF_POPULATED);
+
return 0;
-err:
+
+out_domain:
irq_domain_remove(priv->domain);
+out_unmap:
+ iounmap(priv->base);
+out_free:
+ kfree(priv);
return ret;
}
-static int stm32_pwr_remove(struct platform_device *pdev)
+static int __init stm32_pwr_of_init(struct device_node *np,
+ struct device_node *parent)
{
- struct stm32_pwr_data *priv = platform_get_drvdata(pdev);
-
- irq_domain_remove(priv->domain);
- return 0;
+ return stm32_pwr_init(np, parent);
}
-static const struct of_device_id stm32_pwr_match[] = {
- { .compatible = "st,stm32mp1-pwr" },
- {},
-};
-
-static struct platform_driver stm32_pwr_driver = {
- .probe = stm32_pwr_probe,
- .remove = stm32_pwr_remove,
- .driver = {
- .name = "stm32-pwr",
- .owner = THIS_MODULE,
- .of_match_table = stm32_pwr_match,
- },
-};
-
-static int __init stm32_pwr_init(void)
-{
- return platform_driver_register(&stm32_pwr_driver);
-}
-arch_initcall(stm32_pwr_init);
+IRQCHIP_DECLARE(stm32mp1_pwr_irq, "st,stm32mp1-pwr", stm32_pwr_of_init);
diff --git a/drivers/mfd/stpmic1.c b/drivers/mfd/stpmic1.c
index 5bf6328..648315d 100644
--- a/drivers/mfd/stpmic1.c
+++ b/drivers/mfd/stpmic1.c
@@ -268,13 +268,8 @@ static int stpmic1_probe(struct i2c_client *i2c,
return ddata->irq;
}
- ddata->irq_wake = of_irq_get(np, STPMIC1_WAKEUP_IRQ);
- if (ddata->irq_wake > 0) {
+ if (of_property_read_bool(np, "wakeup-source"))
device_init_wakeup(dev, true);
- ret = dev_pm_set_dedicated_wake_irq(dev, ddata->irq_wake);
- if (ret)
- dev_warn(dev, "failed to set up wakeup irq");
- }
if (!of_property_read_u32(np, "st,main-control-register", &reg)) {
ret = regmap_update_bits(ddata->regmap,
@@ -371,8 +366,8 @@ static int stpmic1_suspend(struct device *dev)
struct stpmic1 *pmic_dev = i2c_get_clientdata(i2c);
disable_irq(pmic_dev->irq);
- if ((pmic_dev->irq_wake > 0) && device_may_wakeup(dev))
- enable_irq_wake(pmic_dev->irq_wake);
+ if (device_may_wakeup(dev))
+ enable_irq_wake(pmic_dev->irq);
return 0;
}
@@ -387,9 +382,10 @@ static int stpmic1_resume(struct device *dev)
if (ret)
return ret;
+ if (device_may_wakeup(dev))
+ disable_irq_wake(pmic_dev->irq);
+
enable_irq(pmic_dev->irq);
- if ((pmic_dev->irq_wake > 0) && device_may_wakeup(dev))
- disable_irq_wake(pmic_dev->irq_wake);
return 0;
}
diff --git a/drivers/mfd/syscon.c b/drivers/mfd/syscon.c
index b6d05cd..a0ba4ff 100644
--- a/drivers/mfd/syscon.c
+++ b/drivers/mfd/syscon.c
@@ -12,6 +12,7 @@
* (at your option) any later version.
*/
+#include <linux/clk.h>
#include <linux/err.h>
#include <linux/hwspinlock.h>
#include <linux/io.h>
@@ -45,6 +46,7 @@ static const struct regmap_config syscon_regmap_config = {
static struct syscon *of_syscon_register(struct device_node *np)
{
+ struct clk *clk;
struct syscon *syscon;
struct regmap *regmap;
void __iomem *base;
@@ -119,6 +121,18 @@ static struct syscon *of_syscon_register(struct device_node *np)
goto err_regmap;
}
+ clk = of_clk_get(np, 0);
+ if (IS_ERR(clk)) {
+ ret = PTR_ERR(clk);
+ /* clock is optional */
+ if (ret != -ENOENT)
+ goto err_clk;
+ } else {
+ ret = regmap_mmio_attach_clk(regmap, clk);
+ if (ret)
+ goto err_attach;
+ }
+
syscon->regmap = regmap;
syscon->np = np;
@@ -128,6 +142,11 @@ static struct syscon *of_syscon_register(struct device_node *np)
return syscon;
+err_attach:
+ if (!IS_ERR(clk))
+ clk_put(clk);
+err_clk:
+ regmap_exit(regmap);
err_regmap:
iounmap(base);
err_map:
diff --git a/drivers/mfd/wm8994-core.c b/drivers/mfd/wm8994-core.c
index 22bd652..755863a 100644
--- a/drivers/mfd/wm8994-core.c
+++ b/drivers/mfd/wm8994-core.c
@@ -12,6 +12,7 @@
*
*/
+#include <linux/clk.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/slab.h>
@@ -314,6 +315,20 @@ static int wm8994_set_pdata_from_of(struct wm8994 *wm8994)
if (pdata->ldo[1].enable < 0)
pdata->ldo[1].enable = 0;
+ pdata->mclk1 = devm_clk_get(wm8994->dev, "MCLK1");
+ if (IS_ERR(pdata->mclk1)) {
+ if (PTR_ERR(pdata->mclk1) != -ENOENT)
+ return PTR_ERR(pdata->mclk1);
+ pdata->mclk1 = NULL;
+ }
+
+ pdata->mclk2 = devm_clk_get(wm8994->dev, "MCLK2");
+ if (IS_ERR(pdata->mclk2)) {
+ if (PTR_ERR(pdata->mclk2) != -ENOENT)
+ return PTR_ERR(pdata->mclk2);
+ pdata->mclk2 = NULL;
+ }
+
return 0;
}
#else
diff --git a/include/linux/mfd/stpmic1.h b/include/linux/mfd/stpmic1.h
index 4abe5f1..fa3f99f 100644
--- a/include/linux/mfd/stpmic1.h
+++ b/include/linux/mfd/stpmic1.h
@@ -206,7 +206,6 @@ struct stpmic1 {
struct device *dev;
struct regmap *regmap;
int irq;
- int irq_wake;
struct regmap_irq_chip_data *irq_data;
};
--
2.7.4

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,914 @@
From 7a16fa25c3bd9a0c078b4d9d2ae445b975afaf69 Mon Sep 17 00:00:00 2001
From: Christophe Priouzeau <christophe.priouzeau@st.com>
Date: Mon, 26 Nov 2018 14:42:41 +0100
Subject: [PATCH 24/52] ARM-stm32mp1-r0-rc2-THERMAL
---
.../devicetree/bindings/thermal/stm32-thermal.txt | 61 ++
drivers/thermal/Kconfig | 2 +-
drivers/thermal/Makefile | 2 +-
drivers/thermal/st/Kconfig | 14 +
drivers/thermal/st/Makefile | 1 +
drivers/thermal/st/stm_thermal.c | 760 +++++++++++++++++++++
6 files changed, 838 insertions(+), 2 deletions(-)
create mode 100644 Documentation/devicetree/bindings/thermal/stm32-thermal.txt
create mode 100644 drivers/thermal/st/stm_thermal.c
diff --git a/Documentation/devicetree/bindings/thermal/stm32-thermal.txt b/Documentation/devicetree/bindings/thermal/stm32-thermal.txt
new file mode 100644
index 0000000..8c0d5a4
--- /dev/null
+++ b/Documentation/devicetree/bindings/thermal/stm32-thermal.txt
@@ -0,0 +1,61 @@
+Binding for Thermal Sensor for STMicroelectronics STM32 series of SoCs.
+
+On STM32 SoCs, the Digital Temperature Sensor (DTS) is in charge of managing an
+analog block which delivers a frequency depending on the internal SoC's
+temperature. By using a reference frequency, DTS is able to provide a sample
+number which can be translated into a temperature by the user.
+
+DTS provides interrupt notification mechanism by threshold. This mechanism
+offers two temperature trip points: passive and critical. The first is intended
+for passive cooling notification while the second is used for over-temperature
+reset.
+
+Required parameters:
+-------------------
+
+compatible: Should be "st,stm32-thermal"
+reg: This should be the physical base address and length of the
+ sensor's registers.
+clocks: Phandle of the clock used by the thermal sensor.
+ See: Documentation/devicetree/bindings/clock/clock-bindings.txt
+clock-names: Should be "pclk" for register access clock and reference clock.
+ See: Documentation/devicetree/bindings/resource-names.txt
+#thermal-sensor-cells: Should be 0. See ./thermal.txt for a description.
+interrupts: Standard way to define interrupt number.
+
+Example:
+
+ thermal-zones {
+ cpu_thermal: cpu-thermal {
+ polling-delay-passive = <0>;
+ polling-delay = <0>;
+
+ thermal-sensors = <&thermal>;
+
+ trips {
+ cpu_alert1: cpu-alert1 {
+ temperature = <85000>;
+ hysteresis = <0>;
+ type = "passive";
+ };
+
+ cpu-crit: cpu-crit {
+ temperature = <120000>;
+ hysteresis = <0>;
+ type = "critical";
+ };
+ };
+
+ cooling-maps {
+ };
+ };
+ };
+
+ thermal: thermal@50028000 {
+ compatible = "st,stm32-thermal";
+ reg = <0x50028000 0x100>;
+ clocks = <&rcc TMPSENS>;
+ clock-names = "pclk";
+ #thermal-sensor-cells = <0>;
+ interrupts = <GIC_SPI 147 IRQ_TYPE_LEVEL_HIGH>;
+ };
diff --git a/drivers/thermal/Kconfig b/drivers/thermal/Kconfig
index 0e69edc..5422523 100644
--- a/drivers/thermal/Kconfig
+++ b/drivers/thermal/Kconfig
@@ -432,7 +432,7 @@ source "drivers/thermal/samsung/Kconfig"
endmenu
menu "STMicroelectronics thermal drivers"
-depends on ARCH_STI && OF
+depends on (ARCH_STI || ARCH_STM32) && OF
source "drivers/thermal/st/Kconfig"
endmenu
diff --git a/drivers/thermal/Makefile b/drivers/thermal/Makefile
index 610344e..82bb50d 100644
--- a/drivers/thermal/Makefile
+++ b/drivers/thermal/Makefile
@@ -53,7 +53,7 @@ obj-$(CONFIG_TI_SOC_THERMAL) += ti-soc-thermal/
obj-$(CONFIG_INT340X_THERMAL) += int340x_thermal/
obj-$(CONFIG_INTEL_BXT_PMIC_THERMAL) += intel_bxt_pmic_thermal.o
obj-$(CONFIG_INTEL_PCH_THERMAL) += intel_pch_thermal.o
-obj-$(CONFIG_ST_THERMAL) += st/
+obj-y += st/
obj-$(CONFIG_QCOM_TSENS) += qcom/
obj-y += tegra/
obj-$(CONFIG_HISI_THERMAL) += hisi_thermal.o
diff --git a/drivers/thermal/st/Kconfig b/drivers/thermal/st/Kconfig
index 490fdbe..b80f9a9 100644
--- a/drivers/thermal/st/Kconfig
+++ b/drivers/thermal/st/Kconfig
@@ -1,3 +1,7 @@
+#
+# STMicroelectronics thermal drivers configuration
+#
+
config ST_THERMAL
tristate "Thermal sensors on STMicroelectronics STi series of SoCs"
help
@@ -10,3 +14,13 @@ config ST_THERMAL_SYSCFG
config ST_THERMAL_MEMMAP
select ST_THERMAL
tristate "STi series memory mapped access based thermal sensors"
+
+config STM32_THERMAL
+ tristate "Thermal framework support on STMicroelectronics STM32 series of SoCs"
+ depends on MACH_STM32MP157
+ default y
+ help
+ Support for thermal framework on STMicroelectronics STM32 series of
+ SoCs. This thermal driver allows to access to general thermal framework
+ functionalities and to acces to SoC sensor functionalities. This
+ configuration is fully dependent of MACH_STM32MP157.
diff --git a/drivers/thermal/st/Makefile b/drivers/thermal/st/Makefile
index b388789..b2b9e9b 100644
--- a/drivers/thermal/st/Makefile
+++ b/drivers/thermal/st/Makefile
@@ -1,3 +1,4 @@
obj-$(CONFIG_ST_THERMAL) := st_thermal.o
obj-$(CONFIG_ST_THERMAL_SYSCFG) += st_thermal_syscfg.o
obj-$(CONFIG_ST_THERMAL_MEMMAP) += st_thermal_memmap.o
+obj-$(CONFIG_STM32_THERMAL) := stm_thermal.o
\ No newline at end of file
diff --git a/drivers/thermal/st/stm_thermal.c b/drivers/thermal/st/stm_thermal.c
new file mode 100644
index 0000000..bbd73c5
--- /dev/null
+++ b/drivers/thermal/st/stm_thermal.c
@@ -0,0 +1,760 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (C) STMicroelectronics 2018 - All Rights Reserved
+ * Author: David Hernandez Sanchez <david.hernandezsanchez@st.com> for
+ * STMicroelectronics.
+ */
+
+#include <linux/clk.h>
+#include <linux/clk-provider.h>
+#include <linux/delay.h>
+#include <linux/err.h>
+#include <linux/interrupt.h>
+#include <linux/io.h>
+#include <linux/iopoll.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/of_address.h>
+#include <linux/of_device.h>
+#include <linux/platform_device.h>
+#include <linux/thermal.h>
+
+#include "../thermal_core.h"
+#include "../thermal_hwmon.h"
+
+/* DTS register offsets */
+#define DTS_CFGR1_OFFSET 0x0
+#define DTS_T0VALR1_OFFSET 0x8
+#define DTS_RAMPVALR_OFFSET 0X10
+#define DTS_ITR1_OFFSET 0x14
+#define DTS_DR_OFFSET 0x1C
+#define DTS_SR_OFFSET 0x20
+#define DTS_ITENR_OFFSET 0x24
+#define DTS_CIFR_OFFSET 0x28
+
+/* DTS_CFGR1 register mask definitions */
+#define HSREF_CLK_DIV_MASK GENMASK(30, 24)
+#define TS1_SMP_TIME_MASK GENMASK(19, 16)
+#define TS1_INTRIG_SEL_MASK GENMASK(11, 8)
+
+/* DTS_T0VALR1 register mask definitions */
+#define TS1_T0_MASK GENMASK(17, 16)
+#define TS1_FMT0_MASK GENMASK(15, 0)
+
+/* DTS_RAMPVALR register mask definitions */
+#define TS1_RAMP_COEFF_MASK GENMASK(15, 0)
+
+/* DTS_ITR1 register mask definitions */
+#define TS1_HITTHD_MASK GENMASK(31, 16)
+#define TS1_LITTHD_MASK GENMASK(15, 0)
+
+/* DTS_DR register mask definitions */
+#define TS1_MFREQ_MASK GENMASK(15, 0)
+
+/* Less significant bit position definitions */
+#define TS1_T0_POS 16
+#define TS1_SMP_TIME_POS 16
+#define TS1_HITTHD_POS 16
+#define HSREF_CLK_DIV_POS 24
+
+/* DTS_CFGR1 bit definitions */
+#define TS1_EN BIT(0)
+#define TS1_START BIT(4)
+#define REFCLK_SEL BIT(20)
+#define REFCLK_LSE REFCLK_SEL
+#define Q_MEAS_OPT BIT(21)
+#define CALIBRATION_CONTROL Q_MEAS_OPT
+
+/* DTS_SR bit definitions */
+#define TS_RDY BIT(15)
+/* Bit definitions below are common for DTS_SR, DTS_ITENR and DTS_CIFR */
+#define HIGH_THRESHOLD BIT(2)
+#define LOW_THRESHOLD BIT(1)
+
+/* Constants */
+#define ADJUST 100
+#define ONE_MHZ 1000000
+#define POLL_TIMEOUT 5000
+#define STARTUP_TIME 40
+#define TS1_T0_VAL0 30
+#define TS1_T0_VAL1 130
+#define NO_HW_TRIG 0
+
+/* The Thermal Framework expects millidegrees */
+#define mcelsius(temp) ((temp) * 1000)
+
+/* The Sensor expects oC degrees */
+#define celsius(temp) ((temp) / 1000)
+
+struct stm_thermal_sensor {
+ struct device *dev;
+ struct thermal_zone_device *th_dev;
+ enum thermal_device_mode mode;
+ struct clk *clk;
+ int high_temp;
+ int low_temp;
+ int temp_critical;
+ int temp_passive;
+ unsigned int low_temp_enabled;
+ int num_trips;
+ int irq;
+ unsigned int irq_enabled;
+ void __iomem *base;
+ int t0, fmt0, ramp_coeff;
+};
+
+static irqreturn_t stm_thermal_alarm_irq(int irq, void *sdata)
+{
+ struct stm_thermal_sensor *sensor = sdata;
+
+ disable_irq_nosync(irq);
+ sensor->irq_enabled = false;
+
+ return IRQ_WAKE_THREAD;
+}
+
+static irqreturn_t stm_thermal_alarm_irq_thread(int irq, void *sdata)
+{
+ u32 value;
+ struct stm_thermal_sensor *sensor = sdata;
+
+ /* read IT reason in SR and clear flags */
+ value = readl_relaxed(sensor->base + DTS_SR_OFFSET);
+
+ if ((value & LOW_THRESHOLD) == LOW_THRESHOLD)
+ writel_relaxed(LOW_THRESHOLD, sensor->base + DTS_CIFR_OFFSET);
+
+ if ((value & HIGH_THRESHOLD) == HIGH_THRESHOLD)
+ writel_relaxed(HIGH_THRESHOLD, sensor->base + DTS_CIFR_OFFSET);
+
+ thermal_zone_device_update(sensor->th_dev, THERMAL_EVENT_UNSPECIFIED);
+
+ return IRQ_HANDLED;
+}
+
+static int stm_sensor_power_on(struct stm_thermal_sensor *sensor)
+{
+ int ret;
+ u32 value;
+
+ /* Enable sensor */
+ value = readl_relaxed(sensor->base + DTS_CFGR1_OFFSET);
+ value |= TS1_EN;
+ writel_relaxed(value, sensor->base + DTS_CFGR1_OFFSET);
+
+ /*
+ * The DTS block can be enabled by setting TSx_EN bit in
+ * DTS_CFGRx register. It requires a startup time of
+ * 40μs. Use 5 ms as arbitrary timeout.
+ */
+ ret = readl_poll_timeout(sensor->base + DTS_SR_OFFSET,
+ value, (value & TS_RDY),
+ STARTUP_TIME, POLL_TIMEOUT);
+ if (ret)
+ return ret;
+
+ /* Start continuous measuring */
+ value = readl_relaxed(sensor->base +
+ DTS_CFGR1_OFFSET);
+ value |= TS1_START;
+ writel_relaxed(value, sensor->base +
+ DTS_CFGR1_OFFSET);
+
+ return 0;
+}
+
+static int stm_sensor_power_off(struct stm_thermal_sensor *sensor)
+{
+ u32 value;
+
+ /* Stop measuring */
+ value = readl_relaxed(sensor->base + DTS_CFGR1_OFFSET);
+ value &= ~TS1_START;
+ writel_relaxed(value, sensor->base + DTS_CFGR1_OFFSET);
+
+ /* Ensure stop is taken into account */
+ usleep_range(STARTUP_TIME, POLL_TIMEOUT);
+
+ /* Disable sensor */
+ value = readl_relaxed(sensor->base + DTS_CFGR1_OFFSET);
+ value &= ~TS1_EN;
+ writel_relaxed(value, sensor->base + DTS_CFGR1_OFFSET);
+
+ /* Ensure disable is taken into account */
+ return readl_poll_timeout(sensor->base + DTS_SR_OFFSET, value,
+ !(value & TS_RDY),
+ STARTUP_TIME, POLL_TIMEOUT);
+}
+
+static int stm_thermal_calibration(struct stm_thermal_sensor *sensor)
+{
+ u32 value, clk_freq;
+ u32 prescaler;
+
+ /* Figure out prescaler value for PCLK during calibration */
+ clk_freq = clk_get_rate(sensor->clk);
+ if (!clk_freq)
+ return -EINVAL;
+
+ prescaler = 0;
+ clk_freq /= ONE_MHZ;
+ if (clk_freq) {
+ while (prescaler <= clk_freq)
+ prescaler++;
+ }
+
+ value = readl_relaxed(sensor->base + DTS_CFGR1_OFFSET);
+
+ /* Clear prescaler */
+ value &= ~HSREF_CLK_DIV_MASK;
+
+ /* Set prescaler. pclk_freq/prescaler < 1MHz */
+ value |= (prescaler << HSREF_CLK_DIV_POS);
+
+ /* Select PCLK as reference clock */
+ value &= ~REFCLK_SEL;
+
+ /* Set maximal sampling time for better precision */
+ value |= TS1_SMP_TIME_MASK;
+
+ /* Measure with calibration */
+ value &= ~CALIBRATION_CONTROL;
+
+ /* select trigger */
+ value &= ~TS1_INTRIG_SEL_MASK;
+ value |= NO_HW_TRIG;
+
+ writel_relaxed(value, sensor->base + DTS_CFGR1_OFFSET);
+
+ return 0;
+}
+
+/* Fill in DTS structure with factory sensor values */
+static int stm_thermal_read_factory_settings(struct stm_thermal_sensor *sensor)
+{
+ /* Retrieve engineering calibration temperature */
+ sensor->t0 = readl_relaxed(sensor->base + DTS_T0VALR1_OFFSET) &
+ TS1_T0_MASK;
+ if (!sensor->t0)
+ sensor->t0 = TS1_T0_VAL0;
+ else
+ sensor->t0 = TS1_T0_VAL1;
+
+ /* Retrieve fmt0 and put it on Hz */
+ sensor->fmt0 = ADJUST * (readl_relaxed(sensor->base +
+ DTS_T0VALR1_OFFSET) & TS1_FMT0_MASK);
+
+ /* Retrieve ramp coefficient */
+ sensor->ramp_coeff = readl_relaxed(sensor->base + DTS_RAMPVALR_OFFSET) &
+ TS1_RAMP_COEFF_MASK;
+
+ if (!sensor->fmt0 || !sensor->ramp_coeff) {
+ dev_err(sensor->dev, "%s: wrong setting\n", __func__);
+ return -EINVAL;
+ }
+
+ dev_dbg(sensor->dev, "%s: T0 = %doC, FMT0 = %dHz, RAMP_COEFF = %dHz/oC",
+ __func__, sensor->t0, sensor->fmt0, sensor->ramp_coeff);
+
+ return 0;
+}
+
+static int stm_thermal_calculate_threshold(struct stm_thermal_sensor *sensor,
+ int temp, u32 *th)
+{
+ int freqM;
+ u32 sampling_time;
+
+ /* Retrieve the number of periods to sample */
+ sampling_time = (readl_relaxed(sensor->base + DTS_CFGR1_OFFSET) &
+ TS1_SMP_TIME_MASK) >> TS1_SMP_TIME_POS;
+
+ /* Figure out the CLK_PTAT frequency for a given temperature */
+ freqM = ((temp - sensor->t0) * sensor->ramp_coeff)
+ + sensor->fmt0;
+
+ dev_dbg(sensor->dev, "%s: freqM for threshold = %d Hz",
+ __func__, freqM);
+
+ /* Figure out the threshold sample number */
+ *th = clk_get_rate(sensor->clk);
+ if (!*th)
+ return -EINVAL;
+
+ *th = *th / freqM;
+
+ *th *= sampling_time;
+
+ return 0;
+}
+
+static int stm_thermal_set_threshold(struct stm_thermal_sensor *sensor)
+{
+ u32 value, th;
+ int ret;
+
+ value = readl_relaxed(sensor->base + DTS_ITR1_OFFSET);
+
+ /* Erase threshold content */
+ value &= ~(TS1_LITTHD_MASK | TS1_HITTHD_MASK);
+
+ /* Retrieve the sample threshold number th for a given temperature */
+ ret = stm_thermal_calculate_threshold(sensor, sensor->high_temp, &th);
+ if (ret)
+ return ret;
+
+ value |= th & TS1_LITTHD_MASK;
+
+ if (sensor->low_temp_enabled) {
+ /* Retrieve the sample threshold */
+ ret = stm_thermal_calculate_threshold(sensor, sensor->low_temp,
+ &th);
+ if (ret)
+ return ret;
+
+ value |= (TS1_HITTHD_MASK & (th << TS1_HITTHD_POS));
+ }
+
+ /* Write value on the Low interrupt threshold */
+ writel_relaxed(value, sensor->base + DTS_ITR1_OFFSET);
+
+ return 0;
+}
+
+/* Disable temperature interrupt */
+static int stm_disable_irq(struct stm_thermal_sensor *sensor)
+{
+ u32 value;
+
+ /* Disable IT generation for low and high thresholds */
+ value = readl_relaxed(sensor->base + DTS_ITENR_OFFSET);
+ writel_relaxed(value & ~(LOW_THRESHOLD | HIGH_THRESHOLD),
+ sensor->base + DTS_ITENR_OFFSET);
+
+ dev_dbg(sensor->dev, "%s: IT disabled on sensor side", __func__);
+
+ return 0;
+}
+
+/* Enable temperature interrupt */
+static int stm_enable_irq(struct stm_thermal_sensor *sensor)
+{
+ u32 value;
+
+ /*
+ * Code below enables High temperature threshold using a low threshold
+ * sampling value
+ */
+
+ /* Make sure LOW_THRESHOLD IT is clear before enabling */
+ writel_relaxed(LOW_THRESHOLD, sensor->base + DTS_CIFR_OFFSET);
+
+ /* Enable IT generation for low threshold */
+ value = readl_relaxed(sensor->base + DTS_ITENR_OFFSET);
+ value |= LOW_THRESHOLD;
+
+ /* Enable the low temperature threshold if needed */
+ if (sensor->low_temp_enabled) {
+ /* Make sure HIGH_THRESHOLD IT is clear before enabling */
+ writel_relaxed(HIGH_THRESHOLD, sensor->base + DTS_CIFR_OFFSET);
+
+ /* Enable IT generation for high threshold */
+ value |= HIGH_THRESHOLD;
+ }
+
+ /* Enable thresholds */
+ writel_relaxed(value, sensor->base + DTS_ITENR_OFFSET);
+
+ dev_dbg(sensor->dev, "%s: IT enabled on sensor side", __func__);
+
+ return 0;
+}
+
+static int stm_thermal_update_threshold(struct stm_thermal_sensor *sensor)
+{
+ int ret;
+
+ sensor->mode = THERMAL_DEVICE_DISABLED;
+
+ ret = stm_sensor_power_off(sensor);
+ if (ret)
+ return ret;
+
+ ret = stm_disable_irq(sensor);
+ if (ret)
+ return ret;
+
+ ret = stm_thermal_set_threshold(sensor);
+ if (ret)
+ return ret;
+
+ ret = stm_enable_irq(sensor);
+ if (ret)
+ return ret;
+
+ ret = stm_sensor_power_on(sensor);
+ if (ret)
+ return ret;
+
+ sensor->mode = THERMAL_DEVICE_ENABLED;
+
+ return 0;
+}
+
+/* Callback to get temperature from HW */
+static int stm_thermal_get_temp(void *data, int *temp)
+{
+ struct stm_thermal_sensor *sensor = data;
+ u32 sampling_time;
+ int freqM, ret;
+
+ if (sensor->mode != THERMAL_DEVICE_ENABLED)
+ return -EAGAIN;
+
+ /* Retrieve the number of samples */
+ ret = readl_poll_timeout(sensor->base + DTS_DR_OFFSET, freqM,
+ (freqM & TS1_MFREQ_MASK), STARTUP_TIME,
+ POLL_TIMEOUT);
+
+ if (ret)
+ return ret;
+
+ if (!freqM)
+ return -ENODATA;
+
+ /* Retrieve the number of periods sampled */
+ sampling_time = (readl_relaxed(sensor->base + DTS_CFGR1_OFFSET) &
+ TS1_SMP_TIME_MASK) >> TS1_SMP_TIME_POS;
+
+ /* Figure out the number of samples per period */
+ freqM /= sampling_time;
+
+ /* Figure out the CLK_PTAT frequency */
+ freqM = clk_get_rate(sensor->clk) / freqM;
+ if (!freqM)
+ return -EINVAL;
+
+ dev_dbg(sensor->dev, "%s: freqM=%d\n", __func__, freqM);
+
+ /* Figure out the temperature in mili celsius */
+ *temp = mcelsius(sensor->t0 + ((freqM - sensor->fmt0) /
+ sensor->ramp_coeff));
+
+ dev_dbg(sensor->dev, "%s: temperature = %d millicelsius",
+ __func__, *temp);
+
+ /* Update thresholds */
+ if (sensor->num_trips > 1) {
+ /* Update alarm threshold value to next higher trip point */
+ if (sensor->high_temp == sensor->temp_passive &&
+ celsius(*temp) >= sensor->temp_passive) {
+ sensor->high_temp = sensor->temp_critical;
+ sensor->low_temp = sensor->temp_passive;
+ sensor->low_temp_enabled = true;
+ ret = stm_thermal_update_threshold(sensor);
+ if (ret)
+ return ret;
+ }
+
+ if (sensor->high_temp == sensor->temp_critical &&
+ celsius(*temp) < sensor->temp_passive) {
+ sensor->high_temp = sensor->temp_passive;
+ sensor->low_temp_enabled = false;
+ ret = stm_thermal_update_threshold(sensor);
+ if (ret)
+ return ret;
+ }
+
+ /*
+ * Re-enable alarm IRQ if temperature below critical
+ * temperature
+ */
+ if (!sensor->irq_enabled &&
+ (celsius(*temp) < sensor->temp_critical)) {
+ sensor->irq_enabled = true;
+ enable_irq(sensor->irq);
+ }
+ }
+
+ return 0;
+}
+
+/* Registers DTS irq to be visible by GIC */
+static int stm_register_irq(struct stm_thermal_sensor *sensor)
+{
+ struct device *dev = sensor->dev;
+ struct platform_device *pdev = to_platform_device(dev);
+ int ret;
+
+ sensor->irq = platform_get_irq(pdev, 0);
+ if (sensor->irq < 0) {
+ dev_err(dev, "%s: Unable to find IRQ\n", __func__);
+ return sensor->irq;
+ }
+
+ ret = devm_request_threaded_irq(dev, sensor->irq,
+ stm_thermal_alarm_irq,
+ stm_thermal_alarm_irq_thread,
+ IRQF_ONESHOT,
+ dev->driver->name, sensor);
+ if (ret) {
+ dev_err(dev, "%s: Failed to register IRQ %d\n", __func__,
+ sensor->irq);
+ return ret;
+ }
+
+ sensor->irq_enabled = true;
+
+ dev_dbg(dev, "%s: thermal IRQ registered", __func__);
+
+ return 0;
+}
+
+static int stm_thermal_sensor_off(struct stm_thermal_sensor *sensor)
+{
+ int ret;
+
+ ret = stm_sensor_power_off(sensor);
+ if (ret)
+ return ret;
+
+ clk_disable_unprepare(sensor->clk);
+
+ return 0;
+}
+
+static int stm_thermal_prepare(struct stm_thermal_sensor *sensor)
+{
+ int ret;
+ struct device *dev = sensor->dev;
+
+ ret = clk_prepare_enable(sensor->clk);
+ if (ret)
+ return ret;
+
+ ret = stm_thermal_read_factory_settings(sensor);
+ if (ret)
+ goto thermal_unprepare;
+
+ ret = stm_thermal_calibration(sensor);
+ if (ret)
+ goto thermal_unprepare;
+
+ /* Set threshold(s) for IRQ */
+ ret = stm_thermal_set_threshold(sensor);
+ if (ret)
+ goto thermal_unprepare;
+
+ ret = stm_enable_irq(sensor);
+ if (ret)
+ goto thermal_unprepare;
+
+ ret = stm_sensor_power_on(sensor);
+ if (ret) {
+ dev_err(dev, "%s: failed to power on sensor\n", __func__);
+ goto irq_disable;
+ }
+
+ return 0;
+
+irq_disable:
+ stm_disable_irq(sensor);
+
+thermal_unprepare:
+ clk_disable_unprepare(sensor->clk);
+
+ return ret;
+}
+
+#ifdef CONFIG_PM_SLEEP
+static int stm_thermal_suspend(struct device *dev)
+{
+ int ret;
+ struct platform_device *pdev = to_platform_device(dev);
+ struct stm_thermal_sensor *sensor = platform_get_drvdata(pdev);
+
+ ret = stm_thermal_sensor_off(sensor);
+ if (ret)
+ return ret;
+
+ sensor->mode = THERMAL_DEVICE_DISABLED;
+
+ return 0;
+}
+
+static int stm_thermal_resume(struct device *dev)
+{
+ int ret;
+ struct platform_device *pdev = to_platform_device(dev);
+ struct stm_thermal_sensor *sensor = platform_get_drvdata(pdev);
+
+ ret = stm_thermal_prepare(sensor);
+ if (ret)
+ return ret;
+
+ sensor->mode = THERMAL_DEVICE_ENABLED;
+
+ return 0;
+}
+#endif /* CONFIG_PM_SLEEP */
+
+SIMPLE_DEV_PM_OPS(stm_thermal_pm_ops, stm_thermal_suspend, stm_thermal_resume);
+
+static const struct thermal_zone_of_device_ops stm_tz_ops = {
+ .get_temp = stm_thermal_get_temp,
+};
+
+static const struct of_device_id stm_thermal_of_match[] = {
+ { .compatible = "st,stm32-thermal"},
+ { /* sentinel */ }
+};
+MODULE_DEVICE_TABLE(of, stm_thermal_of_match);
+
+static int stm_thermal_probe(struct platform_device *pdev)
+{
+ struct stm_thermal_sensor *sensor;
+ struct resource *res;
+ const struct thermal_trip *trip;
+ void __iomem *base;
+ int ret, i;
+
+ if (!pdev->dev.of_node) {
+ dev_err(&pdev->dev, "%s: device tree node not found\n",
+ __func__);
+ return -EINVAL;
+ }
+
+ sensor = devm_kzalloc(&pdev->dev, sizeof(*sensor), GFP_KERNEL);
+ if (!sensor)
+ return -ENOMEM;
+
+ platform_set_drvdata(pdev, sensor);
+
+ sensor->dev = &pdev->dev;
+
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ base = devm_ioremap_resource(&pdev->dev, res);
+ if (IS_ERR(base))
+ return PTR_ERR(base);
+
+ /* Populate sensor */
+ sensor->base = base;
+
+ sensor->clk = devm_clk_get(&pdev->dev, "pclk");
+ if (IS_ERR(sensor->clk)) {
+ dev_err(&pdev->dev, "%s: failed to fetch PCLK clock\n",
+ __func__);
+ return PTR_ERR(sensor->clk);
+ }
+
+ /* Register IRQ into GIC */
+ ret = stm_register_irq(sensor);
+ if (ret)
+ return ret;
+
+ sensor->th_dev = devm_thermal_zone_of_sensor_register(&pdev->dev, 0,
+ sensor,
+ &stm_tz_ops);
+
+ if (IS_ERR(sensor->th_dev)) {
+ dev_err(&pdev->dev, "%s: thermal zone sensor registering KO\n",
+ __func__);
+ ret = PTR_ERR(sensor->th_dev);
+ return ret;
+ }
+
+ if (!sensor->th_dev->ops->get_crit_temp) {
+ /* Critical point must be provided */
+ ret = -EINVAL;
+ goto err_tz;
+ }
+
+ ret = sensor->th_dev->ops->get_crit_temp(sensor->th_dev,
+ &sensor->temp_critical);
+ if (ret) {
+ dev_err(&pdev->dev,
+ "Not able to read critical_temp: %d\n", ret);
+ goto err_tz;
+ }
+
+ sensor->temp_critical = celsius(sensor->temp_critical);
+
+ /* Set thresholds for IRQ */
+ sensor->high_temp = sensor->temp_critical;
+
+ trip = of_thermal_get_trip_points(sensor->th_dev);
+ sensor->num_trips = of_thermal_get_ntrips(sensor->th_dev);
+
+ /* Find out passive temperature if it exists */
+ for (i = (sensor->num_trips - 1); i >= 0; i--) {
+ if (trip[i].type == THERMAL_TRIP_PASSIVE) {
+ sensor->temp_passive = celsius(trip[i].temperature);
+ /* Update high temperature threshold */
+ sensor->high_temp = sensor->temp_passive;
+ }
+ }
+
+ /*
+ * Ensure low_temp_enabled flag is disabled.
+ * By disabling low_temp_enabled, low threshold IT will not be
+ * configured neither enabled because it is not needed as high
+ * threshold is set on the lowest temperature trip point after
+ * probe.
+ */
+ sensor->low_temp_enabled = false;
+
+ /* Configure and enable HW sensor */
+ ret = stm_thermal_prepare(sensor);
+ if (ret) {
+ dev_err(&pdev->dev,
+ "Not able to enable sensor: %d\n", ret);
+ goto err_tz;
+ }
+
+ /*
+ * Thermal_zone doesn't enable hwmon as default,
+ * enable it here
+ */
+ sensor->th_dev->tzp->no_hwmon = false;
+ ret = thermal_add_hwmon_sysfs(sensor->th_dev);
+ if (ret)
+ goto err_tz;
+
+ sensor->mode = THERMAL_DEVICE_ENABLED;
+
+ dev_info(&pdev->dev, "%s: Driver initialized successfully\n",
+ __func__);
+
+ return 0;
+
+err_tz:
+ thermal_zone_of_sensor_unregister(&pdev->dev, sensor->th_dev);
+ return ret;
+}
+
+static int stm_thermal_remove(struct platform_device *pdev)
+{
+ struct stm_thermal_sensor *sensor = platform_get_drvdata(pdev);
+
+ stm_thermal_sensor_off(sensor);
+ thermal_remove_hwmon_sysfs(sensor->th_dev);
+ thermal_zone_of_sensor_unregister(&pdev->dev, sensor->th_dev);
+
+ return 0;
+}
+
+static struct platform_driver stm_thermal_driver = {
+ .driver = {
+ .name = "stm_thermal",
+ .pm = &stm_thermal_pm_ops,
+ .of_match_table = stm_thermal_of_match,
+ },
+ .probe = stm_thermal_probe,
+ .remove = stm_thermal_remove,
+};
+module_platform_driver(stm_thermal_driver);
+
+MODULE_DESCRIPTION("STMicroelectronics STM32 Thermal Sensor Driver");
+MODULE_AUTHOR("David Hernandez Sanchez <david.hernandezsanchez@st.com>");
+MODULE_LICENSE("GPL v2");
+MODULE_ALIAS("platform:stm_thermal");
--
2.7.4

View File

@ -0,0 +1,372 @@
From 222782ff647dfeb33bb442031792a893372fad82 Mon Sep 17 00:00:00 2001
From: Christophe Priouzeau <christophe.priouzeau@st.com>
Date: Mon, 26 Nov 2018 14:43:58 +0100
Subject: [PATCH 25/52] ARM-stm32mp1-r0-rc2-REMOTEPROC
---
.../devicetree/bindings/remoteproc/rproc-srm.txt | 14 ++-
.../devicetree/bindings/remoteproc/stm32-rproc.txt | 15 ++-
drivers/nvmem/stm32-romem.c | 44 +++++----
drivers/remoteproc/rproc_srm_core.h | 14 +--
drivers/remoteproc/rproc_srm_dev.c | 103 +--------------------
drivers/remoteproc/stm32_rproc.c | 2 +-
6 files changed, 42 insertions(+), 150 deletions(-)
diff --git a/Documentation/devicetree/bindings/remoteproc/rproc-srm.txt b/Documentation/devicetree/bindings/remoteproc/rproc-srm.txt
index dce10c0..19a5255 100644
--- a/Documentation/devicetree/bindings/remoteproc/rproc-srm.txt
+++ b/Documentation/devicetree/bindings/remoteproc/rproc-srm.txt
@@ -23,12 +23,16 @@ Optional properties:
- clocks: clocks required by the coprocessor
- clock-names: see clock-bindings.txt
- pinctrl-x: pins configurations required by the coprocessor
-- pinctrl-names: see pinctrl-bindings.txt.
- "rproc_default" is a special pin configuration which is applied except
- if the 'early-booted' property is set.
- In a general way, it is recommended to use names prefixed with "rproc_".
+ The SRM reserves the pins for the coprocessor, which prevents the local
+ processor to use them.
+- pinctrl-names: all names must be prefixed with "rproc_" (ex: "rproc_default").
+ This rule must be strictly followed in order to prevent the SRM to
+ (over)write a pin configuration which is done by the coprocessor.
- x-supply: power supplies required by the coprocessor
-- interrupts: see interrupts.txt
+- interrupts: external interrupts configurations required by the coprocessor.
+ This is optional since the configuration is done by the coprocessor.
+ When defined, the SRM (over)writes the configuration which allows the
+ interrupt controller to check for configuration conflicts.
- interrupt-parent: see interrupts.txt
- interrupt-names: see interrupts.txt
diff --git a/Documentation/devicetree/bindings/remoteproc/stm32-rproc.txt b/Documentation/devicetree/bindings/remoteproc/stm32-rproc.txt
index ee00f1c..7df6a26 100644
--- a/Documentation/devicetree/bindings/remoteproc/stm32-rproc.txt
+++ b/Documentation/devicetree/bindings/remoteproc/stm32-rproc.txt
@@ -33,18 +33,15 @@ Optional properties:
- from local to remote = send message
- from remote to local = send message ack
- a channel (b) working the opposite direction of channel (a)
- - a channel (c) used for two different purposes:
- - used by the remote proc to signal when it has completed
- its critical initalisation.
- Mono-directional channel: from remote to local
- - used by the local proc to notify the remote proc that it
- is about to be shut down.
- Mono-directional channel: from local to remote, where ACK
- from the remote means that it is ready for shutdown
+ - a channel (c) used by the local proc to notify the remote proc
+ that it is about to be shut down.
+ Mono-directional channel:
+ - from local to remote, where ACK from the remote means
+ that it is ready for shutdown
- mbox-names: This property is required if the mboxes property is used.
- must be "vq0" for channel (a)
- must be "vq1" for channel (b)
- - must be "init_shdn" for channel (c)
+ - must be "shutdown" for channel (c)
- memory-region: phandle to the reserved memory node to be associated with the
remoteproc device.
- st,syscfg-pdds: Reference to the system configuration controlling the remote
diff --git a/drivers/nvmem/stm32-romem.c b/drivers/nvmem/stm32-romem.c
index 198872f..34b388c 100644
--- a/drivers/nvmem/stm32-romem.c
+++ b/drivers/nvmem/stm32-romem.c
@@ -19,6 +19,12 @@
#define STM32_SMC_WRITE_SHADOW 0x03
#define STM32_SMC_READ_OTP 0x04
+/* shadow registers offest */
+#define STM32MP15_BSEC_DATA0 0x200
+
+/* 32 (x 32-bits) lower shadow registers */
+#define STM32MP15_BSEC_NUM_LOWER 32
+
struct stm32_romem_cfg {
int size;
};
@@ -77,13 +83,21 @@ static int stm32_bsec_read(void *context, unsigned int offset, void *buf,
return -EINVAL;
for (i = roffset; (i < roffset + rbytes); i += 4) {
- ret = stm32_bsec_smc(STM32_SMC_READ_OTP, i >> 2, 0, &val);
- if (ret) {
- dev_err(priv->dev, "Failed to read data%d (%d)\n",
- i >> 2, ret);
- return ret;
+ u32 otp = i >> 2;
+
+ if (otp < STM32MP15_BSEC_NUM_LOWER) {
+ /* read lower data from shadow registers */
+ val = readl_relaxed(
+ priv->base + STM32MP15_BSEC_DATA0 + i);
+ } else {
+ ret = stm32_bsec_smc(STM32_SMC_READ_SHADOW, otp, 0,
+ &val);
+ if (ret) {
+ dev_err(priv->dev, "Can't read data%d (%d)\n",
+ otp, ret);
+ return ret;
+ }
}
-
/* skip first bytes in case of unaligned read */
if (skip_bytes)
size = min(bytes, (size_t)(4 - skip_bytes));
@@ -127,7 +141,6 @@ static int stm32_romem_probe(struct platform_device *pdev)
const struct stm32_romem_cfg *cfg;
struct device *dev = &pdev->dev;
struct stm32_romem_priv *priv;
- struct nvmem_device *nvmem;
struct resource *res;
priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL);
@@ -154,26 +167,12 @@ static int stm32_romem_probe(struct platform_device *pdev)
priv->cfg.size = resource_size(res);
priv->cfg.reg_read = stm32_romem_read;
} else {
- priv->cfg.read_only = false;
priv->cfg.size = cfg->size;
priv->cfg.reg_read = stm32_bsec_read;
priv->cfg.reg_write = stm32_bsec_write;
}
- nvmem = nvmem_register(&priv->cfg);
- if (IS_ERR(nvmem))
- return PTR_ERR(nvmem);
-
- platform_set_drvdata(pdev, nvmem);
-
- return 0;
-}
-
-static int stm32_romem_remove(struct platform_device *pdev)
-{
- struct nvmem_device *nvmem = platform_get_drvdata(pdev);
-
- return nvmem_unregister(nvmem);
+ return PTR_ERR_OR_ZERO(devm_nvmem_register(dev, &priv->cfg));
}
static const struct stm32_romem_cfg stm32mp15_bsec_cfg = {
@@ -191,7 +190,6 @@ MODULE_DEVICE_TABLE(of, stm32_romem_of_match);
static struct platform_driver stm32_romem_driver = {
.probe = stm32_romem_probe,
- .remove = stm32_romem_remove,
.driver = {
.name = "stm32-romem",
.of_match_table = of_match_ptr(stm32_romem_of_match),
diff --git a/drivers/remoteproc/rproc_srm_core.h b/drivers/remoteproc/rproc_srm_core.h
index 7915f35..7dffdb38 100644
--- a/drivers/remoteproc/rproc_srm_core.h
+++ b/drivers/remoteproc/rproc_srm_core.h
@@ -20,12 +20,10 @@
/**
* Resource type used in resource manager rpmsg:
* RPROC_SRM_RSC_CLOCK: clock resource
- * RPROC_SRM_RSC_PIN: pin resource
* RPROC_SRM_RSC_REGU: regulator resource
*/
#define RPROC_SRM_RSC_CLOCK 0x00
-#define RPROC_SRM_RSC_PIN 0x01
-#define RPROC_SRM_RSC_REGU 0x02
+#define RPROC_SRM_RSC_REGU 0x01
/**
* struct clock_cfg - clock configuration used in resource manager rpmsg
@@ -63,14 +61,6 @@ struct regu_cfg {
};
/**
- * struct pin_cfg - pin configuration used in resource manager rpmsg
- * @name: current pin configuration name (meaningful in GetConfig message)
- */
-struct pin_cfg {
- u8 name[16];
-};
-
-/**
* struct rpmsg_srm_msg - message structure used between processors to
* dynamically update resources configuration
* @message_type: type of the message: see RPROC_SRM_MSG*
@@ -81,7 +71,6 @@ struct pin_cfg {
* see RPROC_SRM_RSC*
* @clock_cfg: clock config - relevant if &rsc_type is RPROC_SRM_RSC_CLOCK
* @regu_cfg: regulator config - relevant if &rsc_type is RPROC_SRM_RSC_REGU
- * @pin_cfg: pin config - relevant if &rsc_type is RPROC_SRM_RSC_PIN
*/
struct rpmsg_srm_msg {
u32 message_type;
@@ -90,7 +79,6 @@ struct rpmsg_srm_msg {
union {
struct clock_cfg clock_cfg;
struct regu_cfg regu_cfg;
- struct pin_cfg pin_cfg;
};
};
diff --git a/drivers/remoteproc/rproc_srm_dev.c b/drivers/remoteproc/rproc_srm_dev.c
index b026f961..7dc99c5 100644
--- a/drivers/remoteproc/rproc_srm_dev.c
+++ b/drivers/remoteproc/rproc_srm_dev.c
@@ -31,7 +31,6 @@ struct rproc_srm_pin_info {
struct list_head list;
unsigned int index;
char *name;
- bool selected;
};
struct rproc_srm_regu_info {
@@ -544,83 +543,6 @@ static int rproc_srm_dev_regus_get(struct rproc_srm_dev *rproc_srm_dev)
}
/* Pins */
-static int rproc_srm_dev_pin_set_cfg(struct rproc_srm_dev *rproc_srm_dev,
- struct pin_cfg *cfg)
-{
- struct rproc_srm_pin_info *pi, *p = NULL;
- struct device *dev = rproc_srm_dev->dev;
- struct pinctrl_state *state;
- int ret;
-
- list_for_each_entry(pi, &rproc_srm_dev->pin_list_head, list) {
- if (!strcmp(pi->name, cfg->name)) {
- p = pi;
- break;
- }
- }
-
- if (!p) {
- dev_err(dev, "unknown pin config (%s)\n", cfg->name);
- return -EINVAL;
- }
-
- state = pinctrl_lookup_state(rproc_srm_dev->pctrl, cfg->name);
- if (IS_ERR(state)) {
- dev_err(dev, "cannot get pin config (%s)\n", cfg->name);
- return -EINVAL;
- }
-
- ret = pinctrl_select_state(rproc_srm_dev->pctrl, state);
- if (ret < 0) {
- dev_err(dev, "cannot set pin config (%s)\n", cfg->name);
- return ret;
- }
-
- list_for_each_entry(pi, &rproc_srm_dev->pin_list_head, list) {
- pi->selected = (pi == p);
- }
-
- dev_dbg(dev, "pin config (%s) selected\n", p->name);
-
- return 0;
-}
-
-static int rproc_srm_dev_pin_get_cfg(struct rproc_srm_dev *rproc_srm_dev,
- struct pin_cfg *cfg)
-{
- struct rproc_srm_pin_info *p;
-
- list_for_each_entry(p, &rproc_srm_dev->pin_list_head, list) {
- if (p->selected) {
- strlcpy(cfg->name, p->name, sizeof(cfg->name));
- return 0;
- }
- }
-
- dev_warn(rproc_srm_dev->dev, "cannot find selected pin state\n");
- strcpy(cfg->name, "");
-
- return 0;
-}
-
-static int rproc_srm_dev_pins_setup(struct rproc_srm_dev *rproc_srm_dev)
-{
- struct rproc_srm_pin_info *p;
- struct pin_cfg cfg = { .name = "rproc_default" };
-
- if (rproc_srm_dev->early_boot)
- /* in early_boot mode do not update pin config */
- return 0;
-
- /* set the "rproc_default" pin config if defined */
- list_for_each_entry(p, &rproc_srm_dev->pin_list_head, list) {
- if (!strcmp(p->name, cfg.name))
- return rproc_srm_dev_pin_set_cfg(rproc_srm_dev, &cfg);
- }
-
- return 0;
-}
-
static void rproc_srm_dev_pins_put(struct rproc_srm_dev *rproc_srm_dev)
{
struct device *dev = rproc_srm_dev->dev;
@@ -677,11 +599,9 @@ static int rproc_srm_dev_pins_get(struct rproc_srm_dev *rproc_srm_dev)
}
p->name = devm_kstrdup(dev, name, GFP_KERNEL);
- if (!strcmp(p->name, PINCTRL_STATE_DEFAULT)) {
- if (rproc_srm_dev->early_boot)
- dev_warn(dev, "pin config potentially overwritten!\n");
- p->selected = true;
- }
+ /* pinctrl-names shall not be "default" (but "rproc_default") */
+ if (!strcmp(p->name, PINCTRL_STATE_DEFAULT))
+ dev_warn(dev, "pin config potentially overwritten!\n");
p->index = i;
@@ -726,13 +646,6 @@ static int rproc_srm_dev_notify_cb(struct notifier_block *nb, unsigned long evt,
ret = rproc_srm_dev_clock_get_cfg(rproc_srm_dev,
&o.clock_cfg);
break;
- case RPROC_SRM_RSC_PIN:
- ret = rproc_srm_dev_pin_set_cfg(rproc_srm_dev,
- &i->pin_cfg);
- if (!ret)
- ret = rproc_srm_dev_pin_get_cfg(rproc_srm_dev,
- &o.pin_cfg);
- break;
case RPROC_SRM_RSC_REGU:
ret = rproc_srm_dev_regu_set_cfg(rproc_srm_dev,
&i->regu_cfg);
@@ -752,10 +665,6 @@ static int rproc_srm_dev_notify_cb(struct notifier_block *nb, unsigned long evt,
ret = rproc_srm_dev_clock_get_cfg(rproc_srm_dev,
&o.clock_cfg);
break;
- case RPROC_SRM_RSC_PIN:
- ret = rproc_srm_dev_pin_get_cfg(rproc_srm_dev,
- &o.pin_cfg);
- break;
case RPROC_SRM_RSC_REGU:
ret = rproc_srm_dev_regu_get_cfg(rproc_srm_dev,
&o.regu_cfg);
@@ -810,11 +719,7 @@ rproc_srm_dev_bind(struct device *dev, struct device *master, void *data)
if (ret)
return ret;
- ret = rproc_srm_dev_pins_setup(rproc_srm_dev);
- if (ret)
- return ret;
-
- /* For IRQs: nothing to setup */
+ /* For pins and IRQs: nothing to setup */
return 0;
}
diff --git a/drivers/remoteproc/stm32_rproc.c b/drivers/remoteproc/stm32_rproc.c
index 998de67..548afdd 100644
--- a/drivers/remoteproc/stm32_rproc.c
+++ b/drivers/remoteproc/stm32_rproc.c
@@ -29,7 +29,7 @@
#define STM32_MBX_VQ0 "vq0"
#define STM32_MBX_VQ1 "vq1"
-#define STM32_MBX_SHUTDOWN "init_shdn"
+#define STM32_MBX_SHUTDOWN "shutdown"
struct stm32_syscon {
struct regmap *map;
--
2.7.4

View File

@ -0,0 +1,273 @@
From f03da721a19075ead436b2edbe4c4080feb8dac8 Mon Sep 17 00:00:00 2001
From: Christophe Priouzeau <christophe.priouzeau@st.com>
Date: Mon, 26 Nov 2018 14:44:24 +0100
Subject: [PATCH 26/52] ARM-stm32mp1-r0-rc2-NET
---
.../devicetree/bindings/net/stm32-dwmac.txt | 6 +-
drivers/net/ethernet/stmicro/stmmac/dwmac-stm32.c | 102 +++++++++++++++++----
.../net/ethernet/stmicro/stmmac/stmmac_platform.c | 3 +
.../wireless/broadcom/brcm80211/brcmfmac/bcmsdh.c | 6 ++
4 files changed, 94 insertions(+), 23 deletions(-)
diff --git a/Documentation/devicetree/bindings/net/stm32-dwmac.txt b/Documentation/devicetree/bindings/net/stm32-dwmac.txt
index 1341012..f42dc68 100644
--- a/Documentation/devicetree/bindings/net/stm32-dwmac.txt
+++ b/Documentation/devicetree/bindings/net/stm32-dwmac.txt
@@ -24,9 +24,9 @@ Required properties:
encompases the glue register, and the offset of the control register.
Optional properties:
-- clock-names: For MPU family "mac-clk-ck" for PHY without quartz
-- st,int-phyclk (boolean) : valid only where PHY do not have quartz and need to be clock
- by RCC
+- clock-names: For MPU family "eth-ck" for PHY without quartz
+- st,eth_clk_sel (boolean) : set this property in RGMII PHY when you do not want use 125Mhz
+- st,eth_ref_clk_sel (boolean) : set this property in RMII mode when you have PHY without crystal 50MHz
Example:
diff --git a/drivers/net/ethernet/stmicro/stmmac/dwmac-stm32.c b/drivers/net/ethernet/stmicro/stmmac/dwmac-stm32.c
index d1cf145..545b168 100644
--- a/drivers/net/ethernet/stmicro/stmmac/dwmac-stm32.c
+++ b/drivers/net/ethernet/stmicro/stmmac/dwmac-stm32.c
@@ -25,9 +25,24 @@
#define SYSCFG_MCU_ETH_MASK BIT(23)
#define SYSCFG_MP1_ETH_MASK GENMASK(23, 16)
+#define SYSCFG_PMCCLRR_OFFSET 0x40
#define SYSCFG_PMCR_ETH_CLK_SEL BIT(16)
#define SYSCFG_PMCR_ETH_REF_CLK_SEL BIT(17)
+
+/* Ethernet PHY interface selection in register SYSCFG Configuration
+ *------------------------------------------
+ * src |BIT(23)| BIT(22)| BIT(21)|BIT(20)|
+ *------------------------------------------
+ * MII | 0 | 0 | 0 | 1 |
+ *------------------------------------------
+ * GMII | 0 | 0 | 0 | 0 |
+ *------------------------------------------
+ * RGMII | 0 | 0 | 1 | n/a |
+ *------------------------------------------
+ * RMII | 1 | 0 | 0 | n/a |
+ *------------------------------------------
+ */
#define SYSCFG_PMCR_ETH_SEL_MII BIT(20)
#define SYSCFG_PMCR_ETH_SEL_RGMII BIT(21)
#define SYSCFG_PMCR_ETH_SEL_RMII BIT(23)
@@ -35,15 +50,54 @@
#define SYSCFG_MCU_ETH_SEL_MII 0
#define SYSCFG_MCU_ETH_SEL_RMII 1
+/* STM32MP1 register definitions
+ *
+ * Below table summarizes the clock requirement and clock sources for
+ * supported phy interface modes.
+ * __________________________________________________________________________
+ *|PHY_MODE | Normal | PHY wo crystal| PHY wo crystal |No 125Mhz from PHY|
+ *| | | 25MHz | 50MHz | |
+ * ---------------------------------------------------------------------------
+ *| MII | - | eth-ck | n/a | n/a |
+ *| | | | | |
+ * ---------------------------------------------------------------------------
+ *| GMII | - | eth-ck | n/a | n/a |
+ *| | | | | |
+ * ---------------------------------------------------------------------------
+ *| RGMII | - | eth-ck | n/a | eth-ck (no pin) |
+ *| | | | | st,eth_clk_sel |
+ * ---------------------------------------------------------------------------
+ *| RMII | - | eth-ck | eth-ck | n/a |
+ *| | | | st,eth_ref_clk_sel | |
+ * ---------------------------------------------------------------------------
+ *
+ * BIT(17) : set this bit in RMII mode when you have PHY without crystal 50MHz
+ * BIT(16) : set this bit in GMII/RGMII PHY when you do not want use 125Mhz
+ * from PHY
+ *-----------------------------------------------------
+ * src | BIT(17) | BIT(16) |
+ *-----------------------------------------------------
+ * MII | n/a | n/a |
+ *-----------------------------------------------------
+ * GMII | n/a | st,eth_clk_sel |
+ *-----------------------------------------------------
+ * RGMII | n/a | st,eth_clk_sel |
+ *-----------------------------------------------------
+ * RMII | st,eth_ref_clk_sel | n/a |
+ *-----------------------------------------------------
+ *
+ */
+
struct stm32_dwmac {
struct clk *clk_tx;
struct clk *clk_rx;
struct clk *clk_eth_ck;
struct clk *clk_ethstp;
struct clk *syscfg_clk;
- bool int_phyclk; /* Clock from RCC to drive PHY */
+ int eth_clk_sel_reg;
+ int eth_ref_clk_sel_reg;
int irq_pwr_wakeup;
- u32 mode_reg; /* MAC glue-logic mode register */
+ u32 mode_reg; /* MAC glue-logic mode register */
struct regmap *regmap;
u32 speed;
const struct stm32_ops *ops;
@@ -103,7 +157,7 @@ static int stm32mp1_clk_prepare(struct stm32_dwmac *dwmac, bool prepare)
if (ret)
return ret;
- if (dwmac->int_phyclk) {
+ if (dwmac->clk_eth_ck) {
ret = clk_prepare_enable(dwmac->clk_eth_ck);
if (ret) {
clk_disable_unprepare(dwmac->syscfg_clk);
@@ -112,7 +166,7 @@ static int stm32mp1_clk_prepare(struct stm32_dwmac *dwmac, bool prepare)
}
} else {
clk_disable_unprepare(dwmac->syscfg_clk);
- if (dwmac->int_phyclk)
+ if (dwmac->clk_eth_ck)
clk_disable_unprepare(dwmac->clk_eth_ck);
}
return ret;
@@ -122,7 +176,7 @@ static int stm32mp1_set_mode(struct plat_stmmacenet_data *plat_dat)
{
struct stm32_dwmac *dwmac = plat_dat->bsp_priv;
u32 reg = dwmac->mode_reg;
- int val;
+ int val, ret;
switch (plat_dat->interface) {
case PHY_INTERFACE_MODE_MII:
@@ -131,19 +185,19 @@ static int stm32mp1_set_mode(struct plat_stmmacenet_data *plat_dat)
break;
case PHY_INTERFACE_MODE_GMII:
val = SYSCFG_PMCR_ETH_SEL_GMII;
- if (dwmac->int_phyclk)
+ if (dwmac->eth_clk_sel_reg)
val |= SYSCFG_PMCR_ETH_CLK_SEL;
pr_debug("SYSCFG init : PHY_INTERFACE_MODE_GMII\n");
break;
case PHY_INTERFACE_MODE_RMII:
val = SYSCFG_PMCR_ETH_SEL_RMII;
- if (dwmac->int_phyclk)
+ if (dwmac->eth_ref_clk_sel_reg)
val |= SYSCFG_PMCR_ETH_REF_CLK_SEL;
pr_debug("SYSCFG init : PHY_INTERFACE_MODE_RMII\n");
break;
case PHY_INTERFACE_MODE_RGMII:
val = SYSCFG_PMCR_ETH_SEL_RGMII;
- if (dwmac->int_phyclk)
+ if (dwmac->eth_clk_sel_reg)
val |= SYSCFG_PMCR_ETH_CLK_SEL;
pr_debug("SYSCFG init : PHY_INTERFACE_MODE_RGMII\n");
break;
@@ -154,6 +208,11 @@ static int stm32mp1_set_mode(struct plat_stmmacenet_data *plat_dat)
return -EINVAL;
}
+ /* Need to update PMCCLRR (clear register) */
+ ret = regmap_update_bits(dwmac->regmap, reg + SYSCFG_PMCCLRR_OFFSET,
+ dwmac->ops->syscfg_eth_mask, ~val);
+
+ /* Update PMCSETR (set register) */
return regmap_update_bits(dwmac->regmap, reg,
dwmac->ops->syscfg_eth_mask, val);
}
@@ -237,22 +296,25 @@ static int stm32mp1_parse_data(struct stm32_dwmac *dwmac,
struct device_node *np = dev->of_node;
int err = 0;
- dwmac->int_phyclk = of_property_read_bool(np, "st,int-phyclk");
+ /* Gigabit Ethernet 125MHz clock selection. */
+ dwmac->eth_clk_sel_reg = of_property_read_bool(np, "st,eth_clk_sel");
- /* Check if internal clk from RCC selected */
- if (dwmac->int_phyclk) {
- /* Get ETH_CLK clocks */
- dwmac->clk_eth_ck = devm_clk_get(dev, "eth-ck");
- if (IS_ERR(dwmac->clk_eth_ck)) {
- dev_err(dev, "No ETH CK clock provided...\n");
- return PTR_ERR(dwmac->clk_eth_ck);
- }
+ /* Ethernet 50Mhz RMII clock selection */
+ dwmac->eth_ref_clk_sel_reg =
+ of_property_read_bool(np, "st,eth_ref_clk_sel");
+
+ /* Get ETH_CLK clocks */
+ dwmac->clk_eth_ck = devm_clk_get(dev, "eth-ck");
+ if (IS_ERR(dwmac->clk_eth_ck)) {
+ dev_warn(dev, "No phy clock provided...\n");
+ dwmac->clk_eth_ck = NULL;
}
/* Clock used for low power mode */
dwmac->clk_ethstp = devm_clk_get(dev, "ethstp");
if (IS_ERR(dwmac->clk_ethstp)) {
- dev_err(dev, "No ETH peripheral clock provided for CStop mode ...\n");
+ dev_err(dev,
+ "No ETH peripheral clock provided for CStop mode ...\n");
return PTR_ERR(dwmac->clk_ethstp);
}
@@ -268,7 +330,7 @@ static int stm32mp1_parse_data(struct stm32_dwmac *dwmac,
*/
dwmac->irq_pwr_wakeup = platform_get_irq_byname(pdev,
"stm32_pwr_wakeup");
- if (!dwmac->int_phyclk && dwmac->irq_pwr_wakeup >= 0) {
+ if ((!dwmac->clk_eth_ck) && dwmac->irq_pwr_wakeup >= 0) {
err = device_init_wakeup(&pdev->dev, true);
if (err) {
dev_err(&pdev->dev, "Failed to init wake up irq\n");
@@ -370,7 +432,7 @@ static int stm32mp1_suspend(struct stm32_dwmac *dwmac)
clk_disable_unprepare(dwmac->clk_tx);
clk_disable_unprepare(dwmac->syscfg_clk);
- if (dwmac->int_phyclk)
+ if (dwmac->clk_eth_ck)
clk_disable_unprepare(dwmac->clk_eth_ck);
return ret;
diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac_platform.c b/drivers/net/ethernet/stmicro/stmmac/stmmac_platform.c
index 2b800ce..3031f2b 100644
--- a/drivers/net/ethernet/stmicro/stmmac/stmmac_platform.c
+++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_platform.c
@@ -408,6 +408,9 @@ stmmac_probe_config_dt(struct platform_device *pdev, const char **mac)
/* Default to phy auto-detection */
plat->phy_addr = -1;
+ /* Get clk_csr from device tree */
+ of_property_read_u32(np, "clk_csr", &plat->clk_csr);
+
/* "snps,phy-addr" is not a standard property. Mark it as deprecated
* and warn of its use. Remove this when phy node support is added.
*/
diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/bcmsdh.c b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/bcmsdh.c
index d2f788d..c7b41ce 100644
--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/bcmsdh.c
+++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/bcmsdh.c
@@ -1129,7 +1129,10 @@ static int brcmf_ops_sdio_suspend(struct device *dev)
enable_irq_wake(sdiodev->settings->bus.sdio.oob_irq_nr);
else
sdio_flags |= MMC_PM_WAKE_SDIO_IRQ;
+ } else {
+ brcmf_sdiod_intr_unregister(sdiodev);
}
+
if (sdio_set_host_pm_flags(sdiodev->func1, sdio_flags))
brcmf_err("Failed to set pm_flags %x\n", sdio_flags);
return 0;
@@ -1145,6 +1148,9 @@ static int brcmf_ops_sdio_resume(struct device *dev)
if (func->num != 2)
return 0;
+ if (!sdiodev->wowl_enabled)
+ brcmf_sdiod_intr_register(sdiodev);
+
brcmf_sdiod_freezer_off(sdiodev);
return 0;
}
--
2.7.4

View File

@ -0,0 +1,241 @@
From bf3772b12539b3595e60b8b334051160269f9071 Mon Sep 17 00:00:00 2001
From: Christophe Priouzeau <christophe.priouzeau@st.com>
Date: Mon, 26 Nov 2018 14:45:33 +0100
Subject: [PATCH 28/52] ARM-stm32mp1-r0-rc2-MMC
---
drivers/mmc/host/mmci.c | 36 +++++++++++++++++++++++++-----------
drivers/mmc/host/mmci.h | 13 +++++++++++--
2 files changed, 36 insertions(+), 13 deletions(-)
diff --git a/drivers/mmc/host/mmci.c b/drivers/mmc/host/mmci.c
index db50d1e..02b631f 100644
--- a/drivers/mmc/host/mmci.c
+++ b/drivers/mmc/host/mmci.c
@@ -135,7 +135,6 @@ static struct variant_data variant_u300 = {
.datactrl_blocksz = 11,
.datactrl_dpsm_enable = MCI_DPSM_ENABLE,
.datactrl_mask_sdio = MCI_DPSM_ST_SDIOEN,
- .st_sdio = true,
.pwrreg_powerup = MCI_PWR_ON,
.f_max = 100000000,
.signal_direction = true,
@@ -146,6 +145,7 @@ static struct variant_data variant_u300 = {
.start_err = MCI_STARTBITERR,
.opendrain = MCI_OD,
.init = mmci_variant_init,
+ .quirks = MMCI_QUIRK_ST_SDIO,
};
static struct variant_data variant_nomadik = {
@@ -161,7 +161,6 @@ static struct variant_data variant_nomadik = {
.datactrl_blocksz = 11,
.datactrl_dpsm_enable = MCI_DPSM_ENABLE,
.datactrl_mask_sdio = MCI_DPSM_ST_SDIOEN,
- .st_sdio = true,
.st_clkdiv = true,
.pwrreg_powerup = MCI_PWR_ON,
.f_max = 100000000,
@@ -173,6 +172,7 @@ static struct variant_data variant_nomadik = {
.start_err = MCI_STARTBITERR,
.opendrain = MCI_OD,
.init = mmci_variant_init,
+ .quirks = MMCI_QUIRK_ST_SDIO,
};
static struct variant_data variant_ux500 = {
@@ -190,7 +190,6 @@ static struct variant_data variant_ux500 = {
.datactrl_blocksz = 11,
.datactrl_dpsm_enable = MCI_DPSM_ENABLE,
.datactrl_mask_sdio = MCI_DPSM_ST_SDIOEN,
- .st_sdio = true,
.st_clkdiv = true,
.pwrreg_powerup = MCI_PWR_ON,
.f_max = 100000000,
@@ -206,6 +205,7 @@ static struct variant_data variant_ux500 = {
.start_err = MCI_STARTBITERR,
.opendrain = MCI_OD,
.init = mmci_variant_init,
+ .quirks = MMCI_QUIRK_ST_SDIO,
};
static struct variant_data variant_ux500v2 = {
@@ -224,7 +224,6 @@ static struct variant_data variant_ux500v2 = {
.datactrl_blocksz = 11,
.datactrl_dpsm_enable = MCI_DPSM_ENABLE,
.datactrl_mask_sdio = MCI_DPSM_ST_SDIOEN,
- .st_sdio = true,
.st_clkdiv = true,
.blksz_datactrl16 = true,
.pwrreg_powerup = MCI_PWR_ON,
@@ -241,6 +240,7 @@ static struct variant_data variant_ux500v2 = {
.start_err = MCI_STARTBITERR,
.opendrain = MCI_OD,
.init = mmci_variant_init,
+ .quirks = MMCI_QUIRK_ST_SDIO,
};
static struct variant_data variant_stm32 = {
@@ -259,13 +259,13 @@ static struct variant_data variant_stm32 = {
.datactrl_blocksz = 11,
.datactrl_dpsm_enable = MCI_DPSM_ENABLE,
.datactrl_mask_sdio = MCI_DPSM_ST_SDIOEN,
- .st_sdio = true,
.st_clkdiv = true,
.pwrreg_powerup = MCI_PWR_ON,
.f_max = 48000000,
.pwrreg_clkgate = true,
.pwrreg_nopower = true,
.init = mmci_variant_init,
+ .quirks = MMCI_QUIRK_ST_SDIO,
};
static struct variant_data variant_stm32_sdmmc = {
@@ -284,12 +284,14 @@ static struct variant_data variant_stm32_sdmmc = {
.datacnt_useless = true,
.datalength_bits = 25,
.datactrl_blocksz = 14,
+ .datactrl_mask_sdio = MCI_DPSM_STM32_SDIOEN,
.stm32_idmabsize_mask = GENMASK(12, 5),
.busy_detect = true,
.busy_timeout = true,
.busy_detect_flag = MCI_STM32_BUSYD0,
.busy_detect_mask = MCI_STM32_BUSYD0ENDMASK,
.init = sdmmc_variant_init,
+ .quirks = MMCI_QUIRK_STM32_DTMODE,
};
static struct variant_data variant_stm32_sdmmcv2 = {
@@ -308,6 +310,7 @@ static struct variant_data variant_stm32_sdmmcv2 = {
.datacnt_useless = true,
.datalength_bits = 25,
.datactrl_blocksz = 14,
+ .datactrl_mask_sdio = MCI_DPSM_STM32_SDIOEN,
.stm32_idmabsize_mask = GENMASK(16, 5),
.dma_lli = true,
.busy_detect = true,
@@ -315,6 +318,7 @@ static struct variant_data variant_stm32_sdmmcv2 = {
.busy_detect_flag = MCI_STM32_BUSYD0,
.busy_detect_mask = MCI_STM32_BUSYD0ENDMASK,
.init = sdmmc_variant_init,
+ .quirks = MMCI_QUIRK_STM32_DTMODE,
};
static struct variant_data variant_qcom = {
@@ -505,7 +509,8 @@ static int mmci_validate_data(struct mmci_host *host,
if (!data)
return 0;
- if (!is_power_of_2(data->blksz)) {
+ if ((host->mmc->card && !mmc_card_sdio(host->mmc->card)) &&
+ !is_power_of_2(data->blksz)) {
dev_err(mmc_dev(host->mmc),
"unsupported block size (%d bytes)\n", data->blksz);
return -EINVAL;
@@ -1068,7 +1073,6 @@ static void mmci_start_data(struct mmci_host *host, struct mmc_data *data)
writel(host->size, base + MMCIDATALENGTH);
blksz_bits = ffs(data->blksz) - 1;
- BUG_ON(1 << blksz_bits != data->blksz);
if (variant->blksz_datactrl16)
datactrl = variant->datactrl_dpsm_enable | (data->blksz << 16);
@@ -1077,6 +1081,16 @@ static void mmci_start_data(struct mmci_host *host, struct mmc_data *data)
else
datactrl = variant->datactrl_dpsm_enable | blksz_bits << 4;
+ if (variant->quirks & MMCI_QUIRK_STM32_DTMODE) {
+ if (host->mmc->card && mmc_card_sdio(host->mmc->card) &&
+ data->blocks == 1)
+ datactrl |= MCI_DPSM_STM32_MODE_SDIO;
+ else if (data->stop && !host->mrq->sbc)
+ datactrl |= MCI_DPSM_STM32_MODE_BLOCK_STOP;
+ else
+ datactrl |= MCI_DPSM_STM32_MODE_BLOCK;
+ }
+
if (data->flags & MMC_DATA_READ)
datactrl |= MCI_DPSM_DIRECTION;
@@ -1091,7 +1105,8 @@ static void mmci_start_data(struct mmci_host *host, struct mmc_data *data)
* otherwise the transfer will not start. The threshold
* depends on the rate of MCLK.
*/
- if (variant->st_sdio && data->flags & MMC_DATA_WRITE &&
+ if (variant->quirks & MMCI_QUIRK_ST_SDIO &&
+ data->flags & MMC_DATA_WRITE &&
(host->size < 8 ||
(host->size <= 8 && host->mclk > 50000000)))
clk = host->clk_reg & ~variant->clkreg_enable;
@@ -1257,11 +1272,10 @@ mmci_data_irq(struct mmci_host *host, struct mmc_data *data,
/* The error clause is handled above, success! */
data->bytes_xfered = data->blksz * data->blocks;
- if (!data->stop || host->mrq->sbc) {
+ if (!data->stop || (host->mrq->sbc && !data->error))
mmci_request_end(host, data->mrq);
- } else {
+ else
mmci_start_command(host, data->stop, 0);
- }
}
}
diff --git a/drivers/mmc/host/mmci.h b/drivers/mmc/host/mmci.h
index 36a744a..55867fc 100644
--- a/drivers/mmc/host/mmci.h
+++ b/drivers/mmc/host/mmci.h
@@ -131,6 +131,12 @@
/* Control register extensions in the Qualcomm versions */
#define MCI_DPSM_QCOM_DATA_PEND BIT(17)
#define MCI_DPSM_QCOM_RX_DATA_PEND BIT(20)
+/* Control register extensions in STM32 versions */
+#define MCI_DPSM_STM32_MODE_BLOCK (0 << 2)
+#define MCI_DPSM_STM32_MODE_SDIO (1 << 2)
+#define MCI_DPSM_STM32_MODE_STREAM (2 << 2)
+#define MCI_DPSM_STM32_MODE_BLOCK_STOP (3 << 2)
+#define MCI_DPSM_STM32_SDIOEN BIT(11)
#define MMCIDATACNT 0x030
#define MMCISTATUS 0x034
@@ -273,7 +279,6 @@ struct mmci_host;
* @fifohalfsize: number of bytes that can be written when MCI_TXFIFOHALFEMPTY
* is asserted (likewise for RX)
* @data_cmd_enable: enable value for data commands.
- * @st_sdio: enable ST specific SDIO logic
* @st_clkdiv: true if using a ST-specific clock divider algorithm
* @stm32_clkdiv: true if using a STM32-specific clock divider algorithm
* @datactrl_mask_ddrmode: ddr mode mask in datactrl register.
@@ -309,6 +314,7 @@ struct mmci_host;
* @opendrain: bitmask identifying the OPENDRAIN bit inside MMCIPOWER register
* @dma_lli: true if variant has dma link list feature.
* @stm32_idmabsize_mask: stm32 sdmmc idma buffer size.
+ * @quirks: A bitmap of hardware quirks that require some special action.
*/
struct variant_data {
unsigned int clkreg;
@@ -330,7 +336,6 @@ struct variant_data {
unsigned int datactrl_dpsm_enable;
u8 datactrl_first:1;
u8 datacnt_useless:1;
- u8 st_sdio:1;
u8 st_clkdiv:1;
u8 stm32_clkdiv:1;
u8 blksz_datactrl16:1;
@@ -355,9 +360,13 @@ struct variant_data {
u32 opendrain;
u8 dma_lli:1;
u32 stm32_idmabsize_mask;
+ u32 quirks;
void (*init)(struct mmci_host *host);
};
+#define MMCI_QUIRK_STM32_DTMODE BIT(0)
+#define MMCI_QUIRK_ST_SDIO BIT(2) /* enable ST specific SDIO logic */
+
/* mmci variant callbacks */
struct mmci_host_ops {
int (*validate_data)(struct mmci_host *host, struct mmc_data *data);
--
2.7.4

View File

@ -0,0 +1,771 @@
From 72179a889501ef339df094abe108846b19e7a06c Mon Sep 17 00:00:00 2001
From: Christophe Priouzeau <christophe.priouzeau@st.com>
Date: Mon, 26 Nov 2018 14:46:26 +0100
Subject: [PATCH 29/52] ARM-stm32mp1-r0-rc2-HWSPINLOCK-IIO-I2C
---
.../devicetree/bindings/iio/adc/st,stm32-adc.txt | 34 +++
arch/arm/Kconfig.debug | 27 ++
drivers/hwspinlock/Kconfig | 9 +
drivers/hwspinlock/Makefile | 1 +
drivers/hwspinlock/stm32_hwspinlock.c | 157 +++++++++++
drivers/i2c/busses/i2c-stm32f7.c | 6 +-
drivers/iio/adc/stm32-adc-core.c | 296 ++++++++++++++++++++-
drivers/iio/adc/stm32-adc.c | 4 +-
8 files changed, 529 insertions(+), 5 deletions(-)
create mode 100644 drivers/hwspinlock/stm32_hwspinlock.c
diff --git a/Documentation/devicetree/bindings/iio/adc/st,stm32-adc.txt b/Documentation/devicetree/bindings/iio/adc/st,stm32-adc.txt
index c46598c..a6aa796 100644
--- a/Documentation/devicetree/bindings/iio/adc/st,stm32-adc.txt
+++ b/Documentation/devicetree/bindings/iio/adc/st,stm32-adc.txt
@@ -49,6 +49,40 @@ Optional properties:
- st,max-clk-rate-hz: Allow to specify desired max clock rate used by analog
circuitry.
+- vdda-supply: Phandle to the vdda input voltage. It can be used to supply ADC
+ analog inputs switches on stm32mp1 and stm32h7.
+
+- vdd-supply: Phandle to the vdd input voltage. It can be used to supply ADC
+ analog inputs switches on stm32mp1.
+
+- st,syscfg-vbooster: Voltage booster control for analog switches supply.
+ This is available on stm32mp1 and stm32h7 (requires vdda-supply property).
+ It must be composed of 3 cells:
+ 1st cell: phandle to syscfg
+ 2nd cell: register offset within SYSCFG
+ 3rd cell: bitmask for BOOSTE on stm32h7, EN_BOOSTER set bit on stm32mp1
+
+- st,syscfg-vbooster-clr: Voltage booster clear for analog switches supply.
+ This is available on stm32mp1 (requires st,syscfg-vbooster and vdda-supply).
+ 1st cell: phandle to syscfg
+ 2nd cell: clear register offset within SYSCFG
+ 3rd cell: bitmask for EN_BOOSTER clear bit on stm32mp1
+
+- st,syscfg-anaswvdd: VDDA / VDD selection for analog switches supply.
+ This is available on stm32mp1 (requires vdda-supply and vdd-supply).
+ It must be composed of 3 cells:
+ 1st cell: phandle to syscfg
+ 2nd cell: register offset within SYSCFG
+ 3rd cell: bitmask for ANASWVDD set bit
+
+- st,syscfg-anaswvdd-clr: VDDA / VDD selection clear for analog switches supply.
+ This is available on stm32mp1 (requires st,syscfg-anaswvdd, vdda-supply and
+ vdd-supply).
+ It must be composed of 3 cells:
+ 1st cell: phandle to syscfg
+ 2nd cell: clear register offset within SYSCFG
+ 3rd cell: bitmask for ANASWVDD clear bit
+
Contents of a stm32 adc child node:
-----------------------------------
An ADC block node should contain at least one subnode, representing an
diff --git a/arch/arm/Kconfig.debug b/arch/arm/Kconfig.debug
index f6fcb8a..d5ec6c3 100644
--- a/arch/arm/Kconfig.debug
+++ b/arch/arm/Kconfig.debug
@@ -1184,6 +1184,28 @@ choice
If unsure, say N.
+ config STM32F4_DEBUG_UART
+ bool "Use STM32F4 UART for low-level debug"
+ depends on ARCH_STM32
+ select DEBUG_STM32_UART
+ help
+ Say Y here if you want kernel low-level debugging support
+ on STM32F4 based platforms, which default UART is wired on
+ USART1.
+
+ If unsure, say N.
+
+ config STM32F7_DEBUG_UART
+ bool "Use STM32F7 UART for low-level debug"
+ depends on ARCH_STM32
+ select DEBUG_STM32_UART
+ help
+ Say Y here if you want kernel low-level debugging support
+ on STM32F7 based platforms, which default UART is wired on
+ USART1.
+
+ If unsure, say N.
+
config TEGRA_DEBUG_UART_AUTO_ODMDATA
bool "Kernel low-level debugging messages via Tegra UART via ODMDATA"
depends on ARCH_TEGRA
@@ -1468,6 +1490,10 @@ config DEBUG_STI_UART
bool
depends on ARCH_STI
+config DEBUG_STM32_UART
+ bool
+ depends on ARCH_STM32
+
config DEBUG_SIRFSOC_UART
bool
depends on ARCH_SIRF
@@ -1517,6 +1543,7 @@ config DEBUG_LL_INCLUDE
default "debug/s5pv210.S" if DEBUG_S5PV210_UART
default "debug/sirf.S" if DEBUG_SIRFSOC_UART
default "debug/sti.S" if DEBUG_STI_UART
+ default "debug/stm32.S" if DEBUG_STM32_UART
default "debug/tegra.S" if DEBUG_TEGRA_UART
default "debug/ux500.S" if DEBUG_UX500_UART
default "debug/vexpress.S" if DEBUG_VEXPRESS_UART0_DETECT
diff --git a/drivers/hwspinlock/Kconfig b/drivers/hwspinlock/Kconfig
index e895d29..7869c67 100644
--- a/drivers/hwspinlock/Kconfig
+++ b/drivers/hwspinlock/Kconfig
@@ -49,6 +49,15 @@ config HWSPINLOCK_SPRD
If unsure, say N.
+config HWSPINLOCK_STM32
+ tristate "STM32 Hardware Spinlock device"
+ depends on MACH_STM32MP157
+ depends on HWSPINLOCK
+ help
+ Say y here to support the STM32 Hardware Spinlock device.
+
+ If unsure, say N.
+
config HSEM_U8500
tristate "STE Hardware Semaphore functionality"
depends on HWSPINLOCK
diff --git a/drivers/hwspinlock/Makefile b/drivers/hwspinlock/Makefile
index b87c01a..ed053e3 100644
--- a/drivers/hwspinlock/Makefile
+++ b/drivers/hwspinlock/Makefile
@@ -8,4 +8,5 @@ obj-$(CONFIG_HWSPINLOCK_OMAP) += omap_hwspinlock.o
obj-$(CONFIG_HWSPINLOCK_QCOM) += qcom_hwspinlock.o
obj-$(CONFIG_HWSPINLOCK_SIRF) += sirf_hwspinlock.o
obj-$(CONFIG_HWSPINLOCK_SPRD) += sprd_hwspinlock.o
+obj-$(CONFIG_HWSPINLOCK_STM32) += stm32_hwspinlock.o
obj-$(CONFIG_HSEM_U8500) += u8500_hsem.o
diff --git a/drivers/hwspinlock/stm32_hwspinlock.c b/drivers/hwspinlock/stm32_hwspinlock.c
new file mode 100644
index 0000000..3242b72
--- /dev/null
+++ b/drivers/hwspinlock/stm32_hwspinlock.c
@@ -0,0 +1,157 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (C) STMicroelectronics SA 2018
+ * Author: Benjamin Gaignard <benjamin.gaignard@st.com> for STMicroelectronics.
+ */
+
+#include <linux/clk.h>
+#include <linux/hwspinlock.h>
+#include <linux/io.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/platform_device.h>
+#include <linux/pm_runtime.h>
+
+#include "hwspinlock_internal.h"
+
+#define STM32_MUTEX_COREID BIT(8)
+#define STM32_MUTEX_LOCK_BIT BIT(31)
+#define STM32_MUTEX_NUM_LOCKS 32
+
+struct stm32_hwspinlock {
+ struct clk *clk;
+ struct hwspinlock_device bank;
+};
+
+static int stm32_hwspinlock_trylock(struct hwspinlock *lock)
+{
+ void __iomem *lock_addr = lock->priv;
+ u32 status;
+
+ writel(STM32_MUTEX_LOCK_BIT | STM32_MUTEX_COREID, lock_addr);
+ status = readl(lock_addr);
+
+ return status == (STM32_MUTEX_LOCK_BIT | STM32_MUTEX_COREID);
+}
+
+static void stm32_hwspinlock_unlock(struct hwspinlock *lock)
+{
+ void __iomem *lock_addr = lock->priv;
+
+ writel(STM32_MUTEX_COREID, lock_addr);
+}
+
+static const struct hwspinlock_ops stm32_hwspinlock_ops = {
+ .trylock = stm32_hwspinlock_trylock,
+ .unlock = stm32_hwspinlock_unlock,
+};
+
+static int stm32_hwspinlock_probe(struct platform_device *pdev)
+{
+ struct stm32_hwspinlock *hw;
+ void __iomem *io_base;
+ struct resource *res;
+ size_t array_size;
+ int i, ret;
+
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ io_base = devm_ioremap_resource(&pdev->dev, res);
+ if (!io_base)
+ return -ENOMEM;
+
+ array_size = STM32_MUTEX_NUM_LOCKS * sizeof(struct hwspinlock);
+ hw = devm_kzalloc(&pdev->dev, sizeof(*hw) + array_size, GFP_KERNEL);
+ if (!hw)
+ return -ENOMEM;
+
+ hw->clk = devm_clk_get(&pdev->dev, "hsem");
+ if (IS_ERR(hw->clk))
+ return PTR_ERR(hw->clk);
+
+ for (i = 0; i < STM32_MUTEX_NUM_LOCKS; i++)
+ hw->bank.lock[i].priv = io_base + i * sizeof(u32);
+
+ platform_set_drvdata(pdev, hw);
+ pm_runtime_enable(&pdev->dev);
+
+ ret = hwspin_lock_register(&hw->bank, &pdev->dev, &stm32_hwspinlock_ops,
+ 0, STM32_MUTEX_NUM_LOCKS);
+
+ if (ret)
+ pm_runtime_disable(&pdev->dev);
+
+ return ret;
+}
+
+static int stm32_hwspinlock_remove(struct platform_device *pdev)
+{
+ struct stm32_hwspinlock *hw = platform_get_drvdata(pdev);
+ int ret;
+
+ ret = hwspin_lock_unregister(&hw->bank);
+ if (ret)
+ dev_err(&pdev->dev, "%s failed: %d\n", __func__, ret);
+
+ pm_runtime_disable(&pdev->dev);
+
+ return 0;
+}
+
+static int __maybe_unused stm32_hwspinlock_runtime_suspend(struct device *dev)
+{
+ struct stm32_hwspinlock *hw = dev_get_drvdata(dev);
+
+ clk_disable_unprepare(hw->clk);
+
+ return 0;
+}
+
+static int __maybe_unused stm32_hwspinlock_runtime_resume(struct device *dev)
+{
+ struct stm32_hwspinlock *hw = dev_get_drvdata(dev);
+
+ clk_prepare_enable(hw->clk);
+
+ return 0;
+}
+
+static const struct dev_pm_ops stm32_hwspinlock_pm_ops = {
+ SET_RUNTIME_PM_OPS(stm32_hwspinlock_runtime_suspend,
+ stm32_hwspinlock_runtime_resume,
+ NULL)
+};
+
+static const struct of_device_id stm32_hwpinlock_ids[] = {
+ { .compatible = "st,stm32-hwspinlock", },
+ {},
+};
+MODULE_DEVICE_TABLE(of, stm32_hwpinlock_ids);
+
+static struct platform_driver stm32_hwspinlock_driver = {
+ .probe = stm32_hwspinlock_probe,
+ .remove = stm32_hwspinlock_remove,
+ .driver = {
+ .name = "stm32_hwspinlock",
+ .of_match_table = stm32_hwpinlock_ids,
+ .pm = &stm32_hwspinlock_pm_ops,
+ },
+};
+
+static int __init stm32_hwspinlock_init(void)
+{
+ return platform_driver_register(&stm32_hwspinlock_driver);
+}
+
+/* board init code might need to reserve hwspinlocks for predefined purposes */
+postcore_initcall(stm32_hwspinlock_init);
+
+static void __exit stm32_hwspinlock_exit(void)
+{
+ platform_driver_unregister(&stm32_hwspinlock_driver);
+}
+module_exit(stm32_hwspinlock_exit);
+
+MODULE_LICENSE("GPL v2");
+MODULE_DESCRIPTION("Hardware spinlock driver for STM32 SoCs");
+MODULE_AUTHOR("Benjamin Gaignard <benjamin.gaignard@st.com>");
diff --git a/drivers/i2c/busses/i2c-stm32f7.c b/drivers/i2c/busses/i2c-stm32f7.c
index c1cbf93..ac30aea 100644
--- a/drivers/i2c/busses/i2c-stm32f7.c
+++ b/drivers/i2c/busses/i2c-stm32f7.c
@@ -457,7 +457,7 @@ static int stm32f7_i2c_compute_timing(struct stm32f7_i2c_dev *i2c_dev,
STM32F7_I2C_ANALOG_FILTER_DELAY_MAX : 0);
dnf_delay = setup->dnf * i2cclk;
- sdadel_min = setup->fall_time - i2c_specs[setup->speed].hddat_min -
+ sdadel_min = i2c_specs[setup->speed].hddat_min + setup->fall_time -
af_delay_min - (setup->dnf + 3) * i2cclk;
sdadel_max = i2c_specs[setup->speed].vddat_max - setup->rise_time -
@@ -501,8 +501,12 @@ static int stm32f7_i2c_compute_timing(struct stm32f7_i2c_dev *i2c_dev,
list_add_tail(&v->node,
&solutions);
+ break;
}
}
+
+ if (p_prev == p)
+ break;
}
}
diff --git a/drivers/iio/adc/stm32-adc-core.c b/drivers/iio/adc/stm32-adc-core.c
index a32e826..6234456 100644
--- a/drivers/iio/adc/stm32-adc-core.c
+++ b/drivers/iio/adc/stm32-adc-core.c
@@ -16,10 +16,12 @@
#include <linux/irqchip/chained_irq.h>
#include <linux/irqdesc.h>
#include <linux/irqdomain.h>
+#include <linux/mfd/syscon.h>
#include <linux/module.h>
#include <linux/of_device.h>
#include <linux/of_irq.h>
#include <linux/pm_runtime.h>
+#include <linux/regmap.h>
#include <linux/regulator/consumer.h>
#include <linux/slab.h>
@@ -88,6 +90,8 @@
#define STM32H7_CKMODE_SHIFT 16
#define STM32H7_CKMODE_MASK GENMASK(17, 16)
+#define STM32_ADC_CORE_SLEEP_DELAY_MS 2000
+
/**
* stm32_adc_common_regs - stm32 common registers, compatible dependent data
* @csr: common status register offset
@@ -117,16 +121,30 @@ struct stm32_adc_priv;
* @regs: common registers for all instances
* @clk_sel: clock selection routine
* @max_clk_rate_hz: maximum analog clock rate (Hz, from datasheet)
+ * @has_syscfg_clr: analog switch control use set and clear registers
* @exti_trigs EXTI triggers info
*/
struct stm32_adc_priv_cfg {
const struct stm32_adc_common_regs *regs;
int (*clk_sel)(struct platform_device *, struct stm32_adc_priv *);
u32 max_clk_rate_hz;
+ int has_syscfg_clr;
struct stm32_adc_trig_info *exti_trigs;
};
/**
+ * stm32_adc_syscfg - stm32 ADC SYSCFG data
+ * @regmap: reference to syscon
+ * @reg: register offset within SYSCFG
+ * @mask: bitmask within SYSCFG register
+ */
+struct stm32_adc_syscfg {
+ struct regmap *regmap;
+ u32 reg;
+ u32 mask;
+};
+
+/**
* struct stm32_adc_priv - stm32 ADC core private data
* @irq: irq(s) for ADC block
* @domain: irq domain reference
@@ -137,6 +155,10 @@ struct stm32_adc_priv_cfg {
* @cfg: compatible configuration data
* @common: common data for all ADC instances
* @ccr_bak: backup'ed CCR in low power mode
+ * @vbooster: BOOSTE syscfg / EN_BOOSTER syscfg set
+ * @vbooster_clr: EN_BOOSTER syscfg clear
+ * @anaswvdd: ANASWVDD syscfg set
+ * @anaswvdd_clr: ANASWVDD syscfg clear
*/
struct stm32_adc_priv {
int irq[STM32_ADC_MAX_ADCS];
@@ -144,10 +166,16 @@ struct stm32_adc_priv {
struct clk *aclk;
struct clk *bclk;
u32 max_clk_rate;
+ struct regulator *vdd;
+ struct regulator *vdda;
struct regulator *vref;
const struct stm32_adc_priv_cfg *cfg;
struct stm32_adc_common common;
u32 ccr_bak;
+ struct stm32_adc_syscfg vbooster;
+ struct stm32_adc_syscfg vbooster_clr;
+ struct stm32_adc_syscfg anaswvdd;
+ struct stm32_adc_syscfg anaswvdd_clr;
};
static struct stm32_adc_priv *to_stm32_adc_priv(struct stm32_adc_common *com)
@@ -567,16 +595,187 @@ static int stm32_adc_triggers_probe(struct platform_device *pdev,
return 0;
}
+static int stm32_adc_switches_supply_en(struct device *dev)
+{
+ struct stm32_adc_common *common = dev_get_drvdata(dev);
+ struct stm32_adc_priv *priv = to_stm32_adc_priv(common);
+ int ret, vdda, vdd = 0;
+ u32 anaswvdd, en_booster;
+
+ /*
+ * On STM32H7 and STM32MP1, the ADC inputs are multiplexed with analog
+ * switches (e.g. PCSEL) which have reduced performances when their
+ * supply is below 2.7V (vdda by default):
+ * - Voltage booster can be used, to get full ADC performances
+ * (increases power consumption).
+ * - Vdd can be used if above 2.7V (STM32MP1 only).
+ *
+ * Make all this optional, since this is a trade-off between analog
+ * performance and power consumption.
+ */
+ if (IS_ERR(priv->vdda) || IS_ERR(priv->vbooster.regmap)) {
+ dev_dbg(dev, "%s: nothing to do\n", __func__);
+ return 0;
+ }
+
+ ret = regulator_enable(priv->vdda);
+ if (ret < 0) {
+ dev_err(dev, "vdda enable failed %d\n", ret);
+ return ret;
+ }
+
+ ret = regulator_get_voltage(priv->vdda);
+ if (ret < 0) {
+ dev_err(dev, "vdda get voltage failed %d\n", ret);
+ goto vdda_dis;
+ }
+ vdda = ret;
+
+ if (!IS_ERR(priv->vdd) && !IS_ERR(priv->anaswvdd.regmap)) {
+ ret = regulator_enable(priv->vdd);
+ if (ret < 0) {
+ dev_err(dev, "vdd enable failed %d\n", ret);
+ goto vdda_dis;
+ }
+
+ ret = regulator_get_voltage(priv->vdd);
+ if (ret < 0) {
+ dev_err(dev, "vdd get voltage failed %d\n", ret);
+ goto vdd_dis;
+ }
+ vdd = ret;
+ }
+
+ /*
+ * Recommended settings for ANASWVDD and EN_BOOSTER:
+ * - vdda > 2.7V: ANASWVDD = 0, EN_BOOSTER = 0
+ * - vdda < 2.7V and vdd < 2.7V: ANASWVDD = 0, EN_BOOSTER = 1
+ * - vdda < 2.7V but vdd > 2.7V: ANASWVDD = 1, EN_BOOSTER = 0 (stm32mp1)
+ */
+ if (vdda > 2700000) {
+ /* analog switches supplied by vdda (default) */
+ anaswvdd = 0;
+ en_booster = 0;
+ } else {
+ if (vdd < 2700000) {
+ /* Voltage booster enabled */
+ anaswvdd = 0;
+ en_booster = priv->vbooster.mask;
+ } else {
+ /* analog switches supplied by vdd */
+ anaswvdd = priv->anaswvdd.mask;
+ en_booster = 0;
+ }
+ }
+
+ dev_dbg(dev, "vdda=%d, vdd=%d, setting: en_booster=%x, anaswvdd=%x\n",
+ vdda, vdd, en_booster, anaswvdd);
+
+ /* direct write en_booster value (or use clear register) */
+ if (en_booster || IS_ERR(priv->vbooster_clr.regmap))
+ ret = regmap_update_bits(priv->vbooster.regmap,
+ priv->vbooster.reg,
+ priv->vbooster.mask, en_booster);
+ else
+ ret = regmap_update_bits(priv->vbooster_clr.regmap,
+ priv->vbooster_clr.reg,
+ priv->vbooster_clr.mask,
+ priv->vbooster_clr.mask);
+ if (ret) {
+ dev_err(dev, "can't access voltage booster, %d\n", ret);
+ goto vdd_dis;
+ }
+
+ /* Booster voltage can take up to 50 μs to stabilize */
+ if (en_booster)
+ usleep_range(50, 100);
+
+ if (!IS_ERR(priv->anaswvdd.regmap)) {
+ /* direct write anaswvdd value (or use clear register) */
+ if (anaswvdd || IS_ERR(priv->anaswvdd_clr.regmap))
+ ret = regmap_update_bits(priv->anaswvdd.regmap,
+ priv->anaswvdd.reg,
+ priv->anaswvdd.mask, anaswvdd);
+ else
+ ret = regmap_update_bits(priv->anaswvdd_clr.regmap,
+ priv->anaswvdd_clr.reg,
+ priv->anaswvdd_clr.mask,
+ priv->anaswvdd_clr.mask);
+ if (ret) {
+ dev_err(dev, "can't access anaswvdd, %d\n", ret);
+ goto booster_dis;
+ }
+ }
+
+ return ret;
+
+booster_dis:
+ if (IS_ERR(priv->vbooster_clr.regmap))
+ regmap_update_bits(priv->vbooster.regmap, priv->vbooster.reg,
+ priv->vbooster.mask, 0);
+ else
+ regmap_update_bits(priv->vbooster_clr.regmap,
+ priv->vbooster_clr.reg,
+ priv->vbooster_clr.mask,
+ priv->vbooster_clr.mask);
+vdd_dis:
+ if (!IS_ERR(priv->vdd) && !IS_ERR(priv->anaswvdd.regmap))
+ regulator_disable(priv->vdd);
+vdda_dis:
+ regulator_disable(priv->vdda);
+
+ return ret;
+}
+
+static void stm32_adc_switches_supply_dis(struct device *dev)
+{
+ struct stm32_adc_common *common = dev_get_drvdata(dev);
+ struct stm32_adc_priv *priv = to_stm32_adc_priv(common);
+
+ if (IS_ERR(priv->vdda) || IS_ERR(priv->vbooster.regmap))
+ return;
+
+ if (!IS_ERR(priv->anaswvdd.regmap)) {
+ if (IS_ERR(priv->anaswvdd_clr.regmap))
+ regmap_update_bits(priv->anaswvdd.regmap,
+ priv->anaswvdd.reg,
+ priv->anaswvdd.mask, 0);
+ else
+ regmap_update_bits(priv->anaswvdd_clr.regmap,
+ priv->anaswvdd_clr.reg,
+ priv->anaswvdd_clr.mask,
+ priv->anaswvdd_clr.mask);
+ }
+
+ if (IS_ERR(priv->vbooster_clr.regmap))
+ regmap_update_bits(priv->vbooster.regmap, priv->vbooster.reg,
+ priv->vbooster.mask, 0);
+ else
+ regmap_update_bits(priv->vbooster_clr.regmap,
+ priv->vbooster_clr.reg,
+ priv->vbooster_clr.mask,
+ priv->vbooster_clr.mask);
+
+ if (!IS_ERR(priv->vdd) && !IS_ERR(priv->anaswvdd.regmap))
+ regulator_disable(priv->vdd);
+
+ regulator_disable(priv->vdda);
+}
+
static int stm32_adc_core_hw_start(struct device *dev)
{
struct stm32_adc_common *common = dev_get_drvdata(dev);
struct stm32_adc_priv *priv = to_stm32_adc_priv(common);
int ret;
+ ret = stm32_adc_switches_supply_en(dev);
+ if (ret < 0)
+ return ret;
+
ret = regulator_enable(priv->vref);
if (ret < 0) {
dev_err(dev, "vref enable failed\n");
- return ret;
+ goto err_switches_disable;
}
if (priv->bclk) {
@@ -604,6 +803,8 @@ static int stm32_adc_core_hw_start(struct device *dev)
clk_disable_unprepare(priv->bclk);
err_regulator_disable:
regulator_disable(priv->vref);
+err_switches_disable:
+ stm32_adc_switches_supply_dis(dev);
return ret;
}
@@ -620,6 +821,68 @@ static void stm32_adc_core_hw_stop(struct device *dev)
if (priv->bclk)
clk_disable_unprepare(priv->bclk);
regulator_disable(priv->vref);
+ stm32_adc_switches_supply_dis(dev);
+}
+
+static int stm32_adc_get_syscfg_cell(struct device_node *np,
+ struct stm32_adc_syscfg *syscfg,
+ const char * prop)
+{
+ int ret;
+
+ syscfg->regmap = syscon_regmap_lookup_by_phandle(np, prop);
+ if (IS_ERR(syscfg->regmap)) {
+ pr_debug("FGA: %s %ld\n", prop, PTR_ERR(syscfg->regmap));
+ /* Optional */
+ if (PTR_ERR(syscfg->regmap) == -ENODEV)
+ return 0;
+ else
+ return PTR_ERR(syscfg->regmap);
+ }
+
+ ret = of_property_read_u32_index(np, prop, 1, &syscfg->reg);
+ if (ret)
+ return ret;
+
+ return of_property_read_u32_index(np, prop, 2, &syscfg->mask);
+}
+
+static int stm32_adc_syscfg_probe(struct platform_device *pdev,
+ struct stm32_adc_priv *priv)
+{
+ struct device_node *np = pdev->dev.of_node;
+ int ret;
+
+ /* Start to lookup BOOSTE/EN_BOOSTER first, for stm32h7/stm32mp1 */
+ ret = stm32_adc_get_syscfg_cell(np, &priv->vbooster,
+ "st,syscfg-vbooster");
+ if (ret)
+ return ret;
+
+ /* Continue with stm32mp1 EN_BOOSTER/ANASWVDD set and clear bits*/
+ ret = stm32_adc_get_syscfg_cell(np, &priv->vbooster_clr,
+ "st,syscfg-vbooster-clr");
+ if (ret)
+ return ret;
+
+ ret = stm32_adc_get_syscfg_cell(np, &priv->anaswvdd,
+ "st,syscfg-anaswvdd");
+ if (ret)
+ return ret;
+
+ ret = stm32_adc_get_syscfg_cell(np, &priv->anaswvdd_clr,
+ "st,syscfg-anaswvdd-clr");
+ if (ret)
+ return ret;
+
+ /* Sanity, check syscfg set/clear pairs are filled in */
+ if (priv->cfg->has_syscfg_clr && ((!IS_ERR(priv->vbooster.regmap) &&
+ IS_ERR(priv->vbooster_clr.regmap)) ||
+ (!IS_ERR(priv->anaswvdd.regmap) &&
+ IS_ERR(priv->anaswvdd_clr.regmap))))
+ return -EINVAL;
+
+ return ret;
}
static int stm32_adc_probe(struct platform_device *pdev)
@@ -657,6 +920,24 @@ static int stm32_adc_probe(struct platform_device *pdev)
return ret;
}
+ priv->vdda = devm_regulator_get_optional(&pdev->dev, "vdda");
+ if (IS_ERR(priv->vdda)) {
+ ret = PTR_ERR(priv->vdda);
+ if (ret != -ENODEV) {
+ dev_err(&pdev->dev, "vdda get failed, %d\n", ret);
+ return ret;
+ }
+ }
+
+ priv->vdd = devm_regulator_get_optional(&pdev->dev, "vdd");
+ if (IS_ERR(priv->vdd)) {
+ ret = PTR_ERR(priv->vdd);
+ if (ret != -ENODEV) {
+ dev_err(&pdev->dev, "vdd get failed, %d\n", ret);
+ return ret;
+ }
+ }
+
priv->aclk = devm_clk_get(&pdev->dev, "adc");
if (IS_ERR(priv->aclk)) {
ret = PTR_ERR(priv->aclk);
@@ -677,8 +958,17 @@ static int stm32_adc_probe(struct platform_device *pdev)
priv->bclk = NULL;
}
+ ret = stm32_adc_syscfg_probe(pdev, priv);
+ if (ret) {
+ if (ret != -EPROBE_DEFER)
+ dev_err(&pdev->dev, "Can't probe syscfg: %d\n", ret);
+ return ret;
+ }
+
pm_runtime_get_noresume(dev);
pm_runtime_set_active(dev);
+ pm_runtime_set_autosuspend_delay(dev, STM32_ADC_CORE_SLEEP_DELAY_MS);
+ pm_runtime_use_autosuspend(dev);
pm_runtime_enable(dev);
ret = stm32_adc_core_hw_start(dev);
@@ -718,7 +1008,8 @@ static int stm32_adc_probe(struct platform_device *pdev)
goto err_irq_remove;
}
- pm_runtime_put(dev);
+ pm_runtime_mark_last_busy(dev);
+ pm_runtime_put_autosuspend(dev);
return 0;
@@ -789,6 +1080,7 @@ static const struct stm32_adc_priv_cfg stm32h7_adc_priv_cfg = {
static const struct stm32_adc_priv_cfg stm32mp1_adc_priv_cfg = {
.regs = &stm32h7_adc_common_regs,
.clk_sel = stm32h7_adc_clk_sel,
+ .has_syscfg_clr = true,
.max_clk_rate_hz = 40000000,
.exti_trigs = stm32h7_adc_exti_trigs,
};
diff --git a/drivers/iio/adc/stm32-adc.c b/drivers/iio/adc/stm32-adc.c
index 980355e..13d2e3c 100644
--- a/drivers/iio/adc/stm32-adc.c
+++ b/drivers/iio/adc/stm32-adc.c
@@ -201,7 +201,7 @@ enum stm32h7_adc_dmngt {
#define STM32_ADC_MAX_SMP 7 /* SMPx range is [0..7] */
#define STM32_ADC_TIMEOUT_US 100000
#define STM32_ADC_TIMEOUT (msecs_to_jiffies(STM32_ADC_TIMEOUT_US / 1000))
-#define STM32_ADC_AUTO_SUSPEND_DELAY_MS 2000
+#define STM32_ADC_HW_STOP_DELAY_MS 100
#define STM32_DMA_BUFFER_SIZE PAGE_SIZE
@@ -2783,7 +2783,7 @@ static int stm32_adc_probe(struct platform_device *pdev)
/* Get stm32-adc-core PM online */
pm_runtime_get_noresume(dev);
pm_runtime_set_active(dev);
- pm_runtime_set_autosuspend_delay(dev, STM32_ADC_AUTO_SUSPEND_DELAY_MS);
+ pm_runtime_set_autosuspend_delay(dev, STM32_ADC_HW_STOP_DELAY_MS);
pm_runtime_use_autosuspend(dev);
pm_runtime_enable(dev);
--
2.7.4

View File

@ -0,0 +1,130 @@
From 73813749b7f0f33a59eb8f321f7d0f9d88dbfbb3 Mon Sep 17 00:00:00 2001
From: Christophe Priouzeau <christophe.priouzeau@st.com>
Date: Mon, 26 Nov 2018 14:46:52 +0100
Subject: [PATCH 31/52] ARM-stm32mp1-r0-rc2-DEFCONFIG
---
arch/arm/configs/fragment-02-multiv7_addons.config | 42 +++++++++++++++++++++-
1 file changed, 41 insertions(+), 1 deletion(-)
diff --git a/arch/arm/configs/fragment-02-multiv7_addons.config b/arch/arm/configs/fragment-02-multiv7_addons.config
index c91840c..4470d85 100644
--- a/arch/arm/configs/fragment-02-multiv7_addons.config
+++ b/arch/arm/configs/fragment-02-multiv7_addons.config
@@ -3,6 +3,7 @@
#
CONFIG_POSIX_MQUEUE=y
CONFIG_USELIB=y
+CONFIG_FUTEX=y
#
# RCU Subsystem
@@ -153,6 +154,12 @@ CONFIG_SERIAL_NONSTANDARD=y
# CONFIG_SERIAL_8250 is not set
#
+# Touchscreen drivers
+#
+CONFIG_TOUCHSCREEN_EDT_FT5X06=m
+CONFIG_TOUCHSCREEN_GOODIX=m
+
+#
# Non-8250 serial port support
#
# CONFIG_SERIAL_BCM63XX is not set
@@ -179,6 +186,7 @@ CONFIG_SERIAL_NONSTANDARD=y
#
# SPI Master Controller Drivers
#
+CONFIG_SPI_STM32=y
CONFIG_SPI_STM32_QSPI=y
#
@@ -237,6 +245,7 @@ CONFIG_PROTECTION_CONSUMER=y
#
# USB HDMI CEC adapters
#
+CONFIG_VIDEO_STM32_HDMI_CEC=m
#
# Media ancillary drivers (tuners, sensors, i2c, spi, frontends)
@@ -246,6 +255,7 @@ CONFIG_PROTECTION_CONSUMER=y
#
# Camera sensor devices
#
+CONFIG_VIDEO_OV5640=y
#
# Graphics support
@@ -261,10 +271,14 @@ CONFIG_PROTECTION_CONSUMER=y
#
# Display Panels
#
+CONFIG_DRM_PANEL_ORISETECH_OTM8009A=m
+CONFIG_DRM_PANEL_RAYDIUM_RM68200=m
#
# Display Interface Bridges
#
+CONFIG_VIDEO_ADV7511=m
+CONFIG_DRM_SII902X=m
#
# Frame buffer hardware drivers
@@ -273,15 +287,34 @@ CONFIG_PROTECTION_CONSUMER=y
#
# Console display driver support
#
+CONFIG_DRM_STM=m
+CONFIG_DRM_STM_DSI=m
+
+#
+# Backlight support
+#
+CONFIG_BACKLIGHT_GPIO=y
#
# HD-Audio
#
+CONFIG_SOUND=y
+CONFIG_SND=y
+CONFIG_SND_SOC=y
+CONFIG_SND_SOC_STM32_SAI=y
+CONFIG_SND_SOC_STM32_I2S=y
+CONFIG_SND_SOC_STM32_SPDIFRX=y
+CONFIG_SND_SOC_STM32_DFSDM=y
+CONFIG_SND_AUDIO_GRAPH_CARD=y
#
# CODEC drivers
#
-
+CONFIG_MFD_WM8994=y
+CONFIG_SND_SOC_WM8994=y
+CONFIG_SND_SOC_DMIC=y
+CONFIG_SND_SOC_CS42L42=y
+CONFIG_SND_SOC_CS42L51_I2C=y
#
# USB Device Class drivers
@@ -300,6 +333,7 @@ CONFIG_PROTECTION_CONSUMER=y
#
# Gadget/Dual-role mode requires USB Gadget support to be enabled
#
+CONFIG_USB_CONFIGFS=y
#
# USB Physical Layer drivers
@@ -460,3 +494,9 @@ CONFIG_STM32_ADC_TEMP=y
# STM32 DAC
#
CONFIG_STM32_DAC=y
+
+#
+# STM32 HSEM
+#
+CONFIG_HWSPINLOCK=y
+CONFIG_HWSPINLOCK_STM32=y
--
2.7.4

View File

@ -0,0 +1,76 @@
From 1028166948f7116f4dcddc74094125db0a7595c8 Mon Sep 17 00:00:00 2001
From: Romuald JEANNE <romuald.jeanne@st.com>
Date: Mon, 10 Dec 2018 15:34:56 +0100
Subject: [PATCH 32/52] ARM: stm32mp1-r0-rc3: DMA
---
drivers/dma/stm32-dma.c | 11 +++++++----
1 file changed, 7 insertions(+), 4 deletions(-)
diff --git a/drivers/dma/stm32-dma.c b/drivers/dma/stm32-dma.c
index 4830f8e..1f9d606 100644
--- a/drivers/dma/stm32-dma.c
+++ b/drivers/dma/stm32-dma.c
@@ -212,6 +212,7 @@ struct stm32_dma_desc {
u32 num_sgs;
dma_addr_t dma_buf;
void *dma_buf_cpu;
+ u32 dma_buf_size;
struct stm32_dma_sg_req sg_req[];
};
@@ -1224,6 +1225,7 @@ static int stm32_dma_mdma_prep_slave_sg(struct stm32_dma_chan *chan,
&desc->dma_buf);
if (!desc->dma_buf_cpu)
return -ENOMEM;
+ desc->dma_buf_size = chan->sram_size;
sram_period = chan->sram_size / 2;
@@ -1316,7 +1318,7 @@ static int stm32_dma_mdma_prep_slave_sg(struct stm32_dma_chan *chan,
}
free_alloc:
gen_pool_free(dmadev->sram_pool, (unsigned long)desc->dma_buf_cpu,
- chan->sram_size);
+ desc->dma_buf_size);
return ret;
}
@@ -1437,7 +1439,7 @@ static struct dma_async_tx_descriptor *stm32_dma_prep_slave_sg(
gen_pool_free(dmadev->sram_pool,
(unsigned long)desc->dma_buf_cpu,
- chan->sram_size);
+ desc->dma_buf_size);
}
kfree(desc);
@@ -1462,6 +1464,7 @@ static int stm32_dma_mdma_prep_dma_cyclic(struct stm32_dma_chan *chan,
&desc->dma_buf);
if (!desc->dma_buf_cpu)
return -ENOMEM;
+ desc->dma_buf_size = 2 * chan->sram_size;
memset(&config, 0, sizeof(config));
mem = buf_addr;
@@ -1511,7 +1514,7 @@ static int stm32_dma_mdma_prep_dma_cyclic(struct stm32_dma_chan *chan,
err:
gen_pool_free(dmadev->sram_pool,
(unsigned long)desc->dma_buf_cpu,
- chan->sram_size);
+ desc->dma_buf_size);
return ret;
}
@@ -1813,7 +1816,7 @@ static void stm32_dma_desc_free(struct virt_dma_desc *vdesc)
gen_pool_free(dmadev->sram_pool,
(unsigned long)desc->dma_buf_cpu,
- chan->sram_size);
+ desc->dma_buf_size);
}
kfree(desc);
--
2.7.4

View File

@ -0,0 +1,133 @@
From dc9ea19f397651b7671ec4268a12d3f49e2bbda0 Mon Sep 17 00:00:00 2001
From: Romuald JEANNE <romuald.jeanne@st.com>
Date: Mon, 10 Dec 2018 15:48:07 +0100
Subject: [PATCH 33/52] ARM: stm32mp1-r0-rc3: DISPLAY
---
drivers/gpu/drm/bridge/sii902x.c | 31 +++++++++++++++++++++++++++----
drivers/gpu/drm/drm_gem.c | 6 ------
2 files changed, 27 insertions(+), 10 deletions(-)
diff --git a/drivers/gpu/drm/bridge/sii902x.c b/drivers/gpu/drm/bridge/sii902x.c
index 512eb03..170657a 100644
--- a/drivers/gpu/drm/bridge/sii902x.c
+++ b/drivers/gpu/drm/bridge/sii902x.c
@@ -397,7 +397,6 @@ static void sii902x_bridge_disable(struct drm_bridge *bridge)
regmap_update_bits(sii902x->regmap, SII902X_SYS_CTRL_DATA,
SII902X_SYS_CTRL_PWR_DWN,
SII902X_SYS_CTRL_PWR_DWN);
- pinctrl_pm_select_sleep_state(&sii902x->i2c->dev);
}
static void sii902x_bridge_enable(struct drm_bridge *bridge)
@@ -405,7 +404,6 @@ static void sii902x_bridge_enable(struct drm_bridge *bridge)
struct sii902x *sii902x = bridge_to_sii902x(bridge);
bool hdmi_mode;
- pinctrl_pm_select_default_state(&sii902x->i2c->dev);
regmap_update_bits(sii902x->regmap, SII902X_PWR_STATE_CTRL,
SII902X_AVI_POWER_STATE_MSK,
SII902X_AVI_POWER_STATE_D(0));
@@ -430,8 +428,17 @@ static void sii902x_bridge_mode_set(struct drm_bridge *bridge,
struct regmap *regmap = sii902x->regmap;
u8 buf[HDMI_INFOFRAME_SIZE(AVI)];
struct hdmi_avi_infoframe frame;
+ unsigned int status = 0;
int ret;
+ DRM_DEBUG_DRIVER("\n");
+
+ regmap_read(sii902x->regmap, SII902X_INT_STATUS, &status);
+
+ /* due to old tv, need to restore pinctrl as soon as possible */
+ if (status & SII902X_PLUGGED_STATUS)
+ pinctrl_pm_select_default_state(&sii902x->i2c->dev);
+
buf[0] = adj->clock;
buf[1] = adj->clock >> 8;
buf[2] = adj->vrefresh;
@@ -819,6 +826,11 @@ static irqreturn_t sii902x_interrupt(int irq, void *data)
regmap_read(sii902x->regmap, SII902X_INT_STATUS, &status);
regmap_write(sii902x->regmap, SII902X_INT_STATUS, status);
+ if (status & SII902X_PLUGGED_STATUS)
+ pinctrl_pm_select_default_state(&sii902x->i2c->dev);
+ else
+ pinctrl_pm_select_sleep_state(&sii902x->i2c->dev);
+
if ((status & SII902X_HOTPLUG_EVENT) && sii902x->bridge.dev)
drm_helper_hpd_irq_event(sii902x->bridge.dev);
@@ -1045,14 +1057,15 @@ static int sii902x_probe(struct i2c_client *client,
sii902x_i2c_bypass_deselect);
if (!sii902x->i2cmux) {
dev_err(dev, "failed to allocate I2C mux\n");
- return -ENOMEM;
+ ret = -ENOMEM;
+ goto err_disable_regulator;
}
sii902x->i2cmux->priv = sii902x;
ret = i2c_mux_add_adapter(sii902x->i2cmux, 0, 0, 0);
if (ret) {
dev_err(dev, "Couldn't add i2c mux adapter\n");
- return ret;
+ goto err_disable_regulator;
}
sii902x_register_audio_driver(dev, sii902x);
@@ -1060,6 +1073,7 @@ static int sii902x_probe(struct i2c_client *client,
return 0;
err_disable_regulator:
+ pinctrl_pm_select_sleep_state(&sii902x->i2c->dev);
regulator_bulk_disable(ARRAY_SIZE(sii902x->supplies),
sii902x->supplies);
@@ -1095,6 +1109,8 @@ static int sii902x_pm_suspend(struct device *dev)
regulator_bulk_disable(ARRAY_SIZE(sii902x->supplies),
sii902x->supplies);
+ pinctrl_pm_select_sleep_state(&sii902x->i2c->dev);
+
return 0;
}
@@ -1109,10 +1125,17 @@ static int sii902x_pm_resume(struct device *dev)
.len = 2,
.buf = data,
};
+ unsigned int status = 0;
int ret;
DRM_DEBUG_DRIVER("\n");
+ regmap_read(sii902x->regmap, SII902X_INT_STATUS, &status);
+
+ /* due to old tv, need to restore pinctrl as soon as possible */
+ if (status & SII902X_PLUGGED_STATUS)
+ pinctrl_pm_select_default_state(&sii902x->i2c->dev);
+
ret = regulator_bulk_enable(ARRAY_SIZE(sii902x->supplies),
sii902x->supplies);
if (ret) {
diff --git a/drivers/gpu/drm/drm_gem.c b/drivers/gpu/drm/drm_gem.c
index bf90625..c7217b1 100644
--- a/drivers/gpu/drm/drm_gem.c
+++ b/drivers/gpu/drm/drm_gem.c
@@ -326,12 +326,6 @@ int drm_gem_dumb_map_offset(struct drm_file *file, struct drm_device *dev,
if (!obj)
return -ENOENT;
- /* Don't allow imported objects to be mapped */
- if (obj->import_attach) {
- ret = -EINVAL;
- goto out;
- }
-
ret = drm_gem_create_mmap_offset(obj);
if (ret)
goto out;
--
2.7.4

View File

@ -0,0 +1,169 @@
From f7da805ac84601d1dbbaf51e8f080844e1e5ae4e Mon Sep 17 00:00:00 2001
From: Romuald JEANNE <romuald.jeanne@st.com>
Date: Mon, 10 Dec 2018 15:40:00 +0100
Subject: [PATCH 34/52] ARM: stm32mp1-r0-rc3: ETH
---
.../devicetree/bindings/net/stm32-dwmac.txt | 4 +--
drivers/net/ethernet/stmicro/stmmac/dwmac-stm32.c | 36 ++++++++++++++--------
drivers/net/ethernet/stmicro/stmmac/stmmac_main.c | 20 ++++++------
3 files changed, 36 insertions(+), 24 deletions(-)
diff --git a/Documentation/devicetree/bindings/net/stm32-dwmac.txt b/Documentation/devicetree/bindings/net/stm32-dwmac.txt
index f42dc68..5f6a6ba 100644
--- a/Documentation/devicetree/bindings/net/stm32-dwmac.txt
+++ b/Documentation/devicetree/bindings/net/stm32-dwmac.txt
@@ -14,8 +14,7 @@ Required properties:
- clock-names: Should be "stmmaceth" for the host clock.
Should be "mac-clk-tx" for the MAC TX clock.
Should be "mac-clk-rx" for the MAC RX clock.
- For MPU family need to add also "ethstp" for power mode clock and,
- "syscfg-clk" for SYSCFG clock.
+ For MPU family need to add also "ethstp" for power mode clock.
- interrupt-names: Should contain a list of interrupt names corresponding to
the interrupts in the interrupts property, if available.
Should be "macirq" for the main MAC IRQ
@@ -25,6 +24,7 @@ Required properties:
Optional properties:
- clock-names: For MPU family "eth-ck" for PHY without quartz
+ "syscfg-clk" for SYSCFG clock.
- st,eth_clk_sel (boolean) : set this property in RGMII PHY when you do not want use 125Mhz
- st,eth_ref_clk_sel (boolean) : set this property in RMII mode when you have PHY without crystal 50MHz
diff --git a/drivers/net/ethernet/stmicro/stmmac/dwmac-stm32.c b/drivers/net/ethernet/stmicro/stmmac/dwmac-stm32.c
index 545b168..8b4ca12 100644
--- a/drivers/net/ethernet/stmicro/stmmac/dwmac-stm32.c
+++ b/drivers/net/ethernet/stmicro/stmmac/dwmac-stm32.c
@@ -153,23 +153,32 @@ static int stm32mp1_clk_prepare(struct stm32_dwmac *dwmac, bool prepare)
int ret = 0;
if (prepare) {
- ret = clk_prepare_enable(dwmac->syscfg_clk);
- if (ret)
- return ret;
-
+ if (dwmac->syscfg_clk) {
+ ret = clk_prepare_enable(dwmac->syscfg_clk);
+ if (ret)
+ return ret;
+ }
if (dwmac->clk_eth_ck) {
ret = clk_prepare_enable(dwmac->clk_eth_ck);
if (ret) {
- clk_disable_unprepare(dwmac->syscfg_clk);
+ if (dwmac->syscfg_clk)
+ goto unprepare_syscfg;
return ret;
}
}
} else {
- clk_disable_unprepare(dwmac->syscfg_clk);
+ if (dwmac->syscfg_clk)
+ clk_disable_unprepare(dwmac->syscfg_clk);
+
if (dwmac->clk_eth_ck)
clk_disable_unprepare(dwmac->clk_eth_ck);
}
return ret;
+
+unprepare_syscfg:
+ clk_disable_unprepare(dwmac->syscfg_clk);
+
+ return ret;
}
static int stm32mp1_set_mode(struct plat_stmmacenet_data *plat_dat)
@@ -209,8 +218,8 @@ static int stm32mp1_set_mode(struct plat_stmmacenet_data *plat_dat)
}
/* Need to update PMCCLRR (clear register) */
- ret = regmap_update_bits(dwmac->regmap, reg + SYSCFG_PMCCLRR_OFFSET,
- dwmac->ops->syscfg_eth_mask, ~val);
+ ret = regmap_write(dwmac->regmap, reg + SYSCFG_PMCCLRR_OFFSET,
+ dwmac->ops->syscfg_eth_mask);
/* Update PMCSETR (set register) */
return regmap_update_bits(dwmac->regmap, reg,
@@ -318,11 +327,13 @@ static int stm32mp1_parse_data(struct stm32_dwmac *dwmac,
return PTR_ERR(dwmac->clk_ethstp);
}
- /* Clock for sysconfig */
+ /* Optional Clock for sysconfig */
dwmac->syscfg_clk = devm_clk_get(dev, "syscfg-clk");
if (IS_ERR(dwmac->syscfg_clk)) {
- dev_err(dev, "No syscfg clock provided...\n");
- return PTR_ERR(dwmac->syscfg_clk);
+ err = PTR_ERR(dwmac->syscfg_clk);
+ if (err != -ENOENT)
+ return err;
+ dwmac->syscfg_clk = NULL;
}
/* Get IRQ information early to have an ability to ask for deferred
@@ -431,7 +442,8 @@ static int stm32mp1_suspend(struct stm32_dwmac *dwmac)
return ret;
clk_disable_unprepare(dwmac->clk_tx);
- clk_disable_unprepare(dwmac->syscfg_clk);
+ if (dwmac->syscfg_clk)
+ clk_disable_unprepare(dwmac->syscfg_clk);
if (dwmac->clk_eth_ck)
clk_disable_unprepare(dwmac->clk_eth_ck);
diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c b/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c
index 75896d6..281d9c7 100644
--- a/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c
+++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c
@@ -2547,12 +2547,6 @@ static int stmmac_hw_setup(struct net_device *dev, bool init_ptp)
netdev_warn(priv->dev, "PTP init failed\n");
}
-#ifdef CONFIG_DEBUG_FS
- ret = stmmac_init_fs(dev);
- if (ret < 0)
- netdev_warn(priv->dev, "%s: failed debugFS registration\n",
- __func__);
-#endif
priv->tx_lpi_timer = STMMAC_DEFAULT_TWT_LS;
if (priv->use_riwt) {
@@ -2753,10 +2747,6 @@ static int stmmac_release(struct net_device *dev)
netif_carrier_off(dev);
-#ifdef CONFIG_DEBUG_FS
- stmmac_exit_fs(dev);
-#endif
-
stmmac_release_ptp(priv);
return 0;
@@ -4394,6 +4384,13 @@ int stmmac_dvr_probe(struct device *device,
goto error_netdev_register;
}
+#ifdef CONFIG_DEBUG_FS
+ ret = stmmac_init_fs(ndev);
+ if (ret < 0)
+ netdev_warn(priv->dev, "%s: failed debugFS registration\n",
+ __func__);
+#endif
+
return ret;
error_netdev_register:
@@ -4429,6 +4426,9 @@ int stmmac_dvr_remove(struct device *dev)
netdev_info(priv->dev, "%s: removing driver", __func__);
+#ifdef CONFIG_DEBUG_FS
+ stmmac_exit_fs(ndev);
+#endif
stmmac_stop_all_dma(priv);
stmmac_mac_set(priv, priv->ioaddr, false);
--
2.7.4

View File

@ -0,0 +1,479 @@
From 461aa8f3143d009efd0365889bddf247cfeafdce Mon Sep 17 00:00:00 2001
From: Romuald JEANNE <romuald.jeanne@st.com>
Date: Mon, 10 Dec 2018 15:35:33 +0100
Subject: [PATCH 35/52] ARM: stm32mp1-r0-rc3: IIO
---
drivers/iio/adc/stm32-adc-core.c | 35 +++++-----
drivers/iio/dac/stm32-dac-core.c | 142 ++++++++++++++++++++++++++++++---------
drivers/iio/dac/stm32-dac.c | 96 +++++++++++++++++++++++++-
3 files changed, 220 insertions(+), 53 deletions(-)
diff --git a/drivers/iio/adc/stm32-adc-core.c b/drivers/iio/adc/stm32-adc-core.c
index 6234456..ed64bb0 100644
--- a/drivers/iio/adc/stm32-adc-core.c
+++ b/drivers/iio/adc/stm32-adc-core.c
@@ -677,10 +677,9 @@ static int stm32_adc_switches_supply_en(struct device *dev)
priv->vbooster.reg,
priv->vbooster.mask, en_booster);
else
- ret = regmap_update_bits(priv->vbooster_clr.regmap,
- priv->vbooster_clr.reg,
- priv->vbooster_clr.mask,
- priv->vbooster_clr.mask);
+ ret = regmap_write(priv->vbooster_clr.regmap,
+ priv->vbooster_clr.reg,
+ priv->vbooster_clr.mask);
if (ret) {
dev_err(dev, "can't access voltage booster, %d\n", ret);
goto vdd_dis;
@@ -697,10 +696,9 @@ static int stm32_adc_switches_supply_en(struct device *dev)
priv->anaswvdd.reg,
priv->anaswvdd.mask, anaswvdd);
else
- ret = regmap_update_bits(priv->anaswvdd_clr.regmap,
- priv->anaswvdd_clr.reg,
- priv->anaswvdd_clr.mask,
- priv->anaswvdd_clr.mask);
+ ret = regmap_write(priv->anaswvdd_clr.regmap,
+ priv->anaswvdd_clr.reg,
+ priv->anaswvdd_clr.mask);
if (ret) {
dev_err(dev, "can't access anaswvdd, %d\n", ret);
goto booster_dis;
@@ -714,10 +712,9 @@ static int stm32_adc_switches_supply_en(struct device *dev)
regmap_update_bits(priv->vbooster.regmap, priv->vbooster.reg,
priv->vbooster.mask, 0);
else
- regmap_update_bits(priv->vbooster_clr.regmap,
- priv->vbooster_clr.reg,
- priv->vbooster_clr.mask,
- priv->vbooster_clr.mask);
+ regmap_write(priv->vbooster_clr.regmap,
+ priv->vbooster_clr.reg,
+ priv->vbooster_clr.mask);
vdd_dis:
if (!IS_ERR(priv->vdd) && !IS_ERR(priv->anaswvdd.regmap))
regulator_disable(priv->vdd);
@@ -741,20 +738,18 @@ static void stm32_adc_switches_supply_dis(struct device *dev)
priv->anaswvdd.reg,
priv->anaswvdd.mask, 0);
else
- regmap_update_bits(priv->anaswvdd_clr.regmap,
- priv->anaswvdd_clr.reg,
- priv->anaswvdd_clr.mask,
- priv->anaswvdd_clr.mask);
+ regmap_write(priv->anaswvdd_clr.regmap,
+ priv->anaswvdd_clr.reg,
+ priv->anaswvdd_clr.mask);
}
if (IS_ERR(priv->vbooster_clr.regmap))
regmap_update_bits(priv->vbooster.regmap, priv->vbooster.reg,
priv->vbooster.mask, 0);
else
- regmap_update_bits(priv->vbooster_clr.regmap,
- priv->vbooster_clr.reg,
- priv->vbooster_clr.mask,
- priv->vbooster_clr.mask);
+ regmap_write(priv->vbooster_clr.regmap,
+ priv->vbooster_clr.reg,
+ priv->vbooster_clr.mask);
if (!IS_ERR(priv->vdd) && !IS_ERR(priv->anaswvdd.regmap))
regulator_disable(priv->vdd);
diff --git a/drivers/iio/dac/stm32-dac-core.c b/drivers/iio/dac/stm32-dac-core.c
index d0fb312..280322b 100644
--- a/drivers/iio/dac/stm32-dac-core.c
+++ b/drivers/iio/dac/stm32-dac-core.c
@@ -11,6 +11,7 @@
#include <linux/delay.h>
#include <linux/module.h>
#include <linux/of_platform.h>
+#include <linux/pm_runtime.h>
#include <linux/regulator/consumer.h>
#include <linux/reset.h>
@@ -50,6 +51,41 @@ static const struct regmap_config stm32_dac_regmap_cfg = {
.max_register = 0x3fc,
};
+static int stm32_dac_core_hw_start(struct device *dev)
+{
+ struct stm32_dac_common *common = dev_get_drvdata(dev);
+ struct stm32_dac_priv *priv = to_stm32_dac_priv(common);
+ int ret;
+
+ ret = regulator_enable(priv->vref);
+ if (ret < 0) {
+ dev_err(dev, "vref enable failed: %d\n", ret);
+ return ret;
+ }
+
+ ret = clk_prepare_enable(priv->pclk);
+ if (ret < 0) {
+ dev_err(dev, "pclk enable failed: %d\n", ret);
+ goto err_regulator_disable;
+ }
+
+ return 0;
+
+err_regulator_disable:
+ regulator_disable(priv->vref);
+
+ return ret;
+}
+
+static void stm32_dac_core_hw_stop(struct device *dev)
+{
+ struct stm32_dac_common *common = dev_get_drvdata(dev);
+ struct stm32_dac_priv *priv = to_stm32_dac_priv(common);
+
+ clk_disable_unprepare(priv->pclk);
+ regulator_disable(priv->vref);
+}
+
static int stm32_dac_probe(struct platform_device *pdev)
{
struct device *dev = &pdev->dev;
@@ -66,6 +102,8 @@ static int stm32_dac_probe(struct platform_device *pdev)
priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
if (!priv)
return -ENOMEM;
+ platform_set_drvdata(pdev, &priv->common);
+
cfg = (const struct stm32_dac_cfg *)
of_match_device(dev->driver->of_match_table, dev)->data;
@@ -74,11 +112,19 @@ static int stm32_dac_probe(struct platform_device *pdev)
if (IS_ERR(mmio))
return PTR_ERR(mmio);
- regmap = devm_regmap_init_mmio(dev, mmio, &stm32_dac_regmap_cfg);
+ regmap = devm_regmap_init_mmio_clk(dev, "pclk", mmio,
+ &stm32_dac_regmap_cfg);
if (IS_ERR(regmap))
return PTR_ERR(regmap);
priv->common.regmap = regmap;
+ priv->pclk = devm_clk_get(dev, "pclk");
+ if (IS_ERR(priv->pclk)) {
+ ret = PTR_ERR(priv->pclk);
+ dev_err(dev, "pclk get failed\n");
+ return ret;
+ }
+
priv->vref = devm_regulator_get(dev, "vref");
if (IS_ERR(priv->vref)) {
ret = PTR_ERR(priv->vref);
@@ -86,33 +132,22 @@ static int stm32_dac_probe(struct platform_device *pdev)
return ret;
}
- ret = regulator_enable(priv->vref);
- if (ret < 0) {
- dev_err(dev, "vref enable failed\n");
- return ret;
- }
+ pm_runtime_get_noresume(dev);
+ pm_runtime_set_active(dev);
+ pm_runtime_enable(dev);
+
+ ret = stm32_dac_core_hw_start(dev);
+ if (ret)
+ goto err_pm_stop;
ret = regulator_get_voltage(priv->vref);
if (ret < 0) {
dev_err(dev, "vref get voltage failed, %d\n", ret);
- goto err_vref;
+ goto err_hw_stop;
}
priv->common.vref_mv = ret / 1000;
dev_dbg(dev, "vref+=%dmV\n", priv->common.vref_mv);
- priv->pclk = devm_clk_get(dev, "pclk");
- if (IS_ERR(priv->pclk)) {
- ret = PTR_ERR(priv->pclk);
- dev_err(dev, "pclk get failed\n");
- goto err_vref;
- }
-
- ret = clk_prepare_enable(priv->pclk);
- if (ret < 0) {
- dev_err(dev, "pclk enable failed\n");
- goto err_vref;
- }
-
priv->rst = devm_reset_control_get_exclusive(dev, NULL);
if (!IS_ERR(priv->rst)) {
reset_control_assert(priv->rst);
@@ -128,39 +163,83 @@ static int stm32_dac_probe(struct platform_device *pdev)
priv->common.hfsel ?
STM32H7_DAC_CR_HFSEL : 0);
if (ret)
- goto err_pclk;
+ goto err_hw_stop;
}
- platform_set_drvdata(pdev, &priv->common);
ret = of_platform_populate(pdev->dev.of_node, NULL, NULL, dev);
if (ret < 0) {
dev_err(dev, "failed to populate DT children\n");
- goto err_pclk;
+ goto err_hw_stop;
}
+ pm_runtime_put(dev);
+
return 0;
-err_pclk:
- clk_disable_unprepare(priv->pclk);
-err_vref:
- regulator_disable(priv->vref);
+err_hw_stop:
+ stm32_dac_core_hw_stop(dev);
+err_pm_stop:
+ pm_runtime_disable(dev);
+ pm_runtime_set_suspended(dev);
+ pm_runtime_put_noidle(dev);
return ret;
}
static int stm32_dac_remove(struct platform_device *pdev)
{
- struct stm32_dac_common *common = platform_get_drvdata(pdev);
+ pm_runtime_get_sync(&pdev->dev);
+ of_platform_depopulate(&pdev->dev);
+ stm32_dac_core_hw_stop(&pdev->dev);
+ pm_runtime_disable(&pdev->dev);
+ pm_runtime_set_suspended(&pdev->dev);
+ pm_runtime_put_noidle(&pdev->dev);
+
+ return 0;
+}
+
+#if defined(CONFIG_PM_SLEEP)
+static int stm32_dac_core_resume(struct device *dev)
+{
+ struct stm32_dac_common *common = dev_get_drvdata(dev);
struct stm32_dac_priv *priv = to_stm32_dac_priv(common);
+ int ret;
- of_platform_depopulate(&pdev->dev);
- clk_disable_unprepare(priv->pclk);
- regulator_disable(priv->vref);
+ /* Unconditionally restore hfsel (maybe lost under low power state) */
+ if (priv->common.hfsel) {
+ ret = regmap_update_bits(priv->common.regmap, STM32_DAC_CR,
+ STM32H7_DAC_CR_HFSEL,
+ STM32H7_DAC_CR_HFSEL);
+ if (ret)
+ return ret;
+ }
+
+ return pm_runtime_force_resume(dev);
+}
+#endif
+
+#if defined(CONFIG_PM)
+static int stm32_dac_core_runtime_suspend(struct device *dev)
+{
+ stm32_dac_core_hw_stop(dev);
return 0;
}
+static int stm32_dac_core_runtime_resume(struct device *dev)
+{
+ return stm32_dac_core_hw_start(dev);
+}
+#endif
+
+static const struct dev_pm_ops stm32_dac_core_pm_ops = {
+ SET_SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend, stm32_dac_core_resume)
+ SET_RUNTIME_PM_OPS(stm32_dac_core_runtime_suspend,
+ stm32_dac_core_runtime_resume,
+ NULL)
+};
+
static const struct stm32_dac_cfg stm32h7_dac_cfg = {
.has_hfsel = true,
};
@@ -182,6 +261,7 @@ static struct platform_driver stm32_dac_driver = {
.driver = {
.name = "stm32-dac-core",
.of_match_table = stm32_dac_of_match,
+ .pm = &stm32_dac_core_pm_ops,
},
};
module_platform_driver(stm32_dac_driver);
diff --git a/drivers/iio/dac/stm32-dac.c b/drivers/iio/dac/stm32-dac.c
index cce26a3..0a8abc5 100644
--- a/drivers/iio/dac/stm32-dac.c
+++ b/drivers/iio/dac/stm32-dac.c
@@ -13,6 +13,7 @@
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/platform_device.h>
+#include <linux/pm_runtime.h>
#include "stm32-dac-core.h"
@@ -20,6 +21,8 @@
#define STM32_DAC_CHANNEL_2 2
#define STM32_DAC_IS_CHAN_1(ch) ((ch) & STM32_DAC_CHANNEL_1)
+#define STM32_DAC_AUTO_SUSPEND_DELAY_MS 2000
+
/**
* struct stm32_dac - private data of DAC driver
* @common: reference to DAC common data
@@ -49,15 +52,34 @@ static int stm32_dac_set_enable_state(struct iio_dev *indio_dev, int ch,
bool enable)
{
struct stm32_dac *dac = iio_priv(indio_dev);
+ struct device *dev = indio_dev->dev.parent;
u32 msk = STM32_DAC_IS_CHAN_1(ch) ? STM32_DAC_CR_EN1 : STM32_DAC_CR_EN2;
u32 en = enable ? msk : 0;
int ret;
+ /* already enabled / disabled ? */
+ mutex_lock(&indio_dev->mlock);
+ ret = stm32_dac_is_enabled(indio_dev, ch);
+ if (ret < 0 || enable == !!ret) {
+ mutex_unlock(&indio_dev->mlock);
+ return ret < 0 ? ret : 0;
+ }
+
+ if (enable) {
+ ret = pm_runtime_get_sync(dev);
+ if (ret < 0) {
+ pm_runtime_put_noidle(dev);
+ mutex_unlock(&indio_dev->mlock);
+ return ret;
+ }
+ }
+
ret = regmap_update_bits(dac->common->regmap, STM32_DAC_CR, msk, en);
+ mutex_unlock(&indio_dev->mlock);
if (ret < 0) {
dev_err(&indio_dev->dev, "%s failed\n", en ?
"Enable" : "Disable");
- return ret;
+ goto err_put_pm;
}
/*
@@ -68,7 +90,20 @@ static int stm32_dac_set_enable_state(struct iio_dev *indio_dev, int ch,
if (en && dac->common->hfsel)
udelay(1);
+ if (!enable) {
+ pm_runtime_mark_last_busy(dev);
+ pm_runtime_put_autosuspend(dev);
+ }
+
return 0;
+
+err_put_pm:
+ if (enable) {
+ pm_runtime_mark_last_busy(dev);
+ pm_runtime_put_autosuspend(dev);
+ }
+
+ return ret;
}
static int stm32_dac_get_value(struct stm32_dac *dac, int channel, int *val)
@@ -272,6 +307,7 @@ static int stm32_dac_chan_of_init(struct iio_dev *indio_dev)
static int stm32_dac_probe(struct platform_device *pdev)
{
struct device_node *np = pdev->dev.of_node;
+ struct device *dev = &pdev->dev;
struct iio_dev *indio_dev;
struct stm32_dac *dac;
int ret;
@@ -296,9 +332,63 @@ static int stm32_dac_probe(struct platform_device *pdev)
if (ret < 0)
return ret;
- return devm_iio_device_register(&pdev->dev, indio_dev);
+ /* Get stm32-dac-core PM online */
+ pm_runtime_get_noresume(dev);
+ pm_runtime_set_active(dev);
+ pm_runtime_set_autosuspend_delay(dev, STM32_DAC_AUTO_SUSPEND_DELAY_MS);
+ pm_runtime_use_autosuspend(dev);
+ pm_runtime_enable(dev);
+
+ ret = iio_device_register(indio_dev);
+ if (ret)
+ goto err_pm_put;
+
+ pm_runtime_mark_last_busy(dev);
+ pm_runtime_put_autosuspend(dev);
+
+ return 0;
+
+err_pm_put:
+ pm_runtime_disable(dev);
+ pm_runtime_set_suspended(dev);
+ pm_runtime_put_noidle(dev);
+
+ return ret;
}
+static int stm32_dac_remove(struct platform_device *pdev)
+{
+ struct iio_dev *indio_dev = platform_get_drvdata(pdev);
+
+ pm_runtime_get_sync(&pdev->dev);
+ iio_device_unregister(indio_dev);
+ pm_runtime_disable(&pdev->dev);
+ pm_runtime_set_suspended(&pdev->dev);
+ pm_runtime_put_noidle(&pdev->dev);
+
+ return 0;
+}
+
+#if defined(CONFIG_PM_SLEEP)
+static int stm32_dac_suspend(struct device *dev)
+{
+ struct iio_dev *indio_dev = dev_get_drvdata(dev);
+ int channel = indio_dev->channels[0].channel;
+ int ret;
+
+ /* Ensure DAC is disabled before suspend */
+ ret = stm32_dac_is_enabled(indio_dev, channel);
+ if (ret)
+ return ret < 0 ? ret : -EBUSY;
+
+ return pm_runtime_force_suspend(dev);
+}
+#endif
+
+static const struct dev_pm_ops stm32_dac_pm_ops = {
+ SET_SYSTEM_SLEEP_PM_OPS(stm32_dac_suspend, pm_runtime_force_resume)
+};
+
static const struct of_device_id stm32_dac_of_match[] = {
{ .compatible = "st,stm32-dac", },
{},
@@ -307,9 +397,11 @@ MODULE_DEVICE_TABLE(of, stm32_dac_of_match);
static struct platform_driver stm32_dac_driver = {
.probe = stm32_dac_probe,
+ .remove = stm32_dac_remove,
.driver = {
.name = "stm32-dac",
.of_match_table = stm32_dac_of_match,
+ .pm = &stm32_dac_pm_ops,
},
};
module_platform_driver(stm32_dac_driver);
--
2.7.4

View File

@ -0,0 +1,135 @@
From adfe9751275d51343a5b7f26ea93246ae617d986 Mon Sep 17 00:00:00 2001
From: Romuald JEANNE <romuald.jeanne@st.com>
Date: Mon, 10 Dec 2018 15:37:06 +0100
Subject: [PATCH 36/52] ARM: stm32mp1-r0-rc3: INPUT TTY
---
.../devicetree/bindings/serial/st,stm32-usart.txt | 1 +
drivers/input/touchscreen/edt-ft5x06.c | 8 +++++++-
drivers/input/touchscreen/goodix.c | 9 +++++++++
drivers/tty/serial/stm32-usart.c | 18 ++++++++++++++++--
4 files changed, 33 insertions(+), 3 deletions(-)
diff --git a/Documentation/devicetree/bindings/serial/st,stm32-usart.txt b/Documentation/devicetree/bindings/serial/st,stm32-usart.txt
index 90ba52f..08b4990 100644
--- a/Documentation/devicetree/bindings/serial/st,stm32-usart.txt
+++ b/Documentation/devicetree/bindings/serial/st,stm32-usart.txt
@@ -14,6 +14,7 @@ Required properties:
- clocks: The input clock of the USART instance
Optional properties:
+- resets: Must contain the phandle to the reset controller.
- pinctrl-names: Set to "default". An additional "sleep" state can be defined
to set pins in sleep state when in low power. In case the device is used as
a wakeup source, "idle" state is defined in order to keep RX pin active.
diff --git a/drivers/input/touchscreen/edt-ft5x06.c b/drivers/input/touchscreen/edt-ft5x06.c
index 1e18ca0..c1c6f2a 100644
--- a/drivers/input/touchscreen/edt-ft5x06.c
+++ b/drivers/input/touchscreen/edt-ft5x06.c
@@ -1033,7 +1033,7 @@ static int edt_ft5x06_ts_probe(struct i2c_client *client,
error = edt_ft5x06_ts_identify(client, tsdata, fw_version);
if (error) {
- dev_err(&client->dev, "touchscreen probe failed\n");
+ dev_dbg(&client->dev, "touchscreen probe failed\n");
return error;
}
@@ -1152,11 +1152,16 @@ static const struct edt_i2c_chip_data edt_ft6236_data = {
.max_support_points = 2,
};
+static const struct edt_i2c_chip_data edt_ft6336_data = {
+ .max_support_points = 2,
+};
+
static const struct i2c_device_id edt_ft5x06_ts_id[] = {
{ .name = "edt-ft5x06", .driver_data = (long)&edt_ft5x06_data },
{ .name = "edt-ft5506", .driver_data = (long)&edt_ft5506_data },
/* Note no edt- prefix for compatibility with the ft6236.c driver */
{ .name = "ft6236", .driver_data = (long)&edt_ft6236_data },
+ { .name = "ft6336", .driver_data = (long)&edt_ft6336_data },
{ /* sentinel */ }
};
MODULE_DEVICE_TABLE(i2c, edt_ft5x06_ts_id);
@@ -1169,6 +1174,7 @@ static const struct of_device_id edt_ft5x06_of_match[] = {
{ .compatible = "edt,edt-ft5506", .data = &edt_ft5506_data },
/* Note focaltech vendor prefix for compatibility with ft6236.c */
{ .compatible = "focaltech,ft6236", .data = &edt_ft6236_data },
+ { .compatible = "focaltech,ft6336", .data = &edt_ft6336_data },
{ /* sentinel */ }
};
MODULE_DEVICE_TABLE(of, edt_ft5x06_of_match);
diff --git a/drivers/input/touchscreen/goodix.c b/drivers/input/touchscreen/goodix.c
index f2d9c2c..9ce8db4 100644
--- a/drivers/input/touchscreen/goodix.c
+++ b/drivers/input/touchscreen/goodix.c
@@ -27,6 +27,7 @@
#include <linux/delay.h>
#include <linux/irq.h>
#include <linux/interrupt.h>
+#include <linux/gpio.h>
#include <linux/slab.h>
#include <linux/acpi.h>
#include <linux/of.h>
@@ -357,6 +358,13 @@ static void goodix_free_irq(struct goodix_ts_data *ts)
static int goodix_request_irq(struct goodix_ts_data *ts)
{
+ int gpio;
+
+ gpio = desc_to_gpio(ts->gpiod_int);
+
+ if (gpio_is_valid(gpio))
+ ts->client->irq = gpio_to_irq(gpio);
+
return devm_request_threaded_irq(&ts->client->dev, ts->client->irq,
NULL, goodix_ts_irq_handler,
ts->irq_flags, ts->client->name, ts);
@@ -949,6 +957,7 @@ static const struct of_device_id goodix_of_match[] = {
{ .compatible = "goodix,gt9271" },
{ .compatible = "goodix,gt928" },
{ .compatible = "goodix,gt967" },
+ { .compatible = "goodix,gt9147",},
{ }
};
MODULE_DEVICE_TABLE(of, goodix_of_match);
diff --git a/drivers/tty/serial/stm32-usart.c b/drivers/tty/serial/stm32-usart.c
index 5c6c3c0..d606eb5 100644
--- a/drivers/tty/serial/stm32-usart.c
+++ b/drivers/tty/serial/stm32-usart.c
@@ -938,6 +938,7 @@ static int stm32_init_port(struct stm32_port *stm32port,
{
struct uart_port *port = &stm32port->port;
struct resource *res;
+ struct pinctrl *uart_pinctrl;
int ret;
port->iotype = UPIO_MEM;
@@ -952,8 +953,21 @@ static int stm32_init_port(struct stm32_port *stm32port,
stm32port->wakeirq = platform_get_irq_byname(pdev, "wakeup");
stm32port->fifoen = stm32port->info->cfg.has_fifo;
- stm32port->console_pins = pinctrl_lookup_state(pdev->dev.pins->p,
- "no_console_suspend");
+
+ uart_pinctrl = devm_pinctrl_get(&pdev->dev);
+ if (IS_ERR(uart_pinctrl)) {
+ ret = PTR_ERR(uart_pinctrl);
+ if (ret != -ENODEV) {
+ dev_err(&pdev->dev,"Can't get pinctrl, error %d\n",
+ ret);
+ return ret;
+ }
+ stm32port->console_pins = ERR_PTR(-ENODEV);
+ }
+ else
+ stm32port->console_pins = pinctrl_lookup_state
+ (uart_pinctrl,"no_console_suspend");
+
if (IS_ERR(stm32port->console_pins)
&& PTR_ERR(stm32port->console_pins) != -ENODEV)
return PTR_ERR(stm32port->console_pins);
--
2.7.4

View File

@ -0,0 +1,277 @@
From 4cc987cced2179b54ebc0a977ff3ef4210acb38c Mon Sep 17 00:00:00 2001
From: Romuald JEANNE <romuald.jeanne@st.com>
Date: Mon, 10 Dec 2018 15:36:09 +0100
Subject: [PATCH 37/52] ARM: stm32mp1-r0-rc3: IRQ Mailbox
---
drivers/irqchip/irq-stm32-exti.c | 122 ++++++++++++++++++++++++++-------------
1 file changed, 83 insertions(+), 39 deletions(-)
diff --git a/drivers/irqchip/irq-stm32-exti.c b/drivers/irqchip/irq-stm32-exti.c
index 9cc15f1..223ee2e 100644
--- a/drivers/irqchip/irq-stm32-exti.c
+++ b/drivers/irqchip/irq-stm32-exti.c
@@ -6,6 +6,7 @@
*/
#include <linux/bitops.h>
+#include <linux/delay.h>
#include <linux/hwspinlock.h>
#include <linux/interrupt.h>
#include <linux/io.h>
@@ -21,7 +22,8 @@
#define IRQS_PER_BANK 32
-#define HWSPINLOCK_TIMEOUT 5 /* msec */
+#define HWSPNLCK_TIMEOUT 1000 /* usec */
+#define HWSPNLCK_RETRY_DELAY 100 /* usec */
struct stm32_exti_bank {
u32 imr_ofst;
@@ -35,6 +37,12 @@ struct stm32_exti_bank {
#define UNDEF_REG ~0
+enum stm32_exti_hwspinlock {
+ HWSPINLOCK_UNKNOWN,
+ HWSPINLOCK_NONE,
+ HWSPINLOCK_READY,
+};
+
struct stm32_desc_irq {
u32 exti;
u32 irq_parent;
@@ -50,7 +58,6 @@ struct stm32_exti_drv_data {
struct stm32_exti_chip_data {
struct stm32_exti_host_data *host_data;
const struct stm32_exti_bank *reg_bank;
- struct hwspinlock *hwlock;
struct raw_spinlock rlock;
u32 wake_active;
u32 mask_cache;
@@ -62,6 +69,9 @@ struct stm32_exti_host_data {
void __iomem *base;
struct stm32_exti_chip_data *chips_data;
const struct stm32_exti_drv_data *drv_data;
+ struct device_node *node;
+ enum stm32_exti_hwspinlock hwlock_state;
+ struct hwspinlock *hwlock;
};
static struct stm32_exti_host_data *stm32_host_data;
@@ -273,20 +283,75 @@ static int stm32_exti_set_type(struct irq_data *d,
return 0;
}
+static int stm32_exti_hwspin_lock(struct stm32_exti_chip_data *chip_data)
+{
+ struct stm32_exti_host_data *host_data = chip_data->host_data;
+ struct hwspinlock *hwlock;
+ int id, ret = 0, timeout = 0;
+
+ /* first time, check for hwspinlock availability */
+ if (unlikely(host_data->hwlock_state == HWSPINLOCK_UNKNOWN)) {
+ id = of_hwspin_lock_get_id(host_data->node, 0);
+ if (id >= 0) {
+ hwlock = hwspin_lock_request_specific(id);
+ if (hwlock) {
+ /* found valid hwspinlock */
+ host_data->hwlock_state = HWSPINLOCK_READY;
+ host_data->hwlock = hwlock;
+ pr_debug("%s hwspinlock = %d\n", __func__, id);
+ } else {
+ host_data->hwlock_state = HWSPINLOCK_NONE;
+ }
+ } else if (id != -EPROBE_DEFER) {
+ host_data->hwlock_state = HWSPINLOCK_NONE;
+ } else {
+ /* hwspinlock driver shall be ready at that stage */
+ ret = -EPROBE_DEFER;
+ }
+ }
+
+ if (likely(host_data->hwlock_state == HWSPINLOCK_READY)) {
+ /*
+ * Use the x_raw API since we are under spin_lock protection.
+ * Do not use the x_timeout API because we are under irq_disable
+ * mode (see __setup_irq())
+ */
+ do {
+ ret = hwspin_trylock_raw(host_data->hwlock);
+ if (!ret)
+ return 0;
+
+ udelay(HWSPNLCK_RETRY_DELAY);
+ timeout += HWSPNLCK_RETRY_DELAY;
+ } while (timeout < HWSPNLCK_TIMEOUT);
+
+ if (ret == -EBUSY)
+ ret = -ETIMEDOUT;
+ }
+
+ if (ret)
+ pr_err("%s can't get hwspinlock (%d)\n", __func__, ret);
+
+ return ret;
+}
+
+static void stm32_exti_hwspin_unlock(struct stm32_exti_chip_data *chip_data)
+{
+ if (likely(chip_data->host_data->hwlock_state == HWSPINLOCK_READY))
+ hwspin_unlock_raw(chip_data->host_data->hwlock);
+}
+
static int stm32_irq_set_type(struct irq_data *d, unsigned int type)
{
struct irq_chip_generic *gc = irq_data_get_irq_chip_data(d);
struct stm32_exti_chip_data *chip_data = gc->private;
const struct stm32_exti_bank *stm32_bank = chip_data->reg_bank;
u32 rtsr, ftsr;
- int err = 0;
+ int err;
irq_gc_lock(gc);
- if (chip_data->hwlock)
- err = hwspin_lock_timeout(chip_data->hwlock,
- HWSPINLOCK_TIMEOUT);
-
+ err = stm32_exti_hwspin_lock(chip_data);
if (err)
goto unlock;
@@ -301,8 +366,7 @@ static int stm32_irq_set_type(struct irq_data *d, unsigned int type)
irq_reg_writel(gc, ftsr, stm32_bank->ftsr_ofst);
unspinlock:
- if (chip_data->hwlock)
- hwspin_unlock(chip_data->hwlock);
+ stm32_exti_hwspin_unlock(chip_data);
unlock:
irq_gc_unlock(gc);
@@ -470,14 +534,11 @@ static int stm32_exti_h_set_type(struct irq_data *d, unsigned int type)
const struct stm32_exti_bank *stm32_bank = chip_data->reg_bank;
void __iomem *base = chip_data->host_data->base;
u32 rtsr, ftsr;
- int err = 0;
+ int err;
raw_spin_lock(&chip_data->rlock);
- if (chip_data->hwlock)
- err = hwspin_lock_timeout(chip_data->hwlock,
- HWSPINLOCK_TIMEOUT);
-
+ err = stm32_exti_hwspin_lock(chip_data);
if (err)
goto unlock;
@@ -492,15 +553,14 @@ static int stm32_exti_h_set_type(struct irq_data *d, unsigned int type)
writel_relaxed(ftsr, base + stm32_bank->ftsr_ofst);
unspinlock:
- if (chip_data->hwlock)
- hwspin_unlock(chip_data->hwlock);
+ stm32_exti_hwspin_unlock(chip_data);
unlock:
raw_spin_unlock(&chip_data->rlock);
if (d->parent_data->chip)
irq_chip_set_type_parent(d, type);
- return 0;
+ return err;
}
static int stm32_exti_h_set_wake(struct irq_data *d, unsigned int on)
@@ -650,6 +710,8 @@ stm32_exti_host_data *stm32_exti_host_init(const struct stm32_exti_drv_data *dd,
return NULL;
host_data->drv_data = dd;
+ host_data->node = node;
+ host_data->hwlock_state = HWSPINLOCK_UNKNOWN;
host_data->chips_data = kcalloc(dd->bank_nr,
sizeof(struct stm32_exti_chip_data),
GFP_KERNEL);
@@ -676,13 +738,11 @@ stm32_exti_host_data *stm32_exti_host_init(const struct stm32_exti_drv_data *dd,
static struct
stm32_exti_chip_data *stm32_exti_chip_init(struct stm32_exti_host_data *h_data,
- u32 bank_idx,
- struct device_node *node)
+ u32 bank_idx)
{
const struct stm32_exti_bank *stm32_bank;
struct stm32_exti_chip_data *chip_data;
void __iomem *base = h_data->base;
- u32 irqs_mask;
stm32_bank = h_data->drv_data->exti_banks[bank_idx];
chip_data = &h_data->chips_data[bank_idx];
@@ -691,10 +751,6 @@ stm32_exti_chip_data *stm32_exti_chip_init(struct stm32_exti_host_data *h_data,
raw_spin_lock_init(&chip_data->rlock);
- /* Determine number of irqs supported */
- writel_relaxed(~0UL, base + stm32_bank->rtsr_ofst);
- irqs_mask = readl_relaxed(base + stm32_bank->rtsr_ofst);
-
/*
* This IP has no reset, so after hot reboot we should
* clear registers to avoid residue
@@ -702,8 +758,7 @@ stm32_exti_chip_data *stm32_exti_chip_init(struct stm32_exti_host_data *h_data,
writel_relaxed(0, base + stm32_bank->imr_ofst);
writel_relaxed(0, base + stm32_bank->emr_ofst);
- pr_info("%s: bank%d, External IRQs available:%#x\n",
- node->full_name, bank_idx, irqs_mask);
+ pr_info("%pOF: bank%d\n", h_data->node, bank_idx);
return chip_data;
}
@@ -716,7 +771,6 @@ static int __init stm32_exti_init(const struct stm32_exti_drv_data *drv_data,
int nr_irqs, ret, i;
struct irq_chip_generic *gc;
struct irq_domain *domain;
- struct hwspinlock *hwlock = NULL;
host_data = stm32_exti_host_init(drv_data, node);
if (!host_data)
@@ -739,22 +793,12 @@ static int __init stm32_exti_init(const struct stm32_exti_drv_data *drv_data,
goto out_free_domain;
}
- /* hwspinlock is optional */
- ret = of_hwspin_lock_get_id(node, 0);
- if (ret < 0) {
- if (ret == -EPROBE_DEFER)
- goto out_free_domain;
- } else {
- hwlock = hwspin_lock_request_specific(ret);
- }
-
for (i = 0; i < drv_data->bank_nr; i++) {
const struct stm32_exti_bank *stm32_bank;
struct stm32_exti_chip_data *chip_data;
stm32_bank = drv_data->exti_banks[i];
- chip_data = stm32_exti_chip_init(host_data, i, node);
- chip_data->hwlock = hwlock;
+ chip_data = stm32_exti_chip_init(host_data, i);
gc = irq_get_domain_generic_chip(domain, i * IRQS_PER_BANK);
@@ -836,7 +880,7 @@ __init stm32_exti_hierarchy_init(const struct stm32_exti_drv_data *drv_data,
return -ENOMEM;
for (i = 0; i < drv_data->bank_nr; i++)
- stm32_exti_chip_init(host_data, i, node);
+ stm32_exti_chip_init(host_data, i);
domain = irq_domain_add_hierarchy(parent_domain, 0,
drv_data->bank_nr * IRQS_PER_BANK,
--
2.7.4

View File

@ -0,0 +1,26 @@
From 6c1f5d14ed9c421276ad7beac5475e1114520369 Mon Sep 17 00:00:00 2001
From: Romuald JEANNE <romuald.jeanne@st.com>
Date: Mon, 10 Dec 2018 15:48:55 +0100
Subject: [PATCH 38/52] ARM: stm32mp1-r0-rc3: MEDIA
---
drivers/media/i2c/ov5640.c | 3 +--
1 file changed, 1 insertion(+), 2 deletions(-)
diff --git a/drivers/media/i2c/ov5640.c b/drivers/media/i2c/ov5640.c
index 27b75e7..22ddfca4 100644
--- a/drivers/media/i2c/ov5640.c
+++ b/drivers/media/i2c/ov5640.c
@@ -2691,8 +2691,7 @@ static int ov5640_s_stream(struct v4l2_subdev *sd, int enable)
if (sensor->streaming == !enable) {
if (enable && sensor->pending_mode_change) {
- ret = ov5640_set_mode(sensor, sensor->last_mode);
-
+ ret = ov5640_set_mode(sensor);
if (ret)
goto out;
}
--
2.7.4

View File

@ -0,0 +1,478 @@
From 0affc90bd300ecd2c60aee7fd97251a8d2aad01f Mon Sep 17 00:00:00 2001
From: Romuald JEANNE <romuald.jeanne@st.com>
Date: Mon, 10 Dec 2018 15:38:59 +0100
Subject: [PATCH 39/52] ARM: stm32mp1-r0-rc3: MMC MTD
---
Documentation/devicetree/bindings/mmc/mmci.txt | 2 +
drivers/mmc/host/mmci.c | 61 +++++++++-
drivers/mmc/host/mmci.h | 8 +-
drivers/mmc/host/mmci_stm32_sdmmc.c | 162 ++++++++++++++++++++++++-
4 files changed, 219 insertions(+), 14 deletions(-)
diff --git a/Documentation/devicetree/bindings/mmc/mmci.txt b/Documentation/devicetree/bindings/mmc/mmci.txt
index 6d3c626..da6d59e 100644
--- a/Documentation/devicetree/bindings/mmc/mmci.txt
+++ b/Documentation/devicetree/bindings/mmc/mmci.txt
@@ -15,6 +15,8 @@ Required properties:
Optional properties:
- arm,primecell-periphid : contains the PrimeCell Peripheral ID, it overrides
the ID provided by the HW
+- reg : sdmmc variant could have a second base register for
+ delay block.
- resets : phandle to internal reset line.
Should be defined for sdmmc variant.
- vqmmc-supply : phandle to the regulator device tree node, mentioned
diff --git a/drivers/mmc/host/mmci.c b/drivers/mmc/host/mmci.c
index 02b631f..6c2b1a0 100644
--- a/drivers/mmc/host/mmci.c
+++ b/drivers/mmc/host/mmci.c
@@ -14,6 +14,7 @@
#include <linux/ioport.h>
#include <linux/device.h>
#include <linux/io.h>
+#include <linux/iopoll.h>
#include <linux/interrupt.h>
#include <linux/kernel.h>
#include <linux/slab.h>
@@ -25,6 +26,7 @@
#include <linux/mmc/pm.h>
#include <linux/mmc/host.h>
#include <linux/mmc/card.h>
+#include <linux/mmc/sd.h>
#include <linux/mmc/slot-gpio.h>
#include <linux/amba/bus.h>
#include <linux/clk.h>
@@ -291,7 +293,8 @@ static struct variant_data variant_stm32_sdmmc = {
.busy_detect_flag = MCI_STM32_BUSYD0,
.busy_detect_mask = MCI_STM32_BUSYD0ENDMASK,
.init = sdmmc_variant_init,
- .quirks = MMCI_QUIRK_STM32_DTMODE,
+ .quirks = MMCI_QUIRK_STM32_DTMODE |
+ MMCI_QUIRK_STM32_VSWITCH,
};
static struct variant_data variant_stm32_sdmmcv2 = {
@@ -318,7 +321,8 @@ static struct variant_data variant_stm32_sdmmcv2 = {
.busy_detect_flag = MCI_STM32_BUSYD0,
.busy_detect_mask = MCI_STM32_BUSYD0ENDMASK,
.init = sdmmc_variant_init,
- .quirks = MMCI_QUIRK_STM32_DTMODE,
+ .quirks = MMCI_QUIRK_STM32_DTMODE |
+ MMCI_QUIRK_STM32_VSWITCH,
};
static struct variant_data variant_qcom = {
@@ -1191,6 +1195,10 @@ mmci_start_command(struct mmci_host *host, struct mmc_command *cmd, u32 c)
writel_relaxed(clks, host->base + MMCIDATATIMER);
}
+ if (host->variant->quirks & MMCI_QUIRK_STM32_VSWITCH &&
+ cmd->opcode == SD_SWITCH_VOLTAGE)
+ mmci_write_pwrreg(host, host->pwr_reg | MCI_STM32_VSWITCHEN);
+
if (/*interrupt*/0)
c |= MCI_CPSM_INTERRUPT;
@@ -1284,13 +1292,13 @@ mmci_cmd_irq(struct mmci_host *host, struct mmc_command *cmd,
unsigned int status)
{
void __iomem *base = host->base;
- bool busy_resp = !!(cmd->flags & MMC_RSP_BUSY);
- bool sbc;
+ bool busy_resp, sbc;
u32 err_msk;
if (!cmd)
return;
+ busy_resp = !!(cmd->flags & MMC_RSP_BUSY);
sbc = (cmd == host->mrq->sbc);
/*
@@ -1575,11 +1583,14 @@ static irqreturn_t mmci_pio_irq(int irq, void *dev_id)
static irqreturn_t mmci_irq(int irq, void *dev_id)
{
struct mmci_host *host = dev_id;
+ bool busy_resp;
u32 status;
int ret = 0;
spin_lock(&host->lock);
+ busy_resp = host->cmd ? !!(host->cmd->flags & MMC_RSP_BUSY) : false;
+
do {
status = readl(host->base + MMCISTATUS);
@@ -1619,9 +1630,12 @@ static irqreturn_t mmci_irq(int irq, void *dev_id)
}
/*
- * Don't poll for busy completion in irq context.
+ * Don't poll for:
+ * -busy completion in irq context.
+ * -cmd without busy response check like cmd11
*/
- if (host->variant->busy_detect && host->busy_status)
+ if (host->variant->busy_detect &&
+ (!busy_resp || host->busy_status))
status &= ~host->variant->busy_detect_flag;
ret = 1;
@@ -1796,6 +1810,8 @@ static int mmci_get_cd(struct mmc_host *mmc)
static int mmci_sig_volt_switch(struct mmc_host *mmc, struct mmc_ios *ios)
{
+ struct mmci_host *host = mmc_priv(mmc);
+ unsigned long flags;
int ret = 0;
if (!IS_ERR(mmc->supply.vqmmc)) {
@@ -1808,6 +1824,28 @@ static int mmci_sig_volt_switch(struct mmc_host *mmc, struct mmc_ios *ios)
case MMC_SIGNAL_VOLTAGE_180:
ret = regulator_set_voltage(mmc->supply.vqmmc,
1700000, 1950000);
+
+ if (ret)
+ break;
+
+ if (host->variant->quirks & MMCI_QUIRK_STM32_VSWITCH) {
+ u32 status;
+
+ spin_lock_irqsave(&host->lock, flags);
+
+ mmci_write_pwrreg(host, host->pwr_reg |
+ MCI_STM32_VSWITCH);
+
+ spin_unlock_irqrestore(&host->lock, flags);
+
+ /* wait voltage switch completion while 10ms */
+ ret = readl_relaxed_poll_timeout(
+ host->base + MMCISTATUS,
+ status,
+ (status & MCI_STM32_VSWEND),
+ 10, 10000);
+ }
+
break;
case MMC_SIGNAL_VOLTAGE_120:
ret = regulator_set_voltage(mmc->supply.vqmmc,
@@ -1822,6 +1860,16 @@ static int mmci_sig_volt_switch(struct mmc_host *mmc, struct mmc_ios *ios)
return ret;
}
+static int mmci_execute_tuning(struct mmc_host *mmc, u32 opcode)
+{
+ struct mmci_host *host = mmc_priv(mmc);
+
+ if (host->ops && host->ops->execute_tuning)
+ return host->ops->execute_tuning(mmc, opcode);
+
+ return -EINVAL;
+}
+
static struct mmc_host_ops mmci_ops = {
.request = mmci_request,
.pre_req = mmci_pre_request,
@@ -1830,6 +1878,7 @@ static struct mmc_host_ops mmci_ops = {
.get_ro = mmc_gpio_get_ro,
.get_cd = mmci_get_cd,
.start_signal_voltage_switch = mmci_sig_volt_switch,
+ .execute_tuning = mmci_execute_tuning,
};
static int mmci_of_parse(struct device_node *np, struct mmc_host *mmc)
diff --git a/drivers/mmc/host/mmci.h b/drivers/mmc/host/mmci.h
index 55867fc..e10093e 100644
--- a/drivers/mmc/host/mmci.h
+++ b/drivers/mmc/host/mmci.h
@@ -170,6 +170,7 @@
#define MCI_STM32_DPSMACTIVE BIT(12)
#define MCI_STM32_BUSYD0 BIT(20)
#define MCI_STM32_BUSYD0END BIT(21)
+#define MCI_STM32_VSWEND BIT(25)
#define MMCICLEAR 0x038
#define MCI_CMDCRCFAILCLR (1 << 0)
@@ -364,8 +365,9 @@ struct variant_data {
void (*init)(struct mmci_host *host);
};
-#define MMCI_QUIRK_STM32_DTMODE BIT(0)
-#define MMCI_QUIRK_ST_SDIO BIT(2) /* enable ST specific SDIO logic */
+#define MMCI_QUIRK_STM32_DTMODE BIT(0)
+#define MMCI_QUIRK_ST_SDIO BIT(2) /* enable ST specific SDIO logic */
+#define MMCI_QUIRK_STM32_VSWITCH BIT(3)
/* mmci variant callbacks */
struct mmci_host_ops {
@@ -382,6 +384,7 @@ struct mmci_host_ops {
void (*dma_error)(struct mmci_host *host);
void (*set_clkreg)(struct mmci_host *host, unsigned int desired);
void (*set_pwrreg)(struct mmci_host *host, unsigned int pwr);
+ int (*execute_tuning)(struct mmc_host *mmc, u32 opcode);
};
struct mmci_host {
@@ -414,6 +417,7 @@ struct mmci_host {
struct mmci_platform_data *plat;
struct mmci_host_ops *ops;
struct variant_data *variant;
+ void *variant_priv;
struct pinctrl *pinctrl;
struct pinctrl_state *pins_default;
struct pinctrl_state *pins_opendrain;
diff --git a/drivers/mmc/host/mmci_stm32_sdmmc.c b/drivers/mmc/host/mmci_stm32_sdmmc.c
index cfbfc6f..e5ccc68 100644
--- a/drivers/mmc/host/mmci_stm32_sdmmc.c
+++ b/drivers/mmc/host/mmci_stm32_sdmmc.c
@@ -3,14 +3,31 @@
* Copyright (C) STMicroelectronics 2018 - All Rights Reserved
* Author: Ludovic.barre@st.com for STMicroelectronics.
*/
+#include <linux/bitfield.h>
#include <linux/delay.h>
#include <linux/dma-mapping.h>
+#include <linux/iopoll.h>
#include <linux/mmc/host.h>
#include <linux/mmc/card.h>
+#include <linux/of_address.h>
#include <linux/reset.h>
#include <linux/scatterlist.h>
#include "mmci.h"
+#define DLYB_CR 0x0
+#define DLYB_CR_DEN BIT(0)
+#define DLYB_CR_SEN BIT(1)
+
+#define DLYB_CFGR 0x4
+#define DLYB_CFGR_SEL_MASK GENMASK(3, 0)
+#define DLYB_CFGR_UNIT_MASK GENMASK(14, 8)
+#define DLYB_CFGR_LNG_MASK GENMASK(27, 16)
+#define DLYB_CFGR_LNGF BIT(31)
+
+#define DLYB_NB_DELAY 11
+#define DLYB_CFGR_SEL_MAX (DLYB_NB_DELAY + 1)
+#define DLYB_CFGR_UNIT_MAX 127
+
#define SDMMC_LLI_BUF_LEN PAGE_SIZE
#define SDMMC_IDMA_BURST BIT(MMCI_STM32_IDMABNDT_SHIFT)
@@ -20,11 +37,17 @@ struct sdmmc_lli_desc {
u32 idmasize;
};
-struct sdmmc_priv {
+struct sdmmc_idma {
dma_addr_t sg_dma;
void *sg_cpu;
};
+struct sdmmc_dlyb {
+ void __iomem *base;
+ u32 unit;
+ u32 max;
+};
+
int sdmmc_idma_validate_data(struct mmci_host *host,
struct mmc_data *data)
{
@@ -36,8 +59,8 @@ int sdmmc_idma_validate_data(struct mmci_host *host,
* excepted the last element which has no constraint on idmasize
*/
for_each_sg(data->sg, sg, data->sg_len - 1, i) {
- if (!IS_ALIGNED(sg_dma_address(data->sg), sizeof(u32)) ||
- !IS_ALIGNED(sg_dma_len(data->sg), SDMMC_IDMA_BURST)) {
+ if (!IS_ALIGNED(data->sg->offset, sizeof(u32)) ||
+ !IS_ALIGNED(data->sg->length, SDMMC_IDMA_BURST)) {
dev_err(mmc_dev(host->mmc),
"unaligned scatterlist: ofst:%x length:%d\n",
data->sg->offset, data->sg->length);
@@ -45,7 +68,7 @@ int sdmmc_idma_validate_data(struct mmci_host *host,
}
}
- if (!IS_ALIGNED(sg_dma_address(data->sg), sizeof(u32))) {
+ if (!IS_ALIGNED(data->sg->offset, sizeof(u32))) {
dev_err(mmc_dev(host->mmc),
"unaligned last scatterlist: ofst:%x length:%d\n",
data->sg->offset, data->sg->length);
@@ -92,7 +115,7 @@ static void sdmmc_idma_unprep_data(struct mmci_host *host,
static int sdmmc_idma_setup(struct mmci_host *host)
{
- struct sdmmc_priv *idma;
+ struct sdmmc_idma *idma;
idma = devm_kzalloc(mmc_dev(host->mmc), sizeof(*idma), GFP_KERNEL);
if (!idma)
@@ -123,7 +146,7 @@ static int sdmmc_idma_setup(struct mmci_host *host)
static int sdmmc_idma_start(struct mmci_host *host, unsigned int *datactrl)
{
- struct sdmmc_priv *idma = host->dma_priv;
+ struct sdmmc_idma *idma = host->dma_priv;
struct sdmmc_lli_desc *desc = (struct sdmmc_lli_desc *)idma->sg_cpu;
struct mmc_data *data = host->data;
struct scatterlist *sg;
@@ -226,12 +249,24 @@ static void mmci_sdmmc_set_clkreg(struct mmci_host *host, unsigned int desired)
mmci_write_clkreg(host, clk);
}
+static void sdmmc_dlyb_input_ck(struct sdmmc_dlyb *dlyb)
+{
+ if (!dlyb || !dlyb->base)
+ return;
+
+ /* Output clock = Input clock */
+ writel_relaxed(0, dlyb->base + DLYB_CR);
+}
+
static void mmci_sdmmc_set_pwrreg(struct mmci_host *host, unsigned int pwr)
{
struct mmc_ios ios = host->mmc->ios;
+ struct sdmmc_dlyb *dlyb = host->variant_priv;
pwr = host->pwr_reg_add;
+ sdmmc_dlyb_input_ck(dlyb);
+
if (ios.power_mode == MMC_POWER_OFF) {
/* Only a reset could power-off sdmmc */
reset_control_assert(host->rst);
@@ -265,6 +300,105 @@ static void mmci_sdmmc_set_pwrreg(struct mmci_host *host, unsigned int pwr)
}
}
+static void sdmmc_dlyb_set_cfgr(struct sdmmc_dlyb *dlyb,
+ int unit, int phase, bool sampler)
+{
+ u32 cr, cfgr;
+
+ writel_relaxed(DLYB_CR_SEN, dlyb->base + DLYB_CR);
+
+ cfgr = FIELD_PREP(DLYB_CFGR_UNIT_MASK, unit) |
+ FIELD_PREP(DLYB_CFGR_SEL_MASK, phase);
+ writel_relaxed(cfgr, dlyb->base + DLYB_CFGR);
+
+ cr = DLYB_CR_DEN;
+ if (sampler)
+ cr |= DLYB_CR_SEN;
+
+ writel_relaxed(cr, dlyb->base + DLYB_CR);
+}
+
+static int sdmmc_dlyb_lng_tuning(struct mmci_host *host)
+{
+ struct sdmmc_dlyb *dlyb = host->variant_priv;
+ u32 cfgr;
+ int i, lng, ret;
+
+ for (i = 0; i <= DLYB_CFGR_UNIT_MAX; i++) {
+ sdmmc_dlyb_set_cfgr(dlyb, i, DLYB_CFGR_SEL_MAX, true);
+
+ ret = readl_relaxed_poll_timeout(dlyb->base + DLYB_CFGR, cfgr,
+ (cfgr & DLYB_CFGR_LNGF),
+ 1, 1000);
+ if (ret) {
+ dev_warn(mmc_dev(host->mmc),
+ "delay line cfg timeout unit:%d cfgr:%d\n",
+ i, cfgr);
+ continue;
+ }
+
+ lng = FIELD_GET(DLYB_CFGR_LNG_MASK, cfgr);
+ if (lng < BIT(DLYB_NB_DELAY) && lng > 0)
+ break;
+ }
+
+ if (i > DLYB_CFGR_UNIT_MAX)
+ return -EINVAL;
+
+ dlyb->unit = i;
+ dlyb->max = __fls(lng);
+
+ return 0;
+}
+
+static int sdmmc_dlyb_phase_tuning(struct mmci_host *host, u32 opcode)
+{
+ struct sdmmc_dlyb *dlyb = host->variant_priv;
+ int cur_len = 0, max_len = 0, end_of_len = 0;
+ int phase;
+
+ for (phase = 0; phase <= dlyb->max; phase++) {
+ sdmmc_dlyb_set_cfgr(dlyb, dlyb->unit, phase, false);
+
+ if (mmc_send_tuning(host->mmc, opcode, NULL)) {
+ cur_len = 0;
+ } else {
+ cur_len++;
+ if (cur_len > max_len) {
+ max_len = cur_len;
+ end_of_len = phase;
+ }
+ }
+ }
+
+ if (!max_len) {
+ dev_err(mmc_dev(host->mmc), "no tuning point found\n");
+ return -EINVAL;
+ }
+
+ phase = end_of_len - max_len / 2;
+ sdmmc_dlyb_set_cfgr(dlyb, dlyb->unit, phase, false);
+
+ dev_dbg(mmc_dev(host->mmc), "unit:%d max_dly:%d phase:%d\n",
+ dlyb->unit, dlyb->max, phase);
+
+ return 0;
+}
+
+static int sdmmc_execute_tuning(struct mmc_host *mmc, u32 opcode)
+{
+ struct mmci_host *host = mmc_priv(mmc);
+ struct sdmmc_dlyb *dlyb = host->variant_priv;
+
+ if (!dlyb || !dlyb->base)
+ return -EINVAL;
+
+ if (sdmmc_dlyb_lng_tuning(host))
+ return -EINVAL;
+
+ return sdmmc_dlyb_phase_tuning(host, opcode);
+}
+
static struct mmci_host_ops sdmmc_variant_ops = {
.validate_data = sdmmc_idma_validate_data,
.prep_data = sdmmc_idma_prep_data,
@@ -274,9 +408,25 @@ static struct mmci_host_ops sdmmc_variant_ops = {
.dma_finalize = sdmmc_idma_finalize,
.set_clkreg = mmci_sdmmc_set_clkreg,
.set_pwrreg = mmci_sdmmc_set_pwrreg,
+ .execute_tuning = sdmmc_execute_tuning,
};
void sdmmc_variant_init(struct mmci_host *host)
{
+ struct device_node *np = host->mmc->parent->of_node;
+ void __iomem *base_dlyb;
+ struct sdmmc_dlyb *dlyb;
+
host->ops = &sdmmc_variant_ops;
+
+ base_dlyb = devm_of_iomap(mmc_dev(host->mmc), np, 1, NULL);
+ if (IS_ERR(base_dlyb))
+ return;
+
+ dlyb = devm_kzalloc(mmc_dev(host->mmc), sizeof(*dlyb), GFP_KERNEL);
+ if (!dlyb)
+ return;
+
+ dlyb->base = base_dlyb;
+ host->variant_priv = dlyb;
}
--
2.7.4

View File

@ -0,0 +1,604 @@
From d00006c83840de8fa5a6049ce31117d4e9c76184 Mon Sep 17 00:00:00 2001
From: Romuald JEANNE <romuald.jeanne@st.com>
Date: Mon, 10 Dec 2018 15:40:47 +0100
Subject: [PATCH 40/52] ARM: stm32mp1-r0-rc3: PINCTRL PWM RESET RTC
---
drivers/pinctrl/stm32/pinctrl-stm32.c | 219 +++++++++++++++++++++++-----------
drivers/regulator/stpmic1_regulator.c | 17 +--
2 files changed, 152 insertions(+), 84 deletions(-)
diff --git a/drivers/pinctrl/stm32/pinctrl-stm32.c b/drivers/pinctrl/stm32/pinctrl-stm32.c
index 914bee4..7a27431 100644
--- a/drivers/pinctrl/stm32/pinctrl-stm32.c
+++ b/drivers/pinctrl/stm32/pinctrl-stm32.c
@@ -7,6 +7,7 @@
* Heavily based on Mediatek's pinctrl driver
*/
#include <linux/clk.h>
+#include <linux/delay.h>
#include <linux/gpio/driver.h>
#include <linux/hwspinlock.h>
#include <linux/io.h>
@@ -65,7 +66,8 @@
#define gpio_range_to_bank(chip) \
container_of(chip, struct stm32_gpio_bank, range)
-#define HWSPINLOCK_TIMEOUT 5 /* msec */
+#define HWSPNLCK_TIMEOUT 1000 /* usec */
+#define HWSPNLCK_RETRY_DELAY 100 /* usec */
static const char * const stm32_gpio_functions[] = {
"gpio", "af0", "af1",
@@ -110,6 +112,8 @@ struct stm32_pinctrl {
struct irq_domain *domain;
struct regmap *regmap;
struct regmap_field *irqmux[STM32_GPIO_PINS_PER_BANK];
+ u16 irqmux_map;
+ spinlock_t irqmux_lock; /* interrupt mux lock */
struct stm32_desc_pin *pins;
u32 npins;
u32 pkg;
@@ -150,6 +154,26 @@ static inline u32 stm32_gpio_get_alt(u32 function)
return 0;
}
+static int stm32_pctrl_hwspin_lock_timeout(struct hwspinlock *hwlock)
+{
+ int ret, timeout = 0;
+
+ /*
+ * Use the x_raw API since we are under spin_lock protection and do not
+ * use the x_timeout API because we are under irq_disable mode
+ */
+ do {
+ ret = hwspin_trylock_raw(hwlock);
+ if (!ret)
+ return ret;
+
+ udelay(HWSPNLCK_RETRY_DELAY);
+ timeout += HWSPNLCK_RETRY_DELAY;
+ } while (timeout < HWSPNLCK_TIMEOUT);
+
+ return ret == -EBUSY ? -ETIMEDOUT : ret;
+}
+
/* GPIO functions */
static inline void __stm32_gpio_set(struct stm32_gpio_bank *bank,
@@ -326,9 +350,40 @@ static int stm32_gpio_domain_activate(struct irq_domain *d,
{
struct stm32_gpio_bank *bank = d->host_data;
struct stm32_pinctrl *pctl = dev_get_drvdata(bank->gpio_chip.parent);
+ unsigned long flags;
+ int ret = 0;
+
+ /*
+ * gpio irq mux is shared between several banks, a lock has to be done
+ * to avoid overriding.
+ */
+ spin_lock_irqsave(&pctl->irqmux_lock, flags);
+
+ if (pctl->irqmux_map & BIT(irq_data->hwirq)) {
+ dev_err(pctl->dev, "irq line %ld already requested.\n",
+ irq_data->hwirq);
+ ret = -EBUSY;
+ goto unlock;
+ } else {
+ pctl->irqmux_map |= BIT(irq_data->hwirq);
+ }
regmap_field_write(pctl->irqmux[irq_data->hwirq], bank->bank_ioport_nr);
- return 0;
+unlock:
+ spin_unlock_irqrestore(&pctl->irqmux_lock, flags);
+ return ret;
+}
+
+static void stm32_gpio_domain_deactivate(struct irq_domain *d,
+ struct irq_data *irq_data)
+{
+ struct stm32_gpio_bank *bank = d->host_data;
+ struct stm32_pinctrl *pctl = dev_get_drvdata(bank->gpio_chip.parent);
+ unsigned long flags;
+
+ spin_lock_irqsave(&pctl->irqmux_lock, flags);
+ pctl->irqmux_map &= ~BIT(irq_data->hwirq);
+ spin_unlock_irqrestore(&pctl->irqmux_lock, flags);
}
static int stm32_gpio_domain_alloc(struct irq_domain *d,
@@ -357,6 +412,7 @@ static const struct irq_domain_ops stm32_gpio_domain_ops = {
.alloc = stm32_gpio_domain_alloc,
.free = irq_domain_free_irqs_common,
.activate = stm32_gpio_domain_activate,
+ .deactivate = stm32_gpio_domain_deactivate,
};
/* Pinctrl functions */
@@ -436,7 +492,7 @@ static int stm32_pctrl_dt_subnode_to_map(struct pinctrl_dev *pctldev,
unsigned int num_configs;
bool has_config = 0;
unsigned reserve = 0;
- int num_pins, num_funcs, maps_per_pin, i, err;
+ int num_pins, num_funcs, maps_per_pin, i, err = 0;
pctl = pinctrl_dev_get_drvdata(pctldev);
@@ -463,41 +519,45 @@ static int stm32_pctrl_dt_subnode_to_map(struct pinctrl_dev *pctldev,
if (has_config && num_pins >= 1)
maps_per_pin++;
- if (!num_pins || !maps_per_pin)
- return -EINVAL;
+ if (!num_pins || !maps_per_pin) {
+ err = -EINVAL;
+ goto exit;
+ }
reserve = num_pins * maps_per_pin;
err = pinctrl_utils_reserve_map(pctldev, map,
reserved_maps, num_maps, reserve);
if (err)
- return err;
+ goto exit;
for (i = 0; i < num_pins; i++) {
err = of_property_read_u32_index(node, "pinmux",
i, &pinfunc);
if (err)
- return err;
+ goto exit;
pin = STM32_GET_PIN_NO(pinfunc);
func = STM32_GET_PIN_FUNC(pinfunc);
if (!stm32_pctrl_is_function_valid(pctl, pin, func)) {
dev_err(pctl->dev, "invalid function.\n");
- return -EINVAL;
+ err = -EINVAL;
+ goto exit;
}
grp = stm32_pctrl_find_group_by_pin(pctl, pin);
if (!grp) {
dev_err(pctl->dev, "unable to match pin %d to group\n",
pin);
- return -EINVAL;
+ err = -EINVAL;
+ goto exit;
}
err = stm32_pctrl_dt_node_to_map_func(pctl, pin, func, grp, map,
reserved_maps, num_maps);
if (err)
- return err;
+ goto exit;
if (has_config) {
err = pinctrl_utils_add_map_configs(pctldev, map,
@@ -505,11 +565,13 @@ static int stm32_pctrl_dt_subnode_to_map(struct pinctrl_dev *pctldev,
configs, num_configs,
PIN_MAP_TYPE_CONFIGS_GROUP);
if (err)
- return err;
+ goto exit;
}
}
- return 0;
+exit:
+ kfree(configs);
+ return err;
}
static int stm32_pctrl_dt_node_to_map(struct pinctrl_dev *pctldev,
@@ -599,8 +661,8 @@ static int stm32_pmx_get_func_groups(struct pinctrl_dev *pctldev,
return 0;
}
-static void stm32_pmx_set_mode(struct stm32_gpio_bank *bank,
- int pin, u32 mode, u32 alt)
+static int stm32_pmx_set_mode(struct stm32_gpio_bank *bank,
+ int pin, u32 mode, u32 alt)
{
struct stm32_pinctrl *pctl = dev_get_drvdata(bank->gpio_chip.parent);
u32 val;
@@ -612,12 +674,12 @@ static void stm32_pmx_set_mode(struct stm32_gpio_bank *bank,
clk_enable(bank->clk);
spin_lock_irqsave(&bank->lock, flags);
- if (pctl->hwlock)
- err = hwspin_lock_timeout(pctl->hwlock, HWSPINLOCK_TIMEOUT);
-
- if (err) {
- dev_err(pctl->dev, "Can't get hwspinlock\n");
- goto unlock;
+ if (pctl->hwlock) {
+ err = stm32_pctrl_hwspin_lock_timeout(pctl->hwlock);
+ if (err) {
+ dev_err(pctl->dev, "Can't get hwspinlock\n");
+ goto unlock;
+ }
}
val = readl_relaxed(bank->base + alt_offset);
@@ -633,11 +695,12 @@ static void stm32_pmx_set_mode(struct stm32_gpio_bank *bank,
stm32_gpio_backup_mode(bank, pin, mode, alt);
if (pctl->hwlock)
- hwspin_unlock(pctl->hwlock);
+ hwspin_unlock_raw(pctl->hwlock);
unlock:
spin_unlock_irqrestore(&bank->lock, flags);
clk_disable(bank->clk);
+ return err;
}
void stm32_pmx_get_mode(struct stm32_gpio_bank *bank, int pin, u32 *mode,
@@ -694,9 +757,7 @@ static int stm32_pmx_set_mux(struct pinctrl_dev *pctldev,
mode = stm32_gpio_get_mode(function);
alt = stm32_gpio_get_alt(function);
- stm32_pmx_set_mode(bank, pin, mode, alt);
-
- return 0;
+ return stm32_pmx_set_mode(bank, pin, mode, alt);
}
static int stm32_pmx_gpio_set_direction(struct pinctrl_dev *pctldev,
@@ -706,9 +767,7 @@ static int stm32_pmx_gpio_set_direction(struct pinctrl_dev *pctldev,
struct stm32_gpio_bank *bank = gpiochip_get_data(range->gc);
int pin = stm32_gpio_pin(gpio);
- stm32_pmx_set_mode(bank, pin, !input, 0);
-
- return 0;
+ return stm32_pmx_set_mode(bank, pin, !input, 0);
}
static const struct pinmux_ops stm32_pmx_ops = {
@@ -722,8 +781,8 @@ static const struct pinmux_ops stm32_pmx_ops = {
/* Pinconf functions */
-static void stm32_pconf_set_driving(struct stm32_gpio_bank *bank,
- unsigned offset, u32 drive)
+static int stm32_pconf_set_driving(struct stm32_gpio_bank *bank,
+ unsigned offset, u32 drive)
{
struct stm32_pinctrl *pctl = dev_get_drvdata(bank->gpio_chip.parent);
unsigned long flags;
@@ -733,12 +792,12 @@ static void stm32_pconf_set_driving(struct stm32_gpio_bank *bank,
clk_enable(bank->clk);
spin_lock_irqsave(&bank->lock, flags);
- if (pctl->hwlock)
- err = hwspin_lock_timeout(pctl->hwlock, HWSPINLOCK_TIMEOUT);
-
- if (err) {
- dev_err(pctl->dev, "Can't get hwspinlock\n");
- goto unlock;
+ if (pctl->hwlock) {
+ err = stm32_pctrl_hwspin_lock_timeout(pctl->hwlock);
+ if (err) {
+ dev_err(pctl->dev, "Can't get hwspinlock\n");
+ goto unlock;
+ }
}
val = readl_relaxed(bank->base + STM32_GPIO_TYPER);
@@ -749,11 +808,12 @@ static void stm32_pconf_set_driving(struct stm32_gpio_bank *bank,
stm32_gpio_backup_driving(bank, offset, drive);
if (pctl->hwlock)
- hwspin_unlock(pctl->hwlock);
+ hwspin_unlock_raw(pctl->hwlock);
unlock:
spin_unlock_irqrestore(&bank->lock, flags);
clk_disable(bank->clk);
+ return err;
}
static u32 stm32_pconf_get_driving(struct stm32_gpio_bank *bank,
@@ -774,8 +834,8 @@ static u32 stm32_pconf_get_driving(struct stm32_gpio_bank *bank,
return (val >> offset);
}
-static void stm32_pconf_set_speed(struct stm32_gpio_bank *bank,
- unsigned offset, u32 speed)
+static int stm32_pconf_set_speed(struct stm32_gpio_bank *bank,
+ unsigned offset, u32 speed)
{
struct stm32_pinctrl *pctl = dev_get_drvdata(bank->gpio_chip.parent);
unsigned long flags;
@@ -785,12 +845,12 @@ static void stm32_pconf_set_speed(struct stm32_gpio_bank *bank,
clk_enable(bank->clk);
spin_lock_irqsave(&bank->lock, flags);
- if (pctl->hwlock)
- err = hwspin_lock_timeout(pctl->hwlock, HWSPINLOCK_TIMEOUT);
-
- if (err) {
- dev_err(pctl->dev, "Can't get hwspinlock\n");
- goto unlock;
+ if (pctl->hwlock) {
+ err = stm32_pctrl_hwspin_lock_timeout(pctl->hwlock);
+ if (err) {
+ dev_err(pctl->dev, "Can't get hwspinlock\n");
+ goto unlock;
+ }
}
val = readl_relaxed(bank->base + STM32_GPIO_SPEEDR);
@@ -801,11 +861,12 @@ static void stm32_pconf_set_speed(struct stm32_gpio_bank *bank,
stm32_gpio_backup_speed(bank, offset, speed);
if (pctl->hwlock)
- hwspin_unlock(pctl->hwlock);
+ hwspin_unlock_raw(pctl->hwlock);
unlock:
spin_unlock_irqrestore(&bank->lock, flags);
clk_disable(bank->clk);
+ return err;
}
static u32 stm32_pconf_get_speed(struct stm32_gpio_bank *bank,
@@ -826,8 +887,8 @@ static u32 stm32_pconf_get_speed(struct stm32_gpio_bank *bank,
return (val >> (offset * 2));
}
-static void stm32_pconf_set_bias(struct stm32_gpio_bank *bank,
- unsigned offset, u32 bias)
+static int stm32_pconf_set_bias(struct stm32_gpio_bank *bank,
+ unsigned offset, u32 bias)
{
struct stm32_pinctrl *pctl = dev_get_drvdata(bank->gpio_chip.parent);
unsigned long flags;
@@ -837,12 +898,12 @@ static void stm32_pconf_set_bias(struct stm32_gpio_bank *bank,
clk_enable(bank->clk);
spin_lock_irqsave(&bank->lock, flags);
- if (pctl->hwlock)
- err = hwspin_lock_timeout(pctl->hwlock, HWSPINLOCK_TIMEOUT);
-
- if (err) {
- dev_err(pctl->dev, "Can't get hwspinlock\n");
- goto unlock;
+ if (pctl->hwlock) {
+ err = stm32_pctrl_hwspin_lock_timeout(pctl->hwlock);
+ if (err) {
+ dev_err(pctl->dev, "Can't get hwspinlock\n");
+ goto unlock;
+ }
}
val = readl_relaxed(bank->base + STM32_GPIO_PUPDR);
@@ -853,11 +914,12 @@ static void stm32_pconf_set_bias(struct stm32_gpio_bank *bank,
stm32_gpio_backup_bias(bank, offset, bias);
if (pctl->hwlock)
- hwspin_unlock(pctl->hwlock);
+ hwspin_unlock_raw(pctl->hwlock);
unlock:
spin_unlock_irqrestore(&bank->lock, flags);
clk_disable(bank->clk);
+ return err;
}
static u32 stm32_pconf_get_bias(struct stm32_gpio_bank *bank,
@@ -920,22 +982,22 @@ static int stm32_pconf_parse_conf(struct pinctrl_dev *pctldev,
switch (param) {
case PIN_CONFIG_DRIVE_PUSH_PULL:
- stm32_pconf_set_driving(bank, offset, 0);
+ ret = stm32_pconf_set_driving(bank, offset, 0);
break;
case PIN_CONFIG_DRIVE_OPEN_DRAIN:
- stm32_pconf_set_driving(bank, offset, 1);
+ ret = stm32_pconf_set_driving(bank, offset, 1);
break;
case PIN_CONFIG_SLEW_RATE:
- stm32_pconf_set_speed(bank, offset, arg);
+ ret = stm32_pconf_set_speed(bank, offset, arg);
break;
case PIN_CONFIG_BIAS_DISABLE:
- stm32_pconf_set_bias(bank, offset, 0);
+ ret = stm32_pconf_set_bias(bank, offset, 0);
break;
case PIN_CONFIG_BIAS_PULL_UP:
- stm32_pconf_set_bias(bank, offset, 1);
+ ret = stm32_pconf_set_bias(bank, offset, 1);
break;
case PIN_CONFIG_BIAS_PULL_DOWN:
- stm32_pconf_set_bias(bank, offset, 2);
+ ret = stm32_pconf_set_bias(bank, offset, 2);
break;
case PIN_CONFIG_OUTPUT:
__stm32_gpio_set(bank, offset, arg);
@@ -1295,6 +1357,8 @@ int stm32_pctl_probe(struct platform_device *pdev)
pctl->hwlock = hwspin_lock_request_specific(hwlock_id);
}
+ spin_lock_init(&pctl->irqmux_lock);
+
pctl->dev = dev;
pctl->match_data = match->data;
@@ -1414,22 +1478,23 @@ void stm32_gpio_backup_bias(struct stm32_gpio_bank *bank,
bank->pin_backup[offset] |= bias << STM32_GPIO_BKP_PUPD_SHIFT;
}
-void stm32_pinctrl_restore_gpio_regs(struct stm32_pinctrl *pctl, u32 pin)
+int stm32_pinctrl_restore_gpio_regs(struct stm32_pinctrl *pctl, u32 pin)
{
const struct pin_desc *desc = pin_desc_get(pctl->pctl_dev, pin);
struct pinctrl_gpio_range *range;
struct stm32_gpio_bank *bank;
u32 val, alt, mode, offset = stm32_gpio_pin(pin);
bool pin_is_irq;
+ int ret;
range = pinctrl_find_gpio_range_from_pin(pctl->pctl_dev, pin);
if (!range)
- return;
+ return 0;
pin_is_irq = gpiochip_line_is_irq(range->gc, offset);
if (!desc || (!pin_is_irq && !desc->gpio_owner))
- return;
+ return 0;
bank = gpiochip_get_data(range->gc);
@@ -1438,7 +1503,10 @@ void stm32_pinctrl_restore_gpio_regs(struct stm32_pinctrl *pctl, u32 pin)
mode = bank->pin_backup[offset] & STM32_GPIO_BKP_MODE_MASK;
mode >>= STM32_GPIO_BKP_MODE_SHIFT;
- stm32_pmx_set_mode(bank, offset, mode, alt);
+ ret = stm32_pmx_set_mode(bank, offset, mode, alt);
+ if (ret)
+ return ret;
+
if (mode == 1) {
val = bank->pin_backup[offset] & BIT(STM32_GPIO_BKP_VAL);
val = val >> STM32_GPIO_BKP_VAL;
@@ -1447,28 +1515,39 @@ void stm32_pinctrl_restore_gpio_regs(struct stm32_pinctrl *pctl, u32 pin)
val = bank->pin_backup[offset] & BIT(STM32_GPIO_BKP_TYPE);
val >>= STM32_GPIO_BKP_TYPE;
- stm32_pconf_set_driving(bank, offset, val);
+ ret = stm32_pconf_set_driving(bank, offset, val);
+ if (ret)
+ return ret;
val = bank->pin_backup[offset] & STM32_GPIO_BKP_SPEED_MASK;
val >>= STM32_GPIO_BKP_SPEED_SHIFT;
- stm32_pconf_set_speed(bank, offset, val);
+ ret = stm32_pconf_set_speed(bank, offset, val);
+ if (ret)
+ return ret;
val = bank->pin_backup[offset] & STM32_GPIO_BKP_PUPD_MASK;
val >>= STM32_GPIO_BKP_PUPD_SHIFT;
- stm32_pconf_set_bias(bank, offset, val);
+ ret = stm32_pconf_set_bias(bank, offset, val);
+ if (ret)
+ return ret;
if (pin_is_irq)
regmap_field_write(pctl->irqmux[offset], bank->bank_ioport_nr);
+
+ return 0;
}
int stm32_pinctrl_resume(struct device *dev)
{
struct stm32_pinctrl *pctl = dev_get_drvdata(dev);
struct stm32_pinctrl_group *g = pctl->groups;
- int i;
+ int i, ret;
- for (i = g->pin; i < g->pin + pctl->ngroups; i++)
- stm32_pinctrl_restore_gpio_regs(pctl, i);
+ for (i = g->pin; i < g->pin + pctl->ngroups; i++) {
+ ret = stm32_pinctrl_restore_gpio_regs(pctl, i);
+ if (ret)
+ return ret;
+ }
return 0;
}
diff --git a/drivers/regulator/stpmic1_regulator.c b/drivers/regulator/stpmic1_regulator.c
index 96f1808..31c960c 100644
--- a/drivers/regulator/stpmic1_regulator.c
+++ b/drivers/regulator/stpmic1_regulator.c
@@ -76,8 +76,9 @@ enum {
#define STPMIC1_BUCK_MODE_LP BUCK_HPLP_ENABLE_MASK
struct regulator_linear_range buck1_ranges[] = {
- REGULATOR_LINEAR_RANGE(600000, 0, 30, 25000),
- REGULATOR_LINEAR_RANGE(1350000, 31, 63, 0),
+ REGULATOR_LINEAR_RANGE(725000, 0, 4, 0),
+ REGULATOR_LINEAR_RANGE(725000, 5, 36, 25000),
+ REGULATOR_LINEAR_RANGE(1500000, 37, 63, 0),
};
struct regulator_linear_range buck2_ranges[] = {
@@ -157,7 +158,6 @@ static struct regulator_ops stpmic1_ldo_ops = {
.disable = regulator_disable_regmap,
.get_voltage_sel = regulator_get_voltage_sel_regmap,
.set_voltage_sel = regulator_set_voltage_sel_regmap,
- .set_pull_down = regulator_set_pull_down_regmap,
.set_over_current_protection = stpmic1_set_icc,
};
@@ -169,7 +169,6 @@ static struct regulator_ops stpmic1_ldo3_ops = {
.disable = regulator_disable_regmap,
.get_voltage_sel = regulator_get_voltage_sel_regmap,
.set_voltage_sel = regulator_set_voltage_sel_regmap,
- .set_pull_down = regulator_set_pull_down_regmap,
.get_bypass = regulator_get_bypass_regmap,
.set_bypass = regulator_set_bypass_regmap,
.set_over_current_protection = stpmic1_set_icc,
@@ -179,7 +178,6 @@ static struct regulator_ops stpmic1_ldo4_fixed_regul_ops = {
.is_enabled = regulator_is_enabled_regmap,
.enable = regulator_enable_regmap,
.disable = regulator_disable_regmap,
- .set_pull_down = regulator_set_pull_down_regmap,
.set_over_current_protection = stpmic1_set_icc,
};
@@ -201,7 +199,6 @@ static struct regulator_ops stpmic1_vref_ddr_ops = {
.is_enabled = regulator_is_enabled_regmap,
.enable = regulator_enable_regmap,
.disable = regulator_disable_regmap,
- .set_pull_down = regulator_set_pull_down_regmap,
};
static struct regulator_ops stpmic1_switch_regul_ops = {
@@ -227,8 +224,6 @@ static struct regulator_ops stpmic1_switch_regul_ops = {
.enable_val = 1, \
.disable_val = 0, \
.enable_time = PMIC_ENABLE_TIME_US, \
- .pull_down_reg = ids##_PULL_DOWN_REG, \
- .pull_down_mask = ids##_PULL_DOWN_MASK, \
.supply_name = #base, \
}
@@ -252,8 +247,6 @@ static struct regulator_ops stpmic1_switch_regul_ops = {
.bypass_mask = LDO_BYPASS_MASK, \
.bypass_val_on = LDO_BYPASS_MASK, \
.bypass_val_off = 0, \
- .pull_down_reg = ids##_PULL_DOWN_REG, \
- .pull_down_mask = ids##_PULL_DOWN_MASK, \
.supply_name = #base, \
}
@@ -271,8 +264,6 @@ static struct regulator_ops stpmic1_switch_regul_ops = {
.enable_val = 1, \
.disable_val = 0, \
.enable_time = PMIC_ENABLE_TIME_US, \
- .pull_down_reg = ids##_PULL_DOWN_REG, \
- .pull_down_mask = ids##_PULL_DOWN_MASK, \
.supply_name = #base, \
}
@@ -312,8 +303,6 @@ static struct regulator_ops stpmic1_switch_regul_ops = {
.enable_val = 1, \
.disable_val = 0, \
.enable_time = PMIC_ENABLE_TIME_US, \
- .pull_down_reg = ids##_PULL_DOWN_REG, \
- .pull_down_mask = ids##_PULL_DOWN_MASK, \
.supply_name = #base, \
}
--
2.7.4

View File

@ -0,0 +1,112 @@
From 6c92e60d3e402e1fcbd1bfa11185c995ce41d190 Mon Sep 17 00:00:00 2001
From: Romuald JEANNE <romuald.jeanne@st.com>
Date: Mon, 10 Dec 2018 15:47:43 +0100
Subject: [PATCH 42/52] ARM: stm32mp1-r0-rc3: SOUND
---
sound/soc/stm/stm32_sai_sub.c | 58 ++++++++++++++++++++++++++++++-------------
1 file changed, 41 insertions(+), 17 deletions(-)
diff --git a/sound/soc/stm/stm32_sai_sub.c b/sound/soc/stm/stm32_sai_sub.c
index 1f23ca4..3f0540a 100644
--- a/sound/soc/stm/stm32_sai_sub.c
+++ b/sound/soc/stm/stm32_sai_sub.c
@@ -313,6 +313,23 @@ static int stm32_sai_set_clk_div(struct stm32_sai_sub_data *sai,
return ret;
}
+static int stm32_sai_set_parent_clock(struct stm32_sai_sub_data *sai,
+ unsigned int rate)
+{
+ struct platform_device *pdev = sai->pdev;
+ struct clk *parent_clk = sai->pdata->clk_x8k;
+ int ret;
+
+ if (!(rate % 11025))
+ parent_clk = sai->pdata->clk_x11k;
+
+ ret = clk_set_parent(sai->sai_ck, parent_clk);
+ if (ret)
+ dev_err(&pdev->dev, "Set parent clock returned: %d\n", ret);
+
+ return ret;
+}
+
static long stm32_sai_mclk_round_rate(struct clk_hw *hw, unsigned long rate,
unsigned long *prate)
{
@@ -492,25 +509,26 @@ static int stm32_sai_set_sysclk(struct snd_soc_dai *cpu_dai,
struct stm32_sai_sub_data *sai = snd_soc_dai_get_drvdata(cpu_dai);
int ret;
- if (dir == SND_SOC_CLOCK_OUT) {
+ if (dir == SND_SOC_CLOCK_OUT && sai->sai_mclk) {
ret = regmap_update_bits(sai->regmap, STM_SAI_CR1_REGX,
SAI_XCR1_NODIV,
(unsigned int)~SAI_XCR1_NODIV);
if (ret < 0)
return ret;
- dev_dbg(cpu_dai->dev, "SAI MCLK frequency is %uHz\n", freq);
- sai->mclk_rate = freq;
+ /* If master clock is used, set parent clock now */
+ ret = stm32_sai_set_parent_clock(sai, freq);
+ if (ret)
+ return ret;
- if (sai->sai_mclk) {
- ret = clk_set_rate_exclusive(sai->sai_mclk,
- sai->mclk_rate);
- if (ret) {
- dev_err(cpu_dai->dev,
- "Could not set mclk rate\n");
- return ret;
- }
+ ret = clk_set_rate_exclusive(sai->sai_mclk, freq);
+ if (ret) {
+ dev_err(cpu_dai->dev, "Could not set mclk rate\n");
+ return ret;
}
+
+ dev_dbg(cpu_dai->dev, "SAI MCLK frequency is %uHz\n", freq);
+ sai->mclk_rate = freq;
}
return 0;
@@ -906,11 +924,13 @@ static int stm32_sai_configure_clock(struct snd_soc_dai *cpu_dai,
int cr1, mask, div = 0;
int sai_clk_rate, mclk_ratio, den;
unsigned int rate = params_rate(params);
+ int ret;
- if (!(rate % 11025))
- clk_set_parent(sai->sai_ck, sai->pdata->clk_x11k);
- else
- clk_set_parent(sai->sai_ck, sai->pdata->clk_x8k);
+ if (!sai->sai_mclk) {
+ ret = stm32_sai_set_parent_clock(sai, rate);
+ if (ret)
+ return ret;
+ }
sai_clk_rate = clk_get_rate(sai->sai_ck);
if (STM_SAI_IS_F4(sai->pdata)) {
@@ -1064,9 +1084,13 @@ static void stm32_sai_shutdown(struct snd_pcm_substream *substream,
regmap_update_bits(sai->regmap, STM_SAI_CR1_REGX, SAI_XCR1_NODIV,
SAI_XCR1_NODIV);
- clk_disable_unprepare(sai->sai_ck);
+ /* Release mclk rate only if rate was actually set */
+ if (sai->mclk_rate) {
+ clk_rate_exclusive_put(sai->sai_mclk);
+ sai->mclk_rate = 0;
+ }
- clk_rate_exclusive_put(sai->sai_mclk);
+ clk_disable_unprepare(sai->sai_ck);
sai->substream = NULL;
}
--
2.7.4

View File

@ -0,0 +1,101 @@
From c38f0f42372e03b8b284804190fdf53ce02722db Mon Sep 17 00:00:00 2001
From: Romuald JEANNE <romuald.jeanne@st.com>
Date: Mon, 10 Dec 2018 15:53:55 +0100
Subject: [PATCH 45/52] ARM: stm32mp1-r0-rc3: DEFCONFIG
---
arch/arm/configs/fragment-02-multiv7_addons.config | 39 +++++++++++++++++-----
1 file changed, 31 insertions(+), 8 deletions(-)
diff --git a/arch/arm/configs/fragment-02-multiv7_addons.config b/arch/arm/configs/fragment-02-multiv7_addons.config
index 4470d85..6ae0453 100644
--- a/arch/arm/configs/fragment-02-multiv7_addons.config
+++ b/arch/arm/configs/fragment-02-multiv7_addons.config
@@ -98,7 +98,10 @@ CONFIG_CAN_M_CAN=y
#
# Bluetooth device drivers
#
-
+CONFIG_BT_RTL=m
+CONFIG_BT_HCIBTUSB=m
+CONFIG_BT_HCIBTUSB=m
+CONFIG_BT_HCIBTUSB_RTL=y
#
# Device Drivers
#
@@ -138,7 +141,12 @@ CONFIG_CHR_DEV_SG=y
# MII PHY device drivers
#
# CONFIG_REALTEK_PHY is not set
-
+CONFIG_RTL_CARDS=m
+CONFIG_RTL8192CU=m
+CONFIG_RTLWIFI=m
+CONFIG_RTLWIFI_USB=m
+CONFIG_RTLWIFI_DEBUG=y
+CONFIG_RTL8192C_COMMON=m
#
# Input Device Drivers
#
@@ -271,14 +279,14 @@ CONFIG_VIDEO_OV5640=y
#
# Display Panels
#
-CONFIG_DRM_PANEL_ORISETECH_OTM8009A=m
-CONFIG_DRM_PANEL_RAYDIUM_RM68200=m
+CONFIG_DRM_PANEL_ORISETECH_OTM8009A=y
+CONFIG_DRM_PANEL_RAYDIUM_RM68200=y
#
# Display Interface Bridges
#
-CONFIG_VIDEO_ADV7511=m
-CONFIG_DRM_SII902X=m
+CONFIG_VIDEO_ADV7511=y
+CONFIG_DRM_SII902X=y
#
# Frame buffer hardware drivers
@@ -287,8 +295,8 @@ CONFIG_DRM_SII902X=m
#
# Console display driver support
#
-CONFIG_DRM_STM=m
-CONFIG_DRM_STM_DSI=m
+CONFIG_DRM_STM=y
+CONFIG_DRM_STM_DSI=y
#
# Backlight support
@@ -359,6 +367,8 @@ CONFIG_USB_CONFIGFS=y
# File systems
#
CONFIG_OVERLAY_FS=y
+# CONFIG_MTD_SPI_NOR_USE_4K_SECTORS is not set
+CONFIG_JFFS2_FS=y
#
# Pseudo filesystems
@@ -452,6 +462,19 @@ CONFIG_REGULATOR_STM32_VREFBUF=y
CONFIG_NVMEM_STM32_ROMEM=y
#
+# STM32 CORESIGHT
+#
+CONFIG_STM_SOURCE_CONSOLE=y
+CONFIG_STM_SOURCE_FTRACE=y
+CONFIG_FUNCTION_TRACER=y
+CONFIG_CORESIGHT=y
+CONFIG_CORESIGHT_LINK_AND_SINK_TMC=y
+CONFIG_CORESIGHT_SINK_TPIU=y
+CONFIG_CORESIGHT_SINK_ETBV10=y
+CONFIG_CORESIGHT_SOURCE_ETM3X=y
+CONFIG_CORESIGHT_STM=y
+
+#
# STM32 IPCC
#
CONFIG_STM32_IPCC=y
--
2.7.4

View File

@ -0,0 +1,25 @@
From 1c6166a178939316cfdd437f8c999616ddf9a7bd Mon Sep 17 00:00:00 2001
From: Romuald JEANNE <romuald.jeanne@st.com>
Date: Fri, 21 Dec 2018 16:57:57 +0100
Subject: [PATCH 46/52] ARM: stm32mp1-r0-rc4: MMC MTD
---
drivers/mmc/host/mmci.c | 2 ++
1 file changed, 2 insertions(+)
diff --git a/drivers/mmc/host/mmci.c b/drivers/mmc/host/mmci.c
index 6c2b1a0..0b7b607 100644
--- a/drivers/mmc/host/mmci.c
+++ b/drivers/mmc/host/mmci.c
@@ -2072,6 +2072,8 @@ static int mmci_probe(struct amba_device *dev,
else if (plat->ocr_mask)
dev_warn(mmc_dev(mmc), "Platform OCR mask is ignored\n");
+ host->pwr_reg = readl_relaxed(host->base + MMCIPOWER);
+
/* We support these capabilities. */
mmc->caps |= MMC_CAP_CMD23;
--
2.7.4

View File

@ -0,0 +1,47 @@
From 41d9204c142d8245f898ca877b4e4044d5db2426 Mon Sep 17 00:00:00 2001
From: Romuald JEANNE <romuald.jeanne@st.com>
Date: Fri, 21 Dec 2018 16:58:12 +0100
Subject: [PATCH 47/52] ARM: stm32mp1-r0-rc4: PINCTRL PWM RESET RTC
---
drivers/pinctrl/pinctrl-stmfx.c | 10 ++++++----
1 file changed, 6 insertions(+), 4 deletions(-)
diff --git a/drivers/pinctrl/pinctrl-stmfx.c b/drivers/pinctrl/pinctrl-stmfx.c
index 15d5757..b68fece 100644
--- a/drivers/pinctrl/pinctrl-stmfx.c
+++ b/drivers/pinctrl/pinctrl-stmfx.c
@@ -542,6 +542,7 @@ static irqreturn_t stmfx_pinctrl_irq_thread_fn(int irq, void *dev_id)
struct stmfx_pinctrl *pctl = (struct stmfx_pinctrl *)dev_id;
struct gpio_chip *gc = &pctl->gpio_chip;
u8 pending[NR_GPIO_REGS];
+ u8 src[NR_GPIO_REGS] = {0, 0, 0};
unsigned long n, status;
int ret;
@@ -550,10 +551,8 @@ static irqreturn_t stmfx_pinctrl_irq_thread_fn(int irq, void *dev_id)
if (ret)
return IRQ_NONE;
- ret = regmap_bulk_write(pctl->stmfx->map, STMFX_REG_IRQ_GPI_ACK,
- pending, NR_GPIO_REGS);
- if (ret)
- return IRQ_NONE;
+ regmap_bulk_write(pctl->stmfx->map, STMFX_REG_IRQ_GPI_SRC,
+ src, NR_GPIO_REGS);
status = *(unsigned long *)pending;
for_each_set_bit(n, &status, gc->ngpio) {
@@ -561,6 +560,9 @@ static irqreturn_t stmfx_pinctrl_irq_thread_fn(int irq, void *dev_id)
stmfx_pinctrl_irq_toggle_trigger(pctl, n);
}
+ regmap_bulk_write(pctl->stmfx->map, STMFX_REG_IRQ_GPI_SRC,
+ pctl->irq_gpi_src, NR_GPIO_REGS);
+
return IRQ_HANDLED;
}
--
2.7.4

View File

@ -0,0 +1,100 @@
From 457cfdb049a39670f15df8cae1d78a2479962ef9 Mon Sep 17 00:00:00 2001
From: Romuald JEANNE <romuald.jeanne@st.com>
Date: Fri, 21 Dec 2018 16:57:38 +0100
Subject: [PATCH 48/52] ARM: stm32mp1-r0-rc4: REMOTEPROC RPMSG
---
drivers/remoteproc/rproc_srm_core.c | 2 +-
drivers/remoteproc/stm32_rproc.c | 40 +++++++++++++++++++++++++++----------
2 files changed, 30 insertions(+), 12 deletions(-)
diff --git a/drivers/remoteproc/rproc_srm_core.c b/drivers/remoteproc/rproc_srm_core.c
index 66be92e..fc61e8b 100644
--- a/drivers/remoteproc/rproc_srm_core.c
+++ b/drivers/remoteproc/rproc_srm_core.c
@@ -189,7 +189,7 @@ static int rproc_srm_core_prepare(struct rproc_subdev *subdev)
/* Wait for every child to be bound */
if (!wait_for_completion_timeout(&rproc_srm_core->all_bound,
msecs_to_jiffies(BIND_TIMEOUT))) {
- dev_err(dev, "bind timeout\n");
+ dev_err(dev, "failed to bind one or more system resource device(s)\n");
ret = -ETIMEDOUT;
goto master;
}
diff --git a/drivers/remoteproc/stm32_rproc.c b/drivers/remoteproc/stm32_rproc.c
index 9a7e034..70b7e55c 100644
--- a/drivers/remoteproc/stm32_rproc.c
+++ b/drivers/remoteproc/stm32_rproc.c
@@ -196,22 +196,12 @@ static int stm32_rproc_mbox_idx(struct rproc *rproc, const unsigned char *name)
static int stm32_rproc_elf_load_rsc_table(struct rproc *rproc,
const struct firmware *fw)
{
- int status, i;
+ int status;
struct resource_table *table = NULL;
struct stm32_rproc *ddata = rproc->priv;
size_t tablesz = 0;
- const struct elf32_hdr *ehdr;
- const struct elf32_phdr *phdr;
if (!rproc->early_boot) {
- /* set coredump segments */
- ehdr = (const struct elf32_hdr *)fw->data;
- phdr = (const struct elf32_phdr *)(fw->data + ehdr->e_phoff);
- for (i = 0; i < ehdr->e_phnum; i++, phdr++)
- rproc_coredump_add_segment(rproc, phdr->p_paddr,
- phdr->p_memsz);
-
- /* load resource table */
status = rproc_elf_load_rsc_table(rproc, fw);
if (status)
goto no_rsc_table;
@@ -276,6 +266,10 @@ static int stm32_rproc_parse_fw(struct rproc *rproc, const struct firmware *fw)
stm32_rproc_mem_alloc,
stm32_rproc_mem_release,
it.node->name);
+
+ if (mem)
+ rproc_coredump_add_segment(rproc, da,
+ rmem->size);
} else {
/* Register reserved memory for vdev buffer alloc */
mem = rproc_of_resm_mem_entry_init(dev, index,
@@ -436,10 +430,34 @@ static int stm32_rproc_set_hold_boot(struct rproc *rproc, bool hold)
return err;
}
+static void stm32_rproc_add_coredump_trace(struct rproc *rproc)
+{
+ struct rproc_debug_trace *trace;
+ struct rproc_dump_segment *segment;
+ bool already_added;
+
+ list_for_each_entry(trace, &rproc->traces, node) {
+ already_added = false;
+
+ list_for_each_entry(segment, &rproc->dump_segments, node) {
+ if (segment->da == trace->trace_mem.da) {
+ already_added = true;
+ break;
+ }
+ }
+
+ if (!already_added)
+ rproc_coredump_add_segment(rproc, trace->trace_mem.da,
+ trace->trace_mem.len);
+ }
+}
+
static int stm32_rproc_start(struct rproc *rproc)
{
int err;
+ stm32_rproc_add_coredump_trace(rproc);
+
/*
* If M4 previously started by bootloader, just guarantee holdboot
* is set to catch any crash.
--
2.7.4

View File

@ -0,0 +1,112 @@
From 06f5ef8ca4c11074b595a4318dba9766092886d5 Mon Sep 17 00:00:00 2001
From: Romuald JEANNE <romuald.jeanne@st.com>
Date: Fri, 21 Dec 2018 16:58:47 +0100
Subject: [PATCH 49/52] ARM: stm32mp1-r0-rc4: SOUND
---
sound/soc/codecs/wm8994.c | 3 +--
sound/soc/stm/stm32_sai_sub.c | 21 ++++++++++++++++++++-
2 files changed, 21 insertions(+), 3 deletions(-)
diff --git a/sound/soc/codecs/wm8994.c b/sound/soc/codecs/wm8994.c
index eb222da..c83ae39 100644
--- a/sound/soc/codecs/wm8994.c
+++ b/sound/soc/codecs/wm8994.c
@@ -868,7 +868,7 @@ static int mclk_event(struct snd_soc_dapm_widget *w,
break;
case SND_SOC_DAPM_POST_PMD:
dev_dbg(comp->dev, "Disable master clock %s\n",
- mclk_id ? "MCLK1" : "MCLK2");
+ mclk_id ? "MCLK2" : "MCLK1");
clk_disable_unprepare(mclk);
break;
}
@@ -1193,7 +1193,6 @@ static int aif2clk_ev(struct snd_soc_dapm_widget *w,
else
adc = WM8994_AIF2ADCL_ENA | WM8994_AIF2ADCR_ENA;
-
val = snd_soc_component_read32(component, WM8994_AIF2_CONTROL_2);
if ((val & WM8994_AIF2DACL_SRC) &&
(val & WM8994_AIF2DACR_SRC))
diff --git a/sound/soc/stm/stm32_sai_sub.c b/sound/soc/stm/stm32_sai_sub.c
index 3f0540a..a9b37f9 100644
--- a/sound/soc/stm/stm32_sai_sub.c
+++ b/sound/soc/stm/stm32_sai_sub.c
@@ -102,6 +102,7 @@
* @spdif_frm_cnt: S/PDIF playback frame counter
* @snd_aes_iec958: iec958 data
* @ctrl_lock: control lock
+ * @spinlock_t: prevent race condition with IRQ
*/
struct stm32_sai_sub_data {
struct platform_device *pdev;
@@ -133,6 +134,7 @@ struct stm32_sai_sub_data {
unsigned int spdif_frm_cnt;
struct snd_aes_iec958 iec958;
struct mutex ctrl_lock; /* protect resources accessed by controls */
+ spinlock_t irq_lock; /* used to prevent race condition with IRQ */
};
enum stm32_sai_fifo_th {
@@ -497,8 +499,10 @@ static irqreturn_t stm32_sai_isr(int irq, void *devid)
status = SNDRV_PCM_STATE_XRUN;
}
- if (status != SNDRV_PCM_STATE_RUNNING)
+ spin_lock(&sai->irq_lock);
+ if (status != SNDRV_PCM_STATE_RUNNING && sai->substream)
snd_pcm_stop_xrun(sai->substream);
+ spin_unlock(&sai->irq_lock);
return IRQ_HANDLED;
}
@@ -703,8 +707,19 @@ static int stm32_sai_startup(struct snd_pcm_substream *substream,
{
struct stm32_sai_sub_data *sai = snd_soc_dai_get_drvdata(cpu_dai);
int imr, cr2, ret;
+ unsigned long flags;
+ spin_lock_irqsave(&sai->irq_lock, flags);
sai->substream = substream;
+ spin_unlock_irqrestore(&sai->irq_lock, flags);
+
+ if (STM_SAI_PROTOCOL_IS_SPDIF(sai)) {
+ snd_pcm_hw_constraint_mask64(substream->runtime,
+ SNDRV_PCM_HW_PARAM_FORMAT,
+ SNDRV_PCM_FMTBIT_S32_LE);
+ snd_pcm_hw_constraint_single(substream->runtime,
+ SNDRV_PCM_HW_PARAM_CHANNELS, 2);
+ }
ret = clk_prepare_enable(sai->sai_ck);
if (ret < 0) {
@@ -1078,6 +1093,7 @@ static void stm32_sai_shutdown(struct snd_pcm_substream *substream,
struct snd_soc_dai *cpu_dai)
{
struct stm32_sai_sub_data *sai = snd_soc_dai_get_drvdata(cpu_dai);
+ unsigned long flags;
regmap_update_bits(sai->regmap, STM_SAI_IMR_REGX, SAI_XIMR_MASK, 0);
@@ -1092,7 +1108,9 @@ static void stm32_sai_shutdown(struct snd_pcm_substream *substream,
clk_disable_unprepare(sai->sai_ck);
+ spin_lock_irqsave(&sai->irq_lock, flags);
sai->substream = NULL;
+ spin_unlock_irqrestore(&sai->irq_lock, flags);
}
static int stm32_sai_pcm_new(struct snd_soc_pcm_runtime *rtd,
@@ -1459,6 +1477,7 @@ static int stm32_sai_sub_probe(struct platform_device *pdev)
sai->pdev = pdev;
mutex_init(&sai->ctrl_lock);
+ spin_lock_init(&sai->irq_lock);
platform_set_drvdata(pdev, sai);
sai->pdata = dev_get_drvdata(pdev->dev.parent);
--
2.7.4

View File

@ -0,0 +1,266 @@
From fc74bada7f6940619f8930556b7c61fe618f2a64 Mon Sep 17 00:00:00 2001
From: Romuald JEANNE <romuald.jeanne@st.com>
Date: Fri, 21 Dec 2018 16:56:27 +0100
Subject: [PATCH 50/52] ARM: stm32mp1-r0-rc4: USB
---
Documentation/devicetree/bindings/usb/dwc2.txt | 2 +
drivers/usb/dwc2/core.h | 11 ++++
drivers/usb/dwc2/core_intr.c | 4 +-
drivers/usb/dwc2/hw.h | 2 +
drivers/usb/dwc2/params.c | 7 ++-
drivers/usb/dwc2/platform.c | 74 +++++++++++++++++++++++---
6 files changed, 90 insertions(+), 10 deletions(-)
diff --git a/Documentation/devicetree/bindings/usb/dwc2.txt b/Documentation/devicetree/bindings/usb/dwc2.txt
index 32b245c..03c62de 100644
--- a/Documentation/devicetree/bindings/usb/dwc2.txt
+++ b/Documentation/devicetree/bindings/usb/dwc2.txt
@@ -43,6 +43,8 @@ Refer to phy/phy-bindings.txt for generic phy consumer properties
doesn't drive it.
- usb33d-supply: external VBUS and ID sensing comparators supply, in order to
perform OTG operation, used on STM32MP1 SoCs.
+- force-b-session-valid: force B-peripheral session instead of relying on
+ VBUS sensing (only valid when dr_mode = "peripheral").
Deprecated properties:
- g-use-dma: gadget DMA mode is automatically detected
diff --git a/drivers/usb/dwc2/core.h b/drivers/usb/dwc2/core.h
index 4c689d1..4c1736f 100644
--- a/drivers/usb/dwc2/core.h
+++ b/drivers/usb/dwc2/core.h
@@ -415,6 +415,12 @@ enum dwc2_ep0_state {
* in DWORDS with possible values from from
* 16-32768 (default: 256, 256, 256, 256, 768,
* 768, 768, 768, 0, 0, 0, 0, 0, 0, 0).
+ * @force_b_session_valid: force B-peripheral session instead of relying on
+ * VBUS sensing (only valid when dr_mode = "peripheral").
+ * @suspend_ignore_power_down: prevent the controller to enter low power mode
+ * upon suspend interrupt. This may help in device mode,
+ * when suspend (3ms idle bus) gets detected before
+ * device session end (VBUS discharge > 3ms).
* @change_speed_quirk: Change speed configuration to DWC2_SPEED_PARAM_FULL
* while full&low speed device connect. And change speed
* back to DWC2_SPEED_PARAM_HIGH while device is gone.
@@ -492,6 +498,8 @@ struct dwc2_core_params {
u32 g_rx_fifo_size;
u32 g_np_tx_fifo_size;
u32 g_tx_fifo_size[MAX_EPS_CHANNELS];
+ bool force_b_session_valid;
+ bool suspend_ignore_power_down;
bool change_speed_quirk;
};
@@ -849,6 +857,8 @@ struct dwc2_hregs_backup {
* removed once all SoCs support usb transceiver.
* @supplies: Definition of USB power supplies
* @vbus_supply: Regulator supplying vbus.
+ * @usb33d: Optional 3.3v regulator used on some stm32 devices to
+ * supply ID and VBUS detection hardware.
* @phyif: PHY interface width
* @lock: Spinlock that protects all the driver data structures
* @priv: Stores a pointer to the struct usb_hcd
@@ -1032,6 +1042,7 @@ struct dwc2_hsotg {
struct dwc2_hsotg_plat *plat;
struct regulator_bulk_data supplies[DWC2_NUM_SUPPLIES];
struct regulator *vbus_supply;
+ struct regulator *usb33d;
u32 phyif;
spinlock_t lock;
diff --git a/drivers/usb/dwc2/core_intr.c b/drivers/usb/dwc2/core_intr.c
index 19ae259..7b4162c 100644
--- a/drivers/usb/dwc2/core_intr.c
+++ b/drivers/usb/dwc2/core_intr.c
@@ -492,7 +492,9 @@ static void dwc2_handle_usb_suspend_intr(struct dwc2_hsotg *hsotg)
hsotg->hw_params.hibernation);
/* Ignore suspend request before enumeration */
- if (!dwc2_is_device_connected(hsotg)) {
+ if (!dwc2_is_device_connected(hsotg) ||
+ hsotg->params.force_b_session_valid ||
+ hsotg->params.suspend_ignore_power_down) {
dev_dbg(hsotg->dev,
"ignore suspend request before enumeration\n");
return;
diff --git a/drivers/usb/dwc2/hw.h b/drivers/usb/dwc2/hw.h
index afde335..31f8c60 100644
--- a/drivers/usb/dwc2/hw.h
+++ b/drivers/usb/dwc2/hw.h
@@ -54,6 +54,8 @@
#define GOTGCTL_HSTSETHNPEN BIT(10)
#define GOTGCTL_HNPREQ BIT(9)
#define GOTGCTL_HSTNEGSCS BIT(8)
+#define GOTGCTL_BVALOVAL BIT(7)
+#define GOTGCTL_BVALOEN BIT(6)
#define GOTGCTL_SESREQ BIT(1)
#define GOTGCTL_SESREQSCS BIT(0)
diff --git a/drivers/usb/dwc2/params.c b/drivers/usb/dwc2/params.c
index 63ccfc9..7fef905 100644
--- a/drivers/usb/dwc2/params.c
+++ b/drivers/usb/dwc2/params.c
@@ -167,7 +167,7 @@ static void dwc2_set_stm32mp1_hsotg_params(struct dwc2_hsotg *hsotg)
p->host_rx_fifo_size = 440;
p->host_nperio_tx_fifo_size = 256;
p->host_perio_tx_fifo_size = 256;
- p->power_down = false;
+ p->suspend_ignore_power_down = true;
}
const struct of_device_id dwc2_of_match_table[] = {
@@ -404,6 +404,11 @@ static void dwc2_get_device_properties(struct dwc2_hsotg *hsotg)
if (of_find_property(hsotg->dev->of_node, "disable-over-current", NULL))
p->oc_disable = true;
+
+ if (hsotg->dr_mode == USB_DR_MODE_PERIPHERAL)
+ p->force_b_session_valid =
+ of_property_read_bool(hsotg->dev->of_node,
+ "force-b-session-valid");
}
static void dwc2_check_param_otg_cap(struct dwc2_hsotg *hsotg)
diff --git a/drivers/usb/dwc2/platform.c b/drivers/usb/dwc2/platform.c
index 2061254..b2e5ddc 100644
--- a/drivers/usb/dwc2/platform.c
+++ b/drivers/usb/dwc2/platform.c
@@ -324,6 +324,10 @@ static int dwc2_driver_remove(struct platform_device *dev)
if (hsotg->gadget_enabled)
dwc2_hsotg_remove(hsotg);
+ if (hsotg->params.activate_stm_id_vb_detection &&
+ !hsotg->params.force_b_session_valid)
+ regulator_disable(hsotg->usb33d);
+
if (hsotg->ll_hw_enabled)
dwc2_lowlevel_hw_disable(hsotg);
@@ -474,18 +478,18 @@ static int dwc2_driver_probe(struct platform_device *dev)
if (retval)
goto error;
- if (hsotg->params.activate_stm_id_vb_detection) {
- struct regulator *usb33d;
+ if (hsotg->params.activate_stm_id_vb_detection &&
+ !hsotg->params.force_b_session_valid) {
u32 ggpio;
- usb33d = devm_regulator_get(hsotg->dev, "usb33d");
- if (IS_ERR(usb33d)) {
- retval = PTR_ERR(usb33d);
+ hsotg->usb33d = devm_regulator_get(hsotg->dev, "usb33d");
+ if (IS_ERR(hsotg->usb33d)) {
+ retval = PTR_ERR(hsotg->usb33d);
dev_err(hsotg->dev,
"can't get voltage level detector supply\n");
goto error;
}
- retval = regulator_enable(usb33d);
+ retval = regulator_enable(hsotg->usb33d);
if (retval) {
dev_err(hsotg->dev,
"can't enable voltage level detector supply\n");
@@ -498,6 +502,15 @@ static int dwc2_driver_probe(struct platform_device *dev)
dwc2_writel(hsotg, ggpio, GGPIO);
}
+ if (hsotg->params.force_b_session_valid) {
+ u32 gotgctl;
+
+ gotgctl = dwc2_readl(hsotg, GOTGCTL);
+ gotgctl |= GOTGCTL_BVALOVAL; /* B-peripheral session value */
+ gotgctl |= GOTGCTL_BVALOEN; /* B-peripheral override enable */
+ dwc2_writel(hsotg, gotgctl, GOTGCTL);
+ }
+
if (hsotg->params.activate_stm_fs_transceiver) {
u32 ggpio;
@@ -516,7 +529,7 @@ static int dwc2_driver_probe(struct platform_device *dev)
if (hsotg->dr_mode != USB_DR_MODE_HOST) {
retval = dwc2_gadget_init(hsotg);
if (retval)
- goto error;
+ goto error_init;
hsotg->gadget_enabled = 1;
}
@@ -525,7 +538,7 @@ static int dwc2_driver_probe(struct platform_device *dev)
if (retval) {
if (hsotg->gadget_enabled)
dwc2_hsotg_remove(hsotg);
- goto error;
+ goto error_init;
}
hsotg->hcd_enabled = 1;
}
@@ -541,6 +554,10 @@ static int dwc2_driver_probe(struct platform_device *dev)
return 0;
+error_init:
+ if (hsotg->params.activate_stm_id_vb_detection &&
+ !hsotg->params.force_b_session_valid)
+ regulator_disable(hsotg->usb33d);
error:
dwc2_lowlevel_hw_disable(hsotg);
return retval;
@@ -554,6 +571,18 @@ static int __maybe_unused dwc2_suspend(struct device *dev)
if (dwc2_is_device_mode(dwc2))
dwc2_hsotg_suspend(dwc2);
+ if (dwc2->params.activate_stm_id_vb_detection &&
+ !dwc2->params.force_b_session_valid) {
+ u32 ggpio;
+
+ ggpio = dwc2_readl(dwc2, GGPIO);
+ ggpio &= ~GGPIO_STM32_OTG_GCCFG_IDEN;
+ ggpio &= ~GGPIO_STM32_OTG_GCCFG_VBDEN;
+ dwc2_writel(dwc2, ggpio, GGPIO);
+
+ regulator_disable(dwc2->usb33d);
+ }
+
if (dwc2->ll_hw_enabled)
ret = __dwc2_lowlevel_hw_disable(dwc2);
@@ -571,6 +600,35 @@ static int __maybe_unused dwc2_resume(struct device *dev)
return ret;
}
+ /* Need to restore FORCEDEVMODE/FORCEHOSTMODE */
+ dwc2_force_dr_mode(dwc2);
+
+ if (dwc2->params.activate_stm_id_vb_detection &&
+ !dwc2->params.force_b_session_valid) {
+ u32 ggpio;
+
+ ret = regulator_enable(dwc2->usb33d);
+ if (ret)
+ return ret;
+
+ ggpio = dwc2_readl(dwc2, GGPIO);
+ ggpio |= GGPIO_STM32_OTG_GCCFG_IDEN;
+ ggpio |= GGPIO_STM32_OTG_GCCFG_VBDEN;
+ dwc2_writel(dwc2, ggpio, GGPIO);
+
+ /* ID/VBUS detection startup time */
+ usleep_range(5000, 7000);
+ }
+
+ if (dwc2->params.force_b_session_valid) {
+ u32 gotgctl;
+
+ gotgctl = dwc2_readl(dwc2, GOTGCTL);
+ gotgctl |= GOTGCTL_BVALOVAL; /* B-peripheral session value */
+ gotgctl |= GOTGCTL_BVALOEN; /* B-peripheral override enable */
+ dwc2_writel(dwc2, gotgctl, GOTGCTL);
+ }
+
if (dwc2_is_device_mode(dwc2))
ret = dwc2_hsotg_resume(dwc2);
--
2.7.4

View File

@ -0,0 +1,607 @@
From a3f6ac74fe67cfacb73bda2ba631d1e5e2680988 Mon Sep 17 00:00:00 2001
From: Romuald JEANNE <romuald.jeanne@st.com>
Date: Fri, 21 Dec 2018 16:56:44 +0100
Subject: [PATCH 51/52] ARM: stm32mp1-r0-rc4: DEVICETREE
---
arch/arm/boot/dts/stm32mp157a-dk1.dts | 14 ++--
arch/arm/boot/dts/stm32mp157c-ed1.dts | 9 ---
arch/arm/boot/dts/stm32mp157c-ev1.dts | 2 -
arch/arm/boot/dts/stm32mp157c-m4-srm.dtsi | 122 +++++++++++++++---------------
arch/arm/boot/dts/stm32mp157c.dtsi | 2 +-
5 files changed, 67 insertions(+), 82 deletions(-)
diff --git a/arch/arm/boot/dts/stm32mp157a-dk1.dts b/arch/arm/boot/dts/stm32mp157a-dk1.dts
index 0a6cf35..7e911f3 100644
--- a/arch/arm/boot/dts/stm32mp157a-dk1.dts
+++ b/arch/arm/boot/dts/stm32mp157a-dk1.dts
@@ -77,11 +77,6 @@
};
};
- iio-hwmon {
- compatible = "iio-hwmon";
- io-channels = <&adc_temp>;
- };
-
sram: sram@10050000 {
compatible = "mmio-sram";
reg = <0x10050000 0x10000>;
@@ -174,6 +169,10 @@
sram = <&dma_pool>;
};
+&dts {
+ status = "okay";
+};
+
&ethernet0 {
status = "okay";
pinctrl-0 = <&ethernet0_rgmii_pins_a>;
@@ -198,10 +197,6 @@
status = "okay";
};
-&hsem {
- status = "okay";
-};
-
&i2c1 {
pinctrl-names = "default", "sleep";
pinctrl-0 = <&i2c1_pins_a>;
@@ -679,6 +674,7 @@
&usbotg_hs {
dr_mode = "peripheral";
+ force-b-session-valid;
phys = <&usbphyc_port1 0>;
phy-names = "usb2-phy";
status = "okay";
diff --git a/arch/arm/boot/dts/stm32mp157c-ed1.dts b/arch/arm/boot/dts/stm32mp157c-ed1.dts
index 798580e..cf2750e 100644
--- a/arch/arm/boot/dts/stm32mp157c-ed1.dts
+++ b/arch/arm/boot/dts/stm32mp157c-ed1.dts
@@ -74,11 +74,6 @@
serial0 = &uart4;
};
- iio-hwmon {
- compatible = "iio-hwmon";
- io-channels = <&adc_temp>;
- };
-
sram: sram@10050000 {
compatible = "mmio-sram";
reg = <0x10050000 0x10000>;
@@ -173,10 +168,6 @@
status = "okay";
};
-&hsem {
- status = "okay";
-};
-
&i2c4 {
pinctrl-names = "default", "sleep";
pinctrl-0 = <&i2c4_pins_a>;
diff --git a/arch/arm/boot/dts/stm32mp157c-ev1.dts b/arch/arm/boot/dts/stm32mp157c-ev1.dts
index 49a62aa..18742e8 100644
--- a/arch/arm/boot/dts/stm32mp157c-ev1.dts
+++ b/arch/arm/boot/dts/stm32mp157c-ev1.dts
@@ -177,7 +177,6 @@
pinctrl-names = "default", "sleep";
pinctrl-0 = <&cec_pins_a>;
pinctrl-1 = <&cec_pins_sleep_a>;
- status = "okay";
};
&dcmi {
@@ -530,7 +529,6 @@
pinctrl-1 = <&i2c5_pins_sleep_a>;
i2c-scl-rising-time-ns = <185>;
i2c-scl-falling-time-ns = <20>;
- status = "okay";
/delete-property/dmas;
/delete-property/dma-names;
};
diff --git a/arch/arm/boot/dts/stm32mp157c-m4-srm.dtsi b/arch/arm/boot/dts/stm32mp157c-m4-srm.dtsi
index a1d132d0..5ebe24b 100644
--- a/arch/arm/boot/dts/stm32mp157c-m4-srm.dtsi
+++ b/arch/arm/boot/dts/stm32mp157c-m4-srm.dtsi
@@ -5,106 +5,106 @@
m4_timers2: timer@40000000 {
compatible = "rproc-srm-dev";
- reg = <0x40000000 0x400>;
+ reg = <0x40000000>;
clocks = <&rcc TIM2_K>;
clock-names = "int";
status = "disabled";
};
m4_timers3: timer@40001000 {
compatible = "rproc-srm-dev";
- reg = <0x40001000 0x400>;
+ reg = <0x40001000>;
clocks = <&rcc TIM3_K>;
clock-names = "int";
status = "disabled";
};
m4_timers4: timer@40002000 {
compatible = "rproc-srm-dev";
- reg = <0x40002000 0x400>;
+ reg = <0x40002000>;
clocks = <&rcc TIM4_K>;
clock-names = "int";
status = "disabled";
};
m4_timers5: timer@40003000 {
compatible = "rproc-srm-dev";
- reg = <0x40003000 0x400>;
+ reg = <0x40003000>;
clocks = <&rcc TIM5_K>;
clock-names = "int";
status = "disabled";
};
m4_timers6: timer@40004000 {
compatible = "rproc-srm-dev";
- reg = <0x40004000 0x400>;
+ reg = <0x40004000>;
clocks = <&rcc TIM6_K>;
clock-names = "int";
status = "disabled";
};
m4_timers7: timer@40005000 {
compatible = "rproc-srm-dev";
- reg = <0x40005000 0x400>;
+ reg = <0x40005000>;
clocks = <&rcc TIM7_K>;
clock-names = "int";
status = "disabled";
};
m4_timers12: timer@40006000 {
compatible = "rproc-srm-dev";
- reg = <0x40006000 0x400>;
+ reg = <0x40006000>;
clocks = <&rcc TIM12_K>;
clock-names = "int";
status = "disabled";
};
m4_timers13: timer@40007000 {
compatible = "rproc-srm-dev";
- reg = <0x40007000 0x400>;
+ reg = <0x40007000>;
clocks = <&rcc TIM13_K>;
clock-names = "int";
status = "disabled";
};
m4_timers14: timer@40008000 {
compatible = "rproc-srm-dev";
- reg = <0x40008000 0x400>;
+ reg = <0x40008000>;
clocks = <&rcc TIM14_K>;
clock-names = "int";
status = "disabled";
};
m4_lptimer1: timer@40009000 {
compatible = "rproc-srm-dev";
- reg = <0x40009000 0x400>;
+ reg = <0x40009000>;
clocks = <&rcc LPTIM1_K>;
clock-names = "mux";
status = "disabled";
};
m4_spi2: spi@4000b000 {
compatible = "rproc-srm-dev";
- reg = <0x4000b000 0x400>;
+ reg = <0x4000b000>;
clocks = <&rcc SPI2_K>;
status = "disabled";
};
m4_i2s2: audio-controller@4000b000 {
compatible = "rproc-srm-dev";
- reg = <0x4000b000 0x400>;
+ reg = <0x4000b000>;
status = "disabled";
};
m4_spi3: spi@4000c000 {
compatible = "rproc-srm-dev";
- reg = <0x4000c000 0x400>;
+ reg = <0x4000c000>;
clocks = <&rcc SPI3_K>;
status = "disabled";
};
m4_i2s3: audio-controller@4000c000 {
compatible = "rproc-srm-dev";
- reg = <0x4000c000 0x400>;
+ reg = <0x4000c000>;
status = "disabled";
};
m4_spdifrx: audio-controller@4000d000 {
compatible = "rproc-srm-dev";
- reg = <0x4000d000 0x400>;
+ reg = <0x4000d000>;
clocks = <&rcc SPDIF_K>;
clock-names = "kclk";
status = "disabled";
};
m4_usart2: serial@4000e000 {
compatible = "rproc-srm-dev";
- reg = <0x4000e000 0x400>;
+ reg = <0x4000e000>;
interrupt-parent = <&exti>;
interrupts = <27 1>;
clocks = <&rcc USART2_K>;
@@ -112,7 +112,7 @@
};
m4_usart3: serial@4000f000 {
compatible = "rproc-srm-dev";
- reg = <0x4000f000 0x400>;
+ reg = <0x4000f000>;
interrupt-parent = <&exti>;
interrupts = <28 1>;
clocks = <&rcc USART3_K>;
@@ -120,7 +120,7 @@
};
m4_uart4: serial@40010000 {
compatible = "rproc-srm-dev";
- reg = <0x40010000 0x400>;
+ reg = <0x40010000>;
interrupt-parent = <&exti>;
interrupts = <30 1>;
clocks = <&rcc UART4_K>;
@@ -128,7 +128,7 @@
};
m4_uart5: serial@40011000 {
compatible = "rproc-srm-dev";
- reg = <0x40011000 0x400>;
+ reg = <0x40011000>;
interrupt-parent = <&exti>;
interrupts = <31 1>;
clocks = <&rcc UART5_K>;
@@ -136,7 +136,7 @@
};
m4_i2c1: i2c@40012000 {
compatible = "rproc-srm-dev";
- reg = <0x40012000 0x400>;
+ reg = <0x40012000>;
interrupt-parent = <&exti>;
interrupts = <21 1>;
clocks = <&rcc I2C1_K>;
@@ -144,7 +144,7 @@
};
m4_i2c2: i2c@40013000 {
compatible = "rproc-srm-dev";
- reg = <0x40013000 0x400>;
+ reg = <0x40013000>;
interrupt-parent = <&exti>;
interrupts = <22 1>;
clocks = <&rcc I2C2_K>;
@@ -152,7 +152,7 @@
};
m4_i2c3: i2c@40014000 {
compatible = "rproc-srm-dev";
- reg = <0x40014000 0x400>;
+ reg = <0x40014000>;
interrupt-parent = <&exti>;
interrupts = <23 1>;
clocks = <&rcc I2C3_K>;
@@ -160,7 +160,7 @@
};
m4_i2c5: i2c@40015000 {
compatible = "rproc-srm-dev";
- reg = <0x40015000 0x400>;
+ reg = <0x40015000>;
interrupt-parent = <&exti>;
interrupts = <25 1>;
clocks = <&rcc I2C5_K>;
@@ -168,7 +168,7 @@
};
m4_cec: cec@40016000 {
compatible = "rproc-srm-dev";
- reg = <0x40016000 0x400>;
+ reg = <0x40016000>;
interrupt-parent = <&exti>;
interrupts = <69 1>;
clocks = <&rcc CEC_K>, <&rcc CK_LSE>;
@@ -177,14 +177,14 @@
};
m4_dac: dac@40017000 {
compatible = "rproc-srm-dev";
- reg = <0x40017000 0x400>;
+ reg = <0x40017000>;
clocks = <&rcc DAC12>;
clock-names = "pclk";
status = "disabled";
};
m4_uart7: serial@40018000 {
compatible = "rproc-srm-dev";
- reg = <0x40018000 0x400>;
+ reg = <0x40018000>;
interrupt-parent = <&exti>;
interrupts = <32 1>;
clocks = <&rcc UART7_K>;
@@ -192,7 +192,7 @@
};
m4_uart8: serial@40019000 {
compatible = "rproc-srm-dev";
- reg = <0x40019000 0x400>;
+ reg = <0x40019000>;
interrupt-parent = <&exti>;
interrupts = <33 1>;
clocks = <&rcc UART8_K>;
@@ -200,21 +200,21 @@
};
m4_timers1: timer@44000000 {
compatible = "rproc-srm-dev";
- reg = <0x44000000 0x400>;
+ reg = <0x44000000>;
clocks = <&rcc TIM1_K>;
clock-names = "int";
status = "disabled";
};
m4_timers8: timer@44001000 {
compatible = "rproc-srm-dev";
- reg = <0x44001000 0x400>;
+ reg = <0x44001000>;
clocks = <&rcc TIM8_K>;
clock-names = "int";
status = "disabled";
};
m4_usart6: serial@44003000 {
compatible = "rproc-srm-dev";
- reg = <0x44003000 0x400>;
+ reg = <0x44003000>;
interrupt-parent = <&exti>;
interrupts = <29 1>;
clocks = <&rcc USART6_K>;
@@ -222,203 +222,203 @@
};
m4_spi1: spi@44004000 {
compatible = "rproc-srm-dev";
- reg = <0x44004000 0x400>;
+ reg = <0x44004000>;
clocks = <&rcc SPI1_K>;
status = "disabled";
};
m4_i2s1: audio-controller@44004000 {
compatible = "rproc-srm-dev";
- reg = <0x44004000 0x400>;
+ reg = <0x44004000>;
status = "disabled";
};
m4_spi4: spi@44005000 {
compatible = "rproc-srm-dev";
- reg = <0x44005000 0x400>;
+ reg = <0x44005000>;
clocks = <&rcc SPI4_K>;
status = "disabled";
};
m4_timers15: timer@44006000 {
compatible = "rproc-srm-dev";
- reg = <0x44006000 0x400>;
+ reg = <0x44006000>;
clocks = <&rcc TIM15_K>;
clock-names = "int";
status = "disabled";
};
m4_timers16: timer@44007000 {
compatible = "rproc-srm-dev";
- reg = <0x44007000 0x400>;
+ reg = <0x44007000>;
clocks = <&rcc TIM16_K>;
clock-names = "int";
status = "disabled";
};
m4_timers17: timer@44008000 {
compatible = "rproc-srm-dev";
- reg = <0x44008000 0x400>;
+ reg = <0x44008000>;
clocks = <&rcc TIM17_K>;
clock-names = "int";
status = "disabled";
};
m4_spi5: spi@44009000 {
compatible = "rproc-srm-dev";
- reg = <0x44009000 0x400>;
+ reg = <0x44009000>;
clocks = <&rcc SPI5_K>;
status = "disabled";
};
m4_sai1: sai@4400a000 {
compatible = "rproc-srm-dev";
- reg = <0x4400a000 0x4>;
+ reg = <0x4400a000>;
clocks = <&rcc SAI1_K>;
clock-names = "sai_ck";
status = "disabled";
};
m4_sai2: sai@4400b000 {
compatible = "rproc-srm-dev";
- reg = <0x4400b000 0x4>;
+ reg = <0x4400b000>;
clocks = <&rcc SAI2_K>;
clock-names = "sai_ck";
status = "disabled";
};
m4_sai3: sai@4400c000 {
compatible = "rproc-srm-dev";
- reg = <0x4400c000 0x4>;
+ reg = <0x4400c000>;
clocks = <&rcc SAI3_K>;
clock-names = "sai_ck";
status = "disabled";
};
m4_dfsdm: dfsdm@4400d000 {
compatible = "rproc-srm-dev";
- reg = <0x4400d000 0x800>;
+ reg = <0x4400d000>;
clocks = <&rcc DFSDM_K>;
clock-names = "dfsdm";
status = "disabled";
};
m4_m_can1: can@4400e000 {
compatible = "rproc-srm-dev";
- reg = <0x4400e000 0x400>, <0x44011000 0x2800>;
+ reg = <0x4400e000>, <0x44011000>;
clocks = <&rcc CK_HSE>, <&rcc FDCAN_K>;
clock-names = "hclk", "cclk";
status = "disabled";
};
m4_m_can2: can@4400f000 {
compatible = "rproc-srm-dev";
- reg = <0x4400f000 0x400>, <0x44011000 0x2800>;
+ reg = <0x4400f000>, <0x44011000>;
clocks = <&rcc CK_HSE>, <&rcc FDCAN_K>;
clock-names = "hclk", "cclk";
status = "disabled";
};
m4_dma1: dma@48000000 {
compatible = "rproc-srm-dev";
- reg = <0x48000000 0x400>;
+ reg = <0x48000000>;
clocks = <&rcc DMA1>;
status = "disabled";
};
m4_dma2: dma@48001000 {
compatible = "rproc-srm-dev";
- reg = <0x48001000 0x400>;
+ reg = <0x48001000>;
clocks = <&rcc DMA2>;
status = "disabled";
};
m4_dmamux1: dma-router@48002000 {
compatible = "rproc-srm-dev";
- reg = <0x48002000 0x1c>;
+ reg = <0x48002000>;
clocks = <&rcc DMAMUX>;
status = "disabled";
};
m4_adc: adc@48003000 {
compatible = "rproc-srm-dev";
- reg = <0x48003000 0x400>;
+ reg = <0x48003000>;
clocks = <&rcc ADC12>, <&rcc ADC12_K>;
clock-names = "bus", "adc";
status = "disabled";
};
m4_sdmmc3: sdmmc@48004000 {
compatible = "rproc-srm-dev";
- reg = <0x48004000 0x400>, <0x48005000 0x400>;
+ reg = <0x48004000>, <0x48005000>;
clocks = <&rcc SDMMC3_K>;
status = "disabled";
};
m4_usbotg_hs: usb-otg@49000000 {
compatible = "rproc-srm-dev";
- reg = <0x49000000 0x10000>;
+ reg = <0x49000000>;
clocks = <&rcc USBO_K>;
clock-names = "otg";
status = "disabled";
};
m4_hash2: hash@4c002000 {
compatible = "rproc-srm-dev";
- reg = <0x4c002000 0x400>;
+ reg = <0x4c002000>;
clocks = <&rcc HASH2>;
status = "disabled";
};
m4_rng2: rng@4c003000 {
compatible = "rproc-srm-dev";
- reg = <0x4c003000 0x400>;
+ reg = <0x4c003000>;
clocks = <&rcc RNG2_K>;
status = "disabled";
};
m4_crc2: crc@4c004000 {
compatible = "rproc-srm-dev";
- reg = <0x4c004000 0x400>;
+ reg = <0x4c004000>;
clocks = <&rcc CRC2>;
status = "disabled";
};
m4_cryp2: cryp@4c005000 {
compatible = "rproc-srm-dev";
- reg = <0x4c005000 0x400>;
+ reg = <0x4c005000>;
clocks = <&rcc CRYP2>;
status = "disabled";
};
m4_dcmi: dcmi@4c006000 {
compatible = "rproc-srm-dev";
- reg = <0x4c006000 0x400>;
+ reg = <0x4c006000>;
clocks = <&rcc DCMI>;
clock-names = "mclk";
status = "disabled";
};
m4_lptimer2: timer@50021000 {
compatible = "rproc-srm-dev";
- reg = <0x50021000 0x400>;
+ reg = <0x50021000>;
clocks = <&rcc LPTIM2_K>;
clock-names = "mux";
status = "disabled";
};
m4_lptimer3: timer@50022000 {
compatible = "rproc-srm-dev";
- reg = <0x50022000 0x400>;
+ reg = <0x50022000>;
clocks = <&rcc LPTIM3_K>;
clock-names = "mux";
status = "disabled";
};
m4_lptimer4: timer@50023000 {
compatible = "rproc-srm-dev";
- reg = <0x50023000 0x400>;
+ reg = <0x50023000>;
clocks = <&rcc LPTIM4_K>;
clock-names = "mux";
status = "disabled";
};
m4_lptimer5: timer@50024000 {
compatible = "rproc-srm-dev";
- reg = <0x50024000 0x400>;
+ reg = <0x50024000>;
clocks = <&rcc LPTIM5_K>;
clock-names = "mux";
status = "disabled";
};
m4_sai4: sai@50027000 {
compatible = "rproc-srm-dev";
- reg = <0x50027000 0x4>;
+ reg = <0x50027000>;
clocks = <&rcc SAI4_K>;
clock-names = "sai_ck";
status = "disabled";
};
m4_qspi: qspi@58003000 {
compatible = "rproc-srm-dev";
- reg = <0x58003000 0x1000>, <0x70000000 0x10000000>;
+ reg = <0x58003000>, <0x70000000>;
clocks = <&rcc QSPI_K>;
status = "disabled";
};
m4_ethernet0: ethernet@5800a000 {
compatible = "rproc-srm-dev";
- reg = <0x5800a000 0x2000>;
+ reg = <0x5800a000>;
clock-names = "stmmaceth",
"mac-clk-tx",
"mac-clk-rx",
diff --git a/arch/arm/boot/dts/stm32mp157c.dtsi b/arch/arm/boot/dts/stm32mp157c.dtsi
index 7a7ef47..4de499e 100644
--- a/arch/arm/boot/dts/stm32mp157c.dtsi
+++ b/arch/arm/boot/dts/stm32mp157c.dtsi
@@ -1231,7 +1231,7 @@
reg = <0x4c000000 0x400>;
clocks = <&rcc HSEM>;
clock-names = "hsem";
- status = "disabled";
+ status = "okay";
};
ipcc: mailbox@4c001000 {
--
2.7.4

View File

@ -0,0 +1,36 @@
From 619ff8e35045cb1cb0f235bd24236ff36453186a Mon Sep 17 00:00:00 2001
From: Romuald JEANNE <romuald.jeanne@st.com>
Date: Fri, 21 Dec 2018 16:57:19 +0100
Subject: [PATCH 52/52] ARM: stm32mp1-r0-rc4: DEFCONFIG
---
arch/arm/configs/fragment-02-multiv7_addons.config | 13 -------------
1 file changed, 13 deletions(-)
diff --git a/arch/arm/configs/fragment-02-multiv7_addons.config b/arch/arm/configs/fragment-02-multiv7_addons.config
index 6ae0453..38c5562 100644
--- a/arch/arm/configs/fragment-02-multiv7_addons.config
+++ b/arch/arm/configs/fragment-02-multiv7_addons.config
@@ -462,19 +462,6 @@ CONFIG_REGULATOR_STM32_VREFBUF=y
CONFIG_NVMEM_STM32_ROMEM=y
#
-# STM32 CORESIGHT
-#
-CONFIG_STM_SOURCE_CONSOLE=y
-CONFIG_STM_SOURCE_FTRACE=y
-CONFIG_FUNCTION_TRACER=y
-CONFIG_CORESIGHT=y
-CONFIG_CORESIGHT_LINK_AND_SINK_TMC=y
-CONFIG_CORESIGHT_SINK_TPIU=y
-CONFIG_CORESIGHT_SINK_ETBV10=y
-CONFIG_CORESIGHT_SOURCE_ETM3X=y
-CONFIG_CORESIGHT_STM=y
-
-#
# STM32 IPCC
#
CONFIG_STM32_IPCC=y
--
2.7.4

View File

@ -0,0 +1,117 @@
From 5648392b05ff7bb1f513ad9e9eb27b5420ce745d Mon Sep 17 00:00:00 2001
From: christophe montaud <christophe.montaud@st.com>
Date: Mon, 14 Jan 2019 17:19:51 +0100
Subject: [PATCH 54/55] ARM stm32mp1 r0 rc4 hotfix-w903.1 DEVICETREE
---
arch/arm/boot/dts/stm32mp157a-dk1.dts | 13 +++++++++++++
arch/arm/boot/dts/stm32mp157c-dk2.dts | 1 +
arch/arm/boot/dts/stm32mp157c.dtsi | 14 ++++++++++++++
3 files changed, 28 insertions(+)
diff --git a/arch/arm/boot/dts/stm32mp157a-dk1.dts b/arch/arm/boot/dts/stm32mp157a-dk1.dts
index 7e911f3..28017e4 100644
--- a/arch/arm/boot/dts/stm32mp157a-dk1.dts
+++ b/arch/arm/boot/dts/stm32mp157a-dk1.dts
@@ -287,6 +287,19 @@
/delete-property/dmas;
/delete-property/dma-names;
+ typec: stusb1600@28 {
+ compatible = "st,stusb1600";
+ reg = <0x28>;
+ status = "okay";
+
+ typec_con: connector {
+ compatible = "usb-c-connector";
+ label = "USB-C";
+ power-role = "sink";
+ power-opmode = "default";
+ };
+ };
+
pmic: stpmic@33 {
compatible = "st,stpmic1";
reg = <0x33>;
diff --git a/arch/arm/boot/dts/stm32mp157c-dk2.dts b/arch/arm/boot/dts/stm32mp157c-dk2.dts
index c276c59..340e022 100644
--- a/arch/arm/boot/dts/stm32mp157c-dk2.dts
+++ b/arch/arm/boot/dts/stm32mp157c-dk2.dts
@@ -106,6 +106,7 @@
/* Wifi */
&sdmmc2 {
+ arm,primecell-periphid = <0x10153180>;
pinctrl-names = "default", "opendrain", "sleep";
pinctrl-0 = <&sdmmc2_b4_pins_a>;
pinctrl-1 = <&sdmmc2_b4_od_pins_a>;
diff --git a/arch/arm/boot/dts/stm32mp157c.dtsi b/arch/arm/boot/dts/stm32mp157c.dtsi
index 4de499e..b09ef8b 100644
--- a/arch/arm/boot/dts/stm32mp157c.dtsi
+++ b/arch/arm/boot/dts/stm32mp157c.dtsi
@@ -892,6 +892,8 @@
compatible = "st,stm32-sai-sub-a";
reg = <0x4 0x1c>;
+ clocks = <&rcc SAI1_K>;
+ clock-names = "sai_ck";
dmas = <&dmamux1 87 0x400 0x01>;
status = "disabled";
};
@@ -900,6 +902,8 @@
#sound-dai-cells = <0>;
compatible = "st,stm32-sai-sub-b";
reg = <0x24 0x1c>;
+ clocks = <&rcc SAI1_K>;
+ clock-names = "sai_ck";
dmas = <&dmamux1 88 0x400 0x01>;
status = "disabled";
};
@@ -919,6 +923,8 @@
#sound-dai-cells = <0>;
compatible = "st,stm32-sai-sub-a";
reg = <0x4 0x1c>;
+ clocks = <&rcc SAI2_K>;
+ clock-names = "sai_ck";
dmas = <&dmamux1 89 0x400 0x01>;
status = "disabled";
};
@@ -927,6 +933,8 @@
#sound-dai-cells = <0>;
compatible = "st,stm32-sai-sub-b";
reg = <0x24 0x1c>;
+ clocks = <&rcc SAI2_K>;
+ clock-names = "sai_ck";
dmas = <&dmamux1 90 0x400 0x01>;
status = "disabled";
};
@@ -946,6 +954,8 @@
#sound-dai-cells = <0>;
compatible = "st,stm32-sai-sub-a";
reg = <0x04 0x1c>;
+ clocks = <&rcc SAI3_K>;
+ clock-names = "sai_ck";
dmas = <&dmamux1 113 0x400 0x01>;
status = "disabled";
};
@@ -954,6 +964,8 @@
#sound-dai-cells = <0>;
compatible = "st,stm32-sai-sub-b";
reg = <0x24 0x1c>;
+ clocks = <&rcc SAI3_K>;
+ clock-names = "sai_ck";
dmas = <&dmamux1 114 0x400 0x01>;
status = "disabled";
};
@@ -1442,6 +1454,8 @@
#sound-dai-cells = <0>;
compatible = "st,stm32-sai-sub-b";
reg = <0x24 0x1c>;
+ clocks = <&rcc SAI4_K>;
+ clock-names = "sai_ck";
dmas = <&dmamux1 100 0x400 0x01>;
status = "disabled";
};
--
2.7.4

View File

@ -0,0 +1,25 @@
From 449bea3af472f64774547738478ca3b2cfa91cae Mon Sep 17 00:00:00 2001
From: christophe montaud <christophe.montaud@st.com>
Date: Mon, 14 Jan 2019 17:20:30 +0100
Subject: [PATCH 55/55] ARM stm32mp1 r0 rc4 hotfix-w903.1 DEFCONFIG
---
arch/arm/configs/fragment-02-multiv7_addons.config | 2 ++
1 file changed, 2 insertions(+)
diff --git a/arch/arm/configs/fragment-02-multiv7_addons.config b/arch/arm/configs/fragment-02-multiv7_addons.config
index 38c5562..ddf15a9 100644
--- a/arch/arm/configs/fragment-02-multiv7_addons.config
+++ b/arch/arm/configs/fragment-02-multiv7_addons.config
@@ -346,6 +346,8 @@ CONFIG_USB_CONFIGFS=y
#
# USB Physical Layer drivers
#
+CONFIG_TYPEC=y
+CONFIG_TYPEC_STUSB=y
#
# Platform Support
--
2.7.4

View File

@ -0,0 +1,554 @@
From b6678ec426d7dbc5248a2d98c0c2c7a5b55e4d5f Mon Sep 17 00:00:00 2001
From: christophe montaud <christophe.montaud@st.com>
Date: Wed, 16 Jan 2019 17:51:05 +0100
Subject: [PATCH 56/58] ARM stm32mp1 r0 rc4 hotfix w903.3 DRIVERS
---
drivers/clk/clk-stm32mp1.c | 142 ++++++++++++++++++++--------------
drivers/i2c/busses/i2c-stm32f7.c | 33 +++++++-
drivers/irqchip/irq-stm32-exti.c | 160 +++++++++++++++++++++++++--------------
kernel/power/suspend.c | 1 -
4 files changed, 218 insertions(+), 118 deletions(-)
diff --git a/drivers/clk/clk-stm32mp1.c b/drivers/clk/clk-stm32mp1.c
index 7eccaa1..56d7b86 100644
--- a/drivers/clk/clk-stm32mp1.c
+++ b/drivers/clk/clk-stm32mp1.c
@@ -2215,8 +2215,8 @@ static const struct stm32_mux_cfg ker_mux_cfg[M_LAST] = {
static const struct clock_config stm32mp1_clock_cfg[] = {
/* Oscillator divider */
- DIV(NO_ID, "clk-hsi-div", "clk-hsi", 0, RCC_HSICFGR, 0, 2,
- CLK_DIVIDER_READ_ONLY),
+ DIV(NO_ID, "clk-hsi-div", "clk-hsi", CLK_DIVIDER_POWER_OF_TWO,
+ RCC_HSICFGR, 0, 2, CLK_DIVIDER_READ_ONLY),
/* External / Internal Oscillators */
SGATE_MP1(CK_HSE, "ck_hse", "clk-hse", 0, RCC_OCENSETR, 8, 0),
@@ -2517,11 +2517,10 @@ static const struct clock_config stm32mp1_clock_cfg[] = {
CLK_SET_RATE_NO_REPARENT,
_NO_GATE,
_MMUX(M_ETHCK),
- _DIV(RCC_ETHCKSELR, 4, 4, CLK_DIVIDER_ALLOW_ZERO, NULL)),
+ _DIV(RCC_ETHCKSELR, 4, 4, 0, NULL)),
/* RTC clock */
- SDIV(NO_ID, "ck_hse_rtc", "ck_hse", 0, RCC_RTCDIVR, 0, 7,
- CLK_DIVIDER_ALLOW_ZERO),
+ SDIV(NO_ID, "ck_hse_rtc", "ck_hse", 0, RCC_RTCDIVR, 0, 6, 0),
COMPOSITE(RTC, "ck_rtc", rtc_src, CLK_OPS_PARENT_ENABLE |
CLK_SET_RATE_PARENT,
@@ -2724,52 +2723,53 @@ static struct sreg clock_gating[] = {
};
struct smux {
- const char *name;
- struct clk *clk;
- struct clk *clkp;
+ u32 clk_id;
+ u32 mux_id;
+ struct clk_hw *hw;
};
-#define KER_SRC(_clk_name)\
+#define KER_SRC(_clk_id, _mux_id)\
{\
- .name = _clk_name,\
-}
-
-struct smux _mux_kernel[] = {
- KER_SRC("sdmmc1_k"),
- KER_SRC("spi2_k"),
- KER_SRC("spi4_k"),
- KER_SRC("i2c1_k"),
- KER_SRC("i2c3_k"),
- KER_SRC("lptim2_k"),
- KER_SRC("lptim3_k"),
- KER_SRC("usart2_k"),
- KER_SRC("usart3_k"),
- KER_SRC("uart7_k"),
- KER_SRC("sai1_k"),
- KER_SRC("ethck_k"),
- KER_SRC("i2c4_k"),
- KER_SRC("rng2_k"),
- KER_SRC("sdmmc3_k"),
- KER_SRC("fmc_k"),
- KER_SRC("qspi_k"),
- KER_SRC("usbphy_k"),
- KER_SRC("usbo_k"),
- KER_SRC("spdif_k"),
- KER_SRC("spi1_k"),
- KER_SRC("cec_k"),
- KER_SRC("lptim1_k"),
- KER_SRC("uart6_k"),
- KER_SRC("fdcan_k"),
- KER_SRC("sai2_k"),
- KER_SRC("sai3_k"),
- KER_SRC("sai4_k"),
- KER_SRC("adc12_k"),
- KER_SRC("dsi_k"),
- KER_SRC("ck_per"),
- KER_SRC("rng1_k"),
- KER_SRC("stgen_k"),
- KER_SRC("usart1_k"),
- KER_SRC("spi6_k"),
+ .clk_id = _clk_id,\
+ .mux_id = _mux_id,\
+}
+
+struct smux _mux_kernel[M_LAST] = {
+ KER_SRC(SDMMC1_K, M_SDMMC12),
+ KER_SRC(SDMMC3_K, M_SDMMC3),
+ KER_SRC(FMC_K, M_FMC),
+ KER_SRC(QSPI_K, M_QSPI),
+ KER_SRC(RNG1_K, M_RNG1),
+ KER_SRC(RNG2_K, M_RNG2),
+ KER_SRC(USBPHY_K, M_USBPHY),
+ KER_SRC(USBO_K, M_USBO),
+ KER_SRC(STGEN_K, M_STGEN),
+ KER_SRC(SPDIF_K, M_SPDIF),
+ KER_SRC(SPI1_K, M_SPI1),
+ KER_SRC(SPI2_K, M_SPI23),
+ KER_SRC(SPI4_K, M_SPI45),
+ KER_SRC(SPI6_K, M_SPI6),
+ KER_SRC(CEC_K, M_CEC),
+ KER_SRC(I2C1_K, M_I2C12),
+ KER_SRC(I2C3_K, M_I2C35),
+ KER_SRC(I2C4_K, M_I2C46),
+ KER_SRC(LPTIM1_K, M_LPTIM1),
+ KER_SRC(LPTIM2_K, M_LPTIM23),
+ KER_SRC(LPTIM4_K, M_LPTIM45),
+ KER_SRC(USART1_K, M_USART1),
+ KER_SRC(USART2_K, M_UART24),
+ KER_SRC(USART3_K, M_UART35),
+ KER_SRC(USART6_K, M_USART6),
+ KER_SRC(UART7_K, M_UART78),
+ KER_SRC(SAI1_K, M_SAI1),
+ KER_SRC(SAI2_K, M_SAI2),
+ KER_SRC(SAI3_K, M_SAI3),
+ KER_SRC(SAI4_K, M_SAI4),
+ KER_SRC(DSI_K, M_DSI),
+ KER_SRC(FDCAN_K, M_FDCAN),
+ KER_SRC(ADC12_K, M_ADC12),
+ KER_SRC(ETHCK_K, M_ETHCK),
+ KER_SRC(CK_PER, M_CKPER),
};
static struct sreg pll_clock[] = {
@@ -2861,22 +2861,52 @@ static void stm32mp1_restore_pll(struct sreg *sreg, int size)
}
}
-static void stm32mp1_backup_mux(struct smux *smux, int size)
+static void stm32mp1_backup_mux(struct device_node *np,
+ struct smux *smux, int size)
{
int i;
+ struct of_phandle_args clkspec;
+
+ clkspec.np = np;
+ clkspec.args_count = 1;
for (i = 0; i < size; i++) {
- smux[i].clk = __clk_lookup(smux[i].name);
- smux[i].clkp = clk_get_parent(smux[i].clk);
+ clkspec.args[0] = smux[i].clk_id;
+ smux[i].hw = __clk_get_hw(of_clk_get_from_provider(&clkspec));
}
}
static void stm32mp1_restore_mux(struct smux *smux, int size)
{
int i;
+ struct clk_hw *hw, *hwp1, *hwp2;
+ struct mux_cfg *mux;
+ u8 idx;
- for (i = 0; i < size; i++)
- clk_set_parent_force(smux[i].clk, smux[i].clkp);
+ /* These MUX are glitch free.
+ * Then we have to restore mux thru clock framework
+ * to be sure that CLK_OPS_PARENT_ENABLE will be exploited
+ */
+ for (i = 0; i < M_LAST; i++) {
+ /* get parent strored in clock framework */
+ hw = smux[i].hw;
+ hwp1 = clk_hw_get_parent(hw);
+
+ /* Get parent corresponding to mux register */
+ mux = ker_mux_cfg[smux[i].mux_id].mux;
+ idx = readl_relaxed(rcc_base + mux->reg_off) >> mux->shift;
+ idx &= (BIT(mux->width) - 1);
+ hwp2 = clk_hw_get_parent_by_index(hw, idx);
+
+ /* check if parent from mux & clock framework are differents */
+ if (hwp1 != hwp2) {
+ /* update first clock framework with the true parent */
+ clk_set_parent(hw->clk, hwp2->clk);
+
+ /* Restore now new parent */
+ clk_set_parent(hw->clk, hwp1->clk);
+ }
+ }
}
#define RCC_BIT_HSI 0
@@ -2900,9 +2930,6 @@ static int stm32mp1_clk_suspend(void)
/* Save clock gating regs */
stm32mp1_backup_sreg(clock_gating, ARRAY_SIZE(clock_gating));
- /* Save kernel clock regs */
- stm32mp1_backup_mux(_mux_kernel, ARRAY_SIZE(_mux_kernel));
-
/* Enable ck_xxx_ker clocks if ck_xxx was on */
reg = readl_relaxed(rcc_base + RCC_OCENSETR) & RCC_CK_OSC_MASK;
writel_relaxed(reg << 1, rcc_base + RCC_OCENSETR);
@@ -2970,6 +2997,9 @@ static int stm32_rcc_init_pwr(struct device_node *np)
SMC(STM32_SVC_RCC, STM32_WRITE, RCC_SREQCLRR, RCC_STOP_MASK);
+ /* Prepare kernel clock source backup */
+ stm32mp1_backup_mux(np, _mux_kernel, ARRAY_SIZE(_mux_kernel));
+
register_syscore_ops(&stm32mp1_clk_ops);
return 0;
diff --git a/drivers/i2c/busses/i2c-stm32f7.c b/drivers/i2c/busses/i2c-stm32f7.c
index ac30aea..3af2637 100644
--- a/drivers/i2c/busses/i2c-stm32f7.c
+++ b/drivers/i2c/busses/i2c-stm32f7.c
@@ -978,6 +978,26 @@ static int stm32f7_i2c_smbus_xfer_msg(struct stm32f7_i2c_dev *i2c_dev,
cr2 &= ~STM32F7_I2C_CR2_RD_WRN;
f7_msg->read_write = I2C_SMBUS_READ;
break;
+ case I2C_SMBUS_I2C_BLOCK_DATA:
+ if (data->block[0] > I2C_SMBUS_BLOCK_MAX) {
+ dev_err(dev, "Invalid block %s size %d\n",
+ f7_msg->read_write == I2C_SMBUS_READ ?
+ "read" : "write",
+ data->block[0]);
+ return -EINVAL;
+ }
+
+ if (f7_msg->read_write) {
+ f7_msg->stop = false;
+ f7_msg->count = data->block[0];
+ cr2 &= ~STM32F7_I2C_CR2_RD_WRN;
+ } else {
+ f7_msg->stop = true;
+ f7_msg->count = data->block[0] + 1;
+ for (i = 1; i <= data->block[0]; i++)
+ f7_msg->smbus_buf[i] = data->block[i];
+ }
+ break;
default:
dev_err(dev, "Unsupported smbus protocol %d\n", f7_msg->size);
return -EOPNOTSUPP;
@@ -986,7 +1006,8 @@ static int stm32f7_i2c_smbus_xfer_msg(struct stm32f7_i2c_dev *i2c_dev,
f7_msg->buf = f7_msg->smbus_buf;
/* Configure PEC */
- if ((flags & I2C_CLIENT_PEC) && f7_msg->size != I2C_SMBUS_QUICK) {
+ if ((flags & I2C_CLIENT_PEC) && f7_msg->size != I2C_SMBUS_QUICK &&
+ f7_msg->size != I2C_SMBUS_I2C_BLOCK_DATA) {
cr1 |= STM32F7_I2C_CR1_PECEN;
cr2 |= STM32F7_I2C_CR2_PECBYTE;
if (!f7_msg->read_write)
@@ -1655,7 +1676,8 @@ static int stm32f7_i2c_smbus_xfer(struct i2c_adapter *adapter, u16 addr,
}
/* Check PEC */
- if ((flags & I2C_CLIENT_PEC) && size != I2C_SMBUS_QUICK && read_write) {
+ if ((flags & I2C_CLIENT_PEC) && size != I2C_SMBUS_QUICK &&
+ size != I2C_SMBUS_I2C_BLOCK_DATA && read_write) {
ret = stm32f7_i2c_smbus_check_pec(i2c_dev);
if (ret)
goto pm_free;
@@ -1672,6 +1694,10 @@ static int stm32f7_i2c_smbus_xfer(struct i2c_adapter *adapter, u16 addr,
data->word = f7_msg->smbus_buf[0] |
(f7_msg->smbus_buf[1] << 8);
break;
+ case I2C_SMBUS_I2C_BLOCK_DATA:
+ for (i = 0; i < data->block[0]; i++)
+ data->block[i + 1] = f7_msg->smbus_buf[i];
+ break;
case I2C_SMBUS_BLOCK_DATA:
case I2C_SMBUS_BLOCK_PROC_CALL:
for (i = 0; i <= f7_msg->smbus_buf[0]; i++)
@@ -1854,7 +1880,8 @@ static u32 stm32f7_i2c_func(struct i2c_adapter *adap)
I2C_FUNC_SMBUS_QUICK | I2C_FUNC_SMBUS_BYTE |
I2C_FUNC_SMBUS_BYTE_DATA | I2C_FUNC_SMBUS_WORD_DATA |
I2C_FUNC_SMBUS_BLOCK_DATA | I2C_FUNC_SMBUS_BLOCK_PROC_CALL |
- I2C_FUNC_SMBUS_PROC_CALL | I2C_FUNC_SMBUS_PEC;
+ I2C_FUNC_SMBUS_PROC_CALL | I2C_FUNC_SMBUS_PEC |
+ I2C_FUNC_SMBUS_I2C_BLOCK;
}
static struct i2c_algorithm stm32f7_i2c_algo = {
diff --git a/drivers/irqchip/irq-stm32-exti.c b/drivers/irqchip/irq-stm32-exti.c
index 223ee2e..793be075a 100644
--- a/drivers/irqchip/irq-stm32-exti.c
+++ b/drivers/irqchip/irq-stm32-exti.c
@@ -14,8 +14,10 @@
#include <linux/irqchip.h>
#include <linux/irqchip/chained_irq.h>
#include <linux/irqdomain.h>
+#include <linux/module.h>
#include <linux/of_address.h>
#include <linux/of_irq.h>
+#include <linux/of_platform.h>
#include <linux/syscore_ops.h>
#include <dt-bindings/interrupt-controller/arm-gic.h>
@@ -37,12 +39,6 @@ struct stm32_exti_bank {
#define UNDEF_REG ~0
-enum stm32_exti_hwspinlock {
- HWSPINLOCK_UNKNOWN,
- HWSPINLOCK_NONE,
- HWSPINLOCK_READY,
-};
-
struct stm32_desc_irq {
u32 exti;
u32 irq_parent;
@@ -69,8 +65,6 @@ struct stm32_exti_host_data {
void __iomem *base;
struct stm32_exti_chip_data *chips_data;
const struct stm32_exti_drv_data *drv_data;
- struct device_node *node;
- enum stm32_exti_hwspinlock hwlock_state;
struct hwspinlock *hwlock;
};
@@ -285,49 +279,27 @@ static int stm32_exti_set_type(struct irq_data *d,
static int stm32_exti_hwspin_lock(struct stm32_exti_chip_data *chip_data)
{
- struct stm32_exti_host_data *host_data = chip_data->host_data;
- struct hwspinlock *hwlock;
- int id, ret = 0, timeout = 0;
-
- /* first time, check for hwspinlock availability */
- if (unlikely(host_data->hwlock_state == HWSPINLOCK_UNKNOWN)) {
- id = of_hwspin_lock_get_id(host_data->node, 0);
- if (id >= 0) {
- hwlock = hwspin_lock_request_specific(id);
- if (hwlock) {
- /* found valid hwspinlock */
- host_data->hwlock_state = HWSPINLOCK_READY;
- host_data->hwlock = hwlock;
- pr_debug("%s hwspinlock = %d\n", __func__, id);
- } else {
- host_data->hwlock_state = HWSPINLOCK_NONE;
- }
- } else if (id != -EPROBE_DEFER) {
- host_data->hwlock_state = HWSPINLOCK_NONE;
- } else {
- /* hwspinlock driver shall be ready at that stage */
- ret = -EPROBE_DEFER;
- }
- }
+ int ret, timeout = 0;
- if (likely(host_data->hwlock_state == HWSPINLOCK_READY)) {
- /*
- * Use the x_raw API since we are under spin_lock protection.
- * Do not use the x_timeout API because we are under irq_disable
- * mode (see __setup_irq())
- */
- do {
- ret = hwspin_trylock_raw(host_data->hwlock);
- if (!ret)
- return 0;
-
- udelay(HWSPNLCK_RETRY_DELAY);
- timeout += HWSPNLCK_RETRY_DELAY;
- } while (timeout < HWSPNLCK_TIMEOUT);
-
- if (ret == -EBUSY)
- ret = -ETIMEDOUT;
- }
+ if (!chip_data->host_data->hwlock)
+ return 0;
+
+ /*
+ * Use the x_raw API since we are under spin_lock protection.
+ * Do not use the x_timeout API because we are under irq_disable
+ * mode (see __setup_irq())
+ */
+ do {
+ ret = hwspin_trylock_raw(chip_data->host_data->hwlock);
+ if (!ret)
+ return 0;
+
+ udelay(HWSPNLCK_RETRY_DELAY);
+ timeout += HWSPNLCK_RETRY_DELAY;
+ } while (timeout < HWSPNLCK_TIMEOUT);
+
+ if (ret == -EBUSY)
+ ret = -ETIMEDOUT;
if (ret)
pr_err("%s can't get hwspinlock (%d)\n", __func__, ret);
@@ -337,7 +309,7 @@ static int stm32_exti_hwspin_lock(struct stm32_exti_chip_data *chip_data)
static void stm32_exti_hwspin_unlock(struct stm32_exti_chip_data *chip_data)
{
- if (likely(chip_data->host_data->hwlock_state == HWSPINLOCK_READY))
+ if (chip_data->host_data->hwlock)
hwspin_unlock_raw(chip_data->host_data->hwlock);
}
@@ -710,8 +682,6 @@ stm32_exti_host_data *stm32_exti_host_init(const struct stm32_exti_drv_data *dd,
return NULL;
host_data->drv_data = dd;
- host_data->node = node;
- host_data->hwlock_state = HWSPINLOCK_UNKNOWN;
host_data->chips_data = kcalloc(dd->bank_nr,
sizeof(struct stm32_exti_chip_data),
GFP_KERNEL);
@@ -738,7 +708,8 @@ stm32_exti_host_data *stm32_exti_host_init(const struct stm32_exti_drv_data *dd,
static struct
stm32_exti_chip_data *stm32_exti_chip_init(struct stm32_exti_host_data *h_data,
- u32 bank_idx)
+ u32 bank_idx,
+ struct device_node *node)
{
const struct stm32_exti_bank *stm32_bank;
struct stm32_exti_chip_data *chip_data;
@@ -758,7 +729,7 @@ stm32_exti_chip_data *stm32_exti_chip_init(struct stm32_exti_host_data *h_data,
writel_relaxed(0, base + stm32_bank->imr_ofst);
writel_relaxed(0, base + stm32_bank->emr_ofst);
- pr_info("%pOF: bank%d\n", h_data->node, bank_idx);
+ pr_info("%pOF: bank%d\n", node, bank_idx);
return chip_data;
}
@@ -798,7 +769,7 @@ static int __init stm32_exti_init(const struct stm32_exti_drv_data *drv_data,
struct stm32_exti_chip_data *chip_data;
stm32_bank = drv_data->exti_banks[i];
- chip_data = stm32_exti_chip_init(host_data, i);
+ chip_data = stm32_exti_chip_init(host_data, i, node);
gc = irq_get_domain_generic_chip(domain, i * IRQS_PER_BANK);
@@ -880,7 +851,7 @@ __init stm32_exti_hierarchy_init(const struct stm32_exti_drv_data *drv_data,
return -ENOMEM;
for (i = 0; i < drv_data->bank_nr; i++)
- stm32_exti_chip_init(host_data, i);
+ stm32_exti_chip_init(host_data, i, node);
domain = irq_domain_add_hierarchy(parent_domain, 0,
drv_data->bank_nr * IRQS_PER_BANK,
@@ -938,6 +909,71 @@ __init stm32_exti_hierarchy_init(const struct stm32_exti_drv_data *drv_data,
return ret;
}
+/* Note : stm32_exti_probe() is called after stm32*_exti_of_init() */
+static int stm32_exti_probe(struct platform_device *pdev)
+{
+ int id, ret = 0;
+
+ id = of_hwspin_lock_get_id(pdev->dev.of_node, 0);
+
+ if (id == -EPROBE_DEFER)
+ /* hwspinlock framework not ready */
+ return -EPROBE_DEFER;
+
+ if (id == -ENOENT)
+ /* no hwspinlock defined (not an error, it is optional) */
+ return 0;
+
+ if (id >= 0) {
+ stm32_host_data->hwlock = hwspin_lock_request_specific(id);
+ if (!stm32_host_data->hwlock) {
+ dev_err(&pdev->dev, "Failed to request hwspinlock\n");
+ ret = -EINVAL;
+ }
+ } else {
+ dev_err(&pdev->dev, "Failed to get hwspinlock\n");
+ ret = id;
+ }
+
+ return ret;
+}
+
+static int stm32_exti_remove(struct platform_device *pdev)
+{
+ if (stm32_host_data->hwlock)
+ return hwspin_lock_free(stm32_host_data->hwlock);
+
+ return 0;
+}
+
+static const struct of_device_id stm32_exti_ids[] = {
+ { .compatible = "st,stm32mp1-exti", },
+ {},
+};
+MODULE_DEVICE_TABLE(of, stm32_exti_ids);
+
+static struct platform_driver stm32_exti_driver = {
+ .probe = stm32_exti_probe,
+ .remove = stm32_exti_remove,
+ .driver = {
+ .name = "stm32_exti",
+ .of_match_table = stm32_exti_ids,
+ },
+};
+
+static int __init stm32_exti_arch_init(void)
+{
+ return platform_driver_register(&stm32_exti_driver);
+}
+
+static void __exit stm32_exti_arch_exit(void)
+{
+ return platform_driver_unregister(&stm32_exti_driver);
+}
+
+arch_initcall(stm32_exti_arch_init);
+module_exit(stm32_exti_arch_exit);
+
static int __init stm32f4_exti_of_init(struct device_node *np,
struct device_node *parent)
{
@@ -957,7 +993,15 @@ IRQCHIP_DECLARE(stm32h7_exti, "st,stm32h7-exti", stm32h7_exti_of_init);
static int __init stm32mp1_exti_of_init(struct device_node *np,
struct device_node *parent)
{
- return stm32_exti_hierarchy_init(&stm32mp1_drv_data, np, parent);
+ int ret;
+
+ ret = stm32_exti_hierarchy_init(&stm32mp1_drv_data, np, parent);
+
+ /* Clear the OF_POPULATED flag so that stm32_exti_probe can be called */
+ if (!ret)
+ of_node_clear_flag(np, OF_POPULATED);
+
+ return ret;
}
IRQCHIP_DECLARE(stm32mp1_exti, "st,stm32mp1-exti", stm32mp1_exti_of_init);
diff --git a/kernel/power/suspend.c b/kernel/power/suspend.c
index 0bd595a..64f6aec 100644
--- a/kernel/power/suspend.c
+++ b/kernel/power/suspend.c
@@ -36,7 +36,6 @@
#include "power.h"
const char * const pm_labels[] = {
- [PM_SUSPEND_TO_IDLE] = "freeze",
[PM_SUSPEND_STANDBY] = "standby",
[PM_SUSPEND_MEM] = "mem",
};
--
2.7.4

View File

@ -0,0 +1,119 @@
From f30f869d9bb396c6981fc2800149c373d21586de Mon Sep 17 00:00:00 2001
From: christophe montaud <christophe.montaud@st.com>
Date: Wed, 16 Jan 2019 17:52:31 +0100
Subject: [PATCH 57/58] ARM stm32mp1 r0 rc4 hotfix w903.3 DEVICETREE
---
arch/arm/boot/dts/stm32mp157-pinctrl.dtsi | 30 ++++++++++++++++++++++++++++++
arch/arm/boot/dts/stm32mp157a-dk1.dts | 12 +++++++++++-
arch/arm/boot/dts/stm32mp157c-dk2.dts | 2 +-
arch/arm/boot/dts/stm32mp157c-ed1.dts | 2 +-
4 files changed, 43 insertions(+), 3 deletions(-)
diff --git a/arch/arm/boot/dts/stm32mp157-pinctrl.dtsi b/arch/arm/boot/dts/stm32mp157-pinctrl.dtsi
index 183d7ba..474e7e3 100644
--- a/arch/arm/boot/dts/stm32mp157-pinctrl.dtsi
+++ b/arch/arm/boot/dts/stm32mp157-pinctrl.dtsi
@@ -1413,6 +1413,36 @@
};
};
+ uart7_pins_a: uart7-0 {
+ pins1 {
+ pinmux = <STM32_PINMUX('E', 8, AF7)>; /* USART7_TX */
+ bias-disable;
+ drive-push-pull;
+ slew-rate = <0>;
+ };
+ pins2 {
+ pinmux = <STM32_PINMUX('E', 7, AF7)>; /* USART7_RX */
+ bias-disable;
+ };
+ };
+
+ uart7_idle_pins_a: uart7-idle-0 {
+ pins1 {
+ pinmux = <STM32_PINMUX('E', 8, ANALOG)>; /* USART7_TX */
+ };
+ pins2 {
+ pinmux = <STM32_PINMUX('E', 7, AF7)>; /* USART7_RX */
+ bias-disable;
+ };
+ };
+
+ uart7_sleep_pins_a: uart7-sleep-0 {
+ pins {
+ pinmux = <STM32_PINMUX('E', 8, ANALOG)>, /* USART7_TX */
+ <STM32_PINMUX('E', 7, ANALOG)>; /* USART7_RX */
+ };
+ };
+
usart2_pins_a: usart2-0 {
pins1 {
pinmux = <STM32_PINMUX('D', 5, AF7)>, /* USART2_TX */
diff --git a/arch/arm/boot/dts/stm32mp157a-dk1.dts b/arch/arm/boot/dts/stm32mp157a-dk1.dts
index 28017e4..467c226 100644
--- a/arch/arm/boot/dts/stm32mp157a-dk1.dts
+++ b/arch/arm/boot/dts/stm32mp157a-dk1.dts
@@ -20,6 +20,8 @@
aliases {
ethernet0 = &ethernet0;
serial0 = &uart4;
+ serial1 = &usart3;
+ serial2 = &uart7;
};
chosen {
@@ -310,7 +312,7 @@
st,main-control-register = <0x04>;
st,vin-control-register = <0xc0>;
- st,usb-control-register = <0x30>;
+ st,usb-control-register = <0x20>;
regulators {
compatible = "st,stpmic1-regulators";
@@ -671,6 +673,14 @@
status = "okay";
};
+&uart7 {
+ pinctrl-names = "default", "sleep", "idle";
+ pinctrl-0 = <&uart7_pins_a>;
+ pinctrl-1 = <&uart7_sleep_pins_a>;
+ pinctrl-2 = <&uart7_idle_pins_a>;
+ status = "disabled";
+};
+
&usart3 {
pinctrl-names = "default", "sleep", "idle";
pinctrl-0 = <&usart3_pins_b>;
diff --git a/arch/arm/boot/dts/stm32mp157c-dk2.dts b/arch/arm/boot/dts/stm32mp157c-dk2.dts
index 340e022..4da15cd 100644
--- a/arch/arm/boot/dts/stm32mp157c-dk2.dts
+++ b/arch/arm/boot/dts/stm32mp157c-dk2.dts
@@ -14,7 +14,7 @@
compatible = "st,stm32mp157c-dk2", "st,stm32mp157";
aliases {
- serial1 = &usart2;
+ serial3 = &usart2;
};
wifi_pwrseq: wifi-pwrseq {
diff --git a/arch/arm/boot/dts/stm32mp157c-ed1.dts b/arch/arm/boot/dts/stm32mp157c-ed1.dts
index cf2750e..6d49f21 100644
--- a/arch/arm/boot/dts/stm32mp157c-ed1.dts
+++ b/arch/arm/boot/dts/stm32mp157c-ed1.dts
@@ -188,7 +188,7 @@
st,main-control-register = <0x04>;
st,vin-control-register = <0xc0>;
- st,usb-control-register = <0x30>;
+ st,usb-control-register = <0x20>;
regulators {
compatible = "st,stpmic1-regulators";
--
2.7.4

View File

@ -0,0 +1,26 @@
From 2cfb67b0a4403e68016a50c1302da9a8eeb15a6b Mon Sep 17 00:00:00 2001
From: christophe montaud <christophe.montaud@st.com>
Date: Wed, 16 Jan 2019 17:53:15 +0100
Subject: [PATCH 58/58] ARM stm32mp1 r0 rc4 hotfix w903.3 DEFCONFIG
---
arch/arm/configs/fragment-02-multiv7_addons.config | 3 ---
1 file changed, 3 deletions(-)
diff --git a/arch/arm/configs/fragment-02-multiv7_addons.config b/arch/arm/configs/fragment-02-multiv7_addons.config
index ddf15a9..7b489e4 100644
--- a/arch/arm/configs/fragment-02-multiv7_addons.config
+++ b/arch/arm/configs/fragment-02-multiv7_addons.config
@@ -123,9 +123,6 @@ CONFIG_CMA_SIZE_MBYTES=128
#
# LPDDR & LPDDR2 PCM memory drivers
#
-CONFIG_OF_RESOLVE=y
-CONFIG_OF_OVERLAY=y
-CONFIG_OF_CONFIGFS=y
#
# Misc devices
--
2.7.4

View File

@ -0,0 +1,927 @@
From dbfd12db19506dc6d598c11d72aa0fb81c41aa82 Mon Sep 17 00:00:00 2001
From: christophe montaud <christophe.montaud@st.com>
Date: Thu, 24 Jan 2019 10:51:36 +0100
Subject: [PATCH 59/60] ARM stm32mp1 r0 rc4 hotfix w904.3 DRIVERS
---
drivers/dma/stm32-dma.c | 4 +
drivers/gpu/drm/panel/panel-orisetech-otm8009a.c | 64 +++++------
drivers/gpu/drm/stm/dw_mipi_dsi-stm.c | 51 ++++++---
drivers/remoteproc/stm32_rproc.c | 21 ++--
drivers/tty/serial/stm32-usart.c | 8 ++
drivers/tty/serial/stm32-usart.h | 2 +-
drivers/usb/dwc2/core.h | 29 +++++
drivers/usb/dwc2/debugfs.c | 1 +
drivers/usb/dwc2/gadget.c | 133 +++++++++++++++++++++--
drivers/usb/dwc2/hcd.c | 3 -
drivers/usb/dwc2/hcd.h | 2 +-
drivers/usb/dwc2/hcd_queue.c | 19 ++--
drivers/usb/dwc2/hw.h | 17 +++
drivers/usb/dwc2/params.c | 18 ++-
14 files changed, 294 insertions(+), 78 deletions(-)
diff --git a/drivers/dma/stm32-dma.c b/drivers/dma/stm32-dma.c
index 1f9d606..5abfa4f 100644
--- a/drivers/dma/stm32-dma.c
+++ b/drivers/dma/stm32-dma.c
@@ -1242,6 +1242,7 @@ static int stm32_dma_mdma_prep_slave_sg(struct stm32_dma_chan *chan,
dev_err(chan2dev(chan),
"max buf size = %d bytes\n",
chan->sram_size);
+ ret = -EINVAL;
goto free_alloc;
}
} else {
@@ -1939,6 +1940,8 @@ static int stm32_dma_probe(struct platform_device *pdev)
dev_dbg(&pdev->dev, "SRAM pool: %zu KiB\n",
gen_pool_size(dmadev->sram_pool) / 1024);
+ dma_set_max_seg_size(&pdev->dev, STM32_DMA_ALIGNED_MAX_DATA_ITEMS);
+
dma_cap_set(DMA_SLAVE, dd->cap_mask);
dma_cap_set(DMA_PRIVATE, dd->cap_mask);
dma_cap_set(DMA_CYCLIC, dd->cap_mask);
@@ -1959,6 +1962,7 @@ static int stm32_dma_probe(struct platform_device *pdev)
BIT(DMA_SLAVE_BUSWIDTH_4_BYTES);
dd->directions = BIT(DMA_DEV_TO_MEM) | BIT(DMA_MEM_TO_DEV);
dd->residue_granularity = DMA_RESIDUE_GRANULARITY_BURST;
+ dd->copy_align = DMAENGINE_ALIGN_32_BYTES;
dd->max_burst = STM32_DMA_MAX_BURST;
dd->descriptor_reuse = true;
dd->dev = &pdev->dev;
diff --git a/drivers/gpu/drm/panel/panel-orisetech-otm8009a.c b/drivers/gpu/drm/panel/panel-orisetech-otm8009a.c
index a76d03a..ee7486b 100644
--- a/drivers/gpu/drm/panel/panel-orisetech-otm8009a.c
+++ b/drivers/gpu/drm/panel/panel-orisetech-otm8009a.c
@@ -254,24 +254,12 @@ static int otm8009a_init_sequence(struct otm8009a *ctx)
static int otm8009a_disable(struct drm_panel *panel)
{
struct otm8009a *ctx = panel_to_otm8009a(panel);
- struct mipi_dsi_device *dsi = to_mipi_dsi_device(ctx->dev);
- int ret;
if (!ctx->enabled)
return 0; /* This is not an issue so we return 0 here */
backlight_disable(ctx->bl_dev);
- ret = mipi_dsi_dcs_set_display_off(dsi);
- if (ret)
- return ret;
-
- ret = mipi_dsi_dcs_enter_sleep_mode(dsi);
- if (ret)
- return ret;
-
- msleep(120);
-
ctx->enabled = false;
return 0;
@@ -280,16 +268,23 @@ static int otm8009a_disable(struct drm_panel *panel)
static int otm8009a_unprepare(struct drm_panel *panel)
{
struct otm8009a *ctx = panel_to_otm8009a(panel);
+ struct mipi_dsi_device *dsi = to_mipi_dsi_device(ctx->dev);
+ int ret;
if (!ctx->prepared)
return 0;
- if (ctx->reset_gpio) {
- gpiod_set_value_cansleep(ctx->reset_gpio, 1);
- msleep(20);
- }
+ ret = mipi_dsi_dcs_set_display_off(dsi);
+ if (ret)
+ return ret;
- regulator_disable(ctx->supply);
+ msleep(10);
+
+ ret = mipi_dsi_dcs_enter_sleep_mode(dsi);
+ if (ret)
+ return ret;
+
+ msleep(120);
ctx->prepared = false;
@@ -304,20 +299,6 @@ static int otm8009a_prepare(struct drm_panel *panel)
if (ctx->prepared)
return 0;
- ret = regulator_enable(ctx->supply);
- if (ret < 0) {
- DRM_ERROR("failed to enable supply: %d\n", ret);
- return ret;
- }
-
- if (ctx->reset_gpio) {
- gpiod_set_value_cansleep(ctx->reset_gpio, 0);
- gpiod_set_value_cansleep(ctx->reset_gpio, 1);
- msleep(20);
- gpiod_set_value_cansleep(ctx->reset_gpio, 0);
- msleep(100);
- }
-
ret = otm8009a_init_sequence(ctx);
if (ret)
return ret;
@@ -475,6 +456,20 @@ static int otm8009a_probe(struct mipi_dsi_device *dsi)
return ret;
}
+ ret = regulator_enable(ctx->supply);
+ if (ret < 0) {
+ DRM_ERROR("failed to enable supply: %d\n", ret);
+ return ret;
+ }
+
+ if (ctx->reset_gpio) {
+ gpiod_set_value_cansleep(ctx->reset_gpio, 0);
+ gpiod_set_value_cansleep(ctx->reset_gpio, 1);
+ msleep(20);
+ gpiod_set_value_cansleep(ctx->reset_gpio, 0);
+ msleep(100);
+ }
+
return 0;
}
@@ -485,6 +480,13 @@ static int otm8009a_remove(struct mipi_dsi_device *dsi)
mipi_dsi_detach(dsi);
drm_panel_remove(&ctx->panel);
+ if (ctx->reset_gpio) {
+ gpiod_set_value_cansleep(ctx->reset_gpio, 1);
+ msleep(20);
+ }
+
+ regulator_disable(ctx->supply);
+
return 0;
}
diff --git a/drivers/gpu/drm/stm/dw_mipi_dsi-stm.c b/drivers/gpu/drm/stm/dw_mipi_dsi-stm.c
index a373651..7b37f97 100644
--- a/drivers/gpu/drm/stm/dw_mipi_dsi-stm.c
+++ b/drivers/gpu/drm/stm/dw_mipi_dsi-stm.c
@@ -305,6 +305,7 @@ static int dw_mipi_dsi_stm_probe(struct platform_device *pdev)
{
struct device *dev = &pdev->dev;
struct dw_mipi_dsi_stm *dsi;
+ struct clk *pclk;
struct resource *res;
int ret;
@@ -335,23 +336,13 @@ static int dw_mipi_dsi_stm_probe(struct platform_device *pdev)
if (IS_ERR(dsi->pllref_clk)) {
ret = PTR_ERR(dsi->pllref_clk);
dev_err(dev, "Unable to get pll reference clock: %d\n", ret);
- regulator_disable(dsi->vdd_supply);
- return ret;
+ goto err_clk_get;
}
ret = clk_prepare_enable(dsi->pllref_clk);
if (ret) {
dev_err(dev, "%s: Failed to enable pllref_clk\n", __func__);
- regulator_disable(dsi->vdd_supply);
- return ret;
- }
-
- dsi->hw_version = dsi_read(dsi, DSI_VERSION) & VERSION;
- if (dsi->hw_version != HWVER_130 && dsi->hw_version != HWVER_131) {
- dev_err(dev, "bad dsi hardware version\n");
- clk_disable_unprepare(dsi->pllref_clk);
- regulator_disable(dsi->vdd_supply);
- return -ENODEV;
+ goto err_clk_get;
}
dw_mipi_dsi_stm_plat_data.base = dsi->base;
@@ -361,13 +352,43 @@ static int dw_mipi_dsi_stm_probe(struct platform_device *pdev)
dsi->dsi = dw_mipi_dsi_probe(pdev, &dw_mipi_dsi_stm_plat_data);
if (IS_ERR(dsi->dsi)) {
+ ret = PTR_ERR(dsi->dsi);
DRM_ERROR("Failed to initialize mipi dsi host\n");
- regulator_disable(dsi->vdd_supply);
- clk_disable_unprepare(dsi->pllref_clk);
- return PTR_ERR(dsi->dsi);
+ goto err_probe;
+ }
+
+ pclk = devm_clk_get(dev, "pclk");
+ if (IS_ERR(pclk)) {
+ ret = PTR_ERR(pclk);
+ dev_err(dev, "Unable to get peripheral clock: %d\n", ret);
+ goto err_probe;
+ }
+
+ ret = clk_prepare_enable(pclk);
+ if (ret) {
+ dev_err(dev, "%s: Failed to enable peripheral clk\n", __func__);
+ goto err_probe;
+ }
+
+ dsi->hw_version = dsi_read(dsi, DSI_VERSION) & VERSION;
+ clk_disable_unprepare(pclk);
+
+ if (dsi->hw_version != HWVER_130 && dsi->hw_version != HWVER_131) {
+ ret = -ENODEV;
+ dev_err(dev, "bad dsi hardware version\n");
+ goto err_probe;
}
return 0;
+
+err_probe:
+ clk_disable_unprepare(dsi->pllref_clk);
+
+err_clk_get:
+ regulator_disable(dsi->vdd_supply);
+
+ return ret;
+
}
static int dw_mipi_dsi_stm_remove(struct platform_device *pdev)
diff --git a/drivers/remoteproc/stm32_rproc.c b/drivers/remoteproc/stm32_rproc.c
index 1d2be11..1827c25 100644
--- a/drivers/remoteproc/stm32_rproc.c
+++ b/drivers/remoteproc/stm32_rproc.c
@@ -104,10 +104,12 @@ static int stm32_rproc_da_to_pa(struct rproc *rproc, u64 da, phys_addr_t *pa)
da >= p_mem->dev_addr + p_mem->size)
continue;
*pa = da - p_mem->dev_addr + p_mem->bus_addr;
- dev_err(rproc->dev.parent, "da %llx to pa %#x\n", da, *pa);
+ dev_dbg(rproc->dev.parent, "da %llx to pa %#x\n", da, *pa);
return 0;
}
+ dev_err(rproc->dev.parent, "can't translate da %llx\n", da);
+
return -EINVAL;
}
@@ -657,20 +659,21 @@ static int stm32_rproc_parse_dt(struct platform_device *pdev)
if (of_property_read_bool(np, "early-booted")) {
rproc->early_boot = true;
-
err = of_property_read_u32(np, "rsc-address", &rsc_da);
- if (!err) {
- err = of_property_read_u32(np, "rsc-size",
- &ddata->rsc_len);
+ if (err)
+ /* no optional rsc table found */
+ return 0;
- if (err) {
- dev_err(dev, "resource table size required as address defined\n");
- return err;
- }
+ err = of_property_read_u32(np, "rsc-size", &ddata->rsc_len);
+ if (err) {
+ dev_err(dev, "resource table size required as address defined\n");
+ return err;
}
+
err = stm32_rproc_da_to_pa(rproc, rsc_da, &rsc_pa);
if (err)
return err;
+
ddata->rsc_va = ioremap_wc(rsc_pa, ddata->rsc_len);
if (IS_ERR_OR_NULL(ddata->rsc_va)) {
dev_err(dev, "Unable to map memory region: %pa+%zx\n",
diff --git a/drivers/tty/serial/stm32-usart.c b/drivers/tty/serial/stm32-usart.c
index d606eb5..6fc57fc 100644
--- a/drivers/tty/serial/stm32-usart.c
+++ b/drivers/tty/serial/stm32-usart.c
@@ -250,8 +250,16 @@ static void stm32_receive_chars(struct uart_port *port, bool threaded)
ofs->icr);
port->icount.overrun++;
} else if (sr & USART_SR_PE) {
+ if (ofs->icr != UNDEF_REG)
+ writel_relaxed(USART_ICR_PECF,
+ port->membase +
+ ofs->icr);
port->icount.parity++;
} else if (sr & USART_SR_FE) {
+ if (ofs->icr != UNDEF_REG)
+ writel_relaxed(USART_ICR_FECF,
+ port->membase +
+ ofs->icr);
port->icount.frame++;
}
diff --git a/drivers/tty/serial/stm32-usart.h b/drivers/tty/serial/stm32-usart.h
index f1f5c1c..53d7e7b 100644
--- a/drivers/tty/serial/stm32-usart.h
+++ b/drivers/tty/serial/stm32-usart.h
@@ -241,7 +241,7 @@ struct stm32_usart_info stm32h7_info = {
/* USART_ICR */
#define USART_ICR_PECF BIT(0) /* F7 */
-#define USART_ICR_FFECF BIT(1) /* F7 */
+#define USART_ICR_FECF BIT(1) /* F7 */
#define USART_ICR_NCF BIT(2) /* F7 */
#define USART_ICR_ORECF BIT(3) /* F7 */
#define USART_ICR_IDLECF BIT(4) /* F7 */
diff --git a/drivers/usb/dwc2/core.h b/drivers/usb/dwc2/core.h
index 4c1736f..3d8fa58 100644
--- a/drivers/usb/dwc2/core.h
+++ b/drivers/usb/dwc2/core.h
@@ -393,6 +393,20 @@ enum dwc2_ep0_state {
* 0 - No
* 1 - Yes
* @hird_threshold: Value of BESL or HIRD Threshold.
+ * @ref_clk_per: Indicates in terms of pico seconds the period
+ * of ref_clk.
+ * 62500 - 16MHz
+ * 58823 - 17MHz
+ * 52083 - 19.2MHz
+ * 50000 - 20MHz
+ * 41666 - 24MHz
+ * 33333 - 30MHz (default)
+ * 25000 - 40MHz
+ * @sof_cnt_wkup_alert: Indicates in term of number of SOF's after which
+ * the controller should generate an interrupt if the
+ * device had been in L1 state until that period.
+ * This is used by SW to initiate Remote WakeUp in the
+ * controller so as to sync to the uF number from the host.
* @activate_stm_fs_transceiver: Activate internal transceiver using GGPIO
* register.
* 0 - Deactivate the transceiver (default)
@@ -426,6 +440,9 @@ enum dwc2_ep0_state {
* back to DWC2_SPEED_PARAM_HIGH while device is gone.
* 0 - No (default)
* 1 - Yes
+ * @service_interval: Enable service interval based scheduling.
+ * 0 - No
+ * 1 - Yes
*
* The following parameters may be specified when starting the module. These
* parameters define how the DWC_otg controller should be configured. A
@@ -471,6 +488,7 @@ struct dwc2_core_params {
bool lpm_clock_gating;
bool besl;
bool hird_threshold_en;
+ bool service_interval;
u8 hird_threshold;
bool activate_stm_fs_transceiver;
bool activate_stm_id_vb_detection;
@@ -479,6 +497,10 @@ struct dwc2_core_params {
u32 max_transfer_size;
u32 ahbcfg;
+ /* GREFCLK parameters */
+ u32 ref_clk_per;
+ u16 sof_cnt_wkup_alert;
+
/* Host parameters */
bool host_dma;
bool dma_desc_enable;
@@ -618,6 +640,10 @@ struct dwc2_core_params {
* FIFO sizing is enabled 16 to 32768
* Actual maximum value is autodetected and also
* the default.
+ * @service_interval_mode: For enabling service interval based scheduling in the
+ * controller.
+ * 0 - Disable
+ * 1 - Enable
*/
struct dwc2_hw_params {
unsigned op_mode:3;
@@ -648,6 +674,7 @@ struct dwc2_hw_params {
unsigned utmi_phy_data_width:2;
unsigned lpm_mode:1;
unsigned ipg_isoc_en:1;
+ unsigned service_interval_mode:1;
u32 snpsid;
u32 dev_ep_dirs;
u32 g_tx_fifo_size[MAX_EPS_CHANNELS];
@@ -1372,6 +1399,7 @@ int dwc2_hsotg_tx_fifo_count(struct dwc2_hsotg *hsotg);
int dwc2_hsotg_tx_fifo_total_depth(struct dwc2_hsotg *hsotg);
int dwc2_hsotg_tx_fifo_average_depth(struct dwc2_hsotg *hsotg);
void dwc2_gadget_init_lpm(struct dwc2_hsotg *hsotg);
+void dwc2_gadget_program_ref_clk(struct dwc2_hsotg *hsotg);
#else
static inline int dwc2_hsotg_remove(struct dwc2_hsotg *dwc2)
{ return 0; }
@@ -1406,6 +1434,7 @@ static inline int dwc2_hsotg_tx_fifo_total_depth(struct dwc2_hsotg *hsotg)
static inline int dwc2_hsotg_tx_fifo_average_depth(struct dwc2_hsotg *hsotg)
{ return 0; }
static inline void dwc2_gadget_init_lpm(struct dwc2_hsotg *hsotg) {}
+static inline void dwc2_gadget_program_ref_clk(struct dwc2_hsotg *hsotg) {}
#endif
#if IS_ENABLED(CONFIG_USB_DWC2_HOST) || IS_ENABLED(CONFIG_USB_DWC2_DUAL_ROLE)
diff --git a/drivers/usb/dwc2/debugfs.c b/drivers/usb/dwc2/debugfs.c
index 22d015b..7f62f4c 100644
--- a/drivers/usb/dwc2/debugfs.c
+++ b/drivers/usb/dwc2/debugfs.c
@@ -701,6 +701,7 @@ static int params_show(struct seq_file *seq, void *v)
print_param(seq, p, besl);
print_param(seq, p, hird_threshold_en);
print_param(seq, p, hird_threshold);
+ print_param(seq, p, service_interval);
print_param(seq, p, host_dma);
print_param(seq, p, g_dma);
print_param(seq, p, g_dma_desc);
diff --git a/drivers/usb/dwc2/gadget.c b/drivers/usb/dwc2/gadget.c
index 220c0f9..55ef3cc 100644
--- a/drivers/usb/dwc2/gadget.c
+++ b/drivers/usb/dwc2/gadget.c
@@ -123,6 +123,24 @@ static inline void dwc2_gadget_incr_frame_num(struct dwc2_hsotg_ep *hs_ep)
}
/**
+ * dwc2_gadget_dec_frame_num_by_one - Decrements the targeted frame number
+ * by one.
+ * @hs_ep: The endpoint.
+ *
+ * This function used in service interval based scheduling flow to calculate
+ * descriptor frame number filed value. For service interval mode frame
+ * number in descriptor should point to last (u)frame in the interval.
+ *
+ */
+static inline void dwc2_gadget_dec_frame_num_by_one(struct dwc2_hsotg_ep *hs_ep)
+{
+ if (hs_ep->target_frame)
+ hs_ep->target_frame -= 1;
+ else
+ hs_ep->target_frame = DSTS_SOFFN_LIMIT;
+}
+
+/**
* dwc2_hsotg_en_gsint - enable one or more of the general interrupt
* @hsotg: The device state
* @ints: A bitmask of the interrupts to enable
@@ -228,6 +246,27 @@ int dwc2_hsotg_tx_fifo_total_depth(struct dwc2_hsotg *hsotg)
}
/**
+ * dwc2_gadget_wkup_alert_handler - Handler for WKUP_ALERT interrupt
+ *
+ * @hsotg: Programming view of the DWC_otg controller
+ *
+ */
+static void dwc2_gadget_wkup_alert_handler(struct dwc2_hsotg *hsotg)
+{
+ u32 gintsts2;
+ u32 gintmsk2;
+
+ gintsts2 = dwc2_readl(hsotg, GINTSTS2);
+ gintmsk2 = dwc2_readl(hsotg, GINTMSK2);
+
+ if (gintsts2 & GINTSTS2_WKUP_ALERT_INT) {
+ dev_dbg(hsotg->dev, "%s: Wkup_Alert_Int\n", __func__);
+ dwc2_set_bit(hsotg, GINTSTS2, GINTSTS2_WKUP_ALERT_INT);
+ dwc2_set_bit(hsotg, DCTL, DCTL_RMTWKUPSIG);
+ }
+}
+
+/**
* dwc2_hsotg_tx_fifo_average_depth - returns average depth of device mode
* TX FIFOs
*
@@ -2812,6 +2851,23 @@ static void dwc2_gadget_handle_nak(struct dwc2_hsotg_ep *hs_ep)
if (using_desc_dma(hsotg)) {
hs_ep->target_frame = hsotg->frame_number;
dwc2_gadget_incr_frame_num(hs_ep);
+
+ /* In service interval mode target_frame must
+ * be set to last (u)frame of the service interval.
+ */
+ if (hsotg->params.service_interval) {
+ /* Set target_frame to the first (u)frame of
+ * the service interval
+ */
+ hs_ep->target_frame &= ~hs_ep->interval + 1;
+
+ /* Set target_frame to the last (u)frame of
+ * the service interval
+ */
+ dwc2_gadget_incr_frame_num(hs_ep);
+ dwc2_gadget_dec_frame_num_by_one(hs_ep);
+ }
+
dwc2_gadget_start_isoc_ddma(hs_ep);
return;
}
@@ -3127,6 +3183,7 @@ void dwc2_hsotg_disconnect(struct dwc2_hsotg *hsotg)
hsotg->connected = 0;
hsotg->test_mode = 0;
+ /* all endpoints should be shutdown */
for (ep = 0; ep < hsotg->num_of_eps; ep++) {
if (hsotg->eps_in[ep])
kill_all_requests(hsotg, hsotg->eps_in[ep],
@@ -3177,6 +3234,7 @@ static void dwc2_hsotg_irq_fifoempty(struct dwc2_hsotg *hsotg, bool periodic)
GINTSTS_PTXFEMP | \
GINTSTS_RXFLVL)
+static int dwc2_hsotg_ep_disable(struct usb_ep *ep);
/**
* dwc2_hsotg_core_init - issue softreset to the core
* @hsotg: The device state
@@ -3191,13 +3249,23 @@ void dwc2_hsotg_core_init_disconnected(struct dwc2_hsotg *hsotg,
u32 val;
u32 usbcfg;
u32 dcfg = 0;
+ int ep;
/* Kill any ep0 requests as controller will be reinitialized */
kill_all_requests(hsotg, hsotg->eps_out[0], -ECONNRESET);
- if (!is_usb_reset)
+ if (!is_usb_reset) {
if (dwc2_core_reset(hsotg, true))
return;
+ } else {
+ /* all endpoints should be shutdown */
+ for (ep = 1; ep < hsotg->num_of_eps; ep++) {
+ if (hsotg->eps_in[ep])
+ dwc2_hsotg_ep_disable(&hsotg->eps_in[ep]->ep);
+ if (hsotg->eps_out[ep])
+ dwc2_hsotg_ep_disable(&hsotg->eps_out[ep]->ep);
+ }
+ }
/*
* we must now enable ep0 ready for host detection and then
@@ -3312,6 +3380,10 @@ void dwc2_hsotg_core_init_disconnected(struct dwc2_hsotg *hsotg,
dwc2_set_bit(hsotg, DIEPMSK, DIEPMSK_BNAININTRMSK);
}
+ /* Enable Service Interval mode if supported */
+ if (using_desc_dma(hsotg) && hsotg->params.service_interval)
+ dwc2_set_bit(hsotg, DCTL, DCTL_SERVICE_INTERVAL_SUPPORTED);
+
dwc2_writel(hsotg, 0, DAINTMSK);
dev_dbg(hsotg->dev, "EP0: DIEPCTL0=0x%08x, DOEPCTL0=0x%08x\n",
@@ -3368,6 +3440,10 @@ void dwc2_hsotg_core_init_disconnected(struct dwc2_hsotg *hsotg,
/* configure the core to support LPM */
dwc2_gadget_init_lpm(hsotg);
+ /* program GREFCLK register if needed */
+ if (using_desc_dma(hsotg) && hsotg->params.service_interval)
+ dwc2_gadget_program_ref_clk(hsotg);
+
/* must be at-least 3ms to allow bus to see disconnect */
mdelay(3);
@@ -3676,6 +3752,10 @@ static irqreturn_t dwc2_hsotg_irq(int irq, void *pw)
if (gintsts & IRQ_RETRY_MASK && --retry_count > 0)
goto irq_retry;
+ /* Check WKUP_ALERT interrupt*/
+ if (hsotg->params.service_interval)
+ dwc2_gadget_wkup_alert_handler(hsotg);
+
spin_unlock(&hsotg->lock);
return IRQ_HANDLED;
@@ -3990,7 +4070,6 @@ static int dwc2_hsotg_ep_disable(struct usb_ep *ep)
struct dwc2_hsotg *hsotg = hs_ep->parent;
int dir_in = hs_ep->dir_in;
int index = hs_ep->index;
- unsigned long flags;
u32 epctrl_reg;
u32 ctrl;
@@ -4008,8 +4087,6 @@ static int dwc2_hsotg_ep_disable(struct usb_ep *ep)
epctrl_reg = dir_in ? DIEPCTL(index) : DOEPCTL(index);
- spin_lock_irqsave(&hsotg->lock, flags);
-
ctrl = dwc2_readl(hsotg, epctrl_reg);
if (ctrl & DXEPCTL_EPENA)
@@ -4032,10 +4109,22 @@ static int dwc2_hsotg_ep_disable(struct usb_ep *ep)
hs_ep->fifo_index = 0;
hs_ep->fifo_size = 0;
- spin_unlock_irqrestore(&hsotg->lock, flags);
return 0;
}
+static int dwc2_hsotg_ep_disable_lock(struct usb_ep *ep)
+{
+ struct dwc2_hsotg_ep *hs_ep = our_ep(ep);
+ struct dwc2_hsotg *hsotg = hs_ep->parent;
+ unsigned long flags;
+ int ret;
+
+ spin_lock_irqsave(&hsotg->lock, flags);
+ ret = dwc2_hsotg_ep_disable(ep);
+ spin_unlock_irqrestore(&hsotg->lock, flags);
+ return ret;
+}
+
/**
* on_list - check request is on the given endpoint
* @ep: The endpoint to check.
@@ -4183,7 +4272,7 @@ static int dwc2_hsotg_ep_sethalt_lock(struct usb_ep *ep, int value)
static const struct usb_ep_ops dwc2_hsotg_ep_ops = {
.enable = dwc2_hsotg_ep_enable,
- .disable = dwc2_hsotg_ep_disable,
+ .disable = dwc2_hsotg_ep_disable_lock,
.alloc_request = dwc2_hsotg_ep_alloc_request,
.free_request = dwc2_hsotg_ep_free_request,
.queue = dwc2_hsotg_ep_queue_lock,
@@ -4323,9 +4412,9 @@ static int dwc2_hsotg_udc_stop(struct usb_gadget *gadget)
/* all endpoints should be shutdown */
for (ep = 1; ep < hsotg->num_of_eps; ep++) {
if (hsotg->eps_in[ep])
- dwc2_hsotg_ep_disable(&hsotg->eps_in[ep]->ep);
+ dwc2_hsotg_ep_disable_lock(&hsotg->eps_in[ep]->ep);
if (hsotg->eps_out[ep])
- dwc2_hsotg_ep_disable(&hsotg->eps_out[ep]->ep);
+ dwc2_hsotg_ep_disable_lock(&hsotg->eps_out[ep]->ep);
}
spin_lock_irqsave(&hsotg->lock, flags);
@@ -4773,9 +4862,9 @@ int dwc2_hsotg_suspend(struct dwc2_hsotg *hsotg)
for (ep = 0; ep < hsotg->num_of_eps; ep++) {
if (hsotg->eps_in[ep])
- dwc2_hsotg_ep_disable(&hsotg->eps_in[ep]->ep);
+ dwc2_hsotg_ep_disable_lock(&hsotg->eps_in[ep]->ep);
if (hsotg->eps_out[ep])
- dwc2_hsotg_ep_disable(&hsotg->eps_out[ep]->ep);
+ dwc2_hsotg_ep_disable_lock(&hsotg->eps_out[ep]->ep);
}
}
@@ -4942,8 +5031,32 @@ void dwc2_gadget_init_lpm(struct dwc2_hsotg *hsotg)
val |= hsotg->params.lpm_clock_gating ? GLPMCFG_ENBLSLPM : 0;
val |= hsotg->params.hird_threshold << GLPMCFG_HIRD_THRES_SHIFT;
val |= hsotg->params.besl ? GLPMCFG_ENBESL : 0;
+ val |= GLPMCFG_LPM_ACCEPT_CTRL_ISOC;
dwc2_writel(hsotg, val, GLPMCFG);
dev_dbg(hsotg->dev, "GLPMCFG=0x%08x\n", dwc2_readl(hsotg, GLPMCFG));
+
+ /* Unmask WKUP_ALERT Interrupt */
+ if (hsotg->params.service_interval)
+ dwc2_set_bit(hsotg, GINTMSK2, GINTMSK2_WKUP_ALERT_INT_MSK);
+}
+
+/**
+ * dwc2_gadget_program_ref_clk - Program GREFCLK register in device mode
+ *
+ * @hsotg: Programming view of DWC_otg controller
+ *
+ */
+void dwc2_gadget_program_ref_clk(struct dwc2_hsotg *hsotg)
+{
+ u32 val = 0;
+
+ val |= GREFCLK_REF_CLK_MODE;
+ val |= hsotg->params.ref_clk_per << GREFCLK_REFCLKPER_SHIFT;
+ val |= hsotg->params.sof_cnt_wkup_alert <<
+ GREFCLK_SOF_CNT_WKUP_ALERT_SHIFT;
+
+ dwc2_writel(hsotg, val, GREFCLK);
+ dev_dbg(hsotg->dev, "GREFCLK=0x%08x\n", dwc2_readl(hsotg, GREFCLK));
}
/**
diff --git a/drivers/usb/dwc2/hcd.c b/drivers/usb/dwc2/hcd.c
index 12fa6c0..7f128b1 100644
--- a/drivers/usb/dwc2/hcd.c
+++ b/drivers/usb/dwc2/hcd.c
@@ -1309,14 +1309,11 @@ static void dwc2_hc_write_packet(struct dwc2_hsotg *hsotg,
u32 remaining_count;
u32 byte_count;
u32 dword_count;
- u32 __iomem *data_fifo;
u32 *data_buf = (u32 *)chan->xfer_buf;
if (dbg_hc(chan))
dev_vdbg(hsotg->dev, "%s()\n", __func__);
- data_fifo = (u32 __iomem *)(hsotg->regs + HCFIFO(chan->hc_num));
-
remaining_count = chan->xfer_len - chan->xfer_count;
if (remaining_count > chan->max_packet)
byte_count = chan->max_packet;
diff --git a/drivers/usb/dwc2/hcd.h b/drivers/usb/dwc2/hcd.h
index 3f9bccc..c089ffa 100644
--- a/drivers/usb/dwc2/hcd.h
+++ b/drivers/usb/dwc2/hcd.h
@@ -366,7 +366,7 @@ struct dwc2_qh {
u32 desc_list_sz;
u32 *n_bytes;
struct timer_list unreserve_timer;
- struct timer_list wait_timer;
+ struct hrtimer wait_timer;
struct dwc2_tt *dwc_tt;
int ttport;
unsigned tt_buffer_dirty:1;
diff --git a/drivers/usb/dwc2/hcd_queue.c b/drivers/usb/dwc2/hcd_queue.c
index 40839591..ea3aa64 100644
--- a/drivers/usb/dwc2/hcd_queue.c
+++ b/drivers/usb/dwc2/hcd_queue.c
@@ -59,7 +59,7 @@
#define DWC2_UNRESERVE_DELAY (msecs_to_jiffies(5))
/* If we get a NAK, wait this long before retrying */
-#define DWC2_RETRY_WAIT_DELAY (msecs_to_jiffies(1))
+#define DWC2_RETRY_WAIT_DELAY 1*1E6L
/**
* dwc2_periodic_channel_available() - Checks that a channel is available for a
@@ -1464,10 +1464,12 @@ static void dwc2_deschedule_periodic(struct dwc2_hsotg *hsotg,
* qh back to the "inactive" list, then queues transactions.
*
* @t: Pointer to wait_timer in a qh.
+ *
+ * Return: HRTIMER_NORESTART to not automatically restart this timer.
*/
-static void dwc2_wait_timer_fn(struct timer_list *t)
+static enum hrtimer_restart dwc2_wait_timer_fn(struct hrtimer *t)
{
- struct dwc2_qh *qh = from_timer(qh, t, wait_timer);
+ struct dwc2_qh *qh = container_of(t, struct dwc2_qh, wait_timer);
struct dwc2_hsotg *hsotg = qh->hsotg;
unsigned long flags;
@@ -1491,6 +1493,7 @@ static void dwc2_wait_timer_fn(struct timer_list *t)
}
spin_unlock_irqrestore(&hsotg->lock, flags);
+ return HRTIMER_NORESTART;
}
/**
@@ -1521,7 +1524,8 @@ static void dwc2_qh_init(struct dwc2_hsotg *hsotg, struct dwc2_qh *qh,
/* Initialize QH */
qh->hsotg = hsotg;
timer_setup(&qh->unreserve_timer, dwc2_unreserve_timer_fn, 0);
- timer_setup(&qh->wait_timer, dwc2_wait_timer_fn, 0);
+ hrtimer_init(&qh->wait_timer, CLOCK_MONOTONIC, HRTIMER_MODE_REL);
+ qh->wait_timer.function = &dwc2_wait_timer_fn;
qh->ep_type = ep_type;
qh->ep_is_in = ep_is_in;
@@ -1690,7 +1694,7 @@ void dwc2_hcd_qh_free(struct dwc2_hsotg *hsotg, struct dwc2_qh *qh)
* won't do anything anyway, but we want it to finish before we free
* memory.
*/
- del_timer_sync(&qh->wait_timer);
+ hrtimer_cancel(&qh->wait_timer);
dwc2_host_put_tt_info(hsotg, qh->dwc_tt);
@@ -1716,6 +1720,7 @@ int dwc2_hcd_qh_add(struct dwc2_hsotg *hsotg, struct dwc2_qh *qh)
{
int status;
u32 intr_mask;
+ ktime_t delay;
if (dbg_qh(qh))
dev_vdbg(hsotg->dev, "%s()\n", __func__);
@@ -1734,8 +1739,8 @@ int dwc2_hcd_qh_add(struct dwc2_hsotg *hsotg, struct dwc2_qh *qh)
list_add_tail(&qh->qh_list_entry,
&hsotg->non_periodic_sched_waiting);
qh->wait_timer_cancel = false;
- mod_timer(&qh->wait_timer,
- jiffies + DWC2_RETRY_WAIT_DELAY + 1);
+ delay = ktime_set(0, DWC2_RETRY_WAIT_DELAY);
+ hrtimer_start(&qh->wait_timer, delay, HRTIMER_MODE_REL);
} else {
list_add_tail(&qh->qh_list_entry,
&hsotg->non_periodic_sched_inactive);
diff --git a/drivers/usb/dwc2/hw.h b/drivers/usb/dwc2/hw.h
index 31f8c60..4980ecb 100644
--- a/drivers/usb/dwc2/hw.h
+++ b/drivers/usb/dwc2/hw.h
@@ -316,6 +316,7 @@
#define GHWCFG4_UTMI_PHY_DATA_WIDTH_SHIFT 14
#define GHWCFG4_ACG_SUPPORTED BIT(12)
#define GHWCFG4_IPG_ISOC_SUPPORTED BIT(11)
+#define GHWCFG4_SERVICE_INTERVAL_SUPPORTED BIT(10)
#define GHWCFG4_UTMI_PHY_DATA_WIDTH_8 0
#define GHWCFG4_UTMI_PHY_DATA_WIDTH_16 1
#define GHWCFG4_UTMI_PHY_DATA_WIDTH_8_OR_16 2
@@ -336,6 +337,8 @@
#define GLPMCFG_SNDLPM BIT(24)
#define GLPMCFG_RETRY_CNT_MASK (0x7 << 21)
#define GLPMCFG_RETRY_CNT_SHIFT 21
+#define GLPMCFG_LPM_ACCEPT_CTRL_CONTROL BIT(21)
+#define GLPMCFG_LPM_ACCEPT_CTRL_ISOC BIT(22)
#define GLPMCFG_LPM_CHNL_INDX_MASK (0xf << 17)
#define GLPMCFG_LPM_CHNL_INDX_SHIFT 17
#define GLPMCFG_L1RESUMEOK BIT(16)
@@ -408,6 +411,19 @@
#define ADPCTL_PRB_DSCHRG_MASK (0x3 << 0)
#define ADPCTL_PRB_DSCHRG_SHIFT 0
+#define GREFCLK HSOTG_REG(0x0064)
+#define GREFCLK_REFCLKPER_MASK (0x1ffff << 15)
+#define GREFCLK_REFCLKPER_SHIFT 15
+#define GREFCLK_REF_CLK_MODE BIT(14)
+#define GREFCLK_SOF_CNT_WKUP_ALERT_MASK (0x3ff)
+#define GREFCLK_SOF_CNT_WKUP_ALERT_SHIFT 0
+
+#define GINTMSK2 HSOTG_REG(0x0068)
+#define GINTMSK2_WKUP_ALERT_INT_MSK BIT(0)
+
+#define GINTSTS2 HSOTG_REG(0x006c)
+#define GINTSTS2_WKUP_ALERT_INT BIT(0)
+
#define HPTXFSIZ HSOTG_REG(0x100)
/* Use FIFOSIZE_* constants to access this register */
@@ -447,6 +463,7 @@
#define DCFG_DEVSPD_FS48 3
#define DCTL HSOTG_REG(0x804)
+#define DCTL_SERVICE_INTERVAL_SUPPORTED BIT(19)
#define DCTL_PWRONPRGDONE BIT(11)
#define DCTL_CGOUTNAK BIT(10)
#define DCTL_SGOUTNAK BIT(9)
diff --git a/drivers/usb/dwc2/params.c b/drivers/usb/dwc2/params.c
index 7fef905..bdcabb1 100644
--- a/drivers/usb/dwc2/params.c
+++ b/drivers/usb/dwc2/params.c
@@ -71,6 +71,13 @@ static void dwc2_set_his_params(struct dwc2_hsotg *hsotg)
p->power_down = false;
}
+static void dwc2_set_s3c6400_params(struct dwc2_hsotg *hsotg)
+{
+ struct dwc2_core_params *p = &hsotg->params;
+
+ p->power_down = 0;
+}
+
static void dwc2_set_rk_params(struct dwc2_hsotg *hsotg)
{
struct dwc2_core_params *p = &hsotg->params;
@@ -81,6 +88,7 @@ static void dwc2_set_rk_params(struct dwc2_hsotg *hsotg)
p->host_perio_tx_fifo_size = 256;
p->ahbcfg = GAHBCFG_HBSTLEN_INCR16 <<
GAHBCFG_HBSTLEN_SHIFT;
+ p->power_down = 0;
}
static void dwc2_set_ltq_params(struct dwc2_hsotg *hsotg)
@@ -110,6 +118,7 @@ static void dwc2_set_amlogic_params(struct dwc2_hsotg *hsotg)
p->phy_type = DWC2_PHY_TYPE_PARAM_UTMI;
p->ahbcfg = GAHBCFG_HBSTLEN_INCR8 <<
GAHBCFG_HBSTLEN_SHIFT;
+ p->power_down = DWC2_POWER_DOWN_PARAM_NONE;
}
static void dwc2_set_amcc_params(struct dwc2_hsotg *hsotg)
@@ -177,7 +186,8 @@ const struct of_device_id dwc2_of_match_table[] = {
{ .compatible = "lantiq,arx100-usb", .data = dwc2_set_ltq_params },
{ .compatible = "lantiq,xrx200-usb", .data = dwc2_set_ltq_params },
{ .compatible = "snps,dwc2" },
- { .compatible = "samsung,s3c6400-hsotg" },
+ { .compatible = "samsung,s3c6400-hsotg",
+ .data = dwc2_set_s3c6400_params },
{ .compatible = "amlogic,meson8-usb",
.data = dwc2_set_amlogic_params },
{ .compatible = "amlogic,meson8b-usb",
@@ -330,9 +340,12 @@ static void dwc2_set_default_params(struct dwc2_hsotg *hsotg)
p->hird_threshold_en = true;
p->hird_threshold = 4;
p->ipg_isoc_en = false;
+ p->service_interval = false;
p->max_packet_count = hw->max_packet_count;
p->max_transfer_size = hw->max_transfer_size;
p->ahbcfg = GAHBCFG_HBSTLEN_INCR << GAHBCFG_HBSTLEN_SHIFT;
+ p->ref_clk_per = 33333;
+ p->sof_cnt_wkup_alert = 100;
if ((hsotg->dr_mode == USB_DR_MODE_HOST) ||
(hsotg->dr_mode == USB_DR_MODE_OTG)) {
@@ -628,6 +641,7 @@ static void dwc2_check_params(struct dwc2_hsotg *hsotg)
CHECK_BOOL(besl, (hsotg->hw_params.snpsid >= DWC2_CORE_REV_3_00a));
CHECK_BOOL(hird_threshold_en, hsotg->params.lpm);
CHECK_RANGE(hird_threshold, 0, hsotg->params.besl ? 12 : 7, 0);
+ CHECK_BOOL(service_interval, hw->service_interval_mode);
CHECK_RANGE(max_packet_count,
15, hw->max_packet_count,
hw->max_packet_count);
@@ -816,6 +830,8 @@ int dwc2_get_hwparams(struct dwc2_hsotg *hsotg)
GHWCFG4_UTMI_PHY_DATA_WIDTH_SHIFT;
hw->acg_enable = !!(hwcfg4 & GHWCFG4_ACG_SUPPORTED);
hw->ipg_isoc_en = !!(hwcfg4 & GHWCFG4_IPG_ISOC_SUPPORTED);
+ hw->service_interval_mode = !!(hwcfg4 &
+ GHWCFG4_SERVICE_INTERVAL_SUPPORTED);
/* fifo sizes */
hw->rx_fifo_size = (grxfsiz & GRXFSIZ_DEPTH_MASK) >>
--
2.7.4

View File

@ -0,0 +1,186 @@
From 56b9c52ec61df693bd997e3ef1465230a6cb1834 Mon Sep 17 00:00:00 2001
From: christophe montaud <christophe.montaud@st.com>
Date: Thu, 24 Jan 2019 10:52:11 +0100
Subject: [PATCH 60/60] ARM stm32mp1 r0 rc4 hotfix w904.3 DEVICETREE
---
arch/arm/boot/dts/stm32mp157-pinctrl.dtsi | 43 +++++++++++++++++++++++++++++++
arch/arm/boot/dts/stm32mp157a-dk1.dts | 2 +-
arch/arm/boot/dts/stm32mp157c-dk2.dts | 4 +--
arch/arm/boot/dts/stm32mp157c-ed1.dts | 2 +-
arch/arm/boot/dts/stm32mp157c.dtsi | 22 +++++++---------
5 files changed, 57 insertions(+), 16 deletions(-)
diff --git a/arch/arm/boot/dts/stm32mp157-pinctrl.dtsi b/arch/arm/boot/dts/stm32mp157-pinctrl.dtsi
index 474e7e3..6e4e5c9 100644
--- a/arch/arm/boot/dts/stm32mp157-pinctrl.dtsi
+++ b/arch/arm/boot/dts/stm32mp157-pinctrl.dtsi
@@ -1249,6 +1249,49 @@
};
};
+ sdmmc2_b4_pins_b: sdmmc2-b4-1 {
+ pins1 {
+ pinmux = <STM32_PINMUX('B', 14, AF9)>, /* SDMMC2_D0 */
+ <STM32_PINMUX('B', 15, AF9)>, /* SDMMC2_D1 */
+ <STM32_PINMUX('B', 3, AF9)>, /* SDMMC2_D2 */
+ <STM32_PINMUX('B', 4, AF9)>, /* SDMMC2_D3 */
+ <STM32_PINMUX('G', 6, AF10)>; /* SDMMC2_CMD */
+ slew-rate = <1>;
+ drive-push-pull;
+ bias-disable;
+ };
+ pins2 {
+ pinmux = <STM32_PINMUX('E', 3, AF9)>; /* SDMMC2_CK */
+ slew-rate = <2>;
+ drive-push-pull;
+ bias-disable;
+ };
+ };
+
+ sdmmc2_b4_od_pins_b: sdmmc2-b4-od-1 {
+ pins1 {
+ pinmux = <STM32_PINMUX('B', 14, AF9)>, /* SDMMC2_D0 */
+ <STM32_PINMUX('B', 15, AF9)>, /* SDMMC2_D1 */
+ <STM32_PINMUX('B', 3, AF9)>, /* SDMMC2_D2 */
+ <STM32_PINMUX('B', 4, AF9)>; /* SDMMC2_D3 */
+ slew-rate = <1>;
+ drive-push-pull;
+ bias-disable;
+ };
+ pins2 {
+ pinmux = <STM32_PINMUX('E', 3, AF9)>; /* SDMMC2_CK */
+ slew-rate = <2>;
+ drive-push-pull;
+ bias-disable;
+ };
+ pins3 {
+ pinmux = <STM32_PINMUX('G', 6, AF10)>; /* SDMMC2_CMD */
+ slew-rate = <1>;
+ drive-open-drain;
+ bias-disable;
+ };
+ };
+
sdmmc2_d47_pins_a: sdmmc2-d47-0 {
pins {
pinmux = <STM32_PINMUX('A', 8, AF9)>, /* SDMMC2_D4 */
diff --git a/arch/arm/boot/dts/stm32mp157a-dk1.dts b/arch/arm/boot/dts/stm32mp157a-dk1.dts
index 467c226..e3a36d3 100644
--- a/arch/arm/boot/dts/stm32mp157a-dk1.dts
+++ b/arch/arm/boot/dts/stm32mp157a-dk1.dts
@@ -325,7 +325,7 @@
vddcore: buck1 {
regulator-name = "vddcore";
- regulator-min-microvolt = <800000>;
+ regulator-min-microvolt = <1200000>;
regulator-max-microvolt = <1350000>;
regulator-always-on;
regulator-initial-mode = <0>;
diff --git a/arch/arm/boot/dts/stm32mp157c-dk2.dts b/arch/arm/boot/dts/stm32mp157c-dk2.dts
index 4da15cd..20a86f1 100644
--- a/arch/arm/boot/dts/stm32mp157c-dk2.dts
+++ b/arch/arm/boot/dts/stm32mp157c-dk2.dts
@@ -108,8 +108,8 @@
&sdmmc2 {
arm,primecell-periphid = <0x10153180>;
pinctrl-names = "default", "opendrain", "sleep";
- pinctrl-0 = <&sdmmc2_b4_pins_a>;
- pinctrl-1 = <&sdmmc2_b4_od_pins_a>;
+ pinctrl-0 = <&sdmmc2_b4_pins_b>;
+ pinctrl-1 = <&sdmmc2_b4_od_pins_b>;
pinctrl-2 = <&sdmmc2_b4_sleep_pins_a>;
non-removable;
st,neg-edge;
diff --git a/arch/arm/boot/dts/stm32mp157c-ed1.dts b/arch/arm/boot/dts/stm32mp157c-ed1.dts
index 6d49f21..780c992 100644
--- a/arch/arm/boot/dts/stm32mp157c-ed1.dts
+++ b/arch/arm/boot/dts/stm32mp157c-ed1.dts
@@ -203,7 +203,7 @@
vddcore: buck1 {
regulator-name = "vddcore";
- regulator-min-microvolt = <800000>;
+ regulator-min-microvolt = <1200000>;
regulator-max-microvolt = <1350000>;
regulator-always-on;
regulator-initial-mode = <0>;
diff --git a/arch/arm/boot/dts/stm32mp157c.dtsi b/arch/arm/boot/dts/stm32mp157c.dtsi
index b09ef8b..694e6e0 100644
--- a/arch/arm/boot/dts/stm32mp157c.dtsi
+++ b/arch/arm/boot/dts/stm32mp157c.dtsi
@@ -430,8 +430,8 @@
interrupts = <GIC_SPI 36 IRQ_TYPE_LEVEL_HIGH>;
clocks = <&rcc SPI2_K>;
resets = <&rcc SPI2_R>;
- dmas = <&dmamux1 39 0x400 0x05>,
- <&dmamux1 40 0x400 0x05>;
+ dmas = <&dmamux1 39 0x400 0x01>,
+ <&dmamux1 40 0x400 0x01>;
dma-names = "rx", "tx";
power-domains = <&pd_core>;
status = "disabled";
@@ -456,8 +456,8 @@
interrupts = <GIC_SPI 51 IRQ_TYPE_LEVEL_HIGH>;
clocks = <&rcc SPI3_K>;
resets = <&rcc SPI3_R>;
- dmas = <&dmamux1 61 0x400 0x05>,
- <&dmamux1 62 0x400 0x05>;
+ dmas = <&dmamux1 61 0x400 0x01>,
+ <&dmamux1 62 0x400 0x01>;
dma-names = "rx", "tx";
power-domains = <&pd_core>;
status = "disabled";
@@ -756,8 +756,8 @@
interrupts = <GIC_SPI 35 IRQ_TYPE_LEVEL_HIGH>;
clocks = <&rcc SPI1_K>;
resets = <&rcc SPI1_R>;
- dmas = <&dmamux1 37 0x400 0x05>,
- <&dmamux1 38 0x400 0x05>;
+ dmas = <&dmamux1 37 0x400 0x01>,
+ <&dmamux1 38 0x400 0x01>;
dma-names = "rx", "tx";
power-domains = <&pd_core>;
status = "disabled";
@@ -782,8 +782,8 @@
interrupts = <GIC_SPI 84 IRQ_TYPE_LEVEL_HIGH>;
clocks = <&rcc SPI4_K>;
resets = <&rcc SPI4_R>;
- dmas = <&dmamux1 83 0x400 0x05>,
- <&dmamux1 84 0x400 0x05>;
+ dmas = <&dmamux1 83 0x400 0x01>,
+ <&dmamux1 84 0x400 0x01>;
dma-names = "rx", "tx";
power-domains = <&pd_core>;
status = "disabled";
@@ -870,8 +870,8 @@
interrupts = <GIC_SPI 85 IRQ_TYPE_LEVEL_HIGH>;
clocks = <&rcc SPI5_K>;
resets = <&rcc SPI5_R>;
- dmas = <&dmamux1 85 0x400 0x05>,
- <&dmamux1 86 0x400 0x05>;
+ dmas = <&dmamux1 85 0x400 0x01>,
+ <&dmamux1 86 0x400 0x01>;
dma-names = "rx", "tx";
power-domains = <&pd_core>;
status = "disabled";
@@ -1770,7 +1770,6 @@
clocks = <&rcc USBH>;
resets = <&rcc USBH_R>;
interrupts = <GIC_SPI 74 IRQ_TYPE_LEVEL_HIGH>;
- power-domains = <&pd_core>;
status = "disabled";
};
@@ -1781,7 +1780,6 @@
resets = <&rcc USBH_R>;
interrupts = <GIC_SPI 75 IRQ_TYPE_LEVEL_HIGH>;
companion = <&usbh_ohci>;
- power-domains = <&pd_core>;
status = "disabled";
};
--
2.7.4

View File

@ -0,0 +1,111 @@
From 5f558583046192d07b1718d6db15cef522fa0bce Mon Sep 17 00:00:00 2001
From: christophe montaud <christophe.montaud@st.com>
Date: Mon, 28 Jan 2019 10:49:20 +0100
Subject: [PATCH 61/62] ARM stm32mp1 r0 rc4 hotfix w904.5 DRIVERS
---
drivers/gpu/drm/panel/panel-orisetech-otm8009a.c | 38 ++++++++++++++----------
drivers/usb/dwc2/platform.c | 13 ++++++--
2 files changed, 33 insertions(+), 18 deletions(-)
diff --git a/drivers/gpu/drm/panel/panel-orisetech-otm8009a.c b/drivers/gpu/drm/panel/panel-orisetech-otm8009a.c
index ee7486b..78a7e62 100644
--- a/drivers/gpu/drm/panel/panel-orisetech-otm8009a.c
+++ b/drivers/gpu/drm/panel/panel-orisetech-otm8009a.c
@@ -284,7 +284,9 @@ static int otm8009a_unprepare(struct drm_panel *panel)
if (ret)
return ret;
- msleep(120);
+ msleep(10);
+
+ regulator_disable(ctx->supply);
ctx->prepared = false;
@@ -299,6 +301,26 @@ static int otm8009a_prepare(struct drm_panel *panel)
if (ctx->prepared)
return 0;
+ if (ctx->reset_gpio) {
+ gpiod_set_value_cansleep(ctx->reset_gpio, 0);
+ gpiod_set_value_cansleep(ctx->reset_gpio, 1);
+ }
+
+ msleep(20);
+
+ ret = regulator_enable(ctx->supply);
+ if (ret < 0) {
+ DRM_ERROR("failed to enable supply: %d\n", ret);
+ return ret;
+ }
+
+ msleep(120);
+
+ if (ctx->reset_gpio) {
+ gpiod_set_value_cansleep(ctx->reset_gpio, 0);
+ msleep(20);
+ }
+
ret = otm8009a_init_sequence(ctx);
if (ret)
return ret;
@@ -456,20 +478,6 @@ static int otm8009a_probe(struct mipi_dsi_device *dsi)
return ret;
}
- ret = regulator_enable(ctx->supply);
- if (ret < 0) {
- DRM_ERROR("failed to enable supply: %d\n", ret);
- return ret;
- }
-
- if (ctx->reset_gpio) {
- gpiod_set_value_cansleep(ctx->reset_gpio, 0);
- gpiod_set_value_cansleep(ctx->reset_gpio, 1);
- msleep(20);
- gpiod_set_value_cansleep(ctx->reset_gpio, 0);
- msleep(100);
- }
-
return 0;
}
diff --git a/drivers/usb/dwc2/platform.c b/drivers/usb/dwc2/platform.c
index b2e5ddc..b80d046 100644
--- a/drivers/usb/dwc2/platform.c
+++ b/drivers/usb/dwc2/platform.c
@@ -568,13 +568,17 @@ static int __maybe_unused dwc2_suspend(struct device *dev)
struct dwc2_hsotg *dwc2 = dev_get_drvdata(dev);
int ret = 0;
- if (dwc2_is_device_mode(dwc2))
- dwc2_hsotg_suspend(dwc2);
-
if (dwc2->params.activate_stm_id_vb_detection &&
!dwc2->params.force_b_session_valid) {
u32 ggpio;
+ /*
+ * Need to force the mode to the current mode to avoid Mode
+ * Mismatch Interrupt when ID and VBUS detection will be
+ * disabled
+ */
+ dwc2_force_mode(dwc2, dwc2_is_host_mode(dwc2));
+
ggpio = dwc2_readl(dwc2, GGPIO);
ggpio &= ~GGPIO_STM32_OTG_GCCFG_IDEN;
ggpio &= ~GGPIO_STM32_OTG_GCCFG_VBDEN;
@@ -583,6 +587,9 @@ static int __maybe_unused dwc2_suspend(struct device *dev)
regulator_disable(dwc2->usb33d);
}
+ if (dwc2_is_device_mode(dwc2))
+ dwc2_hsotg_suspend(dwc2);
+
if (dwc2->ll_hw_enabled)
ret = __dwc2_lowlevel_hw_disable(dwc2);
--
2.7.4

View File

@ -0,0 +1,24 @@
From 771fc61468f4af9f733beb9dbe070033ea2b826a Mon Sep 17 00:00:00 2001
From: christophe montaud <christophe.montaud@st.com>
Date: Mon, 28 Jan 2019 10:49:58 +0100
Subject: [PATCH 62/62] ARM stm32mp1 r0 rc4 hotfix w904.5 DEVICETREE
---
arch/arm/boot/dts/stm32mp157c.dtsi | 1 -
1 file changed, 1 deletion(-)
diff --git a/arch/arm/boot/dts/stm32mp157c.dtsi b/arch/arm/boot/dts/stm32mp157c.dtsi
index 694e6e0..9647119 100644
--- a/arch/arm/boot/dts/stm32mp157c.dtsi
+++ b/arch/arm/boot/dts/stm32mp157c.dtsi
@@ -1233,7 +1233,6 @@
g-tx-fifo-size = <128 128 64 64 64 64 32 32>;
dr_mode = "otg";
usb33d-supply = <&usb33>;
- power-domains = <&pd_core>;
status = "disabled";
};
--
2.7.4

View File

@ -0,0 +1,188 @@
From 67b204258838dd2c940d5b1508318b4890324a06 Mon Sep 17 00:00:00 2001
From: christophe montaud <christophe.montaud@st.com>
Date: Tue, 29 Jan 2019 17:31:19 +0100
Subject: [PATCH 63/64] ARM stm32mp1 r0 rc4 hotfix w905.2 DRIVERS
---
drivers/dma/stm32-dma.c | 70 ++++++++++++++++++++++++++++++++++++---------
drivers/usb/dwc2/platform.c | 38 ++++++++++++++++++------
2 files changed, 87 insertions(+), 21 deletions(-)
diff --git a/drivers/dma/stm32-dma.c b/drivers/dma/stm32-dma.c
index 5abfa4f..dc3ba91 100644
--- a/drivers/dma/stm32-dma.c
+++ b/drivers/dma/stm32-dma.c
@@ -1675,37 +1675,81 @@ static struct dma_async_tx_descriptor *stm32_dma_prep_dma_memcpy(
return vchan_tx_prep(&chan->vchan, &desc->vdesc, flags);
}
+static bool stm32_dma_is_current_sg(struct stm32_dma_chan *chan)
+{
+ struct stm32_dma_device *dmadev = stm32_dma_get_dev(chan);
+ struct stm32_dma_sg_req *sg_req;
+ u32 dma_scr, dma_smar, id;
+
+ id = chan->id;
+ dma_scr = stm32_dma_read(dmadev, STM32_DMA_SCR(id));
+
+ if (!(dma_scr & STM32_DMA_SCR_DBM))
+ return true;
+
+ sg_req = &chan->desc->sg_req[chan->next_sg];
+
+ if (dma_scr & STM32_DMA_SCR_CT) {
+ dma_smar = stm32_dma_read(dmadev, STM32_DMA_SM0AR(id));
+ return (dma_smar == sg_req->chan_reg.dma_sm0ar);
+ }
+
+ dma_smar = stm32_dma_read(dmadev, STM32_DMA_SM1AR(id));
+
+ return (dma_smar == sg_req->chan_reg.dma_sm1ar);
+}
+
static size_t stm32_dma_desc_residue(struct stm32_dma_chan *chan,
struct stm32_dma_desc *desc,
u32 next_sg)
{
u32 modulo, burst_size;
- u32 residue = 0;
+ u32 residue;
+ u32 n_sg = next_sg;
+ struct stm32_dma_sg_req *sg_req = &chan->desc->sg_req[chan->next_sg];
int i;
/* Drain case */
if (chan->residue_after_drain)
return chan->residue_after_drain;
+ residue = stm32_dma_get_remaining_bytes(chan);
+
/*
- * In cyclic mode, for the last period, residue = remaining bytes from
- * NDTR
+ * Calculate the residue means compute the descriptors
+ * information:
+ * - the sg currently transferred
+ * - the remaining position in this sg (NDTR).
+ *
+ * The issue is that a race condition can occur if DMA is
+ * running. DMA can have started to transfer the next sg before
+ * the position in sg is read. In this case the remaing position
+ * can correspond to the new sg position.
+ * The strategy implemented in the stm32 driver is to check the
+ * sg transition. If detected we can not trust the SxNDTR register value
+ * this register can not be up to date during the transition.
+ * in this case we can assume that the dma is at the beginning of next
+ * sg so we calculate the residue in consequence.
*/
- if (chan->desc->cyclic && next_sg == 0) {
- residue = stm32_dma_get_remaining_bytes(chan);
- goto end;
+
+ if (!stm32_dma_is_current_sg(chan)) {
+ n_sg++;
+ if (n_sg == chan->desc->num_sgs)
+ n_sg = 0;
+ residue = sg_dma_len(&sg_req->stm32_sgl_req);
}
/*
- * For all other periods in cyclic mode, and in sg mode,
- * residue = remaining bytes from NDTR + remaining periods/sg to be
- * transferred
+ * In cyclic mode, for the last period, residue = remaining bytes
+ * from NDTR
+ * else for all other periods in cyclic mode, and in sg mode,
+ * residue = remaining bytes from NDTR + remaining
+ * periods/sg to be transferred
*/
- for (i = next_sg; i < desc->num_sgs; i++)
- residue += sg_dma_len(&desc->sg_req[i].stm32_sgl_req);
- residue += stm32_dma_get_remaining_bytes(chan);
+ if (!chan->desc->cyclic || n_sg != 0)
+ for (i = n_sg; i < desc->num_sgs; i++)
+ residue += sg_dma_len(&desc->sg_req[i].stm32_sgl_req);
-end:
if (!chan->mem_burst)
return residue;
diff --git a/drivers/usb/dwc2/platform.c b/drivers/usb/dwc2/platform.c
index b80d046..7e6960c 100644
--- a/drivers/usb/dwc2/platform.c
+++ b/drivers/usb/dwc2/platform.c
@@ -568,16 +568,35 @@ static int __maybe_unused dwc2_suspend(struct device *dev)
struct dwc2_hsotg *dwc2 = dev_get_drvdata(dev);
int ret = 0;
+ if (dwc2_is_device_mode(dwc2))
+ dwc2_hsotg_suspend(dwc2);
+
if (dwc2->params.activate_stm_id_vb_detection &&
!dwc2->params.force_b_session_valid) {
- u32 ggpio;
+ u32 ggpio, gotgctl;
+ int is_host = dwc2_is_host_mode(dwc2);
/*
* Need to force the mode to the current mode to avoid Mode
- * Mismatch Interrupt when ID and VBUS detection will be
- * disabled
+ * Mismatch Interrupt when ID detection will be disabled.
*/
- dwc2_force_mode(dwc2, dwc2_is_host_mode(dwc2));
+ dwc2_force_mode(dwc2, is_host);
+
+ if (!is_host) {
+ gotgctl = dwc2_readl(dwc2, GOTGCTL);
+ /*
+ * We're about to disable Vbus detection hw before low
+ * power mode entry. Then an undesired disconnect
+ * interrupt may occur which is racy with low power
+ * (low-level hw disable). Then check valid session
+ * to force B-peripheral session value.
+ */
+ if (gotgctl & GOTGCTL_BSESVLD) {
+ gotgctl |= GOTGCTL_BVALOVAL;
+ gotgctl |= GOTGCTL_BVALOEN;
+ dwc2_writel(dwc2, gotgctl, GOTGCTL);
+ }
+ }
ggpio = dwc2_readl(dwc2, GGPIO);
ggpio &= ~GGPIO_STM32_OTG_GCCFG_IDEN;
@@ -587,9 +606,6 @@ static int __maybe_unused dwc2_suspend(struct device *dev)
regulator_disable(dwc2->usb33d);
}
- if (dwc2_is_device_mode(dwc2))
- dwc2_hsotg_suspend(dwc2);
-
if (dwc2->ll_hw_enabled)
ret = __dwc2_lowlevel_hw_disable(dwc2);
@@ -612,7 +628,7 @@ static int __maybe_unused dwc2_resume(struct device *dev)
if (dwc2->params.activate_stm_id_vb_detection &&
!dwc2->params.force_b_session_valid) {
- u32 ggpio;
+ u32 ggpio, gotgctl;
ret = regulator_enable(dwc2->usb33d);
if (ret)
@@ -625,6 +641,12 @@ static int __maybe_unused dwc2_resume(struct device *dev)
/* ID/VBUS detection startup time */
usleep_range(5000, 7000);
+
+ /* Unconditionally clear B-Session Valid override */
+ gotgctl = dwc2_readl(dwc2, GOTGCTL);
+ gotgctl &= ~GOTGCTL_BVALOVAL;
+ gotgctl &= ~GOTGCTL_BVALOEN;
+ dwc2_writel(dwc2, gotgctl, GOTGCTL);
}
if (dwc2->params.force_b_session_valid) {
--
2.7.4

View File

@ -0,0 +1,24 @@
From cad13a8b78d8d320394dbed545df8e47c199bbd1 Mon Sep 17 00:00:00 2001
From: christophe montaud <christophe.montaud@st.com>
Date: Tue, 29 Jan 2019 17:31:53 +0100
Subject: [PATCH 64/64] ARM stm32mp1 r0 rc4 hotfix w905.2 DEVICETREE
---
arch/arm/boot/dts/stm32mp157c.dtsi | 1 +
1 file changed, 1 insertion(+)
diff --git a/arch/arm/boot/dts/stm32mp157c.dtsi b/arch/arm/boot/dts/stm32mp157c.dtsi
index 9647119..5581a1c 100644
--- a/arch/arm/boot/dts/stm32mp157c.dtsi
+++ b/arch/arm/boot/dts/stm32mp157c.dtsi
@@ -58,6 +58,7 @@
<GIC_PPI 11 (GIC_CPU_MASK_SIMPLE(4) | IRQ_TYPE_LEVEL_LOW)>,
<GIC_PPI 10 (GIC_CPU_MASK_SIMPLE(4) | IRQ_TYPE_LEVEL_LOW)>;
interrupt-parent = <&intc>;
+ always-on;
};
clocks {
--
2.7.4

View File

@ -0,0 +1,389 @@
#
# systemd specific
#
CONFIG_TASKSTATS=y
CONFIG_TASK_DELAY_ACCT=y
CONFIG_TASK_XACCT=y
CONFIG_TASK_IO_ACCOUNTING=y
# CONFIG_CGROUP_DEBUG is not set
CONFIG_CGROUP_FREEZER=y
CONFIG_CGROUP_DEVICE=y
CONFIG_CPUSETS=y
CONFIG_CGROUP_CPUACCT=y
CONFIG_CGROUP_SCHED=y
CONFIG_BLK_CGROUP=y
CONFIG_AUTOFS4_FS=y
CONFIG_SYSV_FS=y
# CONFIG_SYSFS_DEPRECATED is not set
# CONFIG_SYSFS_DEPRECATED_V2 is not set
CONFIG_HOTPLUG=y
CONFIG_UEVENT_HELPER_PATH=""
CONFIG_UNIX=y
CONFIG_SYSFS=y
CONFIG_PROC_FS=y
CONFIG_TMPFS=y
CONFIG_INOTIFY_USER=y
CONFIG_SIGNALFD=y
CONFIG_TMPFS_POSIX_ACL=y
CONFIG_BLK_DEV_BSG=y
CONFIG_DEVTMPFS=y
CONFIG_DEVTMPFS_MOUNT=y
CONFIG_CGROUPS=y
CONFIG_CGROUP_NS=y
CONFIG_PROC_PID_CPUSET=y
CONFIG_RESOURCE_COUNTERS=y
CONFIG_FUSE_FS=y
CONFIG_TIMERFD=y
CONFIG_EPOLL=y
CONFIG_NET=y
CONFIG_FHANDLE=y
CONFIG_CRYPTO_USER_API_HASH=y
CONFIG_CRYPTO_HMAC=y
CONFIG_CRYPTO_SHA256=y
# CONFIG_FW_LOADER_USER_HELPER is not set
CONFIG_DMIID=y
CONFIG_NET_NS=y
CONFIG_DEVPTS_MULTIPLE_INSTANCES=y
CONFIG_USER_NS=y
CONFIG_IPV6=y
CONFIG_TMPFS_XATTR=y
CONFIG_TMPFS_POSIX_ACL=y
CONFIG_EXT4_FS_POSIX_ACL=y
CONFIG_XFS_POSIX_ACL=y
CONFIG_BTRFS_FS_POSIX_ACL=y
CONFIG_CHECKPOINT_RESTORE=y
CONFIG_CGROUP_SCHED=y
CONFIG_FAIR_GROUP_SCHED=y
CONFIG_SECCOMP=y
CONFIG_CFS_BANDWIDTH=y
CONFIG_CGROUP_BPF=y
# CONFIG_RT_GROUP_SCHED is not set
CONFIG_DEVPTS_MULTIPLE_INSTANCES=y
# CONFIG_AUDIT is not set
CONFIG_BPF_SYSCALL=y
# -------------------------------------------
# IP Table
# -------------------------------------------
CONFIG_UNIX_DIAG=m
CONFIG_TLS=m
CONFIG_IP_MULTICAST=y
CONFIG_IP_ADVANCED_ROUTER=y
CONFIG_IP_FIB_TRIE_STATS=y
CONFIG_IP_MULTIPLE_TABLES=y
CONFIG_IP_ROUTE_MULTIPATH=y
CONFIG_IP_ROUTE_VERBOSE=y
CONFIG_NET_IPIP=m
CONFIG_NET_IPGRE_DEMUX=m
CONFIG_NET_IPGRE=m
CONFIG_NET_IPGRE_BROADCAST=y
CONFIG_IP_MROUTE=y
CONFIG_IP_MROUTE_MULTIPLE_TABLES=y
CONFIG_IP_PIMSM_V1=y
CONFIG_IP_PIMSM_V2=y
CONFIG_NET_IPVTI=m
CONFIG_NET_FOU_IP_TUNNELS=y
CONFIG_INET_AH=m
CONFIG_INET_ESP=m
CONFIG_INET_ESP_OFFLOAD=m
CONFIG_INET_IPCOMP=m
CONFIG_INET_XFRM_MODE_TRANSPORT=m
CONFIG_INET_XFRM_MODE_TUNNEL=m
CONFIG_INET_XFRM_MODE_BEET=m
CONFIG_INET_DIAG=m
CONFIG_INET_UDP_DIAG=m
CONFIG_INET_RAW_DIAG=mCONFIG_BPF_SYSCALL=y
CONFIG_INET_DIAG_DESTROY=y
CONFIG_TCP_CONG_ADVANCED=y
CONFIG_TCP_MD5SIG=y
CONFIG_IPV6=m
CONFIG_IPV6_ROUTE_INFO=y
CONFIG_INET6_ESP_OFFLOAD=m
CONFIG_INET6_XFRM_MODE_ROUTEOPTIMIZATION=m
CONFIG_IPV6_VTI=m
CONFIG_IPV6_SIT_6RD=y
CONFIG_IPV6_GRE=m
CONFIG_IPV6_SUBTREES=y
CONFIG_IPV6_MROUTE=y
CONFIG_IPV6_MROUTE_MULTIPLE_TABLES=y
CONFIG_IPV6_PIMSM_V2=y
CONFIG_IPV6_SEG6_LWTUNNEL=y
CONFIG_IPV6_SEG6_HMAC=y
CONFIG_NETWORK_SECMARK=y
CONFIG_NETWORK_PHY_TIMESTAMPING=y
CONFIG_NETFILTER=y
CONFIG_NF_CONNTRACK=m
CONFIG_NF_LOG_NETDEV=m
CONFIG_NF_CONNTRACK_SECMARK=y
CONFIG_NF_CONNTRACK_EVENTS=y
CONFIG_NF_CONNTRACK_TIMEOUT=y
CONFIG_NF_CONNTRACK_TIMESTAMP=y
CONFIG_NF_CONNTRACK_AMANDA=m
CONFIG_NF_CONNTRACK_FTP=m
CONFIG_NF_CONNTRACK_H323=m
CONFIG_NF_CONNTRACK_IRC=m
CONFIG_NF_CONNTRACK_NETBIOS_NS=m
CONFIG_NF_CONNTRACK_SNMP=m
CONFIG_NF_CONNTRACK_PPTP=m
CONFIG_NF_CONNTRACK_SIP=m
CONFIG_NF_CONNTRACK_TFTP=m
CONFIG_NF_CT_NETLINK=mCONFIG_BPF_SYSCALL=y
CONFIG_NF_CT_NETLINK_TIMEOUT=m
CONFIG_NF_CT_NETLINK_HELPER=m
CONFIG_NETFILTER_NETLINK_GLUE_CT=y
CONFIG_NF_TABLES=m
CONFIG_NF_TABLES_INET=m
CONFIG_NF_TABLES_NETDEV=m
CONFIG_NFT_EXTHDR=m
CONFIG_NFT_META=m
CONFIG_NFT_RT=m
CONFIG_NFT_NUMGEN=m
CONFIG_NFT_CT=m
CONFIG_NFT_SET_RBTREE=m
CONFIG_NFT_SET_HASH=m
CONFIG_NFT_SET_BITMAP=m
CONFIG_NFT_COUNTER=m
CONFIG_NFT_LOG=m
CONFIG_NFT_LIMIT=m
CONFIG_NFT_MASQ=m
CONFIG_NFT_REDIR=m
CONFIG_NFT_NAT=m
CONFIG_NFT_OBJREF=m
CONFIG_NFT_QUEUE=m
CONFIG_NFT_QUOTA=m
CONFIG_NFT_REJECT=m
CONFIG_NFT_HASH=m
CONFIG_NFT_DUP_NETDEV=m
CONFIG_NFT_FWD_NETDEV=m
CONFIG_NETFILTER_XT_TARGET_CLASSIFY=m
CONFIG_NETFILTER_XT_TARGET_CONNMARK=m
CONFIG_NETFILTER_XT_TARGET_CONNSECMARK=m
CONFIG_NETFILTER_XT_TARGET_HMARK=m
CONFIG_NETFILTER_XT_TARGET_IDLETIMER=m
CONFIG_NETFILTER_XT_TARGET_LED=m
CONFIG_NETFILTER_XT_TARGET_LOG=m
CONFIG_NETFILTER_XT_TARGET_MARK=m
CONFIG_NETFILTER_XT_TARGET_NFLOG=m
CONFIG_NETFILTER_XT_TARGET_NFQUEUE=m
CONFIG_NETFILTER_XT_TARGET_TEE=m
CONFIG_NETFILTER_XT_TARGET_SECMARK=m
CONFIG_NETFILTER_XT_TARGET_TCPMSS=m
CONFIG_NETFILTER_XT_MATCH_ADDRTYPE=m
CONFIG_NETFILTER_XT_MATCH_BPF=m
CONFIG_NETFILTER_XT_MATCH_CGROUP=m
CONFIG_NETFILTER_XT_MATCH_CLUSTER=m
CONFIG_NETFILTER_XT_MATCH_COMMENT=m
CONFIG_NETFILTER_XT_MATCH_CONNBYTES=m
CONFIG_NETFILTER_XT_MATCH_CONNLABEL=m
CONFIG_NETFILTER_XT_MATCH_CONNLIMIT=m
CONFIG_NETFILTER_XT_MATCH_CONNMARK=m
CONFIG_NETFILTER_XT_MATCH_CONNTRACK=m
CONFIG_NETFILTER_XT_MATCH_CPU=m
CONFIG_NETFILTER_XT_MATCH_DCCP=m
CONFIG_NETFILTER_XT_MATCH_DEVGROUP=m
CONFIG_NETFILTER_XT_MATCH_DSCP=m
CONFIG_NETFILTER_XT_MATCH_ESP=m
CONFIG_NETFILTER_XT_MATCH_HASHLIMIT=m
CONFIG_NETFILTER_XT_MATCH_HELPER=m
CONFIG_NETFILTER_XT_MATCH_IPCOMP=m
CONFIG_NETFILTER_XT_MATCH_IPRANGE=m
CONFIG_NETFILTER_XT_MATCH_LENGTH=m
CONFIG_NETFILTER_XT_MATCH_LIMIT=m
CONFIG_NETFILTER_XT_MATCH_MAC=m
CONFIG_NETFILTER_XT_MATCH_MARK=m
CONFIG_NETFILTER_XT_MATCH_MULTIPORT=m
CONFIG_NETFILTER_XT_MATCH_NFACCT=m
CONFIG_NETFILTER_XT_MATCH_OSF=m
CONFIG_NETFILTER_XT_MATCH_OWNER=m
CONFIG_NETFILTER_XT_MATCH_POLICY=m
CONFIG_NETFILTER_XT_MATCH_PHYSDEV=m
CONFIG_NETFILTER_XT_MATCH_PKTTYPE=m
CONFIG_NETFILTER_XT_MATCH_QUOTA=m
CONFIG_NETFILTER_XT_MATCH_RATEEST=m
CONFIG_NETFILTER_XT_MATCH_REALM=m
CONFIG_NETFILTER_XT_MATCH_RECENT=m
CONFIG_NETFILTER_XT_MATCH_SCTP=m
CONFIG_NETFILTER_XT_MATCH_STATE=m
CONFIG_NETFILTER_XT_MATCH_STATISTIC=m
CONFIG_NETFILTER_XT_MATCH_STRING=m
CONFIG_NETFILTER_XT_MATCH_TCPMSS=m
CONFIG_NETFILTER_XT_MATCH_TIME=m
CONFIG_NETFILTER_XT_MATCH_U32=m
CONFIG_IP_SET=m
CONFIG_IP_VS=m
CONFIG_NF_CONNTRACK_IPV4=m
CONFIG_NF_SOCKET_IPV4=m
CONFIG_NFT_CHAIN_ROUTE_IPV4=m
CONFIG_NFT_DUP_IPV4=m
CONFIG_NFT_FIB_IPV4=m
CONFIG_NF_TABLES_ARP=m
CONFIG_NF_LOG_ARP=m
CONFIG_NFT_CHAIN_NAT_IPV4=m
CONFIG_NFT_MASQ_IPV4=m
CONFIG_NFT_REDIR_IPV4=m
CONFIG_IP_NF_IPTABLES=m
CONFIG_IP_NF_MATCH_AH=m
CONFIG_IP_NF_MATCH_ECN=m
CONFIG_IP_NF_MATCH_RPFILTER=m
CONFIG_IP_NF_MATCH_TTL=m
CONFIG_IP_NF_FILTER=m
CONFIG_IP_NF_TARGET_REJECT=m
CONFIG_IP_NF_TARGET_SYNPROXY=m
CONFIG_IP_NF_NAT=m
CONFIG_IP_NF_TARGET_MASQUERADE=m
CONFIG_IP_NF_TARGET_NETMAP=m
CONFIG_IP_NF_TARGET_REDIRECT=m
CONFIG_IP_NF_MANGLE=m
CONFIG_IP_NF_TARGET_CLUSTERIP=m
CONFIG_IP_NF_TARGET_ECN=m
CONFIG_IP_NF_TARGET_TTL=m
CONFIG_IP_NF_RAW=m
CONFIG_IP_NF_ARPTABLES=m
CONFIG_IP_NF_ARPFILTER=m
CONFIG_IP_NF_ARP_MANGLE=m
CONFIG_NF_CONNTRACK_IPV6=m
CONFIG_NF_SOCKET_IPV6=m
CONFIG_NFT_CHAIN_ROUTE_IPV6=m
CONFIG_NFT_DUP_IPV6=m
CONFIG_NFT_FIB_IPV6=m
CONFIG_NFT_CHAIN_NAT_IPV6=m
CONFIG_NFT_MASQ_IPV6=m
CONFIG_NFT_REDIR_IPV6=m
CONFIG_IP6_NF_IPTABLES=m
CONFIG_IP6_NF_MATCH_AH=m
CONFIG_IP6_NF_MATCH_EUI64=m
CONFIG_IP6_NF_MATCH_FRAG=m
CONFIG_IP6_NF_MATCH_OPTS=m
CONFIG_IP6_NF_MATCH_HL=m
CONFIG_IP6_NF_MATCH_IPV6HEADER=m
CONFIG_IP6_NF_MATCH_MH=m
CONFIG_IP6_NF_MATCH_RPFILTER=m
CONFIG_IP6_NF_MATCH_RT=m
CONFIG_IP6_NF_TARGET_HL=m
CONFIG_IP6_NF_FILTER=m
CONFIG_IP6_NF_TARGET_REJECT=m
CONFIG_IP6_NF_TARGET_SYNPROXY=m
CONFIG_IP6_NF_MANGLE=m
CONFIG_IP6_NF_RAW=m
CONFIG_IP6_NF_NAT=m
CONFIG_IP6_NF_TARGET_MASQUERADE=m
CONFIG_IP6_NF_TARGET_NPT=m
CONFIG_NF_TABLES_BRIDGE=m
CONFIG_NFT_BRIDGE_META=m
CONFIG_NFT_BRIDGE_REJECT=m
CONFIG_NF_LOG_BRIDGE=m
CONFIG_BRIDGE_NF_EBTABLES=m
CONFIG_BRIDGE_EBT_BROUTE=m
CONFIG_BRIDGE_EBT_T_FILTER=m
CONFIG_BRIDGE_EBT_T_NAT=m
CONFIG_BRIDGE_EBT_802_3=m
CONFIG_BRIDGE_EBT_AMONG=m
CONFIG_BRIDGE_EBT_ARP=m
CONFIG_BRIDGE_EBT_IP=m
CONFIG_BRIDGE_EBT_IP6=m
CONFIG_BRIDGE_EBT_LIMIT=m
CONFIG_BRIDGE_EBT_MARK=m
CONFIG_BRIDGE_EBT_PKTTYPE=m
CONFIG_BRIDGE_EBT_STP=m
CONFIG_BRIDGE_EBT_VLAN=m
CONFIG_BRIDGE_EBT_ARPREPLY=m
CONFIG_BRIDGE_EBT_DNAT=m
CONFIG_BRIDGE_EBT_MARK_T=m
CONFIG_BRIDGE_EBT_REDIRECT=m
CONFIG_BRIDGE_EBT_SNAT=m
CONFIG_BRIDGE_EBT_LOG=m
CONFIG_BRIDGE_EBT_NFLOG=m
CONFIG_L2TP=m
CONFIG_BRIDGE=m
CONFIG_VLAN_8021Q=m
CONFIG_VLAN_8021Q_GVRP=y
CONFIG_VLAN_8021Q_MVRP=y
CONFIG_LLC2=m
CONFIG_6LOWPAN=m
CONFIG_6LOWPAN_DEBUGFS=y
CONFIG_IEEE802154=m
CONFIG_NET_SCHED=y
CONFIG_NET_SCH_CBQ=m
CONFIG_NET_SCH_HTB=m
CONFIG_NET_SCH_HFSC=m
CONFIG_NET_SCH_PRIO=m
CONFIG_NET_SCH_MULTIQ=m
CONFIG_NET_SCH_RED=m
CONFIG_NET_SCH_SFB=m
CONFIG_NET_SCH_SFQ=m
CONFIG_NET_SCH_TEQL=m
CONFIG_NET_SCH_TBF=m
CONFIG_NET_SCH_GRED=m
CONFIG_NET_SCH_DSMARK=m
CONFIG_NET_SCH_NETEM=m
CONFIG_NET_SCH_DRR=m
CONFIG_NET_SCH_MQPRIO=m
CONFIG_NET_SCH_CHOKE=m
CONFIG_NET_SCH_QFQ=m
CONFIG_NET_SCH_CODEL=m
CONFIG_NET_SCH_FQ_CODEL=m
CONFIG_NET_SCH_FQ=m
CONFIG_NET_SCH_HHF=m
CONFIG_NET_SCH_PIE=m
CONFIG_NET_SCH_PLUG=m
CONFIG_NET_SCH_DEFAULT=y
CONFIG_NET_CLS_BASIC=m
CONFIG_NET_CLS_TCINDEX=m
CONFIG_NET_CLS_ROUTE4=m
CONFIG_NET_CLS_FW=m
CONFIG_NET_CLS_U32=m
CONFIG_CLS_U32_PERF=y
CONFIG_CLS_U32_MARK=y
CONFIG_NET_CLS_RSVP=m
CONFIG_NET_CLS_RSVP6=m
CONFIG_NET_CLS_FLOW=m
CONFIG_NET_CLS_CGROUP=m
CONFIG_NET_CLS_BPF=m
CONFIG_NET_CLS_FLOWER=m
CONFIG_NET_CLS_MATCHALL=m
CONFIG_NET_EMATCH=y
CONFIG_NET_EMATCH_CMP=m
CONFIG_NET_EMATCH_NBYTE=m
CONFIG_NET_EMATCH_U32=m
CONFIG_NET_EMATCH_META=m
CONFIG_NET_EMATCH_TEXT=m
CONFIG_NET_EMATCH_CANID=m
CONFIG_NET_CLS_ACT=y
CONFIG_NET_ACT_POLICE=m
CONFIG_NET_ACT_GACT=m
CONFIG_GACT_PROB=y
CONFIG_NET_ACT_MIRRED=m
CONFIG_NET_ACT_SAMPLE=m
CONFIG_NET_ACT_NAT=m
CONFIG_NET_ACT_PEDIT=m
CONFIG_NET_ACT_CSUM=m
CONFIG_NET_ACT_VLAN=m
CONFIG_NET_ACT_BPF=m
CONFIG_NET_ACT_SKBMOD=m
CONFIG_NET_ACT_IFE=m
CONFIG_NET_ACT_TUNNEL_KEY=m
CONFIG_NET_IFE_SKBMARK=m
CONFIG_NET_IFE_SKBPRIO=m
CONFIG_NET_IFE_SKBTCINDEX=m
CONFIG_NET_CLS_IND=y
CONFIG_DCB=y
CONFIG_BATMAN_ADV=m
CONFIG_BATMAN_ADV_BATMAN_V=y
CONFIG_BATMAN_ADV_DAT=y
CONFIG_BATMAN_ADV_NC=y
CONFIG_BATMAN_ADV_MCAST=y
CONFIG_BATMAN_ADV_DEBUG=y
CONFIG_OPENVSWITCH=m
CONFIG_VSOCKETS=m
CONFIG_VIRTIO_VSOCKETS=m
CONFIG_NETLINK_DIAG=m
CONFIG_NET_NSH=m
CONFIG_HSR=m
CONFIG_CGROUP_NET_PRIO=y
CONFIG_BPF_JIT=y
CONFIG_BT_6LOWPAN=m
CONFIG_MACVLAN=m
CONFIG_MACVTAP=m
CONFIG_TUN=m
CONFIG_TUN_VNET_CROSS_LE=y
CONFIG_VETH=m

View File

@ -0,0 +1,2 @@
CONFIG_TEE=y
CONFIG_OPTEE=y

View File

@ -0,0 +1,13 @@
# Allow to load kernel modules built with different kernel version
CONFIG_MODULE_FORCE_LOAD=y
CONFIG_MODVERSIONS=y
# Support of iks01a2
CONFIG_IIO_BUFFER=y
CONFIG_IIO_KFIFO_BUF=y
CONFIG_IIO_TRIGGERED_BUFFER=y
CONFIG_HTS221=y
CONFIG_IIO_ST_PRESS=m
CONFIG_IIO_ST_LSM6DSX=m
CONFIG_IIO_ST_LSM6DSX_I2C=m

View File

@ -0,0 +1,346 @@
Compilation of kernel:
1. Pre-requisite
2. Initialise cross-compilation via SDK
3. Prepare kernel source code
4. Manage the kernel source code
5. Configure kernel source code
6. Compile kernel source code
7. Update software on board
1. Pre-requisite:
-----------------
OpenSTLinux SDK must be installed.
For kernel build, you need to install:
- libncurses and libncursesw dev package
Ubuntu: sudo apt-get install libncurses5-dev libncursesw5-dev
Fedora: sudo yum install ncurses-devel
- mkimage
Ubuntu: sudo apt-get install u-boot-tools
Fedora: sudo yum install u-boot-tools
Only if you like to have a git management of the code (see section 4
[Manage the kernel source code]):
- git:
Ubuntu: sudo apt-get install git-core gitk
Fedora: sudo yum install git
If you have never configured your git configuration, run the following commands:
$> git config --global user.name "your_name"
$> git config --global user.email "your_email@example.com"
2. Initialise cross-compilation via SDK:
----------------------------------------
Source SDK environment:
$> source <path to SDK>/environment-setup-cortexa9hf-neon-openstlinux_weston-linux-gnueabi
To verify if your cross-compilation environment has been put in place correctly,
run the following command:
$> set | grep CROSS
CROSS_COMPILE=arm-openstlinux_weston-linux-gnueabi-
Warning: the environment is valid only on the shell session where you have
sourced the SDK environment.
3. Prepare kernel source:
-------------------------
If you have the tarball and the list of patches, then you must extract the
tarball and apply the patches.
$> tar xfz <kernel source>.tar.gz
or
$> tar xfj <kernel source>.tar.bz2
or
$> tar xfJ <kernel source>.tar.xz
$> cd <directory to kernel source code>
NB: if you like to have a git management of the code, see section 4 [Manage the
kernel source code]
if there is some patch, please apply it on source code
$> for p in `ls -1 <path to patch>/*.patch`; do patch -p1 < $p; done
4. Manage the kernel source code:
---------------------------------
4.1 Setup kernel source code under git
--------------------------------------
If you like to have a better management of change made on kernel source, you can
use git.
* With the kernel source code extracted in the section 3 [Prepare kernel source]
$> cd <directory to kernel source code>
$> test -d .git || git init . && git add . && git commit -m "new kernel" && git gc
$> git checkout -b WORKING
Apply patches:
$> for p in `ls -1 <path to patch>/*.patch`; do git am $p; done
NB: this is the fastest way to get your kernel source code ready for development
Or
* With the kernel source code from the Linux kernel git repositories:
URL: https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux-stable.git
Branch: ##GIT_BRANCH##
Revision: ##GIT_SRCREV##
$> git clone https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux-stable.git
$> cd <kernel source>
$> git checkout -b WORKING ##GIT_SRCREV##
$> for p in `ls -1 <path to patch>/*.patch`; do git am $p; done
NB: this way is slightly slower than the tarball extraction but you get
advantage of all git history.
4.2 Predefined kernel version vs auto-generated kernel version:
---------------------------------------------------------------
If you are using git for managing your source code, kernel makefile get the SHA1
of current git and add it to kernel version number generated.
ex.: 4.9.23-g3e866b0 (kernel version + SHA1 of current git commit)
To bypass this auto-generation of kernel version number:
$> cd <directory to kernel source code>
$> echo "" > .scmversion
This file avoid to have a kernel version with SHA1:
- With scmversion file: 4.9.23
- Without scmversion file: 4.9.23-g3e866b0
This configuration allows to build new kernel from modified source code without
any issue when using the new kernel binary on target regarding any external
kernel module already available on target rootfs (as built without scmversion).
5. Configure kernel source code:
--------------------------------
There are two methods to configure and compile kernel source code:
- Inside kernel source tree directory
- Outside kernel source tree in a build directory
We highly preconized the build is a build directory method as:
- It avoids mixing files generated by the build with the source files inside
same directories
- To remove all the files generated by the build, it's enough to remove the
build directory
- You can build for different configurations in several build directories, e.g.:
1) build in "build_1" for a first kernel configuration
2) build in "build_2" for a second kernel configuration
Then this leaves the 2 images available for tests
* Configure on a build directory (different of kernel source code directory)
Here for example, build directory is located at the same level of kernel
source code
$> cd <directory to kernel source code>
$> mkdir -p ../build
$> make ARCH=arm O="$PWD/../build" multi_v7_defconfig fragment*.config
If there are some fragments, apply them
* manually one by one:
$> scripts/kconfig/merge_config.sh -m -r -O $PWD/../build $PWD/../build/.config ../fragment-01-xxx.config
$> scripts/kconfig/merge_config.sh -m -r -O $PWD/../build $PWD/../build/.config ../fragment-02-xxx.config
...
$> yes '' | make ARCH=arm oldconfig O="$PWD/../build"
* or, by loop:
$> for f in `ls -1 ../fragment*.config`; do scripts/kconfig/merge_config.sh -m -r -O $PWD/../build $PWD/../build/.config $f; done
$> yes '' | make ARCH=arm oldconfig O="$PWD/../build"
* Configure on the current source code directory
$> cd <directory to kernel source code>
$> make ARCH=arm multi_v7_defconfig fragment*.config
If there are some fragments, apply them
* manually one by one:
$> scripts/kconfig/merge_config.sh -m -r .config ../fragment-01-xxxx.config
$> scripts/kconfig/merge_config.sh -m -r .config ../fragment-02-xxxx.config
...
$> yes '' | make oldconfig
* or, by loop:
$> for f in `ls -1 ../fragment*.config`; do scripts/kconfig/merge_config.sh -m -r .config $f; done
$> yes '' | make ARCH=arm oldconfig
NB: Two types of fragments are provided:
* official fragments (fragment-xxx.config)
* optional fragments as example (optional-fragment-xxx.config) to add a
feature not enabled by default.
The order in which fragments are applied is determined by the number of the
fragment filename (fragment-001, fragment-002, e.g.).
Please pay special attention to the naming of your optional fragments to
ensure you select the right features.
6. Compile kernel source code:
------------------------------
You MUST compile from the directory on which the configuration has been done (i.e.
the directory which contains the '.config' file).
It's preconized to use the method with dedicated build directory for a better
managment of changes made on source code (as all build artifacts will be located
inside the dedicated build directory).
* Compile and install on a build directory (different of kernel source code directory)
$> cd <directory to kernel source code>
* Build kernel images (uImage and vmlinux) and device tree (dtbs)
$> make ARCH=arm uImage vmlinux dtbs LOADADDR=0xC2000040 O="$PWD/../build"
* Build kernel module
$> make ARCH=arm modules O="$PWD/../build"
* Generate output build artifacts
$> make ARCH=arm INSTALL_MOD_PATH="$PWD/../build/install_artifact" modules_install O="$PWD/../build"
$> mkdir -p $PWD/../build/install_artifact/boot/
$> cp $PWD/../build/arch/arm/boot/uImage $PWD/../build/install_artifact/boot/
$> cp $PWD/../build/arch/arm/boot/dts/st*.dtb $PWD/../build/install_artifact/boot/
or
$> cd <build directory>
* Build kernel images (uImage and vmlinux) and device tree (dtbs)
$> make ARCH=arm uImage vmlinux dtbs LOADADDR=0xC2000040
* Build kernel module
$> make ARCH=arm modules
* Generate output build artifacts
$> make ARCH=arm INSTALL_MOD_PATH="$PWD/../build/install_artifact" modules_install
$> mkdir -p $PWD/../build/install_artifact/boot/
$> cp $PWD/../build/arch/arm/boot/uImage $PWD/../build/install_artifact/boot/
$> cp $PWD/../build/arch/arm/boot/dts/st*.dtb $PWD/../build/install_artifact/boot/
* Compile and install on the current source code directory
$> cd <directory to kernel source code>
* Build kernel images (uImage and vmlinux) and device tree (dtbs)
$> make ARCH=arm uImage vmlinux dtbs LOADADDR=0xC2000040
* Build kernel module
$> make ARCH=arm modules
* Generate output build artifacts
$> make ARCH=arm INSTALL_MOD_PATH="$PWD/install_artifact" modules_install
$> mkdir -p $PWD/install_artifact/boot/
$> cp $PWD/arch/arm/boot/uImage $PWD/install_artifact/boot/
$> cp $PWD/arch/arm/boot/dts/st*.dtb $PWD/install_artifact/boot/
7. Update software on board:
----------------------------
7.1. Partitioning of binaries:
------------------------------
* Bootfs:
Bootfs contains the kernel and the devicetree.
* Rootfs:
Rootfs contains the external kernel modules.
Please refer to User guide for more details.
7.2. Update via network:
------------------------
* kernel + devicetree
$> cd <path to install_artifact dir>/install_artifact
$> ssh root@<ip of board> mount <device corresponding to bootfs> /boot
$> scp -r boot/* root@<ip of board>:/boot/
$> ssh root@<ip of board> umount /boot
* kernel modules
$> cd <path to install_artifact dir>/install_artifact
Remove the link on install_artifact/lib/modules/<kernel version>/
$> rm lib/modules/<kernel version>/source lib/modules/<kernel version>/build
Optionally, strip kernel modules (to reduce the size of each kernel modules)
$> find . -name "*.ko" | xargs $STRIP --strip-debug --remove-section=.comment --remove-section=.note --preserve-dates
Copy kernel modules:
$> scp -r lib/modules/* root@<ip of board>:/lib/modules/
Generate a list of module dependencies (modules.dep) and a list of symbols
provided by modules (modules.symbols):
$> ssh root@<ip of board> /sbin/depmod -a
Synchronize data on disk with memory
$> ssh root@<ip of board> sync
Reboot the board in order to take update into account
$> ssh root@<ip of board> reboot
7.3. Update via SDCARD on your Linux PC:
----------------------------------------
* kernel + devicetree
$> cd <path to install_artifact dir>/install_artifact
Verify sdcard are mounted on your Linux PC: /media/$USER/bootfs
$> cp -r boot/* /media/$USER/bootfs/
Depending of your Linux configuration, you may call the command under sudo
$> sudo cp -r boot/* /media/$USER/bootfs/
Don't forget to unmount properly sdcard
* kernel modules
$> cd <path to install_artifact dir>/install_artifact
Remove the link on install_artifact/lib/modules/<kernel version>/
$> rm lib/modules/<kernel version>/source lib/modules/<kernel version>/build
Optionally, strip kernel modules (to reduce the size of each kernel modules)
$> find . -name "*.ko" | xargs $STRIP --strip-debug --remove-section=.comment --remove-section=.note --preserve-dates
Verify sdcard are mounted on your Linux PC: /media/$USER/rootfs
Copy kernel modules:
$> cp -r lib/modules/* /media/$USER/rootfs/lib/modules/
Depending of your Linux configuration, you may call the command under sudo
$> sudo cp -r lib/modules/* /media/$USER/rootfs/lib/modules/
Don't forget to unmount properly sdcard
Generate a list of module dependencies (modules.dep) and a list of symbols
provided by modules (modules.symbols):
$> ssh root@<ip of board> depmod -a
Synchronize data on disk with memory
$> ssh root@<ip of board> sync
Reboot the board in order to take update into account
$> ssh root@<ip of board> reboot
7.4. Update via SDCARD on your BOARD (via U-Boot):
--------------------------------------------------
You MUST configure first, via U-Boot, the board into usb mass storage:
* Plug the SDCARD on Board.
* Start the board and stop on U-boot shell:
Hit any key to stop autoboot: 0
STM32MP>
* plug an USB cable between the PC and the board via USB OTG port.
* On U-Boot shell, call the usb mass storage functionnality:
STM32MP> ums 0 mmc 0
ums <USB controller> <dev type: mmc|usb> <dev[:part]>
Example:
For SDCARD: ums 0 mmc 0
For USB Disk: ums 0 usb 0
* kernel + devicetree
$> cd <path to install_artifact dir>/install_artifact
Remove the link on install_artifact/lib/modules/<kernel version>/
$> rm lib/modules/<kernel version>/source lib/modules/<kernel version>/build
Optionally, strip kernel modules (to reduce the size of each kernel modules)
$> find . -name "*.ko" | xargs $STRIP --strip-debug --remove-section=.comment --remove-section=.note --preserve-dates
Verify sdcard mount point are mounted on your Linux PC: /media/$USER/bootfs
$> cp -r boot/* /media/$USER/bootfs/
Depending of your Linux configuration, you may call the command under sudo
$> sudo cp -rf boot/* /media/$USER/bootfs/
Don't forget to unmount properly sdcard
Warning: kernel and device tree file name must be aligned between
extlinux.conf file and file system.
* kernel modules
$> cd <path to install_artifact dir>/install_artifact
Remove the link on install_artifact/lib/modules/<kernel version>/
$> rm lib/modules/<kernel version>/source lib/modules/<kernel version>/build
Optionally, strip kernel modules (to reduce the size of each kernel modules)
$> find . -name "*.ko" | xargs $STRIP --strip-debug --remove-section=.comment --remove-section=.note --preserve-dates
Verify sdcard mount point are mounted on your Linux PC: /media/$USER/rootfs
Copy kernel modules:
$> cp -rf lib/modules/* /media/$USER/rootfs/lib/modules/
Depending of your Linux configuration, you may call the command under sudo
$> sudo cp -r lib/modules/* /media/$USER/rootfs/lib/modules/
Don't forget to unmount properly sdcard
At next runtime, don't forget to generate a list of module dependencies
(modules.dep) and a list of symbols provided by modules (modules.symbols):
$on board> depmod -a
Synchronize data on disk with memory
$on board> sync
Reboot the board in order to take update into account
$on board> reboot
8. Useful information:
----------------------
* How to re-generate kernel database on board:
$on board> depmod -a
(don't forget to synchronize the filesystem before to reboot)
$on board> sync
* How to see the list of external kernel modules loaded:
$on board> lsmod
* How to see information about kernel module:
$on board> modinfo ./install_artifact/lib/modules/<kernel version>/kernel/drivers/leds/led-class-flash.ko
Example usage:
filename: <build directory>./install_artifact/lib/modules/4.9.23-g3e866b0/kernel/drivers/leds/led-class-flash.ko
license: GPL v2
description: LED Flash class interface
author: Jacek Anaszewski <j.anaszewski@samsung.com>
depends:
intree: Y
vermagic: 4.9.23-g3e866b0 SMP mod_unload ARMv7 p2v8

View File

@ -0,0 +1,135 @@
SUMMARY = "Linux STM32MP Kernel"
SECTION = "kernel"
LICENSE = "GPLv2"
LIC_FILES_CHKSUM = "file://COPYING;md5=bbea815ee2795b2f4230826c0c6b8814"
include linux-stm32mp.inc
SRC_URI = "https://cdn.kernel.org/pub/linux/kernel/v4.x/linux-4.19.9.tar.xz"
SRC_URI[md5sum] = "d7e09d6be85ec8548c73e8713531e958"
SRC_URI[sha256sum] = "fc116cc6829c73944215d3b3ac0fc368dde9e8235b456744afffde001269dbf2"
SRC_URI += " \
file://${LINUX_VERSION}/4.19.9/0001-ARM-stm32mp1-r0-rc1-MACHINE.patch \
file://${LINUX_VERSION}/4.19.9/0002-ARM-stm32mp1-r0-rc1-CLOCK.patch \
file://${LINUX_VERSION}/4.19.9/0003-ARM-stm32mp1-r0-rc1-DMA.patch \
file://${LINUX_VERSION}/4.19.9/0004-ARM-stm32mp1-r0-rc1-I2C.patch \
file://${LINUX_VERSION}/4.19.9/0005-ARM-stm32mp1-r0-rc1-IIO.patch \
file://${LINUX_VERSION}/4.19.9/0006-ARM-stm32mp1-r0-rc1-IRQ-Mailbox.patch \
file://${LINUX_VERSION}/4.19.9/0007-ARM-stm32mp1-r0-rc1-INPUT-TTY.patch \
file://${LINUX_VERSION}/4.19.9/0008-ARM-stm32mp1-r0-rc1-MFD.patch \
file://${LINUX_VERSION}/4.19.9/0009-ARM-stm32mp1-r0-rc1-MMC-MTD.patch \
file://${LINUX_VERSION}/4.19.9/0010-ARM-stm32mp1-r0-rc1-ETH.patch \
file://${LINUX_VERSION}/4.19.9/0011-ARM-stm32mp1-r0-rc1-NVMEM.patch \
file://${LINUX_VERSION}/4.19.9/0012-ARM-stm32mp1-r0-rc1-PINCTRL-PWM-RESET-RTC.patch \
file://${LINUX_VERSION}/4.19.9/0013-ARM-stm32mp1-r0-rc1-REMOTEPROC-RPMSG.patch \
file://${LINUX_VERSION}/4.19.9/0014-ARM-stm32mp1-r0-rc1-WATCHDOG.patch \
file://${LINUX_VERSION}/4.19.9/0015-ARM-stm32mp1-r0-rc1-MISC.patch \
file://${LINUX_VERSION}/4.19.9/0016-ARM-stm32mp1-r0-rc1-DEVICETREE.patch \
file://${LINUX_VERSION}/4.19.9/0017-ARM-stm32mp1-r0-rc1-DEFCONFIG.patch \
file://${LINUX_VERSION}/4.19.9/0018-ARM-stm32mp1-r0-rc2-DRM-KMS.patch \
file://${LINUX_VERSION}/4.19.9/0019-ARM-stm32mp1-r0-rc2-SOUND.patch \
file://${LINUX_VERSION}/4.19.9/0020-ARM-stm32mp1-r0-rc2-MEDIA.patch \
file://${LINUX_VERSION}/4.19.9/0021-ARM-stm32mp1-r0-rc2-PINCTRL.patch \
file://${LINUX_VERSION}/4.19.9/0022-ARM-stm32mp1-r0-rc2-MFD-IRQ.patch \
file://${LINUX_VERSION}/4.19.9/0023-ARM-stm32mp1-r0-rc2-USB.patch \
file://${LINUX_VERSION}/4.19.9/0024-ARM-stm32mp1-r0-rc2-THERMAL.patch \
file://${LINUX_VERSION}/4.19.9/0025-ARM-stm32mp1-r0-rc2-REMOTEPROC.patch \
file://${LINUX_VERSION}/4.19.9/0026-ARM-stm32mp1-r0-rc2-NET.patch \
file://${LINUX_VERSION}/4.19.9/0027-ARM-stm32mp1-r0-rc2-HWCLK-SPI.patch \
file://${LINUX_VERSION}/4.19.9/0028-ARM-stm32mp1-r0-rc2-MMC.patch \
file://${LINUX_VERSION}/4.19.9/0029-ARM-stm32mp1-r0-rc2-HWSPINLOCK-IIO-I2C.patch \
file://${LINUX_VERSION}/4.19.9/0030-ARM-stm32mp1-r0-rc2-DEVICETREE.patch \
file://${LINUX_VERSION}/4.19.9/0031-ARM-stm32mp1-r0-rc2-DEFCONFIG.patch \
file://${LINUX_VERSION}/4.19.9/0032-ARM-stm32mp1-r0-rc3-DMA.patch \
file://${LINUX_VERSION}/4.19.9/0033-ARM-stm32mp1-r0-rc3-DISPLAY.patch \
file://${LINUX_VERSION}/4.19.9/0034-ARM-stm32mp1-r0-rc3-ETH.patch \
file://${LINUX_VERSION}/4.19.9/0035-ARM-stm32mp1-r0-rc3-IIO.patch \
file://${LINUX_VERSION}/4.19.9/0036-ARM-stm32mp1-r0-rc3-INPUT-TTY.patch \
file://${LINUX_VERSION}/4.19.9/0037-ARM-stm32mp1-r0-rc3-IRQ-Mailbox.patch \
file://${LINUX_VERSION}/4.19.9/0038-ARM-stm32mp1-r0-rc3-MEDIA.patch \
file://${LINUX_VERSION}/4.19.9/0039-ARM-stm32mp1-r0-rc3-MMC-MTD.patch \
file://${LINUX_VERSION}/4.19.9/0040-ARM-stm32mp1-r0-rc3-PINCTRL-PWM-RESET-RTC.patch \
file://${LINUX_VERSION}/4.19.9/0041-ARM-stm32mp1-r0-rc3-REMOTEPROC-RPMSG.patch \
file://${LINUX_VERSION}/4.19.9/0042-ARM-stm32mp1-r0-rc3-SOUND.patch \
file://${LINUX_VERSION}/4.19.9/0043-ARM-stm32mp1-r0-rc3-MISC.patch \
file://${LINUX_VERSION}/4.19.9/0044-ARM-stm32mp1-r0-rc3-DEVICETREE.patch \
file://${LINUX_VERSION}/4.19.9/0045-ARM-stm32mp1-r0-rc3-DEFCONFIG.patch \
file://${LINUX_VERSION}/4.19.9/0046-ARM-stm32mp1-r0-rc4-MMC-MTD.patch \
file://${LINUX_VERSION}/4.19.9/0047-ARM-stm32mp1-r0-rc4-PINCTRL-PWM-RESET-RTC.patch \
file://${LINUX_VERSION}/4.19.9/0048-ARM-stm32mp1-r0-rc4-REMOTEPROC-RPMSG.patch \
file://${LINUX_VERSION}/4.19.9/0049-ARM-stm32mp1-r0-rc4-SOUND.patch \
file://${LINUX_VERSION}/4.19.9/0050-ARM-stm32mp1-r0-rc4-USB.patch \
file://${LINUX_VERSION}/4.19.9/0051-ARM-stm32mp1-r0-rc4-DEVICETREE.patch \
file://${LINUX_VERSION}/4.19.9/0052-ARM-stm32mp1-r0-rc4-DEFCONFIG.patch \
\
file://${LINUX_VERSION}/4.19.9/0053-ARM-stm32mp1-r0-rc4-hotfix-w903.1-DRIVERS.patch \
file://${LINUX_VERSION}/4.19.9/0054-ARM-stm32mp1-r0-rc4-hotfix-w903.1-DEVICETREE.patch \
file://${LINUX_VERSION}/4.19.9/0055-ARM-stm32mp1-r0-rc4-hotfix-w903.1-DEFCONFIG.patch \
\
file://${LINUX_VERSION}/4.19.9/0056-ARM-stm32mp1-r0-rc4-hotfix-w903.3-DRIVERS.patch \
file://${LINUX_VERSION}/4.19.9/0057-ARM-stm32mp1-r0-rc4-hotfix-w903.3-DEVICETREE.patch \
file://${LINUX_VERSION}/4.19.9/0058-ARM-stm32mp1-r0-rc4-hotfix-w903.3-DEFCONFIG.patch \
\
file://${LINUX_VERSION}/4.19.9/0059-ARM-stm32mp1-r0-rc4-hotfix-w904.3-DRIVERS.patch \
file://${LINUX_VERSION}/4.19.9/0060-ARM-stm32mp1-r0-rc4-hotfix-w904.3-DEVICETREE.patch \
\
file://${LINUX_VERSION}/4.19.9/0061-ARM-stm32mp1-r0-rc4-hotfix-w904.5-DRIVERS.patch \
file://${LINUX_VERSION}/4.19.9/0062-ARM-stm32mp1-r0-rc4-hotfix-w904.5-DEVICETREE.patch \
\
file://${LINUX_VERSION}/4.19.9/0063-ARM-stm32mp1-r0-rc4-hotfix-w905.2-DRIVERS.patch \
file://${LINUX_VERSION}/4.19.9/0064-ARM-stm32mp1-r0-rc4-hotfix-w905.2-DEVICETREE.patch \
"
LINUX_VERSION = "4.19"
PV = "${LINUX_VERSION}"
S = "${WORKDIR}/linux-4.19.9"
# ---------------------------------
# Configure devupstream class usage
# ---------------------------------
BBCLASSEXTEND = "devupstream:target"
SRC_URI_class-devupstream = "git://github.com/STMicroelectronics/linux.git;protocol=https;branch=v${LINUX_VERSION}-stm32mp"
SRCREV_class-devupstream = "196201973b7048ccf75aa63ac3c3673f8b6ee1c1"
# ---------------------------------
# Configure default preference to manage dynamic selection between tarball and github
# ---------------------------------
STM32MP_SOURCE_SELECTION ?= "tarball"
DEFAULT_PREFERENCE = "${@bb.utils.contains('STM32MP_SOURCE_SELECTION', 'github', '-1', '1', d)}"
# -------------------------------------------------------------
# Defconfig
#
KERNEL_DEFCONFIG = "multi_v7_defconfig"
KERNEL_CONFIG_FRAGMENTS = "${@bb.utils.contains('KERNEL_DEFCONFIG', 'multi_v7_defconfig', '${S}/arch/arm/configs/fragment-01-multiv7_cleanup.config', '', d)}"
KERNEL_CONFIG_FRAGMENTS += "${@bb.utils.contains('KERNEL_DEFCONFIG', 'multi_v7_defconfig', '${S}/arch/arm/configs/fragment-02-multiv7_addons.config', '', d)}"
KERNEL_CONFIG_FRAGMENTS += "${@bb.utils.contains('DISTRO_FEATURES', 'systemd', '${WORKDIR}/fragments/4.19/fragment-03-systemd.config', '', d)} "
KERNEL_CONFIG_FRAGMENTS += "${@bb.utils.contains('COMBINED_FEATURES', 'optee', '${WORKDIR}/fragments/4.19/fragment-04-optee.config', '', d)}"
KERNEL_CONFIG_FRAGMENTS += "${WORKDIR}/fragments/4.19/fragment-05-modules.config"
SRC_URI += "file://4.19/fragment-03-systemd.config;subdir=fragments"
SRC_URI += "file://4.19/fragment-04-optee.config;subdir=fragments"
SRC_URI += "file://4.19/fragment-05-modules.config;subdir=fragments"
# Don't forget to add/del for devupstream
SRC_URI_append_class-devupstream = " file://4.19/fragment-03-systemd.config;subdir=fragments "
SRC_URI_append_class-devupstream = " file://4.19/fragment-04-optee.config;subdir=fragments "
SRC_URI_append_class-devupstream = " file://4.19/fragment-05-modules.config;subdir=fragments "
# -------------------------------------------------------------
# Kernel Args
#
KERNEL_EXTRA_ARGS += "LOADADDR=${ST_KERNEL_LOADADDR}"
# -------------------------------------------------------------
# Archiver
#
inherit archiver
ARCHIVER_MODE[src] = "${@'original' if d.getVar('ST_ARCHIVER_ENABLE') == '1' else ''}"
SRC_URI =+ "file://README.HOW_TO.txt"
inherit archiver_stm32mp_clean