* Re: [PATCH v6 1/5] irqchip/aspeed-i2c-ic: binding docs for Aspeed I2C Interrupt Controller
From: Brendan Higgins @ 2017-03-29 20:51 UTC (permalink / raw)
To: Benjamin Herrenschmidt
Cc: Wolfram Sang, Rob Herring, Mark Rutland, Thomas Gleixner,
Jason Cooper, Marc Zyngier, Joel Stanley, Vladimir Zapolskiy,
Kachalov Anton, Cédric Le Goater, linux-i2c, devicetree,
Linux Kernel Mailing List, OpenBMC Maillist
In-Reply-To: <1490789505.3177.184.camel@kernel.crashing.org>
> Regarding the other comment about the "fast mode", my main worry here
> is that somebody might come up with a 2Mhz capable device, we'll hit
> your 1Mhz test, enable fast mode, and shoot it with 3.4Mhz which it
> might not be happy at all about...
>
> I think the cut-off for switching to the "fast" mode should basically
> be the fast speed mode frequency (which isn't clear from the spec but
> seems to be 3.4Mhz). Otherwise people will end up with higher speeds
> than what they asked for and that's bad.
Ah, but see the documentation only says that high speed mode sets the
Base Clock divisor to zero; is does not say anything about tCKHigh or
tCKLow (clk_high and clk_low in my code respectively), which are the
only parameters which are manipulated for speeds greater than or equal
to 1.5MHz since:
# I forgot the "APB_freq /" part in the comment on my
aspeed_i2c_get_clk_reg_val(...)
# My function still does the computation correctly, I just forgot this
in the comment.
SCL_freq = APB_freq / (1 << base_clk) * (clk_high + 1 + clk_low + 1)
so if base_clk = 0, clk_high = 15, clk_low = 15, APB_freq = 50MHz
SCL_freq = APB_freq / (1 << base_clk) * (clk_high + 1 + clk_low + 1)
= 50000000 / (1 << 0) * (15 + 1 + 15 + 1)
= 50000000 / 32
= 1562500Hz
= ~1.5MHz
so maybe instead of setting a hard limit like I did, maybe the best
thing is to just check and see what the base_clk gets set to and if it
gets set to zero, we turn on high speed mode. What do you think?
Cheers
^ permalink raw reply
* Re: [PATCH v3 1/7] pinctrl: dt-bindings: Add documentation for Armada 37xx pin controllers
From: Rob Herring @ 2017-03-29 21:11 UTC (permalink / raw)
To: Gregory CLEMENT
Cc: Thomas Petazzoni, Andrew Lunn, Jason Cooper, devicetree,
Linus Walleij, linux-kernel, Nadav Haklai, linux-gpio, Victor Gu,
Neta Zur Hershkovits, Hua Jing, Marcin Wojtas, Wilson Ding,
linux-arm-kernel, Sebastian Hesselbarth
In-Reply-To: <941d03c9a3bdfd5e789aada29b35184ec9fed9fe.1490282185.git-series.gregory.clement@free-electrons.com>
On Thu, Mar 23, 2017 at 04:19:01PM +0100, Gregory CLEMENT wrote:
> Document the device tree binding for the pin controllers found on the
> Armada 37xx SoCs.
>
> Update the binding documention of the xtal clk which is a subnode of this
> syscon node.
>
> Signed-off-by: Gregory CLEMENT <gregory.clement@free-electrons.com>
> ---
> Documentation/devicetree/bindings/clock/armada3700-xtal-clock.txt | 7 +--
> Documentation/devicetree/bindings/pinctrl/marvell,armada-37xx-pinctrl.txt | 183 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++-
> 2 files changed, 187 insertions(+), 3 deletions(-)
> create mode 100644 Documentation/devicetree/bindings/pinctrl/marvell,armada-37xx-pinctrl.txt
>
> diff --git a/Documentation/devicetree/bindings/clock/armada3700-xtal-clock.txt b/Documentation/devicetree/bindings/clock/armada3700-xtal-clock.txt
> index a88f1f05fbd6..4c0807f28cfa 100644
> --- a/Documentation/devicetree/bindings/clock/armada3700-xtal-clock.txt
> +++ b/Documentation/devicetree/bindings/clock/armada3700-xtal-clock.txt
> @@ -5,6 +5,7 @@ reading the gpio latch register.
>
> This node must be a subnode of the node exposing the register address
> of the GPIO block where the gpio latch is located.
> +See Documentation/devicetree/bindings/pinctrl/marvell,armada-37xx-pinctrl.txt
>
> Required properties:
> - compatible : shall be one of the following:
> @@ -16,9 +17,9 @@ Optional properties:
> output names ("xtal")
>
> Example:
> -gpio1: gpio@13800 {
> - compatible = "marvell,armada-3700-gpio", "syscon", "simple-mfd";
> - reg = <0x13800 0x1000>;
> +pinctrl_nb: pinctrl-nb@13800 {
> + compatible = "armada3710-nb-pinctrl", "syscon", "simple-mfd";
> + reg = <0x13800 0x100>, <0x13C00 0x20>;
>
> xtalclk: xtal-clk {
> compatible = "marvell,armada-3700-xtal-clock";
> diff --git a/Documentation/devicetree/bindings/pinctrl/marvell,armada-37xx-pinctrl.txt b/Documentation/devicetree/bindings/pinctrl/marvell,armada-37xx-pinctrl.txt
> new file mode 100644
> index 000000000000..2eda81e0bca1
> --- /dev/null
> +++ b/Documentation/devicetree/bindings/pinctrl/marvell,armada-37xx-pinctrl.txt
> @@ -0,0 +1,183 @@
> +* Marvell Armada 37xx SoC pin and gpio controller
> +
> +Each Armada 37xx SoC come with two pin and gpio controller one for the
> +south bridge and the other for the north bridge.
> +
> +Inside this set of register the gpio latch allows exposing some
> +configuration of the SoC and especially the clock frequency of the
> +xtal. Hence, this node is a represent as syscon allowing sharing the
> +register between multiple hardware block.
> +
> +GPIO and pin controller:
> +------------------------
> +
> +Main node:
> +
> +Refer to pinctrl-bindings.txt in this directory for details of the
> +common pinctrl bindings used by client devices, including the meaning
> +of the phrase "pin configuration node".
> +
> +Required properties for pinctrl driver:
> +
> +- compatible: "marvell,armada3710-sb-pinctrl", "syscon, "simple-mfd"
> + for the south bridge
> + "marvell,armada3710-nb-pinctrl", "syscon, "simple-mfd"
> + for the north bridge
> +- reg: The first set of register are for pinctrl/gpio and the second
> + set for the interrupt controller
> +- interrupts: list of the interrupt use by the gpio
> +
> +Available groups and functions for the North bridge:
> +
> +group: jtag
> + - pins 20-24
> + - functions jtag, gpio
> +
> +group sdio0
> + - pins 8-10
> + - functions sdio, gpio
> +
> +group emmc_nb
> + - pins 27-35
> + - functions emmc, gpio
> +
> +group pwm0
> + - pin 11 (GPIO1-11)
> + - functions pwm, gpio
> +
> +group pwm1
> + - pin 12
> + - functions pwm, gpio
> +
> +group pwm2
> + - pin 13
> + - functions pwm, gpio
> +
> +group pwm3
> + - pin 14
> + - functions pwm, gpio
> +
> +group pmic1
> + - pin 17
> + - functions pmic, gpio
> +
> +group pmic0
> + - pin 16
> + - functions pmic, gpio
> +
> +group i2c2
> + - pins 2-3
> + - functions i2c, gpio
> +
> +group i2c1
> + - pins 0-1
> + - functions i2c, gpio
> +
> +group spi_cs1
> + - pin 17
> + - functions spi, gpio
> +
> +group spi_cs2
> + - pin 18
> + - functions spi, gpio
> +
> +group spi_cs3
> + - pin 19
> + - functions spi, gpio
> +
> +group onewire
> + - pin 4
> + - functions onewire, gpio
> +
> +group uart1
> + - pins 25-26
> + - functions uart, gpio
> +
> +group spi_quad
> + - pins 15-16
> + - functions spi, gpio
> +
> +group uart_2
> + - pins 9-10
> + - functions uart, gpio
> +
> +Available groups and functions for the South bridge:
> +
> +group usb32_drvvbus0
> + - pin 36
> + - functions drvbus, gpio
> +
> +group usb2_drvvbus1
> + - pin 37
> + - functions drvbus, gpio
> +
> +group sdio_sb
> + - pins 60-64
> + - functions sdio, gpio
> +
> +group rgmii
> + - pins 42-55
> + - functions mii, gpio
> +
> +group pcie1
> + - pins 39-40
> + - functions pcie, gpio
> +
> +group ptp
> + - pins 56-58
> + - functions ptp, gpio
> +
> +group ptp_clk
> + - pin 57
> + - functions ptp, mii
> +
> +group ptp_trig
> + - pin 58
> + - functions ptp, mii
> +
> +group mii_col
> + - pin 59
> + - functions mii, mii_err
> +
> +GPIO subnode:
> +
> +Please refer to gpio.txt in this directory for details of gpio-ranges property
> +and the common GPIO bindings used by client devices.
> +
> +Required properties for gpio driver under the gpio subnode:
Why does this need to be a sub node? You should probably have a
compatible if it is.
> +- interrupts: List of interrupt specifier for the controllers interrupt.
> +- gpio-controller: Marks the device node as a gpio controller.
> +- #gpio-cells: Should be 2. The first cell is the GPIO number and the
> + second cell specifies GPIO flags, as defined in
> + <dt-bindings/gpio/gpio.h>. Only the GPIO_ACTIVE_HIGH and
> + GPIO_ACTIVE_LOW flags are supported.
> +- gpio-ranges: Range of pins managed by the GPIO controller.
> +
> +Xtal Clock bindings for Marvell Armada 37xx SoCs
> +------------------------------------------------
> +
> +see Documentation/devicetree/bindings/clock/armada3700-xtal-clock.txt
> +
> +
> +Example:
> +pinctrl_sb: pinctrl-sb@18800 {
pinctrl@
> + compatible = "marvell,armada3710-sb-pinctrl", "syscon", "simple-mfd";
> + reg = <0x18800 0x100>, <0x18C00 0x20>;
> + gpiosb: gpiosb {
gpio@
> + #gpio-cells = <2>;
> + gpio-ranges = <&pinctrl_sb 0 0 29>;
> + gpio-controller;
> + interrupts =
> + <GIC_SPI 160 IRQ_TYPE_LEVEL_HIGH>,
> + <GIC_SPI 159 IRQ_TYPE_LEVEL_HIGH>,
> + <GIC_SPI 158 IRQ_TYPE_LEVEL_HIGH>,
> + <GIC_SPI 157 IRQ_TYPE_LEVEL_HIGH>,
> + <GIC_SPI 156 IRQ_TYPE_LEVEL_HIGH>;
> + };
> +
> + rgmii_pins: mii-pins {
> + groups = "rgmii";
> + function = "mii";
> + };
> +
> +};
> --
> git-series 0.9.1
^ permalink raw reply
* Re: [PATCH v4 1/2] dt-bindings: Add INNOLUX P079ZCA panel bindings
From: Rob Herring @ 2017-03-29 21:12 UTC (permalink / raw)
To: Chris Zhong
Cc: Mark Rutland, devicetree, linux-kernel, dri-devel, linux-rockchip
In-Reply-To: <1490316692-20506-1-git-send-email-zyw@rock-chips.com>
On Fri, Mar 24, 2017 at 08:51:31AM +0800, Chris Zhong wrote:
> The Innolux P079ZCA is a 7.85" panel with a 768X1024 resolution and
> connected to DSI using four lanes.
>
> Signed-off-by: Chris Zhong <zyw@rock-chips.com>
> Reviewed-by: Brian Norris <briannorris@chromium.org>
> ---
>
> Changes in v4: None
> Changes in v3: None
> Changes in v2: None
>
> .../bindings/display/panel/innolux,p079zca.txt | 23 ++++++++++++++++++++++
> 1 file changed, 23 insertions(+)
> create mode 100644 Documentation/devicetree/bindings/display/panel/innolux,p079zca.txt
Acked-by: Rob Herring <robh@kernel.org>
_______________________________________________
dri-devel mailing list
dri-devel@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/dri-devel
^ permalink raw reply
* [RFC PATCH 0/5] soc/fsl/qbman: Rework private memory allocations
From: Roy Pledge @ 2017-03-29 21:13 UTC (permalink / raw)
To: robin.murphy-5wv7dgnIgG8, oss-fOR+EgIDQEHk1uMJSBkQmQ,
linuxppc-dev-uLR06cmDAlY/bJ5BZ2RsiQ,
linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r,
devicetree-u79uwXL29TY76Z2rM5mHXA
Cc: madalin.bucur-3arQi8VN3Tc, Roy Pledge
The QBMan device requires three separate memory areas that are only
accessed by the device. These areas are reserved using the OF reserved
memory mechanism and associated to the device in the device trees
memory-region attribute. However in order to be allocatable using
the dma_alloc() APIs the reservations compatiable string must
include "shared-dma-pool" and specify "no-map".
This set of changes updates the QBMan driver, PPC device trees and
bindings to use the above mechasism. This work was encouraged as part
of preparing this driver to work on ARM processors.
Roy Pledge (5):
soc/fsl/qbman: Use shared-dma-pool for BMan private memory allocations
soc/fsl/qbman: Use shared-dma-pool for QMan private memory allocations
dts: arch/powerpc: Update Freescale DTS for QBMan memory allocations
dt-bindings: soc/fsl: Update reserved memory binding for QBMan
powerpc: Add HAVE_GENERIC_DMA_COHERENT options to Kconfig
Documentation/devicetree/bindings/soc/fsl/bman.txt | 10 +-
Documentation/devicetree/bindings/soc/fsl/qman.txt | 16 +--
arch/powerpc/Kconfig | 1 +
arch/powerpc/boot/dts/fsl/b4qds.dtsi | 6 ++
arch/powerpc/boot/dts/fsl/b4si-post.dtsi | 15 ---
arch/powerpc/boot/dts/fsl/cyrus_p5020.dts | 6 ++
arch/powerpc/boot/dts/fsl/kmcent2.dts | 6 ++
arch/powerpc/boot/dts/fsl/kmcoge4.dts | 6 ++
arch/powerpc/boot/dts/fsl/oca4080.dts | 6 ++
arch/powerpc/boot/dts/fsl/p1023rdb.dts | 6 ++
arch/powerpc/boot/dts/fsl/p1023si-post.dtsi | 15 ---
arch/powerpc/boot/dts/fsl/p2041rdb.dts | 6 ++
arch/powerpc/boot/dts/fsl/p2041si-post.dtsi | 15 ---
arch/powerpc/boot/dts/fsl/p3041ds.dts | 6 ++
arch/powerpc/boot/dts/fsl/p3041si-post.dtsi | 15 ---
arch/powerpc/boot/dts/fsl/p4080ds.dts | 6 ++
arch/powerpc/boot/dts/fsl/p4080si-post.dtsi | 15 ---
arch/powerpc/boot/dts/fsl/p5020ds.dts | 6 ++
arch/powerpc/boot/dts/fsl/p5020si-post.dtsi | 15 ---
arch/powerpc/boot/dts/fsl/p5040ds.dts | 6 ++
arch/powerpc/boot/dts/fsl/p5040si-post.dtsi | 15 ---
arch/powerpc/boot/dts/fsl/t1023rdb.dts | 6 ++
arch/powerpc/boot/dts/fsl/t1023si-post.dtsi | 15 ---
arch/powerpc/boot/dts/fsl/t1024qds.dts | 6 ++
arch/powerpc/boot/dts/fsl/t1024rdb.dts | 6 ++
arch/powerpc/boot/dts/fsl/t1040si-post.dtsi | 15 ---
arch/powerpc/boot/dts/fsl/t104xd4rdb.dtsi | 6 ++
arch/powerpc/boot/dts/fsl/t104xqds.dtsi | 6 ++
arch/powerpc/boot/dts/fsl/t104xrdb.dtsi | 6 ++
arch/powerpc/boot/dts/fsl/t2081si-post.dtsi | 15 ---
arch/powerpc/boot/dts/fsl/t208xqds.dtsi | 6 ++
arch/powerpc/boot/dts/fsl/t208xrdb.dtsi | 6 ++
arch/powerpc/boot/dts/fsl/t4240qds.dts | 6 ++
arch/powerpc/boot/dts/fsl/t4240rdb.dts | 6 ++
arch/powerpc/boot/dts/fsl/t4240si-post.dtsi | 15 ---
drivers/soc/fsl/qbman/bman_ccsr.c | 27 ++++-
drivers/soc/fsl/qbman/bman_priv.h | 3 +
drivers/soc/fsl/qbman/qman_ccsr.c | 119 ++++++++++++---------
drivers/soc/fsl/qbman/qman_priv.h | 4 +-
drivers/soc/fsl/qbman/qman_test.h | 2 -
40 files changed, 238 insertions(+), 235 deletions(-)
--
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
* [RFC PATCH 1/5] soc/fsl/qbman: Use shared-dma-pool for BMan private memory allocations
From: Roy Pledge @ 2017-03-29 21:13 UTC (permalink / raw)
To: robin.murphy-5wv7dgnIgG8, oss-fOR+EgIDQEHk1uMJSBkQmQ,
linuxppc-dev-uLR06cmDAlY/bJ5BZ2RsiQ,
linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r,
devicetree-u79uwXL29TY76Z2rM5mHXA
Cc: madalin.bucur-3arQi8VN3Tc, Roy Pledge
In-Reply-To: <1490822037-6752-1-git-send-email-roy.pledge-3arQi8VN3Tc@public.gmane.org>
Use the shared-memory-pool mechanism for free buffer proxy record
area allocation.
Signed-off-by: Roy Pledge <roy.pledge-3arQi8VN3Tc@public.gmane.org>
---
drivers/soc/fsl/qbman/bman_ccsr.c | 27 ++++++++++++++++++++++++++-
drivers/soc/fsl/qbman/bman_priv.h | 3 +++
2 files changed, 29 insertions(+), 1 deletion(-)
diff --git a/drivers/soc/fsl/qbman/bman_ccsr.c b/drivers/soc/fsl/qbman/bman_ccsr.c
index a8e8389..5485c3c 100644
--- a/drivers/soc/fsl/qbman/bman_ccsr.c
+++ b/drivers/soc/fsl/qbman/bman_ccsr.c
@@ -170,10 +170,11 @@ static int fsl_bman_probe(struct platform_device *pdev)
{
int ret, err_irq;
struct device *dev = &pdev->dev;
- struct device_node *node = dev->of_node;
+ struct device_node *mem_node, *node = dev->of_node;
struct resource *res;
u16 id, bm_pool_cnt;
u8 major, minor;
+ u64 size;
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
if (!res) {
@@ -201,6 +202,30 @@ static int fsl_bman_probe(struct platform_device *pdev)
return -ENODEV;
}
+ ret = of_reserved_mem_device_init(dev);
+ if (ret) {
+ dev_err(dev, "of_reserved_mem_device_init() failed 0x%x\n", ret);
+ return -ENODEV;
+ }
+ mem_node = of_parse_phandle(dev->of_node, "memory-region", 0);
+ if (mem_node) {
+ ret = of_property_read_u64(mem_node, "size", &size);
+ if (ret) {
+ dev_err(dev, "FBPR: of_address_to_resource fails 0x%x\n", ret);
+ return -ENODEV;
+ }
+ fbpr_sz = size;
+ } else {
+ dev_err(dev, "No memory-region found for FBPR\n");
+ return -ENODEV;
+ }
+ if (!dma_zalloc_coherent(dev, fbpr_sz, &fbpr_a, 0)) {
+ dev_err(dev, "Alloc FBPR memory failed\n");
+ return -ENODEV;
+ }
+
+ dev_info(dev, "Allocated FBPR 0x%llx 0x%zx\n", fbpr_a, fbpr_sz);
+
bm_set_memory(fbpr_a, fbpr_sz);
err_irq = platform_get_irq(pdev, 0);
diff --git a/drivers/soc/fsl/qbman/bman_priv.h b/drivers/soc/fsl/qbman/bman_priv.h
index f6896a2..765a4bf 100644
--- a/drivers/soc/fsl/qbman/bman_priv.h
+++ b/drivers/soc/fsl/qbman/bman_priv.h
@@ -33,6 +33,9 @@
#include "dpaa_sys.h"
#include <soc/fsl/bman.h>
+#include <linux/dma-contiguous.h>
+#include <linux/of_address.h>
+#include <linux/dma-mapping.h>
/* Portal processing (interrupt) sources */
#define BM_PIRQ_RCRI 0x00000002 /* RCR Ring (below threshold) */
--
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
* [RFC PATCH 2/5] soc/fsl/qbman: Use shared-dma-pool for QMan private memory allocations
From: Roy Pledge @ 2017-03-29 21:13 UTC (permalink / raw)
To: robin.murphy-5wv7dgnIgG8, oss-fOR+EgIDQEHk1uMJSBkQmQ,
linuxppc-dev-uLR06cmDAlY/bJ5BZ2RsiQ,
linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r,
devicetree-u79uwXL29TY76Z2rM5mHXA
Cc: madalin.bucur-3arQi8VN3Tc, Roy Pledge
In-Reply-To: <1490822037-6752-1-git-send-email-roy.pledge-3arQi8VN3Tc@public.gmane.org>
Use the shared-memory-pool mechanism for frame queue descriptor and
packed frame descriptor record area allocations.
Signed-off-by: Roy Pledge <roy.pledge-3arQi8VN3Tc@public.gmane.org>
---
drivers/soc/fsl/qbman/qman_ccsr.c | 119 +++++++++++++++++++++-----------------
drivers/soc/fsl/qbman/qman_priv.h | 4 +-
drivers/soc/fsl/qbman/qman_test.h | 2 -
3 files changed, 68 insertions(+), 57 deletions(-)
diff --git a/drivers/soc/fsl/qbman/qman_ccsr.c b/drivers/soc/fsl/qbman/qman_ccsr.c
index 90bc40c..35c59ca 100644
--- a/drivers/soc/fsl/qbman/qman_ccsr.c
+++ b/drivers/soc/fsl/qbman/qman_ccsr.c
@@ -400,63 +400,19 @@ static int qm_init_pfdr(struct device *dev, u32 pfdr_start, u32 num)
return -ENODEV;
}
-/*
- * Ideally we would use the DMA API to turn rmem->base into a DMA address
- * (especially if iommu translations ever get involved). Unfortunately, the
- * DMA API currently does not allow mapping anything that is not backed with
- * a struct page.
- */
+/* QMan needs two global memory areas initialized at boot time:
+ 1) FQD: Frame Queue Descriptors used to manage frame queues
+ 2) PFDR: Packed Frame Queue Descriptor Records used to store frames
+ Both areas are reserved using the device tree reserved memory framework
+ and the addresses and sizes are initialized when the QMan device is probed */
static dma_addr_t fqd_a, pfdr_a;
static size_t fqd_sz, pfdr_sz;
-static int qman_fqd(struct reserved_mem *rmem)
-{
- fqd_a = rmem->base;
- fqd_sz = rmem->size;
-
- WARN_ON(!(fqd_a && fqd_sz));
-
- return 0;
-}
-RESERVEDMEM_OF_DECLARE(qman_fqd, "fsl,qman-fqd", qman_fqd);
-
-static int qman_pfdr(struct reserved_mem *rmem)
-{
- pfdr_a = rmem->base;
- pfdr_sz = rmem->size;
-
- WARN_ON(!(pfdr_a && pfdr_sz));
-
- return 0;
-}
-RESERVEDMEM_OF_DECLARE(qman_pfdr, "fsl,qman-pfdr", qman_pfdr);
-
static unsigned int qm_get_fqid_maxcnt(void)
{
return fqd_sz / 64;
}
-/*
- * Flush this memory range from data cache so that QMAN originated
- * transactions for this memory region could be marked non-coherent.
- */
-static int zero_priv_mem(struct device *dev, struct device_node *node,
- phys_addr_t addr, size_t sz)
-{
- /* map as cacheable, non-guarded */
- void __iomem *tmpp = ioremap_prot(addr, sz, 0);
-
- if (!tmpp)
- return -ENOMEM;
-
- memset_io(tmpp, 0, sz);
- flush_dcache_range((unsigned long)tmpp,
- (unsigned long)tmpp + sz);
- iounmap(tmpp);
-
- return 0;
-}
-
static void log_edata_bits(struct device *dev, u32 bit_count)
{
u32 i, j, mask = 0xffffffff;
@@ -687,11 +643,12 @@ static int qman_resource_init(struct device *dev)
static int fsl_qman_probe(struct platform_device *pdev)
{
struct device *dev = &pdev->dev;
- struct device_node *node = dev->of_node;
+ struct device_node *mem_node, *node = dev->of_node;
struct resource *res;
int ret, err_irq;
u16 id;
u8 major, minor;
+ u64 size;
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
if (!res) {
@@ -727,10 +684,66 @@ static int fsl_qman_probe(struct platform_device *pdev)
qm_channel_caam = QMAN_CHANNEL_CAAM_REV3;
}
- ret = zero_priv_mem(dev, node, fqd_a, fqd_sz);
- WARN_ON(ret);
- if (ret)
+ /* Order of memory regions is assumed as FQD followed by PFDR
+ in order to ensure allocations from the correct regions the
+ driver initializes then allocates each piece in order */
+
+ ret = of_reserved_mem_device_init_by_idx(dev, dev->of_node, 0);
+ if (ret) {
+ dev_err(dev, "of_reserved_mem_device_init_by_idx(0) failed 0x%x\n",
+ ret);
+ return -ENODEV;
+ }
+ mem_node = of_parse_phandle(dev->of_node, "memory-region", 0);
+ if (mem_node) {
+ ret = of_property_read_u64(mem_node, "size", &size);
+ if (ret) {
+ dev_err(dev, "FQD: of_address_to_resource fails 0x%x\n", ret);
+ return -ENODEV;
+ }
+ fqd_sz = size;
+ } else {
+ dev_err(dev, "No memory-region found for FQD\n");
+ return -ENODEV;
+ }
+ if (!dma_zalloc_coherent(dev, fqd_sz, &fqd_a, 0)) {
+ dev_err(dev, "Alloc FQD memory failed\n");
+ return -ENODEV;
+ }
+
+ dev_info(dev, "Allocated FQD 0x%llx 0x%zx\n", fqd_a, fqd_sz);
+
+ /* Disassociate the FQD reseverd memory area from the device because
+ a device can only have one DMA memory area. This should be fine
+ since the memory is allocated and initalized and only ever accessed
+ by the QMan device from now on */
+ of_reserved_mem_device_release(dev);
+
+ /* Setup PFDR memory */
+ ret = of_reserved_mem_device_init_by_idx(dev, dev->of_node, 1);
+ if (ret) {
+ dev_err(dev, "of_reserved_mem_device_init(1) failed 0x%x\n",
+ ret);
+ return -ENODEV;
+ }
+ mem_node = of_parse_phandle(dev->of_node, "memory-region", 1);
+ if (mem_node) {
+ ret = of_property_read_u64(mem_node, "size", &size);
+ if (ret) {
+ dev_err(dev, "PFDR: of_address_to_resource fails 0x%x\n", ret);
+ return -ENODEV;
+ }
+ pfdr_sz = size;
+ } else {
+ dev_err(dev, "No memory-region found for PFDR\n");
+ return -ENODEV;
+ }
+ if (!dma_zalloc_coherent(dev, pfdr_sz, &pfdr_a, 0)) {
+ dev_err(dev, "Alloc PFDR Failed size 0x%zx\n", pfdr_sz);
return -ENODEV;
+ }
+
+ dev_info(dev, "Allocated PFDR 0x%llx 0x%zx\n", pfdr_a, pfdr_sz);
ret = qman_init_ccsr(dev);
if (ret) {
diff --git a/drivers/soc/fsl/qbman/qman_priv.h b/drivers/soc/fsl/qbman/qman_priv.h
index 22725bd..1e998ea5 100644
--- a/drivers/soc/fsl/qbman/qman_priv.h
+++ b/drivers/soc/fsl/qbman/qman_priv.h
@@ -28,12 +28,12 @@
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
-#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
-
#include "dpaa_sys.h"
#include <soc/fsl/qman.h>
#include <linux/iommu.h>
+#include <linux/dma-contiguous.h>
+#include <linux/of_address.h>
#if defined(CONFIG_FSL_PAMU)
#include <asm/fsl_pamu_stash.h>
diff --git a/drivers/soc/fsl/qbman/qman_test.h b/drivers/soc/fsl/qbman/qman_test.h
index d5f8cb2..41bdbc48 100644
--- a/drivers/soc/fsl/qbman/qman_test.h
+++ b/drivers/soc/fsl/qbman/qman_test.h
@@ -30,7 +30,5 @@
#include "qman_priv.h"
-#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
-
int qman_test_stash(void);
int qman_test_api(void);
--
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
* [RFC PATCH 3/5] dts: arch/powerpc: Update Freescale DTS for QBMan memory allocations
From: Roy Pledge @ 2017-03-29 21:13 UTC (permalink / raw)
To: robin.murphy-5wv7dgnIgG8, oss-fOR+EgIDQEHk1uMJSBkQmQ,
linuxppc-dev-uLR06cmDAlY/bJ5BZ2RsiQ,
linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r,
devicetree-u79uwXL29TY76Z2rM5mHXA
Cc: madalin.bucur-3arQi8VN3Tc, Roy Pledge
In-Reply-To: <1490822037-6752-1-git-send-email-roy.pledge-3arQi8VN3Tc@public.gmane.org>
QBMan now uses the shared-dma-pool mechansim to manage early
memory reservations.
Signed-off-by: Roy Pledge <roy.pledge-3arQi8VN3Tc@public.gmane.org>
---
arch/powerpc/boot/dts/fsl/b4qds.dtsi | 6 ++++++
arch/powerpc/boot/dts/fsl/b4si-post.dtsi | 15 ---------------
arch/powerpc/boot/dts/fsl/cyrus_p5020.dts | 6 ++++++
arch/powerpc/boot/dts/fsl/kmcent2.dts | 6 ++++++
arch/powerpc/boot/dts/fsl/kmcoge4.dts | 6 ++++++
arch/powerpc/boot/dts/fsl/oca4080.dts | 6 ++++++
arch/powerpc/boot/dts/fsl/p1023rdb.dts | 6 ++++++
arch/powerpc/boot/dts/fsl/p1023si-post.dtsi | 15 ---------------
arch/powerpc/boot/dts/fsl/p2041rdb.dts | 6 ++++++
arch/powerpc/boot/dts/fsl/p2041si-post.dtsi | 15 ---------------
arch/powerpc/boot/dts/fsl/p3041ds.dts | 6 ++++++
arch/powerpc/boot/dts/fsl/p3041si-post.dtsi | 15 ---------------
arch/powerpc/boot/dts/fsl/p4080ds.dts | 6 ++++++
arch/powerpc/boot/dts/fsl/p4080si-post.dtsi | 15 ---------------
arch/powerpc/boot/dts/fsl/p5020ds.dts | 6 ++++++
arch/powerpc/boot/dts/fsl/p5020si-post.dtsi | 15 ---------------
arch/powerpc/boot/dts/fsl/p5040ds.dts | 6 ++++++
arch/powerpc/boot/dts/fsl/p5040si-post.dtsi | 15 ---------------
arch/powerpc/boot/dts/fsl/t1023rdb.dts | 6 ++++++
arch/powerpc/boot/dts/fsl/t1023si-post.dtsi | 15 ---------------
arch/powerpc/boot/dts/fsl/t1024qds.dts | 6 ++++++
arch/powerpc/boot/dts/fsl/t1024rdb.dts | 6 ++++++
arch/powerpc/boot/dts/fsl/t1040si-post.dtsi | 15 ---------------
arch/powerpc/boot/dts/fsl/t104xd4rdb.dtsi | 6 ++++++
arch/powerpc/boot/dts/fsl/t104xqds.dtsi | 6 ++++++
arch/powerpc/boot/dts/fsl/t104xrdb.dtsi | 6 ++++++
arch/powerpc/boot/dts/fsl/t2081si-post.dtsi | 15 ---------------
arch/powerpc/boot/dts/fsl/t208xqds.dtsi | 6 ++++++
arch/powerpc/boot/dts/fsl/t208xrdb.dtsi | 6 ++++++
arch/powerpc/boot/dts/fsl/t4240qds.dts | 6 ++++++
arch/powerpc/boot/dts/fsl/t4240rdb.dts | 6 ++++++
arch/powerpc/boot/dts/fsl/t4240si-post.dtsi | 15 ---------------
32 files changed, 126 insertions(+), 165 deletions(-)
diff --git a/arch/powerpc/boot/dts/fsl/b4qds.dtsi b/arch/powerpc/boot/dts/fsl/b4qds.dtsi
index 3785ef8..a2abd1e 100644
--- a/arch/powerpc/boot/dts/fsl/b4qds.dtsi
+++ b/arch/powerpc/boot/dts/fsl/b4qds.dtsi
@@ -110,16 +110,22 @@
ranges;
bman_fbpr: bman-fbpr {
+ compatible = "shared-dma-pool";
size = <0 0x1000000>;
alignment = <0 0x1000000>;
+ no-map;
};
qman_fqd: qman-fqd {
+ compatible = "shared-dma-pool";
size = <0 0x400000>;
alignment = <0 0x400000>;
+ no-map;
};
qman_pfdr: qman-pfdr {
+ compatible = "shared-dma-pool";
size = <0 0x2000000>;
alignment = <0 0x2000000>;
+ no-map;
};
};
diff --git a/arch/powerpc/boot/dts/fsl/b4si-post.dtsi b/arch/powerpc/boot/dts/fsl/b4si-post.dtsi
index 1b33f51..844d99b 100644
--- a/arch/powerpc/boot/dts/fsl/b4si-post.dtsi
+++ b/arch/powerpc/boot/dts/fsl/b4si-post.dtsi
@@ -32,21 +32,6 @@
* this software, even if advised of the possibility of such damage.
*/
-&bman_fbpr {
- compatible = "fsl,bman-fbpr";
- alloc-ranges = <0 0 0x10000 0>;
-};
-
-&qman_fqd {
- compatible = "fsl,qman-fqd";
- alloc-ranges = <0 0 0x10000 0>;
-};
-
-&qman_pfdr {
- compatible = "fsl,qman-pfdr";
- alloc-ranges = <0 0 0x10000 0>;
-};
-
&ifc {
#address-cells = <2>;
#size-cells = <1>;
diff --git a/arch/powerpc/boot/dts/fsl/cyrus_p5020.dts b/arch/powerpc/boot/dts/fsl/cyrus_p5020.dts
index c603390..2b2227b 100644
--- a/arch/powerpc/boot/dts/fsl/cyrus_p5020.dts
+++ b/arch/powerpc/boot/dts/fsl/cyrus_p5020.dts
@@ -31,16 +31,22 @@
ranges;
bman_fbpr: bman-fbpr {
+ compatible = "shared-dma-pool";
size = <0 0x1000000>;
alignment = <0 0x1000000>;
+ no-map;
};
qman_fqd: qman-fqd {
+ compatible = "shared-dma-pool";
size = <0 0x400000>;
alignment = <0 0x400000>;
+ no-map;
};
qman_pfdr: qman-pfdr {
+ compatible = "shared-dma-pool";
size = <0 0x2000000>;
alignment = <0 0x2000000>;
+ no-map;
};
};
diff --git a/arch/powerpc/boot/dts/fsl/kmcent2.dts b/arch/powerpc/boot/dts/fsl/kmcent2.dts
index 47afa43..98f5257 100644
--- a/arch/powerpc/boot/dts/fsl/kmcent2.dts
+++ b/arch/powerpc/boot/dts/fsl/kmcent2.dts
@@ -28,16 +28,22 @@
ranges;
bman_fbpr: bman-fbpr {
+ compatible = "shared-dma-pool";
size = <0 0x1000000>;
alignment = <0 0x1000000>;
+ no-map;
};
qman_fqd: qman-fqd {
+ compatible = "shared-dma-pool";
size = <0 0x400000>;
alignment = <0 0x400000>;
+ no-map;
};
qman_pfdr: qman-pfdr {
+ compatible = "shared-dma-pool";
size = <0 0x2000000>;
alignment = <0 0x2000000>;
+ no-map;
};
};
diff --git a/arch/powerpc/boot/dts/fsl/kmcoge4.dts b/arch/powerpc/boot/dts/fsl/kmcoge4.dts
index e103c0f..6cfff87 100644
--- a/arch/powerpc/boot/dts/fsl/kmcoge4.dts
+++ b/arch/powerpc/boot/dts/fsl/kmcoge4.dts
@@ -31,16 +31,22 @@
ranges;
bman_fbpr: bman-fbpr {
+ compatible = "shared-dma-pool";
size = <0 0x1000000>;
alignment = <0 0x1000000>;
+ no-map;
};
qman_fqd: qman-fqd {
+ compatible = "shared-dma-pool";
size = <0 0x400000>;
alignment = <0 0x400000>;
+ no-map;
};
qman_pfdr: qman-pfdr {
+ compatible = "shared-dma-pool";
size = <0 0x2000000>;
alignment = <0 0x2000000>;
+ no-map;
};
};
diff --git a/arch/powerpc/boot/dts/fsl/oca4080.dts b/arch/powerpc/boot/dts/fsl/oca4080.dts
index 17bc6f3..e06ce75 100644
--- a/arch/powerpc/boot/dts/fsl/oca4080.dts
+++ b/arch/powerpc/boot/dts/fsl/oca4080.dts
@@ -55,16 +55,22 @@
ranges;
bman_fbpr: bman-fbpr {
+ compatible = "shared-dma-pool";
size = <0 0x1000000>;
alignment = <0 0x1000000>;
+ no-map;
};
qman_fqd: qman-fqd {
+ compatible = "shared-dma-pool";
size = <0 0x400000>;
alignment = <0 0x400000>;
+ no-map;
};
qman_pfdr: qman-pfdr {
+ compatible = "shared-dma-pool";
size = <0 0x2000000>;
alignment = <0 0x2000000>;
+ no-map;
};
};
diff --git a/arch/powerpc/boot/dts/fsl/p1023rdb.dts b/arch/powerpc/boot/dts/fsl/p1023rdb.dts
index 9716ca6..d4abdcf 100644
--- a/arch/powerpc/boot/dts/fsl/p1023rdb.dts
+++ b/arch/powerpc/boot/dts/fsl/p1023rdb.dts
@@ -53,16 +53,22 @@
ranges;
bman_fbpr: bman-fbpr {
+ compatible = "shared-dma-pool";
size = <0 0x1000000>;
alignment = <0 0x1000000>;
+ no-map;
};
qman_fqd: qman-fqd {
+ compatible = "shared-dma-pool";
size = <0 0x400000>;
alignment = <0 0x400000>;
+ no-map;
};
qman_pfdr: qman-pfdr {
+ compatible = "shared-dma-pool";
size = <0 0x2000000>;
alignment = <0 0x2000000>;
+ no-map;
};
};
diff --git a/arch/powerpc/boot/dts/fsl/p1023si-post.dtsi b/arch/powerpc/boot/dts/fsl/p1023si-post.dtsi
index da6d3fc..9dbbba6 100644
--- a/arch/powerpc/boot/dts/fsl/p1023si-post.dtsi
+++ b/arch/powerpc/boot/dts/fsl/p1023si-post.dtsi
@@ -32,21 +32,6 @@
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
-&bman_fbpr {
- compatible = "fsl,bman-fbpr";
- alloc-ranges = <0 0 0x10 0>;
-};
-
-&qman_fqd {
- compatible = "fsl,qman-fqd";
- alloc-ranges = <0 0 0x10 0>;
-};
-
-&qman_pfdr {
- compatible = "fsl,qman-pfdr";
- alloc-ranges = <0 0 0x10 0>;
-};
-
&lbc {
#address-cells = <2>;
#size-cells = <1>;
diff --git a/arch/powerpc/boot/dts/fsl/p2041rdb.dts b/arch/powerpc/boot/dts/fsl/p2041rdb.dts
index e50fea9..4f6c233 100644
--- a/arch/powerpc/boot/dts/fsl/p2041rdb.dts
+++ b/arch/powerpc/boot/dts/fsl/p2041rdb.dts
@@ -64,16 +64,22 @@
ranges;
bman_fbpr: bman-fbpr {
+ compatible = "shared-dma-pool";
size = <0 0x1000000>;
alignment = <0 0x1000000>;
+ no-map;
};
qman_fqd: qman-fqd {
+ compatible = "shared-dma-pool";
size = <0 0x400000>;
alignment = <0 0x400000>;
+ no-map;
};
qman_pfdr: qman-pfdr {
+ compatible = "shared-dma-pool";
size = <0 0x2000000>;
alignment = <0 0x2000000>;
+ no-map;
};
};
diff --git a/arch/powerpc/boot/dts/fsl/p2041si-post.dtsi b/arch/powerpc/boot/dts/fsl/p2041si-post.dtsi
index 51e975d..f8615bb 100644
--- a/arch/powerpc/boot/dts/fsl/p2041si-post.dtsi
+++ b/arch/powerpc/boot/dts/fsl/p2041si-post.dtsi
@@ -32,21 +32,6 @@
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
-&bman_fbpr {
- compatible = "fsl,bman-fbpr";
- alloc-ranges = <0 0 0x10 0>;
-};
-
-&qman_fqd {
- compatible = "fsl,qman-fqd";
- alloc-ranges = <0 0 0x10 0>;
-};
-
-&qman_pfdr {
- compatible = "fsl,qman-pfdr";
- alloc-ranges = <0 0 0x10 0>;
-};
-
&lbc {
compatible = "fsl,p2041-elbc", "fsl,elbc", "simple-bus";
interrupts = <25 2 0 0>;
diff --git a/arch/powerpc/boot/dts/fsl/p3041ds.dts b/arch/powerpc/boot/dts/fsl/p3041ds.dts
index 40748e4..50507c9 100644
--- a/arch/powerpc/boot/dts/fsl/p3041ds.dts
+++ b/arch/powerpc/boot/dts/fsl/p3041ds.dts
@@ -65,16 +65,22 @@
ranges;
bman_fbpr: bman-fbpr {
+ compatible = "shared-dma-pool";
size = <0 0x1000000>;
alignment = <0 0x1000000>;
+ no-map;
};
qman_fqd: qman-fqd {
+ compatible = "shared-dma-pool";
size = <0 0x400000>;
alignment = <0 0x400000>;
+ no-map;
};
qman_pfdr: qman-pfdr {
+ compatible = "shared-dma-pool";
size = <0 0x2000000>;
alignment = <0 0x2000000>;
+ no-map;
};
};
diff --git a/arch/powerpc/boot/dts/fsl/p3041si-post.dtsi b/arch/powerpc/boot/dts/fsl/p3041si-post.dtsi
index 187676f..a19b86c 100644
--- a/arch/powerpc/boot/dts/fsl/p3041si-post.dtsi
+++ b/arch/powerpc/boot/dts/fsl/p3041si-post.dtsi
@@ -32,21 +32,6 @@
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
-&bman_fbpr {
- compatible = "fsl,bman-fbpr";
- alloc-ranges = <0 0 0x10 0>;
-};
-
-&qman_fqd {
- compatible = "fsl,qman-fqd";
- alloc-ranges = <0 0 0x10 0>;
-};
-
-&qman_pfdr {
- compatible = "fsl,qman-pfdr";
- alloc-ranges = <0 0 0x10 0>;
-};
-
&lbc {
compatible = "fsl,p3041-elbc", "fsl,elbc", "simple-bus";
interrupts = <25 2 0 0>;
diff --git a/arch/powerpc/boot/dts/fsl/p4080ds.dts b/arch/powerpc/boot/dts/fsl/p4080ds.dts
index 816b978..813117a 100644
--- a/arch/powerpc/boot/dts/fsl/p4080ds.dts
+++ b/arch/powerpc/boot/dts/fsl/p4080ds.dts
@@ -65,16 +65,22 @@
ranges;
bman_fbpr: bman-fbpr {
+ compatible = "shared-dma-pool";
size = <0 0x1000000>;
alignment = <0 0x1000000>;
+ no-map;
};
qman_fqd: qman-fqd {
+ compatible = "shared-dma-pool";
size = <0 0x400000>;
alignment = <0 0x400000>;
+ no-map;
};
qman_pfdr: qman-pfdr {
+ compatible = "shared-dma-pool";
size = <0 0x2000000>;
alignment = <0 0x2000000>;
+ no-map;
};
};
diff --git a/arch/powerpc/boot/dts/fsl/p4080si-post.dtsi b/arch/powerpc/boot/dts/fsl/p4080si-post.dtsi
index a025208..42868c7 100644
--- a/arch/powerpc/boot/dts/fsl/p4080si-post.dtsi
+++ b/arch/powerpc/boot/dts/fsl/p4080si-post.dtsi
@@ -32,21 +32,6 @@
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
-&bman_fbpr {
- compatible = "fsl,bman-fbpr";
- alloc-ranges = <0 0 0x10 0>;
-};
-
-&qman_fqd {
- compatible = "fsl,qman-fqd";
- alloc-ranges = <0 0 0x10 0>;
-};
-
-&qman_pfdr {
- compatible = "fsl,qman-pfdr";
- alloc-ranges = <0 0 0x10 0>;
-};
-
&lbc {
compatible = "fsl,p4080-elbc", "fsl,elbc", "simple-bus";
interrupts = <25 2 0 0>;
diff --git a/arch/powerpc/boot/dts/fsl/p5020ds.dts b/arch/powerpc/boot/dts/fsl/p5020ds.dts
index cd6f373..479f772 100644
--- a/arch/powerpc/boot/dts/fsl/p5020ds.dts
+++ b/arch/powerpc/boot/dts/fsl/p5020ds.dts
@@ -65,16 +65,22 @@
ranges;
bman_fbpr: bman-fbpr {
+ compatible = "shared-dma-pool";
size = <0 0x1000000>;
alignment = <0 0x1000000>;
+ no-map;
};
qman_fqd: qman-fqd {
+ compatible = "shared-dma-pool";
size = <0 0x400000>;
alignment = <0 0x400000>;
+ no-map;
};
qman_pfdr: qman-pfdr {
+ compatible = "shared-dma-pool";
size = <0 0x2000000>;
alignment = <0 0x2000000>;
+ no-map;
};
};
diff --git a/arch/powerpc/boot/dts/fsl/p5020si-post.dtsi b/arch/powerpc/boot/dts/fsl/p5020si-post.dtsi
index cd008cd..dec5e12 100644
--- a/arch/powerpc/boot/dts/fsl/p5020si-post.dtsi
+++ b/arch/powerpc/boot/dts/fsl/p5020si-post.dtsi
@@ -32,21 +32,6 @@
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
-&bman_fbpr {
- compatible = "fsl,bman-fbpr";
- alloc-ranges = <0 0 0x10000 0>;
-};
-
-&qman_fqd {
- compatible = "fsl,qman-fqd";
- alloc-ranges = <0 0 0x10000 0>;
-};
-
-&qman_pfdr {
- compatible = "fsl,qman-pfdr";
- alloc-ranges = <0 0 0x10000 0>;
-};
-
&lbc {
compatible = "fsl,p5020-elbc", "fsl,elbc", "simple-bus";
interrupts = <25 2 0 0>;
diff --git a/arch/powerpc/boot/dts/fsl/p5040ds.dts b/arch/powerpc/boot/dts/fsl/p5040ds.dts
index 4508473..b97ca39 100644
--- a/arch/powerpc/boot/dts/fsl/p5040ds.dts
+++ b/arch/powerpc/boot/dts/fsl/p5040ds.dts
@@ -77,16 +77,22 @@
ranges;
bman_fbpr: bman-fbpr {
+ compatible = "shared-dma-pool";
size = <0 0x1000000>;
alignment = <0 0x1000000>;
+ no-map;
};
qman_fqd: qman-fqd {
+ compatible = "shared-dma-pool";
size = <0 0x400000>;
alignment = <0 0x400000>;
+ no-map;
};
qman_pfdr: qman-pfdr {
+ compatible = "shared-dma-pool";
size = <0 0x2000000>;
alignment = <0 0x2000000>;
+ no-map;
};
};
diff --git a/arch/powerpc/boot/dts/fsl/p5040si-post.dtsi b/arch/powerpc/boot/dts/fsl/p5040si-post.dtsi
index e2bd931..7a109d5 100644
--- a/arch/powerpc/boot/dts/fsl/p5040si-post.dtsi
+++ b/arch/powerpc/boot/dts/fsl/p5040si-post.dtsi
@@ -32,21 +32,6 @@
* software, even if advised of the possibility of such damage.
*/
-&bman_fbpr {
- compatible = "fsl,bman-fbpr";
- alloc-ranges = <0 0 0x10000 0>;
-};
-
-&qman_fqd {
- compatible = "fsl,qman-fqd";
- alloc-ranges = <0 0 0x10000 0>;
-};
-
-&qman_pfdr {
- compatible = "fsl,qman-pfdr";
- alloc-ranges = <0 0 0x10000 0>;
-};
-
&lbc {
compatible = "fsl,p5040-elbc", "fsl,elbc", "simple-bus";
interrupts = <25 2 0 0>;
diff --git a/arch/powerpc/boot/dts/fsl/t1023rdb.dts b/arch/powerpc/boot/dts/fsl/t1023rdb.dts
index 5ba6fbf..034ec42 100644
--- a/arch/powerpc/boot/dts/fsl/t1023rdb.dts
+++ b/arch/powerpc/boot/dts/fsl/t1023rdb.dts
@@ -47,18 +47,24 @@
ranges;
bman_fbpr: bman-fbpr {
+ compatible = "shared-dma-pool";
size = <0 0x1000000>;
alignment = <0 0x1000000>;
+ no-map;
};
qman_fqd: qman-fqd {
+ compatible = "shared-dma-pool";
size = <0 0x400000>;
alignment = <0 0x400000>;
+ no-map;
};
qman_pfdr: qman-pfdr {
+ compatible = "shared-dma-pool";
size = <0 0x2000000>;
alignment = <0 0x2000000>;
+ no-map;
};
};
diff --git a/arch/powerpc/boot/dts/fsl/t1023si-post.dtsi b/arch/powerpc/boot/dts/fsl/t1023si-post.dtsi
index 4908af5..de951f8 100644
--- a/arch/powerpc/boot/dts/fsl/t1023si-post.dtsi
+++ b/arch/powerpc/boot/dts/fsl/t1023si-post.dtsi
@@ -34,21 +34,6 @@
#include <dt-bindings/thermal/thermal.h>
-&bman_fbpr {
- compatible = "fsl,bman-fbpr";
- alloc-ranges = <0 0 0x10000 0>;
-};
-
-&qman_fqd {
- compatible = "fsl,qman-fqd";
- alloc-ranges = <0 0 0x10000 0>;
-};
-
-&qman_pfdr {
- compatible = "fsl,qman-pfdr";
- alloc-ranges = <0 0 0x10000 0>;
-};
-
&ifc {
#address-cells = <2>;
#size-cells = <1>;
diff --git a/arch/powerpc/boot/dts/fsl/t1024qds.dts b/arch/powerpc/boot/dts/fsl/t1024qds.dts
index d6858b7..a6fa860 100644
--- a/arch/powerpc/boot/dts/fsl/t1024qds.dts
+++ b/arch/powerpc/boot/dts/fsl/t1024qds.dts
@@ -47,18 +47,24 @@
ranges;
bman_fbpr: bman-fbpr {
+ compatible = "shared-dma-pool";
size = <0 0x1000000>;
alignment = <0 0x1000000>;
+ no-map;
};
qman_fqd: qman-fqd {
+ compatible = "shared-dma-pool";
size = <0 0x400000>;
alignment = <0 0x400000>;
+ no-map;
};
qman_pfdr: qman-pfdr {
+ compatible = "shared-dma-pool";
size = <0 0x2000000>;
alignment = <0 0x2000000>;
+ no-map;
};
};
diff --git a/arch/powerpc/boot/dts/fsl/t1024rdb.dts b/arch/powerpc/boot/dts/fsl/t1024rdb.dts
index 73a6453..09cf13c 100644
--- a/arch/powerpc/boot/dts/fsl/t1024rdb.dts
+++ b/arch/powerpc/boot/dts/fsl/t1024rdb.dts
@@ -51,18 +51,24 @@
ranges;
bman_fbpr: bman-fbpr {
+ compatible = "shared-dma-pool";
size = <0 0x1000000>;
alignment = <0 0x1000000>;
+ no-map;
};
qman_fqd: qman-fqd {
+ compatible = "shared-dma-pool";
size = <0 0x400000>;
alignment = <0 0x400000>;
+ no-map;
};
qman_pfdr: qman-pfdr {
+ compatible = "shared-dma-pool";
size = <0 0x2000000>;
alignment = <0 0x2000000>;
+ no-map;
};
};
diff --git a/arch/powerpc/boot/dts/fsl/t1040si-post.dtsi b/arch/powerpc/boot/dts/fsl/t1040si-post.dtsi
index 145c7f4..3fa5a14 100644
--- a/arch/powerpc/boot/dts/fsl/t1040si-post.dtsi
+++ b/arch/powerpc/boot/dts/fsl/t1040si-post.dtsi
@@ -34,21 +34,6 @@
#include <dt-bindings/thermal/thermal.h>
-&bman_fbpr {
- compatible = "fsl,bman-fbpr";
- alloc-ranges = <0 0 0x10000 0>;
-};
-
-&qman_fqd {
- compatible = "fsl,qman-fqd";
- alloc-ranges = <0 0 0x10000 0>;
-};
-
-&qman_pfdr {
- compatible = "fsl,qman-pfdr";
- alloc-ranges = <0 0 0x10000 0>;
-};
-
&ifc {
#address-cells = <2>;
#size-cells = <1>;
diff --git a/arch/powerpc/boot/dts/fsl/t104xd4rdb.dtsi b/arch/powerpc/boot/dts/fsl/t104xd4rdb.dtsi
index 863f943..531600b 100644
--- a/arch/powerpc/boot/dts/fsl/t104xd4rdb.dtsi
+++ b/arch/powerpc/boot/dts/fsl/t104xd4rdb.dtsi
@@ -39,16 +39,22 @@
ranges;
bman_fbpr: bman-fbpr {
+ compatible = "shared-dma-pool";
size = <0 0x1000000>;
alignment = <0 0x1000000>;
+ no-map;
};
qman_fqd: qman-fqd {
+ compatible = "shared-dma-pool";
size = <0 0x400000>;
alignment = <0 0x400000>;
+ no-map;
};
qman_pfdr: qman-pfdr {
+ compatible = "shared-dma-pool";
size = <0 0x2000000>;
alignment = <0 0x2000000>;
+ no-map;
};
};
diff --git a/arch/powerpc/boot/dts/fsl/t104xqds.dtsi b/arch/powerpc/boot/dts/fsl/t104xqds.dtsi
index 2fd4cbe..bb7cc7b 100644
--- a/arch/powerpc/boot/dts/fsl/t104xqds.dtsi
+++ b/arch/powerpc/boot/dts/fsl/t104xqds.dtsi
@@ -71,16 +71,22 @@
ranges;
bman_fbpr: bman-fbpr {
+ compatible = "shared-dma-pool";
size = <0 0x1000000>;
alignment = <0 0x1000000>;
+ no-map;
};
qman_fqd: qman-fqd {
+ compatible = "shared-dma-pool";
size = <0 0x400000>;
alignment = <0 0x400000>;
+ no-map;
};
qman_pfdr: qman-pfdr {
+ compatible = "shared-dma-pool";
size = <0 0x2000000>;
alignment = <0 0x2000000>;
+ no-map
};
};
diff --git a/arch/powerpc/boot/dts/fsl/t104xrdb.dtsi b/arch/powerpc/boot/dts/fsl/t104xrdb.dtsi
index 5fdddbd..d0ba614 100644
--- a/arch/powerpc/boot/dts/fsl/t104xrdb.dtsi
+++ b/arch/powerpc/boot/dts/fsl/t104xrdb.dtsi
@@ -45,16 +45,22 @@
ranges;
bman_fbpr: bman-fbpr {
+ compatible = "shared-dma-pool";
size = <0 0x1000000>;
alignment = <0 0x1000000>;
+ no-map;
};
qman_fqd: qman-fqd {
+ compatible = "shared-dma-pool";
size = <0 0x400000>;
alignment = <0 0x400000>;
+ no-map;
};
qman_pfdr: qman-pfdr {
+ compatible = "shared-dma-pool";
size = <0 0x2000000>;
alignment = <0 0x2000000>;
+ no-map;
};
};
diff --git a/arch/powerpc/boot/dts/fsl/t2081si-post.dtsi b/arch/powerpc/boot/dts/fsl/t2081si-post.dtsi
index a97296c..5215e86 100644
--- a/arch/powerpc/boot/dts/fsl/t2081si-post.dtsi
+++ b/arch/powerpc/boot/dts/fsl/t2081si-post.dtsi
@@ -32,21 +32,6 @@
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
-&bman_fbpr {
- compatible = "fsl,bman-fbpr";
- alloc-ranges = <0 0 0x10000 0>;
-};
-
-&qman_fqd {
- compatible = "fsl,qman-fqd";
- alloc-ranges = <0 0 0x10000 0>;
-};
-
-&qman_pfdr {
- compatible = "fsl,qman-pfdr";
- alloc-ranges = <0 0 0x10000 0>;
-};
-
&ifc {
#address-cells = <2>;
#size-cells = <1>;
diff --git a/arch/powerpc/boot/dts/fsl/t208xqds.dtsi b/arch/powerpc/boot/dts/fsl/t208xqds.dtsi
index ec080bd..334da3b 100644
--- a/arch/powerpc/boot/dts/fsl/t208xqds.dtsi
+++ b/arch/powerpc/boot/dts/fsl/t208xqds.dtsi
@@ -45,16 +45,22 @@
ranges;
bman_fbpr: bman-fbpr {
+ compatible = "shared-dma-pool";
size = <0 0x1000000>;
alignment = <0 0x1000000>;
+ no-map;
};
qman_fqd: qman-fqd {
+ compatible = "shared-dma-pool";
size = <0 0x400000>;
alignment = <0 0x400000>;
+ no-map;
};
qman_pfdr: qman-pfdr {
+ compatible = "shared-dma-pool";
size = <0 0x2000000>;
alignment = <0 0x2000000>;
+ no-map;
};
};
diff --git a/arch/powerpc/boot/dts/fsl/t208xrdb.dtsi b/arch/powerpc/boot/dts/fsl/t208xrdb.dtsi
index ff87e67..102fe75 100644
--- a/arch/powerpc/boot/dts/fsl/t208xrdb.dtsi
+++ b/arch/powerpc/boot/dts/fsl/t208xrdb.dtsi
@@ -45,16 +45,22 @@
ranges;
bman_fbpr: bman-fbpr {
+ compatible = "shared-dma-pool";
size = <0 0x1000000>;
alignment = <0 0x1000000>;
+ no-map;
};
qman_fqd: qman-fqd {
+ compatible = "shared-dma-pool";
size = <0 0x400000>;
alignment = <0 0x400000>;
+ no-map;
};
qman_pfdr: qman-pfdr {
+ compatible = "shared-dma-pool";
size = <0 0x2000000>;
alignment = <0 0x2000000>;
+ no-map;
};
};
diff --git a/arch/powerpc/boot/dts/fsl/t4240qds.dts b/arch/powerpc/boot/dts/fsl/t4240qds.dts
index 9573cea..92375b4 100644
--- a/arch/powerpc/boot/dts/fsl/t4240qds.dts
+++ b/arch/powerpc/boot/dts/fsl/t4240qds.dts
@@ -326,16 +326,22 @@
ranges;
bman_fbpr: bman-fbpr {
+ compatible = "shared-dma-pool";
size = <0 0x1000000>;
alignment = <0 0x1000000>;
+ no-map;
};
qman_fqd: qman-fqd {
+ compatible = "shared-dma-pool";
size = <0 0x400000>;
alignment = <0 0x400000>;
+ no-map;
};
qman_pfdr: qman-pfdr {
+ compatible = "shared-dma-pool";
size = <0 0x2000000>;
alignment = <0 0x2000000>;
+ no-map;
};
};
diff --git a/arch/powerpc/boot/dts/fsl/t4240rdb.dts b/arch/powerpc/boot/dts/fsl/t4240rdb.dts
index 8166c66..5cd8a62 100644
--- a/arch/powerpc/boot/dts/fsl/t4240rdb.dts
+++ b/arch/powerpc/boot/dts/fsl/t4240rdb.dts
@@ -86,16 +86,22 @@
ranges;
bman_fbpr: bman-fbpr {
+ compatible = "shared-dma-pool";
size = <0 0x1000000>;
alignment = <0 0x1000000>;
+ no-map;
};
qman_fqd: qman-fqd {
+ compatible = "shared-dma-pool";
size = <0 0x400000>;
alignment = <0 0x400000>;
+ no-map;
};
qman_pfdr: qman-pfdr {
+ compatible = "shared-dma-pool";
size = <0 0x2000000>;
alignment = <0 0x2000000>;
+ no-map;
};
};
diff --git a/arch/powerpc/boot/dts/fsl/t4240si-post.dtsi b/arch/powerpc/boot/dts/fsl/t4240si-post.dtsi
index 68c4ead..97d5ae1 100644
--- a/arch/powerpc/boot/dts/fsl/t4240si-post.dtsi
+++ b/arch/powerpc/boot/dts/fsl/t4240si-post.dtsi
@@ -32,21 +32,6 @@
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
-&bman_fbpr {
- compatible = "fsl,bman-fbpr";
- alloc-ranges = <0 0 0x10000 0>;
-};
-
-&qman_fqd {
- compatible = "fsl,qman-fqd";
- alloc-ranges = <0 0 0x10000 0>;
-};
-
-&qman_pfdr {
- compatible = "fsl,qman-pfdr";
- alloc-ranges = <0 0 0x10000 0>;
-};
-
&ifc {
#address-cells = <2>;
#size-cells = <1>;
--
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
* [RFC PATCH 4/5] dt-bindings: soc/fsl: Update reserved memory binding for QBMan
From: Roy Pledge @ 2017-03-29 21:13 UTC (permalink / raw)
To: robin.murphy-5wv7dgnIgG8, oss-fOR+EgIDQEHk1uMJSBkQmQ,
linuxppc-dev-uLR06cmDAlY/bJ5BZ2RsiQ,
linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r,
devicetree-u79uwXL29TY76Z2rM5mHXA
Cc: madalin.bucur-3arQi8VN3Tc, Roy Pledge
In-Reply-To: <1490822037-6752-1-git-send-email-roy.pledge-3arQi8VN3Tc@public.gmane.org>
Updates the QMan and BMan device tree bindings for reserved memory
nodes. This makes the reserved memory allocation compatiable with
the shared-dma-pool usage.
Signed-off-by: Roy Pledge <roy.pledge-3arQi8VN3Tc@public.gmane.org>
---
Documentation/devicetree/bindings/soc/fsl/bman.txt | 10 +++++-----
Documentation/devicetree/bindings/soc/fsl/qman.txt | 16 +++++++++-------
2 files changed, 14 insertions(+), 12 deletions(-)
diff --git a/Documentation/devicetree/bindings/soc/fsl/bman.txt b/Documentation/devicetree/bindings/soc/fsl/bman.txt
index 47ac834..bdf2fae7 100644
--- a/Documentation/devicetree/bindings/soc/fsl/bman.txt
+++ b/Documentation/devicetree/bindings/soc/fsl/bman.txt
@@ -65,8 +65,8 @@ to the respective BMan instance
BMan Private Memory Node
BMan requires a contiguous range of physical memory used for the backing store
-for BMan Free Buffer Proxy Records (FBPR). This memory is reserved/allocated as a
-node under the /reserved-memory node
+for BMan Free Buffer Proxy Records (FBPR). This memory is reserved/allocated as
+a node under the /reserved-memory node.
The BMan FBPR memory node must be named "bman-fbpr"
@@ -75,7 +75,7 @@ PROPERTIES
- compatible
Usage: required
Value type: <stringlist>
- Definition: Must inclide "fsl,bman-fbpr"
+ Definition: Must include "shared-mem-pool"
The following constraints are relevant to the FBPR private memory:
- The size must be 2^(size + 1), with size = 11..33. That is 4 KiB to
@@ -100,10 +100,10 @@ The example below shows a BMan FBPR dynamic allocation memory node
ranges;
bman_fbpr: bman-fbpr {
- compatible = "fsl,bman-fbpr";
- alloc-ranges = <0 0 0x10 0>;
+ compatible = "shared-mem-pool";
size = <0 0x1000000>;
alignment = <0 0x1000000>;
+ no-map;
};
};
diff --git a/Documentation/devicetree/bindings/soc/fsl/qman.txt b/Documentation/devicetree/bindings/soc/fsl/qman.txt
index 556ebb8..3e7d863 100644
--- a/Documentation/devicetree/bindings/soc/fsl/qman.txt
+++ b/Documentation/devicetree/bindings/soc/fsl/qman.txt
@@ -74,7 +74,9 @@ QMan Private Memory Nodes
QMan requires two contiguous range of physical memory used for the backing store
for QMan Frame Queue Descriptor (FQD) and Packed Frame Descriptor Record (PFDR).
-This memory is reserved/allocated as a nodes under the /reserved-memory node
+This memory is reserved/allocated as a node under the /reserved-memory node.
+
+For additional details about reserved memory regions see reserved-memory.txt
The QMan FQD memory node must be named "qman-fqd"
@@ -83,7 +85,7 @@ PROPERTIES
- compatible
Usage: required
Value type: <stringlist>
- Definition: Must inclide "fsl,qman-fqd"
+ Definition: Must include "shared-dma-pool"
The QMan PFDR memory node must be named "qman-pfdr"
@@ -92,7 +94,7 @@ PROPERTIES
- compatible
Usage: required
Value type: <stringlist>
- Definition: Must inclide "fsl,qman-pfdr"
+ Definition: Must include "shared-dma-pool"
The following constraints are relevant to the FQD and PFDR private memory:
- The size must be 2^(size + 1), with size = 11..29. That is 4 KiB to
@@ -117,16 +119,16 @@ The example below shows a QMan FQD and a PFDR dynamic allocation memory nodes
ranges;
qman_fqd: qman-fqd {
- compatible = "fsl,qman-fqd";
- alloc-ranges = <0 0 0x10 0>;
+ compatible = "shared-dma-pool";
size = <0 0x400000>;
alignment = <0 0x400000>;
+ no-map;
};
qman_pfdr: qman-pfdr {
- compatible = "fsl,qman-pfdr";
- alloc-ranges = <0 0 0x10 0>;
+ compatible = "shared-dma-pool";
size = <0 0x2000000>;
alignment = <0 0x2000000>;
+ no-map;
};
};
--
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
* [RFC PATCH 5/5] powerpc: Add HAVE_GENERIC_DMA_COHERENT options to Kconfig
From: Roy Pledge @ 2017-03-29 21:13 UTC (permalink / raw)
To: robin.murphy-5wv7dgnIgG8, oss-fOR+EgIDQEHk1uMJSBkQmQ,
linuxppc-dev-uLR06cmDAlY/bJ5BZ2RsiQ,
linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r,
devicetree-u79uwXL29TY76Z2rM5mHXA
Cc: madalin.bucur-3arQi8VN3Tc, Roy Pledge
In-Reply-To: <1490822037-6752-1-git-send-email-roy.pledge-3arQi8VN3Tc@public.gmane.org>
Enable HAVE_GENERIC_DMA_COHERENT to enable use of shared-dma-pool
reserved memory mappings
Signed-off-by: Roy Pledge <roy.pledge-3arQi8VN3Tc@public.gmane.org>
---
arch/powerpc/Kconfig | 1 +
1 file changed, 1 insertion(+)
diff --git a/arch/powerpc/Kconfig b/arch/powerpc/Kconfig
index 186e060..0e80e8b 100644
--- a/arch/powerpc/Kconfig
+++ b/arch/powerpc/Kconfig
@@ -136,6 +136,7 @@ config PPC
select HAVE_FUNCTION_GRAPH_TRACER
select HAVE_FUNCTION_TRACER
select HAVE_GCC_PLUGINS
+ select HAVE_GENERIC_DMA_COHERENT
select HAVE_GENERIC_GUP
select HAVE_HW_BREAKPOINT if PERF_EVENTS && (PPC_BOOK3S || PPC_8xx)
select HAVE_IDE
--
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: [PATCHv3 00/10] Nokia H4+ support
From: Rob Herring @ 2017-03-29 21:17 UTC (permalink / raw)
To: Sebastian Reichel
Cc: Marcel Holtmann, Gustavo Padovan, Johan Hedberg, Samuel Thibault,
Pavel Machek, Tony Lindgren, Greg Kroah-Hartman, Jiri Slaby,
Mark Rutland, open list:BLUETOOTH DRIVERS,
linux-serial@vger.kernel.org, devicetree@vger.kernel.org,
linux-kernel@vger.kernel.org
In-Reply-To: <20170328155939.31566-1-sre@kernel.org>
On Tue, Mar 28, 2017 at 10:59 AM, Sebastian Reichel <sre@kernel.org> wrote:
> Hi,
>
> Here is PATCHv3 for the Nokia bluetooth patchset. I addressed all comments from
> Rob and Pavel regarding the serdev patches and dropped the *.dts patches, since
> they were queued by Tony. I also changed the patch order, so that the serdev
> patches come first. All of them have Acked-by from Rob, so I think it makes
> sense to merge them to serdev subsystem (now) and provide an immutable branch
> for the bluetooth subsystem.
Greg doesn't read cover letters generally and since the serdev patches
are Cc rather than To him, he's probably not planning to pick them up.
Rob
^ permalink raw reply
* Re: [PATCH v6 1/5] irqchip/aspeed-i2c-ic: binding docs for Aspeed I2C Interrupt Controller
From: Benjamin Herrenschmidt @ 2017-03-29 21:17 UTC (permalink / raw)
To: Brendan Higgins
Cc: Wolfram Sang, Rob Herring, Mark Rutland, Thomas Gleixner,
Jason Cooper, Marc Zyngier, Joel Stanley, Vladimir Zapolskiy,
Kachalov Anton, Cédric Le Goater, linux-i2c, devicetree,
Linux Kernel Mailing List, OpenBMC Maillist
In-Reply-To: <CAFd5g460U4c3rMtKphxnu=OADTfD=oe8Z+JPn-H82zpHKJUqfw@mail.gmail.com>
On Wed, 2017-03-29 at 13:51 -0700, Brendan Higgins wrote:
> so maybe instead of setting a hard limit like I did, maybe the best
> thing is to just check and see what the base_clk gets set to and if
> it gets set to zero, we turn on high speed mode. What do you think?
Ah maybe. Did you scope it to see if clock_hi/low do indeed apply in
high speed mode ?
I wonder if that bit does other things.. I would be interesting to
check. Ohterwise why have the bit rather than just have the driver
write 0 to the divisor ?
The doc for the high speed mode bit says "high speed mode (3.4Mbps)"
which is why I, maybe incorrectly, assumed it was a fixed frequency.
Anyway, not a huge deal at this point, but something to look into
at some stage.
Cheers,
Ben.
^ permalink raw reply
* [PATCH v2 1/1] of: Move OF property and graph API from base.c to property.c
From: Sakari Ailus @ 2017-03-29 21:24 UTC (permalink / raw)
To: devicetree, rafael
Cc: linux-acpi, sudeep.holla, lorenzo.pieralisi, mika.westerberg,
mark.rutland, broonie, robh, ahs3, frowand.list
base.c contains both core OF functions and increasingly other
functionality such as accessing properties and graphs, including
convenience functions. In the near future this would also include OF
specific implementation of the fwnode property and graph APIs.
Create driver/of/property.c to contain procedures for accessing and
interpreting device tree properties. The procedures are moved from
drivers/of/base.c, with no changes other than copying only the includes
required by the moved procedures.
Signed-off-by: Sakari Ailus <sakari.ailus@linux.intel.com>
---
since v1:
- Improved commit message.
- Tell that OF property and graph interface functions are located in the
newly created property.c, and that the origin of the functions in
property.c is base.c.
drivers/of/Makefile | 2 +-
drivers/of/base.c | 702 -----------------------------------------------
drivers/of/property.c | 732 ++++++++++++++++++++++++++++++++++++++++++++++++++
3 files changed, 733 insertions(+), 703 deletions(-)
create mode 100644 drivers/of/property.c
diff --git a/drivers/of/Makefile b/drivers/of/Makefile
index d7efd9d..97dc01c 100644
--- a/drivers/of/Makefile
+++ b/drivers/of/Makefile
@@ -1,4 +1,4 @@
-obj-y = base.o device.o platform.o
+obj-y = base.o device.o platform.o property.o
obj-$(CONFIG_OF_DYNAMIC) += dynamic.o
obj-$(CONFIG_OF_FLATTREE) += fdt.o
obj-$(CONFIG_OF_EARLY_FLATTREE) += fdt_address.o
diff --git a/drivers/of/base.c b/drivers/of/base.c
index d7c4629..d57188d 100644
--- a/drivers/of/base.c
+++ b/drivers/of/base.c
@@ -1113,427 +1113,6 @@ struct device_node *of_find_node_by_phandle(phandle handle)
}
EXPORT_SYMBOL(of_find_node_by_phandle);
-/**
- * of_property_count_elems_of_size - Count the number of elements in a property
- *
- * @np: device node from which the property value is to be read.
- * @propname: name of the property to be searched.
- * @elem_size: size of the individual element
- *
- * Search for a property in a device node and count the number of elements of
- * size elem_size in it. Returns number of elements on sucess, -EINVAL if the
- * property does not exist or its length does not match a multiple of elem_size
- * and -ENODATA if the property does not have a value.
- */
-int of_property_count_elems_of_size(const struct device_node *np,
- const char *propname, int elem_size)
-{
- struct property *prop = of_find_property(np, propname, NULL);
-
- if (!prop)
- return -EINVAL;
- if (!prop->value)
- return -ENODATA;
-
- if (prop->length % elem_size != 0) {
- pr_err("size of %s in node %s is not a multiple of %d\n",
- propname, np->full_name, elem_size);
- return -EINVAL;
- }
-
- return prop->length / elem_size;
-}
-EXPORT_SYMBOL_GPL(of_property_count_elems_of_size);
-
-/**
- * of_find_property_value_of_size
- *
- * @np: device node from which the property value is to be read.
- * @propname: name of the property to be searched.
- * @min: minimum allowed length of property value
- * @max: maximum allowed length of property value (0 means unlimited)
- * @len: if !=NULL, actual length is written to here
- *
- * Search for a property in a device node and valid the requested size.
- * Returns the property value on success, -EINVAL if the property does not
- * exist, -ENODATA if property does not have a value, and -EOVERFLOW if the
- * property data is too small or too large.
- *
- */
-static void *of_find_property_value_of_size(const struct device_node *np,
- const char *propname, u32 min, u32 max, size_t *len)
-{
- struct property *prop = of_find_property(np, propname, NULL);
-
- if (!prop)
- return ERR_PTR(-EINVAL);
- if (!prop->value)
- return ERR_PTR(-ENODATA);
- if (prop->length < min)
- return ERR_PTR(-EOVERFLOW);
- if (max && prop->length > max)
- return ERR_PTR(-EOVERFLOW);
-
- if (len)
- *len = prop->length;
-
- return prop->value;
-}
-
-/**
- * of_property_read_u32_index - Find and read a u32 from a multi-value property.
- *
- * @np: device node from which the property value is to be read.
- * @propname: name of the property to be searched.
- * @index: index of the u32 in the list of values
- * @out_value: pointer to return value, modified only if no error.
- *
- * Search for a property in a device node and read nth 32-bit value from
- * it. Returns 0 on success, -EINVAL if the property does not exist,
- * -ENODATA if property does not have a value, and -EOVERFLOW if the
- * property data isn't large enough.
- *
- * The out_value is modified only if a valid u32 value can be decoded.
- */
-int of_property_read_u32_index(const struct device_node *np,
- const char *propname,
- u32 index, u32 *out_value)
-{
- const u32 *val = of_find_property_value_of_size(np, propname,
- ((index + 1) * sizeof(*out_value)),
- 0,
- NULL);
-
- if (IS_ERR(val))
- return PTR_ERR(val);
-
- *out_value = be32_to_cpup(((__be32 *)val) + index);
- return 0;
-}
-EXPORT_SYMBOL_GPL(of_property_read_u32_index);
-
-/**
- * of_property_read_variable_u8_array - Find and read an array of u8 from a
- * property, with bounds on the minimum and maximum array size.
- *
- * @np: device node from which the property value is to be read.
- * @propname: name of the property to be searched.
- * @out_values: pointer to return value, modified only if return value is 0.
- * @sz_min: minimum number of array elements to read
- * @sz_max: maximum number of array elements to read, if zero there is no
- * upper limit on the number of elements in the dts entry but only
- * sz_min will be read.
- *
- * Search for a property in a device node and read 8-bit value(s) from
- * it. Returns number of elements read on success, -EINVAL if the property
- * does not exist, -ENODATA if property does not have a value, and -EOVERFLOW
- * if the property data is smaller than sz_min or longer than sz_max.
- *
- * dts entry of array should be like:
- * property = /bits/ 8 <0x50 0x60 0x70>;
- *
- * The out_values is modified only if a valid u8 value can be decoded.
- */
-int of_property_read_variable_u8_array(const struct device_node *np,
- const char *propname, u8 *out_values,
- size_t sz_min, size_t sz_max)
-{
- size_t sz, count;
- const u8 *val = of_find_property_value_of_size(np, propname,
- (sz_min * sizeof(*out_values)),
- (sz_max * sizeof(*out_values)),
- &sz);
-
- if (IS_ERR(val))
- return PTR_ERR(val);
-
- if (!sz_max)
- sz = sz_min;
- else
- sz /= sizeof(*out_values);
-
- count = sz;
- while (count--)
- *out_values++ = *val++;
-
- return sz;
-}
-EXPORT_SYMBOL_GPL(of_property_read_variable_u8_array);
-
-/**
- * of_property_read_variable_u16_array - Find and read an array of u16 from a
- * property, with bounds on the minimum and maximum array size.
- *
- * @np: device node from which the property value is to be read.
- * @propname: name of the property to be searched.
- * @out_values: pointer to return value, modified only if return value is 0.
- * @sz_min: minimum number of array elements to read
- * @sz_max: maximum number of array elements to read, if zero there is no
- * upper limit on the number of elements in the dts entry but only
- * sz_min will be read.
- *
- * Search for a property in a device node and read 16-bit value(s) from
- * it. Returns number of elements read on success, -EINVAL if the property
- * does not exist, -ENODATA if property does not have a value, and -EOVERFLOW
- * if the property data is smaller than sz_min or longer than sz_max.
- *
- * dts entry of array should be like:
- * property = /bits/ 16 <0x5000 0x6000 0x7000>;
- *
- * The out_values is modified only if a valid u16 value can be decoded.
- */
-int of_property_read_variable_u16_array(const struct device_node *np,
- const char *propname, u16 *out_values,
- size_t sz_min, size_t sz_max)
-{
- size_t sz, count;
- const __be16 *val = of_find_property_value_of_size(np, propname,
- (sz_min * sizeof(*out_values)),
- (sz_max * sizeof(*out_values)),
- &sz);
-
- if (IS_ERR(val))
- return PTR_ERR(val);
-
- if (!sz_max)
- sz = sz_min;
- else
- sz /= sizeof(*out_values);
-
- count = sz;
- while (count--)
- *out_values++ = be16_to_cpup(val++);
-
- return sz;
-}
-EXPORT_SYMBOL_GPL(of_property_read_variable_u16_array);
-
-/**
- * of_property_read_variable_u32_array - Find and read an array of 32 bit
- * integers from a property, with bounds on the minimum and maximum array size.
- *
- * @np: device node from which the property value is to be read.
- * @propname: name of the property to be searched.
- * @out_values: pointer to return value, modified only if return value is 0.
- * @sz_min: minimum number of array elements to read
- * @sz_max: maximum number of array elements to read, if zero there is no
- * upper limit on the number of elements in the dts entry but only
- * sz_min will be read.
- *
- * Search for a property in a device node and read 32-bit value(s) from
- * it. Returns number of elements read on success, -EINVAL if the property
- * does not exist, -ENODATA if property does not have a value, and -EOVERFLOW
- * if the property data is smaller than sz_min or longer than sz_max.
- *
- * The out_values is modified only if a valid u32 value can be decoded.
- */
-int of_property_read_variable_u32_array(const struct device_node *np,
- const char *propname, u32 *out_values,
- size_t sz_min, size_t sz_max)
-{
- size_t sz, count;
- const __be32 *val = of_find_property_value_of_size(np, propname,
- (sz_min * sizeof(*out_values)),
- (sz_max * sizeof(*out_values)),
- &sz);
-
- if (IS_ERR(val))
- return PTR_ERR(val);
-
- if (!sz_max)
- sz = sz_min;
- else
- sz /= sizeof(*out_values);
-
- count = sz;
- while (count--)
- *out_values++ = be32_to_cpup(val++);
-
- return sz;
-}
-EXPORT_SYMBOL_GPL(of_property_read_variable_u32_array);
-
-/**
- * of_property_read_u64 - Find and read a 64 bit integer from a property
- * @np: device node from which the property value is to be read.
- * @propname: name of the property to be searched.
- * @out_value: pointer to return value, modified only if return value is 0.
- *
- * Search for a property in a device node and read a 64-bit value from
- * it. Returns 0 on success, -EINVAL if the property does not exist,
- * -ENODATA if property does not have a value, and -EOVERFLOW if the
- * property data isn't large enough.
- *
- * The out_value is modified only if a valid u64 value can be decoded.
- */
-int of_property_read_u64(const struct device_node *np, const char *propname,
- u64 *out_value)
-{
- const __be32 *val = of_find_property_value_of_size(np, propname,
- sizeof(*out_value),
- 0,
- NULL);
-
- if (IS_ERR(val))
- return PTR_ERR(val);
-
- *out_value = of_read_number(val, 2);
- return 0;
-}
-EXPORT_SYMBOL_GPL(of_property_read_u64);
-
-/**
- * of_property_read_variable_u64_array - Find and read an array of 64 bit
- * integers from a property, with bounds on the minimum and maximum array size.
- *
- * @np: device node from which the property value is to be read.
- * @propname: name of the property to be searched.
- * @out_values: pointer to return value, modified only if return value is 0.
- * @sz_min: minimum number of array elements to read
- * @sz_max: maximum number of array elements to read, if zero there is no
- * upper limit on the number of elements in the dts entry but only
- * sz_min will be read.
- *
- * Search for a property in a device node and read 64-bit value(s) from
- * it. Returns number of elements read on success, -EINVAL if the property
- * does not exist, -ENODATA if property does not have a value, and -EOVERFLOW
- * if the property data is smaller than sz_min or longer than sz_max.
- *
- * The out_values is modified only if a valid u64 value can be decoded.
- */
-int of_property_read_variable_u64_array(const struct device_node *np,
- const char *propname, u64 *out_values,
- size_t sz_min, size_t sz_max)
-{
- size_t sz, count;
- const __be32 *val = of_find_property_value_of_size(np, propname,
- (sz_min * sizeof(*out_values)),
- (sz_max * sizeof(*out_values)),
- &sz);
-
- if (IS_ERR(val))
- return PTR_ERR(val);
-
- if (!sz_max)
- sz = sz_min;
- else
- sz /= sizeof(*out_values);
-
- count = sz;
- while (count--) {
- *out_values++ = of_read_number(val, 2);
- val += 2;
- }
-
- return sz;
-}
-EXPORT_SYMBOL_GPL(of_property_read_variable_u64_array);
-
-/**
- * of_property_read_string - Find and read a string from a property
- * @np: device node from which the property value is to be read.
- * @propname: name of the property to be searched.
- * @out_string: pointer to null terminated return string, modified only if
- * return value is 0.
- *
- * Search for a property in a device tree node and retrieve a null
- * terminated string value (pointer to data, not a copy). Returns 0 on
- * success, -EINVAL if the property does not exist, -ENODATA if property
- * does not have a value, and -EILSEQ if the string is not null-terminated
- * within the length of the property data.
- *
- * The out_string pointer is modified only if a valid string can be decoded.
- */
-int of_property_read_string(const struct device_node *np, const char *propname,
- const char **out_string)
-{
- const struct property *prop = of_find_property(np, propname, NULL);
- if (!prop)
- return -EINVAL;
- if (!prop->value)
- return -ENODATA;
- if (strnlen(prop->value, prop->length) >= prop->length)
- return -EILSEQ;
- *out_string = prop->value;
- return 0;
-}
-EXPORT_SYMBOL_GPL(of_property_read_string);
-
-/**
- * of_property_match_string() - Find string in a list and return index
- * @np: pointer to node containing string list property
- * @propname: string list property name
- * @string: pointer to string to search for in string list
- *
- * This function searches a string list property and returns the index
- * of a specific string value.
- */
-int of_property_match_string(const struct device_node *np, const char *propname,
- const char *string)
-{
- const struct property *prop = of_find_property(np, propname, NULL);
- size_t l;
- int i;
- const char *p, *end;
-
- if (!prop)
- return -EINVAL;
- if (!prop->value)
- return -ENODATA;
-
- p = prop->value;
- end = p + prop->length;
-
- for (i = 0; p < end; i++, p += l) {
- l = strnlen(p, end - p) + 1;
- if (p + l > end)
- return -EILSEQ;
- pr_debug("comparing %s with %s\n", string, p);
- if (strcmp(string, p) == 0)
- return i; /* Found it; return index */
- }
- return -ENODATA;
-}
-EXPORT_SYMBOL_GPL(of_property_match_string);
-
-/**
- * of_property_read_string_helper() - Utility helper for parsing string properties
- * @np: device node from which the property value is to be read.
- * @propname: name of the property to be searched.
- * @out_strs: output array of string pointers.
- * @sz: number of array elements to read.
- * @skip: Number of strings to skip over at beginning of list.
- *
- * Don't call this function directly. It is a utility helper for the
- * of_property_read_string*() family of functions.
- */
-int of_property_read_string_helper(const struct device_node *np,
- const char *propname, const char **out_strs,
- size_t sz, int skip)
-{
- const struct property *prop = of_find_property(np, propname, NULL);
- int l = 0, i = 0;
- const char *p, *end;
-
- if (!prop)
- return -EINVAL;
- if (!prop->value)
- return -ENODATA;
- p = prop->value;
- end = p + prop->length;
-
- for (i = 0; p < end && (!out_strs || i < skip + sz); i++, p += l) {
- l = strnlen(p, end - p) + 1;
- if (p + l > end)
- return -EILSEQ;
- if (out_strs && i >= skip)
- *out_strs++ = p;
- }
- i -= skip;
- return i <= 0 ? -ENODATA : i;
-}
-EXPORT_SYMBOL_GPL(of_property_read_string_helper);
-
void of_print_phandle_args(const char *msg, const struct of_phandle_args *args)
{
int i;
@@ -2180,47 +1759,6 @@ int of_alias_get_highest_id(const char *stem)
}
EXPORT_SYMBOL_GPL(of_alias_get_highest_id);
-const __be32 *of_prop_next_u32(struct property *prop, const __be32 *cur,
- u32 *pu)
-{
- const void *curv = cur;
-
- if (!prop)
- return NULL;
-
- if (!cur) {
- curv = prop->value;
- goto out_val;
- }
-
- curv += sizeof(*cur);
- if (curv >= prop->value + prop->length)
- return NULL;
-
-out_val:
- *pu = be32_to_cpup(curv);
- return curv;
-}
-EXPORT_SYMBOL_GPL(of_prop_next_u32);
-
-const char *of_prop_next_string(struct property *prop, const char *cur)
-{
- const void *curv = cur;
-
- if (!prop)
- return NULL;
-
- if (!cur)
- return prop->value;
-
- curv += strlen(cur) + 1;
- if (curv >= prop->value + prop->length)
- return NULL;
-
- return curv;
-}
-EXPORT_SYMBOL_GPL(of_prop_next_string);
-
/**
* of_console_check() - Test and setup console for DT setup
* @dn - Pointer to device node
@@ -2295,243 +1833,3 @@ int of_find_last_cache_level(unsigned int cpu)
return cache_level;
}
-
-/**
- * of_graph_parse_endpoint() - parse common endpoint node properties
- * @node: pointer to endpoint device_node
- * @endpoint: pointer to the OF endpoint data structure
- *
- * The caller should hold a reference to @node.
- */
-int of_graph_parse_endpoint(const struct device_node *node,
- struct of_endpoint *endpoint)
-{
- struct device_node *port_node = of_get_parent(node);
-
- WARN_ONCE(!port_node, "%s(): endpoint %s has no parent node\n",
- __func__, node->full_name);
-
- memset(endpoint, 0, sizeof(*endpoint));
-
- endpoint->local_node = node;
- /*
- * It doesn't matter whether the two calls below succeed.
- * If they don't then the default value 0 is used.
- */
- of_property_read_u32(port_node, "reg", &endpoint->port);
- of_property_read_u32(node, "reg", &endpoint->id);
-
- of_node_put(port_node);
-
- return 0;
-}
-EXPORT_SYMBOL(of_graph_parse_endpoint);
-
-/**
- * of_graph_get_port_by_id() - get the port matching a given id
- * @parent: pointer to the parent device node
- * @id: id of the port
- *
- * Return: A 'port' node pointer with refcount incremented. The caller
- * has to use of_node_put() on it when done.
- */
-struct device_node *of_graph_get_port_by_id(struct device_node *parent, u32 id)
-{
- struct device_node *node, *port;
-
- node = of_get_child_by_name(parent, "ports");
- if (node)
- parent = node;
-
- for_each_child_of_node(parent, port) {
- u32 port_id = 0;
-
- if (of_node_cmp(port->name, "port") != 0)
- continue;
- of_property_read_u32(port, "reg", &port_id);
- if (id == port_id)
- break;
- }
-
- of_node_put(node);
-
- return port;
-}
-EXPORT_SYMBOL(of_graph_get_port_by_id);
-
-/**
- * of_graph_get_next_endpoint() - get next endpoint node
- * @parent: pointer to the parent device node
- * @prev: previous endpoint node, or NULL to get first
- *
- * Return: An 'endpoint' node pointer with refcount incremented. Refcount
- * of the passed @prev node is decremented.
- */
-struct device_node *of_graph_get_next_endpoint(const struct device_node *parent,
- struct device_node *prev)
-{
- struct device_node *endpoint;
- struct device_node *port;
-
- if (!parent)
- return NULL;
-
- /*
- * Start by locating the port node. If no previous endpoint is specified
- * search for the first port node, otherwise get the previous endpoint
- * parent port node.
- */
- if (!prev) {
- struct device_node *node;
-
- node = of_get_child_by_name(parent, "ports");
- if (node)
- parent = node;
-
- port = of_get_child_by_name(parent, "port");
- of_node_put(node);
-
- if (!port) {
- pr_err("graph: no port node found in %s\n",
- parent->full_name);
- return NULL;
- }
- } else {
- port = of_get_parent(prev);
- if (WARN_ONCE(!port, "%s(): endpoint %s has no parent node\n",
- __func__, prev->full_name))
- return NULL;
- }
-
- while (1) {
- /*
- * Now that we have a port node, get the next endpoint by
- * getting the next child. If the previous endpoint is NULL this
- * will return the first child.
- */
- endpoint = of_get_next_child(port, prev);
- if (endpoint) {
- of_node_put(port);
- return endpoint;
- }
-
- /* No more endpoints under this port, try the next one. */
- prev = NULL;
-
- do {
- port = of_get_next_child(parent, port);
- if (!port)
- return NULL;
- } while (of_node_cmp(port->name, "port"));
- }
-}
-EXPORT_SYMBOL(of_graph_get_next_endpoint);
-
-/**
- * of_graph_get_endpoint_by_regs() - get endpoint node of specific identifiers
- * @parent: pointer to the parent device node
- * @port_reg: identifier (value of reg property) of the parent port node
- * @reg: identifier (value of reg property) of the endpoint node
- *
- * Return: An 'endpoint' node pointer which is identified by reg and at the same
- * is the child of a port node identified by port_reg. reg and port_reg are
- * ignored when they are -1.
- */
-struct device_node *of_graph_get_endpoint_by_regs(
- const struct device_node *parent, int port_reg, int reg)
-{
- struct of_endpoint endpoint;
- struct device_node *node = NULL;
-
- for_each_endpoint_of_node(parent, node) {
- of_graph_parse_endpoint(node, &endpoint);
- if (((port_reg == -1) || (endpoint.port == port_reg)) &&
- ((reg == -1) || (endpoint.id == reg)))
- return node;
- }
-
- return NULL;
-}
-EXPORT_SYMBOL(of_graph_get_endpoint_by_regs);
-
-/**
- * of_graph_get_remote_port_parent() - get remote port's parent node
- * @node: pointer to a local endpoint device_node
- *
- * Return: Remote device node associated with remote endpoint node linked
- * to @node. Use of_node_put() on it when done.
- */
-struct device_node *of_graph_get_remote_port_parent(
- const struct device_node *node)
-{
- struct device_node *np;
- unsigned int depth;
-
- /* Get remote endpoint node. */
- np = of_parse_phandle(node, "remote-endpoint", 0);
-
- /* Walk 3 levels up only if there is 'ports' node. */
- for (depth = 3; depth && np; depth--) {
- np = of_get_next_parent(np);
- if (depth == 2 && of_node_cmp(np->name, "ports"))
- break;
- }
- return np;
-}
-EXPORT_SYMBOL(of_graph_get_remote_port_parent);
-
-/**
- * of_graph_get_remote_port() - get remote port node
- * @node: pointer to a local endpoint device_node
- *
- * Return: Remote port node associated with remote endpoint node linked
- * to @node. Use of_node_put() on it when done.
- */
-struct device_node *of_graph_get_remote_port(const struct device_node *node)
-{
- struct device_node *np;
-
- /* Get remote endpoint node. */
- np = of_parse_phandle(node, "remote-endpoint", 0);
- if (!np)
- return NULL;
- return of_get_next_parent(np);
-}
-EXPORT_SYMBOL(of_graph_get_remote_port);
-
-/**
- * of_graph_get_remote_node() - get remote parent device_node for given port/endpoint
- * @node: pointer to parent device_node containing graph port/endpoint
- * @port: identifier (value of reg property) of the parent port node
- * @endpoint: identifier (value of reg property) of the endpoint node
- *
- * Return: Remote device node associated with remote endpoint node linked
- * to @node. Use of_node_put() on it when done.
- */
-struct device_node *of_graph_get_remote_node(const struct device_node *node,
- u32 port, u32 endpoint)
-{
- struct device_node *endpoint_node, *remote;
-
- endpoint_node = of_graph_get_endpoint_by_regs(node, port, endpoint);
- if (!endpoint_node) {
- pr_debug("no valid endpoint (%d, %d) for node %s\n",
- port, endpoint, node->full_name);
- return NULL;
- }
-
- remote = of_graph_get_remote_port_parent(endpoint_node);
- of_node_put(endpoint_node);
- if (!remote) {
- pr_debug("no valid remote node\n");
- return NULL;
- }
-
- if (!of_device_is_available(remote)) {
- pr_debug("not available for remote node\n");
- return NULL;
- }
-
- return remote;
-}
-EXPORT_SYMBOL(of_graph_get_remote_node);
diff --git a/drivers/of/property.c b/drivers/of/property.c
new file mode 100644
index 0000000..e9fc8bb
--- /dev/null
+++ b/drivers/of/property.c
@@ -0,0 +1,732 @@
+/*
+ * drivers/of/property.c - Procedures for accessing and interpreting
+ * Devicetree properties and graphs.
+ *
+ * Initially created by copying procedures from drivers/of/base.c. This
+ * file contains the OF property as well as the OF graph interface
+ * functions.
+ *
+ * Paul Mackerras August 1996.
+ * Copyright (C) 1996-2005 Paul Mackerras.
+ *
+ * Adapted for 64bit PowerPC by Dave Engebretsen and Peter Bergner.
+ * {engebret|bergner}@us.ibm.com
+ *
+ * Adapted for sparc and sparc64 by David S. Miller davem@davemloft.net
+ *
+ * Reconsolidated from arch/x/kernel/prom.c by Stephen Rothwell and
+ * Grant Likely.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version
+ * 2 of the License, or (at your option) any later version.
+ */
+
+#include <linux/of.h>
+#include <linux/of_device.h>
+#include <linux/of_graph.h>
+#include <linux/string.h>
+
+#include "of_private.h"
+/**
+ * of_property_count_elems_of_size - Count the number of elements in a property
+ *
+ * @np: device node from which the property value is to be read.
+ * @propname: name of the property to be searched.
+ * @elem_size: size of the individual element
+ *
+ * Search for a property in a device node and count the number of elements of
+ * size elem_size in it. Returns number of elements on sucess, -EINVAL if the
+ * property does not exist or its length does not match a multiple of elem_size
+ * and -ENODATA if the property does not have a value.
+ */
+int of_property_count_elems_of_size(const struct device_node *np,
+ const char *propname, int elem_size)
+{
+ struct property *prop = of_find_property(np, propname, NULL);
+
+ if (!prop)
+ return -EINVAL;
+ if (!prop->value)
+ return -ENODATA;
+
+ if (prop->length % elem_size != 0) {
+ pr_err("size of %s in node %s is not a multiple of %d\n",
+ propname, np->full_name, elem_size);
+ return -EINVAL;
+ }
+
+ return prop->length / elem_size;
+}
+EXPORT_SYMBOL_GPL(of_property_count_elems_of_size);
+
+/**
+ * of_find_property_value_of_size
+ *
+ * @np: device node from which the property value is to be read.
+ * @propname: name of the property to be searched.
+ * @min: minimum allowed length of property value
+ * @max: maximum allowed length of property value (0 means unlimited)
+ * @len: if !=NULL, actual length is written to here
+ *
+ * Search for a property in a device node and valid the requested size.
+ * Returns the property value on success, -EINVAL if the property does not
+ * exist, -ENODATA if property does not have a value, and -EOVERFLOW if the
+ * property data is too small or too large.
+ *
+ */
+static void *of_find_property_value_of_size(const struct device_node *np,
+ const char *propname, u32 min, u32 max, size_t *len)
+{
+ struct property *prop = of_find_property(np, propname, NULL);
+
+ if (!prop)
+ return ERR_PTR(-EINVAL);
+ if (!prop->value)
+ return ERR_PTR(-ENODATA);
+ if (prop->length < min)
+ return ERR_PTR(-EOVERFLOW);
+ if (max && prop->length > max)
+ return ERR_PTR(-EOVERFLOW);
+
+ if (len)
+ *len = prop->length;
+
+ return prop->value;
+}
+
+/**
+ * of_property_read_u32_index - Find and read a u32 from a multi-value property.
+ *
+ * @np: device node from which the property value is to be read.
+ * @propname: name of the property to be searched.
+ * @index: index of the u32 in the list of values
+ * @out_value: pointer to return value, modified only if no error.
+ *
+ * Search for a property in a device node and read nth 32-bit value from
+ * it. Returns 0 on success, -EINVAL if the property does not exist,
+ * -ENODATA if property does not have a value, and -EOVERFLOW if the
+ * property data isn't large enough.
+ *
+ * The out_value is modified only if a valid u32 value can be decoded.
+ */
+int of_property_read_u32_index(const struct device_node *np,
+ const char *propname,
+ u32 index, u32 *out_value)
+{
+ const u32 *val = of_find_property_value_of_size(np, propname,
+ ((index + 1) * sizeof(*out_value)),
+ 0,
+ NULL);
+
+ if (IS_ERR(val))
+ return PTR_ERR(val);
+
+ *out_value = be32_to_cpup(((__be32 *)val) + index);
+ return 0;
+}
+EXPORT_SYMBOL_GPL(of_property_read_u32_index);
+
+/**
+ * of_property_read_variable_u8_array - Find and read an array of u8 from a
+ * property, with bounds on the minimum and maximum array size.
+ *
+ * @np: device node from which the property value is to be read.
+ * @propname: name of the property to be searched.
+ * @out_values: pointer to return value, modified only if return value is 0.
+ * @sz_min: minimum number of array elements to read
+ * @sz_max: maximum number of array elements to read, if zero there is no
+ * upper limit on the number of elements in the dts entry but only
+ * sz_min will be read.
+ *
+ * Search for a property in a device node and read 8-bit value(s) from
+ * it. Returns number of elements read on success, -EINVAL if the property
+ * does not exist, -ENODATA if property does not have a value, and -EOVERFLOW
+ * if the property data is smaller than sz_min or longer than sz_max.
+ *
+ * dts entry of array should be like:
+ * property = /bits/ 8 <0x50 0x60 0x70>;
+ *
+ * The out_values is modified only if a valid u8 value can be decoded.
+ */
+int of_property_read_variable_u8_array(const struct device_node *np,
+ const char *propname, u8 *out_values,
+ size_t sz_min, size_t sz_max)
+{
+ size_t sz, count;
+ const u8 *val = of_find_property_value_of_size(np, propname,
+ (sz_min * sizeof(*out_values)),
+ (sz_max * sizeof(*out_values)),
+ &sz);
+
+ if (IS_ERR(val))
+ return PTR_ERR(val);
+
+ if (!sz_max)
+ sz = sz_min;
+ else
+ sz /= sizeof(*out_values);
+
+ count = sz;
+ while (count--)
+ *out_values++ = *val++;
+
+ return sz;
+}
+EXPORT_SYMBOL_GPL(of_property_read_variable_u8_array);
+
+/**
+ * of_property_read_variable_u16_array - Find and read an array of u16 from a
+ * property, with bounds on the minimum and maximum array size.
+ *
+ * @np: device node from which the property value is to be read.
+ * @propname: name of the property to be searched.
+ * @out_values: pointer to return value, modified only if return value is 0.
+ * @sz_min: minimum number of array elements to read
+ * @sz_max: maximum number of array elements to read, if zero there is no
+ * upper limit on the number of elements in the dts entry but only
+ * sz_min will be read.
+ *
+ * Search for a property in a device node and read 16-bit value(s) from
+ * it. Returns number of elements read on success, -EINVAL if the property
+ * does not exist, -ENODATA if property does not have a value, and -EOVERFLOW
+ * if the property data is smaller than sz_min or longer than sz_max.
+ *
+ * dts entry of array should be like:
+ * property = /bits/ 16 <0x5000 0x6000 0x7000>;
+ *
+ * The out_values is modified only if a valid u16 value can be decoded.
+ */
+int of_property_read_variable_u16_array(const struct device_node *np,
+ const char *propname, u16 *out_values,
+ size_t sz_min, size_t sz_max)
+{
+ size_t sz, count;
+ const __be16 *val = of_find_property_value_of_size(np, propname,
+ (sz_min * sizeof(*out_values)),
+ (sz_max * sizeof(*out_values)),
+ &sz);
+
+ if (IS_ERR(val))
+ return PTR_ERR(val);
+
+ if (!sz_max)
+ sz = sz_min;
+ else
+ sz /= sizeof(*out_values);
+
+ count = sz;
+ while (count--)
+ *out_values++ = be16_to_cpup(val++);
+
+ return sz;
+}
+EXPORT_SYMBOL_GPL(of_property_read_variable_u16_array);
+
+/**
+ * of_property_read_variable_u32_array - Find and read an array of 32 bit
+ * integers from a property, with bounds on the minimum and maximum array size.
+ *
+ * @np: device node from which the property value is to be read.
+ * @propname: name of the property to be searched.
+ * @out_values: pointer to return value, modified only if return value is 0.
+ * @sz_min: minimum number of array elements to read
+ * @sz_max: maximum number of array elements to read, if zero there is no
+ * upper limit on the number of elements in the dts entry but only
+ * sz_min will be read.
+ *
+ * Search for a property in a device node and read 32-bit value(s) from
+ * it. Returns number of elements read on success, -EINVAL if the property
+ * does not exist, -ENODATA if property does not have a value, and -EOVERFLOW
+ * if the property data is smaller than sz_min or longer than sz_max.
+ *
+ * The out_values is modified only if a valid u32 value can be decoded.
+ */
+int of_property_read_variable_u32_array(const struct device_node *np,
+ const char *propname, u32 *out_values,
+ size_t sz_min, size_t sz_max)
+{
+ size_t sz, count;
+ const __be32 *val = of_find_property_value_of_size(np, propname,
+ (sz_min * sizeof(*out_values)),
+ (sz_max * sizeof(*out_values)),
+ &sz);
+
+ if (IS_ERR(val))
+ return PTR_ERR(val);
+
+ if (!sz_max)
+ sz = sz_min;
+ else
+ sz /= sizeof(*out_values);
+
+ count = sz;
+ while (count--)
+ *out_values++ = be32_to_cpup(val++);
+
+ return sz;
+}
+EXPORT_SYMBOL_GPL(of_property_read_variable_u32_array);
+
+/**
+ * of_property_read_u64 - Find and read a 64 bit integer from a property
+ * @np: device node from which the property value is to be read.
+ * @propname: name of the property to be searched.
+ * @out_value: pointer to return value, modified only if return value is 0.
+ *
+ * Search for a property in a device node and read a 64-bit value from
+ * it. Returns 0 on success, -EINVAL if the property does not exist,
+ * -ENODATA if property does not have a value, and -EOVERFLOW if the
+ * property data isn't large enough.
+ *
+ * The out_value is modified only if a valid u64 value can be decoded.
+ */
+int of_property_read_u64(const struct device_node *np, const char *propname,
+ u64 *out_value)
+{
+ const __be32 *val = of_find_property_value_of_size(np, propname,
+ sizeof(*out_value),
+ 0,
+ NULL);
+
+ if (IS_ERR(val))
+ return PTR_ERR(val);
+
+ *out_value = of_read_number(val, 2);
+ return 0;
+}
+EXPORT_SYMBOL_GPL(of_property_read_u64);
+
+/**
+ * of_property_read_variable_u64_array - Find and read an array of 64 bit
+ * integers from a property, with bounds on the minimum and maximum array size.
+ *
+ * @np: device node from which the property value is to be read.
+ * @propname: name of the property to be searched.
+ * @out_values: pointer to return value, modified only if return value is 0.
+ * @sz_min: minimum number of array elements to read
+ * @sz_max: maximum number of array elements to read, if zero there is no
+ * upper limit on the number of elements in the dts entry but only
+ * sz_min will be read.
+ *
+ * Search for a property in a device node and read 64-bit value(s) from
+ * it. Returns number of elements read on success, -EINVAL if the property
+ * does not exist, -ENODATA if property does not have a value, and -EOVERFLOW
+ * if the property data is smaller than sz_min or longer than sz_max.
+ *
+ * The out_values is modified only if a valid u64 value can be decoded.
+ */
+int of_property_read_variable_u64_array(const struct device_node *np,
+ const char *propname, u64 *out_values,
+ size_t sz_min, size_t sz_max)
+{
+ size_t sz, count;
+ const __be32 *val = of_find_property_value_of_size(np, propname,
+ (sz_min * sizeof(*out_values)),
+ (sz_max * sizeof(*out_values)),
+ &sz);
+
+ if (IS_ERR(val))
+ return PTR_ERR(val);
+
+ if (!sz_max)
+ sz = sz_min;
+ else
+ sz /= sizeof(*out_values);
+
+ count = sz;
+ while (count--) {
+ *out_values++ = of_read_number(val, 2);
+ val += 2;
+ }
+
+ return sz;
+}
+EXPORT_SYMBOL_GPL(of_property_read_variable_u64_array);
+
+/**
+ * of_property_read_string - Find and read a string from a property
+ * @np: device node from which the property value is to be read.
+ * @propname: name of the property to be searched.
+ * @out_string: pointer to null terminated return string, modified only if
+ * return value is 0.
+ *
+ * Search for a property in a device tree node and retrieve a null
+ * terminated string value (pointer to data, not a copy). Returns 0 on
+ * success, -EINVAL if the property does not exist, -ENODATA if property
+ * does not have a value, and -EILSEQ if the string is not null-terminated
+ * within the length of the property data.
+ *
+ * The out_string pointer is modified only if a valid string can be decoded.
+ */
+int of_property_read_string(const struct device_node *np, const char *propname,
+ const char **out_string)
+{
+ const struct property *prop = of_find_property(np, propname, NULL);
+ if (!prop)
+ return -EINVAL;
+ if (!prop->value)
+ return -ENODATA;
+ if (strnlen(prop->value, prop->length) >= prop->length)
+ return -EILSEQ;
+ *out_string = prop->value;
+ return 0;
+}
+EXPORT_SYMBOL_GPL(of_property_read_string);
+
+/**
+ * of_property_match_string() - Find string in a list and return index
+ * @np: pointer to node containing string list property
+ * @propname: string list property name
+ * @string: pointer to string to search for in string list
+ *
+ * This function searches a string list property and returns the index
+ * of a specific string value.
+ */
+int of_property_match_string(const struct device_node *np, const char *propname,
+ const char *string)
+{
+ const struct property *prop = of_find_property(np, propname, NULL);
+ size_t l;
+ int i;
+ const char *p, *end;
+
+ if (!prop)
+ return -EINVAL;
+ if (!prop->value)
+ return -ENODATA;
+
+ p = prop->value;
+ end = p + prop->length;
+
+ for (i = 0; p < end; i++, p += l) {
+ l = strnlen(p, end - p) + 1;
+ if (p + l > end)
+ return -EILSEQ;
+ pr_debug("comparing %s with %s\n", string, p);
+ if (strcmp(string, p) == 0)
+ return i; /* Found it; return index */
+ }
+ return -ENODATA;
+}
+EXPORT_SYMBOL_GPL(of_property_match_string);
+
+/**
+ * of_property_read_string_helper() - Utility helper for parsing string properties
+ * @np: device node from which the property value is to be read.
+ * @propname: name of the property to be searched.
+ * @out_strs: output array of string pointers.
+ * @sz: number of array elements to read.
+ * @skip: Number of strings to skip over at beginning of list.
+ *
+ * Don't call this function directly. It is a utility helper for the
+ * of_property_read_string*() family of functions.
+ */
+int of_property_read_string_helper(const struct device_node *np,
+ const char *propname, const char **out_strs,
+ size_t sz, int skip)
+{
+ const struct property *prop = of_find_property(np, propname, NULL);
+ int l = 0, i = 0;
+ const char *p, *end;
+
+ if (!prop)
+ return -EINVAL;
+ if (!prop->value)
+ return -ENODATA;
+ p = prop->value;
+ end = p + prop->length;
+
+ for (i = 0; p < end && (!out_strs || i < skip + sz); i++, p += l) {
+ l = strnlen(p, end - p) + 1;
+ if (p + l > end)
+ return -EILSEQ;
+ if (out_strs && i >= skip)
+ *out_strs++ = p;
+ }
+ i -= skip;
+ return i <= 0 ? -ENODATA : i;
+}
+EXPORT_SYMBOL_GPL(of_property_read_string_helper);
+
+const __be32 *of_prop_next_u32(struct property *prop, const __be32 *cur,
+ u32 *pu)
+{
+ const void *curv = cur;
+
+ if (!prop)
+ return NULL;
+
+ if (!cur) {
+ curv = prop->value;
+ goto out_val;
+ }
+
+ curv += sizeof(*cur);
+ if (curv >= prop->value + prop->length)
+ return NULL;
+
+out_val:
+ *pu = be32_to_cpup(curv);
+ return curv;
+}
+EXPORT_SYMBOL_GPL(of_prop_next_u32);
+
+const char *of_prop_next_string(struct property *prop, const char *cur)
+{
+ const void *curv = cur;
+
+ if (!prop)
+ return NULL;
+
+ if (!cur)
+ return prop->value;
+
+ curv += strlen(cur) + 1;
+ if (curv >= prop->value + prop->length)
+ return NULL;
+
+ return curv;
+}
+EXPORT_SYMBOL_GPL(of_prop_next_string);
+
+/**
+ * of_graph_parse_endpoint() - parse common endpoint node properties
+ * @node: pointer to endpoint device_node
+ * @endpoint: pointer to the OF endpoint data structure
+ *
+ * The caller should hold a reference to @node.
+ */
+int of_graph_parse_endpoint(const struct device_node *node,
+ struct of_endpoint *endpoint)
+{
+ struct device_node *port_node = of_get_parent(node);
+
+ WARN_ONCE(!port_node, "%s(): endpoint %s has no parent node\n",
+ __func__, node->full_name);
+
+ memset(endpoint, 0, sizeof(*endpoint));
+
+ endpoint->local_node = node;
+ /*
+ * It doesn't matter whether the two calls below succeed.
+ * If they don't then the default value 0 is used.
+ */
+ of_property_read_u32(port_node, "reg", &endpoint->port);
+ of_property_read_u32(node, "reg", &endpoint->id);
+
+ of_node_put(port_node);
+
+ return 0;
+}
+EXPORT_SYMBOL(of_graph_parse_endpoint);
+
+/**
+ * of_graph_get_port_by_id() - get the port matching a given id
+ * @parent: pointer to the parent device node
+ * @id: id of the port
+ *
+ * Return: A 'port' node pointer with refcount incremented. The caller
+ * has to use of_node_put() on it when done.
+ */
+struct device_node *of_graph_get_port_by_id(struct device_node *parent, u32 id)
+{
+ struct device_node *node, *port;
+
+ node = of_get_child_by_name(parent, "ports");
+ if (node)
+ parent = node;
+
+ for_each_child_of_node(parent, port) {
+ u32 port_id = 0;
+
+ if (of_node_cmp(port->name, "port") != 0)
+ continue;
+ of_property_read_u32(port, "reg", &port_id);
+ if (id == port_id)
+ break;
+ }
+
+ of_node_put(node);
+
+ return port;
+}
+EXPORT_SYMBOL(of_graph_get_port_by_id);
+
+/**
+ * of_graph_get_next_endpoint() - get next endpoint node
+ * @parent: pointer to the parent device node
+ * @prev: previous endpoint node, or NULL to get first
+ *
+ * Return: An 'endpoint' node pointer with refcount incremented. Refcount
+ * of the passed @prev node is decremented.
+ */
+struct device_node *of_graph_get_next_endpoint(const struct device_node *parent,
+ struct device_node *prev)
+{
+ struct device_node *endpoint;
+ struct device_node *port;
+
+ if (!parent)
+ return NULL;
+
+ /*
+ * Start by locating the port node. If no previous endpoint is specified
+ * search for the first port node, otherwise get the previous endpoint
+ * parent port node.
+ */
+ if (!prev) {
+ struct device_node *node;
+
+ node = of_get_child_by_name(parent, "ports");
+ if (node)
+ parent = node;
+
+ port = of_get_child_by_name(parent, "port");
+ of_node_put(node);
+
+ if (!port) {
+ pr_err("graph: no port node found in %s\n",
+ parent->full_name);
+ return NULL;
+ }
+ } else {
+ port = of_get_parent(prev);
+ if (WARN_ONCE(!port, "%s(): endpoint %s has no parent node\n",
+ __func__, prev->full_name))
+ return NULL;
+ }
+
+ while (1) {
+ /*
+ * Now that we have a port node, get the next endpoint by
+ * getting the next child. If the previous endpoint is NULL this
+ * will return the first child.
+ */
+ endpoint = of_get_next_child(port, prev);
+ if (endpoint) {
+ of_node_put(port);
+ return endpoint;
+ }
+
+ /* No more endpoints under this port, try the next one. */
+ prev = NULL;
+
+ do {
+ port = of_get_next_child(parent, port);
+ if (!port)
+ return NULL;
+ } while (of_node_cmp(port->name, "port"));
+ }
+}
+EXPORT_SYMBOL(of_graph_get_next_endpoint);
+
+/**
+ * of_graph_get_endpoint_by_regs() - get endpoint node of specific identifiers
+ * @parent: pointer to the parent device node
+ * @port_reg: identifier (value of reg property) of the parent port node
+ * @reg: identifier (value of reg property) of the endpoint node
+ *
+ * Return: An 'endpoint' node pointer which is identified by reg and at the same
+ * is the child of a port node identified by port_reg. reg and port_reg are
+ * ignored when they are -1.
+ */
+struct device_node *of_graph_get_endpoint_by_regs(
+ const struct device_node *parent, int port_reg, int reg)
+{
+ struct of_endpoint endpoint;
+ struct device_node *node = NULL;
+
+ for_each_endpoint_of_node(parent, node) {
+ of_graph_parse_endpoint(node, &endpoint);
+ if (((port_reg == -1) || (endpoint.port == port_reg)) &&
+ ((reg == -1) || (endpoint.id == reg)))
+ return node;
+ }
+
+ return NULL;
+}
+EXPORT_SYMBOL(of_graph_get_endpoint_by_regs);
+
+/**
+ * of_graph_get_remote_port_parent() - get remote port's parent node
+ * @node: pointer to a local endpoint device_node
+ *
+ * Return: Remote device node associated with remote endpoint node linked
+ * to @node. Use of_node_put() on it when done.
+ */
+struct device_node *of_graph_get_remote_port_parent(
+ const struct device_node *node)
+{
+ struct device_node *np;
+ unsigned int depth;
+
+ /* Get remote endpoint node. */
+ np = of_parse_phandle(node, "remote-endpoint", 0);
+
+ /* Walk 3 levels up only if there is 'ports' node. */
+ for (depth = 3; depth && np; depth--) {
+ np = of_get_next_parent(np);
+ if (depth == 2 && of_node_cmp(np->name, "ports"))
+ break;
+ }
+ return np;
+}
+EXPORT_SYMBOL(of_graph_get_remote_port_parent);
+
+/**
+ * of_graph_get_remote_port() - get remote port node
+ * @node: pointer to a local endpoint device_node
+ *
+ * Return: Remote port node associated with remote endpoint node linked
+ * to @node. Use of_node_put() on it when done.
+ */
+struct device_node *of_graph_get_remote_port(const struct device_node *node)
+{
+ struct device_node *np;
+
+ /* Get remote endpoint node. */
+ np = of_parse_phandle(node, "remote-endpoint", 0);
+ if (!np)
+ return NULL;
+ return of_get_next_parent(np);
+}
+EXPORT_SYMBOL(of_graph_get_remote_port);
+
+/**
+ * of_graph_get_remote_node() - get remote parent device_node for given port/endpoint
+ * @node: pointer to parent device_node containing graph port/endpoint
+ * @port: identifier (value of reg property) of the parent port node
+ * @endpoint: identifier (value of reg property) of the endpoint node
+ *
+ * Return: Remote device node associated with remote endpoint node linked
+ * to @node. Use of_node_put() on it when done.
+ */
+struct device_node *of_graph_get_remote_node(const struct device_node *node,
+ u32 port, u32 endpoint)
+{
+ struct device_node *endpoint_node, *remote;
+
+ endpoint_node = of_graph_get_endpoint_by_regs(node, port, endpoint);
+ if (!endpoint_node) {
+ pr_debug("no valid endpoint (%d, %d) for node %s\n",
+ port, endpoint, node->full_name);
+ return NULL;
+ }
+
+ remote = of_graph_get_remote_port_parent(endpoint_node);
+ of_node_put(endpoint_node);
+ if (!remote) {
+ pr_debug("no valid remote node\n");
+ return NULL;
+ }
+
+ if (!of_device_is_available(remote)) {
+ pr_debug("not available for remote node\n");
+ return NULL;
+ }
+
+ return remote;
+}
+EXPORT_SYMBOL(of_graph_get_remote_node);
--
2.7.4
^ permalink raw reply related
* Re: [PATCHv3] iio: adc: cpcap: Add minimal support for CPCAP PMIC ADC
From: Rob Herring @ 2017-03-29 21:26 UTC (permalink / raw)
To: Tony Lindgren
Cc: Jonathan Cameron, Hartmut Knaack, Lars-Peter Clausen,
Peter Meerwald-Stadler, linux-iio-u79uwXL29TY76Z2rM5mHXA,
linux-omap-u79uwXL29TY76Z2rM5mHXA,
devicetree-u79uwXL29TY76Z2rM5mHXA, Marcel Partap, Michael Scott,
Sebastian Reichel
In-Reply-To: <20170324033842.12541-1-tony-4v6yS6AI5VpBDgjK7y7TUQ@public.gmane.org>
On Thu, Mar 23, 2017 at 08:38:42PM -0700, Tony Lindgren wrote:
> On Motorola phones like droid 4 there is a custom CPCAP PMIC. This PMIC
> has ADCs that are used for battery charging and USB PHY VBUS and ID pin
> detection.
>
> Unfortunately the only documentation for this ADC seems to be the
> Motorola mapphone Linux kernel tree. I have tested that reading raw and
> scaled values works, but I have not used the timed sampling that the ADC
> seems to support.
>
> Let's add a minimal support for it so we can eventually provide IIO
> channels for the related battery charging and USB PHY drivers.
>
> Cc: devicetree-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
> Cc: Marcel Partap <mpartap-hi6Y0CQ0nG0@public.gmane.org>
> Cc: Michael Scott <michael.scott-QSEj5FYQhm4dnm+yROfE0A@public.gmane.org>
> Cc: Sebastian Reichel <sre-DgEjT+Ai2ygdnm+yROfE0A@public.gmane.org>
> Signed-off-by: Tony Lindgren <tony-4v6yS6AI5VpBDgjK7y7TUQ@public.gmane.org>
> ---
>
> Changes since v2:
>
> - Simplify things further by using channel based indexing and
> remove more drivers specific enumerations
>
> Changes since v1:
>
> - Fix numerous issues pointed out by Peter Meerwald-Stadler
> <pmeerw-jW+XmwGofnusTnJN9+BGXg@public.gmane.org> and Jonathan Cameron <jic23-DgEjT+Ai2ygdnm+yROfE0A@public.gmane.org>
>
> - Simplify things further by limiting read functions to a
> single channel instead of a bank and got rid of the driver
> specific cpcap_adc_conv_type in favor of IIO generic types
>
> ---
> .../devicetree/bindings/iio/adc/cpcap-adc.txt | 18 +
Acked-by: Rob Herring <robh-DgEjT+Ai2ygdnm+yROfE0A@public.gmane.org>
> drivers/iio/adc/Kconfig | 11 +
> drivers/iio/adc/Makefile | 1 +
> drivers/iio/adc/cpcap-adc.c | 1007 ++++++++++++++++++++
> 4 files changed, 1037 insertions(+)
> create mode 100644 Documentation/devicetree/bindings/iio/adc/cpcap-adc.txt
> create mode 100644 drivers/iio/adc/cpcap-adc.c
^ permalink raw reply
* Re: [PATCHv3 00/10] Nokia H4+ support
From: Marcel Holtmann @ 2017-03-29 21:33 UTC (permalink / raw)
To: Rob Herring
Cc: Sebastian Reichel, Gustavo F. Padovan, Johan Hedberg,
Samuel Thibault, Pavel Machek, Tony Lindgren, Greg Kroah-Hartman,
Jiri Slaby, Mark Rutland, open list:BLUETOOTH DRIVERS,
linux-serial@vger.kernel.org, devicetree@vger.kernel.org,
linux-kernel@vger.kernel.org, David S. Miller
In-Reply-To: <CAL_JsqJcQ9ANtt71KRitOJ9spKD1SaeoL4RDftiCEPs8TjLJGA@mail.gmail.com>
Hi Rob,
>> Here is PATCHv3 for the Nokia bluetooth patchset. I addressed all comments from
>> Rob and Pavel regarding the serdev patches and dropped the *.dts patches, since
>> they were queued by Tony. I also changed the patch order, so that the serdev
>> patches come first. All of them have Acked-by from Rob, so I think it makes
>> sense to merge them to serdev subsystem (now) and provide an immutable branch
>> for the bluetooth subsystem.
>
> Greg doesn't read cover letters generally and since the serdev patches
> are Cc rather than To him, he's probably not planning to pick them up.
I wonder actually if we should merge all of these via bluetooth-next tree with proper Ack from Greg. However it would be good to also get buy in from Dave for merging this ultimately through net-next.
Regards
Marcel
^ permalink raw reply
* Re: [PATCHv3 2/2] leds: cpcap: new driver
From: Sebastian Reichel @ 2017-03-29 21:38 UTC (permalink / raw)
To: Jacek Anaszewski
Cc: Richard Purdie, Pavel Machek, Lee Jones, Tony Lindgren,
Rob Herring, Mark Rutland, linux-leds, devicetree, linux-kernel
In-Reply-To: <b3a00d96-7eda-4f7f-62f8-364954449b6b@gmail.com>
[-- Attachment #1: Type: text/plain, Size: 2210 bytes --]
Hi,
On Wed, Mar 29, 2017 at 09:12:57PM +0200, Jacek Anaszewski wrote:
> On 03/24/2017 09:47 AM, Sebastian Reichel wrote:
> > Motorola CPCAP is a PMIC (power management integrated circuit) found
> > in multiple smartphones. This driver adds support for the chip's LED
> > controllers. This introduces support for all controllers used by the
> > Droid 4. According to Motorola's driver (no datasheets available)
> > there a couple of more LED controllers. I did not add support for
> > them, since I cannot verify that they work with my modifications.
> >
> > Acked-by: Pavel Machek <pavel@ucw.cz>
> > Signed-off-by: Sebastian Reichel <sre@kernel.org>
> > ---
> > Changes since PATCHv1:
> > - binding: reference common led binding for label
> > - drop DEBUG define (leftover)
> > - s/led/LED/g in debug prints
> > - order includes alphabetically
> > - introduce mutex, since led API is not atomic
> > - register led class after initial register setup
> > - use GPLv2+ in header
> > - drop unsupported leds from driver
> >
> > Changes since PATCHv2:
> > - use standard defines instead CPCAP_LED_OFF and CPCAP_LED_ON
> >
> > Notes:
> > - The "motorola" vendor-prefix is added via rtc-next
> > ---
> > .../devicetree/bindings/leds/cpcap-leds.txt | 29 +++
> > drivers/leds/Kconfig | 9 +
> > drivers/leds/Makefile | 1 +
> > drivers/leds/leds-cpcap.c | 239 +++++++++++++++++++++
> > 4 files changed, 278 insertions(+)
> > create mode 100644 Documentation/devicetree/bindings/leds/cpcap-leds.txt
> > create mode 100644 drivers/leds/leds-cpcap.c
> >
> > diff --git a/Documentation/devicetree/bindings/leds/cpcap-leds.txt b/Documentation/devicetree/bindings/leds/cpcap-leds.txt
> > new file mode 100644
> > index 000000000000..ebf7cdc7f70c
> > --- /dev/null
> > +++ b/Documentation/devicetree/bindings/leds/cpcap-leds.txt
>
> I've changed cpcap-leds.txt to leds-cpcap.txt to match the prevailing
> pattern for LED DT bindings file names.
>
> Please let me know if you have any objections.
Acked-by: Sebastian Reichel <sre@kernel.org>
-- Sebastian
[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 833 bytes --]
^ permalink raw reply
* Re: [PATCH 0/3] dtc updates for 4.12
From: Rob Herring @ 2017-03-29 21:41 UTC (permalink / raw)
To: Olof Johansson
Cc: devicetree@vger.kernel.org, linux-kernel@vger.kernel.org,
Frank Rowand, Mark Rutland, arm@kernel.org
In-Reply-To: <CAL_JsqL3z1dqYZ68jtt2coNhM8sbZZWimuCku2mTHWDuS+kj6g@mail.gmail.com>
On Tue, Mar 21, 2017 at 2:55 PM, Rob Herring <robh@kernel.org> wrote:
> On Tue, Mar 21, 2017 at 2:15 PM, Olof Johansson <olof@lixom.net> wrote:
>> On Tue, Mar 21, 2017 at 9:19 AM, Rob Herring <robh@kernel.org> wrote:
>>> This series syncs dtc with current mainline. The primary motivation is
>>> to pull in the new checks I've worked on. This gives lots of new
>>> warnings which are turned off by default.
>>>
>>> Arm-soc folks, I've left the PCI checks enabled as they are pretty much
>>> all real errors and there aren't that many (about 1200, but that's lots
>>> of duplicates). I have a patch for some of them.
>>
>> Yay for better warnings!
>>
>> But as with all changes of this kind, when new warnings are introduced
>> please give people some time to remove them without turning them on by
>> default. We had a cycle like that already.
>
> Which I quickly fixed and learned my lesson. That's why I tried
> getting this out earlier as well.
>
>> Main reason is that it becomes too hard to spot new warnings when they
>> come in if the logs are flooded with 1200 existing warnings.
>
> Yeah. Since almost everything is an include, the warnings really multiply.
>
>> How many of them do you have patches for, per chance? If we can see
>> them show up quickly the answer to the above might be a bit different.
>
> Okay, I lied or lost them... It looks like it is 79 unique warnings
> for arm. I'll take a stab at fixing them.
Well, after all the fixes, there's still some false positives, so I'm going to turn off the warnings by default anyway.
Rob
^ permalink raw reply
* Re: [PATCH 2/2] DT: leds: Add Qualcomm Light Pulse Generator binding
From: Pavel Machek @ 2017-03-29 22:13 UTC (permalink / raw)
To: Bjorn Andersson
Cc: Richard Purdie, Jacek Anaszewski, Rob Herring, Mark Rutland,
linux-leds, devicetree, linux-kernel, linux-arm-msm
In-Reply-To: <20170323055435.29197-2-bjorn.andersson@linaro.org>
[-- Attachment #1: Type: text/plain, Size: 1779 bytes --]
Hi!
> +- qcom,pattern:
> + Usage: optional
> + Value type: <u16-list>
> + Definition: list of 16 bit duty cycle values to make up the pattern to
> + be programmed into the LUT. Values should be in the range
> + [0,512).
> +
> +- qcom,pattern-length-ms:
> + Usage: optional
> + Value type: <u32>
> + Definition: duration, in milliseconds, of the ramp generator running
> + one pass over the defined pattern
> +
> +- qcom,pattern-pause-lo-ms:
> + Usage: optional
> + Value type: <u32>
> + Definition: duration, in milliseconds, for the ramp generator to pause
> + before iterating over the pattern
> +
> +- qcom,pattern-pause-hi-ms:
> + Usage: optional
> + Value type: <u32>
> + Definition: duration, in milliseconds, for the ramp generator to pause
> + after iterating over the pattern
> +
> +- qcom,pattern-ping-pong:
> + Usage: optional
> + Value type: <boolean>
> + Definition: denotes that the ramp generator should reverse direction
> + when reaching the end of the pattern, instead of wrapping
> + to the beginning
> +
> +- qcom,pattern-oneshot:
> + Usage: optional
> + Value type: <boolean>
> + Definition: denotes that the ramp generator should stop after a single
> + pass over the pattern
> +
> +- qcom,pattern-reverse:
> + Usage: optional
> + Value type: <boolean>
> + Definition: denotes that the ramp generator should operate backwards
> + over the pattern
I'd not do this. While we _may_ want to specify default trigger and
default blinking behaviour, we should do it in a way that is common
for all the drivers.
Pavel
--
(english) http://www.livejournal.com/~pavelmachek
(cesky, pictures) http://atrey.karlin.mff.cuni.cz/~pavel/picture/horses/blog.html
[-- Attachment #2: Digital signature --]
[-- Type: application/pgp-signature, Size: 181 bytes --]
^ permalink raw reply
* Re: [PATCH linux v5 1/2] Documentation: dt-bindings: Document bindings for ASPEED AST2400/AST2500 PWM and Fan tach controller device driver
From: Jaghathiswari Rankappagounder Natarajan @ 2017-03-29 22:14 UTC (permalink / raw)
To: Joel Stanley, jdelvare, Guenter Roeck, linux-hwmon, linux-kernel,
OpenBMC Maillist, Jonathan Corbet, linux-doc, robh+dt,
mark.rutland, devicetree
Cc: Jaghathiswari Rankappagounder Natarajan
In-Reply-To: <20170324181723.29379-2-jaghu@google.com>
Please provide review comments.
On Fri, Mar 24, 2017 at 11:17 AM, Jaghathiswari Rankappagounder
Natarajan <jaghu@google.com> wrote:
> This binding provides interface for adding values related to ASPEED
> AST2400/2500 PWM and Fan tach controller support.
> The PWM controller can support upto 8 PWM output ports.
> The Fan tach controller can support upto 16 tachometer inputs.
>
> Signed-off-by: Jaghathiswari Rankappagounder Natarajan <jaghu@google.com>
> ---
> v5:
> - Changed the naming scheme to aspeed,ast2400/2500-pwm-tacho
> - Removed gpio pin muxing
> - Added aspeed vendor prefix for fan-tach-ch
> - Changed to fan@0/1
> - Changed reg to 32 bits
>
> v4:
> - Used 'reg'
>
> v3:
> - Made the structure more common
>
> v2:
> - Removed '_' in node and property names
> - Gave some explanation for the properties used
>
> .../devicetree/bindings/hwmon/aspeed-pwm-tacho.txt | 68 ++++++++++++++++++++++
> 1 file changed, 68 insertions(+)
> create mode 100644 Documentation/devicetree/bindings/hwmon/aspeed-pwm-tacho.txt
>
> diff --git a/Documentation/devicetree/bindings/hwmon/aspeed-pwm-tacho.txt b/Documentation/devicetree/bindings/hwmon/aspeed-pwm-tacho.txt
> new file mode 100644
> index 000000000000..f96d32bfcdfa
> --- /dev/null
> +++ b/Documentation/devicetree/bindings/hwmon/aspeed-pwm-tacho.txt
> @@ -0,0 +1,68 @@
> +ASPEED AST2400/AST2500 PWM and Fan Tacho controller device driver
> +
> +The ASPEED PWM controller can support upto 8 PWM outputs. The ASPEED Fan Tacho
> +controller can support upto 16 Fan tachometer inputs.
> +
> +There can be upto 8 fans supported. Each fan can have one PWM output and
> +one/two Fan tach inputs.
> +
> +Required properties for pwm-tacho node:
> +- #address-cells : should be 1.
> +
> +- #size-cells : should be 1.
> +
> +- reg : address and length of the register set for the device.
> +
> +- pinctrl-names : a pinctrl state named "default" must be defined.
> +
> +- pinctrl-0 : phandle referencing pin configuration of the PWM ports.
> +
> +- compatible : should be "aspeed,ast2400-pwm-tacho" for AST2400 and
> + "aspeed,ast2500-pwm-tacho" for AST2500.
> +
> +- clocks : a fixed clock providing input clock frequency(PWM
> + and Fan Tach clock)
> +
> +fan subnode format:
> +===================
> +Under fan subnode there can upto 8 child nodes, with each child node
> +representing a fan. If there are 8 fans each fan can have one PWM port and
> +one/two Fan tach inputs.
> +
> +Required properties for each child node:
> +- reg : should specify PWM source port.
> + integer value in the range 0 to 7 with 0 indicating PWM port A and
> + 7 indicating PWM port H.
> +
> +- aspeed-fan-tach-ch : should specify the Fan tach input channel.
> + integer value in the range 0 through 15, with 0 indicating
> + Fan tach channel 0 and 15 indicating Fan tach channel 15.
> + Atleast one Fan tach input channel is required.
> +
> +Examples:
> +
> +pwm_tacho_fixed_clk: fixedclk {
> + compatible = "fixed-clock";
> + #clock-cells = <0>;
> + clock-frequency = <24000000>;
> +}
> +
> +pwm_tacho: pwmtachocontroller@1e786000 {
> + #address-cells = <1>;
> + #size-cells = <1>;
> + reg = <0x1E786000 0x1000>;
> + compatible = "aspeed,ast2500-pwm-tacho";
> + clocks = <&pwm_tacho_fixed_clk>;
> + pinctrl-names = "default";
> + pinctrl-0 = <&pinctrl_pwm0_default &pinctrl_pwm1_default>;
> +
> + fan@0 {
> + reg = <0x00>;
> + aspeed-fan-tach-ch = /bits/ 8 <0x00>;
> + };
> +
> + fan@1 {
> + reg = <0x01>;
> + aspeed-fan-tach-ch = /bits/ 8 <0x01 0x02>;
> + };
> +};
> --
> 2.12.1.578.ge9c3154ca4-goog
>
^ permalink raw reply
* Re: [PATCH linux v5 2/2] drivers: hwmon: Support for ASPEED PWM/Fan tach
From: Jaghathiswari Rankappagounder Natarajan @ 2017-03-29 22:15 UTC (permalink / raw)
To: Joel Stanley, jdelvare, Guenter Roeck, linux-hwmon, linux-kernel,
OpenBMC Maillist, Jonathan Corbet, linux-doc, robh+dt,
mark.rutland, devicetree
Cc: Jaghathiswari Rankappagounder Natarajan
In-Reply-To: <20170324181723.29379-3-jaghu@google.com>
Please provide review comments.
On Fri, Mar 24, 2017 at 11:17 AM, Jaghathiswari Rankappagounder
Natarajan <jaghu@google.com> wrote:
> The ASPEED AST2400/2500 PWM controller supports 8 PWM output ports.
> The ASPEED AST2400/2500 Fan tach controller supports 16 tachometer
> inputs.
> The device driver matches on the device tree node. The configuration
> values
> are read from the device tree and written to the respective registers.
> The driver provides a sysfs entries through which the user can
> configure the duty-cycle value (ranging from 0 to 100 percent) and read
> the
> fan tach rpm value.
>
> Signed-off-by: Jaghathiswari Rankappagounder Natarajan <jaghu@google.com>
> ---
> v5:
> - Changed the driver to suit the changes in the device tree documentation
>
> v4:
> - Modified this driver to suit the representation in the devicetree
>
> v3:
> - Only sent out device tree documentation; did not send this driver
>
> v2:
> - Used BIT()
> - Used regmap
> - Avoided division when raw data is 0
> - Removed empty lines between declaration
> - Removed macros; Used two attribute groups and used is_visible callback
> - Returned error when properties are undefined
> - Removed .owner field
> - Used PTR_ERR_OR_ZERO
> - Removed explicit of_node_put for child nodes
>
> Documentation/hwmon/aspeed-pwm-tacho | 22 +
> drivers/hwmon/Kconfig | 13 +-
> drivers/hwmon/Makefile | 1 +
> drivers/hwmon/aspeed-pwm-tacho.c | 854 +++++++++++++++++++++++++++++++++++
> 4 files changed, 888 insertions(+), 2 deletions(-)
> create mode 100644 Documentation/hwmon/aspeed-pwm-tacho
> create mode 100644 drivers/hwmon/aspeed-pwm-tacho.c
>
> diff --git a/Documentation/hwmon/aspeed-pwm-tacho b/Documentation/hwmon/aspeed-pwm-tacho
> new file mode 100644
> index 000000000000..0e9ec6d5f900
> --- /dev/null
> +++ b/Documentation/hwmon/aspeed-pwm-tacho
> @@ -0,0 +1,22 @@
> +Kernel driver aspeed-pwm-tacho
> +==============================
> +
> +Supported chips:
> + ASPEED AST2400/2500
> +
> +Authors:
> + <jaghu@google.com>
> +
> +Description:
> +------------
> +This driver implements support for ASPEED AST2400/2500 PWM and Fan Tacho
> +controller. The PWM controller supports upto 8 PWM outputs. The Fan tacho
> +controller supports upto 16 tachometer inputs.
> +
> +The driver provides the following sensor accesses in sysfs:
> +
> +fanX_input ro provide current fan rotation value in RPM as reported
> + by the fan to the device.
> +
> +pwmX rw get or set PWM fan control value. This is an integer
> + value between 0(off) and 255(full speed).
> diff --git a/drivers/hwmon/Kconfig b/drivers/hwmon/Kconfig
> index 45cef3d2c75c..487110f21827 100644
> --- a/drivers/hwmon/Kconfig
> +++ b/drivers/hwmon/Kconfig
> @@ -341,6 +341,15 @@ config SENSORS_ASB100
> This driver can also be built as a module. If so, the module
> will be called asb100.
>
> +config SENSORS_ASPEED
> + tristate "ASPEED AST2400/AST2500 PWM and Fan tach driver"
> + help
> + This driver provides support for ASPEED AST2400/AST2500 PWM
> + and Fan Tacho controllers.
> +
> + This driver can also be built as a module. If so, the module
> + will be called aspeed_pwm_tacho.
> +
> config SENSORS_ATXP1
> tristate "Attansic ATXP1 VID controller"
> depends on I2C
> @@ -952,7 +961,7 @@ config SENSORS_LM70
> help
> If you say yes here you get support for the National Semiconductor
> LM70, LM71, LM74 and Texas Instruments TMP121/TMP123 digital tempera-
> - ture sensor chips.
> + true sensor chips.
>
> This driver can also be built as a module. If so, the module
> will be called lm70.
> @@ -1506,7 +1515,7 @@ config SENSORS_ADS7871
>
> config SENSORS_AMC6821
> tristate "Texas Instruments AMC6821"
> - depends on I2C
> + depends on I2C
> help
> If you say yes here you get support for the Texas Instruments
> AMC6821 hardware monitoring chips.
> diff --git a/drivers/hwmon/Makefile b/drivers/hwmon/Makefile
> index aecf4ba17460..83025cc9bb45 100644
> --- a/drivers/hwmon/Makefile
> +++ b/drivers/hwmon/Makefile
> @@ -46,6 +46,7 @@ obj-$(CONFIG_SENSORS_ADT7475) += adt7475.o
> obj-$(CONFIG_SENSORS_APPLESMC) += applesmc.o
> obj-$(CONFIG_SENSORS_ARM_SCPI) += scpi-hwmon.o
> obj-$(CONFIG_SENSORS_ASC7621) += asc7621.o
> +obj-$(CONFIG_SENSORS_ASPEED) += aspeed-pwm-tacho.o
> obj-$(CONFIG_SENSORS_ATXP1) += atxp1.o
> obj-$(CONFIG_SENSORS_CORETEMP) += coretemp.o
> obj-$(CONFIG_SENSORS_DA9052_ADC)+= da9052-hwmon.o
> diff --git a/drivers/hwmon/aspeed-pwm-tacho.c b/drivers/hwmon/aspeed-pwm-tacho.c
> new file mode 100644
> index 000000000000..28888cc34555
> --- /dev/null
> +++ b/drivers/hwmon/aspeed-pwm-tacho.c
> @@ -0,0 +1,854 @@
> +/*
> + * Copyright (c) 2016 Google, Inc
> + *
> + * This program is free software; you can redistribute it and/or modify
> + * it under the terms of the GNU General Public License version 2 or later as
> + * published by the Free Software Foundation.
> + */
> +
> +#include <linux/clk.h>
> +#include <linux/gpio/consumer.h>
> +#include <linux/delay.h>
> +#include <linux/hwmon.h>
> +#include <linux/hwmon-sysfs.h>
> +#include <linux/io.h>
> +#include <linux/kernel.h>
> +#include <linux/module.h>
> +#include <linux/of_platform.h>
> +#include <linux/of_device.h>
> +#include <linux/platform_device.h>
> +#include <linux/sysfs.h>
> +#include <linux/regmap.h>
> +
> +/* ASPEED PWM & FAN Tach Register Definition */
> +#define ASPEED_PTCR_CTRL 0x00
> +#define ASPEED_PTCR_CLK_CTRL 0x04
> +#define ASPEED_PTCR_DUTY0_CTRL 0x08
> +#define ASPEED_PTCR_DUTY1_CTRL 0x0c
> +#define ASPEED_PTCR_TYPEM_CTRL 0x10
> +#define ASPEED_PTCR_TYPEM_CTRL1 0x14
> +#define ASPEED_PTCR_TYPEN_CTRL 0x18
> +#define ASPEED_PTCR_TYPEN_CTRL1 0x1c
> +#define ASPEED_PTCR_TACH_SOURCE 0x20
> +#define ASPEED_PTCR_TRIGGER 0x28
> +#define ASPEED_PTCR_RESULT 0x2c
> +#define ASPEED_PTCR_INTR_CTRL 0x30
> +#define ASPEED_PTCR_INTR_STS 0x34
> +#define ASPEED_PTCR_TYPEM_LIMIT 0x38
> +#define ASPEED_PTCR_TYPEN_LIMIT 0x3C
> +#define ASPEED_PTCR_CTRL_EXT 0x40
> +#define ASPEED_PTCR_CLK_CTRL_EXT 0x44
> +#define ASPEED_PTCR_DUTY2_CTRL 0x48
> +#define ASPEED_PTCR_DUTY3_CTRL 0x4c
> +#define ASPEED_PTCR_TYPEO_CTRL 0x50
> +#define ASPEED_PTCR_TYPEO_CTRL1 0x54
> +#define ASPEED_PTCR_TACH_SOURCE_EXT 0x60
> +#define ASPEED_PTCR_TYPEO_LIMIT 0x78
> +
> +/* ASPEED_PTCR_CTRL : 0x00 - General Control Register */
> +#define ASPEED_PTCR_CTRL_SET_PWMD_TYPE_PART1 15
> +#define ASPEED_PTCR_CTRL_SET_PWMD_TYPE_PART2 6
> +#define ASPEED_PTCR_CTRL_SET_PWMD_TYPE_MASK (BIT(7) | BIT(15))
> +
> +#define ASPEED_PTCR_CTRL_SET_PWMC_TYPE_PART1 14
> +#define ASPEED_PTCR_CTRL_SET_PWMC_TYPE_PART2 5
> +#define ASPEED_PTCR_CTRL_SET_PWMC_TYPE_MASK (BIT(6) | BIT(14))
> +
> +#define ASPEED_PTCR_CTRL_SET_PWMB_TYPE_PART1 13
> +#define ASPEED_PTCR_CTRL_SET_PWMB_TYPE_PART2 4
> +#define ASPEED_PTCR_CTRL_SET_PWMB_TYPE_MASK (BIT(5) | BIT(13))
> +
> +#define ASPEED_PTCR_CTRL_SET_PWMA_TYPE_PART1 12
> +#define ASPEED_PTCR_CTRL_SET_PWMA_TYPE_PART2 3
> +#define ASPEED_PTCR_CTRL_SET_PWMA_TYPE_MASK (BIT(4) | BIT(12))
> +
> +#define ASPEED_PTCR_CTRL_FAN_NUM_EN(x) BIT(16 + (x))
> +
> +#define ASPEED_PTCR_CTRL_PWMD_EN BIT(11)
> +#define ASPEED_PTCR_CTRL_PWMC_EN BIT(10)
> +#define ASPEED_PTCR_CTRL_PWMB_EN BIT(9)
> +#define ASPEED_PTCR_CTRL_PWMA_EN BIT(8)
> +
> +#define ASPEED_PTCR_CTRL_CLK_SRC BIT(1)
> +#define ASPEED_PTCR_CTRL_CLK_EN BIT(0)
> +
> +/* ASPEED_PTCR_CLK_CTRL : 0x04 - Clock Control Register */
> +/* TYPE N */
> +#define ASPEED_PTCR_CLK_CTRL_TYPEN_MASK GENMASK(31, 16)
> +#define ASPEED_PTCR_CLK_CTRL_TYPEN_UNIT 24
> +#define ASPEED_PTCR_CLK_CTRL_TYPEN_H 20
> +#define ASPEED_PTCR_CLK_CTRL_TYPEN_L 16
> +/* TYPE M */
> +#define ASPEED_PTCR_CLK_CTRL_TYPEM_MASK GENMASK(15, 0)
> +#define ASPEED_PTCR_CLK_CTRL_TYPEM_UNIT 8
> +#define ASPEED_PTCR_CLK_CTRL_TYPEM_H 4
> +#define ASPEED_PTCR_CLK_CTRL_TYPEM_L 0
> +
> +/*
> + * ASPEED_PTCR_DUTY_CTRL/1/2/3 : 0x08/0x0C/0x48/0x4C - PWM-FAN duty control
> + * 0/1/2/3 register
> + */
> +#define DUTY_CTRL_PWM2_FALL_POINT 24
> +#define DUTY_CTRL_PWM2_RISE_POINT 16
> +#define DUTY_CTRL_PWM2_RISE_FALL_MASK GENMASK(31, 16)
> +#define DUTY_CTRL_PWM1_FALL_POINT 8
> +#define DUTY_CTRL_PWM1_RISE_POINT 0
> +#define DUTY_CTRL_PWM1_RISE_FALL_MASK GENMASK(15, 0)
> +
> +/* ASPEED_PTCR_TYPEM_CTRL : 0x10/0x18/0x50 - Type M/N/O Ctrl 0 Register */
> +#define TYPE_CTRL_FAN_MASK (GENMASK(5, 1) | GENMASK(31, 16))
> +#define TYPE_CTRL_FAN1_MASK GENMASK(31, 0)
> +#define TYPE_CTRL_FAN_PERIOD 16
> +#define TYPE_CTRL_FAN_MODE 4
> +#define TYPE_CTRL_FAN_DIVISION 1
> +#define TYPE_CTRL_FAN_TYPE_EN 1
> +
> +/* ASPEED_PTCR_TACH_SOURCE : 0x20/0x60 - Tach Source Register */
> +/* bit [0,1] at 0x20, bit [2] at 0x60 */
> +#define TACH_PWM_SOURCE_BIT01(x) ((x) * 2)
> +#define TACH_PWM_SOURCE_BIT2(x) ((x) * 2)
> +#define TACH_PWM_SOURCE_MASK_BIT01(x) (0x3 << ((x) * 2))
> +#define TACH_PWM_SOURCE_MASK_BIT2(x) BIT((x) * 2)
> +
> +/* ASPEED_PTCR_RESULT : 0x2c - Result Register */
> +#define RESULT_STATUS_MASK BIT(31)
> +#define RESULT_VALUE_MASK 0xfffff
> +
> +/* ASPEED_PTCR_CTRL_EXT : 0x40 - General Control Extension #1 Register */
> +#define ASPEED_PTCR_CTRL_SET_PWMH_TYPE_PART1 15
> +#define ASPEED_PTCR_CTRL_SET_PWMH_TYPE_PART2 6
> +#define ASPEED_PTCR_CTRL_SET_PWMH_TYPE_MASK (BIT(7) | BIT(15))
> +
> +#define ASPEED_PTCR_CTRL_SET_PWMG_TYPE_PART1 14
> +#define ASPEED_PTCR_CTRL_SET_PWMG_TYPE_PART2 5
> +#define ASPEED_PTCR_CTRL_SET_PWMG_TYPE_MASK (BIT(6) | BIT(14))
> +
> +#define ASPEED_PTCR_CTRL_SET_PWMF_TYPE_PART1 13
> +#define ASPEED_PTCR_CTRL_SET_PWMF_TYPE_PART2 4
> +#define ASPEED_PTCR_CTRL_SET_PWMF_TYPE_MASK (BIT(5) | BIT(13))
> +
> +#define ASPEED_PTCR_CTRL_SET_PWME_TYPE_PART1 12
> +#define ASPEED_PTCR_CTRL_SET_PWME_TYPE_PART2 3
> +#define ASPEED_PTCR_CTRL_SET_PWME_TYPE_MASK (BIT(4) | BIT(12))
> +
> +#define ASPEED_PTCR_CTRL_PWMH_EN BIT(11)
> +#define ASPEED_PTCR_CTRL_PWMG_EN BIT(10)
> +#define ASPEED_PTCR_CTRL_PWMF_EN BIT(9)
> +#define ASPEED_PTCR_CTRL_PWME_EN BIT(8)
> +
> +/* ASPEED_PTCR_CLK_EXT_CTRL : 0x44 - Clock Control Extension #1 Register */
> +/* TYPE O */
> +#define ASPEED_PTCR_CLK_CTRL_TYPEO_MASK GENMASK(15, 0)
> +#define ASPEED_PTCR_CLK_CTRL_TYPEO_UNIT 8
> +#define ASPEED_PTCR_CLK_CTRL_TYPEO_H 4
> +#define ASPEED_PTCR_CLK_CTRL_TYPEO_L 0
> +
> +#define PWM_MAX 255
> +
> +#define M_PWM_DIV_H 0x00
> +#define M_PWM_DIV_L 0x05
> +#define M_PWM_PERIOD 0x5F
> +#define M_TACH_CLK_DIV 0x00
> +#define M_TACH_MODE 0x00
> +#define M_TACH_UNIT 0x1000
> +#define INIT_FAN_CTRL 0xFF
> +
> +struct aspeed_pwm_tacho_regmap {
> + void __iomem *regs;
> +};
> +
> +struct aspeed_pwm_tacho_data {
> + struct regmap *regmap;
> + unsigned long clk_freq;
> + bool pwm_present[8];
> + bool fan_tach_present[16];
> + u8 type_pwm_clock_unit[3];
> + u8 type_pwm_clock_division_h[3];
> + u8 type_pwm_clock_division_l[3];
> + u8 type_fan_tach_clock_division[3];
> + u16 type_fan_tach_unit[3];
> + u8 pwm_port_type[8];
> + u8 pwm_port_fan_ctrl[8];
> + u8 fan_tach_ch_source[16];
> + const struct attribute_group *groups[2];
> +};
> +
> +enum type { TYPEM, TYPEN, TYPEO };
> +
> +struct type_params {
> + u32 l_value;
> + u32 h_value;
> + u32 unit_value;
> + u32 clk_ctrl_mask;
> + u32 clk_ctrl_reg;
> + u32 ctrl_reg;
> + u32 ctrl_reg1;
> +};
> +
> +static const struct type_params type_params[] = {
> + [TYPEM] = {
> + .l_value = ASPEED_PTCR_CLK_CTRL_TYPEM_L,
> + .h_value = ASPEED_PTCR_CLK_CTRL_TYPEM_H,
> + .unit_value = ASPEED_PTCR_CLK_CTRL_TYPEM_UNIT,
> + .clk_ctrl_mask = ASPEED_PTCR_CLK_CTRL_TYPEM_MASK,
> + .clk_ctrl_reg = ASPEED_PTCR_CLK_CTRL,
> + .ctrl_reg = ASPEED_PTCR_TYPEM_CTRL,
> + .ctrl_reg1 = ASPEED_PTCR_TYPEM_CTRL1,
> + },
> + [TYPEN] = {
> + .l_value = ASPEED_PTCR_CLK_CTRL_TYPEN_L,
> + .h_value = ASPEED_PTCR_CLK_CTRL_TYPEN_H,
> + .unit_value = ASPEED_PTCR_CLK_CTRL_TYPEN_UNIT,
> + .clk_ctrl_mask = ASPEED_PTCR_CLK_CTRL_TYPEN_MASK,
> + .clk_ctrl_reg = ASPEED_PTCR_CLK_CTRL,
> + .ctrl_reg = ASPEED_PTCR_TYPEN_CTRL,
> + .ctrl_reg1 = ASPEED_PTCR_TYPEN_CTRL1,
> + },
> + [TYPEO] = {
> + .l_value = ASPEED_PTCR_CLK_CTRL_TYPEO_L,
> + .h_value = ASPEED_PTCR_CLK_CTRL_TYPEO_H,
> + .unit_value = ASPEED_PTCR_CLK_CTRL_TYPEO_UNIT,
> + .clk_ctrl_mask = ASPEED_PTCR_CLK_CTRL_TYPEO_MASK,
> + .clk_ctrl_reg = ASPEED_PTCR_CLK_CTRL_EXT,
> + .ctrl_reg = ASPEED_PTCR_TYPEO_CTRL,
> + .ctrl_reg1 = ASPEED_PTCR_TYPEO_CTRL1,
> + }
> +};
> +
> +enum pwm_port { PWMA, PWMB, PWMC, PWMD, PWME, PWMF, PWMG, PWMH };
> +
> +struct pwm_port_params {
> + u32 pwm_en;
> + u32 ctrl_reg;
> + u32 type_part1;
> + u32 type_part2;
> + u32 type_mask;
> + u32 duty_ctrl_rise_point;
> + u32 duty_ctrl_fall_point;
> + u32 duty_ctrl_reg;
> + u32 duty_ctrl_rise_fall_mask;
> +};
> +
> +static const struct pwm_port_params pwm_port_params[] = {
> + [PWMA] = {
> + .pwm_en = ASPEED_PTCR_CTRL_PWMA_EN,
> + .ctrl_reg = ASPEED_PTCR_CTRL,
> + .type_part1 = ASPEED_PTCR_CTRL_SET_PWMA_TYPE_PART1,
> + .type_part2 = ASPEED_PTCR_CTRL_SET_PWMA_TYPE_PART2,
> + .type_mask = ASPEED_PTCR_CTRL_SET_PWMA_TYPE_MASK,
> + .duty_ctrl_rise_point = DUTY_CTRL_PWM1_RISE_POINT,
> + .duty_ctrl_fall_point = DUTY_CTRL_PWM1_FALL_POINT,
> + .duty_ctrl_reg = ASPEED_PTCR_DUTY0_CTRL,
> + .duty_ctrl_rise_fall_mask = DUTY_CTRL_PWM1_RISE_FALL_MASK,
> + },
> + [PWMB] = {
> + .pwm_en = ASPEED_PTCR_CTRL_PWMB_EN,
> + .ctrl_reg = ASPEED_PTCR_CTRL,
> + .type_part1 = ASPEED_PTCR_CTRL_SET_PWMB_TYPE_PART1,
> + .type_part2 = ASPEED_PTCR_CTRL_SET_PWMB_TYPE_PART2,
> + .type_mask = ASPEED_PTCR_CTRL_SET_PWMB_TYPE_MASK,
> + .duty_ctrl_rise_point = DUTY_CTRL_PWM2_RISE_POINT,
> + .duty_ctrl_fall_point = DUTY_CTRL_PWM2_FALL_POINT,
> + .duty_ctrl_reg = ASPEED_PTCR_DUTY0_CTRL,
> + .duty_ctrl_rise_fall_mask = DUTY_CTRL_PWM2_RISE_FALL_MASK,
> + },
> + [PWMC] = {
> + .pwm_en = ASPEED_PTCR_CTRL_PWMC_EN,
> + .ctrl_reg = ASPEED_PTCR_CTRL,
> + .type_part1 = ASPEED_PTCR_CTRL_SET_PWMC_TYPE_PART1,
> + .type_part2 = ASPEED_PTCR_CTRL_SET_PWMC_TYPE_PART2,
> + .type_mask = ASPEED_PTCR_CTRL_SET_PWMC_TYPE_MASK,
> + .duty_ctrl_rise_point = DUTY_CTRL_PWM1_RISE_POINT,
> + .duty_ctrl_fall_point = DUTY_CTRL_PWM1_FALL_POINT,
> + .duty_ctrl_reg = ASPEED_PTCR_DUTY1_CTRL,
> + .duty_ctrl_rise_fall_mask = DUTY_CTRL_PWM1_RISE_FALL_MASK,
> + },
> + [PWMD] = {
> + .pwm_en = ASPEED_PTCR_CTRL_PWMD_EN,
> + .ctrl_reg = ASPEED_PTCR_CTRL,
> + .type_part1 = ASPEED_PTCR_CTRL_SET_PWMD_TYPE_PART1,
> + .type_part2 = ASPEED_PTCR_CTRL_SET_PWMD_TYPE_PART2,
> + .type_mask = ASPEED_PTCR_CTRL_SET_PWMD_TYPE_MASK,
> + .duty_ctrl_rise_point = DUTY_CTRL_PWM2_RISE_POINT,
> + .duty_ctrl_fall_point = DUTY_CTRL_PWM2_FALL_POINT,
> + .duty_ctrl_reg = ASPEED_PTCR_DUTY1_CTRL,
> + .duty_ctrl_rise_fall_mask = DUTY_CTRL_PWM2_RISE_FALL_MASK,
> + },
> + [PWME] = {
> + .pwm_en = ASPEED_PTCR_CTRL_PWME_EN,
> + .ctrl_reg = ASPEED_PTCR_CTRL_EXT,
> + .type_part1 = ASPEED_PTCR_CTRL_SET_PWME_TYPE_PART1,
> + .type_part2 = ASPEED_PTCR_CTRL_SET_PWME_TYPE_PART2,
> + .type_mask = ASPEED_PTCR_CTRL_SET_PWME_TYPE_MASK,
> + .duty_ctrl_rise_point = DUTY_CTRL_PWM1_RISE_POINT,
> + .duty_ctrl_fall_point = DUTY_CTRL_PWM1_FALL_POINT,
> + .duty_ctrl_reg = ASPEED_PTCR_DUTY2_CTRL,
> + .duty_ctrl_rise_fall_mask = DUTY_CTRL_PWM1_RISE_FALL_MASK,
> + },
> + [PWMF] = {
> + .pwm_en = ASPEED_PTCR_CTRL_PWMF_EN,
> + .ctrl_reg = ASPEED_PTCR_CTRL_EXT,
> + .type_part1 = ASPEED_PTCR_CTRL_SET_PWMF_TYPE_PART1,
> + .type_part2 = ASPEED_PTCR_CTRL_SET_PWMF_TYPE_PART2,
> + .type_mask = ASPEED_PTCR_CTRL_SET_PWMF_TYPE_MASK,
> + .duty_ctrl_rise_point = DUTY_CTRL_PWM2_RISE_POINT,
> + .duty_ctrl_fall_point = DUTY_CTRL_PWM2_FALL_POINT,
> + .duty_ctrl_reg = ASPEED_PTCR_DUTY2_CTRL,
> + .duty_ctrl_rise_fall_mask = DUTY_CTRL_PWM2_RISE_FALL_MASK,
> + },
> + [PWMG] = {
> + .pwm_en = ASPEED_PTCR_CTRL_PWMG_EN,
> + .ctrl_reg = ASPEED_PTCR_CTRL_EXT,
> + .type_part1 = ASPEED_PTCR_CTRL_SET_PWMG_TYPE_PART1,
> + .type_part2 = ASPEED_PTCR_CTRL_SET_PWMG_TYPE_PART2,
> + .type_mask = ASPEED_PTCR_CTRL_SET_PWMG_TYPE_MASK,
> + .duty_ctrl_rise_point = DUTY_CTRL_PWM1_RISE_POINT,
> + .duty_ctrl_fall_point = DUTY_CTRL_PWM1_FALL_POINT,
> + .duty_ctrl_reg = ASPEED_PTCR_DUTY3_CTRL,
> + .duty_ctrl_rise_fall_mask = DUTY_CTRL_PWM1_RISE_FALL_MASK,
> + },
> + [PWMH] = {
> + .pwm_en = ASPEED_PTCR_CTRL_PWMH_EN,
> + .ctrl_reg = ASPEED_PTCR_CTRL_EXT,
> + .type_part1 = ASPEED_PTCR_CTRL_SET_PWMH_TYPE_PART1,
> + .type_part2 = ASPEED_PTCR_CTRL_SET_PWMH_TYPE_PART2,
> + .type_mask = ASPEED_PTCR_CTRL_SET_PWMH_TYPE_MASK,
> + .duty_ctrl_rise_point = DUTY_CTRL_PWM2_RISE_POINT,
> + .duty_ctrl_fall_point = DUTY_CTRL_PWM2_FALL_POINT,
> + .duty_ctrl_reg = ASPEED_PTCR_DUTY3_CTRL,
> + .duty_ctrl_rise_fall_mask = DUTY_CTRL_PWM2_RISE_FALL_MASK,
> + }
> +};
> +
> +static int regmap_aspeed_pwm_tacho_reg_write(void *context, unsigned int reg,
> + unsigned int val)
> +{
> + struct aspeed_pwm_tacho_regmap *hregmap = context;
> +
> + writel(val, hregmap->regs + reg);
> + return 0;
> +}
> +
> +static int regmap_aspeed_pwm_tacho_reg_read(void *context, unsigned int reg,
> + unsigned int *val)
> +{
> + struct aspeed_pwm_tacho_regmap *hregmap = context;
> +
> + *val = readl(hregmap->regs + reg);
> + return 0;
> +}
> +
> +static const struct regmap_config aspeed_pwm_tacho_regmap_config = {
> + .reg_bits = 32,
> + .val_bits = 32,
> + .reg_stride = 4,
> + .max_register = ASPEED_PTCR_TYPEO_LIMIT,
> + .reg_write = regmap_aspeed_pwm_tacho_reg_write,
> + .reg_read = regmap_aspeed_pwm_tacho_reg_read,
> + .fast_io = true,
> +};
> +
> +static void aspeed_set_clock_enable(struct regmap *regmap, bool val)
> +{
> + regmap_update_bits(regmap, ASPEED_PTCR_CTRL,
> + ASPEED_PTCR_CTRL_CLK_EN,
> + val ? ASPEED_PTCR_CTRL_CLK_EN : 0);
> +}
> +
> +static void aspeed_set_clock_source(struct regmap *regmap, int val)
> +{
> + regmap_update_bits(regmap, ASPEED_PTCR_CTRL,
> + ASPEED_PTCR_CTRL_CLK_SRC,
> + val ? ASPEED_PTCR_CTRL_CLK_SRC : 0);
> +}
> +
> +static void aspeed_set_pwm_clock_values(struct regmap *regmap, u8 type,
> + u8 div_high, u8 div_low, u8 unit)
> +{
> + u32 reg_value = ((div_high << type_params[type].h_value) |
> + (div_low << type_params[type].l_value) |
> + (unit << type_params[type].unit_value));
> +
> + regmap_update_bits(regmap, type_params[type].clk_ctrl_reg,
> + type_params[type].clk_ctrl_mask, reg_value);
> +}
> +
> +static void aspeed_set_pwm_port_enable(struct regmap *regmap, u8 pwm_port,
> + bool enable)
> +{
> + regmap_update_bits(regmap, pwm_port_params[pwm_port].ctrl_reg,
> + pwm_port_params[pwm_port].pwm_en,
> + enable ? pwm_port_params[pwm_port].pwm_en : 0);
> +}
> +
> +static void aspeed_set_pwm_port_type(struct regmap *regmap,
> + u8 pwm_port, u8 type)
> +{
> + u32 reg_value = (type & 0x1) << pwm_port_params[pwm_port].type_part1;
> +
> + reg_value |= (type & 0x2) << pwm_port_params[pwm_port].type_part2;
> +
> + regmap_update_bits(regmap, pwm_port_params[pwm_port].ctrl_reg,
> + pwm_port_params[pwm_port].type_mask, reg_value);
> +}
> +
> +static void aspeed_set_pwm_port_duty_rising_falling(struct regmap *regmap,
> + u8 pwm_port, u8 rising,
> + u8 falling)
> +{
> + u32 reg_value = (rising <<
> + pwm_port_params[pwm_port].duty_ctrl_rise_point);
> + reg_value |= (falling <<
> + pwm_port_params[pwm_port].duty_ctrl_fall_point);
> +
> + regmap_update_bits(regmap, pwm_port_params[pwm_port].duty_ctrl_reg,
> + pwm_port_params[pwm_port].duty_ctrl_rise_fall_mask,
> + reg_value);
> +}
> +
> +static void aspeed_set_tacho_type_enable(struct regmap *regmap, u8 type,
> + bool enable)
> +{
> + regmap_update_bits(regmap, type_params[type].ctrl_reg,
> + TYPE_CTRL_FAN_TYPE_EN,
> + enable ? TYPE_CTRL_FAN_TYPE_EN : 0);
> +}
> +
> +static void aspeed_set_tacho_type_values(struct regmap *regmap, u8 type,
> + u8 mode, u16 unit, u8 division)
> +{
> + u32 reg_value = ((mode << TYPE_CTRL_FAN_MODE) |
> + (unit << TYPE_CTRL_FAN_PERIOD) |
> + (division << TYPE_CTRL_FAN_DIVISION));
> +
> + regmap_update_bits(regmap, type_params[type].ctrl_reg,
> + TYPE_CTRL_FAN_MASK, reg_value);
> + regmap_update_bits(regmap, type_params[type].ctrl_reg1,
> + TYPE_CTRL_FAN1_MASK, unit << 16);
> +}
> +
> +static void aspeed_set_fan_tach_ch_enable(struct regmap *regmap, u8 fan_tach_ch,
> + bool enable)
> +{
> + regmap_update_bits(regmap, ASPEED_PTCR_CTRL,
> + ASPEED_PTCR_CTRL_FAN_NUM_EN(fan_tach_ch),
> + enable ?
> + ASPEED_PTCR_CTRL_FAN_NUM_EN(fan_tach_ch) : 0);
> +}
> +
> +static void aspeed_set_fan_tach_ch_source(struct regmap *regmap, u8 fan_tach_ch,
> + u8 fan_tach_ch_source)
> +{
> + u32 reg_value1 = ((fan_tach_ch_source & 0x3) <<
> + TACH_PWM_SOURCE_BIT01(fan_tach_ch));
> + u32 reg_value2 = (((fan_tach_ch_source & 0x4) >> 2) <<
> + TACH_PWM_SOURCE_BIT2(fan_tach_ch));
> +
> + regmap_update_bits(regmap, ASPEED_PTCR_TACH_SOURCE,
> + TACH_PWM_SOURCE_MASK_BIT01(fan_tach_ch),
> + reg_value1);
> +
> + regmap_update_bits(regmap, ASPEED_PTCR_TACH_SOURCE_EXT,
> + TACH_PWM_SOURCE_MASK_BIT2(fan_tach_ch),
> + reg_value2);
> +}
> +
> +static void aspeed_set_pwm_port_fan_ctrl(struct aspeed_pwm_tacho_data *priv,
> + u8 index, u8 fan_ctrl)
> +{
> + u16 period, dc_time_on;
> +
> + period = priv->type_pwm_clock_unit[priv->pwm_port_type[index]];
> + period += 1;
> + dc_time_on = (fan_ctrl * period) / PWM_MAX;
> +
> + if (dc_time_on == 0) {
> + aspeed_set_pwm_port_enable(priv->regmap, index, false);
> + } else {
> + if (dc_time_on == period)
> + dc_time_on = 0;
> +
> + aspeed_set_pwm_port_duty_rising_falling(priv->regmap, index, 0,
> + dc_time_on);
> + aspeed_set_pwm_port_enable(priv->regmap, index, true);
> + }
> +}
> +
> +static u32 aspeed_get_fan_tach_ch_measure_period(struct aspeed_pwm_tacho_data
> + *priv, u8 type)
> +{
> + u32 clk;
> + u16 tacho_unit;
> + u8 clk_unit, div_h, div_l, tacho_div;
> +
> + clk = priv->clk_freq;
> + clk_unit = priv->type_pwm_clock_unit[type];
> + div_h = priv->type_pwm_clock_division_h[type];
> + div_h = 0x1 << div_h;
> + div_l = priv->type_pwm_clock_division_l[type];
> + if (div_l == 0)
> + div_l = 1;
> + else
> + div_l = div_l * 2;
> +
> + tacho_unit = priv->type_fan_tach_unit[type];
> + tacho_div = priv->type_fan_tach_clock_division[type];
> +
> + tacho_div = 0x4 << (tacho_div * 2);
> + return clk / (clk_unit * div_h * div_l * tacho_div * tacho_unit);
> +}
> +
> +static u32 aspeed_get_fan_tach_ch_rpm(struct aspeed_pwm_tacho_data *priv,
> + u8 fan_tach_ch)
> +{
> + u32 raw_data, tach_div, clk_source, timeout = 0, sec, val;
> + u8 fan_tach_ch_source, type;
> +
> + regmap_write(priv->regmap, ASPEED_PTCR_TRIGGER, 0);
> + regmap_write(priv->regmap, ASPEED_PTCR_TRIGGER, 0x1 << fan_tach_ch);
> +
> + fan_tach_ch_source = priv->fan_tach_ch_source[fan_tach_ch];
> + type = priv->pwm_port_type[fan_tach_ch_source];
> +
> + sec = (1000 / aspeed_get_fan_tach_ch_measure_period(priv, type));
> +
> + msleep(sec);
> +
> + regmap_read(priv->regmap, ASPEED_PTCR_RESULT, &val);
> + while (!(val & RESULT_STATUS_MASK)) {
> + timeout++;
> + if (timeout > 1)
> + return 0;
> + msleep(sec);
> + }
> +
> + regmap_read(priv->regmap, ASPEED_PTCR_RESULT, &val);
> + raw_data = val & RESULT_VALUE_MASK;
> + tach_div = priv->type_fan_tach_clock_division[type];
> +
> + tach_div = 0x4 << (tach_div * 2);
> + clk_source = priv->clk_freq;
> +
> + if (raw_data == 0)
> + return 0;
> + else
> + return (clk_source * 60) / (2 * raw_data * tach_div);
> +}
> +
> +static ssize_t set_pwm(struct device *dev, struct device_attribute *attr,
> + const char *buf, size_t count)
> +{
> + struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr);
> + int index = sensor_attr->index;
> + int ret;
> + struct aspeed_pwm_tacho_data *priv = dev_get_drvdata(dev);
> + long fan_ctrl;
> +
> + ret = kstrtol(buf, 10, &fan_ctrl);
> + if (ret != 0)
> + return ret;
> +
> + if (fan_ctrl < 0 || fan_ctrl > PWM_MAX)
> + return -EINVAL;
> +
> + if (priv->pwm_port_fan_ctrl[index] == fan_ctrl)
> + return count;
> +
> + priv->pwm_port_fan_ctrl[index] = fan_ctrl;
> + aspeed_set_pwm_port_fan_ctrl(priv, index, fan_ctrl);
> +
> + return count;
> +}
> +
> +static ssize_t show_pwm(struct device *dev, struct device_attribute *attr,
> + char *buf)
> +{
> + struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr);
> + int index = sensor_attr->index;
> + struct aspeed_pwm_tacho_data *priv = dev_get_drvdata(dev);
> +
> + return sprintf(buf, "%u\n", priv->pwm_port_fan_ctrl[index]);
> +}
> +
> +static ssize_t show_rpm(struct device *dev, struct device_attribute *attr,
> + char *buf)
> +{
> + struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr);
> + int index = sensor_attr->index;
> + u32 rpm;
> + struct aspeed_pwm_tacho_data *priv = dev_get_drvdata(dev);
> +
> + rpm = aspeed_get_fan_tach_ch_rpm(priv, index);
> +
> + return sprintf(buf, "%u\n", rpm);
> +}
> +
> +static umode_t pwm_is_visible(struct kobject *kobj,
> + struct attribute *a, int index)
> +{
> + struct device *dev = container_of(kobj, struct device, kobj);
> + struct aspeed_pwm_tacho_data *priv = dev_get_drvdata(dev);
> +
> + if (!priv->pwm_present[index])
> + return 0;
> + return a->mode;
> +}
> +
> +static umode_t fan_dev_is_visible(struct kobject *kobj,
> + struct attribute *a, int index)
> +{
> + struct device *dev = container_of(kobj, struct device, kobj);
> + struct aspeed_pwm_tacho_data *priv = dev_get_drvdata(dev);
> +
> + if (!priv->fan_tach_present[index])
> + return 0;
> + return a->mode;
> +}
> +
> +static SENSOR_DEVICE_ATTR(pwm0, 0644,
> + show_pwm, set_pwm, 0);
> +static SENSOR_DEVICE_ATTR(pwm1, 0644,
> + show_pwm, set_pwm, 1);
> +static SENSOR_DEVICE_ATTR(pwm2, 0644,
> + show_pwm, set_pwm, 2);
> +static SENSOR_DEVICE_ATTR(pwm3, 0644,
> + show_pwm, set_pwm, 3);
> +static SENSOR_DEVICE_ATTR(pwm4, 0644,
> + show_pwm, set_pwm, 4);
> +static SENSOR_DEVICE_ATTR(pwm5, 0644,
> + show_pwm, set_pwm, 5);
> +static SENSOR_DEVICE_ATTR(pwm6, 0644,
> + show_pwm, set_pwm, 6);
> +static SENSOR_DEVICE_ATTR(pwm7, 0644,
> + show_pwm, set_pwm, 7);
> +
> +static struct attribute *pwm_dev_attrs[] = {
> + &sensor_dev_attr_pwm0.dev_attr.attr,
> + &sensor_dev_attr_pwm1.dev_attr.attr,
> + &sensor_dev_attr_pwm2.dev_attr.attr,
> + &sensor_dev_attr_pwm3.dev_attr.attr,
> + &sensor_dev_attr_pwm4.dev_attr.attr,
> + &sensor_dev_attr_pwm5.dev_attr.attr,
> + &sensor_dev_attr_pwm6.dev_attr.attr,
> + &sensor_dev_attr_pwm7.dev_attr.attr,
> + NULL,
> +};
> +
> +static const struct attribute_group pwm_dev_group = {
> + .attrs = pwm_dev_attrs,
> + .is_visible = pwm_is_visible,
> +};
> +
> +static SENSOR_DEVICE_ATTR(fan0_input, 0444,
> + show_rpm, NULL, 0);
> +static SENSOR_DEVICE_ATTR(fan1_input, 0444,
> + show_rpm, NULL, 1);
> +static SENSOR_DEVICE_ATTR(fan2_input, 0444,
> + show_rpm, NULL, 2);
> +static SENSOR_DEVICE_ATTR(fan3_input, 0444,
> + show_rpm, NULL, 3);
> +static SENSOR_DEVICE_ATTR(fan4_input, 0444,
> + show_rpm, NULL, 4);
> +static SENSOR_DEVICE_ATTR(fan5_input, 0444,
> + show_rpm, NULL, 5);
> +static SENSOR_DEVICE_ATTR(fan6_input, 0444,
> + show_rpm, NULL, 6);
> +static SENSOR_DEVICE_ATTR(fan7_input, 0444,
> + show_rpm, NULL, 7);
> +static SENSOR_DEVICE_ATTR(fan8_input, 0444,
> + show_rpm, NULL, 8);
> +static SENSOR_DEVICE_ATTR(fan9_input, 0444,
> + show_rpm, NULL, 9);
> +static SENSOR_DEVICE_ATTR(fan10_input, 0444,
> + show_rpm, NULL, 10);
> +static SENSOR_DEVICE_ATTR(fan11_input, 0444,
> + show_rpm, NULL, 11);
> +static SENSOR_DEVICE_ATTR(fan12_input, 0444,
> + show_rpm, NULL, 12);
> +static SENSOR_DEVICE_ATTR(fan13_input, 0444,
> + show_rpm, NULL, 13);
> +static SENSOR_DEVICE_ATTR(fan14_input, 0444,
> + show_rpm, NULL, 14);
> +static SENSOR_DEVICE_ATTR(fan15_input, 0444,
> + show_rpm, NULL, 15);
> +
> +static struct attribute *fan_dev_attrs[] = {
> + &sensor_dev_attr_fan0_input.dev_attr.attr,
> + &sensor_dev_attr_fan1_input.dev_attr.attr,
> + &sensor_dev_attr_fan2_input.dev_attr.attr,
> + &sensor_dev_attr_fan3_input.dev_attr.attr,
> + &sensor_dev_attr_fan4_input.dev_attr.attr,
> + &sensor_dev_attr_fan5_input.dev_attr.attr,
> + &sensor_dev_attr_fan6_input.dev_attr.attr,
> + &sensor_dev_attr_fan7_input.dev_attr.attr,
> + &sensor_dev_attr_fan8_input.dev_attr.attr,
> + &sensor_dev_attr_fan9_input.dev_attr.attr,
> + &sensor_dev_attr_fan10_input.dev_attr.attr,
> + &sensor_dev_attr_fan11_input.dev_attr.attr,
> + &sensor_dev_attr_fan12_input.dev_attr.attr,
> + &sensor_dev_attr_fan13_input.dev_attr.attr,
> + &sensor_dev_attr_fan14_input.dev_attr.attr,
> + &sensor_dev_attr_fan15_input.dev_attr.attr,
> + NULL
> +};
> +
> +static const struct attribute_group fan_dev_group = {
> + .attrs = fan_dev_attrs,
> + .is_visible = fan_dev_is_visible,
> +};
> +
> +/*
> + * The clock type is type M :
> + * The PWM frequency = 24MHz / (type M clock division L bit *
> + * type M clock division H bit * (type M PWM period bit + 1))
> + */
> +static void aspeed_create_type(struct aspeed_pwm_tacho_data *priv)
> +{
> + priv->type_pwm_clock_division_h[TYPEM] = M_PWM_DIV_H;
> + priv->type_pwm_clock_division_l[TYPEM] = M_PWM_DIV_L;
> + priv->type_pwm_clock_unit[TYPEM] = M_PWM_PERIOD;
> + aspeed_set_pwm_clock_values(priv->regmap, TYPEM, M_PWM_DIV_H,
> + M_PWM_DIV_L, M_PWM_PERIOD);
> + aspeed_set_tacho_type_enable(priv->regmap, TYPEM, true);
> + priv->type_fan_tach_clock_division[TYPEM] = M_TACH_CLK_DIV;
> + priv->type_fan_tach_unit[TYPEM] = M_TACH_UNIT;
> + aspeed_set_tacho_type_values(priv->regmap, TYPEM, M_TACH_MODE,
> + M_TACH_UNIT, M_TACH_CLK_DIV);
> +}
> +
> +static void aspeed_create_pwm_port(struct aspeed_pwm_tacho_data *priv,
> + u8 pwm_port)
> +{
> + aspeed_set_pwm_port_enable(priv->regmap, pwm_port, true);
> + priv->pwm_present[pwm_port] = true;
> +
> + priv->pwm_port_type[pwm_port] = TYPEM;
> + aspeed_set_pwm_port_type(priv->regmap, pwm_port, TYPEM);
> +
> + priv->pwm_port_fan_ctrl[pwm_port] = INIT_FAN_CTRL;
> + aspeed_set_pwm_port_fan_ctrl(priv, pwm_port, INIT_FAN_CTRL);
> +}
> +
> +static void aspeed_create_fan_tach_channel(struct aspeed_pwm_tacho_data *priv,
> + u8 *fan_tach_ch,
> + int count,
> + u8 pwm_source)
> +{
> + u8 val, index;
> +
> + for (val = 0; val < count; val++) {
> + index = fan_tach_ch[val];
> + aspeed_set_fan_tach_ch_enable(priv->regmap, index, true);
> + priv->fan_tach_present[index] = true;
> + priv->fan_tach_ch_source[index] = pwm_source;
> + aspeed_set_fan_tach_ch_source(priv->regmap, index, pwm_source);
> + }
> +}
> +
> +static int aspeed_create_fan(struct device *dev,
> + struct device_node *child,
> + struct aspeed_pwm_tacho_data *priv)
> +{
> + u8 *fan_tach_ch;
> + u32 pwm_port;
> + int ret, count;
> +
> + ret = of_property_read_u32(child, "reg", &pwm_port);
> + if (ret)
> + return ret;
> + aspeed_create_pwm_port(priv, (u8)pwm_port);
> +
> + count = of_property_count_u8_elems(child, "aspeed-fan-tach-ch");
> + if (count < 1)
> + return -EINVAL;
> + fan_tach_ch = devm_kzalloc(dev, sizeof(*fan_tach_ch) * count,
> + GFP_KERNEL);
> + if (!fan_tach_ch)
> + return -ENOMEM;
> + ret = of_property_read_u8_array(child, "aspeed-fan-tach-ch",
> + fan_tach_ch, count);
> + if (ret)
> + return ret;
> + aspeed_create_fan_tach_channel(priv, fan_tach_ch, count, pwm_port);
> +
> + return 0;
> +}
> +
> +static int aspeed_pwm_tacho_probe(struct platform_device *pdev)
> +{
> + struct device *dev = &pdev->dev;
> + struct device_node *np, *child;
> + struct aspeed_pwm_tacho_data *priv;
> + struct aspeed_pwm_tacho_regmap *hregmap;
> + struct resource *res;
> + struct device *hwmon;
> + struct clk *clk;
> + int ret;
> +
> + np = dev->of_node;
> +
> + hregmap = devm_kzalloc(dev, sizeof(*hregmap), GFP_KERNEL);
> + if (!hregmap)
> + return -ENOMEM;
> + res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
> + if (!res)
> + return -ENOENT;
> + hregmap->regs = devm_ioremap_resource(dev, res);
> + if (IS_ERR(hregmap->regs))
> + return PTR_ERR(hregmap->regs);
> + priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
> + if (!priv)
> + return -ENOMEM;
> + priv->regmap = devm_regmap_init(dev, NULL, hregmap,
> + &aspeed_pwm_tacho_regmap_config);
> + if (IS_ERR(priv->regmap))
> + return PTR_ERR(priv->regmap);
> + regmap_write(priv->regmap, ASPEED_PTCR_TACH_SOURCE, 0);
> + regmap_write(priv->regmap, ASPEED_PTCR_TACH_SOURCE_EXT, 0);
> +
> + clk = devm_clk_get(dev, NULL);
> + if (IS_ERR(clk))
> + return -ENODEV;
> + priv->clk_freq = clk_get_rate(clk);
> + aspeed_set_clock_enable(priv->regmap, true);
> + aspeed_set_clock_source(priv->regmap, 0);
> +
> + aspeed_create_type(priv);
> +
> + for_each_child_of_node(np, child) {
> + ret = aspeed_create_fan(dev, child, priv);
> + of_node_put(child);
> + if (ret)
> + return ret;
> + }
> + of_node_put(np);
> +
> + priv->groups[0] = &pwm_dev_group;
> + priv->groups[1] = &fan_dev_group;
> + hwmon = devm_hwmon_device_register_with_groups(dev,
> + "aspeed_pwm_tacho",
> + priv, priv->groups);
> +
> + return PTR_ERR_OR_ZERO(hwmon);
> +}
> +
> +static const struct of_device_id of_pwm_tacho_match_table[] = {
> + { .compatible = "aspeed,ast2400-pwm-tacho", },
> + { .compatible = "aspeed,ast2500-pwm-tacho", },
> + {},
> +};
> +MODULE_DEVICE_TABLE(of, of_pwm_tacho_match_table);
> +
> +static struct platform_driver aspeed_pwm_tacho_driver = {
> + .probe = aspeed_pwm_tacho_probe,
> + .driver = {
> + .name = "aspeed_pwm_tacho",
> + .of_match_table = of_pwm_tacho_match_table,
> + },
> +};
> +
> +module_platform_driver(aspeed_pwm_tacho_driver);
> +
> +MODULE_AUTHOR("Jaghathiswari Rankappagounder Natarajan <jaghu@google.com>");
> +MODULE_DESCRIPTION("ASPEED PWM and Fan Tacho device driver");
> +MODULE_LICENSE("GPL");
> --
> 2.12.1.578.ge9c3154ca4-goog
>
^ permalink raw reply
* Re: [PATCH 1/2] leds: Add driver for Qualcomm LPG
From: Pavel Machek @ 2017-03-29 22:23 UTC (permalink / raw)
To: Bjorn Andersson
Cc: Rob Herring, Richard Purdie, Jacek Anaszewski, linux-kernel,
linux-leds, linux-arm-msm, Mark Rutland, devicetree
In-Reply-To: <20170329190725.GN20094@minitux>
[-- Attachment #1: Type: text/plain, Size: 2854 bytes --]
On Wed 2017-03-29 12:07:25, Bjorn Andersson wrote:
> On Tue 28 Mar 19:17 PDT 2017, Rob Herring wrote:
>
> > On Thu, Mar 23, 2017 at 09:37:49PM +0100, Pavel Machek wrote:
> > > Hi!
> > >
> > > > The Light Pulse Generator (LPG) is a PWM-block found in a wide range of
> > > > PMICs from Qualcomm. It can operate on fixed parameters or based on a
> > > > lookup-table, altering the duty cycle over time - which provides the
> > > > means for e.g. hardware assisted transitions of LED brightness.
> > >
> > > Ok, this is not first hardware that supports something like this. We
> > > have similar hardware that can do blinking on Nokia N900 -- please
> > > take a look at leds-lp55*.c
> >
> > And perhaps some alignment on the bindings too if the N900 has bindings.
> >
>
> There is a binding for ti,lp55xx, but there's nothing I can reuse from
> that binding...because it's completely different hardware.
Agreed, if you drop the pattern stuff from the binding, at least for now.
> > > And it would be really good to provide hardware abstraction. We really
> > > don't want to have different userspace for LPG and for N900 and for
> >
> > I'm interested in what this looks like as several AOSP platforms do
> > tri-color LEDs with custom sysfs extensions.
>
> How to model RGB LEDs has been discussed many times before and I was
> hoping for that discussion to come to some conclusion during the last 2
> years, but now I couldn't wait more - we need this driver for
> db820c.
If you want driver merged quickly, I believe the best way would be to
leave out pattern support for now. We can merge the basic driver
easily to 4.12.
> With this driver, as with many existing, you will have 3 LEDs that you
> set independently.
>
> I did implement blinking by using the PWM straight off, so you can't set
> brightness or synchronize the multiple channels. Perhaps this should be
> changed to use the ramp generator.
>
> To synchronize patterns I suggest that we extend the LUT binding to
> describe groups and when any LPG trigger a restart of the pattern-walker
> we trigger all that are grouped.
>
> These two changes combined allows you to set brightness and blink with a
> RGB-LED.
>
>
> But I will have to dig up some hardware that uses the LPG for driving a
> RGB-LED to be able to test this (and I do prefer that to be done with
> some incremental patches at some later time, if acceptable).
Incremental patches sound like a good idea, yes.
I'd say that testing with actual RGB LED is not a requirement... as
long as we design reasonable interface where the synchronizaction will
be easy.
Thanks and best regards,
Pavel
--
(english) http://www.livejournal.com/~pavelmachek
(cesky, pictures) http://atrey.karlin.mff.cuni.cz/~pavel/picture/horses/blog.html
[-- Attachment #2: Digital signature --]
[-- Type: application/pgp-signature, Size: 181 bytes --]
^ permalink raw reply
* Re: [linux-sunxi] [PATCH v3 06/11] drm/sun4i: add support for Allwinner DE2 mixers
From: Jernej Škrabec @ 2017-03-29 22:33 UTC (permalink / raw)
To: linux-sunxi-/JYPxA39Uh5TLH3MbocFFw, icenowy-h8G6r0blFSE
Cc: Rob Herring, Maxime Ripard, Chen-Yu Tsai,
linux-clk-u79uwXL29TY76Z2rM5mHXA,
devicetree-u79uwXL29TY76Z2rM5mHXA,
linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r,
linux-kernel-u79uwXL29TY76Z2rM5mHXA,
dri-devel-PD4FTy7X32lNgt0PjOBp9y5qC8QIuHrW
In-Reply-To: <20170329194613.55548-7-icenowy-h8G6r0blFSE@public.gmane.org>
Hi,
Dne sreda, 29. marec 2017 ob 21:46:08 CEST je Icenowy Zheng napisal(a):
> Allwinner have a new "Display Engine 2.0" in their new SoCs, which comes
> with mixers to do graphic processing and feed data to TCON, like the old
> backends and frontends.
>
> Add support for the mixer on Allwinner V3s SoC; it's the simplest one.
>
> Currently a lot of functions are still missing -- more investigations
> are needed to gain enough information for them.
>
> Signed-off-by: Icenowy Zheng <icenowy-h8G6r0blFSE@public.gmane.org>
> ---
> Refactored patch in v3.
>
> drivers/gpu/drm/sun4i/Kconfig | 10 +
> drivers/gpu/drm/sun4i/Makefile | 4 +
> drivers/gpu/drm/sun4i/sun8i_layer.c | 156 +++++++++++++++
> drivers/gpu/drm/sun4i/sun8i_layer.h | 35 ++++
> drivers/gpu/drm/sun4i/sun8i_mixer.c | 386
> ++++++++++++++++++++++++++++++++++++ drivers/gpu/drm/sun4i/sun8i_mixer.h |
> 131 ++++++++++++
> 6 files changed, 722 insertions(+)
> create mode 100644 drivers/gpu/drm/sun4i/sun8i_layer.c
> create mode 100644 drivers/gpu/drm/sun4i/sun8i_layer.h
> create mode 100644 drivers/gpu/drm/sun4i/sun8i_mixer.c
> create mode 100644 drivers/gpu/drm/sun4i/sun8i_mixer.h
>
> diff --git a/drivers/gpu/drm/sun4i/Kconfig b/drivers/gpu/drm/sun4i/Kconfig
> index 5a8227f37cc4..15557484520d 100644
> --- a/drivers/gpu/drm/sun4i/Kconfig
> +++ b/drivers/gpu/drm/sun4i/Kconfig
> @@ -22,3 +22,13 @@ config DRM_SUN4I_BACKEND
> original Allwinner Display Engine, which has a backend to
> do some alpha blending and feed graphics to TCON. If M is
> selected the module will be called sun4i-backend.
> +
> +config DRM_SUN4I_SUN8I_MIXER
> + tristate "Support for Allwinner Display Engine 2.0 Mixer"
> + depends on DRM_SUN4I
> + default MACH_SUN8I
> + help
> + Choose this option if you have an Allwinner SoC with the
> + Allwinner Display Engine 2.0, which has a mixer to do some
> + graphics mixture and feed graphics to TCON, If M is
> + selected the module will be called sun8i-mixer.
> diff --git a/drivers/gpu/drm/sun4i/Makefile b/drivers/gpu/drm/sun4i/Makefile
> index 1db1068b9be1..7625c2dad1bb 100644
> --- a/drivers/gpu/drm/sun4i/Makefile
> +++ b/drivers/gpu/drm/sun4i/Makefile
> @@ -9,7 +9,11 @@ sun4i-tcon-y += sun4i_crtc.o
> sun4i-backend-y += sun4i_layer.o
> sun4i-backend-y += sun4i_backend.o
>
> +sun8i-mixer-y += sun8i_layer.o
> +sun8i-mixer-y += sun8i_mixer.o
> +
> obj-$(CONFIG_DRM_SUN4I) += sun4i-drm.o sun4i-tcon.o
> obj-$(CONFIG_DRM_SUN4I_BACKEND) += sun4i-backend.o
> +obj-$(CONFIG_DRM_SUN4I_SUN8I_MIXER) += sun8i-mixer.o
> obj-$(CONFIG_DRM_SUN4I) += sun6i_drc.o
> obj-$(CONFIG_DRM_SUN4I) += sun4i_tv.o
> diff --git a/drivers/gpu/drm/sun4i/sun8i_layer.c
> b/drivers/gpu/drm/sun4i/sun8i_layer.c new file mode 100644
> index 000000000000..5cc4a7f8a7ae
> --- /dev/null
> +++ b/drivers/gpu/drm/sun4i/sun8i_layer.c
> @@ -0,0 +1,156 @@
> +/*
> + * Copyright (C) Icenowy Zheng <icenowy-ymACFijhrKM@public.gmane.org>
> + *
> + * Based on sun4i_layer.h, which is:
> + * Copyright (C) 2015 Free Electrons
> + * Copyright (C) 2015 NextThing Co
> + *
> + * Maxime Ripard <maxime.ripard-wi1+55ScJUtKEb57/3fJTNBPR1lH4CV8@public.gmane.org>
> + *
> + * This program is free software; you can redistribute it and/or
> + * modify it under the terms of the GNU General Public License as
> + * published by the Free Software Foundation; either version 2 of
> + * the License, or (at your option) any later version.
> + */
> +
> +#include <drm/drm_atomic_helper.h>
> +#include <drm/drm_crtc.h>
> +#include <drm/drm_plane_helper.h>
> +#include <drm/drmP.h>
> +
> +#include "sun4i_crtc.h"
> +#include "sun8i_layer.h"
> +#include "sun8i_mixer.h"
> +#include "sunxi_layer.h"
> +
> +struct sun8i_plane_desc {
> + enum drm_plane_type type;
> + const uint32_t *formats;
> + uint32_t nformats;
> +};
> +
> +static int sun8i_mixer_layer_atomic_check(struct drm_plane *plane,
> + struct drm_plane_state *state)
> +{
> + return 0;
> +}
> +
> +static void sun8i_mixer_layer_atomic_disable(struct drm_plane *plane,
> + struct drm_plane_state *old_state)
> +{
> + struct sun8i_layer *layer = plane_to_sun8i_layer(plane);
> + struct sun8i_mixer *mixer = layer->mixer;
> +
> + sun8i_mixer_layer_enable(mixer, layer->id, false);
> +}
> +
> +static void sun8i_mixer_layer_atomic_update(struct drm_plane *plane,
> + struct drm_plane_state *old_state)
> +{
> + struct sun8i_layer *layer = plane_to_sun8i_layer(plane);
> + struct sun8i_mixer *mixer = layer->mixer;
> +
> + sun8i_mixer_update_layer_coord(mixer, layer->id, plane);
> + sun8i_mixer_update_layer_formats(mixer, layer->id, plane);
> + sun8i_mixer_update_layer_buffer(mixer, layer->id, plane);
> + sun8i_mixer_layer_enable(mixer, layer->id, true);
> +}
> +
> +static struct drm_plane_helper_funcs sun8i_mixer_layer_helper_funcs = {
> + .atomic_check = sun8i_mixer_layer_atomic_check,
> + .atomic_disable = sun8i_mixer_layer_atomic_disable,
> + .atomic_update = sun8i_mixer_layer_atomic_update,
> +};
> +
> +static const struct drm_plane_funcs sun8i_mixer_layer_funcs = {
> + .atomic_destroy_state = drm_atomic_helper_plane_destroy_state,
> + .atomic_duplicate_state = drm_atomic_helper_plane_duplicate_state,
> + .destroy = drm_plane_cleanup,
> + .disable_plane = drm_atomic_helper_disable_plane,
> + .reset = drm_atomic_helper_plane_reset,
> + .update_plane = drm_atomic_helper_update_plane,
> +};
> +
> +static const uint32_t sun8i_mixer_layer_formats[] = {
> + DRM_FORMAT_RGB888,
> + DRM_FORMAT_XRGB8888,
> +};
> +
> +static const struct sun8i_plane_desc sun8i_mixer_planes[] = {
> + {
> + .type = DRM_PLANE_TYPE_PRIMARY,
> + .formats = sun8i_mixer_layer_formats,
> + .nformats = ARRAY_SIZE(sun8i_mixer_layer_formats),
> + },
> +};
> +
> +static struct drm_plane *sun8i_layer_get_plane(void *layer)
> +{
> + struct sun8i_layer *sun8i_layer = layer;
> +
> + return &sun8i_layer->plane;
> +}
> +
> +static const struct sunxi_layer_ops layer_ops = {
> + .get_plane = sun8i_layer_get_plane,
> +};
> +
> +static struct sun8i_layer *sun8i_layer_init_one(struct drm_device *drm,
> + struct sun8i_mixer *mixer,
> + const struct sun8i_plane_desc *plane)
> +{
> + struct sun8i_layer *layer;
> + int ret;
> +
> + layer = devm_kzalloc(drm->dev, sizeof(*layer), GFP_KERNEL);
> + if (!layer)
> + return ERR_PTR(-ENOMEM);
> +
> + /* possible crtcs are set later */
> + ret = drm_universal_plane_init(drm, &layer->plane, 0,
> + &sun8i_mixer_layer_funcs,
> + plane->formats, plane->nformats,
> + plane->type, NULL);
> + if (ret) {
> + dev_err(drm->dev, "Couldn't initialize layer\n");
> + return ERR_PTR(ret);
> + }
> +
> + drm_plane_helper_add(&layer->plane,
> + &sun8i_mixer_layer_helper_funcs);
> + layer->mixer = mixer;
> +
> + return layer;
> +}
> +
> +void **sun8i_layers_init(struct drm_device *drm, struct sun4i_crtc *crtc)
> +{
> + struct sun8i_layer **layers;
> + struct sun8i_mixer *mixer = crtc->mixer;
> + int i;
> +
> + layers = devm_kcalloc(drm->dev, ARRAY_SIZE(sun8i_mixer_planes) + 1,
> + sizeof(*layers), GFP_KERNEL);
> + if (!layers)
> + return ERR_PTR(-ENOMEM);
> +
> + for (i = 0; i < ARRAY_SIZE(sun8i_mixer_planes); i++) {
> + const struct sun8i_plane_desc *plane = &sun8i_mixer_planes[i];
> + struct sun8i_layer *layer;
> +
> + layer = sun8i_layer_init_one(drm, mixer, plane);
> + if (IS_ERR(layer)) {
> + dev_err(drm->dev, "Couldn't initialize %s plane\n",
> + i ? "overlay" : "primary");
> + return ERR_CAST(layer);
> + };
> +
> + layer->id = i;
> + layers[i] = layer;
> + };
> +
> + /* Assign layer ops to the CRTC */
> + crtc->layer_ops = &layer_ops;
> +
> + return (void **)layers;
> +}
> diff --git a/drivers/gpu/drm/sun4i/sun8i_layer.h
> b/drivers/gpu/drm/sun4i/sun8i_layer.h new file mode 100644
> index 000000000000..9f145ce842f2
> --- /dev/null
> +++ b/drivers/gpu/drm/sun4i/sun8i_layer.h
> @@ -0,0 +1,35 @@
> +/*
> + * Copyright (C) Icenowy Zheng <icenowy-ymACFijhrKM@public.gmane.org>
> + *
> + * Based on sun4i_layer.h, which is:
> + * Copyright (C) 2015 Free Electrons
> + * Copyright (C) 2015 NextThing Co
> + *
> + * Maxime Ripard <maxime.ripard-wi1+55ScJUtKEb57/3fJTNBPR1lH4CV8@public.gmane.org>
> + *
> + * This program is free software; you can redistribute it and/or
> + * modify it under the terms of the GNU General Public License as
> + * published by the Free Software Foundation; either version 2 of
> + * the License, or (at your option) any later version.
> + */
> +
> +#ifndef _SUN8I_LAYER_H_
> +#define _SUN8I_LAYER_H_
> +
> +struct sun4i_crtc;
> +
> +struct sun8i_layer {
> + struct drm_plane plane;
> + struct sun4i_drv *drv;
> + struct sun8i_mixer *mixer;
> + int id;
> +};
> +
> +static inline struct sun8i_layer *
> +plane_to_sun8i_layer(struct drm_plane *plane)
> +{
> + return container_of(plane, struct sun8i_layer, plane);
> +}
> +
> +void **sun8i_layers_init(struct drm_device *drm, struct sun4i_crtc *crtc);
> +#endif /* _SUN8I_LAYER_H_ */
> diff --git a/drivers/gpu/drm/sun4i/sun8i_mixer.c
> b/drivers/gpu/drm/sun4i/sun8i_mixer.c new file mode 100644
> index 000000000000..1399d1a6c678
> --- /dev/null
> +++ b/drivers/gpu/drm/sun4i/sun8i_mixer.c
> @@ -0,0 +1,386 @@
> +/*
> + * Copyright (C) 2017 Icenowy Zheng <icenowy-ymACFijhrKM@public.gmane.org>
> + *
> + * Based on sun4i_backend.c, which is:
> + * Copyright (C) 2015 Free Electrons
> + * Copyright (C) 2015 NextThing Co
> + *
> + * This program is free software; you can redistribute it and/or
> + * modify it under the terms of the GNU General Public License as
> + * published by the Free Software Foundation; either version 2 of
> + * the License, or (at your option) any later version.
> + */
> +
> +#include <drm/drmP.h>
> +#include <drm/drm_atomic_helper.h>
> +#include <drm/drm_crtc.h>
> +#include <drm/drm_crtc_helper.h>
> +#include <drm/drm_fb_cma_helper.h>
> +#include <drm/drm_gem_cma_helper.h>
> +#include <drm/drm_plane_helper.h>
> +
> +#include <linux/component.h>
> +#include <linux/reset.h>
> +#include <linux/of_device.h>
> +
> +#include "sun4i_drv.h"
> +#include "sun8i_mixer.h"
> +#include "sun8i_layer.h"
> +#include "sunxi_mixer.h"
> +
> +void sun8i_mixer_commit(void *mixer)
> +{
> + struct sun8i_mixer *sun8i_mixer = mixer;
> +
> + DRM_DEBUG_DRIVER("Committing changes\n");
> +
> + regmap_write(sun8i_mixer->regs, SUN8I_MIXER_GLOBAL_DBUFF,
> + SUN8I_MIXER_GLOBAL_DBUFF_ENABLE);
> +}
> +
> +void sun8i_mixer_layer_enable(struct sun8i_mixer *mixer,
> + int layer, bool enable)
> +{
Layer parameter will be always 0 for now, right?
> + u32 val;
> + /* Currently the first UI channel is used */
> + int chan = mixer->cfg->vi_num;
> +
> + DRM_DEBUG_DRIVER("Enabling layer %d in channel %d\n", layer, chan);
> +
> + if (enable)
> + val = SUN8I_MIXER_CHAN_UI_LAYER_ATTR_EN;
> + else
> + val = 0;
> +
> + regmap_update_bits(mixer->regs,
> + SUN8I_MIXER_CHAN_UI_LAYER_ATTR(chan, layer),
> + SUN8I_MIXER_CHAN_UI_LAYER_ATTR_EN, val);
> +
> + /* Set the alpha configuration */
> + regmap_update_bits(mixer->regs,
> + SUN8I_MIXER_CHAN_UI_LAYER_ATTR(chan, layer),
> + SUN8I_MIXER_CHAN_UI_LAYER_ATTR_ALPHA_MODE_MASK,
> + SUN8I_MIXER_CHAN_UI_LAYER_ATTR_ALPHA_MODE_DEF);
> + regmap_update_bits(mixer->regs,
> + SUN8I_MIXER_CHAN_UI_LAYER_ATTR(chan, layer),
> + SUN8I_MIXER_CHAN_UI_LAYER_ATTR_ALPHA_MASK,
> + SUN8I_MIXER_CHAN_UI_LAYER_ATTR_ALPHA_DEF);
> +}
> +EXPORT_SYMBOL(sun8i_mixer_layer_enable);
> +
> +static int sun8i_mixer_drm_format_to_layer(struct drm_plane *plane,
> + u32 format, u32 *mode)
> +{
> + switch (format) {
> + case DRM_FORMAT_XRGB8888:
> + *mode = SUN8I_MIXER_CHAN_UI_LAYER_ATTR_FBFMT_XRGB8888;
> + break;
> +
> + case DRM_FORMAT_RGB888:
> + *mode = SUN8I_MIXER_CHAN_UI_LAYER_ATTR_FBFMT_RGB888;
> + break;
> +
> + default:
> + return -EINVAL;
> + }
> +
> + return 0;
> +}
> +
> +int sun8i_mixer_update_layer_coord(struct sun8i_mixer *mixer,
> + int layer, struct drm_plane *plane)
> +{
> + struct drm_plane_state *state = plane->state;
> + struct drm_framebuffer *fb = state->fb;
> + /* Currently the first UI channel is used */
> + int chan = mixer->cfg->vi_num;
> + int i;
> +
> + DRM_DEBUG_DRIVER("Updating layer %d\n", layer);
> +
> + if (plane->type == DRM_PLANE_TYPE_PRIMARY) {
> + DRM_DEBUG_DRIVER("Primary layer, updating global size W: %u H: %u\n",
> + state->crtc_w, state->crtc_h);
> + regmap_write(mixer->regs, SUN8I_MIXER_GLOBAL_SIZE,
> + SUN8I_MIXER_SIZE(state->crtc_w,
> + state->crtc_h));
> + DRM_DEBUG_DRIVER("Updating blender size\n");
> + for (i = 0; i < SUN8I_MIXER_MAX_CHAN_COUNT; i++)
> + regmap_write(mixer->regs,
> + SUN8I_MIXER_BLEND_ATTR_INSIZE(i),
> + SUN8I_MIXER_SIZE(state->crtc_w,
> + state->crtc_h));
Since only one blend channel is used, you only have to set the first for now.
> + regmap_write(mixer->regs, SUN8I_MIXER_BLEND_OUTSIZE,
> + SUN8I_MIXER_SIZE(state->crtc_w,
> + state->crtc_h));
> + DRM_DEBUG_DRIVER("Updating channel size\n");
> + regmap_write(mixer->regs, SUN8I_MIXER_CHAN_UI_OVL_SIZE(chan),
> + SUN8I_MIXER_SIZE(state->crtc_w,
> + state->crtc_h));
> + }
> +
> + /* Set the line width */
> + DRM_DEBUG_DRIVER("Layer line width: %d bytes\n", fb->pitches[0]);
> + regmap_write(mixer->regs, SUN8I_MIXER_CHAN_UI_LAYER_PITCH(chan, layer),
> + fb->pitches[0]);
> +
> + /* Set height and width */
> + DRM_DEBUG_DRIVER("Layer size W: %u H: %u\n",
> + state->crtc_w, state->crtc_h);
> + regmap_write(mixer->regs, SUN8I_MIXER_CHAN_UI_LAYER_SIZE(chan, layer),
> + SUN8I_MIXER_SIZE(state->crtc_w, state->crtc_h));
> +
> + /* Set base coordinates */
> + DRM_DEBUG_DRIVER("Layer coordinates X: %d Y: %d\n",
> + state->crtc_x, state->crtc_y);
> + regmap_write(mixer->regs, SUN8I_MIXER_CHAN_UI_LAYER_COORD(chan, layer),
> + SUN8I_MIXER_COORD(state->crtc_x, state->crtc_y));
> +
> + return 0;
> +}
> +EXPORT_SYMBOL(sun8i_mixer_update_layer_coord);
> +
> +int sun8i_mixer_update_layer_formats(struct sun8i_mixer *mixer,
> + int layer, struct drm_plane *plane)
> +{
> + struct drm_plane_state *state = plane->state;
> + struct drm_framebuffer *fb = state->fb;
> + bool interlaced = false;
> + u32 val;
> + /* Currently the first UI channel is used */
> + int chan = mixer->cfg->vi_num;
> + int ret;
> +
> + if (plane->state->crtc)
> + interlaced = plane->state->crtc->state->adjusted_mode.flags
> + & DRM_MODE_FLAG_INTERLACE;
> +
> + regmap_update_bits(mixer->regs, SUN8I_MIXER_BLEND_OUTCTL,
> + SUN8I_MIXER_BLEND_OUTCTL_INTERLACED,
> + interlaced ?
> + SUN8I_MIXER_BLEND_OUTCTL_INTERLACED : 0);
> +
> + DRM_DEBUG_DRIVER("Switching display mixer interlaced mode %s\n",
> + interlaced ? "on" : "off");
> +
> + ret = sun8i_mixer_drm_format_to_layer(plane, fb->format->format,
> + &val);
> + if (ret) {
> + DRM_DEBUG_DRIVER("Invalid format\n");
> + return ret;
> + }
> +
> + regmap_update_bits(mixer->regs,
> + SUN8I_MIXER_CHAN_UI_LAYER_ATTR(chan, layer),
> + SUN8I_MIXER_CHAN_UI_LAYER_ATTR_FBFMT_MASK, val);
> +
> + return 0;
> +}
> +EXPORT_SYMBOL(sun8i_mixer_update_layer_formats);
> +
> +int sun8i_mixer_update_layer_buffer(struct sun8i_mixer *mixer,
> + int layer, struct drm_plane *plane)
> +{
> + struct drm_plane_state *state = plane->state;
> + struct drm_framebuffer *fb = state->fb;
> + struct drm_gem_cma_object *gem;
> + dma_addr_t paddr;
> + uint32_t paddr_u32;
> + /* Currently the first UI channel is used */
> + int chan = mixer->cfg->vi_num;
> + int bpp;
> +
> + /* Get the physical address of the buffer in memory */
> + gem = drm_fb_cma_get_gem_obj(fb, 0);
> +
> + DRM_DEBUG_DRIVER("Using GEM @ %pad\n", &gem->paddr);
> +
> + /* Compute the start of the displayed memory */
> + bpp = fb->format->cpp[0];
> + paddr = gem->paddr + fb->offsets[0];
> + paddr += (state->src_x >> 16) * bpp;
> + paddr += (state->src_y >> 16) * fb->pitches[0];
> +
> + DRM_DEBUG_DRIVER("Setting buffer address to %pad\n", &paddr);
> +
> + paddr_u32 = (uint32_t) paddr;
> +
> + regmap_write(mixer->regs,
> + SUN8I_MIXER_CHAN_UI_LAYER_TOP_LADDR(chan, layer),
> + paddr_u32);
> +
> + return 0;
> +}
> +EXPORT_SYMBOL(sun8i_mixer_update_layer_buffer);
> +
> +static const struct sunxi_mixer_ops sun8i_mixer_mixer_ops = {
> + .commit = sun8i_mixer_commit,
> + .layers_init = sun8i_layers_init,
> +};
> +
> +static struct regmap_config sun8i_mixer_regmap_config = {
> + .reg_bits = 32,
> + .val_bits = 32,
> + .reg_stride = 4,
> + .max_register = 0xbffc, /* guessed */
> +};
> +
> +static int sun8i_mixer_bind(struct device *dev, struct device *master,
> + void *data)
> +{
> + struct platform_device *pdev = to_platform_device(dev);
> + struct drm_device *drm = data;
> + struct sun4i_drv *drv = drm->dev_private;
> + struct sun8i_mixer *mixer;
> + struct resource *res;
> + void __iomem *regs;
> + int i, ret;
> +
> + mixer = devm_kzalloc(dev, sizeof(*mixer), GFP_KERNEL);
> + if (!mixer)
> + return -ENOMEM;
> + dev_set_drvdata(dev, mixer);
> + drv->mixer = mixer;
> + drv->mixer_ops = &sun8i_mixer_mixer_ops;
> +
> + mixer->cfg = of_device_get_match_data(dev);
> + if (!mixer->cfg)
> + return -EINVAL;
> +
> + res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
> + regs = devm_ioremap_resource(dev, res);
> + if (IS_ERR(regs))
> + return PTR_ERR(regs);
> +
> + mixer->regs = devm_regmap_init_mmio(dev, regs,
> + &sun8i_mixer_regmap_config);
> + if (IS_ERR(mixer->regs)) {
> + dev_err(dev, "Couldn't create the mixer regmap\n");
> + return PTR_ERR(mixer->regs);
> + }
> +
> + mixer->reset = devm_reset_control_get(dev, NULL);
> + if (IS_ERR(mixer->reset)) {
> + dev_err(dev, "Couldn't get our reset line\n");
> + return PTR_ERR(mixer->reset);
> + }
> +
> + ret = reset_control_deassert(mixer->reset);
> + if (ret) {
> + dev_err(dev, "Couldn't deassert our reset line\n");
> + return ret;
> + }
> +
> + mixer->bus_clk = devm_clk_get(dev, "bus");
> + if (IS_ERR(mixer->bus_clk)) {
> + dev_err(dev, "Couldn't get the mixer bus clock\n");
> + ret = PTR_ERR(mixer->bus_clk);
> + goto err_assert_reset;
> + }
> + clk_prepare_enable(mixer->bus_clk);
> +
> + mixer->mod_clk = devm_clk_get(dev, "mod");
> + if (IS_ERR(mixer->mod_clk)) {
> + dev_err(dev, "Couldn't get the mixer module clock\n");
> + ret = PTR_ERR(mixer->mod_clk);
> + goto err_disable_bus_clk;
> + }
> + clk_prepare_enable(mixer->mod_clk);
> +
> + /* Reset the registers */
> + for (i = 0x0; i < 0x20000; i += 4)
> + regmap_write(mixer->regs, i, 0);
> +
> + /* Enable the mixer */
> + regmap_write(mixer->regs, SUN8I_MIXER_GLOBAL_CTL,
> + SUN8I_MIXER_GLOBAL_CTL_RT_EN);
> +
> + /* Initialize blender */
> + regmap_write(mixer->regs, SUN8I_MIXER_BLEND_FCOLOR_CTL,
> + SUN8I_MIXER_BLEND_FCOLOR_CTL_DEF);
> + regmap_write(mixer->regs, SUN8I_MIXER_BLEND_PREMULTIPLY,
> + SUN8I_MIXER_BLEND_PREMULTIPLY_DEF);
> + regmap_write(mixer->regs, SUN8I_MIXER_BLEND_BKCOLOR,
> + SUN8I_MIXER_BLEND_BKCOLOR_DEF);
> + regmap_write(mixer->regs, SUN8I_MIXER_BLEND_MODE(0),
> + SUN8I_MIXER_BLEND_MODE_DEF);
> + regmap_write(mixer->regs, SUN8I_MIXER_BLEND_MODE(1),
> + SUN8I_MIXER_BLEND_MODE_DEF);
Blend mode has to be set only for active layers, so above statement is not
needed currently.
> + regmap_write(mixer->regs, SUN8I_MIXER_BLEND_CK_CTL,
> + SUN8I_MIXER_BLEND_CK_CTL_DEF);
> +
> + for (i = 0; i < SUN8I_MIXER_MAX_CHAN_COUNT; i++)
> + regmap_write(mixer->regs,
> + SUN8I_MIXER_BLEND_ATTR_FCOLOR(i),
> + SUN8I_MIXER_BLEND_ATTR_FCOLOR_DEF);
Ditto. Setting first layer is enough.
> +
> + /* Select the first UI channel */
> + DRM_DEBUG_DRIVER("Selecting channel %d (first UI channel)\n",
> + mixer->cfg->vi_num);
> + regmap_write(mixer->regs, SUN8I_MIXER_BLEND_ROUTE,
> + mixer->cfg->vi_num);
> +
> + return 0;
> +
> + clk_disable_unprepare(mixer->mod_clk);
> +err_disable_bus_clk:
> + clk_disable_unprepare(mixer->bus_clk);
> +err_assert_reset:
> + reset_control_assert(mixer->reset);
> + return ret;
> +}
> +
> +static void sun8i_mixer_unbind(struct device *dev, struct device *master,
> + void *data)
> +{
> + struct sun8i_mixer *mixer = dev_get_drvdata(dev);
> +
> + clk_disable_unprepare(mixer->mod_clk);
> + clk_disable_unprepare(mixer->bus_clk);
> + reset_control_assert(mixer->reset);
> +}
> +
> +static const struct component_ops sun8i_mixer_ops = {
> + .bind = sun8i_mixer_bind,
> + .unbind = sun8i_mixer_unbind,
> +};
> +
> +static int sun8i_mixer_probe(struct platform_device *pdev)
> +{
> + return component_add(&pdev->dev, &sun8i_mixer_ops);
> +}
> +
> +static int sun8i_mixer_remove(struct platform_device *pdev)
> +{
> + component_del(&pdev->dev, &sun8i_mixer_ops);
> +
> + return 0;
> +}
> +
> +static const struct sun8i_mixer_cfg sun8i_v3s_mixer_cfg = {
> + .vi_num = 2,
> + .ui_num = 1,
> +};
> +
> +static const struct of_device_id sun8i_mixer_of_table[] = {
> + {
> + .compatible = "allwinner,sun8i-v3s-de2-mixer",
> + .data = &sun8i_v3s_mixer_cfg,
> + },
> + { }
> +};
> +MODULE_DEVICE_TABLE(of, sun8i_mixer_of_table);
> +
> +static struct platform_driver sun8i_mixer_platform_driver = {
> + .probe = sun8i_mixer_probe,
> + .remove = sun8i_mixer_remove,
> + .driver = {
> + .name = "sun8i-mixer",
> + .of_match_table = sun8i_mixer_of_table,
> + },
> +};
> +module_platform_driver(sun8i_mixer_platform_driver);
> +
> +MODULE_AUTHOR("Icenowy Zheng <icenowy-ymACFijhrKM@public.gmane.org>");
> +MODULE_DESCRIPTION("Allwinner DE2 Mixer driver");
> +MODULE_LICENSE("GPL");
> diff --git a/drivers/gpu/drm/sun4i/sun8i_mixer.h
> b/drivers/gpu/drm/sun4i/sun8i_mixer.h new file mode 100644
> index 000000000000..7b3b9d747d7d
> --- /dev/null
> +++ b/drivers/gpu/drm/sun4i/sun8i_mixer.h
> @@ -0,0 +1,131 @@
> +/*
> + * Copyright (C) 2017 Icenowy Zheng <icenowy-ymACFijhrKM@public.gmane.org>
> + *
> + * This program is free software; you can redistribute it and/or
> + * modify it under the terms of the GNU General Public License as
> + * published by the Free Software Foundation; either version 2 of
> + * the License, or (at your option) any later version.
> + */
> +
> +#ifndef _SUN8I_MIXER_H_
> +#define _SUN8I_MIXER_H_
> +
> +#include <linux/clk.h>
> +#include <linux/regmap.h>
> +#include <linux/reset.h>
> +
> +#include "sun4i_layer.h"
> +
> +#define SUN8I_MIXER_MAX_CHAN_COUNT 4
> +
> +#define SUN8I_MIXER_SIZE(w, h) (((h) - 1) << 16 | ((w) - 1))
> +#define SUN8I_MIXER_COORD(x, y) ((y) << 16 | (x))
> +
> +#define SUN8I_MIXER_GLOBAL_CTL 0x0
> +#define SUN8I_MIXER_GLOBAL_STATUS 0x4
> +#define SUN8I_MIXER_GLOBAL_DBUFF 0x8
> +#define SUN8I_MIXER_GLOBAL_SIZE 0xc
> +
> +#define SUN8I_MIXER_GLOBAL_CTL_RT_EN 0x1
> +
> +#define SUN8I_MIXER_GLOBAL_DBUFF_ENABLE 0x1
> +
> +#define SUN8I_MIXER_BLEND_FCOLOR_CTL 0x1000
> +#define SUN8I_MIXER_BLEND_ATTR_FCOLOR(x) (0x1004 + 0x10 * (x) + 0x0)
> +#define SUN8I_MIXER_BLEND_ATTR_INSIZE(x) (0x1004 + 0x10 * (x) + 0x4)
> +#define SUN8I_MIXER_BLEND_ATTR_OFFSET(x) (0x1004 + 0x10 * (x) + 0x8)
> +#define SUN8I_MIXER_BLEND_ROUTE 0x1080
> +#define SUN8I_MIXER_BLEND_PREMULTIPLY 0x1084
> +#define SUN8I_MIXER_BLEND_BKCOLOR 0x1088
> +#define SUN8I_MIXER_BLEND_OUTSIZE 0x108c
> +#define SUN8I_MIXER_BLEND_MODE(x) (0x1090 + 0x04 * (x))
> +#define SUN8I_MIXER_BLEND_CK_CTL 0x10b0
> +#define SUN8I_MIXER_BLEND_CK_CFG 0x10b4
> +#define SUN8I_MIXER_BLEND_CK_MAX(x) (0x10c0 + 0x04 * (x))
> +#define SUN8I_MIXER_BLEND_CK_MIN(x) (0x10e0 + 0x04 * (x))
> +#define SUN8I_MIXER_BLEND_OUTCTL 0x10fc
> +
> +/* The following numbers are some still unknown magic numbers */
> +#define SUN8I_MIXER_BLEND_ATTR_FCOLOR_DEF 0xff000000
> +#define SUN8I_MIXER_BLEND_FCOLOR_CTL_DEF 0x00000101
> +#define SUN8I_MIXER_BLEND_PREMULTIPLY_DEF 0x0
> +#define SUN8I_MIXER_BLEND_BKCOLOR_DEF 0xff000000
> +#define SUN8I_MIXER_BLEND_MODE_DEF 0x03010301
> +#define SUN8I_MIXER_BLEND_CK_CTL_DEF 0x0
> +
> +#define SUN8I_MIXER_BLEND_OUTCTL_INTERLACED BIT(1)
> +
> +/*
> + * VI channels are not used now, but the support of them may be introduced
> in + * the future.
> + */
> +
> +#define SUN8I_MIXER_CHAN_UI_LAYER_ATTR(ch, layer) \
> + (0x2000 + 0x1000 * (ch) + 0x20 * (layer) + 0x0)
> +#define SUN8I_MIXER_CHAN_UI_LAYER_SIZE(ch, layer) \
> + (0x2000 + 0x1000 * (ch) + 0x20 * (layer) + 0x4)
> +#define SUN8I_MIXER_CHAN_UI_LAYER_COORD(ch, layer) \
> + (0x2000 + 0x1000 * (ch) + 0x20 * (layer) + 0x8)
> +#define SUN8I_MIXER_CHAN_UI_LAYER_PITCH(ch, layer) \
> + (0x2000 + 0x1000 * (ch) + 0x20 * (layer) + 0xc)
> +#define SUN8I_MIXER_CHAN_UI_LAYER_TOP_LADDR(ch, layer) \
> + (0x2000 + 0x1000 * (ch) + 0x20 * (layer) + 0x10)
> +#define SUN8I_MIXER_CHAN_UI_LAYER_BOT_LADDR(ch, layer) \
> + (0x2000 + 0x1000 * (ch) + 0x20 * (layer) + 0x14)
> +#define SUN8I_MIXER_CHAN_UI_LAYER_FCOLOR(ch, layer) \
> + (0x2000 + 0x1000 * (ch) + 0x20 * (layer) + 0x18)
> +#define SUN8I_MIXER_CHAN_UI_TOP_HADDR(ch) (0x2000 + 0x1000 * (ch) + 0x80)
> +#define SUN8I_MIXER_CHAN_UI_BOT_HADDR(ch) (0x2000 + 0x1000 * (ch) + 0x84)
> +#define SUN8I_MIXER_CHAN_UI_OVL_SIZE(ch) (0x2000 + 0x1000 * (ch) + 0x88)
> +
> +#define SUN8I_MIXER_CHAN_UI_LAYER_ATTR_EN BIT(0)
> +#define SUN8I_MIXER_CHAN_UI_LAYER_ATTR_ALPHA_MODE_MASK GENMASK(2, 1)
> +#define SUN8I_MIXER_CHAN_UI_LAYER_ATTR_FBFMT_MASK GENMASK(11, 8)
> +#define SUN8I_MIXER_CHAN_UI_LAYER_ATTR_ALPHA_MASK GENMASK(31, 24)
> +#define SUN8I_MIXER_CHAN_UI_LAYER_ATTR_ALPHA_MODE_DEF (1 << 1)
> +#define SUN8I_MIXER_CHAN_UI_LAYER_ATTR_FBFMT_ARGB8888 (0 << 8)
> +#define SUN8I_MIXER_CHAN_UI_LAYER_ATTR_FBFMT_XRGB8888 (4 << 8)
> +#define SUN8I_MIXER_CHAN_UI_LAYER_ATTR_FBFMT_RGB888 (8 << 8)
> +#define SUN8I_MIXER_CHAN_UI_LAYER_ATTR_ALPHA_DEF (0xff << 24)
> +
> +/*
> + * These sun-engines are still unknown now, the EN registers are here only
Typo, should be "sub".
Regards,
Jernej
> to + * be used to disable these sub-engines.
> + */
> +#define SUN8I_MIXER_VSU_EN 0x20000
> +#define SUN8I_MIXER_GSU1_EN 0x30000
> +#define SUN8I_MIXER_GSU2_EN 0x40000
> +#define SUN8I_MIXER_GSU3_EN 0x50000
> +#define SUN8I_MIXER_FCE_EN 0xa0000
> +#define SUN8I_MIXER_BWS_EN 0xa2000
> +#define SUN8I_MIXER_LTI_EN 0xa4000
> +#define SUN8I_MIXER_PEAK_EN 0xa6000
> +#define SUN8I_MIXER_ASE_EN 0xa8000
> +#define SUN8I_MIXER_FCC_EN 0xaa000
> +#define SUN8I_MIXER_DCSC_EN 0xb0000
> +
> +struct sun8i_mixer_cfg {
> + int vi_num;
> + int ui_num;
> +};
> +
> +struct sun8i_mixer {
> + struct regmap *regs;
> +
> + const struct sun8i_mixer_cfg *cfg;
> +
> + struct reset_control *reset;
> +
> + struct clk *bus_clk;
> + struct clk *mod_clk;
> +};
> +
> +void sun8i_mixer_layer_enable(struct sun8i_mixer *mixer,
> + int layer, bool enable);
> +int sun8i_mixer_update_layer_coord(struct sun8i_mixer *mixer,
> + int layer, struct drm_plane *plane);
> +int sun8i_mixer_update_layer_formats(struct sun8i_mixer *mixer,
> + int layer, struct drm_plane *plane);
> +int sun8i_mixer_update_layer_buffer(struct sun8i_mixer *mixer,
> + int layer, struct drm_plane *plane);
> +#endif /* _SUN8I_MIXER_H_ */
> --
> 2.12.0
>
> --
> You received this message because you are subscribed to the Google Groups
> "linux-sunxi" group. To unsubscribe from this group and stop receiving
> emails from it, send an email to linux-sunxi+unsubscribe-/JYPxA39Uh5TLH3MbocFF+G/Ez6ZCGd0@public.gmane.org
> For more options, visit https://groups.google.com/d/optout.
--
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 net-next v3 5/5] net-next: dsa: add dsa support for Mediatek MT7530 switch
From: Andrew Lunn @ 2017-03-29 23:12 UTC (permalink / raw)
To: sean.wang-NuS5LvNUpcJWk0Htik3J/w
Cc: f.fainelli-Re5JQEeQqe8AvxtiuMwx3w,
vivien.didelot-4ysUXcep3aM1wj+D4I0NRVaTQe2KTcn/,
matthias.bgg-Re5JQEeQqe8AvxtiuMwx3w,
robh+dt-DgEjT+Ai2ygdnm+yROfE0A, mark.rutland-5wv7dgnIgG8,
devicetree-u79uwXL29TY76Z2rM5mHXA, netdev-u79uwXL29TY76Z2rM5mHXA,
linux-kernel-u79uwXL29TY76Z2rM5mHXA,
linux-mediatek-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r,
davem-fT/PcQaiUtIeIZ0/mPfg9Q, Landen.Chao-NuS5LvNUpcJWk0Htik3J/w,
keyhaede-Re5JQEeQqe8AvxtiuMwx3w, objelf-Re5JQEeQqe8AvxtiuMwx3w
In-Reply-To: <1490780303-18598-6-git-send-email-sean.wang-NuS5LvNUpcJWk0Htik3J/w@public.gmane.org>
> +static struct mt7530_priv *lpriv;
Hi Sean
Why do you need this global variable? What if somebody has two
switches connected?
> +static void mt7530_port_disable(struct dsa_switch *ds, int port,
> + struct phy_device *phy);
> +static int mt7530_cpu_port_enable(struct mt7530_priv *priv,
> + int port);
It is better to move the functions around than have forward
declarations.
> +static u32
> +_mt7530_read(u32 reg)
> +{
> + struct mt7530_priv *priv = lpriv;
> + struct mii_bus *bus = priv->bus;
> + u32 val;
> +
> + mutex_lock_nested(&bus->mdio_lock, MDIO_MUTEX_NESTED);
> +
> + val = mt7530_mii_read(priv, reg);
> +
> + mutex_unlock(&bus->mdio_lock);
> +
> + return val;
> +}
> +
> +static u32
> +mt7530_read(struct mt7530_priv *priv, u32 reg)
> +{
> + return _mt7530_read(reg);
> +}
So here you would pass priv to _mt7530_read().
> +static int
> +mt7530_fdb_cmd(struct mt7530_priv *priv, enum mt7530_fdb_cmd cmd, u32 *rsp)
> +{
> + u32 val;
> + int ret;
> +
> + /* Set the command operating upon the MAC address entries */
> + val = ATC_BUSY | ATC_MAT(0) | cmd;
> + mt7530_write(priv, MT7530_ATC, val);
> +
> + ret = readx_poll_timeout(_mt7530_read, MT7530_ATC, val,
> + !(val & ATC_BUSY), 20, 20000);
This is where your need for lpriv comes, you can only pass a single
argument. But you can work around it. readx_poll_timeout is a
#define. So there is no type check for _mt7530_read, or the arg passed
to it. So pass a struct containing the address and priv.
I think you can then kill of your global lpriv.
Andrew
--
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 2/3] usb: add DT bindings for farady fotg2 host controller
From: Linus Walleij @ 2017-03-29 23:16 UTC (permalink / raw)
To: Rob Herring
Cc: Hans Ulli Kroll, linux-kernel@vger.kernel.org,
devicetree@vger.kernel.org, Linux USB List, Greg Kroah-Hartman,
Mark Rutland
In-Reply-To: <CAL_JsqK7VDomXqMz3YJqL5QjnSb-anwXtG+exz4g_BjPLOaiXQ@mail.gmail.com>
On Tue, Feb 21, 2017 at 3:43 PM, Rob Herring <robh@kernel.org> wrote:
> On Fri, Feb 17, 2017 at 4:07 AM, Hans Ulli Kroll
> <ulli.kroll@googlemail.com> wrote:
>> Hi Rob,
>>
>> On Wed, 15 Feb 2017, Rob Herring wrote:
>>
>>> On Wed, Feb 08, 2017 at 09:00:09PM +0100, Hans Ulli Kroll wrote:
>>> > This adds DT bindings for the Faraday FOTG2 host controller.
>>> >
>>> > Signed-off-by: Hans Ulli Kroll <ulli.kroll@googlemail.com>
>>> > ---
>>> > Documentation/devicetree/bindings/usb/fotg2-host.txt | 15 +++++++++++++++
>>> > 1 file changed, 15 insertions(+)
>>> > create mode 100644 Documentation/devicetree/bindings/usb/fotg2-host.txt
>>> >
>>> > diff --git a/Documentation/devicetree/bindings/usb/fotg2-host.txt b/Documentation/devicetree/bindings/usb/fotg2-host.txt
>>> > new file mode 100644
>>> > index 000000000000..4c07566a4bf5
>>> > --- /dev/null
>>> > +++ b/Documentation/devicetree/bindings/usb/fotg2-host.txt
>>> > @@ -0,0 +1,15 @@
>>> > +Faraday FOTG Host controller
>>> > +
>>> > +Required properties:
>>> > +
>>> > +- compatible: should be "faraday,fotg210-hcd"
>>>
>>> hcd as in "host controller driver"? Bindings describe h/w not drivers.
>>>
>>> It's an OTG controller or host controller?
>>>
>>
>> here only the host controller part used.
>>
>> faraday fotg2 is a dual role hcd/otg device and here is only the
>> host part used.
>
> Because you don't care about device mode or restricted by the IP
> configuration or SoC integration? The former is a user choice and
> shouldn't be part of DT. The latter should be implied by an SoC
> specific compatible string. Using only a compatible string for a
> licensed IP is not specific enough as vendors use differing versions
> and integrate them in different ways.
Hans can you add:
compatible = "cortina,gemini-fotg", "faraday,fotg210-hcd" or something
as composite compatible for our controller?
It's OK for the driver to only match on the latter for now, but for the
future it's nice for the driver to know what silicon it is on.
This is what I've done for most other Cortina/Gemini stuff.
Yours,
Linus Walleij
^ permalink raw reply
* [PATCH 1/5] ARM: dts: imx7-colibri: use OF graph to describe the display
From: Stefan Agner @ 2017-03-29 23:21 UTC (permalink / raw)
To: shawnguo, kernel
Cc: fabio.estevam, robh+dt, mark.rutland, linux-arm-kernel,
devicetree, linux-kernel, Stefan Agner
To make use of the new eLCDIF DRM driver OF graph description is
required. Describe the display using OF graph nodes.
Signed-off-by: Stefan Agner <stefan@agner.ch>
---
arch/arm/boot/dts/imx7-colibri-eval-v3.dtsi | 38 +++++++++++------------------
1 file changed, 14 insertions(+), 24 deletions(-)
diff --git a/arch/arm/boot/dts/imx7-colibri-eval-v3.dtsi b/arch/arm/boot/dts/imx7-colibri-eval-v3.dtsi
index 373ee19196a6..7a98a45a0d95 100644
--- a/arch/arm/boot/dts/imx7-colibri-eval-v3.dtsi
+++ b/arch/arm/boot/dts/imx7-colibri-eval-v3.dtsi
@@ -44,6 +44,17 @@
chosen {
stdout-path = "serial0:115200n8";
};
+
+ panel: panel {
+ compatible = "edt,et057090dhu";
+ backlight = <&bl>;
+
+ port {
+ panel_in: endpoint {
+ remote-endpoint = <&lcdif_out>;
+ };
+ };
+ };
};
&bl {
@@ -75,32 +86,11 @@
};
&lcdif {
- display = <&display0>;
status = "okay";
- display0: lcd-display {
- bits-per-pixel = <16>;
- bus-width = <18>;
-
- display-timings {
- native-mode = <&timing_vga>;
-
- /* Standard VGA timing */
- timing_vga: 640x480 {
- clock-frequency = <25175000>;
- hactive = <640>;
- vactive = <480>;
- hback-porch = <40>;
- hfront-porch = <24>;
- vback-porch = <32>;
- vfront-porch = <11>;
- hsync-len = <96>;
- vsync-len = <2>;
- de-active = <1>;
- hsync-active = <0>;
- vsync-active = <0>;
- pixelclk-active = <0>;
- };
+ port {
+ lcdif_out: endpoint {
+ remote-endpoint = <&panel_in>;
};
};
};
--
2.12.1
^ permalink raw reply related
* [PATCH 2/5] ARM: dts: imx7-colibri: fix PMIC voltages
From: Stefan Agner @ 2017-03-29 23:21 UTC (permalink / raw)
To: shawnguo, kernel
Cc: fabio.estevam, robh+dt, mark.rutland, linux-arm-kernel,
devicetree, linux-kernel, Stefan Agner
In-Reply-To: <20170329232113.19078-1-stefan@agner.ch>
Fix wrong voltage of PWR_EN_+V3.3 rail. The error had no noticeable
effect since no consumer explicitly requested a specific voltage.
Also use round voltages as it is common in other device trees.
Signed-off-by: Stefan Agner <stefan@agner.ch>
---
arch/arm/boot/dts/imx7-colibri.dtsi | 32 ++++++++++++++++----------------
1 file changed, 16 insertions(+), 16 deletions(-)
diff --git a/arch/arm/boot/dts/imx7-colibri.dtsi b/arch/arm/boot/dts/imx7-colibri.dtsi
index a171545478be..47eab920666f 100644
--- a/arch/arm/boot/dts/imx7-colibri.dtsi
+++ b/arch/arm/boot/dts/imx7-colibri.dtsi
@@ -151,29 +151,29 @@
regulators {
reg_DCDC1: DCDC1 { /* V1.0_SOC */
- regulator-min-microvolt = <975000>;
- regulator-max-microvolt = <1125000>;
+ regulator-min-microvolt = <1000000>;
+ regulator-max-microvolt = <1100000>;
regulator-boot-on;
regulator-always-on;
};
reg_DCDC2: DCDC2 { /* V1.1_ARM */
- regulator-min-microvolt = <975000>;
- regulator-max-microvolt = <1125000>;
+ regulator-min-microvolt = <975000>;
+ regulator-max-microvolt = <1100000>;
regulator-boot-on;
regulator-always-on;
};
reg_DCDC3: DCDC3 { /* V1.8 */
- regulator-min-microvolt = <1775000>;
- regulator-max-microvolt = <1825000>;
+ regulator-min-microvolt = <1800000>;
+ regulator-max-microvolt = <1800000>;
regulator-boot-on;
regulator-always-on;
};
reg_DCDC4: DCDC4 { /* V1.35_DRAM */
- regulator-min-microvolt = <1325000>;
- regulator-max-microvolt = <1375000>;
+ regulator-min-microvolt = <1350000>;
+ regulator-max-microvolt = <1350000>;
regulator-boot-on;
regulator-always-on;
};
@@ -185,29 +185,29 @@
};
reg_LDO2: LDO2 { /* +V1.8_SD */
- regulator-min-microvolt = <1775000>;
- regulator-max-microvolt = <3325000>;
+ regulator-min-microvolt = <1800000>;
+ regulator-max-microvolt = <3300000>;
regulator-boot-on;
regulator-always-on;
};
reg_LDO3: LDO3 { /* PWR_EN_+V3.3_LPSR */
- regulator-min-microvolt = <3275000>;
- regulator-max-microvolt = <3325000>;
+ regulator-min-microvolt = <3300000>;
+ regulator-max-microvolt = <3300000>;
regulator-boot-on;
regulator-always-on;
};
reg_LDO4: LDO4 { /* V1.8_LPSR */
- regulator-min-microvolt = <1775000>;
- regulator-max-microvolt = <1825000>;
+ regulator-min-microvolt = <1800000>;
+ regulator-max-microvolt = <1800000>;
regulator-boot-on;
regulator-always-on;
};
reg_LDO5: LDO5 { /* PWR_EN_+V3.3 */
- regulator-min-microvolt = <1775000>;
- regulator-max-microvolt = <1825000>;
+ regulator-min-microvolt = <3300000>;
+ regulator-max-microvolt = <3300000>;
regulator-boot-on;
regulator-always-on;
};
--
2.12.1
^ 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