* [RESEND PATCH, v5 2/5] dt-bindings: mt8173-mtu3: add devicetree bindings
From: Chunfeng Yun @ 2016-08-25 3:05 UTC (permalink / raw)
To: Greg Kroah-Hartman, Felipe Balbi, Mathias Nyman, Oliver Neukum,
Matthias Brugger
Cc: Mark Rutland, devicetree-u79uwXL29TY76Z2rM5mHXA,
linux-usb-u79uwXL29TY76Z2rM5mHXA, Sergei Shtylyov, Pawel Moll,
Ian Campbell, Sascha Hauer, Alan Cooper,
linux-kernel-u79uwXL29TY76Z2rM5mHXA, Rob Herring, Alan Stern,
Kumar Gala, Chunfeng Yun,
linux-mediatek-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r,
linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r
In-Reply-To: <1472094329-18466-1-git-send-email-chunfeng.yun-NuS5LvNUpcJWk0Htik3J/w@public.gmane.org>
add a DT binding doc for MediaTek USB3 DRD driver
Signed-off-by: Chunfeng Yun <chunfeng.yun-NuS5LvNUpcJWk0Htik3J/w@public.gmane.org>
Acked-by: Rob Herring <robh-DgEjT+Ai2ygdnm+yROfE0A@public.gmane.org>
---
.../devicetree/bindings/usb/mt8173-mtu3.txt | 87 ++++++++++++++++++++
1 file changed, 87 insertions(+)
create mode 100644 Documentation/devicetree/bindings/usb/mt8173-mtu3.txt
diff --git a/Documentation/devicetree/bindings/usb/mt8173-mtu3.txt b/Documentation/devicetree/bindings/usb/mt8173-mtu3.txt
new file mode 100644
index 0000000..e049d19
--- /dev/null
+++ b/Documentation/devicetree/bindings/usb/mt8173-mtu3.txt
@@ -0,0 +1,87 @@
+The device node for Mediatek USB3.0 DRD controller
+
+Required properties:
+ - compatible : should be "mediatek,mt8173-mtu3"
+ - reg : specifies physical base address and size of the registers
+ - reg-names: should be "mac" for device IP and "ippc" for IP port control
+ - interrupts : interrupt used by the device IP
+ - power-domains : a phandle to USB power domain node to control USB's
+ mtcmos
+ - vusb33-supply : regulator of USB avdd3.3v
+ - clocks : a list of phandle + clock-specifier pairs, one for each
+ entry in clock-names
+ - clock-names : must contain "sys_ck" for clock of controller;
+ "wakeup_deb_p0" and "wakeup_deb_p1" are optional, they are
+ depends on "mediatek,enable-wakeup"
+ - phys : a list of phandle + phy specifier pairs
+ - dr_mode : should be one of "host", "peripheral" or "otg",
+ refer to usb/generic.txt
+
+Optional properties:
+ - #address-cells, #size-cells : should be '2' if the device has sub-nodes
+ with 'reg' property
+ - ranges : allows valid 1:1 translation between child's address space and
+ parent's address space
+ - extcon : external connector for vbus and idpin changes detection, needed
+ when supports dual-role mode.
+ - vbus-supply : reference to the VBUS regulator, needed when supports
+ dual-role mode.
+ - pinctl-names : a pinctrl state named "default" must be defined,
+ "id_float" and "id_ground" are optinal which depends on
+ "mediatek,enable-manual-drd"
+ - pinctrl-0 : pin control group
+ See: Documentation/devicetree/bindings/pinctrl/pinctrl-binding.txt
+
+ - maximum-speed : valid arguments are "super-speed", "high-speed" and
+ "full-speed"; refer to usb/generic.txt
+ - enable-manual-drd : supports manual dual-role switch via debugfs; usually
+ used when receptacle is TYPE-A and also wants to support dual-role
+ mode.
+ - mediatek,enable-wakeup : supports ip sleep wakeup used by host mode
+ - mediatek,syscon-wakeup : phandle to syscon used to access USB wakeup
+ control register, it depends on "mediatek,enable-wakeup".
+
+Sub-nodes:
+The xhci should be added as subnode to mtu3 as shown in the following example
+if host mode is enabled. The DT binding details of xhci can be found in:
+Documentation/devicetree/bindings/usb/mt8173-xhci.txt
+
+Example:
+ssusb: usb@11271000 {
+ compatible = "mediatek,mt8173-mtu3";
+ reg = <0 0x11271000 0 0x3000>,
+ <0 0x11280700 0 0x0100>;
+ reg-names = "mac", "ippc";
+ interrupts = <GIC_SPI 64 IRQ_TYPE_LEVEL_LOW>;
+ phys = <&phy_port0 PHY_TYPE_USB3>,
+ <&phy_port1 PHY_TYPE_USB2>;
+ power-domains = <&scpsys MT8173_POWER_DOMAIN_USB>;
+ clocks = <&topckgen CLK_TOP_USB30_SEL>,
+ <&pericfg CLK_PERI_USB0>,
+ <&pericfg CLK_PERI_USB1>;
+ clock-names = "sys_ck",
+ "wakeup_deb_p0",
+ "wakeup_deb_p1";
+ vusb33-supply = <&mt6397_vusb_reg>;
+ vbus-supply = <&usb_p0_vbus>;
+ extcon = <&extcon_usb>;
+ dr_mode = "otg";
+ mediatek,enable-wakeup;
+ mediatek,syscon-wakeup = <&pericfg>;
+ #address-cells = <2>;
+ #size-cells = <2>;
+ ranges;
+ status = "disabled";
+
+ usb_host: xhci@11270000 {
+ compatible = "mediatek,mt8173-xhci";
+ reg = <0 0x11270000 0 0x1000>;
+ reg-names = "mac";
+ interrupts = <GIC_SPI 115 IRQ_TYPE_LEVEL_LOW>;
+ power-domains = <&scpsys MT8173_POWER_DOMAIN_USB>;
+ clocks = <&topckgen CLK_TOP_USB30_SEL>;
+ clock-names = "sys_ck";
+ vusb33-supply = <&mt6397_vusb_reg>;
+ status = "disabled";
+ };
+};
--
1.7.9.5
^ permalink raw reply related
* [RESEND PATCH, v5 1/5] dt-bindings: mt8173-xhci: support host side of dual-role mode
From: Chunfeng Yun @ 2016-08-25 3:05 UTC (permalink / raw)
To: Greg Kroah-Hartman, Felipe Balbi, Mathias Nyman, Oliver Neukum,
Matthias Brugger
Cc: Mark Rutland, devicetree-u79uwXL29TY76Z2rM5mHXA,
linux-usb-u79uwXL29TY76Z2rM5mHXA, Sergei Shtylyov, Pawel Moll,
Ian Campbell, Sascha Hauer, Alan Cooper,
linux-kernel-u79uwXL29TY76Z2rM5mHXA, Rob Herring, Alan Stern,
Kumar Gala, Chunfeng Yun,
linux-mediatek-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r,
linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r
In-Reply-To: <1472094329-18466-1-git-send-email-chunfeng.yun-NuS5LvNUpcJWk0Htik3J/w@public.gmane.org>
Some resources, such as IPPC register etc, shared with device
driver are moved into common glue layer when xHCI driver is the
host side of dual-role mode and they should be changed as optional
properties if they are required ones before. For clarity, add
a new part of binding to support host side of dual-role mode.
Additionally add optional properties of pinctrl for host only mode
Signed-off-by: Chunfeng Yun <chunfeng.yun-NuS5LvNUpcJWk0Htik3J/w@public.gmane.org>
Acked-by: Rob Herring <robh-DgEjT+Ai2ygdnm+yROfE0A@public.gmane.org>
---
.../devicetree/bindings/usb/mt8173-xhci.txt | 54 +++++++++++++++++++-
1 file changed, 52 insertions(+), 2 deletions(-)
diff --git a/Documentation/devicetree/bindings/usb/mt8173-xhci.txt b/Documentation/devicetree/bindings/usb/mt8173-xhci.txt
index b3a7ffa..2a930bd 100644
--- a/Documentation/devicetree/bindings/usb/mt8173-xhci.txt
+++ b/Documentation/devicetree/bindings/usb/mt8173-xhci.txt
@@ -2,10 +2,18 @@ MT8173 xHCI
The device node for Mediatek SOC USB3.0 host controller
+There are two scenarios: the first one only supports xHCI driver;
+the second one supports dual-role mode, and the host is based on xHCI
+driver. Take account of backward compatibility, we divide bindings
+into two parts.
+
+1st: only supports xHCI driver
+------------------------------------------------------------------------
+
Required properties:
- compatible : should contain "mediatek,mt8173-xhci"
- - reg : specifies physical base address and size of the registers,
- the first one for MAC, the second for IPPC
+ - reg : specifies physical base address and size of the registers
+ - reg-names: should be "mac" for xHCI MAC and "ippc" for IP port control
- interrupts : interrupt used by the controller
- power-domains : a phandle to USB power domain node to control USB's
mtcmos
@@ -27,12 +35,16 @@ Optional properties:
control register, it depends on "mediatek,wakeup-src".
- vbus-supply : reference to the VBUS regulator;
- usb3-lpm-capable : supports USB3.0 LPM
+ - pinctrl-names : a pinctrl state named "default" must be defined
+ - pinctrl-0 : pin control group
+ See: Documentation/devicetree/bindings/pinctrl/pinctrl-binding.txt
Example:
usb30: usb@11270000 {
compatible = "mediatek,mt8173-xhci";
reg = <0 0x11270000 0 0x1000>,
<0 0x11280700 0 0x0100>;
+ reg-names = "mac", "ippc";
interrupts = <GIC_SPI 115 IRQ_TYPE_LEVEL_LOW>;
power-domains = <&scpsys MT8173_POWER_DOMAIN_USB>;
clocks = <&topckgen CLK_TOP_USB30_SEL>,
@@ -49,3 +61,41 @@ usb30: usb@11270000 {
mediatek,syscon-wakeup = <&pericfg>;
mediatek,wakeup-src = <1>;
};
+
+2nd: dual-role mode with xHCI driver
+------------------------------------------------------------------------
+
+In the case, xhci is added as subnode to mtu3. An example and the DT binding
+details of mtu3 can be found in:
+Documentation/devicetree/bindings/usb/mtu3.txt
+
+Required properties:
+ - compatible : should contain "mediatek,mt8173-xhci"
+ - reg : specifies physical base address and size of the registers
+ - reg-names: should be "mac" for xHCI MAC
+ - interrupts : interrupt used by the host controller
+ - power-domains : a phandle to USB power domain node to control USB's
+ mtcmos
+ - vusb33-supply : regulator of USB avdd3.3v
+
+ - clocks : a list of phandle + clock-specifier pairs, one for each
+ entry in clock-names
+ - clock-names : must be
+ "sys_ck": for clock of xHCI MAC
+
+Optional properties:
+ - vbus-supply : reference to the VBUS regulator;
+ - usb3-lpm-capable : supports USB3.0 LPM
+
+Example:
+usb30: usb@11270000 {
+ compatible = "mediatek,mt8173-xhci";
+ reg = <0 0x11270000 0 0x1000>;
+ reg-names = "mac";
+ interrupts = <GIC_SPI 115 IRQ_TYPE_LEVEL_LOW>;
+ power-domains = <&scpsys MT8173_POWER_DOMAIN_USB>;
+ clocks = <&topckgen CLK_TOP_USB30_SEL>;
+ clock-names = "sys_ck";
+ vusb33-supply = <&mt6397_vusb_reg>;
+ usb3-lpm-capable;
+};
--
1.7.9.5
^ permalink raw reply related
* [RESEND PATCH V5, 0/5] Add MediaTek USB3 DRD Driver
From: Chunfeng Yun @ 2016-08-25 3:05 UTC (permalink / raw)
To: Greg Kroah-Hartman, Felipe Balbi, Mathias Nyman, Oliver Neukum,
Matthias Brugger
Cc: Mark Rutland, devicetree-u79uwXL29TY76Z2rM5mHXA,
linux-usb-u79uwXL29TY76Z2rM5mHXA, Sergei Shtylyov, Pawel Moll,
Ian Campbell, Sascha Hauer, Alan Cooper,
linux-kernel-u79uwXL29TY76Z2rM5mHXA, Rob Herring, Alan Stern,
Kumar Gala, Chunfeng Yun,
linux-mediatek-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r,
linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r
>From e60d29d748a4e9f412c9bb08458083e97d3f523d Mon Sep 17 00:00:00 2001
From: Chunfeng Yun <chunfeng.yun-NuS5LvNUpcJWk0Htik3J/w@public.gmane.org>
Date: Tue, 9 Aug 2016 16:12:31 +0800
Subject: [PATCH V5, 0/5] Add MediaTek USB3 DRD Driver
These patches introduce the MediaTek USB3 dual-role controller
driver.
The driver can be configured as Dual-Role Device (DRD),
Peripheral Only and Host Only (xHCI) modes. It works well
with Mass Storage, RNDIS and g_zero on FS/HS and SS. And it is
tested on MT8173 platform which only contains USB2.0 device IP,
and on MT6290 platform which contains USB3.0 device IP.
Change in v5:
1. modify some comments
2. rename some unsuitable variables
3. add reg-names property for host node
4. add USB_MTU3_DEBUG to control debug messages
Change in v4:
1. fix build errors on non-mediatek platforms
2. provide manual dual-role switch via debugfs instead of sysfs
Change in v3:
1. fix some typo error
2. rename mtu3.txt to mt8173-mtu3.txt
Change in v2:
1. modify binding docs according to suggestions
2. modify some comments and remove some dummy blank lines
3. fix memory leakage
Change in v2:
1. modify binding docs according to suggestions
2. modify some comments and remove some dummy blank lines
3. fix memory leakage
Chunfeng Yun (5):
dt-bindings: mt8173-xhci: support host side of dual-role mode
dt-bindings: mt8173-mtu3: add devicetree bindings
usb: xhci-mtk: make IPPC register optional
usb: Add MediaTek USB3 DRD Driver
arm64: dts: mediatek: add USB3 DRD driver
.../devicetree/bindings/usb/mt8173-mtu3.txt | 87 ++
.../devicetree/bindings/usb/mt8173-xhci.txt | 54 +-
arch/arm64/boot/dts/mediatek/mt8173-evb.dts | 46 +-
arch/arm64/boot/dts/mediatek/mt8173.dtsi | 29 +-
drivers/usb/Kconfig | 2 +
drivers/usb/Makefile | 1 +
drivers/usb/host/xhci-mtk.c | 36 +-
drivers/usb/mtu3/Kconfig | 54 ++
drivers/usb/mtu3/Makefile | 19 +
drivers/usb/mtu3/mtu3.h | 422 ++++++++++
drivers/usb/mtu3/mtu3_core.c | 874 +++++++++++++++++++
drivers/usb/mtu3/mtu3_dr.c | 375 +++++++++
drivers/usb/mtu3/mtu3_dr.h | 108 +++
drivers/usb/mtu3/mtu3_gadget.c | 731 ++++++++++++++++
drivers/usb/mtu3/mtu3_gadget_ep0.c | 879 ++++++++++++++++++++
drivers/usb/mtu3/mtu3_host.c | 294 +++++++
drivers/usb/mtu3/mtu3_hw_regs.h | 473 +++++++++++
drivers/usb/mtu3/mtu3_plat.c | 490 +++++++++++
drivers/usb/mtu3/mtu3_qmu.c | 599 +++++++++++++
drivers/usb/mtu3/mtu3_qmu.h | 43 +
20 files changed, 5598 insertions(+), 18 deletions(-)
create mode 100644 Documentation/devicetree/bindings/usb/mt8173-mtu3.txt
create mode 100644 drivers/usb/mtu3/Kconfig
create mode 100644 drivers/usb/mtu3/Makefile
create mode 100644 drivers/usb/mtu3/mtu3.h
create mode 100644 drivers/usb/mtu3/mtu3_core.c
create mode 100644 drivers/usb/mtu3/mtu3_dr.c
create mode 100644 drivers/usb/mtu3/mtu3_dr.h
create mode 100644 drivers/usb/mtu3/mtu3_gadget.c
create mode 100644 drivers/usb/mtu3/mtu3_gadget_ep0.c
create mode 100644 drivers/usb/mtu3/mtu3_host.c
create mode 100644 drivers/usb/mtu3/mtu3_hw_regs.h
create mode 100644 drivers/usb/mtu3/mtu3_plat.c
create mode 100644 drivers/usb/mtu3/mtu3_qmu.c
create mode 100644 drivers/usb/mtu3/mtu3_qmu.h
^ permalink raw reply
* [PATCH net-next v3 2/2] net: ethernet: mediatek: modify GDM to send packets to the PDMA for RX
From: Nelson Chang @ 2016-08-25 2:26 UTC (permalink / raw)
To: john-Pj+rj9U5foFAfugRpC6u6w, davem-fT/PcQaiUtIeIZ0/mPfg9Q
Cc: netdev-u79uwXL29TY76Z2rM5mHXA, nbd-p3rKhJxN3npAfugRpC6u6w,
linux-mediatek-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r,
nelsonch.tw-Re5JQEeQqe8AvxtiuMwx3w, Nelson Chang
In-Reply-To: <1472091991-1814-1-git-send-email-nelson.chang-NuS5LvNUpcJWk0Htik3J/w@public.gmane.org>
Because we change to use the PDMA as the Ethernet RX DMA engine,
the patch modifies to set GDM to send packets to PDMA for RX.
Signed-off-by: Nelson Chang <nelson.chang-NuS5LvNUpcJWk0Htik3J/w@public.gmane.org>
---
drivers/net/ethernet/mediatek/mtk_eth_soc.c | 4 ++--
drivers/net/ethernet/mediatek/mtk_eth_soc.h | 0
2 files changed, 2 insertions(+), 2 deletions(-)
mode change 100755 => 100644 drivers/net/ethernet/mediatek/mtk_eth_soc.c
mode change 100755 => 100644 drivers/net/ethernet/mediatek/mtk_eth_soc.h
diff --git a/drivers/net/ethernet/mediatek/mtk_eth_soc.c b/drivers/net/ethernet/mediatek/mtk_eth_soc.c
old mode 100755
new mode 100644
index cbeb793..c47fef4
--- a/drivers/net/ethernet/mediatek/mtk_eth_soc.c
+++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.c
@@ -1473,9 +1473,9 @@ static int __init mtk_hw_init(struct mtk_eth *eth)
for (i = 0; i < 2; i++) {
u32 val = mtk_r32(eth, MTK_GDMA_FWD_CFG(i));
- /* setup the forward port to send frame to QDMA */
+ /* setup the forward port to send frame to PDMA */
val &= ~0xffff;
- val |= 0x5555;
+ val |= 0x0000;
/* Enable RX checksum */
val |= MTK_GDMA_ICS_EN | MTK_GDMA_TCS_EN | MTK_GDMA_UCS_EN;
diff --git a/drivers/net/ethernet/mediatek/mtk_eth_soc.h b/drivers/net/ethernet/mediatek/mtk_eth_soc.h
old mode 100755
new mode 100644
--
1.9.1
^ permalink raw reply related
* [PATCH net-next v3 1/2] net: ethernet: mediatek: modify to use the PDMA instead of the QDMA for Ethernet RX
From: Nelson Chang @ 2016-08-25 2:26 UTC (permalink / raw)
To: john-Pj+rj9U5foFAfugRpC6u6w, davem-fT/PcQaiUtIeIZ0/mPfg9Q
Cc: netdev-u79uwXL29TY76Z2rM5mHXA, nbd-p3rKhJxN3npAfugRpC6u6w,
linux-mediatek-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r,
nelsonch.tw-Re5JQEeQqe8AvxtiuMwx3w, Nelson Chang
In-Reply-To: <1472091991-1814-1-git-send-email-nelson.chang-NuS5LvNUpcJWk0Htik3J/w@public.gmane.org>
Because the PDMA has richer features than the QDMA for Ethernet RX
(such as multiple RX rings, HW LRO, etc.),
the patch modifies to use the PDMA to handle Ethernet RX.
Signed-off-by: Nelson Chang <nelson.chang-NuS5LvNUpcJWk0Htik3J/w@public.gmane.org>
---
drivers/net/ethernet/mediatek/mtk_eth_soc.c | 76 +++++++++++++++++------------
drivers/net/ethernet/mediatek/mtk_eth_soc.h | 31 +++++++++++-
2 files changed, 74 insertions(+), 33 deletions(-)
mode change 100644 => 100755 drivers/net/ethernet/mediatek/mtk_eth_soc.c
mode change 100644 => 100755 drivers/net/ethernet/mediatek/mtk_eth_soc.h
diff --git a/drivers/net/ethernet/mediatek/mtk_eth_soc.c b/drivers/net/ethernet/mediatek/mtk_eth_soc.c
old mode 100644
new mode 100755
index 1801fd8..cbeb793
--- a/drivers/net/ethernet/mediatek/mtk_eth_soc.c
+++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.c
@@ -342,25 +342,27 @@ static void mtk_mdio_cleanup(struct mtk_eth *eth)
mdiobus_free(eth->mii_bus);
}
-static inline void mtk_irq_disable(struct mtk_eth *eth, u32 mask)
+static inline void mtk_irq_disable(struct mtk_eth *eth,
+ unsigned reg, u32 mask)
{
unsigned long flags;
u32 val;
spin_lock_irqsave(ð->irq_lock, flags);
- val = mtk_r32(eth, MTK_QDMA_INT_MASK);
- mtk_w32(eth, val & ~mask, MTK_QDMA_INT_MASK);
+ val = mtk_r32(eth, reg);
+ mtk_w32(eth, val & ~mask, reg);
spin_unlock_irqrestore(ð->irq_lock, flags);
}
-static inline void mtk_irq_enable(struct mtk_eth *eth, u32 mask)
+static inline void mtk_irq_enable(struct mtk_eth *eth,
+ unsigned reg, u32 mask)
{
unsigned long flags;
u32 val;
spin_lock_irqsave(ð->irq_lock, flags);
- val = mtk_r32(eth, MTK_QDMA_INT_MASK);
- mtk_w32(eth, val | mask, MTK_QDMA_INT_MASK);
+ val = mtk_r32(eth, reg);
+ mtk_w32(eth, val | mask, reg);
spin_unlock_irqrestore(ð->irq_lock, flags);
}
@@ -897,12 +899,12 @@ release_desc:
* we continue
*/
wmb();
- mtk_w32(eth, ring->calc_idx, MTK_QRX_CRX_IDX0);
+ mtk_w32(eth, ring->calc_idx, MTK_PRX_CRX_IDX0);
done++;
}
if (done < budget)
- mtk_w32(eth, MTK_RX_DONE_INT, MTK_QMTK_INT_STATUS);
+ mtk_w32(eth, MTK_RX_DONE_INT, MTK_PDMA_INT_STATUS);
return done;
}
@@ -1012,7 +1014,7 @@ static int mtk_napi_tx(struct napi_struct *napi, int budget)
return budget;
napi_complete(napi);
- mtk_irq_enable(eth, MTK_TX_DONE_INT);
+ mtk_irq_enable(eth, MTK_QDMA_INT_MASK, MTK_TX_DONE_INT);
return tx_done;
}
@@ -1024,12 +1026,12 @@ static int mtk_napi_rx(struct napi_struct *napi, int budget)
int rx_done = 0;
mtk_handle_status_irq(eth);
- mtk_w32(eth, MTK_RX_DONE_INT, MTK_QMTK_INT_STATUS);
+ mtk_w32(eth, MTK_RX_DONE_INT, MTK_PDMA_INT_STATUS);
rx_done = mtk_poll_rx(napi, budget, eth);
if (unlikely(netif_msg_intr(eth))) {
- status = mtk_r32(eth, MTK_QMTK_INT_STATUS);
- mask = mtk_r32(eth, MTK_QDMA_INT_MASK);
+ status = mtk_r32(eth, MTK_PDMA_INT_STATUS);
+ mask = mtk_r32(eth, MTK_PDMA_INT_MASK);
dev_info(eth->dev,
"done rx %d, intr 0x%08x/0x%x\n",
rx_done, status, mask);
@@ -1038,12 +1040,12 @@ static int mtk_napi_rx(struct napi_struct *napi, int budget)
if (rx_done == budget)
return budget;
- status = mtk_r32(eth, MTK_QMTK_INT_STATUS);
+ status = mtk_r32(eth, MTK_PDMA_INT_STATUS);
if (status & MTK_RX_DONE_INT)
return budget;
napi_complete(napi);
- mtk_irq_enable(eth, MTK_RX_DONE_INT);
+ mtk_irq_enable(eth, MTK_PDMA_INT_MASK, MTK_RX_DONE_INT);
return rx_done;
}
@@ -1092,6 +1094,7 @@ static int mtk_tx_alloc(struct mtk_eth *eth)
mtk_w32(eth,
ring->phys + ((MTK_DMA_SIZE - 1) * sz),
MTK_QTX_DRX_PTR);
+ mtk_w32(eth, (QDMA_RES_THRES << 8) | QDMA_RES_THRES, MTK_QTX_CFG(0));
return 0;
@@ -1162,11 +1165,10 @@ static int mtk_rx_alloc(struct mtk_eth *eth)
*/
wmb();
- mtk_w32(eth, eth->rx_ring.phys, MTK_QRX_BASE_PTR0);
- mtk_w32(eth, MTK_DMA_SIZE, MTK_QRX_MAX_CNT0);
- mtk_w32(eth, eth->rx_ring.calc_idx, MTK_QRX_CRX_IDX0);
- mtk_w32(eth, MTK_PST_DRX_IDX0, MTK_QDMA_RST_IDX);
- mtk_w32(eth, (QDMA_RES_THRES << 8) | QDMA_RES_THRES, MTK_QTX_CFG(0));
+ mtk_w32(eth, eth->rx_ring.phys, MTK_PRX_BASE_PTR0);
+ mtk_w32(eth, MTK_DMA_SIZE, MTK_PRX_MAX_CNT0);
+ mtk_w32(eth, eth->rx_ring.calc_idx, MTK_PRX_CRX_IDX0);
+ mtk_w32(eth, MTK_PST_DRX_IDX0, MTK_PDMA_RST_IDX);
return 0;
}
@@ -1285,7 +1287,7 @@ static irqreturn_t mtk_handle_irq_rx(int irq, void *_eth)
if (likely(napi_schedule_prep(ð->rx_napi))) {
__napi_schedule(ð->rx_napi);
- mtk_irq_disable(eth, MTK_RX_DONE_INT);
+ mtk_irq_disable(eth, MTK_PDMA_INT_MASK, MTK_RX_DONE_INT);
}
return IRQ_HANDLED;
@@ -1297,7 +1299,7 @@ static irqreturn_t mtk_handle_irq_tx(int irq, void *_eth)
if (likely(napi_schedule_prep(ð->tx_napi))) {
__napi_schedule(ð->tx_napi);
- mtk_irq_disable(eth, MTK_TX_DONE_INT);
+ mtk_irq_disable(eth, MTK_QDMA_INT_MASK, MTK_TX_DONE_INT);
}
return IRQ_HANDLED;
@@ -1308,11 +1310,12 @@ static void mtk_poll_controller(struct net_device *dev)
{
struct mtk_mac *mac = netdev_priv(dev);
struct mtk_eth *eth = mac->hw;
- u32 int_mask = MTK_TX_DONE_INT | MTK_RX_DONE_INT;
- mtk_irq_disable(eth, int_mask);
+ mtk_irq_disable(eth, MTK_QDMA_INT_MASK, MTK_TX_DONE_INT);
+ mtk_irq_disable(eth, MTK_PDMA_INT_MASK, MTK_RX_DONE_INT);
mtk_handle_irq_rx(eth->irq[2], dev);
- mtk_irq_enable(eth, int_mask);
+ mtk_irq_enable(eth, MTK_QDMA_INT_MASK, MTK_TX_DONE_INT);
+ mtk_irq_enable(eth, MTK_PDMA_INT_MASK, MTK_RX_DONE_INT);
}
#endif
@@ -1327,11 +1330,15 @@ static int mtk_start_dma(struct mtk_eth *eth)
}
mtk_w32(eth,
- MTK_TX_WB_DDONE | MTK_RX_DMA_EN | MTK_TX_DMA_EN |
- MTK_RX_2B_OFFSET | MTK_DMA_SIZE_16DWORDS |
- MTK_RX_BT_32DWORDS | MTK_NDP_CO_PRO,
+ MTK_TX_WB_DDONE | MTK_TX_DMA_EN |
+ MTK_DMA_SIZE_16DWORDS | MTK_NDP_CO_PRO,
MTK_QDMA_GLO_CFG);
+ mtk_w32(eth,
+ MTK_RX_DMA_EN | MTK_RX_2B_OFFSET |
+ MTK_RX_BT_32DWORDS | MTK_MULTI_EN,
+ MTK_PDMA_GLO_CFG);
+
return 0;
}
@@ -1349,7 +1356,8 @@ static int mtk_open(struct net_device *dev)
napi_enable(ð->tx_napi);
napi_enable(ð->rx_napi);
- mtk_irq_enable(eth, MTK_TX_DONE_INT | MTK_RX_DONE_INT);
+ mtk_irq_enable(eth, MTK_QDMA_INT_MASK, MTK_TX_DONE_INT);
+ mtk_irq_enable(eth, MTK_PDMA_INT_MASK, MTK_RX_DONE_INT);
}
atomic_inc(ð->dma_refcnt);
@@ -1394,7 +1402,8 @@ static int mtk_stop(struct net_device *dev)
if (!atomic_dec_and_test(ð->dma_refcnt))
return 0;
- mtk_irq_disable(eth, MTK_TX_DONE_INT | MTK_RX_DONE_INT);
+ mtk_irq_disable(eth, MTK_QDMA_INT_MASK, MTK_TX_DONE_INT);
+ mtk_irq_disable(eth, MTK_PDMA_INT_MASK, MTK_RX_DONE_INT);
napi_disable(ð->tx_napi);
napi_disable(ð->rx_napi);
@@ -1448,7 +1457,9 @@ static int __init mtk_hw_init(struct mtk_eth *eth)
/* disable delay and normal interrupt */
mtk_w32(eth, 0, MTK_QDMA_DELAY_INT);
- mtk_irq_disable(eth, ~0);
+ mtk_w32(eth, 0, MTK_PDMA_DELAY_INT);
+ mtk_irq_disable(eth, MTK_QDMA_INT_MASK, ~0);
+ mtk_irq_disable(eth, MTK_PDMA_INT_MASK, ~0);
mtk_w32(eth, RST_GL_PSE, MTK_RST_GL);
mtk_w32(eth, 0, MTK_RST_GL);
@@ -1504,7 +1515,8 @@ static void mtk_uninit(struct net_device *dev)
phy_disconnect(mac->phy_dev);
mtk_mdio_cleanup(eth);
- mtk_irq_disable(eth, ~0);
+ mtk_irq_disable(eth, MTK_QDMA_INT_MASK, ~0);
+ mtk_irq_disable(eth, MTK_PDMA_INT_MASK, ~0);
free_irq(eth->irq[1], dev);
free_irq(eth->irq[2], dev);
}
@@ -1683,7 +1695,7 @@ static void mtk_get_ethtool_stats(struct net_device *dev,
}
do {
- data_src = (u64*)hwstats;
+ data_src = (u64 *)hwstats;
data_dst = data;
start = u64_stats_fetch_begin_irq(&hwstats->syncp);
diff --git a/drivers/net/ethernet/mediatek/mtk_eth_soc.h b/drivers/net/ethernet/mediatek/mtk_eth_soc.h
old mode 100644
new mode 100755
index f82e3ac..7c1f3f2
--- a/drivers/net/ethernet/mediatek/mtk_eth_soc.h
+++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.h
@@ -68,6 +68,32 @@
/* Unicast Filter MAC Address Register - High */
#define MTK_GDMA_MAC_ADRH(x) (0x50C + (x * 0x1000))
+/* PDMA RX Base Pointer Register */
+#define MTK_PRX_BASE_PTR0 0x900
+
+/* PDMA RX Maximum Count Register */
+#define MTK_PRX_MAX_CNT0 0x904
+
+/* PDMA RX CPU Pointer Register */
+#define MTK_PRX_CRX_IDX0 0x908
+
+/* PDMA Global Configuration Register */
+#define MTK_PDMA_GLO_CFG 0xa04
+#define MTK_MULTI_EN BIT(10)
+
+/* PDMA Reset Index Register */
+#define MTK_PDMA_RST_IDX 0xa08
+#define MTK_PST_DRX_IDX0 BIT(16)
+
+/* PDMA Delay Interrupt Register */
+#define MTK_PDMA_DELAY_INT 0xa0c
+
+/* PDMA Interrupt Status Register */
+#define MTK_PDMA_INT_STATUS 0xa20
+
+/* PDMA Interrupt Mask Register */
+#define MTK_PDMA_INT_MASK 0xa28
+
/* PDMA Interrupt grouping registers */
#define MTK_PDMA_INT_GRP1 0xa50
#define MTK_PDMA_INT_GRP2 0xa54
@@ -119,13 +145,16 @@
/* QDMA Interrupt Status Register */
#define MTK_QMTK_INT_STATUS 0x1A18
+#define MTK_RX_DONE_INT3 BIT(19)
+#define MTK_RX_DONE_INT2 BIT(18)
#define MTK_RX_DONE_INT1 BIT(17)
#define MTK_RX_DONE_INT0 BIT(16)
#define MTK_TX_DONE_INT3 BIT(3)
#define MTK_TX_DONE_INT2 BIT(2)
#define MTK_TX_DONE_INT1 BIT(1)
#define MTK_TX_DONE_INT0 BIT(0)
-#define MTK_RX_DONE_INT (MTK_RX_DONE_INT0 | MTK_RX_DONE_INT1)
+#define MTK_RX_DONE_INT (MTK_RX_DONE_INT0 | MTK_RX_DONE_INT1 | \
+ MTK_RX_DONE_INT2 | MTK_RX_DONE_INT3)
#define MTK_TX_DONE_INT (MTK_TX_DONE_INT0 | MTK_TX_DONE_INT1 | \
MTK_TX_DONE_INT2 | MTK_TX_DONE_INT3)
--
1.9.1
^ permalink raw reply related
* [PATCH net-next v3 0/2] net: ethernet: mediatek: modify to use the PDMA for Ethernet RX
From: Nelson Chang @ 2016-08-25 2:26 UTC (permalink / raw)
To: john-Pj+rj9U5foFAfugRpC6u6w, davem-fT/PcQaiUtIeIZ0/mPfg9Q
Cc: netdev-u79uwXL29TY76Z2rM5mHXA, nbd-p3rKhJxN3npAfugRpC6u6w,
linux-mediatek-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r,
nelsonch.tw-Re5JQEeQqe8AvxtiuMwx3w, Nelson Chang
This patch set fixes the following issues
v1 -> v2: Fix the bugs of PDMA cpu index and interrupt settings in mtk_poll_rx()
v2 -> v3: Add GDM hardware settings to send packets to PDMA for RX
Nelson Chang (2):
net: ethernet: mediatek: modify to use the PDMA instead of the QDMA
for Ethernet RX
net: ethernet: mediatek: modify GDM to send packets to the PDMA for RX
drivers/net/ethernet/mediatek/mtk_eth_soc.c | 80 +++++++++++++++++------------
drivers/net/ethernet/mediatek/mtk_eth_soc.h | 31 ++++++++++-
2 files changed, 76 insertions(+), 35 deletions(-)
--
1.9.1
^ permalink raw reply
* Re: [PATCH V5, 0/5] Add MediaTek USB3 DRD Driver
From: chunfeng yun @ 2016-08-25 1:40 UTC (permalink / raw)
To: Oliver Neukum
Cc: Mark Rutland, devicetree-u79uwXL29TY76Z2rM5mHXA,
linux-usb-u79uwXL29TY76Z2rM5mHXA, Felipe Balbi, Pawel Moll,
Sergei Shtylyov, Ian Campbell, Greg Kroah-Hartman, Sascha Hauer,
Alan Cooper, linux-kernel-u79uwXL29TY76Z2rM5mHXA, Mathias Nyman,
Rob Herring, linux-mediatek-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r,
Kumar Gala, Matthias Brugger, Alan Stern,
linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r
In-Reply-To: <1472038159.11480.2.camel-IBi9RG/b67k@public.gmane.org>
Hi,
On Wed, 2016-08-24 at 13:29 +0200, Oliver Neukum wrote:
> On Wed, 2016-08-24 at 14:42 +0800, chunfeng yun wrote:
> > Dear all,
> >
> > Could you please help me to review the code?
>
> Is the structure
>
> struct qmu_gpd
>
> shared with the hardware? Do I read this correctly that
> you do PIO to endpoint 0 but DMA to the others?
>
Yes, you are right.
> Could you resend the series?
>
I will do it soon
Thank you.
> Regards
> Oliver
>
>
^ permalink raw reply
* Re: [PATCH v12 2/4] reset: mediatek: Add MT2701 reset driver
From: Stephen Boyd @ 2016-08-24 17:50 UTC (permalink / raw)
To: Erin Lo
Cc: Matthias Brugger, Mike Turquette, Rob Herring, Arnd Bergmann,
Sascha Hauer, Daniel Kurtz, Philipp Zabel, devicetree,
linux-arm-kernel, linux-kernel, linux-mediatek, linux-clk,
srv_heupstream, Shunli Wang, James Liao
In-Reply-To: <1471854565-19810-3-git-send-email-erin.lo@mediatek.com>
On 08/22, Erin Lo wrote:
> diff --git a/drivers/clk/mediatek/clk-mt2701-hif.c b/drivers/clk/mediatek/clk-mt2701-hif.c
> index 18b4ab5..702fd74 100644
> --- a/drivers/clk/mediatek/clk-mt2701-hif.c
> +++ b/drivers/clk/mediatek/clk-mt2701-hif.c
> @@ -52,11 +52,15 @@ static int mtk_hifsys_init(struct device_node *node)
> clk_data);
>
> r = of_clk_add_provider(node, of_clk_src_onecell_get, clk_data);
> - if (r)
> + if (r) {
> pr_err("%s(): could not register clock provider: %d\n",
> __func__, r);
> + return r;
> + }
> +
> + mtk_register_reset_controller(node, 1, 0x34);
The cleanup here isn't great. mtk_register_reset_controller()
should really return an error so that we can properly cleanup if
needed. Fixing that in a later patch would be a good idea.
--
Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum,
a Linux Foundation Collaborative Project
^ permalink raw reply
* Re: [PATCH v12 1/4] clk: mediatek: Add MT2701 clock support
From: Stephen Boyd @ 2016-08-24 17:49 UTC (permalink / raw)
To: Erin Lo
Cc: Rob Herring, Philipp Zabel, Arnd Bergmann,
devicetree-u79uwXL29TY76Z2rM5mHXA, Mike Turquette,
linux-kernel-u79uwXL29TY76Z2rM5mHXA, James Liao,
srv_heupstream-NuS5LvNUpcJWk0Htik3J/w,
linux-mediatek-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r, Shunli Wang,
Sascha Hauer, Matthias Brugger, linux-clk-u79uwXL29TY76Z2rM5mHXA,
linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r
In-Reply-To: <1471854565-19810-2-git-send-email-erin.lo-NuS5LvNUpcJWk0Htik3J/w@public.gmane.org>
On 08/22, Erin Lo wrote:
> +
> +static void __init mtk_infrasys_init_early(struct device_node *node)
> +{
> + int r, i;
> +
> + if (!infra_clk_data) {
> + infra_clk_data = mtk_alloc_clk_data(CLK_INFRA_NR);
> +
> + for (i = 0; i < CLK_INFRA_NR; i++)
> + infra_clk_data->clks[i] = ERR_PTR(-EPROBE_DEFER);
> + }
> +
> + mtk_clk_register_factors(infra_fixed_divs, ARRAY_SIZE(infra_fixed_divs),
> + infra_clk_data);
> +
> + r = of_clk_add_provider(node, of_clk_src_onecell_get, infra_clk_data);
> + if (r)
> + pr_err("%s(): could not register clock provider: %d\n",
> + __func__, r);
> +}
> +CLK_OF_DECLARE(mtk_infra, "mediatek,mt2701-infracfg", mtk_infrasys_init_early);
This should use CLK_OF_DECLARE_DRIVER? Has this been tested on
latest clk-next? Some recent patches make it so that
CLK_OF_DECLARE() prevents platform devices from being created for
the associated DT nodes that match during of_clk_init().
> +
> +static int mtk_infrasys_init(struct device_node *node)
> +{
> + int r, i;
> +
> + if (!infra_clk_data) {
> + infra_clk_data = mtk_alloc_clk_data(CLK_INFRA_NR);
> + } else {
> + for (i = 0; i < CLK_INFRA_NR; i++) {
> + if (infra_clk_data->clks[i] == ERR_PTR(-EPROBE_DEFER))
> + infra_clk_data->clks[i] = ERR_PTR(-ENOENT);
> + }
> + }
> +
> + mtk_clk_register_gates(node, infra_clks, ARRAY_SIZE(infra_clks),
> + infra_clk_data);
> + mtk_clk_register_factors(infra_fixed_divs, ARRAY_SIZE(infra_fixed_divs),
> + infra_clk_data);
> +
> + r = of_clk_add_provider(node, of_clk_src_onecell_get, infra_clk_data);
> + if (r)
> + pr_err("%s(): could not register clock provider: %d\n",
> + __func__, r);
> +
> + return r;
> +}
> +
> +static const struct mtk_gate_regs peri0_cg_regs = {
> + .set_ofs = 0x0008,
> + .clr_ofs = 0x0010,
> + .sta_ofs = 0x0018,
> +};
> +
> +static const struct mtk_gate_regs peri1_cg_regs = {
> + .set_ofs = 0x000c,
> + .clr_ofs = 0x0014,
> + .sta_ofs = 0x001c,
> +};
> +
> +#define GATE_PERI0(_id, _name, _parent, _shift) { \
> + .id = _id, \
> + .name = _name, \
> + .parent_name = _parent, \
> + .regs = &peri0_cg_regs, \
> + .shift = _shift, \
> + .ops = &mtk_clk_gate_ops_setclr, \
> + }
> +
> +#define GATE_PERI1(_id, _name, _parent, _shift) { \
> + .id = _id, \
> + .name = _name, \
> + .parent_name = _parent, \
> + .regs = &peri1_cg_regs, \
> + .shift = _shift, \
> + .ops = &mtk_clk_gate_ops_setclr, \
> + }
> +
> +static const struct mtk_gate peri_clks[] = {
> + GATE_PERI1(CLK_PERI_USB0_MCU, "usb0_mcu_ck", "axi_sel", 31),
> + GATE_PERI1(CLK_PERI_ETH, "eth_ck", "clk26m", 30),
> + GATE_PERI1(CLK_PERI_SPI0, "spi0_ck", "spi0_sel", 29),
> + GATE_PERI1(CLK_PERI_AUXADC, "auxadc_ck", "clk26m", 28),
> + GATE_PERI0(CLK_PERI_I2C3, "i2c3_ck", "clk26m", 27),
> + GATE_PERI0(CLK_PERI_I2C2, "i2c2_ck", "axi_sel", 26),
> + GATE_PERI0(CLK_PERI_I2C1, "i2c1_ck", "axi_sel", 25),
> + GATE_PERI0(CLK_PERI_I2C0, "i2c0_ck", "axi_sel", 24),
> + GATE_PERI0(CLK_PERI_BTIF, "bitif_ck", "axi_sel", 23),
> + GATE_PERI0(CLK_PERI_UART3, "uart3_ck", "axi_sel", 22),
> + GATE_PERI0(CLK_PERI_UART2, "uart2_ck", "axi_sel", 21),
> + GATE_PERI0(CLK_PERI_UART1, "uart1_ck", "axi_sel", 20),
> + GATE_PERI0(CLK_PERI_UART0, "uart0_ck", "axi_sel", 19),
> + GATE_PERI0(CLK_PERI_NLI, "nli_ck", "axi_sel", 18),
> + GATE_PERI0(CLK_PERI_MSDC50_3, "msdc50_3_ck", "emmc_hclk_sel", 17),
> + GATE_PERI0(CLK_PERI_MSDC30_3, "msdc30_3_ck", "msdc30_3_sel", 16),
> + GATE_PERI0(CLK_PERI_MSDC30_2, "msdc30_2_ck", "msdc30_2_sel", 15),
> + GATE_PERI0(CLK_PERI_MSDC30_1, "msdc30_1_ck", "msdc30_1_sel", 14),
> + GATE_PERI0(CLK_PERI_MSDC30_0, "msdc30_0_ck", "msdc30_0_sel", 13),
> + GATE_PERI0(CLK_PERI_AP_DMA, "ap_dma_ck", "axi_sel", 12),
> + GATE_PERI0(CLK_PERI_USB1, "usb1_ck", "usb20_sel", 11),
> + GATE_PERI0(CLK_PERI_USB0, "usb0_ck", "usb20_sel", 10),
> + GATE_PERI0(CLK_PERI_PWM, "pwm_ck", "axi_sel", 9),
> + GATE_PERI0(CLK_PERI_PWM7, "pwm7_ck", "axi_sel", 8),
> + GATE_PERI0(CLK_PERI_PWM6, "pwm6_ck", "axi_sel", 7),
> + GATE_PERI0(CLK_PERI_PWM5, "pwm5_ck", "axi_sel", 6),
> + GATE_PERI0(CLK_PERI_PWM4, "pwm4_ck", "axi_sel", 5),
> + GATE_PERI0(CLK_PERI_PWM3, "pwm3_ck", "axi_sel", 4),
> + GATE_PERI0(CLK_PERI_PWM2, "pwm2_ck", "axi_sel", 3),
> + GATE_PERI0(CLK_PERI_PWM1, "pwm1_ck", "axi_sel", 2),
> + GATE_PERI0(CLK_PERI_THERM, "therm_ck", "axi_sel", 1),
> + GATE_PERI0(CLK_PERI_NFI, "nfi_ck", "nfi2x_sel", 0),
> +
> + GATE_PERI1(CLK_PERI_FCI, "fci_ck", "ms_card_sel", 11),
> + GATE_PERI1(CLK_PERI_SPI2, "spi2_ck", "spi2_sel", 10),
> + GATE_PERI1(CLK_PERI_SPI1, "spi1_ck", "spi1_sel", 9),
> + GATE_PERI1(CLK_PERI_HOST89_DVD, "host89_dvd_ck", "aud2dvd_sel", 8),
> + GATE_PERI1(CLK_PERI_HOST89_SPI, "host89_spi_ck", "spi0_sel", 7),
> + GATE_PERI1(CLK_PERI_HOST89_INT, "host89_int_ck", "axi_sel", 6),
> + GATE_PERI1(CLK_PERI_FLASH, "flash_ck", "nfi2x_sel", 5),
> + GATE_PERI1(CLK_PERI_NFI_PAD, "nfi_pad_ck", "nfi1x_pad", 4),
> + GATE_PERI1(CLK_PERI_NFI_ECC, "nfi_ecc_ck", "nfi1x_pad", 3),
> + GATE_PERI1(CLK_PERI_GCPU, "gcpu_ck", "axi_sel", 2),
> + GATE_PERI1(CLK_PERI_USB_SLV, "usbslv_ck", "axi_sel", 1),
> + GATE_PERI1(CLK_PERI_USB1_MCU, "usb1_mcu_ck", "axi_sel", 0),
> +};
> +
> +static const char * const uart_ck_sel_parents[] = {
> + "clk26m",
> + "uart_sel",
> +};
> +
> +static const struct mtk_composite peri_muxs[] = {
> + MUX(CLK_PERI_UART0_SEL, "uart0_ck_sel", uart_ck_sel_parents,
> + 0x40c, 0, 1),
> + MUX(CLK_PERI_UART1_SEL, "uart1_ck_sel", uart_ck_sel_parents,
> + 0x40c, 1, 1),
> + MUX(CLK_PERI_UART2_SEL, "uart2_ck_sel", uart_ck_sel_parents,
> + 0x40c, 2, 1),
> + MUX(CLK_PERI_UART3_SEL, "uart3_ck_sel", uart_ck_sel_parents,
> + 0x40c, 3, 1),
> +};
> +
> +static int mtk_pericfg_init(struct device_node *node)
> +{
> + struct clk_onecell_data *clk_data;
> + void __iomem *base;
> + int r;
> +
> + base = of_iomap(node, 0);
> + if (!base) {
> + pr_err("%s(): ioremap failed\n", __func__);
Please pass the device structure to these callbacks so that we
can use standard devm_ioremap() type APIs like normal platform
drivers.
> + return -ENOMEM;
> + }
> +
> + clk_data = mtk_alloc_clk_data(CLK_PERI_NR);
> +
> + mtk_clk_register_gates(node, peri_clks, ARRAY_SIZE(peri_clks),
> + clk_data);
> +
> + mtk_clk_register_composites(peri_muxs, ARRAY_SIZE(peri_muxs), base,
> + &lock, clk_data);
> +
> + r = of_clk_add_provider(node, of_clk_src_onecell_get, clk_data);
> + if (r)
> + pr_err("%s(): could not register clock provider: %d\n",
> + __func__, r);
> +
> + return r;
> +}
> +
> +#define MT8590_PLL_FMAX (2000 * MHZ)
> +#define CON0_MT8590_RST_BAR BIT(27)
> +
> +#define PLL(_id, _name, _reg, _pwr_reg, _en_mask, _flags, _pcwbits, _pd_reg, \
> + _pd_shift, _tuner_reg, _pcw_reg, _pcw_shift) { \
> + .id = _id, \
> + .name = _name, \
> + .reg = _reg, \
> + .pwr_reg = _pwr_reg, \
> + .en_mask = _en_mask, \
> + .flags = _flags, \
> + .rst_bar_mask = CON0_MT8590_RST_BAR, \
> + .fmax = MT8590_PLL_FMAX, \
> + .pcwbits = _pcwbits, \
> + .pd_reg = _pd_reg, \
> + .pd_shift = _pd_shift, \
> + .tuner_reg = _tuner_reg, \
> + .pcw_reg = _pcw_reg, \
> + .pcw_shift = _pcw_shift, \
> + }
> +
> +static const struct mtk_pll_data apmixed_plls[] = {
> + PLL(CLK_APMIXED_ARMPLL, "armpll", 0x200, 0x20c, 0x80000001,
> + PLL_AO, 21, 0x204, 24, 0x0, 0x204, 0),
> + PLL(CLK_APMIXED_MAINPLL, "mainpll", 0x210, 0x21c, 0xf0000001,
> + HAVE_RST_BAR, 21, 0x210, 4, 0x0, 0x214, 0),
> + PLL(CLK_APMIXED_UNIVPLL, "univpll", 0x220, 0x22c, 0xf3000001,
> + HAVE_RST_BAR, 7, 0x220, 4, 0x0, 0x224, 14),
> + PLL(CLK_APMIXED_MMPLL, "mmpll", 0x230, 0x23c, 0x00000001, 0,
> + 21, 0x230, 4, 0x0, 0x234, 0),
> + PLL(CLK_APMIXED_MSDCPLL, "msdcpll", 0x240, 0x24c, 0x00000001, 0,
> + 21, 0x240, 4, 0x0, 0x244, 0),
> + PLL(CLK_APMIXED_TVDPLL, "tvdpll", 0x250, 0x25c, 0x00000001, 0,
> + 21, 0x250, 4, 0x0, 0x254, 0),
> + PLL(CLK_APMIXED_AUD1PLL, "aud1pll", 0x270, 0x27c, 0x00000001, 0,
> + 31, 0x270, 4, 0x0, 0x274, 0),
> + PLL(CLK_APMIXED_TRGPLL, "trgpll", 0x280, 0x28c, 0x00000001, 0,
> + 31, 0x280, 4, 0x0, 0x284, 0),
> + PLL(CLK_APMIXED_ETHPLL, "ethpll", 0x290, 0x29c, 0x00000001, 0,
> + 31, 0x290, 4, 0x0, 0x294, 0),
> + PLL(CLK_APMIXED_VDECPLL, "vdecpll", 0x2a0, 0x2ac, 0x00000001, 0,
> + 31, 0x2a0, 4, 0x0, 0x2a4, 0),
> + PLL(CLK_APMIXED_HADDS2PLL, "hadds2pll", 0x2b0, 0x2bc, 0x00000001, 0,
> + 31, 0x2b0, 4, 0x0, 0x2b4, 0),
> + PLL(CLK_APMIXED_AUD2PLL, "aud2pll", 0x2c0, 0x2cc, 0x00000001, 0,
> + 31, 0x2c0, 4, 0x0, 0x2c4, 0),
> + PLL(CLK_APMIXED_TVD2PLL, "tvd2pll", 0x2d0, 0x2dc, 0x00000001, 0,
> + 21, 0x2d0, 4, 0x0, 0x2d4, 0),
> +};
> +
> +static int mtk_apmixedsys_init(struct device_node *node)
> +{
> + struct clk_onecell_data *clk_data;
> + int r;
> +
> + clk_data = mtk_alloc_clk_data(CLK_APMIXED_NR);
> + if (!clk_data)
> + return -ENOMEM;
> +
> + mtk_clk_register_plls(node, apmixed_plls, ARRAY_SIZE(apmixed_plls),
> + clk_data);
> +
> + r = of_clk_add_provider(node, of_clk_src_onecell_get, clk_data);
> + if (r)
> + pr_err("%s(): could not register clock provider: %d\n",
> + __func__, r);
These three lines could be moved to the caller so taht we don't
duplicate the same logic over and over.
> +
> + return r;
> +}
> +
> +static const struct of_device_id of_match_clk_mt2701[] = {
> + {
> + .compatible = "mediatek,mt2701-topckgen",
> + .data = mtk_topckgen_init,
> + }, {
> + .compatible = "mediatek,mt2701-infracfg",
> + .data = mtk_infrasys_init,
> + }, {
> + .compatible = "mediatek,mt2701-pericfg",
> + .data = mtk_pericfg_init,
> + }, {
> + .compatible = "mediatek,mt2701-apmixedsys",
> + .data = mtk_apmixedsys_init,
> + }, {
> + /* sentinel */
> + }
> +};
> +
> +static int clk_mt2701_probe(struct platform_device *pdev)
> +{
> + int (*clk_init)(struct device_node *);
> + const struct of_device_id *of_id;
> +
> + pr_warn("%s():%d: %s\n", __func__, __LINE__, pdev->name);
> +
> + of_id = of_match_node(of_match_clk_mt2701, pdev->dev.of_node);
> + if (!of_id || !of_id->data)
> + return -EINVAL;
This can be
clk_init = of_device_get_match_data(of_match_clk_mt2701, &pdev->dev);
if (!clk_init)
return -EINVAL;
> +
> + clk_init = of_id->data;
> + return clk_init(pdev->dev.of_node);
> +}
> +
> +static struct platform_driver clk_mt2701_drv = {
> + .probe = clk_mt2701_probe,
> + .driver = {
> + .name = "clk-mt2701",
> + .owner = THIS_MODULE,
> + .of_match_table = of_match_clk_mt2701,
> + },
> +};
> +
> +static int __init clk_mt2701_init(void)
> +{
> + return platform_driver_register(&clk_mt2701_drv);
> +}
> +
> +arch_initcall(clk_mt2701_init);
> diff --git a/drivers/clk/mediatek/clk-mtk.c b/drivers/clk/mediatek/clk-mtk.c
> index bb30f70..6a015a8 100644
> --- a/drivers/clk/mediatek/clk-mtk.c
> +++ b/drivers/clk/mediatek/clk-mtk.c
> @@ -58,6 +58,9 @@ void mtk_clk_register_fixed_clks(const struct mtk_fixed_clk *clks,
> for (i = 0; i < num; i++) {
> const struct mtk_fixed_clk *rc = &clks[i];
>
> + if (!IS_ERR_OR_NULL(clk_data->clks[rc->id]))
> + continue;
> +
> clk = clk_register_fixed_rate(NULL, rc->name, rc->parent, 0,
> rc->rate);
>
> @@ -81,6 +84,9 @@ void mtk_clk_register_factors(const struct mtk_fixed_factor *clks,
> for (i = 0; i < num; i++) {
> const struct mtk_fixed_factor *ff = &clks[i];
>
> + if (!IS_ERR_OR_NULL(clk_data->clks[ff->id]))
> + continue;
> +
> clk = clk_register_fixed_factor(NULL, ff->name, ff->parent_name,
> CLK_SET_RATE_PARENT, ff->mult, ff->div);
>
> @@ -116,6 +122,9 @@ int mtk_clk_register_gates(struct device_node *node,
> for (i = 0; i < num; i++) {
> const struct mtk_gate *gate = &clks[i];
>
> + if (!IS_ERR_OR_NULL(clk_data->clks[gate->id]))
> + continue;
> +
> clk = mtk_clk_register_gate(gate->name, gate->parent_name,
> regmap,
> gate->regs->set_ofs,
> @@ -232,6 +241,9 @@ void mtk_clk_register_composites(const struct mtk_composite *mcs,
> for (i = 0; i < num; i++) {
> const struct mtk_composite *mc = &mcs[i];
>
> + if (!IS_ERR_OR_NULL(clk_data->clks[mc->id]))
> + continue;
> +
> clk = mtk_clk_register_composite(mc, base, lock);
>
> if (IS_ERR(clk)) {
> @@ -244,3 +256,31 @@ void mtk_clk_register_composites(const struct mtk_composite *mcs,
> clk_data->clks[mc->id] = clk;
> }
> }
> +
> +void mtk_clk_register_dividers(const struct mtk_clk_divider *mcds,
> + int num, void __iomem *base, spinlock_t *lock,
> + struct clk_onecell_data *clk_data)
> +{
> + struct clk *clk;
> + int i;
> +
> + for (i = 0; i < num; i++) {
> + const struct mtk_clk_divider *mcd = &mcds[i];
> +
> + if (!IS_ERR_OR_NULL(clk_data->clks[mcd->id]))
This dereferences clk_data...
> + continue;
> +
> + clk = clk_register_divider(NULL, mcd->name, mcd->parent_name,
> + mcd->flags, base + mcd->div_reg, mcd->div_shift,
> + mcd->div_width, mcd->clk_divider_flags, lock);
> +
> + if (IS_ERR(clk)) {
> + pr_err("Failed to register clk %s: %ld\n",
> + mcd->name, PTR_ERR(clk));
> + continue;
> + }
> +
> + if (clk_data)
And then we check it for NULL here? That doesn't make any sense.
> + clk_data->clks[mcd->id] = clk;
> + }
> +}
--
Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum,
a Linux Foundation Collaborative Project
^ permalink raw reply
* Re: [PATCH net-next] net: ethernet: mediatek: modify to use the PDMA instead of the QDMA for Ethernet RX
From: John Crispin @ 2016-08-24 13:57 UTC (permalink / raw)
To: Nelson Chang (張家祥), davem@davemloft.net
Cc: netdev@vger.kernel.org, Felix Fietkau,
linux-mediatek@lists.infradead.org, nelsonch.tw@gmail.com,
Sean Wang (王志亘),
Steven Liu (劉人豪),
Carlos Huang (黃士彰)
In-Reply-To: <6133E9B12438EA40B35401C719F0B99B0118AF8846@mtkmbs01n1>
On 24/08/2016 15:39, Nelson Chang (張家祥) wrote:
> Hi John,
>
> The QDMA only has one RX and is without HW LRO feature. The HW QoS is QDMA's
> TX feature with multiple TX rings.
> The Mediatek Ethernet hardware added the features of HW LRO and multiple RX
> rings started from MT7623, but they are only add in the PDMA, not in the
> QDMA.
> So we would like to modify to use PDMA for RX to add the features of HW LRO
> and multiple RX ring in the future.
in general there is nothing to prevent this change but my understanding
was that QDMA HWLRO was broken on mt7621, which is why we used 2 DMA
engines on that SoC and that it was fixed on MT7623.
when i wrote this driver a specific requirement from MTK/WCN was to have
TX and RX QDMA. if this requirement has changed then fine. please do
confirm though that you really want PDMA for RX.
John
> Thanks.
>
>
> BRs,
> Nelson
> -----Original Message-----
> From: John Crispin [mailto:john@phrozen.org]
> Sent: Wednesday, August 24, 2016 8:58 PM
> To: Nelson Chang (張家祥); davem@davemloft.net
> Cc: netdev@vger.kernel.org; Felix Fietkau;
> linux-mediatek@lists.infradead.org; nelsonch.tw@gmail.com; Sean Wang
> (王志亘); Steven Liu (劉人豪); Carlos Huang (黃士彰)
> Subject: Re: [PATCH net-next] net: ethernet: mediatek: modify to use the
> PDMA instead of the QDMA for Ethernet RX
>
>
>
> On 24/08/2016 14:49, Nelson Chang wrote:
>> Because the PDMA has richer features than the QDMA for Ethernet RX
>> (such as multiple RX rings, HW LRO, etc.), the patch modifies to use
>> the PDMA to handle Ethernet RX.
>
> Hi,
>
> QDMA support is needed for the HW QoS to work. QDMA also has HW_LRO support
> you just need to port the additional code from the MTK SDK to make it work.
> additionally QDMA has more than 1 internal ring/queue that you can use, you
> would need to change the RX ring to be a linked list and enable that
> feature as is already done in the RX path.
>
> although the patch is technically not wrong i am not sure if it makes sense
> and the description is for certain not correct. could it be that you are
> basing your assumption on some old SDK ethernet driver ? newer version have
> the described features for the new QDMA engine supported if i am not
> mistaken.
>
> John
>
>>
>> Signed-off-by: Nelson Chang <nelson.chang@mediatek.com>
>> ---
>> drivers/net/ethernet/mediatek/mtk_eth_soc.c | 72
>> +++++++++++++++++------------
>> drivers/net/ethernet/mediatek/mtk_eth_soc.h | 31 ++++++++++++-
>> 2 files changed, 72 insertions(+), 31 deletions(-) mode change
>> 100644 => 100755 drivers/net/ethernet/mediatek/mtk_eth_soc.c
>> mode change 100644 => 100755
>> drivers/net/ethernet/mediatek/mtk_eth_soc.h
>>
>> diff --git a/drivers/net/ethernet/mediatek/mtk_eth_soc.c
>> b/drivers/net/ethernet/mediatek/mtk_eth_soc.c
>> old mode 100644
>> new mode 100755
>> index 1801fd8..27a9156
>> --- a/drivers/net/ethernet/mediatek/mtk_eth_soc.c
>> +++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.c
>> @@ -342,25 +342,27 @@ static void mtk_mdio_cleanup(struct mtk_eth *eth)
>> mdiobus_free(eth->mii_bus);
>> }
>>
>> -static inline void mtk_irq_disable(struct mtk_eth *eth, u32 mask)
>> +static inline void mtk_irq_disable(struct mtk_eth *eth,
>> + unsigned reg, u32 mask)
>> {
>> unsigned long flags;
>> u32 val;
>>
>> spin_lock_irqsave(ð->irq_lock, flags);
>> - val = mtk_r32(eth, MTK_QDMA_INT_MASK);
>> - mtk_w32(eth, val & ~mask, MTK_QDMA_INT_MASK);
>> + val = mtk_r32(eth, reg);
>> + mtk_w32(eth, val & ~mask, reg);
>> spin_unlock_irqrestore(ð->irq_lock, flags); }
>>
>> -static inline void mtk_irq_enable(struct mtk_eth *eth, u32 mask)
>> +static inline void mtk_irq_enable(struct mtk_eth *eth,
>> + unsigned reg, u32 mask)
>> {
>> unsigned long flags;
>> u32 val;
>>
>> spin_lock_irqsave(ð->irq_lock, flags);
>> - val = mtk_r32(eth, MTK_QDMA_INT_MASK);
>> - mtk_w32(eth, val | mask, MTK_QDMA_INT_MASK);
>> + val = mtk_r32(eth, reg);
>> + mtk_w32(eth, val | mask, reg);
>> spin_unlock_irqrestore(ð->irq_lock, flags); }
>>
>> @@ -1012,7 +1014,7 @@ static int mtk_napi_tx(struct napi_struct *napi, int
> budget)
>> return budget;
>>
>> napi_complete(napi);
>> - mtk_irq_enable(eth, MTK_TX_DONE_INT);
>> + mtk_irq_enable(eth, MTK_QDMA_INT_MASK, MTK_TX_DONE_INT);
>>
>> return tx_done;
>> }
>> @@ -1024,12 +1026,12 @@ static int mtk_napi_rx(struct napi_struct *napi,
> int budget)
>> int rx_done = 0;
>>
>> mtk_handle_status_irq(eth);
>> - mtk_w32(eth, MTK_RX_DONE_INT, MTK_QMTK_INT_STATUS);
>> + mtk_w32(eth, MTK_RX_DONE_INT, MTK_PDMA_INT_STATUS);
>> rx_done = mtk_poll_rx(napi, budget, eth);
>>
>> if (unlikely(netif_msg_intr(eth))) {
>> - status = mtk_r32(eth, MTK_QMTK_INT_STATUS);
>> - mask = mtk_r32(eth, MTK_QDMA_INT_MASK);
>> + status = mtk_r32(eth, MTK_PDMA_INT_STATUS);
>> + mask = mtk_r32(eth, MTK_PDMA_INT_MASK);
>> dev_info(eth->dev,
>> "done rx %d, intr 0x%08x/0x%x\n",
>> rx_done, status, mask);
>> @@ -1038,12 +1040,12 @@ static int mtk_napi_rx(struct napi_struct *napi,
> int budget)
>> if (rx_done == budget)
>> return budget;
>>
>> - status = mtk_r32(eth, MTK_QMTK_INT_STATUS);
>> + status = mtk_r32(eth, MTK_PDMA_INT_STATUS);
>> if (status & MTK_RX_DONE_INT)
>> return budget;
>>
>> napi_complete(napi);
>> - mtk_irq_enable(eth, MTK_RX_DONE_INT);
>> + mtk_irq_enable(eth, MTK_PDMA_INT_MASK, MTK_RX_DONE_INT);
>>
>> return rx_done;
>> }
>> @@ -1092,6 +1094,7 @@ static int mtk_tx_alloc(struct mtk_eth *eth)
>> mtk_w32(eth,
>> ring->phys + ((MTK_DMA_SIZE - 1) * sz),
>> MTK_QTX_DRX_PTR);
>> + mtk_w32(eth, (QDMA_RES_THRES << 8) | QDMA_RES_THRES,
>> +MTK_QTX_CFG(0));
>>
>> return 0;
>>
>> @@ -1162,11 +1165,10 @@ static int mtk_rx_alloc(struct mtk_eth *eth)
>> */
>> wmb();
>>
>> - mtk_w32(eth, eth->rx_ring.phys, MTK_QRX_BASE_PTR0);
>> - mtk_w32(eth, MTK_DMA_SIZE, MTK_QRX_MAX_CNT0);
>> - mtk_w32(eth, eth->rx_ring.calc_idx, MTK_QRX_CRX_IDX0);
>> - mtk_w32(eth, MTK_PST_DRX_IDX0, MTK_QDMA_RST_IDX);
>> - mtk_w32(eth, (QDMA_RES_THRES << 8) | QDMA_RES_THRES, MTK_QTX_CFG(0));
>> + mtk_w32(eth, eth->rx_ring.phys, MTK_PRX_BASE_PTR0);
>> + mtk_w32(eth, MTK_DMA_SIZE, MTK_PRX_MAX_CNT0);
>> + mtk_w32(eth, eth->rx_ring.calc_idx, MTK_PRX_CRX_IDX0);
>> + mtk_w32(eth, MTK_PST_DRX_IDX0, MTK_PDMA_RST_IDX);
>>
>> return 0;
>> }
>> @@ -1285,7 +1287,7 @@ static irqreturn_t mtk_handle_irq_rx(int irq,
>> void *_eth)
>>
>> if (likely(napi_schedule_prep(ð->rx_napi))) {
>> __napi_schedule(ð->rx_napi);
>> - mtk_irq_disable(eth, MTK_RX_DONE_INT);
>> + mtk_irq_disable(eth, MTK_PDMA_INT_MASK, MTK_RX_DONE_INT);
>> }
>>
>> return IRQ_HANDLED;
>> @@ -1297,7 +1299,7 @@ static irqreturn_t mtk_handle_irq_tx(int irq,
>> void *_eth)
>>
>> if (likely(napi_schedule_prep(ð->tx_napi))) {
>> __napi_schedule(ð->tx_napi);
>> - mtk_irq_disable(eth, MTK_TX_DONE_INT);
>> + mtk_irq_disable(eth, MTK_QDMA_INT_MASK, MTK_TX_DONE_INT);
>> }
>>
>> return IRQ_HANDLED;
>> @@ -1308,11 +1310,12 @@ static void mtk_poll_controller(struct
>> net_device *dev) {
>> struct mtk_mac *mac = netdev_priv(dev);
>> struct mtk_eth *eth = mac->hw;
>> - u32 int_mask = MTK_TX_DONE_INT | MTK_RX_DONE_INT;
>>
>> - mtk_irq_disable(eth, int_mask);
>> + mtk_irq_disable(eth, MTK_QDMA_INT_MASK, MTK_TX_DONE_INT);
>> + mtk_irq_disable(eth, MTK_PDMA_INT_MASK, MTK_RX_DONE_INT);
>> mtk_handle_irq_rx(eth->irq[2], dev);
>> - mtk_irq_enable(eth, int_mask);
>> + mtk_irq_enable(eth, MTK_QDMA_INT_MASK, MTK_TX_DONE_INT);
>> + mtk_irq_enable(eth, MTK_PDMA_INT_MASK, MTK_RX_DONE_INT);
>> }
>> #endif
>>
>> @@ -1327,11 +1330,15 @@ static int mtk_start_dma(struct mtk_eth *eth)
>> }
>>
>> mtk_w32(eth,
>> - MTK_TX_WB_DDONE | MTK_RX_DMA_EN | MTK_TX_DMA_EN |
>> - MTK_RX_2B_OFFSET | MTK_DMA_SIZE_16DWORDS |
>> - MTK_RX_BT_32DWORDS | MTK_NDP_CO_PRO,
>> + MTK_TX_WB_DDONE | MTK_TX_DMA_EN |
>> + MTK_DMA_SIZE_16DWORDS | MTK_NDP_CO_PRO,
>> MTK_QDMA_GLO_CFG);
>>
>> + mtk_w32(eth,
>> + MTK_RX_DMA_EN | MTK_RX_2B_OFFSET |
>> + MTK_RX_BT_32DWORDS | MTK_MULTI_EN,
>> + MTK_PDMA_GLO_CFG);
>> +
>> return 0;
>> }
>>
>> @@ -1349,7 +1356,8 @@ static int mtk_open(struct net_device *dev)
>>
>> napi_enable(ð->tx_napi);
>> napi_enable(ð->rx_napi);
>> - mtk_irq_enable(eth, MTK_TX_DONE_INT | MTK_RX_DONE_INT);
>> + mtk_irq_enable(eth, MTK_QDMA_INT_MASK, MTK_TX_DONE_INT);
>> + mtk_irq_enable(eth, MTK_PDMA_INT_MASK, MTK_RX_DONE_INT);
>> }
>> atomic_inc(ð->dma_refcnt);
>>
>> @@ -1394,7 +1402,8 @@ static int mtk_stop(struct net_device *dev)
>> if (!atomic_dec_and_test(ð->dma_refcnt))
>> return 0;
>>
>> - mtk_irq_disable(eth, MTK_TX_DONE_INT | MTK_RX_DONE_INT);
>> + mtk_irq_disable(eth, MTK_QDMA_INT_MASK, MTK_TX_DONE_INT);
>> + mtk_irq_disable(eth, MTK_PDMA_INT_MASK, MTK_RX_DONE_INT);
>> napi_disable(ð->tx_napi);
>> napi_disable(ð->rx_napi);
>>
>> @@ -1448,7 +1457,9 @@ static int __init mtk_hw_init(struct mtk_eth
>> *eth)
>>
>> /* disable delay and normal interrupt */
>> mtk_w32(eth, 0, MTK_QDMA_DELAY_INT);
>> - mtk_irq_disable(eth, ~0);
>> + mtk_w32(eth, 0, MTK_PDMA_DELAY_INT);
>> + mtk_irq_disable(eth, MTK_QDMA_INT_MASK, ~0);
>> + mtk_irq_disable(eth, MTK_PDMA_INT_MASK, ~0);
>> mtk_w32(eth, RST_GL_PSE, MTK_RST_GL);
>> mtk_w32(eth, 0, MTK_RST_GL);
>>
>> @@ -1504,7 +1515,8 @@ static void mtk_uninit(struct net_device *dev)
>>
>> phy_disconnect(mac->phy_dev);
>> mtk_mdio_cleanup(eth);
>> - mtk_irq_disable(eth, ~0);
>> + mtk_irq_disable(eth, MTK_QDMA_INT_MASK, ~0);
>> + mtk_irq_disable(eth, MTK_PDMA_INT_MASK, ~0);
>> free_irq(eth->irq[1], dev);
>> free_irq(eth->irq[2], dev);
>> }
>> @@ -1683,7 +1695,7 @@ static void mtk_get_ethtool_stats(struct net_device
> *dev,
>> }
>>
>> do {
>> - data_src = (u64*)hwstats;
>> + data_src = (u64 *)hwstats;
>> data_dst = data;
>> start = u64_stats_fetch_begin_irq(&hwstats->syncp);
>>
>> diff --git a/drivers/net/ethernet/mediatek/mtk_eth_soc.h
>> b/drivers/net/ethernet/mediatek/mtk_eth_soc.h
>> old mode 100644
>> new mode 100755
>> index f82e3ac..7c1f3f2
>> --- a/drivers/net/ethernet/mediatek/mtk_eth_soc.h
>> +++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.h
>> @@ -68,6 +68,32 @@
>> /* Unicast Filter MAC Address Register - High */
>> #define MTK_GDMA_MAC_ADRH(x) (0x50C + (x * 0x1000))
>>
>> +/* PDMA RX Base Pointer Register */
>> +#define MTK_PRX_BASE_PTR0 0x900
>> +
>> +/* PDMA RX Maximum Count Register */
>> +#define MTK_PRX_MAX_CNT0 0x904
>> +
>> +/* PDMA RX CPU Pointer Register */
>> +#define MTK_PRX_CRX_IDX0 0x908
>> +
>> +/* PDMA Global Configuration Register */
>> +#define MTK_PDMA_GLO_CFG 0xa04
>> +#define MTK_MULTI_EN BIT(10)
>> +
>> +/* PDMA Reset Index Register */
>> +#define MTK_PDMA_RST_IDX 0xa08
>> +#define MTK_PST_DRX_IDX0 BIT(16)
>> +
>> +/* PDMA Delay Interrupt Register */
>> +#define MTK_PDMA_DELAY_INT 0xa0c
>> +
>> +/* PDMA Interrupt Status Register */
>> +#define MTK_PDMA_INT_STATUS 0xa20
>> +
>> +/* PDMA Interrupt Mask Register */
>> +#define MTK_PDMA_INT_MASK 0xa28
>> +
>> /* PDMA Interrupt grouping registers */
>> #define MTK_PDMA_INT_GRP1 0xa50
>> #define MTK_PDMA_INT_GRP2 0xa54
>> @@ -119,13 +145,16 @@
>>
>> /* QDMA Interrupt Status Register */
>> #define MTK_QMTK_INT_STATUS 0x1A18
>> +#define MTK_RX_DONE_INT3 BIT(19)
>> +#define MTK_RX_DONE_INT2 BIT(18)
>> #define MTK_RX_DONE_INT1 BIT(17)
>> #define MTK_RX_DONE_INT0 BIT(16)
>> #define MTK_TX_DONE_INT3 BIT(3)
>> #define MTK_TX_DONE_INT2 BIT(2)
>> #define MTK_TX_DONE_INT1 BIT(1)
>> #define MTK_TX_DONE_INT0 BIT(0)
>> -#define MTK_RX_DONE_INT (MTK_RX_DONE_INT0 | MTK_RX_DONE_INT1)
>> +#define MTK_RX_DONE_INT (MTK_RX_DONE_INT0 | MTK_RX_DONE_INT1 | \
>> + MTK_RX_DONE_INT2 | MTK_RX_DONE_INT3)
>> #define MTK_TX_DONE_INT (MTK_TX_DONE_INT0 | MTK_TX_DONE_INT1 | \
>> MTK_TX_DONE_INT2 | MTK_TX_DONE_INT3)
>>
>>
>
^ permalink raw reply
* Re: [PATCH net-next v2] net: ethernet: mediatek: modify to use the PDMA instead of the QDMA for Ethernet RX
From: John Crispin @ 2016-08-24 13:39 UTC (permalink / raw)
To: Nelson Chang, davem; +Cc: netdev, nbd, linux-mediatek, nelsonch.tw
In-Reply-To: <1472045073-22703-1-git-send-email-nelson.chang@mediatek.com>
On 24/08/2016 15:24, Nelson Chang wrote:
> Because the PDMA has richer features than the QDMA for Ethernet RX
> (such as multiple RX rings, HW LRO, etc.),
> the patch modifies to use the PDMA to handle Ethernet RX.
>
> Signed-off-by: Nelson Chang <nelson.chang@mediatek.com>
> ---
there should be a chunk here telling us what the difference between V1
and V2 is.
John
> drivers/net/ethernet/mediatek/mtk_eth_soc.c | 76 +++++++++++++++++------------
> drivers/net/ethernet/mediatek/mtk_eth_soc.h | 31 +++++++++++-
> 2 files changed, 74 insertions(+), 33 deletions(-)
> mode change 100644 => 100755 drivers/net/ethernet/mediatek/mtk_eth_soc.c
> mode change 100644 => 100755 drivers/net/ethernet/mediatek/mtk_eth_soc.h
>
> diff --git a/drivers/net/ethernet/mediatek/mtk_eth_soc.c b/drivers/net/ethernet/mediatek/mtk_eth_soc.c
> old mode 100644
> new mode 100755
> index 1801fd8..cbeb793
> --- a/drivers/net/ethernet/mediatek/mtk_eth_soc.c
> +++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.c
> @@ -342,25 +342,27 @@ static void mtk_mdio_cleanup(struct mtk_eth *eth)
> mdiobus_free(eth->mii_bus);
> }
>
> -static inline void mtk_irq_disable(struct mtk_eth *eth, u32 mask)
> +static inline void mtk_irq_disable(struct mtk_eth *eth,
> + unsigned reg, u32 mask)
> {
> unsigned long flags;
> u32 val;
>
> spin_lock_irqsave(ð->irq_lock, flags);
> - val = mtk_r32(eth, MTK_QDMA_INT_MASK);
> - mtk_w32(eth, val & ~mask, MTK_QDMA_INT_MASK);
> + val = mtk_r32(eth, reg);
> + mtk_w32(eth, val & ~mask, reg);
> spin_unlock_irqrestore(ð->irq_lock, flags);
> }
>
> -static inline void mtk_irq_enable(struct mtk_eth *eth, u32 mask)
> +static inline void mtk_irq_enable(struct mtk_eth *eth,
> + unsigned reg, u32 mask)
> {
> unsigned long flags;
> u32 val;
>
> spin_lock_irqsave(ð->irq_lock, flags);
> - val = mtk_r32(eth, MTK_QDMA_INT_MASK);
> - mtk_w32(eth, val | mask, MTK_QDMA_INT_MASK);
> + val = mtk_r32(eth, reg);
> + mtk_w32(eth, val | mask, reg);
> spin_unlock_irqrestore(ð->irq_lock, flags);
> }
>
> @@ -897,12 +899,12 @@ release_desc:
> * we continue
> */
> wmb();
> - mtk_w32(eth, ring->calc_idx, MTK_QRX_CRX_IDX0);
> + mtk_w32(eth, ring->calc_idx, MTK_PRX_CRX_IDX0);
> done++;
> }
>
> if (done < budget)
> - mtk_w32(eth, MTK_RX_DONE_INT, MTK_QMTK_INT_STATUS);
> + mtk_w32(eth, MTK_RX_DONE_INT, MTK_PDMA_INT_STATUS);
>
> return done;
> }
> @@ -1012,7 +1014,7 @@ static int mtk_napi_tx(struct napi_struct *napi, int budget)
> return budget;
>
> napi_complete(napi);
> - mtk_irq_enable(eth, MTK_TX_DONE_INT);
> + mtk_irq_enable(eth, MTK_QDMA_INT_MASK, MTK_TX_DONE_INT);
>
> return tx_done;
> }
> @@ -1024,12 +1026,12 @@ static int mtk_napi_rx(struct napi_struct *napi, int budget)
> int rx_done = 0;
>
> mtk_handle_status_irq(eth);
> - mtk_w32(eth, MTK_RX_DONE_INT, MTK_QMTK_INT_STATUS);
> + mtk_w32(eth, MTK_RX_DONE_INT, MTK_PDMA_INT_STATUS);
> rx_done = mtk_poll_rx(napi, budget, eth);
>
> if (unlikely(netif_msg_intr(eth))) {
> - status = mtk_r32(eth, MTK_QMTK_INT_STATUS);
> - mask = mtk_r32(eth, MTK_QDMA_INT_MASK);
> + status = mtk_r32(eth, MTK_PDMA_INT_STATUS);
> + mask = mtk_r32(eth, MTK_PDMA_INT_MASK);
> dev_info(eth->dev,
> "done rx %d, intr 0x%08x/0x%x\n",
> rx_done, status, mask);
> @@ -1038,12 +1040,12 @@ static int mtk_napi_rx(struct napi_struct *napi, int budget)
> if (rx_done == budget)
> return budget;
>
> - status = mtk_r32(eth, MTK_QMTK_INT_STATUS);
> + status = mtk_r32(eth, MTK_PDMA_INT_STATUS);
> if (status & MTK_RX_DONE_INT)
> return budget;
>
> napi_complete(napi);
> - mtk_irq_enable(eth, MTK_RX_DONE_INT);
> + mtk_irq_enable(eth, MTK_PDMA_INT_MASK, MTK_RX_DONE_INT);
>
> return rx_done;
> }
> @@ -1092,6 +1094,7 @@ static int mtk_tx_alloc(struct mtk_eth *eth)
> mtk_w32(eth,
> ring->phys + ((MTK_DMA_SIZE - 1) * sz),
> MTK_QTX_DRX_PTR);
> + mtk_w32(eth, (QDMA_RES_THRES << 8) | QDMA_RES_THRES, MTK_QTX_CFG(0));
>
> return 0;
>
> @@ -1162,11 +1165,10 @@ static int mtk_rx_alloc(struct mtk_eth *eth)
> */
> wmb();
>
> - mtk_w32(eth, eth->rx_ring.phys, MTK_QRX_BASE_PTR0);
> - mtk_w32(eth, MTK_DMA_SIZE, MTK_QRX_MAX_CNT0);
> - mtk_w32(eth, eth->rx_ring.calc_idx, MTK_QRX_CRX_IDX0);
> - mtk_w32(eth, MTK_PST_DRX_IDX0, MTK_QDMA_RST_IDX);
> - mtk_w32(eth, (QDMA_RES_THRES << 8) | QDMA_RES_THRES, MTK_QTX_CFG(0));
> + mtk_w32(eth, eth->rx_ring.phys, MTK_PRX_BASE_PTR0);
> + mtk_w32(eth, MTK_DMA_SIZE, MTK_PRX_MAX_CNT0);
> + mtk_w32(eth, eth->rx_ring.calc_idx, MTK_PRX_CRX_IDX0);
> + mtk_w32(eth, MTK_PST_DRX_IDX0, MTK_PDMA_RST_IDX);
>
> return 0;
> }
> @@ -1285,7 +1287,7 @@ static irqreturn_t mtk_handle_irq_rx(int irq, void *_eth)
>
> if (likely(napi_schedule_prep(ð->rx_napi))) {
> __napi_schedule(ð->rx_napi);
> - mtk_irq_disable(eth, MTK_RX_DONE_INT);
> + mtk_irq_disable(eth, MTK_PDMA_INT_MASK, MTK_RX_DONE_INT);
> }
>
> return IRQ_HANDLED;
> @@ -1297,7 +1299,7 @@ static irqreturn_t mtk_handle_irq_tx(int irq, void *_eth)
>
> if (likely(napi_schedule_prep(ð->tx_napi))) {
> __napi_schedule(ð->tx_napi);
> - mtk_irq_disable(eth, MTK_TX_DONE_INT);
> + mtk_irq_disable(eth, MTK_QDMA_INT_MASK, MTK_TX_DONE_INT);
> }
>
> return IRQ_HANDLED;
> @@ -1308,11 +1310,12 @@ static void mtk_poll_controller(struct net_device *dev)
> {
> struct mtk_mac *mac = netdev_priv(dev);
> struct mtk_eth *eth = mac->hw;
> - u32 int_mask = MTK_TX_DONE_INT | MTK_RX_DONE_INT;
>
> - mtk_irq_disable(eth, int_mask);
> + mtk_irq_disable(eth, MTK_QDMA_INT_MASK, MTK_TX_DONE_INT);
> + mtk_irq_disable(eth, MTK_PDMA_INT_MASK, MTK_RX_DONE_INT);
> mtk_handle_irq_rx(eth->irq[2], dev);
> - mtk_irq_enable(eth, int_mask);
> + mtk_irq_enable(eth, MTK_QDMA_INT_MASK, MTK_TX_DONE_INT);
> + mtk_irq_enable(eth, MTK_PDMA_INT_MASK, MTK_RX_DONE_INT);
> }
> #endif
>
> @@ -1327,11 +1330,15 @@ static int mtk_start_dma(struct mtk_eth *eth)
> }
>
> mtk_w32(eth,
> - MTK_TX_WB_DDONE | MTK_RX_DMA_EN | MTK_TX_DMA_EN |
> - MTK_RX_2B_OFFSET | MTK_DMA_SIZE_16DWORDS |
> - MTK_RX_BT_32DWORDS | MTK_NDP_CO_PRO,
> + MTK_TX_WB_DDONE | MTK_TX_DMA_EN |
> + MTK_DMA_SIZE_16DWORDS | MTK_NDP_CO_PRO,
> MTK_QDMA_GLO_CFG);
>
> + mtk_w32(eth,
> + MTK_RX_DMA_EN | MTK_RX_2B_OFFSET |
> + MTK_RX_BT_32DWORDS | MTK_MULTI_EN,
> + MTK_PDMA_GLO_CFG);
> +
> return 0;
> }
>
> @@ -1349,7 +1356,8 @@ static int mtk_open(struct net_device *dev)
>
> napi_enable(ð->tx_napi);
> napi_enable(ð->rx_napi);
> - mtk_irq_enable(eth, MTK_TX_DONE_INT | MTK_RX_DONE_INT);
> + mtk_irq_enable(eth, MTK_QDMA_INT_MASK, MTK_TX_DONE_INT);
> + mtk_irq_enable(eth, MTK_PDMA_INT_MASK, MTK_RX_DONE_INT);
> }
> atomic_inc(ð->dma_refcnt);
>
> @@ -1394,7 +1402,8 @@ static int mtk_stop(struct net_device *dev)
> if (!atomic_dec_and_test(ð->dma_refcnt))
> return 0;
>
> - mtk_irq_disable(eth, MTK_TX_DONE_INT | MTK_RX_DONE_INT);
> + mtk_irq_disable(eth, MTK_QDMA_INT_MASK, MTK_TX_DONE_INT);
> + mtk_irq_disable(eth, MTK_PDMA_INT_MASK, MTK_RX_DONE_INT);
> napi_disable(ð->tx_napi);
> napi_disable(ð->rx_napi);
>
> @@ -1448,7 +1457,9 @@ static int __init mtk_hw_init(struct mtk_eth *eth)
>
> /* disable delay and normal interrupt */
> mtk_w32(eth, 0, MTK_QDMA_DELAY_INT);
> - mtk_irq_disable(eth, ~0);
> + mtk_w32(eth, 0, MTK_PDMA_DELAY_INT);
> + mtk_irq_disable(eth, MTK_QDMA_INT_MASK, ~0);
> + mtk_irq_disable(eth, MTK_PDMA_INT_MASK, ~0);
> mtk_w32(eth, RST_GL_PSE, MTK_RST_GL);
> mtk_w32(eth, 0, MTK_RST_GL);
>
> @@ -1504,7 +1515,8 @@ static void mtk_uninit(struct net_device *dev)
>
> phy_disconnect(mac->phy_dev);
> mtk_mdio_cleanup(eth);
> - mtk_irq_disable(eth, ~0);
> + mtk_irq_disable(eth, MTK_QDMA_INT_MASK, ~0);
> + mtk_irq_disable(eth, MTK_PDMA_INT_MASK, ~0);
> free_irq(eth->irq[1], dev);
> free_irq(eth->irq[2], dev);
> }
> @@ -1683,7 +1695,7 @@ static void mtk_get_ethtool_stats(struct net_device *dev,
> }
>
> do {
> - data_src = (u64*)hwstats;
> + data_src = (u64 *)hwstats;
> data_dst = data;
> start = u64_stats_fetch_begin_irq(&hwstats->syncp);
>
> diff --git a/drivers/net/ethernet/mediatek/mtk_eth_soc.h b/drivers/net/ethernet/mediatek/mtk_eth_soc.h
> old mode 100644
> new mode 100755
> index f82e3ac..7c1f3f2
> --- a/drivers/net/ethernet/mediatek/mtk_eth_soc.h
> +++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.h
> @@ -68,6 +68,32 @@
> /* Unicast Filter MAC Address Register - High */
> #define MTK_GDMA_MAC_ADRH(x) (0x50C + (x * 0x1000))
>
> +/* PDMA RX Base Pointer Register */
> +#define MTK_PRX_BASE_PTR0 0x900
> +
> +/* PDMA RX Maximum Count Register */
> +#define MTK_PRX_MAX_CNT0 0x904
> +
> +/* PDMA RX CPU Pointer Register */
> +#define MTK_PRX_CRX_IDX0 0x908
> +
> +/* PDMA Global Configuration Register */
> +#define MTK_PDMA_GLO_CFG 0xa04
> +#define MTK_MULTI_EN BIT(10)
> +
> +/* PDMA Reset Index Register */
> +#define MTK_PDMA_RST_IDX 0xa08
> +#define MTK_PST_DRX_IDX0 BIT(16)
> +
> +/* PDMA Delay Interrupt Register */
> +#define MTK_PDMA_DELAY_INT 0xa0c
> +
> +/* PDMA Interrupt Status Register */
> +#define MTK_PDMA_INT_STATUS 0xa20
> +
> +/* PDMA Interrupt Mask Register */
> +#define MTK_PDMA_INT_MASK 0xa28
> +
> /* PDMA Interrupt grouping registers */
> #define MTK_PDMA_INT_GRP1 0xa50
> #define MTK_PDMA_INT_GRP2 0xa54
> @@ -119,13 +145,16 @@
>
> /* QDMA Interrupt Status Register */
> #define MTK_QMTK_INT_STATUS 0x1A18
> +#define MTK_RX_DONE_INT3 BIT(19)
> +#define MTK_RX_DONE_INT2 BIT(18)
> #define MTK_RX_DONE_INT1 BIT(17)
> #define MTK_RX_DONE_INT0 BIT(16)
> #define MTK_TX_DONE_INT3 BIT(3)
> #define MTK_TX_DONE_INT2 BIT(2)
> #define MTK_TX_DONE_INT1 BIT(1)
> #define MTK_TX_DONE_INT0 BIT(0)
> -#define MTK_RX_DONE_INT (MTK_RX_DONE_INT0 | MTK_RX_DONE_INT1)
> +#define MTK_RX_DONE_INT (MTK_RX_DONE_INT0 | MTK_RX_DONE_INT1 | \
> + MTK_RX_DONE_INT2 | MTK_RX_DONE_INT3)
> #define MTK_TX_DONE_INT (MTK_TX_DONE_INT0 | MTK_TX_DONE_INT1 | \
> MTK_TX_DONE_INT2 | MTK_TX_DONE_INT3)
>
>
^ permalink raw reply
* [PATCH net-next v2] net: ethernet: mediatek: modify to use the PDMA instead of the QDMA for Ethernet RX
From: Nelson Chang @ 2016-08-24 13:24 UTC (permalink / raw)
To: john, davem; +Cc: nbd, netdev, linux-mediatek, nelsonch.tw, Nelson Chang
Because the PDMA has richer features than the QDMA for Ethernet RX
(such as multiple RX rings, HW LRO, etc.),
the patch modifies to use the PDMA to handle Ethernet RX.
Signed-off-by: Nelson Chang <nelson.chang@mediatek.com>
---
drivers/net/ethernet/mediatek/mtk_eth_soc.c | 76 +++++++++++++++++------------
drivers/net/ethernet/mediatek/mtk_eth_soc.h | 31 +++++++++++-
2 files changed, 74 insertions(+), 33 deletions(-)
mode change 100644 => 100755 drivers/net/ethernet/mediatek/mtk_eth_soc.c
mode change 100644 => 100755 drivers/net/ethernet/mediatek/mtk_eth_soc.h
diff --git a/drivers/net/ethernet/mediatek/mtk_eth_soc.c b/drivers/net/ethernet/mediatek/mtk_eth_soc.c
old mode 100644
new mode 100755
index 1801fd8..cbeb793
--- a/drivers/net/ethernet/mediatek/mtk_eth_soc.c
+++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.c
@@ -342,25 +342,27 @@ static void mtk_mdio_cleanup(struct mtk_eth *eth)
mdiobus_free(eth->mii_bus);
}
-static inline void mtk_irq_disable(struct mtk_eth *eth, u32 mask)
+static inline void mtk_irq_disable(struct mtk_eth *eth,
+ unsigned reg, u32 mask)
{
unsigned long flags;
u32 val;
spin_lock_irqsave(ð->irq_lock, flags);
- val = mtk_r32(eth, MTK_QDMA_INT_MASK);
- mtk_w32(eth, val & ~mask, MTK_QDMA_INT_MASK);
+ val = mtk_r32(eth, reg);
+ mtk_w32(eth, val & ~mask, reg);
spin_unlock_irqrestore(ð->irq_lock, flags);
}
-static inline void mtk_irq_enable(struct mtk_eth *eth, u32 mask)
+static inline void mtk_irq_enable(struct mtk_eth *eth,
+ unsigned reg, u32 mask)
{
unsigned long flags;
u32 val;
spin_lock_irqsave(ð->irq_lock, flags);
- val = mtk_r32(eth, MTK_QDMA_INT_MASK);
- mtk_w32(eth, val | mask, MTK_QDMA_INT_MASK);
+ val = mtk_r32(eth, reg);
+ mtk_w32(eth, val | mask, reg);
spin_unlock_irqrestore(ð->irq_lock, flags);
}
@@ -897,12 +899,12 @@ release_desc:
* we continue
*/
wmb();
- mtk_w32(eth, ring->calc_idx, MTK_QRX_CRX_IDX0);
+ mtk_w32(eth, ring->calc_idx, MTK_PRX_CRX_IDX0);
done++;
}
if (done < budget)
- mtk_w32(eth, MTK_RX_DONE_INT, MTK_QMTK_INT_STATUS);
+ mtk_w32(eth, MTK_RX_DONE_INT, MTK_PDMA_INT_STATUS);
return done;
}
@@ -1012,7 +1014,7 @@ static int mtk_napi_tx(struct napi_struct *napi, int budget)
return budget;
napi_complete(napi);
- mtk_irq_enable(eth, MTK_TX_DONE_INT);
+ mtk_irq_enable(eth, MTK_QDMA_INT_MASK, MTK_TX_DONE_INT);
return tx_done;
}
@@ -1024,12 +1026,12 @@ static int mtk_napi_rx(struct napi_struct *napi, int budget)
int rx_done = 0;
mtk_handle_status_irq(eth);
- mtk_w32(eth, MTK_RX_DONE_INT, MTK_QMTK_INT_STATUS);
+ mtk_w32(eth, MTK_RX_DONE_INT, MTK_PDMA_INT_STATUS);
rx_done = mtk_poll_rx(napi, budget, eth);
if (unlikely(netif_msg_intr(eth))) {
- status = mtk_r32(eth, MTK_QMTK_INT_STATUS);
- mask = mtk_r32(eth, MTK_QDMA_INT_MASK);
+ status = mtk_r32(eth, MTK_PDMA_INT_STATUS);
+ mask = mtk_r32(eth, MTK_PDMA_INT_MASK);
dev_info(eth->dev,
"done rx %d, intr 0x%08x/0x%x\n",
rx_done, status, mask);
@@ -1038,12 +1040,12 @@ static int mtk_napi_rx(struct napi_struct *napi, int budget)
if (rx_done == budget)
return budget;
- status = mtk_r32(eth, MTK_QMTK_INT_STATUS);
+ status = mtk_r32(eth, MTK_PDMA_INT_STATUS);
if (status & MTK_RX_DONE_INT)
return budget;
napi_complete(napi);
- mtk_irq_enable(eth, MTK_RX_DONE_INT);
+ mtk_irq_enable(eth, MTK_PDMA_INT_MASK, MTK_RX_DONE_INT);
return rx_done;
}
@@ -1092,6 +1094,7 @@ static int mtk_tx_alloc(struct mtk_eth *eth)
mtk_w32(eth,
ring->phys + ((MTK_DMA_SIZE - 1) * sz),
MTK_QTX_DRX_PTR);
+ mtk_w32(eth, (QDMA_RES_THRES << 8) | QDMA_RES_THRES, MTK_QTX_CFG(0));
return 0;
@@ -1162,11 +1165,10 @@ static int mtk_rx_alloc(struct mtk_eth *eth)
*/
wmb();
- mtk_w32(eth, eth->rx_ring.phys, MTK_QRX_BASE_PTR0);
- mtk_w32(eth, MTK_DMA_SIZE, MTK_QRX_MAX_CNT0);
- mtk_w32(eth, eth->rx_ring.calc_idx, MTK_QRX_CRX_IDX0);
- mtk_w32(eth, MTK_PST_DRX_IDX0, MTK_QDMA_RST_IDX);
- mtk_w32(eth, (QDMA_RES_THRES << 8) | QDMA_RES_THRES, MTK_QTX_CFG(0));
+ mtk_w32(eth, eth->rx_ring.phys, MTK_PRX_BASE_PTR0);
+ mtk_w32(eth, MTK_DMA_SIZE, MTK_PRX_MAX_CNT0);
+ mtk_w32(eth, eth->rx_ring.calc_idx, MTK_PRX_CRX_IDX0);
+ mtk_w32(eth, MTK_PST_DRX_IDX0, MTK_PDMA_RST_IDX);
return 0;
}
@@ -1285,7 +1287,7 @@ static irqreturn_t mtk_handle_irq_rx(int irq, void *_eth)
if (likely(napi_schedule_prep(ð->rx_napi))) {
__napi_schedule(ð->rx_napi);
- mtk_irq_disable(eth, MTK_RX_DONE_INT);
+ mtk_irq_disable(eth, MTK_PDMA_INT_MASK, MTK_RX_DONE_INT);
}
return IRQ_HANDLED;
@@ -1297,7 +1299,7 @@ static irqreturn_t mtk_handle_irq_tx(int irq, void *_eth)
if (likely(napi_schedule_prep(ð->tx_napi))) {
__napi_schedule(ð->tx_napi);
- mtk_irq_disable(eth, MTK_TX_DONE_INT);
+ mtk_irq_disable(eth, MTK_QDMA_INT_MASK, MTK_TX_DONE_INT);
}
return IRQ_HANDLED;
@@ -1308,11 +1310,12 @@ static void mtk_poll_controller(struct net_device *dev)
{
struct mtk_mac *mac = netdev_priv(dev);
struct mtk_eth *eth = mac->hw;
- u32 int_mask = MTK_TX_DONE_INT | MTK_RX_DONE_INT;
- mtk_irq_disable(eth, int_mask);
+ mtk_irq_disable(eth, MTK_QDMA_INT_MASK, MTK_TX_DONE_INT);
+ mtk_irq_disable(eth, MTK_PDMA_INT_MASK, MTK_RX_DONE_INT);
mtk_handle_irq_rx(eth->irq[2], dev);
- mtk_irq_enable(eth, int_mask);
+ mtk_irq_enable(eth, MTK_QDMA_INT_MASK, MTK_TX_DONE_INT);
+ mtk_irq_enable(eth, MTK_PDMA_INT_MASK, MTK_RX_DONE_INT);
}
#endif
@@ -1327,11 +1330,15 @@ static int mtk_start_dma(struct mtk_eth *eth)
}
mtk_w32(eth,
- MTK_TX_WB_DDONE | MTK_RX_DMA_EN | MTK_TX_DMA_EN |
- MTK_RX_2B_OFFSET | MTK_DMA_SIZE_16DWORDS |
- MTK_RX_BT_32DWORDS | MTK_NDP_CO_PRO,
+ MTK_TX_WB_DDONE | MTK_TX_DMA_EN |
+ MTK_DMA_SIZE_16DWORDS | MTK_NDP_CO_PRO,
MTK_QDMA_GLO_CFG);
+ mtk_w32(eth,
+ MTK_RX_DMA_EN | MTK_RX_2B_OFFSET |
+ MTK_RX_BT_32DWORDS | MTK_MULTI_EN,
+ MTK_PDMA_GLO_CFG);
+
return 0;
}
@@ -1349,7 +1356,8 @@ static int mtk_open(struct net_device *dev)
napi_enable(ð->tx_napi);
napi_enable(ð->rx_napi);
- mtk_irq_enable(eth, MTK_TX_DONE_INT | MTK_RX_DONE_INT);
+ mtk_irq_enable(eth, MTK_QDMA_INT_MASK, MTK_TX_DONE_INT);
+ mtk_irq_enable(eth, MTK_PDMA_INT_MASK, MTK_RX_DONE_INT);
}
atomic_inc(ð->dma_refcnt);
@@ -1394,7 +1402,8 @@ static int mtk_stop(struct net_device *dev)
if (!atomic_dec_and_test(ð->dma_refcnt))
return 0;
- mtk_irq_disable(eth, MTK_TX_DONE_INT | MTK_RX_DONE_INT);
+ mtk_irq_disable(eth, MTK_QDMA_INT_MASK, MTK_TX_DONE_INT);
+ mtk_irq_disable(eth, MTK_PDMA_INT_MASK, MTK_RX_DONE_INT);
napi_disable(ð->tx_napi);
napi_disable(ð->rx_napi);
@@ -1448,7 +1457,9 @@ static int __init mtk_hw_init(struct mtk_eth *eth)
/* disable delay and normal interrupt */
mtk_w32(eth, 0, MTK_QDMA_DELAY_INT);
- mtk_irq_disable(eth, ~0);
+ mtk_w32(eth, 0, MTK_PDMA_DELAY_INT);
+ mtk_irq_disable(eth, MTK_QDMA_INT_MASK, ~0);
+ mtk_irq_disable(eth, MTK_PDMA_INT_MASK, ~0);
mtk_w32(eth, RST_GL_PSE, MTK_RST_GL);
mtk_w32(eth, 0, MTK_RST_GL);
@@ -1504,7 +1515,8 @@ static void mtk_uninit(struct net_device *dev)
phy_disconnect(mac->phy_dev);
mtk_mdio_cleanup(eth);
- mtk_irq_disable(eth, ~0);
+ mtk_irq_disable(eth, MTK_QDMA_INT_MASK, ~0);
+ mtk_irq_disable(eth, MTK_PDMA_INT_MASK, ~0);
free_irq(eth->irq[1], dev);
free_irq(eth->irq[2], dev);
}
@@ -1683,7 +1695,7 @@ static void mtk_get_ethtool_stats(struct net_device *dev,
}
do {
- data_src = (u64*)hwstats;
+ data_src = (u64 *)hwstats;
data_dst = data;
start = u64_stats_fetch_begin_irq(&hwstats->syncp);
diff --git a/drivers/net/ethernet/mediatek/mtk_eth_soc.h b/drivers/net/ethernet/mediatek/mtk_eth_soc.h
old mode 100644
new mode 100755
index f82e3ac..7c1f3f2
--- a/drivers/net/ethernet/mediatek/mtk_eth_soc.h
+++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.h
@@ -68,6 +68,32 @@
/* Unicast Filter MAC Address Register - High */
#define MTK_GDMA_MAC_ADRH(x) (0x50C + (x * 0x1000))
+/* PDMA RX Base Pointer Register */
+#define MTK_PRX_BASE_PTR0 0x900
+
+/* PDMA RX Maximum Count Register */
+#define MTK_PRX_MAX_CNT0 0x904
+
+/* PDMA RX CPU Pointer Register */
+#define MTK_PRX_CRX_IDX0 0x908
+
+/* PDMA Global Configuration Register */
+#define MTK_PDMA_GLO_CFG 0xa04
+#define MTK_MULTI_EN BIT(10)
+
+/* PDMA Reset Index Register */
+#define MTK_PDMA_RST_IDX 0xa08
+#define MTK_PST_DRX_IDX0 BIT(16)
+
+/* PDMA Delay Interrupt Register */
+#define MTK_PDMA_DELAY_INT 0xa0c
+
+/* PDMA Interrupt Status Register */
+#define MTK_PDMA_INT_STATUS 0xa20
+
+/* PDMA Interrupt Mask Register */
+#define MTK_PDMA_INT_MASK 0xa28
+
/* PDMA Interrupt grouping registers */
#define MTK_PDMA_INT_GRP1 0xa50
#define MTK_PDMA_INT_GRP2 0xa54
@@ -119,13 +145,16 @@
/* QDMA Interrupt Status Register */
#define MTK_QMTK_INT_STATUS 0x1A18
+#define MTK_RX_DONE_INT3 BIT(19)
+#define MTK_RX_DONE_INT2 BIT(18)
#define MTK_RX_DONE_INT1 BIT(17)
#define MTK_RX_DONE_INT0 BIT(16)
#define MTK_TX_DONE_INT3 BIT(3)
#define MTK_TX_DONE_INT2 BIT(2)
#define MTK_TX_DONE_INT1 BIT(1)
#define MTK_TX_DONE_INT0 BIT(0)
-#define MTK_RX_DONE_INT (MTK_RX_DONE_INT0 | MTK_RX_DONE_INT1)
+#define MTK_RX_DONE_INT (MTK_RX_DONE_INT0 | MTK_RX_DONE_INT1 | \
+ MTK_RX_DONE_INT2 | MTK_RX_DONE_INT3)
#define MTK_TX_DONE_INT (MTK_TX_DONE_INT0 | MTK_TX_DONE_INT1 | \
MTK_TX_DONE_INT2 | MTK_TX_DONE_INT3)
--
1.9.1
^ permalink raw reply related
* Re: [PATCH net-next] net: ethernet: mediatek: modify to use the PDMA instead of the QDMA for Ethernet RX
From: John Crispin @ 2016-08-24 12:58 UTC (permalink / raw)
To: Nelson Chang, davem
Cc: netdev, Felix Fietkau, linux-mediatek, nelsonch.tw,
Sean Wang (王志亘),
Steven Liu (劉人豪),
Carlos Huang (黃士彰)
In-Reply-To: <1472042992-911-1-git-send-email-nelson.chang@mediatek.com>
On 24/08/2016 14:49, Nelson Chang wrote:
> Because the PDMA has richer features than the QDMA for Ethernet RX
> (such as multiple RX rings, HW LRO, etc.),
> the patch modifies to use the PDMA to handle Ethernet RX.
Hi,
QDMA support is needed for the HW QoS to work. QDMA also has HW_LRO
support you just need to port the additional code from the MTK SDK to
make it work. additionally QDMA has more than 1 internal ring/queue that
you can use, you would need to change the RX ring to be a linked list
and enable that feature as is already done in the RX path.
although the patch is technically not wrong i am not sure if it makes
sense and the description is for certain not correct. could it be that
you are basing your assumption on some old SDK ethernet driver ? newer
version have the described features for the new QDMA engine supported if
i am not mistaken.
John
>
> Signed-off-by: Nelson Chang <nelson.chang@mediatek.com>
> ---
> drivers/net/ethernet/mediatek/mtk_eth_soc.c | 72 +++++++++++++++++------------
> drivers/net/ethernet/mediatek/mtk_eth_soc.h | 31 ++++++++++++-
> 2 files changed, 72 insertions(+), 31 deletions(-)
> mode change 100644 => 100755 drivers/net/ethernet/mediatek/mtk_eth_soc.c
> mode change 100644 => 100755 drivers/net/ethernet/mediatek/mtk_eth_soc.h
>
> diff --git a/drivers/net/ethernet/mediatek/mtk_eth_soc.c b/drivers/net/ethernet/mediatek/mtk_eth_soc.c
> old mode 100644
> new mode 100755
> index 1801fd8..27a9156
> --- a/drivers/net/ethernet/mediatek/mtk_eth_soc.c
> +++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.c
> @@ -342,25 +342,27 @@ static void mtk_mdio_cleanup(struct mtk_eth *eth)
> mdiobus_free(eth->mii_bus);
> }
>
> -static inline void mtk_irq_disable(struct mtk_eth *eth, u32 mask)
> +static inline void mtk_irq_disable(struct mtk_eth *eth,
> + unsigned reg, u32 mask)
> {
> unsigned long flags;
> u32 val;
>
> spin_lock_irqsave(ð->irq_lock, flags);
> - val = mtk_r32(eth, MTK_QDMA_INT_MASK);
> - mtk_w32(eth, val & ~mask, MTK_QDMA_INT_MASK);
> + val = mtk_r32(eth, reg);
> + mtk_w32(eth, val & ~mask, reg);
> spin_unlock_irqrestore(ð->irq_lock, flags);
> }
>
> -static inline void mtk_irq_enable(struct mtk_eth *eth, u32 mask)
> +static inline void mtk_irq_enable(struct mtk_eth *eth,
> + unsigned reg, u32 mask)
> {
> unsigned long flags;
> u32 val;
>
> spin_lock_irqsave(ð->irq_lock, flags);
> - val = mtk_r32(eth, MTK_QDMA_INT_MASK);
> - mtk_w32(eth, val | mask, MTK_QDMA_INT_MASK);
> + val = mtk_r32(eth, reg);
> + mtk_w32(eth, val | mask, reg);
> spin_unlock_irqrestore(ð->irq_lock, flags);
> }
>
> @@ -1012,7 +1014,7 @@ static int mtk_napi_tx(struct napi_struct *napi, int budget)
> return budget;
>
> napi_complete(napi);
> - mtk_irq_enable(eth, MTK_TX_DONE_INT);
> + mtk_irq_enable(eth, MTK_QDMA_INT_MASK, MTK_TX_DONE_INT);
>
> return tx_done;
> }
> @@ -1024,12 +1026,12 @@ static int mtk_napi_rx(struct napi_struct *napi, int budget)
> int rx_done = 0;
>
> mtk_handle_status_irq(eth);
> - mtk_w32(eth, MTK_RX_DONE_INT, MTK_QMTK_INT_STATUS);
> + mtk_w32(eth, MTK_RX_DONE_INT, MTK_PDMA_INT_STATUS);
> rx_done = mtk_poll_rx(napi, budget, eth);
>
> if (unlikely(netif_msg_intr(eth))) {
> - status = mtk_r32(eth, MTK_QMTK_INT_STATUS);
> - mask = mtk_r32(eth, MTK_QDMA_INT_MASK);
> + status = mtk_r32(eth, MTK_PDMA_INT_STATUS);
> + mask = mtk_r32(eth, MTK_PDMA_INT_MASK);
> dev_info(eth->dev,
> "done rx %d, intr 0x%08x/0x%x\n",
> rx_done, status, mask);
> @@ -1038,12 +1040,12 @@ static int mtk_napi_rx(struct napi_struct *napi, int budget)
> if (rx_done == budget)
> return budget;
>
> - status = mtk_r32(eth, MTK_QMTK_INT_STATUS);
> + status = mtk_r32(eth, MTK_PDMA_INT_STATUS);
> if (status & MTK_RX_DONE_INT)
> return budget;
>
> napi_complete(napi);
> - mtk_irq_enable(eth, MTK_RX_DONE_INT);
> + mtk_irq_enable(eth, MTK_PDMA_INT_MASK, MTK_RX_DONE_INT);
>
> return rx_done;
> }
> @@ -1092,6 +1094,7 @@ static int mtk_tx_alloc(struct mtk_eth *eth)
> mtk_w32(eth,
> ring->phys + ((MTK_DMA_SIZE - 1) * sz),
> MTK_QTX_DRX_PTR);
> + mtk_w32(eth, (QDMA_RES_THRES << 8) | QDMA_RES_THRES, MTK_QTX_CFG(0));
>
> return 0;
>
> @@ -1162,11 +1165,10 @@ static int mtk_rx_alloc(struct mtk_eth *eth)
> */
> wmb();
>
> - mtk_w32(eth, eth->rx_ring.phys, MTK_QRX_BASE_PTR0);
> - mtk_w32(eth, MTK_DMA_SIZE, MTK_QRX_MAX_CNT0);
> - mtk_w32(eth, eth->rx_ring.calc_idx, MTK_QRX_CRX_IDX0);
> - mtk_w32(eth, MTK_PST_DRX_IDX0, MTK_QDMA_RST_IDX);
> - mtk_w32(eth, (QDMA_RES_THRES << 8) | QDMA_RES_THRES, MTK_QTX_CFG(0));
> + mtk_w32(eth, eth->rx_ring.phys, MTK_PRX_BASE_PTR0);
> + mtk_w32(eth, MTK_DMA_SIZE, MTK_PRX_MAX_CNT0);
> + mtk_w32(eth, eth->rx_ring.calc_idx, MTK_PRX_CRX_IDX0);
> + mtk_w32(eth, MTK_PST_DRX_IDX0, MTK_PDMA_RST_IDX);
>
> return 0;
> }
> @@ -1285,7 +1287,7 @@ static irqreturn_t mtk_handle_irq_rx(int irq, void *_eth)
>
> if (likely(napi_schedule_prep(ð->rx_napi))) {
> __napi_schedule(ð->rx_napi);
> - mtk_irq_disable(eth, MTK_RX_DONE_INT);
> + mtk_irq_disable(eth, MTK_PDMA_INT_MASK, MTK_RX_DONE_INT);
> }
>
> return IRQ_HANDLED;
> @@ -1297,7 +1299,7 @@ static irqreturn_t mtk_handle_irq_tx(int irq, void *_eth)
>
> if (likely(napi_schedule_prep(ð->tx_napi))) {
> __napi_schedule(ð->tx_napi);
> - mtk_irq_disable(eth, MTK_TX_DONE_INT);
> + mtk_irq_disable(eth, MTK_QDMA_INT_MASK, MTK_TX_DONE_INT);
> }
>
> return IRQ_HANDLED;
> @@ -1308,11 +1310,12 @@ static void mtk_poll_controller(struct net_device *dev)
> {
> struct mtk_mac *mac = netdev_priv(dev);
> struct mtk_eth *eth = mac->hw;
> - u32 int_mask = MTK_TX_DONE_INT | MTK_RX_DONE_INT;
>
> - mtk_irq_disable(eth, int_mask);
> + mtk_irq_disable(eth, MTK_QDMA_INT_MASK, MTK_TX_DONE_INT);
> + mtk_irq_disable(eth, MTK_PDMA_INT_MASK, MTK_RX_DONE_INT);
> mtk_handle_irq_rx(eth->irq[2], dev);
> - mtk_irq_enable(eth, int_mask);
> + mtk_irq_enable(eth, MTK_QDMA_INT_MASK, MTK_TX_DONE_INT);
> + mtk_irq_enable(eth, MTK_PDMA_INT_MASK, MTK_RX_DONE_INT);
> }
> #endif
>
> @@ -1327,11 +1330,15 @@ static int mtk_start_dma(struct mtk_eth *eth)
> }
>
> mtk_w32(eth,
> - MTK_TX_WB_DDONE | MTK_RX_DMA_EN | MTK_TX_DMA_EN |
> - MTK_RX_2B_OFFSET | MTK_DMA_SIZE_16DWORDS |
> - MTK_RX_BT_32DWORDS | MTK_NDP_CO_PRO,
> + MTK_TX_WB_DDONE | MTK_TX_DMA_EN |
> + MTK_DMA_SIZE_16DWORDS | MTK_NDP_CO_PRO,
> MTK_QDMA_GLO_CFG);
>
> + mtk_w32(eth,
> + MTK_RX_DMA_EN | MTK_RX_2B_OFFSET |
> + MTK_RX_BT_32DWORDS | MTK_MULTI_EN,
> + MTK_PDMA_GLO_CFG);
> +
> return 0;
> }
>
> @@ -1349,7 +1356,8 @@ static int mtk_open(struct net_device *dev)
>
> napi_enable(ð->tx_napi);
> napi_enable(ð->rx_napi);
> - mtk_irq_enable(eth, MTK_TX_DONE_INT | MTK_RX_DONE_INT);
> + mtk_irq_enable(eth, MTK_QDMA_INT_MASK, MTK_TX_DONE_INT);
> + mtk_irq_enable(eth, MTK_PDMA_INT_MASK, MTK_RX_DONE_INT);
> }
> atomic_inc(ð->dma_refcnt);
>
> @@ -1394,7 +1402,8 @@ static int mtk_stop(struct net_device *dev)
> if (!atomic_dec_and_test(ð->dma_refcnt))
> return 0;
>
> - mtk_irq_disable(eth, MTK_TX_DONE_INT | MTK_RX_DONE_INT);
> + mtk_irq_disable(eth, MTK_QDMA_INT_MASK, MTK_TX_DONE_INT);
> + mtk_irq_disable(eth, MTK_PDMA_INT_MASK, MTK_RX_DONE_INT);
> napi_disable(ð->tx_napi);
> napi_disable(ð->rx_napi);
>
> @@ -1448,7 +1457,9 @@ static int __init mtk_hw_init(struct mtk_eth *eth)
>
> /* disable delay and normal interrupt */
> mtk_w32(eth, 0, MTK_QDMA_DELAY_INT);
> - mtk_irq_disable(eth, ~0);
> + mtk_w32(eth, 0, MTK_PDMA_DELAY_INT);
> + mtk_irq_disable(eth, MTK_QDMA_INT_MASK, ~0);
> + mtk_irq_disable(eth, MTK_PDMA_INT_MASK, ~0);
> mtk_w32(eth, RST_GL_PSE, MTK_RST_GL);
> mtk_w32(eth, 0, MTK_RST_GL);
>
> @@ -1504,7 +1515,8 @@ static void mtk_uninit(struct net_device *dev)
>
> phy_disconnect(mac->phy_dev);
> mtk_mdio_cleanup(eth);
> - mtk_irq_disable(eth, ~0);
> + mtk_irq_disable(eth, MTK_QDMA_INT_MASK, ~0);
> + mtk_irq_disable(eth, MTK_PDMA_INT_MASK, ~0);
> free_irq(eth->irq[1], dev);
> free_irq(eth->irq[2], dev);
> }
> @@ -1683,7 +1695,7 @@ static void mtk_get_ethtool_stats(struct net_device *dev,
> }
>
> do {
> - data_src = (u64*)hwstats;
> + data_src = (u64 *)hwstats;
> data_dst = data;
> start = u64_stats_fetch_begin_irq(&hwstats->syncp);
>
> diff --git a/drivers/net/ethernet/mediatek/mtk_eth_soc.h b/drivers/net/ethernet/mediatek/mtk_eth_soc.h
> old mode 100644
> new mode 100755
> index f82e3ac..7c1f3f2
> --- a/drivers/net/ethernet/mediatek/mtk_eth_soc.h
> +++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.h
> @@ -68,6 +68,32 @@
> /* Unicast Filter MAC Address Register - High */
> #define MTK_GDMA_MAC_ADRH(x) (0x50C + (x * 0x1000))
>
> +/* PDMA RX Base Pointer Register */
> +#define MTK_PRX_BASE_PTR0 0x900
> +
> +/* PDMA RX Maximum Count Register */
> +#define MTK_PRX_MAX_CNT0 0x904
> +
> +/* PDMA RX CPU Pointer Register */
> +#define MTK_PRX_CRX_IDX0 0x908
> +
> +/* PDMA Global Configuration Register */
> +#define MTK_PDMA_GLO_CFG 0xa04
> +#define MTK_MULTI_EN BIT(10)
> +
> +/* PDMA Reset Index Register */
> +#define MTK_PDMA_RST_IDX 0xa08
> +#define MTK_PST_DRX_IDX0 BIT(16)
> +
> +/* PDMA Delay Interrupt Register */
> +#define MTK_PDMA_DELAY_INT 0xa0c
> +
> +/* PDMA Interrupt Status Register */
> +#define MTK_PDMA_INT_STATUS 0xa20
> +
> +/* PDMA Interrupt Mask Register */
> +#define MTK_PDMA_INT_MASK 0xa28
> +
> /* PDMA Interrupt grouping registers */
> #define MTK_PDMA_INT_GRP1 0xa50
> #define MTK_PDMA_INT_GRP2 0xa54
> @@ -119,13 +145,16 @@
>
> /* QDMA Interrupt Status Register */
> #define MTK_QMTK_INT_STATUS 0x1A18
> +#define MTK_RX_DONE_INT3 BIT(19)
> +#define MTK_RX_DONE_INT2 BIT(18)
> #define MTK_RX_DONE_INT1 BIT(17)
> #define MTK_RX_DONE_INT0 BIT(16)
> #define MTK_TX_DONE_INT3 BIT(3)
> #define MTK_TX_DONE_INT2 BIT(2)
> #define MTK_TX_DONE_INT1 BIT(1)
> #define MTK_TX_DONE_INT0 BIT(0)
> -#define MTK_RX_DONE_INT (MTK_RX_DONE_INT0 | MTK_RX_DONE_INT1)
> +#define MTK_RX_DONE_INT (MTK_RX_DONE_INT0 | MTK_RX_DONE_INT1 | \
> + MTK_RX_DONE_INT2 | MTK_RX_DONE_INT3)
> #define MTK_TX_DONE_INT (MTK_TX_DONE_INT0 | MTK_TX_DONE_INT1 | \
> MTK_TX_DONE_INT2 | MTK_TX_DONE_INT3)
>
>
^ permalink raw reply
* [PATCH net-next] net: ethernet: mediatek: modify to use the PDMA instead of the QDMA for Ethernet RX
From: Nelson Chang @ 2016-08-24 12:49 UTC (permalink / raw)
To: john, davem; +Cc: nbd, netdev, linux-mediatek, nelsonch.tw, Nelson Chang
Because the PDMA has richer features than the QDMA for Ethernet RX
(such as multiple RX rings, HW LRO, etc.),
the patch modifies to use the PDMA to handle Ethernet RX.
Signed-off-by: Nelson Chang <nelson.chang@mediatek.com>
---
drivers/net/ethernet/mediatek/mtk_eth_soc.c | 72 +++++++++++++++++------------
drivers/net/ethernet/mediatek/mtk_eth_soc.h | 31 ++++++++++++-
2 files changed, 72 insertions(+), 31 deletions(-)
mode change 100644 => 100755 drivers/net/ethernet/mediatek/mtk_eth_soc.c
mode change 100644 => 100755 drivers/net/ethernet/mediatek/mtk_eth_soc.h
diff --git a/drivers/net/ethernet/mediatek/mtk_eth_soc.c b/drivers/net/ethernet/mediatek/mtk_eth_soc.c
old mode 100644
new mode 100755
index 1801fd8..27a9156
--- a/drivers/net/ethernet/mediatek/mtk_eth_soc.c
+++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.c
@@ -342,25 +342,27 @@ static void mtk_mdio_cleanup(struct mtk_eth *eth)
mdiobus_free(eth->mii_bus);
}
-static inline void mtk_irq_disable(struct mtk_eth *eth, u32 mask)
+static inline void mtk_irq_disable(struct mtk_eth *eth,
+ unsigned reg, u32 mask)
{
unsigned long flags;
u32 val;
spin_lock_irqsave(ð->irq_lock, flags);
- val = mtk_r32(eth, MTK_QDMA_INT_MASK);
- mtk_w32(eth, val & ~mask, MTK_QDMA_INT_MASK);
+ val = mtk_r32(eth, reg);
+ mtk_w32(eth, val & ~mask, reg);
spin_unlock_irqrestore(ð->irq_lock, flags);
}
-static inline void mtk_irq_enable(struct mtk_eth *eth, u32 mask)
+static inline void mtk_irq_enable(struct mtk_eth *eth,
+ unsigned reg, u32 mask)
{
unsigned long flags;
u32 val;
spin_lock_irqsave(ð->irq_lock, flags);
- val = mtk_r32(eth, MTK_QDMA_INT_MASK);
- mtk_w32(eth, val | mask, MTK_QDMA_INT_MASK);
+ val = mtk_r32(eth, reg);
+ mtk_w32(eth, val | mask, reg);
spin_unlock_irqrestore(ð->irq_lock, flags);
}
@@ -1012,7 +1014,7 @@ static int mtk_napi_tx(struct napi_struct *napi, int budget)
return budget;
napi_complete(napi);
- mtk_irq_enable(eth, MTK_TX_DONE_INT);
+ mtk_irq_enable(eth, MTK_QDMA_INT_MASK, MTK_TX_DONE_INT);
return tx_done;
}
@@ -1024,12 +1026,12 @@ static int mtk_napi_rx(struct napi_struct *napi, int budget)
int rx_done = 0;
mtk_handle_status_irq(eth);
- mtk_w32(eth, MTK_RX_DONE_INT, MTK_QMTK_INT_STATUS);
+ mtk_w32(eth, MTK_RX_DONE_INT, MTK_PDMA_INT_STATUS);
rx_done = mtk_poll_rx(napi, budget, eth);
if (unlikely(netif_msg_intr(eth))) {
- status = mtk_r32(eth, MTK_QMTK_INT_STATUS);
- mask = mtk_r32(eth, MTK_QDMA_INT_MASK);
+ status = mtk_r32(eth, MTK_PDMA_INT_STATUS);
+ mask = mtk_r32(eth, MTK_PDMA_INT_MASK);
dev_info(eth->dev,
"done rx %d, intr 0x%08x/0x%x\n",
rx_done, status, mask);
@@ -1038,12 +1040,12 @@ static int mtk_napi_rx(struct napi_struct *napi, int budget)
if (rx_done == budget)
return budget;
- status = mtk_r32(eth, MTK_QMTK_INT_STATUS);
+ status = mtk_r32(eth, MTK_PDMA_INT_STATUS);
if (status & MTK_RX_DONE_INT)
return budget;
napi_complete(napi);
- mtk_irq_enable(eth, MTK_RX_DONE_INT);
+ mtk_irq_enable(eth, MTK_PDMA_INT_MASK, MTK_RX_DONE_INT);
return rx_done;
}
@@ -1092,6 +1094,7 @@ static int mtk_tx_alloc(struct mtk_eth *eth)
mtk_w32(eth,
ring->phys + ((MTK_DMA_SIZE - 1) * sz),
MTK_QTX_DRX_PTR);
+ mtk_w32(eth, (QDMA_RES_THRES << 8) | QDMA_RES_THRES, MTK_QTX_CFG(0));
return 0;
@@ -1162,11 +1165,10 @@ static int mtk_rx_alloc(struct mtk_eth *eth)
*/
wmb();
- mtk_w32(eth, eth->rx_ring.phys, MTK_QRX_BASE_PTR0);
- mtk_w32(eth, MTK_DMA_SIZE, MTK_QRX_MAX_CNT0);
- mtk_w32(eth, eth->rx_ring.calc_idx, MTK_QRX_CRX_IDX0);
- mtk_w32(eth, MTK_PST_DRX_IDX0, MTK_QDMA_RST_IDX);
- mtk_w32(eth, (QDMA_RES_THRES << 8) | QDMA_RES_THRES, MTK_QTX_CFG(0));
+ mtk_w32(eth, eth->rx_ring.phys, MTK_PRX_BASE_PTR0);
+ mtk_w32(eth, MTK_DMA_SIZE, MTK_PRX_MAX_CNT0);
+ mtk_w32(eth, eth->rx_ring.calc_idx, MTK_PRX_CRX_IDX0);
+ mtk_w32(eth, MTK_PST_DRX_IDX0, MTK_PDMA_RST_IDX);
return 0;
}
@@ -1285,7 +1287,7 @@ static irqreturn_t mtk_handle_irq_rx(int irq, void *_eth)
if (likely(napi_schedule_prep(ð->rx_napi))) {
__napi_schedule(ð->rx_napi);
- mtk_irq_disable(eth, MTK_RX_DONE_INT);
+ mtk_irq_disable(eth, MTK_PDMA_INT_MASK, MTK_RX_DONE_INT);
}
return IRQ_HANDLED;
@@ -1297,7 +1299,7 @@ static irqreturn_t mtk_handle_irq_tx(int irq, void *_eth)
if (likely(napi_schedule_prep(ð->tx_napi))) {
__napi_schedule(ð->tx_napi);
- mtk_irq_disable(eth, MTK_TX_DONE_INT);
+ mtk_irq_disable(eth, MTK_QDMA_INT_MASK, MTK_TX_DONE_INT);
}
return IRQ_HANDLED;
@@ -1308,11 +1310,12 @@ static void mtk_poll_controller(struct net_device *dev)
{
struct mtk_mac *mac = netdev_priv(dev);
struct mtk_eth *eth = mac->hw;
- u32 int_mask = MTK_TX_DONE_INT | MTK_RX_DONE_INT;
- mtk_irq_disable(eth, int_mask);
+ mtk_irq_disable(eth, MTK_QDMA_INT_MASK, MTK_TX_DONE_INT);
+ mtk_irq_disable(eth, MTK_PDMA_INT_MASK, MTK_RX_DONE_INT);
mtk_handle_irq_rx(eth->irq[2], dev);
- mtk_irq_enable(eth, int_mask);
+ mtk_irq_enable(eth, MTK_QDMA_INT_MASK, MTK_TX_DONE_INT);
+ mtk_irq_enable(eth, MTK_PDMA_INT_MASK, MTK_RX_DONE_INT);
}
#endif
@@ -1327,11 +1330,15 @@ static int mtk_start_dma(struct mtk_eth *eth)
}
mtk_w32(eth,
- MTK_TX_WB_DDONE | MTK_RX_DMA_EN | MTK_TX_DMA_EN |
- MTK_RX_2B_OFFSET | MTK_DMA_SIZE_16DWORDS |
- MTK_RX_BT_32DWORDS | MTK_NDP_CO_PRO,
+ MTK_TX_WB_DDONE | MTK_TX_DMA_EN |
+ MTK_DMA_SIZE_16DWORDS | MTK_NDP_CO_PRO,
MTK_QDMA_GLO_CFG);
+ mtk_w32(eth,
+ MTK_RX_DMA_EN | MTK_RX_2B_OFFSET |
+ MTK_RX_BT_32DWORDS | MTK_MULTI_EN,
+ MTK_PDMA_GLO_CFG);
+
return 0;
}
@@ -1349,7 +1356,8 @@ static int mtk_open(struct net_device *dev)
napi_enable(ð->tx_napi);
napi_enable(ð->rx_napi);
- mtk_irq_enable(eth, MTK_TX_DONE_INT | MTK_RX_DONE_INT);
+ mtk_irq_enable(eth, MTK_QDMA_INT_MASK, MTK_TX_DONE_INT);
+ mtk_irq_enable(eth, MTK_PDMA_INT_MASK, MTK_RX_DONE_INT);
}
atomic_inc(ð->dma_refcnt);
@@ -1394,7 +1402,8 @@ static int mtk_stop(struct net_device *dev)
if (!atomic_dec_and_test(ð->dma_refcnt))
return 0;
- mtk_irq_disable(eth, MTK_TX_DONE_INT | MTK_RX_DONE_INT);
+ mtk_irq_disable(eth, MTK_QDMA_INT_MASK, MTK_TX_DONE_INT);
+ mtk_irq_disable(eth, MTK_PDMA_INT_MASK, MTK_RX_DONE_INT);
napi_disable(ð->tx_napi);
napi_disable(ð->rx_napi);
@@ -1448,7 +1457,9 @@ static int __init mtk_hw_init(struct mtk_eth *eth)
/* disable delay and normal interrupt */
mtk_w32(eth, 0, MTK_QDMA_DELAY_INT);
- mtk_irq_disable(eth, ~0);
+ mtk_w32(eth, 0, MTK_PDMA_DELAY_INT);
+ mtk_irq_disable(eth, MTK_QDMA_INT_MASK, ~0);
+ mtk_irq_disable(eth, MTK_PDMA_INT_MASK, ~0);
mtk_w32(eth, RST_GL_PSE, MTK_RST_GL);
mtk_w32(eth, 0, MTK_RST_GL);
@@ -1504,7 +1515,8 @@ static void mtk_uninit(struct net_device *dev)
phy_disconnect(mac->phy_dev);
mtk_mdio_cleanup(eth);
- mtk_irq_disable(eth, ~0);
+ mtk_irq_disable(eth, MTK_QDMA_INT_MASK, ~0);
+ mtk_irq_disable(eth, MTK_PDMA_INT_MASK, ~0);
free_irq(eth->irq[1], dev);
free_irq(eth->irq[2], dev);
}
@@ -1683,7 +1695,7 @@ static void mtk_get_ethtool_stats(struct net_device *dev,
}
do {
- data_src = (u64*)hwstats;
+ data_src = (u64 *)hwstats;
data_dst = data;
start = u64_stats_fetch_begin_irq(&hwstats->syncp);
diff --git a/drivers/net/ethernet/mediatek/mtk_eth_soc.h b/drivers/net/ethernet/mediatek/mtk_eth_soc.h
old mode 100644
new mode 100755
index f82e3ac..7c1f3f2
--- a/drivers/net/ethernet/mediatek/mtk_eth_soc.h
+++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.h
@@ -68,6 +68,32 @@
/* Unicast Filter MAC Address Register - High */
#define MTK_GDMA_MAC_ADRH(x) (0x50C + (x * 0x1000))
+/* PDMA RX Base Pointer Register */
+#define MTK_PRX_BASE_PTR0 0x900
+
+/* PDMA RX Maximum Count Register */
+#define MTK_PRX_MAX_CNT0 0x904
+
+/* PDMA RX CPU Pointer Register */
+#define MTK_PRX_CRX_IDX0 0x908
+
+/* PDMA Global Configuration Register */
+#define MTK_PDMA_GLO_CFG 0xa04
+#define MTK_MULTI_EN BIT(10)
+
+/* PDMA Reset Index Register */
+#define MTK_PDMA_RST_IDX 0xa08
+#define MTK_PST_DRX_IDX0 BIT(16)
+
+/* PDMA Delay Interrupt Register */
+#define MTK_PDMA_DELAY_INT 0xa0c
+
+/* PDMA Interrupt Status Register */
+#define MTK_PDMA_INT_STATUS 0xa20
+
+/* PDMA Interrupt Mask Register */
+#define MTK_PDMA_INT_MASK 0xa28
+
/* PDMA Interrupt grouping registers */
#define MTK_PDMA_INT_GRP1 0xa50
#define MTK_PDMA_INT_GRP2 0xa54
@@ -119,13 +145,16 @@
/* QDMA Interrupt Status Register */
#define MTK_QMTK_INT_STATUS 0x1A18
+#define MTK_RX_DONE_INT3 BIT(19)
+#define MTK_RX_DONE_INT2 BIT(18)
#define MTK_RX_DONE_INT1 BIT(17)
#define MTK_RX_DONE_INT0 BIT(16)
#define MTK_TX_DONE_INT3 BIT(3)
#define MTK_TX_DONE_INT2 BIT(2)
#define MTK_TX_DONE_INT1 BIT(1)
#define MTK_TX_DONE_INT0 BIT(0)
-#define MTK_RX_DONE_INT (MTK_RX_DONE_INT0 | MTK_RX_DONE_INT1)
+#define MTK_RX_DONE_INT (MTK_RX_DONE_INT0 | MTK_RX_DONE_INT1 | \
+ MTK_RX_DONE_INT2 | MTK_RX_DONE_INT3)
#define MTK_TX_DONE_INT (MTK_TX_DONE_INT0 | MTK_TX_DONE_INT1 | \
MTK_TX_DONE_INT2 | MTK_TX_DONE_INT3)
--
1.9.1
^ permalink raw reply related
* Re: [PATCH V5, 0/5] Add MediaTek USB3 DRD Driver
From: Oliver Neukum @ 2016-08-24 11:29 UTC (permalink / raw)
To: chunfeng yun
Cc: Mark Rutland, devicetree-u79uwXL29TY76Z2rM5mHXA,
linux-usb-u79uwXL29TY76Z2rM5mHXA, Felipe Balbi, Pawel Moll,
Sergei Shtylyov, Ian Campbell, Greg Kroah-Hartman, Sascha Hauer,
Alan Cooper, linux-kernel-u79uwXL29TY76Z2rM5mHXA, Mathias Nyman,
Rob Herring, linux-mediatek-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r,
Kumar Gala, Matthias Brugger, Alan Stern,
linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r
In-Reply-To: <1472020923.27677.1.camel@mhfsdcap03>
On Wed, 2016-08-24 at 14:42 +0800, chunfeng yun wrote:
> Dear all,
>
> Could you please help me to review the code?
Is the structure
struct qmu_gpd
shared with the hardware? Do I read this correctly that
you do PIO to endpoint 0 but DMA to the others?
Could you resend the series?
Regards
Oliver
^ permalink raw reply
* Re: [PATCH v13 0/4] Mediatek MT8173 CMDQ support
From: Matthias Brugger @ 2016-08-24 11:00 UTC (permalink / raw)
To: HS Liao, Rob Herring
Cc: Daniel Kurtz, Sascha Hauer, devicetree-u79uwXL29TY76Z2rM5mHXA,
linux-kernel-u79uwXL29TY76Z2rM5mHXA,
linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r,
linux-mediatek-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r,
srv_heupstream-NuS5LvNUpcJWk0Htik3J/w, Sascha Hauer,
Philipp Zabel, Nicolas Boichat, CK HU, cawa cheng, Bibby Hsieh,
YT Shen, Daoyuan Huang, Damon Chu, Josh-YC Liu, Glory Hung,
Jiaguang Zhang, Dennis-YC Hsieh, Monica
In-Reply-To: <1472009252-1074-1-git-send-email-hs.liao-NuS5LvNUpcJWk0Htik3J/w@public.gmane.org>
On 24/08/16 05:27, HS Liao wrote:
>
> Hi,
>
> This is Mediatek MT8173 Command Queue(CMDQ) driver. The CMDQ is used
> to help write registers with critical time limitation, such as
> updating display configuration during the vblank. It controls Global
> Command Engine (GCE) hardware to achieve this requirement.
>
> These patches have a build dependency on top of v4.8-rc1.
>
> Changes since v12:
> - remove mediatek,gce from device tree
Why? The binding got accepted by Rob.
>
> Best regards,
> HS Liao
>
> HS Liao (4):
> dt-bindings: soc: Add documentation for the MediaTek GCE unit
> CMDQ: Mediatek CMDQ driver
> arm64: dts: mt8173: Add GCE node
> CMDQ: save more energy in idle
>
> .../devicetree/bindings/soc/mediatek/gce.txt | 44 +
> arch/arm64/boot/dts/mediatek/mt8173.dtsi | 10 +
> drivers/soc/mediatek/Kconfig | 11 +
> drivers/soc/mediatek/Makefile | 1 +
> drivers/soc/mediatek/mtk-cmdq.c | 983 +++++++++++++++++++++
The driver uses the mailbox framework, so it should live in the
drivers/mailbox folder.
Please don't forget to add Jassi to the loop, as he is the maintainer of
this subsystem and the last instance to decide if/when the driver will
get accepted.
Thanks,
Matthias
> include/soc/mediatek/cmdq.h | 180 ++++
> 6 files changed, 1229 insertions(+)
> create mode 100644 Documentation/devicetree/bindings/soc/mediatek/gce.txt
> create mode 100644 drivers/soc/mediatek/mtk-cmdq.c
> create mode 100644 include/soc/mediatek/cmdq.h
>
--
To unsubscribe from this list: send the line "unsubscribe devicetree" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
^ permalink raw reply
* Re: [PATCH V5, 0/5] Add MediaTek USB3 DRD Driver
From: chunfeng yun @ 2016-08-24 6:42 UTC (permalink / raw)
To: Greg Kroah-Hartman
Cc: Felipe Balbi, Mathias Nyman, Matthias Brugger, Alan Stern,
Rob Herring, Mark Rutland, Ian Campbell, Sergei Shtylyov,
Pawel Moll, Kumar Gala, Sascha Hauer, Alan Cooper,
linux-usb-u79uwXL29TY76Z2rM5mHXA,
devicetree-u79uwXL29TY76Z2rM5mHXA,
linux-kernel-u79uwXL29TY76Z2rM5mHXA,
linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r,
linux-mediatek-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r
In-Reply-To: <1470730998-9563-1-git-send-email-chunfeng.yun-NuS5LvNUpcJWk0Htik3J/w@public.gmane.org>
Dear all,
Could you please help me to review the code?
Thank you very much.
On Tue, 2016-08-09 at 16:23 +0800, Chunfeng Yun wrote:
> These patches introduce the MediaTek USB3 dual-role controller
> driver.
>
> The driver can be configured as Dual-Role Device (DRD),
> Peripheral Only and Host Only (xHCI) modes. It works well
> with Mass Storage, RNDIS and g_zero on FS/HS and SS. And it is
> tested on MT8173 platform which only contains USB2.0 device IP,
> and on MT6290 platform which contains USB3.0 device IP.
>
> Change in v5:
> 1. modify some comments
> 2. rename some unsuitable variables
> 3. add reg-names property for host node
> 4. add USB_MTU3_DEBUG to control debug messages
>
> Change in v4:
> 1. fix build errors on non-mediatek platforms
> 2. provide manual dual-role switch via debugfs instead of sysfs
>
> Change in v3:
> 1. fix some typo error
> 2. rename mtu3.txt to mt8173-mtu3.txt
>
> Change in v2:
> 1. modify binding docs according to suggestions
> 2. modify some comments and remove some dummy blank lines
> 3. fix memory leakage
>
>
> Chunfeng Yun (5):
> dt-bindings: mt8173-xhci: support host side of dual-role mode
> dt-bindings: mt8173-mtu3: add devicetree bindings
> usb: xhci-mtk: make IPPC register optional
> usb: Add MediaTek USB3 DRD Driver
> arm64: dts: mediatek: add USB3 DRD driver
>
> .../devicetree/bindings/usb/mt8173-mtu3.txt | 87 ++
> .../devicetree/bindings/usb/mt8173-xhci.txt | 54 +-
> arch/arm64/boot/dts/mediatek/mt8173-evb.dts | 46 +-
> arch/arm64/boot/dts/mediatek/mt8173.dtsi | 29 +-
> drivers/usb/Kconfig | 2 +
> drivers/usb/Makefile | 1 +
> drivers/usb/host/xhci-mtk.c | 36 +-
> drivers/usb/mtu3/Kconfig | 54 ++
> drivers/usb/mtu3/Makefile | 19 +
> drivers/usb/mtu3/mtu3.h | 422 ++++++++++
> drivers/usb/mtu3/mtu3_core.c | 874 +++++++++++++++++++
> drivers/usb/mtu3/mtu3_dr.c | 375 +++++++++
> drivers/usb/mtu3/mtu3_dr.h | 108 +++
> drivers/usb/mtu3/mtu3_gadget.c | 731 ++++++++++++++++
> drivers/usb/mtu3/mtu3_gadget_ep0.c | 879 ++++++++++++++++++++
> drivers/usb/mtu3/mtu3_host.c | 294 +++++++
> drivers/usb/mtu3/mtu3_hw_regs.h | 473 +++++++++++
> drivers/usb/mtu3/mtu3_plat.c | 490 +++++++++++
> drivers/usb/mtu3/mtu3_qmu.c | 599 +++++++++++++
> drivers/usb/mtu3/mtu3_qmu.h | 43 +
> 20 files changed, 5598 insertions(+), 18 deletions(-)
> create mode 100644 Documentation/devicetree/bindings/usb/mt8173-mtu3.txt
> create mode 100644 drivers/usb/mtu3/Kconfig
> create mode 100644 drivers/usb/mtu3/Makefile
> create mode 100644 drivers/usb/mtu3/mtu3.h
> create mode 100644 drivers/usb/mtu3/mtu3_core.c
> create mode 100644 drivers/usb/mtu3/mtu3_dr.c
> create mode 100644 drivers/usb/mtu3/mtu3_dr.h
> create mode 100644 drivers/usb/mtu3/mtu3_gadget.c
> create mode 100644 drivers/usb/mtu3/mtu3_gadget_ep0.c
> create mode 100644 drivers/usb/mtu3/mtu3_host.c
> create mode 100644 drivers/usb/mtu3/mtu3_hw_regs.h
> create mode 100644 drivers/usb/mtu3/mtu3_plat.c
> create mode 100644 drivers/usb/mtu3/mtu3_qmu.c
> create mode 100644 drivers/usb/mtu3/mtu3_qmu.h
>
--
To unsubscribe from this list: send the line "unsubscribe linux-usb" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
^ permalink raw reply
* [PATCH v13 4/4] CMDQ: save more energy in idle
From: HS Liao @ 2016-08-24 3:27 UTC (permalink / raw)
To: Rob Herring, Matthias Brugger
Cc: Daniel Kurtz, Sascha Hauer, devicetree-u79uwXL29TY76Z2rM5mHXA,
linux-kernel-u79uwXL29TY76Z2rM5mHXA,
linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r,
linux-mediatek-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r,
srv_heupstream-NuS5LvNUpcJWk0Htik3J/w, Sascha Hauer,
Philipp Zabel, Nicolas Boichat, CK HU, cawa cheng, Bibby Hsieh,
YT Shen, Daoyuan Huang, Damon Chu, Josh-YC Liu, Glory Hung,
Jiaguang Zhang, Dennis-YC Hsieh
In-Reply-To: <1472009252-1074-1-git-send-email-hs.liao-NuS5LvNUpcJWk0Htik3J/w@public.gmane.org>
Use clk_disable_unprepare instead of clk_disable to save more energy
when CMDQ is idle.
Signed-off-by: HS Liao <hs.liao-NuS5LvNUpcJWk0Htik3J/w@public.gmane.org>
---
drivers/soc/mediatek/mtk-cmdq.c | 54 +++++++++++++++++++++++++++++++++++------
1 file changed, 46 insertions(+), 8 deletions(-)
diff --git a/drivers/soc/mediatek/mtk-cmdq.c b/drivers/soc/mediatek/mtk-cmdq.c
index 7ca3113..a0fcbef 100644
--- a/drivers/soc/mediatek/mtk-cmdq.c
+++ b/drivers/soc/mediatek/mtk-cmdq.c
@@ -28,6 +28,7 @@
#include <linux/spinlock.h>
#include <linux/suspend.h>
#include <linux/timer.h>
+#include <linux/workqueue.h>
#include <soc/mediatek/cmdq.h>
#define CMDQ_THR_MAX_COUNT 3 /* main, sub, general(misc) */
@@ -128,10 +129,16 @@ struct cmdq_task {
struct cmdq_task_cb cb;
};
+struct cmdq_clk_release {
+ struct cmdq *cmdq;
+ struct work_struct release_work;
+};
+
struct cmdq {
struct mbox_controller mbox;
void __iomem *base;
u32 irq;
+ struct workqueue_struct *clk_release_wq;
struct cmdq_thread thread[CMDQ_THR_MAX_COUNT];
struct mutex task_mutex;
struct clk *clock;
@@ -297,11 +304,19 @@ static void cmdq_thread_wait_end(struct cmdq_thread *thread,
static void cmdq_task_exec(struct cmdq_task *task, struct cmdq_thread *thread)
{
struct cmdq *cmdq = task->cmdq;
- unsigned long curr_pa, end_pa;
+ unsigned long curr_pa, end_pa, flags;
task->thread = thread;
if (list_empty(&thread->task_busy_list)) {
- WARN_ON(clk_enable(cmdq->clock) < 0);
+ /*
+ * Unlock for clk prepare (sleeping function).
+ * We are safe to do that since we have task_mutex and
+ * only flush will add task.
+ */
+ spin_unlock_irqrestore(&thread->chan->lock, flags);
+ WARN_ON(clk_prepare_enable(cmdq->clock) < 0);
+ spin_lock_irqsave(&thread->chan->lock, flags);
+
WARN_ON(cmdq_thread_reset(cmdq, thread) < 0);
writel(task->pa_base, thread->base + CMDQ_THR_CURR_ADDR);
@@ -383,6 +398,26 @@ static void cmdq_task_handle_error(struct cmdq_task *task)
cmdq_thread_resume(thread);
}
+static void cmdq_clk_release_work(struct work_struct *work_item)
+{
+ struct cmdq_clk_release *clk_release = container_of(work_item,
+ struct cmdq_clk_release, release_work);
+ struct cmdq *cmdq = clk_release->cmdq;
+
+ clk_disable_unprepare(cmdq->clock);
+ kfree(clk_release);
+}
+
+static void cmdq_clk_release_schedule(struct cmdq *cmdq)
+{
+ struct cmdq_clk_release *clk_release;
+
+ clk_release = kmalloc(sizeof(*clk_release), GFP_ATOMIC);
+ clk_release->cmdq = cmdq;
+ INIT_WORK(&clk_release->release_work, cmdq_clk_release_work);
+ queue_work(cmdq->clk_release_wq, &clk_release->release_work);
+}
+
static void cmdq_thread_irq_handler(struct cmdq *cmdq,
struct cmdq_thread *thread)
{
@@ -432,7 +467,7 @@ static void cmdq_thread_irq_handler(struct cmdq *cmdq,
if (list_empty(&thread->task_busy_list)) {
cmdq_thread_disable(cmdq, thread);
- clk_disable(cmdq->clock);
+ cmdq_clk_release_schedule(cmdq);
} else {
mod_timer(&thread->timeout,
jiffies + msecs_to_jiffies(CMDQ_TIMEOUT_MS));
@@ -491,7 +526,7 @@ static void cmdq_thread_handle_timeout(unsigned long data)
cmdq_thread_resume(thread);
cmdq_thread_disable(cmdq, thread);
- clk_disable(cmdq->clock);
+ cmdq_clk_release_schedule(cmdq);
spin_unlock_irqrestore(&thread->chan->lock, flags);
}
@@ -779,7 +814,7 @@ static int cmdq_suspend(struct device *dev)
msleep(20);
}
- clk_unprepare(cmdq->clock);
+ flush_workqueue(cmdq->clk_release_wq);
return 0;
}
@@ -787,7 +822,6 @@ static int cmdq_resume(struct device *dev)
{
struct cmdq *cmdq = dev_get_drvdata(dev);
- WARN_ON(clk_prepare(cmdq->clock) < 0);
cmdq->suspended = false;
return 0;
}
@@ -796,8 +830,8 @@ static int cmdq_remove(struct platform_device *pdev)
{
struct cmdq *cmdq = platform_get_drvdata(pdev);
+ destroy_workqueue(cmdq->clk_release_wq);
mbox_controller_unregister(&cmdq->mbox);
- clk_unprepare(cmdq->clock);
return 0;
}
@@ -916,8 +950,12 @@ static int cmdq_probe(struct platform_device *pdev)
return err;
}
+ cmdq->clk_release_wq = alloc_ordered_workqueue(
+ "%s", WQ_MEM_RECLAIM | WQ_HIGHPRI,
+ "cmdq_clk_release");
+
platform_set_drvdata(pdev, cmdq);
- WARN_ON(clk_prepare(cmdq->clock) < 0);
+
return 0;
}
--
1.9.1
--
To unsubscribe from this list: send the line "unsubscribe devicetree" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
^ permalink raw reply related
* [PATCH v13 3/4] arm64: dts: mt8173: Add GCE node
From: HS Liao @ 2016-08-24 3:27 UTC (permalink / raw)
To: Rob Herring, Matthias Brugger
Cc: Daniel Kurtz, Sascha Hauer, devicetree, linux-kernel,
linux-arm-kernel, linux-mediatek, srv_heupstream, Sascha Hauer,
Philipp Zabel, Nicolas Boichat, CK HU, cawa cheng, Bibby Hsieh,
YT Shen, Daoyuan Huang, Damon Chu, Josh-YC Liu, Glory Hung,
Jiaguang Zhang, Dennis-YC Hsieh
In-Reply-To: <1472009252-1074-1-git-send-email-hs.liao@mediatek.com>
This patch adds the device node of the GCE hardware for CMDQ module.
Signed-off-by: HS Liao <hs.liao@mediatek.com>
---
arch/arm64/boot/dts/mediatek/mt8173.dtsi | 10 ++++++++++
1 file changed, 10 insertions(+)
diff --git a/arch/arm64/boot/dts/mediatek/mt8173.dtsi b/arch/arm64/boot/dts/mediatek/mt8173.dtsi
index 10f638f..00d9d92 100644
--- a/arch/arm64/boot/dts/mediatek/mt8173.dtsi
+++ b/arch/arm64/boot/dts/mediatek/mt8173.dtsi
@@ -383,6 +383,16 @@
#clock-cells = <1>;
};
+ gce: gce@10212000 {
+ compatible = "mediatek,mt8173-gce";
+ reg = <0 0x10212000 0 0x1000>;
+ interrupts = <GIC_SPI 135 IRQ_TYPE_LEVEL_LOW>;
+ clocks = <&infracfg CLK_INFRA_GCE>;
+ clock-names = "gce";
+
+ #mbox-cells = <2>;
+ };
+
mipi_tx0: mipi-dphy@10215000 {
compatible = "mediatek,mt8173-mipi-tx";
reg = <0 0x10215000 0 0x1000>;
--
1.9.1
^ permalink raw reply related
* [PATCH v13 2/4] CMDQ: Mediatek CMDQ driver
From: HS Liao @ 2016-08-24 3:27 UTC (permalink / raw)
To: Rob Herring, Matthias Brugger
Cc: Monica Wang, Jiaguang Zhang, Nicolas Boichat, cawa cheng, HS Liao,
Bibby Hsieh, YT Shen, Damon Chu,
devicetree-u79uwXL29TY76Z2rM5mHXA, Sascha Hauer, Daoyuan Huang,
Sascha Hauer, Glory Hung, CK HU,
linux-mediatek-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r,
linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r,
srv_heupstream-NuS5LvNUpcJWk0Htik3J/w, Josh-YC Liu,
linux-kernel-u79uwXL29TY76Z2rM5mHXA, Dennis-YC Hsieh,
Philipp Zabel
In-Reply-To: <1472009252-1074-1-git-send-email-hs.liao-NuS5LvNUpcJWk0Htik3J/w@public.gmane.org>
This patch is first version of Mediatek Command Queue(CMDQ) driver. The
CMDQ is used to help write registers with critical time limitation,
such as updating display configuration during the vblank. It controls
Global Command Engine (GCE) hardware to achieve this requirement.
Currently, CMDQ only supports display related hardwares, but we expect
it can be extended to other hardwares for future requirements.
Signed-off-by: HS Liao <hs.liao-NuS5LvNUpcJWk0Htik3J/w@public.gmane.org>
Signed-off-by: CK Hu <ck.hu-NuS5LvNUpcJWk0Htik3J/w@public.gmane.org>
---
drivers/soc/mediatek/Kconfig | 11 +
drivers/soc/mediatek/Makefile | 1 +
drivers/soc/mediatek/mtk-cmdq.c | 945 ++++++++++++++++++++++++++++++++++++++++
include/soc/mediatek/cmdq.h | 180 ++++++++
4 files changed, 1137 insertions(+)
create mode 100644 drivers/soc/mediatek/mtk-cmdq.c
create mode 100644 include/soc/mediatek/cmdq.h
diff --git a/drivers/soc/mediatek/Kconfig b/drivers/soc/mediatek/Kconfig
index 0a4ea80..50869e4 100644
--- a/drivers/soc/mediatek/Kconfig
+++ b/drivers/soc/mediatek/Kconfig
@@ -1,6 +1,17 @@
#
# MediaTek SoC drivers
#
+config MTK_CMDQ
+ bool "MediaTek CMDQ Support"
+ depends on ARM64 && ( ARCH_MEDIATEK || COMPILE_TEST )
+ select MAILBOX
+ select MTK_INFRACFG
+ help
+ Say yes here to add support for the MediaTek Command Queue (CMDQ)
+ driver. The CMDQ is used to help read/write registers with critical
+ time limitation, such as updating display configuration during the
+ vblank.
+
config MTK_INFRACFG
bool "MediaTek INFRACFG Support"
depends on ARCH_MEDIATEK || COMPILE_TEST
diff --git a/drivers/soc/mediatek/Makefile b/drivers/soc/mediatek/Makefile
index 12998b0..f7397ef 100644
--- a/drivers/soc/mediatek/Makefile
+++ b/drivers/soc/mediatek/Makefile
@@ -1,3 +1,4 @@
+obj-$(CONFIG_MTK_CMDQ) += mtk-cmdq.o
obj-$(CONFIG_MTK_INFRACFG) += mtk-infracfg.o
obj-$(CONFIG_MTK_PMIC_WRAP) += mtk-pmic-wrap.o
obj-$(CONFIG_MTK_SCPSYS) += mtk-scpsys.o
diff --git a/drivers/soc/mediatek/mtk-cmdq.c b/drivers/soc/mediatek/mtk-cmdq.c
new file mode 100644
index 0000000..7ca3113
--- /dev/null
+++ b/drivers/soc/mediatek/mtk-cmdq.c
@@ -0,0 +1,945 @@
+/*
+ * Copyright (c) 2015 MediaTek Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/bitops.h>
+#include <linux/clk.h>
+#include <linux/clk-provider.h>
+#include <linux/completion.h>
+#include <linux/dma-mapping.h>
+#include <linux/errno.h>
+#include <linux/interrupt.h>
+#include <linux/iopoll.h>
+#include <linux/kernel.h>
+#include <linux/kthread.h>
+#include <linux/mutex.h>
+#include <linux/of_address.h>
+#include <linux/of_irq.h>
+#include <linux/slab.h>
+#include <linux/spinlock.h>
+#include <linux/suspend.h>
+#include <linux/timer.h>
+#include <soc/mediatek/cmdq.h>
+
+#define CMDQ_THR_MAX_COUNT 3 /* main, sub, general(misc) */
+#define CMDQ_INST_SIZE 8 /* instruction is 64-bit */
+#define CMDQ_TIMEOUT_MS 1000
+#define CMDQ_IRQ_MASK 0xffff
+#define CMDQ_NUM_CMD(t) (t->cmd_buf_size / CMDQ_INST_SIZE)
+
+#define CMDQ_CURR_IRQ_STATUS 0x10
+#define CMDQ_THR_SLOT_CYCLES 0x30
+
+#define CMDQ_THR_BASE 0x100
+#define CMDQ_THR_SIZE 0x80
+#define CMDQ_THR_WARM_RESET 0x00
+#define CMDQ_THR_ENABLE_TASK 0x04
+#define CMDQ_THR_SUSPEND_TASK 0x08
+#define CMDQ_THR_CURR_STATUS 0x0c
+#define CMDQ_THR_IRQ_STATUS 0x10
+#define CMDQ_THR_IRQ_ENABLE 0x14
+#define CMDQ_THR_CURR_ADDR 0x20
+#define CMDQ_THR_END_ADDR 0x24
+
+#define CMDQ_THR_ENABLED 0x1
+#define CMDQ_THR_DISABLED 0x0
+#define CMDQ_THR_SUSPEND 0x1
+#define CMDQ_THR_RESUME 0x0
+#define CMDQ_THR_STATUS_SUSPENDED BIT(1)
+#define CMDQ_THR_DO_WARM_RESET BIT(0)
+#define CMDQ_THR_ACTIVE_SLOT_CYCLES 0x3200
+#define CMDQ_THR_IRQ_DONE 0x1
+#define CMDQ_THR_IRQ_ERROR 0x12
+#define CMDQ_THR_IRQ_EN (CMDQ_THR_IRQ_ERROR | CMDQ_THR_IRQ_DONE)
+
+#define CMDQ_OP_CODE_SHIFT 24
+#define CMDQ_SUBSYS_SHIFT 16
+
+#define CMDQ_ARG_A_WRITE_MASK 0xffff
+#define CMDQ_OP_CODE_MASK (0xff << CMDQ_OP_CODE_SHIFT)
+
+#define CMDQ_WRITE_ENABLE_MASK BIT(0)
+#define CMDQ_JUMP_BY_OFFSET 0x10000000
+#define CMDQ_JUMP_BY_PA 0x10000001
+#define CMDQ_JUMP_PASS CMDQ_INST_SIZE
+#define CMDQ_WFE_UPDATE BIT(31)
+#define CMDQ_WFE_WAIT BIT(15)
+#define CMDQ_WFE_WAIT_VALUE 0x1
+#define CMDQ_EOC_IRQ_EN BIT(0)
+
+/*
+ * CMDQ_CODE_MASK:
+ * set write mask
+ * format: op mask
+ * CMDQ_CODE_WRITE:
+ * write value into target register
+ * format: op subsys address value
+ * CMDQ_CODE_JUMP:
+ * jump by offset
+ * format: op offset
+ * CMDQ_CODE_WFE:
+ * wait for event and clear
+ * it is just clear if no wait
+ * format: [wait] op event update:1 to_wait:1 wait:1
+ * [clear] op event update:1 to_wait:0 wait:0
+ * CMDQ_CODE_EOC:
+ * end of command
+ * format: op irq_flag
+ */
+enum cmdq_code {
+ CMDQ_CODE_MASK = 0x02,
+ CMDQ_CODE_WRITE = 0x04,
+ CMDQ_CODE_JUMP = 0x10,
+ CMDQ_CODE_WFE = 0x20,
+ CMDQ_CODE_EOC = 0x40,
+};
+
+struct cmdq_task_cb {
+ cmdq_async_flush_cb cb;
+ void *data;
+};
+
+struct cmdq_thread {
+ struct mbox_chan *chan;
+ void __iomem *base;
+ struct list_head task_busy_list;
+ struct timer_list timeout;
+ bool atomic_exec;
+};
+
+struct cmdq_task {
+ struct cmdq *cmdq;
+ struct list_head list_entry;
+ void *va_base;
+ dma_addr_t pa_base;
+ size_t cmd_buf_size; /* command occupied size */
+ size_t buf_size; /* real buffer size */
+ bool finalized;
+ struct cmdq_thread *thread;
+ struct cmdq_task_cb cb;
+};
+
+struct cmdq {
+ struct mbox_controller mbox;
+ void __iomem *base;
+ u32 irq;
+ struct cmdq_thread thread[CMDQ_THR_MAX_COUNT];
+ struct mutex task_mutex;
+ struct clk *clock;
+ bool suspended;
+};
+
+struct cmdq_subsys {
+ u32 base;
+ int id;
+};
+
+static const struct cmdq_subsys gce_subsys[] = {
+ {0x1400, 1},
+ {0x1401, 2},
+ {0x1402, 3},
+};
+
+static int cmdq_subsys_base_to_id(u32 base)
+{
+ int i;
+
+ for (i = 0; i < ARRAY_SIZE(gce_subsys); i++)
+ if (gce_subsys[i].base == base)
+ return gce_subsys[i].id;
+ return -EFAULT;
+}
+
+static int cmdq_thread_suspend(struct cmdq *cmdq, struct cmdq_thread *thread)
+{
+ u32 status;
+
+ writel(CMDQ_THR_SUSPEND, thread->base + CMDQ_THR_SUSPEND_TASK);
+
+ /* If already disabled, treat as suspended successful. */
+ if (!(readl(thread->base + CMDQ_THR_ENABLE_TASK) & CMDQ_THR_ENABLED))
+ return 0;
+
+ if (readl_poll_timeout_atomic(thread->base + CMDQ_THR_CURR_STATUS,
+ status, status & CMDQ_THR_STATUS_SUSPENDED, 0, 10)) {
+ dev_err(cmdq->mbox.dev, "suspend GCE thread 0x%x failed\n",
+ (u32)(thread->base - cmdq->base));
+ return -EFAULT;
+ }
+
+ return 0;
+}
+
+static void cmdq_thread_resume(struct cmdq_thread *thread)
+{
+ writel(CMDQ_THR_RESUME, thread->base + CMDQ_THR_SUSPEND_TASK);
+}
+
+static int cmdq_thread_reset(struct cmdq *cmdq, struct cmdq_thread *thread)
+{
+ u32 warm_reset;
+
+ writel(CMDQ_THR_DO_WARM_RESET, thread->base + CMDQ_THR_WARM_RESET);
+ if (readl_poll_timeout_atomic(thread->base + CMDQ_THR_WARM_RESET,
+ warm_reset, !(warm_reset & CMDQ_THR_DO_WARM_RESET),
+ 0, 10)) {
+ dev_err(cmdq->mbox.dev, "reset GCE thread 0x%x failed\n",
+ (u32)(thread->base - cmdq->base));
+ return -EFAULT;
+ }
+ writel(CMDQ_THR_ACTIVE_SLOT_CYCLES, cmdq->base + CMDQ_THR_SLOT_CYCLES);
+ return 0;
+}
+
+static void cmdq_thread_disable(struct cmdq *cmdq, struct cmdq_thread *thread)
+{
+ cmdq_thread_reset(cmdq, thread);
+ writel(CMDQ_THR_DISABLED, thread->base + CMDQ_THR_ENABLE_TASK);
+}
+
+/* notify GCE to re-fetch commands by setting GCE thread PC */
+static void cmdq_thread_invalidate_fetched_data(struct cmdq_thread *thread)
+{
+ writel(readl(thread->base + CMDQ_THR_CURR_ADDR),
+ thread->base + CMDQ_THR_CURR_ADDR);
+}
+
+static void cmdq_task_insert_into_thread(struct cmdq_task *task)
+{
+ struct device *dev = task->cmdq->mbox.dev;
+ struct cmdq_thread *thread = task->thread;
+ struct cmdq_task *prev_task = list_last_entry(
+ &thread->task_busy_list, typeof(*task), list_entry);
+ u64 *prev_task_base = prev_task->va_base;
+
+ /* let previous task jump to this task */
+ dma_sync_single_for_cpu(dev, prev_task->pa_base,
+ prev_task->cmd_buf_size, DMA_TO_DEVICE);
+ prev_task_base[CMDQ_NUM_CMD(prev_task) - 1] =
+ (u64)CMDQ_JUMP_BY_PA << 32 | task->pa_base;
+ dma_sync_single_for_device(dev, prev_task->pa_base,
+ prev_task->cmd_buf_size, DMA_TO_DEVICE);
+
+ cmdq_thread_invalidate_fetched_data(thread);
+}
+
+static bool cmdq_command_is_wfe(u64 cmd)
+{
+ u64 wfe_option = CMDQ_WFE_UPDATE | CMDQ_WFE_WAIT | CMDQ_WFE_WAIT_VALUE;
+ u64 wfe_op = (u64)(CMDQ_CODE_WFE << CMDQ_OP_CODE_SHIFT) << 32;
+ u64 wfe_mask = (u64)CMDQ_OP_CODE_MASK << 32 | 0xffffffff;
+
+ return ((cmd & wfe_mask) == (wfe_op | wfe_option));
+}
+
+/* we assume tasks in the same display GCE thread are waiting the same event. */
+static void cmdq_task_remove_wfe(struct cmdq_task *task)
+{
+ struct device *dev = task->cmdq->mbox.dev;
+ u64 *base = task->va_base;
+ int i;
+
+ dma_sync_single_for_cpu(dev, task->pa_base, task->cmd_buf_size,
+ DMA_TO_DEVICE);
+ for (i = 0; i < CMDQ_NUM_CMD(task); i++)
+ if (cmdq_command_is_wfe(base[i]))
+ base[i] = (u64)CMDQ_JUMP_BY_OFFSET << 32 |
+ CMDQ_JUMP_PASS;
+ dma_sync_single_for_device(dev, task->pa_base, task->cmd_buf_size,
+ DMA_TO_DEVICE);
+}
+
+static bool cmdq_thread_is_in_wfe(struct cmdq_thread *thread,
+ unsigned long curr_pa)
+{
+ struct device *dev = thread->chan->mbox->dev;
+ struct cmdq_task *task;
+ u32 task_end_pa;
+ u64 *va;
+ bool ret;
+
+ task = list_first_entry(&thread->task_busy_list, struct cmdq_task,
+ list_entry);
+ task_end_pa = task->pa_base + task->cmd_buf_size;
+ if (!(curr_pa >= task->pa_base &&
+ curr_pa < task_end_pa - CMDQ_INST_SIZE))
+ return false;
+
+ va = task->va_base + (curr_pa - task->pa_base);
+ dma_sync_single_for_cpu(dev, task->pa_base, task->cmd_buf_size,
+ DMA_TO_DEVICE);
+ ret = cmdq_command_is_wfe(*va);
+ dma_sync_single_for_device(dev, task->pa_base, task->cmd_buf_size,
+ DMA_TO_DEVICE);
+ return ret;
+}
+
+static void cmdq_thread_wait_end(struct cmdq_thread *thread,
+ unsigned long end_pa)
+{
+ struct device *dev = thread->chan->mbox->dev;
+ unsigned long curr_pa;
+
+ if (readl_poll_timeout_atomic(thread->base + CMDQ_THR_CURR_ADDR,
+ curr_pa, curr_pa == end_pa, 1, 20))
+ dev_err(dev, "GCE thread cannot run to end.\n");
+}
+
+static void cmdq_task_exec(struct cmdq_task *task, struct cmdq_thread *thread)
+{
+ struct cmdq *cmdq = task->cmdq;
+ unsigned long curr_pa, end_pa;
+
+ task->thread = thread;
+ if (list_empty(&thread->task_busy_list)) {
+ WARN_ON(clk_enable(cmdq->clock) < 0);
+ WARN_ON(cmdq_thread_reset(cmdq, thread) < 0);
+
+ writel(task->pa_base, thread->base + CMDQ_THR_CURR_ADDR);
+ writel(task->pa_base + task->cmd_buf_size,
+ thread->base + CMDQ_THR_END_ADDR);
+ writel(CMDQ_THR_IRQ_EN, thread->base + CMDQ_THR_IRQ_ENABLE);
+ writel(CMDQ_THR_ENABLED, thread->base + CMDQ_THR_ENABLE_TASK);
+
+ mod_timer(&thread->timeout,
+ jiffies + msecs_to_jiffies(CMDQ_TIMEOUT_MS));
+ } else {
+ WARN_ON(cmdq_thread_suspend(cmdq, thread) < 0);
+ curr_pa = readl(thread->base + CMDQ_THR_CURR_ADDR);
+ end_pa = readl(thread->base + CMDQ_THR_END_ADDR);
+
+ /*
+ * Atomic execution should remove the following wfe, i.e. only
+ * wait event at first task, and prevent to pause when running.
+ */
+ if (thread->atomic_exec) {
+ /* GCE is executing if command is not WFE */
+ if (!cmdq_thread_is_in_wfe(thread, curr_pa)) {
+ cmdq_thread_resume(thread);
+ cmdq_thread_wait_end(thread, end_pa);
+ WARN_ON(cmdq_thread_suspend(cmdq, thread) < 0);
+ /* set to this task directly */
+ writel(task->pa_base,
+ thread->base + CMDQ_THR_CURR_ADDR);
+ } else {
+ cmdq_task_insert_into_thread(task);
+ cmdq_task_remove_wfe(task);
+ smp_mb(); /* modify jump before enable thread */
+ }
+ } else {
+ /* check boundary */
+ if (curr_pa == end_pa - CMDQ_INST_SIZE ||
+ curr_pa == end_pa) {
+ /* set to this task directly */
+ writel(task->pa_base,
+ thread->base + CMDQ_THR_CURR_ADDR);
+ } else {
+ cmdq_task_insert_into_thread(task);
+ smp_mb(); /* modify jump before enable thread */
+ }
+ }
+ writel(task->pa_base + task->cmd_buf_size,
+ thread->base + CMDQ_THR_END_ADDR);
+ cmdq_thread_resume(thread);
+ }
+ list_move_tail(&task->list_entry, &thread->task_busy_list);
+}
+
+static void cmdq_task_exec_done(struct cmdq_task *task, bool err)
+{
+ struct device *dev = task->cmdq->mbox.dev;
+ struct cmdq_cb_data cmdq_cb_data;
+
+ if (task->cb.cb) {
+ cmdq_cb_data.err = err;
+ cmdq_cb_data.data = task->cb.data;
+ task->cb.cb(cmdq_cb_data);
+ }
+ list_del(&task->list_entry);
+ dma_unmap_single(dev, task->pa_base, task->cmd_buf_size, DMA_TO_DEVICE);
+ kfree(task->va_base);
+}
+
+static void cmdq_task_handle_error(struct cmdq_task *task)
+{
+ struct cmdq_thread *thread = task->thread;
+ struct cmdq_task *next_task;
+
+ dev_err(task->cmdq->mbox.dev, "task 0x%p error\n", task);
+ WARN_ON(cmdq_thread_suspend(task->cmdq, thread) < 0);
+ next_task = list_first_entry_or_null(&thread->task_busy_list,
+ struct cmdq_task, list_entry);
+ if (next_task)
+ writel(next_task->pa_base, thread->base + CMDQ_THR_CURR_ADDR);
+ cmdq_thread_resume(thread);
+}
+
+static void cmdq_thread_irq_handler(struct cmdq *cmdq,
+ struct cmdq_thread *thread)
+{
+ struct cmdq_task *task, *tmp, *curr_task = NULL;
+ u32 curr_pa, irq_flag, task_end_pa;
+ bool err;
+
+ irq_flag = readl(thread->base + CMDQ_THR_IRQ_STATUS);
+ writel(~irq_flag, thread->base + CMDQ_THR_IRQ_STATUS);
+
+ /*
+ * When ISR call this function, another CPU core could run
+ * "release task" right before we acquire the spin lock, and thus
+ * reset / disable this GCE thread, so we need to check the enable
+ * bit of this GCE thread.
+ */
+ if (!(readl(thread->base + CMDQ_THR_ENABLE_TASK) & CMDQ_THR_ENABLED))
+ return;
+
+ if (irq_flag & CMDQ_THR_IRQ_ERROR)
+ err = true;
+ else if (irq_flag & CMDQ_THR_IRQ_DONE)
+ err = false;
+ else
+ return;
+
+ curr_pa = readl(thread->base + CMDQ_THR_CURR_ADDR);
+
+ list_for_each_entry_safe(task, tmp, &thread->task_busy_list,
+ list_entry) {
+ task_end_pa = task->pa_base + task->cmd_buf_size;
+ if (curr_pa >= task->pa_base && curr_pa < task_end_pa)
+ curr_task = task;
+
+ if (!curr_task || curr_pa == task_end_pa - CMDQ_INST_SIZE) {
+ cmdq_task_exec_done(task, false);
+ kfree(task);
+ } else if (err) {
+ cmdq_task_exec_done(task, true);
+ cmdq_task_handle_error(curr_task);
+ kfree(task);
+ }
+
+ if (curr_task)
+ break;
+ }
+
+ if (list_empty(&thread->task_busy_list)) {
+ cmdq_thread_disable(cmdq, thread);
+ clk_disable(cmdq->clock);
+ } else {
+ mod_timer(&thread->timeout,
+ jiffies + msecs_to_jiffies(CMDQ_TIMEOUT_MS));
+ }
+}
+
+static irqreturn_t cmdq_irq_handler(int irq, void *dev)
+{
+ struct cmdq *cmdq = dev;
+ unsigned long irq_status, flags = 0L;
+ int bit;
+
+ irq_status = readl(cmdq->base + CMDQ_CURR_IRQ_STATUS) & CMDQ_IRQ_MASK;
+ if (!(irq_status ^ CMDQ_IRQ_MASK))
+ return IRQ_NONE;
+
+ for_each_clear_bit(bit, &irq_status, fls(CMDQ_IRQ_MASK)) {
+ struct cmdq_thread *thread = &cmdq->thread[bit];
+
+ spin_lock_irqsave(&thread->chan->lock, flags);
+ cmdq_thread_irq_handler(cmdq, thread);
+ spin_unlock_irqrestore(&thread->chan->lock, flags);
+ }
+ return IRQ_HANDLED;
+}
+
+static void cmdq_thread_handle_timeout(unsigned long data)
+{
+ struct cmdq_thread *thread = (struct cmdq_thread *)data;
+ struct cmdq *cmdq = container_of(thread->chan->mbox, struct cmdq, mbox);
+ struct cmdq_task *task, *tmp;
+ unsigned long flags;
+
+ spin_lock_irqsave(&thread->chan->lock, flags);
+ WARN_ON(cmdq_thread_suspend(cmdq, thread) < 0);
+
+ /*
+ * Although IRQ is disabled, GCE continues to execute.
+ * It may have pending IRQ before GCE thread is suspended,
+ * so check this condition again.
+ */
+ cmdq_thread_irq_handler(cmdq, thread);
+
+ if (list_empty(&thread->task_busy_list)) {
+ cmdq_thread_resume(thread);
+ spin_unlock_irqrestore(&thread->chan->lock, flags);
+ return;
+ }
+
+ dev_err(cmdq->mbox.dev, "timeout\n");
+ list_for_each_entry_safe(task, tmp, &thread->task_busy_list,
+ list_entry) {
+ cmdq_task_exec_done(task, true);
+ kfree(task);
+ }
+
+ cmdq_thread_resume(thread);
+ cmdq_thread_disable(cmdq, thread);
+ clk_disable(cmdq->clock);
+ spin_unlock_irqrestore(&thread->chan->lock, flags);
+}
+
+static int cmdq_task_realloc_cmd_buffer(struct cmdq_task *task, size_t size)
+{
+ void *new_buf;
+
+ new_buf = krealloc(task->va_base, size, GFP_KERNEL | __GFP_ZERO);
+ if (!new_buf)
+ return -ENOMEM;
+ task->va_base = new_buf;
+ task->buf_size = size;
+ return 0;
+}
+
+struct cmdq_base *cmdq_register_device(struct device *dev)
+{
+ struct cmdq_base *cmdq_base;
+ struct resource res;
+ int subsys;
+ u32 base;
+
+ if (of_address_to_resource(dev->of_node, 0, &res))
+ return NULL;
+ base = (u32)res.start;
+
+ subsys = cmdq_subsys_base_to_id(base >> 16);
+ if (subsys < 0)
+ return NULL;
+
+ cmdq_base = devm_kmalloc(dev, sizeof(*cmdq_base), GFP_KERNEL);
+ if (!cmdq_base)
+ return NULL;
+ cmdq_base->subsys = subsys;
+ cmdq_base->base = base;
+
+ return cmdq_base;
+}
+EXPORT_SYMBOL(cmdq_register_device);
+
+struct cmdq_client *cmdq_mbox_create(struct device *dev, int index)
+{
+ struct cmdq_client *client;
+
+ client = kzalloc(sizeof(*client), GFP_KERNEL);
+ client->client.dev = dev;
+ client->client.tx_block = false;
+ client->chan = mbox_request_channel(&client->client, index);
+ return client;
+}
+EXPORT_SYMBOL(cmdq_mbox_create);
+
+int cmdq_task_create(struct device *dev, struct cmdq_task **task_ptr)
+{
+ struct cmdq_task *task;
+ int err;
+
+ task = kzalloc(sizeof(*task), GFP_KERNEL);
+ if (!task)
+ return -ENOMEM;
+ task->cmdq = dev_get_drvdata(dev);
+ err = cmdq_task_realloc_cmd_buffer(task, PAGE_SIZE);
+ if (err < 0) {
+ kfree(task);
+ return err;
+ }
+ *task_ptr = task;
+ return 0;
+}
+EXPORT_SYMBOL(cmdq_task_create);
+
+static int cmdq_task_append_command(struct cmdq_task *task, enum cmdq_code code,
+ u32 arg_a, u32 arg_b)
+{
+ u64 *cmd_ptr;
+ int err;
+
+ if (WARN_ON(task->finalized))
+ return -EBUSY;
+ if (unlikely(task->cmd_buf_size + CMDQ_INST_SIZE > task->buf_size)) {
+ err = cmdq_task_realloc_cmd_buffer(task, task->buf_size * 2);
+ if (err < 0)
+ return err;
+ }
+ cmd_ptr = task->va_base + task->cmd_buf_size;
+ (*cmd_ptr) = (u64)((code << CMDQ_OP_CODE_SHIFT) | arg_a) << 32 | arg_b;
+ task->cmd_buf_size += CMDQ_INST_SIZE;
+ return 0;
+}
+
+int cmdq_task_write(struct cmdq_task *task, u32 value, struct cmdq_base *base,
+ u32 offset)
+{
+ u32 arg_a = ((base->base + offset) & CMDQ_ARG_A_WRITE_MASK) |
+ (base->subsys << CMDQ_SUBSYS_SHIFT);
+ return cmdq_task_append_command(task, CMDQ_CODE_WRITE, arg_a, value);
+}
+EXPORT_SYMBOL(cmdq_task_write);
+
+int cmdq_task_write_mask(struct cmdq_task *task, u32 value,
+ struct cmdq_base *base, u32 offset, u32 mask)
+{
+ u32 offset_mask = offset;
+ int err;
+
+ if (mask != 0xffffffff) {
+ err = cmdq_task_append_command(task, CMDQ_CODE_MASK, 0, ~mask);
+ if (err < 0)
+ return err;
+ offset_mask |= CMDQ_WRITE_ENABLE_MASK;
+ }
+ return cmdq_task_write(task, value, base, offset_mask);
+}
+EXPORT_SYMBOL(cmdq_task_write_mask);
+
+static const u32 cmdq_event_value[CMDQ_MAX_EVENT] = {
+ /* Display start of frame(SOF) events */
+ [CMDQ_EVENT_DISP_OVL0_SOF] = 11,
+ [CMDQ_EVENT_DISP_OVL1_SOF] = 12,
+ [CMDQ_EVENT_DISP_RDMA0_SOF] = 13,
+ [CMDQ_EVENT_DISP_RDMA1_SOF] = 14,
+ [CMDQ_EVENT_DISP_RDMA2_SOF] = 15,
+ [CMDQ_EVENT_DISP_WDMA0_SOF] = 16,
+ [CMDQ_EVENT_DISP_WDMA1_SOF] = 17,
+ /* Display end of frame(EOF) events */
+ [CMDQ_EVENT_DISP_OVL0_EOF] = 39,
+ [CMDQ_EVENT_DISP_OVL1_EOF] = 40,
+ [CMDQ_EVENT_DISP_RDMA0_EOF] = 41,
+ [CMDQ_EVENT_DISP_RDMA1_EOF] = 42,
+ [CMDQ_EVENT_DISP_RDMA2_EOF] = 43,
+ [CMDQ_EVENT_DISP_WDMA0_EOF] = 44,
+ [CMDQ_EVENT_DISP_WDMA1_EOF] = 45,
+ /* Mutex end of frame(EOF) events */
+ [CMDQ_EVENT_MUTEX0_STREAM_EOF] = 53,
+ [CMDQ_EVENT_MUTEX1_STREAM_EOF] = 54,
+ [CMDQ_EVENT_MUTEX2_STREAM_EOF] = 55,
+ [CMDQ_EVENT_MUTEX3_STREAM_EOF] = 56,
+ [CMDQ_EVENT_MUTEX4_STREAM_EOF] = 57,
+ /* Display underrun events */
+ [CMDQ_EVENT_DISP_RDMA0_UNDERRUN] = 63,
+ [CMDQ_EVENT_DISP_RDMA1_UNDERRUN] = 64,
+ [CMDQ_EVENT_DISP_RDMA2_UNDERRUN] = 65,
+};
+
+int cmdq_task_wfe(struct cmdq_task *task, enum cmdq_event event)
+{
+ u32 arg_b;
+
+ if (event >= CMDQ_MAX_EVENT || event < 0)
+ return -EINVAL;
+
+ /*
+ * WFE arg_b
+ * bit 0-11: wait value
+ * bit 15: 1 - wait, 0 - no wait
+ * bit 16-27: update value
+ * bit 31: 1 - update, 0 - no update
+ */
+ arg_b = CMDQ_WFE_UPDATE | CMDQ_WFE_WAIT | CMDQ_WFE_WAIT_VALUE;
+ return cmdq_task_append_command(task, CMDQ_CODE_WFE,
+ cmdq_event_value[event], arg_b);
+}
+EXPORT_SYMBOL(cmdq_task_wfe);
+
+int cmdq_task_clear_event(struct cmdq_task *task, enum cmdq_event event)
+{
+ if (event >= CMDQ_MAX_EVENT || event < 0)
+ return -EINVAL;
+
+ return cmdq_task_append_command(task, CMDQ_CODE_WFE,
+ cmdq_event_value[event], CMDQ_WFE_UPDATE);
+}
+EXPORT_SYMBOL(cmdq_task_clear_event);
+
+static int cmdq_task_finalize(struct cmdq_task *task)
+{
+ int err;
+
+ if (task->finalized)
+ return 0;
+
+ /* insert EOC and generate IRQ for each command iteration */
+ err = cmdq_task_append_command(task, CMDQ_CODE_EOC, 0, CMDQ_EOC_IRQ_EN);
+ if (err < 0)
+ return err;
+
+ /* JUMP to end */
+ err = cmdq_task_append_command(task, CMDQ_CODE_JUMP, 0, CMDQ_JUMP_PASS);
+ if (err < 0)
+ return err;
+
+ task->finalized = true;
+ return 0;
+}
+
+int cmdq_task_flush_async(struct cmdq_client *client, struct cmdq_task *task,
+ cmdq_async_flush_cb cb, void *data)
+{
+ struct cmdq *cmdq = task->cmdq;
+ int err;
+
+ mutex_lock(&cmdq->task_mutex);
+ if (cmdq->suspended) {
+ dev_err(cmdq->mbox.dev, "%s is called after suspended\n",
+ __func__);
+ mutex_unlock(&cmdq->task_mutex);
+ return -EPERM;
+ }
+
+ err = cmdq_task_finalize(task);
+ if (err < 0) {
+ mutex_unlock(&cmdq->task_mutex);
+ return err;
+ }
+
+ INIT_LIST_HEAD(&task->list_entry);
+ task->cb.cb = cb;
+ task->cb.data = data;
+ task->pa_base = dma_map_single(cmdq->mbox.dev, task->va_base,
+ task->cmd_buf_size, DMA_TO_DEVICE);
+
+ mbox_send_message(client->chan, task);
+ /* We can send next task immediately, so just call txdone. */
+ mbox_client_txdone(client->chan, 0);
+ mutex_unlock(&cmdq->task_mutex);
+ return 0;
+}
+EXPORT_SYMBOL(cmdq_task_flush_async);
+
+struct cmdq_flush_completion {
+ struct completion cmplt;
+ bool err;
+};
+
+static void cmdq_task_flush_cb(struct cmdq_cb_data data)
+{
+ struct cmdq_flush_completion *cmplt = data.data;
+
+ cmplt->err = data.err;
+ complete(&cmplt->cmplt);
+}
+
+int cmdq_task_flush(struct cmdq_client *client, struct cmdq_task *task)
+{
+ struct cmdq_flush_completion cmplt;
+ int err;
+
+ init_completion(&cmplt.cmplt);
+ err = cmdq_task_flush_async(client, task, cmdq_task_flush_cb, &cmplt);
+ if (err < 0)
+ return err;
+ wait_for_completion(&cmplt.cmplt);
+ return cmplt.err ? -EFAULT : 0;
+}
+EXPORT_SYMBOL(cmdq_task_flush);
+
+void cmdq_mbox_free(struct cmdq_client *client)
+{
+ mbox_free_channel(client->chan);
+ kfree(client);
+}
+EXPORT_SYMBOL(cmdq_mbox_free);
+
+static int cmdq_suspend(struct device *dev)
+{
+ struct cmdq *cmdq = dev_get_drvdata(dev);
+ struct cmdq_thread *thread;
+ int i;
+ bool task_running = false;
+
+ mutex_lock(&cmdq->task_mutex);
+ cmdq->suspended = true;
+ mutex_unlock(&cmdq->task_mutex);
+
+ for (i = 0; i < ARRAY_SIZE(cmdq->thread); i++) {
+ thread = &cmdq->thread[i];
+ if (!list_empty(&thread->task_busy_list)) {
+ mod_timer(&thread->timeout, jiffies + 1);
+ task_running = true;
+ }
+ }
+
+ if (task_running) {
+ dev_warn(dev, "exist running task(s) in suspend\n");
+ msleep(20);
+ }
+
+ clk_unprepare(cmdq->clock);
+ return 0;
+}
+
+static int cmdq_resume(struct device *dev)
+{
+ struct cmdq *cmdq = dev_get_drvdata(dev);
+
+ WARN_ON(clk_prepare(cmdq->clock) < 0);
+ cmdq->suspended = false;
+ return 0;
+}
+
+static int cmdq_remove(struct platform_device *pdev)
+{
+ struct cmdq *cmdq = platform_get_drvdata(pdev);
+
+ mbox_controller_unregister(&cmdq->mbox);
+ clk_unprepare(cmdq->clock);
+ return 0;
+}
+
+static int cmdq_mbox_send_data(struct mbox_chan *chan, void *data)
+{
+ cmdq_task_exec(data, chan->con_priv);
+ return 0;
+}
+
+static int cmdq_mbox_startup(struct mbox_chan *chan)
+{
+ return 0;
+}
+
+static void cmdq_mbox_shutdown(struct mbox_chan *chan)
+{
+}
+
+static bool cmdq_mbox_last_tx_done(struct mbox_chan *chan)
+{
+ return true;
+}
+
+static const struct mbox_chan_ops cmdq_mbox_chan_ops = {
+ .send_data = cmdq_mbox_send_data,
+ .startup = cmdq_mbox_startup,
+ .shutdown = cmdq_mbox_shutdown,
+ .last_tx_done = cmdq_mbox_last_tx_done,
+};
+
+static struct mbox_chan *cmdq_xlate(struct mbox_controller *mbox,
+ const struct of_phandle_args *sp)
+{
+ int ind = sp->args[0];
+ struct cmdq_thread *thread;
+
+ if (ind >= mbox->num_chans)
+ return ERR_PTR(-EINVAL);
+
+ thread = mbox->chans[ind].con_priv;
+ thread->atomic_exec = (sp->args[1] != 0);
+ thread->chan = &mbox->chans[ind];
+
+ return &mbox->chans[ind];
+}
+
+static int cmdq_probe(struct platform_device *pdev)
+{
+ struct device *dev = &pdev->dev;
+ struct device_node *node = dev->of_node;
+ struct resource *res;
+ struct cmdq *cmdq;
+ int err, i;
+
+ cmdq = devm_kzalloc(dev, sizeof(*cmdq), GFP_KERNEL);
+ if (!cmdq)
+ return -ENOMEM;
+
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ cmdq->base = devm_ioremap_resource(dev, res);
+ if (IS_ERR(cmdq->base)) {
+ dev_err(dev, "failed to ioremap gce\n");
+ return PTR_ERR(cmdq->base);
+ }
+
+ cmdq->irq = irq_of_parse_and_map(node, 0);
+ if (!cmdq->irq) {
+ dev_err(dev, "failed to get irq\n");
+ return -EINVAL;
+ }
+ err = devm_request_irq(dev, cmdq->irq, cmdq_irq_handler, IRQF_SHARED,
+ "mtk_cmdq", cmdq);
+ if (err < 0) {
+ dev_err(dev, "failed to register ISR (%d)\n", err);
+ return err;
+ }
+
+ dev_dbg(dev, "cmdq device: addr:0x%p, va:0x%p, irq:%d\n",
+ dev, cmdq->base, cmdq->irq);
+
+ cmdq->clock = devm_clk_get(dev, "gce");
+ if (IS_ERR(cmdq->clock)) {
+ dev_err(dev, "failed to get gce clk\n");
+ return PTR_ERR(cmdq->clock);
+ }
+
+ mutex_init(&cmdq->task_mutex);
+
+ cmdq->mbox.dev = dev;
+ cmdq->mbox.chans = devm_kcalloc(dev, CMDQ_THR_MAX_COUNT,
+ sizeof(*cmdq->mbox.chans), GFP_KERNEL);
+ if (!cmdq->mbox.chans)
+ return -ENOMEM;
+
+ cmdq->mbox.num_chans = CMDQ_THR_MAX_COUNT;
+ cmdq->mbox.ops = &cmdq_mbox_chan_ops;
+ cmdq->mbox.of_xlate = cmdq_xlate;
+
+ /* make use of TXDONE_BY_ACK */
+ cmdq->mbox.txdone_irq = false;
+ cmdq->mbox.txdone_poll = false;
+
+ for (i = 0; i < ARRAY_SIZE(cmdq->thread); i++) {
+ cmdq->thread[i].base = cmdq->base + CMDQ_THR_BASE +
+ CMDQ_THR_SIZE * i;
+ INIT_LIST_HEAD(&cmdq->thread[i].task_busy_list);
+ init_timer(&cmdq->thread[i].timeout);
+ cmdq->thread[i].timeout.function = cmdq_thread_handle_timeout;
+ cmdq->thread[i].timeout.data = (unsigned long)&cmdq->thread[i];
+ cmdq->mbox.chans[i].con_priv = &cmdq->thread[i];
+ }
+
+ err = mbox_controller_register(&cmdq->mbox);
+ if (err < 0) {
+ dev_err(dev, "failed to register mailbox: %d\n", err);
+ return err;
+ }
+
+ platform_set_drvdata(pdev, cmdq);
+ WARN_ON(clk_prepare(cmdq->clock) < 0);
+ return 0;
+}
+
+static const struct dev_pm_ops cmdq_pm_ops = {
+ .suspend = cmdq_suspend,
+ .resume = cmdq_resume,
+};
+
+static const struct of_device_id cmdq_of_ids[] = {
+ {.compatible = "mediatek,mt8173-gce",},
+ {}
+};
+
+static struct platform_driver cmdq_drv = {
+ .probe = cmdq_probe,
+ .remove = cmdq_remove,
+ .driver = {
+ .name = "mtk_cmdq",
+ .owner = THIS_MODULE,
+ .pm = &cmdq_pm_ops,
+ .of_match_table = cmdq_of_ids,
+ }
+};
+
+builtin_platform_driver(cmdq_drv);
diff --git a/include/soc/mediatek/cmdq.h b/include/soc/mediatek/cmdq.h
new file mode 100644
index 0000000..c3c924d
--- /dev/null
+++ b/include/soc/mediatek/cmdq.h
@@ -0,0 +1,180 @@
+/*
+ * Copyright (c) 2015 MediaTek Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#ifndef __MTK_CMDQ_H__
+#define __MTK_CMDQ_H__
+
+#include <linux/mailbox_client.h>
+#include <linux/mailbox_controller.h>
+#include <linux/platform_device.h>
+#include <linux/types.h>
+
+/* display events in command queue(CMDQ) */
+enum cmdq_event {
+ /* Display start of frame(SOF) events */
+ CMDQ_EVENT_DISP_OVL0_SOF,
+ CMDQ_EVENT_DISP_OVL1_SOF,
+ CMDQ_EVENT_DISP_RDMA0_SOF,
+ CMDQ_EVENT_DISP_RDMA1_SOF,
+ CMDQ_EVENT_DISP_RDMA2_SOF,
+ CMDQ_EVENT_DISP_WDMA0_SOF,
+ CMDQ_EVENT_DISP_WDMA1_SOF,
+ /* Display end of frame(EOF) events */
+ CMDQ_EVENT_DISP_OVL0_EOF,
+ CMDQ_EVENT_DISP_OVL1_EOF,
+ CMDQ_EVENT_DISP_RDMA0_EOF,
+ CMDQ_EVENT_DISP_RDMA1_EOF,
+ CMDQ_EVENT_DISP_RDMA2_EOF,
+ CMDQ_EVENT_DISP_WDMA0_EOF,
+ CMDQ_EVENT_DISP_WDMA1_EOF,
+ /* Mutex end of frame(EOF) events */
+ CMDQ_EVENT_MUTEX0_STREAM_EOF,
+ CMDQ_EVENT_MUTEX1_STREAM_EOF,
+ CMDQ_EVENT_MUTEX2_STREAM_EOF,
+ CMDQ_EVENT_MUTEX3_STREAM_EOF,
+ CMDQ_EVENT_MUTEX4_STREAM_EOF,
+ /* Display underrun events */
+ CMDQ_EVENT_DISP_RDMA0_UNDERRUN,
+ CMDQ_EVENT_DISP_RDMA1_UNDERRUN,
+ CMDQ_EVENT_DISP_RDMA2_UNDERRUN,
+ /* Keep this at the end */
+ CMDQ_MAX_EVENT,
+};
+
+struct cmdq_cb_data {
+ bool err;
+ void *data;
+};
+
+typedef void (*cmdq_async_flush_cb)(struct cmdq_cb_data data);
+
+struct cmdq_task;
+
+struct cmdq_base {
+ int subsys;
+ u32 base;
+};
+
+struct cmdq_client {
+ struct mbox_client client;
+ struct mbox_chan *chan;
+};
+
+/**
+ * cmdq_register_device() - register device which needs CMDQ
+ * @dev: device for CMDQ to access its registers
+ *
+ * Return: cmdq_base pointer or NULL for failed
+ */
+struct cmdq_base *cmdq_register_device(struct device *dev);
+
+/**
+ * cmdq_mbox_create() - create CMDQ mailbox client and channel
+ * @dev: device of CMDQ mailbox client
+ * @index: index of CMDQ mailbox channel
+ *
+ * Return: CMDQ mailbox client pointer
+ */
+struct cmdq_client *cmdq_mbox_create(struct device *dev, int index);
+
+/**
+ * cmdq_task_create() - create CMDQ task
+ * @dev: CMDQ device
+ * @task_ptr: CMDQ task pointer to retrieve cmdq_task
+ *
+ * Return: 0 for success; else the error code is returned
+ */
+int cmdq_task_create(struct device *dev, struct cmdq_task **task_ptr);
+
+/**
+ * cmdq_task_write() - append write command to the CMDQ task
+ * @task: the CMDQ task
+ * @value: the specified target register value
+ * @base: the CMDQ base
+ * @offset: register offset from module base
+ *
+ * Return: 0 for success; else the error code is returned
+ */
+int cmdq_task_write(struct cmdq_task *task, u32 value,
+ struct cmdq_base *base, u32 offset);
+
+/**
+ * cmdq_task_write_mask() - append write command with mask to the CMDQ task
+ * @task: the CMDQ task
+ * @value: the specified target register value
+ * @base: the CMDQ base
+ * @offset: register offset from module base
+ * @mask: the specified target register mask
+ *
+ * Return: 0 for success; else the error code is returned
+ */
+int cmdq_task_write_mask(struct cmdq_task *task, u32 value,
+ struct cmdq_base *base, u32 offset, u32 mask);
+
+/**
+ * cmdq_task_wfe() - append wait for event command to the CMDQ task
+ * @task: the CMDQ task
+ * @event: the desired event type to "wait and CLEAR"
+ *
+ * Return: 0 for success; else the error code is returned
+ */
+int cmdq_task_wfe(struct cmdq_task *task, enum cmdq_event event);
+
+/**
+ * cmdq_task_clear_event() - append clear event command to the CMDQ task
+ * @task: the CMDQ task
+ * @event: the desired event to be cleared
+ *
+ * Return: 0 for success; else the error code is returned
+ */
+int cmdq_task_clear_event(struct cmdq_task *task, enum cmdq_event event);
+
+/**
+ * cmdq_task_flush() - trigger CMDQ to execute the recorded commands
+ * @client: the CMDQ mailbox client
+ * @task: the CMDQ task
+ *
+ * Return: 0 for success; else the error code is returned
+ *
+ * Trigger CMDQ to execute the recorded commands. Note that this is a
+ * synchronous flush function. When the function returned, the recorded
+ * commands have been done. CMDQ task will be destroy automatically
+ * after CMDQ finish all the recorded commands.
+ */
+int cmdq_task_flush(struct cmdq_client *client, struct cmdq_task *task);
+
+/**
+ * cmdq_task_flush_async() - trigger CMDQ to asynchronously execute the recorded
+ * commands and call back at the end of ISR
+ * @client: the CMDQ mailbox client
+ * @task: the CMDQ task
+ * @cb: called at the end of CMDQ ISR
+ * @data: this data will pass back to cb
+ *
+ * Return: 0 for success; else the error code is returned
+ *
+ * Trigger CMDQ to asynchronously execute the recorded commands and call back
+ * at the end of ISR. Note that this is an ASYNC function. When the function
+ * returned, it may or may not be finished. CMDQ task will be destroy
+ * automatically after CMDQ finish all the recorded commands.
+ */
+int cmdq_task_flush_async(struct cmdq_client *client, struct cmdq_task *task,
+ cmdq_async_flush_cb cb, void *data);
+
+/**
+ * cmdq_mbox_free() - destroy CMDQ mailbox client and channel
+ * @client: the CMDQ mailbox client
+ */
+void cmdq_mbox_free(struct cmdq_client *client);
+
+#endif /* __MTK_CMDQ_H__ */
--
1.9.1
^ permalink raw reply related
* [PATCH v13 1/4] dt-bindings: soc: Add documentation for the MediaTek GCE unit
From: HS Liao @ 2016-08-24 3:27 UTC (permalink / raw)
To: Rob Herring, Matthias Brugger
Cc: Monica Wang, Jiaguang Zhang, Nicolas Boichat, cawa cheng, HS Liao,
Bibby Hsieh, YT Shen, Damon Chu,
devicetree-u79uwXL29TY76Z2rM5mHXA, Sascha Hauer, Daoyuan Huang,
Sascha Hauer, Glory Hung, CK HU,
linux-mediatek-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r,
linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r,
srv_heupstream-NuS5LvNUpcJWk0Htik3J/w, Josh-YC Liu,
linux-kernel-u79uwXL29TY76Z2rM5mHXA, Dennis-YC Hsieh,
Philipp Zabel
In-Reply-To: <1472009252-1074-1-git-send-email-hs.liao-NuS5LvNUpcJWk0Htik3J/w@public.gmane.org>
This adds documentation for the MediaTek Global Command Engine (GCE) unit
found in MT8173 SoCs.
Signed-off-by: HS Liao <hs.liao-NuS5LvNUpcJWk0Htik3J/w@public.gmane.org>
Acked-by: Rob Herring <robh-DgEjT+Ai2ygdnm+yROfE0A@public.gmane.org>
---
.../devicetree/bindings/soc/mediatek/gce.txt | 44 ++++++++++++++++++++++
1 file changed, 44 insertions(+)
create mode 100644 Documentation/devicetree/bindings/soc/mediatek/gce.txt
diff --git a/Documentation/devicetree/bindings/soc/mediatek/gce.txt b/Documentation/devicetree/bindings/soc/mediatek/gce.txt
new file mode 100644
index 0000000..55c4105
--- /dev/null
+++ b/Documentation/devicetree/bindings/soc/mediatek/gce.txt
@@ -0,0 +1,44 @@
+MediaTek GCE
+===============
+
+The Global Command Engine (GCE) is used to help read/write registers with
+critical time limitation, such as updating display configuration during the
+vblank. The GCE can be used to implement the Command Queue (CMDQ) driver.
+
+CMDQ driver uses mailbox framework for communication. Please refer to
+../../mailbox/mailbox.txt for generic information about mailbox device-tree
+bindings.
+
+Required properties:
+- compatible: Must be "mediatek,mt8173-gce"
+- reg: Address range of the GCE unit
+- interrupts: The interrupt signal from the GCE block
+- clock: Clocks according to the common clock binding
+- clock-names: Must be "gce" to stand for GCE clock
+- #mbox-cells: Should be 2
+
+Required properties for a client device:
+- mboxes: client use mailbox to communicate with GCE, it should have this
+ property and list of phandle, mailbox channel specifiers, and atomic
+ execution flag.
+
+Example:
+
+ gce: gce@10212000 {
+ compatible = "mediatek,mt8173-gce";
+ reg = <0 0x10212000 0 0x1000>;
+ interrupts = <GIC_SPI 135 IRQ_TYPE_LEVEL_LOW>;
+ clocks = <&infracfg CLK_INFRA_GCE>;
+ clock-names = "gce";
+
+ #mbox-cells = <2>;
+ };
+
+Example for a client device:
+
+ mmsys: clock-controller@14000000 {
+ compatible = "mediatek,mt8173-mmsys";
+ mboxes = <&gce 0 1 /* main display with atomic execution */
+ &gce 1 1>; /* sub display with atomic execution */
+ ...
+ };
--
1.9.1
^ permalink raw reply related
* [PATCH v13 0/4] Mediatek MT8173 CMDQ support
From: HS Liao @ 2016-08-24 3:27 UTC (permalink / raw)
To: Rob Herring, Matthias Brugger
Cc: Monica Wang, Jiaguang Zhang, Nicolas Boichat, cawa cheng, HS Liao,
Bibby Hsieh, YT Shen, Damon Chu,
devicetree-u79uwXL29TY76Z2rM5mHXA, Sascha Hauer, Daoyuan Huang,
Sascha Hauer, Glory Hung, CK HU,
linux-mediatek-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r,
linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r,
srv_heupstream-NuS5LvNUpcJWk0Htik3J/w, Josh-YC Liu,
linux-kernel-u79uwXL29TY76Z2rM5mHXA, Dennis-YC Hsieh,
Philipp Zabel
Hi,
This is Mediatek MT8173 Command Queue(CMDQ) driver. The CMDQ is used
to help write registers with critical time limitation, such as
updating display configuration during the vblank. It controls Global
Command Engine (GCE) hardware to achieve this requirement.
These patches have a build dependency on top of v4.8-rc1.
Changes since v12:
- remove mediatek,gce from device tree
Best regards,
HS Liao
HS Liao (4):
dt-bindings: soc: Add documentation for the MediaTek GCE unit
CMDQ: Mediatek CMDQ driver
arm64: dts: mt8173: Add GCE node
CMDQ: save more energy in idle
.../devicetree/bindings/soc/mediatek/gce.txt | 44 +
arch/arm64/boot/dts/mediatek/mt8173.dtsi | 10 +
drivers/soc/mediatek/Kconfig | 11 +
drivers/soc/mediatek/Makefile | 1 +
drivers/soc/mediatek/mtk-cmdq.c | 983 +++++++++++++++++++++
include/soc/mediatek/cmdq.h | 180 ++++
6 files changed, 1229 insertions(+)
create mode 100644 Documentation/devicetree/bindings/soc/mediatek/gce.txt
create mode 100644 drivers/soc/mediatek/mtk-cmdq.c
create mode 100644 include/soc/mediatek/cmdq.h
--
1.9.1
^ permalink raw reply
* Re: Request for drivers for MT6735P SoC
From: Andrey Utkin @ 2016-08-23 11:48 UTC (permalink / raw)
To: Mars Cheng
Cc: Matthias Brugger, CC Hwang,
linux-mediatek-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r, Jades Shih
In-Reply-To: <1471924285.7841.3.camel@mtkswgap22>
On Tue, Aug 23, 2016 at 11:51:25AM +0800, Mars Cheng wrote:
> Hi Andrey
>
> It looks like the following link meets your need:
> http://support.lenovo.com/tw/zh/products/phones/vibe-series/c2/downloads/ds113086
>
> I'm not Lenovo guy. Good Luck. :-)
Thanks a lot Mars!
Seems with this archive it's possible even to mainline some kernel stuff :)
^ permalink raw reply
* Re: Request for drivers for MT6735P SoC
From: Mars Cheng @ 2016-08-23 3:51 UTC (permalink / raw)
To: Andrey Utkin
Cc: Matthias Brugger, CC Hwang,
linux-mediatek-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r, Jades Shih
In-Reply-To: <20160822221801.hidc5p3lvrgnymr4@acer>
On Tue, 2016-08-23 at 01:18 +0300, Andrey Utkin wrote:
> On Mon, Aug 22, 2016 at 07:05:33PM +0200, Matthias Brugger wrote:
> >
> >
> > On 17/08/16 13:13, Andrey Utkin wrote:
> > > Hi!
> > > Looking for kernel sources for MT6735P chipset which powers Lenovo C2
> > > Vibe {,Power} phones. Found none. Is it going to be published?
> > > Thanks in advance.
> >
> > Ask Lenovo about the source code. Because of licensing of the kernel
> > they are obligated to provide the source code to them, in theory.
> >
> > Good luck and let us know if you are lucky.
>
> Valid hint.
> However, their contact form on corporate site has a wall of "enter
> serial id of device". Currently I don't own a unit of subj, and
> apparently not really going to buy one because of such attitude of them.
> But maybe somebody reading this has contact with Lenovo dev guys and
> could forward my inquiry to them?
Hi Andrey
It looks like the following link meets your need:
http://support.lenovo.com/tw/zh/products/phones/vibe-series/c2/downloads/ds113086
I'm not Lenovo guy. Good Luck. :-)
>
> _______________________________________________
> Linux-mediatek mailing list
> Linux-mediatek-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r@public.gmane.org
> http://lists.infradead.org/mailman/listinfo/linux-mediatek
^ permalink raw reply
* Re: [PATCH v7 3/3] arm: dts: mt2701: Add auxadc node.
From: kbuild test robot @ 2016-08-23 0:51 UTC (permalink / raw)
Cc: kbuild-all-JC7UmRfGjtg, robh+dt-DgEjT+Ai2ygdnm+yROfE0A,
jic23-DgEjT+Ai2ygdnm+yROfE0A, knaack.h-Mmb7MZpHnFY,
lars-Qo5EllUWu/uELgA04lAiVw, pmeerw-jW+XmwGofnusTnJN9+BGXg,
srv_heupstream-NuS5LvNUpcJWk0Htik3J/w,
liguo.zhang-NuS5LvNUpcJWk0Htik3J/w,
yingjoe.chen-NuS5LvNUpcJWk0Htik3J/w,
eddie.huang-NuS5LvNUpcJWk0Htik3J/w,
erin.lo-NuS5LvNUpcJWk0Htik3J/w,
dawei.chien-NuS5LvNUpcJWk0Htik3J/w,
matthias.bgg-Re5JQEeQqe8AvxtiuMwx3w,
s.hauer-bIcnvbaLZ9MEGnE8C9+IrQ, devicetree-u79uwXL29TY76Z2rM5mHXA,
linux-kernel-u79uwXL29TY76Z2rM5mHXA,
linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r,
linux-iio-u79uwXL29TY76Z2rM5mHXA,
linux-mediatek-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r, Zhiyong Tao
In-Reply-To: <1471504297-26947-4-git-send-email-zhiyong.tao-NuS5LvNUpcJWk0Htik3J/w@public.gmane.org>
[-- Attachment #1: Type: text/plain, Size: 1296 bytes --]
Hi Zhiyong,
[auto build test ERROR on robh/for-next]
[also build test ERROR on v4.8-rc3 next-20160822]
[if your patch is applied to the wrong git tree, please drop us a note to help improve the system]
[Suggest to use git(>=2.9.0) format-patch --base=<commit> (or --base=auto for convenience) to record what (public, well-known) commit your patch series was built on]
[Check https://git-scm.com/docs/git-format-patch for more information]
url: https://github.com/0day-ci/linux/commits/Zhiyong-Tao/AUXADC-Mediatek-auxadc-driver/20160818-152251
base: https://git.kernel.org/pub/scm/linux/kernel/git/robh/linux.git for-next
config: arm-hisi_defconfig (attached as .config)
compiler: arm-linux-gnueabi-gcc (Debian 5.4.0-6) 5.4.0 20160609
reproduce:
wget https://git.kernel.org/cgit/linux/kernel/git/wfg/lkp-tests.git/plain/sbin/make.cross -O ~/bin/make.cross
chmod +x ~/bin/make.cross
# save the attached .config to linux build tree
make.cross ARCH=arm
All errors (new ones prefixed by >>):
>> Error: arch/arm/boot/dts/mt2701.dtsi:145.22-23 syntax error
FATAL ERROR: Unable to parse input tree
---
0-DAY kernel test infrastructure Open Source Technology Center
https://lists.01.org/pipermail/kbuild-all Intel Corporation
[-- Attachment #2: .config.gz --]
[-- Type: application/octet-stream, Size: 17570 bytes --]
^ 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