* [PATCH 1/5] drm/panel: Add support for the EDT ETM0700G0BDH6
From: Jan Tuerk @ 2017-11-23 12:55 UTC (permalink / raw)
To: Rob Herring, Mark Rutland, Thierry Reding, David Airlie,
Russell King, Shawn Guo, Sascha Hauer, Fabio Estevam, Jan Tuerk,
Andreas Färber, Kevin Hilman, Maxime Ripard,
Alexandre Belloni, Greg Kroah-Hartman, SZ Lin, devicetree,
linux-kernel, dri-devel, linux-arm-kernel
In-Reply-To: <20171123125600.41562-1-jan.tuerk@emtrion.com>
[-- Attachment #1: Type: text/plain, Size: 2811 bytes --]
The Emerging Display Technology ETM0700G0BDH6 is exactly
the same display as the ETM0700G0DH6, exept the pixelclock
polarity. Therefore re-use the ETM0700G0DH6 modes. It is
used by default on emtrion Avari based development kits.
Signed-off-by: Jan Tuerk <jan.tuerk@emtrion.com>
---
.../bindings/display/panel/edt,etm0700g0bdh6.txt | 9 +++++++++
drivers/gpu/drm/panel/panel-simple.c | 15 +++++++++++++++
2 files changed, 24 insertions(+)
create mode 100644 Documentation/devicetree/bindings/display/panel/edt,etm0700g0bdh6.txt
diff --git a/Documentation/devicetree/bindings/display/panel/edt,etm0700g0bdh6.txt b/Documentation/devicetree/bindings/display/panel/edt,etm0700g0bdh6.txt
new file mode 100644
index 000000000000..099e30bfa17f
--- /dev/null
+++ b/Documentation/devicetree/bindings/display/panel/edt,etm0700g0bdh6.txt
@@ -0,0 +1,9 @@
+Emerging Display Technology Corp. ETM0700G0BDH6 7.0" WVGA TFT LCD panel
+
+Required properties:
+ compatible: "edt,etm0700g0bdh6"
+
+This panel is exactly the same as ETM0700G0DH6 except the pixelclock polarity.
+
+This binding is compatible with the simple-panel binding, which is specified
+in simple-panel.txt in this directory.
diff --git a/drivers/gpu/drm/panel/panel-simple.c b/drivers/gpu/drm/panel/panel-simple.c
index b7c4709f7b34..42442034b53e 100644
--- a/drivers/gpu/drm/panel/panel-simple.c
+++ b/drivers/gpu/drm/panel/panel-simple.c
@@ -886,6 +886,18 @@ static const struct panel_desc edt_etm0700g0dh6 = {
.bus_flags = DRM_BUS_FLAG_DE_HIGH | DRM_BUS_FLAG_PIXDATA_NEGEDGE,
};
+static const struct panel_desc edt_etm0700g0bdh6 = {
+ .modes = &edt_etm0700g0dh6_mode,
+ .num_modes = 1,
+ .bpc = 6,
+ .size = {
+ .width = 152,
+ .height = 91,
+ },
+ .bus_format = MEDIA_BUS_FMT_RGB666_1X18,
+ .bus_flags = DRM_BUS_FLAG_DE_HIGH | DRM_BUS_FLAG_PIXDATA_POSEDGE,
+};
+
static const struct drm_display_mode foxlink_fl500wvr00_a0t_mode = {
.clock = 32260,
.hdisplay = 800,
@@ -2029,6 +2041,9 @@ static const struct of_device_id platform_of_match[] = {
.compatible = "edt,etm0700g0dh6",
.data = &edt_etm0700g0dh6,
}, {
+ .compatible = "edt,etm0700g0bdh6",
+ .data = &edt_etm0700g0bdh6,
+ }, {
.compatible = "foxlink,fl500wvr00-a0t",
.data = &foxlink_fl500wvr00_a0t,
}, {
--
2.11.0
emtrion GmbH
Kreativpark - Alter Schlachthof 45
76131 Karlsruhe
GERMANY
http://www.emtrion.de
_______________________________________
Amtsgericht Mannheim
HRB 110 300
Geschäftsführer: Dieter Baur, Ramona Maurer
_______________________________________
[-- Attachment #2: Type: text/plain, Size: 176 bytes --]
_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
^ permalink raw reply related
* [PATCH 2/5] dt-bindings: Add vendor prefix for emtrion GmbH
From: Jan Tuerk @ 2017-11-23 12:55 UTC (permalink / raw)
To: Rob Herring, Mark Rutland, Thierry Reding, David Airlie,
Russell King, Shawn Guo, Sascha Hauer, Fabio Estevam, Jan Tuerk,
Andreas Färber, Kevin Hilman, Maxime Ripard, SZ Lin,
Greg Kroah-Hartman, Alexandre Belloni, devicetree, linux-kernel,
dri-devel, linux-arm-kernel
In-Reply-To: <20171123125600.41562-1-jan.tuerk@emtrion.com>
[-- Attachment #1: Type: text/plain, Size: 1151 bytes --]
emtrion is a system integrator and manufacturer of embedded systems.
Website: https://www.emtrion.de
Signed-off-by: Jan Tuerk <jan.tuerk@emtrion.com>
---
Documentation/devicetree/bindings/vendor-prefixes.txt | 1 +
1 file changed, 1 insertion(+)
diff --git a/Documentation/devicetree/bindings/vendor-prefixes.txt b/Documentation/devicetree/bindings/vendor-prefixes.txt
index 0994bdd82cd3..5215c5767260 100644
--- a/Documentation/devicetree/bindings/vendor-prefixes.txt
+++ b/Documentation/devicetree/bindings/vendor-prefixes.txt
@@ -102,6 +102,7 @@ eeti eGalax_eMPIA Technology Inc
elan Elan Microelectronic Corp.
embest Shenzhen Embest Technology Co., Ltd.
emmicro EM Microelectronic
+emtrion emtrion GmbH
energymicro Silicon Laboratories (formerly Energy Micro AS)
engicam Engicam S.r.l.
epcos EPCOS AG
--
2.11.0
emtrion GmbH
Kreativpark - Alter Schlachthof 45
76131 Karlsruhe
GERMANY
http://www.emtrion.de
_______________________________________
Amtsgericht Mannheim
HRB 110 300
Geschäftsführer: Dieter Baur, Ramona Maurer
_______________________________________
[-- Attachment #2: Type: text/plain, Size: 176 bytes --]
_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
^ permalink raw reply related
* [PATCH 3/5] ARM: dts: imx: Add an cpu0 label for imx6dl devices.
From: Jan Tuerk @ 2017-11-23 12:55 UTC (permalink / raw)
To: Rob Herring, Mark Rutland, Thierry Reding, David Airlie,
Russell King, Shawn Guo, Sascha Hauer, Fabio Estevam, Jan Tuerk,
Andreas Färber, Kevin Hilman, Maxime Ripard, SZ Lin,
Alexandre Belloni, Greg Kroah-Hartman, devicetree, linux-kernel,
dri-devel, linux-arm-kernel
In-Reply-To: <20171123125600.41562-1-jan.tuerk@emtrion.com>
Adding the label cpu0 allows the adjustment of cpu-parameters
by reference in overlaying dtsi files in the same way as it
is possible for imx6q devices.
Signed-off-by: Jan Tuerk <jan.tuerk@emtrion.com>
---
arch/arm/boot/dts/imx6dl.dtsi | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/arch/arm/boot/dts/imx6dl.dtsi b/arch/arm/boot/dts/imx6dl.dtsi
index 4d693a75ce98..623c12519b81 100644
--- a/arch/arm/boot/dts/imx6dl.dtsi
+++ b/arch/arm/boot/dts/imx6dl.dtsi
@@ -21,7 +21,7 @@
#address-cells = <1>;
#size-cells = <0>;
- cpu@0 {
+ cpu0: cpu@0 {
compatible = "arm,cortex-a9";
device_type = "cpu";
reg = <0>;
--
2.11.0
emtrion GmbH
Kreativpark - Alter Schlachthof 45
76131 Karlsruhe
GERMANY
http://www.emtrion.de
_______________________________________
Amtsgericht Mannheim
HRB 110 300
Geschäftsführer: Dieter Baur, Ramona Maurer
_______________________________________
^ permalink raw reply related
* [PATCH 4/5] ARM: dts: Add support for emtrion emCON-MX6 series
From: Jan Tuerk @ 2017-11-23 12:55 UTC (permalink / raw)
To: Rob Herring, Mark Rutland, Thierry Reding, David Airlie,
Russell King, Shawn Guo, Sascha Hauer, Fabio Estevam, Jan Tuerk,
Andreas Färber, Kevin Hilman, Geert Uytterhoeven,
Alexandre Belloni, SZ Lin, Greg Kroah-Hartman, devicetree,
linux-kernel, dri-devel, linux-arm-kernel
In-Reply-To: <20171123125600.41562-1-jan.tuerk@emtrion.com>
[-- Attachment #1: Type: text/plain, Size: 51803 bytes --]
This patch adds support for the emtrion GmbH emCON-MX6 modules.
They are available with imx.6 Solo, Dual-Lite, Dual and Quad
equipped with Memory from 512MB to 2GB (configured by U-Boot).
Our default developer-Kit ships with the Avari baseboard and the
EDT ETM0700G0BDH6 Display (imx6[q|dl]-emcon-avari).
The devicetree is split into the common part providing all module
components and the basic support for all SoC versions
(imx6qdl-emcon.dtsi) and parts which are i.mx6 S|DL and D|Q relevant.
Finally the support for the avari baseboard in the developer-kit
configuration is provided by the emcon-avari dts files.
Signed-off-by: Jan Tuerk <jan.tuerk@emtrion.com>
---
Documentation/devicetree/bindings/arm/emtrion.txt | 13 +
arch/arm/boot/dts/Makefile | 2 +
arch/arm/boot/dts/imx6dl-emcon-avari.dts | 233 ++++++
arch/arm/boot/dts/imx6dl-emcon.dtsi | 37 +
arch/arm/boot/dts/imx6q-emcon-avari.dts | 233 ++++++
arch/arm/boot/dts/imx6q-emcon.dtsi | 37 +
arch/arm/boot/dts/imx6qdl-emcon.dtsi | 849 ++++++++++++++++++++++
7 files changed, 1404 insertions(+)
create mode 100644 Documentation/devicetree/bindings/arm/emtrion.txt
create mode 100644 arch/arm/boot/dts/imx6dl-emcon-avari.dts
create mode 100644 arch/arm/boot/dts/imx6dl-emcon.dtsi
create mode 100644 arch/arm/boot/dts/imx6q-emcon-avari.dts
create mode 100644 arch/arm/boot/dts/imx6q-emcon.dtsi
create mode 100644 arch/arm/boot/dts/imx6qdl-emcon.dtsi
diff --git a/Documentation/devicetree/bindings/arm/emtrion.txt b/Documentation/devicetree/bindings/arm/emtrion.txt
new file mode 100644
index 000000000000..3ff6c6c2034d
--- /dev/null
+++ b/Documentation/devicetree/bindings/arm/emtrion.txt
@@ -0,0 +1,13 @@
+Emtrion Devicetree Bindings
+===========================
+
+emCON Series:
+-------------
+
+Required root node properties
+ - compatible:
+ - "emtrion,emcon-mx6", "fsl,imx6q", "fsl,imx6dl"; : emCON-MX6 Generic SoM
+ - "emtrion,emcon-mx6", "fsl,imx6q"; : emCON-MX6D or emCON-MX6Q SoM
+ - "emtrion,emcon-mx6-avari", "fsl,imx6q"; : emCON-MX6D or emCON-MX6Q SoM on Avari Base
+ - "emtrion,emcon-mx6", "fsl,imx6dl"; : emCON-MX6S or emCON-MX6DL SoM
+ - "emtrion,emcon-mx6-avari", "fsl,imx6dl"; : emCON-MX6S or emCON-MX6DL SoM on Avari Base
diff --git a/arch/arm/boot/dts/Makefile b/arch/arm/boot/dts/Makefile
index d0381e9caf21..5ce643ece228 100644
--- a/arch/arm/boot/dts/Makefile
+++ b/arch/arm/boot/dts/Makefile
@@ -373,6 +373,7 @@ dtb-$(CONFIG_SOC_IMX6Q) += \
imx6dl-colibri-eval-v3.dtb \
imx6dl-cubox-i.dtb \
imx6dl-dfi-fs700-m60.dtb \
+ imx6dl-emcon-avari.dtb \
imx6dl-gw51xx.dtb \
imx6dl-gw52xx.dtb \
imx6dl-gw53xx.dtb \
@@ -424,6 +425,7 @@ dtb-$(CONFIG_SOC_IMX6Q) += \
imx6q-dfi-fs700-m60.dtb \
imx6q-display5-tianma-tm070-1280x768.dtb \
imx6q-dmo-edmqmx6.dtb \
+ imx6q-emcon-avari.dtb \
imx6q-evi.dtb \
imx6q-gk802.dtb \
imx6q-gw51xx.dtb \
diff --git a/arch/arm/boot/dts/imx6dl-emcon-avari.dts b/arch/arm/boot/dts/imx6dl-emcon-avari.dts
new file mode 100644
index 000000000000..f8ca63258eda
--- /dev/null
+++ b/arch/arm/boot/dts/imx6dl-emcon-avari.dts
@@ -0,0 +1,233 @@
+/*
+ * Copyright (C) 2017 emtrion GmbH
+ * Author: Jan Tuerk <jan.tuerk@emtrion.com>
+ *
+ * The code contained herein is licensed under the GNU General Public
+ * License. You may obtain a copy of the GNU General Public License
+ * Version 2 or later at the following locations:
+ *
+ * http://www.opensource.org/licenses/gpl-license.html
+ * http://www.gnu.org/copyleft/gpl.html
+ *
+ * SPDX-License-Identifier: GPL-2.0
+ *
+ */
+
+/dts-v1/;
+#include "imx6dl.dtsi"
+#include "imx6qdl-emcon.dtsi"
+#include "imx6dl-emcon.dtsi" /*Include camera2 pinmux*/
+
+/ {
+ model = "emtrion SoM emCON-MX6 Solo/Dual-Lite Avari";
+ compatible = "emtrion,emcon-mx6-avari", "fsl,imx6dl";
+
+ aliases {
+ mmc0 = &usdhc3;
+ mmc2 = &usdhc1;
+ mmc1 = &usdhc2;
+ mmc3 = &usdhc4;
+ };
+
+ chosen {
+ stdout-path = <&uart1>;
+ };
+
+ memory {
+ reg = <0x10000000 0x40000000>;
+ };
+
+ supplies {
+ compatible = "simple-bus";
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ wallplug5p0: supply@0 {
+ compatible = "regulator-fixed";
+ reg = <0>;
+ regulator-name = "WALL-PLUG";
+ regulator-min-microvolt = <5000000>;
+ regulator-max-microvolt = <5000000>;
+ regulator-always-on;
+ regulator-boot-on;
+ };
+
+ base3p3: supply@1 {
+ compatible = "regulator-fixed";
+ reg = <1>;
+ vin-supply = <&wallplug5p0>;
+ regulator-name = "3V3-avari";
+ regulator-min-microvolt = <3300000>;
+ regulator-max-microvolt = <3300000>;
+ regulator-always-on;
+ regulator-boot-on;
+ };
+
+ base1p5: supply@2 {
+ compatible = "regulator-fixed";
+ reg = <2>;
+ vin-supply = <&base3p3>;
+ regulator-name = "1V5-avari";
+ regulator-min-microvolt = <1500000>;
+ regulator-max-microvolt = <1500000>;
+ regulator-always-on;
+ regulator-boot-on;
+ };
+
+ reg_usb_otg: otgvbus {
+ compatible = "regulator-fixed";
+ reg = <3>;
+ vin-supply = <&wallplug5p0>;
+ regulator-name = "OTG_VBUS";
+ regulator-min-microvolt = <5000000>;
+ regulator-max-microvolt = <5000000>;
+ gpio = <&gpio1 8 GPIO_ACTIVE_LOW>;
+ regulator-always-on;
+ };
+
+ };
+
+
+ sndosc: 12MHZosc {
+ compatible = "fixed-clock";
+ #clock-cells = <0>;
+ clock-frequency = <12000000>;
+ };
+
+ sound {
+ compatible = "fsl,imx-audio-sgtl5000";
+ model = "emCON-avari-sgtl5000";
+ ssi-controller = <&ssi2>;
+ audio-codec = <&sgtl5000>;
+ audio-routing =
+ "Headphone Jack", "HP_OUT";
+ mux-int-port = <2>;
+ mux-ext-port = <3>;
+ };
+
+};
+
+
+&iomuxc {
+ pinctrl-names = "default";
+ /*Unused emCON-MX6 outputs on AVARI*/
+ pinctrl-0 = <
+ &pinctrl_emcon_gpio1 &pinctrl_emcon_gpio2
+ &pinctrl_emcon_gpio3 &pinctrl_emcon_gpio5
+ &pinctrl_emcon_gpio6 &pinctrl_emcon_gpio7
+ &pinctrl_emcon_gpio8 &pinctrl_emcon_irq_a
+ &pinctrl_emcon_irq_b &pinctrl_emcon_irq_c
+ &pinctrl_emcon_irq_pwr &pinctrl_nor_flash
+ &pinctrl_usdhc2
+ &pinctrl_spdif_out &pinctrl_spdif_in
+ &pinctrl_cpi1 &pinctrl_cpi2
+ >;
+};
+
+&audmux {
+ pinctrl-names = "default";
+ pinctrl-0 = <&pinctrl_audmux>;
+ status = "okay";
+};
+
+
+
+&i2c3 {
+ clock-frequency = <100000>;
+ pinctrl-names = "default";
+ pinctrl-0 = <&pinctrl_i2c3>;
+ status = "okay";
+
+ sgtl5000: sgtl5000@0a {
+ compatible = "fsl,sgtl5000";
+ reg = <0x0a>;
+ clocks = <&sndosc>;
+ VDDA-supply = <&base3p3>;
+ VDDIO-supply = <&base3p3>;
+ };
+
+ boardID: pca8754a@3A {
+ compatible = "nxp,pca8574";
+ reg = <0x3A>;
+ gpio-controller;
+ #gpio-cells = <1>;
+ };
+
+ captouch: edt-ft5x06@38 {
+ reg = <0x38>;
+ pinctrl-names = "default";
+ pinctrl-0 = <&pinctrl_irq_touch2 &pinctrl_emcon_gpio4>;
+ interrupt-parent = <&gpio6>;
+ interrupts = <31 IRQ_TYPE_EDGE_FALLING>;
+ compatible = "edt,edt-ft5406";
+ wake-gpios = <&gpio2 3 GPIO_ACTIVE_HIGH>;
+ wakeup-source;
+ };
+};
+
+&ssi2 {
+ status = "okay";
+};
+
+&rgb_encoder {
+ status = "okay";
+};
+
+&rgb_panel {
+ compatible = "edt,etm0700g0bdh6";
+ status = "okay";
+};
+
+&i2c2 {
+ status = "okay";
+};
+
+&hdmi {
+ ddc-i2c-bus = <&i2c2>;
+ status = "okay";
+};
+
+&usbh1 {
+ status = "okay";
+};
+
+&usbotg {
+ status = "okay";
+};
+
+&pcie {
+ status = "okay";
+};
+
+&usdhc1 {
+ status = "okay";
+};
+
+&can1 {
+ status = "okay";
+};
+
+&can2 {
+ status = "okay";
+};
+
+&uart2 {
+ status = "okay";
+ uart-has-rtscts;
+};
+
+&uart3 {
+ status = "okay";
+};
+
+&uart4 {
+ status = "okay";
+};
+
+&uart5 {
+ status = "okay";
+};
+
+&ecspi2 {
+ status = "okay";
+};
diff --git a/arch/arm/boot/dts/imx6dl-emcon.dtsi b/arch/arm/boot/dts/imx6dl-emcon.dtsi
new file mode 100644
index 000000000000..47f43bae5ac5
--- /dev/null
+++ b/arch/arm/boot/dts/imx6dl-emcon.dtsi
@@ -0,0 +1,37 @@
+/*
+ * Copyright (C) 2017 emtrion GmbH
+ * Author: Jan Tuerk <jan.tuerk@emtrion.com>
+ *
+ * The code contained herein is licensed under the GNU General Public
+ * License. You may obtain a copy of the GNU General Public License
+ * Version 2 or later at the following locations:
+ *
+ * http://www.opensource.org/licenses/gpl-license.html
+ * http://www.gnu.org/copyleft/gpl.html
+ *
+ * SPDX-License-Identifier: GPL-2.0
+ *
+ */
+
+/ {
+ model = "emtrion SoM emCON-MX6 Solo/DualLite";
+ compatible = "emtrion,emcon-mx6","fsl,imx6dl";
+};
+
+&iomuxc {
+ pinctrl_cpi2: csi1grp {
+ fsl,pins = <
+ MX6QDL_PAD_EIM_D17__IPU1_CSI1_PIXCLK 0x0b0b1
+ MX6QDL_PAD_EIM_EB3__IPU1_CSI1_HSYNC 0x1b0b1
+ MX6QDL_PAD_EIM_D29__IPU1_CSI1_VSYNC 0x1b0b1
+ MX6QDL_PAD_EIM_A17__IPU1_CSI1_DATA12 0x1b0b1
+ MX6QDL_PAD_EIM_D27__IPU1_CSI1_DATA13 0x1b0b1
+ MX6QDL_PAD_EIM_D26__IPU1_CSI1_DATA14 0x1b0b1
+ MX6QDL_PAD_EIM_D20__IPU1_CSI1_DATA15 0x1b0b1
+ MX6QDL_PAD_EIM_D19__IPU1_CSI1_DATA16 0x1b0b1
+ MX6QDL_PAD_EIM_D18__IPU1_CSI1_DATA17 0x1b0b1
+ MX6QDL_PAD_EIM_D16__IPU1_CSI1_DATA18 0x1b0b1
+ MX6QDL_PAD_EIM_EB2__IPU1_CSI1_DATA19 0x1b0b1
+ >;
+ };
+};
diff --git a/arch/arm/boot/dts/imx6q-emcon-avari.dts b/arch/arm/boot/dts/imx6q-emcon-avari.dts
new file mode 100644
index 000000000000..bccfd6344c18
--- /dev/null
+++ b/arch/arm/boot/dts/imx6q-emcon-avari.dts
@@ -0,0 +1,233 @@
+/*
+ * Copyright (C) 2017 emtrion GmbH
+ * Author: Jan Tuerk <jan.tuerk@emtrion.com>
+ *
+ * The code contained herein is licensed under the GNU General Public
+ * License. You may obtain a copy of the GNU General Public License
+ * Version 2 or later at the following locations:
+ *
+ * http://www.opensource.org/licenses/gpl-license.html
+ * http://www.gnu.org/copyleft/gpl.html
+ *
+ * SPDX-License-Identifier: GPL-2.0
+ *
+ */
+
+/dts-v1/;
+#include "imx6q.dtsi"
+#include "imx6qdl-emcon.dtsi"
+#include "imx6q-emcon.dtsi" /*Include camera2 pinmux*/
+
+/ {
+ model = "emtrion SoM emCON-MX6 Dual/Quad on Avari";
+ compatible = "emtrion,emcon-mx6-avari", "fsl,imx6q";
+
+ aliases {
+ mmc0 = &usdhc3;
+ mmc2 = &usdhc1;
+ mmc1 = &usdhc2;
+ mmc3 = &usdhc4;
+ };
+
+ chosen {
+ stdout-path = <&uart1>;
+ };
+
+ memory {
+ reg = <0x10000000 0x40000000>;
+ };
+
+ supplies {
+ compatible = "simple-bus";
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ wallplug5p0: supply@0 {
+ compatible = "regulator-fixed";
+ reg = <0>;
+ regulator-name = "WALL-PLUG";
+ regulator-min-microvolt = <5000000>;
+ regulator-max-microvolt = <5000000>;
+ regulator-always-on;
+ regulator-boot-on;
+ };
+
+ base3p3: supply@1 {
+ compatible = "regulator-fixed";
+ reg = <1>;
+ vin-supply = <&wallplug5p0>;
+ regulator-name = "3V3-avari";
+ regulator-min-microvolt = <3300000>;
+ regulator-max-microvolt = <3300000>;
+ regulator-always-on;
+ regulator-boot-on;
+ };
+
+ base1p5: supply@2 {
+ compatible = "regulator-fixed";
+ reg = <2>;
+ vin-supply = <&base3p3>;
+ regulator-name = "1V5-avari";
+ regulator-min-microvolt = <1500000>;
+ regulator-max-microvolt = <1500000>;
+ regulator-always-on;
+ regulator-boot-on;
+ };
+
+ reg_usb_otg: otgvbus {
+ compatible = "regulator-fixed";
+ reg = <3>;
+ vin-supply = <&wallplug5p0>;
+ regulator-name = "OTG_VBUS";
+ regulator-min-microvolt = <5000000>;
+ regulator-max-microvolt = <5000000>;
+ gpio = <&gpio1 8 GPIO_ACTIVE_LOW>;
+ regulator-always-on;
+ };
+
+ };
+
+
+ sndosc: 12MHZosc {
+ compatible = "fixed-clock";
+ #clock-cells = <0>;
+ clock-frequency = <12000000>;
+ };
+
+ sound {
+ compatible = "fsl,imx-audio-sgtl5000";
+ model = "emCON-avari-sgtl5000";
+ ssi-controller = <&ssi2>;
+ audio-codec = <&sgtl5000>;
+ audio-routing =
+ "Headphone Jack", "HP_OUT";
+ mux-int-port = <2>;
+ mux-ext-port = <3>;
+ };
+
+};
+
+
+&iomuxc {
+ pinctrl-names = "default";
+ /*Unused emCON-MX6 pingroups on AVARI baseboard, enable defaults*/
+ pinctrl-0 = <
+ &pinctrl_emcon_gpio1 &pinctrl_emcon_gpio2
+ &pinctrl_emcon_gpio3 &pinctrl_emcon_gpio5
+ &pinctrl_emcon_gpio6 &pinctrl_emcon_gpio7
+ &pinctrl_emcon_gpio8 &pinctrl_emcon_irq_a
+ &pinctrl_emcon_irq_b &pinctrl_emcon_irq_c
+ &pinctrl_emcon_irq_pwr &pinctrl_nor_flash
+ &pinctrl_usdhc2
+ &pinctrl_spdif_out &pinctrl_spdif_in
+ &pinctrl_cpi1 &pinctrl_cpi2
+ >;
+};
+
+&audmux {
+ pinctrl-names = "default";
+ pinctrl-0 = <&pinctrl_audmux>;
+ status = "okay";
+};
+
+
+
+&i2c3 {
+ clock-frequency = <100000>;
+ pinctrl-names = "default";
+ pinctrl-0 = <&pinctrl_i2c3>;
+ status = "okay";
+
+ sgtl5000: sgtl5000@0a {
+ compatible = "fsl,sgtl5000";
+ reg = <0x0a>;
+ clocks = <&sndosc>;
+ VDDA-supply = <&base3p3>;
+ VDDIO-supply = <&base3p3>;
+ };
+
+ boardID: pca8754a@3A {
+ compatible = "nxp,pca8574";
+ reg = <0x3A>;
+ gpio-controller;
+ #gpio-cells = <1>;
+ };
+
+ captouch: edt-ft5x06@38 {
+ reg = <0x38>;
+ pinctrl-names = "default";
+ pinctrl-0 = <&pinctrl_irq_touch2 &pinctrl_emcon_gpio4>;
+ interrupt-parent = <&gpio6>;
+ interrupts = <31 IRQ_TYPE_EDGE_FALLING>;
+ compatible = "edt,edt-ft5406";
+ wake-gpios = <&gpio2 3 GPIO_ACTIVE_HIGH>;
+ wakeup-source;
+ };
+};
+
+&ssi2 {
+ status = "okay";
+};
+
+&rgb_encoder {
+ status = "okay";
+};
+
+&rgb_panel {
+ compatible = "edt,etm0700g0bdh6";
+ status = "okay";
+};
+
+&i2c2 {
+ status = "okay";
+};
+
+&hdmi {
+ ddc-i2c-bus = <&i2c2>;
+ status = "okay";
+};
+
+&usbh1 {
+ status = "okay";
+};
+
+&usbotg {
+ status = "okay";
+};
+
+&pcie {
+ status = "okay";
+};
+
+&usdhc1 {
+ status = "okay";
+};
+
+&can1 {
+ status = "okay";
+};
+
+&can2 {
+ status = "okay";
+};
+
+&uart2 {
+ status = "okay";
+ uart-has-rtscts;
+};
+
+&uart3 {
+ status = "okay";
+};
+
+&uart4 {
+ status = "okay";
+};
+
+&uart5 {
+ status = "okay";
+};
+
+&ecspi2 {
+ status = "okay";
+};
diff --git a/arch/arm/boot/dts/imx6q-emcon.dtsi b/arch/arm/boot/dts/imx6q-emcon.dtsi
new file mode 100644
index 000000000000..64fc0cd74c05
--- /dev/null
+++ b/arch/arm/boot/dts/imx6q-emcon.dtsi
@@ -0,0 +1,37 @@
+/*
+ * Copyright (C) 2017 emtrion GmbH
+ * Author: Jan Tuerk <jan.tuerk@emtrion.com>
+ *
+ * The code contained herein is licensed under the GNU General Public
+ * License. You may obtain a copy of the GNU General Public License
+ * Version 2 or later at the following locations:
+ *
+ * http://www.opensource.org/licenses/gpl-license.html
+ * http://www.gnu.org/copyleft/gpl.html
+ *
+ * SPDX-License-Identifier: GPL-2.0
+ *
+ */
+
+/ {
+ model = "emtrion SoM emCON-MX6 Dual/Quad";
+ compatible = "emtrion,emcon-mx6","fsl,imx6q";
+};
+
+&iomuxc {
+ pinctrl_cpi2: csi1grp {
+ fsl,pins = <
+ MX6QDL_PAD_EIM_D17__IPU2_CSI1_PIXCLK 0x0b0b1
+ MX6QDL_PAD_EIM_EB3__IPU2_CSI1_HSYNC 0x1b0b1
+ MX6QDL_PAD_EIM_D29__IPU2_CSI1_VSYNC 0x1b0b1
+ MX6QDL_PAD_EIM_A17__IPU2_CSI1_DATA12 0x1b0b1
+ MX6QDL_PAD_EIM_D27__IPU2_CSI1_DATA13 0x1b0b1
+ MX6QDL_PAD_EIM_D26__IPU2_CSI1_DATA14 0x1b0b1
+ MX6QDL_PAD_EIM_D20__IPU2_CSI1_DATA15 0x1b0b1
+ MX6QDL_PAD_EIM_D19__IPU2_CSI1_DATA16 0x1b0b1
+ MX6QDL_PAD_EIM_D18__IPU2_CSI1_DATA17 0x1b0b1
+ MX6QDL_PAD_EIM_D16__IPU2_CSI1_DATA18 0x1b0b1
+ MX6QDL_PAD_EIM_EB2__IPU2_CSI1_DATA19 0x1b0b1
+ >;
+ };
+};
diff --git a/arch/arm/boot/dts/imx6qdl-emcon.dtsi b/arch/arm/boot/dts/imx6qdl-emcon.dtsi
new file mode 100644
index 000000000000..22ad05880ea7
--- /dev/null
+++ b/arch/arm/boot/dts/imx6qdl-emcon.dtsi
@@ -0,0 +1,849 @@
+/*
+ * Copyright (C) 2017 emtrion GmbH
+ * Author: Jan Tuerk <jan.tuerk@emtrion.com>
+ *
+ * The code contained herein is licensed under the GNU General Public
+ * License. You may obtain a copy of the GNU General Public License
+ * Version 2 or later at the following locations:
+ *
+ * http://www.opensource.org/licenses/gpl-license.html
+ * http://www.gnu.org/copyleft/gpl.html
+ *
+ * SPDX-License-Identifier: GPL-2.0
+ *
+ */
+
+#include <dt-bindings/gpio/gpio.h>
+#include <dt-bindings/pwm/pwm.h>
+#include <dt-bindings/input/input.h>
+
+/ {
+
+ model = "emtrion SoM emCON-MX6";
+ compatible = "emtrion,emcon-mx6","fsl,imx6q", "fsl,imx6dl";
+
+ aliases {
+ mmc0 = &usdhc3;
+ mmc2 = &usdhc1;
+ mmc1 = &usdhc2;
+ };
+
+ regulators {
+ compatible = "simple-bus";
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ reg_parallel_disp: regulator@0 {
+ compatible = "regulator-fixed";
+ reg = <0>;
+ pinctrl-names = "default";
+ pinctrl-0 = <&pinctrl_rgb_bl_en>;
+ regulator-name = "LCD-Supply";
+ regulator-min-microvolt = <5000000>;
+ regulator-max-microvolt = <5000000>;
+ gpio = <&gpio7 9 GPIO_ACTIVE_HIGH>;
+ enable-active-high;
+ };
+
+ reg_lvds_disp: regulator@1 {
+ compatible = "regulator-fixed";
+ reg = <1>;
+ regulator-name = "LVDS-Supply";
+ regulator-min-microvolt = <5000000>;
+ regulator-max-microvolt = <5000000>;
+ gpio = <&gpio7 10 GPIO_ACTIVE_HIGH>;
+ enable-active-high;
+ };
+ };
+
+ som_leds: leds {
+ compatible = "gpio-leds";
+ pinctrl-names = "default";
+ pinctrl-0 = <&pinctrl_som_leds>;
+
+ green {
+ label = "som:green";
+ gpios = <&gpio3 0 GPIO_ACTIVE_HIGH>;
+ linux,default-trigger = "heartbeat";
+ default-state = "on";
+ };
+
+ red {
+ label = "som:red";
+ gpios = <&gpio3 1 GPIO_ACTIVE_LOW>;
+ default-state = "keep";
+ };
+
+ };
+
+ gpio-keys {
+ compatible = "gpio-keys";
+ pinctrl-names = "default";
+ pinctrl-0 = <&pinctrl_emcon_wake>;
+
+ wake {
+ label = "Wake";
+ linux,code = <KEY_WAKEUP>;
+ gpios = <&gpio3 2 GPIO_ACTIVE_LOW>;
+ wakeup-source;
+ };
+ };
+
+ pwm_fan: pwm-fan {
+ compatible = "pwm-fan";
+ cooling-min-state = <0>;
+ cooling-max-state = <4>;
+ #cooling-cells = <2>;
+ pwms = <&pwm4 0 50000>;
+ cooling-levels = <0 64 127 191 255>;
+ status = "disabled";
+ };
+
+ rgb_encoder: lcd@di0 {
+ compatible = "fsl,imx-parallel-display";
+ #address-cells = <1>;
+ #size-cells = <0>;
+ pinctrl-names = "default";
+ pinctrl-0 = <&pinctrl_rgb24_display>;
+ status = "disabled";
+
+ port@0 {
+ reg = <0>;
+ rgb_encoder_in: endpoint {
+ remote-endpoint = <&ipu1_di0_disp0>;
+ };
+ };
+
+ port@1 {
+ reg = <1>;
+ rgb_encoder_out: endpoint {
+ remote-endpoint = <&rgb_panel_in>;
+ };
+ };
+ };
+
+ rgb_panel: panel {
+ backlight = <&rgb_backlight>;
+ power-supply = <®_prallel_disp>;
+ port {
+ rgb_panel_in: endpoint {
+ remote-endpoint = <&rgb_encoder_out>;
+ };
+ };
+ };
+
+ rgb_backlight: rgb_backlight {
+ compatible = "pwm-backlight";
+ pinctrl-names = "default";
+ pinctrl-0 = <&pinctrl_rgb_bl>;
+ enable-gpios = <&gpio6 8 GPIO_ACTIVE_HIGH>;
+ pwms = <&pwm3 0 5000000>;
+ brightness-levels = <250 176 160 144 128 112
+ 96 80 64 48 32 16 8 1
+ >;
+ default-brightness-level = <13>;
+ status = "okay";
+ };
+
+ lvds_backlight: lvds_backlight {
+ compatible = "pwm-backlight";
+ pinctrl-names = "default";
+ pinctrl-0 = <&pinctrl_lvds_bl>;
+ enable-gpios = <&gpio6 9 GPIO_ACTIVE_HIGH>;
+ pwms = <&pwm1 0 50000>;
+ brightness-levels = <0 4 8 16 32 64 80 96 112
+ 128 144 160 176 250
+ >;
+ default-brightness-level = <13>;
+ status = "okay";
+ };
+};
+
+
+&iomuxc {
+
+ pinctrl_secure: securegrp {
+ fsl,pins = <
+ MX6QDL_PAD_GPIO_18__GPIO7_IO13 0x1b0b1
+ >;
+ };
+
+ pinctrl_uart1: uart1grp {
+ fsl,pins = <
+ MX6QDL_PAD_CSI0_DAT10__UART1_TX_DATA 0x1b0b1
+ MX6QDL_PAD_CSI0_DAT11__UART1_RX_DATA 0x1b0b1
+ >;
+ };
+
+ pinctrl_uart2: uart2grp {
+ fsl,pins = <
+ MX6QDL_PAD_SD4_DAT5__UART2_RTS_B 0x1b0b1
+ MX6QDL_PAD_SD4_DAT6__UART2_CTS_B 0x1b0b1
+ MX6QDL_PAD_SD4_DAT7__UART2_TX_DATA 0x1b0b1
+ MX6QDL_PAD_SD4_DAT4__UART2_RX_DATA 0x1b0b1
+ >;
+ };
+
+ pinctrl_uart3: uart3grp {
+ fsl,pins = <
+ MX6QDL_PAD_EIM_D24__UART3_TX_DATA 0x1b0b1
+ MX6QDL_PAD_EIM_D25__UART3_RX_DATA 0x1b0b1
+ >;
+ };
+
+ pinctrl_uart4: uart4grp {
+ fsl,pins = <
+ MX6QDL_PAD_KEY_COL0__UART4_TX_DATA 0x1b0b1
+ MX6QDL_PAD_KEY_ROW0__UART4_RX_DATA 0x1b0b1
+ >;
+ };
+
+ pinctrl_uart5: uart5grp {
+ fsl,pins = <
+ MX6QDL_PAD_KEY_COL1__UART5_TX_DATA 0x1b0b1
+ MX6QDL_PAD_KEY_ROW1__UART5_RX_DATA 0x1b0b1
+ >;
+ };
+
+ pinctrl_emcon_gpio1: emcongpio1 {
+ fsl,pins = <
+ MX6QDL_PAD_NANDF_D0__GPIO2_IO00 0x0b0b1
+ >;
+ };
+
+ pinctrl_emcon_gpio2: emcongpio2 {
+ fsl,pins = <
+ MX6QDL_PAD_NANDF_D1__GPIO2_IO01 0x0b0b1
+ >;
+ };
+
+ pinctrl_emcon_gpio3: emcongpio3 {
+ fsl,pins = <
+ MX6QDL_PAD_NANDF_D2__GPIO2_IO02 0x0b0b1
+ >;
+ };
+
+ pinctrl_emcon_gpio4: emcongpio4 {
+ fsl,pins = <
+ MX6QDL_PAD_NANDF_D3__GPIO2_IO03 0x0b0b1
+ >;
+ };
+
+ pinctrl_emcon_gpio5: emcongpio5 {
+ fsl,pins = <
+ MX6QDL_PAD_NANDF_D4__GPIO2_IO04 0x0b0b1
+ >;
+ };
+
+ pinctrl_emcon_gpio6: emcongpio6 {
+ fsl,pins = <
+ MX6QDL_PAD_NANDF_D5__GPIO2_IO05 0x0b0b1
+ >;
+ };
+
+ pinctrl_emcon_gpio7: emcongpio7 {
+ fsl,pins = <
+ MX6QDL_PAD_NANDF_D6__GPIO2_IO06 0x0b0b1
+ >;
+ };
+
+ pinctrl_emcon_gpio8: emcongpio8 {
+ fsl,pins = <
+ MX6QDL_PAD_NANDF_D7__GPIO2_IO07 0x0b0b1
+ >;
+ };
+
+ pinctrl_emcon_irq_a: emconirqa {
+ fsl,pins = <
+ MX6QDL_PAD_NANDF_CLE__GPIO6_IO07 0x0b0b1
+ >;
+ };
+
+ pinctrl_emcon_irq_b: emconirqb {
+ fsl,pins = <
+ MX6QDL_PAD_NANDF_CS2__GPIO6_IO15 0x0b0b1
+ >;
+ };
+
+ pinctrl_emcon_irq_c: emconirqc {
+ fsl,pins = <
+ MX6QDL_PAD_NANDF_CS3__GPIO6_IO16 0x0b0b1
+ >;
+ };
+
+ pinctrl_emcon_wake: emconwake {
+ fsl,pins = <
+ MX6QDL_PAD_EIM_DA2__GPIO3_IO02 0x1b0b1
+ >;
+ };
+
+ pinctrl_emcon_irq_pwr: emconirqpwr {
+ fsl,pins = <
+ MX6QDL_PAD_EIM_D23__GPIO3_IO23 0x0b0b1
+ >;
+ };
+
+ pinctrl_som_leds: somledgrp {
+ fsl,pins = <
+ MX6QDL_PAD_EIM_DA0__GPIO3_IO00 0x0b0b1
+ MX6QDL_PAD_EIM_DA1__GPIO3_IO01 0x0b0b1
+ >;
+ };
+
+ pinctrl_nor_flash: norflashgrp {
+ fsl,pins = <
+ MX6QDL_PAD_NANDF_CS0__GPIO6_IO11 0x1b0b1
+ MX6QDL_PAD_EIM_D21__ECSPI4_SCLK 0x100b1
+ MX6QDL_PAD_EIM_D28__ECSPI4_MOSI 0x100b1
+ MX6QDL_PAD_EIM_D22__ECSPI4_MISO 0x100b1
+ MX6QDL_PAD_EIM_A25__GPIO5_IO02 0x100b1
+ >;
+ };
+
+ pinctrl_ecspi2: ecspi2grp {
+ fsl,pins = <
+ MX6QDL_PAD_EIM_CS0__ECSPI2_SCLK 0x100b1
+ MX6QDL_PAD_EIM_CS1__ECSPI2_MOSI 0x100b1
+ MX6QDL_PAD_EIM_OE__ECSPI2_MISO 0x100b1
+ MX6QDL_PAD_EIM_LBA__GPIO2_IO27 0x100b1
+ MX6QDL_PAD_EIM_RW__GPIO2_IO26 0x100b1
+ >;
+ };
+
+ pinctrl_pwm_fan: pwmfan {
+ fsl,pins = <
+ MX6QDL_PAD_SD4_DAT2__PWM4_OUT 0x0b0b1
+ >;
+ };
+
+ pinctrl_can1: can1grp {
+ fsl,pins = <
+ MX6QDL_PAD_KEY_COL2__FLEXCAN1_TX 0x1b0b1
+ MX6QDL_PAD_KEY_ROW2__FLEXCAN1_RX 0x1b0b1
+ >;
+ };
+
+ pinctrl_can2: can2grp {
+ fsl,pins = <
+ MX6QDL_PAD_KEY_COL4__FLEXCAN2_TX 0x1b0b1
+ MX6QDL_PAD_KEY_ROW4__FLEXCAN2_RX 0x1b0b1
+ >;
+ };
+
+ pinctrl_spdif_out: spdifout {
+ fsl,pins = <
+ MX6QDL_PAD_GPIO_19__SPDIF_OUT 0x13091
+ >;
+ };
+
+ pinctrl_spdif_in: spdifin {
+ fsl,pins = <
+ MX6QDL_PAD_GPIO_16__SPDIF_IN 0x1b0b0
+ >;
+ };
+
+ pinctrl_cpi1: csi0grp {
+ fsl,pins = <
+ MX6QDL_PAD_CSI0_PIXCLK__IPU1_CSI0_PIXCLK 0xb0b1
+ MX6QDL_PAD_CSI0_MCLK__IPU1_CSI0_HSYNC 0x1b0b1
+ MX6QDL_PAD_CSI0_VSYNC__IPU1_CSI0_VSYNC 0x1b0b1
+ MX6QDL_PAD_CSI0_DAT12__IPU1_CSI0_DATA12 0x1b0b1
+ MX6QDL_PAD_CSI0_DAT13__IPU1_CSI0_DATA13 0x1b0b1
+ MX6QDL_PAD_CSI0_DAT14__IPU1_CSI0_DATA14 0x1b0b1
+ MX6QDL_PAD_CSI0_DAT15__IPU1_CSI0_DATA15 0x1b0b1
+ MX6QDL_PAD_CSI0_DAT16__IPU1_CSI0_DATA16 0x1b0b1
+ MX6QDL_PAD_CSI0_DAT17__IPU1_CSI0_DATA17 0x1b0b1
+ MX6QDL_PAD_CSI0_DAT18__IPU1_CSI0_DATA18 0x1b0b1
+ MX6QDL_PAD_CSI0_DAT19__IPU1_CSI0_DATA19 0x1b0b1
+ >;
+ };
+
+ /*camera2-pinctrl is in imx6q-emcon.dtsi or imx6dl-emcon.dtsi*/
+
+ pinctrl_pcie_ctrl: pciegrp {
+ fsl,pins = <
+ MX6QDL_PAD_EIM_A16__GPIO2_IO22 0x1b0b1
+ MX6QDL_PAD_GPIO_17__GPIO7_IO12 0x1b0b1
+ >;
+ };
+
+ pinctrl_audmux: audmux {
+ fsl,pins = <
+ MX6QDL_PAD_CSI0_DAT7__AUD3_RXD 0x130b0
+ MX6QDL_PAD_CSI0_DAT4__AUD3_TXC 0x1b060
+ MX6QDL_PAD_CSI0_DAT5__AUD3_TXD 0x130B0
+ MX6QDL_PAD_CSI0_DAT6__AUD3_TXFS 0x1b060
+ >;
+ };
+
+ pinctrl_i2c1: i2c1grp {
+ fsl,pins = <
+ MX6QDL_PAD_CSI0_DAT8__I2C1_SDA 0x4001b8b1
+ MX6QDL_PAD_CSI0_DAT9__I2C1_SCL 0x4001b8b1
+ >;
+ };
+
+ pinctrl_i2c2: i2c2grp {
+ fsl,pins = <
+ MX6QDL_PAD_KEY_COL3__I2C2_SCL 0x4001b8b1
+ MX6QDL_PAD_KEY_ROW3__I2C2_SDA 0x4001b8b1
+ >;
+ };
+
+ pinctrl_i2c3: i2c3grp {
+ fsl,pins = <
+ MX6QDL_PAD_GPIO_3__I2C3_SCL 0x4000b070
+ MX6QDL_PAD_GPIO_6__I2C3_SDA 0x4001b870
+ >;
+ };
+
+ pinctrl_pmic: pmicgrp {
+ fsl,pins = <
+ MX6QDL_PAD_SD4_DAT0__GPIO2_IO08 0x0b0b1
+ >;
+ };
+
+ pinctrl_usb_host1: usbhgrp {
+ fsl,pins = <
+ MX6QDL_PAD_EIM_D31__USB_H1_PWR 0x1B058
+ MX6QDL_PAD_EIM_D30__USB_H1_OC 0x1B058
+ >;
+ };
+
+ pinctrl_usb_otg: usbotggrp {
+ fsl,pins = <
+ MX6QDL_PAD_ENET_RX_ER__USB_OTG_ID 0x17059
+ MX6QDL_PAD_GPIO_7__GPIO1_IO07 0x17059
+ MX6QDL_PAD_GPIO_8__GPIO1_IO08 0x17059
+ >;
+ };
+
+ pinctrl_lvds_reg: lvdsreggrp {
+ fsl,pins = <
+ MX6QDL_PAD_SD4_CLK__GPIO7_IO10 0x0b0b1
+ >;
+ };
+
+ pinctrl_lvds_bl: lvdsbacklightgrp {
+ fsl,pins = <
+ MX6QDL_PAD_GPIO_9__PWM1_OUT 0x0b0b1
+ MX6QDL_PAD_NANDF_WP_B__GPIO6_IO09 0x0b0b1
+ >;
+ };
+
+ pinctrl_irq_touch1: irqtouch1 {
+ fsl,pins = <
+ MX6QDL_PAD_GPIO_5__GPIO1_IO05 0x0b0b1
+ >;
+ };
+
+ pinctrl_rgb_bl_en: rgbenable {
+ fsl,pins = <
+ MX6QDL_PAD_SD4_CMD__GPIO7_IO09 0x0b0b1
+ >;
+ };
+
+ pinctrl_irq_touch2: irqtouch2 {
+ fsl,pins = <
+ MX6QDL_PAD_EIM_BCLK__GPIO6_IO31 0x0b0b1
+ >;
+ };
+
+ pinctrl_rgb_bl: rgbbacklightgrp {
+ fsl,pins = <
+ MX6QDL_PAD_SD4_DAT1__PWM3_OUT 0x0b0b1
+ MX6QDL_PAD_NANDF_ALE__GPIO6_IO08 0x0b0b1
+ >;
+ };
+
+ pinctrl_rgb24_display: rgbgrp {
+ fsl,pins = <
+ MX6QDL_PAD_DI0_DISP_CLK__IPU1_DI0_DISP_CLK 0x10
+ MX6QDL_PAD_DI0_PIN15__IPU1_DI0_PIN15 0x10
+ MX6QDL_PAD_DI0_PIN2__IPU1_DI0_PIN02 0x10
+ MX6QDL_PAD_DI0_PIN3__IPU1_DI0_PIN03 0x10
+ MX6QDL_PAD_DISP0_DAT0__IPU1_DISP0_DATA00 0x10
+ MX6QDL_PAD_DISP0_DAT1__IPU1_DISP0_DATA01 0x10
+ MX6QDL_PAD_DISP0_DAT2__IPU1_DISP0_DATA02 0x10
+ MX6QDL_PAD_DISP0_DAT3__IPU1_DISP0_DATA03 0x10
+ MX6QDL_PAD_DISP0_DAT4__IPU1_DISP0_DATA04 0x10
+ MX6QDL_PAD_DISP0_DAT5__IPU1_DISP0_DATA05 0x10
+ MX6QDL_PAD_DISP0_DAT6__IPU1_DISP0_DATA06 0x10
+ MX6QDL_PAD_DISP0_DAT7__IPU1_DISP0_DATA07 0x10
+ MX6QDL_PAD_DISP0_DAT8__IPU1_DISP0_DATA08 0x10
+ MX6QDL_PAD_DISP0_DAT9__IPU1_DISP0_DATA09 0x10
+ MX6QDL_PAD_DISP0_DAT10__IPU1_DISP0_DATA10 0x10
+ MX6QDL_PAD_DISP0_DAT11__IPU1_DISP0_DATA11 0x10
+ MX6QDL_PAD_DISP0_DAT12__IPU1_DISP0_DATA12 0x10
+ MX6QDL_PAD_DISP0_DAT13__IPU1_DISP0_DATA13 0x10
+ MX6QDL_PAD_DISP0_DAT14__IPU1_DISP0_DATA14 0x10
+ MX6QDL_PAD_DISP0_DAT15__IPU1_DISP0_DATA15 0x10
+ MX6QDL_PAD_DISP0_DAT16__IPU1_DISP0_DATA16 0x10
+ MX6QDL_PAD_DISP0_DAT17__IPU1_DISP0_DATA17 0x10
+ MX6QDL_PAD_DISP0_DAT18__IPU1_DISP0_DATA18 0x10
+ MX6QDL_PAD_DISP0_DAT19__IPU1_DISP0_DATA19 0x10
+ MX6QDL_PAD_DISP0_DAT20__IPU1_DISP0_DATA20 0x10
+ MX6QDL_PAD_DISP0_DAT21__IPU1_DISP0_DATA21 0x10
+ MX6QDL_PAD_DISP0_DAT22__IPU1_DISP0_DATA22 0x10
+ MX6QDL_PAD_DISP0_DAT23__IPU1_DISP0_DATA23 0x10
+ >;
+ };
+
+ pinctrl_enet: enetgrp {
+ fsl,pins = <
+ MX6QDL_PAD_ENET_MDIO__ENET_MDIO 0x1b030
+ MX6QDL_PAD_ENET_MDC__ENET_MDC 0x1b030
+ MX6QDL_PAD_RGMII_TXC__RGMII_TXC 0x1b030
+ MX6QDL_PAD_RGMII_TD0__RGMII_TD0 0x1b030
+ MX6QDL_PAD_RGMII_TD1__RGMII_TD1 0x1b030
+ MX6QDL_PAD_RGMII_TD2__RGMII_TD2 0x1b030
+ MX6QDL_PAD_RGMII_TD3__RGMII_TD3 0x1b030
+ MX6QDL_PAD_RGMII_TX_CTL__RGMII_TX_CTL 0x1b030
+ MX6QDL_PAD_ENET_REF_CLK__ENET_TX_CLK 0x4001a0b1
+ MX6QDL_PAD_RGMII_RXC__RGMII_RXC 0x1b030
+ MX6QDL_PAD_RGMII_RD0__RGMII_RD0 0x1b030
+ MX6QDL_PAD_RGMII_RD1__RGMII_RD1 0x1b030
+ MX6QDL_PAD_RGMII_RD2__RGMII_RD2 0x1b030
+ MX6QDL_PAD_RGMII_RD3__RGMII_RD3 0x1b030
+ MX6QDL_PAD_RGMII_RX_CTL__RGMII_RX_CTL 0x1b0b0
+ MX6QDL_PAD_CSI0_DATA_EN__GPIO5_IO20 0x1b058
+ MX6QDL_PAD_ENET_TXD0__GPIO1_IO30 0x1b0b0
+ >;
+ };
+
+
+ pinctrl_usdhc3: usdhc3grp {
+ fsl,pins = <
+ MX6QDL_PAD_SD3_CMD__SD3_CMD 0x17059
+ MX6QDL_PAD_SD3_CLK__SD3_CLK 0x10059
+ MX6QDL_PAD_SD3_DAT0__SD3_DATA0 0x17059
+ MX6QDL_PAD_SD3_DAT1__SD3_DATA1 0x17059
+ MX6QDL_PAD_SD3_DAT2__SD3_DATA2 0x17059
+ MX6QDL_PAD_SD3_DAT3__SD3_DATA3 0x17059
+ MX6QDL_PAD_SD3_DAT4__SD3_DATA4 0x17059
+ MX6QDL_PAD_SD3_DAT5__SD3_DATA5 0x17059
+ MX6QDL_PAD_SD3_DAT6__SD3_DATA6 0x17059
+ MX6QDL_PAD_SD3_DAT7__SD3_DATA7 0x17059
+ MX6QDL_PAD_SD3_RST__SD3_RESET 0x1b0b1
+ >;
+ };
+
+ pinctrl_usdhc1: usdhc1grp {
+ fsl,pins = <
+ MX6QDL_PAD_SD1_CMD__SD1_CMD 0x17059
+ MX6QDL_PAD_SD1_CLK__SD1_CLK 0x10059
+ MX6QDL_PAD_SD1_DAT0__SD1_DATA0 0x17059
+ MX6QDL_PAD_SD1_DAT1__SD1_DATA1 0x17059
+ MX6QDL_PAD_SD1_DAT2__SD1_DATA2 0x17059
+ MX6QDL_PAD_SD1_DAT3__SD1_DATA3 0x17059
+ MX6QDL_PAD_GPIO_1__SD1_CD_B 0x1b0b1
+ MX6QDL_PAD_DI0_PIN4__SD1_WP 0x1b0b1
+ >;
+ };
+
+ pinctrl_usdhc2: usdhc2grp {
+ fsl,pins = <
+ MX6QDL_PAD_SD2_CMD__SD2_CMD 0x17059
+ MX6QDL_PAD_SD2_CLK__SD2_CLK 0x10059
+ MX6QDL_PAD_SD2_DAT0__SD2_DATA0 0x17059
+ MX6QDL_PAD_SD2_DAT1__SD2_DATA1 0x17059
+ MX6QDL_PAD_SD2_DAT2__SD2_DATA2 0x17059
+ MX6QDL_PAD_SD2_DAT3__SD2_DATA3 0x17059
+ MX6QDL_PAD_GPIO_4__SD2_CD_B 0x1b0b1
+ MX6QDL_PAD_GPIO_2__SD2_WP 0x1b0b1
+ >;
+ };
+
+};
+
+
+&i2c1 {
+ clock-frequency = <100000>;
+ pinctrl-names = "default";
+ pinctrl-0 = <&pinctrl_i2c1>;
+ status = "okay";
+
+ rtc: rtc@68 {
+ compatible = "dallas,ds1307";
+ reg = <0x68>;
+ };
+
+ da9063: da9063@58 {
+ compatible = "dlg,da9063";
+ reg = <0x58>;
+ pinctrl-names = "default";
+ pinctrl-0 = <&pinctrl_pmic>;
+ interrupt-parent = <&gpio2>;
+ interrupts = <8 IRQ_TYPE_LEVEL_LOW>;
+ interrupt-controller;
+
+ onkey {
+ wakeup-source;
+ compatible = "dlg,da9063-onkey";
+ };
+
+ wdt {
+ compatible = "dlg,da9063-watchdog";
+ timeout-sec = <0>;
+ };
+
+ regulators {
+ vddcore_reg: bcore1 {
+ regulator-min-microvolt = <1100000>;
+ regulator-max-microvolt = <1450000>;
+ regulator-ramp-delay = <20000>;
+ regulator-name = "DA9063_CORE";
+ regulator-always-on;
+ };
+
+ vddsoc_reg: bcore2 {
+ regulator-min-microvolt = <1100000>;
+ regulator-max-microvolt = <1450000>;
+ regulator-ramp-delay = <20000>;
+ regulator-name = "DA9063_SOC";
+ regulator-always-on;
+ };
+
+ vdd_ddr3_reg: bpro {
+ regulator-min-microvolt = <1500000>;
+ regulator-max-microvolt = <1500000>;
+ regulator-ramp-delay = <20000>;
+ regulator-always-on;
+ };
+
+ vdd_3v3_reg: bperi {
+ regulator-min-microvolt = <3300000>;
+ regulator-max-microvolt = <3300000>;
+ regulator-ramp-delay = <20000>;
+ regulator-always-on;
+ };
+
+ vdd_sata_reg: ldo3 {
+ regulator-min-microvolt = <2500000>;
+ regulator-max-microvolt = <2500000>;
+ regulator-always-on;
+ };
+ vdd_mipi_reg: ldo4 {
+ regulator-min-microvolt = <2500000>;
+ regulator-max-microvolt = <2500000>;
+ regulator-always-on;
+ };
+
+ vdd_mx6_snvs_reg: ldo5 {
+ regulator-min-microvolt = <3300000>;
+ regulator-max-microvolt = <3300000>;
+ regulator-always-on;
+ };
+
+ vdd_hdmi_reg: ldo6 {
+ regulator-min-microvolt = <2500000>;
+ regulator-max-microvolt = <2500000>;
+ regulator-always-on;
+ regulator-boot-on;
+ };
+
+ vdd_pcie_reg: ldo7 {
+ regulator-min-microvolt = <2500000>;
+ regulator-max-microvolt = <2500000>;
+ regulator-always-on;
+ };
+
+ vdd_1V8_reg: ldo8 {
+ regulator-min-microvolt = <1800000>;
+ regulator-max-microvolt = <1800000>;
+ regulator-always-on;
+ };
+
+ vdd_3V3_sdc_reg: ldo9 {
+ regulator-min-microvolt = <1800000>;
+ regulator-max-microvolt = <3300000>;
+ regulator-always-on;
+ };
+
+ vdd_1V2_reg: ldo10 {
+ regulator-min-microvolt = <1200000>;
+ regulator-max-microvolt = <1200000>;
+ regulator-always-on;
+ };
+ };
+ };
+};
+
+&uart1 {
+ pinctrl-names = "default";
+ pinctrl-0 = <&pinctrl_uart1>;
+ status = "okay";
+};
+
+&uart2 {
+ pinctrl-names = "default";
+ pinctrl-0 = <&pinctrl_uart2>;
+};
+
+&uart3 {
+ pinctrl-names = "default";
+ pinctrl-0 = <&pinctrl_uart3>;
+};
+
+&uart4 {
+ pinctrl-names = "default";
+ pinctrl-0 = <&pinctrl_uart4>;
+};
+
+&uart5 {
+ pinctrl-names = "default";
+ pinctrl-0 = <&pinctrl_uart5>;
+};
+
+&fec {
+ pinctrl-names = "default";
+ pinctrl-0 = <&pinctrl_enet>;
+ phy-mode = "rgmii";
+ phy-reset-gpios = <&gpio5 20 GPIO_ACTIVE_LOW>;
+ phy-reset-duration = <50>;
+ phy-supply = <&vdd_1V8_reg>;
+ phy-handle = <&ksz9031>;
+ status = "okay";
+
+
+ mdio {
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ ksz9031: phy {
+ reg = <0>;
+ compatible = "ethernet-phy-ieee802.3-c22";
+ interrupt-parent = <&gpio1>;
+ interrupts = <30 IRQ_TYPE_EDGE_FALLING>;
+ rxdv-skew-ps = <480>;
+ txen-skew-ps = <480>;
+ rxd0-skew-ps = <480>;
+ rxd1-skew-ps = <480>;
+ rxd2-skew-ps = <480>;
+ rxd3-skew-ps = <480>;
+ txd0-skew-ps = <420>;
+ txd1-skew-ps = <420>;
+ txd2-skew-ps = <360>;
+ txd3-skew-ps = <360>;
+ txc-skew-ps = <1020>;
+ rxc-skew-ps = <960>;
+ };
+ };
+};
+
+
+&usdhc3 {
+ pinctrl-names = "default";
+ pinctrl-0 = <&pinctrl_usdhc3>;
+ non-removable;
+ bus-width = <8>;
+ status = "okay";
+};
+
+&pcie {
+ pinctrl-names = "default";
+ pinctrl-0 = <&pinctrl_pcie_ctrl>;
+ reset-gpio = <&gpio7 12 GPIO_ACTIVE_LOW>;
+ disable-gpio = <&gpio2 22 GPIO_ACTIVE_LOW>;
+};
+
+&i2c2 {
+ clock-frequency = <100000>;
+ pinctrl-names = "default";
+ pinctrl-0 = <&pinctrl_i2c2>;
+};
+
+&usdhc1 {
+ pinctrl-names = "default";
+ pinctrl-0 = <&pinctrl_usdhc1>;
+ fsl,wp-controller;
+};
+
+&usdhc2 {
+ pinctrl-names = "default";
+ pinctrl-0 = <&pinctrl_usdhc2>;
+ fsl,wp-controller;
+};
+
+
+&ipu1_di0_disp0 {
+ remote-endpoint = <&rgb_encoder_in>;
+};
+
+&pwm1 {
+ status = "okay";
+};
+
+&pwm3 {
+ status = "okay";
+};
+
+&pwm4 {
+ status = "okay";
+};
+
+&ecspi2 {
+ pinctrl-names = "default";
+ pinctrl-0 = <&pinctrl_ecspi2>;
+ cs-gpios = <&gpio2 25 GPIO_ACTIVE_HIGH>,
+ <&gpio2 26 GPIO_ACTIVE_HIGH>;
+};
+
+&ecspi4 {
+ pinctrl-names = "default";
+ pinctrl-0 = <&pinctrl_nor_flash>;
+};
+
+&can1 {
+ pinctrl-names = "default";
+ pinctrl-0 = <&pinctrl_can1>;
+};
+
+&can2 {
+ pinctrl-names = "default";
+ pinctrl-0 = <&pinctrl_can2>;
+};
+
+&usbh1 {
+ pinctrl-names = "default";
+ pinctrl-0 = <&pinctrl_usb_host1>;
+};
+
+&usbotg {
+ pinctrl-names = "default";
+ pinctrl-0 = <&pinctrl_usb_otg>;
+ vbus-supply = <®_usb_otg>;
+ dr_mode = "peripheral";
+};
+
+/******device power Management*********/
+
+&cpu0 {
+ voltage-tolerance = <2>;
+};
+
+®_arm {
+ vin-supply = <&vddcore_reg>;
+};
+
+®_soc {
+ vin-supply = <&vddsoc_reg>;
+};
+
+®_pu {
+ vin-supply = <&vddsoc_reg>;
+};
+
+
+
+/*******Disabled HW following***********/
+
+
+&weim {
+ status = "disabled";
+};
+
+&snvs_rtc {
+ status = "disabled";
+};
+
--
2.11.0
emtrion GmbH
Kreativpark - Alter Schlachthof 45
76131 Karlsruhe
GERMANY
http://www.emtrion.de
_______________________________________
Amtsgericht Mannheim
HRB 110 300
Geschäftsführer: Dieter Baur, Ramona Maurer
_______________________________________
[-- Attachment #2: Type: text/plain, Size: 176 bytes --]
_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
^ permalink raw reply related
* [PATCH 5/5] ARM: imx_v6_v7_defconfig: Enable DA0963 PMIC support.
From: Jan Tuerk @ 2017-11-23 12:55 UTC (permalink / raw)
To: Rob Herring, Mark Rutland, Thierry Reding, David Airlie,
Russell King, Shawn Guo, Sascha Hauer, Fabio Estevam, Jan Tuerk,
Andreas Färber, Kevin Hilman, Maxime Ripard, SZ Lin,
Alexandre Belloni, Greg Kroah-Hartman, devicetree, linux-kernel,
dri-devel, linux-arm-kernel
In-Reply-To: <20171123125600.41562-1-jan.tuerk@emtrion.com>
[-- Attachment #1: Type: text/plain, Size: 1779 bytes --]
All recent emtrion modules based on i.mx6 make use of the DA0963.
Therefore enable it with the following defaults:
- CONFIG_MFD_DA9063=y
- CONFIG_REGULATOR_DA9063=y
- CONFIG_DA9063_WATCHDOG=m
- CONFIG_RTC_DRV_DA9063=m
MFD and REGULATOR are built-in to have it at Kernel boot-time.
The WATCHDOG and RTC are optional and could be loaded from userspace.
Signed-off-by: Jan Tuerk <jan.tuerk@emtrion.com>
---
arch/arm/configs/imx_v6_v7_defconfig | 4 ++++
1 file changed, 4 insertions(+)
diff --git a/arch/arm/configs/imx_v6_v7_defconfig b/arch/arm/configs/imx_v6_v7_defconfig
index 0d4494922561..09cd8048b0c1 100644
--- a/arch/arm/configs/imx_v6_v7_defconfig
+++ b/arch/arm/configs/imx_v6_v7_defconfig
@@ -215,8 +215,10 @@ CONFIG_THERMAL_WRITABLE_TRIPS=y
CONFIG_CPU_THERMAL=y
CONFIG_IMX_THERMAL=y
CONFIG_WATCHDOG=y
+CONFIG_DA9063_WATCHDOG=m
CONFIG_IMX2_WDT=y
CONFIG_MFD_DA9052_I2C=y
+CONFIG_MFD_DA9063=y
CONFIG_MFD_MC13XXX_SPI=y
CONFIG_MFD_MC13XXX_I2C=y
CONFIG_MFD_STMPE=y
@@ -224,6 +226,7 @@ CONFIG_REGULATOR=y
CONFIG_REGULATOR_FIXED_VOLTAGE=y
CONFIG_REGULATOR_ANATOP=y
CONFIG_REGULATOR_DA9052=y
+CONFIG_REGULATOR_DA9063=y
CONFIG_REGULATOR_GPIO=y
CONFIG_REGULATOR_MC13783=y
CONFIG_REGULATOR_MC13892=y
@@ -349,6 +352,7 @@ CONFIG_RTC_DRV_PCF8563=y
CONFIG_RTC_DRV_M41T80=y
CONFIG_RTC_DRV_MC13XXX=y
CONFIG_RTC_DRV_MXC=y
+CONFIG_RTC_DRV_DA9063=m
CONFIG_RTC_DRV_SNVS=y
CONFIG_DMADEVICES=y
CONFIG_FSL_EDMA=y
--
2.11.0
emtrion GmbH
Kreativpark - Alter Schlachthof 45
76131 Karlsruhe
GERMANY
http://www.emtrion.de
_______________________________________
Amtsgericht Mannheim
HRB 110 300
Geschäftsführer: Dieter Baur, Ramona Maurer
_______________________________________
[-- Attachment #2: Type: text/plain, Size: 176 bytes --]
_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
^ permalink raw reply related
* Re: [PATCH 2/5] dt-bindings: Add vendor prefix for emtrion GmbH
From: Andreas Färber @ 2017-11-23 12:58 UTC (permalink / raw)
To: Jan Tuerk, Rob Herring, Mark Rutland, Thierry Reding,
David Airlie, Russell King, Shawn Guo, Sascha Hauer,
Fabio Estevam, Kevin Hilman, Maxime Ripard, SZ Lin,
Greg Kroah-Hartman, Alexandre Belloni, devicetree, linux-kernel,
dri-devel, linux-arm-kernel
In-Reply-To: <20171123125600.41562-3-jan.tuerk@emtrion.com>
Am 23.11.2017 um 13:55 schrieb Jan Tuerk:
> emtrion is a system integrator and manufacturer of embedded systems.
>
> Website: https://www.emtrion.de
>
> Signed-off-by: Jan Tuerk <jan.tuerk@emtrion.com>
> ---
> Documentation/devicetree/bindings/vendor-prefixes.txt | 1 +
> 1 file changed, 1 insertion(+)
Reviewed-by: Andreas Färber <afaerber@suse.de>
Regards,
Andreas
--
SUSE Linux GmbH, Maxfeldstr. 5, 90409 Nürnberg, Germany
GF: Felix Imendörffer, Jane Smithard, Graham Norton
HRB 21284 (AG Nürnberg)
^ permalink raw reply
* Re: [PATCH 3/5] ARM: dts: imx: Add an cpu0 label for imx6dl devices.
From: Andreas Färber @ 2017-11-23 13:00 UTC (permalink / raw)
To: Jan Tuerk, Rob Herring, Mark Rutland, Thierry Reding,
David Airlie, Russell King, Shawn Guo, Sascha Hauer,
Fabio Estevam, Kevin Hilman, Maxime Ripard, SZ Lin,
Alexandre Belloni, Greg Kroah-Hartman,
devicetree-u79uwXL29TY76Z2rM5mHXA,
linux-kernel-u79uwXL29TY76Z2rM5mHXA,
dri-devel-PD4FTy7X32lNgt0PjOBp9y5qC8QIuHrW,
linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r
In-Reply-To: <20171123125600.41562-4-jan.tuerk-BU0Y/NROKIhBDgjK7y7TUQ@public.gmane.org>
Am 23.11.2017 um 13:55 schrieb Jan Tuerk:
> Adding the label cpu0 allows the adjustment of cpu-parameters
> by reference in overlaying dtsi files in the same way as it
> is possible for imx6q devices.
>
> Signed-off-by: Jan Tuerk <jan.tuerk-BU0Y/NROKIhBDgjK7y7TUQ@public.gmane.org>
> ---
> arch/arm/boot/dts/imx6dl.dtsi | 2 +-
> 1 file changed, 1 insertion(+), 1 deletion(-)
Reviewed-by: Andreas Färber <afaerber-l3A5Bk7waGM@public.gmane.org>
Thanks,
Andreas
--
SUSE Linux GmbH, Maxfeldstr. 5, 90409 Nürnberg, Germany
GF: Felix Imendörffer, Jane Smithard, Graham Norton
HRB 21284 (AG Nürnberg)
--
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
* [PATCH] ARM: dts: move G2D node to exynos5
From: Tobias Jakobi @ 2017-11-23 13:58 UTC (permalink / raw)
To: linux-samsung-soc; +Cc: m.szyprowski, devicetree, Tobias Jakobi
Current the node is only defined in the exynos5250 DT, while
the corresponding MMUs are also to be found in the exynos5420
DT. Move the node to exynos5 and only setup the MMUs in the
corresponding DT.
Disable the node by default, since exynos5410 also includes
the dtsi, but currently does not define the G2D clock.
Tested-by: Marek Szyprowski <m.szyprowski@samsung.com>
Signed-off-by: Tobias Jakobi <tjakobi@math.uni-bielefeld.de>
---
arch/arm/boot/dts/exynos5.dtsi | 7 +++++++
arch/arm/boot/dts/exynos5250.dtsi | 16 +++++++---------
arch/arm/boot/dts/exynos5420.dtsi | 7 +++++++
3 files changed, 21 insertions(+), 9 deletions(-)
diff --git a/arch/arm/boot/dts/exynos5.dtsi b/arch/arm/boot/dts/exynos5.dtsi
index 66d22521c976..f3fec03a7595 100644
--- a/arch/arm/boot/dts/exynos5.dtsi
+++ b/arch/arm/boot/dts/exynos5.dtsi
@@ -204,5 +204,12 @@
#size-cells = <0>;
status = "disabled";
};
+
+ g2d: g2d@10850000 {
+ compatible = "samsung,exynos5250-g2d";
+ reg = <0x10850000 0x1000>;
+ interrupts = <GIC_SPI 91 IRQ_TYPE_LEVEL_HIGH>;
+ status = "disabled";
+ };
};
};
diff --git a/arch/arm/boot/dts/exynos5250.dtsi b/arch/arm/boot/dts/exynos5250.dtsi
index 5286084e1032..b6a8a2ef499a 100644
--- a/arch/arm/boot/dts/exynos5250.dtsi
+++ b/arch/arm/boot/dts/exynos5250.dtsi
@@ -245,15 +245,6 @@
samsung,syscon-phandle = <&pmu_system_controller>;
};
- g2d@10850000 {
- compatible = "samsung,exynos5250-g2d";
- reg = <0x10850000 0x1000>;
- interrupts = <GIC_SPI 91 IRQ_TYPE_LEVEL_HIGH>;
- clocks = <&clock CLK_G2D>;
- clock-names = "fimg2d";
- iommus = <&sysmmu_g2d>;
- };
-
mfc: codec@11000000 {
compatible = "samsung,mfc-v6";
reg = <0x11000000 0x10000>;
@@ -1024,6 +1015,13 @@
iommus = <&sysmmu_fimd1>;
};
+&g2d {
+ iommus = <&sysmmu_g2d>;
+ clocks = <&clock CLK_G2D>;
+ clock-names = "fimg2d";
+ status = "okay";
+};
+
&i2c_0 {
clocks = <&clock CLK_I2C0>;
clock-names = "i2c";
diff --git a/arch/arm/boot/dts/exynos5420.dtsi b/arch/arm/boot/dts/exynos5420.dtsi
index 8aa2cc7aa125..81447fffcc94 100644
--- a/arch/arm/boot/dts/exynos5420.dtsi
+++ b/arch/arm/boot/dts/exynos5420.dtsi
@@ -1349,6 +1349,13 @@
iommu-names = "m0", "m1";
};
+&g2d {
+ iommus = <&sysmmu_g2dr>, <&sysmmu_g2dw>;
+ clocks = <&clock CLK_G2D>;
+ clock-names = "fimg2d";
+ status = "okay";
+};
+
&i2c_0 {
clocks = <&clock CLK_I2C0>;
clock-names = "i2c";
--
2.13.5
^ permalink raw reply related
* Re: [PATCH] arm64: dts: Hi3660: Fix state id for 'CPU_NAP' state
From: Sudeep Holla @ 2017-11-23 14:03 UTC (permalink / raw)
To: Leo Yan, Wei Xu, Mark Rutland,
linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r,
linux-kernel-u79uwXL29TY76Z2rM5mHXA, Rob Herring,
devicetree-u79uwXL29TY76Z2rM5mHXA, Daniel Lezcano
Cc: Sudeep Holla, Vincent Guittot
In-Reply-To: <1511415614-9859-1-git-send-email-leo.yan-QSEj5FYQhm4dnm+yROfE0A@public.gmane.org>
Hi Daniel,
Thanks a lot for pointing me to this and having some useful discussion
in private. That helped to dig a bit further on this.
On 23/11/17 05:40, Leo Yan wrote:
> Thanks a lot for Vincent Guittot careful work to find bug for 'CPU_NAP'
> idle state. From ftrace log we can observe CA73 CPUs can be easily waken
> up from 'CPU_NAP' state but the 'waken up' CPUs doesn't handle anything
> and sleep again; so there have tons of trace events for CA73 CPUs
> entering and exiting idle state.
>
> On Hi3660 CA73 has retention state 'CPU_NAP' for CPU idle, this state we
> set its psci parameter as '0x0000001' and from this parameter it can
> calculate state id is 1. Unfortunately ARM trusted firmware (ARM-TF)
> takes 1 as a invalid value for state id, so the CPU cannot enter idle
> state and directly bail out to kernel.
>
> This commit changes psci parameter to '0x00000000' for state id = 0;
> this id is accepted by ARM trusted firmware and finally CPU can stay
> properly in 'CPU_NAP' state.
>
I would like to conditionally NACK this patch. If we can't update the
ARM TF at all then, I will agree with this change reluctantly.
This looks like an artifact of copy paste in ARM TF port for this
platform. If you look as PSCI specification, CPU suspend parameter has
some recommendations and it's good to follow then unless you have strong
reasons not to.
As Daniel pointed to me, this patch is required to satisfy TF
particularly [1]. Now that looks like copy pasted from Juno or FVP port
and if you look deeper, it's clearly under !ARM_RECOM_STATE_ID_ENC [2]
which was not copied IIUC :).
Juno's implementation is legacy as these recommendations were added
later in the specification while Juno is 3 year old platform now.
Though strictly speaking it's not violation of the PSCI specification,
but I would rather get this fixed not before it's too late and copied to
the next generation of platforms. Since the firmware can be easily
upgraded that shouldn't be that difficult.
--
Regards,
Sudeep
[1]
https://github.com/ARM-software/arm-trusted-firmware/blob/master/plat/hisilicon/hikey960/hikey960_pm.c#L156
[2]
https://github.com/ARM-software/arm-trusted-firmware/blob/master/plat/arm/common/arm_pm.c#L28
--
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 1/2] usb: xhci: add relaxed timing quirk bit
From: Adam Wallis @ 2017-11-23 14:35 UTC (permalink / raw)
To: Mathias Nyman, Rob Herring
Cc: linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r@public.gmane.org,
Greg Kroah-Hartman, Mathias Nyman, Linux USB List,
devicetree-u79uwXL29TY76Z2rM5mHXA@public.gmane.org, Mark Rutland,
Timur Tabi, Chunfeng Yun
In-Reply-To: <c46e19a2-4b37-473c-a563-6fddf0c62070-VuQAYsv1563Yd54FQh9/CA@public.gmane.org>
On 11/23/2017 5:59 AM, Mathias Nyman wrote:
> On 23.11.2017 01:32, Adam Wallis wrote:
>> On 11/22/2017 10:24 AM, Mathias Nyman wrote:
>> [..]
>>>
>>> We know have at least two hosts/platforms that need custom interrupt moderation
>>> values
>>>
>>> How about adding a u32 device property for xhci with the interrupt moderation
>>> interval in
>>> nanoseconds? And also add a u32 imod_interval variable to struct xhci_hcd?
>>> imod_interval can be set to the current default 40000ns (160*250ns) and
>>> overwritten if
>>> device_property_read_u32() returns something else.
>>>
>>
>> Isn't the 160 value quite aggressive anyway? Section 5.5.2.2 of the xHCI spec
>> says that maximum observable interrupt rate should never exceed 8000
>> interrupts/second. I believe the IMOD value in the most aggressive case would
>> then be 500 by this statement [ 1 / (250e-9 * 500) = 8000 irqs/second ]
>>
>> Perhaps I am misreading the spec or just doing the math wrong? With the default
>> value of 160, we are interrupting 25,000 irq/second...which is over 3 times the
>> maximum stated value (again, assuming I did the math right)
>>
>> Anyway, my preference would be to set the IMOD default val to 4000 (~1ms) per
>> the recommended value in Table 49 of the spec and allow platforms to adjust as
>> necessary from that point.
>>
>> Thoughts on this?
>>
>
> I think current 40us is still reasonable, it's about ~3 times per
> usb microframe (125us) .8000 interrupts per second just covers the microframe rate,
> which is the shortest interval a interrupt transfer can require service.
>
> 1ms interrupt interval is too long. In the worst case ~8 microframes could pass
> before the driver is aware of a error it needs to take care of.
> USB 3.1 devices can transfer 6 burst of 16 max sized packets (6 x 16 x 2014) bytes
> per microframe.
>
> closer to 125us could probably work as well, but unless we are fixing some issue or
> getting some other bigger benefit out of it I don't think it's worth changing it
> just to see if it breaks stuff.
I agree - my patch will just stick with the current default as the fallback
value if no device property is submitted.
>
> Thanks
> -Mathias
> --
> To unsubscribe from this list: send the line "unsubscribe linux-usb" in
> the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
> More majordomo info at http://vger.kernel.org/majordomo-info.html
--
Adam Wallis
Qualcomm Datacenter Technologies as an affiliate of Qualcomm Technologies, Inc.
Qualcomm Technologies, Inc. is a member of the Code Aurora Forum,
a Linux Foundation Collaborative Project.
--
To unsubscribe from this list: send the line "unsubscribe linux-usb" 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
* [PATCH 0/5] PCI: Add support to the Cadence PCIe controller
From: Cyrille Pitchen @ 2017-11-23 15:01 UTC (permalink / raw)
To: bhelgaas, kishon, lorenzo.pieralisi, linux-pci
Cc: adouglas, stelford, dgary, kgopi, eandrews, thomas.petazzoni,
sureshp, nsekhar, linux-kernel, robh, devicetree, Cyrille Pitchen
Hi all,
this series of patches adds support to the Cadence PCIe controller.
It was tested on a ARM64 platform emulated by a Palladium running both
linux-next (next-20171123) and pci-next kernels.
The host mode was tested with some PCIe devices connected to the Palladium
through a speed-bridge. Some of those devices were a USB host controller
and a SATA controller. The PCIe host controller was also tested with a
second controller configured in endpoint mode and connected back to back
to the first controller.
The EndPoint Controller (EPC) driver of this series was tested with the
pci-epf-test.c EndPoint Function (EPF) driver and the pcitest userspace
program.
For linux-next, I applied this series on top of Kishon's patch
("PCI: endpoint: Use EPC's device in dma_alloc_coherent/dma_free_coherent")
otherwise dma_alloc_coherent() fails when called by pci_epf_alloc_space().
Also, I patched drivers/Makefile rather than drivers/pci/Makefile to make
the drivers/pci/cadence/pcie-cadence-ep.o linked after
drivers/pci/endpoint/*.o objects, otherwise the built-in pci-cadence-ep
driver would be probed before the PCI endpoint framework would have been
initialized, which results in a kernel crash.
I guess this is the reason why the "pci/dwc" line was also put in
drivers/Makefile, right after the "pci/endpoint" line.
Best regards,
Cyrille
Cyrille Pitchen (4):
PCI: Add vendor ID for Cadence
PCI: cadence: Add host driver for Cadence PCIe controller
dt-bindings: PCI: cadence: Add DT bindings for Cadence PCIe endpoint
controller
PCI: cadence: add EndPoint Controller driver for Cadence PCIe
controller
Scott Telford (1):
dt-bindings: PCI: cadence: Add DT bindings for Cadence PCIe host
controller
.../devicetree/bindings/pci/cdns,cdns-pcie-ep.txt | 20 +
.../bindings/pci/cdns,cdns-pcie-host.txt | 54 ++
drivers/Makefile | 1 +
drivers/pci/Kconfig | 1 +
drivers/pci/cadence/Kconfig | 33 ++
drivers/pci/cadence/Makefile | 3 +
drivers/pci/cadence/pcie-cadence-ep.c | 553 +++++++++++++++++++++
drivers/pci/cadence/pcie-cadence-host.c | 425 ++++++++++++++++
drivers/pci/cadence/pcie-cadence.c | 110 ++++
drivers/pci/cadence/pcie-cadence.h | 325 ++++++++++++
include/linux/pci_ids.h | 2 +
11 files changed, 1527 insertions(+)
create mode 100644 Documentation/devicetree/bindings/pci/cdns,cdns-pcie-ep.txt
create mode 100644 Documentation/devicetree/bindings/pci/cdns,cdns-pcie-host.txt
create mode 100644 drivers/pci/cadence/Kconfig
create mode 100644 drivers/pci/cadence/Makefile
create mode 100644 drivers/pci/cadence/pcie-cadence-ep.c
create mode 100644 drivers/pci/cadence/pcie-cadence-host.c
create mode 100644 drivers/pci/cadence/pcie-cadence.c
create mode 100644 drivers/pci/cadence/pcie-cadence.h
--
2.11.0
^ permalink raw reply
* [PATCH 1/5] PCI: Add vendor ID for Cadence
From: Cyrille Pitchen @ 2017-11-23 15:01 UTC (permalink / raw)
To: bhelgaas-hpIqsD4AKlfQT0dZR+AlfA, kishon-l0cyMroinI0,
lorenzo.pieralisi-5wv7dgnIgG8, linux-pci-u79uwXL29TY76Z2rM5mHXA
Cc: adouglas-vna1KIf7WgpBDgjK7y7TUQ, stelford-vna1KIf7WgpBDgjK7y7TUQ,
dgary-vna1KIf7WgpBDgjK7y7TUQ, kgopi-vna1KIf7WgpBDgjK7y7TUQ,
eandrews-vna1KIf7WgpBDgjK7y7TUQ,
thomas.petazzoni-wi1+55ScJUtKEb57/3fJTNBPR1lH4CV8,
sureshp-vna1KIf7WgpBDgjK7y7TUQ, nsekhar-l0cyMroinI0,
linux-kernel-u79uwXL29TY76Z2rM5mHXA, robh-DgEjT+Ai2ygdnm+yROfE0A,
devicetree-u79uwXL29TY76Z2rM5mHXA, Cyrille Pitchen
In-Reply-To: <cover.1511439189.git.cyrille.pitchen-wi1+55ScJUtKEb57/3fJTNBPR1lH4CV8@public.gmane.org>
This patch adds a new PCI vendor ID for Cadence.
Signed-off-by: Cyrille Pitchen <cyrille.pitchen-wi1+55ScJUtKEb57/3fJTNBPR1lH4CV8@public.gmane.org>
---
include/linux/pci_ids.h | 2 ++
1 file changed, 2 insertions(+)
diff --git a/include/linux/pci_ids.h b/include/linux/pci_ids.h
index ab20dc5db423..eb13e84e1fef 100644
--- a/include/linux/pci_ids.h
+++ b/include/linux/pci_ids.h
@@ -2381,6 +2381,8 @@
#define PCI_VENDOR_ID_LENOVO 0x17aa
+#define PCI_VENDOR_ID_CDNS 0x17cd
+
#define PCI_VENDOR_ID_ARECA 0x17d3
#define PCI_DEVICE_ID_ARECA_1110 0x1110
#define PCI_DEVICE_ID_ARECA_1120 0x1120
--
2.11.0
--
To unsubscribe from this list: send the line "unsubscribe devicetree" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
^ permalink raw reply related
* [PATCH 2/5] dt-bindings: PCI: cadence: Add DT bindings for Cadence PCIe host controller
From: Cyrille Pitchen @ 2017-11-23 15:01 UTC (permalink / raw)
To: bhelgaas, kishon, lorenzo.pieralisi, linux-pci
Cc: adouglas, stelford, dgary, kgopi, eandrews, thomas.petazzoni,
sureshp, nsekhar, linux-kernel, robh, devicetree, Cyrille Pitchen
In-Reply-To: <cover.1511439189.git.cyrille.pitchen@free-electrons.com>
From: Scott Telford <stelford@cadence.com>
This patch adds documentation for the DT bindings of the Cadence PCIe
controller when configured in host (Root Complex) mode.
Signed-off-by: Scott Telford <stelford@cadence.com>
Signed-off-by: Cyrille Pitchen <cyrille.pitchen@free-electrons.com>
dt-bindings: PCI: cadence: host fixup
---
.../bindings/pci/cdns,cdns-pcie-host.txt | 54 ++++++++++++++++++++++
1 file changed, 54 insertions(+)
create mode 100644 Documentation/devicetree/bindings/pci/cdns,cdns-pcie-host.txt
diff --git a/Documentation/devicetree/bindings/pci/cdns,cdns-pcie-host.txt b/Documentation/devicetree/bindings/pci/cdns,cdns-pcie-host.txt
new file mode 100644
index 000000000000..4b3df8ffd5e1
--- /dev/null
+++ b/Documentation/devicetree/bindings/pci/cdns,cdns-pcie-host.txt
@@ -0,0 +1,54 @@
+* Cadence PCIe host controller
+
+This PCIe controller inherits the base properties defined in
+host-generic-pci.txt.
+
+Required properties:
+- compatible: should contain "cdns,cdns-pcie-host" to identify the IP used.
+- reg: Should contain the PCIe configuration window base address, controller
+ register base address, and AXI interface region base address respectively.
+- reg-names: Must be "cfg", "reg" and "mem" respectively.
+- #address-cells: set to <3>
+- #size-cells: set to <2>
+- device_type: set to "pci"
+- ranges: ranges for the PCI memory and I/O regions
+- #interrupt-cells: set to <1>
+- interrupt-map-mask and interrupt-map: standard PCI
+ properties to define the mapping of the PCIe interface to interrupt
+ numbers.
+
+Example:
+
+ pci@fb000000 {
+ compatible = "cdns,cdns-pcie-host";
+ device_type = "pci";
+ #address-cells = <3>;
+ #size-cells = <2>;
+ bus-range = <0x0 0xff>;
+ linux,pci-domain = <0>;
+
+ // CPU_PHYSICAL(2) SIZE(2)
+ reg = <0x0 0x41000000 0x0 0x00001000>, /* Config space */
+ <0x0 0xfb000000 0x0 0x01000000>, /* Base Address */
+ <0x0 0x40000000 0x0 0x04000000>; /* AXI region */
+ reg-names = "cfg", "reg", "mem";
+
+ // BUS_ADDRESS(3) CPU_PHYSICAL(1) SIZE(2)
+ ranges =
+ <0x02000000 0x0 0x42000000 0x0 0x42000000 0x0 0x1000000>,
+ <0x01000000 0x0 0x43000000 0x0 0x43000000 0x0 0x0010000>;
+
+
+ #interrupt-cells = <0x1>;
+
+ // PCI_DEVICE(3) INT#(1) CONTROLLER(PHANDLE) CONTROLLER_DATA(5)
+ interrupt-map = <0x0 0x0 0x0 0x1 &gic 0x0 0x0 0x0 14 0x1
+ 0x0 0x0 0x0 0x2 &gic 0x0 0x0 0x0 15 0x1
+ 0x0 0x0 0x0 0x3 &gic 0x0 0x0 0x0 16 0x1
+ 0x0 0x0 0x0 0x4 &gic 0x0 0x0 0x0 17 0x1>;
+
+ // PCI_DEVICE(3) INT#(1)
+ interrupt-map-mask = <0x0000 0x0 0x0 0x7>;
+
+ msi-parent = <&its_pci>;
+ };
--
2.11.0
^ permalink raw reply related
* [PATCH 3/5] PCI: cadence: Add host driver for Cadence PCIe controller
From: Cyrille Pitchen @ 2017-11-23 15:01 UTC (permalink / raw)
To: bhelgaas-hpIqsD4AKlfQT0dZR+AlfA, kishon-l0cyMroinI0,
lorenzo.pieralisi-5wv7dgnIgG8, linux-pci-u79uwXL29TY76Z2rM5mHXA
Cc: adouglas-vna1KIf7WgpBDgjK7y7TUQ, stelford-vna1KIf7WgpBDgjK7y7TUQ,
dgary-vna1KIf7WgpBDgjK7y7TUQ, kgopi-vna1KIf7WgpBDgjK7y7TUQ,
eandrews-vna1KIf7WgpBDgjK7y7TUQ,
thomas.petazzoni-wi1+55ScJUtKEb57/3fJTNBPR1lH4CV8,
sureshp-vna1KIf7WgpBDgjK7y7TUQ, nsekhar-l0cyMroinI0,
linux-kernel-u79uwXL29TY76Z2rM5mHXA, robh-DgEjT+Ai2ygdnm+yROfE0A,
devicetree-u79uwXL29TY76Z2rM5mHXA, Cyrille Pitchen
In-Reply-To: <cover.1511439189.git.cyrille.pitchen-wi1+55ScJUtKEb57/3fJTNBPR1lH4CV8@public.gmane.org>
This patch adds support to the Cadence PCIe controller in host mode.
Signed-off-by: Cyrille Pitchen <cyrille.pitchen-wi1+55ScJUtKEb57/3fJTNBPR1lH4CV8@public.gmane.org>
---
drivers/Makefile | 1 +
drivers/pci/Kconfig | 1 +
drivers/pci/cadence/Kconfig | 24 ++
drivers/pci/cadence/Makefile | 2 +
drivers/pci/cadence/pcie-cadence-host.c | 425 ++++++++++++++++++++++++++++++++
drivers/pci/cadence/pcie-cadence.c | 110 +++++++++
drivers/pci/cadence/pcie-cadence.h | 325 ++++++++++++++++++++++++
7 files changed, 888 insertions(+)
create mode 100644 drivers/pci/cadence/Kconfig
create mode 100644 drivers/pci/cadence/Makefile
create mode 100644 drivers/pci/cadence/pcie-cadence-host.c
create mode 100644 drivers/pci/cadence/pcie-cadence.c
create mode 100644 drivers/pci/cadence/pcie-cadence.h
diff --git a/drivers/Makefile b/drivers/Makefile
index 1d034b680431..27bdd98784d9 100644
--- a/drivers/Makefile
+++ b/drivers/Makefile
@@ -18,6 +18,7 @@ obj-y += pwm/
obj-$(CONFIG_PCI) += pci/
obj-$(CONFIG_PCI_ENDPOINT) += pci/endpoint/
+obj-$(CONFIG_PCI_CADENCE) += pci/cadence/
# PCI dwc controller drivers
obj-y += pci/dwc/
diff --git a/drivers/pci/Kconfig b/drivers/pci/Kconfig
index 90944667ccea..2471b2e36b8b 100644
--- a/drivers/pci/Kconfig
+++ b/drivers/pci/Kconfig
@@ -144,6 +144,7 @@ config PCI_HYPERV
PCI devices from a PCI backend to support PCI driver domains.
source "drivers/pci/hotplug/Kconfig"
+source "drivers/pci/cadence/Kconfig"
source "drivers/pci/dwc/Kconfig"
source "drivers/pci/host/Kconfig"
source "drivers/pci/endpoint/Kconfig"
diff --git a/drivers/pci/cadence/Kconfig b/drivers/pci/cadence/Kconfig
new file mode 100644
index 000000000000..120306cae2aa
--- /dev/null
+++ b/drivers/pci/cadence/Kconfig
@@ -0,0 +1,24 @@
+menuconfig PCI_CADENCE
+ bool "Cadence PCI controllers support"
+ depends on PCI && HAS_IOMEM
+ help
+ Say Y here if you want to support some Cadence PCI controller.
+
+ When in doubt, say N.
+
+if PCI_CADENCE
+
+config PCIE_CADENCE
+ bool
+
+config PCIE_CADENCE_HOST
+ bool "Cadence PCIe host controller"
+ depends on OF
+ depends on PCI_MSI_IRQ_DOMAIN
+ select PCIE_CADENCE
+ help
+ Say Y here if you want to support the Cadence PCIe controller in host
+ mode. This PCIe controller may be embedded into many different vendors
+ SoCs.
+
+endif # PCI_CADENCE
diff --git a/drivers/pci/cadence/Makefile b/drivers/pci/cadence/Makefile
new file mode 100644
index 000000000000..d57d192d2595
--- /dev/null
+++ b/drivers/pci/cadence/Makefile
@@ -0,0 +1,2 @@
+obj-$(CONFIG_PCIE_CADENCE) += pcie-cadence.o
+obj-$(CONFIG_PCIE_CADENCE_HOST) += pcie-cadence-host.o
diff --git a/drivers/pci/cadence/pcie-cadence-host.c b/drivers/pci/cadence/pcie-cadence-host.c
new file mode 100644
index 000000000000..252471e72a93
--- /dev/null
+++ b/drivers/pci/cadence/pcie-cadence-host.c
@@ -0,0 +1,425 @@
+/*
+ * Cadence PCIe host controller driver.
+ *
+ * Copyright (c) 2017 Cadence
+ *
+ * Author: Cyrille Pitchen <cyrille.pitchen-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 version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+#include <linux/kernel.h>
+#include <linux/of_address.h>
+#include <linux/of_pci.h>
+#include <linux/platform_device.h>
+#include <linux/pm_runtime.h>
+
+#include "pcie-cadence.h"
+
+/**
+ * struct cdns_pcie_rc_data - hardware specific data
+ * @max_regions: maximum number of regions supported by the hardware
+ * @vendor_id: PCI vendor ID
+ * @device_id: PCI device ID
+ * @no_bar_nbits: Number of bits to keep for inbound (PCIe -> CPU) address
+ * translation (nbits sets into the "no BAR match" register).
+ */
+struct cdns_pcie_rc_data {
+ size_t max_regions;
+ u16 vendor_id;
+ u16 device_id;
+ u8 no_bar_nbits;
+};
+
+/**
+ * struct cdns_pcie_rc - private data for this PCIe Root Complex driver
+ * @pcie: Cadence PCIe controller
+ * @dev: pointer to PCIe device
+ * @cfg_res: start/end offsets in the physical system memory to map PCI
+ * configuration space accesses
+ * @bus_range: first/last buses behind the PCIe host controller
+ * @cfg_base: IO mapped window to access the PCI configuration space of a
+ * single function at a time
+ * @data: pointer to a 'struct cdns_pcie_rc_data'
+ */
+struct cdns_pcie_rc {
+ struct cdns_pcie pcie;
+ struct device *dev;
+ struct resource *cfg_res;
+ struct resource *bus_range;
+ void __iomem *cfg_base;
+ const struct cdns_pcie_rc_data *data;
+};
+
+static void __iomem *
+cdns_pci_map_bus(struct pci_bus *bus, unsigned int devfn, int where)
+{
+ struct pci_host_bridge *bridge = pci_find_host_bridge(bus);
+ struct cdns_pcie_rc *rc = pci_host_bridge_priv(bridge);
+ struct cdns_pcie *pcie = &rc->pcie;
+ unsigned int busn = bus->number;
+ u32 addr0, desc0;
+
+ if (busn < rc->bus_range->start || busn > rc->bus_range->end)
+ return NULL;
+
+ if (busn == rc->bus_range->start) {
+ if (devfn)
+ return NULL;
+
+ return pcie->reg_base + (where & 0xfff);
+ }
+
+ /* Update Output registers for AXI region 0. */
+ addr0 = CDNS_PCIE_AT_OB_REGION_PCI_ADDR0_NBITS(12) |
+ CDNS_PCIE_AT_OB_REGION_PCI_ADDR0_DEVFN(devfn) |
+ CDNS_PCIE_AT_OB_REGION_PCI_ADDR0_BUS(busn);
+ cdns_pcie_writel(pcie, CDNS_PCIE_AT_OB_REGION_PCI_ADDR0(0), addr0);
+
+ /* Configuration Type 0 or Type 1 access. */
+ desc0 = CDNS_PCIE_AT_OB_REGION_DESC0_HARDCODED_RID |
+ CDNS_PCIE_AT_OB_REGION_DESC0_DEVFN(0);
+ /*
+ * The bus number was already set once for all in desc1 by
+ * cdns_pcie_host_init_address_translation().
+ */
+ if (busn == rc->bus_range->start + 1)
+ desc0 |= CDNS_PCIE_AT_OB_REGION_DESC0_TYPE_CONF_TYPE0;
+ else
+ desc0 |= CDNS_PCIE_AT_OB_REGION_DESC0_TYPE_CONF_TYPE1;
+ cdns_pcie_writel(pcie, CDNS_PCIE_AT_OB_REGION_DESC0(0), desc0);
+
+ return rc->cfg_base + (where & 0xfff);
+}
+
+static struct pci_ops cdns_pcie_host_ops = {
+ .map_bus = cdns_pci_map_bus,
+ .read = pci_generic_config_read,
+ .write = pci_generic_config_write,
+};
+
+static const struct cdns_pcie_rc_data cdns_pcie_rc_data = {
+ .max_regions = 32,
+ .vendor_id = PCI_VENDOR_ID_CDNS,
+ .device_id = 0x0200,
+ .no_bar_nbits = 32,
+};
+
+static const struct of_device_id cdns_pcie_host_of_match[] = {
+ { .compatible = "cdns,cdns-pcie-host",
+ .data = &cdns_pcie_rc_data },
+
+ { },
+};
+
+static int cdns_pcie_parse_request_of_pci_ranges(struct device *dev,
+ struct list_head *resources,
+ struct resource **bus_range)
+{
+ int err, res_valid = 0;
+ struct device_node *np = dev->of_node;
+ resource_size_t iobase;
+ struct resource_entry *win, *tmp;
+
+ err = of_pci_get_host_bridge_resources(np, 0, 0xff, resources, &iobase);
+ if (err)
+ return err;
+
+ err = devm_request_pci_bus_resources(dev, resources);
+ if (err)
+ return err;
+
+ resource_list_for_each_entry_safe(win, tmp, resources) {
+ struct resource *res = win->res;
+
+ switch (resource_type(res)) {
+ case IORESOURCE_IO:
+ err = pci_remap_iospace(res, iobase);
+ if (err) {
+ dev_warn(dev, "error %d: failed to map resource %pR\n",
+ err, res);
+ resource_list_destroy_entry(win);
+ }
+ break;
+ case IORESOURCE_MEM:
+ res_valid |= !(res->flags & IORESOURCE_PREFETCH);
+ break;
+ case IORESOURCE_BUS:
+ *bus_range = res;
+ break;
+ }
+ }
+
+ if (res_valid)
+ return 0;
+
+ dev_err(dev, "non-prefetchable memory resource required\n");
+ return -EINVAL;
+}
+
+static int cdns_pcie_host_init_root_port(struct cdns_pcie_rc *rc)
+{
+ const struct cdns_pcie_rc_data *data = rc->data;
+ struct cdns_pcie *pcie = &rc->pcie;
+ u8 pbn, sbn, subn;
+ u32 value, ctrl;
+
+ /*
+ * Set the root complex BAR configuration register:
+ * - disable both BAR0 and BAR1.
+ * - enable Prefetchable Memory Base and Limit registers in type 1
+ * config space (64 bits).
+ * - enable IO Base and Limit registers in type 1 config
+ * space (32 bits).
+ */
+ ctrl = CDNS_PCIE_LM_BAR_CFG_CTRL_DISABLED;
+ value = CDNS_PCIE_LM_RC_BAR_CFG_BAR0_CTRL(ctrl) |
+ CDNS_PCIE_LM_RC_BAR_CFG_BAR1_CTRL(ctrl) |
+ CDNS_PCIE_LM_RC_BAR_CFG_PREFETCH_MEM_ENABLE |
+ CDNS_PCIE_LM_RC_BAR_CFG_PREFETCH_MEM_64BITS |
+ CDNS_PCIE_LM_RC_BAR_CFG_IO_ENABLE |
+ CDNS_PCIE_LM_RC_BAR_CFG_IO_32BITS;
+ cdns_pcie_writel(pcie, CDNS_PCIE_LM_RC_BAR_CFG, value);
+
+ /* Set root port configuration space */
+ if (data->vendor_id != 0xffff)
+ cdns_pcie_rp_writew(pcie, PCI_VENDOR_ID, data->vendor_id);
+ if (data->device_id != 0xffff)
+ cdns_pcie_rp_writew(pcie, PCI_DEVICE_ID, data->device_id);
+
+ cdns_pcie_rp_writeb(pcie, PCI_CLASS_REVISION, 0);
+ cdns_pcie_rp_writeb(pcie, PCI_CLASS_PROG, 0);
+ cdns_pcie_rp_writew(pcie, PCI_CLASS_DEVICE, PCI_CLASS_BRIDGE_PCI);
+
+ pbn = rc->bus_range->start;
+ sbn = pbn + 1; /* Single root port. */
+ subn = rc->bus_range->end;
+ cdns_pcie_rp_writeb(pcie, PCI_PRIMARY_BUS, pbn);
+ cdns_pcie_rp_writeb(pcie, PCI_SECONDARY_BUS, sbn);
+ cdns_pcie_rp_writeb(pcie, PCI_SUBORDINATE_BUS, subn);
+
+ return 0;
+}
+
+static int cdns_pcie_host_init_address_translation(struct cdns_pcie_rc *rc)
+{
+ struct cdns_pcie *pcie = &rc->pcie;
+ struct resource *cfg_res = rc->cfg_res;
+ struct resource *mem_res = pcie->mem_res;
+ struct resource *bus_range = rc->bus_range;
+ struct device *dev = rc->dev;
+ struct device_node *np = dev->of_node;
+ struct of_pci_range_parser parser;
+ struct of_pci_range range;
+ u32 addr0, addr1, desc1;
+ u64 cpu_addr;
+ int r, err;
+
+ /*
+ * Reserve region 0 for PCI configure space accesses:
+ * OB_REGION_PCI_ADDR0 and OB_REGION_DESC0 are updated dynamically by
+ * cdns_pci_map_bus(), other region registers are set here once for all.
+ */
+ addr1 = 0; /* Should be programmed to zero. */
+ desc1 = CDNS_PCIE_AT_OB_REGION_DESC1_BUS(bus_range->start);
+ cdns_pcie_writel(pcie, CDNS_PCIE_AT_OB_REGION_PCI_ADDR1(0), addr1);
+ cdns_pcie_writel(pcie, CDNS_PCIE_AT_OB_REGION_DESC1(0), desc1);
+
+ cpu_addr = cfg_res->start - mem_res->start;
+ addr0 = CDNS_PCIE_AT_OB_REGION_CPU_ADDR0_NBITS(12) |
+ (lower_32_bits(cpu_addr) & GENMASK(31, 8));
+ addr1 = upper_32_bits(cpu_addr);
+ cdns_pcie_writel(pcie, CDNS_PCIE_AT_OB_REGION_CPU_ADDR0(0), addr0);
+ cdns_pcie_writel(pcie, CDNS_PCIE_AT_OB_REGION_CPU_ADDR1(0), addr1);
+
+ err = of_pci_range_parser_init(&parser, np);
+ if (err)
+ return err;
+
+ r = 1;
+ for_each_of_pci_range(&parser, &range) {
+ bool is_io;
+
+ if (r >= rc->data->max_regions)
+ break;
+
+ if ((range.flags & IORESOURCE_TYPE_BITS) == IORESOURCE_MEM)
+ is_io = false;
+ else if ((range.flags & IORESOURCE_TYPE_BITS) == IORESOURCE_IO)
+ is_io = true;
+ else
+ continue;
+
+ cdns_pcie_set_outbound_region(pcie, r, is_io,
+ range.cpu_addr,
+ range.pci_addr,
+ range.size);
+ r++;
+ }
+
+ /*
+ * Set Root Port no BAR match Inbound Translation registers:
+ * needed for MSI.
+ * Root Port BAR0 and BAR1 are disabled, hence no need to set their
+ * inbound translation registers.
+ */
+ addr0 = CDNS_PCIE_AT_IB_RP_BAR_ADDR0_NBITS(rc->data->no_bar_nbits);
+ addr1 = 0;
+ cdns_pcie_writel(pcie, CDNS_PCIE_AT_IB_RP_BAR_ADDR0(RP_NO_BAR), addr0);
+ cdns_pcie_writel(pcie, CDNS_PCIE_AT_IB_RP_BAR_ADDR1(RP_NO_BAR), addr1);
+
+ return 0;
+}
+
+static int cdns_pcie_host_init(struct device *dev,
+ struct list_head *resources,
+ struct cdns_pcie_rc *rc)
+{
+ struct resource *bus_range = NULL;
+ int err;
+
+ /* Parse our PCI ranges and request their resources */
+ err = cdns_pcie_parse_request_of_pci_ranges(dev, resources, &bus_range);
+ if (err)
+ goto err_out;
+
+ if (bus_range->start > bus_range->end) {
+ err = -EINVAL;
+ goto err_out;
+ }
+ rc->bus_range = bus_range;
+ rc->pcie.bus = bus_range->start;
+
+ err = cdns_pcie_host_init_root_port(rc);
+ if (err)
+ goto err_out;
+
+ err = cdns_pcie_host_init_address_translation(rc);
+ if (err)
+ goto err_out;
+
+ return 0;
+
+ err_out:
+ pci_free_resource_list(resources);
+ return err;
+}
+
+static int cdns_pcie_host_probe(struct platform_device *pdev)
+{
+ const struct of_device_id *of_id;
+ const char *type;
+ struct device *dev = &pdev->dev;
+ struct device_node *np = dev->of_node;
+ struct pci_bus *bus, *child;
+ struct pci_host_bridge *bridge;
+ struct list_head resources;
+ struct cdns_pcie_rc *rc;
+ struct cdns_pcie *pcie;
+ struct resource *res;
+ int ret;
+
+ bridge = devm_pci_alloc_host_bridge(dev, sizeof(*rc));
+ if (!bridge)
+ return -ENOMEM;
+
+ rc = pci_host_bridge_priv(bridge);
+ rc->dev = dev;
+ platform_set_drvdata(pdev, rc);
+
+ pcie = &rc->pcie;
+ pcie->is_rc = true;
+
+ of_id = of_match_node(cdns_pcie_host_of_match, np);
+ rc->data = (const struct cdns_pcie_rc_data *)of_id->data;
+
+ type = of_get_property(np, "device_type", NULL);
+ if (!type || strcmp(type, "pci")) {
+ dev_err(dev, "invalid \"device_type\" %s\n", type);
+ return -EINVAL;
+ }
+
+ res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "reg");
+ pcie->reg_base = devm_ioremap_resource(dev, res);
+ if (IS_ERR(pcie->reg_base)) {
+ dev_err(dev, "missing \"reg\"\n");
+ return PTR_ERR(pcie->reg_base);
+ }
+
+ res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "cfg");
+ rc->cfg_base = devm_ioremap_resource(dev, res);
+ if (IS_ERR(rc->cfg_base)) {
+ dev_err(dev, "missing \"cfg\"\n");
+ return PTR_ERR(rc->cfg_base);
+ }
+ rc->cfg_res = res;
+
+ res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "mem");
+ if (!res) {
+ dev_err(dev, "missing \"mem\"\n");
+ return -EINVAL;
+ }
+ pcie->mem_res = res;
+
+ pm_runtime_enable(dev);
+ ret = pm_runtime_get_sync(dev);
+ if (ret < 0) {
+ dev_err(dev, "pm_runtime_get_sync() failed\n");
+ goto err_get_sync;
+ }
+
+ INIT_LIST_HEAD(&resources);
+ ret = cdns_pcie_host_init(dev, &resources, rc);
+ if (ret)
+ goto err_init;
+
+ list_splice_init(&resources, &bridge->windows);
+ bridge->dev.parent = dev;
+ bridge->busnr = pcie->bus;
+ bridge->ops = &cdns_pcie_host_ops;
+ bridge->map_irq = of_irq_parse_and_map_pci;
+ bridge->swizzle_irq = pci_common_swizzle;
+
+ ret = pci_scan_root_bus_bridge(bridge);
+ if (ret < 0) {
+ dev_err(dev, "Scanning root bridge failed");
+ goto err_init;
+ }
+
+ bus = bridge->bus;
+ pci_bus_size_bridges(bus);
+ pci_bus_assign_resources(bus);
+
+ list_for_each_entry(child, &bus->children, node)
+ pcie_bus_configure_settings(child);
+
+ pci_bus_add_devices(bus);
+
+ return 0;
+
+ err_init:
+ pm_runtime_put_sync(dev);
+
+ err_get_sync:
+ pm_runtime_disable(dev);
+
+ return ret;
+}
+
+static struct platform_driver cdns_pcie_host_driver = {
+ .driver = {
+ .name = "cdns-pcie-host",
+ .of_match_table = cdns_pcie_host_of_match,
+ },
+ .probe = cdns_pcie_host_probe,
+};
+builtin_platform_driver(cdns_pcie_host_driver);
diff --git a/drivers/pci/cadence/pcie-cadence.c b/drivers/pci/cadence/pcie-cadence.c
new file mode 100644
index 000000000000..5c10879d5e96
--- /dev/null
+++ b/drivers/pci/cadence/pcie-cadence.c
@@ -0,0 +1,110 @@
+/*
+ * Cadence PCIe controller driver.
+ *
+ * Copyright (c) 2017 Cadence
+ *
+ * Author: Cyrille Pitchen <cyrille.pitchen-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 version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <linux/kernel.h>
+
+#include "pcie-cadence.h"
+
+void cdns_pcie_set_outbound_region(struct cdns_pcie *pcie, u32 r, bool is_io,
+ u64 cpu_addr, u64 pci_addr, size_t size)
+{
+ /*
+ * roundup_pow_of_two() returns an unsigned long, which is not suited
+ * for 64bit values.
+ */
+ u64 sz = 1ULL << fls64(size - 1);
+ int nbits = ilog2(sz);
+ u32 addr0, addr1, desc0, desc1;
+
+ if (nbits < 8)
+ nbits = 8;
+
+ /* Set the PCI address */
+ addr0 = CDNS_PCIE_AT_OB_REGION_PCI_ADDR0_NBITS(nbits) |
+ (lower_32_bits(pci_addr) & GENMASK(31, 8));
+ addr1 = upper_32_bits(pci_addr);
+
+ cdns_pcie_writel(pcie, CDNS_PCIE_AT_OB_REGION_PCI_ADDR0(r), addr0);
+ cdns_pcie_writel(pcie, CDNS_PCIE_AT_OB_REGION_PCI_ADDR1(r), addr1);
+
+ /* Set the PCIe header descriptor */
+ if (is_io)
+ desc0 = CDNS_PCIE_AT_OB_REGION_DESC0_TYPE_IO;
+ else
+ desc0 = CDNS_PCIE_AT_OB_REGION_DESC0_TYPE_MEM;
+ desc1 = 0;
+
+ if (pcie->is_rc) {
+ desc0 |= CDNS_PCIE_AT_OB_REGION_DESC0_HARDCODED_RID |
+ CDNS_PCIE_AT_OB_REGION_DESC0_DEVFN(0);
+ desc1 |= CDNS_PCIE_AT_OB_REGION_DESC1_BUS(pcie->bus);
+ }
+
+ cdns_pcie_writel(pcie, CDNS_PCIE_AT_OB_REGION_DESC0(r), desc0);
+ cdns_pcie_writel(pcie, CDNS_PCIE_AT_OB_REGION_DESC1(r), desc1);
+
+ /* Set the CPU address */
+ cpu_addr -= pcie->mem_res->start;
+ addr0 = CDNS_PCIE_AT_OB_REGION_CPU_ADDR0_NBITS(nbits) |
+ (lower_32_bits(cpu_addr) & GENMASK(31, 8));
+ addr1 = upper_32_bits(cpu_addr);
+
+ cdns_pcie_writel(pcie, CDNS_PCIE_AT_OB_REGION_CPU_ADDR0(r), addr0);
+ cdns_pcie_writel(pcie, CDNS_PCIE_AT_OB_REGION_CPU_ADDR1(r), addr1);
+}
+
+void cdns_pcie_set_outbound_region_for_normal_msg(struct cdns_pcie *pcie, u32 r,
+ u64 cpu_addr)
+{
+ u32 addr0, addr1, desc0, desc1;
+
+ desc0 = CDNS_PCIE_AT_OB_REGION_DESC0_TYPE_NORMAL_MSG;
+ desc1 = 0;
+ if (pcie->is_rc) {
+ desc0 |= CDNS_PCIE_AT_OB_REGION_DESC0_HARDCODED_RID |
+ CDNS_PCIE_AT_OB_REGION_DESC0_DEVFN(0);
+ desc1 |= CDNS_PCIE_AT_OB_REGION_DESC1_BUS(pcie->bus);
+ }
+
+ /* Set the CPU address */
+ cpu_addr -= pcie->mem_res->start;
+ addr0 = CDNS_PCIE_AT_OB_REGION_CPU_ADDR0_NBITS(17) |
+ (lower_32_bits(cpu_addr) & GENMASK(31, 8));
+ addr1 = upper_32_bits(cpu_addr);
+
+ cdns_pcie_writel(pcie, CDNS_PCIE_AT_OB_REGION_PCI_ADDR0(r), 0);
+ cdns_pcie_writel(pcie, CDNS_PCIE_AT_OB_REGION_PCI_ADDR1(r), 0);
+ cdns_pcie_writel(pcie, CDNS_PCIE_AT_OB_REGION_DESC0(r), desc0);
+ cdns_pcie_writel(pcie, CDNS_PCIE_AT_OB_REGION_DESC1(r), desc1);
+ cdns_pcie_writel(pcie, CDNS_PCIE_AT_OB_REGION_CPU_ADDR0(r), addr0);
+ cdns_pcie_writel(pcie, CDNS_PCIE_AT_OB_REGION_CPU_ADDR1(r), addr1);
+}
+
+void cdns_pcie_reset_outbound_region(struct cdns_pcie *pcie, u32 r)
+{
+ cdns_pcie_writel(pcie, CDNS_PCIE_AT_OB_REGION_PCI_ADDR0(r), 0);
+ cdns_pcie_writel(pcie, CDNS_PCIE_AT_OB_REGION_PCI_ADDR1(r), 0);
+
+ cdns_pcie_writel(pcie, CDNS_PCIE_AT_OB_REGION_DESC0(r), 0);
+ cdns_pcie_writel(pcie, CDNS_PCIE_AT_OB_REGION_DESC1(r), 0);
+
+ cdns_pcie_writel(pcie, CDNS_PCIE_AT_OB_REGION_CPU_ADDR0(r), 0);
+ cdns_pcie_writel(pcie, CDNS_PCIE_AT_OB_REGION_CPU_ADDR1(r), 0);
+}
diff --git a/drivers/pci/cadence/pcie-cadence.h b/drivers/pci/cadence/pcie-cadence.h
new file mode 100644
index 000000000000..195e23b7d4fe
--- /dev/null
+++ b/drivers/pci/cadence/pcie-cadence.h
@@ -0,0 +1,325 @@
+/*
+ * Cadence PCIe controller driver.
+ *
+ * Copyright (c) 2017 Cadence
+ *
+ * Author: Cyrille Pitchen <cyrille.pitchen-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 version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef _PCIE_CADENCE_H
+#define _PCIE_CADENCE_H
+
+#include <linux/kernel.h>
+#include <linux/pci.h>
+
+/*
+ * Local Management Registers
+ */
+#define CDNS_PCIE_LM_BASE 0x00100000
+
+/* Vendor ID Register */
+#define CDNS_PCIE_LM_ID (CDNS_PCIE_LM_BASE + 0x0044)
+#define CDNS_PCIE_LM_ID_VENDOR_MASK GENMASK(15, 0)
+#define CDNS_PCIE_LM_ID_VENDOR_SHIFT 0
+#define CDNS_PCIE_LM_ID_VENDOR(vid) \
+ (((vid) << CDNS_PCIE_LM_ID_VENDOR_SHIFT) & CDNS_PCIE_LM_ID_VENDOR_MASK)
+#define CDNS_PCIE_LM_ID_SUBSYS_MASK GENMASK(31, 16)
+#define CDNS_PCIE_LM_ID_SUBSYS_SHIFT 16
+#define CDNS_PCIE_LM_ID_SUBSYS(sub) \
+ (((sub) << CDNS_PCIE_LM_ID_SUBSYS_SHIFT) & CDNS_PCIE_LM_ID_SUBSYS_MASK)
+
+/* Root Port Requestor ID Register */
+#define CDNS_PCIE_LM_RP_RID (CDNS_PCIE_LM_BASE + 0x0228)
+#define CDNS_PCIE_LM_RP_RID_MASK GENMASK(15, 0)
+#define CDNS_PCIE_LM_RP_RID_SHIFT 0
+#define CDNS_PCIE_LM_RP_RID_(rid) \
+ (((rid) << CDNS_PCIE_LM_RP_RID_SHIFT) & CDNS_PCIE_LM_RP_RID_MASK)
+
+/* Endpoint Bus and Device Number Register */
+#define CDNS_PCIE_LM_EP_ID (CDNS_PCIE_LM_BASE + 0x022c)
+#define CDNS_PCIE_LM_EP_ID_DEV_MASK GENMASK(4, 0)
+#define CDNS_PCIE_LM_EP_ID_DEV_SHIFT 0
+#define CDNS_PCIE_LM_EP_ID_BUS_MASK GENMASK(15, 8)
+#define CDNS_PCIE_LM_EP_ID_BUS_SHIFT 8
+
+/* Endpoint Function f BAR b Configuration Registers */
+#define CDNS_PCIE_LM_EP_FUNC_BAR_CFG0(fn) \
+ (CDNS_PCIE_LM_BASE + 0x0240 + (fn) * 0x0008)
+#define CDNS_PCIE_LM_EP_FUNC_BAR_CFG1(fn) \
+ (CDNS_PCIE_LM_BASE + 0x0244 + (fn) * 0x0008)
+#define CDNS_PCIE_LM_EP_FUNC_BAR_CFG_BAR_APERTURE_MASK(b) \
+ (GENMASK(4, 0) << ((b) * 8))
+#define CDNS_PCIE_LM_EP_FUNC_BAR_CFG_BAR_APERTURE(b, a) \
+ (((a) << ((b) * 8)) & CDNS_PCIE_LM_EP_FUNC_BAR_CFG_BAR_APERTURE_MASK(b))
+#define CDNS_PCIE_LM_EP_FUNC_BAR_CFG_BAR_CTRL_MASK(b) \
+ (GENMASK(7, 5) << ((b) * 8))
+#define CDNS_PCIE_LM_EP_FUNC_BAR_CFG_BAR_CTRL(b, c) \
+ (((c) << ((b) * 8 + 5)) & CDNS_PCIE_LM_EP_FUNC_BAR_CFG_BAR_CTRL_MASK(b))
+
+/* Endpoint Function Configuration Register */
+#define CDNS_PCIE_LM_EP_FUNC_CFG (CDNS_PCIE_LM_BASE + 0x02c0)
+
+/* Root Complex BAR Configuration Register */
+#define CDNS_PCIE_LM_RC_BAR_CFG (CDNS_PCIE_LM_BASE + 0x0300)
+#define CDNS_PCIE_LM_RC_BAR_CFG_BAR0_APERTURE_MASK GENMASK(5, 0)
+#define CDNS_PCIE_LM_RC_BAR_CFG_BAR0_APERTURE(a) \
+ (((a) << 0) & CDNS_PCIE_LM_RC_BAR_CFG_BAR0_APERTURE_MASK)
+#define CDNS_PCIE_LM_RC_BAR_CFG_BAR0_CTRL_MASK GENMASK(8, 6)
+#define CDNS_PCIE_LM_RC_BAR_CFG_BAR0_CTRL(c) \
+ (((c) << 6) & CDNS_PCIE_LM_RC_BAR_CFG_BAR0_CTRL_MASK)
+#define CDNS_PCIE_LM_RC_BAR_CFG_BAR1_APERTURE_MASK GENMASK(13, 9)
+#define CDNS_PCIE_LM_RC_BAR_CFG_BAR1_APERTURE(a) \
+ (((a) << 9) & CDNS_PCIE_LM_RC_BAR_CFG_BAR1_APERTURE_MASK)
+#define CDNS_PCIE_LM_RC_BAR_CFG_BAR1_CTRL_MASK GENMASK(16, 14)
+#define CDNS_PCIE_LM_RC_BAR_CFG_BAR1_CTRL(c) \
+ (((c) << 14) & CDNS_PCIE_LM_RC_BAR_CFG_BAR1_CTRL_MASK)
+#define CDNS_PCIE_LM_RC_BAR_CFG_PREFETCH_MEM_ENABLE BIT(17)
+#define CDNS_PCIE_LM_RC_BAR_CFG_PREFETCH_MEM_32BITS 0
+#define CDNS_PCIE_LM_RC_BAR_CFG_PREFETCH_MEM_64BITS BIT(18)
+#define CDNS_PCIE_LM_RC_BAR_CFG_IO_ENABLE BIT(19)
+#define CDNS_PCIE_LM_RC_BAR_CFG_IO_16BITS 0
+#define CDNS_PCIE_LM_RC_BAR_CFG_IO_32BITS BIT(20)
+#define CDNS_PCIE_LM_RC_BAR_CFG_CHECK_ENABLE BIT(31)
+
+/* BAR control values applicable to both Endpoint Function and Root Complex */
+#define CDNS_PCIE_LM_BAR_CFG_CTRL_DISABLED 0x0
+#define CDNS_PCIE_LM_BAR_CFG_CTRL_IO_32BITS 0x1
+#define CDNS_PCIE_LM_BAR_CFG_CTRL_MEM_32BITS 0x4
+#define CDNS_PCIE_LM_BAR_CFG_CTRL_PREFETCH_MEM_32BITS 0x5
+#define CDNS_PCIE_LM_BAR_CFG_CTRL_MEM_64BITS 0x6
+#define CDNS_PCIE_LM_BAR_CFG_CTRL_PREFETCH_MEM_64BITS 0x7
+
+
+/*
+ * Endpoint Function Registers (PCI configuration space for endpoint functions)
+ */
+#define CDNS_PCIE_EP_FUNC_BASE(fn) (((fn) << 12) & GENMASK(19, 12))
+
+#define CDNS_PCIE_EP_FUNC_MSI_CAP_OFFSET 0x90
+
+/*
+ * Root Port Registers (PCI configuration space for the root port function)
+ */
+#define CDNS_PCIE_RP_BASE 0x00200000
+
+
+/*
+ * Address Translation Registers
+ */
+#define CDNS_PCIE_AT_BASE 0x00400000
+
+/* Region r Outbound AXI to PCIe Address Translation Register 0 */
+#define CDNS_PCIE_AT_OB_REGION_PCI_ADDR0(r) \
+ (CDNS_PCIE_AT_BASE + 0x0000 + ((r) & 0x1f) * 0x0020)
+#define CDNS_PCIE_AT_OB_REGION_PCI_ADDR0_NBITS_MASK GENMASK(5, 0)
+#define CDNS_PCIE_AT_OB_REGION_PCI_ADDR0_NBITS(nbits) \
+ (((nbits) - 1) & CDNS_PCIE_AT_OB_REGION_PCI_ADDR0_NBITS_MASK)
+#define CDNS_PCIE_AT_OB_REGION_PCI_ADDR0_DEVFN_MASK GENMASK(19, 12)
+#define CDNS_PCIE_AT_OB_REGION_PCI_ADDR0_DEVFN(devfn) \
+ (((devfn) << 12) & CDNS_PCIE_AT_OB_REGION_PCI_ADDR0_DEVFN_MASK)
+#define CDNS_PCIE_AT_OB_REGION_PCI_ADDR0_BUS_MASK GENMASK(27, 20)
+#define CDNS_PCIE_AT_OB_REGION_PCI_ADDR0_BUS(bus) \
+ (((bus) << 20) & CDNS_PCIE_AT_OB_REGION_PCI_ADDR0_BUS_MASK)
+
+/* Region r Outbound AXI to PCIe Address Translation Register 1 */
+#define CDNS_PCIE_AT_OB_REGION_PCI_ADDR1(r) \
+ (CDNS_PCIE_AT_BASE + 0x0004 + ((r) & 0x1f) * 0x0020)
+
+/* Region r Outbound PCIe Descriptor Register 0 */
+#define CDNS_PCIE_AT_OB_REGION_DESC0(r) \
+ (CDNS_PCIE_AT_BASE + 0x0008 + ((r) & 0x1f) * 0x0020)
+#define CDNS_PCIE_AT_OB_REGION_DESC0_TYPE_MASK GENMASK(3, 0)
+#define CDNS_PCIE_AT_OB_REGION_DESC0_TYPE_MEM 0x2
+#define CDNS_PCIE_AT_OB_REGION_DESC0_TYPE_IO 0x6
+#define CDNS_PCIE_AT_OB_REGION_DESC0_TYPE_CONF_TYPE0 0xa
+#define CDNS_PCIE_AT_OB_REGION_DESC0_TYPE_CONF_TYPE1 0xb
+#define CDNS_PCIE_AT_OB_REGION_DESC0_TYPE_NORMAL_MSG 0xc
+#define CDNS_PCIE_AT_OB_REGION_DESC0_TYPE_VENDOR_MSG 0xd
+/* Bit 23 MUST be set in RC mode. */
+#define CDNS_PCIE_AT_OB_REGION_DESC0_HARDCODED_RID BIT(23)
+#define CDNS_PCIE_AT_OB_REGION_DESC0_DEVFN_MASK GENMASK(31, 24)
+#define CDNS_PCIE_AT_OB_REGION_DESC0_DEVFN(devfn) \
+ (((devfn) << 24) & CDNS_PCIE_AT_OB_REGION_DESC0_DEVFN_MASK)
+
+/* Region r Outbound PCIe Descriptor Register 1 */
+#define CDNS_PCIE_AT_OB_REGION_DESC1(r) \
+ (CDNS_PCIE_AT_BASE + 0x000c + ((r) & 0x1f) * 0x0020)
+#define CDNS_PCIE_AT_OB_REGION_DESC1_BUS_MASK GENMASK(7, 0)
+#define CDNS_PCIE_AT_OB_REGION_DESC1_BUS(bus) \
+ ((bus) & CDNS_PCIE_AT_OB_REGION_DESC1_BUS_MASK)
+
+/* Region r AXI Region Base Address Register 0 */
+#define CDNS_PCIE_AT_OB_REGION_CPU_ADDR0(r) \
+ (CDNS_PCIE_AT_BASE + 0x0018 + ((r) & 0x1f) * 0x0020)
+#define CDNS_PCIE_AT_OB_REGION_CPU_ADDR0_NBITS_MASK GENMASK(5, 0)
+#define CDNS_PCIE_AT_OB_REGION_CPU_ADDR0_NBITS(nbits) \
+ (((nbits) - 1) & CDNS_PCIE_AT_OB_REGION_CPU_ADDR0_NBITS_MASK)
+
+/* Region r AXI Region Base Address Register 1 */
+#define CDNS_PCIE_AT_OB_REGION_CPU_ADDR1(r) \
+ (CDNS_PCIE_AT_BASE + 0x001c + ((r) & 0x1f) * 0x0020)
+
+/* Root Port BAR Inbound PCIe to AXI Address Translation Register */
+#define CDNS_PCIE_AT_IB_RP_BAR_ADDR0(bar) \
+ (CDNS_PCIE_AT_BASE + 0x0800 + (bar) * 0x0008)
+#define CDNS_PCIE_AT_IB_RP_BAR_ADDR0_NBITS_MASK GENMASK(5, 0)
+#define CDNS_PCIE_AT_IB_RP_BAR_ADDR0_NBITS(nbits) \
+ (((nbits) - 1) & CDNS_PCIE_AT_IB_RP_BAR_ADDR0_NBITS_MASK)
+#define CDNS_PCIE_AT_IB_RP_BAR_ADDR1(bar) \
+ (CDNS_PCIE_AT_BASE + 0x0804 + (bar) * 0x0008)
+
+enum cdns_pcie_rp_bar {
+ RP_BAR0,
+ RP_BAR1,
+ RP_NO_BAR
+};
+
+/* Endpoint Function BAR Inbound PCIe to AXI Address Translation Register */
+#define CDNS_PCIE_AT_IB_EP_FUNC_BAR_ADDR0(fn, bar) \
+ (CDNS_PCIE_AT_BASE + 0x0840 + (fn) * 0x0040 + (bar) * 0x0008)
+#define CDNS_PCIE_AT_IB_EP_FUNC_BAR_ADDR1(fn, bar) \
+ (CDNS_PCIE_AT_BASE + 0x0844 + (fn) * 0x0040 + (bar) * 0x0008)
+
+/* Normal/Vendor specific message access: offset inside some outbound region */
+#define CDNS_PCIE_NORMAL_MSG_ROUTING_MASK GENMASK(7, 5)
+#define CDNS_PCIE_NORMAL_MSG_ROUTING(route) \
+ (((route) << 5) & CDNS_PCIE_NORMAL_MSG_ROUTING_MASK)
+#define CDNS_PCIE_NORMAL_MSG_CODE_MASK GENMASK(15, 8)
+#define CDNS_PCIE_NORMAL_MSG_CODE(code) \
+ (((code) << 8) & CDNS_PCIE_NORMAL_MSG_CODE_MASK)
+#define CDNS_PCIE_MSG_NO_DATA BIT(16)
+
+enum cdns_pcie_msg_code {
+ MSG_CODE_ASSERT_INTA = 0x20,
+ MSG_CODE_ASSERT_INTB = 0x21,
+ MSG_CODE_ASSERT_INTC = 0x22,
+ MSG_CODE_ASSERT_INTD = 0x23,
+ MSG_CODE_DEASSERT_INTA = 0x24,
+ MSG_CODE_DEASSERT_INTB = 0x25,
+ MSG_CODE_DEASSERT_INTC = 0x26,
+ MSG_CODE_DEASSERT_INTD = 0x27,
+};
+
+enum cdns_pcie_msg_routing {
+ /* Route to Root Complex */
+ MSG_ROUTING_TO_RC,
+
+ /* Use Address Routing */
+ MSG_ROUTING_BY_ADDR,
+
+ /* Use ID Routing */
+ MSG_ROUTING_BY_ID,
+
+ /* Route as Broadcast Message from Root Complex */
+ MSG_ROUTING_BCAST,
+
+ /* Local message; terminate at receiver (INTx messages) */
+ MSG_ROUTING_LOCAL,
+
+ /* Gather & route to Root Complex (PME_TO_Ack message) */
+ MSG_ROUTING_GATHER,
+};
+
+/**
+ * struct cdns_pcie - private data for Cadence PCIe controller drivers
+ * @reg_base: IO mapped register base
+ * @mem_res: start/end offsets in the physical system memory to map PCI accesses
+ * @is_rc: tell whether the PCIe controller mode is Root Complex or Endpoint.
+ * @bus: In Root Complex mode, the bus number
+ */
+struct cdns_pcie {
+ void __iomem *reg_base;
+ struct resource *mem_res;
+ bool is_rc;
+ u8 bus;
+};
+
+/* Register access */
+static inline void cdns_pcie_writeb(struct cdns_pcie *pcie, u32 reg, u8 value)
+{
+ writeb(value, pcie->reg_base + reg);
+}
+
+static inline void cdns_pcie_writew(struct cdns_pcie *pcie, u32 reg, u16 value)
+{
+ writew(value, pcie->reg_base + reg);
+}
+
+static inline void cdns_pcie_writel(struct cdns_pcie *pcie, u32 reg, u32 value)
+{
+ writel(value, pcie->reg_base + reg);
+}
+
+static inline u32 cdns_pcie_readl(struct cdns_pcie *pcie, u32 reg)
+{
+ return readl(pcie->reg_base + reg);
+}
+
+/* Root Port register access */
+static inline void cdns_pcie_rp_writeb(struct cdns_pcie *pcie,
+ u32 reg, u8 value)
+{
+ writeb(value, pcie->reg_base + CDNS_PCIE_RP_BASE + reg);
+}
+
+static inline void cdns_pcie_rp_writew(struct cdns_pcie *pcie,
+ u32 reg, u16 value)
+{
+ writew(value, pcie->reg_base + CDNS_PCIE_RP_BASE + reg);
+}
+
+/* Endpoint Function register access */
+static inline void cdns_pcie_ep_fn_writeb(struct cdns_pcie *pcie, u8 fn,
+ u32 reg, u8 value)
+{
+ writeb(value, pcie->reg_base + CDNS_PCIE_EP_FUNC_BASE(fn) + reg);
+}
+
+static inline void cdns_pcie_ep_fn_writew(struct cdns_pcie *pcie, u8 fn,
+ u32 reg, u16 value)
+{
+ writew(value, pcie->reg_base + CDNS_PCIE_EP_FUNC_BASE(fn) + reg);
+}
+
+static inline void cdns_pcie_ep_fn_writel(struct cdns_pcie *pcie, u8 fn,
+ u32 reg, u16 value)
+{
+ writel(value, pcie->reg_base + CDNS_PCIE_EP_FUNC_BASE(fn) + reg);
+}
+
+static inline u8 cdns_pcie_ep_fn_readb(struct cdns_pcie *pcie, u8 fn, u32 reg)
+{
+ return readb(pcie->reg_base + CDNS_PCIE_EP_FUNC_BASE(fn) + reg);
+}
+
+static inline u16 cdns_pcie_ep_fn_readw(struct cdns_pcie *pcie, u8 fn, u32 reg)
+{
+ return readw(pcie->reg_base + CDNS_PCIE_EP_FUNC_BASE(fn) + reg);
+}
+
+static inline u32 cdns_pcie_ep_fn_readl(struct cdns_pcie *pcie, u8 fn, u32 reg)
+{
+ return readl(pcie->reg_base + CDNS_PCIE_EP_FUNC_BASE(fn) + reg);
+}
+
+void cdns_pcie_set_outbound_region(struct cdns_pcie *pcie, u32 r, bool is_io,
+ u64 cpu_addr, u64 pci_addr, size_t size);
+
+void cdns_pcie_set_outbound_region_for_normal_msg(struct cdns_pcie *pcie, u32 r,
+ u64 cpu_addr);
+
+void cdns_pcie_reset_outbound_region(struct cdns_pcie *pcie, u32 r);
+
+#endif /* _PCIE_CADENCE_H */
--
2.11.0
--
To unsubscribe from this list: send the line "unsubscribe devicetree" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
^ permalink raw reply related
* [PATCH 4/5] dt-bindings: PCI: cadence: Add DT bindings for Cadence PCIe endpoint controller
From: Cyrille Pitchen @ 2017-11-23 15:01 UTC (permalink / raw)
To: bhelgaas, kishon, lorenzo.pieralisi, linux-pci
Cc: adouglas, stelford, dgary, kgopi, eandrews, thomas.petazzoni,
sureshp, nsekhar, linux-kernel, robh, devicetree, Cyrille Pitchen
In-Reply-To: <cover.1511439189.git.cyrille.pitchen@free-electrons.com>
This patch documents the DT bindings for the Cadence PCIe controller
when configured in endpoint mode.
Signed-off-by: Cyrille Pitchen <cyrille.pitchen@free-electrons.com>
---
.../devicetree/bindings/pci/cdns,cdns-pcie-ep.txt | 20 ++++++++++++++++++++
1 file changed, 20 insertions(+)
create mode 100644 Documentation/devicetree/bindings/pci/cdns,cdns-pcie-ep.txt
diff --git a/Documentation/devicetree/bindings/pci/cdns,cdns-pcie-ep.txt b/Documentation/devicetree/bindings/pci/cdns,cdns-pcie-ep.txt
new file mode 100644
index 000000000000..d4168d79cceb
--- /dev/null
+++ b/Documentation/devicetree/bindings/pci/cdns,cdns-pcie-ep.txt
@@ -0,0 +1,20 @@
+* Cadence PCIe endpoint controller
+
+Required properties:
+- compatible: should contain "cdns,cdns-pcie-ep" to identify the IP used.
+- reg: should contain the controller register base address and AXI interface
+ region base address respectively.
+- reg-names: Must be "reg" and "mem" respectively.
+
+Optional properties:
+- max-functions: maximum number of functions that can be configured.
+
+Example:
+
+ pci@fc000000 {
+ compatible = "cdns,cdns-pcie-ep";
+ reg = <0x0 0xfc000000 0x0 0x01000000>, /* Base Address */
+ <0x0 0x80000000 0x0 0x40000000>; /* AXI region */
+ reg-names = "reg", "mem";
+ max-functions = /bits/ 8 <8>;
+ };
--
2.11.0
^ permalink raw reply related
* [PATCH 5/5] PCI: cadence: add EndPoint Controller driver for Cadence PCIe controller
From: Cyrille Pitchen @ 2017-11-23 15:01 UTC (permalink / raw)
To: bhelgaas, kishon, lorenzo.pieralisi, linux-pci
Cc: adouglas, stelford, dgary, kgopi, eandrews, thomas.petazzoni,
sureshp, nsekhar, linux-kernel, robh, devicetree, Cyrille Pitchen
In-Reply-To: <cover.1511439189.git.cyrille.pitchen@free-electrons.com>
This patch adds support to the Cadence PCIe controller in endpoint mode.
Signed-off-by: Cyrille Pitchen <cyrille.pitchen@free-electrons.com>
---
drivers/pci/cadence/Kconfig | 9 +
drivers/pci/cadence/Makefile | 1 +
drivers/pci/cadence/pcie-cadence-ep.c | 553 ++++++++++++++++++++++++++++++++++
3 files changed, 563 insertions(+)
create mode 100644 drivers/pci/cadence/pcie-cadence-ep.c
diff --git a/drivers/pci/cadence/Kconfig b/drivers/pci/cadence/Kconfig
index 120306cae2aa..b2e6af71f39e 100644
--- a/drivers/pci/cadence/Kconfig
+++ b/drivers/pci/cadence/Kconfig
@@ -21,4 +21,13 @@ config PCIE_CADENCE_HOST
mode. This PCIe controller may be embedded into many different vendors
SoCs.
+config PCIE_CADENCE_EP
+ bool "Cadence PCIe endpoint controller"
+ depends on PCI_ENDPOINT
+ select PCIE_CADENCE
+ help
+ Say Y here if you want to support the Cadence PCIe controller in
+ endpoint mode. This PCIe controller may be embedded into many
+ different vendors SoCs.
+
endif # PCI_CADENCE
diff --git a/drivers/pci/cadence/Makefile b/drivers/pci/cadence/Makefile
index d57d192d2595..61e9c8d6839d 100644
--- a/drivers/pci/cadence/Makefile
+++ b/drivers/pci/cadence/Makefile
@@ -1,2 +1,3 @@
obj-$(CONFIG_PCIE_CADENCE) += pcie-cadence.o
obj-$(CONFIG_PCIE_CADENCE_HOST) += pcie-cadence-host.o
+obj-$(CONFIG_PCIE_CADENCE_EP) += pcie-cadence-ep.o
diff --git a/drivers/pci/cadence/pcie-cadence-ep.c b/drivers/pci/cadence/pcie-cadence-ep.c
new file mode 100644
index 000000000000..a1d761101a9c
--- /dev/null
+++ b/drivers/pci/cadence/pcie-cadence-ep.c
@@ -0,0 +1,553 @@
+/*
+ * Cadence PCIe host controller driver.
+ *
+ * Copyright (c) 2017 Cadence
+ *
+ * Author: Cyrille Pitchen <cyrille.pitchen@free-electrons.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+#include <linux/kernel.h>
+#include <linux/of.h>
+#include <linux/pci-epc.h>
+#include <linux/platform_device.h>
+#include <linux/pm_runtime.h>
+#include <linux/sizes.h>
+#include <linux/delay.h>
+
+#include "pcie-cadence.h"
+
+#define CDNS_PCIE_EP_MIN_APERTURE 128 /* 128 bytes */
+#define CDNS_PCIE_EP_IRQ_PCI_ADDR_NONE 0x1
+#define CDNS_PCIE_EP_IRQ_PCI_ADDR_LEGACY 0x3
+
+/**
+ * struct cdns_pcie_ep_data - hardware specific data
+ * @max_regions: maximum nmuber of regions supported by hardware
+ */
+struct cdns_pcie_ep_data {
+ size_t max_regions;
+};
+
+/**
+ * struct cdns_pcie_ep - private data for this PCIe endpoint controller driver
+ * @pcie: Cadence PCIe controller
+ * @data: pointer to a 'struct cdns_pcie_data'
+ */
+struct cdns_pcie_ep {
+ struct cdns_pcie pcie;
+ const struct cdns_pcie_ep_data *data;
+ struct pci_epc *epc;
+ unsigned long ob_region_map;
+ phys_addr_t *ob_addr;
+ phys_addr_t irq_phys_addr;
+ void __iomem *irq_cpu_addr;
+ u64 irq_pci_addr;
+ u8 irq_pending;
+};
+
+static int cdns_pcie_ep_write_header(struct pci_epc *epc,
+ struct pci_epf_header *hdr)
+{
+ struct cdns_pcie_ep *ep = epc_get_drvdata(epc);
+ struct cdns_pcie *pcie = &ep->pcie;
+ u8 fn = 0;
+
+ if (fn == 0) {
+ u32 id = CDNS_PCIE_LM_ID_VENDOR(hdr->vendorid) |
+ CDNS_PCIE_LM_ID_SUBSYS(hdr->subsys_vendor_id);
+ cdns_pcie_writel(pcie, CDNS_PCIE_LM_ID, id);
+ }
+ cdns_pcie_ep_fn_writew(pcie, fn, PCI_DEVICE_ID, hdr->deviceid);
+ cdns_pcie_ep_fn_writeb(pcie, fn, PCI_REVISION_ID, hdr->revid);
+ cdns_pcie_ep_fn_writeb(pcie, fn, PCI_CLASS_PROG, hdr->progif_code);
+ cdns_pcie_ep_fn_writew(pcie, fn, PCI_CLASS_DEVICE,
+ hdr->subclass_code | hdr->baseclass_code << 8);
+ cdns_pcie_ep_fn_writeb(pcie, fn, PCI_CACHE_LINE_SIZE,
+ hdr->cache_line_size);
+ cdns_pcie_ep_fn_writew(pcie, fn, PCI_SUBSYSTEM_ID, hdr->subsys_id);
+ cdns_pcie_ep_fn_writeb(pcie, fn, PCI_INTERRUPT_PIN, hdr->interrupt_pin);
+
+ return 0;
+}
+
+static int cdns_pcie_ep_set_bar(struct pci_epc *epc, enum pci_barno bar,
+ dma_addr_t bar_phys, size_t size, int flags)
+{
+ struct cdns_pcie_ep *ep = epc_get_drvdata(epc);
+ struct cdns_pcie *pcie = &ep->pcie;
+ u32 addr0, addr1, reg, cfg, b, aperture, ctrl;
+ u8 fn = 0;
+ u64 sz;
+
+ /* BAR size is 2^(aperture + 7) */
+ sz = max_t(size_t, size, CDNS_PCIE_EP_MIN_APERTURE);
+ sz = 1ULL << fls64(sz - 1);
+ aperture = ilog2(sz) - 7; /* 128B -> 0, 256B -> 1, 512B -> 2, ... */
+
+ if ((flags & PCI_BASE_ADDRESS_SPACE) == PCI_BASE_ADDRESS_SPACE_IO) {
+ ctrl = CDNS_PCIE_LM_BAR_CFG_CTRL_IO_32BITS;
+ } else {
+ bool is_prefetch = !!(flags & PCI_BASE_ADDRESS_MEM_PREFETCH);
+ bool is_64bits = sz > SZ_2G;
+
+ if (is_64bits && (bar & 1))
+ return -EINVAL;
+
+ switch (is_64bits << 1 | is_prefetch) {
+ case 0:
+ ctrl = CDNS_PCIE_LM_BAR_CFG_CTRL_MEM_32BITS;
+ break;
+
+ case 1:
+ ctrl = CDNS_PCIE_LM_BAR_CFG_CTRL_PREFETCH_MEM_32BITS;
+ break;
+
+ case 2:
+ ctrl = CDNS_PCIE_LM_BAR_CFG_CTRL_MEM_64BITS;
+ break;
+
+ case 3:
+ ctrl = CDNS_PCIE_LM_BAR_CFG_CTRL_PREFETCH_MEM_64BITS;
+ break;
+ }
+ }
+
+ addr0 = lower_32_bits(bar_phys);
+ addr1 = upper_32_bits(bar_phys);
+ cdns_pcie_writel(pcie, CDNS_PCIE_AT_IB_EP_FUNC_BAR_ADDR0(fn, bar),
+ addr0);
+ cdns_pcie_writel(pcie, CDNS_PCIE_AT_IB_EP_FUNC_BAR_ADDR1(fn, bar),
+ addr1);
+
+ if (bar < BAR_4) {
+ reg = CDNS_PCIE_LM_EP_FUNC_BAR_CFG0(fn);
+ b = bar;
+ } else {
+ reg = CDNS_PCIE_LM_EP_FUNC_BAR_CFG1(fn);
+ b = bar - BAR_4;
+ }
+
+ cfg = cdns_pcie_readl(pcie, reg);
+ cfg &= ~(CDNS_PCIE_LM_EP_FUNC_BAR_CFG_BAR_APERTURE_MASK(b) |
+ CDNS_PCIE_LM_EP_FUNC_BAR_CFG_BAR_CTRL_MASK(b));
+ cfg |= (CDNS_PCIE_LM_EP_FUNC_BAR_CFG_BAR_APERTURE(b, aperture) |
+ CDNS_PCIE_LM_EP_FUNC_BAR_CFG_BAR_CTRL(b, ctrl));
+ cdns_pcie_writel(pcie, reg, cfg);
+
+ return 0;
+}
+
+static void cdns_pcie_ep_clear_bar(struct pci_epc *epc, enum pci_barno bar)
+{
+ struct cdns_pcie_ep *ep = epc_get_drvdata(epc);
+ struct cdns_pcie *pcie = &ep->pcie;
+ u32 reg, cfg, b, ctrl;
+ u8 fn = 0;
+
+ if (bar < BAR_4) {
+ reg = CDNS_PCIE_LM_EP_FUNC_BAR_CFG0(fn);
+ b = bar;
+ } else {
+ reg = CDNS_PCIE_LM_EP_FUNC_BAR_CFG1(fn);
+ b = bar - BAR_4;
+ }
+
+ ctrl = CDNS_PCIE_LM_BAR_CFG_CTRL_DISABLED;
+ cfg = cdns_pcie_readl(pcie, reg);
+ cfg &= ~(CDNS_PCIE_LM_EP_FUNC_BAR_CFG_BAR_APERTURE_MASK(b) |
+ CDNS_PCIE_LM_EP_FUNC_BAR_CFG_BAR_CTRL_MASK(b));
+ cfg |= CDNS_PCIE_LM_EP_FUNC_BAR_CFG_BAR_CTRL_MASK(ctrl);
+ cdns_pcie_writel(pcie, reg, cfg);
+
+ cdns_pcie_writel(pcie, CDNS_PCIE_AT_IB_EP_FUNC_BAR_ADDR0(fn, bar), 0);
+ cdns_pcie_writel(pcie, CDNS_PCIE_AT_IB_EP_FUNC_BAR_ADDR1(fn, bar), 0);
+}
+
+static int cdns_pcie_ep_map_addr(struct pci_epc *epc, phys_addr_t addr,
+ u64 pci_addr, size_t size)
+{
+ struct cdns_pcie_ep *ep = epc_get_drvdata(epc);
+ struct cdns_pcie *pcie = &ep->pcie;
+ u32 r;
+
+ r = find_first_zero_bit(&ep->ob_region_map, sizeof(ep->ob_region_map));
+ if (r >= ep->data->max_regions - 1) {
+ dev_err(&epc->dev, "no free outbound region\n");
+ return -EINVAL;
+ }
+
+ cdns_pcie_set_outbound_region(pcie, r, false, addr, pci_addr, size);
+
+ set_bit(r, &ep->ob_region_map);
+ ep->ob_addr[r] = addr;
+
+ return 0;
+}
+
+static void cdns_pcie_ep_unmap_addr(struct pci_epc *epc, phys_addr_t addr)
+{
+ struct cdns_pcie_ep *ep = epc_get_drvdata(epc);
+ struct cdns_pcie *pcie = &ep->pcie;
+ u32 r;
+
+ for (r = 0; r < ep->data->max_regions - 1; r++)
+ if (ep->ob_addr[r] == addr)
+ break;
+
+ if (r >= ep->data->max_regions - 1)
+ return;
+
+ cdns_pcie_reset_outbound_region(pcie, r);
+
+ ep->ob_addr[r] = 0;
+ clear_bit(r, &ep->ob_region_map);
+}
+
+static int cdns_pcie_ep_set_msi(struct pci_epc *epc, u8 mmc)
+{
+ struct cdns_pcie_ep *ep = epc_get_drvdata(epc);
+ struct cdns_pcie *pcie = &ep->pcie;
+ u32 cap = CDNS_PCIE_EP_FUNC_MSI_CAP_OFFSET;
+ u16 flags;
+ u8 fn = 0;
+
+ /* Validate the ID of the MSI Capability structure. */
+ if (cdns_pcie_ep_fn_readb(pcie, fn, cap) != PCI_CAP_ID_MSI)
+ return -EINVAL;
+
+ /*
+ * Set the Multiple Message Capable bitfield into the Message Control
+ * register.
+ */
+ flags = cdns_pcie_ep_fn_readw(pcie, fn, cap + PCI_MSI_FLAGS);
+ flags = (flags & ~PCI_MSI_FLAGS_QMASK) | (mmc << 1);
+ flags |= PCI_MSI_FLAGS_64BIT;
+ flags &= ~PCI_MSI_FLAGS_MASKBIT;
+ cdns_pcie_ep_fn_writew(pcie, fn, cap + PCI_MSI_FLAGS, flags);
+
+ return 0;
+}
+
+static int cdns_pcie_ep_get_msi(struct pci_epc *epc)
+{
+ struct cdns_pcie_ep *ep = epc_get_drvdata(epc);
+ struct cdns_pcie *pcie = &ep->pcie;
+ u32 cap = CDNS_PCIE_EP_FUNC_MSI_CAP_OFFSET;
+ u16 flags, mmc, mme;
+ u8 fn = 0;
+
+ /* Validate the ID of the MSI Capability structure. */
+ if (cdns_pcie_ep_fn_readb(pcie, fn, cap) != PCI_CAP_ID_MSI)
+ return -EINVAL;
+
+ /* Validate that the MSI feature is actually enabled. */
+ flags = cdns_pcie_ep_fn_readw(pcie, fn, cap + PCI_MSI_FLAGS);
+ if (!(flags & PCI_MSI_FLAGS_ENABLE))
+ return -EINVAL;
+
+ /*
+ * Get the Multiple Message Enable bitfield from the Message Control
+ * register.
+ */
+ mmc = (flags & PCI_MSI_FLAGS_QMASK) >> 1;
+ mme = (flags & PCI_MSI_FLAGS_QSIZE) >> 4;
+ if (mme > mmc)
+ mme = mmc;
+ if (mme > 5)
+ mme = 5;
+
+ return mme;
+}
+
+static void cdns_pcie_ep_assert_intx(struct cdns_pcie_ep *ep, u8 fn,
+ u8 intx, bool is_asserted)
+{
+ struct cdns_pcie *pcie = &ep->pcie;
+ u32 r = ep->data->max_regions - 1;
+ u32 offset;
+ u16 status;
+ u8 msg_code;
+
+ intx &= 3;
+
+ /* Set the outbound region if needed. */
+ if (unlikely(ep->irq_pci_addr != CDNS_PCIE_EP_IRQ_PCI_ADDR_LEGACY)) {
+ /* Last region was reserved for IRQ writes. */
+ cdns_pcie_set_outbound_region_for_normal_msg(pcie, r,
+ ep->irq_phys_addr);
+ ep->irq_pci_addr = CDNS_PCIE_EP_IRQ_PCI_ADDR_LEGACY;
+ }
+
+ if (is_asserted) {
+ ep->irq_pending |= BIT(intx);
+ msg_code = MSG_CODE_ASSERT_INTA + intx;
+ } else {
+ ep->irq_pending &= ~BIT(intx);
+ msg_code = MSG_CODE_DEASSERT_INTA + intx;
+ }
+
+ status = cdns_pcie_ep_fn_readw(pcie, fn, PCI_STATUS);
+ if (((status & PCI_STATUS_INTERRUPT) != 0) ^ (ep->irq_pending != 0)) {
+ status ^= PCI_STATUS_INTERRUPT;
+ cdns_pcie_ep_fn_writew(pcie, fn, PCI_STATUS, status);
+ }
+
+ offset = CDNS_PCIE_NORMAL_MSG_ROUTING(MSG_ROUTING_LOCAL) |
+ CDNS_PCIE_NORMAL_MSG_CODE(msg_code) |
+ CDNS_PCIE_MSG_NO_DATA;
+ writel(0, ep->irq_cpu_addr + offset);
+}
+
+static int cdns_pcie_ep_send_legacy_irq(struct cdns_pcie_ep *ep, u8 fn, u8 intx)
+{
+ u16 cmd;
+
+ cmd = cdns_pcie_ep_fn_readw(&ep->pcie, fn, PCI_COMMAND);
+ if (cmd & PCI_COMMAND_INTX_DISABLE)
+ return -EINVAL;
+
+ cdns_pcie_ep_assert_intx(ep, fn, intx, true);
+ mdelay(1);
+ cdns_pcie_ep_assert_intx(ep, fn, intx, false);
+ return 0;
+}
+
+static int cdns_pcie_ep_raise_irq(struct pci_epc *epc,
+ enum pci_epc_irq_type type, u8 interrupt_num)
+{
+ struct cdns_pcie_ep *ep = epc_get_drvdata(epc);
+ struct cdns_pcie *pcie = &ep->pcie;
+ u32 cap = CDNS_PCIE_EP_FUNC_MSI_CAP_OFFSET;
+ u16 flags, mmc, mme, data, data_mask;
+ u8 msi_count;
+ u64 pci_addr, pci_addr_mask = 0xff;
+ u8 fn = 0;
+
+ /* Handle legacy IRQ. */
+ if (type == PCI_EPC_IRQ_LEGACY)
+ return cdns_pcie_ep_send_legacy_irq(ep, fn, 0);
+
+ /* Otherwise MSI. */
+ if (type != PCI_EPC_IRQ_MSI)
+ return -EINVAL;
+
+ /* Check whether the MSI feature has been enabled by the PCI host. */
+ flags = cdns_pcie_ep_fn_readw(pcie, fn, cap + PCI_MSI_FLAGS);
+ if (!(flags & PCI_MSI_FLAGS_ENABLE))
+ return -EINVAL;
+
+ /* Get the number of enabled MSIs */
+ mmc = (flags & PCI_MSI_FLAGS_QMASK) >> 1;
+ mme = (flags & PCI_MSI_FLAGS_QSIZE) >> 4;
+ if (mme > mmc)
+ mme = mmc;
+ if (mme > 5)
+ mme = 5;
+
+ msi_count = 1 << mme;
+ if (!interrupt_num || interrupt_num > msi_count)
+ return -EINVAL;
+
+ /* Compute the data value to be written. */
+ data_mask = msi_count - 1;
+ data = cdns_pcie_ep_fn_readw(pcie, fn, cap + PCI_MSI_DATA_64);
+ data = (data & ~data_mask) | ((interrupt_num - 1) & data_mask);
+
+ /* Get the PCI address where to write the data into. */
+ pci_addr = cdns_pcie_ep_fn_readl(pcie, fn, cap + PCI_MSI_ADDRESS_HI);
+ pci_addr <<= 32;
+ pci_addr |= cdns_pcie_ep_fn_readl(pcie, fn, cap + PCI_MSI_ADDRESS_LO);
+ pci_addr &= GENMASK_ULL(63, 2);
+
+ /* Set the outbound region if needed. */
+ if (unlikely(ep->irq_pci_addr != pci_addr)) {
+ /* Last region was reserved for IRQ writes. */
+ cdns_pcie_set_outbound_region(pcie, ep->data->max_regions - 1,
+ false,
+ ep->irq_phys_addr,
+ pci_addr & ~pci_addr_mask,
+ pci_addr_mask + 1);
+ ep->irq_pci_addr = pci_addr;
+ }
+ writew(data, ep->irq_cpu_addr + (pci_addr & pci_addr_mask));
+
+ return 0;
+}
+
+static int cdns_pcie_ep_start(struct pci_epc *epc)
+{
+ struct cdns_pcie_ep *ep = epc_get_drvdata(epc);
+ struct cdns_pcie *pcie = &ep->pcie;
+ struct pci_epf *epf;
+ u32 cfg;
+ u8 fn = 0;
+
+ /* Enable this endpoint function. */
+ cfg = cdns_pcie_readl(pcie, CDNS_PCIE_LM_EP_FUNC_CFG);
+ cfg |= BIT(fn);
+ cdns_pcie_writel(pcie, CDNS_PCIE_LM_EP_FUNC_CFG, cfg);
+
+ /*
+ * Already linked-up: don't call directly pci_epc_linkup() because we've
+ * already locked the epc->lock.
+ */
+ list_for_each_entry(epf, &epc->pci_epf, list)
+ pci_epf_linkup(epf);
+
+ return 0;
+}
+
+static void cdns_pcie_ep_stop(struct pci_epc *epc)
+{
+ struct cdns_pcie_ep *ep = epc_get_drvdata(epc);
+ struct cdns_pcie *pcie = &ep->pcie;
+ u32 cfg;
+ u8 fn = 0;
+
+ /* Disable this endpoint function (function 0 can't be disabled). */
+ cfg = cdns_pcie_readl(pcie, CDNS_PCIE_LM_EP_FUNC_CFG);
+ cfg &= ~BIT(fn);
+ cdns_pcie_writel(pcie, CDNS_PCIE_LM_EP_FUNC_CFG, cfg);
+}
+
+static const struct pci_epc_ops cdns_pcie_epc_ops = {
+ .write_header = cdns_pcie_ep_write_header,
+ .set_bar = cdns_pcie_ep_set_bar,
+ .clear_bar = cdns_pcie_ep_clear_bar,
+ .map_addr = cdns_pcie_ep_map_addr,
+ .unmap_addr = cdns_pcie_ep_unmap_addr,
+ .set_msi = cdns_pcie_ep_set_msi,
+ .get_msi = cdns_pcie_ep_get_msi,
+ .raise_irq = cdns_pcie_ep_raise_irq,
+ .start = cdns_pcie_ep_start,
+ .stop = cdns_pcie_ep_stop,
+};
+
+static const struct cdns_pcie_ep_data cdns_pcie_ep_data = {
+ .max_regions = 16,
+};
+
+static const struct of_device_id cdns_pcie_ep_of_match[] = {
+ { .compatible = "cdns,cdns-pcie-ep",
+ .data = &cdns_pcie_ep_data },
+
+ { },
+};
+
+static int cdns_pcie_ep_probe(struct platform_device *pdev)
+{
+ struct device *dev = &pdev->dev;
+ struct device_node *np = dev->of_node;
+ const struct of_device_id *of_id;
+ struct cdns_pcie_ep *ep;
+ struct cdns_pcie *pcie;
+ struct pci_epc *epc;
+ struct resource *res;
+ size_t max_regions;
+ int ret;
+
+ ep = devm_kzalloc(dev, sizeof(*ep), GFP_KERNEL);
+ if (!ep)
+ return -ENOMEM;
+
+ platform_set_drvdata(pdev, ep);
+
+ pcie = &ep->pcie;
+ pcie->is_rc = false;
+
+ of_id = of_match_node(cdns_pcie_ep_of_match, np);
+ ep->data = (const struct cdns_pcie_ep_data *)of_id->data;
+
+ res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "reg");
+ pcie->reg_base = devm_ioremap_resource(dev, res);
+ if (IS_ERR(pcie->reg_base)) {
+ dev_err(dev, "missing \"reg\"\n");
+ return PTR_ERR(pcie->reg_base);
+ }
+
+ res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "mem");
+ if (!res) {
+ dev_err(dev, "missing \"mem\"\n");
+ return -EINVAL;
+ }
+ pcie->mem_res = res;
+
+ max_regions = ep->data->max_regions;
+ ep->ob_addr = devm_kzalloc(dev, max_regions * sizeof(*ep->ob_addr),
+ GFP_KERNEL);
+ if (!ep->ob_addr)
+ return -ENOMEM;
+
+ pm_runtime_enable(dev);
+ ret = pm_runtime_get_sync(dev);
+ if (ret < 0) {
+ dev_err(dev, "pm_runtime_get_sync() failed\n");
+ goto err_get_sync;
+ }
+
+ /* Disable all but function 0 (anyway BIT(0) is hardwired to 1). */
+ cdns_pcie_writel(pcie, CDNS_PCIE_LM_EP_FUNC_CFG, BIT(0));
+
+ epc = devm_pci_epc_create(dev, &cdns_pcie_epc_ops);
+ if (IS_ERR(epc)) {
+ dev_err(dev, "failed to create epc device\n");
+ ret = PTR_ERR(epc);
+ goto err_init;
+ }
+
+ ep->epc = epc;
+ epc_set_drvdata(epc, ep);
+
+ ret = of_property_read_u8(np, "max-functions", &epc->max_functions);
+ if (ret < 0)
+ epc->max_functions = 1;
+
+ ret = pci_epc_mem_init(epc, pcie->mem_res->start,
+ resource_size(pcie->mem_res));
+ if (ret < 0) {
+ dev_err(dev, "failed to initialize the memory space\n");
+ goto err_init;
+ }
+
+ ep->irq_cpu_addr = pci_epc_mem_alloc_addr(epc, &ep->irq_phys_addr,
+ SZ_128K);
+ if (!ep->irq_cpu_addr) {
+ dev_err(dev, "failed to reserve memory space for MSI\n");
+ ret = -ENOMEM;
+ goto free_epc_mem;
+ }
+ ep->irq_pci_addr = CDNS_PCIE_EP_IRQ_PCI_ADDR_NONE;
+
+ return 0;
+
+ free_epc_mem:
+ pci_epc_mem_exit(epc);
+
+ err_init:
+ pm_runtime_put_sync(dev);
+
+ err_get_sync:
+ pm_runtime_disable(dev);
+
+ return ret;
+}
+
+static struct platform_driver cdns_pcie_ep_driver = {
+ .driver = {
+ .name = "cdns-pcie-ep",
+ .of_match_table = cdns_pcie_ep_of_match,
+ },
+ .probe = cdns_pcie_ep_probe,
+};
+builtin_platform_driver(cdns_pcie_ep_driver);
--
2.11.0
^ permalink raw reply related
* Re: [PATCH 1/5] drm/panel: Add support for the EDT ETM0700G0BDH6
From: Fabio Estevam @ 2017-11-23 15:08 UTC (permalink / raw)
To: Jan Tuerk
Cc: Rob Herring, Mark Rutland, Thierry Reding, David Airlie,
Russell King, Shawn Guo, Sascha Hauer, Fabio Estevam,
Andreas Färber, Kevin Hilman, Maxime Ripard,
Alexandre Belloni, Greg Kroah-Hartman, SZ Lin,
devicetree-u79uwXL29TY76Z2rM5mHXA@public.gmane.org, linux-kernel,
DRI mailing list,
linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r
In-Reply-To: <20171123125600.41562-2-jan.tuerk-BU0Y/NROKIhBDgjK7y7TUQ@public.gmane.org>
Hi Jan,
On Thu, Nov 23, 2017 at 10:55 AM, Jan Tuerk <jan.tuerk-BU0Y/NROKIhBDgjK7y7TUQ@public.gmane.org> wrote:
> The Emerging Display Technology ETM0700G0BDH6 is exactly
> the same display as the ETM0700G0DH6, exept the pixelclock
> polarity. Therefore re-use the ETM0700G0DH6 modes. It is
> used by default on emtrion Avari based development kits.
>
> Signed-off-by: Jan Tuerk <jan.tuerk-BU0Y/NROKIhBDgjK7y7TUQ@public.gmane.org>
Please run ./scripts/checkpatch.pl on your patch. Currently it gives:
total: 18 errors, 13 warnings, 39 lines checked
Please fix and resend. Also, you could try git send-email in the next time.
Regards,
Fabio Estevam
--
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
* [PATCH 0/3] True RNG driver for Samsung Exynos 5250+ SoCs
From: Łukasz Stelmach @ 2017-11-23 15:09 UTC (permalink / raw)
To: Rob Herring, Matt Mackall, Herbert Xu, Krzysztof Kozlowski,
devicetree, linux-crypto, linux-samsung-soc, linux-kernel
Cc: Marek Szyprowski, Bartlomiej Zolnierkiewicz, Łukasz Stelmach
In-Reply-To: <CGME20171123150956eucas1p2e6d42c88692291e4e0d0e7719519bf35@eucas1p2.samsung.com>
Hello.
The following patches add support for the true random number generator
found in Samsung Exynos 5250+ SoCs.
Patch #1 adds documentation for devicetree bindings.
Patch #2 introduces the driver and appropriate changes in Makefile and Kconfig.
Patch #3 adds nodes in devicetree files for Exynos SoCs.
Łukasz Stelmach (3):
dt-bindings: hwrng: Add Samsung Exynos 5250+ True RNG bindings
hwrng: exynos - add Samsung Exynos True RNG driver
ARM: dts: exynos: Add nodes for True Random Number Generator
.../bindings/rng/samsung,exynos5250-trng.txt | 17 ++
MAINTAINERS | 7 +
arch/arm/boot/dts/exynos5.dtsi | 5 +
arch/arm/boot/dts/exynos5250.dtsi | 5 +
arch/arm/boot/dts/exynos5410.dtsi | 5 +
arch/arm/boot/dts/exynos5420.dtsi | 5 +
drivers/char/hw_random/Kconfig | 12 +
drivers/char/hw_random/Makefile | 1 +
drivers/char/hw_random/exynos-trng.c | 256 +++++++++++++++++++++
9 files changed, 313 insertions(+)
create mode 100644 Documentation/devicetree/bindings/rng/samsung,exynos5250-trng.txt
create mode 100644 drivers/char/hw_random/exynos-trng.c
--
2.11.0
^ permalink raw reply
* [PATCH 1/3] dt-bindings: hwrng: Add Samsung Exynos 5250+ True RNG bindings
From: Łukasz Stelmach @ 2017-11-23 15:09 UTC (permalink / raw)
To: Rob Herring, Matt Mackall, Herbert Xu, Krzysztof Kozlowski,
devicetree-u79uwXL29TY76Z2rM5mHXA,
linux-crypto-u79uwXL29TY76Z2rM5mHXA,
linux-samsung-soc-u79uwXL29TY76Z2rM5mHXA,
linux-kernel-u79uwXL29TY76Z2rM5mHXA
Cc: Marek Szyprowski, Bartlomiej Zolnierkiewicz, Łukasz Stelmach
In-Reply-To: <20171123150914.31462-1-l.stelmach-Sze3O3UU22JBDgjK7y7TUQ@public.gmane.org>
Add binding documentation for the True Random Number Generator
found on Samsung Exynos 5250+ SoCs.
Signed-off-by: Łukasz Stelmach <l.stelmach-Sze3O3UU22JBDgjK7y7TUQ@public.gmane.org>
---
.../devicetree/bindings/rng/samsung,exynos5250-trng.txt | 17 +++++++++++++++++
1 file changed, 17 insertions(+)
create mode 100644 Documentation/devicetree/bindings/rng/samsung,exynos5250-trng.txt
diff --git a/Documentation/devicetree/bindings/rng/samsung,exynos5250-trng.txt b/Documentation/devicetree/bindings/rng/samsung,exynos5250-trng.txt
new file mode 100644
index 000000000000..22dfe8cb21c0
--- /dev/null
+++ b/Documentation/devicetree/bindings/rng/samsung,exynos5250-trng.txt
@@ -0,0 +1,17 @@
+Exynos True Random Number Generator
+
+Required properties:
+
+- compatible : Should be "samsung,exynos5250-trng".
+- reg : Specifies base physical address and size of the registers map.
+- clocks : Phandle to clock-controller plus clock-specifier pair.
+- clock-names : "secss" as a clock name.
+
+Example:
+
+ trng@10830600 {
+ compatible = "samsung,exynos5250-trng";
+ reg = <0x10830600 0x100>;
+ clocks = <&clock CLK_SSS>;
+ clock-names = "secss";
+ };
--
2.11.0
--
To unsubscribe from this list: send the line "unsubscribe devicetree" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
^ permalink raw reply related
* [PATCH 2/3] hwrng: exynos - add Samsung Exynos True RNG driver
From: Łukasz Stelmach @ 2017-11-23 15:09 UTC (permalink / raw)
To: Rob Herring, Matt Mackall, Herbert Xu, Krzysztof Kozlowski,
devicetree, linux-crypto, linux-samsung-soc, linux-kernel
Cc: Marek Szyprowski, Bartlomiej Zolnierkiewicz, Łukasz Stelmach
In-Reply-To: <20171123150914.31462-1-l.stelmach@samsung.com>
Add support for True Random Number Generator found in Samsung Exynos
5250+ SoCs.
Signed-off-by: Łukasz Stelmach <l.stelmach@samsung.com>
---
MAINTAINERS | 7 +
drivers/char/hw_random/Kconfig | 12 ++
drivers/char/hw_random/Makefile | 1 +
drivers/char/hw_random/exynos-trng.c | 256 +++++++++++++++++++++++++++++++++++
4 files changed, 276 insertions(+)
create mode 100644 drivers/char/hw_random/exynos-trng.c
diff --git a/MAINTAINERS b/MAINTAINERS
index 2811a211632c..992074cca612 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -11780,6 +11780,13 @@ S: Maintained
F: drivers/crypto/exynos-rng.c
F: Documentation/devicetree/bindings/rng/samsung,exynos-rng4.txt
+SAMSUNG EXYNOS TRUE RANDOM NUMBER GENERATOR (TRNG) DRIVER
+M: Łukasz Stelmach <l.stelmach@samsung.com>
+L: linux-samsung-soc@vger.kernel.org
+S: Maintained
+F: drivers/char/hw_random/exynos-trng.c
+F: Documentation/devicetree/bindings/rng/samsung,exynos5250-trng.txt
+
SAMSUNG FRAMEBUFFER DRIVER
M: Jingoo Han <jingoohan1@gmail.com>
L: linux-fbdev@vger.kernel.org
diff --git a/drivers/char/hw_random/Kconfig b/drivers/char/hw_random/Kconfig
index 95a031e9eced..a788ac07081b 100644
--- a/drivers/char/hw_random/Kconfig
+++ b/drivers/char/hw_random/Kconfig
@@ -449,6 +449,18 @@ config HW_RANDOM_S390
If unsure, say Y.
+config HW_RANDOM_EXYNOS
+ tristate "Samsung Exynos True Random Number Generator support"
+ depends on ARCH_EXYNOS || COMPILE_TEST
+ default HW_RANDOM
+ ---help---
+ This driver provides support for the True Random Number
+ Generator available in Exynos SoCs.
+
+ To compile this driver as a module, choose M here: the module
+ will be called exynos-trng.
+
+ If unsure, say Y.
endif # HW_RANDOM
config UML_RANDOM
diff --git a/drivers/char/hw_random/Makefile b/drivers/char/hw_random/Makefile
index f3728d008fff..5595df97da7a 100644
--- a/drivers/char/hw_random/Makefile
+++ b/drivers/char/hw_random/Makefile
@@ -14,6 +14,7 @@ obj-$(CONFIG_HW_RANDOM_GEODE) += geode-rng.o
obj-$(CONFIG_HW_RANDOM_N2RNG) += n2-rng.o
n2-rng-y := n2-drv.o n2-asm.o
obj-$(CONFIG_HW_RANDOM_VIA) += via-rng.o
+obj-$(CONFIG_HW_RANDOM_EXYNOS) += exynos-trng.o
obj-$(CONFIG_HW_RANDOM_IXP4XX) += ixp4xx-rng.o
obj-$(CONFIG_HW_RANDOM_OMAP) += omap-rng.o
obj-$(CONFIG_HW_RANDOM_OMAP3_ROM) += omap3-rom-rng.o
diff --git a/drivers/char/hw_random/exynos-trng.c b/drivers/char/hw_random/exynos-trng.c
new file mode 100644
index 000000000000..340e106cae24
--- /dev/null
+++ b/drivers/char/hw_random/exynos-trng.c
@@ -0,0 +1,256 @@
+/*
+ * RNG driver for Exynos TRNGs
+ *
+ * Author: Łukasz Stelmach <l.stelmach@samsung.com>
+ *
+ * Copyright 2017 (c) Samsung Electronics Software, Inc.
+ *
+ * Based on the Exynos PRNG driver drivers/crypto/exynos-rng by
+ * Krzysztof Kozłowski <krzk@kernel.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;
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/clk.h>
+#include <linux/crypto.h>
+#include <linux/delay.h>
+#include <linux/err.h>
+#include <linux/hw_random.h>
+#include <linux/io.h>
+#include <linux/iopoll.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/pm_runtime.h>
+
+#define EXYNOS_TRNG_CLKDIV (0x0)
+#define EXYNOS_TRNG_CTRL (0x20)
+#define EXYNOS_TRNG_POST_CTRL (0x30)
+#define EXYNOS_TRNG_ONLINE_CTRL (0x40)
+#define EXYNOS_TRNG_ONLINE_STAT (0x44)
+#define EXYNOS_TRNG_ONLINE_MAXCHI2 (0x48)
+#define EXYNOS_TRNG_FIFO_CTRL (0x50)
+#define EXYNOS_TRNG_FIFO_0 (0x80)
+#define EXYNOS_TRNG_FIFO_1 (0x84)
+#define EXYNOS_TRNG_FIFO_2 (0x88)
+#define EXYNOS_TRNG_FIFO_3 (0x8c)
+#define EXYNOS_TRNG_FIFO_4 (0x90)
+#define EXYNOS_TRNG_FIFO_5 (0x94)
+#define EXYNOS_TRNG_FIFO_6 (0x98)
+#define EXYNOS_TRNG_FIFO_7 (0x9c)
+#define EXYNOS_TRNG_FIFO_LEN (8)
+#define EXYNOS_TRNG_CLOCK_RATE (500000)
+
+struct exynos_trng_dev {
+ struct device *dev;
+ void __iomem *mem;
+ struct clk *clk;
+ struct hwrng rng;
+};
+
+struct exynos_trng_dev *exynos_trng_dev;
+
+static inline void exynos_trng_set_reg(struct exynos_trng_dev *trng, u16 reg,
+ u32 val)
+{
+ /* Check range of reg? */
+ __raw_writel(val, trng->mem + reg);
+}
+
+static inline u32 exynos_trng_get_reg(struct exynos_trng_dev *trng, u16 reg)
+{
+ /* Check range of reg? */
+ return __raw_readl(trng->mem + reg);
+}
+
+static int exynos_trng_do_read(struct hwrng *rng, void *data, size_t max,
+ bool wait)
+{
+ struct exynos_trng_dev *trng;
+ u32 val;
+
+ max = max > (EXYNOS_TRNG_FIFO_LEN * 4) ?
+ (EXYNOS_TRNG_FIFO_LEN * 4) : max;
+
+ trng = (struct exynos_trng_dev *)rng->priv;
+
+ exynos_trng_set_reg(trng, EXYNOS_TRNG_FIFO_CTRL, max * 8);
+ val = readl_poll_timeout(trng->mem + EXYNOS_TRNG_FIFO_CTRL, val,
+ val == 0, 200, 1000000);
+ if (val < 0)
+ return val;
+
+ memcpy_fromio(data, trng->mem + EXYNOS_TRNG_FIFO_0, max);
+
+ return max;
+}
+
+static int exynos_trng_init(struct hwrng *rng)
+{
+ struct exynos_trng_dev *trng;
+ unsigned long sss_rate;
+ u32 val;
+
+ trng = (struct exynos_trng_dev *)rng->priv;
+ sss_rate = clk_get_rate(trng->clk);
+
+ /* For most TRNG circuits the clock frequency of under 500 kHz
+ * is safe.
+ */
+ val = sss_rate / (EXYNOS_TRNG_CLOCK_RATE * 2);
+ if (val > 0x7fff) {
+ dev_err(trng->dev, "clock divider too large: %d", val);
+ return -ERANGE;
+ }
+ val = val << 1;
+ exynos_trng_set_reg(trng, EXYNOS_TRNG_CLKDIV, val);
+
+ /* Enable the generator. */
+ val = 1 << 31;
+ exynos_trng_set_reg(trng, EXYNOS_TRNG_CTRL, val);
+
+ /* Disable post processing. /dev/hwrng is supposed to deliver
+ * unprocessed data.
+ */
+ exynos_trng_set_reg(trng, EXYNOS_TRNG_POST_CTRL, 0);
+
+ return 0;
+}
+
+static int exynos_trng_probe(struct platform_device *pdev)
+{
+ struct exynos_trng_dev *trng;
+ struct resource *res;
+ int ret = -ENOMEM;
+
+ if (exynos_trng_dev)
+ return -EEXIST;
+
+ trng = devm_kzalloc(&pdev->dev, sizeof(*trng), GFP_KERNEL);
+ if (!trng)
+ goto err_ioremap;
+
+ trng->rng.name = devm_kstrdup(&pdev->dev, dev_name(&pdev->dev),
+ GFP_KERNEL);
+ if (!trng->rng.name)
+ goto err_ioremap;
+
+ trng->rng.init = exynos_trng_init;
+ trng->rng.read = exynos_trng_do_read;
+ trng->rng.priv = (unsigned long) trng;
+
+ platform_set_drvdata(pdev, trng);
+ trng->dev = &pdev->dev;
+
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ trng->mem = devm_ioremap_resource(&pdev->dev, res);
+ if (IS_ERR(trng->mem)) {
+ dev_err(&pdev->dev, "Couldn't map IO resources.\n");
+ ret = PTR_ERR(trng->mem);
+ goto err_ioremap;
+ }
+
+ pm_runtime_enable(&pdev->dev);
+ ret = pm_runtime_get_sync(&pdev->dev);
+ if (ret < 0) {
+ dev_err(&pdev->dev, "pm_runtime_get_sync() failed: %d.\n", ret);
+ goto err_ioremap;
+ }
+
+ trng->clk = devm_clk_get(&pdev->dev, "secss");
+ if (IS_ERR(trng->clk)) {
+ /* XXX: EPROBE_DEFER ? */
+ dev_err(&pdev->dev, "Couldn't get clock.\n");
+ ret = PTR_ERR(trng->clk);
+ goto err_clock;
+ }
+
+ ret = clk_prepare_enable(trng->clk);
+ if (ret) {
+ dev_err(&pdev->dev, "Unable to enable the clk: %d.\n", ret);
+ goto err_clock;
+ }
+
+ ret = hwrng_register(&trng->rng);
+ if (ret) {
+ dev_err(&pdev->dev, "Couldn't register hwrng device.\n");
+ goto err_register;
+ }
+
+ dev_info(&pdev->dev, "Exynos True Random Number Generator.\n");
+
+ return 0;
+
+err_register:
+ clk_disable_unprepare(trng->clk);
+
+err_clock:
+ trng->mem = NULL;
+ pm_runtime_put_sync(&pdev->dev);
+ pm_runtime_disable(&pdev->dev);
+
+err_ioremap:
+ dev_err(&pdev->dev, "Initialisation failed.\n");
+ return ret;
+}
+
+static int exynos_trng_remove(struct platform_device *pdev)
+{
+ exynos_trng_dev = NULL;
+
+ return 0;
+}
+
+static int __maybe_unused exynos_trng_suspend(struct device *dev)
+{
+ pm_runtime_put_sync(dev);
+
+ return 0;
+}
+
+static int __maybe_unused exynos_trng_resume(struct device *dev)
+{
+ int ret;
+
+ ret = pm_runtime_get_sync(dev);
+ if (ret < 0) {
+ dev_err(dev, "pm_runtime_get_sync() failed: %d.\n", ret);
+ pm_runtime_put_noidle(dev);
+ return ret;
+ }
+
+ return 0;
+}
+
+static SIMPLE_DEV_PM_OPS(exynos_trng_pm_ops, exynos_trng_suspend,
+ exynos_trng_resume);
+
+static const struct of_device_id exynos_trng_dt_match[] = {
+ {
+ .compatible = "samsung,exynos5250-trng",
+ },
+ { },
+};
+MODULE_DEVICE_TABLE(of, exynos_rng_dt_match);
+
+static struct platform_driver exynos_trng_driver = {
+ .driver = {
+ .name = "exynos-trng",
+ .pm = &exynos_trng_pm_ops,
+ .of_match_table = exynos_trng_dt_match,
+ },
+ .probe = exynos_trng_probe,
+ .remove = exynos_trng_remove,
+};
+
+module_platform_driver(exynos_trng_driver);
+MODULE_AUTHOR("Łukasz Stelmach");
+MODULE_DESCRIPTION("H/W TRNG driver for Exynos chips");
+MODULE_LICENSE("GPL");
--
2.11.0
^ permalink raw reply related
* [PATCH 3/3] ARM: dts: exynos: Add nodes for True Random Number Generator
From: Łukasz Stelmach @ 2017-11-23 15:09 UTC (permalink / raw)
To: Rob Herring, Matt Mackall, Herbert Xu, Krzysztof Kozlowski,
devicetree, linux-crypto, linux-samsung-soc, linux-kernel
Cc: Marek Szyprowski, Bartlomiej Zolnierkiewicz, Łukasz Stelmach
In-Reply-To: <20171123150914.31462-1-l.stelmach@samsung.com>
Add nodes for the True Random Number Generator found in Samsung Exynos
5250+ SoCs.
Signed-off-by: Łukasz Stelmach <l.stelmach@samsung.com>
---
arch/arm/boot/dts/exynos5.dtsi | 5 +++++
arch/arm/boot/dts/exynos5250.dtsi | 5 +++++
arch/arm/boot/dts/exynos5410.dtsi | 5 +++++
arch/arm/boot/dts/exynos5420.dtsi | 5 +++++
4 files changed, 20 insertions(+)
diff --git a/arch/arm/boot/dts/exynos5.dtsi b/arch/arm/boot/dts/exynos5.dtsi
index 7da4a4285b24..6a298b536e1c 100644
--- a/arch/arm/boot/dts/exynos5.dtsi
+++ b/arch/arm/boot/dts/exynos5.dtsi
@@ -210,5 +210,10 @@
reg = <0x10830000 0x300>;
interrupts = <GIC_SPI 112 IRQ_TYPE_LEVEL_HIGH>;
};
+
+ trng: trng@10830600 {
+ compatible = "samsung,exynos5250-trng";
+ reg = <0x10830600 0x100>;
+ };
};
};
diff --git a/arch/arm/boot/dts/exynos5250.dtsi b/arch/arm/boot/dts/exynos5250.dtsi
index 8032d7e567fc..332fe04b772b 100644
--- a/arch/arm/boot/dts/exynos5250.dtsi
+++ b/arch/arm/boot/dts/exynos5250.dtsi
@@ -1081,4 +1081,9 @@
clock-names = "secss";
};
+&trng {
+ clocks = <&clock CLK_SSS>;
+ clock-names = "secss";
+};
+
#include "exynos5250-pinctrl.dtsi"
diff --git a/arch/arm/boot/dts/exynos5410.dtsi b/arch/arm/boot/dts/exynos5410.dtsi
index 7eab4bc07cec..f3991206a562 100644
--- a/arch/arm/boot/dts/exynos5410.dtsi
+++ b/arch/arm/boot/dts/exynos5410.dtsi
@@ -379,6 +379,11 @@
3 0 0x07000000 0x20000>;
};
+&trng {
+ clocks = <&clock CLK_SSS>;
+ clock-names = "secss";
+};
+
&usbdrd3_0 {
clocks = <&clock CLK_USBD300>;
clock-names = "usbdrd30";
diff --git a/arch/arm/boot/dts/exynos5420.dtsi b/arch/arm/boot/dts/exynos5420.dtsi
index 02d2f898efa6..2f4e5542f354 100644
--- a/arch/arm/boot/dts/exynos5420.dtsi
+++ b/arch/arm/boot/dts/exynos5420.dtsi
@@ -1454,6 +1454,11 @@
clock-names = "secss";
};
+&trng {
+ clocks = <&clock CLK_SSS>;
+ clock-names = "secss";
+};
+
&usbdrd3_0 {
clocks = <&clock CLK_USBD300>;
clock-names = "usbdrd30";
--
2.11.0
^ permalink raw reply related
* AW: [PATCH 1/5] drm/panel: Add support for the EDT ETM0700G0BDH6
From: Türk, Jan @ 2017-11-23 15:18 UTC (permalink / raw)
To: 'Fabio Estevam'
Cc: Rob Herring, Mark Rutland, Thierry Reding, David Airlie,
Russell King, Shawn Guo, Sascha Hauer, Fabio Estevam,
Andreas Färber, Kevin Hilman, Maxime Ripard,
Alexandre Belloni, Greg Kroah-Hartman, SZ Lin,
devicetree-u79uwXL29TY76Z2rM5mHXA@public.gmane.org, linux-kernel,
DRI mailing list
In-Reply-To: <CAOMZO5D_xAWAnuH47BjAt4xNtz=c2dGn+kL6X8gW_auOTmDq5g-JsoAwUIsXosN+BqQ9rBEUg@public.gmane.org>
[-- Warning: decoded text below may be mangled, UTF-8 assumed --]
[-- Attachment #1: Type: text/plain; charset="utf-8", Size: 641 bytes --]
Hi Fabio,
I've used git send-email and tested the patches by checkpatch.pl before without any problems.
So it might have been touched by the mail server, so can you send me your checkpatch.pl log (directly)?
Regards,
Jan Tuerk
emtrion GmbH
Kreativpark - Alter Schlachthof 45
76131 Karlsruhe
GERMANY
http://www.emtrion.de
_______________________________________
Amtsgericht Mannheim
HRB 110 300
Geschäftsführer: Dieter Baur, Ramona Maurer
_______________________________________
N§²æìr¸yúèØb²X¬¶Ç§vØ^)Þº{.nÇ+·zøzÚÞz)í
æèw*\x1fjg¬±¨\x1e¶Ý¢j.ïÛ°\½½MúgjÌæa×\x02' ©Þ¢¸\f¢·¦j:+v¨wèjØm¶ÿ¾\a«êçzZ+ùÝ¢j"ú!¶i
^ permalink raw reply
* Re: [PATCH 2/3] hwrng: exynos - add Samsung Exynos True RNG driver
From: Andrew F. Davis @ 2017-11-23 15:45 UTC (permalink / raw)
To: Łukasz Stelmach, Rob Herring, Matt Mackall, Herbert Xu,
Krzysztof Kozlowski, devicetree, linux-crypto, linux-samsung-soc,
linux-kernel
Cc: Marek Szyprowski, Bartlomiej Zolnierkiewicz
In-Reply-To: <20171123150914.31462-3-l.stelmach@samsung.com>
On 11/23/2017 09:09 AM, Łukasz Stelmach wrote:
> Add support for True Random Number Generator found in Samsung Exynos
> 5250+ SoCs.
>
> Signed-off-by: Łukasz Stelmach <l.stelmach@samsung.com>
> ---
> MAINTAINERS | 7 +
> drivers/char/hw_random/Kconfig | 12 ++
> drivers/char/hw_random/Makefile | 1 +
> drivers/char/hw_random/exynos-trng.c | 256 +++++++++++++++++++++++++++++++++++
> 4 files changed, 276 insertions(+)
> create mode 100644 drivers/char/hw_random/exynos-trng.c
>
> diff --git a/MAINTAINERS b/MAINTAINERS
> index 2811a211632c..992074cca612 100644
> --- a/MAINTAINERS
> +++ b/MAINTAINERS
> @@ -11780,6 +11780,13 @@ S: Maintained
> F: drivers/crypto/exynos-rng.c
> F: Documentation/devicetree/bindings/rng/samsung,exynos-rng4.txt
>
> +SAMSUNG EXYNOS TRUE RANDOM NUMBER GENERATOR (TRNG) DRIVER
> +M: Łukasz Stelmach <l.stelmach@samsung.com>
> +L: linux-samsung-soc@vger.kernel.org
> +S: Maintained
> +F: drivers/char/hw_random/exynos-trng.c
> +F: Documentation/devicetree/bindings/rng/samsung,exynos5250-trng.txt
> +
> SAMSUNG FRAMEBUFFER DRIVER
> M: Jingoo Han <jingoohan1@gmail.com>
> L: linux-fbdev@vger.kernel.org
> diff --git a/drivers/char/hw_random/Kconfig b/drivers/char/hw_random/Kconfig
> index 95a031e9eced..a788ac07081b 100644
> --- a/drivers/char/hw_random/Kconfig
> +++ b/drivers/char/hw_random/Kconfig
> @@ -449,6 +449,18 @@ config HW_RANDOM_S390
>
> If unsure, say Y.
>
> +config HW_RANDOM_EXYNOS
> + tristate "Samsung Exynos True Random Number Generator support"
> + depends on ARCH_EXYNOS || COMPILE_TEST
> + default HW_RANDOM
> + ---help---
> + This driver provides support for the True Random Number
> + Generator available in Exynos SoCs.
> +
Some whitespace strangness here.
> + To compile this driver as a module, choose M here: the module
> + will be called exynos-trng.
> +
> + If unsure, say Y.
> endif # HW_RANDOM
>
> config UML_RANDOM
> diff --git a/drivers/char/hw_random/Makefile b/drivers/char/hw_random/Makefile
> index f3728d008fff..5595df97da7a 100644
> --- a/drivers/char/hw_random/Makefile
> +++ b/drivers/char/hw_random/Makefile
> @@ -14,6 +14,7 @@ obj-$(CONFIG_HW_RANDOM_GEODE) += geode-rng.o
> obj-$(CONFIG_HW_RANDOM_N2RNG) += n2-rng.o
> n2-rng-y := n2-drv.o n2-asm.o
> obj-$(CONFIG_HW_RANDOM_VIA) += via-rng.o
> +obj-$(CONFIG_HW_RANDOM_EXYNOS) += exynos-trng.o
> obj-$(CONFIG_HW_RANDOM_IXP4XX) += ixp4xx-rng.o
> obj-$(CONFIG_HW_RANDOM_OMAP) += omap-rng.o
> obj-$(CONFIG_HW_RANDOM_OMAP3_ROM) += omap3-rom-rng.o
> diff --git a/drivers/char/hw_random/exynos-trng.c b/drivers/char/hw_random/exynos-trng.c
> new file mode 100644
> index 000000000000..340e106cae24
> --- /dev/null
> +++ b/drivers/char/hw_random/exynos-trng.c
> @@ -0,0 +1,256 @@
> +/*
> + * RNG driver for Exynos TRNGs
> + *
> + * Author: Łukasz Stelmach <l.stelmach@samsung.com>
> + *
> + * Copyright 2017 (c) Samsung Electronics Software, Inc.
> + *
> + * Based on the Exynos PRNG driver drivers/crypto/exynos-rng by
> + * Krzysztof Kozłowski <krzk@kernel.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;
> + *
> + * This program is distributed in the hope that it will be useful,
> + * but WITHOUT ANY WARRANTY; without even the implied warranty of
> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
> + * GNU General Public License for more details.
> + */
> +
> +#include <linux/clk.h>
> +#include <linux/crypto.h>
> +#include <linux/delay.h>
> +#include <linux/err.h>
> +#include <linux/hw_random.h>
> +#include <linux/io.h>
> +#include <linux/iopoll.h>
> +#include <linux/kernel.h>
> +#include <linux/module.h>
> +#include <linux/platform_device.h>
> +#include <linux/pm_runtime.h>
> +
> +#define EXYNOS_TRNG_CLKDIV (0x0)
> +#define EXYNOS_TRNG_CTRL (0x20)
> +#define EXYNOS_TRNG_POST_CTRL (0x30)
> +#define EXYNOS_TRNG_ONLINE_CTRL (0x40)
> +#define EXYNOS_TRNG_ONLINE_STAT (0x44)
> +#define EXYNOS_TRNG_ONLINE_MAXCHI2 (0x48)
> +#define EXYNOS_TRNG_FIFO_CTRL (0x50)
> +#define EXYNOS_TRNG_FIFO_0 (0x80)
> +#define EXYNOS_TRNG_FIFO_1 (0x84)
> +#define EXYNOS_TRNG_FIFO_2 (0x88)
> +#define EXYNOS_TRNG_FIFO_3 (0x8c)
> +#define EXYNOS_TRNG_FIFO_4 (0x90)
> +#define EXYNOS_TRNG_FIFO_5 (0x94)
> +#define EXYNOS_TRNG_FIFO_6 (0x98)
> +#define EXYNOS_TRNG_FIFO_7 (0x9c)
> +#define EXYNOS_TRNG_FIFO_LEN (8)
> +#define EXYNOS_TRNG_CLOCK_RATE (500000)
> +
> +struct exynos_trng_dev {
> + struct device *dev;
> + void __iomem *mem;
> + struct clk *clk;
> + struct hwrng rng;
> +};
> +
> +struct exynos_trng_dev *exynos_trng_dev;
This only seems to be used as a flag to block this driver from probing
twice, but it doesn't even do that as it is not ever set to anything.
Even if it was, why block a system from having two?
> +
> +static inline void exynos_trng_set_reg(struct exynos_trng_dev *trng, u16 reg,
> + u32 val)
> +{
> + /* Check range of reg? */
> + __raw_writel(val, trng->mem + reg);
If you are not checking, then just drop this one line function, it adds
nothing.
> +}
> +
> +static inline u32 exynos_trng_get_reg(struct exynos_trng_dev *trng, u16 reg)
> +{
> + /* Check range of reg? */
> + return __raw_readl(trng->mem + reg);
Same
> +}
> +
> +static int exynos_trng_do_read(struct hwrng *rng, void *data, size_t max,
> + bool wait)
> +{
> + struct exynos_trng_dev *trng;
> + u32 val;
> +
> + max = max > (EXYNOS_TRNG_FIFO_LEN * 4) ?
> + (EXYNOS_TRNG_FIFO_LEN * 4) : max;
min()
> +
> + trng = (struct exynos_trng_dev *)rng->priv;
> +
> + exynos_trng_set_reg(trng, EXYNOS_TRNG_FIFO_CTRL, max * 8);
> + val = readl_poll_timeout(trng->mem + EXYNOS_TRNG_FIFO_CTRL, val,
> + val == 0, 200, 1000000);
> + if (val < 0)
> + return val;
> +
> + memcpy_fromio(data, trng->mem + EXYNOS_TRNG_FIFO_0, max);
> +
> + return max;
> +}
> +
> +static int exynos_trng_init(struct hwrng *rng)
> +{
> + struct exynos_trng_dev *trng;
> + unsigned long sss_rate;
> + u32 val;
> +
> + trng = (struct exynos_trng_dev *)rng->priv;
Move up to initializer.
> + sss_rate = clk_get_rate(trng->clk);
> +
> + /* For most TRNG circuits the clock frequency of under 500 kHz
> + * is safe.
> + */
> + val = sss_rate / (EXYNOS_TRNG_CLOCK_RATE * 2);
> + if (val > 0x7fff) {
> + dev_err(trng->dev, "clock divider too large: %d", val);
> + return -ERANGE;
> + }
> + val = val << 1;
> + exynos_trng_set_reg(trng, EXYNOS_TRNG_CLKDIV, val);
> +
> + /* Enable the generator. */
> + val = 1 << 31;
#define TRNG_CTRL_ENABLE BIT(31)
> + exynos_trng_set_reg(trng, EXYNOS_TRNG_CTRL, val);
> +
> + /* Disable post processing. /dev/hwrng is supposed to deliver
> + * unprocessed data.
> + */
> + exynos_trng_set_reg(trng, EXYNOS_TRNG_POST_CTRL, 0);
> +
> + return 0;
> +}
> +
> +static int exynos_trng_probe(struct platform_device *pdev)
> +{
> + struct exynos_trng_dev *trng;
> + struct resource *res;
> + int ret = -ENOMEM;
> +
> + if (exynos_trng_dev)
> + return -EEXIST;
> +
> + trng = devm_kzalloc(&pdev->dev, sizeof(*trng), GFP_KERNEL);
> + if (!trng)
> + goto err_ioremap;
> +
> + trng->rng.name = devm_kstrdup(&pdev->dev, dev_name(&pdev->dev),
> + GFP_KERNEL);
> + if (!trng->rng.name)
> + goto err_ioremap;
> +
> + trng->rng.init = exynos_trng_init;
> + trng->rng.read = exynos_trng_do_read;
> + trng->rng.priv = (unsigned long) trng;
> +
> + platform_set_drvdata(pdev, trng);
> + trng->dev = &pdev->dev;
> +
> + res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
> + trng->mem = devm_ioremap_resource(&pdev->dev, res);
> + if (IS_ERR(trng->mem)) {
> + dev_err(&pdev->dev, "Couldn't map IO resources.\n");
> + ret = PTR_ERR(trng->mem);
> + goto err_ioremap;
> + }
> +
> + pm_runtime_enable(&pdev->dev);
> + ret = pm_runtime_get_sync(&pdev->dev);
> + if (ret < 0) {
> + dev_err(&pdev->dev, "pm_runtime_get_sync() failed: %d.\n", ret);
"Could not get runtime PM",
Be descriptive an consistent, the other dev_errs don't print ret, it
will get printed as part of the probe fail message.
> + goto err_ioremap;
> + }
> +
> + trng->clk = devm_clk_get(&pdev->dev, "secss");
> + if (IS_ERR(trng->clk)) {
> + /* XXX: EPROBE_DEFER ? */
Are you asking? If it's posible the clock is not available then yes, you
should not print the below message and exit gracefully.
> + dev_err(&pdev->dev, "Couldn't get clock.\n");
> + ret = PTR_ERR(trng->clk);
> + goto err_clock;
> + }
> +
> + ret = clk_prepare_enable(trng->clk);
> + if (ret) {
> + dev_err(&pdev->dev, "Unable to enable the clk: %d.\n", ret);
> + goto err_clock;
> + }
> +
> + ret = hwrng_register(&trng->rng);
> + if (ret) {
> + dev_err(&pdev->dev, "Couldn't register hwrng device.\n");
> + goto err_register;
> + }
> +
> + dev_info(&pdev->dev, "Exynos True Random Number Generator.\n");
> +
> + return 0;
> +
> +err_register:
> + clk_disable_unprepare(trng->clk);
> +
> +err_clock:
> + trng->mem = NULL;
> + pm_runtime_put_sync(&pdev->dev);
> + pm_runtime_disable(&pdev->dev);
> +
> +err_ioremap:
> + dev_err(&pdev->dev, "Initialisation failed.\n");
> + return ret;
> +}
> +
> +static int exynos_trng_remove(struct platform_device *pdev)
> +{
pm_runtime_*, or just use devm_ versions and drop this function.
> + exynos_trng_dev = NULL;
> +
> + return 0;
> +}
> +
> +static int __maybe_unused exynos_trng_suspend(struct device *dev)
> +{
> + pm_runtime_put_sync(dev);
> +
> + return 0;
> +}
> +
> +static int __maybe_unused exynos_trng_resume(struct device *dev)
> +{
> + int ret;
> +
> + ret = pm_runtime_get_sync(dev);
> + if (ret < 0) {
> + dev_err(dev, "pm_runtime_get_sync() failed: %d.\n", ret);
> + pm_runtime_put_noidle(dev);
> + return ret;
> + }
> +
> + return 0;
> +}
> +
> +static SIMPLE_DEV_PM_OPS(exynos_trng_pm_ops, exynos_trng_suspend,
> + exynos_trng_resume);
> +
> +static const struct of_device_id exynos_trng_dt_match[] = {
> + {
> + .compatible = "samsung,exynos5250-trng",
> + },
> + { },
> +};
> +MODULE_DEVICE_TABLE(of, exynos_rng_dt_match);
> +
> +static struct platform_driver exynos_trng_driver = {
> + .driver = {
> + .name = "exynos-trng",
> + .pm = &exynos_trng_pm_ops,
> + .of_match_table = exynos_trng_dt_match,
> + },
> + .probe = exynos_trng_probe,
> + .remove = exynos_trng_remove,
> +};
> +
> +module_platform_driver(exynos_trng_driver);
> +MODULE_AUTHOR("Łukasz Stelmach");
> +MODULE_DESCRIPTION("H/W TRNG driver for Exynos chips");
> +MODULE_LICENSE("GPL");
>
^ permalink raw reply
* Re: [PATCH v4 3/5] misc serdev: Add w2sg0004 (gps receiver) power control driver
From: Andrew F. Davis @ 2017-11-23 16:06 UTC (permalink / raw)
To: H. Nikolaus Schaller, Rob Herring, Mark Rutland,
Benoît Cousson, Tony Lindgren, Russell King, Arnd Bergmann,
Greg Kroah-Hartman, Kevin Hilman, Andreas Färber,
Thierry Reding, Jonathan Cameron
Cc: devicetree, linux-omap, linux-kernel, kernel, letux-kernel,
linux-arm-kernel
In-Reply-To: <871b744f878be8a0a4758ce549ff6ecaea8b6894.1510781876.git.hns@goldelico.com>
On 11/15/2017 03:37 PM, H. Nikolaus Schaller wrote:
> Add driver for Wi2Wi W2SG0004/84 GPS module connected through uart.
>
> Use serdev API hooks to monitor and forward the UART traffic to /dev/ttyGPSn
> and turn on/off the module. It also detects if the module is turned on (sends data)
> but should be off, e.g. if it was already turned on during boot or power-on-reset.
>
> Additionally, rfkill block/unblock can be used to control an external LNA
> (and power down the module if not needed).
>
> The driver concept is based on code developed by NeilBrown <neilb@suse.de>
> but simplified and adapted to use the new serdev API introduced in 4.11.
>
> Signed-off-by: H. Nikolaus Schaller <hns@goldelico.com>
> ---
> drivers/misc/Kconfig | 10 +
> drivers/misc/Makefile | 1 +
> drivers/misc/w2sg0004.c | 545 ++++++++++++++++++++++++++++++++++++++++++++++++
> 3 files changed, 556 insertions(+)
> create mode 100644 drivers/misc/w2sg0004.c
>
> diff --git a/drivers/misc/Kconfig b/drivers/misc/Kconfig
> index 8136dc7e863d..09d171d68408 100644
> --- a/drivers/misc/Kconfig
> +++ b/drivers/misc/Kconfig
> @@ -518,4 +518,14 @@ source "drivers/misc/mic/Kconfig"
> source "drivers/misc/genwqe/Kconfig"
> source "drivers/misc/echo/Kconfig"
> source "drivers/misc/cxl/Kconfig"
> +
> +config W2SG0004
> + tristate "W2SG00x4 on/off control"
> + depends on GPIOLIB && SERIAL_DEV_BUS
> + help
> + Enable on/off control of W2SG00x4 GPS moduled connected
> + to some SoC UART to allow powering up/down if the /dev/ttyGPSn
> + is opened/closed.
> + It also provides a rfkill gps name to control the LNA power.
> +
> endmenu
> diff --git a/drivers/misc/Makefile b/drivers/misc/Makefile
> index ad0e64fdba34..abcb667e0ff0 100644
> --- a/drivers/misc/Makefile
> +++ b/drivers/misc/Makefile
> @@ -51,6 +51,7 @@ obj-$(CONFIG_SRAM_EXEC) += sram-exec.o
> obj-y += mic/
> obj-$(CONFIG_GENWQE) += genwqe/
> obj-$(CONFIG_ECHO) += echo/
> +obj-$(CONFIG_W2SG0004) += w2sg0004.o
> obj-$(CONFIG_VEXPRESS_SYSCFG) += vexpress-syscfg.o
> obj-$(CONFIG_CXL_BASE) += cxl/
> obj-$(CONFIG_ASPEED_LPC_CTRL) += aspeed-lpc-ctrl.o
> diff --git a/drivers/misc/w2sg0004.c b/drivers/misc/w2sg0004.c
> new file mode 100644
> index 000000000000..12e14b5e0a99
> --- /dev/null
> +++ b/drivers/misc/w2sg0004.c
> @@ -0,0 +1,545 @@
> +// SPDX-License-Identifier: GPL-2.0
Damn this looks ugly, oh well :/
> +/*
> + * Driver for power controlling the w2sg0004/w2sg0084 GPS receiver.
> + *
Think you still need copyright tag here somewhere.
> + * This receiver has an ON/OFF pin which must be toggled to
> + * turn the device 'on' of 'off'. A high->low->high toggle
> + * will switch the device on if it is off, and off if it is on.
> + *
> + * To enable receiving on/off requests we register with the
> + * UART power management notifications.
> + *
> + * It is not possible to directly detect the state of the device.
> + * However when it is on it will send characters on a UART line
> + * regularly.
> + *
> + * To detect that the power state is out of sync (e.g. if GPS
> + * was enabled before a reboot), we register for UART data received
> + * notifications.
> + *
> + * In addition we register as a rfkill client so that we can
> + * control the LNA power.
> + *
> + */
> +
> +#include <linux/delay.h>
> +#include <linux/err.h>
> +#include <linux/interrupt.h>
> +#include <linux/irq.h>
> +#include <linux/module.h>
> +#include <linux/of.h>
> +#include <linux/of_irq.h>
> +#include <linux/of_gpio.h>
> +#include <linux/platform_device.h>
> +#include <linux/regulator/consumer.h>
> +#include <linux/rfkill.h>
> +#include <linux/serdev.h>
> +#include <linux/sched.h>
> +#include <linux/slab.h>
> +#include <linux/tty.h>
> +#include <linux/tty_flip.h>
> +#include <linux/workqueue.h>
> +
> +/*
> + * There seems to be restrictions on how quickly we can toggle the
> + * on/off line. data sheets says "two rtc ticks", whatever that means.
> + * If we do it too soon it doesn't work.
> + * So we have a state machine which uses the common work queue to ensure
> + * clean transitions.
> + * When a change is requested we record that request and only act on it
> + * once the previous change has completed.
> + * A change involves a 10ms low pulse, and a 990ms raised level, so only
> + * one change per second.
> + */
> +
> +enum w2sg_state {
> + W2SG_IDLE, /* is not changing state */
> + W2SG_PULSE, /* activate on/off impulse */
> + W2SG_NOPULSE /* deactivate on/off impulse */
> +};
> +
> +struct w2sg_data {
> + struct rfkill *rf_kill;
> + struct regulator *lna_regulator;
> + int lna_blocked; /* rfkill block gps active */
> + int lna_is_off; /* LNA is currently off */
> + int is_on; /* current state (0/1) */
> + unsigned long last_toggle;
> + unsigned long backoff; /* time to wait since last_toggle */
> + int on_off_gpio; /* the on-off gpio number */
> + struct serdev_device *uart; /* uart connected to the chip */
> + struct tty_driver *tty_drv; /* this is the user space tty */
> + struct device *dev; /* from tty_port_register_device() */
> + struct tty_port port;
> + int open_count; /* how often we were opened */
> + enum w2sg_state state;
> + int requested; /* requested state (0/1) */
> + int suspended;
> + struct delayed_work work;
> + int discard_count;
> +};
> +
Kernel doc style.
> +static struct w2sg_data *w2sg_by_minor[1];
> +
If you can only have one right now then just drop the array.
> +static int w2sg_set_lna_power(struct w2sg_data *data)
> +{
> + int ret = 0;
> + int off = data->suspended || !data->requested || data->lna_blocked;
> +
> + pr_debug("%s: %s\n", __func__, off ? "off" : "on");
> +
> + if (off != data->lna_is_off) {
> + data->lna_is_off = off;
> + if (!IS_ERR_OR_NULL(data->lna_regulator)) {
> + if (off)
> + regulator_disable(data->lna_regulator);
> + else
> + ret = regulator_enable(data->lna_regulator);
> + }
> + }
> +
> + return ret;
> +}
> +
> +static void w2sg_set_power(void *pdata, int val)
> +{
> + struct w2sg_data *data = (struct w2sg_data *) pdata;
> +
> + pr_debug("%s to state=%d (requested=%d)\n", __func__, val, data->requested);
> +
> + if (val && !data->requested) {
> + data->requested = true;
> + } else if (!val && data->requested) {
> + data->backoff = HZ;
> + data->requested = false;
> + } else
> + return;
> +
> + pr_debug("w2sg00x4 scheduled for %d\n", data->requested);
> +
> + if (!data->suspended)
> + schedule_delayed_work(&data->work, 0);
> +}
> +
> +/* called each time data is received by the UART (i.e. sent by the w2sg0004) */
> +
> +static int w2sg_uart_receive_buf(struct serdev_device *serdev,
> + const unsigned char *rxdata,
> + size_t count)
> +{
> + struct w2sg_data *data =
> + (struct w2sg_data *) serdev_device_get_drvdata(serdev);
> +
> + if (!data->requested && !data->is_on) {
> + /*
> + * we have received characters while the w2sg
> + * should have been be turned off
> + */
> + data->discard_count += count;
> + if ((data->state == W2SG_IDLE) &&
> + time_after(jiffies,
> + data->last_toggle + data->backoff)) {
> + /* Should be off by now, time to toggle again */
> + pr_debug("w2sg00x4 has sent %d characters data although it should be off!\n",
> + data->discard_count);
> +
> + data->discard_count = 0;
> +
> + data->is_on = true;
> + data->backoff *= 2;
> + if (!data->suspended)
> + schedule_delayed_work(&data->work, 0);
> + }
> + } else if (data->open_count > 0) {
> + int n;
> +
> + pr_debug("w2sg00x4: push %lu chars to tty port\n",
> + (unsigned long) count);
> +
> + /* pass to user-space */
> + n = tty_insert_flip_string(&data->port, rxdata, count);
> + if (n != count)
> + pr_err("w2sg00x4: did loose %lu characters\n",
> + (unsigned long) (count - n));
> + tty_flip_buffer_push(&data->port);
> + return n;
> + }
> +
> + /* assume we have processed everything */
> + return count;
> +}
> +
> +/* try to toggle the power state by sending a pulse to the on-off GPIO */
> +
drop extra line, same everywhere
> +static void toggle_work(struct work_struct *work)
> +{
> + struct w2sg_data *data = container_of(work, struct w2sg_data,
> + work.work);
> +
> + switch (data->state) {
> + case W2SG_IDLE:
> + if (data->requested == data->is_on)
> + return;
> +
> + w2sg_set_lna_power(data); /* update LNA power state */
> + gpio_set_value_cansleep(data->on_off_gpio, 0);
> + data->state = W2SG_PULSE;
> +
> + pr_debug("w2sg: power gpio ON\n");
> +
> + schedule_delayed_work(&data->work,
> + msecs_to_jiffies(10));
> + break;
> +
> + case W2SG_PULSE:
> + gpio_set_value_cansleep(data->on_off_gpio, 1);
> + data->last_toggle = jiffies;
> + data->state = W2SG_NOPULSE;
> + data->is_on = !data->is_on;
> +
> + pr_debug("w2sg: power gpio OFF\n");
> +
> + schedule_delayed_work(&data->work,
> + msecs_to_jiffies(10));
> + break;
> +
> + case W2SG_NOPULSE:
> + data->state = W2SG_IDLE;
> +
> + pr_debug("w2sg: idle\n");
> +
> + break;
> +
> + }
> +}
> +
> +static int w2sg_rfkill_set_block(void *pdata, bool blocked)
> +{
> + struct w2sg_data *data = pdata;
> +
> + pr_debug("%s: blocked: %d\n", __func__, blocked);
> +
> + data->lna_blocked = blocked;
> +
> + return w2sg_set_lna_power(data);
> +}
> +
> +static struct rfkill_ops w2sg0004_rfkill_ops = {
> + .set_block = w2sg_rfkill_set_block,
> +};
> +
> +static struct serdev_device_ops serdev_ops = {
> + .receive_buf = w2sg_uart_receive_buf,
> +};
> +
> +/*
> + * we are a man-in the middle between the user-space visible tty port
> + * and the serdev tty where the chip is connected.
> + * This allows us to recognise when the device should be powered on
> + * or off and handle the "false" state that data arrives while no
> + * users-space tty client exists.
> + */
> +
> +static struct w2sg_data *w2sg_get_by_minor(unsigned int minor)
> +{
> + return w2sg_by_minor[minor];
> +}
> +
> +static int w2sg_tty_install(struct tty_driver *driver, struct tty_struct *tty)
> +{
> + struct w2sg_data *data;
> + int retval;
> +
> + pr_debug("%s() tty = %p\n", __func__, tty);
> +
> + data = w2sg_get_by_minor(tty->index);
> +
> + if (!data)
> + return -ENODEV;
> +
> + retval = tty_standard_install(driver, tty);
> + if (retval)
> + goto error_init_termios;
> +
> + tty->driver_data = data;
> +
> + return 0;
> +
> +error_init_termios:
> + tty_port_put(&data->port);
> + return retval;
> +}
> +
> +static int w2sg_tty_open(struct tty_struct *tty, struct file *file)
> +{
> + struct w2sg_data *data = tty->driver_data;
> +
> + pr_debug("%s() data = %p open_count = ++%d\n", __func__, data, data->open_count);
> +
> + w2sg_set_power(data, ++data->open_count > 0);
> +
> + return tty_port_open(&data->port, tty, file);
> +}
> +
> +static void w2sg_tty_close(struct tty_struct *tty, struct file *file)
> +{
> + struct w2sg_data *data = tty->driver_data;
> +
> + pr_debug("%s()\n", __func__);
> +
> + w2sg_set_power(data, --data->open_count > 0);
> +
> + tty_port_close(&data->port, tty, file);
> +}
> +
> +static int w2sg_tty_write(struct tty_struct *tty,
> + const unsigned char *buffer, int count)
> +{
> + struct w2sg_data *data = tty->driver_data;
> +
> + /* simply pass down to UART */
> + return serdev_device_write_buf(data->uart, buffer, count);
> +}
> +
> +static const struct tty_operations w2sg_serial_ops = {
> + .install = w2sg_tty_install,
> + .open = w2sg_tty_open,
> + .close = w2sg_tty_close,
> + .write = w2sg_tty_write,
> +};
> +
> +static const struct tty_port_operations w2sg_port_ops = {
> +};
drop the brackets? or use NULL below, not sure if this needs memory.
> +
> +static int w2sg_probe(struct serdev_device *serdev)
> +{
> + struct w2sg_data *data;
> + struct rfkill *rf_kill;
> + int err;
> + int minor;
> + enum of_gpio_flags flags;
> +
> + pr_debug("%s()\n", __func__);
> +
> + minor = 0;
> + if (w2sg_by_minor[minor]) {
> + pr_err("w2sg minor is already in use!\n");
> + return -ENODEV;
> + }
> +
> + data = devm_kzalloc(&serdev->dev, sizeof(*data), GFP_KERNEL);
> + if (data == NULL)
> + return -ENOMEM;
> +
> + w2sg_by_minor[minor] = data;
> +
> + serdev_device_set_drvdata(serdev, data);
> +
> + data->on_off_gpio = of_get_named_gpio_flags(serdev->dev.of_node,
> + "enable-gpios", 0,
> + &flags);
> + /* defer until we have all gpios */
> + if (data->on_off_gpio == -EPROBE_DEFER)
> + return -EPROBE_DEFER;
> +
> + data->lna_regulator = devm_regulator_get_optional(&serdev->dev,
> + "lna");
> + if (IS_ERR(data->lna_regulator)) {
> + /* defer until we can get the regulator */
> + if (PTR_ERR(data->lna_regulator) == -EPROBE_DEFER)
> + return -EPROBE_DEFER;
> +
> + data->lna_regulator = NULL;
> + }
> + pr_debug("%s() lna_regulator = %p\n", __func__, data->lna_regulator);
> +
> + data->lna_blocked = true;
> + data->lna_is_off = true;
> +
> + data->is_on = false;
> + data->requested = false;
> + data->state = W2SG_IDLE;
> + data->last_toggle = jiffies;
> + data->backoff = HZ;
> +
> + data->uart = serdev;
> +
> + INIT_DELAYED_WORK(&data->work, toggle_work);
> +
> + err = devm_gpio_request(&serdev->dev, data->on_off_gpio,
> + "w2sg0004-on-off");
> + if (err < 0)
> + goto out;
> +
> + gpio_direction_output(data->on_off_gpio, false);
> +
> + serdev_device_set_client_ops(data->uart, &serdev_ops);
> + serdev_device_open(data->uart);
> +
> + serdev_device_set_baudrate(data->uart, 9600);
> + serdev_device_set_flow_control(data->uart, false);
> +
> + rf_kill = rfkill_alloc("GPS", &serdev->dev, RFKILL_TYPE_GPS,
> + &w2sg0004_rfkill_ops, data);
> + if (rf_kill == NULL) {
> + err = -ENOMEM;
> + goto err_rfkill;
> + }
> +
> + err = rfkill_register(rf_kill);
> + if (err) {
> + dev_err(&serdev->dev, "Cannot register rfkill device\n");
> + goto err_rfkill;
> + }
> +
> + data->rf_kill = rf_kill;
> +
> + /* allocate the tty driver */
> + data->tty_drv = alloc_tty_driver(1);
> + if (!data->tty_drv)
> + return -ENOMEM;
> +
> + /* initialize the tty driver */
> + data->tty_drv->owner = THIS_MODULE;
> + data->tty_drv->driver_name = "w2sg0004";
> + data->tty_drv->name = "ttyGPS";
> + data->tty_drv->major = 0;
> + data->tty_drv->minor_start = 0;
> + data->tty_drv->type = TTY_DRIVER_TYPE_SERIAL;
> + data->tty_drv->subtype = SERIAL_TYPE_NORMAL;
> + data->tty_drv->flags = TTY_DRIVER_REAL_RAW | TTY_DRIVER_DYNAMIC_DEV;
> + data->tty_drv->init_termios = tty_std_termios;
> + data->tty_drv->init_termios.c_cflag = B9600 | CS8 | CREAD |
> + HUPCL | CLOCAL;
> + /*
> + * optional:
> + * tty_termios_encode_baud_rate(&data->tty_drv->init_termios,
> + 115200, 115200);
> + * w2sg_tty_termios(&data->tty_drv->init_termios);
> + */
> + tty_set_operations(data->tty_drv, &w2sg_serial_ops);
> +
> + /* register the tty driver */
> + err = tty_register_driver(data->tty_drv);
> + if (err) {
> + pr_err("%s - tty_register_driver failed(%d)\n",
> + __func__, err);
> + put_tty_driver(data->tty_drv);
> + goto err_rfkill;
> + }
> +
> + tty_port_init(&data->port);
> + data->port.ops = &w2sg_port_ops;
> +
> + pr_debug("w2sg call tty_port_register_device\n");
> +
> + data->dev = tty_port_register_device(&data->port,
> + data->tty_drv, minor, &serdev->dev);
> +
> + pr_debug("w2sg probed\n");
> +
> + /* keep off until user space requests the device */
> + w2sg_set_power(data, false);
> +
> + return 0;
> +
> +err_rfkill:
> + rfkill_destroy(rf_kill);
> + serdev_device_close(data->uart);
> +out:
> + return err;
> +}
> +
> +static void w2sg_remove(struct serdev_device *serdev)
> +{
> + struct w2sg_data *data = serdev_device_get_drvdata(serdev);
> + int minor;
> +
> + cancel_delayed_work_sync(&data->work);
> +
> + /* what is the right sequence to avoid problems? */
> + serdev_device_close(data->uart);
> +
> + minor = 0;
> + tty_unregister_device(data->tty_drv, minor);
> +
> + tty_unregister_driver(data->tty_drv);
> +}
> +
> +static int w2sg_suspend(struct device *dev)
__maybe_unused, or if PM is disabled you will get a warning.
> +{
> + struct w2sg_data *data = dev_get_drvdata(dev);
> +
> + data->suspended = true;
> +
> + cancel_delayed_work_sync(&data->work);
> +
> + w2sg_set_lna_power(data); /* shuts down if needed */
> +
> + if (data->state == W2SG_PULSE) {
> + msleep(10);
> + gpio_set_value_cansleep(data->on_off_gpio, 1);
> + data->last_toggle = jiffies;
> + data->is_on = !data->is_on;
> + data->state = W2SG_NOPULSE;
> + }
> +
> + if (data->state == W2SG_NOPULSE) {
> + msleep(10);
> + data->state = W2SG_IDLE;
> + }
> +
> + if (data->is_on) {
> + pr_info("GPS off for suspend %d %d %d\n", data->requested,
> + data->is_on, data->lna_is_off);
> +
> + gpio_set_value_cansleep(data->on_off_gpio, 0);
> + msleep(10);
> + gpio_set_value_cansleep(data->on_off_gpio, 1);
> + data->is_on = 0;
> + }
> +
> + return 0;
> +}
> +
> +static int w2sg_resume(struct device *dev)
> +{
> + struct w2sg_data *data = dev_get_drvdata(dev);
> +
> + data->suspended = false;
> +
> + pr_info("GPS resuming %d %d %d\n", data->requested,
> + data->is_on, data->lna_is_off);
> +
> + schedule_delayed_work(&data->work, 0); /* enables LNA if needed */
> +
> + return 0;
> +}
> +
> +static const struct of_device_id w2sg0004_of_match[] = {
> + { .compatible = "wi2wi,w2sg0004" },
> + { .compatible = "wi2wi,w2sg0084" },
> + {},
> +};
> +MODULE_DEVICE_TABLE(of, w2sg0004_of_match);
> +
> +SIMPLE_DEV_PM_OPS(w2sg_pm_ops, w2sg_suspend, w2sg_resume);
> +
> +static struct serdev_device_driver w2sg_driver = {
> + .probe = w2sg_probe,
> + .remove = w2sg_remove,
> + .driver = {
> + .name = "w2sg0004",
> + .owner = THIS_MODULE,
> + .pm = &w2sg_pm_ops,
> + .of_match_table = of_match_ptr(w2sg0004_of_match)
> + },
> +};
> +
> +module_serdev_device_driver(w2sg_driver);
> +
> +MODULE_ALIAS("w2sg0004");
Is this needed?
> +
> +MODULE_AUTHOR("NeilBrown <neilb@suse.de>");
Who really wrote this?
> +MODULE_DESCRIPTION("w2sg0004 GPS power management driver");
> +MODULE_LICENSE("GPL v2");
>
^ permalink raw reply
* Re: [PATCH 1/3] dt-bindings: hwrng: Add Samsung Exynos 5250+ True RNG bindings
From: Krzysztof Kozlowski @ 2017-11-23 16:17 UTC (permalink / raw)
To: Łukasz Stelmach
Cc: Rob Herring, Matt Mackall, Herbert Xu, devicetree, linux-crypto,
linux-samsung-soc, linux-kernel, Marek Szyprowski,
Bartlomiej Zolnierkiewicz
In-Reply-To: <20171123150914.31462-2-l.stelmach@samsung.com>
On Thu, Nov 23, 2017 at 4:09 PM, Łukasz Stelmach <l.stelmach@samsung.com> wrote:
> Add binding documentation for the True Random Number Generator
> found on Samsung Exynos 5250+ SoCs.
>
> Signed-off-by: Łukasz Stelmach <l.stelmach@samsung.com>
> ---
> .../devicetree/bindings/rng/samsung,exynos5250-trng.txt | 17 +++++++++++++++++
> 1 file changed, 17 insertions(+)
> create mode 100644 Documentation/devicetree/bindings/rng/samsung,exynos5250-trng.txt
Reviewed-by: Krzysztof Kozlowski <krzk@kernel.org>
Best regards,
Krzysztof
^ permalink raw reply
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