* Re: [PATCH V10 07/12] of/acpi: Configure dma operations at probe time for platform/amba/pci bus devices
From: Sricharan R @ 2017-04-04 12:30 UTC (permalink / raw)
To: Robin Murphy, will.deacon, joro, lorenzo.pieralisi, iommu,
linux-arm-kernel, linux-arm-msm, m.szyprowski, bhelgaas,
linux-pci, linux-acpi, tn, hanjun.guo, okaya, robh+dt,
frowand.list, devicetree, linux-kernel, sudeep.holla, rjw, lenb,
catalin.marinas, arnd, linux-arch, gregkh
In-Reply-To: <1d036139-b885-bac6-01c0-78d3ac690d80@arm.com>
Hi Robin,
On 4/4/2017 5:47 PM, Robin Murphy wrote:
> On 04/04/17 11:18, Sricharan R wrote:
>> Configuring DMA ops at probe time will allow deferring device probe when
>> the IOMMU isn't available yet. The dma_configure for the device is
>> now called from the generic device_attach callback just before the
>> bus/driver probe is called. This way, configuring the DMA ops for the
>> device would be called at the same place for all bus_types, hence the
>> deferred probing mechanism should work for all buses as well.
>>
>> pci_bus_add_devices (platform/amba)(_device_create/driver_register)
>> | |
>> pci_bus_add_device (device_add/driver_register)
>> | |
>> device_attach device_initial_probe
>> | |
>> __device_attach_driver __device_attach_driver
>> |
>> driver_probe_device
>> |
>> really_probe
>> |
>> dma_configure
>>
>> Similarly on the device/driver_unregister path __device_release_driver is
>> called which inturn calls dma_deconfigure.
>>
>> This patch changes the dma ops configuration to probe time for
>> both OF and ACPI based platform/amba/pci bus devices.
>
> Reviewed-by: Robin Murphy <robin.murphy@arm.com>
>
> It's possible we could subsume {of,acpi}_dma_deconfigure() into
> dma_deconfigure() entirely in future if it becomes clear that neither of
> them will ever need to do anything firmware-specific, but I think for
> now it's probably safer to keep the current symmetry - calling
> arch_teardown_dma_ops() twice is benign (and even if it weren't, I'd say
> it really should be!)
>
Ya, calling it twice should cause no harm. If nothing firmware specific
gets added this could simply be put in deconfigure itself in future.
Thanks for all the reviews !!
Regards,
Sricharan
> Robin.
>
>> Tested-by: Marek Szyprowski <m.szyprowski@samsung.com>
>> Tested-by: Hanjun Guo <hanjun.guo@linaro.org>
>> Acked-by: Bjorn Helgaas <bhelgaas@google.com> (drivers/pci part)
>> Acked-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
>> Signed-off-by: Sricharan R <sricharan@codeaurora.org>
>> ---
>>
>> [V10] Added dummy dma_(de)configure functions in case
>> of !CONFIG_HAS_DMA to avoid build breaks.
>>
>> drivers/acpi/glue.c | 5 -----
>> drivers/base/dd.c | 9 +++++++++
>> drivers/base/dma-mapping.c | 40 ++++++++++++++++++++++++++++++++++++++++
>> drivers/of/platform.c | 5 +----
>> drivers/pci/probe.c | 28 ----------------------------
>> include/linux/dma-mapping.h | 12 ++++++++++++
>> 6 files changed, 62 insertions(+), 37 deletions(-)
>>
>> diff --git a/drivers/acpi/glue.c b/drivers/acpi/glue.c
>> index fb19e1c..c05f241 100644
>> --- a/drivers/acpi/glue.c
>> +++ b/drivers/acpi/glue.c
>> @@ -176,7 +176,6 @@ int acpi_bind_one(struct device *dev, struct acpi_device *acpi_dev)
>> struct list_head *physnode_list;
>> unsigned int node_id;
>> int retval = -EINVAL;
>> - enum dev_dma_attr attr;
>>
>> if (has_acpi_companion(dev)) {
>> if (acpi_dev) {
>> @@ -233,10 +232,6 @@ int acpi_bind_one(struct device *dev, struct acpi_device *acpi_dev)
>> if (!has_acpi_companion(dev))
>> ACPI_COMPANION_SET(dev, acpi_dev);
>>
>> - attr = acpi_get_dma_attr(acpi_dev);
>> - if (attr != DEV_DMA_NOT_SUPPORTED)
>> - acpi_dma_configure(dev, attr);
>> -
>> acpi_physnode_link_name(physical_node_name, node_id);
>> retval = sysfs_create_link(&acpi_dev->dev.kobj, &dev->kobj,
>> physical_node_name);
>> diff --git a/drivers/base/dd.c b/drivers/base/dd.c
>> index a1fbf55..4882f06 100644
>> --- a/drivers/base/dd.c
>> +++ b/drivers/base/dd.c
>> @@ -19,6 +19,7 @@
>>
>> #include <linux/device.h>
>> #include <linux/delay.h>
>> +#include <linux/dma-mapping.h>
>> #include <linux/module.h>
>> #include <linux/kthread.h>
>> #include <linux/wait.h>
>> @@ -356,6 +357,10 @@ static int really_probe(struct device *dev, struct device_driver *drv)
>> if (ret)
>> goto pinctrl_bind_failed;
>>
>> + ret = dma_configure(dev);
>> + if (ret)
>> + goto dma_failed;
>> +
>> if (driver_sysfs_add(dev)) {
>> printk(KERN_ERR "%s: driver_sysfs_add(%s) failed\n",
>> __func__, dev_name(dev));
>> @@ -417,6 +422,8 @@ static int really_probe(struct device *dev, struct device_driver *drv)
>> goto done;
>>
>> probe_failed:
>> + dma_deconfigure(dev);
>> +dma_failed:
>> if (dev->bus)
>> blocking_notifier_call_chain(&dev->bus->p->bus_notifier,
>> BUS_NOTIFY_DRIVER_NOT_BOUND, dev);
>> @@ -826,6 +833,8 @@ static void __device_release_driver(struct device *dev, struct device *parent)
>> drv->remove(dev);
>>
>> device_links_driver_cleanup(dev);
>> + dma_deconfigure(dev);
>> +
>> devres_release_all(dev);
>> dev->driver = NULL;
>> dev_set_drvdata(dev, NULL);
>> diff --git a/drivers/base/dma-mapping.c b/drivers/base/dma-mapping.c
>> index efd71cf..449b948 100644
>> --- a/drivers/base/dma-mapping.c
>> +++ b/drivers/base/dma-mapping.c
>> @@ -7,9 +7,11 @@
>> * This file is released under the GPLv2.
>> */
>>
>> +#include <linux/acpi.h>
>> #include <linux/dma-mapping.h>
>> #include <linux/export.h>
>> #include <linux/gfp.h>
>> +#include <linux/of_device.h>
>> #include <linux/slab.h>
>> #include <linux/vmalloc.h>
>>
>> @@ -341,3 +343,41 @@ void dma_common_free_remap(void *cpu_addr, size_t size, unsigned long vm_flags)
>> vunmap(cpu_addr);
>> }
>> #endif
>> +
>> +/*
>> + * Common configuration to enable DMA API use for a device
>> + */
>> +#include <linux/pci.h>
>> +
>> +int dma_configure(struct device *dev)
>> +{
>> + struct device *bridge = NULL, *dma_dev = dev;
>> + enum dev_dma_attr attr;
>> +
>> + if (dev_is_pci(dev)) {
>> + bridge = pci_get_host_bridge_device(to_pci_dev(dev));
>> + dma_dev = bridge;
>> + if (IS_ENABLED(CONFIG_OF) && dma_dev->parent &&
>> + dma_dev->parent->of_node)
>> + dma_dev = dma_dev->parent;
>> + }
>> +
>> + if (dma_dev->of_node) {
>> + of_dma_configure(dev, dma_dev->of_node);
>> + } else if (has_acpi_companion(dma_dev)) {
>> + attr = acpi_get_dma_attr(to_acpi_device_node(dma_dev->fwnode));
>> + if (attr != DEV_DMA_NOT_SUPPORTED)
>> + acpi_dma_configure(dev, attr);
>> + }
>> +
>> + if (bridge)
>> + pci_put_host_bridge_device(bridge);
>> +
>> + return 0;
>> +}
>> +
>> +void dma_deconfigure(struct device *dev)
>> +{
>> + of_dma_deconfigure(dev);
>> + acpi_dma_deconfigure(dev);
>> +}
>> diff --git a/drivers/of/platform.c b/drivers/of/platform.c
>> index 5344db5..2aa4ebb 100644
>> --- a/drivers/of/platform.c
>> +++ b/drivers/of/platform.c
>> @@ -22,6 +22,7 @@
>> #include <linux/slab.h>
>> #include <linux/of_address.h>
>> #include <linux/of_device.h>
>> +#include <linux/of_iommu.h>
>> #include <linux/of_irq.h>
>> #include <linux/of_platform.h>
>> #include <linux/platform_device.h>
>> @@ -186,11 +187,9 @@ static struct platform_device *of_platform_device_create_pdata(
>>
>> dev->dev.bus = &platform_bus_type;
>> dev->dev.platform_data = platform_data;
>> - of_dma_configure(&dev->dev, dev->dev.of_node);
>> of_msi_configure(&dev->dev, dev->dev.of_node);
>>
>> if (of_device_add(dev) != 0) {
>> - of_dma_deconfigure(&dev->dev);
>> platform_device_put(dev);
>> goto err_clear_flag;
>> }
>> @@ -248,7 +247,6 @@ static struct amba_device *of_amba_device_create(struct device_node *node,
>> dev_set_name(&dev->dev, "%s", bus_id);
>> else
>> of_device_make_bus_id(&dev->dev);
>> - of_dma_configure(&dev->dev, dev->dev.of_node);
>>
>> /* Allow the HW Peripheral ID to be overridden */
>> prop = of_get_property(node, "arm,primecell-periphid", NULL);
>> @@ -542,7 +540,6 @@ static int of_platform_device_destroy(struct device *dev, void *data)
>> amba_device_unregister(to_amba_device(dev));
>> #endif
>>
>> - of_dma_deconfigure(dev);
>> of_node_clear_flag(dev->of_node, OF_POPULATED);
>> of_node_clear_flag(dev->of_node, OF_POPULATED_BUS);
>> return 0;
>> diff --git a/drivers/pci/probe.c b/drivers/pci/probe.c
>> index dfc9a27..5a8dd43 100644
>> --- a/drivers/pci/probe.c
>> +++ b/drivers/pci/probe.c
>> @@ -1893,33 +1893,6 @@ static void pci_set_msi_domain(struct pci_dev *dev)
>> dev_set_msi_domain(&dev->dev, d);
>> }
>>
>> -/**
>> - * pci_dma_configure - Setup DMA configuration
>> - * @dev: ptr to pci_dev struct of the PCI device
>> - *
>> - * Function to update PCI devices's DMA configuration using the same
>> - * info from the OF node or ACPI node of host bridge's parent (if any).
>> - */
>> -static void pci_dma_configure(struct pci_dev *dev)
>> -{
>> - struct device *bridge = pci_get_host_bridge_device(dev);
>> -
>> - if (IS_ENABLED(CONFIG_OF) &&
>> - bridge->parent && bridge->parent->of_node) {
>> - of_dma_configure(&dev->dev, bridge->parent->of_node);
>> - } else if (has_acpi_companion(bridge)) {
>> - struct acpi_device *adev = to_acpi_device_node(bridge->fwnode);
>> - enum dev_dma_attr attr = acpi_get_dma_attr(adev);
>> -
>> - if (attr == DEV_DMA_NOT_SUPPORTED)
>> - dev_warn(&dev->dev, "DMA not supported.\n");
>> - else
>> - acpi_dma_configure(&dev->dev, attr);
>> - }
>> -
>> - pci_put_host_bridge_device(bridge);
>> -}
>> -
>> void pci_device_add(struct pci_dev *dev, struct pci_bus *bus)
>> {
>> int ret;
>> @@ -1933,7 +1906,6 @@ void pci_device_add(struct pci_dev *dev, struct pci_bus *bus)
>> dev->dev.dma_mask = &dev->dma_mask;
>> dev->dev.dma_parms = &dev->dma_parms;
>> dev->dev.coherent_dma_mask = 0xffffffffull;
>> - pci_dma_configure(dev);
>>
>> pci_set_dma_max_seg_size(dev, 65536);
>> pci_set_dma_seg_boundary(dev, 0xffffffff);
>> diff --git a/include/linux/dma-mapping.h b/include/linux/dma-mapping.h
>> index 0977317..4f3eece 100644
>> --- a/include/linux/dma-mapping.h
>> +++ b/include/linux/dma-mapping.h
>> @@ -728,6 +728,18 @@ void *dma_mark_declared_memory_occupied(struct device *dev,
>> }
>> #endif /* CONFIG_HAVE_GENERIC_DMA_COHERENT */
>>
>> +#ifdef CONFIG_HAS_DMA
>> +int dma_configure(struct device *dev);
>> +void dma_deconfigure(struct device *dev);
>> +#else
>> +static inline int dma_configure(struct device *dev)
>> +{
>> + return 0;
>> +}
>> +
>> +static inline void dma_deconfigure(struct device *dev) {}
>> +#endif
>> +
>> /*
>> * Managed DMA API
>> */
>>
>
> --
> To unsubscribe from this list: send the line "unsubscribe linux-arm-msm" in
> the body of a message to majordomo@vger.kernel.org
> More majordomo info at http://vger.kernel.org/majordomo-info.html
>
--
"QUALCOMM INDIA, on behalf of Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum, hosted by The Linux Foundation
^ permalink raw reply
* [PATCH v3] clk: stm32h7: Add stm32h743 clock driver
From: gabriel.fernandez @ 2017-04-04 12:30 UTC (permalink / raw)
To: Rob Herring, Mark Rutland, Russell King, Maxime Coquelin,
Alexandre Torgue, Michael Turquette, Stephen Boyd, Nicolas Pitre,
Arnd Bergmann, daniel.thompson, andrea.merello, radoslaw.pietrzyk,
Lee Jones
Cc: devicetree, linux-arm-kernel, linux-kernel, linux-clk,
gabriel.fernandez, ludovic.barre, olivier.bideau, amelie.delaunay
From: Gabriel Fernandez <gabriel.fernandez@st.com>
This patch enables clocks for STM32H743 boards.
Signed-off-by: Gabriel Fernandez <gabriel.fernandez@st.com>
for MFD changes:
Acked-by: Lee Jones <lee.jones@linaro.org>
for DT-Bindings
Acked-by: Rob Herring <robh@kernel.org>
v3:
- fix compatible string "stm32h7-pll" into "st,stm32h7-pll"
- fix bad parent name for mco2 clock
- set CLK_SET_RATE_PARENT for ltdc clock
- set CLK_IGNORE_UNUSED for pll1
- disable power domain write protection on disable ops if needed
v2:
- rename compatible string "stm32,pll" into "stm32h7-pll"
- suppress "st,pllrge" property
- suppress "st, frac-status" property
- change management of "st,frac" property
0 : enable 0 pll integer mode
other values : enable pll in fractional mode (value is
the fractional factor)
---
.../devicetree/bindings/clock/st,stm32h7-rcc.txt | 151 ++
drivers/clk/Makefile | 1 +
drivers/clk/clk-stm32h7.c | 1675 ++++++++++++++++++++
include/dt-bindings/clock/stm32h7-clks.h | 165 ++
include/dt-bindings/mfd/stm32h7-rcc.h | 137 ++
5 files changed, 2129 insertions(+)
create mode 100644 Documentation/devicetree/bindings/clock/st,stm32h7-rcc.txt
create mode 100644 drivers/clk/clk-stm32h7.c
create mode 100644 include/dt-bindings/clock/stm32h7-clks.h
create mode 100644 include/dt-bindings/mfd/stm32h7-rcc.h
diff --git a/Documentation/devicetree/bindings/clock/st,stm32h7-rcc.txt b/Documentation/devicetree/bindings/clock/st,stm32h7-rcc.txt
new file mode 100644
index 0000000..d34ce5b7
--- /dev/null
+++ b/Documentation/devicetree/bindings/clock/st,stm32h7-rcc.txt
@@ -0,0 +1,151 @@
+STMicroelectronics STM32H7 Reset and Clock Controller
+=====================================================
+
+The RCC IP is both a reset and a clock controller.
+
+Please refer to clock-bindings.txt for common clock controller binding usage.
+Please also refer to reset.txt for common reset controller binding usage.
+
+Required properties:
+- compatible: Should be:
+ "st,stm32h743-rcc"
+
+- reg: should be register base and length as documented in the
+ datasheet
+
+- #reset-cells: 1, see below
+
+- #clock-cells : from common clock binding; shall be set to 1
+
+- clocks: External oscillator clock phandle
+ - high speed external clock signal (HSE)
+ - low speed external clock signal (LSE)
+ - external I2S clock (I2S_CKIN)
+
+- st,syscfg: phandle for pwrcfg, mandatory to disable/enable backup domain
+ write protection (RTC clock).
+
+- pll x node: Allow to register a pll with specific parameters.
+ Please see PLL section below.
+
+Example:
+
+ rcc: rcc@58024400 {
+ #reset-cells = <1>;
+ #clock-cells = <2>
+ compatible = "st,stm32h743-rcc", "st,stm32-rcc";
+ reg = <0x58024400 0x400>;
+ clocks = <&clk_hse>, <&clk_lse>, <&clk_i2s_ckin>;
+
+ st,syscfg = <&pwrcfg>;
+
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ vco1@0 {
+ #clock-cells = <0>;
+ compatible = "st,stm32h7-pll";
+ reg = <0>;
+ };
+
+ vco2@1 {
+ #clock-cells = <0>;
+ compatible = "st,stm32h7-pll";
+ reg = <1>;
+ st,clock-div = <2>;
+ st,clock-mult = <40>;
+ st,frac = <0>;
+ st,vcosel = <1>;
+ };
+ vco3@2 {
+ #clock-cells = <0>;
+ compatible = "st,stm32h7-pll";
+ reg = <2>;
+ st,clock-div = <2>;
+ st,clock-mult = <40>;
+ st,frac = <1024>;
+ st,vcosel = <1>;
+ };
+ };
+
+
+STM32H7 PLL
+-----------
+
+The VCO of STM32 PLL could be reprensented like this:
+
+ Vref --------- --------
+ ---->| / DIVM |---->| x DIVN | ------> VCO
+ --------- --------
+ ^
+ |
+ -------
+ | FRACN |
+ -------
+
+When the PLL is configured in integer mode:
+- VCO = ( Vref / DIVM ) * DIVN
+
+When the PLL is configured in fractional mode:
+- VCO = ( Vref / DIVM ) * ( DIVN + FRACN / 2^13)
+
+
+Required properties for pll node:
+- compatible: Should be:
+ "st,stm32h7-pll"
+
+- #clock-cells: from common clock binding; shall be set to 0
+- reg: Should be the pll number.
+
+Optional properties:
+- st,clock-div: DIVM division factor : <1..63>
+- st,clock-mult: DIVN multiplication factor : <4..512>
+
+- st,frac:
+ - 0 Pll is configured in integer mode
+ - <1..8191> Pll is configure in fractional mode and the value is
+ the part of the multiplication factor.
+
+- st,vcosel: VCO selection
+ - 0: Wide VCO range:192 to 836 MHz
+ - 1: Medium VCO range:150 to 420 MHz
+
+The peripheral clock consumer should specify the desired clock by
+having the clock ID in its "clocks" phandle cell.
+
+All available clocks are defined as preprocessor macros in
+dt-bindings/clock/stm32h7-clks.h header and can be used in device
+tree sources.
+
+Example:
+
+ timer5: timer@40000c00 {
+ compatible = "st,stm32-timer";
+ reg = <0x40000c00 0x400>;
+ interrupts = <50>;
+ clocks = <&rcc TIM5_CK>;
+
+ };
+
+Specifying softreset control of devices
+=======================================
+
+Device nodes should specify the reset channel required in their "resets"
+property, containing a phandle to the reset device node and an index specifying
+which channel to use.
+The index is the bit number within the RCC registers bank, starting from RCC
+base address.
+It is calculated as: index = register_offset / 4 * 32 + bit_offset.
+Where bit_offset is the bit offset within the register.
+
+For example, for CRC reset:
+ crc = AHB4RSTR_offset / 4 * 32 + CRCRST_bit_offset = 0x88 / 4 * 32 + 19 = 1107
+
+All available preprocessor macros for reset are defined dt-bindings//mfd/stm32h7-rcc.h
+header and can be used in device tree sources.
+
+example:
+
+ timer2 {
+ resets = <&rcc STM32H7_APB1L_RESET(TIM2)>;
+ };
diff --git a/drivers/clk/Makefile b/drivers/clk/Makefile
index 92c12b8..734aa02 100644
--- a/drivers/clk/Makefile
+++ b/drivers/clk/Makefile
@@ -42,6 +42,7 @@ obj-$(CONFIG_COMMON_CLK_SI5351) += clk-si5351.o
obj-$(CONFIG_COMMON_CLK_SI514) += clk-si514.o
obj-$(CONFIG_COMMON_CLK_SI570) += clk-si570.o
obj-$(CONFIG_ARCH_STM32) += clk-stm32f4.o
+obj-$(CONFIG_ARCH_STM32) += clk-stm32h7.o
obj-$(CONFIG_ARCH_TANGO) += clk-tango4.o
obj-$(CONFIG_CLK_TWL6040) += clk-twl6040.o
obj-$(CONFIG_ARCH_U300) += clk-u300.o
diff --git a/drivers/clk/clk-stm32h7.c b/drivers/clk/clk-stm32h7.c
new file mode 100644
index 0000000..cdcb27e
--- /dev/null
+++ b/drivers/clk/clk-stm32h7.c
@@ -0,0 +1,1675 @@
+/*
+ * Copyright (C) Gabriel Fernandez 2017
+ * Author: Gabriel Fernandez <gabriel.fernandez@st.com>
+ *
+ * License terms: GPL V2.0.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <linux/clk.h>
+#include <linux/clk-provider.h>
+#include <linux/err.h>
+#include <linux/io.h>
+#include <linux/mfd/syscon.h>
+#include <linux/of.h>
+#include <linux/of_address.h>
+#include <linux/slab.h>
+#include <linux/spinlock.h>
+#include <linux/regmap.h>
+
+#include <dt-bindings/clock/stm32h7-clks.h>
+
+/* Reset Clock Control Registers */
+#define RCC_CR 0x00
+#define RCC_CFGR 0x10
+#define RCC_D1CFGR 0x18
+#define RCC_D2CFGR 0x1C
+#define RCC_D3CFGR 0x20
+#define RCC_PLLCKSELR 0x28
+#define RCC_PLLCFGR 0x2C
+#define RCC_PLL1DIVR 0x30
+#define RCC_PLL1FRACR 0x34
+#define RCC_PLL2DIVR 0x38
+#define RCC_PLL2FRACR 0x3C
+#define RCC_PLL3DIVR 0x40
+#define RCC_PLL3FRACR 0x44
+#define RCC_D1CCIPR 0x4C
+#define RCC_D2CCIP1R 0x50
+#define RCC_D2CCIP2R 0x54
+#define RCC_D3CCIPR 0x58
+#define RCC_BDCR 0x70
+#define RCC_CSR 0x74
+#define RCC_AHB3ENR 0xD4
+#define RCC_AHB1ENR 0xD8
+#define RCC_AHB2ENR 0xDC
+#define RCC_AHB4ENR 0xE0
+#define RCC_APB3ENR 0xE4
+#define RCC_APB1LENR 0xE8
+#define RCC_APB1HENR 0xEC
+#define RCC_APB2ENR 0xF0
+#define RCC_APB4ENR 0xF4
+
+static DEFINE_SPINLOCK(rlock);
+
+static void __iomem *base;
+static struct regmap *pdrm;
+static struct clk_hw **hws;
+
+/* System clock parent */
+static const char * const sys_src[] = {
+ "hsi_ck", "csi_ck", "hse_ck", "pll1_p" };
+
+static const char * const tracein_src[] = {
+ "hsi_ck", "csi_ck", "hse_ck", "pll1_r" };
+
+static const char * const per_src[] = {
+ "hsi_ker", "csi_ker", "hse_ck", "disabled" };
+
+static const char * const pll_src[] = {
+ "hsi_ck", "csi_ck", "hse_ck", "no clock" };
+
+static const char * const sdmmc_src[] = { "pll1_q", "pll2_r" };
+
+static const char * const dsi_src[] = { "ck_dsi_phy", "pll2_q" };
+
+static const char * const qspi_src[] = {
+ "hclk", "pll1_q", "pll2_r", "per_ck" };
+
+static const char * const fmc_src[] = {
+ "hclk", "pll1_q", "pll2_r", "per_ck" };
+
+/* Kernel clock parent */
+static const char * const swp_src[] = { "pclk1", "hsi_ker" };
+
+static const char * const fdcan_src[] = { "hse_ck", "pll1_q", "pll2_q" };
+
+static const char * const dfsdm1_src[] = { "pclk2", "sys_ck" };
+
+static const char * const spdifrx_src[] = {
+ "pll1_q", "pll2_r", "pll3_r", "hsi_ker" };
+
+static const char *spi_src1[5] = {
+ "pll1_q", "pll2_p", "pll3_p", NULL, "per_ck" };
+
+static const char * const spi_src2[] = {
+ "pclk2", "pll2_q", "pll3_q", "hsi_ker", "csi_ker", "hse_ck" };
+
+static const char * const spi_src3[] = {
+ "pclk4", "pll2_q", "pll3_q", "hsi_ker", "csi_ker", "hse_ck" };
+
+static const char * const lptim_src1[] = {
+ "pclk1", "pll2_p", "pll3_r", "lse_ck", "lsi_ck", "per_ck" };
+
+static const char * const lptim_src2[] = {
+ "pclk4", "pll2_p", "pll3_r", "lse_ck", "lsi_ck", "per_ck" };
+
+static const char * const cec_src[] = {"lse_ck", "lsi_ck", "csi_ker_div122" };
+
+static const char * const usbotg_src[] = {"pll1_q", "pll3_q", "rc48_ck" };
+
+/* i2c 1,2,3 src */
+static const char * const i2c_src1[] = {
+ "pclk1", "pll3_r", "hsi_ker", "csi_ker" };
+
+static const char * const i2c_src2[] = {
+ "pclk4", "pll3_r", "hsi_ker", "csi_ker" };
+
+static const char * const rng_src[] = {
+ "rc48_ck", "pll1_q", "lse_ck", "lsi_ck" };
+
+/* usart 1,6 src */
+static const char * const usart_src1[] = {
+ "pclk2", "pll2_q", "pll3_q", "hsi_ker", "csi_ker", "lse_ck" };
+
+/* usart 2,3,4,5,7,8 src */
+static const char * const usart_src2[] = {
+ "pclk1", "pll2_q", "pll3_q", "hsi_ker", "csi_ker", "lse_ck" };
+
+static const char *sai_src[5] = {
+ "pll1_q", "pll2_p", "pll3_p", NULL, "per_ck" };
+
+static const char * const adc_src[] = { "pll2_p", "pll3_r", "per_ck" };
+
+/* lptim 2,3,4,5 src */
+static const char * const lpuart1_src[] = {
+ "pclk3", "pll2_q", "pll3_q", "csi_ker", "lse_ck" };
+
+static const char * const hrtim_src[] = { "tim2_ker", "d1cpre" };
+
+/* RTC clock parent */
+static const char * const rtc_src[] = { "off", "lse_ck", "lsi_ck", "hse_1M" };
+
+/* Micro-controller output clock parent */
+static const char * const mco_src1[] = {
+ "hsi_ck", "lse_ck", "hse_ck", "pll1_q", "rc48_ck" };
+
+static const char * const mco_src2[] = {
+ "sys_ck", "pll2_p", "hse_ck", "pll1_p", "csi_ck", "lsi_ck" };
+
+/* LCD clock */
+static const char * const ltdc_src[] = {"pll3_r"};
+
+/* Power domain helper */
+static inline void disable_power_domain_write_protection(void)
+{
+ if (pdrm)
+ regmap_update_bits(pdrm, 0x00, (1 << 8), (1 << 8));
+}
+
+static inline void enable_power_domain_write_protection(void)
+{
+ if (pdrm)
+ regmap_update_bits(pdrm, 0x00, (1 << 8), (0 << 8));
+}
+
+static inline int is_enable_power_domain_write_protection(void)
+{
+ if (pdrm) {
+ u32 val;
+
+ regmap_read(pdrm, 0x00, &val);
+
+ return !(val & 0x100);
+ }
+ return -1;
+}
+
+/* Gate clock with ready bit and backup domain management */
+struct stm32_ready_gate {
+ struct clk_gate gate;
+ u8 bit_rdy;
+ u8 backup_domain;
+};
+
+#define to_ready_gate_clk(_rgate) container_of(_rgate, struct stm32_ready_gate,\
+ gate)
+
+#define RGATE_TIMEOUT 600000
+
+static int ready_gate_clk_is_enabled(struct clk_hw *hw)
+{
+ return clk_gate_ops.is_enabled(hw);
+}
+
+static int ready_gate_clk_enable(struct clk_hw *hw)
+{
+ struct clk_gate *gate = to_clk_gate(hw);
+ struct stm32_ready_gate *rgate = to_ready_gate_clk(gate);
+ int dbp_status;
+ int bit_status;
+ unsigned int timeout = RGATE_TIMEOUT;
+
+ if (clk_gate_ops.is_enabled(hw))
+ return 0;
+
+ dbp_status = is_enable_power_domain_write_protection();
+
+ if (rgate->backup_domain && dbp_status)
+ disable_power_domain_write_protection();
+
+ clk_gate_ops.enable(hw);
+
+ do {
+ bit_status = !(readl(gate->reg) & BIT(rgate->bit_rdy));
+
+ if (bit_status)
+ udelay(1000);
+
+ } while (bit_status && --timeout);
+
+ if (rgate->backup_domain && dbp_status)
+ enable_power_domain_write_protection();
+
+ return bit_status;
+}
+
+static void ready_gate_clk_disable(struct clk_hw *hw)
+{
+ struct clk_gate *gate = to_clk_gate(hw);
+ struct stm32_ready_gate *rgate = to_ready_gate_clk(gate);
+ int dbp_status;
+ int bit_status;
+ unsigned int timeout = RGATE_TIMEOUT;
+
+ if (!ready_gate_clk_is_enabled(hw))
+ return;
+
+ dbp_status = is_enable_power_domain_write_protection();
+
+ if (rgate->backup_domain && dbp_status)
+ disable_power_domain_write_protection();
+
+ clk_gate_ops.disable(hw);
+
+ do {
+ bit_status = !!(readl(gate->reg) & BIT(rgate->bit_rdy));
+
+ if (bit_status)
+ udelay(1000);
+
+ } while (bit_status && --timeout);
+ if (rgate->backup_domain && dbp_status)
+ enable_power_domain_write_protection();
+}
+
+static const struct clk_ops ready_gate_clk_ops = {
+ .enable = ready_gate_clk_enable,
+ .disable = ready_gate_clk_disable,
+ .is_enabled = ready_gate_clk_is_enabled,
+};
+
+static struct clk_hw *clk_register_ready_gate(struct device *dev,
+ const char *name, const char *parent_name,
+ void __iomem *reg, u8 bit_idx, u8 bit_rdy,
+ u8 backup_domain, unsigned long flags, spinlock_t *lock)
+{
+ struct stm32_ready_gate *rgate;
+ struct clk_init_data init = { NULL };
+ struct clk_hw *hw;
+ int ret;
+
+ rgate = kzalloc(sizeof(*rgate), GFP_KERNEL);
+ if (!rgate)
+ return ERR_PTR(-ENOMEM);
+
+ init.name = name;
+ init.ops = &ready_gate_clk_ops;
+ init.flags = flags;
+ init.parent_names = &parent_name;
+ init.num_parents = 1;
+
+ rgate->bit_rdy = bit_rdy;
+ rgate->backup_domain = backup_domain;
+
+ rgate->gate.lock = lock;
+ rgate->gate.reg = reg;
+ rgate->gate.bit_idx = bit_idx;
+ rgate->gate.hw.init = &init;
+
+ hw = &rgate->gate.hw;
+ ret = clk_hw_register(dev, hw);
+ if (ret) {
+ kfree(rgate);
+ hw = ERR_PTR(ret);
+ }
+
+ return hw;
+}
+
+struct gate_cfg {
+ u32 offset;
+ u8 bit_idx;
+};
+
+struct muxdiv_cfg {
+ u32 offset;
+ u8 shift;
+ u8 width;
+};
+
+struct composite_clk_cfg {
+ struct gate_cfg *gate;
+ struct muxdiv_cfg *mux;
+ struct muxdiv_cfg *div;
+ const char *name;
+ const char * const *parent_name;
+ int num_parents;
+ u32 flags;
+};
+
+struct composite_clk_gcfg_t {
+ u8 flags;
+ const struct clk_ops *ops;
+};
+
+/*
+ * General config definition of a composite clock (only clock diviser for rate)
+ */
+struct composite_clk_gcfg {
+ struct composite_clk_gcfg_t *mux;
+ struct composite_clk_gcfg_t *div;
+ struct composite_clk_gcfg_t *gate;
+};
+
+#define M_CFG_MUX(_mux_ops, _mux_flags)\
+ .mux = &(struct composite_clk_gcfg_t) { _mux_flags, _mux_ops}
+
+#define M_CFG_DIV(_rate_ops, _rate_flags)\
+ .div = &(struct composite_clk_gcfg_t) {_rate_flags, _rate_ops}
+
+#define M_CFG_GATE(_gate_ops, _gate_flags)\
+ .gate = &(struct composite_clk_gcfg_t) { _gate_flags, _gate_ops}
+
+static struct clk_mux *_get_cmux(void __iomem *reg, u8 shift, u8 width,
+ u32 flags, spinlock_t *lock)
+{
+ struct clk_mux *mux;
+
+ mux = kzalloc(sizeof(*mux), GFP_KERNEL);
+ if (!mux)
+ return ERR_PTR(-ENOMEM);
+
+ mux->reg = reg;
+ mux->shift = shift;
+ mux->mask = (1 << width) - 1;
+ mux->flags = flags;
+ mux->lock = lock;
+
+ return mux;
+}
+
+static struct clk_divider *_get_cdiv(void __iomem *reg, u8 shift, u8 width,
+ u32 flags, spinlock_t *lock)
+{
+ struct clk_divider *div;
+
+ div = kzalloc(sizeof(*div), GFP_KERNEL);
+
+ if (!div)
+ return ERR_PTR(-ENOMEM);
+
+ div->reg = reg;
+ div->shift = shift;
+ div->width = width;
+ div->flags = flags;
+ div->lock = lock;
+
+ return div;
+}
+
+static struct clk_gate *_get_cgate(void __iomem *reg, u8 bit_idx, u32 flags,
+ spinlock_t *lock)
+{
+ struct clk_gate *gate;
+
+ gate = kzalloc(sizeof(*gate), GFP_KERNEL);
+ if (!gate)
+ return ERR_PTR(-ENOMEM);
+
+ gate->reg = reg;
+ gate->bit_idx = bit_idx;
+ gate->flags = flags;
+ gate->lock = lock;
+
+ return gate;
+}
+
+struct composite_cfg {
+ struct clk_hw *mux_hw;
+ struct clk_hw *div_hw;
+ struct clk_hw *gate_hw;
+
+ const struct clk_ops *mux_ops;
+ const struct clk_ops *div_ops;
+ const struct clk_ops *gate_ops;
+};
+
+static void get_cfg_composite_div(const struct composite_clk_gcfg *gcfg,
+ const struct composite_clk_cfg *cfg,
+ struct composite_cfg *composite, spinlock_t *lock)
+{
+ struct clk_mux *mux = NULL;
+ struct clk_divider *div = NULL;
+ struct clk_gate *gate = NULL;
+ const struct clk_ops *mux_ops, *div_ops, *gate_ops;
+ struct clk_hw *mux_hw;
+ struct clk_hw *div_hw;
+ struct clk_hw *gate_hw;
+
+ mux_ops = div_ops = gate_ops = NULL;
+ mux_hw = div_hw = gate_hw = NULL;
+
+ if (gcfg->mux) {
+ mux = _get_cmux(base + cfg->mux->offset,
+ cfg->mux->shift,
+ cfg->mux->width,
+ gcfg->mux->flags, lock);
+
+ if (!IS_ERR(mux)) {
+ mux_hw = &mux->hw;
+ mux_ops = gcfg->mux->ops ?
+ gcfg->mux->ops : &clk_mux_ops;
+ }
+ }
+
+ if (gcfg->div) {
+ div = _get_cdiv(base + cfg->div->offset,
+ cfg->div->shift,
+ cfg->div->width,
+ gcfg->div->flags, lock);
+
+ if (!IS_ERR(div)) {
+ div_hw = &div->hw;
+ div_ops = gcfg->div->ops ?
+ gcfg->div->ops : &clk_divider_ops;
+ }
+
+ }
+
+ if (gcfg->gate) {
+ gate = _get_cgate(base + cfg->gate->offset,
+ cfg->gate->bit_idx,
+ gcfg->gate->flags, lock);
+
+ if (!IS_ERR(gate)) {
+ gate_hw = &gate->hw;
+ gate_ops = gcfg->gate->ops ?
+ gcfg->gate->ops : &clk_gate_ops;
+ }
+
+ }
+
+ composite->mux_hw = mux_hw;
+ composite->mux_ops = mux_ops;
+
+ composite->div_hw = div_hw;
+ composite->div_ops = div_ops;
+
+ composite->gate_hw = gate_hw;
+ composite->gate_ops = gate_ops;
+}
+
+/* Kernel Timer */
+struct timer_ker {
+ u8 dppre_shift;
+ struct clk_hw hw;
+ spinlock_t *lock;
+};
+
+#define to_timer_ker(_hw) container_of(_hw, struct timer_ker, hw)
+
+static unsigned long timer_ker_recalc_rate(struct clk_hw *hw,
+ unsigned long parent_rate)
+{
+ struct timer_ker *clk_elem = to_timer_ker(hw);
+ u32 timpre;
+ u32 dppre_shift = clk_elem->dppre_shift;
+ u32 prescaler;
+ u32 mul;
+
+ timpre = (readl(base + RCC_CFGR) >> 15) & 0x01;
+
+ prescaler = (readl(base + RCC_D2CFGR) >> dppre_shift) & 0x03;
+
+ mul = 2;
+
+ if (prescaler < 4)
+ mul = 1;
+
+ else if (timpre && prescaler > 4)
+ mul = 4;
+
+ return parent_rate * mul;
+}
+
+static const struct clk_ops timer_ker_ops = {
+ .recalc_rate = timer_ker_recalc_rate,
+};
+
+static struct clk_hw *clk_register_stm32_timer_ker(struct device *dev,
+ const char *name, const char *parent_name,
+ unsigned long flags,
+ u8 dppre_shift,
+ spinlock_t lock)
+{
+ struct timer_ker *element;
+ struct clk_init_data init;
+ struct clk_hw *hw;
+ int err;
+
+ element = kzalloc(sizeof(*element), GFP_KERNEL);
+ if (!element)
+ return ERR_PTR(-ENOMEM);
+
+ init.name = name;
+ init.ops = &timer_ker_ops;
+ init.flags = flags;
+ init.parent_names = &parent_name;
+ init.num_parents = 1;
+
+ element->hw.init = &init;
+ element->lock = &lock;
+ element->dppre_shift = dppre_shift;
+
+ hw = &element->hw;
+ err = clk_hw_register(dev, hw);
+
+ if (err) {
+ kfree(element);
+ return ERR_PTR(err);
+ }
+
+ return hw;
+}
+
+static const struct clk_div_table d1cpre_div_table[] = {
+ { 0, 1 }, { 1, 1 }, { 2, 1 }, { 3, 1},
+ { 4, 1 }, { 5, 1 }, { 6, 1 }, { 7, 1},
+ { 8, 2 }, { 9, 4 }, { 10, 8 }, { 11, 16 },
+ { 12, 64 }, { 13, 128 }, { 14, 256 },
+ { 15, 512 },
+ { 0 },
+};
+
+static const struct clk_div_table ppre_div_table[] = {
+ { 0, 1 }, { 1, 1 }, { 2, 1 }, { 3, 1},
+ { 4, 2 }, { 5, 4 }, { 6, 8 }, { 7, 16 },
+ { 0 },
+};
+
+static void register_core_and_bus_clocks(void)
+{
+ /* CORE AND BUS */
+ hws[SYS_D1CPRE] = clk_hw_register_divider_table(NULL, "d1cpre",
+ "sys_ck", CLK_IGNORE_UNUSED, base + RCC_D1CFGR, 8, 4, 0,
+ d1cpre_div_table, &rlock);
+
+ hws[HCLK] = clk_hw_register_divider_table(NULL, "hclk", "d1cpre",
+ CLK_IGNORE_UNUSED, base + RCC_D1CFGR, 0, 4, 0,
+ d1cpre_div_table, &rlock);
+
+ /* D1 DOMAIN */
+ /* * CPU Systick */
+ hws[CPU_SYSTICK] = clk_hw_register_fixed_factor(NULL, "systick",
+ "d1cpre", 0, 1, 8);
+
+ /* * APB3 peripheral */
+ hws[PCLK3] = clk_hw_register_divider_table(NULL, "pclk3", "hclk", 0,
+ base + RCC_D1CFGR, 4, 3, 0,
+ ppre_div_table, &rlock);
+
+ /* D2 DOMAIN */
+ /* * APB1 peripheral */
+ hws[PCLK1] = clk_hw_register_divider_table(NULL, "pclk1", "hclk", 0,
+ base + RCC_D2CFGR, 4, 3, 0,
+ ppre_div_table, &rlock);
+
+ /* Timers prescaler clocks */
+ clk_register_stm32_timer_ker(NULL, "tim1_ker", "pclk1", 0,
+ 4, rlock);
+
+ /* * APB2 peripheral */
+ hws[PCLK2] = clk_hw_register_divider_table(NULL, "pclk2", "hclk", 0,
+ base + RCC_D2CFGR, 8, 3, 0, ppre_div_table, &rlock);
+
+ clk_register_stm32_timer_ker(NULL, "tim2_ker", "pclk2", 0, 8, rlock);
+
+ /* D3 DOMAIN */
+ /* * APB4 peripheral */
+ hws[PCLK4] = clk_hw_register_divider_table(NULL, "pclk4", "hclk", 0,
+ base + RCC_D3CFGR, 4, 3, 0,
+ ppre_div_table, &rlock);
+}
+
+/* MUX clock configuration */
+struct stm32_mux_clk {
+ const char *name;
+ const char * const *parents;
+ u8 num_parents;
+ u32 offset;
+ u8 shift;
+ u8 width;
+ u32 flags;
+};
+
+#define M_MCLOCF(_name, _parents, _mux_offset, _mux_shift, _mux_width, _flags)\
+{\
+ .name = _name,\
+ .parents = _parents,\
+ .num_parents = ARRAY_SIZE(_parents),\
+ .offset = _mux_offset,\
+ .shift = _mux_shift,\
+ .width = _mux_width,\
+ .flags = _flags,\
+}
+#define M_MCLOC(_name, _parents, _mux_offset, _mux_shift, _mux_width)\
+ M_MCLOCF(_name, _parents, _mux_offset, _mux_shift, _mux_width, 0)\
+
+static const struct stm32_mux_clk stm32_mclk[] __initconst = {
+ M_MCLOC("per_ck", per_src, RCC_D1CCIPR, 28, 3),
+ M_MCLOC("pllsrc", pll_src, RCC_PLLCKSELR, 0, 3),
+ M_MCLOC("sys_ck", sys_src, RCC_CFGR, 0, 3),
+ M_MCLOC("tracein_ck", tracein_src, RCC_CFGR, 0, 3),
+};
+
+/* Oscillary clock configuration */
+struct stm32_osc_clk {
+ const char *name;
+ const char *parent;
+ u32 gate_offset;
+ u8 bit_idx;
+ u8 bit_rdy;
+ u32 flags;
+};
+
+#define OSC_CLKF(_name, _parent, _gate_offset, _bit_idx, _bit_rdy, _flags)\
+{\
+ .name = _name,\
+ .parent = _parent,\
+ .gate_offset = _gate_offset,\
+ .bit_idx = _bit_idx,\
+ .bit_rdy = _bit_rdy,\
+ .flags = _flags,\
+}
+#define OSC_CLK(_name, _parent, _gate_offset, _bit_idx, _bit_rdy)\
+ OSC_CLKF(_name, _parent, _gate_offset, _bit_idx, _bit_rdy, 0)
+
+static const struct stm32_osc_clk stm32_oclk[] __initconst = {
+ OSC_CLKF("hsi_ck", "hsidiv", RCC_CR, 0, 2, CLK_IGNORE_UNUSED),
+ OSC_CLKF("hsi_ker", "hsidiv", RCC_CR, 1, 2, CLK_IGNORE_UNUSED),
+ OSC_CLKF("csi_ck", "clk-csi", RCC_CR, 7, 8, CLK_IGNORE_UNUSED),
+ OSC_CLKF("csi_ker", "clk-csi", RCC_CR, 9, 8, CLK_IGNORE_UNUSED),
+ OSC_CLKF("rc48_ck", "clk-rc48", RCC_CR, 12, 13, CLK_IGNORE_UNUSED),
+ OSC_CLKF("lsi_ck", "clk-lsi", RCC_CSR, 0, 1, CLK_IGNORE_UNUSED),
+};
+
+/* PLL configuration */
+struct st32h7_pll_cfg {
+ u8 bit_idx;
+ u32 offset_divr;
+ u8 bit_frac_en;
+ u32 offset_frac;
+ u8 divm;
+};
+
+struct stm32_pll_data {
+ const char *name;
+ const char *parent_name;
+ unsigned long flags;
+ const struct st32h7_pll_cfg *cfg;
+};
+
+static const struct st32h7_pll_cfg stm32h7_pll1 = {
+ .bit_idx = 24,
+ .offset_divr = RCC_PLL1DIVR,
+ .bit_frac_en = 0,
+ .offset_frac = RCC_PLL1FRACR,
+ .divm = 4,
+};
+
+static const struct st32h7_pll_cfg stm32h7_pll2 = {
+ .bit_idx = 26,
+ .offset_divr = RCC_PLL2DIVR,
+ .bit_frac_en = 4,
+ .offset_frac = RCC_PLL2FRACR,
+ .divm = 12,
+};
+
+static const struct st32h7_pll_cfg stm32h7_pll3 = {
+ .bit_idx = 28,
+ .offset_divr = RCC_PLL3DIVR,
+ .bit_frac_en = 8,
+ .offset_frac = RCC_PLL3FRACR,
+ .divm = 20,
+};
+
+static const struct stm32_pll_data stm32_pll[] = {
+ { "vco1", "pllsrc", CLK_IGNORE_UNUSED, &stm32h7_pll1 },
+ { "vco2", "pllsrc", 0, &stm32h7_pll2 },
+ { "vco3", "pllsrc", 0, &stm32h7_pll3 },
+};
+
+struct stm32_fractional_divider {
+ void __iomem *mreg;
+ u8 mshift;
+ u8 mwidth;
+ u32 mmask;
+
+ void __iomem *nreg;
+ u8 nshift;
+ u8 nwidth;
+
+ void __iomem *freg_status;
+ u8 freg_bit;
+ void __iomem *freg_value;
+ u8 fshift;
+ u8 fwidth;
+
+ u8 flags;
+ struct clk_hw hw;
+ spinlock_t *lock;
+};
+
+struct stm32_pll_obj {
+ spinlock_t *lock;
+ struct stm32_fractional_divider div;
+ struct stm32_ready_gate rgate;
+ struct clk_hw hw;
+};
+
+#define to_pll(_hw) container_of(_hw, struct stm32_pll_obj, hw)
+
+static int pll_is_enabled(struct clk_hw *hw)
+{
+ struct stm32_pll_obj *clk_elem = to_pll(hw);
+ struct clk_hw *_hw = &clk_elem->rgate.gate.hw;
+
+ __clk_hw_set_clk(_hw, hw);
+
+ return ready_gate_clk_ops.is_enabled(_hw);
+}
+
+static int pll_enable(struct clk_hw *hw)
+{
+ struct stm32_pll_obj *clk_elem = to_pll(hw);
+ struct clk_hw *_hw = &clk_elem->rgate.gate.hw;
+
+ __clk_hw_set_clk(_hw, hw);
+
+ return ready_gate_clk_ops.enable(_hw);
+}
+
+static void pll_disable(struct clk_hw *hw)
+{
+ struct stm32_pll_obj *clk_elem = to_pll(hw);
+ struct clk_hw *_hw = &clk_elem->rgate.gate.hw;
+
+ __clk_hw_set_clk(_hw, hw);
+
+ ready_gate_clk_ops.disable(_hw);
+}
+
+static int pll_frac_is_enabled(struct clk_hw *hw)
+{
+ struct stm32_pll_obj *clk_elem = to_pll(hw);
+ struct stm32_fractional_divider *fd = &clk_elem->div;
+
+ return (readl(fd->freg_status) >> fd->freg_bit) & 0x01;
+}
+
+static unsigned long pll_read_frac(struct clk_hw *hw)
+{
+ struct stm32_pll_obj *clk_elem = to_pll(hw);
+ struct stm32_fractional_divider *fd = &clk_elem->div;
+
+ return (readl(fd->freg_value) >> fd->fshift) &
+ GENMASK(fd->fwidth - 1, 0);
+}
+
+static unsigned long pll_fd_recalc_rate(struct clk_hw *hw,
+ unsigned long parent_rate)
+{
+ struct stm32_pll_obj *clk_elem = to_pll(hw);
+ struct stm32_fractional_divider *fd = &clk_elem->div;
+ unsigned long m, n;
+ u32 val, mask;
+ u64 rate, rate1 = 0;
+
+ val = clk_readl(fd->mreg);
+ mask = (GENMASK(fd->mwidth - 1, 0) << fd->mshift);
+ m = (val & mask) >> fd->mshift;
+
+ val = clk_readl(fd->nreg);
+ mask = (GENMASK(fd->nwidth - 1, 0) << fd->nshift);
+ n = ((val & mask) >> fd->nshift) + 1;
+
+ if (!n || !m)
+ return parent_rate;
+
+ rate = (u64)parent_rate * n;
+ do_div(rate, m);
+
+ if (pll_frac_is_enabled(hw)) {
+ val = pll_read_frac(hw);
+ rate1 = (u64) parent_rate * (u64) val;
+ do_div(rate1, (m * 8191));
+ }
+
+ return rate + rate1;
+}
+
+static const struct clk_ops pll_ops = {
+ .enable = pll_enable,
+ .disable = pll_disable,
+ .is_enabled = pll_is_enabled,
+ .recalc_rate = pll_fd_recalc_rate,
+};
+
+static struct clk_hw *clk_register_stm32_pll(struct device *dev,
+ const char *name,
+ const char *parent,
+ unsigned long flags,
+ const struct st32h7_pll_cfg *cfg,
+ spinlock_t *lock)
+{
+
+ struct stm32_pll_obj *pll;
+ struct clk_init_data init = { NULL };
+ struct clk_hw *hw;
+ int ret;
+ struct stm32_fractional_divider *div = NULL;
+ struct stm32_ready_gate *rgate;
+
+ pll = kzalloc(sizeof(*pll), GFP_KERNEL);
+ if (!pll)
+ return ERR_PTR(-ENOMEM);
+
+ init.name = name;
+ init.ops = &pll_ops;
+ init.flags = flags;
+ init.parent_names = &parent;
+ init.num_parents = 1;
+ pll->hw.init = &init;
+
+ hw = &pll->hw;
+ rgate = &pll->rgate;
+
+ rgate->bit_rdy = cfg->bit_idx + 1;
+ rgate->gate.lock = lock;
+ rgate->gate.reg = base + RCC_CR;
+ rgate->gate.bit_idx = cfg->bit_idx;
+
+ div = &pll->div;
+ div->flags = 0;
+ div->mreg = base + RCC_PLLCKSELR;
+ div->mshift = cfg->divm;
+ div->mwidth = 6;
+ div->nreg = base + cfg->offset_divr;
+ div->nshift = 0;
+ div->nwidth = 9;
+
+ div->freg_status = base + RCC_PLLCFGR;
+ div->freg_bit = cfg->bit_frac_en;
+ div->freg_value = base + cfg->offset_frac;
+ div->fshift = 3;
+ div->fwidth = 13;
+
+ div->lock = lock;
+
+ ret = clk_hw_register(dev, hw);
+ if (ret) {
+ kfree(pll);
+ hw = ERR_PTR(ret);
+ }
+
+ return hw;
+}
+
+/* ODF CLOCKS */
+static unsigned long odf_divider_recalc_rate(struct clk_hw *hw,
+ unsigned long parent_rate)
+{
+ return clk_divider_ops.recalc_rate(hw, parent_rate);
+}
+
+static long odf_divider_round_rate(struct clk_hw *hw, unsigned long rate,
+ unsigned long *prate)
+{
+ return clk_divider_ops.round_rate(hw, rate, prate);
+}
+
+static int odf_divider_set_rate(struct clk_hw *hw, unsigned long rate,
+ unsigned long parent_rate)
+{
+ struct clk_hw *hwp;
+ int pll_status;
+ int ret;
+
+ hwp = clk_hw_get_parent(hw);
+
+ pll_status = pll_is_enabled(hwp);
+
+ if (pll_status)
+ pll_disable(hwp);
+
+ ret = clk_divider_ops.set_rate(hw, rate, parent_rate);
+
+ if (pll_status)
+ pll_enable(hwp);
+
+ return ret;
+}
+
+static const struct clk_ops odf_divider_ops = {
+ .recalc_rate = odf_divider_recalc_rate,
+ .round_rate = odf_divider_round_rate,
+ .set_rate = odf_divider_set_rate,
+};
+
+
+static int odf_gate_is_enabled(struct clk_hw *hw)
+{
+ return clk_gate_ops.is_enabled(hw);
+}
+
+static int odf_gate_enable(struct clk_hw *hw)
+{
+ struct clk_hw *hwp;
+ int pll_status;
+ int ret;
+
+ if (odf_gate_is_enabled(hw))
+ return 0;
+
+ hwp = clk_hw_get_parent(hw);
+
+ pll_status = pll_is_enabled(hwp);
+
+ if (pll_status)
+ pll_disable(hwp);
+
+ ret = clk_gate_ops.enable(hw);
+
+ if (pll_status)
+ pll_enable(hwp);
+
+ return ret;
+}
+
+static void odf_gate_disable(struct clk_hw *hw)
+{
+ struct clk_hw *hwp;
+ int pll_status;
+
+ if (!odf_gate_is_enabled(hw))
+ return;
+
+ clk_gate_ops.disable(hw);
+
+ hwp = clk_hw_get_parent(hw);
+
+ pll_status = pll_is_enabled(hwp);
+
+ if (pll_status)
+ pll_disable(hwp);
+
+ clk_gate_ops.disable(hw);
+
+ if (pll_status)
+ pll_enable(hwp);
+}
+
+static const struct clk_ops odf_gate_ops = {
+ .enable = odf_gate_enable,
+ .disable = odf_gate_disable,
+ .is_enabled = odf_gate_is_enabled,
+};
+
+static struct composite_clk_gcfg odf_clk_gcfg = {
+ M_CFG_DIV(&odf_divider_ops, 0),
+ M_CFG_GATE(&odf_gate_ops, 0),
+};
+
+#define M_ODF_F(_name, _parent, _gate_offset, _bit_idx, _rate_offset,\
+ _rate_shift, _rate_width, _flags)\
+{\
+ .mux = NULL,\
+ .div = &(struct muxdiv_cfg) {_rate_offset, _rate_shift, _rate_width},\
+ .gate = &(struct gate_cfg) {_gate_offset, _bit_idx },\
+ .name = _name,\
+ .parent_name = &(const char *) {_parent},\
+ .num_parents = 1,\
+ .flags = _flags,\
+}
+
+#define M_ODF(_name, _parent, _gate_offset, _bit_idx, _rate_offset,\
+ _rate_shift, _rate_width)\
+M_ODF_F(_name, _parent, _gate_offset, _bit_idx, _rate_offset,\
+ _rate_shift, _rate_width, 0)\
+
+static const struct composite_clk_cfg stm32_odf[3][3] = {
+ {
+ M_ODF_F("pll1_p", "vco1", RCC_PLLCFGR, 16, RCC_PLL1DIVR, 9, 7,
+ CLK_IGNORE_UNUSED),
+ M_ODF_F("pll1_q", "vco1", RCC_PLLCFGR, 17, RCC_PLL1DIVR, 16, 7,
+ CLK_IGNORE_UNUSED),
+ M_ODF_F("pll1_r", "vco1", RCC_PLLCFGR, 18, RCC_PLL1DIVR, 24, 7,
+ CLK_IGNORE_UNUSED),
+ },
+
+ {
+ M_ODF("pll2_p", "vco2", RCC_PLLCFGR, 19, RCC_PLL2DIVR, 9, 7),
+ M_ODF("pll2_q", "vco2", RCC_PLLCFGR, 20, RCC_PLL2DIVR, 16, 7),
+ M_ODF("pll2_r", "vco2", RCC_PLLCFGR, 21, RCC_PLL2DIVR, 24, 7),
+ },
+ {
+ M_ODF("pll3_p", "vco3", RCC_PLLCFGR, 22, RCC_PLL3DIVR, 9, 7),
+ M_ODF("pll3_q", "vco3", RCC_PLLCFGR, 23, RCC_PLL3DIVR, 16, 7),
+ M_ODF("pll3_r", "vco3", RCC_PLLCFGR, 24, RCC_PLL3DIVR, 24, 7),
+ }
+};
+
+/* PLL config structure from DT */
+struct pll_param {
+ u32 index;
+ u32 mult;
+ u32 div;
+ u32 frac;
+ u32 vcosel;
+};
+
+static int of_get_stm32_pll(struct device_node *np, struct pll_param *param)
+{
+ if (of_property_read_u32(np, "reg", ¶m->index) ||
+ param->index >= ARRAY_SIZE(stm32_pll))
+ return -EINVAL;
+
+ of_property_read_u32(np, "st,clock-div", ¶m->div);
+
+ of_property_read_u32(np, "st,clock-mult", ¶m->mult);
+
+ param->frac = ~0;
+ of_property_read_u32(np, "st,frac", ¶m->frac);
+
+ param->vcosel = ~0;
+ of_property_read_u32(np, "st,vcosel", ¶m->vcosel);
+
+ return 0;
+}
+
+
+static void stm32_pll_save_param(struct pll_param *pll_dt_cfg,
+ const struct st32h7_pll_cfg *cfg)
+{
+ unsigned long m, n;
+ u32 val, mask;
+ int idx = pll_dt_cfg->index;
+ int pll_status, pllrge;
+ unsigned long ref_ck;
+
+
+ /* Save PLL parameters from DT if needed */
+ m = pll_dt_cfg->div;
+ n = pll_dt_cfg->mult;
+ if (!(n || m || pll_dt_cfg->frac != ~0 ||
+ pll_dt_cfg->vcosel != ~0))
+ return;
+
+ /* We have to disable pll before modify pll register */
+ val = clk_readl(base + RCC_CR);
+ pll_status = val & BIT(cfg->bit_idx);
+ if (pll_status) {
+ val &= ~BIT(cfg->bit_idx);
+ writel(val, base + RCC_CR);
+ }
+
+ /* Save DIVM division factor */
+ val = clk_readl(base + RCC_PLLCKSELR);
+ mask = 0x3f << cfg->divm;
+ if (m) {
+ val &= ~mask;
+ val |= (m << cfg->divm);
+ writel(val, base + RCC_PLLCKSELR);
+ } else
+ m = (val & mask) >> cfg->divm ?: 1;
+
+ /* Save DIVN multiplication factor */
+ if (n) {
+ val = clk_readl(base + cfg->offset_divr);
+ val &= ~0x1ff;
+ val |= (n - 1);
+ writel(val, base + cfg->offset_divr);
+ }
+
+ /* If there is a "st,frac" property */
+ if (pll_dt_cfg->frac != ~0) {
+ u32 val_status;
+ int status = 0;
+
+ /* 0: pll is configured in integer mode */
+ /* else is configured in fractional mode */
+ if (pll_dt_cfg->frac)
+ status = 1;
+
+ /* clear frac status before */
+ val_status = readl(base + RCC_PLLCFGR);
+ val_status &= ~BIT(cfg->bit_frac_en);
+ writel(val_status, base + RCC_PLLCFGR);
+
+ /* Save the fractional factor */
+ if (status) {
+ /* write frac value */
+ val = clk_readl(base + cfg->offset_frac);
+ val &= ~(0x1fff << 3);
+ val |= ((pll_dt_cfg->frac) << 3);
+ writel(val, base + cfg->offset_frac);
+
+ /* Enable fractional mode */
+ val_status |= status << cfg->bit_frac_en;
+ writel(val_status, base + RCC_PLLCFGR);
+ }
+ }
+
+ /* Save VCO frequency range */
+ if (pll_dt_cfg->vcosel != ~0) {
+ val = readl(base + RCC_PLLCFGR);
+ val &= ~BIT(cfg->bit_frac_en + 1);
+ val |= (pll_dt_cfg->vcosel & 0x01) << (cfg->bit_frac_en + 1);
+ writel(val, base + RCC_PLLCFGR);
+ }
+
+ /* Update PLLRGE */
+ ref_ck = clk_get_rate(__clk_lookup(stm32_pll[idx].parent_name)) / m;
+
+ pllrge = 3;
+ if (ref_ck < 2000000)
+ pllrge = 0;
+ else if (ref_ck < 4000000)
+ pllrge = 1;
+ else if (ref_ck < 8000000)
+ pllrge = 2;
+
+ /* Write reference frequency range */
+ val = readl(base + RCC_PLLCFGR);
+ val &= ~(0x3 << (cfg->bit_frac_en + 2));
+ val |= (pllrge & 0x3) << (cfg->bit_frac_en + 2);
+ writel(val, base + RCC_PLLCFGR);
+
+ /* Restore pll status */
+ if (pll_status) {
+ val = clk_readl(base + RCC_CR);
+ val |= BIT(cfg->bit_idx);
+ writel(val, base + RCC_CR);
+ }
+}
+
+static void stm32_h7_pll_init(struct device_node *np)
+{
+ struct pll_param pll_dt_cfg = { };
+ struct clk_hw *hw;
+ int idx, n;
+
+ if (of_get_stm32_pll(np, &pll_dt_cfg))
+ return;
+
+ idx = pll_dt_cfg.index;
+
+ stm32_pll_save_param(&pll_dt_cfg, stm32_pll[idx].cfg);
+
+ /* Register the VCO */
+ hw = clk_register_stm32_pll(NULL, stm32_pll[idx].name,
+ stm32_pll[idx].parent_name, stm32_pll[idx].flags,
+ stm32_pll[idx].cfg,
+ &rlock);
+
+ /* Register the 3 output dividers */
+ for (n = 0; n < 3; n++) {
+ struct composite_cfg c_cfg;
+
+ get_cfg_composite_div(&odf_clk_gcfg, &stm32_odf[idx][n],
+ &c_cfg, &rlock);
+
+ hws[ODF_BANK + (idx * 3) + n] = clk_hw_register_composite(NULL,
+ stm32_odf[idx][n].name,
+ stm32_odf[idx][n].parent_name,
+ stm32_odf[idx][n].num_parents,
+ c_cfg.mux_hw, c_cfg.mux_ops,
+ c_cfg.div_hw, c_cfg.div_ops,
+ c_cfg.gate_hw, c_cfg.gate_ops,
+ stm32_odf[idx][n].flags);
+ }
+}
+
+/* PERIF CLOCKS */
+struct pclk_t {
+ u32 gate_offset;
+ u8 bit_idx;
+ const char *name;
+ const char *parent;
+ u32 flags;
+};
+
+#define PER_CLKF(_gate_offset, _bit_idx, _name, _parent, _flags)\
+{\
+ .gate_offset = _gate_offset,\
+ .bit_idx = _bit_idx,\
+ .name = _name,\
+ .parent = _parent,\
+ .flags = _flags,\
+}
+#define PER_CLK(_gate_offset, _bit_idx, _name, _parent)\
+ PER_CLKF(_gate_offset, _bit_idx, _name, _parent, 0)
+
+static const struct pclk_t pclk[] = {
+ PER_CLK(RCC_AHB3ENR, 31, "d1sram1", "hclk"),
+ PER_CLK(RCC_AHB3ENR, 30, "itcm", "hclk"),
+ PER_CLK(RCC_AHB3ENR, 29, "dtcm2", "hclk"),
+ PER_CLK(RCC_AHB3ENR, 28, "dtcm1", "hclk"),
+ PER_CLK(RCC_AHB3ENR, 8, "flitf", "hclk"),
+ PER_CLK(RCC_AHB3ENR, 5, "jpgdec", "hclk"),
+ PER_CLK(RCC_AHB3ENR, 4, "dma2d", "hclk"),
+ PER_CLK(RCC_AHB3ENR, 0, "mdma", "hclk"),
+ PER_CLK(RCC_AHB1ENR, 28, "usb2ulpi", "hclk"),
+ PER_CLK(RCC_AHB1ENR, 26, "usb1ulpi", "hclk"),
+ PER_CLK(RCC_AHB1ENR, 17, "eth1rx", "hclk"),
+ PER_CLK(RCC_AHB1ENR, 16, "eth1tx", "hclk"),
+ PER_CLK(RCC_AHB1ENR, 15, "eth1mac", "hclk"),
+ PER_CLK(RCC_AHB1ENR, 14, "art", "hclk"),
+ PER_CLK(RCC_AHB1ENR, 1, "dma2", "hclk"),
+ PER_CLK(RCC_AHB1ENR, 0, "dma1", "hclk"),
+ PER_CLK(RCC_AHB2ENR, 31, "d2sram3", "hclk"),
+ PER_CLK(RCC_AHB2ENR, 30, "d2sram2", "hclk"),
+ PER_CLK(RCC_AHB2ENR, 29, "d2sram1", "hclk"),
+ PER_CLK(RCC_AHB2ENR, 5, "hash", "hclk"),
+ PER_CLK(RCC_AHB2ENR, 4, "crypt", "hclk"),
+ PER_CLK(RCC_AHB2ENR, 0, "camitf", "hclk"),
+ PER_CLK(RCC_AHB4ENR, 28, "bkpram", "hclk"),
+ PER_CLK(RCC_AHB4ENR, 25, "hsem", "hclk"),
+ PER_CLK(RCC_AHB4ENR, 21, "bdma", "hclk"),
+ PER_CLK(RCC_AHB4ENR, 19, "crc", "hclk"),
+ PER_CLK(RCC_AHB4ENR, 10, "gpiok", "hclk"),
+ PER_CLK(RCC_AHB4ENR, 9, "gpioj", "hclk"),
+ PER_CLK(RCC_AHB4ENR, 8, "gpioi", "hclk"),
+ PER_CLK(RCC_AHB4ENR, 7, "gpioh", "hclk"),
+ PER_CLK(RCC_AHB4ENR, 6, "gpiog", "hclk"),
+ PER_CLK(RCC_AHB4ENR, 5, "gpiof", "hclk"),
+ PER_CLK(RCC_AHB4ENR, 4, "gpioe", "hclk"),
+ PER_CLK(RCC_AHB4ENR, 3, "gpiod", "hclk"),
+ PER_CLK(RCC_AHB4ENR, 2, "gpioc", "hclk"),
+ PER_CLK(RCC_AHB4ENR, 1, "gpiob", "hclk"),
+ PER_CLK(RCC_AHB4ENR, 0, "gpioa", "hclk"),
+ PER_CLK(RCC_APB3ENR, 6, "wwdg1", "pclk3"),
+ PER_CLK(RCC_APB1LENR, 29, "dac12", "pclk1"),
+ PER_CLK(RCC_APB1LENR, 11, "wwdg2", "pclk1"),
+ PER_CLK(RCC_APB1LENR, 8, "tim14", "pclk1"),
+ PER_CLK(RCC_APB1LENR, 7, "tim13", "pclk1"),
+ PER_CLK(RCC_APB1LENR, 6, "tim12", "pclk1"),
+ PER_CLK(RCC_APB1LENR, 5, "tim7", "pclk1"),
+ PER_CLK(RCC_APB1LENR, 4, "tim6", "pclk1"),
+ PER_CLK(RCC_APB1LENR, 3, "tim5", "pclk1"),
+ PER_CLK(RCC_APB1LENR, 2, "tim4", "pclk1"),
+ PER_CLK(RCC_APB1LENR, 1, "tim3", "pclk1"),
+ PER_CLK(RCC_APB1LENR, 0, "tim2", "pclk1"),
+ PER_CLK(RCC_APB1HENR, 5, "mdios", "pclk1"),
+ PER_CLK(RCC_APB1HENR, 4, "opamp", "pclk1"),
+ PER_CLK(RCC_APB1HENR, 1, "crs", "pclk1"),
+ PER_CLK(RCC_APB2ENR, 18, "tim17", "pclk2"),
+ PER_CLK(RCC_APB2ENR, 17, "tim16", "pclk2"),
+ PER_CLK(RCC_APB2ENR, 16, "tim15", "pclk2"),
+ PER_CLK(RCC_APB2ENR, 1, "tim8", "pclk2"),
+ PER_CLK(RCC_APB2ENR, 0, "tim1", "pclk2"),
+ PER_CLK(RCC_APB4ENR, 26, "tmpsens", "pclk4"),
+ PER_CLK(RCC_APB4ENR, 16, "rtcapb", "pclk4"),
+ PER_CLK(RCC_APB4ENR, 15, "vref", "pclk4"),
+ PER_CLK(RCC_APB4ENR, 14, "comp12", "pclk4"),
+ PER_CLK(RCC_APB4ENR, 1, "syscfg", "pclk4"),
+};
+
+/* KERNEL CLOCKS */
+#define KER_CLKF(_gate_offset, _bit_idx,\
+ _mux_offset, _mux_shift, _mux_width,\
+ _name, _parent_name,\
+ _flags) \
+{ \
+ .gate = &(struct gate_cfg) {_gate_offset, _bit_idx},\
+ .mux = &(struct muxdiv_cfg) {_mux_offset, _mux_shift, _mux_width },\
+ .name = _name, \
+ .parent_name = _parent_name, \
+ .num_parents = ARRAY_SIZE(_parent_name),\
+ .flags = _flags,\
+}
+#define KER_CLK(_gate_offset, _bit_idx, _mux_offset, _mux_shift, _mux_width,\
+ _name, _parent_name) \
+KER_CLKF(_gate_offset, _bit_idx, _mux_offset, _mux_shift, _mux_width,\
+ _name, _parent_name, 0)\
+
+#define KER_CLKF_NOMUX(_gate_offset, _bit_idx,\
+ _name, _parent_name,\
+ _flags) \
+{ \
+ .gate = &(struct gate_cfg) {_gate_offset, _bit_idx},\
+ .mux = NULL,\
+ .name = _name, \
+ .parent_name = _parent_name, \
+ .num_parents = 1,\
+ .flags = _flags,\
+}
+
+static const struct composite_clk_cfg kclk[] = {
+ KER_CLK(RCC_AHB3ENR, 16, RCC_D1CCIPR, 16, 1, "sdmmc1", sdmmc_src),
+ KER_CLKF(RCC_AHB3ENR, 14, RCC_D1CCIPR, 4, 2, "quadspi", qspi_src,
+ CLK_IGNORE_UNUSED),
+ KER_CLKF(RCC_AHB3ENR, 12, RCC_D1CCIPR, 0, 2, "fmc", fmc_src,
+ CLK_IGNORE_UNUSED),
+ KER_CLK(RCC_AHB1ENR, 27, RCC_D2CCIP2R, 20, 2, "usb2otg", usbotg_src),
+ KER_CLK(RCC_AHB1ENR, 25, RCC_D2CCIP2R, 20, 2, "usb1otg", usbotg_src),
+ KER_CLK(RCC_AHB1ENR, 5, RCC_D3CCIPR, 16, 2, "adc12", adc_src),
+ KER_CLK(RCC_AHB2ENR, 9, RCC_D1CCIPR, 16, 1, "sdmmc2", sdmmc_src),
+ KER_CLK(RCC_AHB2ENR, 6, RCC_D2CCIP2R, 8, 2, "rng", rng_src),
+ KER_CLK(RCC_AHB4ENR, 24, RCC_D3CCIPR, 16, 2, "adc3", adc_src),
+ KER_CLK(RCC_APB3ENR, 4, RCC_D1CCIPR, 8, 1, "dsi", dsi_src),
+ KER_CLKF_NOMUX(RCC_APB3ENR, 3, "ltdc", ltdc_src, CLK_SET_RATE_PARENT),
+ KER_CLK(RCC_APB1LENR, 31, RCC_D2CCIP2R, 0, 3, "usart8", usart_src2),
+ KER_CLK(RCC_APB1LENR, 30, RCC_D2CCIP2R, 0, 3, "usart7", usart_src2),
+ KER_CLK(RCC_APB1LENR, 27, RCC_D2CCIP2R, 22, 2, "hdmicec", cec_src),
+ KER_CLK(RCC_APB1LENR, 23, RCC_D2CCIP2R, 12, 2, "i2c3", i2c_src1),
+ KER_CLK(RCC_APB1LENR, 22, RCC_D2CCIP2R, 12, 2, "i2c2", i2c_src1),
+ KER_CLK(RCC_APB1LENR, 21, RCC_D2CCIP2R, 12, 2, "i2c1", i2c_src1),
+ KER_CLK(RCC_APB1LENR, 20, RCC_D2CCIP2R, 0, 3, "uart5", usart_src2),
+ KER_CLK(RCC_APB1LENR, 19, RCC_D2CCIP2R, 0, 3, "uart4", usart_src2),
+ KER_CLK(RCC_APB1LENR, 18, RCC_D2CCIP2R, 0, 3, "usart3", usart_src2),
+ KER_CLK(RCC_APB1LENR, 17, RCC_D2CCIP2R, 0, 3, "usart2", usart_src2),
+ KER_CLK(RCC_APB1LENR, 16, RCC_D2CCIP1R, 20, 2, "spdifrx", spdifrx_src),
+ KER_CLK(RCC_APB1LENR, 15, RCC_D2CCIP1R, 16, 3, "spi3", spi_src1),
+ KER_CLK(RCC_APB1LENR, 14, RCC_D2CCIP1R, 16, 3, "spi2", spi_src1),
+ KER_CLK(RCC_APB1LENR, 9, RCC_D2CCIP2R, 28, 3, "lptim1", lptim_src1),
+ KER_CLK(RCC_APB1HENR, 8, RCC_D2CCIP1R, 28, 2, "fdcan", fdcan_src),
+ KER_CLK(RCC_APB1HENR, 2, RCC_D2CCIP1R, 31, 1, "swp", swp_src),
+ KER_CLK(RCC_APB2ENR, 29, RCC_CFGR, 14, 1, "hrtim", hrtim_src),
+ KER_CLK(RCC_APB2ENR, 28, RCC_D2CCIP1R, 24, 1, "dfsdm1", dfsdm1_src),
+ KER_CLK(RCC_APB2ENR, 24, RCC_D2CCIP1R, 6, 3, "sai3", sai_src),
+ KER_CLK(RCC_APB2ENR, 23, RCC_D2CCIP1R, 6, 3, "sai2", sai_src),
+ KER_CLK(RCC_APB2ENR, 22, RCC_D2CCIP1R, 0, 3, "sai1", sai_src),
+ KER_CLK(RCC_APB2ENR, 20, RCC_D2CCIP1R, 16, 3, "spi5", spi_src2),
+ KER_CLK(RCC_APB2ENR, 13, RCC_D2CCIP1R, 16, 3, "spi4", spi_src2),
+ KER_CLK(RCC_APB2ENR, 12, RCC_D2CCIP1R, 16, 3, "spi1", spi_src1),
+ KER_CLK(RCC_APB2ENR, 5, RCC_D2CCIP2R, 3, 3, "usart6", usart_src1),
+ KER_CLK(RCC_APB2ENR, 4, RCC_D2CCIP2R, 3, 3, "usart1", usart_src1),
+ KER_CLK(RCC_APB4ENR, 21, RCC_D3CCIPR, 24, 3, "sai4b", sai_src),
+ KER_CLK(RCC_APB4ENR, 21, RCC_D3CCIPR, 21, 3, "sai4a", sai_src),
+ KER_CLK(RCC_APB4ENR, 12, RCC_D3CCIPR, 13, 3, "lptim5", lptim_src2),
+ KER_CLK(RCC_APB4ENR, 11, RCC_D3CCIPR, 13, 3, "lptim4", lptim_src2),
+ KER_CLK(RCC_APB4ENR, 10, RCC_D3CCIPR, 13, 3, "lptim3", lptim_src2),
+ KER_CLK(RCC_APB4ENR, 9, RCC_D3CCIPR, 10, 3, "lptim2", lptim_src2),
+ KER_CLK(RCC_APB4ENR, 7, RCC_D3CCIPR, 8, 2, "i2c4", i2c_src2),
+ KER_CLK(RCC_APB4ENR, 5, RCC_D3CCIPR, 28, 3, "spi6", spi_src3),
+ KER_CLK(RCC_APB4ENR, 3, RCC_D3CCIPR, 0, 3, "lpuart1", lpuart1_src),
+};
+
+static struct composite_clk_gcfg kernel_clk_cfg = {
+ M_CFG_MUX(NULL, 0),
+ M_CFG_GATE(NULL, 0),
+};
+
+/* RTC clock */
+static u8 rtc_mux_get_parent(struct clk_hw *hw)
+{
+ return clk_mux_ops.get_parent(hw);
+}
+
+static int rtc_mux_set_parent(struct clk_hw *hw, u8 index)
+{
+ int dbp_status;
+ int err;
+
+ dbp_status = is_enable_power_domain_write_protection();
+
+ if (dbp_status)
+ disable_power_domain_write_protection();
+
+ err = clk_mux_ops.set_parent(hw, index);
+
+ if (dbp_status)
+ enable_power_domain_write_protection();
+
+ return err;
+}
+
+static int rtc_mux_determine_rate(struct clk_hw *hw,
+ struct clk_rate_request *req)
+{
+ return clk_mux_ops.determine_rate(hw, req);
+}
+
+static const struct clk_ops rtc_mux_ops = {
+ .get_parent = rtc_mux_get_parent,
+ .set_parent = rtc_mux_set_parent,
+ .determine_rate = rtc_mux_determine_rate,
+};
+
+/* Clock gate with backup domain protection management */
+static int bd_gate_is_enabled(struct clk_hw *hw)
+{
+ return clk_gate_ops.is_enabled(hw);
+}
+
+static int bd_gate_enable(struct clk_hw *hw)
+{
+ int dbp_status;
+ int err;
+
+ if (bd_gate_is_enabled(hw))
+ return 0;
+
+ dbp_status = is_enable_power_domain_write_protection();
+
+ if (dbp_status)
+ disable_power_domain_write_protection();
+
+ err = clk_gate_ops.enable(hw);
+
+ if (dbp_status)
+ enable_power_domain_write_protection();
+
+ return err;
+}
+
+static void bd_gate_disable(struct clk_hw *hw)
+{
+ int dbp_status;
+
+ if (!bd_gate_is_enabled(hw))
+ return;
+
+ dbp_status = is_enable_power_domain_write_protection();
+
+ if (dbp_status)
+ disable_power_domain_write_protection();
+
+ clk_gate_ops.disable(hw);
+
+ if (dbp_status)
+ enable_power_domain_write_protection();
+}
+
+static const struct clk_ops bd_gate_ops = {
+ .enable = bd_gate_enable,
+ .disable = bd_gate_disable,
+ .is_enabled = bd_gate_is_enabled,
+};
+
+static struct composite_clk_gcfg rtc_clk_cfg = {
+ M_CFG_MUX(&rtc_mux_ops, 0),
+ M_CFG_GATE(&bd_gate_ops, 0),
+};
+
+static const struct composite_clk_cfg rtc_clk =
+ KER_CLK(RCC_BDCR, 15, RCC_BDCR, 8, 2, "rtc_ck", rtc_src);
+
+/* Micro-controller output clock */
+static struct composite_clk_gcfg mco_clk_cfg = {
+ M_CFG_MUX(NULL, 0),
+ M_CFG_DIV(NULL, CLK_DIVIDER_ONE_BASED | CLK_DIVIDER_ALLOW_ZERO),
+};
+
+#define M_MCO_F(_name, _parents, _mux_offset, _mux_shift, _mux_width,\
+ _rate_offset, _rate_shift, _rate_width,\
+ _flags)\
+{\
+ .mux = &(struct muxdiv_cfg) {_mux_offset, _mux_shift, _mux_width },\
+ .div = &(struct muxdiv_cfg) {_rate_offset, _rate_shift, _rate_width},\
+ .gate = NULL,\
+ .name = _name,\
+ .parent_name = _parents,\
+ .num_parents = ARRAY_SIZE(_parents),\
+ .flags = _flags,\
+}
+
+static const struct composite_clk_cfg mco_clk[] = {
+ M_MCO_F("mco1", mco_src1, RCC_CFGR, 22, 4, RCC_CFGR, 18, 4, 0),
+ M_MCO_F("mco2", mco_src2, RCC_CFGR, 29, 3, RCC_CFGR, 25, 4, 0),
+};
+
+static void __init stm32h7_rcc_init(struct device_node *np)
+{
+ struct clk_hw_onecell_data *clk_data;
+ struct device_node *node;
+ struct composite_cfg c_cfg;
+ int n;
+ const char *hse_clk, *lse_clk, *i2s_clk;
+
+ clk_data = kzalloc(sizeof(*clk_data) +
+ sizeof(*clk_data->hws) * STM32H7_MAX_CLKS,
+ GFP_KERNEL);
+ if (!clk_data)
+ return;
+
+ clk_data->num = STM32H7_MAX_CLKS;
+
+ hws = clk_data->hws;
+
+ for (n = 0; n < STM32H7_MAX_CLKS; n++)
+ hws[n] = ERR_PTR(-ENOENT);
+
+ /* get RCC base @ from DT */
+ base = of_iomap(np, 0);
+ if (!base) {
+ pr_err("%s: unable to map resource", np->name);
+ goto err_free_clks;
+ }
+
+ pdrm = syscon_regmap_lookup_by_phandle(np, "st,syscfg");
+ if (IS_ERR(pdrm)) {
+ pdrm = NULL;
+ pr_warn("%s: Unable to get syscfg\n", __func__);
+ }
+
+ /* Put parent names from DT */
+ hse_clk = of_clk_get_parent_name(np, 0);
+ lse_clk = of_clk_get_parent_name(np, 1);
+ i2s_clk = of_clk_get_parent_name(np, 2);
+
+ sai_src[3] = i2s_clk;
+ spi_src1[3] = i2s_clk;
+
+ /* Register Internal oscillators */
+ clk_hw_register_fixed_rate(NULL, "clk-hsi", NULL, 0, 64000000);
+ clk_hw_register_fixed_rate(NULL, "clk-csi", NULL, 0, 4000000);
+ clk_hw_register_fixed_rate(NULL, "clk-lsi", NULL, 0, 32000);
+ clk_hw_register_fixed_rate(NULL, "clk-rc48", NULL, 0, 48000);
+
+ /* This clock is coming from outside. Frequencies unknown */
+ hws[CK_DSI_PHY] = clk_hw_register_fixed_rate(NULL, "ck_dsi_phy", NULL,
+ 0, 0);
+
+ hws[HSI_DIV] = clk_hw_register_divider(NULL, "hsidiv", "clk-hsi", 0,
+ base + RCC_CR, 3, 2, CLK_DIVIDER_POWER_OF_TWO,
+ &rlock);
+
+ hws[HSE_1M] = clk_hw_register_divider(NULL, "hse_1M", "hse_ck", 0,
+ base + RCC_CFGR, 8, 6, CLK_DIVIDER_ONE_BASED |
+ CLK_DIVIDER_ALLOW_ZERO,
+ &rlock);
+
+ /* Mux system clocks */
+ for (n = 0; n < ARRAY_SIZE(stm32_mclk); n++)
+ hws[MCLK_BANK + n] = clk_hw_register_mux(NULL,
+ stm32_mclk[n].name,
+ stm32_mclk[n].parents,
+ stm32_mclk[n].num_parents,
+ stm32_mclk[n].flags,
+ stm32_mclk[n].offset + base,
+ stm32_mclk[n].shift,
+ stm32_mclk[n].width,
+ 0,
+ &rlock);
+
+ register_core_and_bus_clocks();
+
+ /* Oscillary clocks */
+ for (n = 0; n < ARRAY_SIZE(stm32_oclk); n++)
+ hws[OSC_BANK + n] = clk_register_ready_gate(NULL,
+ stm32_oclk[n].name,
+ stm32_oclk[n].parent,
+ stm32_oclk[n].gate_offset + base,
+ stm32_oclk[n].bit_idx,
+ stm32_oclk[n].bit_rdy,
+ 0,
+ stm32_oclk[n].flags,
+ &rlock);
+
+ hws[HSE_CK] = clk_register_ready_gate(NULL,
+ "hse_ck",
+ hse_clk,
+ RCC_CR + base,
+ 16, 17,
+ 0,
+ 0,
+ &rlock);
+
+ hws[LSE_CK] = clk_register_ready_gate(NULL,
+ "lse_ck",
+ lse_clk,
+ RCC_BDCR + base,
+ 0, 1,
+ 1,
+ 0,
+ &rlock);
+
+ hws[CSI_KER_DIV122 + n] = clk_hw_register_fixed_factor(NULL,
+ "csi_ker_div122", "csi_ker", 0, 1, 122);
+
+ /* PLLs */
+ for_each_compatible_node(node, NULL, "st,stm32h7-pll")
+ stm32_h7_pll_init(node);
+
+ /* Peripheral clocks */
+ for (n = 0; n < ARRAY_SIZE(pclk); n++)
+ hws[PERIF_BANK + n] = clk_hw_register_gate(NULL, pclk[n].name,
+ pclk[n].parent,
+ pclk[n].flags, base + pclk[n].gate_offset,
+ pclk[n].bit_idx, pclk[n].flags, &rlock);
+
+ /* Kernel clocks */
+ for (n = 0; n < ARRAY_SIZE(kclk); n++) {
+ get_cfg_composite_div(&kernel_clk_cfg, &kclk[n], &c_cfg,
+ &rlock);
+
+ hws[KERN_BANK + n] = clk_hw_register_composite(NULL,
+ kclk[n].name,
+ kclk[n].parent_name,
+ kclk[n].num_parents,
+ c_cfg.mux_hw, c_cfg.mux_ops,
+ c_cfg.div_hw, c_cfg.div_ops,
+ c_cfg.gate_hw, c_cfg.gate_ops,
+ kclk[n].flags);
+ }
+
+ /* RTC clock (default state is off) */
+ clk_hw_register_fixed_rate(NULL, "off", NULL, 0, 0);
+
+ get_cfg_composite_div(&rtc_clk_cfg, &rtc_clk, &c_cfg, &rlock);
+
+ hws[RTC_CK] = clk_hw_register_composite(NULL,
+ rtc_clk.name,
+ rtc_clk.parent_name,
+ rtc_clk.num_parents,
+ c_cfg.mux_hw, c_cfg.mux_ops,
+ c_cfg.div_hw, c_cfg.div_ops,
+ c_cfg.gate_hw, c_cfg.gate_ops,
+ rtc_clk.flags);
+
+ /* Micro-controller clocks */
+ for (n = 0; n < ARRAY_SIZE(mco_clk); n++) {
+ get_cfg_composite_div(&mco_clk_cfg, &mco_clk[n], &c_cfg,
+ &rlock);
+
+ hws[MCO_BANK + n] = clk_hw_register_composite(NULL,
+ mco_clk[n].name,
+ mco_clk[n].parent_name,
+ mco_clk[n].num_parents,
+ c_cfg.mux_hw, c_cfg.mux_ops,
+ c_cfg.div_hw, c_cfg.div_ops,
+ c_cfg.gate_hw, c_cfg.gate_ops,
+ mco_clk[n].flags);
+ }
+
+ of_clk_add_hw_provider(np, of_clk_hw_onecell_get, clk_data);
+
+ return;
+
+err_free_clks:
+ kfree(clk_data);
+}
+CLK_OF_DECLARE_DRIVER(stm32h7_rcc, "st,stm32h743-rcc", stm32h7_rcc_init);
diff --git a/include/dt-bindings/clock/stm32h7-clks.h b/include/dt-bindings/clock/stm32h7-clks.h
new file mode 100644
index 0000000..6637272
--- /dev/null
+++ b/include/dt-bindings/clock/stm32h7-clks.h
@@ -0,0 +1,165 @@
+/* SYS, CORE AND BUS CLOCKS */
+#define SYS_D1CPRE 0
+#define HCLK 1
+#define PCLK1 2
+#define PCLK2 3
+#define PCLK3 4
+#define PCLK4 5
+#define HSI_DIV 6
+#define HSE_1M 7
+#define I2S_CKIN 8
+#define CK_DSI_PHY 9
+#define HSE_CK 10
+#define LSE_CK 11
+#define CSI_KER_DIV122 12
+#define RTC_CK 13
+#define CPU_SYSTICK 14
+
+/* OSCILLATOR BANK */
+#define OSC_BANK 18
+#define HSI_CK 18
+#define HSI_KER_CK 19
+#define CSI_CK 20
+#define CSI_KER_CK 21
+#define RC48_CK 22
+#define LSI_CK 23
+
+/* MCLOCK BANK */
+#define MCLK_BANK 28
+#define PER_CK 28
+#define PLLSRC 29
+#define SYS_CK 30
+#define TRACEIN_CK 31
+
+/* ODF BANK */
+#define ODF_BANK 32
+#define PLL1_P 32
+#define PLL1_Q 33
+#define PLL1_R 34
+#define PLL2_P 35
+#define PLL2_Q 36
+#define PLL2_R 37
+#define PLL3_P 38
+#define PLL3_Q 39
+#define PLL3_R 40
+
+/* MCO BANK */
+#define MCO_BANK 41
+#define MCO1 41
+#define MCO2 42
+
+/* PERIF BANK */
+#define PERIF_BANK 50
+#define D1SRAM1_CK 50
+#define ITCM_CK 51
+#define DTCM2_CK 52
+#define DTCM1_CK 53
+#define FLITF_CK 54
+#define JPGDEC_CK 55
+#define DMA2D_CK 56
+#define MDMA_CK 57
+#define USB2ULPI_CK 58
+#define USB1ULPI_CK 59
+#define ETH1RX_CK 60
+#define ETH1TX_CK 61
+#define ETH1MAC_CK 62
+#define ART_CK 63
+#define DMA2_CK 64
+#define DMA1_CK 65
+#define D2SRAM3_CK 66
+#define D2SRAM2_CK 67
+#define D2SRAM1_CK 68
+#define HASH_CK 69
+#define CRYPT_CK 70
+#define CAMITF_CK 71
+#define BKPRAM_CK 72
+#define HSEM_CK 73
+#define BDMA_CK 74
+#define CRC_CK 75
+#define GPIOK_CK 76
+#define GPIOJ_CK 77
+#define GPIOI_CK 78
+#define GPIOH_CK 79
+#define GPIOG_CK 80
+#define GPIOF_CK 81
+#define GPIOE_CK 82
+#define GPIOD_CK 83
+#define GPIOC_CK 84
+#define GPIOB_CK 85
+#define GPIOA_CK 86
+#define WWDG1_CK 87
+#define DAC12_CK 88
+#define WWDG2_CK 89
+#define TIM14_CK 90
+#define TIM13_CK 91
+#define TIM12_CK 92
+#define TIM7_CK 93
+#define TIM6_CK 94
+#define TIM5_CK 95
+#define TIM4_CK 96
+#define TIM3_CK 97
+#define TIM2_CK 98
+#define MDIOS_CK 99
+#define OPAMP_CK 100
+#define CRS_CK 101
+#define TIM17_CK 102
+#define TIM16_CK 103
+#define TIM15_CK 104
+#define TIM8_CK 105
+#define TIM1_CK 106
+#define TMPSENS_CK 107
+#define RTCAPB_CK 108
+#define VREF_CK 109
+#define COMP12_CK 110
+#define SYSCFG_CK 111
+
+/* KERNEL BANK */
+#define KERN_BANK 120
+#define SDMMC1_CK 120
+#define QUADSPI_CK 121
+#define FMC_CK 122
+#define USB2OTG_CK 123
+#define USB1OTG_CK 124
+#define ADC12_CK 125
+#define SDMMC2_CK 126
+#define RNG_CK 127
+#define ADC3_CK 128
+#define DSI_CK 129
+#define LTDC_CK 130
+#define USART8_CK 131
+#define USART7_CK 132
+#define HDMICEC_CK 133
+#define I2C3_CK 134
+#define I2C2_CK 135
+#define I2C1_CK 136
+#define UART5_CK 137
+#define UART4_CK 138
+#define USART3_CK 139
+#define USART2_CK 140
+#define SPDIFRX_CK 141
+#define SPI3_CK 142
+#define SPI2_CK 143
+#define LPTIM1_CK 144
+#define FDCAN_CK 145
+#define SWP_CK 146
+#define HRTIM_CK 147
+#define DFSDM1_CK 148
+#define SAI3_CK 149
+#define SAI2_CK 150
+#define SAI1_CK 151
+#define SPI5_CK 152
+#define SPI4_CK 153
+#define SPI1_CK 154
+#define USART6_CK 155
+#define USART1_CK 156
+#define SAI4B_CK 157
+#define SAI4A_CK 158
+#define LPTIM5_CK 159
+#define LPTIM4_CK 160
+#define LPTIM3_CK 161
+#define LPTIM2_CK 162
+#define I2C4_CK 163
+#define SPI6_CK 164
+#define LPUART1_CK 165
+
+#define STM32H7_MAX_CLKS 166
diff --git a/include/dt-bindings/mfd/stm32h7-rcc.h b/include/dt-bindings/mfd/stm32h7-rcc.h
new file mode 100644
index 0000000..3af6a65
--- /dev/null
+++ b/include/dt-bindings/mfd/stm32h7-rcc.h
@@ -0,0 +1,137 @@
+/*
+ * This header provides constants for the STM32H7 RCC IP
+ */
+
+#ifndef _DT_BINDINGS_MFD_STM32H7_RCC_H
+#define _DT_BINDINGS_MFD_STM32H7_RCC_H
+
+/* AHB3 */
+#define STM32H7_RCC_AHB3_MDMA 0
+#define STM32H7_RCC_AHB3_DMA2D 4
+#define STM32H7_RCC_AHB3_JPGDEC 5
+#define STM32H7_RCC_AHB3_FMC 12
+#define STM32H7_RCC_AHB3_QUADSPI 14
+#define STM32H7_RCC_AHB3_SDMMC1 16
+#define STM32H7_RCC_AHB3_CPU 31
+
+#define STM32H7_AHB3_RESET(bit) (STM32H7_RCC_AHB3_##bit + (0x7C * 8))
+
+/* AHB1 */
+#define STM32H7_RCC_AHB1_DMA1 0
+#define STM32H7_RCC_AHB1_DMA2 1
+#define STM32H7_RCC_AHB1_ADC12 5
+#define STM32H7_RCC_AHB1_ART 14
+#define STM32H7_RCC_AHB1_ETH1MAC 15
+#define STM32H7_RCC_AHB1_USB1OTG 25
+#define STM32H7_RCC_AHB1_USB2OTG 27
+
+#define STM32H7_AHB1_RESET(bit) (STM32H7_RCC_AHB1_##bit + (0x80 * 8))
+
+/* AHB2 */
+#define STM32H7_RCC_AHB2_CAMITF 0
+#define STM32H7_RCC_AHB2_CRYPT 4
+#define STM32H7_RCC_AHB2_HASH 5
+#define STM32H7_RCC_AHB2_RNG 6
+#define STM32H7_RCC_AHB2_SDMMC2 9
+
+#define STM32H7_AHB2_RESET(bit) (STM32H7_RCC_AHB2_##bit + (0x84 * 8))
+
+/* AHB4 */
+#define STM32H7_RCC_AHB4_GPIOA 0
+#define STM32H7_RCC_AHB4_GPIOB 1
+#define STM32H7_RCC_AHB4_GPIOC 2
+#define STM32H7_RCC_AHB4_GPIOD 3
+#define STM32H7_RCC_AHB4_GPIOE 4
+#define STM32H7_RCC_AHB4_GPIOF 5
+#define STM32H7_RCC_AHB4_GPIOG 6
+#define STM32H7_RCC_AHB4_GPIOH 7
+#define STM32H7_RCC_AHB4_GPIOI 8
+#define STM32H7_RCC_AHB4_GPIOJ 9
+#define STM32H7_RCC_AHB4_GPIOK 10
+#define STM32H7_RCC_AHB4_CRC 19
+#define STM32H7_RCC_AHB4_BDMA 21
+#define STM32H7_RCC_AHB4_ADC3 24
+#define STM32H7_RCC_AHB4_HSEM 25
+
+#define STM32H7_AHB4_RESET(bit) (STM32H7_RCC_AHB4_##bit + (0x88 * 8))
+
+
+/* APB3 */
+#define STM32H7_RCC_APB3_LTDC 3
+#define STM32H7_RCC_APB3_DSI 4
+
+#define STM32H7_APB3_RESET(bit) (STM32H7_RCC_APB3_##bit + (0x8C * 8))
+
+/* APB1L */
+#define STM32H7_RCC_APB1L_TIM2 0
+#define STM32H7_RCC_APB1L_TIM3 1
+#define STM32H7_RCC_APB1L_TIM4 2
+#define STM32H7_RCC_APB1L_TIM5 3
+#define STM32H7_RCC_APB1L_TIM6 4
+#define STM32H7_RCC_APB1L_TIM7 5
+#define STM32H7_RCC_APB1L_TIM12 6
+#define STM32H7_RCC_APB1L_TIM13 7
+#define STM32H7_RCC_APB1L_TIM14 8
+#define STM32H7_RCC_APB1L_LPTIM1 9
+#define STM32H7_RCC_APB1L_SPI2 14
+#define STM32H7_RCC_APB1L_SPI3 15
+#define STM32H7_RCC_APB1L_SPDIF_RX 16
+#define STM32H7_RCC_APB1L_USART2 17
+#define STM32H7_RCC_APB1L_USART3 18
+#define STM32H7_RCC_APB1L_UART4 19
+#define STM32H7_RCC_APB1L_UART5 20
+#define STM32H7_RCC_APB1L_I2C1 21
+#define STM32H7_RCC_APB1L_I2C2 22
+#define STM32H7_RCC_APB1L_I2C3 23
+#define STM32H7_RCC_APB1L_HDMICEC 27
+#define STM32H7_RCC_APB1L_DAC12 29
+#define STM32H7_RCC_APB1L_USART7 30
+#define STM32H7_RCC_APB1L_USART8 31
+
+#define STM32H7_APB1L_RESET(bit) (STM32H7_RCC_APB1L_##bit + (0x90 * 8))
+
+/* APB1H */
+#define STM32H7_RCC_APB1H_CRS 1
+#define STM32H7_RCC_APB1H_SWP 2
+#define STM32H7_RCC_APB1H_OPAMP 4
+#define STM32H7_RCC_APB1H_MDIOS 5
+#define STM32H7_RCC_APB1H_FDCAN 8
+
+#define STM32H7_APB1H_RESET(bit) (STM32H7_RCC_APB1H_##bit + (0x94 * 8))
+
+/* APB2 */
+#define STM32H7_RCC_APB2_TIM1 0
+#define STM32H7_RCC_APB2_TIM8 1
+#define STM32H7_RCC_APB2_USART1 4
+#define STM32H7_RCC_APB2_USART6 5
+#define STM32H7_RCC_APB2_SPI1 12
+#define STM32H7_RCC_APB2_SPI4 13
+#define STM32H7_RCC_APB2_TIM15 16
+#define STM32H7_RCC_APB2_TIM16 17
+#define STM32H7_RCC_APB2_TIM17 18
+#define STM32H7_RCC_APB2_SPI5 20
+#define STM32H7_RCC_APB2_SAI1 22
+#define STM32H7_RCC_APB2_SAI2 23
+#define STM32H7_RCC_APB2_SAI3 24
+#define STM32H7_RCC_APB2_DFSDM1 28
+#define STM32H7_RCC_APB2_HRTIM 29
+
+#define STM32H7_APB2_RESET(bit) (STM32H7_RCC_APB2_##bit + (0x98 * 8))
+
+/* APB4 */
+#define STM32H7_RCC_APB4_SYSCFG 1
+#define STM32H7_RCC_APB4_LPUART1 3
+#define STM32H7_RCC_APB4_SPI6 5
+#define STM32H7_RCC_APB4_I2C4 7
+#define STM32H7_RCC_APB4_LPTIM2 9
+#define STM32H7_RCC_APB4_LPTIM3 10
+#define STM32H7_RCC_APB4_LPTIM4 11
+#define STM32H7_RCC_APB4_LPTIM5 12
+#define STM32H7_RCC_APB4_COMP12 14
+#define STM32H7_RCC_APB4_VREF 15
+#define STM32H7_RCC_APB4_SAI4 21
+#define STM32H7_RCC_APB4_TMPSENS 26
+
+#define STM32H7_APB4_RESET(bit) (STM32H7_RCC_APB4_##bit + (0x9C * 8))
+
+#endif /* _DT_BINDINGS_MFD_STM32H7_RCC_H */
--
1.9.1
^ permalink raw reply related
* Re: [PATCH 2/3] dt-bindings: arm: amlogic: Add SoC information bindings
From: Rob Herring @ 2017-04-04 12:26 UTC (permalink / raw)
To: Neil Armstrong
Cc: Arnd Bergmann, Kevin Hilman, Carlo Caione,
linux-amlogic-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r, Linux ARM,
Linux Kernel Mailing List,
devicetree-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
In-Reply-To: <265460a5-9295-f58a-f149-030e5dd750a1-rdvid1DuHRBWk0Htik3J/w@public.gmane.org>
On Tue, Apr 4, 2017 at 3:51 AM, Neil Armstrong <narmstrong-rdvid1DuHRBWk0Htik3J/w@public.gmane.org> wrote:
> On 04/03/2017 06:34 PM, Rob Herring wrote:
>> On Fri, Mar 31, 2017 at 04:10:30PM +0200, Neil Armstrong wrote:
>>> On 03/31/2017 03:44 PM, Arnd Bergmann wrote:
>>>> On Fri, Mar 31, 2017 at 10:47 AM, Neil Armstrong
>>>> <narmstrong-rdvid1DuHRBWk0Htik3J/w@public.gmane.org> wrote:
>>>>> Add bindings for the SoC information register of the Amlogic SoCs.
>>>>>
>>>>> Signed-off-by: Neil Armstrong <narmstrong-rdvid1DuHRBWk0Htik3J/w@public.gmane.org>
>>>>> ---
>>>>> Documentation/devicetree/bindings/arm/amlogic.txt | 20 ++++++++++++++++++++
>>>>> 1 file changed, 20 insertions(+)
>>>>>
>>>>> diff --git a/Documentation/devicetree/bindings/arm/amlogic.txt b/Documentation/devicetree/bindings/arm/amlogic.txt
>>>>> index bfd5b55..b850985 100644
>>>>> --- a/Documentation/devicetree/bindings/arm/amlogic.txt
>>>>> +++ b/Documentation/devicetree/bindings/arm/amlogic.txt
>>>>> @@ -52,3 +52,23 @@ Board compatible values:
>>>>> - "amlogic,q201" (Meson gxm s912)
>>>>> - "nexbox,a95x" (Meson gxbb or Meson gxl s905x)
>>>>> - "nexbox,a1" (Meson gxm s912)
>>>>> +
>>>>> +Amlogic Meson GX SoCs Information
>>>>> +----------------------------------
>>>>> +
>>>>> +The Meson SoCs have a Product Register that allows to retrieve SoC type,
>>>>> +package and revision information. If present, a device node for this register
>>>>> +should be added.
>>>>> +
>>>>> +Required properties:
>>>>> + - compatible: For Meson GX SoCs, must be "amlogic,meson-gx-socinfo".
>>>>> + - reg: Base address and length of the register block.
>>>>> +
>>>>> +Examples
>>>>> +--------
>>>>> +
>>>>> + chipid@220 {
>>>>> + compatible = "amlogic,meson-gx-socinfo";
>>>>> + reg = <0x0 0x00220 0x0 0x4>;
>>>>> + };
>>>>> +
>>>>
>>>> The register location would hint that this is in the middle of some block of
>>>> random registers, i.e. a syscon or some unrelated device.
>>>>
>>>> Are you sure that "socinfo" is the actual name of the IP block and that
>>>> it only has a single 32-bit register?
>>>>
>>>> Arnd
>>>>
>>>
>>> Hi Arnd,
>>>
>>> I'm sorry I did not find any relevant registers in the docs or source code describing
>>> it in a specific block of registers, and no close enough register definitions either.
>>> They may be used by the secure firmware I imagine.
>>>
>>> For the register name, Amlogic refers it to "cpu_version" in their code, but it really
>>> gives some details on the whole SoC and package, and socinfo seems better.
>>
>> A register at address 0x220 seems a bit strange (unless there's ranges
>> you're not showing), but ROM code at this address would be fairly
>> typical. And putting version information into the ROM is also common.
>>
>> Rob
>>
>
> Hi Rob.
>
> Indeed it's part of a larger range :
> aobus: aobus@c8100000 {
> compatible = "simple-bus";
> reg = <0x0 0xc8100000 0x0 0x100000>;
> #address-cells = <2>;
> #size-cells = <2>;
> ranges = <0x0 0x0 0x0 0xc8100000 0x0 0x100000>;
>
>
> While scrubbing on the uboot source, I found a sort of block of registers dedicated to communicate with
> the secure firmware :
> AO_SEC_REG0 0x140
> AO_SEC_REG1 0x144
> AO_SEC_REG2 0x148
> AO_SEC_TMODE_PWD0 0x160
> AO_SEC_TMODE_PWD1 0x164
> AO_SEC_TMODE_PWD2 0x168
> AO_SEC_TMODE_PWD3 0x16C
> AO_SEC_SCRATCH 0x17C
> AO_SEC_JTAG_PWD0 0x180
> AO_SEC_JTAG_PWD1 0x184
> AO_SEC_JTAG_PWD2 0x188
> AO_SEC_JTAG_PWD3 0x18C
> AO_SEC_JTAG_SEC_CNTL 0x190
> AO_SEC_JTAG_PWD_ADDR0 0x194
> AO_SEC_JTAG_PWD_ADDR1 0x198
> AO_SEC_JTAG_PWD_ADDR2 0x19C
> AO_SEC_JTAG_PWD_ADDR3 0x1A0
> AO_SEC_SHARED_AHB_SRAM_REG0_0 0x1C0
> AO_SEC_SHARED_AHB_SRAM_REG0_1 0x1C4
> AO_SEC_SHARED_AHB_SRAM_REG0_2 0x1C8
> AO_SEC_SHARED_AHB_SRAM_REG1_0 0x1CC
> AO_SEC_SHARED_AHB_SRAM_REG1_1 0x1D0
> AO_SEC_SHARED_AHB_SRAM_REG1_2 0x1D4
> AO_SEC_SHARED_AHB_SRAM_REG2_0 0x1D8
> AO_SEC_SHARED_AHB_SRAM_REG2_1 0x1DC
> AO_SEC_SHARED_AHB_SRAM_REG2_2 0x1E0
> AO_SEC_SHARED_AHB_SRAM_REG3_0 0x1E4
> AO_SEC_SHARED_AHB_SRAM_REG3_1 0x1E8
> AO_SEC_SHARED_AHB_SRAM_REG3_2 0x1EC
> AO_SEC_AO_AHB_SRAM_REG0_0 0x1F0
> AO_SEC_AO_AHB_SRAM_REG0_1 0x1F4
> AO_SEC_AO_AHB_SRAM_REG1_0 0x1F8
> AO_SEC_AO_AHB_SRAM_REG1_1 0x1FC
> AO_SEC_SD_CFG8 0x220
> AO_SEC_SD_CFG9 0x224
> AO_SEC_SD_CFG10 0x228
> AO_SEC_SD_CFG11 0x22C
> AO_SEC_SD_CFG12 0x230
> AO_SEC_SD_CFG13 0x234
> AO_SEC_SD_CFG14 0x238
> AO_SEC_SD_CFG15 0x23C
> AO_SEC_GP_CFG0 0x240
> AO_SEC_GP_CFG1 0x244
> AO_SEC_GP_CFG2 0x248
> AO_SEC_GP_CFG3 0x24C
> AO_SEC_GP_CFG4 0x250
> AO_SEC_GP_CFG5 0x254
> AO_SEC_GP_CFG6 0x258
> AO_SEC_GP_CFG7 0x25C
> AO_SEC_GP_CFG8 0x260
> AO_SEC_GP_CFG9 0x264
> AO_SEC_GP_CFG10 0x268
> AO_SEC_GP_CFG11 0x26C
> AO_SEC_GP_CFG12 0x270
> AO_SEC_GP_CFG13 0x274
> AO_SEC_GP_CFG14 0x278
> AO_SEC_GP_CFG15 0x27C
>
>
> As you see, the register we use here is AO_SEC_SD_CFG8...
>
> Should I define all this block as simple-mfd and refer to it as a regmap ?
>
> aobus: aobus@c8100000 {
> compatible = "simple-bus";
> reg = <0x0 0xc8100000 0x0 0x100000>;
> #address-cells = <2>;
> #size-cells = <2>;
> ranges = <0x0 0x0 0x0 0xc8100000 0x0 0x100000>;
>
> ao_secure: ao-secure@140 {
> compatible = "amlogic,meson-gx-ao-secure", "simple-mfd";
> reg = <0x0 0x140 0x0 0x140>;
> };
> };
>
> chipid {
> compatible = "amlogic,meson-gx-socinfo";
> ao-secure = <&ao_secure>;
> chip-info-reg = <0xe0>;
Why even divide it up further in DT? IMO, describing single
registers/address in DT is too fine grained.
Rob
--
To unsubscribe from this list: send the line "unsubscribe devicetree" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
^ permalink raw reply
* Re: [PATCH v2 1/2] dt-bindings: Document the STM32 QSPI bindings
From: Rob Herring @ 2017-04-04 12:20 UTC (permalink / raw)
To: Ludovic BARRE
Cc: Cyrille Pitchen, Marek Vasut, David Woodhouse, Brian Norris,
Boris Brezillon, Richard Weinberger, Alexandre Torgue,
linux-mtd-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r@public.gmane.org,
linux-kernel-u79uwXL29TY76Z2rM5mHXA@public.gmane.org,
devicetree-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
In-Reply-To: <bd7cf1f8-e3b6-5752-47ef-2f54d56f81cc-qxv4g6HH51o@public.gmane.org>
On Tue, Apr 4, 2017 at 2:28 AM, Ludovic BARRE <ludovic.barre-qxv4g6HH51o@public.gmane.org> wrote:
> Hi Rob
>
> thanks for review
> my comments below
>
> br
> Ludo
>
> On 04/03/2017 06:57 PM, Rob Herring wrote:
>>
>> On Fri, Mar 31, 2017 at 07:02:03PM +0200, Ludovic Barre wrote:
>>>
>>> From: Ludovic Barre <ludovic.barre-qxv4g6HH51o@public.gmane.org>
>>>
>>> This patch adds documentation of device tree bindings for the STM32
>>> QSPI controller.
>>>
>>> Signed-off-by: Ludovic Barre <ludovic.barre-qxv4g6HH51o@public.gmane.org>
>>> ---
>>> .../devicetree/bindings/mtd/stm32-quadspi.txt | 45
>>> ++++++++++++++++++++++
>>> 1 file changed, 45 insertions(+)
>>> create mode 100644
>>> Documentation/devicetree/bindings/mtd/stm32-quadspi.txt
>>>
>>> diff --git a/Documentation/devicetree/bindings/mtd/stm32-quadspi.txt
>>> b/Documentation/devicetree/bindings/mtd/stm32-quadspi.txt
>>> new file mode 100644
>>> index 0000000..95a8ebd
>>> --- /dev/null
>>> +++ b/Documentation/devicetree/bindings/mtd/stm32-quadspi.txt
>>> @@ -0,0 +1,45 @@
>>> +* STMicroelectronics Quad Serial Peripheral Interface(QuadSPI)
>>> +
>>> +Required properties:
>>> +- compatible: should be "st,stm32f469-qspi"
>>> +- reg: contains the register location and length.
>>> + (optional) the memory mapping address and length
>>
>> Why optional? Either the h/w has it or doesn't. If some chips don't,
>> they should have a different compatible string.
>
> in fact, the stm32 qspi controller can operate in any of the following
> modes:
> -indirect mode: all the operations are performed using the qspi registers
> with read/write.
> -read memory-mapped mode: the external Flash memory is mapped to the
> microcontroller address space and is seen by the system as if it was
> an internal memory (use memcpy_fromio). this mode improve read throughput
>
> if qspi_mm is defined the qspi controller use read memory-mapped mode
> else the controller transfers in indirect mode.
You should always have the memory region defined because that's what
the h/w has. If you want another property to select the mode, then
perhaps that's fine. But why? Can't the OS figure out which to use?
Why would you ever not use memory mapped mode unless the driver
doesn't yet support it?
Rob
--
To unsubscribe from this list: send the line "unsubscribe devicetree" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
^ permalink raw reply
* Re: [PATCH V10 07/12] of/acpi: Configure dma operations at probe time for platform/amba/pci bus devices
From: Robin Murphy @ 2017-04-04 12:17 UTC (permalink / raw)
To: Sricharan R, will.deacon-5wv7dgnIgG8, joro-zLv9SwRftAIdnm+yROfE0A,
lorenzo.pieralisi-5wv7dgnIgG8,
iommu-cunTk1MwBs9QetFLy7KEm3xJsTq8ys+cHZ5vskTnxNA,
linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r,
linux-arm-msm-u79uwXL29TY76Z2rM5mHXA,
m.szyprowski-Sze3O3UU22JBDgjK7y7TUQ,
bhelgaas-hpIqsD4AKlfQT0dZR+AlfA, linux-pci-u79uwXL29TY76Z2rM5mHXA,
linux-acpi-u79uwXL29TY76Z2rM5mHXA, tn-nYOzD4b6Jr9Wk0Htik3J/w,
hanjun.guo-QSEj5FYQhm4dnm+yROfE0A, okaya-sgV2jX0FEOL9JmXXK+q4OQ,
robh+dt-DgEjT+Ai2ygdnm+yROfE0A,
frowand.list-Re5JQEeQqe8AvxtiuMwx3w,
devicetree-u79uwXL29TY76Z2rM5mHXA,
linux-kernel-u79uwXL29TY76Z2rM5mHXA, sudeep.holla-5wv7dgnIgG8,
rjw-LthD3rsA81gm4RdzfppkhA, lenb-DgEjT+Ai2ygdnm+yROfE0A,
catalin.marinas-5wv7dgnIgG8, arnd-r2nGTMty4D4,
linux-arch-u79uwXL29TY76Z2rM5mHXA,
gregkh-hQyY1W1yCW8ekmWlsbkhG0B+6BGkLq7r
In-Reply-To: <1491301105-5274-8-git-send-email-sricharan-sgV2jX0FEOL9JmXXK+q4OQ@public.gmane.org>
On 04/04/17 11:18, Sricharan R wrote:
> Configuring DMA ops at probe time will allow deferring device probe when
> the IOMMU isn't available yet. The dma_configure for the device is
> now called from the generic device_attach callback just before the
> bus/driver probe is called. This way, configuring the DMA ops for the
> device would be called at the same place for all bus_types, hence the
> deferred probing mechanism should work for all buses as well.
>
> pci_bus_add_devices (platform/amba)(_device_create/driver_register)
> | |
> pci_bus_add_device (device_add/driver_register)
> | |
> device_attach device_initial_probe
> | |
> __device_attach_driver __device_attach_driver
> |
> driver_probe_device
> |
> really_probe
> |
> dma_configure
>
> Similarly on the device/driver_unregister path __device_release_driver is
> called which inturn calls dma_deconfigure.
>
> This patch changes the dma ops configuration to probe time for
> both OF and ACPI based platform/amba/pci bus devices.
Reviewed-by: Robin Murphy <robin.murphy-5wv7dgnIgG8@public.gmane.org>
It's possible we could subsume {of,acpi}_dma_deconfigure() into
dma_deconfigure() entirely in future if it becomes clear that neither of
them will ever need to do anything firmware-specific, but I think for
now it's probably safer to keep the current symmetry - calling
arch_teardown_dma_ops() twice is benign (and even if it weren't, I'd say
it really should be!)
Robin.
> Tested-by: Marek Szyprowski <m.szyprowski-Sze3O3UU22JBDgjK7y7TUQ@public.gmane.org>
> Tested-by: Hanjun Guo <hanjun.guo-QSEj5FYQhm4dnm+yROfE0A@public.gmane.org>
> Acked-by: Bjorn Helgaas <bhelgaas-hpIqsD4AKlfQT0dZR+AlfA@public.gmane.org> (drivers/pci part)
> Acked-by: Rafael J. Wysocki <rafael.j.wysocki-ral2JQCrhuEAvxtiuMwx3w@public.gmane.org>
> Signed-off-by: Sricharan R <sricharan-sgV2jX0FEOL9JmXXK+q4OQ@public.gmane.org>
> ---
>
> [V10] Added dummy dma_(de)configure functions in case
> of !CONFIG_HAS_DMA to avoid build breaks.
>
> drivers/acpi/glue.c | 5 -----
> drivers/base/dd.c | 9 +++++++++
> drivers/base/dma-mapping.c | 40 ++++++++++++++++++++++++++++++++++++++++
> drivers/of/platform.c | 5 +----
> drivers/pci/probe.c | 28 ----------------------------
> include/linux/dma-mapping.h | 12 ++++++++++++
> 6 files changed, 62 insertions(+), 37 deletions(-)
>
> diff --git a/drivers/acpi/glue.c b/drivers/acpi/glue.c
> index fb19e1c..c05f241 100644
> --- a/drivers/acpi/glue.c
> +++ b/drivers/acpi/glue.c
> @@ -176,7 +176,6 @@ int acpi_bind_one(struct device *dev, struct acpi_device *acpi_dev)
> struct list_head *physnode_list;
> unsigned int node_id;
> int retval = -EINVAL;
> - enum dev_dma_attr attr;
>
> if (has_acpi_companion(dev)) {
> if (acpi_dev) {
> @@ -233,10 +232,6 @@ int acpi_bind_one(struct device *dev, struct acpi_device *acpi_dev)
> if (!has_acpi_companion(dev))
> ACPI_COMPANION_SET(dev, acpi_dev);
>
> - attr = acpi_get_dma_attr(acpi_dev);
> - if (attr != DEV_DMA_NOT_SUPPORTED)
> - acpi_dma_configure(dev, attr);
> -
> acpi_physnode_link_name(physical_node_name, node_id);
> retval = sysfs_create_link(&acpi_dev->dev.kobj, &dev->kobj,
> physical_node_name);
> diff --git a/drivers/base/dd.c b/drivers/base/dd.c
> index a1fbf55..4882f06 100644
> --- a/drivers/base/dd.c
> +++ b/drivers/base/dd.c
> @@ -19,6 +19,7 @@
>
> #include <linux/device.h>
> #include <linux/delay.h>
> +#include <linux/dma-mapping.h>
> #include <linux/module.h>
> #include <linux/kthread.h>
> #include <linux/wait.h>
> @@ -356,6 +357,10 @@ static int really_probe(struct device *dev, struct device_driver *drv)
> if (ret)
> goto pinctrl_bind_failed;
>
> + ret = dma_configure(dev);
> + if (ret)
> + goto dma_failed;
> +
> if (driver_sysfs_add(dev)) {
> printk(KERN_ERR "%s: driver_sysfs_add(%s) failed\n",
> __func__, dev_name(dev));
> @@ -417,6 +422,8 @@ static int really_probe(struct device *dev, struct device_driver *drv)
> goto done;
>
> probe_failed:
> + dma_deconfigure(dev);
> +dma_failed:
> if (dev->bus)
> blocking_notifier_call_chain(&dev->bus->p->bus_notifier,
> BUS_NOTIFY_DRIVER_NOT_BOUND, dev);
> @@ -826,6 +833,8 @@ static void __device_release_driver(struct device *dev, struct device *parent)
> drv->remove(dev);
>
> device_links_driver_cleanup(dev);
> + dma_deconfigure(dev);
> +
> devres_release_all(dev);
> dev->driver = NULL;
> dev_set_drvdata(dev, NULL);
> diff --git a/drivers/base/dma-mapping.c b/drivers/base/dma-mapping.c
> index efd71cf..449b948 100644
> --- a/drivers/base/dma-mapping.c
> +++ b/drivers/base/dma-mapping.c
> @@ -7,9 +7,11 @@
> * This file is released under the GPLv2.
> */
>
> +#include <linux/acpi.h>
> #include <linux/dma-mapping.h>
> #include <linux/export.h>
> #include <linux/gfp.h>
> +#include <linux/of_device.h>
> #include <linux/slab.h>
> #include <linux/vmalloc.h>
>
> @@ -341,3 +343,41 @@ void dma_common_free_remap(void *cpu_addr, size_t size, unsigned long vm_flags)
> vunmap(cpu_addr);
> }
> #endif
> +
> +/*
> + * Common configuration to enable DMA API use for a device
> + */
> +#include <linux/pci.h>
> +
> +int dma_configure(struct device *dev)
> +{
> + struct device *bridge = NULL, *dma_dev = dev;
> + enum dev_dma_attr attr;
> +
> + if (dev_is_pci(dev)) {
> + bridge = pci_get_host_bridge_device(to_pci_dev(dev));
> + dma_dev = bridge;
> + if (IS_ENABLED(CONFIG_OF) && dma_dev->parent &&
> + dma_dev->parent->of_node)
> + dma_dev = dma_dev->parent;
> + }
> +
> + if (dma_dev->of_node) {
> + of_dma_configure(dev, dma_dev->of_node);
> + } else if (has_acpi_companion(dma_dev)) {
> + attr = acpi_get_dma_attr(to_acpi_device_node(dma_dev->fwnode));
> + if (attr != DEV_DMA_NOT_SUPPORTED)
> + acpi_dma_configure(dev, attr);
> + }
> +
> + if (bridge)
> + pci_put_host_bridge_device(bridge);
> +
> + return 0;
> +}
> +
> +void dma_deconfigure(struct device *dev)
> +{
> + of_dma_deconfigure(dev);
> + acpi_dma_deconfigure(dev);
> +}
> diff --git a/drivers/of/platform.c b/drivers/of/platform.c
> index 5344db5..2aa4ebb 100644
> --- a/drivers/of/platform.c
> +++ b/drivers/of/platform.c
> @@ -22,6 +22,7 @@
> #include <linux/slab.h>
> #include <linux/of_address.h>
> #include <linux/of_device.h>
> +#include <linux/of_iommu.h>
> #include <linux/of_irq.h>
> #include <linux/of_platform.h>
> #include <linux/platform_device.h>
> @@ -186,11 +187,9 @@ static struct platform_device *of_platform_device_create_pdata(
>
> dev->dev.bus = &platform_bus_type;
> dev->dev.platform_data = platform_data;
> - of_dma_configure(&dev->dev, dev->dev.of_node);
> of_msi_configure(&dev->dev, dev->dev.of_node);
>
> if (of_device_add(dev) != 0) {
> - of_dma_deconfigure(&dev->dev);
> platform_device_put(dev);
> goto err_clear_flag;
> }
> @@ -248,7 +247,6 @@ static struct amba_device *of_amba_device_create(struct device_node *node,
> dev_set_name(&dev->dev, "%s", bus_id);
> else
> of_device_make_bus_id(&dev->dev);
> - of_dma_configure(&dev->dev, dev->dev.of_node);
>
> /* Allow the HW Peripheral ID to be overridden */
> prop = of_get_property(node, "arm,primecell-periphid", NULL);
> @@ -542,7 +540,6 @@ static int of_platform_device_destroy(struct device *dev, void *data)
> amba_device_unregister(to_amba_device(dev));
> #endif
>
> - of_dma_deconfigure(dev);
> of_node_clear_flag(dev->of_node, OF_POPULATED);
> of_node_clear_flag(dev->of_node, OF_POPULATED_BUS);
> return 0;
> diff --git a/drivers/pci/probe.c b/drivers/pci/probe.c
> index dfc9a27..5a8dd43 100644
> --- a/drivers/pci/probe.c
> +++ b/drivers/pci/probe.c
> @@ -1893,33 +1893,6 @@ static void pci_set_msi_domain(struct pci_dev *dev)
> dev_set_msi_domain(&dev->dev, d);
> }
>
> -/**
> - * pci_dma_configure - Setup DMA configuration
> - * @dev: ptr to pci_dev struct of the PCI device
> - *
> - * Function to update PCI devices's DMA configuration using the same
> - * info from the OF node or ACPI node of host bridge's parent (if any).
> - */
> -static void pci_dma_configure(struct pci_dev *dev)
> -{
> - struct device *bridge = pci_get_host_bridge_device(dev);
> -
> - if (IS_ENABLED(CONFIG_OF) &&
> - bridge->parent && bridge->parent->of_node) {
> - of_dma_configure(&dev->dev, bridge->parent->of_node);
> - } else if (has_acpi_companion(bridge)) {
> - struct acpi_device *adev = to_acpi_device_node(bridge->fwnode);
> - enum dev_dma_attr attr = acpi_get_dma_attr(adev);
> -
> - if (attr == DEV_DMA_NOT_SUPPORTED)
> - dev_warn(&dev->dev, "DMA not supported.\n");
> - else
> - acpi_dma_configure(&dev->dev, attr);
> - }
> -
> - pci_put_host_bridge_device(bridge);
> -}
> -
> void pci_device_add(struct pci_dev *dev, struct pci_bus *bus)
> {
> int ret;
> @@ -1933,7 +1906,6 @@ void pci_device_add(struct pci_dev *dev, struct pci_bus *bus)
> dev->dev.dma_mask = &dev->dma_mask;
> dev->dev.dma_parms = &dev->dma_parms;
> dev->dev.coherent_dma_mask = 0xffffffffull;
> - pci_dma_configure(dev);
>
> pci_set_dma_max_seg_size(dev, 65536);
> pci_set_dma_seg_boundary(dev, 0xffffffff);
> diff --git a/include/linux/dma-mapping.h b/include/linux/dma-mapping.h
> index 0977317..4f3eece 100644
> --- a/include/linux/dma-mapping.h
> +++ b/include/linux/dma-mapping.h
> @@ -728,6 +728,18 @@ void *dma_mark_declared_memory_occupied(struct device *dev,
> }
> #endif /* CONFIG_HAVE_GENERIC_DMA_COHERENT */
>
> +#ifdef CONFIG_HAS_DMA
> +int dma_configure(struct device *dev);
> +void dma_deconfigure(struct device *dev);
> +#else
> +static inline int dma_configure(struct device *dev)
> +{
> + return 0;
> +}
> +
> +static inline void dma_deconfigure(struct device *dev) {}
> +#endif
> +
> /*
> * Managed DMA API
> */
>
^ permalink raw reply
* [PATCH v3 08/11] dt-bindings: Add bindings for the Amlogic Meson dw-hdmi extension
From: Neil Armstrong @ 2017-04-04 12:15 UTC (permalink / raw)
To: airlied
Cc: devicetree, Neil Armstrong, linux-kernel, dri-devel,
linux-amlogic, linux-arm-kernel
In-Reply-To: <1491308131-22071-1-git-send-email-narmstrong@baylibre.com>
This binding describes the Amlogic Meson specific extension to the
Synopsys Designware HDMI Controller.
Acked-by: Rob Herring <robh@kernel.org>
Signed-off-by: Neil Armstrong <narmstrong@baylibre.com>
---
.../bindings/display/amlogic,meson-dw-hdmi.txt | 111 +++++++++++++++++++++
1 file changed, 111 insertions(+)
create mode 100644 Documentation/devicetree/bindings/display/amlogic,meson-dw-hdmi.txt
diff --git a/Documentation/devicetree/bindings/display/amlogic,meson-dw-hdmi.txt b/Documentation/devicetree/bindings/display/amlogic,meson-dw-hdmi.txt
new file mode 100644
index 0000000..7f040ed
--- /dev/null
+++ b/Documentation/devicetree/bindings/display/amlogic,meson-dw-hdmi.txt
@@ -0,0 +1,111 @@
+Amlogic specific extensions to the Synopsys Designware HDMI Controller
+======================================================================
+
+The Amlogic Meson Synopsys Designware Integration is composed of :
+- A Synopsys DesignWare HDMI Controller IP
+- A TOP control block controlling the Clocks and PHY
+- A custom HDMI PHY in order to convert video to TMDS signal
+ ___________________________________
+| HDMI TOP |<= HPD
+|___________________________________|
+| | |
+| Synopsys HDMI | HDMI PHY |=> TMDS
+| Controller |________________|
+|___________________________________|<=> DDC
+
+The HDMI TOP block only supports HPD sensing.
+The Synopsys HDMI Controller interrupt is routed through the
+TOP Block interrupt.
+Communication to the TOP Block and the Synopsys HDMI Controller is done
+via a pair of dedicated addr+read/write registers.
+The HDMI PHY is configured by registers in the HHI register block.
+
+Pixel data arrives in 4:4:4 format from the VENC block and the VPU HDMI mux
+selects either the ENCI encoder for the 576i or 480i formats or the ENCP
+encoder for all the other formats including interlaced HD formats.
+
+The VENC uses a DVI encoder on top of the ENCI or ENCP encoders to generate
+DVI timings for the HDMI controller.
+
+Amlogic Meson GXBB, GXL and GXM SoCs families embeds the Synopsys DesignWare
+HDMI TX IP version 2.01a with HDCP and I2C & S/PDIF
+audio source interfaces.
+
+Required properties:
+- compatible: value should be different for each SoC family as :
+ - GXBB (S905) : "amlogic,meson-gxbb-dw-hdmi"
+ - GXL (S905X, S905D) : "amlogic,meson-gxl-dw-hdmi"
+ - GXM (S912) : "amlogic,meson-gxm-dw-hdmi"
+ followed by the common "amlogic,meson-gx-dw-hdmi"
+- reg: Physical base address and length of the controller's registers.
+- interrupts: The HDMI interrupt number
+- clocks, clock-names : must have the phandles to the HDMI iahb and isfr clocks,
+ and the Amlogic Meson venci clocks as described in
+ Documentation/devicetree/bindings/clock/clock-bindings.txt,
+ the clocks are soc specific, the clock-names should be "iahb", "isfr", "venci"
+- resets, resets-names: must have the phandles to the HDMI apb, glue and phy
+ resets as described in :
+ Documentation/devicetree/bindings/reset/reset.txt,
+ the reset-names should be "hdmitx_apb", "hdmitx", "hdmitx_phy"
+
+Required nodes:
+
+The connections to the HDMI ports are modeled using the OF graph
+bindings specified in Documentation/devicetree/bindings/graph.txt.
+
+The following table lists for each supported model the port number
+corresponding to each HDMI output and input.
+
+ Port 0 Port 1
+-----------------------------------------
+ S905 (GXBB) VENC Input TMDS Output
+ S905X (GXL) VENC Input TMDS Output
+ S905D (GXL) VENC Input TMDS Output
+ S912 (GXM) VENC Input TMDS Output
+
+Example:
+
+hdmi-connector {
+ compatible = "hdmi-connector";
+ type = "a";
+
+ port {
+ hdmi_connector_in: endpoint {
+ remote-endpoint = <&hdmi_tx_tmds_out>;
+ };
+ };
+};
+
+hdmi_tx: hdmi-tx@c883a000 {
+ compatible = "amlogic,meson-gxbb-dw-hdmi", "amlogic,meson-gx-dw-hdmi";
+ reg = <0x0 0xc883a000 0x0 0x1c>;
+ interrupts = <GIC_SPI 57 IRQ_TYPE_EDGE_RISING>;
+ resets = <&reset RESET_HDMITX_CAPB3>,
+ <&reset RESET_HDMI_SYSTEM_RESET>,
+ <&reset RESET_HDMI_TX>;
+ reset-names = "hdmitx_apb", "hdmitx", "hdmitx_phy";
+ clocks = <&clkc CLKID_HDMI_PCLK>,
+ <&clkc CLKID_CLK81>,
+ <&clkc CLKID_GCLK_VENCI_INT0>;
+ clock-names = "isfr", "iahb", "venci";
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ /* VPU VENC Input */
+ hdmi_tx_venc_port: port@0 {
+ reg = <0>;
+
+ hdmi_tx_in: endpoint {
+ remote-endpoint = <&hdmi_tx_out>;
+ };
+ };
+
+ /* TMDS Output */
+ hdmi_tx_tmds_port: port@1 {
+ reg = <1>;
+
+ hdmi_tx_tmds_out: endpoint {
+ remote-endpoint = <&hdmi_connector_in>;
+ };
+ };
+};
--
1.9.1
_______________________________________________
dri-devel mailing list
dri-devel@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/dri-devel
^ permalink raw reply related
* [PATCH 1/3 v5] iio: xoadc: augment DT bindings a bit
From: Linus Walleij @ 2017-04-04 12:08 UTC (permalink / raw)
To: Jonathan Cameron, linux-iio-u79uwXL29TY76Z2rM5mHXA
Cc: Linus Walleij, devicetree-u79uwXL29TY76Z2rM5mHXA
In order to accommodate in a logical manner for the premuxed channels
in PM8921 and the similarly addressed channels in later PMICs, we
need a twocell arrangement with premux and analog mux setting as
a tuple to uniquely identify a hardware channel.
These bindings are not yet in use, so it should be fine to augment
them before we actually start using it in drivers and device trees.
This scheme came out of lengthy discussions and reverse-engineering
and reading of the few information sources we have.
Cc: devicetree-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
Acked-by: Rob Herring <robh+dt-DgEjT+Ai2ygdnm+yROfE0A@public.gmane.org>
Suggested-by: Björn Andersson <bjorn.andersson-QSEj5FYQhm4dnm+yROfE0A@public.gmane.org>
Signed-off-by: Linus Walleij <linus.walleij-QSEj5FYQhm4dnm+yROfE0A@public.gmane.org>
---
ChangeLog v3->v5:
- Some nitpicky spelling fixes. Added Rob's ACK.
ChangeLog v2->v3:
- Drop leading zeroes on unit addresses.
ChangeLog v1->v2:
- Name nodes with <01 02> in a foo@0102 pattern.
- Minor spelling nits.
- Delete flimsy leftover docs from an interrim development path.
---
.../bindings/iio/adc/qcom,pm8xxx-xoadc.txt | 76 ++++++++++++----------
1 file changed, 42 insertions(+), 34 deletions(-)
diff --git a/Documentation/devicetree/bindings/iio/adc/qcom,pm8xxx-xoadc.txt b/Documentation/devicetree/bindings/iio/adc/qcom,pm8xxx-xoadc.txt
index 53cd146d8096..3ae06127789e 100644
--- a/Documentation/devicetree/bindings/iio/adc/qcom,pm8xxx-xoadc.txt
+++ b/Documentation/devicetree/bindings/iio/adc/qcom,pm8xxx-xoadc.txt
@@ -19,32 +19,42 @@ Required properties:
with PMIC variant but is typically something like 2.2 or 1.8V.
The following required properties are standard for IO channels, see
-iio-bindings.txt for more details:
+iio-bindings.txt for more details, but notice that this particular
+ADC has a special addressing scheme that require two cells for
+identifying each ADC channel:
-- #address-cells: should be set to <1>
+- #address-cells: should be set to <2>, the first cell is the
+ prescaler (on PM8058) or premux (on PM8921) with two valid bits
+ so legal values are 0x00, 0x01 or 0x02. The second cell
+ is the main analog mux setting (0x00..0x0f). The combination
+ of prescaler/premux and analog mux uniquely addresses a hardware
+ channel on all systems.
- #size-cells: should be set to <0>
-- #io-channel-cells: should be set to <1>
+- #io-channel-cells: should be set to <2>, again the cells are
+ precaler or premux followed by the analog muxing line.
- interrupts: should refer to the parent PMIC interrupt controller
and reference the proper ADC interrupt.
Required subnodes:
-The ADC channels are configured as subnodes of the ADC. Since some of
-them are used for calibrating the ADC, these nodes are compulsory:
+The ADC channels are configured as subnodes of the ADC.
+
+Since some of them are used for calibrating the ADC, these nodes are
+compulsory:
adc-channel@c {
- reg = <0x0c>;
+ reg = <0x00 0x0c>;
};
adc-channel@d {
- reg = <0x0d>;
+ reg = <0x00 0x0d>;
};
adc-channel@f {
- reg = <0x0f>;
+ reg = <0x00 0x0f>;
};
These three nodes are used for absolute and ratiometric calibration
@@ -52,13 +62,13 @@ and only need to have these reg values: they are by hardware definition
1:1 ratio converters that sample 625, 1250 and 0 milliV and create
an interpolation calibration for all other ADCs.
-Optional subnodes: any channels other than channel 0x0c, 0x0d and
-0x0f are optional.
+Optional subnodes: any channels other than channels [0x00 0x0c],
+[0x00 0x0d] and [0x00 0x0f] are optional.
Required channel node properties:
- reg: should contain the hardware channel number in the range
- 0 .. 0x0f (4 bits). The hardware only supports 16 channels.
+ 0 .. 0xff (8 bits).
Optional channel node properties:
@@ -94,56 +104,54 @@ Example:
xoadc: xoadc@197 {
compatible = "qcom,pm8058-adc";
reg = <0x197>;
- interrupt-parent = <&pm8058>;
- interrupts = <76 1>;
- #address-cells = <1>;
+ interrupts-extended = <&pm8058 76 IRQ_TYPE_EDGE_RISING>;
+ #address-cells = <2>;
#size-cells = <0>;
- #io-channel-cells = <1>;
+ #io-channel-cells = <2>;
vcoin: adc-channel@0 {
- reg = <0x00>;
+ reg = <0x00 0x00>;
};
vbat: adc-channel@1 {
- reg = <0x01>;
+ reg = <0x00 0x01>;
};
dcin: adc-channel@2 {
- reg = <0x02>;
+ reg = <0x00 0x02>;
};
ichg: adc-channel@3 {
- reg = <0x03>;
+ reg = <0x00 0x03>;
};
vph_pwr: adc-channel@4 {
- reg = <0x04>;
+ reg = <0x00 0x04>;
};
usb_vbus: adc-channel@a {
- reg = <0x0a>;
+ reg = <0x00 0x0a>;
};
die_temp: adc-channel@b {
- reg = <0x0b>;
+ reg = <0x00 0x0b>;
};
ref_625mv: adc-channel@c {
- reg = <0x0c>;
+ reg = <0x00 0x0c>;
};
ref_1250mv: adc-channel@d {
- reg = <0x0d>;
+ reg = <0x00 0x0d>;
};
ref_325mv: adc-channel@e {
- reg = <0x0e>;
+ reg = <0x00 0x0e>;
};
ref_muxoff: adc-channel@f {
- reg = <0x0f>;
+ reg = <0x00 0x0f>;
};
};
-
/* IIO client node */
iio-hwmon {
compatible = "iio-hwmon";
- io-channels = <&xoadc 0x01>, /* Battery */
- <&xoadc 0x02>, /* DC in (charger) */
- <&xoadc 0x04>, /* VPH the main system voltage */
- <&xoadc 0x0b>, /* Die temperature */
- <&xoadc 0x0c>, /* Reference voltage 1.25V */
- <&xoadc 0x0d>, /* Reference voltage 0.625V */
- <&xoadc 0x0e>; /* Reference voltage 0.325V */
+ io-channels = <&xoadc 0x00 0x01>, /* Battery */
+ <&xoadc 0x00 0x02>, /* DC in (charger) */
+ <&xoadc 0x00 0x04>, /* VPH the main system voltage */
+ <&xoadc 0x00 0x0b>, /* Die temperature */
+ <&xoadc 0x00 0x0c>, /* Reference voltage 1.25V */
+ <&xoadc 0x00 0x0d>, /* Reference voltage 0.625V */
+ <&xoadc 0x00 0x0e>; /* Reference voltage 0.325V */
};
--
2.9.3
--
To unsubscribe from this list: send the line "unsubscribe devicetree" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
^ permalink raw reply related
* Re: [PATCH v2 08/13] ARM64: dts: meson-gx: Add shared CMA dma memory pool
From: Kevin Hilman @ 2017-04-04 11:57 UTC (permalink / raw)
To: Neil Armstrong
Cc: devicetree, linux-kernel, dri-devel, linux-amlogic,
linux-arm-kernel
In-Reply-To: <43dd4aec-7002-5844-2e34-8507860a8268@baylibre.com>
Neil Armstrong <narmstrong@baylibre.com> writes:
> On 03/21/2017 04:25 PM, Neil Armstrong wrote:
>> The HDMI modes needs more CMA memory to be reserved at boot-time.
>>
>> Signed-off-by: Neil Armstrong <narmstrong@baylibre.com>
[...]
> Hi Kevin,
>
> Please take this one for the amlogic arm-soc DT tree.
>
Applied to v4.12/dt64,
Kevin
_______________________________________________
dri-devel mailing list
dri-devel@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/dri-devel
^ permalink raw reply
* Re: [PATCH v2 09/13] ARM64: dts: meson-gx: Add support for HDMI output
From: Kevin Hilman @ 2017-04-04 11:57 UTC (permalink / raw)
To: Neil Armstrong
Cc: devicetree, linux-kernel, dri-devel, linux-amlogic,
linux-arm-kernel
In-Reply-To: <be91a6f7-19ad-5d50-4f0c-03e2821493d4@baylibre.com>
Neil Armstrong <narmstrong@baylibre.com> writes:
> On 03/21/2017 04:25 PM, Neil Armstrong wrote:
>> Add HDMI output and connector nodes.
>>
>> Signed-off-by: Neil Armstrong <narmstrong@baylibre.com>
[...]
>
> Hi Kevin,
>
> Please take this one for the amlogic arm-soc DT tree.
>
Applied to v4.12/dt64,
Kevin
_______________________________________________
dri-devel mailing list
dri-devel@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/dri-devel
^ permalink raw reply
* Re: [PATCH v3 5/7] mfd: Add Device Tree bindings document for TI tps6105x chip
From: Javier Martinez Canillas @ 2017-04-04 11:48 UTC (permalink / raw)
To: Lee Jones
Cc: linux-kernel-u79uwXL29TY76Z2rM5mHXA,
devicetree-u79uwXL29TY76Z2rM5mHXA, Rob Herring, Mark Rutland
In-Reply-To: <20170404082739.6w6ltgdr2mgaqq4l@dell>
Hello Lee,
On 04/04/2017 04:27 AM, Lee Jones wrote:
> On Mon, 03 Apr 2017, Javier Martinez Canillas wrote:
>
>> Hello Lee,
>>
>> On 04/03/2017 07:15 AM, Lee Jones wrote:
>>
>> [snip]
>>
>>>> +
>>>> +The TP61050/TPS61052 is a high-power "white LED driver". This boost converter
>>>> +is also used for other things than white LEDs, and also contains a GPIO pin.
>>>
>>> What functions does it offer?
>>>
>>
>> Same comment than before, I'm not really familiar with this driver. But I'll
>> look what are the MFD cell instantiated to better understand dev functions
>> and expand this documentation accordingly.
>
> Writing documentation for H/W you are unfamiliar with is a bad idea IMHO.
>
I just wanted to add an OF device ID table to the driver to make sure the
driver won't have a regression when the I2C core reports an OF modalias
but was asked to also write a DT binding doc in this case...
I'm happy to drop the DT binding doc patch and someone more familiar to do
it as a follow up.
Best regards,
--
Javier Martinez Canillas
Open Source Group
Samsung Research America
--
To unsubscribe from this list: send the line "unsubscribe devicetree" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
^ permalink raw reply
* Re: [PATCH V10 12/12] ACPI/IORT: Remove linker section for IORT entries probing
From: Robin Murphy @ 2017-04-04 11:33 UTC (permalink / raw)
To: Sricharan R, will.deacon, joro, lorenzo.pieralisi, iommu,
linux-arm-kernel, linux-arm-msm, m.szyprowski, bhelgaas,
linux-pci, linux-acpi, tn, hanjun.guo, okaya, robh+dt,
frowand.list, devicetree, linux-kernel, sudeep.holla, rjw, lenb,
catalin.marinas, arnd, linux-arch, gregkh
In-Reply-To: <1491301105-5274-13-git-send-email-sricharan@codeaurora.org>
On 04/04/17 11:18, Sricharan R wrote:
> From: Lorenzo Pieralisi <lorenzo.pieralisi@arm.com>
>
> The IORT linker section introduced by commit 34ceea275f62
> ("ACPI/IORT: Introduce linker section for IORT entries probing")
> was needed to make sure SMMU drivers are registered (and therefore
> probed) in the kernel before devices using the SMMU have a chance
> to probe in turn.
>
> Through the introduction of deferred IOMMU configuration the linker
> section based IORT probing infrastructure is not needed any longer, in
> that device/SMMU probe dependencies are managed through the probe
> deferral mechanism, making the IORT linker section infrastructure
> unused, so that it can be removed.
>
> Remove the unused IORT linker section probing infrastructure
> from the kernel to complete the ACPI IORT IOMMU configure probe
> deferral mechanism implementation.
Reviewed-by: Robin Murphy <robin.murphy@arm.com>
> Tested-by: Hanjun Guo <hanjun.guo@linaro.org>
> Signed-off-by: Lorenzo Pieralisi <lorenzo.pieralisi@arm.com>
> Cc: Robin Murphy <robin.murphy@arm.com>
> Cc: Sricharan R <sricharan@codeaurora.org>
> ---
> drivers/acpi/arm64/iort.c | 2 --
> include/asm-generic/vmlinux.lds.h | 1 -
> include/linux/acpi_iort.h | 3 ---
> 3 files changed, 6 deletions(-)
>
> diff --git a/drivers/acpi/arm64/iort.c b/drivers/acpi/arm64/iort.c
> index e323ece..e7b1940 100644
> --- a/drivers/acpi/arm64/iort.c
> +++ b/drivers/acpi/arm64/iort.c
> @@ -1000,6 +1000,4 @@ void __init acpi_iort_init(void)
> }
>
> iort_init_platform_devices();
> -
> - acpi_probe_device_table(iort);
> }
> diff --git a/include/asm-generic/vmlinux.lds.h b/include/asm-generic/vmlinux.lds.h
> index 0968d13..9faa26c 100644
> --- a/include/asm-generic/vmlinux.lds.h
> +++ b/include/asm-generic/vmlinux.lds.h
> @@ -566,7 +566,6 @@
> IRQCHIP_OF_MATCH_TABLE() \
> ACPI_PROBE_TABLE(irqchip) \
> ACPI_PROBE_TABLE(clksrc) \
> - ACPI_PROBE_TABLE(iort) \
> EARLYCON_TABLE()
>
> #define INIT_TEXT \
> diff --git a/include/linux/acpi_iort.h b/include/linux/acpi_iort.h
> index 77e0809..f167e1d04 100644
> --- a/include/linux/acpi_iort.h
> +++ b/include/linux/acpi_iort.h
> @@ -52,7 +52,4 @@ const struct iommu_ops *iort_iommu_configure(struct device *dev)
> { return NULL; }
> #endif
>
> -#define IORT_ACPI_DECLARE(name, table_id, fn) \
> - ACPI_DECLARE_PROBE_ENTRY(iort, name, table_id, 0, NULL, 0, fn)
> -
> #endif /* __ACPI_IORT_H__ */
>
^ permalink raw reply
* Re: [PATCH V10 09/12] drivers: acpi: Handle IOMMU lookup failure with deferred probing or error
From: Robin Murphy @ 2017-04-04 11:31 UTC (permalink / raw)
To: Sricharan R, will.deacon, joro, lorenzo.pieralisi, iommu,
linux-arm-kernel, linux-arm-msm, m.szyprowski, bhelgaas,
linux-pci, linux-acpi, tn, hanjun.guo, okaya, robh+dt,
frowand.list, devicetree, linux-kernel, sudeep.holla, rjw, lenb,
catalin.marinas, arnd, linux-arch, gregkh
In-Reply-To: <1491301105-5274-10-git-send-email-sricharan@codeaurora.org>
On 04/04/17 11:18, Sricharan R wrote:
> This is an equivalent to the DT's handling of the iommu master's probe
> with deferred probing when the corrsponding iommu is not probed yet.
> The lack of a registered IOMMU can be caused by the lack of a driver for
> the IOMMU, the IOMMU device probe not having been performed yet, having
> been deferred, or having failed.
>
> The first case occurs when the firmware describes the bus master and
> IOMMU topology correctly but no device driver exists for the IOMMU yet
> or the device driver has not been compiled in. Return NULL, the caller
> will configure the device without an IOMMU.
>
> The second and third cases are handled by deferring the probe of the bus
> master device which will eventually get reprobed after the IOMMU.
>
> The last case is currently handled by deferring the probe of the bus
> master device as well. A mechanism to either configure the bus master
> device without an IOMMU or to fail the bus master device probe depending
> on whether the IOMMU is optional or mandatory would be a good
> enhancement.
I think we really have caught everything now...
Reviewed-by: Robin Murphy <robin.murphy@arm.com>
> Tested-by: Hanjun Guo <hanjun.guo@linaro.org>
> [Lorenzo: Added fixes for dma_coherent_mask overflow, acpi_dma_configure
> called multiple times for same device]
> Signed-off-by: Lorenzo Pieralisi <lorenzo.pieralisi@arm.com>
> Signed-off-by: Sricharan R <sricharan@codeaurora.org>
> ---
>
> [V10] Added Lorenzo's ACPI fix for coherent_dma_mask overflow
> and the fix for dma_configure getting called more than
> once for the same device.
>
> drivers/acpi/arm64/iort.c | 33 ++++++++++++++++++++++++++++++++-
> drivers/acpi/scan.c | 11 ++++++++---
> drivers/base/dma-mapping.c | 2 +-
> include/acpi/acpi_bus.h | 2 +-
> include/linux/acpi.h | 7 +++++--
> 5 files changed, 47 insertions(+), 8 deletions(-)
>
> diff --git a/drivers/acpi/arm64/iort.c b/drivers/acpi/arm64/iort.c
> index 3dd9ec3..e323ece 100644
> --- a/drivers/acpi/arm64/iort.c
> +++ b/drivers/acpi/arm64/iort.c
> @@ -543,6 +543,14 @@ static const struct iommu_ops *iort_iommu_xlate(struct device *dev,
> const struct iommu_ops *ops = NULL;
> int ret = -ENODEV;
> struct fwnode_handle *iort_fwnode;
> + struct iommu_fwspec *fwspec = dev->iommu_fwspec;
> +
> + /*
> + * If we already translated the fwspec there
> + * is nothing left to do, return the iommu_ops.
> + */
> + if (fwspec && fwspec->ops)
> + return fwspec->ops;
>
> if (node) {
> iort_fwnode = iort_get_fwnode(node);
> @@ -550,8 +558,17 @@ static const struct iommu_ops *iort_iommu_xlate(struct device *dev,
> return NULL;
>
> ops = iommu_ops_from_fwnode(iort_fwnode);
> + /*
> + * If the ops look-up fails, this means that either
> + * the SMMU drivers have not been probed yet or that
> + * the SMMU drivers are not built in the kernel;
> + * Depending on whether the SMMU drivers are built-in
> + * in the kernel or not, defer the IOMMU configuration
> + * or just abort it.
> + */
> if (!ops)
> - return NULL;
> + return iort_iommu_driver_enabled(node->type) ?
> + ERR_PTR(-EPROBE_DEFER) : NULL;
>
> ret = arm_smmu_iort_xlate(dev, streamid, iort_fwnode, ops);
> }
> @@ -625,12 +642,26 @@ const struct iommu_ops *iort_iommu_configure(struct device *dev)
>
> while (parent) {
> ops = iort_iommu_xlate(dev, parent, streamid);
> + if (IS_ERR_OR_NULL(ops))
> + return ops;
>
> parent = iort_node_get_id(node, &streamid,
> IORT_IOMMU_TYPE, i++);
> }
> }
>
> + /*
> + * If we have reason to believe the IOMMU driver missed the initial
> + * add_device callback for dev, replay it to get things in order.
> + */
> + if (!IS_ERR_OR_NULL(ops) && ops->add_device &&
> + dev->bus && !dev->iommu_group) {
> + int err = ops->add_device(dev);
> +
> + if (err)
> + ops = ERR_PTR(err);
> + }
> +
> return ops;
> }
>
> diff --git a/drivers/acpi/scan.c b/drivers/acpi/scan.c
> index 1926918..2a513cc 100644
> --- a/drivers/acpi/scan.c
> +++ b/drivers/acpi/scan.c
> @@ -1373,20 +1373,25 @@ enum dev_dma_attr acpi_get_dma_attr(struct acpi_device *adev)
> * @dev: The pointer to the device
> * @attr: device dma attributes
> */
> -void acpi_dma_configure(struct device *dev, enum dev_dma_attr attr)
> +int acpi_dma_configure(struct device *dev, enum dev_dma_attr attr)
> {
> const struct iommu_ops *iommu;
> + u64 size;
>
> iort_set_dma_mask(dev);
>
> iommu = iort_iommu_configure(dev);
> + if (IS_ERR(iommu))
> + return PTR_ERR(iommu);
>
> + size = max(dev->coherent_dma_mask, dev->coherent_dma_mask + 1);
> /*
> * Assume dma valid range starts at 0 and covers the whole
> * coherent_dma_mask.
> */
> - arch_setup_dma_ops(dev, 0, dev->coherent_dma_mask + 1, iommu,
> - attr == DEV_DMA_COHERENT);
> + arch_setup_dma_ops(dev, 0, size, iommu, attr == DEV_DMA_COHERENT);
> +
> + return 0;
> }
> EXPORT_SYMBOL_GPL(acpi_dma_configure);
>
> diff --git a/drivers/base/dma-mapping.c b/drivers/base/dma-mapping.c
> index 82bd45c..755a2b5 100644
> --- a/drivers/base/dma-mapping.c
> +++ b/drivers/base/dma-mapping.c
> @@ -368,7 +368,7 @@ int dma_configure(struct device *dev)
> } else if (has_acpi_companion(dma_dev)) {
> attr = acpi_get_dma_attr(to_acpi_device_node(dma_dev->fwnode));
> if (attr != DEV_DMA_NOT_SUPPORTED)
> - acpi_dma_configure(dev, attr);
> + ret = acpi_dma_configure(dev, attr);
> }
>
> if (bridge)
> diff --git a/include/acpi/acpi_bus.h b/include/acpi/acpi_bus.h
> index ef0ae8a..2a9a5de 100644
> --- a/include/acpi/acpi_bus.h
> +++ b/include/acpi/acpi_bus.h
> @@ -575,7 +575,7 @@ struct acpi_pci_root {
>
> bool acpi_dma_supported(struct acpi_device *adev);
> enum dev_dma_attr acpi_get_dma_attr(struct acpi_device *adev);
> -void acpi_dma_configure(struct device *dev, enum dev_dma_attr attr);
> +int acpi_dma_configure(struct device *dev, enum dev_dma_attr attr);
> void acpi_dma_deconfigure(struct device *dev);
>
> struct acpi_device *acpi_find_child_device(struct acpi_device *parent,
> diff --git a/include/linux/acpi.h b/include/linux/acpi.h
> index 9b05886..79d06ef6 100644
> --- a/include/linux/acpi.h
> +++ b/include/linux/acpi.h
> @@ -762,8 +762,11 @@ static inline enum dev_dma_attr acpi_get_dma_attr(struct acpi_device *adev)
> return DEV_DMA_NOT_SUPPORTED;
> }
>
> -static inline void acpi_dma_configure(struct device *dev,
> - enum dev_dma_attr attr) { }
> +static inline int acpi_dma_configure(struct device *dev,
> + enum dev_dma_attr attr)
> +{
> + return 0;
> +}
>
> static inline void acpi_dma_deconfigure(struct device *dev) { }
>
>
^ permalink raw reply
* Re: [PATCH V10 08/12] iommu: of: Handle IOMMU lookup failure with deferred probing or error
From: Robin Murphy @ 2017-04-04 11:24 UTC (permalink / raw)
To: Sricharan R, will.deacon, joro, lorenzo.pieralisi, iommu,
linux-arm-kernel, linux-arm-msm, m.szyprowski, bhelgaas,
linux-pci, linux-acpi, tn, hanjun.guo, okaya, robh+dt,
frowand.list, devicetree, linux-kernel, sudeep.holla, rjw, lenb,
catalin.marinas, arnd, linux-arch, gregkh
In-Reply-To: <1491301105-5274-9-git-send-email-sricharan@codeaurora.org>
On 04/04/17 11:18, Sricharan R wrote:
> From: Laurent Pinchart <laurent.pinchart+renesas@ideasonboard.com>
>
> Failures to look up an IOMMU when parsing the DT iommus property need to
> be handled separately from the .of_xlate() failures to support deferred
> probing.
>
> The lack of a registered IOMMU can be caused by the lack of a driver for
> the IOMMU, the IOMMU device probe not having been performed yet, having
> been deferred, or having failed.
>
> The first case occurs when the device tree describes the bus master and
> IOMMU topology correctly but no device driver exists for the IOMMU yet
> or the device driver has not been compiled in. Return NULL, the caller
> will configure the device without an IOMMU.
>
> The second and third cases are handled by deferring the probe of the bus
> master device which will eventually get reprobed after the IOMMU.
>
> The last case is currently handled by deferring the probe of the bus
> master device as well. A mechanism to either configure the bus master
> device without an IOMMU or to fail the bus master device probe depending
> on whether the IOMMU is optional or mandatory would be a good
> enhancement.
Reviewed-by: Robin Murphy <robin.murphy@arm.com>
> Tested-by: Marek Szyprowski <m.szyprowski@samsung.com>
> Signed-off-by: Laurent Pichart <laurent.pinchart+renesas@ideasonboard.com>
> Signed-off-by: Sricharan R <sricharan@codeaurora.org>
> ---
> drivers/base/dma-mapping.c | 5 +++--
> drivers/iommu/of_iommu.c | 4 ++--
> drivers/of/device.c | 7 ++++++-
> include/linux/of_device.h | 9 ++++++---
> 4 files changed, 17 insertions(+), 8 deletions(-)
>
> diff --git a/drivers/base/dma-mapping.c b/drivers/base/dma-mapping.c
> index 449b948..82bd45c 100644
> --- a/drivers/base/dma-mapping.c
> +++ b/drivers/base/dma-mapping.c
> @@ -353,6 +353,7 @@ int dma_configure(struct device *dev)
> {
> struct device *bridge = NULL, *dma_dev = dev;
> enum dev_dma_attr attr;
> + int ret = 0;
>
> if (dev_is_pci(dev)) {
> bridge = pci_get_host_bridge_device(to_pci_dev(dev));
> @@ -363,7 +364,7 @@ int dma_configure(struct device *dev)
> }
>
> if (dma_dev->of_node) {
> - of_dma_configure(dev, dma_dev->of_node);
> + ret = of_dma_configure(dev, dma_dev->of_node);
> } else if (has_acpi_companion(dma_dev)) {
> attr = acpi_get_dma_attr(to_acpi_device_node(dma_dev->fwnode));
> if (attr != DEV_DMA_NOT_SUPPORTED)
> @@ -373,7 +374,7 @@ int dma_configure(struct device *dev)
> if (bridge)
> pci_put_host_bridge_device(bridge);
>
> - return 0;
> + return ret;
> }
>
> void dma_deconfigure(struct device *dev)
> diff --git a/drivers/iommu/of_iommu.c b/drivers/iommu/of_iommu.c
> index c8be889..9f44ee8 100644
> --- a/drivers/iommu/of_iommu.c
> +++ b/drivers/iommu/of_iommu.c
> @@ -236,7 +236,7 @@ const struct iommu_ops *of_iommu_configure(struct device *dev,
> ops = ERR_PTR(err);
> }
>
> - return IS_ERR(ops) ? NULL : ops;
> + return ops;
> }
>
> static int __init of_iommu_init(void)
> @@ -247,7 +247,7 @@ static int __init of_iommu_init(void)
> for_each_matching_node_and_match(np, matches, &match) {
> const of_iommu_init_fn init_fn = match->data;
>
> - if (init_fn(np))
> + if (init_fn && init_fn(np))
> pr_err("Failed to initialise IOMMU %s\n",
> of_node_full_name(np));
> }
> diff --git a/drivers/of/device.c b/drivers/of/device.c
> index c2ae6bb..bea8aec 100644
> --- a/drivers/of/device.c
> +++ b/drivers/of/device.c
> @@ -82,7 +82,7 @@ int of_device_add(struct platform_device *ofdev)
> * can use a platform bus notifier and handle BUS_NOTIFY_ADD_DEVICE events
> * to fix up DMA configuration.
> */
> -void of_dma_configure(struct device *dev, struct device_node *np)
> +int of_dma_configure(struct device *dev, struct device_node *np)
> {
> u64 dma_addr, paddr, size;
> int ret;
> @@ -129,10 +129,15 @@ void of_dma_configure(struct device *dev, struct device_node *np)
> coherent ? " " : " not ");
>
> iommu = of_iommu_configure(dev, np);
> + if (IS_ERR(iommu))
> + return PTR_ERR(iommu);
> +
> dev_dbg(dev, "device is%sbehind an iommu\n",
> iommu ? " " : " not ");
>
> arch_setup_dma_ops(dev, dma_addr, size, iommu, coherent);
> +
> + return 0;
> }
> EXPORT_SYMBOL_GPL(of_dma_configure);
>
> diff --git a/include/linux/of_device.h b/include/linux/of_device.h
> index af98455..2cacdd8 100644
> --- a/include/linux/of_device.h
> +++ b/include/linux/of_device.h
> @@ -55,7 +55,7 @@ static inline struct device_node *of_cpu_device_node_get(int cpu)
> return of_node_get(cpu_dev->of_node);
> }
>
> -void of_dma_configure(struct device *dev, struct device_node *np);
> +int of_dma_configure(struct device *dev, struct device_node *np);
> void of_dma_deconfigure(struct device *dev);
> #else /* CONFIG_OF */
>
> @@ -104,8 +104,11 @@ static inline struct device_node *of_cpu_device_node_get(int cpu)
> {
> return NULL;
> }
> -static inline void of_dma_configure(struct device *dev, struct device_node *np)
> -{}
> +
> +static inline int of_dma_configure(struct device *dev, struct device_node *np)
> +{
> + return 0;
> +}
> static inline void of_dma_deconfigure(struct device *dev)
> {}
> #endif /* CONFIG_OF */
>
^ permalink raw reply
* Re: [PATCH V10 06/12] of: device: Fix overflow of coherent_dma_mask
From: Robin Murphy @ 2017-04-04 11:10 UTC (permalink / raw)
To: Sricharan R, will.deacon-5wv7dgnIgG8, joro-zLv9SwRftAIdnm+yROfE0A,
lorenzo.pieralisi-5wv7dgnIgG8,
iommu-cunTk1MwBs9QetFLy7KEm3xJsTq8ys+cHZ5vskTnxNA,
linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r,
linux-arm-msm-u79uwXL29TY76Z2rM5mHXA,
m.szyprowski-Sze3O3UU22JBDgjK7y7TUQ,
bhelgaas-hpIqsD4AKlfQT0dZR+AlfA, linux-pci-u79uwXL29TY76Z2rM5mHXA,
linux-acpi-u79uwXL29TY76Z2rM5mHXA, tn-nYOzD4b6Jr9Wk0Htik3J/w,
hanjun.guo-QSEj5FYQhm4dnm+yROfE0A, okaya-sgV2jX0FEOL9JmXXK+q4OQ,
robh+dt-DgEjT+Ai2ygdnm+yROfE0A,
frowand.list-Re5JQEeQqe8AvxtiuMwx3w,
devicetree-u79uwXL29TY76Z2rM5mHXA,
linux-kernel-u79uwXL29TY76Z2rM5mHXA, sudeep.holla-5wv7dgnIgG8,
rjw-LthD3rsA81gm4RdzfppkhA, lenb-DgEjT+Ai2ygdnm+yROfE0A,
catalin.marinas-5wv7dgnIgG8, arnd-r2nGTMty4D4,
linux-arch-u79uwXL29TY76Z2rM5mHXA,
gregkh-hQyY1W1yCW8ekmWlsbkhG0B+6BGkLq7r
In-Reply-To: <1491301105-5274-7-git-send-email-sricharan-sgV2jX0FEOL9JmXXK+q4OQ@public.gmane.org>
On 04/04/17 11:18, Sricharan R wrote:
> Size of the dma-range is calculated as coherent_dma_mask + 1
> and passed to arch_setup_dma_ops further. It overflows when
> the coherent_dma_mask is set for full 64 bits 0xFFFFFFFFFFFFFFFF,
> resulting in size getting passed as 0 wrongly. Fix this by
> passsing in max(mask, mask + 1). Note that in this case
> when the mask is set to full 64bits, we will be passing the mask
> itself to arch_setup_dma_ops instead of the size. The real fix
> for this should be to make arch_setup_dma_ops receive the
> mask and handle it, to be done in the future.
Agreed; in the meantime, this fix is neat and robust enough.
Reviewed-by: Robin Murphy <robin.murphy-5wv7dgnIgG8@public.gmane.org>
> Signed-off-by: Sricharan R <sricharan-sgV2jX0FEOL9JmXXK+q4OQ@public.gmane.org>
> ---
> drivers/of/device.c | 2 +-
> 1 file changed, 1 insertion(+), 1 deletion(-)
>
> diff --git a/drivers/of/device.c b/drivers/of/device.c
> index c17c19d..c2ae6bb 100644
> --- a/drivers/of/device.c
> +++ b/drivers/of/device.c
> @@ -107,7 +107,7 @@ void of_dma_configure(struct device *dev, struct device_node *np)
> ret = of_dma_get_range(np, &dma_addr, &paddr, &size);
> if (ret < 0) {
> dma_addr = offset = 0;
> - size = dev->coherent_dma_mask + 1;
> + size = max(dev->coherent_dma_mask, dev->coherent_dma_mask + 1);
> } else {
> offset = PFN_DOWN(paddr - dma_addr);
> dev_dbg(dev, "dma_pfn_offset(%#08lx)\n", offset);
>
^ permalink raw reply
* Re: [PATCH v8 1/2] media: i2c/ov5645: add the device tree binding document
From: Todor Tomov @ 2017-04-04 11:06 UTC (permalink / raw)
To: Sakari Ailus
Cc: mchehab, laurent.pinchart, hans.verkuil, linux-media,
linux-kernel, robh+dt, mark.rutland, devicetree
In-Reply-To: <20170404093150.GB3288@valkosipuli.retiisi.org.uk>
Hi Sakari,
Thank you for the time to review this again.
On 04/04/2017 12:31 PM, Sakari Ailus wrote:
> Hi Todor,
>
> On Mon, Apr 03, 2017 at 05:02:28PM +0300, Todor Tomov wrote:
>> Add the document for ov5645 device tree binding.
>>
>> Signed-off-by: Todor Tomov <todor.tomov@linaro.org>
>> Reviewed-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
>> ---
>> .../devicetree/bindings/media/i2c/ov5645.txt | 54 ++++++++++++++++++++++
>> 1 file changed, 54 insertions(+)
>> create mode 100644 Documentation/devicetree/bindings/media/i2c/ov5645.txt
>>
>> diff --git a/Documentation/devicetree/bindings/media/i2c/ov5645.txt b/Documentation/devicetree/bindings/media/i2c/ov5645.txt
>> new file mode 100644
>> index 0000000..fd7aec9
>> --- /dev/null
>> +++ b/Documentation/devicetree/bindings/media/i2c/ov5645.txt
>> @@ -0,0 +1,54 @@
>> +* Omnivision 1/4-Inch 5Mp CMOS Digital Image Sensor
>> +
>> +The Omnivision OV5645 is a 1/4-Inch CMOS active pixel digital image sensor with
>> +an active array size of 2592H x 1944V. It is programmable through a serial I2C
>> +interface.
>> +
>> +Required Properties:
>> +- compatible: Value should be "ovti,ov5645".
>> +- clocks: Reference to the xclk clock.
>> +- clock-names: Should be "xclk".
>> +- clock-frequency: Frequency of the xclk clock.
>> +- enable-gpios: Chip enable GPIO. Polarity is GPIO_ACTIVE_HIGH. This corresponds
>> + to the hardware pin PWDNB which is physically active low.
>> +- reset-gpios: Chip reset GPIO. Polarity is GPIO_ACTIVE_LOW. This corresponds to
>> + the hardware pin RESETB.
>> +- vdddo-supply: Chip digital IO regulator.
>> +- vdda-supply: Chip analog regulator.
>> +- vddd-supply: Chip digital core regulator.
>> +
>> +The device node must contain one 'port' child node for its digital output
>> +video port, in accordance with the video interface bindings defined in
>> +Documentation/devicetree/bindings/media/video-interfaces.txt.
>> +
>> +Example:
>> +
>> + &i2c1 {
>> + ...
>> +
>> + ov5645: ov5645@78 {
>> + compatible = "ovti,ov5645";
>> + reg = <0x78>;
>> +
>> + enable-gpios = <&gpio1 6 GPIO_ACTIVE_HIGH>;
>> + reset-gpios = <&gpio5 20 GPIO_ACTIVE_LOW>;
>> + pinctrl-names = "default";
>> + pinctrl-0 = <&camera_rear_default>;
>> +
>> + clocks = <&clks 200>;
>> + clock-names = "xclk";
>> + clock-frequency = <23880000>;
>> +
>> + vdddo-supply = <&camera_dovdd_1v8>;
>> + vdda-supply = <&camera_avdd_2v8>;
>> + vddd-supply = <&camera_dvdd_1v2>;
>> +
>> + port {
>> + ov5645_ep: endpoint {
>> + clock-lanes = <1>;
>> + data-lanes = <0 2>;
>
> If the sensor does not support lane reordering, I'd use 0 for the clock lane
> and lanes starting from 1 for data-lanes.
Yes, the sensor doesn't really support lane reordering. I'll keep this in mind for the next time.
>
> I guess it'd be good to document this but that's definitely out of scope of
> the patchset.
>
> Acked-by: Sakari Ailus <sakari.ailus@linux.intel.com>
>
>> + remote-endpoint = <&csi0_ep>;
>> + };
>> + };
>> + };
>> + };
>
--
Best regards,
Todor Tomov
^ permalink raw reply
* Re: [PATCH V10 05/12] ACPI/IORT: Add function to check SMMUs drivers presence
From: Robin Murphy @ 2017-04-04 11:04 UTC (permalink / raw)
To: Sricharan R, will.deacon-5wv7dgnIgG8, joro-zLv9SwRftAIdnm+yROfE0A,
lorenzo.pieralisi-5wv7dgnIgG8,
iommu-cunTk1MwBs9QetFLy7KEm3xJsTq8ys+cHZ5vskTnxNA,
linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r,
linux-arm-msm-u79uwXL29TY76Z2rM5mHXA,
m.szyprowski-Sze3O3UU22JBDgjK7y7TUQ,
bhelgaas-hpIqsD4AKlfQT0dZR+AlfA, linux-pci-u79uwXL29TY76Z2rM5mHXA,
linux-acpi-u79uwXL29TY76Z2rM5mHXA, tn-nYOzD4b6Jr9Wk0Htik3J/w,
hanjun.guo-QSEj5FYQhm4dnm+yROfE0A, okaya-sgV2jX0FEOL9JmXXK+q4OQ,
robh+dt-DgEjT+Ai2ygdnm+yROfE0A,
frowand.list-Re5JQEeQqe8AvxtiuMwx3w,
devicetree-u79uwXL29TY76Z2rM5mHXA,
linux-kernel-u79uwXL29TY76Z2rM5mHXA, sudeep.holla-5wv7dgnIgG8,
rjw-LthD3rsA81gm4RdzfppkhA, lenb-DgEjT+Ai2ygdnm+yROfE0A,
catalin.marinas-5wv7dgnIgG8, arnd-r2nGTMty4D4,
linux-arch-u79uwXL29TY76Z2rM5mHXA,
gregkh-hQyY1W1yCW8ekmWlsbkhG0B+6BGkLq7r
In-Reply-To: <1491301105-5274-6-git-send-email-sricharan-sgV2jX0FEOL9JmXXK+q4OQ@public.gmane.org>
On 04/04/17 11:18, Sricharan R wrote:
> From: Lorenzo Pieralisi <lorenzo.pieralisi-5wv7dgnIgG8@public.gmane.org>
>
> The IOMMU probe deferral implementation requires a mechanism to detect
> if drivers for SMMU components are built-in in the kernel to detect
> whether IOMMU configuration for a given device should be deferred (ie
> SMMU drivers present but still not probed) or not (drivers not present).
>
> Add a simple function to IORT to detect if SMMU drivers for SMMU
> components managed by IORT are built-in in the kernel.
Ah, if only DT could be this neat and tidy :D
Reviewed-by: Robin Murphy <robin.murphy-5wv7dgnIgG8@public.gmane.org>
> Tested-by: Hanjun Guo <hanjun.guo-QSEj5FYQhm4dnm+yROfE0A@public.gmane.org>
> Signed-off-by: Lorenzo Pieralisi <lorenzo.pieralisi-5wv7dgnIgG8@public.gmane.org>
> Cc: Robin Murphy <robin.murphy-5wv7dgnIgG8@public.gmane.org>
> Cc: Sricharan R <sricharan-sgV2jX0FEOL9JmXXK+q4OQ@public.gmane.org>
> ---
> drivers/acpi/arm64/iort.c | 13 +++++++++++++
> 1 file changed, 13 insertions(+)
>
> diff --git a/drivers/acpi/arm64/iort.c b/drivers/acpi/arm64/iort.c
> index 4a5bb96..3dd9ec3 100644
> --- a/drivers/acpi/arm64/iort.c
> +++ b/drivers/acpi/arm64/iort.c
> @@ -523,6 +523,19 @@ static int arm_smmu_iort_xlate(struct device *dev, u32 streamid,
> return ret;
> }
>
> +static inline bool iort_iommu_driver_enabled(u8 type)
> +{
> + switch (type) {
> + case ACPI_IORT_NODE_SMMU_V3:
> + return IS_BUILTIN(CONFIG_ARM_SMMU_V3);
> + case ACPI_IORT_NODE_SMMU:
> + return IS_BUILTIN(CONFIG_ARM_SMMU);
> + default:
> + pr_warn("IORT node type %u does not describe an SMMU\n", type);
> + return false;
> + }
> +}
> +
> static const struct iommu_ops *iort_iommu_xlate(struct device *dev,
> struct acpi_iort_node *node,
> u32 streamid)
>
^ permalink raw reply
* [PATCH v7 9/9] dts: arm64: hip07: Add Hisilicon SoC PMU support
From: Anurup M @ 2017-04-04 10:56 UTC (permalink / raw)
To: mark.rutland, will.deacon, robh+dt, xuwei5, catalin.marinas
Cc: devicetree, linux-kernel, linux-arm-kernel, anurup.m,
zhangshaokun, tanxiaojun, sanil.kumar, john.garry,
gabriele.paoloni, shiju.jose, huangdaode, linuxarm, dikshit.n,
shyju.pv, anurupvasu
Add nodes for djtag, L3 cache and MN to support uncore events.
Signed-off-by: Anurup M <anurup.m@huawei.com>
---
arch/arm64/boot/dts/hisilicon/hip07.dtsi | 87 ++++++++++++++++++++++++++++++++
1 file changed, 87 insertions(+)
diff --git a/arch/arm64/boot/dts/hisilicon/hip07.dtsi b/arch/arm64/boot/dts/hisilicon/hip07.dtsi
index 5144eb1..1099f6e 100644
--- a/arch/arm64/boot/dts/hisilicon/hip07.dtsi
+++ b/arch/arm64/boot/dts/hisilicon/hip07.dtsi
@@ -1056,4 +1056,91 @@
status = "disabled";
};
};
+
+ djtag0: djtag@60010000 {
+ compatible = "hisilicon,hip07-cpu-djtag-v2";
+ reg = <0x0 0x60010000 0x0 0x10000>;
+ hisilicon,scl-id = <0x03>;
+
+ /* L3 cache bank 0 for socket0 CPU die scl#3 */
+ pmul3c0 {
+ compatible = "hisilicon,hip07-pmu-l3c-v2";
+ hisilicon,module-id = <0x01>;
+ hisilicon,instance-id = <0x01>;
+ };
+
+ /* L3 cache bank 1 for socket0 CPU die scl#3 */
+ pmul3c1 {
+ compatible = "hisilicon,hip07-pmu-l3c-v2";
+ hisilicon,module-id = <0x02>;
+ hisilicon,instance-id = <0x01>;
+ };
+
+ /* L3 cache bank 2 for socket0 CPU die scl#3 */
+ pmul3c2 {
+ compatible = "hisilicon,hip07-pmu-l3c-v2";
+ hisilicon,module-id = <0x03>;
+ hisilicon,instance-id = <0x01>;
+ };
+
+ /* L3 cache bank 3 for socket0 CPU die scl#3 */
+ pmul3c3 {
+ compatible = "hisilicon,hip07-pmu-l3c-v2";
+ hisilicon,module-id = <0x04>;
+ hisilicon,instance-id = <0x01>;
+ };
+
+ /*
+ * Miscellaneous node for socket0
+ * CPU die scl#3
+ */
+ pmumn0 {
+ compatible = "hisilicon,hip07-pmu-mn-v2";
+ hisilicon,module-id = <0x21>;
+ };
+ };
+
+ djtag1: djtag@40010000 {
+ compatible = "hisilicon,hip07-cpu-djtag-v2";
+ reg = <0x0 0x40010000 0x0 0x10000>;
+ hisilicon,scl-id = <0x01>;
+
+ /* L3 cache bank 0 for socket0 CPU die scl#1 */
+ pmul3c0 {
+ compatible = "hisilicon,hip07-pmu-l3c-v2";
+ hisilicon,module-id = <0x01>;
+ hisilicon,instance-id = <0x01>;
+ };
+
+ /* L3 cache bank 1 for socket0 CPU die scl#1 */
+ pmul3c1 {
+ compatible = "hisilicon,hip07-pmu-l3c-v2";
+ hisilicon,module-id = <0x02>;
+ hisilicon,instance-id = <0x01>;
+ };
+
+ /* L3 cache bank 2 for socket0 CPU die scl#1 */
+ pmul3c2 {
+ compatible = "hisilicon,hip07-pmu-l3c-v2";
+ hisilicon,module-id = <0x03>;
+ hisilicon,instance-id = <0x01>;
+ };
+
+ /* L3 cache bank 3 for socket0 CPU die scl#1 */
+ pmul3c3 {
+ compatible = "hisilicon,hip07-pmu-l3c-v2";
+ hisilicon,module-id = <0x04>;
+ hisilicon,instance-id = <0x01>;
+ };
+
+ /*
+ * Miscellaneous node for socket0
+ * CPU die scl#1
+ */
+ pmumn1 {
+ compatible = "hisilicon,hip07-pmu-mn-v2";
+ hisilicon,module-id = <0x21>;
+ };
+ };
+
};
--
2.1.4
^ permalink raw reply related
* [PATCH v7 3/9] dt-bindings: perf: hisi: Add Devicetree bindings for Hisilicon SoC PMU
From: Anurup M @ 2017-04-04 10:55 UTC (permalink / raw)
To: robh+dt, mark.rutland, will.deacon
Cc: linux-kernel, devicetree, linux-arm-kernel, anurup.m,
zhangshaokun, tanxiaojun, xuwei5, sanil.kumar, john.garry,
gabriele.paoloni, shiju.jose, huangdaode, wangkefeng.wang,
linuxarm, dikshit.n, shyju.pv, anurupvasu
1) Device tree bindings for Hisilicon SoC PMU.
2) Add example for Hisilicon L3 cache and MN PMU.
3) Add child nodes of L3C and MN in djtag bindings example.
Signed-off-by: Anurup M <anurup.m@huawei.com>
Signed-off-by: Shaokun Zhang <zhangshaokun@hisilicon.com>
---
.../devicetree/bindings/arm/hisilicon/djtag.txt | 29 +++++++
.../devicetree/bindings/arm/hisilicon/pmu.txt | 93 ++++++++++++++++++++++
2 files changed, 122 insertions(+)
create mode 100644 Documentation/devicetree/bindings/arm/hisilicon/pmu.txt
diff --git a/Documentation/devicetree/bindings/arm/hisilicon/djtag.txt b/Documentation/devicetree/bindings/arm/hisilicon/djtag.txt
index fde5bab..27e67cc 100644
--- a/Documentation/devicetree/bindings/arm/hisilicon/djtag.txt
+++ b/Documentation/devicetree/bindings/arm/hisilicon/djtag.txt
@@ -27,6 +27,35 @@ Example 1: Djtag for CPU die in HiP07
hisilicon,scl-id = <0x03>;
/* All connecting components will appear as child nodes */
+
+ pmul3c0 {
+ compatible = "hisilicon,hip07-pmu-l3c-v2";
+ hisilicon,module-id = <0x01>;
+ hisilicon,instance-id = <0x01>;
+ };
+
+ pmul3c1 {
+ compatible = "hisilicon,hip07-pmu-l3c-v2";
+ hisilicon,module-id = <0x02>;
+ hisilicon,instance-id = <0x01>;
+ };
+
+ pmul3c2 {
+ compatible = "hisilicon,hip07-pmu-l3c-v2";
+ hisilicon,module-id = <0x03>;
+ hisilicon,instance-id = <0x01>;
+ };
+
+ pmul3c3 {
+ compatible = "hisilicon,hip07-pmu-l3c-v2";
+ hisilicon,module-id = <0x04>;
+ hisilicon,instance-id = <0x01>;
+ };
+
+ pmumn0 {
+ compatible = "hisilicon,hip07-pmu-mn-v2";
+ hisilicon,module-id = <0x21>;
+ };
};
Hisilicon HiP05/06/07 djtag for IO die
diff --git a/Documentation/devicetree/bindings/arm/hisilicon/pmu.txt b/Documentation/devicetree/bindings/arm/hisilicon/pmu.txt
new file mode 100644
index 0000000..488e740
--- /dev/null
+++ b/Documentation/devicetree/bindings/arm/hisilicon/pmu.txt
@@ -0,0 +1,93 @@
+Hisilicon SoC HiP05/06/07 ARMv8 PMU
+===================================
+
+The Hisilicon SoC chips like HiP05/06/07 etc. consist of various independent
+system device PMUs such as L3 cache (L3C) and Miscellaneous Nodes(MN). These
+PMU devices are independent and have hardware logic to gather statistics and
+performance information.
+
+HiSilicon SoC chip is encapsulated by multiple CPU and IO dies. The CPU die
+is called as Super CPU cluster (SCCL) which includes 16 cpu-cores. Every SCCL
+in HiP05/06/07 chips are further grouped as CPU clusters (CCL) which includes
+4 cpu-cores each.
+e.g. In the case of HiP05/06/07, each SCCL has 1 L3 cache and 1 MN PMU device.
+The L3 cache is further grouped as 4 L3 cache banks in a SCCL.
+
+The Hisilicon SoC PMU DT node bindings for uncore PMU devices are as below.
+For PMU devices like L3 cache. MN etc. which are accessed using the djtag,
+the parent node will be the djtag node of the corresponding CPU die (SCCL).
+
+L3 cache
+---------
+The L3 cache is dedicated for each SCCL. Each SCCL in HiP05/06/07 chips have 4
+L3 cache banks. Each L3 cache bank have separate DT nodes.
+
+Required properties:
+
+ - compatible : This value should be as follows
+ (a) "hisilicon,hip05-pmu-l3c-v1" for v1 hw in HiP05 chipset
+ (b) "hisilicon,hip06-pmu-l3c-v1" for v1 hw in HiP06 chipset
+ (c) "hisilicon,hip07-pmu-l3c-v2" for v2 hw in HiP07 chipset
+
+ - hisilicon,module-id : This property is the module identifier for djtag.
+ In v1 hw, this value is 0x04 for all L3 cache instances. But
+ in v2 hw, this value is unique for each L3 cache instance.
+
+ - hisilicon,instance-id : This property will identify the L3 cache instance
+ or bank in djtag. In v1 hw, this value is unique for each L3 cache
+ instance. But in v2 hw, it is 0x01 for all L3 cache instances.
+
+ *The counter overflow IRQ is not supported in v1, v2 hardware (HiP05/06/07).
+
+Miscellaneous Node
+------------------
+The MN is dedicated for each SCCL and hence there are separate DT nodes for MN
+for each SCCL.
+
+Required properties:
+
+ - compatible : This value should be as follows
+ (a) "hisilicon,hip05-pmu-mn-v1" for v1 hw in HiP05 chipset
+ (b) "hisilicon,hip06-pmu-mn-v1" for v1 hw in HiP06 chipset
+ (c) "hisilicon,hip07-pmu-mn-v2" for v2 hw in HiP07 chipset
+
+ - hisilicon,module-id : Module ID to input for djtag.
+
+ *The counter overflow IRQ is not supported in v1, v2 hardware (HiP05/06/07).
+
+Example:
+
+ djtag0: djtag@60010000 {
+ compatible = "hisilicon,hip07-cpu-djtag-v2";
+ reg = <0x0 0x60010000 0x0 0x10000>;
+ hisilicon,scl-id = <0x03>;
+
+ pmul3c0 {
+ compatible = "hisilicon,hip07-pmu-l3c-v2";
+ hisilicon,module-id = <0x01>;
+ hisilicon,instance-id = <0x01>;
+ };
+
+ pmul3c1 {
+ compatible = "hisilicon,hip07-pmu-l3c-v2";
+ hisilicon,module-id = <0x02>;
+ hisilicon,instance-id = <0x01>;
+ };
+
+ pmul3c2 {
+ compatible = "hisilicon,hip07-pmu-l3c-v2";
+ hisilicon,module-id = <0x03>;
+ hisilicon,instance-id = <0x01>;
+ };
+
+ pmul3c3 {
+ compatible = "hisilicon,hip07-pmu-l3c-v2";
+ hisilicon,module-id = <0x04>;
+ hisilicon,instance-id = <0x01>;
+ };
+
+ pmumn0 {
+ compatible = "hisilicon,hip07-pmu-mn-v2";
+ hisilicon,module-id = <0x21>;
+ };
+ };
--
2.1.4
^ permalink raw reply related
* [PATCH v7 2/9] dt-bindings: hisi: Add Hisilicon HiP05/06/07 Djtag dts bindings
From: Anurup M @ 2017-04-04 10:55 UTC (permalink / raw)
To: robh+dt-DgEjT+Ai2ygdnm+yROfE0A, mark.rutland-5wv7dgnIgG8,
will.deacon-5wv7dgnIgG8
Cc: linux-kernel-u79uwXL29TY76Z2rM5mHXA,
devicetree-u79uwXL29TY76Z2rM5mHXA,
linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r,
anurup.m-hv44wF8Li93QT0dZR+AlfA,
zhangshaokun-C8/M+/jPZTeaMJb+Lgu22Q,
tanxiaojun-hv44wF8Li93QT0dZR+AlfA, xuwei5-C8/M+/jPZTeaMJb+Lgu22Q,
sanil.kumar-C8/M+/jPZTeaMJb+Lgu22Q,
john.garry-hv44wF8Li93QT0dZR+AlfA,
gabriele.paoloni-hv44wF8Li93QT0dZR+AlfA,
shiju.jose-hv44wF8Li93QT0dZR+AlfA,
huangdaode-C8/M+/jPZTeaMJb+Lgu22Q,
wangkefeng.wang-hv44wF8Li93QT0dZR+AlfA,
linuxarm-hv44wF8Li93QT0dZR+AlfA, dikshit.n-hv44wF8Li93QT0dZR+AlfA,
shyju.pv-hv44wF8Li93QT0dZR+AlfA,
anurupvasu-Re5JQEeQqe8AvxtiuMwx3w
From: Tan Xiaojun <tanxiaojun-hv44wF8Li93QT0dZR+AlfA@public.gmane.org>
Add Hisilicon HiP05/06/07 Djtag dts bindings for CPU and IO Die
Signed-off-by: Tan Xiaojun <tanxiaojun-hv44wF8Li93QT0dZR+AlfA@public.gmane.org>
Signed-off-by: Anurup M <anurup.m-hv44wF8Li93QT0dZR+AlfA@public.gmane.org>
Acked-by: Rob Herring <robh-DgEjT+Ai2ygdnm+yROfE0A@public.gmane.org>
---
.../devicetree/bindings/arm/hisilicon/djtag.txt | 51 ++++++++++++++++++++++
1 file changed, 51 insertions(+)
create mode 100644 Documentation/devicetree/bindings/arm/hisilicon/djtag.txt
diff --git a/Documentation/devicetree/bindings/arm/hisilicon/djtag.txt b/Documentation/devicetree/bindings/arm/hisilicon/djtag.txt
new file mode 100644
index 0000000..fde5bab
--- /dev/null
+++ b/Documentation/devicetree/bindings/arm/hisilicon/djtag.txt
@@ -0,0 +1,51 @@
+The Hisilicon Djtag is an independent component which connects with some other
+components in the SoC by Debug Bus. The djtag is available in CPU and IO dies
+in the chip. The djtag controls access to connecting modules of CPU and IO
+dies.
+The various connecting components in CPU die (like L3 cache, L3 cache PMU etc.)
+are accessed by djtag during real time debugging. In IO die there are connecting
+components like RSA. These components appear as devices attached to djtag bus.
+
+Hisilicon HiP05/06/07 djtag for CPU die
+Required properties:
+ - compatible : The value should be as follows
+ (a) "hisilicon,hip05-cpu-djtag-v1" for CPU die which use v1 hw in
+ HiP05 chipset.
+ (b) "hisilicon,hip06-cpu-djtag-v1" for CPU die which use v1 hw in
+ HiP06 chipset.
+ (c) "hisilicon,hip07-cpu-djtag-v2" for CPU die which use v2 hw in
+ HiP07 chipset.
+ - reg : Register address and size
+ - hisilicon,scl-id : The Super Cluster ID for CPU or IO die
+
+Example 1: Djtag for CPU die in HiP07
+
+ /* for Hisilicon HiP07 djtag for CPU Die */
+ djtag0: djtag@60010000 {
+ compatible = "hisilicon,hip07-cpu-djtag-v2";
+ reg = <0x0 0x60010000 0x0 0x10000>;
+ hisilicon,scl-id = <0x03>;
+
+ /* All connecting components will appear as child nodes */
+ };
+
+Hisilicon HiP05/06/07 djtag for IO die
+Required properties:
+ - compatible : The value should be as follows
+ (a) "hisilicon,hip05-io-djtag-v1" for IO die which use v1 hw in
+ HiP05 chipset.
+ (c) "hisilicon,hip06-io-djtag-v2" for IO die which use v2 hw in
+ HiP06 chipset.
+ (d) "hisilicon,hip07-io-djtag-v2" for IO die which use v2 hw in
+ HiP07 chipset
+
+Example 2: Djtag for IO die in HiP05
+
+ /* for Hisilicon HiP05 djtag for IO Die */
+ djtag1: djtag@d0000000 {
+ compatible = "hisilicon,hip05-io-djtag-v1";
+ reg = <0x0 0xd0000000 0x0 0x10000>;
+ hisilicon,scl-id = <0x0>;
+
+ /* All connecting components will appear as child nodes */
+ };
--
2.1.4
--
To unsubscribe from this list: send the line "unsubscribe devicetree" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
^ permalink raw reply related
* [PATCH v7 0/9] perf: arm64: Support for Hisilicon SoC Hardware event counters
From: Anurup M @ 2017-04-04 10:54 UTC (permalink / raw)
To: robh+dt, gregkh, catalin.marinas, geert+renesas, davem, akpm,
corbet, mark.rutland, will.deacon
Cc: linux-kernel, devicetree, linux-arm-kernel, anurup.m,
zhangshaokun, tanxiaojun, xuwei5, sanil.kumar, john.garry,
gabriele.paoloni, shiju.jose, huangdaode, wangkefeng.wang,
linuxarm, dikshit.n, shyju.pv, anurupvasu
Provide Support for Hisilicon SoC(HiP05/06/07) Hardware event counters.
The Hisilicon SoC HiP0x series has many uncore or non-CPU performance
events and counters units.
This v7 version has addressed review comments of v6 version and based on 4.11-rc1.
This patch series is implemented refering to arm-cci, Intel/AMD uncore and
also the cavium thunderX and xgene uncore pmu patches.
Support for Hisilicon L3 cache(L3C) and Miscellaneous nodes(MN) hardware
events and counters are added in this implementation.
The uncore PMU units are registered as separate PMUs.
e.g. in the case of L3 cache, which consist of 4 banks/instances, each bank
is registered with perf as separate PMU, as each bank have separate control
registers and interrupts. These units are also not CPU affine in the current
chip versions.
The Hisilicon uncore PMUs can be found under /sys/bus/event_source/devices.
The counters are exported via sysfs in the corresponding events files
under the PMU directory so the perf tool can list the event names.
There is no counter overflow IRQ support in hardware for these uncore PMUs.
So the driver use poll method using hrtimer to avoid overflow.
ToDo:
1) ACPI probe and reset support.
Version history
---------------
v7
--
- use BUG_ON for djtag access timeout and simplified callers.
- Split hisilicon,module-id in dt-bindings and add hisilicon,instance-id
property. Also describe the properties with more detail.
- Add event group validation for available counters.
- Fold hrtimer patches to main PMU patches of L3 cache and MN.
- Move event used mask to hisi_pmu_hwevents struct.
- Remove some unused #define.
- Fix all sparse and gcc W=1 warnings.
- Fix comments of V6 version.
v6
--
- Rebase to 4.11-rc1
- Modify Copyright year to 2017.
v5
--
- Use hrtimer to avoid overflow as MN counter overflow IRQ is broken
in hardware.
- Remove IRQ handling of MN in driver and update pmu dt-bindings.
- Fix reveiw comments in v4 version.
v4
--
- Counter overflow IRQ handling for MN PMU.
- Use hrtimer to avoid counter overflow in L3 Cache PMU.
- Use hisi-cpu- and hisi-io- for djtag compatible field.
- Fix reveiw comments in v3 version.
v3
--
- Fix review comments of v2 version.
- Handle event groups. Do not allow group of mixed PMUs.
- Use hip0x prefix for compatible names.
- Fix all sparse and gcc W=1 warnings.
v2
--
- Fix review comments of v1 version.
- Move djtag driver to drivers/perf/hisilicon.
- Have separate PMU instance for each L3 cache banks.
- Modify device properties in DTS as per review comments.
- Handle hardware version difference.
- Change compatible names of djtag so use prefix hisi-
and remove chip version as driver only depend on djtag
hw version.
- use devm_kzalloc.
- Remove DDRC changes in this series. As the DDRC PMU doesnot
depend on djtag it will be send separately.
v1
--
-Initial version with support for L3C, MN and DDRC event counters
-Djtag driver is used to access registers of L3 cache and MN.
Anurup M (6):
arm64: MAINTAINERS: hisi: Add hisilicon SoC PMU support
dt-bindings: perf: hisi: Add Devicetree bindings for Hisilicon SoC PMU
Documentation: perf: hisi: Documentation for HiP05/06/07 PMU event
counting.
drivers: perf: hisi: Update Kconfig for Hisilicon PMU support
drivers: perf: hisi: Add support for Hisilicon SoC event counters
dts: arm64: hip07: Add Hisilicon SoC PMU support
Shaokun Zhang (1):
drivers: perf: hisi: Miscellanous node(MN) event counting in perf
Tan Xiaojun (2):
dt-bindings: hisi: Add Hisilicon HiP05/06/07 Djtag dts bindings
drivers: perf: hisi: Add support for Hisilicon Djtag driver
.../devicetree/bindings/arm/hisilicon/djtag.txt | 80 +++
.../devicetree/bindings/arm/hisilicon/pmu.txt | 93 +++
Documentation/perf/hisi-pmu.txt | 75 +++
MAINTAINERS | 10 +
arch/arm64/boot/dts/hisilicon/hip07.dtsi | 87 +++
drivers/perf/Kconfig | 8 +
drivers/perf/Makefile | 1 +
drivers/perf/hisilicon/Makefile | 1 +
drivers/perf/hisilicon/djtag.c | 684 +++++++++++++++++++++
drivers/perf/hisilicon/djtag.h | 47 ++
drivers/perf/hisilicon/hisi_uncore_l3c.c | 598 ++++++++++++++++++
drivers/perf/hisilicon/hisi_uncore_mn.c | 478 ++++++++++++++
drivers/perf/hisilicon/hisi_uncore_pmu.c | 424 +++++++++++++
drivers/perf/hisilicon/hisi_uncore_pmu.h | 137 +++++
14 files changed, 2723 insertions(+)
create mode 100644 Documentation/devicetree/bindings/arm/hisilicon/djtag.txt
create mode 100644 Documentation/devicetree/bindings/arm/hisilicon/pmu.txt
create mode 100644 Documentation/perf/hisi-pmu.txt
create mode 100644 drivers/perf/hisilicon/Makefile
create mode 100644 drivers/perf/hisilicon/djtag.c
create mode 100644 drivers/perf/hisilicon/djtag.h
create mode 100644 drivers/perf/hisilicon/hisi_uncore_l3c.c
create mode 100644 drivers/perf/hisilicon/hisi_uncore_mn.c
create mode 100644 drivers/perf/hisilicon/hisi_uncore_pmu.c
create mode 100644 drivers/perf/hisilicon/hisi_uncore_pmu.h
--
2.1.4
^ permalink raw reply
* Re: [PATCH V10 04/12] of: dma: Make of_dma_deconfigure() public
From: Robin Murphy @ 2017-04-04 10:47 UTC (permalink / raw)
To: Sricharan R, will.deacon-5wv7dgnIgG8, joro-zLv9SwRftAIdnm+yROfE0A,
lorenzo.pieralisi-5wv7dgnIgG8,
iommu-cunTk1MwBs9QetFLy7KEm3xJsTq8ys+cHZ5vskTnxNA,
linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r,
linux-arm-msm-u79uwXL29TY76Z2rM5mHXA,
m.szyprowski-Sze3O3UU22JBDgjK7y7TUQ,
bhelgaas-hpIqsD4AKlfQT0dZR+AlfA, linux-pci-u79uwXL29TY76Z2rM5mHXA,
linux-acpi-u79uwXL29TY76Z2rM5mHXA, tn-nYOzD4b6Jr9Wk0Htik3J/w,
hanjun.guo-QSEj5FYQhm4dnm+yROfE0A, okaya-sgV2jX0FEOL9JmXXK+q4OQ,
robh+dt-DgEjT+Ai2ygdnm+yROfE0A,
frowand.list-Re5JQEeQqe8AvxtiuMwx3w,
devicetree-u79uwXL29TY76Z2rM5mHXA,
linux-kernel-u79uwXL29TY76Z2rM5mHXA, sudeep.holla-5wv7dgnIgG8,
rjw-LthD3rsA81gm4RdzfppkhA, lenb-DgEjT+Ai2ygdnm+yROfE0A,
catalin.marinas-5wv7dgnIgG8, arnd-r2nGTMty4D4,
linux-arch-u79uwXL29TY76Z2rM5mHXA,
gregkh-hQyY1W1yCW8ekmWlsbkhG0B+6BGkLq7r
In-Reply-To: <1491301105-5274-5-git-send-email-sricharan-sgV2jX0FEOL9JmXXK+q4OQ@public.gmane.org>
On 04/04/17 11:18, Sricharan R wrote:
> From: Laurent Pinchart <laurent.pinchart+renesas-ryLnwIuWjnjg/C1BVhZhaw@public.gmane.org>
>
> As part of moving DMA initializing to probe time the
> of_dma_deconfigure() function will need to be called from different
> source files. Make it public and move it to drivers/of/device.c where
> the of_dma_configure() function is.
Reviewed-by: Robin Murphy <robin.murphy-5wv7dgnIgG8@public.gmane.org>
> Tested-by: Marek Szyprowski <m.szyprowski-Sze3O3UU22JBDgjK7y7TUQ@public.gmane.org>
> Signed-off-by: Laurent Pinchart <laurent.pinchart+renesas-ryLnwIuWjnjg/C1BVhZhaw@public.gmane.org>
> ---
> drivers/of/device.c | 12 ++++++++++++
> drivers/of/platform.c | 5 -----
> include/linux/of_device.h | 3 +++
> 3 files changed, 15 insertions(+), 5 deletions(-)
>
> diff --git a/drivers/of/device.c b/drivers/of/device.c
> index 09dedd0..c17c19d 100644
> --- a/drivers/of/device.c
> +++ b/drivers/of/device.c
> @@ -136,6 +136,18 @@ void of_dma_configure(struct device *dev, struct device_node *np)
> }
> EXPORT_SYMBOL_GPL(of_dma_configure);
>
> +/**
> + * of_dma_deconfigure - Clean up DMA configuration
> + * @dev: Device for which to clean up DMA configuration
> + *
> + * Clean up all configuration performed by of_dma_configure_ops() and free all
> + * resources that have been allocated.
> + */
> +void of_dma_deconfigure(struct device *dev)
> +{
> + arch_teardown_dma_ops(dev);
> +}
> +
> int of_device_register(struct platform_device *pdev)
> {
> device_initialize(&pdev->dev);
> diff --git a/drivers/of/platform.c b/drivers/of/platform.c
> index 5dfcc96..5344db5 100644
> --- a/drivers/of/platform.c
> +++ b/drivers/of/platform.c
> @@ -158,11 +158,6 @@ struct platform_device *of_device_alloc(struct device_node *np,
> }
> EXPORT_SYMBOL(of_device_alloc);
>
> -static void of_dma_deconfigure(struct device *dev)
> -{
> - arch_teardown_dma_ops(dev);
> -}
> -
> /**
> * of_platform_device_create_pdata - Alloc, initialize and register an of_device
> * @np: pointer to node to create device for
> diff --git a/include/linux/of_device.h b/include/linux/of_device.h
> index c12dace..af98455 100644
> --- a/include/linux/of_device.h
> +++ b/include/linux/of_device.h
> @@ -56,6 +56,7 @@ static inline struct device_node *of_cpu_device_node_get(int cpu)
> }
>
> void of_dma_configure(struct device *dev, struct device_node *np);
> +void of_dma_deconfigure(struct device *dev);
> #else /* CONFIG_OF */
>
> static inline int of_driver_match_device(struct device *dev,
> @@ -105,6 +106,8 @@ static inline struct device_node *of_cpu_device_node_get(int cpu)
> }
> static inline void of_dma_configure(struct device *dev, struct device_node *np)
> {}
> +static inline void of_dma_deconfigure(struct device *dev)
> +{}
> #endif /* CONFIG_OF */
>
> #endif /* _LINUX_OF_DEVICE_H */
>
^ permalink raw reply
* Re: [PATCH V10 03/12] of: dma: Move range size workaround to of_dma_get_range()
From: Robin Murphy @ 2017-04-04 10:46 UTC (permalink / raw)
To: Sricharan R, will.deacon-5wv7dgnIgG8, joro-zLv9SwRftAIdnm+yROfE0A,
lorenzo.pieralisi-5wv7dgnIgG8,
iommu-cunTk1MwBs9QetFLy7KEm3xJsTq8ys+cHZ5vskTnxNA,
linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r,
linux-arm-msm-u79uwXL29TY76Z2rM5mHXA,
m.szyprowski-Sze3O3UU22JBDgjK7y7TUQ,
bhelgaas-hpIqsD4AKlfQT0dZR+AlfA, linux-pci-u79uwXL29TY76Z2rM5mHXA,
linux-acpi-u79uwXL29TY76Z2rM5mHXA, tn-nYOzD4b6Jr9Wk0Htik3J/w,
hanjun.guo-QSEj5FYQhm4dnm+yROfE0A, okaya-sgV2jX0FEOL9JmXXK+q4OQ,
robh+dt-DgEjT+Ai2ygdnm+yROfE0A,
frowand.list-Re5JQEeQqe8AvxtiuMwx3w,
devicetree-u79uwXL29TY76Z2rM5mHXA,
linux-kernel-u79uwXL29TY76Z2rM5mHXA, sudeep.holla-5wv7dgnIgG8,
rjw-LthD3rsA81gm4RdzfppkhA, lenb-DgEjT+Ai2ygdnm+yROfE0A,
catalin.marinas-5wv7dgnIgG8, arnd-r2nGTMty4D4,
linux-arch-u79uwXL29TY76Z2rM5mHXA,
gregkh-hQyY1W1yCW8ekmWlsbkhG0B+6BGkLq7r
In-Reply-To: <1491301105-5274-4-git-send-email-sricharan-sgV2jX0FEOL9JmXXK+q4OQ@public.gmane.org>
On 04/04/17 11:18, Sricharan R wrote:
> From: Laurent Pinchart <laurent.pinchart+renesas-ryLnwIuWjnjg/C1BVhZhaw@public.gmane.org>
>
> Invalid dma-ranges values should be worked around when retrieving the
> DMA range in of_dma_get_range(), not by all callers of the function.
> This isn't much of a problem now that we have a single caller, but that
> situation will change when moving DMA configuration to device probe
> time.
Just for completeness:
Reviewed-by: Robin Murphy <robin.murphy-5wv7dgnIgG8@public.gmane.org>
> Tested-by: Marek Szyprowski <m.szyprowski-Sze3O3UU22JBDgjK7y7TUQ@public.gmane.org>
> Signed-off-by: Laurent Pinchart <laurent.pinchart+renesas-ryLnwIuWjnjg/C1BVhZhaw@public.gmane.org>
> ---
> drivers/of/address.c | 20 ++++++++++++++++++--
> drivers/of/device.c | 15 ---------------
> 2 files changed, 18 insertions(+), 17 deletions(-)
>
> diff --git a/drivers/of/address.c b/drivers/of/address.c
> index 02b2903..6aeb816 100644
> --- a/drivers/of/address.c
> +++ b/drivers/of/address.c
> @@ -819,8 +819,8 @@ void __iomem *of_io_request_and_map(struct device_node *np, int index,
> * CPU addr (phys_addr_t) : pna cells
> * size : nsize cells
> *
> - * It returns -ENODEV if "dma-ranges" property was not found
> - * for this device in DT.
> + * Return 0 on success, -ENODEV if the "dma-ranges" property was not found for
> + * this device in DT, or -EINVAL if the CPU address or size is invalid.
> */
> int of_dma_get_range(struct device_node *np, u64 *dma_addr, u64 *paddr, u64 *size)
> {
> @@ -880,6 +880,22 @@ int of_dma_get_range(struct device_node *np, u64 *dma_addr, u64 *paddr, u64 *siz
> *dma_addr = dmaaddr;
>
> *size = of_read_number(ranges + naddr + pna, nsize);
> + /*
> + * DT nodes sometimes incorrectly set the size as a mask. Work around
> + * those incorrect DT by computing the size as mask + 1.
> + */
> + if (*size & 1) {
> + pr_warn("%s: size 0x%llx for dma-range in node(%s) set as mask\n",
> + __func__, *size, np->full_name);
> + *size = *size + 1;
> + }
> +
> + if (!*size) {
> + pr_err("%s: invalid size zero for dma-range in node(%s)\n",
> + __func__, np->full_name);
> + ret = -EINVAL;
> + goto out;
> + }
>
> pr_debug("dma_addr(%llx) cpu_addr(%llx) size(%llx)\n",
> *dma_addr, *paddr, *size);
> diff --git a/drivers/of/device.c b/drivers/of/device.c
> index b1e6beb..09dedd0 100644
> --- a/drivers/of/device.c
> +++ b/drivers/of/device.c
> @@ -110,21 +110,6 @@ void of_dma_configure(struct device *dev, struct device_node *np)
> size = dev->coherent_dma_mask + 1;
> } else {
> offset = PFN_DOWN(paddr - dma_addr);
> -
> - /*
> - * Add a work around to treat the size as mask + 1 in case
> - * it is defined in DT as a mask.
> - */
> - if (size & 1) {
> - dev_warn(dev, "Invalid size 0x%llx for dma-range\n",
> - size);
> - size = size + 1;
> - }
> -
> - if (!size) {
> - dev_err(dev, "Adjusted size 0x%llx invalid\n", size);
> - return;
> - }
> dev_dbg(dev, "dma_pfn_offset(%#08lx)\n", offset);
> }
>
>
^ permalink raw reply
* [PATCH V10 12/12] ACPI/IORT: Remove linker section for IORT entries probing
From: Sricharan R @ 2017-04-04 10:18 UTC (permalink / raw)
To: robin.murphy-5wv7dgnIgG8, will.deacon-5wv7dgnIgG8,
joro-zLv9SwRftAIdnm+yROfE0A, lorenzo.pieralisi-5wv7dgnIgG8,
iommu-cunTk1MwBs9QetFLy7KEm3xJsTq8ys+cHZ5vskTnxNA,
linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r,
linux-arm-msm-u79uwXL29TY76Z2rM5mHXA,
m.szyprowski-Sze3O3UU22JBDgjK7y7TUQ,
bhelgaas-hpIqsD4AKlfQT0dZR+AlfA, linux-pci-u79uwXL29TY76Z2rM5mHXA,
linux-acpi-u79uwXL29TY76Z2rM5mHXA, tn-nYOzD4b6Jr9Wk0Htik3J/w,
hanjun.guo-QSEj5FYQhm4dnm+yROfE0A, okaya-sgV2jX0FEOL9JmXXK+q4OQ,
robh+dt-DgEjT+Ai2ygdnm+yROfE0A,
frowand.list-Re5JQEeQqe8AvxtiuMwx3w,
devicetree-u79uwXL29TY76Z2rM5mHXA,
linux-kernel-u79uwXL29TY76Z2rM5mHXA, sudeep.holla-5wv7dgnIgG8,
rjw-LthD3rsA81gm4RdzfppkhA, lenb-DgEjT+Ai2ygdnm+yROfE0A,
catalin.marinas-5wv7dgnIgG8, arnd-r2nGTMty4D4,
linux-arch-u79uwXL29TY76Z2rM5mHXA,
gregkh-hQyY1W1yCW8ekmWlsbkhG0B+6BGkLq7r
In-Reply-To: <1491301105-5274-1-git-send-email-sricharan-sgV2jX0FEOL9JmXXK+q4OQ@public.gmane.org>
From: Lorenzo Pieralisi <lorenzo.pieralisi-5wv7dgnIgG8@public.gmane.org>
The IORT linker section introduced by commit 34ceea275f62
("ACPI/IORT: Introduce linker section for IORT entries probing")
was needed to make sure SMMU drivers are registered (and therefore
probed) in the kernel before devices using the SMMU have a chance
to probe in turn.
Through the introduction of deferred IOMMU configuration the linker
section based IORT probing infrastructure is not needed any longer, in
that device/SMMU probe dependencies are managed through the probe
deferral mechanism, making the IORT linker section infrastructure
unused, so that it can be removed.
Remove the unused IORT linker section probing infrastructure
from the kernel to complete the ACPI IORT IOMMU configure probe
deferral mechanism implementation.
Tested-by: Hanjun Guo <hanjun.guo-QSEj5FYQhm4dnm+yROfE0A@public.gmane.org>
Signed-off-by: Lorenzo Pieralisi <lorenzo.pieralisi-5wv7dgnIgG8@public.gmane.org>
Cc: Robin Murphy <robin.murphy-5wv7dgnIgG8@public.gmane.org>
Cc: Sricharan R <sricharan-sgV2jX0FEOL9JmXXK+q4OQ@public.gmane.org>
---
drivers/acpi/arm64/iort.c | 2 --
include/asm-generic/vmlinux.lds.h | 1 -
include/linux/acpi_iort.h | 3 ---
3 files changed, 6 deletions(-)
diff --git a/drivers/acpi/arm64/iort.c b/drivers/acpi/arm64/iort.c
index e323ece..e7b1940 100644
--- a/drivers/acpi/arm64/iort.c
+++ b/drivers/acpi/arm64/iort.c
@@ -1000,6 +1000,4 @@ void __init acpi_iort_init(void)
}
iort_init_platform_devices();
-
- acpi_probe_device_table(iort);
}
diff --git a/include/asm-generic/vmlinux.lds.h b/include/asm-generic/vmlinux.lds.h
index 0968d13..9faa26c 100644
--- a/include/asm-generic/vmlinux.lds.h
+++ b/include/asm-generic/vmlinux.lds.h
@@ -566,7 +566,6 @@
IRQCHIP_OF_MATCH_TABLE() \
ACPI_PROBE_TABLE(irqchip) \
ACPI_PROBE_TABLE(clksrc) \
- ACPI_PROBE_TABLE(iort) \
EARLYCON_TABLE()
#define INIT_TEXT \
diff --git a/include/linux/acpi_iort.h b/include/linux/acpi_iort.h
index 77e0809..f167e1d04 100644
--- a/include/linux/acpi_iort.h
+++ b/include/linux/acpi_iort.h
@@ -52,7 +52,4 @@ const struct iommu_ops *iort_iommu_configure(struct device *dev)
{ return NULL; }
#endif
-#define IORT_ACPI_DECLARE(name, table_id, fn) \
- ACPI_DECLARE_PROBE_ENTRY(iort, name, table_id, 0, NULL, 0, fn)
-
#endif /* __ACPI_IORT_H__ */
--
QUALCOMM INDIA, on behalf of Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum, hosted by The Linux Foundation
^ permalink raw reply related
* [PATCH V10 11/12] iommu/arm-smmu: Clean up early-probing workarounds
From: Sricharan R @ 2017-04-04 10:18 UTC (permalink / raw)
To: robin.murphy-5wv7dgnIgG8, will.deacon-5wv7dgnIgG8,
joro-zLv9SwRftAIdnm+yROfE0A, lorenzo.pieralisi-5wv7dgnIgG8,
iommu-cunTk1MwBs9QetFLy7KEm3xJsTq8ys+cHZ5vskTnxNA,
linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r,
linux-arm-msm-u79uwXL29TY76Z2rM5mHXA,
m.szyprowski-Sze3O3UU22JBDgjK7y7TUQ,
bhelgaas-hpIqsD4AKlfQT0dZR+AlfA, linux-pci-u79uwXL29TY76Z2rM5mHXA,
linux-acpi-u79uwXL29TY76Z2rM5mHXA, tn-nYOzD4b6Jr9Wk0Htik3J/w,
hanjun.guo-QSEj5FYQhm4dnm+yROfE0A, okaya-sgV2jX0FEOL9JmXXK+q4OQ,
robh+dt-DgEjT+Ai2ygdnm+yROfE0A,
frowand.list-Re5JQEeQqe8AvxtiuMwx3w,
devicetree-u79uwXL29TY76Z2rM5mHXA,
linux-kernel-u79uwXL29TY76Z2rM5mHXA, sudeep.holla-5wv7dgnIgG8,
rjw-LthD3rsA81gm4RdzfppkhA, lenb-DgEjT+Ai2ygdnm+yROfE0A,
catalin.marinas-5wv7dgnIgG8, arnd-r2nGTMty4D4,
linux-arch-u79uwXL29TY76Z2rM5mHXA,
gregkh-hQyY1W1yCW8ekmWlsbkhG0B+6BGkLq7r
In-Reply-To: <1491301105-5274-1-git-send-email-sricharan-sgV2jX0FEOL9JmXXK+q4OQ@public.gmane.org>
From: Robin Murphy <robin.murphy-5wv7dgnIgG8@public.gmane.org>
Now that the appropriate ordering is enforced via probe-deferral of
masters in core code, rip it all out and bask in the simplicity.
Tested-by: Hanjun Guo <hanjun.guo-QSEj5FYQhm4dnm+yROfE0A@public.gmane.org>
Acked-by: Will Deacon <will.deacon-5wv7dgnIgG8@public.gmane.org>
Signed-off-by: Robin Murphy <robin.murphy-5wv7dgnIgG8@public.gmane.org>
[Sricharan: Rebased on top of ACPI IORT SMMU series]
Signed-off-by: Sricharan R <sricharan-sgV2jX0FEOL9JmXXK+q4OQ@public.gmane.org>
---
drivers/iommu/arm-smmu-v3.c | 46 +-----------------
drivers/iommu/arm-smmu.c | 110 +++++++++++++++++++-------------------------
2 files changed, 49 insertions(+), 107 deletions(-)
diff --git a/drivers/iommu/arm-smmu-v3.c b/drivers/iommu/arm-smmu-v3.c
index 591bb96..4362139 100644
--- a/drivers/iommu/arm-smmu-v3.c
+++ b/drivers/iommu/arm-smmu-v3.c
@@ -2761,51 +2761,9 @@ static int arm_smmu_device_remove(struct platform_device *pdev)
.probe = arm_smmu_device_probe,
.remove = arm_smmu_device_remove,
};
+module_platform_driver(arm_smmu_driver);
-static int __init arm_smmu_init(void)
-{
- static bool registered;
- int ret = 0;
-
- if (!registered) {
- ret = platform_driver_register(&arm_smmu_driver);
- registered = !ret;
- }
- return ret;
-}
-
-static void __exit arm_smmu_exit(void)
-{
- return platform_driver_unregister(&arm_smmu_driver);
-}
-
-subsys_initcall(arm_smmu_init);
-module_exit(arm_smmu_exit);
-
-static int __init arm_smmu_of_init(struct device_node *np)
-{
- int ret = arm_smmu_init();
-
- if (ret)
- return ret;
-
- if (!of_platform_device_create(np, NULL, platform_bus_type.dev_root))
- return -ENODEV;
-
- return 0;
-}
-IOMMU_OF_DECLARE(arm_smmuv3, "arm,smmu-v3", arm_smmu_of_init);
-
-#ifdef CONFIG_ACPI
-static int __init acpi_smmu_v3_init(struct acpi_table_header *table)
-{
- if (iort_node_match(ACPI_IORT_NODE_SMMU_V3))
- return arm_smmu_init();
-
- return 0;
-}
-IORT_ACPI_DECLARE(arm_smmu_v3, ACPI_SIG_IORT, acpi_smmu_v3_init);
-#endif
+IOMMU_OF_DECLARE(arm_smmuv3, "arm,smmu-v3", NULL);
MODULE_DESCRIPTION("IOMMU API for ARM architected SMMUv3 implementations");
MODULE_AUTHOR("Will Deacon <will.deacon-5wv7dgnIgG8@public.gmane.org>");
diff --git a/drivers/iommu/arm-smmu.c b/drivers/iommu/arm-smmu.c
index b493c99..792fe7d 100644
--- a/drivers/iommu/arm-smmu.c
+++ b/drivers/iommu/arm-smmu.c
@@ -2075,6 +2075,23 @@ static int arm_smmu_device_dt_probe(struct platform_device *pdev,
return 0;
}
+static void arm_smmu_bus_init(void)
+{
+ /* Oh, for a proper bus abstraction */
+ if (!iommu_present(&platform_bus_type))
+ bus_set_iommu(&platform_bus_type, &arm_smmu_ops);
+#ifdef CONFIG_ARM_AMBA
+ if (!iommu_present(&amba_bustype))
+ bus_set_iommu(&amba_bustype, &arm_smmu_ops);
+#endif
+#ifdef CONFIG_PCI
+ if (!iommu_present(&pci_bus_type)) {
+ pci_request_acs();
+ bus_set_iommu(&pci_bus_type, &arm_smmu_ops);
+ }
+#endif
+}
+
static int arm_smmu_device_probe(struct platform_device *pdev)
{
struct resource *res;
@@ -2180,21 +2197,30 @@ static int arm_smmu_device_probe(struct platform_device *pdev)
arm_smmu_device_reset(smmu);
arm_smmu_test_smr_masks(smmu);
- /* Oh, for a proper bus abstraction */
- if (!iommu_present(&platform_bus_type))
- bus_set_iommu(&platform_bus_type, &arm_smmu_ops);
-#ifdef CONFIG_ARM_AMBA
- if (!iommu_present(&amba_bustype))
- bus_set_iommu(&amba_bustype, &arm_smmu_ops);
-#endif
-#ifdef CONFIG_PCI
- if (!iommu_present(&pci_bus_type)) {
- pci_request_acs();
- bus_set_iommu(&pci_bus_type, &arm_smmu_ops);
- }
-#endif
+ /*
+ * For ACPI and generic DT bindings, an SMMU will be probed before
+ * any device which might need it, so we want the bus ops in place
+ * ready to handle default domain setup as soon as any SMMU exists.
+ */
+ if (!using_legacy_binding)
+ arm_smmu_bus_init();
+
+ return 0;
+}
+
+/*
+ * With the legacy DT binding in play, though, we have no guarantees about
+ * probe order, but then we're also not doing default domains, so we can
+ * delay setting bus ops until we're sure every possible SMMU is ready,
+ * and that way ensure that no add_device() calls get missed.
+ */
+static int arm_smmu_legacy_bus_init(void)
+{
+ if (using_legacy_binding)
+ arm_smmu_bus_init();
return 0;
}
+device_initcall_sync(arm_smmu_legacy_bus_init);
static int arm_smmu_device_remove(struct platform_device *pdev)
{
@@ -2219,56 +2245,14 @@ static int arm_smmu_device_remove(struct platform_device *pdev)
.probe = arm_smmu_device_probe,
.remove = arm_smmu_device_remove,
};
-
-static int __init arm_smmu_init(void)
-{
- static bool registered;
- int ret = 0;
-
- if (!registered) {
- ret = platform_driver_register(&arm_smmu_driver);
- registered = !ret;
- }
- return ret;
-}
-
-static void __exit arm_smmu_exit(void)
-{
- return platform_driver_unregister(&arm_smmu_driver);
-}
-
-subsys_initcall(arm_smmu_init);
-module_exit(arm_smmu_exit);
-
-static int __init arm_smmu_of_init(struct device_node *np)
-{
- int ret = arm_smmu_init();
-
- if (ret)
- return ret;
-
- if (!of_platform_device_create(np, NULL, platform_bus_type.dev_root))
- return -ENODEV;
-
- return 0;
-}
-IOMMU_OF_DECLARE(arm_smmuv1, "arm,smmu-v1", arm_smmu_of_init);
-IOMMU_OF_DECLARE(arm_smmuv2, "arm,smmu-v2", arm_smmu_of_init);
-IOMMU_OF_DECLARE(arm_mmu400, "arm,mmu-400", arm_smmu_of_init);
-IOMMU_OF_DECLARE(arm_mmu401, "arm,mmu-401", arm_smmu_of_init);
-IOMMU_OF_DECLARE(arm_mmu500, "arm,mmu-500", arm_smmu_of_init);
-IOMMU_OF_DECLARE(cavium_smmuv2, "cavium,smmu-v2", arm_smmu_of_init);
-
-#ifdef CONFIG_ACPI
-static int __init arm_smmu_acpi_init(struct acpi_table_header *table)
-{
- if (iort_node_match(ACPI_IORT_NODE_SMMU))
- return arm_smmu_init();
-
- return 0;
-}
-IORT_ACPI_DECLARE(arm_smmu, ACPI_SIG_IORT, arm_smmu_acpi_init);
-#endif
+module_platform_driver(arm_smmu_driver);
+
+IOMMU_OF_DECLARE(arm_smmuv1, "arm,smmu-v1", NULL);
+IOMMU_OF_DECLARE(arm_smmuv2, "arm,smmu-v2", NULL);
+IOMMU_OF_DECLARE(arm_mmu400, "arm,mmu-400", NULL);
+IOMMU_OF_DECLARE(arm_mmu401, "arm,mmu-401", NULL);
+IOMMU_OF_DECLARE(arm_mmu500, "arm,mmu-500", NULL);
+IOMMU_OF_DECLARE(cavium_smmuv2, "cavium,smmu-v2", NULL);
MODULE_DESCRIPTION("IOMMU API for ARM architected SMMU implementations");
MODULE_AUTHOR("Will Deacon <will.deacon-5wv7dgnIgG8@public.gmane.org>");
--
QUALCOMM INDIA, on behalf of Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum, hosted by The Linux Foundation
^ permalink raw reply related
* [PATCH V10 10/12] arm64: dma-mapping: Remove the notifier trick to handle early setting of dma_ops
From: Sricharan R @ 2017-04-04 10:18 UTC (permalink / raw)
To: robin.murphy-5wv7dgnIgG8, will.deacon-5wv7dgnIgG8,
joro-zLv9SwRftAIdnm+yROfE0A, lorenzo.pieralisi-5wv7dgnIgG8,
iommu-cunTk1MwBs9QetFLy7KEm3xJsTq8ys+cHZ5vskTnxNA,
linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r,
linux-arm-msm-u79uwXL29TY76Z2rM5mHXA,
m.szyprowski-Sze3O3UU22JBDgjK7y7TUQ,
bhelgaas-hpIqsD4AKlfQT0dZR+AlfA, linux-pci-u79uwXL29TY76Z2rM5mHXA,
linux-acpi-u79uwXL29TY76Z2rM5mHXA, tn-nYOzD4b6Jr9Wk0Htik3J/w,
hanjun.guo-QSEj5FYQhm4dnm+yROfE0A, okaya-sgV2jX0FEOL9JmXXK+q4OQ,
robh+dt-DgEjT+Ai2ygdnm+yROfE0A,
frowand.list-Re5JQEeQqe8AvxtiuMwx3w,
devicetree-u79uwXL29TY76Z2rM5mHXA,
linux-kernel-u79uwXL29TY76Z2rM5mHXA, sudeep.holla-5wv7dgnIgG8,
rjw-LthD3rsA81gm4RdzfppkhA, lenb-DgEjT+Ai2ygdnm+yROfE0A,
catalin.marinas-5wv7dgnIgG8, arnd-r2nGTMty4D4,
linux-arch-u79uwXL29TY76Z2rM5mHXA,
gregkh-hQyY1W1yCW8ekmWlsbkhG0B+6BGkLq7r
In-Reply-To: <1491301105-5274-1-git-send-email-sricharan-sgV2jX0FEOL9JmXXK+q4OQ@public.gmane.org>
With arch_setup_dma_ops now being called late during device's probe after
the device's iommu is probed, the notifier trick required to handle the
early setup of dma_ops before the iommu group gets created is not
required. So removing the notifier's here.
Tested-by: Marek Szyprowski <m.szyprowski-Sze3O3UU22JBDgjK7y7TUQ@public.gmane.org>
Tested-by: Hanjun Guo <hanjun.guo-QSEj5FYQhm4dnm+yROfE0A@public.gmane.org>
Acked-by: Will Deacon <will.deacon-5wv7dgnIgG8@public.gmane.org>
Signed-off-by: Sricharan R <sricharan-sgV2jX0FEOL9JmXXK+q4OQ@public.gmane.org>
[rm: clean up even more]
Signed-off-by: Robin Murphy <robin.murphy-5wv7dgnIgG8@public.gmane.org>
---
arch/arm64/mm/dma-mapping.c | 142 ++++++--------------------------------------
1 file changed, 18 insertions(+), 124 deletions(-)
diff --git a/arch/arm64/mm/dma-mapping.c b/arch/arm64/mm/dma-mapping.c
index 81cdb2e..b465759 100644
--- a/arch/arm64/mm/dma-mapping.c
+++ b/arch/arm64/mm/dma-mapping.c
@@ -813,34 +813,26 @@ static void __iommu_unmap_sg_attrs(struct device *dev,
.mapping_error = iommu_dma_mapping_error,
};
-/*
- * TODO: Right now __iommu_setup_dma_ops() gets called too early to do
- * everything it needs to - the device is only partially created and the
- * IOMMU driver hasn't seen it yet, so it can't have a group. Thus we
- * need this delayed attachment dance. Once IOMMU probe ordering is sorted
- * to move the arch_setup_dma_ops() call later, all the notifier bits below
- * become unnecessary, and will go away.
- */
-struct iommu_dma_notifier_data {
- struct list_head list;
- struct device *dev;
- const struct iommu_ops *ops;
- u64 dma_base;
- u64 size;
-};
-static LIST_HEAD(iommu_dma_masters);
-static DEFINE_MUTEX(iommu_dma_notifier_lock);
+static int __init __iommu_dma_init(void)
+{
+ return iommu_dma_init();
+}
+arch_initcall(__iommu_dma_init);
-static bool do_iommu_attach(struct device *dev, const struct iommu_ops *ops,
- u64 dma_base, u64 size)
+static void __iommu_setup_dma_ops(struct device *dev, u64 dma_base, u64 size,
+ const struct iommu_ops *ops)
{
- struct iommu_domain *domain = iommu_get_domain_for_dev(dev);
+ struct iommu_domain *domain;
+
+ if (!ops)
+ return;
/*
- * If the IOMMU driver has the DMA domain support that we require,
- * then the IOMMU core will have already configured a group for this
- * device, and allocated the default domain for that group.
+ * The IOMMU core code allocates the default DMA domain, which the
+ * underlying IOMMU driver needs to support via the dma-iommu layer.
*/
+ domain = iommu_get_domain_for_dev(dev);
+
if (!domain)
goto out_err;
@@ -851,109 +843,11 @@ static bool do_iommu_attach(struct device *dev, const struct iommu_ops *ops,
dev->dma_ops = &iommu_dma_ops;
}
- return true;
+ return;
+
out_err:
- pr_warn("Failed to set up IOMMU for device %s; retaining platform DMA ops\n",
+ pr_warn("Failed to set up IOMMU for device %s; retaining platform DMA ops\n",
dev_name(dev));
- return false;
-}
-
-static void queue_iommu_attach(struct device *dev, const struct iommu_ops *ops,
- u64 dma_base, u64 size)
-{
- struct iommu_dma_notifier_data *iommudata;
-
- iommudata = kzalloc(sizeof(*iommudata), GFP_KERNEL);
- if (!iommudata)
- return;
-
- iommudata->dev = dev;
- iommudata->ops = ops;
- iommudata->dma_base = dma_base;
- iommudata->size = size;
-
- mutex_lock(&iommu_dma_notifier_lock);
- list_add(&iommudata->list, &iommu_dma_masters);
- mutex_unlock(&iommu_dma_notifier_lock);
-}
-
-static int __iommu_attach_notifier(struct notifier_block *nb,
- unsigned long action, void *data)
-{
- struct iommu_dma_notifier_data *master, *tmp;
-
- if (action != BUS_NOTIFY_BIND_DRIVER)
- return 0;
-
- mutex_lock(&iommu_dma_notifier_lock);
- list_for_each_entry_safe(master, tmp, &iommu_dma_masters, list) {
- if (data == master->dev && do_iommu_attach(master->dev,
- master->ops, master->dma_base, master->size)) {
- list_del(&master->list);
- kfree(master);
- break;
- }
- }
- mutex_unlock(&iommu_dma_notifier_lock);
- return 0;
-}
-
-static int __init register_iommu_dma_ops_notifier(struct bus_type *bus)
-{
- struct notifier_block *nb = kzalloc(sizeof(*nb), GFP_KERNEL);
- int ret;
-
- if (!nb)
- return -ENOMEM;
-
- nb->notifier_call = __iommu_attach_notifier;
-
- ret = bus_register_notifier(bus, nb);
- if (ret) {
- pr_warn("Failed to register DMA domain notifier; IOMMU DMA ops unavailable on bus '%s'\n",
- bus->name);
- kfree(nb);
- }
- return ret;
-}
-
-static int __init __iommu_dma_init(void)
-{
- int ret;
-
- ret = iommu_dma_init();
- if (!ret)
- ret = register_iommu_dma_ops_notifier(&platform_bus_type);
- if (!ret)
- ret = register_iommu_dma_ops_notifier(&amba_bustype);
-#ifdef CONFIG_PCI
- if (!ret)
- ret = register_iommu_dma_ops_notifier(&pci_bus_type);
-#endif
- return ret;
-}
-arch_initcall(__iommu_dma_init);
-
-static void __iommu_setup_dma_ops(struct device *dev, u64 dma_base, u64 size,
- const struct iommu_ops *ops)
-{
- struct iommu_group *group;
-
- if (!ops)
- return;
- /*
- * TODO: As a concession to the future, we're ready to handle being
- * called both early and late (i.e. after bus_add_device). Once all
- * the platform bus code is reworked to call us late and the notifier
- * junk above goes away, move the body of do_iommu_attach here.
- */
- group = iommu_group_get(dev);
- if (group) {
- do_iommu_attach(dev, ops, dma_base, size);
- iommu_group_put(group);
- } else {
- queue_iommu_attach(dev, ops, dma_base, size);
- }
}
void arch_teardown_dma_ops(struct device *dev)
--
QUALCOMM INDIA, on behalf of Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum, hosted by The Linux Foundation
^ permalink raw reply related
page: next (older) | prev (newer) | latest
- recent:[subjects (threaded)|topics (new)|topics (active)]
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox