* [PATCH] dt-bindings: usb: renesas_gen3: Rename bindings documentation file to reflect IP block
From: Simon Horman @ 2019-08-01 9:13 UTC (permalink / raw)
To: Greg Kroah-Hartman
Cc: Yoshihiro Shimoda, Geert Uytterhoeven, Niklas Söderlund,
Magnus Damm, Rob Herring, Mark Rutland, linux-usb, devicetree,
linux-renesas-soc, Simon Horman
For consistency with the naming of (most) other documentation files for DT
bindings for Renesas IP blocks rename the Renesas USB3.0 peripheral
documentation file from renesas,gen3.txt to renesas,usb3-peri.txt
This refines a recent rename from renesas,gen3.txt to renesas-gen3.txt.
The motivation is to to more accurately reflect the IP block documented in
this file.
Signed-off-by: Simon Horman <horms+renesas@verge.net.au>
---
* Based on v5.3-rc1
---
.../devicetree/bindings/usb/{renesas,usb3.txt => renesas,usb3-peri.txt} | 0
1 file changed, 0 insertions(+), 0 deletions(-)
rename Documentation/devicetree/bindings/usb/{renesas,usb3.txt => renesas,usb3-peri.txt} (100%)
diff --git a/Documentation/devicetree/bindings/usb/renesas,usb3.txt b/Documentation/devicetree/bindings/usb/renesas,usb3-peri.txt
similarity index 100%
rename from Documentation/devicetree/bindings/usb/renesas,usb3.txt
rename to Documentation/devicetree/bindings/usb/renesas,usb3-peri.txt
--
2.11.0
^ permalink raw reply
* Re: [PATCH v2 1/1] dt-bindings: reset: Fix typo in imx8mq resets
From: Philipp Zabel @ 2019-08-01 9:01 UTC (permalink / raw)
To: Guido Günther, Shawn Guo, Sascha Hauer,
Pengutronix Kernel Team, Fabio Estevam, NXP Linux Team,
Rob Herring, Mark Rutland, linux-arm-kernel, linux-kernel,
devicetree
In-Reply-To: <660b4fb6ab9acec05aa5fde323d878e04e3d1f64.1564647612.git.agx@sigxcpu.org>
On Thu, 2019-08-01 at 10:20 +0200, Guido Günther wrote:
> Some of the mipi dsi resets were called
>
> IMX8MQ_RESET_MIPI_DIS__
>
> instead of
>
> IMX8MQ_RESET_MIPI_DSI__
>
> Since they're DSI related this looks like a typo. This fixes the
> only in tree user as well to not break bisecting.
>
> Signed-off-by: Guido Günther <agx@sigxcpu.org>
Thank you, this was a typo in the Rev.0 reference manual.
It has been fixed in Rev. 1.
Applied to reset/next with Lucas' R-b.
regards
Philipp
^ permalink raw reply
* Re: [PATCH v2 4/6] irqchip/irq-pruss-intc: Add helper functions to configure internal mapping
From: Marc Zyngier @ 2019-08-01 8:45 UTC (permalink / raw)
To: Suman Anna, Thomas Gleixner, Jason Cooper
Cc: Rob Herring, David Lechner, Tony Lindgren, Andrew F. Davis,
Roger Quadros, Lokesh Vutla, Grygorii Strashko, Sekhar Nori,
Murali Karicheri, devicetree, linux-omap, linux-arm-kernel,
linux-kernel
In-Reply-To: <20190731224149.11153-5-s-anna@ti.com>
On 31/07/2019 23:41, Suman Anna wrote:
> The PRUSS INTC receives a number of system input interrupt source events
> and supports individual control configuration and hardware prioritization.
> These input events can be mapped to some output interrupt lines through 2
> levels of many-to-one mapping i.e. events to channel mapping and channels
> to output interrupts.
>
> This mapping information is provided through the PRU firmware that is
> loaded onto a PRU core/s or through the device tree node of the PRU
> application. The mapping is configured by the PRU remoteproc driver, and
> is setup before the PRU core is started and cleaned up after the PRU core
> is stopped. This event mapping configuration logic programs the Channel
> Map Registers (CMRx) and Host-Interrupt Map Registers (HMRx) only when a
> new program is being loaded/started and the same events and interrupt
> channels are reset to zero when stopping a PRU.
>
> Add two helper functions: pruss_intc_configure() & pruss_intc_unconfigure()
> that the PRU remoteproc driver can use to configure the PRUSS INTC.
So let me see if I correctly understand this: this adds yet another
firmware description parser, with a private interface to another
(undisclosed?) driver, bypassing the standard irqchip configuration
mechanism. It sounds great, doesn't it?
What I cannot really infer from this message (-ETOOMUCHJARGON) is what
interrupts this affects:
- Interrupts from random devices to the PRUSS?
- Interrupts from the PRUSS to the host?
- Something else?
When does this happen? Under control of what? It isn't even clear why
this is part of this irqchip driver.
Depending what this does, there may be ways to fit it into the standard
interrupt configuration framework. After all, we already have standard
interfaces to route interrupts to virtual CPUs, effectively passing full
control of an interrupt to another entity. If you squint hard enough,
your PRUSS can fit that description.
If that doesn't work, then we need to make the IRQ framework grok that
kind of requirement (hence my request for clarification). But I'm
strongly opposed to inventing a SoC-private way of configuring
interrupts behind the kernel's back.
Thanks,
M.
--
Jazz is not dead, it just smells funny...
^ permalink raw reply
* Re: [PATCH v2 1/1] dt-bindings: reset: Fix typo in imx8mq resets
From: Lucas Stach @ 2019-08-01 8:41 UTC (permalink / raw)
To: Guido Günther, Philipp Zabel, Shawn Guo, Sascha Hauer,
Pengutronix Kernel Team, Fabio Estevam, NXP Linux Team,
Rob Herring, Mark Rutland, linux-arm-kernel, linux-kernel,
devicetree
In-Reply-To: <660b4fb6ab9acec05aa5fde323d878e04e3d1f64.1564647612.git.agx@sigxcpu.org>
Am Donnerstag, den 01.08.2019, 10:20 +0200 schrieb Guido Günther:
> Some of the mipi dsi resets were called
>
> IMX8MQ_RESET_MIPI_DIS__
>
> instead of
>
> IMX8MQ_RESET_MIPI_DSI__
>
> Since they're DSI related this looks like a typo. This fixes the
> only in tree user as well to not break bisecting.
>
> Signed-off-by: Guido Günther <agx@sigxcpu.org>
Reviewed-by: Lucas Stach <l.stach@pengutronix.de>
> ---
> drivers/reset/reset-imx7.c | 12 ++++++------
> include/dt-bindings/reset/imx8mq-reset.h | 6 +++---
> 2 files changed, 9 insertions(+), 9 deletions(-)
>
> diff --git a/drivers/reset/reset-imx7.c b/drivers/reset/reset-imx7.c
> index 3ecd770f910b..1443a55a0c29 100644
> --- a/drivers/reset/reset-imx7.c
> +++ b/drivers/reset/reset-imx7.c
> @@ -169,9 +169,9 @@ static const struct imx7_src_signal imx8mq_src_signals[IMX8MQ_RESET_NUM] = {
> > > [IMX8MQ_RESET_OTG2_PHY_RESET] = { SRC_USBOPHY2_RCR, BIT(0) },
> > > [IMX8MQ_RESET_MIPI_DSI_RESET_BYTE_N] = { SRC_MIPIPHY_RCR, BIT(1) },
> > > [IMX8MQ_RESET_MIPI_DSI_RESET_N] = { SRC_MIPIPHY_RCR, BIT(2) },
> > > - [IMX8MQ_RESET_MIPI_DIS_DPI_RESET_N] = { SRC_MIPIPHY_RCR, BIT(3) },
> > > - [IMX8MQ_RESET_MIPI_DIS_ESC_RESET_N] = { SRC_MIPIPHY_RCR, BIT(4) },
> > > - [IMX8MQ_RESET_MIPI_DIS_PCLK_RESET_N] = { SRC_MIPIPHY_RCR, BIT(5) },
> > > + [IMX8MQ_RESET_MIPI_DSI_DPI_RESET_N] = { SRC_MIPIPHY_RCR, BIT(3) },
> > > + [IMX8MQ_RESET_MIPI_DSI_ESC_RESET_N] = { SRC_MIPIPHY_RCR, BIT(4) },
> > > + [IMX8MQ_RESET_MIPI_DSI_PCLK_RESET_N] = { SRC_MIPIPHY_RCR, BIT(5) },
> > > [IMX8MQ_RESET_PCIEPHY] = { SRC_PCIEPHY_RCR,
> > BIT(2) | BIT(1) },
> > > [IMX8MQ_RESET_PCIEPHY_PERST] = { SRC_PCIEPHY_RCR, BIT(3) },
> @@ -220,9 +220,9 @@ static int imx8mq_reset_set(struct reset_controller_dev *rcdev,
>
> > case IMX8MQ_RESET_PCIE_CTRL_APPS_EN:
> > > case IMX8MQ_RESET_PCIE2_CTRL_APPS_EN: /* fallthrough */
> > > - case IMX8MQ_RESET_MIPI_DIS_PCLK_RESET_N: /* fallthrough */
> > > - case IMX8MQ_RESET_MIPI_DIS_ESC_RESET_N: /* fallthrough */
> > > - case IMX8MQ_RESET_MIPI_DIS_DPI_RESET_N: /* fallthrough */
> > > + case IMX8MQ_RESET_MIPI_DSI_PCLK_RESET_N: /* fallthrough */
> > > + case IMX8MQ_RESET_MIPI_DSI_ESC_RESET_N: /* fallthrough */
> > > + case IMX8MQ_RESET_MIPI_DSI_DPI_RESET_N: /* fallthrough */
> > > case IMX8MQ_RESET_MIPI_DSI_RESET_N: /* fallthrough */
> > > case IMX8MQ_RESET_MIPI_DSI_RESET_BYTE_N: /* fallthrough */
> > value = assert ? 0 : bit;
> diff --git a/include/dt-bindings/reset/imx8mq-reset.h b/include/dt-bindings/reset/imx8mq-reset.h
> index 57c592498aa0..bfa41b0e24f6 100644
> --- a/include/dt-bindings/reset/imx8mq-reset.h
> +++ b/include/dt-bindings/reset/imx8mq-reset.h
> @@ -31,9 +31,9 @@
> > #define IMX8MQ_RESET_OTG2_PHY_RESET 20
> > #define IMX8MQ_RESET_MIPI_DSI_RESET_BYTE_N 21
> > #define IMX8MQ_RESET_MIPI_DSI_RESET_N 22
> > -#define IMX8MQ_RESET_MIPI_DIS_DPI_RESET_N 23
> > -#define IMX8MQ_RESET_MIPI_DIS_ESC_RESET_N 24
> > -#define IMX8MQ_RESET_MIPI_DIS_PCLK_RESET_N 25
> > +#define IMX8MQ_RESET_MIPI_DSI_DPI_RESET_N 23
> > +#define IMX8MQ_RESET_MIPI_DSI_ESC_RESET_N 24
> > +#define IMX8MQ_RESET_MIPI_DSI_PCLK_RESET_N 25
> > #define IMX8MQ_RESET_PCIEPHY 26
> > #define IMX8MQ_RESET_PCIEPHY_PERST 27
> > #define IMX8MQ_RESET_PCIE_CTRL_APPS_EN 28
^ permalink raw reply
* [PATCH 3/3] arm64: dts: ls1088a-qds: Add the spi-flash nodes under the DSPI controller
From: Chuanhua Han @ 2019-08-01 8:31 UTC (permalink / raw)
To: broonie, robh+dt, mark.rutland, shawnguo, leoyang.li
Cc: linux-spi, devicetree, linux-kernel, linux-arm-kernel,
Chuanhua Han
In-Reply-To: <20190801083105.30102-1-chuanhua.han@nxp.com>
This patch adds the spi-flash nodes under the DSPI controller for
ls1088a-qds boards.
Signed-off-by: Chuanhua Han <chuanhua.han@nxp.com>
---
arch/arm64/boot/dts/freescale/fsl-ls1088a-qds.dts | 33 +++++++++++++++++++++++
1 file changed, 33 insertions(+)
diff --git a/arch/arm64/boot/dts/freescale/fsl-ls1088a-qds.dts b/arch/arm64/boot/dts/freescale/fsl-ls1088a-qds.dts
index 6f48d21..120e62d 100644
--- a/arch/arm64/boot/dts/freescale/fsl-ls1088a-qds.dts
+++ b/arch/arm64/boot/dts/freescale/fsl-ls1088a-qds.dts
@@ -17,6 +17,39 @@
compatible = "fsl,ls1088a-qds", "fsl,ls1088a";
};
+&dspi {
+ bus-num = <0>;
+ status = "okay";
+
+ flash@0 {
+ #address-cells = <1>;
+ #size-cells = <1>;
+ compatible = "jedec,spi-nor";
+ reg = <0>;
+ spi-max-frequency = <1000000>;
+ };
+
+ flash@1 {
+ #address-cells = <1>;
+ #size-cells = <1>;
+ compatible = "jedec,spi-nor";
+ spi-cpol;
+ spi-cpha;
+ spi-max-frequency = <3500000>;
+ reg = <1>;
+ };
+
+ flash@2 {
+ #address-cells = <1>;
+ #size-cells = <1>;
+ compatible = "jedec,spi-nor";
+ spi-cpol;
+ spi-cpha;
+ spi-max-frequency = <3500000>;
+ reg = <2>;
+ };
+};
+
&i2c0 {
status = "okay";
--
2.9.5
^ permalink raw reply related
* [PATCH 2/3] arm64: dts: ls1088a: Add the DSPI controller node
From: Chuanhua Han @ 2019-08-01 8:31 UTC (permalink / raw)
To: broonie, robh+dt, mark.rutland, shawnguo, leoyang.li
Cc: linux-spi, devicetree, linux-kernel, linux-arm-kernel,
Chuanhua Han
In-Reply-To: <20190801083105.30102-1-chuanhua.han@nxp.com>
This patch adds the DSPI controller node for ls1088a boards.
Signed-off-by: Chuanhua Han <chuanhua.han@nxp.com>
---
arch/arm64/boot/dts/freescale/fsl-ls1088a.dtsi | 13 +++++++++++++
1 file changed, 13 insertions(+)
diff --git a/arch/arm64/boot/dts/freescale/fsl-ls1088a.dtsi b/arch/arm64/boot/dts/freescale/fsl-ls1088a.dtsi
index dacd8cf..fe8f1bd 100644
--- a/arch/arm64/boot/dts/freescale/fsl-ls1088a.dtsi
+++ b/arch/arm64/boot/dts/freescale/fsl-ls1088a.dtsi
@@ -252,6 +252,19 @@
#thermal-sensor-cells = <1>;
};
+ dspi: spi@2100000 {
+ compatible = "fsl,ls1088a-dspi",
+ "fsl,ls1021a-v1.0-dspi";
+ #address-cells = <1>;
+ #size-cells = <0>;
+ reg = <0x0 0x2100000 0x0 0x10000>;
+ interrupts = <GIC_SPI 26 IRQ_TYPE_LEVEL_HIGH>;
+ clock-names = "dspi";
+ clocks = <&clockgen 4 1>;
+ spi-num-chipselects = <6>;
+ status = "disabled";
+ };
+
duart0: serial@21c0500 {
compatible = "fsl,ns16550", "ns16550a";
reg = <0x0 0x21c0500 0x0 0x100>;
--
2.9.5
^ permalink raw reply related
* [PATCH 1/3] dt-bindings: fsl: dspi: Add fsl,ls1088a-dspi compatible string
From: Chuanhua Han @ 2019-08-01 8:31 UTC (permalink / raw)
To: broonie, robh+dt, mark.rutland, shawnguo, leoyang.li
Cc: linux-spi, devicetree, linux-kernel, linux-arm-kernel,
Chuanhua Han
new compatible string: "fsl,ls1088a-dspi".
Signed-off-by: Chuanhua Han <chuanhua.han@nxp.com>
---
Documentation/devicetree/bindings/spi/spi-fsl-dspi.txt | 1 +
1 file changed, 1 insertion(+)
diff --git a/Documentation/devicetree/bindings/spi/spi-fsl-dspi.txt b/Documentation/devicetree/bindings/spi/spi-fsl-dspi.txt
index dcc7eaa..162e024 100644
--- a/Documentation/devicetree/bindings/spi/spi-fsl-dspi.txt
+++ b/Documentation/devicetree/bindings/spi/spi-fsl-dspi.txt
@@ -6,6 +6,7 @@ Required properties:
or
"fsl,ls2080a-dspi" followed by "fsl,ls2085a-dspi"
"fsl,ls1012a-dspi" followed by "fsl,ls1021a-v1.0-dspi"
+ "fsl,ls1088a-dspi" followed by "fsl,ls1021a-v1.0-dspi"
- reg : Offset and length of the register set for the device
- interrupts : Should contain SPI controller interrupt
- clocks: from common clock binding: handle to dspi clock.
--
2.9.5
^ permalink raw reply related
* Re: [PATCH] at91/dt: ariettag25: style cleanup
From: Ludovic Desroches @ 2019-08-01 8:26 UTC (permalink / raw)
To: Uwe Kleine-König
Cc: Mark Rutland, devicetree, Alexandre Belloni, Rob Herring,
linux-arm-kernel
In-Reply-To: <20190731220045.3992-1-uwe@kleine-koenig.org>
On Thu, Aug 01, 2019 at 12:00:45AM +0200, Uwe Kleine-König wrote:
> External E-Mail
>
>
> - newline between properties and sub-nodes
> - use tags from included dtsi instead of duplicating the hierarchy
> - status should be the last property
> - drop duplicated alias
>
> There are no differences in the generated .dtb
>
> Signed-off-by: Uwe Kleine-König <uwe@kleine-koenig.org>
Acked-by: Ludovic Desroches <ludovic.desroches@microchip.com>
> ---
> Hello,
>
> these are the style rules I was teached when modifying imx dts files.
> Do they apply to at91, too?
Hello Uwe,
It's okay for me, we had no guidelines at the beginning, that explain
some inconsistency among our dt files. We tend to follow these rules
excepted the use of labels.
I would like to be sure that Nicolas and Alexandre are on the same
wavelength than me.
Regards
Ludovic
>
> Best regards
> Uwe
>
> arch/arm/boot/dts/at91-ariettag25.dts | 87 +++++++++++++--------------
> 1 file changed, 43 insertions(+), 44 deletions(-)
>
> diff --git a/arch/arm/boot/dts/at91-ariettag25.dts b/arch/arm/boot/dts/at91-ariettag25.dts
> index 7a34c4dc05d2..8f9f5a22cbf6 100644
> --- a/arch/arm/boot/dts/at91-ariettag25.dts
> +++ b/arch/arm/boot/dts/at91-ariettag25.dts
> @@ -6,14 +6,11 @@
> */
> /dts-v1/;
> #include "at91sam9g25.dtsi"
> +
> / {
> model = "Acme Systems Arietta G25";
> compatible = "acme,ariettag25", "atmel,at91sam9x5", "atmel,at91sam9";
>
> - aliases {
> - serial0 = &dbgu;
> - };
> -
> chosen {
> stdout-path = "serial0:115200n8";
> };
> @@ -34,55 +31,16 @@
>
> ahb {
> apb {
> - mmc0: mmc@f0008000 {
> - pinctrl-0 = <
> - &pinctrl_mmc0_slot0_clk_cmd_dat0
> - &pinctrl_mmc0_slot0_dat1_3>;
> - status = "okay";
> -
> - slot@0 {
> - reg = <0>;
> - bus-width = <4>;
> - };
> - };
> -
> - tcb0: timer@f8008000 {
> - timer@0 {
> - compatible = "atmel,tcb-timer";
> - reg = <0>;
> - };
> -
> - timer@1 {
> - compatible = "atmel,tcb-timer";
> - reg = <1>;
> - };
> - };
> -
> - usb2: gadget@f803c000 {
> - status = "okay";
> - };
> -
> - dbgu: serial@fffff200 {
> - status = "okay";
> - };
> -
> rtc@fffffeb0 {
> status = "okay";
> };
> };
>
> - usb0: ohci@600000 {
> - status = "okay";
> - num-ports = <3>;
> - };
> -
> - usb1: ehci@700000 {
> - status = "okay";
> - };
> };
>
> leds {
> compatible = "gpio-leds";
> +
> arietta_led {
> label = "arietta_led";
> gpios = <&pioB 8 GPIO_ACTIVE_HIGH>; /* PB8 */
> @@ -90,3 +48,44 @@
> };
> };
> };
> +
> +&dbgu {
> + status = "okay";
> +};
> +
> +&mmc0 {
> + pinctrl-0 = <
> + &pinctrl_mmc0_slot0_clk_cmd_dat0
> + &pinctrl_mmc0_slot0_dat1_3>;
> + status = "okay";
> +
> + slot@0 {
> + reg = <0>;
> + bus-width = <4>;
> + };
> +};
> +
> +&tcb0 {
> + timer@0 {
> + compatible = "atmel,tcb-timer";
> + reg = <0>;
> + };
> +
> + timer@1 {
> + compatible = "atmel,tcb-timer";
> + reg = <1>;
> + };
> +};
> +
> +&usb0 {
> + num-ports = <3>;
> + status = "okay";
> +};
> +
> +&usb1 {
> + status = "okay";
> +};
> +
> +&usb2 {
> + status = "okay";
> +};
> --
> 2.20.1
>
>
> _______________________________________________
> linux-arm-kernel mailing list
> linux-arm-kernel@lists.infradead.org
> http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
^ permalink raw reply
* Re: [PATCH 2/2] reset: imx7: Fix IMX8MQ_RESET_MIPI_DSI_ defines
From: Guido Günther @ 2019-08-01 8:22 UTC (permalink / raw)
To: Lucas Stach
Cc: Philipp Zabel, Shawn Guo, Sascha Hauer, Pengutronix Kernel Team,
Fabio Estevam, NXP Linux Team, Rob Herring, Mark Rutland,
linux-arm-kernel, linux-kernel, devicetree
In-Reply-To: <1564591585.7267.22.camel@pengutronix.de>
Hi Lucas,
On Wed, Jul 31, 2019 at 06:46:25PM +0200, Lucas Stach wrote:
> Am Mittwoch, den 31.07.2019, 18:43 +0200 schrieb Guido Günther:
> > Some of the mipi dsi resets were called
> >
> > IMX8MQ_RESET_MIPI_DIS_
> >
> > instead of
> >
> > IMX8MQ_RESET_MIPI_DSI_
> >
> > Since they're DSI related this looks like a typo.
> >
> > I wasn't sure if this should be a single patch since it otherwise breaks
> > bisectability. I couldn't find any device trees using this yet.
>
> Yes, I think this should be squashed into a single commit. Other than
> that, the change looks correct.
Thanks for having a look. Sent out v2 as a single patch.
Cheers,
-- Guido
>
> Regards,
> Lucas
>
> > Signed-off-by: Guido Günther <agx@sigxcpu.org>
> > ---
> > drivers/reset/reset-imx7.c | 12 ++++++------
> > 1 file changed, 6 insertions(+), 6 deletions(-)
> >
> > diff --git a/drivers/reset/reset-imx7.c b/drivers/reset/reset-imx7.c
> > index 3ecd770f910b..1443a55a0c29 100644
> > --- a/drivers/reset/reset-imx7.c
> > +++ b/drivers/reset/reset-imx7.c
> > @@ -169,9 +169,9 @@ static const struct imx7_src_signal imx8mq_src_signals[IMX8MQ_RESET_NUM] = {
> > > > [IMX8MQ_RESET_OTG2_PHY_RESET] = { SRC_USBOPHY2_RCR, BIT(0) },
> > > > [IMX8MQ_RESET_MIPI_DSI_RESET_BYTE_N] = { SRC_MIPIPHY_RCR, BIT(1) },
> > > > [IMX8MQ_RESET_MIPI_DSI_RESET_N] = { SRC_MIPIPHY_RCR, BIT(2) },
> > > > - [IMX8MQ_RESET_MIPI_DIS_DPI_RESET_N] = { SRC_MIPIPHY_RCR, BIT(3) },
> > > > - [IMX8MQ_RESET_MIPI_DIS_ESC_RESET_N] = { SRC_MIPIPHY_RCR, BIT(4) },
> > > > - [IMX8MQ_RESET_MIPI_DIS_PCLK_RESET_N] = { SRC_MIPIPHY_RCR, BIT(5) },
> > > > + [IMX8MQ_RESET_MIPI_DSI_DPI_RESET_N] = { SRC_MIPIPHY_RCR, BIT(3) },
> > > > + [IMX8MQ_RESET_MIPI_DSI_ESC_RESET_N] = { SRC_MIPIPHY_RCR, BIT(4) },
> > > > + [IMX8MQ_RESET_MIPI_DSI_PCLK_RESET_N] = { SRC_MIPIPHY_RCR, BIT(5) },
> > > > [IMX8MQ_RESET_PCIEPHY] = { SRC_PCIEPHY_RCR,
> > > BIT(2) | BIT(1) },
> > > > [IMX8MQ_RESET_PCIEPHY_PERST] = { SRC_PCIEPHY_RCR, BIT(3) },
> > @@ -220,9 +220,9 @@ static int imx8mq_reset_set(struct reset_controller_dev *rcdev,
> >
> > > case IMX8MQ_RESET_PCIE_CTRL_APPS_EN:
> > > > case IMX8MQ_RESET_PCIE2_CTRL_APPS_EN: /* fallthrough */
> > > > - case IMX8MQ_RESET_MIPI_DIS_PCLK_RESET_N: /* fallthrough */
> > > > - case IMX8MQ_RESET_MIPI_DIS_ESC_RESET_N: /* fallthrough */
> > > > - case IMX8MQ_RESET_MIPI_DIS_DPI_RESET_N: /* fallthrough */
> > > > + case IMX8MQ_RESET_MIPI_DSI_PCLK_RESET_N: /* fallthrough */
> > > > + case IMX8MQ_RESET_MIPI_DSI_ESC_RESET_N: /* fallthrough */
> > > > + case IMX8MQ_RESET_MIPI_DSI_DPI_RESET_N: /* fallthrough */
> > > > case IMX8MQ_RESET_MIPI_DSI_RESET_N: /* fallthrough */
> > > > case IMX8MQ_RESET_MIPI_DSI_RESET_BYTE_N: /* fallthrough */
> > > value = assert ? 0 : bit;
>
^ permalink raw reply
* [PATCH v2 1/1] dt-bindings: reset: Fix typo in imx8mq resets
From: Guido Günther @ 2019-08-01 8:20 UTC (permalink / raw)
To: Philipp Zabel, Shawn Guo, Sascha Hauer, Pengutronix Kernel Team,
Fabio Estevam, NXP Linux Team, Rob Herring, Mark Rutland,
linux-arm-kernel, linux-kernel, devicetree
In-Reply-To: <cover.1564647612.git.agx@sigxcpu.org>
Some of the mipi dsi resets were called
IMX8MQ_RESET_MIPI_DIS__
instead of
IMX8MQ_RESET_MIPI_DSI__
Since they're DSI related this looks like a typo. This fixes the
only in tree user as well to not break bisecting.
Signed-off-by: Guido Günther <agx@sigxcpu.org>
---
drivers/reset/reset-imx7.c | 12 ++++++------
include/dt-bindings/reset/imx8mq-reset.h | 6 +++---
2 files changed, 9 insertions(+), 9 deletions(-)
diff --git a/drivers/reset/reset-imx7.c b/drivers/reset/reset-imx7.c
index 3ecd770f910b..1443a55a0c29 100644
--- a/drivers/reset/reset-imx7.c
+++ b/drivers/reset/reset-imx7.c
@@ -169,9 +169,9 @@ static const struct imx7_src_signal imx8mq_src_signals[IMX8MQ_RESET_NUM] = {
[IMX8MQ_RESET_OTG2_PHY_RESET] = { SRC_USBOPHY2_RCR, BIT(0) },
[IMX8MQ_RESET_MIPI_DSI_RESET_BYTE_N] = { SRC_MIPIPHY_RCR, BIT(1) },
[IMX8MQ_RESET_MIPI_DSI_RESET_N] = { SRC_MIPIPHY_RCR, BIT(2) },
- [IMX8MQ_RESET_MIPI_DIS_DPI_RESET_N] = { SRC_MIPIPHY_RCR, BIT(3) },
- [IMX8MQ_RESET_MIPI_DIS_ESC_RESET_N] = { SRC_MIPIPHY_RCR, BIT(4) },
- [IMX8MQ_RESET_MIPI_DIS_PCLK_RESET_N] = { SRC_MIPIPHY_RCR, BIT(5) },
+ [IMX8MQ_RESET_MIPI_DSI_DPI_RESET_N] = { SRC_MIPIPHY_RCR, BIT(3) },
+ [IMX8MQ_RESET_MIPI_DSI_ESC_RESET_N] = { SRC_MIPIPHY_RCR, BIT(4) },
+ [IMX8MQ_RESET_MIPI_DSI_PCLK_RESET_N] = { SRC_MIPIPHY_RCR, BIT(5) },
[IMX8MQ_RESET_PCIEPHY] = { SRC_PCIEPHY_RCR,
BIT(2) | BIT(1) },
[IMX8MQ_RESET_PCIEPHY_PERST] = { SRC_PCIEPHY_RCR, BIT(3) },
@@ -220,9 +220,9 @@ static int imx8mq_reset_set(struct reset_controller_dev *rcdev,
case IMX8MQ_RESET_PCIE_CTRL_APPS_EN:
case IMX8MQ_RESET_PCIE2_CTRL_APPS_EN: /* fallthrough */
- case IMX8MQ_RESET_MIPI_DIS_PCLK_RESET_N: /* fallthrough */
- case IMX8MQ_RESET_MIPI_DIS_ESC_RESET_N: /* fallthrough */
- case IMX8MQ_RESET_MIPI_DIS_DPI_RESET_N: /* fallthrough */
+ case IMX8MQ_RESET_MIPI_DSI_PCLK_RESET_N: /* fallthrough */
+ case IMX8MQ_RESET_MIPI_DSI_ESC_RESET_N: /* fallthrough */
+ case IMX8MQ_RESET_MIPI_DSI_DPI_RESET_N: /* fallthrough */
case IMX8MQ_RESET_MIPI_DSI_RESET_N: /* fallthrough */
case IMX8MQ_RESET_MIPI_DSI_RESET_BYTE_N: /* fallthrough */
value = assert ? 0 : bit;
diff --git a/include/dt-bindings/reset/imx8mq-reset.h b/include/dt-bindings/reset/imx8mq-reset.h
index 57c592498aa0..bfa41b0e24f6 100644
--- a/include/dt-bindings/reset/imx8mq-reset.h
+++ b/include/dt-bindings/reset/imx8mq-reset.h
@@ -31,9 +31,9 @@
#define IMX8MQ_RESET_OTG2_PHY_RESET 20
#define IMX8MQ_RESET_MIPI_DSI_RESET_BYTE_N 21
#define IMX8MQ_RESET_MIPI_DSI_RESET_N 22
-#define IMX8MQ_RESET_MIPI_DIS_DPI_RESET_N 23
-#define IMX8MQ_RESET_MIPI_DIS_ESC_RESET_N 24
-#define IMX8MQ_RESET_MIPI_DIS_PCLK_RESET_N 25
+#define IMX8MQ_RESET_MIPI_DSI_DPI_RESET_N 23
+#define IMX8MQ_RESET_MIPI_DSI_ESC_RESET_N 24
+#define IMX8MQ_RESET_MIPI_DSI_PCLK_RESET_N 25
#define IMX8MQ_RESET_PCIEPHY 26
#define IMX8MQ_RESET_PCIEPHY_PERST 27
#define IMX8MQ_RESET_PCIE_CTRL_APPS_EN 28
--
2.20.1
^ permalink raw reply related
* [PATCH v2 0/1] imx: Fix typo in iMQ8MQ reset names
From: Guido Günther @ 2019-08-01 8:20 UTC (permalink / raw)
To: Philipp Zabel, Shawn Guo, Sascha Hauer, Pengutronix Kernel Team,
Fabio Estevam, NXP Linux Team, Rob Herring, Mark Rutland,
linux-arm-kernel, linux-kernel, devicetree
Some of the mipi dsi resets were called
IMX8MQ_RESET_MIPI_DIS_
instead of
IMX8MQ_RESET_MIPI_DSI_
Since they're DSI related this looks like a typo. This fixes the only in tree
user as well to not break bisecting.
Guido Günther (1):
dt-bindings: reset: Fix typo in imx8mq resets
drivers/reset/reset-imx7.c | 12 ++++++------
include/dt-bindings/reset/imx8mq-reset.h | 6 +++---
2 files changed, 9 insertions(+), 9 deletions(-)
--
2.20.1
^ permalink raw reply
* Re: [PATCH v3 2/4] edac: Add support for Amazon's Annapurna Labs L1 EDAC
From: Hawa, Hanna @ 2019-08-01 8:20 UTC (permalink / raw)
To: James Morse
Cc: robh+dt, mark.rutland, bp, mchehab, davem, gregkh, linus.walleij,
Jonathan.Cameron, nicolas.ferre, paulmck, dwmw, benh, ronenk,
talel, jonnyc, hanochu, devicetree, linux-kernel, linux-edac
In-Reply-To: <a2dc6760-50e2-6e98-5b61-002836d92dd2@arm.com>
On 7/26/2019 7:49 PM, James Morse wrote:
> Hi Hanna,
>
> On 15/07/2019 14:24, Hanna Hawa wrote:
>> Adds support for Amazon's Annapurna Labs L1 EDAC driver to detect and
>> report L1 errors.
>
>> diff --git a/drivers/edac/al_l1_edac.c b/drivers/edac/al_l1_edac.c
>> new file mode 100644
>> index 0000000..70510ea
>> --- /dev/null
>> +++ b/drivers/edac/al_l1_edac.c
>> @@ -0,0 +1,156 @@
>
>> +#include <linux/bitfield.h>
>
> You need <linux/smp.h> for on-each_cpu().
>
>> +#include "edac_device.h"
>> +#include "edac_module.h"
>
> You need <asm/sysreg.h> for the sys_reg() macro. The ARCH_ALPINE dependency doesn't stop
> this from being built on 32bit arm, where this sys_reg() won't work/exist.
Will fix.
>
> [...]
>
>> +static void al_l1_edac_cpumerrsr(void *arg)
>> +{
>> + struct edac_device_ctl_info *edac_dev = arg;
>> + int cpu, i;
>> + u32 ramid, repeat, other, fatal;
>> + u64 val = read_sysreg_s(ARM_CA57_CPUMERRSR_EL1);
>> + char msg[AL_L1_EDAC_MSG_MAX];
>> + int space, count;
>> + char *p;
>> + if (!(FIELD_GET(ARM_CA57_CPUMERRSR_VALID, val)))
>> + return;
>> + space = sizeof(msg);
>> + p = msg;
>> + count = snprintf(p, space, "CPU%d L1 %serror detected", cpu,
>> + (fatal) ? "Fatal " : "");
>> + p += count;
>> + space -= count;
>
> snprintf() will return the number of characters it would have generated, even if that is
> more than space. If this happen, space becomes negative, p points outside msg[] and msg[]
> isn't NULL terminated...
>
> It looks like you want scnprintf(), which returns the number of characters written to buf
> instead. (I don't see how 256 characters would be printed by this code)
Will use scnprintf() instead.
>
>
>> + switch (ramid) {
>> + case ARM_CA57_L1_I_TAG_RAM:
>> + count = snprintf(p, space, " RAMID='L1-I Tag RAM'");
>> + break;
>> + case ARM_CA57_L1_I_DATA_RAM:
>> + count = snprintf(p, space, " RAMID='L1-I Data RAM'");
>> + break;
>> + case ARM_CA57_L1_D_TAG_RAM:
>> + count = snprintf(p, space, " RAMID='L1-D Tag RAM'");
>> + break;
>> + case ARM_CA57_L1_D_DATA_RAM:
>> + count = snprintf(p, space, " RAMID='L1-D Data RAM'");
>> + break;
>> + case ARM_CA57_L2_TLB_RAM:
>> + count = snprintf(p, space, " RAMID='L2 TLB RAM'");
>> + break;
>> + default:
>> + count = snprintf(p, space, " RAMID='unknown'");
>> + break;
>> + }
>> +
>> + p += count;
>> + space -= count;
>> + count = snprintf(p, space,
>> + " repeat=%d, other=%d (CPUMERRSR_EL1=0x%llx)",
>> + repeat, other, val);
>> +
>> + for (i = 0; i < repeat; i++) {
>> + if (fatal)
>> + edac_device_handle_ue(edac_dev, 0, 0, msg);
>> + else
>> + edac_device_handle_ce(edac_dev, 0, 0, msg);
>> + }
>> +
>> + write_sysreg_s(0, ARM_CA57_CPUMERRSR_EL1);
>
> Writing 0 just after you've read the value would minimise the window where repeat could
> have increased behind your back, or another error was counted as other, when it could have
> been reported more accurately.
Good point, I will move the write after checking the valid bit.
>
>
>> +}
>
>
>> +static int al_l1_edac_probe(struct platform_device *pdev)
>> +{
>> + struct edac_device_ctl_info *edac_dev;
>> + struct device *dev = &pdev->dev;
>> + int ret;
>> +
>> + edac_dev = edac_device_alloc_ctl_info(0, (char *)dev_name(dev), 1, "L",
>> + 1, 1, NULL, 0,
>> + edac_device_alloc_index());
>> + if (IS_ERR(edac_dev))
>
> edac_device_alloc_ctl_info() returns NULL, or dev_ctl, which comes from kzalloc(). I think
> you need to check for NULL here, IS_ERR() only catches the -errno range. (there is an
> IS_ERR_OR_NULL() if you really needed both)
Will fix.
>
>
>> + return -ENOMEM;
>
>
> With the header-includes and edac_device_alloc_ctl_info() NULL check:
> Reviewed-by: James Morse <james.morse@arm.com>
Thanks James.
Thanks,
Hanna
>
>
> Thanks,
>
> James
>
^ permalink raw reply
* Re: [RFC PATCH 09/11] devfreq: exynos-bus: Add interconnect functionality to exynos-bus
From: Artur Świgoń @ 2019-08-01 7:59 UTC (permalink / raw)
To: Georgi Djakov, devicetree, linux-arm-kernel, linux-samsung-soc,
linux-kernel, linux-pm, dri-devel
Cc: krzk, cw00.choi, myungjoo.ham, inki.dae, sw0312.kim, m.szyprowski,
Bartłomiej Żołnierkiewicz
In-Reply-To: <6e8b2081-2fb3-9ab8-37d1-8b5fe5fd8e11@linaro.org>
Hi Georgi,
On Fri, 2019-07-26 at 11:05 +0300, Georgi Djakov wrote:
> Hi Artur,
>
> On 7/23/19 15:20, Artur Świgoń wrote:
> > This patch adds interconnect functionality to the exynos-bus devfreq
> > driver.
> >
> > The SoC topology is a graph (or, more specifically, a tree) and most of its
> > edges are taken from the devfreq parent-child hierarchy (cf.
> > Documentation/devicetree/bindings/devfreq/exynos-bus.txt). The previous
> > patch adds missing edges to the DT (under the name 'parent'). Due to
> > unspecified relative probing order, -EPROBE_DEFER may be propagated to
> > guarantee that a child is probed before its parent.
> >
> > Each bus is now an interconnect provider and an interconnect node as well
> > (cf. Documentation/interconnect/interconnect.rst), i.e. every bus registers
> > itself as a node. Node IDs are not hardcoded but rather assigned at
> > runtime, in probing order (subject to the above-mentioned exception
> > regarding relative order). This approach allows for using this driver with
> > various Exynos SoCs.
>
> I am not familiar with the Exynos bus topology, but it seems to me that it's not
> represented correctly. An interconnect provider with just a single node (port)
> is odd. I would expect that each provider consists of multiple master and slave
> nodes. This data would be used by a framework to understand what are the links
> and how the traffic flows between the IP blocks and through which buses.
To summarize the exynos-bus topology[1] used by the devfreq driver: There are
many data buses for data transfer in Samsung Exynos SoC. Every bus has its own
clock. Buses often share power lines, in which case one of the buses on the
power line is referred to as 'parent' (or as 'devfreq' in the DT). In the
particular case of Exynos4412[1][2], the topology can be expressed as follows:
bus_dmc
-- bus_acp
-- bus_c2c
bus_leftbus
-- bus_rightbus
-- bus_display
-- bus_fsys
-- bus_peri
-- bus_mfc
Where bus_dmc and bus_leftbus probably could be referred to as masters, and the
following indented nodes as slaves. Patch 08/11 of this RFC additionally adds
the following to the DT:
bus_dmc
-- bus_leftbus
Which makes the topology a valid tree.
The exynos-bus concept in devfreq[3] is designed in such a way that every bus is
probed separately as a platform device, and is a largely independent entity.
This RFC proposes an extension to the existing devfreq driver that basically
provides a simple QoS to ensure minimum clock frequency for selected buses
(possibly overriding devfreq governor calculations) using the interconnect
framework.
The hierarchy is modelled in such a way that every bus is an interconnect node.
On the other hand, what is considered an interconnect provider here is quite
arbitrary, but for the reasons mentioned in the above paragraph, this RFC
assumes that every bus is a provider of itself as a node. Using an alternative
singleton provider approach was deemed more complicated since the 'dev' field in
'struct icc_provider' has to be set to something meaningful and we are tied to
the 'samsung,exynos-bus' compatible string in the driver (and multiple instances
of exynos-bus probed in indeterminate relative order).
I'm looking forward to hearing any additional thoughts you may have on this
topic.
Best regards,
--
Artur Świgoń
Samsung R&D Institute Poland
Samsung Electronics
[1] Documentation/devicetree/bindings/devfreq/exynos-bus.txt
[2]
arch/arm/boot/dts/exynos4412-odroid-common.dtsi
[3] drivers/devfreq/exynos-bus.c
(subject of this patch)
^ permalink raw reply
* [PATCH] ARM: dts: stm32: add DFSDM pins to stm32mp157c
From: Olivier Moysan @ 2019-08-01 7:46 UTC (permalink / raw)
To: linux-stm32, alexandre.torgue, robh, mark.rutland, devicetree,
linux-arm-kernel, linux-kernel, olivier.moysan
Add DFSDM pins to stm32mp157c.
Signed-off-by: Olivier Moysan <olivier.moysan@st.com>
---
arch/arm/boot/dts/stm32mp157-pinctrl.dtsi | 39 +++++++++++++++++++++++++++++++
1 file changed, 39 insertions(+)
diff --git a/arch/arm/boot/dts/stm32mp157-pinctrl.dtsi b/arch/arm/boot/dts/stm32mp157-pinctrl.dtsi
index 9eaec9bf8cb8..f96a928cbc49 100644
--- a/arch/arm/boot/dts/stm32mp157-pinctrl.dtsi
+++ b/arch/arm/boot/dts/stm32mp157-pinctrl.dtsi
@@ -230,6 +230,45 @@
};
};
+ dfsdm_clkout_pins_a: dfsdm-clkout-pins-0 {
+ pins {
+ pinmux = <STM32_PINMUX('B', 13, AF3)>; /* DFSDM_CKOUT */
+ bias-disable;
+ drive-push-pull;
+ slew-rate = <0>;
+ };
+ };
+
+ dfsdm_clkout_sleep_pins_a: dfsdm-clkout-sleep-pins-0 {
+ pins {
+ pinmux = <STM32_PINMUX('B', 13, ANALOG)>; /* DFSDM_CKOUT */
+ };
+ };
+
+ dfsdm_data1_pins_a: dfsdm-data1-pins-0 {
+ pins {
+ pinmux = <STM32_PINMUX('C', 3, AF3)>; /* DFSDM_DATA1 */
+ };
+ };
+
+ dfsdm_data1_sleep_pins_a: dfsdm-data1-sleep-pins-0 {
+ pins {
+ pinmux = <STM32_PINMUX('C', 3, ANALOG)>; /* DFSDM_DATA1 */
+ };
+ };
+
+ dfsdm_data3_pins_a: dfsdm-data3-pins-0 {
+ pins {
+ pinmux = <STM32_PINMUX('F', 13, AF6)>; /* DFSDM_DATA3 */
+ };
+ };
+
+ dfsdm_data3_sleep_pins_a: dfsdm-data3-sleep-pins-0 {
+ pins {
+ pinmux = <STM32_PINMUX('F', 13, ANALOG)>; /* DFSDM_DATA3 */
+ };
+ };
+
ethernet0_rgmii_pins_a: rgmii-0 {
pins1 {
pinmux = <STM32_PINMUX('G', 5, AF11)>, /* ETH_RGMII_CLK125 */
--
2.7.4
^ permalink raw reply related
* Re: [PATCH 0/3] media: Add support for Cadence CSI2RX version 2.1
From: Jan Kotas @ 2019-08-01 7:36 UTC (permalink / raw)
To: Maxime Ripard, mchehab@kernel.org, Rob Herring, Mark Rutland
Cc: Rafal Ciepiela, linux-media, linux-devicetree, LKML, Jan Kotas
In-Reply-To: <20190725102648.13445-1-jank@cadence.com>
> On 25 Jul 2019, at 12:26, Jan Kotas <jank@cadence.com> wrote:
>
> This patchset adds support for Cadence CSI2RX controller version 2.1.
> It currently limits maximum amount of data lanes to 4.
> Existing compatibility with v1.3 is maintained.
>
> Jan Kotas (3):
> media: dt-bindings: Update bindings for Cadence CSI2RX version 2.1
> media: Add lane checks for Cadence CSI2RX
> media: Add support for Cadence CSI2RX 2.1
>
> .../devicetree/bindings/media/cdns,csi2rx.txt | 4 +-
> drivers/media/platform/cadence/cdns-csi2rx.c | 150 +++++++++++++++++----
> 2 files changed, 129 insertions(+), 25 deletions(-)
>
> --
> 2.15.0
>
Gentle ping.
Regards,
Jan
^ permalink raw reply
* [PATCH v1 2/2] net: npcm: add NPCM7xx EMC 10/100 Ethernet driver
From: Avi Fishman @ 2019-08-01 7:26 UTC (permalink / raw)
To: venture, yuenn, benjaminfair, davem, robh+dt, mark.rutland,
gregkh
Cc: avifishman70, tmaimon77, tali.perry1, openbmc, netdev, devicetree,
linux-kernel, tglx
In-Reply-To: <20190801072611.27935-1-avifishman70@gmail.com>
EMC Ethernet Media Access Controller supports 10/100 Mbps and
RMII.
This driver has been working on Nuvoton BMC NPCM7xx.
Signed-off-by: Avi Fishman <avifishman70@gmail.com>
---
drivers/net/ethernet/nuvoton/Kconfig | 21 +-
drivers/net/ethernet/nuvoton/Makefile | 2 +
drivers/net/ethernet/nuvoton/npcm7xx_emc.c | 2073 ++++++++++++++++++++
3 files changed, 2093 insertions(+), 3 deletions(-)
create mode 100644 drivers/net/ethernet/nuvoton/npcm7xx_emc.c
diff --git a/drivers/net/ethernet/nuvoton/Kconfig b/drivers/net/ethernet/nuvoton/Kconfig
index 325e26c549f8..3820dd3bc4b7 100644
--- a/drivers/net/ethernet/nuvoton/Kconfig
+++ b/drivers/net/ethernet/nuvoton/Kconfig
@@ -6,8 +6,8 @@
config NET_VENDOR_NUVOTON
bool "Nuvoton devices"
default y
- depends on ARM && ARCH_W90X900
- ---help---
+ depends on ARM && (ARCH_W90X900 || ARCH_NPCM7XX)
+ help
If you have a network (Ethernet) card belonging to this class, say Y.
Note that the answer to this question doesn't directly affect the
@@ -22,8 +22,23 @@ config W90P910_ETH
depends on ARM && ARCH_W90X900
select PHYLIB
select MII
- ---help---
+ help
Say Y here if you want to use built-in Ethernet ports
on w90p910 processor.
+config NPCM7XX_EMC_ETH
+ bool "Nuvoton NPCM7XX Ethernet EMC"
+ depends on ARM && ARCH_NPCM7XX
+ select PHYLIB
+ select MII
+ help
+ Say Y here if you want to use built-in Ethernet MAC
+ on NPCM750 MCU.
+
+config NPCM7XX_EMC_ETH_DEBUG
+ bool "Nuvoton NPCM7XX Ethernet EMC debug"
+ depends on NPCM7XX_EMC_ETH
+ help
+ Say Y here if you want debug info via /proc/driver/npcm7xx_emc.x
+
endif # NET_VENDOR_NUVOTON
diff --git a/drivers/net/ethernet/nuvoton/Makefile b/drivers/net/ethernet/nuvoton/Makefile
index 66f6e728d54b..e32be694e987 100644
--- a/drivers/net/ethernet/nuvoton/Makefile
+++ b/drivers/net/ethernet/nuvoton/Makefile
@@ -3,4 +3,6 @@
# Makefile for the Nuvoton network device drivers.
#
+#Eternet 10/100 EMC
obj-$(CONFIG_W90P910_ETH) += w90p910_ether.o
+obj-$(CONFIG_NPCM7XX_EMC_ETH) += npcm7xx_emc.o
diff --git a/drivers/net/ethernet/nuvoton/npcm7xx_emc.c b/drivers/net/ethernet/nuvoton/npcm7xx_emc.c
new file mode 100644
index 000000000000..de56c7192b76
--- /dev/null
+++ b/drivers/net/ethernet/nuvoton/npcm7xx_emc.c
@@ -0,0 +1,2073 @@
+// SPDX-License-Identifier: GPL-2.0
+// Copyright (c) 2014-2019 Nuvoton Technology corporation.
+
+#ifdef CONFIG_NPCM7XX_EMC_ETH_DEBUG
+#define DEBUG
+#endif
+
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/mii.h>
+#include <linux/phy.h>
+#include <linux/netdevice.h>
+#include <linux/etherdevice.h>
+#include <linux/skbuff.h>
+#include <linux/ethtool.h>
+#include <linux/platform_device.h>
+#include <linux/gfp.h>
+#include <linux/kthread.h>
+#include <linux/interrupt.h>
+#include <linux/spinlock.h>
+#include <linux/ctype.h>
+#include <linux/debugfs.h>
+#include <linux/reset.h>
+
+#include <linux/clk.h>
+
+#include <linux/of.h>
+#include <linux/of_net.h>
+#include <linux/of_device.h>
+#include <linux/dma-mapping.h>
+
+#include <linux/regmap.h>
+#include <linux/mfd/syscon.h>
+
+#include <linux/if_ether.h>
+
+#include <net/ip.h>
+#include <net/ncsi.h>
+
+#ifdef CONFIG_DEBUG_FS
+static struct dentry *npcm7xx_fs_dir;
+#endif
+
+#define MFSEL1_OFFSET 0x00C
+#define MFSEL3_OFFSET 0x064
+#define INTCR_OFFSET 0x03C
+
+#define IPSRST1_OFFSET 0x020
+
+#define DRV_MODULE_NAME "npcm7xx-emc"
+#define DRV_MODULE_VERSION "3.90"
+
+/* Ethernet MAC Registers */
+#define REG_CAMCMR 0x00
+#define REG_CAMEN 0x04
+#define REG_CAMM_BASE 0x08
+#define REG_CAML_BASE 0x0c
+#define REG_TXDLSA 0x88
+#define REG_RXDLSA 0x8C
+#define REG_MCMDR 0x90
+#define REG_MIID 0x94
+#define REG_MIIDA 0x98
+#define REG_FFTCR 0x9C
+#define REG_TSDR 0xa0
+#define REG_RSDR 0xa4
+#define REG_DMARFC 0xa8
+#define REG_MIEN 0xac
+#define REG_MISTA 0xb0
+#define REG_MGSTA 0xb4
+#define REG_MPCNT 0xb8
+#define REG_MRPC 0xbc
+#define REG_MRPCC 0xc0
+#define REG_MREPC 0xc4
+#define REG_DMARFS 0xc8
+#define REG_CTXDSA 0xcc
+#define REG_CTXBSA 0xd0
+#define REG_CRXDSA 0xd4
+#define REG_CRXBSA 0xd8
+
+/* EMC Diagnostic Registers */
+#define REG_RXFSM 0x200
+#define REG_TXFSM 0x204
+#define REG_FSM0 0x208
+#define REG_FSM1 0x20c
+#define REG_DCR 0x210
+#define REG_DMMIR 0x214
+#define REG_BISTR 0x300
+
+/* mac controller bit */
+#define MCMDR_RXON BIT(0)
+#define MCMDR_ALP BIT(1)
+#define MCMDR_ACP BIT(3)
+#define MCMDR_SPCRC BIT(5)
+#define MCMDR_TXON BIT(8)
+#define MCMDR_NDEF BIT(9)
+#define MCMDR_FDUP BIT(18)
+#define MCMDR_ENMDC BIT(19)
+#define MCMDR_OPMOD BIT(20)
+#define SWR BIT(24)
+
+/* cam command regiser */
+#define CAMCMR_AUP BIT(0)
+#define CAMCMR_AMP BIT(1)
+#define CAMCMR_ABP BIT(2)
+#define CAMCMR_CCAM BIT(3)
+#define CAMCMR_ECMP BIT(4)
+
+/* cam enable regiser */
+#define CAM0EN BIT(0)
+
+/* mac mii controller bit */
+#define PHYAD BIT(8)
+#define PHYWR BIT(16)
+#define PHYBUSY BIT(17)
+#define PHYPRESP BIT(18)
+#define MDCON BIT(19)
+#define CAM_ENTRY_SIZE 0x08
+
+/* rx and tx status */
+#define TXDS_TXCP BIT(19)
+#define RXDS_CRCE BIT(17)
+#define RXDS_PTLE BIT(19)
+#define RXDS_RXGD BIT(20)
+#define RXDS_ALIE BIT(21)
+#define RXDS_RP BIT(22)
+
+/* mac interrupt status*/
+#define MISTA_RXINTR BIT(0)
+#define MISTA_CRCE BIT(1)
+#define MISTA_RXOV BIT(2)
+#define MISTA_PTLE BIT(3)
+#define MISTA_RXGD BIT(4)
+#define MISTA_ALIE BIT(5)
+#define MISTA_RP BIT(6)
+#define MISTA_MMP BIT(7)
+#define MISTA_DFOI BIT(8)
+#define MISTA_DENI BIT(9)
+#define MISTA_RDU BIT(10)
+#define MISTA_RXBERR BIT(11)
+#define MISTA_CFR BIT(14)
+#define MISTA_TXINTR BIT(16)
+#define MISTA_TXEMP BIT(17)
+#define MISTA_TXCP BIT(18)
+#define MISTA_EXDEF BIT(19)
+#define MISTA_NCS BIT(20)
+#define MISTA_TXABT BIT(21)
+#define MISTA_LC BIT(22)
+#define MISTA_TDU BIT(23)
+#define MISTA_TXBERR BIT(24)
+
+/* Transmit/Receive Start Demand Register */
+#define ENSTART BIT(0)
+
+#define ENRXINTR BIT(0)
+#define ENCRCE BIT(1)
+#define EMRXOV BIT(2)
+#define ENPTLE BIT(3)
+#define ENRXGD BIT(4)
+#define ENALIE BIT(5)
+#define ENRP BIT(6)
+#define ENMMP BIT(7)
+#define ENDFO BIT(8)
+#define ENDENI BIT(9)
+#define ENRDU BIT(10)
+#define ENRXBERR BIT(11)
+#define ENCFR BIT(14)
+#define ENTXINTR BIT(16)
+#define ENTXEMP BIT(17)
+#define ENTXCP BIT(18)
+#define ENTXDEF BIT(19)
+#define ENNCS BIT(20)
+#define ENTXABT BIT(21)
+#define ENLC BIT(22)
+#define ENTDU BIT(23)
+#define ENTXBERR BIT(24)
+
+/* rx and tx owner bit */
+#define RX_OWN_DMA BIT(31)
+#define TX_OWN_DMA BIT(31)
+
+/* tx frame desc controller bit */
+#define MACTXINTEN BIT(2)
+#define CRCMODE BIT(1)
+#define PADDINGMODE BIT(0)
+
+/* fftcr controller bit */
+#define RXTHD (0x03 << 0)
+#define TXTHD (0x02 << 8)
+#define BLENGTH (0x02 << 20)
+
+/* global setting for driver */
+#define RX_QUEUE_LEN 128
+#define TX_QUEUE_LEN 64
+#define MAX_RBUFF_SZ 0x600
+#define MAX_TBUFF_SZ 0x600
+#define TX_TIMEOUT 50
+#define DELAY 1000
+#define CAM0 0x0
+#define RX_POLL_SIZE 16
+
+#ifdef CONFIG_VLAN_8021Q
+#define IS_VLAN 1
+#else
+#define IS_VLAN 0
+#endif
+
+#define MAX_PACKET_SIZE (1514 + (IS_VLAN * 4))
+#define MAX_PACKET_SIZE_W_CRC (MAX_PACKET_SIZE + 4) /* 1518 */
+
+#define MHZ (1000 * 1000)
+#define MII_TIMEOUT 100
+
+struct plat_npcm7xx_emc_data {
+ char *phy_bus_name;
+ int phy_addr;
+ unsigned char mac_addr[ETH_ALEN];
+};
+
+struct npcm7xx_rxbd {
+ __le32 sl;
+ __le32 buffer;
+ __le32 reserved;
+ __le32 next;
+};
+
+struct npcm7xx_txbd {
+ __le32 mode; /* Ownership bit and some other bits */
+ __le32 buffer; /* Transmit Buffer Starting Address */
+ __le32 sl; /* Transmit Byte Count and status bits */
+ __le32 next; /* Next Tx Descriptor Starting Address */
+};
+
+struct npcm7xx_ether {
+ struct sk_buff *rx_skb[RX_QUEUE_LEN];
+ struct sk_buff *tx_skb[TX_QUEUE_LEN];
+ spinlock_t lock; /* lock sk */
+ struct npcm7xx_rxbd *rdesc;
+ struct npcm7xx_txbd *tdesc;
+ dma_addr_t rdesc_phys;
+ dma_addr_t tdesc_phys;
+ struct net_device_stats stats;
+ struct platform_device *pdev;
+ struct net_device *netdev;
+ struct resource *res;
+ unsigned int msg_enable;
+ struct mii_bus *mii_bus;
+ struct phy_device *phy_dev;
+ struct napi_struct napi;
+ struct ncsi_dev *ncsidev;
+ bool use_ncsi;
+ void __iomem *reg;
+ int rxirq;
+ int txirq;
+ unsigned int cur_tx;
+ unsigned int cur_rx;
+ unsigned int finish_tx;
+ unsigned int pending_tx;
+ __le32 start_tx_ptr;
+ __le32 start_rx_ptr;
+ unsigned int rx_berr;
+ unsigned int rx_err;
+ unsigned int rdu;
+ unsigned int rxov;
+ __le32 camcmr;
+ unsigned int rx_stuck;
+ int link;
+ int speed;
+ int duplex;
+ int need_reset;
+ char *dump_buf;
+ struct reset_control *reset;
+
+ /* Scratch page to use when rx skb alloc fails */
+ void *rx_scratch;
+ dma_addr_t rx_scratch_dma;
+
+ /* debug counters */
+ unsigned int max_waiting_rx;
+ unsigned int rx_count_pool;
+ unsigned int count_xmit;
+ unsigned int rx_int_count;
+ unsigned int rx_err_count;
+ unsigned int tx_int_count;
+ unsigned int tx_tdu;
+ unsigned int tx_tdu_i;
+ unsigned int tx_cp_i;
+ unsigned int count_finish;
+
+#ifdef CONFIG_DEBUG_FS
+ struct dentry *dbgfs_dir;
+ struct dentry *dbgfs_status;
+ struct dentry *dbgfs_dma_cap;
+#endif
+};
+
+#if defined CONFIG_NPCM7XX_EMC_ETH_DEBUG || defined CONFIG_DEBUG_FS
+#define REG_PRINT(reg_name) {t = scnprintf(next, size, "%-10s = %08X\n", \
+ #reg_name, readl(ether->reg + (reg_name))); size -= t; next += t; }
+#define DUMP_PRINT(f, x...) {t = scnprintf(next, size, f, ## x); size -= t; \
+ next += t; }
+
+static int npcm7xx_info_dump(char *buf, int count, struct net_device *netdev)
+{
+ struct npcm7xx_ether *ether = netdev_priv(netdev);
+ struct npcm7xx_txbd *txbd;
+ struct npcm7xx_rxbd *rxbd;
+ unsigned long flags;
+ unsigned int i, cur, txd_offset, rxd_offset;
+ char *next = buf;
+ unsigned int size = count;
+ int t;
+ int is_locked = spin_is_locked(ðer->lock);
+
+ if (!is_locked)
+ spin_lock_irqsave(ðer->lock, flags);
+
+ /* ------basic driver information ---- */
+ DUMP_PRINT("NPCM7XX EMC %s driver version: %s\n", netdev->name,
+ DRV_MODULE_VERSION);
+
+ REG_PRINT(REG_CAMCMR);
+ REG_PRINT(REG_CAMEN);
+ REG_PRINT(REG_CAMM_BASE);
+ REG_PRINT(REG_CAML_BASE);
+ REG_PRINT(REG_TXDLSA);
+ REG_PRINT(REG_RXDLSA);
+ REG_PRINT(REG_MCMDR);
+ REG_PRINT(REG_MIID);
+ REG_PRINT(REG_MIIDA);
+ REG_PRINT(REG_FFTCR);
+ REG_PRINT(REG_TSDR);
+ REG_PRINT(REG_RSDR);
+ REG_PRINT(REG_DMARFC);
+ REG_PRINT(REG_MIEN);
+ REG_PRINT(REG_MISTA);
+ REG_PRINT(REG_MGSTA);
+ REG_PRINT(REG_MPCNT);
+ writel(0x7FFF, (ether->reg + REG_MPCNT));
+ REG_PRINT(REG_MRPC);
+ REG_PRINT(REG_MRPCC);
+ REG_PRINT(REG_MREPC);
+ REG_PRINT(REG_DMARFS);
+ REG_PRINT(REG_CTXDSA);
+ REG_PRINT(REG_CTXBSA);
+ REG_PRINT(REG_CRXDSA);
+ REG_PRINT(REG_CRXBSA);
+ REG_PRINT(REG_RXFSM);
+ REG_PRINT(REG_TXFSM);
+ REG_PRINT(REG_FSM0);
+ REG_PRINT(REG_FSM1);
+ REG_PRINT(REG_DCR);
+ REG_PRINT(REG_DMMIR);
+ REG_PRINT(REG_BISTR);
+ DUMP_PRINT("\n");
+
+ DUMP_PRINT("netif_queue %s\n\n", netif_queue_stopped(netdev) ?
+ "Stopped" : "Running");
+ if (ether->rdesc)
+ DUMP_PRINT("napi is %s\n\n", test_bit(NAPI_STATE_SCHED,
+ ðer->napi.state) ?
+ "scheduled" :
+ "not scheduled");
+
+ txd_offset = (readl((ether->reg + REG_CTXDSA)) -
+ readl((ether->reg + REG_TXDLSA))) /
+ sizeof(struct npcm7xx_txbd);
+ DUMP_PRINT("TXD offset %6d\n", txd_offset);
+ DUMP_PRINT("cur_tx %6d\n", ether->cur_tx);
+ DUMP_PRINT("finish_tx %6d\n", ether->finish_tx);
+ DUMP_PRINT("pending_tx %6d\n", ether->pending_tx);
+ /* debug counters */
+ DUMP_PRINT("tx_tdu %6d\n", ether->tx_tdu);
+ ether->tx_tdu = 0;
+ DUMP_PRINT("tx_tdu_i %6d\n", ether->tx_tdu_i);
+ ether->tx_tdu_i = 0;
+ DUMP_PRINT("tx_cp_i %6d\n", ether->tx_cp_i);
+ ether->tx_cp_i = 0;
+ DUMP_PRINT("tx_int_count %6d\n", ether->tx_int_count);
+ ether->tx_int_count = 0;
+ DUMP_PRINT("count_xmit tx %6d\n", ether->count_xmit);
+ ether->count_xmit = 0;
+ DUMP_PRINT("count_finish %6d\n", ether->count_finish);
+ ether->count_finish = 0;
+ DUMP_PRINT("\n");
+
+ rxd_offset = (readl((ether->reg + REG_CRXDSA)) -
+ readl((ether->reg + REG_RXDLSA)))
+ / sizeof(struct npcm7xx_txbd);
+ DUMP_PRINT("RXD offset %6d\n", rxd_offset);
+ DUMP_PRINT("cur_rx %6d\n", ether->cur_rx);
+ DUMP_PRINT("rx_err %6d\n", ether->rx_err);
+ ether->rx_err = 0;
+ DUMP_PRINT("rx_berr %6d\n", ether->rx_berr);
+ ether->rx_berr = 0;
+ DUMP_PRINT("rx_stuck %6d\n", ether->rx_stuck);
+ ether->rx_stuck = 0;
+ DUMP_PRINT("rdu %6d\n", ether->rdu);
+ ether->rdu = 0;
+ DUMP_PRINT("rxov rx %6d\n", ether->rxov);
+ ether->rxov = 0;
+ /* debug counters */
+ DUMP_PRINT("rx_int_count %6d\n", ether->rx_int_count);
+ ether->rx_int_count = 0;
+ DUMP_PRINT("rx_err_count %6d\n", ether->rx_err_count);
+ ether->rx_err_count = 0;
+ DUMP_PRINT("rx_count_pool %6d\n", ether->rx_count_pool);
+ ether->rx_count_pool = 0;
+ DUMP_PRINT("max_waiting_rx %5d\n", ether->max_waiting_rx);
+ ether->max_waiting_rx = 0;
+ DUMP_PRINT("\n");
+ DUMP_PRINT("need_reset %5d\n", ether->need_reset);
+
+ if (ether->tdesc && ether->rdesc) {
+ cur = ether->finish_tx - 2;
+ for (i = 0; i < 3; i++) {
+ cur = (cur + 1) % TX_QUEUE_LEN;
+ txbd = (ether->tdesc + cur);
+ DUMP_PRINT("finish %3d txbd mode %08X buffer %08X sl %08X next %08X tx_skb %p\n",
+ cur, txbd->mode, txbd->buffer,
+ txbd->sl, txbd->next, ether->tx_skb[cur]);
+ }
+ DUMP_PRINT("\n");
+
+ cur = txd_offset - 2;
+ for (i = 0; i < 3; i++) {
+ cur = (cur + 1) % TX_QUEUE_LEN;
+ txbd = (ether->tdesc + cur);
+ DUMP_PRINT("txd_of %3d txbd mode %08X buffer %08X sl %08X next %08X\n",
+ cur, txbd->mode, txbd->buffer,
+ txbd->sl, txbd->next);
+ }
+ DUMP_PRINT("\n");
+
+ cur = ether->cur_tx - 63;
+ for (i = 0; i < 64; i++) {
+ cur = (cur + 1) % TX_QUEUE_LEN;
+ txbd = (ether->tdesc + cur);
+ DUMP_PRINT("cur_tx %3d txbd mode %08X buffer %08X sl %08X next %08X\n",
+ cur, txbd->mode, txbd->buffer,
+ txbd->sl, txbd->next);
+ }
+ DUMP_PRINT("\n");
+
+ cur = ether->cur_rx - 63;
+ for (i = 0; i < 64; i++) {
+ cur = (cur + 1) % RX_QUEUE_LEN;
+ rxbd = (ether->rdesc + cur);
+ DUMP_PRINT("cur_rx %3d rxbd sl %08X buffer %08X sl %08X next %08X\n",
+ cur, rxbd->sl, rxbd->buffer,
+ rxbd->reserved, rxbd->next);
+ }
+ DUMP_PRINT("\n");
+
+ cur = rxd_offset - 2;
+ for (i = 0; i < 3; i++) {
+ cur = (cur + 1) % RX_QUEUE_LEN;
+ rxbd = (ether->rdesc + cur);
+ DUMP_PRINT("rxd_of %3d rxbd sl %08X buffer %08X sl %08X next %08X\n",
+ cur, rxbd->sl, rxbd->buffer,
+ rxbd->reserved, rxbd->next);
+ }
+ DUMP_PRINT("\n");
+ }
+
+ if (!is_locked)
+ spin_unlock_irqrestore(ðer->lock, flags);
+
+ return count - size;
+}
+#endif
+
+#ifdef CONFIG_NPCM7XX_EMC_ETH_DEBUG
+static void npcm7xx_info_print(struct net_device *netdev)
+{
+ char *emc_dump_buf;
+ int count;
+ struct npcm7xx_ether *ether;
+ struct platform_device *pdev;
+ char c;
+ char *tmp_buf;
+ const size_t print_size = 5 * PAGE_SIZE;
+
+ ether = netdev_priv(netdev);
+ pdev = ether->pdev;
+
+ emc_dump_buf = kmalloc(print_size, GFP_KERNEL);
+ if (!emc_dump_buf)
+ return;
+
+ tmp_buf = emc_dump_buf;
+ count = npcm7xx_info_dump(emc_dump_buf, print_size, netdev);
+ while (count > 512) {
+ c = tmp_buf[512];
+ tmp_buf[512] = 0;
+ dev_info(&pdev->dev, "%s", tmp_buf);
+ tmp_buf += 512;
+ tmp_buf[0] = c;
+ count -= 512;
+
+ dev_info(&pdev->dev, "%s", tmp_buf);
+ kfree(emc_dump_buf);
+}
+#endif
+
+#ifdef CONFIG_DEBUG_FS
+#include <linux/seq_file.h>
+
+static int npcm7xx_debug_show(struct seq_file *sf, void *v)
+{
+ struct net_device *netdev = (struct net_device *)sf->private;
+ struct npcm7xx_ether *ether = netdev_priv(netdev);
+ const size_t print_size = 5 * PAGE_SIZE;
+
+ if (!ether->dump_buf) {
+ ether->dump_buf = kmalloc(print_size, GFP_KERNEL);
+ if (!ether->dump_buf)
+ return -1;
+ npcm7xx_info_dump(ether->dump_buf, print_size, netdev);
+ }
+
+ seq_printf(sf, "%s", ether->dump_buf);
+ if (sf->count < sf->size) {
+ kfree(ether->dump_buf);
+ ether->dump_buf = NULL;
+ }
+
+ return 0;
+}
+
+static int npcm7xx_debug_show_open(struct inode *inode, struct file *file)
+{
+ return single_open(file, npcm7xx_debug_show, inode->i_private);
+}
+
+static const struct file_operations npcm7xx_debug_show_fops = {
+ .open = npcm7xx_debug_show_open,
+ .read = seq_read,
+ .llseek = seq_lseek,
+ .release = single_release,
+};
+
+static int npcm7xx_debug_reset(struct seq_file *sf, void *v)
+{
+ struct net_device *netdev = (struct net_device *)sf->private;
+ struct npcm7xx_ether *ether = netdev_priv(netdev);
+ unsigned long flags;
+
+ seq_puts(sf, "Ask to reset the module\n");
+ spin_lock_irqsave(ðer->lock, flags);
+ writel(0, (ether->reg + REG_MIEN));
+ spin_unlock_irqrestore(ðer->lock, flags);
+ ether->need_reset = 1;
+ napi_schedule(ðer->napi);
+
+ return 0;
+}
+
+static int npcm7xx_debug_reset_open(struct inode *inode, struct file *file)
+{
+ return single_open(file, npcm7xx_debug_reset, inode->i_private);
+}
+
+static const struct file_operations npcm7xx_debug_reset_fops = {
+ .owner = THIS_MODULE,
+ .open = npcm7xx_debug_reset_open,
+ .read = seq_read,
+ .llseek = seq_lseek,
+ .release = single_release,
+};
+
+static int npcm7xx_debug_fs(struct npcm7xx_ether *ether)
+{
+ /* Create debugfs main directory if it doesn't exist yet */
+ if (!npcm7xx_fs_dir) {
+ npcm7xx_fs_dir = debugfs_create_dir(DRV_MODULE_NAME, NULL);
+
+ if (!npcm7xx_fs_dir || IS_ERR(npcm7xx_fs_dir)) {
+ dev_err(ðer->pdev->dev,
+ "ERROR %s, debugfs create directory failed\n",
+ DRV_MODULE_NAME);
+ return -ENOMEM;
+ }
+ }
+
+ /* Create per netdev entries */
+ ether->dbgfs_dir = debugfs_create_dir(ether->netdev->name,
+ npcm7xx_fs_dir);
+ if (!ether->dbgfs_dir || IS_ERR(ether->dbgfs_dir)) {
+ dev_err(ðer->pdev->dev,
+ "ERROR failed to create %s directory\n",
+ ether->netdev->name);
+ return -ENOMEM;
+ }
+
+ /* Entry to report DMA RX/TX rings */
+ ether->dbgfs_status =
+ debugfs_create_file("status", 0444,
+ ether->dbgfs_dir, ether->netdev,
+ &npcm7xx_debug_show_fops);
+
+ if (!ether->dbgfs_status || IS_ERR(ether->dbgfs_status)) {
+ dev_err(ðer->pdev->dev,
+ "ERROR creating \'status\' debugfs file\n");
+ debugfs_remove_recursive(ether->dbgfs_dir);
+
+ return -ENOMEM;
+ }
+
+ /* Entry to report the DMA HW features */
+ ether->dbgfs_dma_cap = debugfs_create_file("do_reset", 0444,
+ ether->dbgfs_dir,
+ ether->netdev,
+ &npcm7xx_debug_reset_fops);
+
+ if (!ether->dbgfs_dma_cap || IS_ERR(ether->dbgfs_dma_cap)) {
+ dev_err(ðer->pdev->dev,
+ "ERROR creating stmmac \'do_reset\' debugfs file\n");
+ debugfs_remove_recursive(ether->dbgfs_dir);
+
+ return -ENOMEM;
+ }
+
+ return 0;
+}
+#endif
+
+static void npcm7xx_opmode(struct net_device *netdev, int speed, int duplex)
+{
+ __le32 val;
+ struct npcm7xx_ether *ether = netdev_priv(netdev);
+
+ val = readl((ether->reg + REG_MCMDR));
+ if (speed == 100)
+ val |= MCMDR_OPMOD;
+ else
+ val &= ~MCMDR_OPMOD;
+
+ if (duplex == DUPLEX_FULL)
+ val |= MCMDR_FDUP;
+ else
+ val &= ~MCMDR_FDUP;
+
+ writel(val, (ether->reg + REG_MCMDR));
+}
+
+static void adjust_link(struct net_device *netdev)
+{
+ struct npcm7xx_ether *ether = netdev_priv(netdev);
+ struct phy_device *phydev = ether->phy_dev;
+ bool status_change = false;
+
+ if (phydev->link) {
+ if (ether->speed != phydev->speed ||
+ ether->duplex != phydev->duplex) {
+ ether->speed = phydev->speed;
+ ether->duplex = phydev->duplex;
+ status_change = true;
+ }
+ } else {
+ ether->speed = 0;
+ ether->duplex = -1;
+ }
+
+ if (phydev->link != ether->link) {
+ ether->link = phydev->link;
+ status_change = true;
+ }
+
+ if (status_change)
+ npcm7xx_opmode(netdev, ether->speed, ether->duplex);
+}
+
+static void npcm7xx_write_cam(struct net_device *netdev,
+ unsigned int x, unsigned char *pval)
+{
+ struct npcm7xx_ether *ether = netdev_priv(netdev);
+ __le32 msw, lsw;
+
+ msw = (pval[0] << 24) | (pval[1] << 16) | (pval[2] << 8) | pval[3];
+
+ lsw = (pval[4] << 24) | (pval[5] << 16);
+
+ writel(lsw, (ether->reg + REG_CAML_BASE) + x * CAM_ENTRY_SIZE);
+ writel(msw, (ether->reg + REG_CAMM_BASE) + x * CAM_ENTRY_SIZE);
+ dev_dbg(ðer->pdev->dev,
+ "REG_CAML_BASE = 0x%08X REG_CAMM_BASE = 0x%08X", lsw, msw);
+}
+
+static struct sk_buff *get_new_skb(struct net_device *netdev, u32 i)
+{
+ __le32 buffer;
+ struct npcm7xx_ether *ether = netdev_priv(netdev);
+ struct sk_buff *skb = netdev_alloc_skb(netdev,
+ roundup(MAX_PACKET_SIZE_W_CRC, 4));
+
+ if (unlikely(!skb)) {
+ if (net_ratelimit())
+ netdev_warn(netdev, "failed to allocate rx skb\n");
+ buffer = ether->rx_scratch_dma;
+ } else {
+ /* Do not unmark the following skb_reserve() Receive Buffer
+ * Starting Address must be aligned to 4 bytes and the following
+ * line if unmarked will make it align to 2 and this likely will
+ * hult the RX and crash the linux
+ * skb_reserve(skb, NET_IP_ALIGN);
+ */
+ skb->dev = netdev;
+ buffer = dma_map_single(&netdev->dev,
+ skb->data,
+ roundup(MAX_PACKET_SIZE_W_CRC, 4),
+ DMA_FROM_DEVICE);
+ if (unlikely(dma_mapping_error(&netdev->dev, buffer))) {
+ if (net_ratelimit())
+ netdev_err(netdev, "failed to map rx page\n");
+ dev_kfree_skb_any(skb);
+ buffer = ether->rx_scratch_dma;
+ skb = NULL;
+ }
+ }
+ ether->rx_skb[i] = skb;
+ ether->rdesc[i].buffer = buffer;
+
+ return skb;
+}
+
+/* This API must call with Tx/Rx stopped */
+static void npcm7xx_free_desc(struct net_device *netdev,
+ bool free_also_descriptors)
+{
+ struct sk_buff *skb;
+ u32 i;
+ struct npcm7xx_ether *ether = netdev_priv(netdev);
+ struct platform_device *pdev = ether->pdev;
+
+ for (i = 0; i < TX_QUEUE_LEN; i++) {
+ skb = ether->tx_skb[i];
+ if (skb) {
+ dma_unmap_single(&netdev->dev,
+ (dma_addr_t)(ether->tdesc[i].buffer),
+ skb->len, DMA_TO_DEVICE);
+ dev_kfree_skb_any(skb);
+ ether->tx_skb[i] = NULL;
+ }
+ }
+
+ for (i = 0; i < RX_QUEUE_LEN; i++) {
+ skb = ether->rx_skb[i];
+ if (skb) {
+ dma_unmap_single(&netdev->dev,
+ (dma_addr_t)(ether->rdesc[i].buffer),
+ roundup(MAX_PACKET_SIZE_W_CRC, 4),
+ DMA_FROM_DEVICE);
+ dev_kfree_skb_any(skb);
+ ether->rx_skb[i] = NULL;
+ }
+ }
+
+ if (free_also_descriptors) {
+ if (ether->tdesc)
+ dma_free_coherent(&pdev->dev,
+ sizeof(struct npcm7xx_txbd) *
+ TX_QUEUE_LEN,
+ ether->tdesc, ether->tdesc_phys);
+ ether->tdesc = NULL;
+
+ if (ether->rdesc)
+ dma_free_coherent(&pdev->dev,
+ sizeof(struct npcm7xx_rxbd) *
+ RX_QUEUE_LEN,
+ ether->rdesc, ether->rdesc_phys);
+ ether->rdesc = NULL;
+
+ /* Free scratch packet buffer */
+ if (ether->rx_scratch)
+ dma_free_coherent(&pdev->dev,
+ roundup(MAX_PACKET_SIZE_W_CRC, 4),
+ ether->rx_scratch,
+ ether->rx_scratch_dma);
+ ether->rx_scratch = NULL;
+ }
+}
+
+static int npcm7xx_init_desc(struct net_device *netdev)
+{
+ struct npcm7xx_ether *ether;
+ struct npcm7xx_txbd *tdesc;
+ struct npcm7xx_rxbd *rdesc;
+ struct platform_device *pdev;
+ unsigned int i;
+
+ ether = netdev_priv(netdev);
+ pdev = ether->pdev;
+
+ if (!ether->tdesc) {
+ ether->tdesc = (struct npcm7xx_txbd *)
+ dma_alloc_coherent(&pdev->dev,
+ sizeof(struct npcm7xx_txbd) *
+ TX_QUEUE_LEN,
+ ðer->tdesc_phys,
+ GFP_KERNEL);
+
+ if (!ether->tdesc) {
+ dev_err(&pdev->dev,
+ "Failed to allocate memory for tx desc\n");
+ npcm7xx_free_desc(netdev, true);
+ return -ENOMEM;
+ }
+ }
+
+ if (!ether->rdesc) {
+ ether->rdesc = (struct npcm7xx_rxbd *)
+ dma_alloc_coherent(&pdev->dev,
+ sizeof(struct npcm7xx_rxbd) *
+ RX_QUEUE_LEN,
+ ðer->rdesc_phys,
+ GFP_KERNEL);
+
+ if (!ether->rdesc) {
+ dev_err(&pdev->dev,
+ "Failed to allocate memory for rx desc\n");
+ npcm7xx_free_desc(netdev, true);
+ return -ENOMEM;
+ }
+ }
+
+ for (i = 0; i < TX_QUEUE_LEN; i++) {
+ unsigned int offset;
+
+ tdesc = (ether->tdesc + i);
+
+ if (i == TX_QUEUE_LEN - 1)
+ offset = 0;
+ else
+ offset = sizeof(struct npcm7xx_txbd) * (i + 1);
+
+ tdesc->next = ether->tdesc_phys + offset;
+ tdesc->buffer = (__le32)NULL;
+ tdesc->sl = 0;
+ tdesc->mode = 0;
+ }
+
+ ether->start_tx_ptr = ether->tdesc_phys;
+
+ /* Allocate scratch packet buffer */
+ if (!ether->rx_scratch) {
+ ether->rx_scratch =
+ dma_alloc_coherent(&pdev->dev,
+ roundup(MAX_PACKET_SIZE_W_CRC, 4),
+ ðer->rx_scratch_dma, GFP_KERNEL);
+ if (!ether->rx_scratch) {
+ dev_err(&pdev->dev,
+ "Failed to allocate memory for rx_scratch\n");
+ npcm7xx_free_desc(netdev, true);
+ return -ENOMEM;
+ }
+ }
+
+ for (i = 0; i < RX_QUEUE_LEN; i++) {
+ unsigned int offset;
+
+ rdesc = (ether->rdesc + i);
+
+ if (i == RX_QUEUE_LEN - 1)
+ offset = 0;
+ else
+ offset = sizeof(struct npcm7xx_rxbd) * (i + 1);
+
+ rdesc->next = ether->rdesc_phys + offset;
+ rdesc->sl = RX_OWN_DMA;
+
+ if (!get_new_skb(netdev, i)) {
+ dev_err(&pdev->dev, "get_new_skb() failed\n");
+ npcm7xx_free_desc(netdev, true);
+ return -ENOMEM;
+ }
+ }
+
+ ether->start_rx_ptr = ether->rdesc_phys;
+ for (i = 0; i < TX_QUEUE_LEN; i++)
+ ether->tx_skb[i] = NULL;
+
+ return 0;
+}
+
+static void npcm7xx_set_fifo_threshold(struct net_device *netdev)
+{
+ struct npcm7xx_ether *ether = netdev_priv(netdev);
+ __le32 val;
+
+ val = RXTHD | TXTHD | BLENGTH;
+ writel(val, (ether->reg + REG_FFTCR));
+}
+
+static void npcm7xx_return_default_idle(struct net_device *netdev)
+{
+ struct npcm7xx_ether *ether = netdev_priv(netdev);
+ __le32 val;
+ __le32 saved_bits;
+
+ val = readl((ether->reg + REG_MCMDR));
+ saved_bits = val & (MCMDR_FDUP | MCMDR_OPMOD);
+ val |= SWR;
+ writel(val, (ether->reg + REG_MCMDR));
+
+ /* During the EMC reset the AHB will read 0 from all registers,
+ * so in order to see if the reset finished we can't count on
+ * (ether->reg + REG_MCMDR).SWR to become 0, instead we read another
+ * register that its reset value is not 0,
+ * we choose (ether->reg + REG_FFTCR).
+ */
+ do {
+ val = readl((ether->reg + REG_FFTCR));
+ } while (val == 0);
+
+ /* Now we can verify if (ether->reg + REG_MCMDR).SWR became
+ * 0 (probably it will be 0 on the first read).
+ */
+ do {
+ val = readl((ether->reg + REG_MCMDR));
+ } while (val & SWR);
+
+ /* restore values */
+ writel(saved_bits, (ether->reg + REG_MCMDR));
+}
+
+static void npcm7xx_enable_mac_interrupt(struct net_device *netdev)
+{
+ struct npcm7xx_ether *ether = netdev_priv(netdev);
+ __le32 val;
+
+ val = ENRXINTR | /* Start of RX interrupts */
+ ENCRCE |
+ EMRXOV |
+ (ENPTLE * !IS_VLAN) | /* If we don't support VLAN we want interrupt on long packets */
+ ENRXGD |
+ ENALIE |
+ ENRP |
+ ENMMP |
+ ENDFO |
+ /* ENDENI | */ /* We don't need interrupt on DMA Early Notification */
+ ENRDU | /* We don't need interrupt on Receive Descriptor Unavailable Interrupt */
+ ENRXBERR |
+ /* ENCFR | */
+ ENTXINTR | /* Start of TX interrupts */
+ ENTXEMP |
+ ENTXCP |
+ ENTXDEF |
+ ENNCS |
+ ENTXABT |
+ ENLC |
+ /* ENTDU | */ /* We don't need interrupt on Transmit Descriptor Unavailable at start of operation */
+ ENTXBERR;
+ writel(val, (ether->reg + REG_MIEN));
+}
+
+static void npcm7xx_get_and_clear_int(struct net_device *netdev,
+ __le32 *val, __le32 mask)
+{
+ struct npcm7xx_ether *ether = netdev_priv(netdev);
+
+ *val = readl((ether->reg + REG_MISTA)) & mask;
+ writel(*val, (ether->reg + REG_MISTA));
+}
+
+static void npcm7xx_set_global_maccmd(struct net_device *netdev)
+{
+ struct npcm7xx_ether *ether = netdev_priv(netdev);
+ __le32 val;
+
+ val = readl((ether->reg + REG_MCMDR));
+
+ val |= MCMDR_SPCRC | MCMDR_ENMDC | MCMDR_ACP | MCMDR_NDEF;
+ if (IS_VLAN) {
+ /* we set ALP accept long packets since VLAN packets
+ * are 4 bytes longer than 1518
+ */
+ val |= MCMDR_ALP;
+ /* limit receive length to 1522 bytes due to VLAN */
+ writel(MAX_PACKET_SIZE_W_CRC, (ether->reg + REG_DMARFC));
+ }
+ writel(val, (ether->reg + REG_MCMDR));
+}
+
+static void npcm7xx_enable_cam(struct net_device *netdev)
+{
+ struct npcm7xx_ether *ether = netdev_priv(netdev);
+ __le32 val;
+
+ npcm7xx_write_cam(netdev, CAM0, netdev->dev_addr);
+
+ val = readl((ether->reg + REG_CAMEN));
+ val |= CAM0EN;
+ writel(val, (ether->reg + REG_CAMEN));
+}
+
+static void npcm7xx_set_curdest(struct net_device *netdev)
+{
+ struct npcm7xx_ether *ether = netdev_priv(netdev);
+
+ writel(ether->start_rx_ptr, (ether->reg + REG_RXDLSA));
+ writel(ether->start_tx_ptr, (ether->reg + REG_TXDLSA));
+}
+
+static void npcm7xx_ether_set_rx_mode(struct net_device *netdev)
+{
+ struct npcm7xx_ether *ether;
+ __le32 rx_mode;
+
+ ether = netdev_priv(netdev);
+
+ dev_dbg(ðer->pdev->dev, "%s CAMCMR_AUP\n",
+ (netdev->flags & IFF_PROMISC) ? "Set" : "Clear");
+ if (netdev->flags & IFF_PROMISC)
+ rx_mode = CAMCMR_AUP | CAMCMR_AMP | CAMCMR_ABP | CAMCMR_ECMP;
+ else if ((netdev->flags & IFF_ALLMULTI) || !netdev_mc_empty(netdev))
+ rx_mode = CAMCMR_AMP | CAMCMR_ABP | CAMCMR_ECMP;
+ else
+ rx_mode = CAMCMR_ECMP | CAMCMR_ABP;
+ writel(rx_mode, (ether->reg + REG_CAMCMR));
+ ether->camcmr = rx_mode;
+}
+
+static void npcm7xx_reset_mac(struct net_device *netdev, int need_free)
+{
+ struct npcm7xx_ether *ether = netdev_priv(netdev);
+
+ netif_tx_lock(netdev);
+
+ /* disable RX and TX */
+ writel(readl((ether->reg + REG_MCMDR)) & ~(MCMDR_TXON | MCMDR_RXON),
+ (ether->reg + REG_MCMDR));
+
+ npcm7xx_return_default_idle(netdev);
+ npcm7xx_set_fifo_threshold(netdev);
+
+ if (need_free)
+ npcm7xx_free_desc(netdev, false);
+
+ npcm7xx_init_desc(netdev);
+
+ ether->cur_tx = 0x0;
+ ether->finish_tx = 0x0;
+ ether->pending_tx = 0x0;
+ ether->cur_rx = 0x0;
+ ether->tx_tdu = 0;
+ ether->tx_tdu_i = 0;
+ ether->tx_cp_i = 0;
+
+ npcm7xx_set_curdest(netdev);
+ npcm7xx_enable_cam(netdev);
+ npcm7xx_ether_set_rx_mode(netdev);
+ npcm7xx_enable_mac_interrupt(netdev);
+ npcm7xx_set_global_maccmd(netdev);
+
+ /* enable RX and TX */
+ writel(readl((ether->reg + REG_MCMDR)) | MCMDR_TXON | MCMDR_RXON,
+ (ether->reg + REG_MCMDR));
+
+ /* trigger RX */
+ writel(ENSTART, (ether->reg + REG_RSDR));
+
+ ether->need_reset = 0;
+
+ netif_wake_queue(netdev);
+ netif_tx_unlock(netdev);
+}
+
+static int npcm7xx_mdio_write(struct mii_bus *bus, int phy_id, int regnum,
+ u16 value)
+{
+ struct npcm7xx_ether *ether = bus->priv;
+ unsigned long timeout = jiffies + msecs_to_jiffies(MII_TIMEOUT * 100);
+
+ writel(value, (ether->reg + REG_MIID));
+ writel((phy_id << 0x08) | regnum | PHYBUSY | PHYWR,
+ (ether->reg + REG_MIIDA));
+
+ /* Wait for completion */
+ while (readl((ether->reg + REG_MIIDA)) & PHYBUSY) {
+ if (time_after(jiffies, timeout)) {
+ dev_dbg(ðer->pdev->dev,
+ "mdio read timed out\n ether->reg = 0x%x phy_id=0x%x REG_MIIDA=0x%x\n",
+ (unsigned int)ether->reg, phy_id,
+ readl((ether->reg + REG_MIIDA)));
+ return -ETIMEDOUT;
+ }
+ cpu_relax();
+ }
+
+ return 0;
+}
+
+static int npcm7xx_mdio_read(struct mii_bus *bus, int phy_id, int regnum)
+{
+ struct npcm7xx_ether *ether = bus->priv;
+ unsigned long timeout = jiffies + msecs_to_jiffies(MII_TIMEOUT * 100);
+
+ writel((phy_id << 0x08) | regnum | PHYBUSY, (ether->reg + REG_MIIDA));
+
+ /* Wait for completion */
+ while (readl((ether->reg + REG_MIIDA)) & PHYBUSY) {
+ if (time_after(jiffies, timeout)) {
+ dev_dbg(ðer->pdev->dev,
+ "mdio read timed out\n ether->reg = 0x%x phy_id=0x%x REG_MIIDA=0x%x\n",
+ (unsigned int)ether->reg, phy_id
+ , readl((ether->reg + REG_MIIDA)));
+ return -ETIMEDOUT;
+ }
+ cpu_relax();
+ }
+
+ return readl((ether->reg + REG_MIID));
+}
+
+static int npcm7xx_mdio_reset(struct mii_bus *bus)
+{
+ /* reset EMAC engine?? */
+ return 0;
+}
+
+static int npcm7xx_set_mac_address(struct net_device *netdev, void *addr)
+{
+ struct sockaddr *address = addr;
+
+ if (!is_valid_ether_addr((u8 *)address->sa_data))
+ return -EADDRNOTAVAIL;
+
+ memcpy(netdev->dev_addr, address->sa_data, netdev->addr_len);
+ npcm7xx_write_cam(netdev, CAM0, netdev->dev_addr);
+
+ return 0;
+}
+
+static int npcm7xx_ether_close(struct net_device *netdev)
+{
+ struct npcm7xx_ether *ether = netdev_priv(netdev);
+
+ npcm7xx_return_default_idle(netdev);
+
+ if (ether->phy_dev)
+ phy_stop(ether->phy_dev);
+ else if (ether->use_ncsi)
+ ncsi_stop_dev(ether->ncsidev);
+
+ msleep(20);
+
+ free_irq(ether->txirq, netdev);
+ free_irq(ether->rxirq, netdev);
+
+ netif_stop_queue(netdev);
+ napi_disable(ðer->napi);
+
+ npcm7xx_free_desc(netdev, true);
+
+ kfree(ether->dump_buf);
+ ether->dump_buf = NULL;
+
+ return 0;
+}
+
+static struct net_device_stats *npcm7xx_ether_stats(struct net_device *netdev)
+{
+ struct npcm7xx_ether *ether;
+
+ ether = netdev_priv(netdev);
+ return ðer->stats;
+}
+
+static int npcm7xx_clean_tx(struct net_device *netdev, bool from_xmit)
+{
+ struct npcm7xx_ether *ether = netdev_priv(netdev);
+ struct npcm7xx_txbd *txbd;
+ struct sk_buff *s;
+ dma_addr_t cur_entry, entry;
+ __le32 sl;
+
+ if (ether->pending_tx == 0)
+ return (0);
+
+ cur_entry = readl((ether->reg + REG_CTXDSA));
+
+ /* Release old used buffers */
+ entry = ether->tdesc_phys + sizeof(struct npcm7xx_txbd) *
+ (ether->finish_tx);
+
+ while (entry != cur_entry) {
+ txbd = (ether->tdesc + ether->finish_tx);
+ s = ether->tx_skb[ether->finish_tx];
+ if (!s)
+ break;
+
+ ether->count_finish++;
+
+ dma_unmap_single(&netdev->dev, txbd->buffer, s->len,
+ DMA_TO_DEVICE);
+ consume_skb(s);
+ ether->tx_skb[ether->finish_tx] = NULL;
+
+ if (++ether->finish_tx >= TX_QUEUE_LEN)
+ ether->finish_tx = 0;
+ ether->pending_tx--;
+
+ sl = txbd->sl;
+ if (sl & TXDS_TXCP) {
+ ether->stats.tx_packets++;
+ ether->stats.tx_bytes += (sl & 0xFFFF);
+ } else {
+ ether->stats.tx_errors++;
+ }
+
+ entry = ether->tdesc_phys + sizeof(struct npcm7xx_txbd) *
+ (ether->finish_tx);
+ }
+
+ if (!from_xmit && unlikely(netif_queue_stopped(netdev) &&
+ (TX_QUEUE_LEN - ether->pending_tx) > 1)) {
+ netif_tx_lock(netdev);
+ if (netif_queue_stopped(netdev) &&
+ (TX_QUEUE_LEN - ether->pending_tx) > 1) {
+ netif_wake_queue(netdev);
+ }
+ netif_tx_unlock(netdev);
+ }
+
+ return(0);
+}
+
+static int npcm7xx_ether_start_xmit(struct sk_buff *skb, struct net_device *netdev)
+{
+ struct npcm7xx_ether *ether = netdev_priv(netdev);
+ struct npcm7xx_txbd *txbd;
+ unsigned long flags;
+
+ ether->count_xmit++;
+
+ /* Insert new buffer */
+ txbd = (ether->tdesc + ether->cur_tx);
+ txbd->buffer = dma_map_single(&netdev->dev, skb->data, skb->len,
+ DMA_TO_DEVICE);
+ ether->tx_skb[ether->cur_tx] = skb;
+ if (skb->len > MAX_PACKET_SIZE)
+ dev_err(ðer->pdev->dev,
+ "skb->len (= %d) > MAX_PACKET_SIZE (= %d)\n",
+ skb->len, MAX_PACKET_SIZE);
+
+ txbd->sl = skb->len > MAX_PACKET_SIZE ? MAX_PACKET_SIZE : skb->len;
+ dma_wmb();
+
+ txbd->mode = TX_OWN_DMA | PADDINGMODE | CRCMODE;
+
+ /* make sure that data is in memory before we trigger TX */
+ wmb();
+
+ /* trigger TX */
+ writel(ENSTART, (ether->reg + REG_TSDR));
+
+ if (++ether->cur_tx >= TX_QUEUE_LEN)
+ ether->cur_tx = 0;
+
+ spin_lock_irqsave(ðer->lock, flags);
+ ether->pending_tx++;
+
+ /* sometimes we miss the tx interrupt due to HW issue, so NAPI will not
+ * clean the pending tx, so we clean it also here
+ */
+ npcm7xx_clean_tx(netdev, true);
+
+ if (ether->pending_tx >= TX_QUEUE_LEN - 1) {
+ __le32 reg_mien;
+ unsigned int index_to_wake = ether->cur_tx +
+ ((TX_QUEUE_LEN * 3) / 4);
+
+ if (index_to_wake >= TX_QUEUE_LEN)
+ index_to_wake -= TX_QUEUE_LEN;
+
+ txbd = (ether->tdesc + index_to_wake);
+ txbd->mode = TX_OWN_DMA | PADDINGMODE | CRCMODE | MACTXINTEN;
+
+ /* make sure that data is in memory before we trigger TX */
+ wmb();
+
+ /* Clear TDU interrupt */
+ writel(MISTA_TDU, (ether->reg + REG_MISTA));
+
+ /* due to HW issue somtimes, we miss the TX interrupt we just
+ * set (MACTXINTEN), so we also set TDU for Transmit
+ * Descriptor Unavailable interrupt
+ */
+ reg_mien = readl((ether->reg + REG_MIEN));
+ if (reg_mien != 0)
+ /* Enable TDU interrupt */
+ writel(reg_mien | ENTDU, (ether->reg + REG_MIEN));
+
+ ether->tx_tdu++;
+ netif_stop_queue(netdev);
+ }
+
+ spin_unlock_irqrestore(ðer->lock, flags);
+
+ return 0;
+}
+
+static irqreturn_t npcm7xx_tx_interrupt(int irq, void *dev_id)
+{
+ struct npcm7xx_ether *ether;
+ struct platform_device *pdev;
+ struct net_device *netdev;
+ __le32 status;
+ unsigned long flags;
+
+ netdev = dev_id;
+ ether = netdev_priv(netdev);
+ pdev = ether->pdev;
+
+ npcm7xx_get_and_clear_int(netdev, &status, 0xFFFF0000);
+
+ ether->tx_int_count++;
+
+ if (status & MISTA_EXDEF)
+ dev_err(&pdev->dev, "emc defer exceed interrupt status=0x%08X\n"
+ , status);
+ else if (status & MISTA_TXBERR) {
+ dev_err(&pdev->dev, "emc bus error interrupt status=0x%08X\n",
+ status);
+#ifdef CONFIG_NPCM7XX_EMC_ETH_DEBUG
+ npcm7xx_info_print(netdev);
+#endif
+ spin_lock_irqsave(ðer->lock, flags);
+ writel(0, (ether->reg + REG_MIEN)); /* disable any interrupt */
+ spin_unlock_irqrestore(ðer->lock, flags);
+ ether->need_reset = 1;
+ } else if (status & ~(MISTA_TXINTR | MISTA_TXCP | MISTA_TDU))
+ dev_err(&pdev->dev, "emc other error interrupt status=0x%08X\n",
+ status);
+
+ /* if we got MISTA_TXCP | MISTA_TDU remove those interrupt and call napi */
+ if (status & (MISTA_TXCP | MISTA_TDU) &
+ readl((ether->reg + REG_MIEN))) {
+ __le32 reg_mien;
+
+ spin_lock_irqsave(ðer->lock, flags);
+ reg_mien = readl((ether->reg + REG_MIEN));
+ if (reg_mien & ENTDU)
+ /* Disable TDU interrupt */
+ writel(reg_mien & (~ENTDU), (ether->reg + REG_MIEN));
+
+ spin_unlock_irqrestore(ðer->lock, flags);
+
+ if (status & MISTA_TXCP)
+ ether->tx_cp_i++;
+ if (status & MISTA_TDU)
+ ether->tx_tdu_i++;
+ } else {
+ dev_dbg(&pdev->dev, "status=0x%08X\n", status);
+ }
+
+ napi_schedule(ðer->napi);
+
+ return IRQ_HANDLED;
+}
+
+static irqreturn_t npcm7xx_rx_interrupt(int irq, void *dev_id)
+{
+ struct net_device *netdev = (struct net_device *)dev_id;
+ struct npcm7xx_ether *ether = netdev_priv(netdev);
+ struct platform_device *pdev = ether->pdev;
+ __le32 status;
+ unsigned long flags;
+ unsigned int any_err = 0;
+ __le32 rxfsm;
+
+ npcm7xx_get_and_clear_int(netdev, &status, 0xFFFF);
+ ether->rx_int_count++;
+
+ if (unlikely(status & MISTA_RXBERR)) {
+ ether->rx_berr++;
+ dev_err(&pdev->dev, "emc rx bus error status=0x%08X\n", status);
+#ifdef CONFIG_NPCM7XX_EMC_ETH_DEBUG
+ npcm7xx_info_print(netdev);
+#endif
+ spin_lock_irqsave(ðer->lock, flags);
+ writel(0, (ether->reg + REG_MIEN)); /* disable any interrupt */
+ spin_unlock_irqrestore(ðer->lock, flags);
+ ether->need_reset = 1;
+ napi_schedule(ðer->napi);
+ return IRQ_HANDLED;
+ }
+
+ if (unlikely(status & (MISTA_RXOV | MISTA_RDU))) {
+ /* filter out all received packets until we have
+ * enough available buffer descriptors
+ */
+ writel(0, (ether->reg + REG_CAMCMR));
+ any_err = 1;
+ if (status & (MISTA_RXOV))
+ ether->rxov++;
+ if (status & (MISTA_RDU))
+ ether->rdu++;
+
+ /* workaround Errata 1.36: EMC Hangs on receiving 253-256
+ * byte packet
+ */
+ rxfsm = readl((ether->reg + REG_RXFSM));
+
+ if ((rxfsm & 0xFFFFF000) == 0x08044000) {
+ int i;
+
+ for (i = 0; i < 32; i++) {
+ rxfsm = readl((ether->reg + REG_RXFSM));
+ if ((rxfsm & 0xFFFFF000) != 0x08044000)
+ break;
+ }
+ if (i == 32) {
+ ether->rx_stuck++;
+ spin_lock_irqsave(ðer->lock, flags);
+#ifdef CONFIG_NPCM7XX_EMC_ETH_DEBUG
+ npcm7xx_info_print(netdev);
+#endif
+ writel(0, (ether->reg + REG_MIEN));
+ spin_unlock_irqrestore(ðer->lock, flags);
+ ether->need_reset = 1;
+ napi_schedule(ðer->napi);
+ dev_err(&pdev->dev,
+ "stuck on REG_RXFSM = 0x%08X status=%08X doing reset!\n",
+ rxfsm, status);
+ return IRQ_HANDLED;
+ }
+ }
+ }
+
+ /* echo MISTA status on unexpected flags although we don't do anithing
+ * with them
+ */
+ if (unlikely(status &
+ (/* MISTA_RXINTR | */ /* Receive - all RX interrupt set this */
+ MISTA_CRCE | /* CRC Error */
+ /* MISTA_RXOV | */ /* Receive FIFO Overflow - we alread handled it */
+ (!IS_VLAN * MISTA_PTLE) | /* Packet Too Long is needed if VLAN is not supported */
+ /* MISTA_RXGD | */ /* Receive Good - this is the common good case */
+ MISTA_ALIE | /* Alignment Error */
+ MISTA_RP | /* Runt Packet */
+ MISTA_MMP | /* More Missed Packet */
+ MISTA_DFOI | /* Maximum Frame Length */
+ /* MISTA_DENI | */ /* DMA Early Notification - every packet get this */
+ /* MISTA_RDU | */ /* Receive Descriptor Unavailable */
+ /* MISTA_RXBERR | */ /* Receive Bus Error Interrupt - we alread handled it */
+ /* MISTA_CFR | */ /* Control Frame Receive - not an error */
+ 0))) {
+ dev_dbg(&pdev->dev, "emc rx MISTA status=0x%08X\n", status);
+ any_err = 1;
+ ether->rx_err++;
+ }
+
+ if (!any_err && ((status & MISTA_RXGD) == 0))
+ dev_err(&pdev->dev, "emc rx MISTA status=0x%08X\n", status);
+
+ spin_lock_irqsave(ðer->lock, flags);
+ writel(readl((ether->reg + REG_MIEN)) & ~ENRXGD,
+ (ether->reg + REG_MIEN));
+ spin_unlock_irqrestore(ðer->lock, flags);
+ napi_schedule(ðer->napi);
+
+ return IRQ_HANDLED;
+}
+
+static int npcm7xx_poll(struct napi_struct *napi, int budget)
+{
+ struct npcm7xx_ether *ether =
+ container_of(napi, struct npcm7xx_ether, napi);
+ struct npcm7xx_rxbd *rxbd;
+ struct net_device *netdev = ether->netdev;
+ struct platform_device *pdev = ether->pdev;
+ struct sk_buff *s;
+ unsigned int length;
+ __le32 status;
+ unsigned long flags;
+ int rx_cnt = 0;
+ int complete = 0;
+ unsigned int rx_offset = (readl((ether->reg + REG_CRXDSA)) -
+ ether->start_rx_ptr) /
+ sizeof(struct npcm7xx_txbd);
+ unsigned int local_count = (rx_offset >= ether->cur_rx) ?
+ rx_offset - ether->cur_rx : rx_offset +
+ RX_QUEUE_LEN - ether->cur_rx;
+
+ if (local_count > ether->max_waiting_rx)
+ ether->max_waiting_rx = local_count;
+
+ if (local_count > (4 * RX_POLL_SIZE))
+ /* we are porbably in a storm of short packets and we don't
+ * want to get into RDU since short packets in RDU cause
+ * many RXOV which may cause EMC halt, so we filter out all
+ * coming packets
+ */
+ writel(0, (ether->reg + REG_CAMCMR));
+
+ if (local_count <= budget)
+ /* we can restore accepting of packets */
+ writel(ether->camcmr, (ether->reg + REG_CAMCMR));
+
+ spin_lock_irqsave(ðer->lock, flags);
+ npcm7xx_clean_tx(netdev, false);
+ spin_unlock_irqrestore(ðer->lock, flags);
+
+ rxbd = (ether->rdesc + ether->cur_rx);
+
+ while (rx_cnt < budget) {
+ status = rxbd->sl;
+ if ((status & RX_OWN_DMA) == RX_OWN_DMA) {
+ complete = 1;
+ break;
+ }
+ /* for debug puposes we save the previous value */
+ rxbd->reserved = status;
+ s = ether->rx_skb[ether->cur_rx];
+ length = status & 0xFFFF;
+
+ /* If VLAN is not supporte RXDS_PTLE (packet too long) is also
+ * an error
+ */
+ if (likely((status & (RXDS_RXGD | RXDS_CRCE | RXDS_ALIE |
+ RXDS_RP | (IS_VLAN ? 0 : RXDS_PTLE))) ==
+ RXDS_RXGD) && likely(length <= MAX_PACKET_SIZE)) {
+ dma_unmap_single(&netdev->dev, (dma_addr_t)rxbd->buffer,
+ roundup(MAX_PACKET_SIZE_W_CRC, 4),
+ DMA_FROM_DEVICE);
+
+ skb_put(s, length);
+ s->protocol = eth_type_trans(s, netdev);
+ netif_receive_skb(s);
+ ether->stats.rx_packets++;
+ ether->stats.rx_bytes += length;
+ rx_cnt++;
+ ether->rx_count_pool++;
+
+ /* now we allocate new skb instead if the used one. */
+ if (!get_new_skb(netdev, ether->cur_rx))
+ ether->stats.rx_dropped++;
+ } else {
+ ether->rx_err_count++;
+ ether->stats.rx_errors++;
+ dev_dbg(&pdev->dev, "rx_errors = %lu status = 0x%08X\n",
+ ether->stats.rx_errors, status);
+
+ if (status & RXDS_RP) {
+ ether->stats.rx_length_errors++;
+ dev_dbg(&pdev->dev, "rx_length_errors = %lu\n",
+ ether->stats.rx_length_errors);
+ } else if (status & RXDS_CRCE) {
+ ether->stats.rx_crc_errors++;
+ dev_dbg(&pdev->dev, "rx_crc_errors = %lu\n",
+ ether->stats.rx_crc_errors);
+ } else if (status & RXDS_ALIE) {
+ ether->stats.rx_frame_errors++;
+ dev_dbg(&pdev->dev, "rx_frame_errors = %lu\n",
+ ether->stats.rx_frame_errors);
+ } else if (((!IS_VLAN) && (status & RXDS_PTLE)) ||
+ length > MAX_PACKET_SIZE) {
+ ether->stats.rx_length_errors++;
+ dev_dbg(&pdev->dev, "rx_length_errors = %lu\n",
+ ether->stats.rx_length_errors);
+ }
+ }
+
+ /* make sure other values are set before we set owner */
+ wmb();
+
+ rxbd->sl = RX_OWN_DMA;
+ /* make sure that data is in memory before we trigger RX */
+ wmb();
+
+ if (++ether->cur_rx >= RX_QUEUE_LEN)
+ ether->cur_rx = 0;
+
+ rxbd = (ether->rdesc + ether->cur_rx);
+ }
+
+ if (complete) {
+ napi_complete(napi);
+
+ if (ether->need_reset) {
+ dev_dbg(&pdev->dev, "Reset\n");
+ npcm7xx_reset_mac(netdev, 1);
+ }
+
+ spin_lock_irqsave(ðer->lock, flags);
+ writel(readl((ether->reg + REG_MIEN)) | ENRXGD, (ether->reg +
+ REG_MIEN));
+ spin_unlock_irqrestore(ðer->lock, flags);
+ } else {
+ rx_offset = (readl((ether->reg + REG_CRXDSA)) -
+ ether->start_rx_ptr) / sizeof(struct npcm7xx_txbd);
+ local_count = (rx_offset >= ether->cur_rx) ? rx_offset -
+ ether->cur_rx : rx_offset + RX_QUEUE_LEN -
+ ether->cur_rx;
+
+ if (local_count > ether->max_waiting_rx)
+ ether->max_waiting_rx = local_count;
+
+ if (local_count > (3 * RX_POLL_SIZE))
+ /* we are porbably in a storm of short packets and
+ * we don't want to get into RDU since short packets in
+ * RDU cause many RXOV which may cause
+ * EMC halt, so we filter out all coming packets
+ */
+ writel(0, (ether->reg + REG_CAMCMR));
+ if (local_count <= RX_POLL_SIZE)
+ /* we can restore accepting of packets */
+ writel(ether->camcmr, (ether->reg + REG_CAMCMR));
+ }
+
+ /* trigger RX */
+ writel(ENSTART, (ether->reg + REG_RSDR));
+ return rx_cnt;
+}
+
+static int npcm7xx_ether_open(struct net_device *netdev)
+{
+ struct npcm7xx_ether *ether;
+ struct platform_device *pdev;
+
+ ether = netdev_priv(netdev);
+ pdev = ether->pdev;
+
+ if (ether->use_ncsi) {
+ ether->speed = 100;
+ ether->duplex = DUPLEX_FULL;
+ npcm7xx_opmode(netdev, 100, DUPLEX_FULL);
+ }
+ npcm7xx_reset_mac(netdev, 0);
+
+ if (request_irq(ether->txirq, npcm7xx_tx_interrupt, 0x0, pdev->name,
+ netdev)) {
+ dev_err(&pdev->dev, "register irq tx failed\n");
+ npcm7xx_ether_close(netdev);
+ return -EAGAIN;
+ }
+
+ if (request_irq(ether->rxirq, npcm7xx_rx_interrupt, 0x0, pdev->name,
+ netdev)) {
+ dev_err(&pdev->dev, "register irq rx failed\n");
+ npcm7xx_ether_close(netdev);
+ return -EAGAIN;
+ }
+
+ if (ether->phy_dev)
+ phy_start(ether->phy_dev);
+ else if (ether->use_ncsi)
+ netif_carrier_on(netdev);
+
+ netif_start_queue(netdev);
+ napi_enable(ðer->napi);
+
+ /* trigger RX */
+ writel(ENSTART, (ether->reg + REG_RSDR));
+
+ /* Start the NCSI device */
+ if (ether->use_ncsi) {
+ int err = ncsi_start_dev(ether->ncsidev);
+
+ if (err) {
+ npcm7xx_ether_close(netdev);
+ return err;
+ }
+ }
+
+ dev_info(&pdev->dev, "%s is OPENED\n", netdev->name);
+
+ return 0;
+}
+
+static int npcm7xx_ether_ioctl(struct net_device *netdev,
+ struct ifreq *ifr, int cmd)
+{
+ struct npcm7xx_ether *ether = netdev_priv(netdev);
+ struct phy_device *phydev = ether->phy_dev;
+
+ if (!netif_running(netdev))
+ return -EINVAL;
+
+ if (!phydev)
+ return -ENODEV;
+
+ return phy_mii_ioctl(phydev, ifr, cmd);
+}
+
+static void npcm7xx_get_drvinfo(struct net_device *netdev,
+ struct ethtool_drvinfo *info)
+{
+ strlcpy(info->driver, DRV_MODULE_NAME, sizeof(info->driver));
+ strlcpy(info->version, DRV_MODULE_VERSION, sizeof(info->version));
+ strlcpy(info->fw_version, "N/A", sizeof(info->fw_version));
+ strlcpy(info->bus_info, "N/A", sizeof(info->bus_info));
+}
+
+static int npcm7xx_get_settings(struct net_device *netdev,
+ struct ethtool_link_ksettings *cmd)
+{
+ struct npcm7xx_ether *ether = netdev_priv(netdev);
+ struct phy_device *phydev = ether->phy_dev;
+
+ if (!phydev)
+ return -ENODEV;
+
+ dev_info(ðer->pdev->dev, "\n\nnpcm7xx_get_settings\n");
+ phy_ethtool_ksettings_get(phydev, cmd);
+
+ return 0;
+}
+
+static int npcm7xx_set_settings(struct net_device *netdev,
+ const struct ethtool_link_ksettings *cmd)
+{
+ struct npcm7xx_ether *ether = netdev_priv(netdev);
+ struct phy_device *phydev = ether->phy_dev;
+ int ret;
+
+ if (!phydev)
+ return -ENODEV;
+
+ dev_info(ðer->pdev->dev, "\n\nnpcm7xx_set_settings\n");
+ ret = phy_ethtool_ksettings_set(phydev, cmd);
+
+ return ret;
+}
+
+static u32 npcm7xx_get_msglevel(struct net_device *netdev)
+{
+ struct npcm7xx_ether *ether = netdev_priv(netdev);
+
+ return ether->msg_enable;
+}
+
+static void npcm7xx_set_msglevel(struct net_device *netdev, u32 level)
+{
+ struct npcm7xx_ether *ether = netdev_priv(netdev);
+
+ ether->msg_enable = level;
+}
+
+static const struct ethtool_ops npcm7xx_ether_ethtool_ops = {
+ .get_link_ksettings = npcm7xx_get_settings,
+ .set_link_ksettings = npcm7xx_set_settings,
+ .get_drvinfo = npcm7xx_get_drvinfo,
+ .get_msglevel = npcm7xx_get_msglevel,
+ .set_msglevel = npcm7xx_set_msglevel,
+ .get_link = ethtool_op_get_link,
+};
+
+static const struct net_device_ops npcm7xx_ether_netdev_ops = {
+ .ndo_open = npcm7xx_ether_open,
+ .ndo_stop = npcm7xx_ether_close,
+ .ndo_start_xmit = npcm7xx_ether_start_xmit,
+ .ndo_get_stats = npcm7xx_ether_stats,
+ .ndo_set_rx_mode = npcm7xx_ether_set_rx_mode,
+ .ndo_set_mac_address = npcm7xx_set_mac_address,
+ .ndo_do_ioctl = npcm7xx_ether_ioctl,
+ .ndo_validate_addr = eth_validate_addr,
+ .ndo_change_mtu = eth_change_mtu,
+};
+
+static void get_mac_address(struct net_device *netdev)
+{
+ struct npcm7xx_ether *ether = netdev_priv(netdev);
+ struct platform_device *pdev = ether->pdev;
+ struct device_node *np = ether->pdev->dev.of_node;
+ const u8 *mac_address = NULL;
+
+ mac_address = of_get_mac_address(np);
+
+ if (mac_address != 0)
+ ether_addr_copy(netdev->dev_addr, mac_address);
+
+ if (is_valid_ether_addr(netdev->dev_addr)) {
+ dev_info(&pdev->dev, "%s: device MAC address : %pM\n",
+ pdev->name, netdev->dev_addr);
+ } else {
+ eth_hw_addr_random(netdev);
+ dev_info(&pdev->dev,
+ "%s: device MAC address (random generator) %pM\n",
+ netdev->name, netdev->dev_addr);
+ }
+}
+
+static int npcm7xx_mii_setup(struct net_device *netdev)
+{
+ struct npcm7xx_ether *ether = netdev_priv(netdev);
+ struct platform_device *pdev;
+ struct phy_device *phydev = NULL;
+ int i, err = 0;
+
+ pdev = ether->pdev;
+
+ ether->mii_bus = mdiobus_alloc();
+ if (!ether->mii_bus) {
+ err = -ENOMEM;
+ dev_err(&pdev->dev, "mdiobus_alloc() failed\n");
+ goto out0;
+ }
+
+ ether->mii_bus->name = "npcm7xx_rmii";
+ ether->mii_bus->read = &npcm7xx_mdio_read;
+ ether->mii_bus->write = &npcm7xx_mdio_write;
+ ether->mii_bus->reset = &npcm7xx_mdio_reset;
+ snprintf(ether->mii_bus->id, MII_BUS_ID_SIZE, "%s-%x",
+ ether->pdev->name, ether->pdev->id);
+ dev_dbg(&pdev->dev, "%s ether->mii_bus->id=%s\n", __func__,
+ ether->mii_bus->id);
+ ether->mii_bus->priv = ether;
+ ether->mii_bus->parent = ðer->pdev->dev;
+
+ for (i = 0; i < PHY_MAX_ADDR; i++)
+ ether->mii_bus->irq[i] = PHY_POLL;
+
+ platform_set_drvdata(ether->pdev, ether->mii_bus);
+
+ /* Enable MDIO Clock */
+ writel(readl((ether->reg + REG_MCMDR)) | MCMDR_ENMDC,
+ (ether->reg + REG_MCMDR));
+
+ if (mdiobus_register(ether->mii_bus)) {
+ dev_err(&pdev->dev, "mdiobus_register() failed\n");
+ goto out2;
+ }
+
+ phydev = phy_find_first(ether->mii_bus);
+ if (!phydev) {
+ dev_err(&pdev->dev, "phy_find_first() failed\n");
+ goto out3;
+ }
+
+ dev_info(&pdev->dev, " name = %s ETH-Phy-Id = 0x%x\n",
+ phydev_name(phydev), phydev->phy_id);
+
+ phydev = phy_connect(netdev, phydev_name(phydev),
+ &adjust_link,
+ PHY_INTERFACE_MODE_RMII);
+
+ dev_info(&pdev->dev, " ETH-Phy-Id = 0x%x name = %s\n",
+ phydev->phy_id, phydev->drv->name);
+
+ if (IS_ERR(phydev)) {
+ err = PTR_ERR(phydev);
+ dev_err(&pdev->dev, "phy_connect() failed - %d\n", err);
+ goto out3;
+ }
+
+ phydev->supported &= PHY_BASIC_FEATURES;
+ phydev->advertising = phydev->supported;
+ ether->phy_dev = phydev;
+
+ return 0;
+
+out3:
+ mdiobus_unregister(ether->mii_bus);
+out2:
+ kfree(ether->mii_bus->irq);
+ mdiobus_free(ether->mii_bus);
+out0:
+
+ return err;
+}
+
+static const struct of_device_id emc_dt_id[] = {
+ { .compatible = "nuvoton,npcm750-emc", },
+ {},
+};
+MODULE_DEVICE_TABLE(of, emc_dt_id);
+
+static void npcm7xx_ncsi_handler(struct ncsi_dev *nd)
+{
+ if (unlikely(nd->state != ncsi_dev_state_functional))
+ return;
+
+ netdev_info(nd->dev, "NCSI interface %s\n",
+ nd->link_up ? "up" : "down");
+}
+
+static int npcm7xx_ether_probe(struct platform_device *pdev)
+{
+ struct npcm7xx_ether *ether;
+ struct net_device *netdev;
+ int error;
+
+ struct clk *emc_clk = NULL;
+ struct device_node *np = pdev->dev.of_node;
+
+ pdev->id = of_alias_get_id(np, "ethernet");
+ if (pdev->id < 0)
+ pdev->id = 0;
+
+ emc_clk = devm_clk_get(&pdev->dev, NULL);
+
+ if (IS_ERR(emc_clk))
+ return PTR_ERR(emc_clk);
+
+ /* Enable Clock */
+ clk_prepare_enable(emc_clk);
+
+ error = dma_coerce_mask_and_coherent(&pdev->dev, DMA_BIT_MASK(32));
+ if (error)
+ return -ENODEV;
+
+ netdev = alloc_etherdev(sizeof(struct npcm7xx_ether));
+ if (!netdev)
+ return -ENOMEM;
+
+ ether = netdev_priv(netdev);
+
+ ether->reset = devm_reset_control_get(&pdev->dev, NULL);
+ if (IS_ERR(ether->reset))
+ return PTR_ERR(ether->reset);
+
+ /* Reset EMC module */
+ reset_control_assert(ether->reset);
+ udelay(5);
+ reset_control_deassert(ether->reset);
+
+ ether->res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ if (!ether->res) {
+ dev_err(&pdev->dev, "failed to get I/O memory\n");
+ error = -ENXIO;
+ goto failed_free;
+ }
+
+ if (!request_mem_region(ether->res->start,
+ resource_size(ether->res), pdev->name)) {
+ dev_err(&pdev->dev, "failed to request I/O memory\n");
+ error = -EBUSY;
+ goto failed_free;
+ }
+
+ ether->reg = ioremap(ether->res->start, resource_size(ether->res));
+ dev_dbg(&pdev->dev, "%s ether->reg = 0x%x\n", __func__,
+ (unsigned int)ether->reg);
+
+ if (!ether->reg) {
+ dev_err(&pdev->dev, "failed to remap I/O memory\n");
+ error = -ENXIO;
+ goto failed_free_mem;
+ }
+
+ ether->txirq = platform_get_irq(pdev, 0);
+ if (ether->txirq < 0) {
+ dev_err(&pdev->dev, "failed to get ether tx irq\n");
+ error = -ENXIO;
+ goto failed_free_io;
+ }
+
+ ether->rxirq = platform_get_irq(pdev, 1);
+ if (ether->rxirq < 0) {
+ dev_err(&pdev->dev, "failed to get ether rx irq\n");
+ error = -ENXIO;
+ goto failed_free_io;
+ }
+
+ SET_NETDEV_DEV(netdev, &pdev->dev);
+ platform_set_drvdata(pdev, netdev);
+ ether->netdev = netdev;
+
+ ether->pdev = pdev;
+ ether->msg_enable = NETIF_MSG_LINK;
+
+ netdev->netdev_ops = &npcm7xx_ether_netdev_ops;
+ netdev->ethtool_ops = &npcm7xx_ether_ethtool_ops;
+
+ netdev->tx_queue_len = TX_QUEUE_LEN;
+ netdev->dma = 0x0;
+ netdev->watchdog_timeo = TX_TIMEOUT;
+
+ get_mac_address(netdev);
+
+ ether->speed = 100;
+ ether->duplex = DUPLEX_FULL;
+
+ spin_lock_init(ðer->lock);
+
+ netif_napi_add(netdev, ðer->napi, npcm7xx_poll, RX_POLL_SIZE);
+
+ if (pdev->dev.of_node &&
+ of_get_property(pdev->dev.of_node, "use-ncsi", NULL)) {
+ if (!IS_ENABLED(CONFIG_NET_NCSI)) {
+ dev_err(&pdev->dev, "CONFIG_NET_NCSI not enabled\n");
+ error = -ENODEV;
+ goto failed_free_napi;
+ }
+ dev_info(&pdev->dev, "Using NCSI interface\n");
+ ether->use_ncsi = true;
+ ether->ncsidev = ncsi_register_dev(netdev,
+ npcm7xx_ncsi_handler);
+ if (!ether->ncsidev) {
+ error = -ENODEV;
+ goto failed_free_napi;
+ }
+ } else {
+ ether->use_ncsi = false;
+ error = npcm7xx_mii_setup(netdev);
+ if (error < 0) {
+ dev_err(&pdev->dev, "npcm7xx_mii_setup err\n");
+ goto failed_free_napi;
+ }
+ }
+
+ error = register_netdev(netdev);
+ if (error != 0) {
+ dev_err(&pdev->dev, "register_netdev() failed\n");
+ error = -ENODEV;
+ goto failed_free_napi;
+ }
+
+#ifdef CONFIG_DEBUG_FS
+ npcm7xx_debug_fs(ether);
+#endif
+
+ return 0;
+
+failed_free_napi:
+ netif_napi_del(ðer->napi);
+ platform_set_drvdata(pdev, NULL);
+failed_free_io:
+ iounmap(ether->reg);
+failed_free_mem:
+ release_mem_region(ether->res->start, resource_size(ether->res));
+failed_free:
+ free_netdev(netdev);
+
+ return error;
+}
+
+static int npcm7xx_ether_remove(struct platform_device *pdev)
+{
+ struct net_device *netdev = platform_get_drvdata(pdev);
+ struct npcm7xx_ether *ether = netdev_priv(netdev);
+
+#ifdef CONFIG_DEBUG_FS
+ debugfs_remove_recursive(ether->dbgfs_dir);
+#endif
+
+ unregister_netdev(netdev);
+
+ free_irq(ether->txirq, netdev);
+ free_irq(ether->rxirq, netdev);
+
+ if (ether->phy_dev)
+ phy_disconnect(ether->phy_dev);
+
+ mdiobus_unregister(ether->mii_bus);
+ kfree(ether->mii_bus->irq);
+ mdiobus_free(ether->mii_bus);
+
+ platform_set_drvdata(pdev, NULL);
+
+ free_netdev(netdev);
+ return 0;
+}
+
+static struct platform_driver npcm7xx_ether_driver = {
+ .probe = npcm7xx_ether_probe,
+ .remove = npcm7xx_ether_remove,
+ .driver = {
+ .name = DRV_MODULE_NAME,
+ .owner = THIS_MODULE,
+ .of_match_table = of_match_ptr(emc_dt_id),
+ },
+};
+
+module_platform_driver(npcm7xx_ether_driver);
+
+MODULE_AUTHOR("Nuvoton Technology Corp.");
+MODULE_DESCRIPTION("NPCM750 EMC driver");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:npcm750-emc");
+MODULE_VERSION(DRV_MODULE_VERSION);
--
2.18.0
^ permalink raw reply related
* [PATCH v1 1/2] dt-binding: net: document NPCM7xx EMC 10/100 DT bindings
From: Avi Fishman @ 2019-08-01 7:26 UTC (permalink / raw)
To: venture, yuenn, benjaminfair, davem, robh+dt, mark.rutland,
gregkh
Cc: avifishman70, tmaimon77, tali.perry1, openbmc, netdev, devicetree,
linux-kernel, tglx
In-Reply-To: <20190801072611.27935-1-avifishman70@gmail.com>
Added device tree binding documentation for
Nuvoton NPCM7xx Ethernet MAC Controller (EMC) 10/100 RMII
Signed-off-by: Avi Fishman <avifishman70@gmail.com>
---
.../bindings/net/nuvoton,npcm7xx-emc.txt | 38 +++++++++++++++++++
1 file changed, 38 insertions(+)
create mode 100644 Documentation/devicetree/bindings/net/nuvoton,npcm7xx-emc.txt
diff --git a/Documentation/devicetree/bindings/net/nuvoton,npcm7xx-emc.txt b/Documentation/devicetree/bindings/net/nuvoton,npcm7xx-emc.txt
new file mode 100644
index 000000000000..a7ac3ca66de9
--- /dev/null
+++ b/Documentation/devicetree/bindings/net/nuvoton,npcm7xx-emc.txt
@@ -0,0 +1,38 @@
+Nuvoton NPCM7XX 10/100 Ethernet MAC Controller (EMC)
+
+The NPCM7XX provides one or two Ethernet MAC RMII Controllers
+for WAN/LAN applications
+
+Required properties:
+- device_type : Should be "network"
+- compatible : "nuvoton,npcm750-emc" for Poleg NPCM7XX.
+- reg : Offset and length of the register set for the device.
+- interrupts : Contain the emc interrupts with flags for falling edge.
+ first interrupt dedicated to Txirq
+ second interrupt dedicated to Rxirq
+- phy-mode : Should be "rmii" (see ethernet.txt in the same directory)
+- clocks : phandle of emc reference clock.
+- resets : phandle to the reset control for this device.
+- use-ncsi : Use the NC-SI stack instead of an MDIO PHY
+
+Example:
+
+emc0: eth@f0825000 {
+ device_type = "network";
+ compatible = "nuvoton,npcm750-emc";
+ reg = <0xf0825000 0x1000>;
+ interrupts = <GIC_SPI 16 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 15 IRQ_TYPE_LEVEL_HIGH>;
+ phy-mode = "rmii";
+ clocks = <&clk NPCM7XX_CLK_AHB>;
+
+ #use-ncsi; /* add this to support ncsi */
+
+ clock-names = "clk_emc";
+ resets = <&rstc 6>;
+ pinctrl-names = "default";
+ pinctrl-0 = <&r1_pins
+ &r1err_pins
+ &r1md_pins>;
+ status = "okay";
+};
--
2.18.0
^ permalink raw reply related
* [PATCH v1 0/2] add NPCM7xx EMC 10/100 Ethernet driver
From: Avi Fishman @ 2019-08-01 7:26 UTC (permalink / raw)
To: venture, yuenn, benjaminfair, davem, robh+dt, mark.rutland,
gregkh
Cc: avifishman70, tmaimon77, tali.perry1, openbmc, netdev, devicetree,
linux-kernel, tglx
EMC Ethernet Media Access Controller supports 10/100 Mbps and RMII.
This driver has been working on Nuvoton BMC NPCM7xx.
Avi Fishman (2):
dt-binding: net: document NPCM7xx EMC 10/100 DT bindings
net: npcm: add NPCM7xx EMC 10/100 Ethernet driver
.../bindings/net/nuvoton,npcm7xx-emc.txt | 38 +
drivers/net/ethernet/nuvoton/Kconfig | 21 +-
drivers/net/ethernet/nuvoton/Makefile | 2 +
drivers/net/ethernet/nuvoton/npcm7xx_emc.c | 2073 +++++++++++++++++
4 files changed, 2131 insertions(+), 3 deletions(-)
create mode 100644 Documentation/devicetree/bindings/net/nuvoton,npcm7xx-emc.txt
create mode 100644 drivers/net/ethernet/nuvoton/npcm7xx_emc.c
--
2.18.0
^ permalink raw reply
* Re: [PATCH v6 2/2] dt-bindings: mtd: Document Macronix raw NAND controller bindings
From: Miquel Raynal @ 2019-08-01 7:13 UTC (permalink / raw)
To: Mason Yang
Cc: marek.vasut, bbrezillon, dwmw2, computersforpeace, vigneshr,
richard, robh+dt, stefan, mark.rutland, linux-kernel, linux-mtd,
juliensu, paul.burton, liang.yang, lee.jones, anders.roxell,
christophe.kerello, paul, devicetree
In-Reply-To: <1564631710-30276-3-git-send-email-masonccyang@mxic.com.tw>
Hi Mason,
Mason Yang <masonccyang@mxic.com.tw> wrote on Thu, 1 Aug 2019 11:55:10
+0800:
> Document the bindings used by the Macronix raw NAND controller.
>
> Signed-off-by: Mason Yang <masonccyang@mxic.com.tw>
> ---
> Documentation/devicetree/bindings/mtd/mxic-nand.txt | 19 +++++++++++++++++++
> 1 file changed, 19 insertions(+)
> create mode 100644 Documentation/devicetree/bindings/mtd/mxic-nand.txt
>
> diff --git a/Documentation/devicetree/bindings/mtd/mxic-nand.txt b/Documentation/devicetree/bindings/mtd/mxic-nand.txt
> new file mode 100644
> index 0000000..de37d60
> --- /dev/null
> +++ b/Documentation/devicetree/bindings/mtd/mxic-nand.txt
> @@ -0,0 +1,19 @@
> +Macronix Raw NAND Controller Device Tree Bindings
> +-------------------------------------------------
> +
> +Required properties:
> +- compatible: should be "mxicy,multi-itfc-v009-nand-morph"
> +- reg: should contain 1 entry for the registers
> +- interrupts: interrupt line connected to this raw NAND controller
> +- clock-names: should contain "ps", "send" and "send_dly"
> +- clocks: should contain 3 phandles for the "ps", "send" and
> + "send_dly" clocks
> +
> +Example:
> +
> + nand: nand-controller@43c30000 {
> + compatible = "mxicy,multi-itfc-v009-nand-morph";
"mxicy" looks strange to me, I know it has been used in the past and
cannot be removed, but I don't think it is wise to continue using it
while your use "mxic" in all your other contributions. I would update
the prefix to mxic here and fill-in the relevant doc.
Also, what is nand-morph? I thought we were okay for
the "-nand-controller" suffix.
Thanks,
Miquèl
^ permalink raw reply
* RE: [EXT] Re: [Patch v3 1/2] dt-bindings: spi: spi-fsl-qspi: Add ls2080a compatibility string to bindings
From: Ashish Kumar @ 2019-08-01 7:09 UTC (permalink / raw)
To: Rob Herring, Han Xu, broonie@kernel.org
Cc: devicetree@vger.kernel.org, bbrezillon@kernel.org, Kuldeep Singh,
Leo Li, linux-mtd@lists.infradead.org,
linux-arm-kernel@lists.infradead.org
In-Reply-To: <VE1PR04MB66874A887C5BE6209A4AE90F8FDF0@VE1PR04MB6687.eurprd04.prod.outlook.com>
> -----Original Message-----
> From: Leo Li
> Sent: Thursday, August 1, 2019 4:57 AM
> To: Ashish Kumar <ashish.kumar@nxp.com>; Rob Herring
> <robh@kernel.org>; Han Xu <han.xu@nxp.com>
> Cc: devicetree@vger.kernel.org; bbrezillon@kernel.org; broonie@kernel.org;
> linux-arm-kernel@lists.infradead.org; linux-mtd@lists.infradead.org; Kuldeep
> Singh <kuldeep.singh@nxp.com>
> Subject: RE: [EXT] Re: [Patch v3 1/2] dt-bindings: spi: spi-fsl-qspi: Add ls2080a
> compatibility string to bindings
>
>
>
> > -----Original Message-----
> > From: Ashish Kumar
> > Sent: Monday, July 29, 2019 4:11 AM
> > To: Rob Herring <robh@kernel.org>; Leo Li <leoyang.li@nxp.com>
> > Cc: devicetree@vger.kernel.org; bbrezillon@kernel.org;
> > broonie@kernel.org; linux-arm-kernel@lists.infradead.org;
> > linux-mtd@lists.infradead.org; Kuldeep Singh <kuldeep.singh@nxp.com>
> > Subject: RE: [EXT] Re: [Patch v3 1/2] dt-bindings: spi: spi-fsl-qspi:
> > Add ls2080a compatibility string to bindings
> >
> >
> >
> > > -----Original Message-----
> > > From: Rob Herring <robh@kernel.org>
> > > Sent: Wednesday, July 10, 2019 1:39 AM
> > > To: Ashish Kumar <ashish.kumar@nxp.com>
> > > Cc: devicetree@vger.kernel.org; bbrezillon@kernel.org;
> > > broonie@kernel.org; linux-arm-kernel@lists.infradead.org;
> > > linux-mtd@lists.infradead.org; Ashish Kumar <ashish.kumar@nxp.com>;
> > > Kuldeep Singh <kuldeep.singh@nxp.com>; Ashish Kumar
> > > <ashish.kumar@nxp.com>
> > > Subject: [EXT] Re: [Patch v3 1/2] dt-bindings: spi: spi-fsl-qspi:
> > > Add ls2080a compatibility string to bindings
> > >
> > > Caution: EXT Email
> > >
> > > On Wed, 19 Jun 2019 16:41:53 +0530, Ashish Kumar wrote:
> > > > There are 2 version of QSPI-IP, according to which controller
> > > > registers sets can be big endian or little endian.There are some
> > > > other minor changes like RX fifo depth etc.
> > > >
> > > > The big endian version uses driver compatible "fsl,ls1021a-qspi"
> > > > and little endian version uses driver compatible "fsl,ls2080a-qspi"
> > > >
> > > > Signed-off-by: Kuldeep Singh <kuldeep.singh@nxp.com>
> > > > Signed-off-by: Ashish Kumar <ashish.kumar@nxp.com>
> > > > ---
> > > > v3:
> > > > Rebase to top
> > > > v2:
> > > > Convert to patch series and rebasing done on top of tree
> > > >
> > > > Documentation/devicetree/bindings/spi/spi-fsl-qspi.txt | 3 +--
> > > > 1 file changed, 1 insertion(+), 2 deletions(-)
> > > >
> > >
> > > Reviewed-by: Rob Herring <robh@kernel.org>
> >
> > Hi Leo,
> >
> > I think Rob, is waiting for you ack.
>
> Binding patches usually go through subsystem tree. So I think this actually
> need ack from qspi maintainer Han Xu and be picked up by SPI maintainer.
Hello Han Xu,
Could you please ack this few of my dts patches are dependent on this, waiting to be pushed from Shawn's tree.
Regards
Ashish
>
> Regards,
> Leo
^ permalink raw reply
* RE: [EXT] Re: [Patch v3 2/2] dt-bindings: spi: spi-fsl-qspi: Add bindings of ls1088a and ls1012a
From: Ashish Kumar @ 2019-08-01 7:09 UTC (permalink / raw)
To: Rob Herring, Han Xu, broonie@kernel.org
Cc: devicetree@vger.kernel.org, bbrezillon@kernel.org, Kuldeep Singh,
Leo Li, linux-mtd@lists.infradead.org,
linux-arm-kernel@lists.infradead.org
In-Reply-To: <VE1PR04MB66879C5045A813E7311534D68FDF0@VE1PR04MB6687.eurprd04.prod.outlook.com>
> -----Original Message-----
> From: Leo Li
> Sent: Thursday, August 1, 2019 4:59 AM
> To: Ashish Kumar <ashish.kumar@nxp.com>; Rob Herring
> <robh@kernel.org>; Han Xu <han.xu@nxp.com>
> Cc: devicetree@vger.kernel.org; bbrezillon@kernel.org; broonie@kernel.org;
> linux-arm-kernel@lists.infradead.org; linux-mtd@lists.infradead.org; Kuldeep
> Singh <kuldeep.singh@nxp.com>
> Subject: RE: [EXT] Re: [Patch v3 2/2] dt-bindings: spi: spi-fsl-qspi: Add
> bindings of ls1088a and ls1012a
>
>
>
> > -----Original Message-----
> > From: Ashish Kumar
> > Sent: Monday, July 29, 2019 4:09 AM
> > To: Rob Herring <robh@kernel.org>; Leo Li <leoyang.li@nxp.com>
> > Cc: devicetree@vger.kernel.org; bbrezillon@kernel.org;
> > broonie@kernel.org; linux-arm-kernel@lists.infradead.org;
> > linux-mtd@lists.infradead.org; Kuldeep Singh <kuldeep.singh@nxp.com>
> > Subject: RE: [EXT] Re: [Patch v3 2/2] dt-bindings: spi: spi-fsl-qspi:
> > Add bindings of ls1088a and ls1012a
> >
> >
> >
> > > -----Original Message-----
> > > From: Rob Herring <robh@kernel.org>
> > > Sent: Wednesday, July 10, 2019 1:39 AM
> > > To: Ashish Kumar <ashish.kumar@nxp.com>
> > > Cc: devicetree@vger.kernel.org; bbrezillon@kernel.org;
> > > broonie@kernel.org; linux-arm-kernel@lists.infradead.org;
> > > linux-mtd@lists.infradead.org; Ashish Kumar <ashish.kumar@nxp.com>;
> > > Kuldeep Singh <kuldeep.singh@nxp.com>; Ashish Kumar
> > > <ashish.kumar@nxp.com>
> > > Subject: [EXT] Re: [Patch v3 2/2] dt-bindings: spi: spi-fsl-qspi:
> > > Add bindings of ls1088a and ls1012a
> > >
> > > Caution: EXT Email
> > >
> > > On Wed, 19 Jun 2019 16:41:54 +0530, Ashish Kumar wrote:
> > > > Signed-off-by: Kuldeep Singh <kuldeep.singh@nxp.com>
> > > > Signed-off-by: Ashish Kumar <ashish.kumar@nxp.com>
> > > > ---
> > > > v3:
> > > > Rebase to top
> > > > v2:
> > > > Convert to patch series and rebasing done on top of tree
> > > >
> > > > Documentation/devicetree/bindings/spi/spi-fsl-qspi.txt | 2 ++
> > > > 1 file changed, 2 insertions(+)
> > > >
> > >
> > > Reviewed-by: Rob Herring <robh@kernel.org>
> >
> > Hi Leo,
> >
> > I think Rob, is waiting for you ack.
>
> Binding patches usually go through subsystem tree. So I think this actually
> need ack from qspi maintainer Han Xu and be picked up by SPI maintainer.
Ok.
Hello Han Xu,
Could you please ack this few of my dts patches are dependent on this, waiting to be pushed from Shawn's tree.
Regards
Ashish
>
> Regards,
> Leo
^ permalink raw reply
* Re: [PATCH v6 1/2] mtd: rawnand: Add Macronix raw NAND controller driver
From: Boris Brezillon @ 2019-08-01 6:22 UTC (permalink / raw)
To: Mason Yang
Cc: miquel.raynal, marek.vasut, bbrezillon, dwmw2, computersforpeace,
vigneshr, richard, robh+dt, stefan, mark.rutland, linux-kernel,
linux-mtd, juliensu, paul.burton, liang.yang, lee.jones,
anders.roxell, christophe.kerello, paul, devicetree
In-Reply-To: <1564631710-30276-2-git-send-email-masonccyang@mxic.com.tw>
On Thu, 1 Aug 2019 11:55:09 +0800
Mason Yang <masonccyang@mxic.com.tw> wrote:
> Add a driver for Macronix raw NAND controller.
>
> Signed-off-by: Mason Yang <masonccyang@mxic.com.tw>
> ---
> drivers/mtd/nand/raw/Kconfig | 6 +
> drivers/mtd/nand/raw/Makefile | 1 +
> drivers/mtd/nand/raw/mxic_nand.c | 554 +++++++++++++++++++++++++++++++++++++++
> 3 files changed, 561 insertions(+)
> create mode 100644 drivers/mtd/nand/raw/mxic_nand.c
>
> diff --git a/drivers/mtd/nand/raw/Kconfig b/drivers/mtd/nand/raw/Kconfig
> index 5a711d8..9cff36a 100644
> --- a/drivers/mtd/nand/raw/Kconfig
> +++ b/drivers/mtd/nand/raw/Kconfig
> @@ -407,6 +407,12 @@ config MTD_NAND_MTK
> Enables support for NAND controller on MTK SoCs.
> This controller is found on mt27xx, mt81xx, mt65xx SoCs.
>
> +config MTD_NAND_MXIC
> + tristate "Macronix raw NAND controller"
> + depends on HAS_IOMEM || COMPILE_TEST
> + help
> + This selects the Macronix raw NAND controller driver.
> +
> config MTD_NAND_TEGRA
> tristate "NVIDIA Tegra NAND controller"
> depends on ARCH_TEGRA || COMPILE_TEST
> diff --git a/drivers/mtd/nand/raw/Makefile b/drivers/mtd/nand/raw/Makefile
> index efaf5cd..9b43fbf 100644
> --- a/drivers/mtd/nand/raw/Makefile
> +++ b/drivers/mtd/nand/raw/Makefile
> @@ -54,6 +54,7 @@ obj-$(CONFIG_MTD_NAND_HISI504) += hisi504_nand.o
> obj-$(CONFIG_MTD_NAND_BRCMNAND) += brcmnand/
> obj-$(CONFIG_MTD_NAND_QCOM) += qcom_nandc.o
> obj-$(CONFIG_MTD_NAND_MTK) += mtk_ecc.o mtk_nand.o
> +obj-$(CONFIG_MTD_NAND_MXIC) += mxic_nand.o
> obj-$(CONFIG_MTD_NAND_TEGRA) += tegra_nand.o
> obj-$(CONFIG_MTD_NAND_STM32_FMC2) += stm32_fmc2_nand.o
> obj-$(CONFIG_MTD_NAND_MESON) += meson_nand.o
> diff --git a/drivers/mtd/nand/raw/mxic_nand.c b/drivers/mtd/nand/raw/mxic_nand.c
> new file mode 100644
> index 0000000..56e816d
> --- /dev/null
> +++ b/drivers/mtd/nand/raw/mxic_nand.c
> @@ -0,0 +1,554 @@
> +// SPDX-License-Identifier: GPL-2.0
> +/*
> + * Copyright (C) 2019 Macronix International Co., Ltd.
> + *
> + * Author:
> + * Mason Yang <masonccyang@mxic.com.tw>
> + */
> +
> +#include <linux/clk.h>
> +#include <linux/io.h>
> +#include <linux/iopoll.h>
> +#include <linux/module.h>
> +#include <linux/mtd/mtd.h>
> +#include <linux/mtd/rawnand.h>
> +#include <linux/mtd/nand_ecc.h>
> +#include <linux/platform_device.h>
> +
> +#include "internals.h"
> +
> +#define HC_CFG 0x0
> +#define HC_CFG_IF_CFG(x) ((x) << 27)
> +#define HC_CFG_DUAL_SLAVE BIT(31)
> +#define HC_CFG_INDIVIDUAL BIT(30)
> +#define HC_CFG_NIO(x) (((x) / 4) << 27)
> +#define HC_CFG_TYPE(s, t) ((t) << (23 + ((s) * 2)))
> +#define HC_CFG_TYPE_SPI_NOR 0
> +#define HC_CFG_TYPE_SPI_NAND 1
> +#define HC_CFG_TYPE_SPI_RAM 2
> +#define HC_CFG_TYPE_RAW_NAND 3
> +#define HC_CFG_SLV_ACT(x) ((x) << 21)
> +#define HC_CFG_CLK_PH_EN BIT(20)
> +#define HC_CFG_CLK_POL_INV BIT(19)
> +#define HC_CFG_BIG_ENDIAN BIT(18)
> +#define HC_CFG_DATA_PASS BIT(17)
> +#define HC_CFG_IDLE_SIO_LVL(x) ((x) << 16)
> +#define HC_CFG_MAN_START_EN BIT(3)
> +#define HC_CFG_MAN_START BIT(2)
> +#define HC_CFG_MAN_CS_EN BIT(1)
> +#define HC_CFG_MAN_CS_ASSERT BIT(0)
> +
> +#define INT_STS 0x4
> +#define INT_STS_EN 0x8
> +#define INT_SIG_EN 0xc
> +#define INT_STS_ALL GENMASK(31, 0)
> +#define INT_RDY_PIN BIT(26)
> +#define INT_RDY_SR BIT(25)
> +#define INT_LNR_SUSP BIT(24)
> +#define INT_ECC_ERR BIT(17)
> +#define INT_CRC_ERR BIT(16)
> +#define INT_LWR_DIS BIT(12)
> +#define INT_LRD_DIS BIT(11)
> +#define INT_SDMA_INT BIT(10)
> +#define INT_DMA_FINISH BIT(9)
> +#define INT_RX_NOT_FULL BIT(3)
> +#define INT_RX_NOT_EMPTY BIT(2)
> +#define INT_TX_NOT_FULL BIT(1)
> +#define INT_TX_EMPTY BIT(0)
> +
> +#define HC_EN 0x10
> +#define HC_EN_BIT BIT(0)
> +
> +#define TXD(x) (0x14 + ((x) * 4))
> +#define RXD 0x24
> +
> +#define SS_CTRL(s) (0x30 + ((s) * 4))
> +#define LRD_CFG 0x44
> +#define LWR_CFG 0x80
> +#define RWW_CFG 0x70
> +#define OP_READ BIT(23)
> +#define OP_DUMMY_CYC(x) ((x) << 17)
> +#define OP_ADDR_BYTES(x) ((x) << 14)
> +#define OP_CMD_BYTES(x) (((x) - 1) << 13)
> +#define OP_OCTA_CRC_EN BIT(12)
> +#define OP_DQS_EN BIT(11)
> +#define OP_ENHC_EN BIT(10)
> +#define OP_PREAMBLE_EN BIT(9)
> +#define OP_DATA_DDR BIT(8)
> +#define OP_DATA_BUSW(x) ((x) << 6)
> +#define OP_ADDR_DDR BIT(5)
> +#define OP_ADDR_BUSW(x) ((x) << 3)
> +#define OP_CMD_DDR BIT(2)
> +#define OP_CMD_BUSW(x) (x)
> +#define OP_BUSW_1 0
> +#define OP_BUSW_2 1
> +#define OP_BUSW_4 2
> +#define OP_BUSW_8 3
> +
> +#define OCTA_CRC 0x38
> +#define OCTA_CRC_IN_EN(s) BIT(3 + ((s) * 16))
> +#define OCTA_CRC_CHUNK(s, x) ((fls((x) / 32)) << (1 + ((s) * 16)))
> +#define OCTA_CRC_OUT_EN(s) BIT(0 + ((s) * 16))
> +
> +#define ONFI_DIN_CNT(s) (0x3c + (s))
> +
> +#define LRD_CTRL 0x48
> +#define RWW_CTRL 0x74
> +#define LWR_CTRL 0x84
> +#define LMODE_EN BIT(31)
> +#define LMODE_SLV_ACT(x) ((x) << 21)
> +#define LMODE_CMD1(x) ((x) << 8)
> +#define LMODE_CMD0(x) (x)
> +
> +#define LRD_ADDR 0x4c
> +#define LWR_ADDR 0x88
> +#define LRD_RANGE 0x50
> +#define LWR_RANGE 0x8c
> +
> +#define AXI_SLV_ADDR 0x54
> +
> +#define DMAC_RD_CFG 0x58
> +#define DMAC_WR_CFG 0x94
> +#define DMAC_CFG_PERIPH_EN BIT(31)
> +#define DMAC_CFG_ALLFLUSH_EN BIT(30)
> +#define DMAC_CFG_LASTFLUSH_EN BIT(29)
> +#define DMAC_CFG_QE(x) (((x) + 1) << 16)
> +#define DMAC_CFG_BURST_LEN(x) (((x) + 1) << 12)
> +#define DMAC_CFG_BURST_SZ(x) ((x) << 8)
> +#define DMAC_CFG_DIR_READ BIT(1)
> +#define DMAC_CFG_START BIT(0)
> +
> +#define DMAC_RD_CNT 0x5c
> +#define DMAC_WR_CNT 0x98
> +
> +#define SDMA_ADDR 0x60
> +
> +#define DMAM_CFG 0x64
> +#define DMAM_CFG_START BIT(31)
> +#define DMAM_CFG_CONT BIT(30)
> +#define DMAM_CFG_SDMA_GAP(x) (fls((x) / 8192) << 2)
> +#define DMAM_CFG_DIR_READ BIT(1)
> +#define DMAM_CFG_EN BIT(0)
> +
> +#define DMAM_CNT 0x68
> +
> +#define LNR_TIMER_TH 0x6c
> +
> +#define RDM_CFG0 0x78
> +#define RDM_CFG0_POLY(x) (x)
> +
> +#define RDM_CFG1 0x7c
> +#define RDM_CFG1_RDM_EN BIT(31)
> +#define RDM_CFG1_SEED(x) (x)
> +
> +#define LWR_SUSP_CTRL 0x90
> +#define LWR_SUSP_CTRL_EN BIT(31)
> +
> +#define DMAS_CTRL 0x9c
> +#define DMAS_CTRL_EN BIT(31)
> +#define DMAS_CTRL_DIR_READ BIT(30)
> +
> +#define DATA_STROB 0xa0
> +#define DATA_STROB_EDO_EN BIT(2)
> +#define DATA_STROB_INV_POL BIT(1)
> +#define DATA_STROB_DELAY_2CYC BIT(0)
> +
> +#define IDLY_CODE(x) (0xa4 + ((x) * 4))
> +#define IDLY_CODE_VAL(x, v) ((v) << (((x) % 4) * 8))
> +
> +#define GPIO 0xc4
> +#define GPIO_PT(x) BIT(3 + ((x) * 16))
> +#define GPIO_RESET(x) BIT(2 + ((x) * 16))
> +#define GPIO_HOLDB(x) BIT(1 + ((x) * 16))
> +#define GPIO_WPB(x) BIT((x) * 16)
> +
> +#define HC_VER 0xd0
> +
> +#define HW_TEST(x) (0xe0 + ((x) * 4))
> +
> +#define MXIC_NFC_MAX_CLK_HZ 50000000
> +
> +struct mxic_nand_ctlr {
> + struct clk *ps_clk;
> + struct clk *send_clk;
> + struct clk *send_dly_clk;
> + void __iomem *regs;
> + struct nand_controller controller;
> + struct device *dev;
> + void *priv;
Looks like this priv field point to a nand_chip object. Please replace
it by:
struct nand_chip *chip;
> +};
> +
> +struct mxic_nand_chip {
> + struct nand_chip chip;
> +};
No need to define your own nand_chip struct if all it contains is the
base definition.
> +
> +static int mxic_nfc_clk_enable(struct mxic_nand_ctlr *nfc)
> +{
> + int ret;
> +
> + ret = clk_prepare_enable(nfc->ps_clk);
> + if (ret)
> + return ret;
> +
> + ret = clk_prepare_enable(nfc->send_clk);
> + if (ret)
> + goto err_ps_clk;
> +
> + ret = clk_prepare_enable(nfc->send_dly_clk);
> + if (ret)
> + goto err_send_dly_clk;
> +
> + return ret;
> +
> +err_send_dly_clk:
> + clk_disable_unprepare(nfc->send_clk);
> +err_ps_clk:
> + clk_disable_unprepare(nfc->ps_clk);
> +
> + return ret;
> +}
> +
> +static void mxic_nfc_clk_disable(struct mxic_nand_ctlr *nfc)
> +{
> + clk_disable_unprepare(nfc->send_clk);
> + clk_disable_unprepare(nfc->send_dly_clk);
> + clk_disable_unprepare(nfc->ps_clk);
> +}
> +
> +static void mxic_nfc_set_input_delay(struct mxic_nand_ctlr *nfc, u8 idly_code)
> +{
> + writel(IDLY_CODE_VAL(0, idly_code) |
> + IDLY_CODE_VAL(1, idly_code) |
> + IDLY_CODE_VAL(2, idly_code) |
> + IDLY_CODE_VAL(3, idly_code),
> + nfc->regs + IDLY_CODE(0));
> + writel(IDLY_CODE_VAL(4, idly_code) |
> + IDLY_CODE_VAL(5, idly_code) |
> + IDLY_CODE_VAL(6, idly_code) |
> + IDLY_CODE_VAL(7, idly_code),
> + nfc->regs + IDLY_CODE(1));
> +}
> +
> +static int mxic_nfc_clk_setup(struct mxic_nand_ctlr *nfc, unsigned long freq)
> +{
> + int ret;
> +
> + ret = clk_set_rate(nfc->send_clk, freq);
> + if (ret)
> + return ret;
> +
> + ret = clk_set_rate(nfc->send_dly_clk, freq);
> + if (ret)
> + return ret;
> +
> + /*
> + * A constant delay range from 0x0 ~ 0x1F for input delay,
> + * the unit is 78 ps, the max input delay is 2.418 ns.
> + */
> + mxic_nfc_set_input_delay(nfc, 0xf);
Just curious. Shouldn't we use that to support EDO modes? This being
said, a delay of 2.5ns will not be enough for EDO...
> +
> + /*
> + * Phase degree = 360 * freq * output-delay
> + * where output-delay is a constant value 1 ns in FPGA.
> + *
> + * Get Phase degree = 360 * freq * 1 ns
> + * = 360 * freq * 1 sec / 1000000000
> + * = 9 * freq / 25000000
> + */
> + ret = clk_set_phase(nfc->send_dly_clk, 9 * freq / 25000000);
> + if (ret)
> + return ret;
> +
> + return 0;
> +}
> +
> +static int mxic_nfc_set_freq(struct mxic_nand_ctlr *nfc, unsigned long freq)
> +{
> + int ret;
> +
> + if (freq > MXIC_NFC_MAX_CLK_HZ)
> + freq = MXIC_NFC_MAX_CLK_HZ;
> +
> + mxic_nfc_clk_disable(nfc);
> + ret = mxic_nfc_clk_setup(nfc, freq);
> + if (ret)
> + return ret;
> +
> + ret = mxic_nfc_clk_enable(nfc);
> + if (ret)
> + return ret;
> +
> + return 0;
> +}
> +
> +static void mxic_nfc_hw_init(struct mxic_nand_ctlr *nfc)
> +{
> + writel(DATA_STROB_EDO_EN, nfc->regs + DATA_STROB);
Oh, no, here is the EDO flag. BTW, you should not have it set by
default, it's something you configure in your ->setup_data_interface()
implementation.
> + writel(HC_CFG_NIO(8) | HC_CFG_TYPE(1, HC_CFG_TYPE_RAW_NAND) |
> + HC_CFG_SLV_ACT(0) | HC_CFG_MAN_CS_EN |
> + HC_CFG_IDLE_SIO_LVL(1), nfc->regs + HC_CFG);
> + writel(INT_STS_ALL, nfc->regs + INT_STS_EN);
> + writel(0x0, nfc->regs + ONFI_DIN_CNT(0));
> + writel(0, nfc->regs + LRD_CFG);
> + writel(0, nfc->regs + LRD_CTRL);
> + writel(0x0, nfc->regs + HC_EN);
> +
> + /* Default 10 MHz to setup tRC_min/tWC_min:100 ns */
> + mxic_nfc_set_freq(nfc, 10000000);
Again, not something you should configure here, but I guess having a
default setting does not hurt.
> +}
> +
> +static void mxic_nfc_cs_enable(struct mxic_nand_ctlr *nfc)
> +{
> + writel(readl(nfc->regs + HC_CFG) | HC_CFG_MAN_CS_EN,
> + nfc->regs + HC_CFG);
> + writel(HC_CFG_MAN_CS_ASSERT | readl(nfc->regs + HC_CFG),
> + nfc->regs + HC_CFG);
> +}
> +
> +static void mxic_nfc_cs_disable(struct mxic_nand_ctlr *nfc)
> +{
> + writel(~HC_CFG_MAN_CS_ASSERT & readl(nfc->regs + HC_CFG),
> + nfc->regs + HC_CFG);
> +}
> +
> +static int mxic_nfc_wait_ready(struct nand_chip *chip)
> +{
> + struct mxic_nand_ctlr *nfc = nand_get_controller_data(chip);
> + u32 sts;
> +
> + return readl_poll_timeout(nfc->regs + INT_STS, sts,
> + sts & INT_RDY_PIN, 0, USEC_PER_SEC);
You're not using interrupts at all? For things like R/B wait it's
usually a good thing to rely on interrupts instead of status-polling.
> +}
> +
> +static int mxic_nfc_data_xfer(struct mxic_nand_ctlr *nfc, const void *txbuf,
> + void *rxbuf, unsigned int len)
> +{
> + unsigned int pos = 0;
> +
> + while (pos < len) {
> + unsigned int nbytes = len - pos;
> + u32 data = 0xffffffff;
> + u32 sts;
> + int ret;
> +
> + if (nbytes > 4)
> + nbytes = 4;
> +
> + if (txbuf)
> + memcpy(&data, txbuf + pos, nbytes);
> +
> + ret = readl_poll_timeout(nfc->regs + INT_STS, sts,
> + sts & INT_TX_EMPTY, 0, USEC_PER_SEC);
> + if (ret)
> + return ret;
> +
> + writel(data, nfc->regs + TXD(nbytes % 4));
> +
> + ret = readl_poll_timeout(nfc->regs + INT_STS, sts,
> + sts & INT_TX_EMPTY, 0,
> + USEC_PER_SEC);
> + if (ret)
> + return ret;
> +
> + ret = readl_poll_timeout(nfc->regs + INT_STS, sts,
> + sts & INT_RX_NOT_EMPTY, 0,
> + USEC_PER_SEC);
> + if (ret)
> + return ret;
> +
> + data = readl(nfc->regs + RXD);
> + if (rxbuf) {
> + data >>= (8 * (4 - nbytes));
> + memcpy(rxbuf + pos, &data, nbytes);
> + }
> + if (readl(nfc->regs + INT_STS) & INT_RX_NOT_EMPTY)
> + dev_warn(nfc->dev, "RX FIFO not empty\n")
> +
> + pos += nbytes;
> + }
> +
> + return 0;
> +}
> +
> +static int mxic_nfc_exec_op(struct nand_chip *chip,
> + const struct nand_operation *op, bool check_only)
> +{
> + struct mxic_nand_ctlr *nfc = nand_get_controller_data(chip);
> + const struct nand_op_instr *instr = NULL;
> + int ret = 0;
> + unsigned int op_id;
> +
> + mxic_nfc_cs_enable(nfc);
> + for (op_id = 0; op_id < op->ninstrs; op_id++) {
> + instr = &op->instrs[op_id];
> +
> + switch (instr->type) {
> + case NAND_OP_CMD_INSTR:
> + writel(0, nfc->regs + HC_EN);
> + writel(HC_EN_BIT, nfc->regs + HC_EN);
> + writel(OP_CMD_BUSW(OP_BUSW_8) | OP_DUMMY_CYC(0x3F) |
> + OP_CMD_BYTES(0), nfc->regs + SS_CTRL(0));
> +
> + ret = mxic_nfc_data_xfer(nfc,
> + &instr->ctx.cmd.opcode,
> + NULL, 1);
> + break;
> +
> + case NAND_OP_ADDR_INSTR:
> + writel(OP_ADDR_BUSW(OP_BUSW_8) | OP_DUMMY_CYC(0x3F) |
> + OP_ADDR_BYTES(instr->ctx.addr.naddrs),
> + nfc->regs + SS_CTRL(0));
> + ret = mxic_nfc_data_xfer(nfc,
> + instr->ctx.addr.addrs, NULL,
> + instr->ctx.addr.naddrs);
> + break;
> +
> + case NAND_OP_DATA_IN_INSTR:
> + writel(0x0, nfc->regs + ONFI_DIN_CNT(0));
> + writel(OP_DATA_BUSW(OP_BUSW_8) | OP_DUMMY_CYC(0x3F) |
> + OP_READ, nfc->regs + SS_CTRL(0));
> + ret = mxic_nfc_data_xfer(nfc, NULL,
> + instr->ctx.data.buf.in,
> + instr->ctx.data.len);
> + break;
> +
> + case NAND_OP_DATA_OUT_INSTR:
> + writel(instr->ctx.data.len,
> + nfc->regs + ONFI_DIN_CNT(0));
> + writel(OP_DATA_BUSW(OP_BUSW_8) | OP_DUMMY_CYC(0x3F),
> + nfc->regs + SS_CTRL(0));
> + ret = mxic_nfc_data_xfer(nfc,
> + instr->ctx.data.buf.out, NULL,
> + instr->ctx.data.len);
> + break;
> +
> + case NAND_OP_WAITRDY_INSTR:
> + ret = mxic_nfc_wait_ready(chip);
> + break;
> + }
> + }
> + mxic_nfc_cs_disable(nfc);
> +
> + return ret;
> +}
> +
> +static int mxic_nfc_setup_data_interface(struct nand_chip *chip, int chipnr,
> + const struct nand_data_interface *conf)
> +{
> + struct mxic_nand_ctlr *nfc = nand_get_controller_data(chip);
> + const struct nand_sdr_timings *sdr;
> + unsigned long freq;
> +
> + sdr = nand_get_sdr_timings(conf);
> + if (IS_ERR(sdr))
> + return PTR_ERR(sdr);
> +
> + if (chipnr < 0)
Please use the NAND_DATA_IFACE_CHECK_ONLY macro for this check:
if (chipnr == NAND_DATA_IFACE_CHECK_ONLY)
return 0;
> + return 0;
> +
> + if (sdr->tRC_min)
> + freq = 1000000000 / (sdr->tRC_min / 1000);
Please use NSEC_PER_SEC instead of 1000000000. And I think you can get
rid of the check on sdr->tRC_min (it should never be 0).
> +
> + return mxic_nfc_set_freq(nfc, freq);
You should set the EDO when ->tRC_min < 30000 IIRC, clear it otherwise.
> +}
> +
> +static const struct nand_controller_ops mxic_nand_controller_ops = {
> + .exec_op = mxic_nfc_exec_op,
> + .setup_data_interface = mxic_nfc_setup_data_interface,
> +};
> +
> +static int mxic_nfc_probe(struct platform_device *pdev)
> +{
> + struct mtd_info *mtd;
> + struct mxic_nand_ctlr *nfc;
> + struct mxic_nand_chip *mxic_nand;
> + struct nand_chip *nand_chip;
> + struct resource *res;
> + int err;
> +
> + nfc = devm_kzalloc(&pdev->dev, sizeof(struct mxic_nand_ctlr),
> + GFP_KERNEL);
> + if (!nfc)
> + return -ENOMEM;
> +
> + mxic_nand = devm_kzalloc(&pdev->dev, sizeof(struct mxic_nand_chip),
> + GFP_KERNEL);
> + if (!mxic_nand)
> + return -ENOMEM;
> +
> + nfc->ps_clk = devm_clk_get(&pdev->dev, "ps");
> + if (IS_ERR(nfc->ps_clk))
> + return PTR_ERR(nfc->ps_clk);
> +
> + nfc->send_clk = devm_clk_get(&pdev->dev, "send");
> + if (IS_ERR(nfc->send_clk))
> + return PTR_ERR(nfc->send_clk);
> +
> + nfc->send_dly_clk = devm_clk_get(&pdev->dev, "send_dly");
> + if (IS_ERR(nfc->send_dly_clk))
> + return PTR_ERR(nfc->send_dly_clk);
> +
> + res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
> + nfc->regs = devm_ioremap_resource(&pdev->dev, res);
> + if (IS_ERR(nfc->regs))
> + return PTR_ERR(nfc->regs);
> +
> + nand_chip = &mxic_nand->chip;
> + mtd = nand_to_mtd(nand_chip);
> + mtd->dev.parent = &pdev->dev;
> + nand_chip->ecc.priv = NULL;
No need to do this NULL assignment, the object is allocated with
devm_kzalloc().
> + nand_set_flash_node(nand_chip, pdev->dev.of_node);
The flash node should be a child of pdev->dev.of_node,
pdev->dev.of_node is representing your controller not the NAND chip.
> + nand_chip->priv = nfc;
> + nfc->dev = &pdev->dev;
> + nfc->priv = nand_chip;
> +
> + nfc->controller.ops = &mxic_nand_controller_ops;
> + nand_controller_init(&nfc->controller);
> + nand_chip->controller = &nfc->controller;
> +
> + mxic_nfc_hw_init(nfc);
> +
> + err = nand_scan(nand_chip, 1);
> + if (err)
> + goto fail;
> +
> + err = mtd_device_register(mtd, NULL, 0);
> + if (err)
> + goto fail;
> +
> + platform_set_drvdata(pdev, nfc);
> + return 0;
> +
> +fail:
> + mxic_nfc_clk_disable(nfc);
Looks like you never call mxic_nfc_clk_enable(), which means you'll end
up with unbalanced prepare/enable counts. Also not sure how that can
work unless the bootloader takes care of enabling the clks for you.
> + return err;
> +}
> +
> +static int mxic_nfc_remove(struct platform_device *pdev)
> +{
> + struct mxic_nand_ctlr *nfc = platform_get_drvdata(pdev);
> +
> + nand_release(nfc->priv);
> + mxic_nfc_clk_disable(nfc);
> + return 0;
> +}
> +
> +static const struct of_device_id mxic_nfc_of_ids[] = {
> + { .compatible = "mxicy,multi-itfc-v009-nand-morph", },
> + {},
> +};
> +MODULE_DEVICE_TABLE(of, mxic_nfc_of_ids);
> +
> +static struct platform_driver mxic_nfc_driver = {
> + .probe = mxic_nfc_probe,
> + .remove = mxic_nfc_remove,
> + .driver = {
> + .name = "mxic-nfc",
> + .of_match_table = mxic_nfc_of_ids,
> + },
> +};
> +module_platform_driver(mxic_nfc_driver);
> +
> +MODULE_AUTHOR("Mason Yang <masonccyang@mxic.com.tw>");
> +MODULE_DESCRIPTION("Macronix raw NAND controller driver");
> +MODULE_LICENSE("GPL v2");
^ permalink raw reply
* Re: [PATCH v9 0/7] Solve postboot supplier cleanup and optimize probe ordering
From: Greg Kroah-Hartman @ 2019-08-01 6:12 UTC (permalink / raw)
To: Saravana Kannan
Cc: Rob Herring, Mark Rutland, Rafael J. Wysocki, Frank Rowand,
devicetree, linux-kernel, David Collins, kernel-team
In-Reply-To: <20190731221721.187713-1-saravanak@google.com>
On Wed, Jul 31, 2019 at 03:17:13PM -0700, Saravana Kannan wrote:
> Add device-links to track functional dependencies between devices
> after they are created (but before they are probed) by looking at
> their common DT bindings like clocks, interconnects, etc.
>
> Having functional dependencies automatically added before the devices
> are probed, provides the following benefits:
>
> - Optimizes device probe order and avoids the useless work of
> attempting probes of devices that will not probe successfully
> (because their suppliers aren't present or haven't probed yet).
>
> For example, in a commonly available mobile SoC, registering just
> one consumer device's driver at an initcall level earlier than the
> supplier device's driver causes 11 failed probe attempts before the
> consumer device probes successfully. This was with a kernel with all
> the drivers statically compiled in. This problem gets a lot worse if
> all the drivers are loaded as modules without direct symbol
> dependencies.
>
> - Supplier devices like clock providers, interconnect providers, etc
> need to keep the resources they provide active and at a particular
> state(s) during boot up even if their current set of consumers don't
> request the resource to be active. This is because the rest of the
> consumers might not have probed yet and turning off the resource
> before all the consumers have probed could lead to a hang or
> undesired user experience.
>
> Some frameworks (Eg: regulator) handle this today by turning off
> "unused" resources at late_initcall_sync and hoping all the devices
> have probed by then. This is not a valid assumption for systems with
> loadable modules. Other frameworks (Eg: clock) just don't handle
> this due to the lack of a clear signal for when they can turn off
> resources. This leads to downstream hacks to handle cases like this
> that can easily be solved in the upstream kernel.
>
> By linking devices before they are probed, we give suppliers a clear
> count of the number of dependent consumers. Once all of the
> consumers are active, the suppliers can turn off the unused
> resources without making assumptions about the number of consumers.
>
> By default we just add device-links to track "driver presence" (probe
> succeeded) of the supplier device. If any other functionality provided
> by device-links are needed, it is left to the consumer/supplier
> devices to change the link when they probe.
All now queued up in my driver-core-testing branch, and if 0-day is
happy with this, will move it to my "real" driver-core-next branch in a
day or so to get included in linux-next.
thanks for sticking with this!
greg k-h
^ permalink raw reply
* Re: [PATCH v6 2/2] dt-bindings: mtd: Document Macronix raw NAND controller bindings
From: Boris Brezillon @ 2019-08-01 5:57 UTC (permalink / raw)
To: Mason Yang
Cc: miquel.raynal, marek.vasut, bbrezillon, dwmw2, computersforpeace,
vigneshr, richard, robh+dt, stefan, mark.rutland, linux-kernel,
linux-mtd, juliensu, paul.burton, liang.yang, lee.jones,
anders.roxell, christophe.kerello, paul, devicetree
In-Reply-To: <1564631710-30276-3-git-send-email-masonccyang@mxic.com.tw>
On Thu, 1 Aug 2019 11:55:10 +0800
Mason Yang <masonccyang@mxic.com.tw> wrote:
> Document the bindings used by the Macronix raw NAND controller.
>
> Signed-off-by: Mason Yang <masonccyang@mxic.com.tw>
> ---
> Documentation/devicetree/bindings/mtd/mxic-nand.txt | 19 +++++++++++++++++++
> 1 file changed, 19 insertions(+)
> create mode 100644 Documentation/devicetree/bindings/mtd/mxic-nand.txt
>
> diff --git a/Documentation/devicetree/bindings/mtd/mxic-nand.txt b/Documentation/devicetree/bindings/mtd/mxic-nand.txt
> new file mode 100644
> index 0000000..de37d60
> --- /dev/null
> +++ b/Documentation/devicetree/bindings/mtd/mxic-nand.txt
> @@ -0,0 +1,19 @@
> +Macronix Raw NAND Controller Device Tree Bindings
> +-------------------------------------------------
> +
> +Required properties:
> +- compatible: should be "mxicy,multi-itfc-v009-nand-morph"
> +- reg: should contain 1 entry for the registers
> +- interrupts: interrupt line connected to this raw NAND controller
> +- clock-names: should contain "ps", "send" and "send_dly"
> +- clocks: should contain 3 phandles for the "ps", "send" and
> + "send_dly" clocks
> +
> +Example:
> +
> + nand: nand-controller@43c30000 {
> + compatible = "mxicy,multi-itfc-v009-nand-morph";
> + reg = <0x43c30000 0x10000>;
> + clocks = <&clkwizard 0>, <&clkwizard 1>, <&clkc 15>;
> + clock-names = "send", "send_dly", "ps";
You should have subnodes describing the NAND connected to the
controller (see [1]).
[1]https://elixir.bootlin.com/linux/v5.3-rc2/source/Documentation/devicetree/bindings/mtd/nand-controller.yaml#L131
> + };
^ permalink raw reply
* Re: [PATCH 0/3] ARM: dts: aspeed: Deprecate g[45]-style compatibles
From: Andrew Jeffery @ 2019-08-01 5:45 UTC (permalink / raw)
To: Linus Walleij
Cc: linux-aspeed, Lee Jones, Rob Herring, Mark Rutland, Joel Stanley,
open list:OPEN FIRMWARE AND FLATTENED DEVICE TREE BINDINGS,
Linux ARM, linux-kernel@vger.kernel.org, open list:GPIO SUBSYSTEM
In-Reply-To: <9d0f2b20-e6f6-419c-a866-c4a0dd92aa63@www.fastmail.com>
On Tue, 30 Jul 2019, at 10:27, Andrew Jeffery wrote:
>
>
> On Tue, 30 Jul 2019, at 07:23, Linus Walleij wrote:
> > On Wed, Jul 24, 2019 at 10:13 AM Andrew Jeffery <andrew@aj.id.au> wrote:
> >
> > > It's probably best if we push the three patches all through one tree rather
> > > than fragmenting. Is everyone happy if Joel applies them to the aspeed tree?
> >
> > If you are sure it will not collide with parallell work in the
> > pinctrl tree, yes.
> > Acked-by: Linus Walleij <linus.walleij@linaro.org>
> >
> > (If it does collide I'd prefer to take the pinctrl patches and fix the
> > conflicts in my tree.)
>
> Fair enough, I don't know the answer so I'll poke around. I don't
> really mind
> where the series goes in, I just want to avoid landing only part of it
> if I split it up.
Okay, it currently conflicts with my cleanup-devicetree-warnings series.
Joel, do you mind if Linus takes this series through the pinctrl tree, given
the fix to the devicetrees is patch 1/3?
Andrew
^ 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