mirror of
https://github.com/Fishwaldo/build.git
synced 2025-03-23 15:21:39 +00:00
Rockchip-default update patches
-- Thanks again to @ntemis for bringing these together and letting me know about it - Tinker reboot now seemingly solved by a proper method, should no longer require OF workarounds - various fixes from various sources, see patches for complete information. - boots, still needs debugging of BT/touchscreen/sound - some patch warnings exist, again WIP update for those willing to take a look. (@chwe17 perhaps?)
This commit is contained in:
parent
f3d0fce4bc
commit
96135c6065
20 changed files with 17035 additions and 491 deletions
|
@ -3818,6 +3818,8 @@ CONFIG_MMC=y
|
|||
# CONFIG_MMC_DEBUG is not set
|
||||
# CONFIG_MMC_EMBEDDED_SDIO is not set
|
||||
# CONFIG_MMC_PARANOID_SD_INIT is not set
|
||||
CONFIG_PWRSEQ_EMMC=y
|
||||
CONFIG_PWRSEQ_SIMPLE=y
|
||||
|
||||
#
|
||||
# MMC/SD/SDIO Card Drivers
|
||||
|
|
1092
patch/kernel/rockchip-default/01-linux-0001-rockchip.patch
Normal file
1092
patch/kernel/rockchip-default/01-linux-0001-rockchip.patch
Normal file
File diff suppressed because it is too large
Load diff
1597
patch/kernel/rockchip-default/01-linux-0004-audio.patch
Normal file
1597
patch/kernel/rockchip-default/01-linux-0004-audio.patch
Normal file
File diff suppressed because it is too large
Load diff
7032
patch/kernel/rockchip-default/01-linux-0005-dts.patch
Normal file
7032
patch/kernel/rockchip-default/01-linux-0005-dts.patch
Normal file
File diff suppressed because it is too large
Load diff
870
patch/kernel/rockchip-default/01-linux-0006-rtl8211f.patch
Normal file
870
patch/kernel/rockchip-default/01-linux-0006-rtl8211f.patch
Normal file
|
@ -0,0 +1,870 @@
|
|||
From c5300de0fe982ae8a78e1b95ef7bf30b744e4ca1 Mon Sep 17 00:00:00 2001
|
||||
From: Martin Blumenstingl <martin.blumenstingl@googlemail.com>
|
||||
Date: Fri, 25 Nov 2016 14:12:01 +0100
|
||||
Subject: [PATCH] UPSTREAM: net: phy: realtek: fix enabling of the TX-delay for
|
||||
RTL8211F
|
||||
|
||||
The old logic always enabled the TX-delay when the phy-mode was set to
|
||||
PHY_INTERFACE_MODE_RGMII. There are dedicated phy-modes which tell the
|
||||
PHY driver to enable the RX and/or TX delays:
|
||||
- PHY_INTERFACE_MODE_RGMII should disable the RX and TX delay in the
|
||||
PHY (if required, the MAC should add the delays in this case)
|
||||
- PHY_INTERFACE_MODE_RGMII_ID should enable RX and TX delay in the PHY
|
||||
- PHY_INTERFACE_MODE_RGMII_TXID should enable the TX delay in the PHY
|
||||
- PHY_INTERFACE_MODE_RGMII_RXID should enable the RX delay in the PHY
|
||||
(currently not supported by RTL8211F)
|
||||
|
||||
With this patch we enable the TX delay for PHY_INTERFACE_MODE_RGMII_ID
|
||||
and PHY_INTERFACE_MODE_RGMII_TXID.
|
||||
Additionally we now explicity disable the TX-delay, which seems to be
|
||||
enabled automatically after a hard-reset of the PHY (by triggering it's
|
||||
reset pin) to get a consistent state (as defined by the phy-mode).
|
||||
|
||||
This fixes a compatibility problem with some SoCs where the TX-delay was
|
||||
also added by the MAC. With the TX-delay being applied twice the TX
|
||||
clock was off and TX traffic was broken or very slow (<10Mbit/s) on
|
||||
1000Mbit/s links.
|
||||
|
||||
Signed-off-by: Martin Blumenstingl <martin.blumenstingl@googlemail.com>
|
||||
Reviewed-by: Florian Fainelli <f.fainelli@gmail.com>
|
||||
Signed-off-by: David S. Miller <davem@davemloft.net>
|
||||
(cherry picked from commit e3230494b57ece68750e3e32d3e53d6b00917058)
|
||||
---
|
||||
drivers/net/phy/realtek.c | 20 ++++++++++++--------
|
||||
1 file changed, 12 insertions(+), 8 deletions(-)
|
||||
|
||||
diff --git a/drivers/net/phy/realtek.c b/drivers/net/phy/realtek.c
|
||||
index 43ab691362d4..686f3b259dc0 100644
|
||||
--- a/drivers/net/phy/realtek.c
|
||||
+++ b/drivers/net/phy/realtek.c
|
||||
@@ -102,15 +102,19 @@ static int rtl8211f_config_init(struct phy_device *phydev)
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
- if (phydev->interface == PHY_INTERFACE_MODE_RGMII) {
|
||||
- /* enable TXDLY */
|
||||
- phy_write(phydev, RTL8211F_PAGE_SELECT, 0xd08);
|
||||
- reg = phy_read(phydev, 0x11);
|
||||
+ phy_write(phydev, RTL8211F_PAGE_SELECT, 0xd08);
|
||||
+ reg = phy_read(phydev, 0x11);
|
||||
+
|
||||
+ /* enable TX-delay for rgmii-id and rgmii-txid, otherwise disable it */
|
||||
+ if (phydev->interface == PHY_INTERFACE_MODE_RGMII_ID ||
|
||||
+ phydev->interface == PHY_INTERFACE_MODE_RGMII_TXID)
|
||||
reg |= RTL8211F_TX_DELAY;
|
||||
- phy_write(phydev, 0x11, reg);
|
||||
- /* restore to default page 0 */
|
||||
- phy_write(phydev, RTL8211F_PAGE_SELECT, 0x0);
|
||||
- }
|
||||
+ else
|
||||
+ reg &= ~RTL8211F_TX_DELAY;
|
||||
+
|
||||
+ phy_write(phydev, 0x11, reg);
|
||||
+ /* restore to default page 0 */
|
||||
+ phy_write(phydev, RTL8211F_PAGE_SELECT, 0x0);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
From 647c38d9964680f7fbb24c5a889ef74b23b4cbd4 Mon Sep 17 00:00:00 2001
|
||||
From: Kunihiko Hayashi <hayashi.kunihiko@socionext.com>
|
||||
Date: Tue, 12 Sep 2017 18:54:35 +0900
|
||||
Subject: [PATCH] UPSTREAM: net: phy: realtek: rename RTL8211F_PAGE_SELECT to
|
||||
RTL821x_PAGE_SELECT
|
||||
|
||||
This renames the definition of page select register from
|
||||
RTL8211F_PAGE_SELECT to RTL821x_PAGE_SELECT to use it across models.
|
||||
|
||||
Signed-off-by: Kunihiko Hayashi <hayashi.kunihiko@socionext.com>
|
||||
Reviewed-by: Andrew Lunn <andrew@lunn.ch>
|
||||
Signed-off-by: David S. Miller <davem@davemloft.net>
|
||||
(cherry picked from commit 013955a6556766a76f9f2cc31e740fc6db6ecff4)
|
||||
---
|
||||
drivers/net/phy/realtek.c | 10 +++++-----
|
||||
1 file changed, 5 insertions(+), 5 deletions(-)
|
||||
|
||||
diff --git a/drivers/net/phy/realtek.c b/drivers/net/phy/realtek.c
|
||||
index 686f3b259dc0..d58cc8f518ac 100644
|
||||
--- a/drivers/net/phy/realtek.c
|
||||
+++ b/drivers/net/phy/realtek.c
|
||||
@@ -22,11 +22,11 @@
|
||||
#define RTL821x_INER 0x12
|
||||
#define RTL821x_INER_INIT 0x6400
|
||||
#define RTL821x_INSR 0x13
|
||||
+#define RTL821x_PAGE_SELECT 0x1f
|
||||
#define RTL8211E_INER_LINK_STATUS 0x400
|
||||
|
||||
#define RTL8211F_INER_LINK_STATUS 0x0010
|
||||
#define RTL8211F_INSR 0x1d
|
||||
-#define RTL8211F_PAGE_SELECT 0x1f
|
||||
#define RTL8211F_TX_DELAY 0x100
|
||||
|
||||
MODULE_DESCRIPTION("Realtek PHY driver");
|
||||
@@ -46,10 +46,10 @@ static int rtl8211f_ack_interrupt(struct phy_device *phydev)
|
||||
{
|
||||
int err;
|
||||
|
||||
- phy_write(phydev, RTL8211F_PAGE_SELECT, 0xa43);
|
||||
+ phy_write(phydev, RTL821x_PAGE_SELECT, 0xa43);
|
||||
err = phy_read(phydev, RTL8211F_INSR);
|
||||
/* restore to default page 0 */
|
||||
- phy_write(phydev, RTL8211F_PAGE_SELECT, 0x0);
|
||||
+ phy_write(phydev, RTL821x_PAGE_SELECT, 0x0);
|
||||
|
||||
return (err < 0) ? err : 0;
|
||||
}
|
||||
@@ -102,7 +102,7 @@ static int rtl8211f_config_init(struct phy_device *phydev)
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
- phy_write(phydev, RTL8211F_PAGE_SELECT, 0xd08);
|
||||
+ phy_write(phydev, RTL821x_PAGE_SELECT, 0xd08);
|
||||
reg = phy_read(phydev, 0x11);
|
||||
|
||||
/* enable TX-delay for rgmii-id and rgmii-txid, otherwise disable it */
|
||||
@@ -114,7 +114,7 @@ static int rtl8211f_config_init(struct phy_device *phydev)
|
||||
|
||||
phy_write(phydev, 0x11, reg);
|
||||
/* restore to default page 0 */
|
||||
- phy_write(phydev, RTL8211F_PAGE_SELECT, 0x0);
|
||||
+ phy_write(phydev, RTL821x_PAGE_SELECT, 0x0);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
From 724532e7b4ad78722821763c639a73383a0f4418 Mon Sep 17 00:00:00 2001
|
||||
From: Jassi Brar <jaswinder.singh@linaro.org>
|
||||
Date: Tue, 12 Sep 2017 18:54:36 +0900
|
||||
Subject: [PATCH] UPSTREAM: net: phy: realtek: add RTL8201F phy-id and
|
||||
functions
|
||||
|
||||
Add RTL8201F phy-id and the related functions to the driver.
|
||||
|
||||
The original patch is as follows:
|
||||
https://patchwork.kernel.org/patch/2538341/
|
||||
|
||||
Signed-off-by: Jongsung Kim <neidhard.kim@lge.com>
|
||||
Signed-off-by: Jassi Brar <jaswinder.singh@linaro.org>
|
||||
Signed-off-by: Kunihiko Hayashi <hayashi.kunihiko@socionext.com>
|
||||
Reviewed-by: Andrew Lunn <andrew@lunn.ch>
|
||||
Reviewed-by: Florian Fainelli <f.fainelli@gmail.com>
|
||||
Signed-off-by: David S. Miller <davem@davemloft.net>
|
||||
(cherry picked from commit 513588dd44b09bb5fdd5066a4fbc1e7443b86d1c)
|
||||
---
|
||||
drivers/net/phy/realtek.c | 44 ++++++++++++++++++++++++++++++++++++++++++++
|
||||
1 file changed, 44 insertions(+)
|
||||
|
||||
diff --git a/drivers/net/phy/realtek.c b/drivers/net/phy/realtek.c
|
||||
index d58cc8f518ac..422cf1f6a60c 100644
|
||||
--- a/drivers/net/phy/realtek.c
|
||||
+++ b/drivers/net/phy/realtek.c
|
||||
@@ -29,10 +29,22 @@
|
||||
#define RTL8211F_INSR 0x1d
|
||||
#define RTL8211F_TX_DELAY 0x100
|
||||
|
||||
+#define RTL8201F_ISR 0x1e
|
||||
+#define RTL8201F_IER 0x13
|
||||
+
|
||||
MODULE_DESCRIPTION("Realtek PHY driver");
|
||||
MODULE_AUTHOR("Johnson Leung");
|
||||
MODULE_LICENSE("GPL");
|
||||
|
||||
+static int rtl8201_ack_interrupt(struct phy_device *phydev)
|
||||
+{
|
||||
+ int err;
|
||||
+
|
||||
+ err = phy_read(phydev, RTL8201F_ISR);
|
||||
+
|
||||
+ return (err < 0) ? err : 0;
|
||||
+}
|
||||
+
|
||||
static int rtl821x_ack_interrupt(struct phy_device *phydev)
|
||||
{
|
||||
int err;
|
||||
@@ -54,6 +66,25 @@ static int rtl8211f_ack_interrupt(struct phy_device *phydev)
|
||||
return (err < 0) ? err : 0;
|
||||
}
|
||||
|
||||
+static int rtl8201_config_intr(struct phy_device *phydev)
|
||||
+{
|
||||
+ int err;
|
||||
+
|
||||
+ /* switch to page 7 */
|
||||
+ phy_write(phydev, RTL821x_PAGE_SELECT, 0x7);
|
||||
+
|
||||
+ if (phydev->interrupts == PHY_INTERRUPT_ENABLED)
|
||||
+ err = phy_write(phydev, RTL8201F_IER,
|
||||
+ BIT(13) | BIT(12) | BIT(11));
|
||||
+ else
|
||||
+ err = phy_write(phydev, RTL8201F_IER, 0);
|
||||
+
|
||||
+ /* restore to default page 0 */
|
||||
+ phy_write(phydev, RTL821x_PAGE_SELECT, 0x0);
|
||||
+
|
||||
+ return err;
|
||||
+}
|
||||
+
|
||||
static int rtl8211b_config_intr(struct phy_device *phydev)
|
||||
{
|
||||
int err;
|
||||
@@ -129,6 +160,18 @@ static struct phy_driver realtek_drvs[] = {
|
||||
.config_aneg = &genphy_config_aneg,
|
||||
.read_status = &genphy_read_status,
|
||||
.driver = { .owner = THIS_MODULE,},
|
||||
+ }, {
|
||||
+ .phy_id = 0x001cc816,
|
||||
+ .name = "RTL8201F 10/100Mbps Ethernet",
|
||||
+ .phy_id_mask = 0x001fffff,
|
||||
+ .features = PHY_BASIC_FEATURES,
|
||||
+ .flags = PHY_HAS_INTERRUPT,
|
||||
+ .config_aneg = &genphy_config_aneg,
|
||||
+ .read_status = &genphy_read_status,
|
||||
+ .ack_interrupt = &rtl8201_ack_interrupt,
|
||||
+ .config_intr = &rtl8201_config_intr,
|
||||
+ .suspend = genphy_suspend,
|
||||
+ .resume = genphy_resume,
|
||||
}, {
|
||||
.phy_id = 0x001cc912,
|
||||
.name = "RTL8211B Gigabit Ethernet",
|
||||
@@ -186,6 +229,7 @@ static struct phy_driver realtek_drvs[] = {
|
||||
module_phy_driver(realtek_drvs);
|
||||
|
||||
static struct mdio_device_id __maybe_unused realtek_tbl[] = {
|
||||
+ { 0x001cc816, 0x001fffff },
|
||||
{ 0x001cc912, 0x001fffff },
|
||||
{ 0x001cc914, 0x001fffff },
|
||||
{ 0x001cc915, 0x001fffff },
|
||||
|
||||
From 933e1e195c40a941b6e5dec0c6a3a4bb7f804cf7 Mon Sep 17 00:00:00 2001
|
||||
From: Heiner Kallweit <hkallweit1@gmail.com>
|
||||
Date: Sun, 12 Nov 2017 16:16:04 +0100
|
||||
Subject: [PATCH] UPSTREAM: net: phy: realtek: fix RTL8211F interrupt mode
|
||||
|
||||
After commit b94d22d94ad22 "ARM64: dts: meson-gx: add external PHY
|
||||
interrupt on some platforms" ethernet stopped working on my Odroid-C2
|
||||
which has a RTL8211F phy.
|
||||
|
||||
It turned out that no interrupts were triggered. Further analysis
|
||||
showed the register INER can't be altered on page 0.
|
||||
Because register INSR needs to be accessed via page 0xa43 I assumed
|
||||
that register INER needs to be accessed via some page too.
|
||||
Some brute force check resulted in page 0xa42 being the right one.
|
||||
|
||||
With this patch the phy is working properly in interrupt mode.
|
||||
|
||||
Fixes: 3447cf2e9a11 ("net/phy: Add support for Realtek RTL8211F")
|
||||
Signed-off-by: Heiner Kallweit <hkallweit1@gmail.com>
|
||||
Tested-by: Jerome Brunet <jbrunet@baylibre.com>
|
||||
Signed-off-by: David S. Miller <davem@davemloft.net>
|
||||
(cherry picked from commit 3697d058b08d5b874f0253de173ef72e5d648f9a)
|
||||
---
|
||||
drivers/net/phy/realtek.c | 2 ++
|
||||
1 file changed, 2 insertions(+)
|
||||
|
||||
diff --git a/drivers/net/phy/realtek.c b/drivers/net/phy/realtek.c
|
||||
index 422cf1f6a60c..a30d0c08c63b 100644
|
||||
--- a/drivers/net/phy/realtek.c
|
||||
+++ b/drivers/net/phy/realtek.c
|
||||
@@ -115,11 +115,13 @@ static int rtl8211f_config_intr(struct phy_device *phydev)
|
||||
{
|
||||
int err;
|
||||
|
||||
+ phy_write(phydev, RTL821x_PAGE_SELECT, 0xa42);
|
||||
if (phydev->interrupts == PHY_INTERRUPT_ENABLED)
|
||||
err = phy_write(phydev, RTL821x_INER,
|
||||
RTL8211F_INER_LINK_STATUS);
|
||||
else
|
||||
err = phy_write(phydev, RTL821x_INER, 0);
|
||||
+ phy_write(phydev, RTL821x_PAGE_SELECT, 0);
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
From 046a2dc318a05236e06b09d8c0ca3f1005cbceca Mon Sep 17 00:00:00 2001
|
||||
From: Martin Blumenstingl <martin.blumenstingl@googlemail.com>
|
||||
Date: Sat, 2 Dec 2017 22:51:24 +0100
|
||||
Subject: [PATCH] UPSTREAM: net: phy: realtek: use the BIT and GENMASK macros
|
||||
|
||||
This makes it easier to compare the #defines with the datasheets.
|
||||
No functional changes.
|
||||
|
||||
Signed-off-by: Martin Blumenstingl <martin.blumenstingl@googlemail.com>
|
||||
Reviewed-by: Andrew Lunn <andrew@lunn.ch>
|
||||
Signed-off-by: David S. Miller <davem@davemloft.net>
|
||||
(cherry picked from commit 8cc5baefbc0266b6d6c8e99cb8568f59be36a575)
|
||||
---
|
||||
drivers/net/phy/realtek.c | 11 ++++++-----
|
||||
1 file changed, 6 insertions(+), 5 deletions(-)
|
||||
|
||||
diff --git a/drivers/net/phy/realtek.c b/drivers/net/phy/realtek.c
|
||||
index a30d0c08c63b..f8dc29a75828 100644
|
||||
--- a/drivers/net/phy/realtek.c
|
||||
+++ b/drivers/net/phy/realtek.c
|
||||
@@ -13,21 +13,22 @@
|
||||
* option) any later version.
|
||||
*
|
||||
*/
|
||||
+#include <linux/bitops.h>
|
||||
#include <linux/phy.h>
|
||||
#include <linux/module.h>
|
||||
|
||||
#define RTL821x_PHYSR 0x11
|
||||
-#define RTL821x_PHYSR_DUPLEX 0x2000
|
||||
-#define RTL821x_PHYSR_SPEED 0xc000
|
||||
+#define RTL821x_PHYSR_DUPLEX BIT(13)
|
||||
+#define RTL821x_PHYSR_SPEED GENMASK(15, 14)
|
||||
#define RTL821x_INER 0x12
|
||||
#define RTL821x_INER_INIT 0x6400
|
||||
#define RTL821x_INSR 0x13
|
||||
#define RTL821x_PAGE_SELECT 0x1f
|
||||
-#define RTL8211E_INER_LINK_STATUS 0x400
|
||||
+#define RTL8211E_INER_LINK_STATUS BIT(10)
|
||||
|
||||
-#define RTL8211F_INER_LINK_STATUS 0x0010
|
||||
+#define RTL8211F_INER_LINK_STATUS BIT(4)
|
||||
#define RTL8211F_INSR 0x1d
|
||||
-#define RTL8211F_TX_DELAY 0x100
|
||||
+#define RTL8211F_TX_DELAY BIT(8)
|
||||
|
||||
#define RTL8201F_ISR 0x1e
|
||||
#define RTL8201F_IER 0x13
|
||||
|
||||
From 7894b1cae69475242cdb1ca0fb639a5d70ac6316 Mon Sep 17 00:00:00 2001
|
||||
From: Martin Blumenstingl <martin.blumenstingl@googlemail.com>
|
||||
Date: Sat, 2 Dec 2017 22:51:25 +0100
|
||||
Subject: [PATCH] UPSTREAM: net: phy: realtek: rename RTL821x_INER_INIT to
|
||||
RTL8211B_INER_INIT
|
||||
|
||||
This macro is only used by the RTL8211B code. RTL8211E and RTL8211F both
|
||||
use other bits to initialize the RTL821x_INER register.
|
||||
No functional changes.
|
||||
|
||||
Signed-off-by: Martin Blumenstingl <martin.blumenstingl@googlemail.com>
|
||||
Reviewed-by: Andrew Lunn <andrew@lunn.ch>
|
||||
Signed-off-by: David S. Miller <davem@davemloft.net>
|
||||
(cherry picked from commit 69021e32ec3ef02170482f6ed8130febaed27357)
|
||||
---
|
||||
drivers/net/phy/realtek.c | 4 ++--
|
||||
1 file changed, 2 insertions(+), 2 deletions(-)
|
||||
|
||||
diff --git a/drivers/net/phy/realtek.c b/drivers/net/phy/realtek.c
|
||||
index f8dc29a75828..89308eac4088 100644
|
||||
--- a/drivers/net/phy/realtek.c
|
||||
+++ b/drivers/net/phy/realtek.c
|
||||
@@ -21,7 +21,7 @@
|
||||
#define RTL821x_PHYSR_DUPLEX BIT(13)
|
||||
#define RTL821x_PHYSR_SPEED GENMASK(15, 14)
|
||||
#define RTL821x_INER 0x12
|
||||
-#define RTL821x_INER_INIT 0x6400
|
||||
+#define RTL8211B_INER_INIT 0x6400
|
||||
#define RTL821x_INSR 0x13
|
||||
#define RTL821x_PAGE_SELECT 0x1f
|
||||
#define RTL8211E_INER_LINK_STATUS BIT(10)
|
||||
@@ -92,7 +92,7 @@ static int rtl8211b_config_intr(struct phy_device *phydev)
|
||||
|
||||
if (phydev->interrupts == PHY_INTERRUPT_ENABLED)
|
||||
err = phy_write(phydev, RTL821x_INER,
|
||||
- RTL821x_INER_INIT);
|
||||
+ RTL8211B_INER_INIT);
|
||||
else
|
||||
err = phy_write(phydev, RTL821x_INER, 0);
|
||||
|
||||
|
||||
From f6e8b6c88c6b3d4925607575bc4387a289d49708 Mon Sep 17 00:00:00 2001
|
||||
From: Martin Blumenstingl <martin.blumenstingl@googlemail.com>
|
||||
Date: Sat, 2 Dec 2017 22:51:26 +0100
|
||||
Subject: [PATCH] UPSTREAM: net: phy: realtek: group all register bit #defines
|
||||
for RTL821x_INER
|
||||
|
||||
This simply moves all register bit #defines which describe the (PHY
|
||||
specific) bits in the RTL821x_INER right below the RTL821x_INER register
|
||||
definition. This makes it easier to spot which registers and bits belong
|
||||
together.
|
||||
No functional changes.
|
||||
|
||||
Signed-off-by: Martin Blumenstingl <martin.blumenstingl@googlemail.com>
|
||||
Reviewed-by: Andrew Lunn <andrew@lunn.ch>
|
||||
Signed-off-by: David S. Miller <davem@davemloft.net>
|
||||
(cherry picked from commit a82f266d240d87e6111878bbfe287024fb6857c1)
|
||||
---
|
||||
drivers/net/phy/realtek.c | 7 +++++--
|
||||
1 file changed, 5 insertions(+), 2 deletions(-)
|
||||
|
||||
diff --git a/drivers/net/phy/realtek.c b/drivers/net/phy/realtek.c
|
||||
index 89308eac4088..df97d903d2bf 100644
|
||||
--- a/drivers/net/phy/realtek.c
|
||||
+++ b/drivers/net/phy/realtek.c
|
||||
@@ -20,13 +20,16 @@
|
||||
#define RTL821x_PHYSR 0x11
|
||||
#define RTL821x_PHYSR_DUPLEX BIT(13)
|
||||
#define RTL821x_PHYSR_SPEED GENMASK(15, 14)
|
||||
+
|
||||
#define RTL821x_INER 0x12
|
||||
#define RTL8211B_INER_INIT 0x6400
|
||||
+#define RTL8211E_INER_LINK_STATUS BIT(10)
|
||||
+#define RTL8211F_INER_LINK_STATUS BIT(4)
|
||||
+
|
||||
#define RTL821x_INSR 0x13
|
||||
+
|
||||
#define RTL821x_PAGE_SELECT 0x1f
|
||||
-#define RTL8211E_INER_LINK_STATUS BIT(10)
|
||||
|
||||
-#define RTL8211F_INER_LINK_STATUS BIT(4)
|
||||
#define RTL8211F_INSR 0x1d
|
||||
#define RTL8211F_TX_DELAY BIT(8)
|
||||
|
||||
|
||||
From d5e2b112bb8e5707fc2fb727122ee5a8444ee462 Mon Sep 17 00:00:00 2001
|
||||
From: Martin Blumenstingl <martin.blumenstingl@googlemail.com>
|
||||
Date: Sat, 2 Dec 2017 22:51:27 +0100
|
||||
Subject: [PATCH] UPSTREAM: net: phy: realtek: use the same indentation for all
|
||||
#defines
|
||||
|
||||
This simply makes the code easier to read. No functional changes.
|
||||
|
||||
Signed-off-by: Martin Blumenstingl <martin.blumenstingl@googlemail.com>
|
||||
Reviewed-by: Andrew Lunn <andrew@lunn.ch>
|
||||
Signed-off-by: David S. Miller <davem@davemloft.net>
|
||||
(cherry picked from commit f609ab0ed8e7bef2cd61d230bf9e83e1ec5b9ddb)
|
||||
---
|
||||
drivers/net/phy/realtek.c | 27 ++++++++++++++-------------
|
||||
1 file changed, 14 insertions(+), 13 deletions(-)
|
||||
|
||||
diff --git a/drivers/net/phy/realtek.c b/drivers/net/phy/realtek.c
|
||||
index df97d903d2bf..701f34ad7d8d 100644
|
||||
--- a/drivers/net/phy/realtek.c
|
||||
+++ b/drivers/net/phy/realtek.c
|
||||
@@ -17,24 +17,25 @@
|
||||
#include <linux/phy.h>
|
||||
#include <linux/module.h>
|
||||
|
||||
-#define RTL821x_PHYSR 0x11
|
||||
-#define RTL821x_PHYSR_DUPLEX BIT(13)
|
||||
-#define RTL821x_PHYSR_SPEED GENMASK(15, 14)
|
||||
+#define RTL821x_PHYSR 0x11
|
||||
+#define RTL821x_PHYSR_DUPLEX BIT(13)
|
||||
+#define RTL821x_PHYSR_SPEED GENMASK(15, 14)
|
||||
|
||||
-#define RTL821x_INER 0x12
|
||||
-#define RTL8211B_INER_INIT 0x6400
|
||||
-#define RTL8211E_INER_LINK_STATUS BIT(10)
|
||||
-#define RTL8211F_INER_LINK_STATUS BIT(4)
|
||||
+#define RTL821x_INER 0x12
|
||||
+#define RTL8211B_INER_INIT 0x6400
|
||||
+#define RTL8211E_INER_LINK_STATUS BIT(10)
|
||||
+#define RTL8211F_INER_LINK_STATUS BIT(4)
|
||||
|
||||
-#define RTL821x_INSR 0x13
|
||||
+#define RTL821x_INSR 0x13
|
||||
|
||||
-#define RTL821x_PAGE_SELECT 0x1f
|
||||
+#define RTL821x_PAGE_SELECT 0x1f
|
||||
|
||||
-#define RTL8211F_INSR 0x1d
|
||||
-#define RTL8211F_TX_DELAY BIT(8)
|
||||
+#define RTL8211F_INSR 0x1d
|
||||
|
||||
-#define RTL8201F_ISR 0x1e
|
||||
-#define RTL8201F_IER 0x13
|
||||
+#define RTL8211F_TX_DELAY BIT(8)
|
||||
+
|
||||
+#define RTL8201F_ISR 0x1e
|
||||
+#define RTL8201F_IER 0x13
|
||||
|
||||
MODULE_DESCRIPTION("Realtek PHY driver");
|
||||
MODULE_AUTHOR("Johnson Leung");
|
||||
|
||||
From 8c16425a3c99a1cca4458eb17bd6414d65074027 Mon Sep 17 00:00:00 2001
|
||||
From: Martin Blumenstingl <martin.blumenstingl@googlemail.com>
|
||||
Date: Sat, 2 Dec 2017 22:51:28 +0100
|
||||
Subject: [PATCH] UPSTREAM: net: phy: realtek: add utility functions to
|
||||
read/write page addresses
|
||||
|
||||
Realtek PHYs implement the concept of so-called "extension pages". The
|
||||
reason for this is probably because these PHYs expose more registers
|
||||
than available in the standard address range.
|
||||
After all read/write operations on such a page are done the driver
|
||||
should switch back to page 0 where the standard MII registers (such as
|
||||
MII_BMCR) are available.
|
||||
|
||||
When referring to such a register the datasheets of RTL8211E and
|
||||
RTL8211F always specify:
|
||||
- the page / "ext. page" which has to be written to RTL821x_PAGE_SELECT
|
||||
- an address (sometimes also called reg)
|
||||
|
||||
These new utility functions make the existing code easier to read since
|
||||
it removes some duplication (switching back to page 0 is done within the
|
||||
new helpers for example).
|
||||
|
||||
No functional changes are intended.
|
||||
|
||||
Signed-off-by: Martin Blumenstingl <martin.blumenstingl@googlemail.com>
|
||||
Reviewed-by: Andrew Lunn <andrew@lunn.ch>
|
||||
Signed-off-by: David S. Miller <davem@davemloft.net>
|
||||
(cherry picked from commit 136819a6e8df374e6b9b424586ff11c9e241a1cb)
|
||||
---
|
||||
drivers/net/phy/realtek.c | 83 ++++++++++++++++++++++++++++++-----------------
|
||||
1 file changed, 53 insertions(+), 30 deletions(-)
|
||||
|
||||
diff --git a/drivers/net/phy/realtek.c b/drivers/net/phy/realtek.c
|
||||
index 701f34ad7d8d..b1d52e61d91c 100644
|
||||
--- a/drivers/net/phy/realtek.c
|
||||
+++ b/drivers/net/phy/realtek.c
|
||||
@@ -41,6 +41,39 @@ MODULE_DESCRIPTION("Realtek PHY driver");
|
||||
MODULE_AUTHOR("Johnson Leung");
|
||||
MODULE_LICENSE("GPL");
|
||||
|
||||
+static int rtl8211x_page_read(struct phy_device *phydev, u16 page, u16 address)
|
||||
+{
|
||||
+ int ret;
|
||||
+
|
||||
+ ret = phy_write(phydev, RTL821x_PAGE_SELECT, page);
|
||||
+ if (ret)
|
||||
+ return ret;
|
||||
+
|
||||
+ ret = phy_read(phydev, address);
|
||||
+
|
||||
+ /* restore to default page 0 */
|
||||
+ phy_write(phydev, RTL821x_PAGE_SELECT, 0x0);
|
||||
+
|
||||
+ return ret;
|
||||
+}
|
||||
+
|
||||
+static int rtl8211x_page_write(struct phy_device *phydev, u16 page,
|
||||
+ u16 address, u16 val)
|
||||
+{
|
||||
+ int ret;
|
||||
+
|
||||
+ ret = phy_write(phydev, RTL821x_PAGE_SELECT, page);
|
||||
+ if (ret)
|
||||
+ return ret;
|
||||
+
|
||||
+ ret = phy_write(phydev, address, val);
|
||||
+
|
||||
+ /* restore to default page 0 */
|
||||
+ phy_write(phydev, RTL821x_PAGE_SELECT, 0x0);
|
||||
+
|
||||
+ return ret;
|
||||
+}
|
||||
+
|
||||
static int rtl8201_ack_interrupt(struct phy_device *phydev)
|
||||
{
|
||||
int err;
|
||||
@@ -63,31 +96,21 @@ static int rtl8211f_ack_interrupt(struct phy_device *phydev)
|
||||
{
|
||||
int err;
|
||||
|
||||
- phy_write(phydev, RTL821x_PAGE_SELECT, 0xa43);
|
||||
- err = phy_read(phydev, RTL8211F_INSR);
|
||||
- /* restore to default page 0 */
|
||||
- phy_write(phydev, RTL821x_PAGE_SELECT, 0x0);
|
||||
+ err = rtl8211x_page_read(phydev, 0xa43, RTL8211F_INSR);
|
||||
|
||||
return (err < 0) ? err : 0;
|
||||
}
|
||||
|
||||
static int rtl8201_config_intr(struct phy_device *phydev)
|
||||
{
|
||||
- int err;
|
||||
-
|
||||
- /* switch to page 7 */
|
||||
- phy_write(phydev, RTL821x_PAGE_SELECT, 0x7);
|
||||
+ u16 val;
|
||||
|
||||
if (phydev->interrupts == PHY_INTERRUPT_ENABLED)
|
||||
- err = phy_write(phydev, RTL8201F_IER,
|
||||
- BIT(13) | BIT(12) | BIT(11));
|
||||
+ val = BIT(13) | BIT(12) | BIT(11);
|
||||
else
|
||||
- err = phy_write(phydev, RTL8201F_IER, 0);
|
||||
+ val = 0;
|
||||
|
||||
- /* restore to default page 0 */
|
||||
- phy_write(phydev, RTL821x_PAGE_SELECT, 0x0);
|
||||
-
|
||||
- return err;
|
||||
+ return rtl8211x_page_write(phydev, 0x7, RTL8201F_IER, val);
|
||||
}
|
||||
|
||||
static int rtl8211b_config_intr(struct phy_device *phydev)
|
||||
@@ -118,41 +141,41 @@ static int rtl8211e_config_intr(struct phy_device *phydev)
|
||||
|
||||
static int rtl8211f_config_intr(struct phy_device *phydev)
|
||||
{
|
||||
- int err;
|
||||
+ u16 val;
|
||||
|
||||
- phy_write(phydev, RTL821x_PAGE_SELECT, 0xa42);
|
||||
if (phydev->interrupts == PHY_INTERRUPT_ENABLED)
|
||||
- err = phy_write(phydev, RTL821x_INER,
|
||||
- RTL8211F_INER_LINK_STATUS);
|
||||
+ val = RTL8211F_INER_LINK_STATUS;
|
||||
else
|
||||
- err = phy_write(phydev, RTL821x_INER, 0);
|
||||
- phy_write(phydev, RTL821x_PAGE_SELECT, 0);
|
||||
+ val = 0;
|
||||
|
||||
- return err;
|
||||
+ return rtl8211x_page_write(phydev, 0xa42, RTL821x_INER, val);
|
||||
}
|
||||
|
||||
static int rtl8211f_config_init(struct phy_device *phydev)
|
||||
{
|
||||
int ret;
|
||||
- u16 reg;
|
||||
+ u16 val;
|
||||
|
||||
ret = genphy_config_init(phydev);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
- phy_write(phydev, RTL821x_PAGE_SELECT, 0xd08);
|
||||
- reg = phy_read(phydev, 0x11);
|
||||
+ ret = rtl8211x_page_read(phydev, 0xd08, 0x11);
|
||||
+ if (ret < 0)
|
||||
+ return ret;
|
||||
+
|
||||
+ val = ret & 0xffff;
|
||||
|
||||
/* enable TX-delay for rgmii-id and rgmii-txid, otherwise disable it */
|
||||
if (phydev->interface == PHY_INTERFACE_MODE_RGMII_ID ||
|
||||
phydev->interface == PHY_INTERFACE_MODE_RGMII_TXID)
|
||||
- reg |= RTL8211F_TX_DELAY;
|
||||
+ val |= RTL8211F_TX_DELAY;
|
||||
else
|
||||
- reg &= ~RTL8211F_TX_DELAY;
|
||||
+ val &= ~RTL8211F_TX_DELAY;
|
||||
|
||||
- phy_write(phydev, 0x11, reg);
|
||||
- /* restore to default page 0 */
|
||||
- phy_write(phydev, RTL821x_PAGE_SELECT, 0x0);
|
||||
+ ret = rtl8211x_page_write(phydev, 0xd08, 0x11, val);
|
||||
+ if (ret)
|
||||
+ return ret;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
From 13e556c6d4ece3c890edc414f205cc26381e9826 Mon Sep 17 00:00:00 2001
|
||||
From: Martin Blumenstingl <martin.blumenstingl@googlemail.com>
|
||||
Date: Sat, 2 Dec 2017 23:06:48 +0100
|
||||
Subject: [PATCH] FROMLIST: net: phy: realtek: add support for configuring the
|
||||
RX delay on RTL8211F
|
||||
|
||||
On RTL8211F the RX delay can also be enabled/disabled.
|
||||
The overall behavior of the RX delay is similar to the behavior of the
|
||||
TX delay, which was already supported by the driver.
|
||||
|
||||
The RX delay (similar to the TX delay) may be enabled using hardware pin
|
||||
strapping. If the MAC already configures the RX delay (if required) then
|
||||
the RX delay generated by the RTL8211F PHY has to be turned off.
|
||||
|
||||
While here, update the comment regarding the TX delay why it has to be
|
||||
enabled or disabled within the driver.
|
||||
Also avoid code-duplication by extracting the code to mask/unmask bits
|
||||
in a paged register into a new rtl8211x_page_mask_bits helper function.
|
||||
|
||||
Signed-off-by: Martin Blumenstingl <martin.blumenstingl@googlemail.com>
|
||||
---
|
||||
drivers/net/phy/realtek.c | 55 ++++++++++++++++++++++++++++++++++++++---------
|
||||
1 file changed, 45 insertions(+), 10 deletions(-)
|
||||
|
||||
diff --git a/drivers/net/phy/realtek.c b/drivers/net/phy/realtek.c
|
||||
index b1d52e61d91c..890ea9d18d27 100644
|
||||
--- a/drivers/net/phy/realtek.c
|
||||
+++ b/drivers/net/phy/realtek.c
|
||||
@@ -32,7 +32,10 @@
|
||||
|
||||
#define RTL8211F_INSR 0x1d
|
||||
|
||||
-#define RTL8211F_TX_DELAY BIT(8)
|
||||
+#define RTL8211F_RX_DELAY_REG 0x15
|
||||
+#define RTL8211F_RX_DELAY_EN BIT(3)
|
||||
+#define RTL8211F_TX_DELAY_REG 0x11
|
||||
+#define RTL8211F_TX_DELAY_EN BIT(8)
|
||||
|
||||
#define RTL8201F_ISR 0x1e
|
||||
#define RTL8201F_IER 0x13
|
||||
@@ -74,6 +77,23 @@ static int rtl8211x_page_write(struct phy_device *phydev, u16 page,
|
||||
return ret;
|
||||
}
|
||||
|
||||
+static int rtl8211x_page_mask_bits(struct phy_device *phydev, u16 page,
|
||||
+ u16 address, u16 mask, u16 set)
|
||||
+{
|
||||
+ int ret;
|
||||
+ u16 val;
|
||||
+
|
||||
+ ret = rtl8211x_page_read(phydev, page, address);
|
||||
+ if (ret < 0)
|
||||
+ return ret;
|
||||
+
|
||||
+ val = ret & 0xffff;
|
||||
+ val &= ~mask;
|
||||
+ val |= (set & mask);
|
||||
+
|
||||
+ return rtl8211x_page_write(phydev, page, address, val);
|
||||
+}
|
||||
+
|
||||
static int rtl8201_ack_interrupt(struct phy_device *phydev)
|
||||
{
|
||||
int err;
|
||||
@@ -160,20 +180,35 @@ static int rtl8211f_config_init(struct phy_device *phydev)
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
- ret = rtl8211x_page_read(phydev, 0xd08, 0x11);
|
||||
- if (ret < 0)
|
||||
- return ret;
|
||||
+ /*
|
||||
+ * enable TX-delay for rgmii-id and rgmii-txid, otherwise disable it.
|
||||
+ * this is needed because it can be enabled by pin strapping and
|
||||
+ * conflict with the TX-delay configured by the MAC.
|
||||
+ */
|
||||
+ if (phydev->interface == PHY_INTERFACE_MODE_RGMII_ID ||
|
||||
+ phydev->interface == PHY_INTERFACE_MODE_RGMII_TXID)
|
||||
+ val = RTL8211F_TX_DELAY_EN;
|
||||
+ else
|
||||
+ val = 0;
|
||||
|
||||
- val = ret & 0xffff;
|
||||
+ ret = rtl8211x_page_mask_bits(phydev, 0xd08, RTL8211F_TX_DELAY_REG,
|
||||
+ RTL8211F_TX_DELAY_EN, val);
|
||||
+ if (ret)
|
||||
+ return ret;
|
||||
|
||||
- /* enable TX-delay for rgmii-id and rgmii-txid, otherwise disable it */
|
||||
+ /*
|
||||
+ * enable RX-delay for rgmii-id and rgmii-rxid, otherwise disable it.
|
||||
+ * this is needed because it can be enabled by pin strapping and
|
||||
+ * conflict with the RX-delay configured by the MAC.
|
||||
+ */
|
||||
if (phydev->interface == PHY_INTERFACE_MODE_RGMII_ID ||
|
||||
- phydev->interface == PHY_INTERFACE_MODE_RGMII_TXID)
|
||||
- val |= RTL8211F_TX_DELAY;
|
||||
+ phydev->interface == PHY_INTERFACE_MODE_RGMII_RXID)
|
||||
+ val = RTL8211F_RX_DELAY_EN;
|
||||
else
|
||||
- val &= ~RTL8211F_TX_DELAY;
|
||||
+ val = 0;
|
||||
|
||||
- ret = rtl8211x_page_write(phydev, 0xd08, 0x11, val);
|
||||
+ ret = rtl8211x_page_mask_bits(phydev, 0xd08, RTL8211F_RX_DELAY_REG,
|
||||
+ RTL8211F_RX_DELAY_EN, val);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
|
||||
From e8fa4ce26460af84f028b7d215134caa33aa9ecb Mon Sep 17 00:00:00 2001
|
||||
From: Martin Blumenstingl <martin.blumenstingl@googlemail.com>
|
||||
Date: Sat, 2 Dec 2017 23:06:49 +0100
|
||||
Subject: [PATCH] FROMLIST: net: phy: realtek: configure the INTB pin on
|
||||
RTL8211F
|
||||
|
||||
The interrupt pin on the RTL8211F PHY can be used in two different
|
||||
modes:
|
||||
INTB
|
||||
- the default mode of the PHY
|
||||
- interrupts can be configured through page 0xa42 register RTL821x_INER
|
||||
- interrupts can be ACK'ed through RTL8211F_INSR
|
||||
- it acts as a level-interrupt which is active low
|
||||
- Wake-on-LAN "wakeup" status is available in RTL8211F_INSR bit 7
|
||||
|
||||
PMEB:
|
||||
- special mode for Wake-on-LAN
|
||||
- interrupts configured through page 0xa42 register RTL821x_INER are
|
||||
disabled
|
||||
- it supports a "pulse low" waveform for the interrupt
|
||||
|
||||
For now we simply force the pin into INTB mode since the PHY driver does
|
||||
not support Wake-on-LAN yet.
|
||||
|
||||
Signed-off-by: Martin Blumenstingl <martin.blumenstingl@googlemail.com>
|
||||
---
|
||||
drivers/net/phy/realtek.c | 27 +++++++++++++++++++++++++--
|
||||
1 file changed, 25 insertions(+), 2 deletions(-)
|
||||
|
||||
diff --git a/drivers/net/phy/realtek.c b/drivers/net/phy/realtek.c
|
||||
index 890ea9d18d27..f307d220b49a 100644
|
||||
--- a/drivers/net/phy/realtek.c
|
||||
+++ b/drivers/net/phy/realtek.c
|
||||
@@ -40,6 +40,9 @@
|
||||
#define RTL8201F_ISR 0x1e
|
||||
#define RTL8201F_IER 0x13
|
||||
|
||||
+#define RTL8211F_INTBCR 0x16
|
||||
+#define RTL8211F_INTBCR_INTB_PMEB BIT(5)
|
||||
+
|
||||
MODULE_DESCRIPTION("Realtek PHY driver");
|
||||
MODULE_AUTHOR("Johnson Leung");
|
||||
MODULE_LICENSE("GPL");
|
||||
@@ -161,12 +164,32 @@ static int rtl8211e_config_intr(struct phy_device *phydev)
|
||||
|
||||
static int rtl8211f_config_intr(struct phy_device *phydev)
|
||||
{
|
||||
+ int err;
|
||||
u16 val;
|
||||
|
||||
- if (phydev->interrupts == PHY_INTERRUPT_ENABLED)
|
||||
+ if (phydev->interrupts == PHY_INTERRUPT_ENABLED) {
|
||||
+ /*
|
||||
+ * The interrupt pin has two functions:
|
||||
+ * 0: INTB: it acts as interrupt pin which can be configured
|
||||
+ * through RTL821x_INER and the status can be read through
|
||||
+ * RTL8211F_INSR
|
||||
+ * 1: PMEB: a special "Power Management Event" mode for
|
||||
+ * Wake-on-LAN operation (with support for a "pulse low"
|
||||
+ * wave format). Interrupts configured through RTL821x_INER
|
||||
+ * will not work in this mode
|
||||
+ *
|
||||
+ * select INTB mode in the "INTB pin control" register to
|
||||
+ * ensure that the interrupt pin is in the correct mode.
|
||||
+ */
|
||||
+ err = rtl8211x_page_mask_bits(phydev, 0xd40, RTL8211F_INTBCR,
|
||||
+ RTL8211F_INTBCR_INTB_PMEB, 0);
|
||||
+ if (err)
|
||||
+ return err;
|
||||
+
|
||||
val = RTL8211F_INER_LINK_STATUS;
|
||||
- else
|
||||
+ } else {
|
||||
val = 0;
|
||||
+ }
|
||||
|
||||
return rtl8211x_page_write(phydev, 0xa42, RTL821x_INER, val);
|
||||
}
|
||||
|
||||
From dd026c252cd898bca0b85eb14aa6479b415d2471 Mon Sep 17 00:00:00 2001
|
||||
From: Martin Blumenstingl <martin.blumenstingl@googlemail.com>
|
||||
Date: Sat, 2 Dec 2017 23:06:50 +0100
|
||||
Subject: [PATCH] FROMLIST: net: phy: realtek: add more interrupt bits for
|
||||
RTL8211E and RTL8211F
|
||||
|
||||
This documents a few more bits in the RTL821x_INER register for RTL8211E
|
||||
and RTL8211F. These are added only to document them (as no public
|
||||
datasheets are available for these PHYs), they are currently not used.
|
||||
|
||||
Signed-off-by: Martin Blumenstingl <martin.blumenstingl@googlemail.com>
|
||||
---
|
||||
drivers/net/phy/realtek.c | 7 +++++++
|
||||
1 file changed, 7 insertions(+)
|
||||
|
||||
diff --git a/drivers/net/phy/realtek.c b/drivers/net/phy/realtek.c
|
||||
index f307d220b49a..15d342eefd6d 100644
|
||||
--- a/drivers/net/phy/realtek.c
|
||||
+++ b/drivers/net/phy/realtek.c
|
||||
@@ -24,7 +24,14 @@
|
||||
#define RTL821x_INER 0x12
|
||||
#define RTL8211B_INER_INIT 0x6400
|
||||
#define RTL8211E_INER_LINK_STATUS BIT(10)
|
||||
+#define RTL8211E_INER_ANEG_COMPLETED BIT(11)
|
||||
+#define RTL8211E_INER_PAGE_RECEIVED BIT(12)
|
||||
+#define RTL8211E_INER_ANEG_ERROR BIT(15)
|
||||
#define RTL8211F_INER_LINK_STATUS BIT(4)
|
||||
+#define RTL8211F_INER_PHY_REGISTER_ACCESSIBLE BIT(5)
|
||||
+#define RTL8211F_INER_WOL_PME BIT(7)
|
||||
+#define RTL8211F_INER_ALDPS_STATE_CHANGE BIT(9)
|
||||
+#define RTL8211F_INER_JABBER BIT(10)
|
||||
|
||||
#define RTL821x_INSR 0x13
|
||||
|
1120
patch/kernel/rockchip-default/01-linux-0007-dtoverlay-configfs.patch
Normal file
1120
patch/kernel/rockchip-default/01-linux-0007-dtoverlay-configfs.patch
Normal file
File diff suppressed because it is too large
Load diff
949
patch/kernel/rockchip-default/01-linux-0008-mmc-pwrseq.patch
Normal file
949
patch/kernel/rockchip-default/01-linux-0008-mmc-pwrseq.patch
Normal file
|
@ -0,0 +1,949 @@
|
|||
From 75bb99dc815464846a4add357494acf04212271d Mon Sep 17 00:00:00 2001
|
||||
From: Julia Lawall <Julia.Lawall@lip6.fr>
|
||||
Date: Sat, 14 Nov 2015 18:05:20 +0100
|
||||
Subject: [PATCH] UPSTREAM: mmc: pwrseq: constify mmc_pwrseq_ops structures
|
||||
|
||||
The mmc_pwrseq_ops structures are never modified, so declare them as const.
|
||||
|
||||
Done with the help of Coccinelle.
|
||||
|
||||
Signed-off-by: Julia Lawall <Julia.Lawall@lip6.fr>
|
||||
Signed-off-by: Ulf Hansson <ulf.hansson@linaro.org>
|
||||
(cherry picked from commit ffedbd2210f2f4cba490a9205adc11fd1b89a852)
|
||||
---
|
||||
drivers/mmc/core/pwrseq.h | 2 +-
|
||||
drivers/mmc/core/pwrseq_emmc.c | 2 +-
|
||||
drivers/mmc/core/pwrseq_simple.c | 2 +-
|
||||
3 files changed, 3 insertions(+), 3 deletions(-)
|
||||
|
||||
diff --git a/drivers/mmc/core/pwrseq.h b/drivers/mmc/core/pwrseq.h
|
||||
index 096da48c6a7e..133de0426687 100644
|
||||
--- a/drivers/mmc/core/pwrseq.h
|
||||
+++ b/drivers/mmc/core/pwrseq.h
|
||||
@@ -16,7 +16,7 @@ struct mmc_pwrseq_ops {
|
||||
};
|
||||
|
||||
struct mmc_pwrseq {
|
||||
- struct mmc_pwrseq_ops *ops;
|
||||
+ const struct mmc_pwrseq_ops *ops;
|
||||
};
|
||||
|
||||
#ifdef CONFIG_OF
|
||||
diff --git a/drivers/mmc/core/pwrseq_emmc.c b/drivers/mmc/core/pwrseq_emmc.c
|
||||
index ad4f94ec7e8d..4a82bc77fe49 100644
|
||||
--- a/drivers/mmc/core/pwrseq_emmc.c
|
||||
+++ b/drivers/mmc/core/pwrseq_emmc.c
|
||||
@@ -51,7 +51,7 @@ static void mmc_pwrseq_emmc_free(struct mmc_host *host)
|
||||
kfree(pwrseq);
|
||||
}
|
||||
|
||||
-static struct mmc_pwrseq_ops mmc_pwrseq_emmc_ops = {
|
||||
+static const struct mmc_pwrseq_ops mmc_pwrseq_emmc_ops = {
|
||||
.post_power_on = mmc_pwrseq_emmc_reset,
|
||||
.free = mmc_pwrseq_emmc_free,
|
||||
};
|
||||
diff --git a/drivers/mmc/core/pwrseq_simple.c b/drivers/mmc/core/pwrseq_simple.c
|
||||
index d10538bb5e07..2b16263458af 100644
|
||||
--- a/drivers/mmc/core/pwrseq_simple.c
|
||||
+++ b/drivers/mmc/core/pwrseq_simple.c
|
||||
@@ -87,7 +87,7 @@ static void mmc_pwrseq_simple_free(struct mmc_host *host)
|
||||
kfree(pwrseq);
|
||||
}
|
||||
|
||||
-static struct mmc_pwrseq_ops mmc_pwrseq_simple_ops = {
|
||||
+static const struct mmc_pwrseq_ops mmc_pwrseq_simple_ops = {
|
||||
.pre_power_on = mmc_pwrseq_simple_pre_power_on,
|
||||
.post_power_on = mmc_pwrseq_simple_post_power_on,
|
||||
.power_off = mmc_pwrseq_simple_power_off,
|
||||
|
||||
From 1977551c6ef29f55b398a02112e3075c9a38649d Mon Sep 17 00:00:00 2001
|
||||
From: Martin Fuzzey <mfuzzey@parkeon.com>
|
||||
Date: Wed, 20 Jan 2016 16:08:03 +0100
|
||||
Subject: [PATCH] UPSTREAM: mmc: pwrseq_simple: Make reset-gpios optional to
|
||||
match doc
|
||||
|
||||
The DT binding doc says reset-gpios is an optional property but the code
|
||||
currently bails out if it is omitted.
|
||||
|
||||
This is a regression since it breaks previously working device trees.
|
||||
Fix it by restoring the original documented behaviour.
|
||||
|
||||
Fixes: ce037275861e ("mmc: pwrseq_simple: use GPIO descriptors array API")
|
||||
Tested-by: Tony Lindgren <tony@atomide.com>
|
||||
Signed-off-by: Martin Fuzzey <mfuzzey@parkeon.com>
|
||||
Signed-off-by: Ulf Hansson <ulf.hansson@linaro.org>
|
||||
(cherry picked from commit 64a67d4762ce3ce4c9466eadd152d825fbf84967)
|
||||
---
|
||||
drivers/mmc/core/pwrseq_simple.c | 22 ++++++++++++++--------
|
||||
1 file changed, 14 insertions(+), 8 deletions(-)
|
||||
|
||||
diff --git a/drivers/mmc/core/pwrseq_simple.c b/drivers/mmc/core/pwrseq_simple.c
|
||||
index 2b16263458af..aba786daebca 100644
|
||||
--- a/drivers/mmc/core/pwrseq_simple.c
|
||||
+++ b/drivers/mmc/core/pwrseq_simple.c
|
||||
@@ -29,15 +29,18 @@ struct mmc_pwrseq_simple {
|
||||
static void mmc_pwrseq_simple_set_gpios_value(struct mmc_pwrseq_simple *pwrseq,
|
||||
int value)
|
||||
{
|
||||
- int i;
|
||||
struct gpio_descs *reset_gpios = pwrseq->reset_gpios;
|
||||
- int values[reset_gpios->ndescs];
|
||||
|
||||
- for (i = 0; i < reset_gpios->ndescs; i++)
|
||||
- values[i] = value;
|
||||
+ if (!IS_ERR(reset_gpios)) {
|
||||
+ int i;
|
||||
+ int values[reset_gpios->ndescs];
|
||||
|
||||
- gpiod_set_array_value_cansleep(reset_gpios->ndescs, reset_gpios->desc,
|
||||
- values);
|
||||
+ for (i = 0; i < reset_gpios->ndescs; i++)
|
||||
+ values[i] = value;
|
||||
+
|
||||
+ gpiod_set_array_value_cansleep(
|
||||
+ reset_gpios->ndescs, reset_gpios->desc, values);
|
||||
+ }
|
||||
}
|
||||
|
||||
static void mmc_pwrseq_simple_pre_power_on(struct mmc_host *host)
|
||||
@@ -79,7 +82,8 @@ static void mmc_pwrseq_simple_free(struct mmc_host *host)
|
||||
struct mmc_pwrseq_simple *pwrseq = container_of(host->pwrseq,
|
||||
struct mmc_pwrseq_simple, pwrseq);
|
||||
|
||||
- gpiod_put_array(pwrseq->reset_gpios);
|
||||
+ if (!IS_ERR(pwrseq->reset_gpios))
|
||||
+ gpiod_put_array(pwrseq->reset_gpios);
|
||||
|
||||
if (!IS_ERR(pwrseq->ext_clk))
|
||||
clk_put(pwrseq->ext_clk);
|
||||
@@ -112,7 +116,9 @@ struct mmc_pwrseq *mmc_pwrseq_simple_alloc(struct mmc_host *host,
|
||||
}
|
||||
|
||||
pwrseq->reset_gpios = gpiod_get_array(dev, "reset", GPIOD_OUT_HIGH);
|
||||
- if (IS_ERR(pwrseq->reset_gpios)) {
|
||||
+ if (IS_ERR(pwrseq->reset_gpios) &&
|
||||
+ PTR_ERR(pwrseq->reset_gpios) != -ENOENT &&
|
||||
+ PTR_ERR(pwrseq->reset_gpios) != -ENOSYS) {
|
||||
ret = PTR_ERR(pwrseq->reset_gpios);
|
||||
goto clk_put;
|
||||
}
|
||||
|
||||
From e79ed0004dc68dc2f2189256bf00a1f579c78f1a Mon Sep 17 00:00:00 2001
|
||||
From: Peter Chen <peter.chen@freescale.com>
|
||||
Date: Wed, 6 Jan 2016 11:34:10 +0800
|
||||
Subject: [PATCH] UPSTREAM: mmc: core: pwrseq_simple: remove unused header file
|
||||
|
||||
Signed-off-by: Peter Chen <peter.chen@freescale.com>
|
||||
Signed-off-by: Ulf Hansson <ulf.hansson@linaro.org>
|
||||
(cherry picked from commit 62c03ca3ffa1ddf55a66411be02f7e4678771fce)
|
||||
---
|
||||
drivers/mmc/core/pwrseq_simple.c | 1 -
|
||||
1 file changed, 1 deletion(-)
|
||||
|
||||
diff --git a/drivers/mmc/core/pwrseq_simple.c b/drivers/mmc/core/pwrseq_simple.c
|
||||
index aba786daebca..bc173e18b71c 100644
|
||||
--- a/drivers/mmc/core/pwrseq_simple.c
|
||||
+++ b/drivers/mmc/core/pwrseq_simple.c
|
||||
@@ -12,7 +12,6 @@
|
||||
#include <linux/slab.h>
|
||||
#include <linux/device.h>
|
||||
#include <linux/err.h>
|
||||
-#include <linux/of_gpio.h>
|
||||
#include <linux/gpio/consumer.h>
|
||||
|
||||
#include <linux/mmc/host.h>
|
||||
|
||||
From 545d059f7a0a4c470acfdb0fff30397899597f09 Mon Sep 17 00:00:00 2001
|
||||
From: Srinivas Kandagatla <srinivas.kandagatla@linaro.org>
|
||||
Date: Thu, 14 Apr 2016 14:02:14 +0100
|
||||
Subject: [PATCH] UPSTREAM: mmc: pwrseq_simple: add to_pwrseq_simple() macro
|
||||
|
||||
This patch adds to_pwrseq_simple() macro to make the code more readable.
|
||||
|
||||
Signed-off-by: Srinivas Kandagatla <srinivas.kandagatla@linaro.org>
|
||||
Signed-off-by: Ulf Hansson <ulf.hansson@linaro.org>
|
||||
(cherry picked from commit 5b96fea730ab79bdf6f8071cadf8208296bf5e8d)
|
||||
---
|
||||
drivers/mmc/core/pwrseq_simple.c | 14 ++++++--------
|
||||
1 file changed, 6 insertions(+), 8 deletions(-)
|
||||
|
||||
diff --git a/drivers/mmc/core/pwrseq_simple.c b/drivers/mmc/core/pwrseq_simple.c
|
||||
index bc173e18b71c..f94271bb1f6b 100644
|
||||
--- a/drivers/mmc/core/pwrseq_simple.c
|
||||
+++ b/drivers/mmc/core/pwrseq_simple.c
|
||||
@@ -25,6 +25,8 @@ struct mmc_pwrseq_simple {
|
||||
struct gpio_descs *reset_gpios;
|
||||
};
|
||||
|
||||
+#define to_pwrseq_simple(p) container_of(p, struct mmc_pwrseq_simple, pwrseq)
|
||||
+
|
||||
static void mmc_pwrseq_simple_set_gpios_value(struct mmc_pwrseq_simple *pwrseq,
|
||||
int value)
|
||||
{
|
||||
@@ -44,8 +46,7 @@ static void mmc_pwrseq_simple_set_gpios_value(struct mmc_pwrseq_simple *pwrseq,
|
||||
|
||||
static void mmc_pwrseq_simple_pre_power_on(struct mmc_host *host)
|
||||
{
|
||||
- struct mmc_pwrseq_simple *pwrseq = container_of(host->pwrseq,
|
||||
- struct mmc_pwrseq_simple, pwrseq);
|
||||
+ struct mmc_pwrseq_simple *pwrseq = to_pwrseq_simple(host->pwrseq);
|
||||
|
||||
if (!IS_ERR(pwrseq->ext_clk) && !pwrseq->clk_enabled) {
|
||||
clk_prepare_enable(pwrseq->ext_clk);
|
||||
@@ -57,16 +58,14 @@ static void mmc_pwrseq_simple_pre_power_on(struct mmc_host *host)
|
||||
|
||||
static void mmc_pwrseq_simple_post_power_on(struct mmc_host *host)
|
||||
{
|
||||
- struct mmc_pwrseq_simple *pwrseq = container_of(host->pwrseq,
|
||||
- struct mmc_pwrseq_simple, pwrseq);
|
||||
+ struct mmc_pwrseq_simple *pwrseq = to_pwrseq_simple(host->pwrseq);
|
||||
|
||||
mmc_pwrseq_simple_set_gpios_value(pwrseq, 0);
|
||||
}
|
||||
|
||||
static void mmc_pwrseq_simple_power_off(struct mmc_host *host)
|
||||
{
|
||||
- struct mmc_pwrseq_simple *pwrseq = container_of(host->pwrseq,
|
||||
- struct mmc_pwrseq_simple, pwrseq);
|
||||
+ struct mmc_pwrseq_simple *pwrseq = to_pwrseq_simple(host->pwrseq);
|
||||
|
||||
mmc_pwrseq_simple_set_gpios_value(pwrseq, 1);
|
||||
|
||||
@@ -78,8 +77,7 @@ static void mmc_pwrseq_simple_power_off(struct mmc_host *host)
|
||||
|
||||
static void mmc_pwrseq_simple_free(struct mmc_host *host)
|
||||
{
|
||||
- struct mmc_pwrseq_simple *pwrseq = container_of(host->pwrseq,
|
||||
- struct mmc_pwrseq_simple, pwrseq);
|
||||
+ struct mmc_pwrseq_simple *pwrseq = to_pwrseq_simple(host->pwrseq);
|
||||
|
||||
if (!IS_ERR(pwrseq->reset_gpios))
|
||||
gpiod_put_array(pwrseq->reset_gpios);
|
||||
|
||||
From e8c5f0b9383e6a528c8fc00d61755f8187e4c0b8 Mon Sep 17 00:00:00 2001
|
||||
From: Srinivas Kandagatla <srinivas.kandagatla@linaro.org>
|
||||
Date: Thu, 14 Apr 2016 14:02:15 +0100
|
||||
Subject: [PATCH] UPSTREAM: mmc: pwrseq_emmc: add to_pwrseq_emmc() macro
|
||||
|
||||
This patch adds to_pwrseq_emmc() macro to make the code more readable.
|
||||
|
||||
Signed-off-by: Srinivas Kandagatla <srinivas.kandagatla@linaro.org>
|
||||
Signed-off-by: Ulf Hansson <ulf.hansson@linaro.org>
|
||||
(cherry picked from commit f01b72d0fd53b61cafd25b16d15e18b1ef8ae065)
|
||||
---
|
||||
drivers/mmc/core/pwrseq_emmc.c | 8 ++++----
|
||||
1 file changed, 4 insertions(+), 4 deletions(-)
|
||||
|
||||
diff --git a/drivers/mmc/core/pwrseq_emmc.c b/drivers/mmc/core/pwrseq_emmc.c
|
||||
index 4a82bc77fe49..c2d732aa464c 100644
|
||||
--- a/drivers/mmc/core/pwrseq_emmc.c
|
||||
+++ b/drivers/mmc/core/pwrseq_emmc.c
|
||||
@@ -25,6 +25,8 @@ struct mmc_pwrseq_emmc {
|
||||
struct gpio_desc *reset_gpio;
|
||||
};
|
||||
|
||||
+#define to_pwrseq_emmc(p) container_of(p, struct mmc_pwrseq_emmc, pwrseq)
|
||||
+
|
||||
static void __mmc_pwrseq_emmc_reset(struct mmc_pwrseq_emmc *pwrseq)
|
||||
{
|
||||
gpiod_set_value(pwrseq->reset_gpio, 1);
|
||||
@@ -35,16 +37,14 @@ static void __mmc_pwrseq_emmc_reset(struct mmc_pwrseq_emmc *pwrseq)
|
||||
|
||||
static void mmc_pwrseq_emmc_reset(struct mmc_host *host)
|
||||
{
|
||||
- struct mmc_pwrseq_emmc *pwrseq = container_of(host->pwrseq,
|
||||
- struct mmc_pwrseq_emmc, pwrseq);
|
||||
+ struct mmc_pwrseq_emmc *pwrseq = to_pwrseq_emmc(host->pwrseq);
|
||||
|
||||
__mmc_pwrseq_emmc_reset(pwrseq);
|
||||
}
|
||||
|
||||
static void mmc_pwrseq_emmc_free(struct mmc_host *host)
|
||||
{
|
||||
- struct mmc_pwrseq_emmc *pwrseq = container_of(host->pwrseq,
|
||||
- struct mmc_pwrseq_emmc, pwrseq);
|
||||
+ struct mmc_pwrseq_emmc *pwrseq = to_pwrseq_emmc(host->pwrseq);
|
||||
|
||||
unregister_restart_handler(&pwrseq->reset_nb);
|
||||
gpiod_put(pwrseq->reset_gpio);
|
||||
|
||||
From ef2f3c5b7375b930697a64c85f30f9109e631cb0 Mon Sep 17 00:00:00 2001
|
||||
From: Srinivas Kandagatla <srinivas.kandagatla@linaro.org>
|
||||
Date: Thu, 14 Apr 2016 14:02:16 +0100
|
||||
Subject: [PATCH] UPSTREAM: mmc: pwrseq: convert to proper platform device
|
||||
|
||||
simple-pwrseq and emmc-pwrseq drivers rely on platform_device
|
||||
structure from of_find_device_by_node(), this works mostly. But, as there
|
||||
is no driver associated with this devices, cases like default/init pinctrl
|
||||
setup would never be performed by pwrseq. This becomes problem when the
|
||||
gpios used in pwrseq require pinctrl setup.
|
||||
|
||||
Currently most of the common pinctrl setup is done in
|
||||
drivers/base/pinctrl.c by pinctrl_bind_pins().
|
||||
|
||||
There are two ways to solve this issue on either convert pwrseq drivers
|
||||
to a proper platform drivers or copy the exact code from
|
||||
pcintrl_bind_pins(). I prefer converting pwrseq to proper drivers so that
|
||||
other cases like setting up clks/parents from dt would also be possible.
|
||||
|
||||
Signed-off-by: Srinivas Kandagatla <srinivas.kandagatla@linaro.org>
|
||||
Signed-off-by: Ulf Hansson <ulf.hansson@linaro.org>
|
||||
(cherry picked from commit d97a1e5d7cd2b5b0edc02a40fe6897b710c9e10f)
|
||||
---
|
||||
drivers/mmc/core/Kconfig | 22 ++++++++
|
||||
drivers/mmc/core/Makefile | 4 +-
|
||||
drivers/mmc/core/pwrseq.c | 108 ++++++++++++++++++---------------------
|
||||
drivers/mmc/core/pwrseq.h | 19 ++++---
|
||||
drivers/mmc/core/pwrseq_emmc.c | 75 +++++++++++++++++----------
|
||||
drivers/mmc/core/pwrseq_simple.c | 79 +++++++++++++++-------------
|
||||
6 files changed, 178 insertions(+), 129 deletions(-)
|
||||
|
||||
diff --git a/drivers/mmc/core/Kconfig b/drivers/mmc/core/Kconfig
|
||||
index 87cc07dedd9f..00dfaea06003 100644
|
||||
--- a/drivers/mmc/core/Kconfig
|
||||
+++ b/drivers/mmc/core/Kconfig
|
||||
@@ -16,3 +16,25 @@ config MMC_PARANOID_SD_INIT
|
||||
about re-trying SD init requests. This can be a useful
|
||||
work-around for buggy controllers and hardware. Enable
|
||||
if you are experiencing issues with SD detection.
|
||||
+
|
||||
+config PWRSEQ_EMMC
|
||||
+ tristate "HW reset support for eMMC"
|
||||
+ default y
|
||||
+ depends on OF
|
||||
+ help
|
||||
+ This selects Hardware reset support aka pwrseq-emmc for eMMC
|
||||
+ devices. By default this option is set to y.
|
||||
+
|
||||
+ This driver can also be built as a module. If so, the module
|
||||
+ will be called pwrseq_emmc.
|
||||
+
|
||||
+config PWRSEQ_SIMPLE
|
||||
+ tristate "Simple HW reset support for MMC"
|
||||
+ default y
|
||||
+ depends on OF
|
||||
+ help
|
||||
+ This selects simple hardware reset support aka pwrseq-simple for MMC
|
||||
+ devices. By default this option is set to y.
|
||||
+
|
||||
+ This driver can also be built as a module. If so, the module
|
||||
+ will be called pwrseq_simple.
|
||||
diff --git a/drivers/mmc/core/Makefile b/drivers/mmc/core/Makefile
|
||||
index 2c25138f28b7..f007151dfdc6 100644
|
||||
--- a/drivers/mmc/core/Makefile
|
||||
+++ b/drivers/mmc/core/Makefile
|
||||
@@ -8,5 +8,7 @@ mmc_core-y := core.o bus.o host.o \
|
||||
sdio.o sdio_ops.o sdio_bus.o \
|
||||
sdio_cis.o sdio_io.o sdio_irq.o \
|
||||
quirks.o slot-gpio.o
|
||||
-mmc_core-$(CONFIG_OF) += pwrseq.o pwrseq_simple.o pwrseq_emmc.o
|
||||
+mmc_core-$(CONFIG_OF) += pwrseq.o
|
||||
+obj-$(CONFIG_PWRSEQ_SIMPLE) += pwrseq_simple.o
|
||||
+obj-$(CONFIG_PWRSEQ_EMMC) += pwrseq_emmc.o
|
||||
mmc_core-$(CONFIG_DEBUG_FS) += debugfs.o
|
||||
diff --git a/drivers/mmc/core/pwrseq.c b/drivers/mmc/core/pwrseq.c
|
||||
index 4c1d1757dbf9..9386c4771814 100644
|
||||
--- a/drivers/mmc/core/pwrseq.c
|
||||
+++ b/drivers/mmc/core/pwrseq.c
|
||||
@@ -8,88 +8,55 @@
|
||||
* MMC power sequence management
|
||||
*/
|
||||
#include <linux/kernel.h>
|
||||
-#include <linux/platform_device.h>
|
||||
#include <linux/err.h>
|
||||
+#include <linux/module.h>
|
||||
#include <linux/of.h>
|
||||
-#include <linux/of_platform.h>
|
||||
|
||||
#include <linux/mmc/host.h>
|
||||
|
||||
#include "pwrseq.h"
|
||||
|
||||
-struct mmc_pwrseq_match {
|
||||
- const char *compatible;
|
||||
- struct mmc_pwrseq *(*alloc)(struct mmc_host *host, struct device *dev);
|
||||
-};
|
||||
-
|
||||
-static struct mmc_pwrseq_match pwrseq_match[] = {
|
||||
- {
|
||||
- .compatible = "mmc-pwrseq-simple",
|
||||
- .alloc = mmc_pwrseq_simple_alloc,
|
||||
- }, {
|
||||
- .compatible = "mmc-pwrseq-emmc",
|
||||
- .alloc = mmc_pwrseq_emmc_alloc,
|
||||
- },
|
||||
-};
|
||||
-
|
||||
-static struct mmc_pwrseq_match *mmc_pwrseq_find(struct device_node *np)
|
||||
-{
|
||||
- struct mmc_pwrseq_match *match = ERR_PTR(-ENODEV);
|
||||
- int i;
|
||||
-
|
||||
- for (i = 0; i < ARRAY_SIZE(pwrseq_match); i++) {
|
||||
- if (of_device_is_compatible(np, pwrseq_match[i].compatible)) {
|
||||
- match = &pwrseq_match[i];
|
||||
- break;
|
||||
- }
|
||||
- }
|
||||
-
|
||||
- return match;
|
||||
-}
|
||||
+static DEFINE_MUTEX(pwrseq_list_mutex);
|
||||
+static LIST_HEAD(pwrseq_list);
|
||||
|
||||
int mmc_pwrseq_alloc(struct mmc_host *host)
|
||||
{
|
||||
- struct platform_device *pdev;
|
||||
struct device_node *np;
|
||||
- struct mmc_pwrseq_match *match;
|
||||
- struct mmc_pwrseq *pwrseq;
|
||||
- int ret = 0;
|
||||
+ struct mmc_pwrseq *p;
|
||||
|
||||
np = of_parse_phandle(host->parent->of_node, "mmc-pwrseq", 0);
|
||||
if (!np)
|
||||
return 0;
|
||||
|
||||
- pdev = of_find_device_by_node(np);
|
||||
- if (!pdev) {
|
||||
- ret = -ENODEV;
|
||||
- goto err;
|
||||
- }
|
||||
+ mutex_lock(&pwrseq_list_mutex);
|
||||
+ list_for_each_entry(p, &pwrseq_list, pwrseq_node) {
|
||||
+ if (p->dev->of_node == np) {
|
||||
+ if (!try_module_get(p->owner))
|
||||
+ dev_err(host->parent,
|
||||
+ "increasing module refcount failed\n");
|
||||
+ else
|
||||
+ host->pwrseq = p;
|
||||
|
||||
- match = mmc_pwrseq_find(np);
|
||||
- if (IS_ERR(match)) {
|
||||
- ret = PTR_ERR(match);
|
||||
- goto err;
|
||||
+ break;
|
||||
+ }
|
||||
}
|
||||
|
||||
- pwrseq = match->alloc(host, &pdev->dev);
|
||||
- if (IS_ERR(pwrseq)) {
|
||||
- ret = PTR_ERR(pwrseq);
|
||||
- goto err;
|
||||
- }
|
||||
+ of_node_put(np);
|
||||
+ mutex_unlock(&pwrseq_list_mutex);
|
||||
+
|
||||
+ if (!host->pwrseq)
|
||||
+ return -EPROBE_DEFER;
|
||||
|
||||
- host->pwrseq = pwrseq;
|
||||
dev_info(host->parent, "allocated mmc-pwrseq\n");
|
||||
|
||||
-err:
|
||||
- of_node_put(np);
|
||||
- return ret;
|
||||
+ return 0;
|
||||
}
|
||||
|
||||
void mmc_pwrseq_pre_power_on(struct mmc_host *host)
|
||||
{
|
||||
struct mmc_pwrseq *pwrseq = host->pwrseq;
|
||||
|
||||
- if (pwrseq && pwrseq->ops && pwrseq->ops->pre_power_on)
|
||||
+ if (pwrseq && pwrseq->ops->pre_power_on)
|
||||
pwrseq->ops->pre_power_on(host);
|
||||
}
|
||||
|
||||
@@ -97,7 +64,7 @@ void mmc_pwrseq_post_power_on(struct mmc_host *host)
|
||||
{
|
||||
struct mmc_pwrseq *pwrseq = host->pwrseq;
|
||||
|
||||
- if (pwrseq && pwrseq->ops && pwrseq->ops->post_power_on)
|
||||
+ if (pwrseq && pwrseq->ops->post_power_on)
|
||||
pwrseq->ops->post_power_on(host);
|
||||
}
|
||||
|
||||
@@ -105,7 +72,7 @@ void mmc_pwrseq_power_off(struct mmc_host *host)
|
||||
{
|
||||
struct mmc_pwrseq *pwrseq = host->pwrseq;
|
||||
|
||||
- if (pwrseq && pwrseq->ops && pwrseq->ops->power_off)
|
||||
+ if (pwrseq && pwrseq->ops->power_off)
|
||||
pwrseq->ops->power_off(host);
|
||||
}
|
||||
|
||||
@@ -113,8 +80,31 @@ void mmc_pwrseq_free(struct mmc_host *host)
|
||||
{
|
||||
struct mmc_pwrseq *pwrseq = host->pwrseq;
|
||||
|
||||
- if (pwrseq && pwrseq->ops && pwrseq->ops->free)
|
||||
- pwrseq->ops->free(host);
|
||||
+ if (pwrseq) {
|
||||
+ module_put(pwrseq->owner);
|
||||
+ host->pwrseq = NULL;
|
||||
+ }
|
||||
+}
|
||||
+
|
||||
+int mmc_pwrseq_register(struct mmc_pwrseq *pwrseq)
|
||||
+{
|
||||
+ if (!pwrseq || !pwrseq->ops || !pwrseq->dev)
|
||||
+ return -EINVAL;
|
||||
|
||||
- host->pwrseq = NULL;
|
||||
+ mutex_lock(&pwrseq_list_mutex);
|
||||
+ list_add(&pwrseq->pwrseq_node, &pwrseq_list);
|
||||
+ mutex_unlock(&pwrseq_list_mutex);
|
||||
+
|
||||
+ return 0;
|
||||
+}
|
||||
+EXPORT_SYMBOL_GPL(mmc_pwrseq_register);
|
||||
+
|
||||
+void mmc_pwrseq_unregister(struct mmc_pwrseq *pwrseq)
|
||||
+{
|
||||
+ if (pwrseq) {
|
||||
+ mutex_lock(&pwrseq_list_mutex);
|
||||
+ list_del(&pwrseq->pwrseq_node);
|
||||
+ mutex_unlock(&pwrseq_list_mutex);
|
||||
+ }
|
||||
}
|
||||
+EXPORT_SYMBOL_GPL(mmc_pwrseq_unregister);
|
||||
diff --git a/drivers/mmc/core/pwrseq.h b/drivers/mmc/core/pwrseq.h
|
||||
index 133de0426687..d69e751f148b 100644
|
||||
--- a/drivers/mmc/core/pwrseq.h
|
||||
+++ b/drivers/mmc/core/pwrseq.h
|
||||
@@ -8,32 +8,39 @@
|
||||
#ifndef _MMC_CORE_PWRSEQ_H
|
||||
#define _MMC_CORE_PWRSEQ_H
|
||||
|
||||
+#include <linux/mmc/host.h>
|
||||
+
|
||||
struct mmc_pwrseq_ops {
|
||||
void (*pre_power_on)(struct mmc_host *host);
|
||||
void (*post_power_on)(struct mmc_host *host);
|
||||
void (*power_off)(struct mmc_host *host);
|
||||
- void (*free)(struct mmc_host *host);
|
||||
};
|
||||
|
||||
struct mmc_pwrseq {
|
||||
const struct mmc_pwrseq_ops *ops;
|
||||
+ struct device *dev;
|
||||
+ struct list_head pwrseq_node;
|
||||
+ struct module *owner;
|
||||
};
|
||||
|
||||
#ifdef CONFIG_OF
|
||||
|
||||
+int mmc_pwrseq_register(struct mmc_pwrseq *pwrseq);
|
||||
+void mmc_pwrseq_unregister(struct mmc_pwrseq *pwrseq);
|
||||
+
|
||||
int mmc_pwrseq_alloc(struct mmc_host *host);
|
||||
void mmc_pwrseq_pre_power_on(struct mmc_host *host);
|
||||
void mmc_pwrseq_post_power_on(struct mmc_host *host);
|
||||
void mmc_pwrseq_power_off(struct mmc_host *host);
|
||||
void mmc_pwrseq_free(struct mmc_host *host);
|
||||
|
||||
-struct mmc_pwrseq *mmc_pwrseq_simple_alloc(struct mmc_host *host,
|
||||
- struct device *dev);
|
||||
-struct mmc_pwrseq *mmc_pwrseq_emmc_alloc(struct mmc_host *host,
|
||||
- struct device *dev);
|
||||
-
|
||||
#else
|
||||
|
||||
+static inline int mmc_pwrseq_register(struct mmc_pwrseq *pwrseq)
|
||||
+{
|
||||
+ return -ENOSYS;
|
||||
+}
|
||||
+static inline void mmc_pwrseq_unregister(struct mmc_pwrseq *pwrseq) {}
|
||||
static inline int mmc_pwrseq_alloc(struct mmc_host *host) { return 0; }
|
||||
static inline void mmc_pwrseq_pre_power_on(struct mmc_host *host) {}
|
||||
static inline void mmc_pwrseq_post_power_on(struct mmc_host *host) {}
|
||||
diff --git a/drivers/mmc/core/pwrseq_emmc.c b/drivers/mmc/core/pwrseq_emmc.c
|
||||
index c2d732aa464c..adc9c0c614fb 100644
|
||||
--- a/drivers/mmc/core/pwrseq_emmc.c
|
||||
+++ b/drivers/mmc/core/pwrseq_emmc.c
|
||||
@@ -9,6 +9,9 @@
|
||||
*/
|
||||
#include <linux/delay.h>
|
||||
#include <linux/kernel.h>
|
||||
+#include <linux/init.h>
|
||||
+#include <linux/platform_device.h>
|
||||
+#include <linux/module.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/device.h>
|
||||
#include <linux/err.h>
|
||||
@@ -42,20 +45,6 @@ static void mmc_pwrseq_emmc_reset(struct mmc_host *host)
|
||||
__mmc_pwrseq_emmc_reset(pwrseq);
|
||||
}
|
||||
|
||||
-static void mmc_pwrseq_emmc_free(struct mmc_host *host)
|
||||
-{
|
||||
- struct mmc_pwrseq_emmc *pwrseq = to_pwrseq_emmc(host->pwrseq);
|
||||
-
|
||||
- unregister_restart_handler(&pwrseq->reset_nb);
|
||||
- gpiod_put(pwrseq->reset_gpio);
|
||||
- kfree(pwrseq);
|
||||
-}
|
||||
-
|
||||
-static const struct mmc_pwrseq_ops mmc_pwrseq_emmc_ops = {
|
||||
- .post_power_on = mmc_pwrseq_emmc_reset,
|
||||
- .free = mmc_pwrseq_emmc_free,
|
||||
-};
|
||||
-
|
||||
static int mmc_pwrseq_emmc_reset_nb(struct notifier_block *this,
|
||||
unsigned long mode, void *cmd)
|
||||
{
|
||||
@@ -66,21 +55,22 @@ static int mmc_pwrseq_emmc_reset_nb(struct notifier_block *this,
|
||||
return NOTIFY_DONE;
|
||||
}
|
||||
|
||||
-struct mmc_pwrseq *mmc_pwrseq_emmc_alloc(struct mmc_host *host,
|
||||
- struct device *dev)
|
||||
+static const struct mmc_pwrseq_ops mmc_pwrseq_emmc_ops = {
|
||||
+ .post_power_on = mmc_pwrseq_emmc_reset,
|
||||
+};
|
||||
+
|
||||
+static int mmc_pwrseq_emmc_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct mmc_pwrseq_emmc *pwrseq;
|
||||
- int ret = 0;
|
||||
+ struct device *dev = &pdev->dev;
|
||||
|
||||
- pwrseq = kzalloc(sizeof(struct mmc_pwrseq_emmc), GFP_KERNEL);
|
||||
+ pwrseq = devm_kzalloc(dev, sizeof(*pwrseq), GFP_KERNEL);
|
||||
if (!pwrseq)
|
||||
- return ERR_PTR(-ENOMEM);
|
||||
+ return -ENOMEM;
|
||||
|
||||
- pwrseq->reset_gpio = gpiod_get(dev, "reset", GPIOD_OUT_LOW);
|
||||
- if (IS_ERR(pwrseq->reset_gpio)) {
|
||||
- ret = PTR_ERR(pwrseq->reset_gpio);
|
||||
- goto free;
|
||||
- }
|
||||
+ pwrseq->reset_gpio = devm_gpiod_get(dev, "reset", GPIOD_OUT_LOW);
|
||||
+ if (IS_ERR(pwrseq->reset_gpio))
|
||||
+ return PTR_ERR(pwrseq->reset_gpio);
|
||||
|
||||
/*
|
||||
* register reset handler to ensure emmc reset also from
|
||||
@@ -92,9 +82,38 @@ struct mmc_pwrseq *mmc_pwrseq_emmc_alloc(struct mmc_host *host,
|
||||
register_restart_handler(&pwrseq->reset_nb);
|
||||
|
||||
pwrseq->pwrseq.ops = &mmc_pwrseq_emmc_ops;
|
||||
+ pwrseq->pwrseq.dev = dev;
|
||||
+ pwrseq->pwrseq.owner = THIS_MODULE;
|
||||
+ platform_set_drvdata(pdev, pwrseq);
|
||||
+
|
||||
+ return mmc_pwrseq_register(&pwrseq->pwrseq);
|
||||
+}
|
||||
+
|
||||
+static int mmc_pwrseq_emmc_remove(struct platform_device *pdev)
|
||||
+{
|
||||
+ struct mmc_pwrseq_emmc *pwrseq = platform_get_drvdata(pdev);
|
||||
+
|
||||
+ unregister_restart_handler(&pwrseq->reset_nb);
|
||||
+ mmc_pwrseq_unregister(&pwrseq->pwrseq);
|
||||
|
||||
- return &pwrseq->pwrseq;
|
||||
-free:
|
||||
- kfree(pwrseq);
|
||||
- return ERR_PTR(ret);
|
||||
+ return 0;
|
||||
}
|
||||
+
|
||||
+static const struct of_device_id mmc_pwrseq_emmc_of_match[] = {
|
||||
+ { .compatible = "mmc-pwrseq-emmc",},
|
||||
+ {/* sentinel */},
|
||||
+};
|
||||
+
|
||||
+MODULE_DEVICE_TABLE(of, mmc_pwrseq_emmc_of_match);
|
||||
+
|
||||
+static struct platform_driver mmc_pwrseq_emmc_driver = {
|
||||
+ .probe = mmc_pwrseq_emmc_probe,
|
||||
+ .remove = mmc_pwrseq_emmc_remove,
|
||||
+ .driver = {
|
||||
+ .name = "pwrseq_emmc",
|
||||
+ .of_match_table = mmc_pwrseq_emmc_of_match,
|
||||
+ },
|
||||
+};
|
||||
+
|
||||
+module_platform_driver(mmc_pwrseq_emmc_driver);
|
||||
+MODULE_LICENSE("GPL v2");
|
||||
diff --git a/drivers/mmc/core/pwrseq_simple.c b/drivers/mmc/core/pwrseq_simple.c
|
||||
index f94271bb1f6b..450d907c6e6c 100644
|
||||
--- a/drivers/mmc/core/pwrseq_simple.c
|
||||
+++ b/drivers/mmc/core/pwrseq_simple.c
|
||||
@@ -8,7 +8,10 @@
|
||||
* Simple MMC power sequence management
|
||||
*/
|
||||
#include <linux/clk.h>
|
||||
+#include <linux/init.h>
|
||||
#include <linux/kernel.h>
|
||||
+#include <linux/platform_device.h>
|
||||
+#include <linux/module.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/device.h>
|
||||
#include <linux/err.h>
|
||||
@@ -75,58 +78,64 @@ static void mmc_pwrseq_simple_power_off(struct mmc_host *host)
|
||||
}
|
||||
}
|
||||
|
||||
-static void mmc_pwrseq_simple_free(struct mmc_host *host)
|
||||
-{
|
||||
- struct mmc_pwrseq_simple *pwrseq = to_pwrseq_simple(host->pwrseq);
|
||||
-
|
||||
- if (!IS_ERR(pwrseq->reset_gpios))
|
||||
- gpiod_put_array(pwrseq->reset_gpios);
|
||||
-
|
||||
- if (!IS_ERR(pwrseq->ext_clk))
|
||||
- clk_put(pwrseq->ext_clk);
|
||||
-
|
||||
- kfree(pwrseq);
|
||||
-}
|
||||
-
|
||||
static const struct mmc_pwrseq_ops mmc_pwrseq_simple_ops = {
|
||||
.pre_power_on = mmc_pwrseq_simple_pre_power_on,
|
||||
.post_power_on = mmc_pwrseq_simple_post_power_on,
|
||||
.power_off = mmc_pwrseq_simple_power_off,
|
||||
- .free = mmc_pwrseq_simple_free,
|
||||
};
|
||||
|
||||
-struct mmc_pwrseq *mmc_pwrseq_simple_alloc(struct mmc_host *host,
|
||||
- struct device *dev)
|
||||
+static const struct of_device_id mmc_pwrseq_simple_of_match[] = {
|
||||
+ { .compatible = "mmc-pwrseq-simple",},
|
||||
+ {/* sentinel */},
|
||||
+};
|
||||
+MODULE_DEVICE_TABLE(of, mmc_pwrseq_simple_of_match);
|
||||
+
|
||||
+static int mmc_pwrseq_simple_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct mmc_pwrseq_simple *pwrseq;
|
||||
- int ret = 0;
|
||||
+ struct device *dev = &pdev->dev;
|
||||
|
||||
- pwrseq = kzalloc(sizeof(*pwrseq), GFP_KERNEL);
|
||||
+ pwrseq = devm_kzalloc(dev, sizeof(*pwrseq), GFP_KERNEL);
|
||||
if (!pwrseq)
|
||||
- return ERR_PTR(-ENOMEM);
|
||||
+ return -ENOMEM;
|
||||
|
||||
- pwrseq->ext_clk = clk_get(dev, "ext_clock");
|
||||
- if (IS_ERR(pwrseq->ext_clk) &&
|
||||
- PTR_ERR(pwrseq->ext_clk) != -ENOENT) {
|
||||
- ret = PTR_ERR(pwrseq->ext_clk);
|
||||
- goto free;
|
||||
- }
|
||||
+ pwrseq->ext_clk = devm_clk_get(dev, "ext_clock");
|
||||
+ if (IS_ERR(pwrseq->ext_clk) && PTR_ERR(pwrseq->ext_clk) != -ENOENT)
|
||||
+ return PTR_ERR(pwrseq->ext_clk);
|
||||
|
||||
- pwrseq->reset_gpios = gpiod_get_array(dev, "reset", GPIOD_OUT_HIGH);
|
||||
+ pwrseq->reset_gpios = devm_gpiod_get_array(dev, "reset",
|
||||
+ GPIOD_OUT_HIGH);
|
||||
if (IS_ERR(pwrseq->reset_gpios) &&
|
||||
PTR_ERR(pwrseq->reset_gpios) != -ENOENT &&
|
||||
PTR_ERR(pwrseq->reset_gpios) != -ENOSYS) {
|
||||
- ret = PTR_ERR(pwrseq->reset_gpios);
|
||||
- goto clk_put;
|
||||
+ return PTR_ERR(pwrseq->reset_gpios);
|
||||
}
|
||||
|
||||
+ pwrseq->pwrseq.dev = dev;
|
||||
pwrseq->pwrseq.ops = &mmc_pwrseq_simple_ops;
|
||||
+ pwrseq->pwrseq.owner = THIS_MODULE;
|
||||
+ platform_set_drvdata(pdev, pwrseq);
|
||||
|
||||
- return &pwrseq->pwrseq;
|
||||
-clk_put:
|
||||
- if (!IS_ERR(pwrseq->ext_clk))
|
||||
- clk_put(pwrseq->ext_clk);
|
||||
-free:
|
||||
- kfree(pwrseq);
|
||||
- return ERR_PTR(ret);
|
||||
+ return mmc_pwrseq_register(&pwrseq->pwrseq);
|
||||
}
|
||||
+
|
||||
+static int mmc_pwrseq_simple_remove(struct platform_device *pdev)
|
||||
+{
|
||||
+ struct mmc_pwrseq_simple *pwrseq = platform_get_drvdata(pdev);
|
||||
+
|
||||
+ mmc_pwrseq_unregister(&pwrseq->pwrseq);
|
||||
+
|
||||
+ return 0;
|
||||
+}
|
||||
+
|
||||
+static struct platform_driver mmc_pwrseq_simple_driver = {
|
||||
+ .probe = mmc_pwrseq_simple_probe,
|
||||
+ .remove = mmc_pwrseq_simple_remove,
|
||||
+ .driver = {
|
||||
+ .name = "pwrseq_simple",
|
||||
+ .of_match_table = mmc_pwrseq_simple_of_match,
|
||||
+ },
|
||||
+};
|
||||
+
|
||||
+module_platform_driver(mmc_pwrseq_simple_driver);
|
||||
+MODULE_LICENSE("GPL v2");
|
||||
|
||||
From 42eb02ddb70002e4f72fa627037b6acbdd4cb7a1 Mon Sep 17 00:00:00 2001
|
||||
From: Hans de Goede <hdegoede@redhat.com>
|
||||
Date: Sun, 7 Aug 2016 21:02:38 +0200
|
||||
Subject: [PATCH] UPSTREAM: mmc: pwrseq-simple: Add an optional
|
||||
post-power-on-delay
|
||||
|
||||
Some devices need a while to boot their firmware after providing clks /
|
||||
de-asserting resets before they are ready to receive sdio commands.
|
||||
|
||||
This commits adds a post-power-on-delay-ms devicetree property to
|
||||
mmc-pwrseq-simple for use with such devices.
|
||||
|
||||
Signed-off-by: Hans de Goede <hdegoede@redhat.com>
|
||||
Acked-by: Rob Herring <robh@kernel.org>
|
||||
Signed-off-by: Ulf Hansson <ulf.hansson@linaro.org>
|
||||
(cherry picked from commit 721e0497172f0fa661eed2d63367cddf479f35e8)
|
||||
---
|
||||
Documentation/devicetree/bindings/mmc/mmc-pwrseq-simple.txt | 2 ++
|
||||
drivers/mmc/core/pwrseq_simple.c | 9 +++++++++
|
||||
2 files changed, 11 insertions(+)
|
||||
|
||||
diff --git a/Documentation/devicetree/bindings/mmc/mmc-pwrseq-simple.txt b/Documentation/devicetree/bindings/mmc/mmc-pwrseq-simple.txt
|
||||
index ce0e76749671..e25436861867 100644
|
||||
--- a/Documentation/devicetree/bindings/mmc/mmc-pwrseq-simple.txt
|
||||
+++ b/Documentation/devicetree/bindings/mmc/mmc-pwrseq-simple.txt
|
||||
@@ -16,6 +16,8 @@ Optional properties:
|
||||
See ../clocks/clock-bindings.txt for details.
|
||||
- clock-names : Must include the following entry:
|
||||
"ext_clock" (External clock provided to the card).
|
||||
+- post-power-on-delay-ms : Delay in ms after powering the card and
|
||||
+ de-asserting the reset-gpios (if any)
|
||||
|
||||
Example:
|
||||
|
||||
diff --git a/drivers/mmc/core/pwrseq_simple.c b/drivers/mmc/core/pwrseq_simple.c
|
||||
index 450d907c6e6c..1304160de168 100644
|
||||
--- a/drivers/mmc/core/pwrseq_simple.c
|
||||
+++ b/drivers/mmc/core/pwrseq_simple.c
|
||||
@@ -16,6 +16,8 @@
|
||||
#include <linux/device.h>
|
||||
#include <linux/err.h>
|
||||
#include <linux/gpio/consumer.h>
|
||||
+#include <linux/delay.h>
|
||||
+#include <linux/property.h>
|
||||
|
||||
#include <linux/mmc/host.h>
|
||||
|
||||
@@ -24,6 +26,7 @@
|
||||
struct mmc_pwrseq_simple {
|
||||
struct mmc_pwrseq pwrseq;
|
||||
bool clk_enabled;
|
||||
+ u32 post_power_on_delay_ms;
|
||||
struct clk *ext_clk;
|
||||
struct gpio_descs *reset_gpios;
|
||||
};
|
||||
@@ -64,6 +67,9 @@ static void mmc_pwrseq_simple_post_power_on(struct mmc_host *host)
|
||||
struct mmc_pwrseq_simple *pwrseq = to_pwrseq_simple(host->pwrseq);
|
||||
|
||||
mmc_pwrseq_simple_set_gpios_value(pwrseq, 0);
|
||||
+
|
||||
+ if (pwrseq->post_power_on_delay_ms)
|
||||
+ msleep(pwrseq->post_power_on_delay_ms);
|
||||
}
|
||||
|
||||
static void mmc_pwrseq_simple_power_off(struct mmc_host *host)
|
||||
@@ -111,6 +117,9 @@ static int mmc_pwrseq_simple_probe(struct platform_device *pdev)
|
||||
return PTR_ERR(pwrseq->reset_gpios);
|
||||
}
|
||||
|
||||
+ device_property_read_u32(dev, "post-power-on-delay-ms",
|
||||
+ &pwrseq->post_power_on_delay_ms);
|
||||
+
|
||||
pwrseq->pwrseq.dev = dev;
|
||||
pwrseq->pwrseq.ops = &mmc_pwrseq_simple_ops;
|
||||
pwrseq->pwrseq.owner = THIS_MODULE;
|
||||
|
||||
From bf90ebd56d6f327f77bd7add55b3593679cd5c67 Mon Sep 17 00:00:00 2001
|
||||
From: Ulf Hansson <ulf.hansson@linaro.org>
|
||||
Date: Sat, 6 May 2017 11:41:30 +0200
|
||||
Subject: [PATCH] UPSTREAM: mmc: dt: pwrseq-simple: Invent power-off-delay-us
|
||||
|
||||
During power off, after the GPIO pin has been asserted, some devices like
|
||||
the Wifi chip from TI, Wl18xx, needs a delay before the host continues with
|
||||
clock gating and turning off regulators as to follow a graceful shutdown
|
||||
sequence.
|
||||
|
||||
Therefore invent an optional power-off-delay-us DT binding for
|
||||
mmc-pwrseq-simple, to allow us to support this constraint.
|
||||
|
||||
Cc: devicetree@vger.kernel.org
|
||||
Cc: Rob Herring <robh+dt@kernel.org>
|
||||
Cc: linux-mmc@vger.kernel.org
|
||||
Signed-off-by: Ulf Hansson <ulf.hansson@linaro.org>
|
||||
Acked-by: Arnd Bergmann <arnd@arndb.de>
|
||||
---
|
||||
Documentation/devicetree/bindings/mmc/mmc-pwrseq-simple.txt | 2 ++
|
||||
1 file changed, 2 insertions(+)
|
||||
|
||||
diff --git a/Documentation/devicetree/bindings/mmc/mmc-pwrseq-simple.txt b/Documentation/devicetree/bindings/mmc/mmc-pwrseq-simple.txt
|
||||
index e25436861867..9029b45b8a22 100644
|
||||
--- a/Documentation/devicetree/bindings/mmc/mmc-pwrseq-simple.txt
|
||||
+++ b/Documentation/devicetree/bindings/mmc/mmc-pwrseq-simple.txt
|
||||
@@ -18,6 +18,8 @@ Optional properties:
|
||||
"ext_clock" (External clock provided to the card).
|
||||
- post-power-on-delay-ms : Delay in ms after powering the card and
|
||||
de-asserting the reset-gpios (if any)
|
||||
+- power-off-delay-us : Delay in us after asserting the reset-gpios (if any)
|
||||
+ during power off of the card.
|
||||
|
||||
Example:
|
||||
|
||||
|
||||
From bc79b1f8ca4d16d45b93c2888474bb3f11b10226 Mon Sep 17 00:00:00 2001
|
||||
From: Ulf Hansson <ulf.hansson@linaro.org>
|
||||
Date: Sat, 6 May 2017 11:43:05 +0200
|
||||
Subject: [PATCH] UPSTREAM: mmc: pwrseq_simple: Parse DTS for the
|
||||
power-off-delay-us property
|
||||
|
||||
If the optional power-off-delay-us property is found, insert the
|
||||
corresponding delay after asserting the GPIO during power off. This enables
|
||||
a graceful shutdown sequence for some devices.
|
||||
|
||||
Cc: linux-mmc@vger.kernel.org
|
||||
Signed-off-by: Ulf Hansson <ulf.hansson@linaro.org>
|
||||
Acked-by: Arnd Bergmann <arnd@arndb.de>
|
||||
(cherry picked from commit e9256e142f597edf90c68cec22db4c4aebaa27de)
|
||||
---
|
||||
drivers/mmc/core/pwrseq_simple.c | 7 +++++++
|
||||
1 file changed, 7 insertions(+)
|
||||
|
||||
diff --git a/drivers/mmc/core/pwrseq_simple.c b/drivers/mmc/core/pwrseq_simple.c
|
||||
index 1304160de168..13ef162cf066 100644
|
||||
--- a/drivers/mmc/core/pwrseq_simple.c
|
||||
+++ b/drivers/mmc/core/pwrseq_simple.c
|
||||
@@ -27,6 +27,7 @@ struct mmc_pwrseq_simple {
|
||||
struct mmc_pwrseq pwrseq;
|
||||
bool clk_enabled;
|
||||
u32 post_power_on_delay_ms;
|
||||
+ u32 power_off_delay_us;
|
||||
struct clk *ext_clk;
|
||||
struct gpio_descs *reset_gpios;
|
||||
};
|
||||
@@ -78,6 +79,10 @@ static void mmc_pwrseq_simple_power_off(struct mmc_host *host)
|
||||
|
||||
mmc_pwrseq_simple_set_gpios_value(pwrseq, 1);
|
||||
|
||||
+ if (pwrseq->power_off_delay_us)
|
||||
+ usleep_range(pwrseq->power_off_delay_us,
|
||||
+ 2 * pwrseq->power_off_delay_us);
|
||||
+
|
||||
if (!IS_ERR(pwrseq->ext_clk) && pwrseq->clk_enabled) {
|
||||
clk_disable_unprepare(pwrseq->ext_clk);
|
||||
pwrseq->clk_enabled = false;
|
||||
@@ -119,6 +124,8 @@ static int mmc_pwrseq_simple_probe(struct platform_device *pdev)
|
||||
|
||||
device_property_read_u32(dev, "post-power-on-delay-ms",
|
||||
&pwrseq->post_power_on_delay_ms);
|
||||
+ device_property_read_u32(dev, "power-off-delay-us",
|
||||
+ &pwrseq->power_off_delay_us);
|
||||
|
||||
pwrseq->pwrseq.dev = dev;
|
||||
pwrseq->pwrseq.ops = &mmc_pwrseq_simple_ops;
|
633
patch/kernel/rockchip-default/01-linux-0009-mmc.patch
Normal file
633
patch/kernel/rockchip-default/01-linux-0009-mmc.patch
Normal file
|
@ -0,0 +1,633 @@
|
|||
From 38396ba52ab85ea1eabea3c92fd7532f8732f92e Mon Sep 17 00:00:00 2001
|
||||
From: Jonas Karlman <jonas@kwiboo.se>
|
||||
Date: Tue, 24 Jul 2018 15:49:29 +0200
|
||||
Subject: [PATCH] mmc: core: use hs400es voltage flags
|
||||
|
||||
---
|
||||
drivers/mmc/core/mmc.c | 4 ++--
|
||||
1 file changed, 2 insertions(+), 2 deletions(-)
|
||||
|
||||
diff --git a/drivers/mmc/core/mmc.c b/drivers/mmc/core/mmc.c
|
||||
index a814eb6882aa..1d950f0b3aa6 100644
|
||||
--- a/drivers/mmc/core/mmc.c
|
||||
+++ b/drivers/mmc/core/mmc.c
|
||||
@@ -1259,10 +1259,10 @@ static int mmc_select_hs400es(struct mmc_card *card)
|
||||
goto out_err;
|
||||
}
|
||||
|
||||
- if (card->mmc_avail_type & EXT_CSD_CARD_TYPE_HS200_1_2V)
|
||||
+ if (card->mmc_avail_type & EXT_CSD_CARD_TYPE_HS400_1_2V)
|
||||
err = __mmc_set_signal_voltage(host, MMC_SIGNAL_VOLTAGE_120);
|
||||
|
||||
- if (err && card->mmc_avail_type & EXT_CSD_CARD_TYPE_HS200_1_8V)
|
||||
+ if (err && card->mmc_avail_type & EXT_CSD_CARD_TYPE_HS400_1_8V)
|
||||
err = __mmc_set_signal_voltage(host, MMC_SIGNAL_VOLTAGE_180);
|
||||
|
||||
/* If fails try again during next card power cycle */
|
||||
|
||||
From 92a57737adc14e15e80b6913932bb5d2d3478068 Mon Sep 17 00:00:00 2001
|
||||
From: Haibo Chen <haibo.chen@nxp.com>
|
||||
Date: Tue, 8 Aug 2017 18:54:01 +0800
|
||||
Subject: [PATCH] UPSTREAM: mmc: mmc: correct the logic for setting HS400ES
|
||||
signal voltage
|
||||
|
||||
Change the default err value to -EINVAL, make sure the card only
|
||||
has type EXT_CSD_CARD_TYPE_HS400_1_8V also do the signal voltage
|
||||
setting when select hs400es mode.
|
||||
|
||||
Fixes: commit 1720d3545b77 ("mmc: core: switch to 1V8 or 1V2 for hs400es mode")
|
||||
Cc: <stable@vger.kernel.org>
|
||||
Signed-off-by: Haibo Chen <haibo.chen@nxp.com>
|
||||
Reviewed-by: Shawn Lin <shawn.lin@rock-chips.com>
|
||||
Signed-off-by: Ulf Hansson <ulf.hansson@linaro.org>
|
||||
(cherry picked from commit 92ddd95919466de5d34f3cb43635da9a7f9ab814)
|
||||
---
|
||||
drivers/mmc/core/mmc.c | 2 +-
|
||||
1 file changed, 1 insertion(+), 1 deletion(-)
|
||||
|
||||
diff --git a/drivers/mmc/core/mmc.c b/drivers/mmc/core/mmc.c
|
||||
index 1d950f0b3aa6..70de514dd061 100644
|
||||
--- a/drivers/mmc/core/mmc.c
|
||||
+++ b/drivers/mmc/core/mmc.c
|
||||
@@ -1251,7 +1251,7 @@ out_err:
|
||||
static int mmc_select_hs400es(struct mmc_card *card)
|
||||
{
|
||||
struct mmc_host *host = card->host;
|
||||
- int err = 0;
|
||||
+ int err = -EINVAL;
|
||||
u8 val;
|
||||
|
||||
if (!(host->caps & MMC_CAP_8_BIT_DATA)) {
|
||||
|
||||
From 108a045df9dc1cee2127aec0bdd327ba7f2fdb81 Mon Sep 17 00:00:00 2001
|
||||
From: Ulf Hansson <ulf.hansson@linaro.org>
|
||||
Date: Wed, 25 Jan 2017 10:12:10 +0100
|
||||
Subject: [PATCH] UPSTREAM: mmc: core: Remove redundant code in
|
||||
mmc_set_signal_voltage()
|
||||
|
||||
The mmc_set_signal_voltage() function is used for SD/SDIO when switching to
|
||||
1.8V for UHS mode. Therefore let's remove the redundant code dealing with
|
||||
MMC_SIGNAL_VOLTAGE_330.
|
||||
|
||||
Signed-off-by: Ulf Hansson <ulf.hansson@linaro.org>
|
||||
Reviewed-by: Shawn Lin <shawn.lin@rock-chips.com>
|
||||
Tested-by: Jan Glauber <jglauber@cavium.com>
|
||||
Tested-by: Stefan Wahren <stefan.wahren@i2se.com>
|
||||
(cherry picked from commit a44efa4796249c6d4341935e90e9105d6e1a5f15)
|
||||
---
|
||||
drivers/mmc/core/core.c | 7 -------
|
||||
1 file changed, 7 deletions(-)
|
||||
|
||||
diff --git a/drivers/mmc/core/core.c b/drivers/mmc/core/core.c
|
||||
index 3e3c79feb07b..b69c96ad9486 100644
|
||||
--- a/drivers/mmc/core/core.c
|
||||
+++ b/drivers/mmc/core/core.c
|
||||
@@ -1598,13 +1598,6 @@ int mmc_set_signal_voltage(struct mmc_host *host, int signal_voltage, u32 ocr)
|
||||
|
||||
BUG_ON(!host);
|
||||
|
||||
- /*
|
||||
- * Send CMD11 only if the request is to switch the card to
|
||||
- * 1.8V signalling.
|
||||
- */
|
||||
- if (signal_voltage == MMC_SIGNAL_VOLTAGE_330)
|
||||
- return __mmc_set_signal_voltage(host, signal_voltage);
|
||||
-
|
||||
/*
|
||||
* If we cannot switch voltages, return failure so the caller
|
||||
* can continue without UHS mode
|
||||
|
||||
From d28c1bfff6556db2c4ce1093091293cf20542202 Mon Sep 17 00:00:00 2001
|
||||
From: Ulf Hansson <ulf.hansson@linaro.org>
|
||||
Date: Wed, 25 Jan 2017 10:25:01 +0100
|
||||
Subject: [PATCH] UPSTREAM: mmc: core: Clarify usage of
|
||||
mmc_set_signal_voltage()
|
||||
|
||||
The mmc_set_signal_voltage() function is used for SD/SDIO when switching to
|
||||
1.8V for UHS mode. To clarify this let's do the following changes.
|
||||
|
||||
- We are always providing MMC_SIGNAL_VOLTAGE_180 as the signal_voltage
|
||||
parameter to the function. Then, let's just remove the parameter as it
|
||||
serves no purpose.
|
||||
- Rename the function to mmc_set_uhs_voltage().
|
||||
|
||||
Signed-off-by: Ulf Hansson <ulf.hansson@linaro.org>
|
||||
Reviewed-by: Shawn Lin <shawn.lin@rock-chips.com>
|
||||
Tested-by: Jan Glauber <jglauber@cavium.com>
|
||||
Tested-by: Stefan Wahren <stefan.wahren@i2se.com>
|
||||
(cherry picked from commit 2ed573b603f78289dd1435c94597aa25a97e2b76)
|
||||
---
|
||||
drivers/mmc/core/core.c | 4 ++--
|
||||
drivers/mmc/core/core.h | 2 +-
|
||||
drivers/mmc/core/sd.c | 3 +--
|
||||
drivers/mmc/core/sdio.c | 3 +--
|
||||
4 files changed, 5 insertions(+), 7 deletions(-)
|
||||
|
||||
diff --git a/drivers/mmc/core/core.c b/drivers/mmc/core/core.c
|
||||
index b69c96ad9486..35d19d57d2c5 100644
|
||||
--- a/drivers/mmc/core/core.c
|
||||
+++ b/drivers/mmc/core/core.c
|
||||
@@ -1590,7 +1590,7 @@ int __mmc_set_signal_voltage(struct mmc_host *host, int signal_voltage)
|
||||
|
||||
}
|
||||
|
||||
-int mmc_set_signal_voltage(struct mmc_host *host, int signal_voltage, u32 ocr)
|
||||
+int mmc_set_uhs_voltage(struct mmc_host *host, u32 ocr)
|
||||
{
|
||||
struct mmc_command cmd = {0};
|
||||
int err = 0;
|
||||
@@ -1636,7 +1636,7 @@ int mmc_set_signal_voltage(struct mmc_host *host, int signal_voltage, u32 ocr)
|
||||
host->ios.clock = 0;
|
||||
mmc_set_ios(host);
|
||||
|
||||
- if (__mmc_set_signal_voltage(host, signal_voltage)) {
|
||||
+ if (__mmc_set_signal_voltage(host, MMC_SIGNAL_VOLTAGE_180)) {
|
||||
/*
|
||||
* Voltages may not have been switched, but we've already
|
||||
* sent CMD11, so a power cycle is required anyway
|
||||
diff --git a/drivers/mmc/core/core.h b/drivers/mmc/core/core.h
|
||||
index ed7c3167763a..88ef50b2e0be 100644
|
||||
--- a/drivers/mmc/core/core.h
|
||||
+++ b/drivers/mmc/core/core.h
|
||||
@@ -43,7 +43,7 @@ void mmc_set_clock(struct mmc_host *host, unsigned int hz);
|
||||
void mmc_set_bus_mode(struct mmc_host *host, unsigned int mode);
|
||||
void mmc_set_bus_width(struct mmc_host *host, unsigned int width);
|
||||
u32 mmc_select_voltage(struct mmc_host *host, u32 ocr);
|
||||
-int mmc_set_signal_voltage(struct mmc_host *host, int signal_voltage, u32 ocr);
|
||||
+int mmc_set_uhs_voltage(struct mmc_host *host, u32 ocr);
|
||||
int __mmc_set_signal_voltage(struct mmc_host *host, int signal_voltage);
|
||||
void mmc_set_timing(struct mmc_host *host, unsigned int timing);
|
||||
void mmc_set_driver_type(struct mmc_host *host, unsigned int drv_type);
|
||||
diff --git a/drivers/mmc/core/sd.c b/drivers/mmc/core/sd.c
|
||||
index cd437d6b1843..d9943d82db95 100644
|
||||
--- a/drivers/mmc/core/sd.c
|
||||
+++ b/drivers/mmc/core/sd.c
|
||||
@@ -742,8 +742,7 @@ try_again:
|
||||
*/
|
||||
if (!mmc_host_is_spi(host) && rocr &&
|
||||
((*rocr & 0x41000000) == 0x41000000)) {
|
||||
- err = mmc_set_signal_voltage(host, MMC_SIGNAL_VOLTAGE_180,
|
||||
- pocr);
|
||||
+ err = mmc_set_uhs_voltage(host, pocr);
|
||||
if (err == -EAGAIN) {
|
||||
retries--;
|
||||
goto try_again;
|
||||
diff --git a/drivers/mmc/core/sdio.c b/drivers/mmc/core/sdio.c
|
||||
index c586b11a40b5..f221418542e2 100644
|
||||
--- a/drivers/mmc/core/sdio.c
|
||||
+++ b/drivers/mmc/core/sdio.c
|
||||
@@ -648,8 +648,7 @@ try_again:
|
||||
* to make sure which speed mode should work.
|
||||
*/
|
||||
if (!powered_resume && (rocr & ocr & R4_18V_PRESENT)) {
|
||||
- err = mmc_set_signal_voltage(host, MMC_SIGNAL_VOLTAGE_180,
|
||||
- ocr_card);
|
||||
+ err = mmc_set_uhs_voltage(host, ocr_card);
|
||||
if (err == -EAGAIN) {
|
||||
mmc_sdio_resend_if_cond(host, card);
|
||||
retries--;
|
||||
|
||||
From 0f61c64862ed54163c5f88389170c95055a74f68 Mon Sep 17 00:00:00 2001
|
||||
From: Ulf Hansson <ulf.hansson@linaro.org>
|
||||
Date: Wed, 25 Jan 2017 11:12:34 +0100
|
||||
Subject: [PATCH] UPSTREAM: mmc: core: Rename __mmc_set_signal_voltage() to
|
||||
mmc_set_signal_voltage()
|
||||
|
||||
Earlier the mmc_set_signal_voltage() existed, but since it has been renamed
|
||||
to mmc_set_uhs_voltage(), we can now use that name instead.
|
||||
|
||||
Signed-off-by: Ulf Hansson <ulf.hansson@linaro.org>
|
||||
Reviewed-by: Shawn Lin <shawn.lin@rock-chips.com>
|
||||
Tested-by: Jan Glauber <jglauber@cavium.com>
|
||||
Tested-by: Stefan Wahren <stefan.wahren@i2se.com>
|
||||
(cherry picked from commit 4e74b6b3c6e9adfe6a8fdebfc56a6416a996d905)
|
||||
---
|
||||
drivers/mmc/core/core.c | 10 +++++-----
|
||||
drivers/mmc/core/core.h | 2 +-
|
||||
drivers/mmc/core/mmc.c | 16 ++++++++--------
|
||||
3 files changed, 14 insertions(+), 14 deletions(-)
|
||||
|
||||
diff --git a/drivers/mmc/core/core.c b/drivers/mmc/core/core.c
|
||||
index 35d19d57d2c5..ba285431c2d0 100644
|
||||
--- a/drivers/mmc/core/core.c
|
||||
+++ b/drivers/mmc/core/core.c
|
||||
@@ -1574,7 +1574,7 @@ u32 mmc_select_voltage(struct mmc_host *host, u32 ocr)
|
||||
return ocr;
|
||||
}
|
||||
|
||||
-int __mmc_set_signal_voltage(struct mmc_host *host, int signal_voltage)
|
||||
+int mmc_set_signal_voltage(struct mmc_host *host, int signal_voltage)
|
||||
{
|
||||
int err = 0;
|
||||
int old_signal_voltage = host->ios.signal_voltage;
|
||||
@@ -1636,7 +1636,7 @@ int mmc_set_uhs_voltage(struct mmc_host *host, u32 ocr)
|
||||
host->ios.clock = 0;
|
||||
mmc_set_ios(host);
|
||||
|
||||
- if (__mmc_set_signal_voltage(host, MMC_SIGNAL_VOLTAGE_180)) {
|
||||
+ if (mmc_set_signal_voltage(host, MMC_SIGNAL_VOLTAGE_180)) {
|
||||
/*
|
||||
* Voltages may not have been switched, but we've already
|
||||
* sent CMD11, so a power cycle is required anyway
|
||||
@@ -1745,11 +1745,11 @@ void mmc_power_up(struct mmc_host *host, u32 ocr)
|
||||
mmc_set_initial_state(host);
|
||||
|
||||
/* Try to set signal voltage to 3.3V but fall back to 1.8v or 1.2v */
|
||||
- if (__mmc_set_signal_voltage(host, MMC_SIGNAL_VOLTAGE_330) == 0)
|
||||
+ if (!mmc_set_signal_voltage(host, MMC_SIGNAL_VOLTAGE_330))
|
||||
dev_dbg(mmc_dev(host), "Initial signal voltage of 3.3v\n");
|
||||
- else if (__mmc_set_signal_voltage(host, MMC_SIGNAL_VOLTAGE_180) == 0)
|
||||
+ else if (!mmc_set_signal_voltage(host, MMC_SIGNAL_VOLTAGE_180))
|
||||
dev_dbg(mmc_dev(host), "Initial signal voltage of 1.8v\n");
|
||||
- else if (__mmc_set_signal_voltage(host, MMC_SIGNAL_VOLTAGE_120) == 0)
|
||||
+ else if (!mmc_set_signal_voltage(host, MMC_SIGNAL_VOLTAGE_120))
|
||||
dev_dbg(mmc_dev(host), "Initial signal voltage of 1.2v\n");
|
||||
|
||||
/*
|
||||
diff --git a/drivers/mmc/core/core.h b/drivers/mmc/core/core.h
|
||||
index 88ef50b2e0be..0e4bc1c7a773 100644
|
||||
--- a/drivers/mmc/core/core.h
|
||||
+++ b/drivers/mmc/core/core.h
|
||||
@@ -44,7 +44,7 @@ void mmc_set_bus_mode(struct mmc_host *host, unsigned int mode);
|
||||
void mmc_set_bus_width(struct mmc_host *host, unsigned int width);
|
||||
u32 mmc_select_voltage(struct mmc_host *host, u32 ocr);
|
||||
int mmc_set_uhs_voltage(struct mmc_host *host, u32 ocr);
|
||||
-int __mmc_set_signal_voltage(struct mmc_host *host, int signal_voltage);
|
||||
+int mmc_set_signal_voltage(struct mmc_host *host, int signal_voltage);
|
||||
void mmc_set_timing(struct mmc_host *host, unsigned int timing);
|
||||
void mmc_set_driver_type(struct mmc_host *host, unsigned int drv_type);
|
||||
int mmc_select_drive_strength(struct mmc_card *card, unsigned int max_dtr,
|
||||
diff --git a/drivers/mmc/core/mmc.c b/drivers/mmc/core/mmc.c
|
||||
index 70de514dd061..dd0040a10c0b 100644
|
||||
--- a/drivers/mmc/core/mmc.c
|
||||
+++ b/drivers/mmc/core/mmc.c
|
||||
@@ -1088,14 +1088,14 @@ static int mmc_select_hs_ddr(struct mmc_card *card)
|
||||
*/
|
||||
err = -EINVAL;
|
||||
if (card->mmc_avail_type & EXT_CSD_CARD_TYPE_DDR_1_2V)
|
||||
- err = __mmc_set_signal_voltage(host, MMC_SIGNAL_VOLTAGE_120);
|
||||
+ err = mmc_set_signal_voltage(host, MMC_SIGNAL_VOLTAGE_120);
|
||||
|
||||
if (err && (card->mmc_avail_type & EXT_CSD_CARD_TYPE_DDR_1_8V))
|
||||
- err = __mmc_set_signal_voltage(host, MMC_SIGNAL_VOLTAGE_180);
|
||||
+ err = mmc_set_signal_voltage(host, MMC_SIGNAL_VOLTAGE_180);
|
||||
|
||||
/* make sure vccq is 3.3v after switching disaster */
|
||||
if (err)
|
||||
- err = __mmc_set_signal_voltage(host, MMC_SIGNAL_VOLTAGE_330);
|
||||
+ err = mmc_set_signal_voltage(host, MMC_SIGNAL_VOLTAGE_330);
|
||||
|
||||
if (!err)
|
||||
mmc_set_timing(host, MMC_TIMING_MMC_DDR52);
|
||||
@@ -1260,10 +1260,10 @@ static int mmc_select_hs400es(struct mmc_card *card)
|
||||
}
|
||||
|
||||
if (card->mmc_avail_type & EXT_CSD_CARD_TYPE_HS400_1_2V)
|
||||
- err = __mmc_set_signal_voltage(host, MMC_SIGNAL_VOLTAGE_120);
|
||||
+ err = mmc_set_signal_voltage(host, MMC_SIGNAL_VOLTAGE_120);
|
||||
|
||||
if (err && card->mmc_avail_type & EXT_CSD_CARD_TYPE_HS400_1_8V)
|
||||
- err = __mmc_set_signal_voltage(host, MMC_SIGNAL_VOLTAGE_180);
|
||||
+ err = mmc_set_signal_voltage(host, MMC_SIGNAL_VOLTAGE_180);
|
||||
|
||||
/* If fails try again during next card power cycle */
|
||||
if (err)
|
||||
@@ -1362,10 +1362,10 @@ static int mmc_select_hs200(struct mmc_card *card)
|
||||
|
||||
old_signal_voltage = host->ios.signal_voltage;
|
||||
if (card->mmc_avail_type & EXT_CSD_CARD_TYPE_HS200_1_2V)
|
||||
- err = __mmc_set_signal_voltage(host, MMC_SIGNAL_VOLTAGE_120);
|
||||
+ err = mmc_set_signal_voltage(host, MMC_SIGNAL_VOLTAGE_120);
|
||||
|
||||
if (err && card->mmc_avail_type & EXT_CSD_CARD_TYPE_HS200_1_8V)
|
||||
- err = __mmc_set_signal_voltage(host, MMC_SIGNAL_VOLTAGE_180);
|
||||
+ err = mmc_set_signal_voltage(host, MMC_SIGNAL_VOLTAGE_180);
|
||||
|
||||
/* If fails try again during next card power cycle */
|
||||
if (err)
|
||||
@@ -1393,7 +1393,7 @@ static int mmc_select_hs200(struct mmc_card *card)
|
||||
err:
|
||||
if (err) {
|
||||
/* fall back to the old signal voltage, if fails report error */
|
||||
- if (__mmc_set_signal_voltage(host, old_signal_voltage))
|
||||
+ if (mmc_set_signal_voltage(host, old_signal_voltage))
|
||||
err = -EIO;
|
||||
|
||||
pr_err("%s: %s failed, error %d\n", mmc_hostname(card->host),
|
||||
|
||||
From db9fd591980256d95de5675ebd84759b9cc9831c Mon Sep 17 00:00:00 2001
|
||||
From: Adrian Hunter <adrian.hunter@intel.com>
|
||||
Date: Mon, 25 Sep 2017 11:29:03 +0300
|
||||
Subject: [PATCH] UPSTREAM: mmc: core: Factor out mmc_host_set_uhs_voltage()
|
||||
|
||||
Factor out mmc_host_set_uhs_voltage() so it can be reused.
|
||||
|
||||
Signed-off-by: Adrian Hunter <adrian.hunter@intel.com>
|
||||
Signed-off-by: Ulf Hansson <ulf.hansson@linaro.org>
|
||||
(cherry picked from commit 3f496afb6fb361b282f37968ff7d3d80b0f1b5cb)
|
||||
---
|
||||
drivers/mmc/core/core.c | 38 ++++++++++++++++++++++++--------------
|
||||
drivers/mmc/core/core.h | 1 +
|
||||
2 files changed, 25 insertions(+), 14 deletions(-)
|
||||
|
||||
diff --git a/drivers/mmc/core/core.c b/drivers/mmc/core/core.c
|
||||
index ba285431c2d0..dae82afcbc99 100644
|
||||
--- a/drivers/mmc/core/core.c
|
||||
+++ b/drivers/mmc/core/core.c
|
||||
@@ -1590,11 +1590,33 @@ int mmc_set_signal_voltage(struct mmc_host *host, int signal_voltage)
|
||||
|
||||
}
|
||||
|
||||
+int mmc_host_set_uhs_voltage(struct mmc_host *host)
|
||||
+{
|
||||
+ u32 clock;
|
||||
+
|
||||
+ /*
|
||||
+ * During a signal voltage level switch, the clock must be gated
|
||||
+ * for 5 ms according to the SD spec
|
||||
+ */
|
||||
+ clock = host->ios.clock;
|
||||
+ host->ios.clock = 0;
|
||||
+ mmc_set_ios(host);
|
||||
+
|
||||
+ if (mmc_set_signal_voltage(host, MMC_SIGNAL_VOLTAGE_180))
|
||||
+ return -EAGAIN;
|
||||
+
|
||||
+ /* Keep clock gated for at least 10 ms, though spec only says 5 ms */
|
||||
+ mmc_delay(10);
|
||||
+ host->ios.clock = clock;
|
||||
+ mmc_set_ios(host);
|
||||
+
|
||||
+ return 0;
|
||||
+}
|
||||
+
|
||||
int mmc_set_uhs_voltage(struct mmc_host *host, u32 ocr)
|
||||
{
|
||||
struct mmc_command cmd = {0};
|
||||
int err = 0;
|
||||
- u32 clock;
|
||||
|
||||
BUG_ON(!host);
|
||||
|
||||
@@ -1628,15 +1650,8 @@ int mmc_set_uhs_voltage(struct mmc_host *host, u32 ocr)
|
||||
err = -EAGAIN;
|
||||
goto power_cycle;
|
||||
}
|
||||
- /*
|
||||
- * During a signal voltage level switch, the clock must be gated
|
||||
- * for 5 ms according to the SD spec
|
||||
- */
|
||||
- clock = host->ios.clock;
|
||||
- host->ios.clock = 0;
|
||||
- mmc_set_ios(host);
|
||||
|
||||
- if (mmc_set_signal_voltage(host, MMC_SIGNAL_VOLTAGE_180)) {
|
||||
+ if (mmc_host_set_uhs_voltage(host)) {
|
||||
/*
|
||||
* Voltages may not have been switched, but we've already
|
||||
* sent CMD11, so a power cycle is required anyway
|
||||
@@ -1645,11 +1660,6 @@ int mmc_set_uhs_voltage(struct mmc_host *host, u32 ocr)
|
||||
goto power_cycle;
|
||||
}
|
||||
|
||||
- /* Keep clock gated for at least 10 ms, though spec only says 5 ms */
|
||||
- mmc_delay(10);
|
||||
- host->ios.clock = clock;
|
||||
- mmc_set_ios(host);
|
||||
-
|
||||
/* Wait for at least 1 ms according to spec */
|
||||
mmc_delay(1);
|
||||
|
||||
diff --git a/drivers/mmc/core/core.h b/drivers/mmc/core/core.h
|
||||
index 0e4bc1c7a773..11f3d2c22ecb 100644
|
||||
--- a/drivers/mmc/core/core.h
|
||||
+++ b/drivers/mmc/core/core.h
|
||||
@@ -44,6 +44,7 @@ void mmc_set_bus_mode(struct mmc_host *host, unsigned int mode);
|
||||
void mmc_set_bus_width(struct mmc_host *host, unsigned int width);
|
||||
u32 mmc_select_voltage(struct mmc_host *host, u32 ocr);
|
||||
int mmc_set_uhs_voltage(struct mmc_host *host, u32 ocr);
|
||||
+int mmc_host_set_uhs_voltage(struct mmc_host *host);
|
||||
int mmc_set_signal_voltage(struct mmc_host *host, int signal_voltage);
|
||||
void mmc_set_timing(struct mmc_host *host, unsigned int timing);
|
||||
void mmc_set_driver_type(struct mmc_host *host, unsigned int drv_type);
|
||||
|
||||
From 9c2d593200bd835b8e55eb6e0ba188e4dd9c744e Mon Sep 17 00:00:00 2001
|
||||
From: Adrian Hunter <adrian.hunter@intel.com>
|
||||
Date: Mon, 25 Sep 2017 11:29:04 +0300
|
||||
Subject: [PATCH] UPSTREAM: mmc: sd: Fix signal voltage when there is no power
|
||||
cycle
|
||||
|
||||
Some boards have SD card connectors where the power rail cannot be switched
|
||||
off by the driver. However there are various circumstances when a card
|
||||
might be re-initialized, such as after system resume, warm re-boot, or
|
||||
error handling. However, a UHS card will continue to use 1.8V signaling
|
||||
unless it is power cycled.
|
||||
|
||||
If the card has not been power cycled, it may still be using 1.8V
|
||||
signaling. According to the SD spec., the Bus Speed Mode (function group 1)
|
||||
bits 2 to 4 are zero if the card is initialized at 3.3V signal level. Thus
|
||||
they can be used to determine if the card has already switched to 1.8V
|
||||
signaling. Detect that situation and try to initialize a UHS-I (1.8V)
|
||||
transfer mode.
|
||||
|
||||
Tested with the following cards:
|
||||
Transcend 4GB High Speed
|
||||
Kingston 64GB SDR104
|
||||
Lexar by Micron HIGH-PERFORMANCE 300x 16GB DDR50
|
||||
SanDisk Ultra 8GB DDR50
|
||||
Transcend Ultimate 600x 16GB SDR104
|
||||
Transcend Premium 300x 64GB SDR104
|
||||
Lexar by Micron Professional 1000x 32GB UHS-II SDR104
|
||||
SanDisk Extreme Pro 16GB SDR104
|
||||
|
||||
Signed-off-by: Adrian Hunter <adrian.hunter@intel.com>
|
||||
Tested-by: Zhoujie Wu <zjwu@marvell.com>
|
||||
Reviewed-by: Shawn Lin <shawn.lin@rock-chips.com>
|
||||
Signed-off-by: Ulf Hansson <ulf.hansson@linaro.org>
|
||||
(cherry picked from commit 6a11fc47f175c8d87018e89cb58e2d36c66534cb)
|
||||
---
|
||||
drivers/mmc/core/sd.c | 47 +++++++++++++++++++++++++++++++++++++++++++++--
|
||||
1 file changed, 45 insertions(+), 2 deletions(-)
|
||||
|
||||
diff --git a/drivers/mmc/core/sd.c b/drivers/mmc/core/sd.c
|
||||
index d9943d82db95..2808a281d094 100644
|
||||
--- a/drivers/mmc/core/sd.c
|
||||
+++ b/drivers/mmc/core/sd.c
|
||||
@@ -898,6 +898,18 @@ unsigned mmc_sd_get_max_clock(struct mmc_card *card)
|
||||
return max_dtr;
|
||||
}
|
||||
|
||||
+static bool mmc_sd_card_using_v18(struct mmc_card *card)
|
||||
+{
|
||||
+ /*
|
||||
+ * According to the SD spec., the Bus Speed Mode (function group 1) bits
|
||||
+ * 2 to 4 are zero if the card is initialized at 3.3V signal level. Thus
|
||||
+ * they can be used to determine if the card has already switched to
|
||||
+ * 1.8V signaling.
|
||||
+ */
|
||||
+ return card->sw_caps.sd3_bus_mode &
|
||||
+ (SD_MODE_UHS_SDR50 | SD_MODE_UHS_SDR104 | SD_MODE_UHS_DDR50);
|
||||
+}
|
||||
+
|
||||
/*
|
||||
* Handle the detection and initialisation of a card.
|
||||
*
|
||||
@@ -911,10 +923,11 @@ static int mmc_sd_init_card(struct mmc_host *host, u32 ocr,
|
||||
int err;
|
||||
u32 cid[4];
|
||||
u32 rocr = 0;
|
||||
+ bool v18_fixup_failed = false;
|
||||
|
||||
BUG_ON(!host);
|
||||
WARN_ON(!host->claimed);
|
||||
-
|
||||
+retry:
|
||||
err = mmc_sd_get_cid(host, ocr, cid, &rocr);
|
||||
if (err)
|
||||
return err;
|
||||
@@ -980,6 +993,36 @@ static int mmc_sd_init_card(struct mmc_host *host, u32 ocr,
|
||||
if (err)
|
||||
goto free_card;
|
||||
|
||||
+ /*
|
||||
+ * If the card has not been power cycled, it may still be using 1.8V
|
||||
+ * signaling. Detect that situation and try to initialize a UHS-I (1.8V)
|
||||
+ * transfer mode.
|
||||
+ */
|
||||
+ if (!v18_fixup_failed && !mmc_host_is_spi(host) && mmc_host_uhs(host) &&
|
||||
+ mmc_sd_card_using_v18(card) &&
|
||||
+ host->ios.signal_voltage != MMC_SIGNAL_VOLTAGE_180) {
|
||||
+ /*
|
||||
+ * Re-read switch information in case it has changed since
|
||||
+ * oldcard was initialized.
|
||||
+ */
|
||||
+ if (oldcard) {
|
||||
+ err = mmc_read_switch(card);
|
||||
+ if (err)
|
||||
+ goto free_card;
|
||||
+ }
|
||||
+ if (mmc_sd_card_using_v18(card)) {
|
||||
+ if (mmc_host_set_uhs_voltage(host) ||
|
||||
+ mmc_sd_init_uhs_card(card)) {
|
||||
+ v18_fixup_failed = true;
|
||||
+ mmc_power_cycle(host, ocr);
|
||||
+ if (!oldcard)
|
||||
+ mmc_remove_card(card);
|
||||
+ goto retry;
|
||||
+ }
|
||||
+ goto done;
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
/* Initialization sequence for UHS-I cards */
|
||||
if (rocr & SD_ROCR_S18A && mmc_host_uhs(host)) {
|
||||
err = mmc_sd_init_uhs_card(card);
|
||||
@@ -1012,7 +1055,7 @@ static int mmc_sd_init_card(struct mmc_host *host, u32 ocr,
|
||||
mmc_set_bus_width(host, MMC_BUS_WIDTH_4);
|
||||
}
|
||||
}
|
||||
-
|
||||
+done:
|
||||
host->card = card;
|
||||
return 0;
|
||||
|
||||
|
||||
From 6ee3035196c307a77f95b1c1f3cc537e467fb838 Mon Sep 17 00:00:00 2001
|
||||
From: Ulf Hansson <ulf.hansson@linaro.org>
|
||||
Date: Thu, 5 Apr 2018 21:24:15 +0200
|
||||
Subject: [PATCH] UPSTREAM: mmc: core: Share internal function to set initial
|
||||
signal voltage
|
||||
|
||||
Move the corresponding code for setting the initial signal voltage, from
|
||||
mmc_power_up() into a new function, mmc_set_initial_signal_voltage().
|
||||
|
||||
Make the function internally available to the mmc core, as to allow the
|
||||
following changes to make use of it.
|
||||
|
||||
Signed-off-by: Ulf Hansson <ulf.hansson@linaro.org>
|
||||
Tested-by: Quentin Schulz <quentin.schulz@bootlin.com>
|
||||
Reviewed-by: Shawn Lin <shawn.lin@rock-chips.com>
|
||||
(cherry picked from commit 508c9864ccede5dd4b8a7220b3fe6998763e4407)
|
||||
---
|
||||
drivers/mmc/core/core.c | 19 ++++++++++++-------
|
||||
drivers/mmc/core/core.h | 1 +
|
||||
2 files changed, 13 insertions(+), 7 deletions(-)
|
||||
|
||||
diff --git a/drivers/mmc/core/core.c b/drivers/mmc/core/core.c
|
||||
index dae82afcbc99..7aa83beea957 100644
|
||||
--- a/drivers/mmc/core/core.c
|
||||
+++ b/drivers/mmc/core/core.c
|
||||
@@ -1590,6 +1590,17 @@ int mmc_set_signal_voltage(struct mmc_host *host, int signal_voltage)
|
||||
|
||||
}
|
||||
|
||||
+void mmc_set_initial_signal_voltage(struct mmc_host *host)
|
||||
+{
|
||||
+ /* Try to set signal voltage to 3.3V but fall back to 1.8v or 1.2v */
|
||||
+ if (!mmc_set_signal_voltage(host, MMC_SIGNAL_VOLTAGE_330))
|
||||
+ dev_dbg(mmc_dev(host), "Initial signal voltage of 3.3v\n");
|
||||
+ else if (!mmc_set_signal_voltage(host, MMC_SIGNAL_VOLTAGE_180))
|
||||
+ dev_dbg(mmc_dev(host), "Initial signal voltage of 1.8v\n");
|
||||
+ else if (!mmc_set_signal_voltage(host, MMC_SIGNAL_VOLTAGE_120))
|
||||
+ dev_dbg(mmc_dev(host), "Initial signal voltage of 1.2v\n");
|
||||
+}
|
||||
+
|
||||
int mmc_host_set_uhs_voltage(struct mmc_host *host)
|
||||
{
|
||||
u32 clock;
|
||||
@@ -1754,13 +1765,7 @@ void mmc_power_up(struct mmc_host *host, u32 ocr)
|
||||
/* Set initial state and call mmc_set_ios */
|
||||
mmc_set_initial_state(host);
|
||||
|
||||
- /* Try to set signal voltage to 3.3V but fall back to 1.8v or 1.2v */
|
||||
- if (!mmc_set_signal_voltage(host, MMC_SIGNAL_VOLTAGE_330))
|
||||
- dev_dbg(mmc_dev(host), "Initial signal voltage of 3.3v\n");
|
||||
- else if (!mmc_set_signal_voltage(host, MMC_SIGNAL_VOLTAGE_180))
|
||||
- dev_dbg(mmc_dev(host), "Initial signal voltage of 1.8v\n");
|
||||
- else if (!mmc_set_signal_voltage(host, MMC_SIGNAL_VOLTAGE_120))
|
||||
- dev_dbg(mmc_dev(host), "Initial signal voltage of 1.2v\n");
|
||||
+ mmc_set_initial_signal_voltage(host);
|
||||
|
||||
/*
|
||||
* This delay should be sufficient to allow the power supply
|
||||
diff --git a/drivers/mmc/core/core.h b/drivers/mmc/core/core.h
|
||||
index 11f3d2c22ecb..2634722265ad 100644
|
||||
--- a/drivers/mmc/core/core.h
|
||||
+++ b/drivers/mmc/core/core.h
|
||||
@@ -46,6 +46,7 @@ u32 mmc_select_voltage(struct mmc_host *host, u32 ocr);
|
||||
int mmc_set_uhs_voltage(struct mmc_host *host, u32 ocr);
|
||||
int mmc_host_set_uhs_voltage(struct mmc_host *host);
|
||||
int mmc_set_signal_voltage(struct mmc_host *host, int signal_voltage);
|
||||
+void mmc_set_initial_signal_voltage(struct mmc_host *host);
|
||||
void mmc_set_timing(struct mmc_host *host, unsigned int timing);
|
||||
void mmc_set_driver_type(struct mmc_host *host, unsigned int drv_type);
|
||||
int mmc_select_drive_strength(struct mmc_card *card, unsigned int max_dtr,
|
||||
|
||||
From adadab9687a3e07be7557e4272fdf5a007b4c604 Mon Sep 17 00:00:00 2001
|
||||
From: Jonas Karlman <jonas@kwiboo.se>
|
||||
Date: Tue, 24 Jul 2018 15:50:06 +0200
|
||||
Subject: [PATCH] mmc: core: set initial signal voltage on power off
|
||||
|
||||
---
|
||||
drivers/mmc/core/core.c | 8 ++++++++
|
||||
1 file changed, 8 insertions(+)
|
||||
|
||||
diff --git a/drivers/mmc/core/core.c b/drivers/mmc/core/core.c
|
||||
index 7aa83beea957..d2c59b5e04ab 100644
|
||||
--- a/drivers/mmc/core/core.c
|
||||
+++ b/drivers/mmc/core/core.c
|
||||
@@ -1792,6 +1792,14 @@ void mmc_power_off(struct mmc_host *host)
|
||||
if (host->ios.power_mode == MMC_POWER_OFF)
|
||||
return;
|
||||
|
||||
+ mmc_set_initial_signal_voltage(host);
|
||||
+
|
||||
+ /*
|
||||
+ * This delay should be sufficient to allow the power supply
|
||||
+ * to reach the minimum voltage.
|
||||
+ */
|
||||
+ mmc_delay(10);
|
||||
+
|
||||
mmc_pwrseq_power_off(host);
|
||||
|
||||
host->ios.clock = 0;
|
376
patch/kernel/rockchip-default/01-linux-0010-dvb.patch
Normal file
376
patch/kernel/rockchip-default/01-linux-0010-dvb.patch
Normal file
|
@ -0,0 +1,376 @@
|
|||
From ae39146426642d51de99ba3bdef54912c579991b Mon Sep 17 00:00:00 2001
|
||||
From: Jakub Kicinski <jakub.kicinski@netronome.com>
|
||||
Date: Wed, 31 Aug 2016 12:46:44 +0100
|
||||
Subject: [PATCH] UPSTREAM: add basic register-field manipulation macros
|
||||
|
||||
Common approach to accessing register fields is to define
|
||||
structures or sets of macros containing mask and shift pair.
|
||||
Operations on the register are then performed as follows:
|
||||
|
||||
field = (reg >> shift) & mask;
|
||||
|
||||
reg &= ~(mask << shift);
|
||||
reg |= (field & mask) << shift;
|
||||
|
||||
Defining shift and mask separately is tedious. Ivo van Doorn
|
||||
came up with an idea of computing them at compilation time
|
||||
based on a single shifted mask (later refined by Felix) which
|
||||
can be used like this:
|
||||
|
||||
#define REG_FIELD 0x000ff000
|
||||
|
||||
field = FIELD_GET(REG_FIELD, reg);
|
||||
|
||||
reg &= ~REG_FIELD;
|
||||
reg |= FIELD_PREP(REG_FIELD, field);
|
||||
|
||||
FIELD_{GET,PREP} macros take care of finding out what the
|
||||
appropriate shift is based on compilation time ffs operation.
|
||||
|
||||
GENMASK can be used to define registers (which is usually
|
||||
less error-prone and easier to match with datasheets).
|
||||
|
||||
This approach is the most convenient I've seen so to limit code
|
||||
multiplication let's move the macros to a global header file.
|
||||
Attempts to use static inlines instead of macros failed due
|
||||
to false positive triggering of BUILD_BUG_ON()s, especially with
|
||||
GCC < 6.0.
|
||||
|
||||
Signed-off-by: Jakub Kicinski <jakub.kicinski@netronome.com>
|
||||
Reviewed-by: Dinan Gunawardena <dinan.gunawardena@netronome.com>
|
||||
Signed-off-by: Kalle Valo <kvalo@codeaurora.org>
|
||||
(cherry picked from commit 3e9b3112ec74f192eaab976c3889e34255cae940)
|
||||
---
|
||||
include/linux/bitfield.h | 93 ++++++++++++++++++++++++++++++++++++++++++++++++
|
||||
include/linux/bug.h | 3 ++
|
||||
2 files changed, 96 insertions(+)
|
||||
create mode 100644 include/linux/bitfield.h
|
||||
|
||||
diff --git a/include/linux/bitfield.h b/include/linux/bitfield.h
|
||||
new file mode 100644
|
||||
index 000000000000..f6505d83069d
|
||||
--- /dev/null
|
||||
+++ b/include/linux/bitfield.h
|
||||
@@ -0,0 +1,93 @@
|
||||
+/*
|
||||
+ * Copyright (C) 2014 Felix Fietkau <nbd@nbd.name>
|
||||
+ * Copyright (C) 2004 - 2009 Ivo van Doorn <IvDoorn@gmail.com>
|
||||
+ *
|
||||
+ * This program is free software; you can redistribute it and/or modify
|
||||
+ * it under the terms of the GNU General Public License version 2
|
||||
+ * as published by the Free Software Foundation
|
||||
+ *
|
||||
+ * This program is distributed in the hope that it will be useful,
|
||||
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
+ * GNU General Public License for more details.
|
||||
+ */
|
||||
+
|
||||
+#ifndef _LINUX_BITFIELD_H
|
||||
+#define _LINUX_BITFIELD_H
|
||||
+
|
||||
+#include <linux/bug.h>
|
||||
+
|
||||
+/*
|
||||
+ * Bitfield access macros
|
||||
+ *
|
||||
+ * FIELD_{GET,PREP} macros take as first parameter shifted mask
|
||||
+ * from which they extract the base mask and shift amount.
|
||||
+ * Mask must be a compilation time constant.
|
||||
+ *
|
||||
+ * Example:
|
||||
+ *
|
||||
+ * #define REG_FIELD_A GENMASK(6, 0)
|
||||
+ * #define REG_FIELD_B BIT(7)
|
||||
+ * #define REG_FIELD_C GENMASK(15, 8)
|
||||
+ * #define REG_FIELD_D GENMASK(31, 16)
|
||||
+ *
|
||||
+ * Get:
|
||||
+ * a = FIELD_GET(REG_FIELD_A, reg);
|
||||
+ * b = FIELD_GET(REG_FIELD_B, reg);
|
||||
+ *
|
||||
+ * Set:
|
||||
+ * reg = FIELD_PREP(REG_FIELD_A, 1) |
|
||||
+ * FIELD_PREP(REG_FIELD_B, 0) |
|
||||
+ * FIELD_PREP(REG_FIELD_C, c) |
|
||||
+ * FIELD_PREP(REG_FIELD_D, 0x40);
|
||||
+ *
|
||||
+ * Modify:
|
||||
+ * reg &= ~REG_FIELD_C;
|
||||
+ * reg |= FIELD_PREP(REG_FIELD_C, c);
|
||||
+ */
|
||||
+
|
||||
+#define __bf_shf(x) (__builtin_ffsll(x) - 1)
|
||||
+
|
||||
+#define __BF_FIELD_CHECK(_mask, _reg, _val, _pfx) \
|
||||
+ ({ \
|
||||
+ BUILD_BUG_ON_MSG(!__builtin_constant_p(_mask), \
|
||||
+ _pfx "mask is not constant"); \
|
||||
+ BUILD_BUG_ON_MSG(!(_mask), _pfx "mask is zero"); \
|
||||
+ BUILD_BUG_ON_MSG(__builtin_constant_p(_val) ? \
|
||||
+ ~((_mask) >> __bf_shf(_mask)) & (_val) : 0, \
|
||||
+ _pfx "value too large for the field"); \
|
||||
+ BUILD_BUG_ON_MSG((_mask) > (typeof(_reg))~0ull, \
|
||||
+ _pfx "type of reg too small for mask"); \
|
||||
+ __BUILD_BUG_ON_NOT_POWER_OF_2((_mask) + \
|
||||
+ (1ULL << __bf_shf(_mask))); \
|
||||
+ })
|
||||
+
|
||||
+/**
|
||||
+ * FIELD_PREP() - prepare a bitfield element
|
||||
+ * @_mask: shifted mask defining the field's length and position
|
||||
+ * @_val: value to put in the field
|
||||
+ *
|
||||
+ * FIELD_PREP() masks and shifts up the value. The result should
|
||||
+ * be combined with other fields of the bitfield using logical OR.
|
||||
+ */
|
||||
+#define FIELD_PREP(_mask, _val) \
|
||||
+ ({ \
|
||||
+ __BF_FIELD_CHECK(_mask, 0ULL, _val, "FIELD_PREP: "); \
|
||||
+ ((typeof(_mask))(_val) << __bf_shf(_mask)) & (_mask); \
|
||||
+ })
|
||||
+
|
||||
+/**
|
||||
+ * FIELD_GET() - extract a bitfield element
|
||||
+ * @_mask: shifted mask defining the field's length and position
|
||||
+ * @_reg: 32bit value of entire bitfield
|
||||
+ *
|
||||
+ * FIELD_GET() extracts the field specified by @_mask from the
|
||||
+ * bitfield passed in as @_reg by masking and shifting it down.
|
||||
+ */
|
||||
+#define FIELD_GET(_mask, _reg) \
|
||||
+ ({ \
|
||||
+ __BF_FIELD_CHECK(_mask, _reg, 0U, "FIELD_GET: "); \
|
||||
+ (typeof(_mask))(((_reg) & (_mask)) >> __bf_shf(_mask)); \
|
||||
+ })
|
||||
+
|
||||
+#endif
|
||||
diff --git a/include/linux/bug.h b/include/linux/bug.h
|
||||
index 7f4818673c41..edd3d8d3cd90 100644
|
||||
--- a/include/linux/bug.h
|
||||
+++ b/include/linux/bug.h
|
||||
@@ -13,6 +13,7 @@ enum bug_trap_type {
|
||||
struct pt_regs;
|
||||
|
||||
#ifdef __CHECKER__
|
||||
+#define __BUILD_BUG_ON_NOT_POWER_OF_2(n) (0)
|
||||
#define BUILD_BUG_ON_NOT_POWER_OF_2(n) (0)
|
||||
#define BUILD_BUG_ON_ZERO(e) (0)
|
||||
#define BUILD_BUG_ON_NULL(e) ((void*)0)
|
||||
@@ -23,6 +24,8 @@ struct pt_regs;
|
||||
#else /* __CHECKER__ */
|
||||
|
||||
/* Force a compilation error if a constant expression is not a power of 2 */
|
||||
+#define __BUILD_BUG_ON_NOT_POWER_OF_2(n) \
|
||||
+ BUILD_BUG_ON(((n) & ((n) - 1)) != 0)
|
||||
#define BUILD_BUG_ON_NOT_POWER_OF_2(n) \
|
||||
BUILD_BUG_ON((n) == 0 || (((n) & ((n) - 1)) != 0))
|
||||
|
||||
|
||||
From 8c11cf13e9f5c633bc2d1f3414d3b95c9cc82e4c Mon Sep 17 00:00:00 2001
|
||||
From: Jakub Kicinski <jakub.kicinski@netronome.com>
|
||||
Date: Thu, 9 Feb 2017 09:17:27 -0800
|
||||
Subject: [PATCH] UPSTREAM: bitfield.h: add FIELD_FIT() helper
|
||||
|
||||
Add a helper for checking at runtime that a value will fit inside
|
||||
a specified field/mask.
|
||||
|
||||
Signed-off-by: Jakub Kicinski <jakub.kicinski@netronome.com>
|
||||
Signed-off-by: David S. Miller <davem@davemloft.net>
|
||||
(cherry picked from commit 1697599ee301a52cded6499a09bd609f7f63fd06)
|
||||
---
|
||||
include/linux/bitfield.h | 13 +++++++++++++
|
||||
1 file changed, 13 insertions(+)
|
||||
|
||||
diff --git a/include/linux/bitfield.h b/include/linux/bitfield.h
|
||||
index f6505d83069d..8b9d6fff002d 100644
|
||||
--- a/include/linux/bitfield.h
|
||||
+++ b/include/linux/bitfield.h
|
||||
@@ -62,6 +62,19 @@
|
||||
(1ULL << __bf_shf(_mask))); \
|
||||
})
|
||||
|
||||
+/**
|
||||
+ * FIELD_FIT() - check if value fits in the field
|
||||
+ * @_mask: shifted mask defining the field's length and position
|
||||
+ * @_val: value to test against the field
|
||||
+ *
|
||||
+ * Return: true if @_val can fit inside @_mask, false if @_val is too big.
|
||||
+ */
|
||||
+#define FIELD_FIT(_mask, _val) \
|
||||
+ ({ \
|
||||
+ __BF_FIELD_CHECK(_mask, 0ULL, _val, "FIELD_FIT: "); \
|
||||
+ !((((typeof(_mask))_val) << __bf_shf(_mask)) & ~(_mask)); \
|
||||
+ })
|
||||
+
|
||||
/**
|
||||
* FIELD_PREP() - prepare a bitfield element
|
||||
* @_mask: shifted mask defining the field's length and position
|
||||
|
||||
From 9b03f083c3ba2b3ca6dbcfdc76bf24edfe8b2947 Mon Sep 17 00:00:00 2001
|
||||
From: Laurent Defert <laurent.defert@smartjog.com>
|
||||
Date: Wed, 11 Oct 2017 08:46:52 +0200
|
||||
Subject: [PATCH] FROMLIST: compat_ioctl: add compat handler for
|
||||
FE_SET_PROPERTY and FE_GET_PROPERTY
|
||||
|
||||
https://patchwork.linuxtv.org/patch/8209/
|
||||
---
|
||||
fs/compat_ioctl.c | 138 ++++++++++++++++++++++++++++++++++++++++++++++++++++++
|
||||
1 file changed, 138 insertions(+)
|
||||
|
||||
diff --git a/fs/compat_ioctl.c b/fs/compat_ioctl.c
|
||||
index a52ca5cba015..438ce0c6851e 100644
|
||||
--- a/fs/compat_ioctl.c
|
||||
+++ b/fs/compat_ioctl.c
|
||||
@@ -223,6 +223,140 @@ static int do_video_set_spu_palette(unsigned int fd, unsigned int cmd,
|
||||
return err;
|
||||
}
|
||||
|
||||
+struct compat_dtv_property {
|
||||
+ __u32 cmd;
|
||||
+ __u32 reserved[3];
|
||||
+ union {
|
||||
+ __u32 data;
|
||||
+ struct {
|
||||
+ __u8 data[32];
|
||||
+ __u32 len;
|
||||
+ __u32 reserved1[3];
|
||||
+ compat_uptr_t reserved2;
|
||||
+ } buffer;
|
||||
+ } u;
|
||||
+ int result;
|
||||
+};
|
||||
+
|
||||
+struct compat_dtv_properties {
|
||||
+ __u32 num;
|
||||
+ compat_uptr_t props;
|
||||
+};
|
||||
+
|
||||
+#define FE_SET_PROPERTY32 _IOW('o', 82, struct compat_dtv_properties)
|
||||
+#define FE_GET_PROPERTY32 _IOR('o', 83, struct compat_dtv_properties)
|
||||
+
|
||||
+static int do_fe_set_property(unsigned int fd, unsigned int cmd,
|
||||
+ struct compat_dtv_properties __user *dtv32)
|
||||
+{
|
||||
+ struct dtv_properties __user *dtv;
|
||||
+ struct dtv_property __user *properties;
|
||||
+ struct compat_dtv_property __user *properties32;
|
||||
+ compat_uptr_t data;
|
||||
+
|
||||
+ int err;
|
||||
+ int i;
|
||||
+ __u32 num;
|
||||
+
|
||||
+ err = get_user(num, &dtv32->num);
|
||||
+ err |= get_user(data, &dtv32->props);
|
||||
+
|
||||
+ if(err)
|
||||
+ return -EFAULT;
|
||||
+
|
||||
+ dtv = compat_alloc_user_space(sizeof(struct dtv_properties) +
|
||||
+ sizeof(struct dtv_property) * num);
|
||||
+ properties = (struct dtv_property*)((char*)dtv +
|
||||
+ sizeof(struct dtv_properties));
|
||||
+
|
||||
+ err = put_user(properties, &dtv->props);
|
||||
+ err |= put_user(num, &dtv->num);
|
||||
+
|
||||
+ properties32 = compat_ptr(data);
|
||||
+
|
||||
+ if(err)
|
||||
+ return -EFAULT;
|
||||
+
|
||||
+ for(i = 0; i < num; i++) {
|
||||
+ compat_uptr_t reserved2;
|
||||
+
|
||||
+ err |= copy_in_user(&properties[i], &properties32[i],
|
||||
+ (8 * sizeof(__u32)) + (32 * sizeof(__u8)));
|
||||
+ err |= get_user(reserved2, &properties32[i].u.buffer.reserved2);
|
||||
+ err |= put_user(compat_ptr(reserved2),
|
||||
+ &properties[i].u.buffer.reserved2);
|
||||
+ }
|
||||
+
|
||||
+ if(err)
|
||||
+ return -EFAULT;
|
||||
+
|
||||
+ err = sys_ioctl(fd, FE_SET_PROPERTY, (unsigned long) dtv);
|
||||
+
|
||||
+ for(i = 0; i < num; i++) {
|
||||
+ if(copy_in_user(&properties32[i].result, &properties[i].result,
|
||||
+ sizeof(int)))
|
||||
+ return -EFAULT;
|
||||
+ }
|
||||
+
|
||||
+ return err;
|
||||
+}
|
||||
+
|
||||
+static int do_fe_get_property(unsigned int fd, unsigned int cmd,
|
||||
+ struct compat_dtv_properties __user *dtv32)
|
||||
+{
|
||||
+ struct dtv_properties __user *dtv;
|
||||
+ struct dtv_property __user *properties;
|
||||
+ struct compat_dtv_property __user *properties32;
|
||||
+ compat_uptr_t data;
|
||||
+
|
||||
+ int err;
|
||||
+ int i;
|
||||
+ __u32 num;
|
||||
+
|
||||
+ err = get_user(num, &dtv32->num);
|
||||
+ err |= get_user(data, &dtv32->props);
|
||||
+
|
||||
+ if(err)
|
||||
+ return -EFAULT;
|
||||
+
|
||||
+ dtv = compat_alloc_user_space(sizeof(struct dtv_properties) +
|
||||
+ sizeof(struct dtv_property) * num);
|
||||
+ properties = (struct dtv_property*)((char*)dtv +
|
||||
+ sizeof(struct dtv_properties));
|
||||
+
|
||||
+ err = put_user(properties, &dtv->props);
|
||||
+ err |= put_user(num, &dtv->num);
|
||||
+
|
||||
+ properties32 = compat_ptr(data);
|
||||
+
|
||||
+ if(err)
|
||||
+ return -EFAULT;
|
||||
+
|
||||
+ for(i = 0; i < num; i++) {
|
||||
+ compat_uptr_t reserved2;
|
||||
+
|
||||
+ err |= copy_in_user(&properties[i], &properties32[i],
|
||||
+ (8 * sizeof(__u32)) + (32 * sizeof(__u8)));
|
||||
+ err |= get_user(reserved2, &properties32[i].u.buffer.reserved2);
|
||||
+ err |= put_user(compat_ptr(reserved2),
|
||||
+ &properties[i].u.buffer.reserved2);
|
||||
+ }
|
||||
+
|
||||
+ if(err)
|
||||
+ return -EFAULT;
|
||||
+
|
||||
+ err = sys_ioctl(fd, FE_GET_PROPERTY, (unsigned long) dtv);
|
||||
+
|
||||
+ for(i = 0; i < num; i++) {
|
||||
+
|
||||
+ if(copy_in_user(&properties32[i], &properties[i],
|
||||
+ sizeof(properties32[i])))
|
||||
+ return -EFAULT;
|
||||
+ }
|
||||
+
|
||||
+ return err;
|
||||
+}
|
||||
+
|
||||
#ifdef CONFIG_BLOCK
|
||||
typedef struct sg_io_hdr32 {
|
||||
compat_int_t interface_id; /* [i] 'S' for SCSI generic (required) */
|
||||
@@ -1483,6 +1617,10 @@ static long do_ioctl_trans(int fd, unsigned int cmd,
|
||||
return do_video_stillpicture(fd, cmd, argp);
|
||||
case VIDEO_SET_SPU_PALETTE:
|
||||
return do_video_set_spu_palette(fd, cmd, argp);
|
||||
+ case FE_SET_PROPERTY32:
|
||||
+ return do_fe_set_property(fd, cmd, argp);
|
||||
+ case FE_GET_PROPERTY32:
|
||||
+ return do_fe_get_property(fd, cmd, argp);
|
||||
}
|
||||
|
||||
/*
|
2419
patch/kernel/rockchip-default/01-linux-1000-pl330.patch
Normal file
2419
patch/kernel/rockchip-default/01-linux-1000-pl330.patch
Normal file
File diff suppressed because it is too large
Load diff
945
patch/kernel/rockchip-default/01-linux-1000-vcodec.patch
Normal file
945
patch/kernel/rockchip-default/01-linux-1000-vcodec.patch
Normal file
|
@ -0,0 +1,945 @@
|
|||
From 499f15c3237602cca9ccebe902d31bd7404fb2db Mon Sep 17 00:00:00 2001
|
||||
From: Jonas Karlman <jonas@kwiboo.se>
|
||||
Date: Thu, 5 Jul 2018 00:14:14 +0200
|
||||
Subject: [PATCH] Revert "drm/drm-prime: cache dma_buf import context"
|
||||
|
||||
This reverts commit 5a90381e5acc2cf32be03099a14d05d4362b3348.
|
||||
---
|
||||
drivers/gpu/drm/drm_prime.c | 46 ++---------------------------
|
||||
drivers/gpu/drm/rockchip/rockchip_drm_gem.c | 1 +
|
||||
2 files changed, 3 insertions(+), 44 deletions(-)
|
||||
|
||||
diff --git a/drivers/gpu/drm/drm_prime.c b/drivers/gpu/drm/drm_prime.c
|
||||
index 6f207d5946dc..6b7417a194a3 100644
|
||||
--- a/drivers/gpu/drm/drm_prime.c
|
||||
+++ b/drivers/gpu/drm/drm_prime.c
|
||||
@@ -71,11 +71,6 @@ struct drm_prime_attachment {
|
||||
enum dma_data_direction dir;
|
||||
};
|
||||
|
||||
-struct drm_prime_callback_data {
|
||||
- struct drm_gem_object *obj;
|
||||
- struct sg_table *sgt;
|
||||
-};
|
||||
-
|
||||
static int drm_prime_add_buf_handle(struct drm_prime_file_private *prime_fpriv,
|
||||
struct dma_buf *dma_buf, uint32_t handle)
|
||||
{
|
||||
@@ -524,23 +519,6 @@ out_unlock:
|
||||
}
|
||||
EXPORT_SYMBOL(drm_gem_prime_handle_to_fd);
|
||||
|
||||
-static void drm_gem_prime_dmabuf_release_callback(void *data)
|
||||
-{
|
||||
- struct drm_prime_callback_data *cb_data = data;
|
||||
-
|
||||
- if (cb_data && cb_data->obj && cb_data->obj->import_attach) {
|
||||
- struct dma_buf_attachment *attach = cb_data->obj->import_attach;
|
||||
- struct sg_table *sgt = cb_data->sgt;
|
||||
-
|
||||
- if (sgt)
|
||||
- dma_buf_unmap_attachment(attach, sgt,
|
||||
- DMA_BIDIRECTIONAL);
|
||||
- dma_buf_detach(attach->dmabuf, attach);
|
||||
- drm_gem_object_unreference_unlocked(cb_data->obj);
|
||||
- kfree(cb_data);
|
||||
- }
|
||||
-}
|
||||
-
|
||||
/**
|
||||
* drm_gem_prime_import - helper library implementation of the import callback
|
||||
* @dev: drm_device to import into
|
||||
@@ -555,7 +533,6 @@ struct drm_gem_object *drm_gem_prime_import(struct drm_device *dev,
|
||||
struct dma_buf_attachment *attach;
|
||||
struct sg_table *sgt;
|
||||
struct drm_gem_object *obj;
|
||||
- struct drm_prime_callback_data *cb_data;
|
||||
int ret;
|
||||
|
||||
if (dma_buf->ops == &drm_gem_prime_dmabuf_ops) {
|
||||
@@ -570,13 +547,6 @@ struct drm_gem_object *drm_gem_prime_import(struct drm_device *dev,
|
||||
}
|
||||
}
|
||||
|
||||
- cb_data = dma_buf_get_release_callback_data(dma_buf,
|
||||
- drm_gem_prime_dmabuf_release_callback);
|
||||
- if (cb_data && cb_data->obj && cb_data->obj->dev == dev) {
|
||||
- drm_gem_object_reference(cb_data->obj);
|
||||
- return cb_data->obj;
|
||||
- }
|
||||
-
|
||||
if (!dev->driver->gem_prime_import_sg_table)
|
||||
return ERR_PTR(-EINVAL);
|
||||
|
||||
@@ -585,16 +555,11 @@ struct drm_gem_object *drm_gem_prime_import(struct drm_device *dev,
|
||||
return ERR_CAST(attach);
|
||||
|
||||
get_dma_buf(dma_buf);
|
||||
- cb_data = kmalloc(sizeof(*cb_data), GFP_KERNEL);
|
||||
- if (!cb_data) {
|
||||
- ret = -ENOMEM;
|
||||
- goto fail_detach;
|
||||
- }
|
||||
|
||||
sgt = dma_buf_map_attachment(attach, DMA_BIDIRECTIONAL);
|
||||
if (IS_ERR(sgt)) {
|
||||
ret = PTR_ERR(sgt);
|
||||
- goto fail_free;
|
||||
+ goto fail_detach;
|
||||
}
|
||||
|
||||
obj = dev->driver->gem_prime_import_sg_table(dev, attach, sgt);
|
||||
@@ -602,20 +567,13 @@ struct drm_gem_object *drm_gem_prime_import(struct drm_device *dev,
|
||||
ret = PTR_ERR(obj);
|
||||
goto fail_unmap;
|
||||
}
|
||||
+
|
||||
obj->import_attach = attach;
|
||||
- cb_data->obj = obj;
|
||||
- cb_data->sgt = sgt;
|
||||
- dma_buf_set_release_callback(dma_buf,
|
||||
- drm_gem_prime_dmabuf_release_callback, cb_data);
|
||||
- dma_buf_put(dma_buf);
|
||||
- drm_gem_object_reference(obj);
|
||||
|
||||
return obj;
|
||||
|
||||
fail_unmap:
|
||||
dma_buf_unmap_attachment(attach, sgt, DMA_BIDIRECTIONAL);
|
||||
-fail_free:
|
||||
- kfree(cb_data);
|
||||
fail_detach:
|
||||
dma_buf_detach(dma_buf, attach);
|
||||
dma_buf_put(dma_buf);
|
||||
diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_gem.c b/drivers/gpu/drm/rockchip/rockchip_drm_gem.c
|
||||
index 273a52b5eb66..85bbd19c87b0 100644
|
||||
--- a/drivers/gpu/drm/rockchip/rockchip_drm_gem.c
|
||||
+++ b/drivers/gpu/drm/rockchip/rockchip_drm_gem.c
|
||||
@@ -649,6 +649,7 @@ void rockchip_gem_free_object(struct drm_gem_object *obj)
|
||||
dma_unmap_sg(drm->dev, rk_obj->sgt->sgl,
|
||||
rk_obj->sgt->nents, DMA_BIDIRECTIONAL);
|
||||
}
|
||||
+ drm_prime_gem_destroy(obj, rk_obj->sgt);
|
||||
} else {
|
||||
rockchip_gem_free_buf(rk_obj);
|
||||
}
|
||||
|
||||
From 3dd29985f5f1cec249c833b1b2ca33e131f79825 Mon Sep 17 00:00:00 2001
|
||||
From: Rob Clark <robdclark@gmail.com>
|
||||
Date: Thu, 9 Jun 2016 15:29:19 -0400
|
||||
Subject: [PATCH] UPSTREAM: drm/prime: fix error path deadlock fail
|
||||
|
||||
There were a couple messed up things about this fail path.
|
||||
(1) it would drop object_name_lock twice
|
||||
(2) drm_gem_handle_delete() (in drm_gem_remove_prime_handles())
|
||||
needs to grab prime_lock
|
||||
|
||||
Reported-by: Alex Deucher <alexdeucher@gmail.com>
|
||||
Signed-off-by: Rob Clark <robdclark@gmail.com>
|
||||
Reviewed-by: Alex Deucher <alexander.deucher@amd.com>
|
||||
Signed-off-by: Daniel Vetter <daniel.vetter@ffwll.ch>
|
||||
Link: http://patchwork.freedesktop.org/patch/msgid/1465500559-17873-1-git-send-email-robdclark@gmail.com
|
||||
(cherry picked from commit bd6e2732f0e2894ce792f344c41fc32591436fe3)
|
||||
---
|
||||
drivers/gpu/drm/drm_prime.c | 10 ++++++----
|
||||
1 file changed, 6 insertions(+), 4 deletions(-)
|
||||
|
||||
diff --git a/drivers/gpu/drm/drm_prime.c b/drivers/gpu/drm/drm_prime.c
|
||||
index 6b7417a194a3..d8d85286764d 100644
|
||||
--- a/drivers/gpu/drm/drm_prime.c
|
||||
+++ b/drivers/gpu/drm/drm_prime.c
|
||||
@@ -628,7 +628,7 @@ int drm_gem_prime_fd_to_handle(struct drm_device *dev,
|
||||
get_dma_buf(dma_buf);
|
||||
}
|
||||
|
||||
- /* drm_gem_handle_create_tail unlocks dev->object_name_lock. */
|
||||
+ /* _handle_create_tail unconditionally unlocks dev->object_name_lock. */
|
||||
ret = drm_gem_handle_create_tail(file_priv, obj, handle);
|
||||
drm_gem_object_unreference_unlocked(obj);
|
||||
if (ret)
|
||||
@@ -636,11 +636,10 @@ int drm_gem_prime_fd_to_handle(struct drm_device *dev,
|
||||
|
||||
ret = drm_prime_add_buf_handle(&file_priv->prime,
|
||||
dma_buf, *handle);
|
||||
+ mutex_unlock(&file_priv->prime.lock);
|
||||
if (ret)
|
||||
goto fail;
|
||||
|
||||
- mutex_unlock(&file_priv->prime.lock);
|
||||
-
|
||||
dma_buf_put(dma_buf);
|
||||
|
||||
return 0;
|
||||
@@ -650,11 +649,14 @@ fail:
|
||||
* to detach.. which seems ok..
|
||||
*/
|
||||
drm_gem_handle_delete(file_priv, *handle);
|
||||
+ dma_buf_put(dma_buf);
|
||||
+ return ret;
|
||||
+
|
||||
out_unlock:
|
||||
mutex_unlock(&dev->object_name_lock);
|
||||
out_put:
|
||||
- dma_buf_put(dma_buf);
|
||||
mutex_unlock(&file_priv->prime.lock);
|
||||
+ dma_buf_put(dma_buf);
|
||||
return ret;
|
||||
}
|
||||
EXPORT_SYMBOL(drm_gem_prime_fd_to_handle);
|
||||
|
||||
From a689159fac372a8210d2c63ba63da3a097388b97 Mon Sep 17 00:00:00 2001
|
||||
From: Chris Wilson <chris@chris-wilson.co.uk>
|
||||
Date: Mon, 26 Sep 2016 21:44:14 +0100
|
||||
Subject: [PATCH] UPSTREAM: drm: Convert prime dma-buf <-> handle to rbtree
|
||||
|
||||
Currently we use a linear walk to lookup a handle and return a dma-buf,
|
||||
and vice versa. A long overdue TODO task is to convert that to a
|
||||
hashtable. Since the initial implementation of dma-buf/prime, we now
|
||||
have resizeable hashtables we can use (and now a future task is to RCU
|
||||
enable the lookup!). However, this patch opts to use an rbtree instead
|
||||
to provide O(lgN) lookups (and insertion, deletion). rbtrees were chosen
|
||||
over using the RCU backed resizable hashtable to firstly avoid the
|
||||
reallocations (rbtrees can be embedded entirely within the parent
|
||||
struct) and to favour simpler code with predictable worst case
|
||||
behaviour. In simple testing, the difference between using the constant
|
||||
lookup and insertion of the rhashtable and the rbtree was less than 10%
|
||||
of the wall time (igt/benchmarks/prime_lookup) - both are dramatic
|
||||
improvements over the existing linear lists.
|
||||
|
||||
v2: Favour rbtree over rhashtable
|
||||
|
||||
Bugzilla: https://bugs.freedesktop.org/show_bug.cgi?id=94631
|
||||
Signed-off-by: Chris Wilson <chris@chris-wilson.co.uk>
|
||||
Cc: Sean Paul <seanpaul@chromium.org>
|
||||
Cc: David Herrmann <dh.herrmann@gmail.com>
|
||||
Reviewed-by: David Herrmann <dh.herrmann@gmail.com>
|
||||
Reviewed-by: Sean Paul <seanpaul@chromium.org>
|
||||
Signed-off-by: Daniel Vetter <daniel.vetter@ffwll.ch>
|
||||
Link: http://patchwork.freedesktop.org/patch/msgid/20160926204414.23222-1-chris@chris-wilson.co.uk
|
||||
(cherry picked from commit 077675c1e8a193a6355d4a7c8c7bf63be310b472)
|
||||
---
|
||||
drivers/gpu/drm/drm_prime.c | 85 +++++++++++++++++++++++++++++++++++++++------
|
||||
include/drm/drmP.h | 5 +--
|
||||
2 files changed, 77 insertions(+), 13 deletions(-)
|
||||
|
||||
diff --git a/drivers/gpu/drm/drm_prime.c b/drivers/gpu/drm/drm_prime.c
|
||||
index d8d85286764d..4c49e736bc9c 100644
|
||||
--- a/drivers/gpu/drm/drm_prime.c
|
||||
+++ b/drivers/gpu/drm/drm_prime.c
|
||||
@@ -28,6 +28,7 @@
|
||||
|
||||
#include <linux/export.h>
|
||||
#include <linux/dma-buf.h>
|
||||
+#include <linux/rbtree.h>
|
||||
#include <drm/drmP.h>
|
||||
#include <drm/drm_gem.h>
|
||||
|
||||
@@ -61,9 +62,11 @@
|
||||
*/
|
||||
|
||||
struct drm_prime_member {
|
||||
- struct list_head entry;
|
||||
struct dma_buf *dma_buf;
|
||||
uint32_t handle;
|
||||
+
|
||||
+ struct rb_node dmabuf_rb;
|
||||
+ struct rb_node handle_rb;
|
||||
};
|
||||
|
||||
struct drm_prime_attachment {
|
||||
@@ -75,6 +78,7 @@ static int drm_prime_add_buf_handle(struct drm_prime_file_private *prime_fpriv,
|
||||
struct dma_buf *dma_buf, uint32_t handle)
|
||||
{
|
||||
struct drm_prime_member *member;
|
||||
+ struct rb_node **p, *rb;
|
||||
|
||||
member = kmalloc(sizeof(*member), GFP_KERNEL);
|
||||
if (!member)
|
||||
@@ -83,18 +87,56 @@ static int drm_prime_add_buf_handle(struct drm_prime_file_private *prime_fpriv,
|
||||
get_dma_buf(dma_buf);
|
||||
member->dma_buf = dma_buf;
|
||||
member->handle = handle;
|
||||
- list_add(&member->entry, &prime_fpriv->head);
|
||||
+
|
||||
+ rb = NULL;
|
||||
+ p = &prime_fpriv->dmabufs.rb_node;
|
||||
+ while (*p) {
|
||||
+ struct drm_prime_member *pos;
|
||||
+
|
||||
+ rb = *p;
|
||||
+ pos = rb_entry(rb, struct drm_prime_member, dmabuf_rb);
|
||||
+ if (dma_buf > pos->dma_buf)
|
||||
+ p = &rb->rb_right;
|
||||
+ else
|
||||
+ p = &rb->rb_left;
|
||||
+ }
|
||||
+ rb_link_node(&member->dmabuf_rb, rb, p);
|
||||
+ rb_insert_color(&member->dmabuf_rb, &prime_fpriv->dmabufs);
|
||||
+
|
||||
+ rb = NULL;
|
||||
+ p = &prime_fpriv->handles.rb_node;
|
||||
+ while (*p) {
|
||||
+ struct drm_prime_member *pos;
|
||||
+
|
||||
+ rb = *p;
|
||||
+ pos = rb_entry(rb, struct drm_prime_member, handle_rb);
|
||||
+ if (handle > pos->handle)
|
||||
+ p = &rb->rb_right;
|
||||
+ else
|
||||
+ p = &rb->rb_left;
|
||||
+ }
|
||||
+ rb_link_node(&member->handle_rb, rb, p);
|
||||
+ rb_insert_color(&member->handle_rb, &prime_fpriv->handles);
|
||||
+
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct dma_buf *drm_prime_lookup_buf_by_handle(struct drm_prime_file_private *prime_fpriv,
|
||||
uint32_t handle)
|
||||
{
|
||||
- struct drm_prime_member *member;
|
||||
+ struct rb_node *rb;
|
||||
+
|
||||
+ rb = prime_fpriv->handles.rb_node;
|
||||
+ while (rb) {
|
||||
+ struct drm_prime_member *member;
|
||||
|
||||
- list_for_each_entry(member, &prime_fpriv->head, entry) {
|
||||
+ member = rb_entry(rb, struct drm_prime_member, handle_rb);
|
||||
if (member->handle == handle)
|
||||
return member->dma_buf;
|
||||
+ else if (member->handle < handle)
|
||||
+ rb = rb->rb_right;
|
||||
+ else
|
||||
+ rb = rb->rb_left;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
@@ -104,14 +146,23 @@ static int drm_prime_lookup_buf_handle(struct drm_prime_file_private *prime_fpri
|
||||
struct dma_buf *dma_buf,
|
||||
uint32_t *handle)
|
||||
{
|
||||
- struct drm_prime_member *member;
|
||||
+ struct rb_node *rb;
|
||||
+
|
||||
+ rb = prime_fpriv->dmabufs.rb_node;
|
||||
+ while (rb) {
|
||||
+ struct drm_prime_member *member;
|
||||
|
||||
- list_for_each_entry(member, &prime_fpriv->head, entry) {
|
||||
+ member = rb_entry(rb, struct drm_prime_member, dmabuf_rb);
|
||||
if (member->dma_buf == dma_buf) {
|
||||
*handle = member->handle;
|
||||
return 0;
|
||||
+ } else if (member->dma_buf < dma_buf) {
|
||||
+ rb = rb->rb_right;
|
||||
+ } else {
|
||||
+ rb = rb->rb_left;
|
||||
}
|
||||
}
|
||||
+
|
||||
return -ENOENT;
|
||||
}
|
||||
|
||||
@@ -166,13 +217,24 @@ static void drm_gem_map_detach(struct dma_buf *dma_buf,
|
||||
void drm_prime_remove_buf_handle_locked(struct drm_prime_file_private *prime_fpriv,
|
||||
struct dma_buf *dma_buf)
|
||||
{
|
||||
- struct drm_prime_member *member, *safe;
|
||||
+ struct rb_node *rb;
|
||||
|
||||
- list_for_each_entry_safe(member, safe, &prime_fpriv->head, entry) {
|
||||
+ rb = prime_fpriv->dmabufs.rb_node;
|
||||
+ while (rb) {
|
||||
+ struct drm_prime_member *member;
|
||||
+
|
||||
+ member = rb_entry(rb, struct drm_prime_member, dmabuf_rb);
|
||||
if (member->dma_buf == dma_buf) {
|
||||
+ rb_erase(&member->handle_rb, &prime_fpriv->handles);
|
||||
+ rb_erase(&member->dmabuf_rb, &prime_fpriv->dmabufs);
|
||||
+
|
||||
dma_buf_put(dma_buf);
|
||||
- list_del(&member->entry);
|
||||
kfree(member);
|
||||
+ return;
|
||||
+ } else if (member->dma_buf < dma_buf) {
|
||||
+ rb = rb->rb_right;
|
||||
+ } else {
|
||||
+ rb = rb->rb_left;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -794,12 +856,13 @@ EXPORT_SYMBOL(drm_prime_gem_destroy);
|
||||
|
||||
void drm_prime_init_file_private(struct drm_prime_file_private *prime_fpriv)
|
||||
{
|
||||
- INIT_LIST_HEAD(&prime_fpriv->head);
|
||||
mutex_init(&prime_fpriv->lock);
|
||||
+ prime_fpriv->dmabufs = RB_ROOT;
|
||||
+ prime_fpriv->handles = RB_ROOT;
|
||||
}
|
||||
|
||||
void drm_prime_destroy_file_private(struct drm_prime_file_private *prime_fpriv)
|
||||
{
|
||||
/* by now drm_gem_release should've made sure the list is empty */
|
||||
- WARN_ON(!list_empty(&prime_fpriv->head));
|
||||
+ WARN_ON(!RB_EMPTY_ROOT(&prime_fpriv->dmabufs));
|
||||
}
|
||||
diff --git a/include/drm/drmP.h b/include/drm/drmP.h
|
||||
index 04edcd32b409..93da65df2e7e 100644
|
||||
--- a/include/drm/drmP.h
|
||||
+++ b/include/drm/drmP.h
|
||||
@@ -51,6 +51,7 @@
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/poll.h>
|
||||
#include <linux/ratelimit.h>
|
||||
+#include <linux/rbtree.h>
|
||||
#include <linux/sched.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/types.h>
|
||||
@@ -365,10 +366,10 @@ struct drm_pending_event {
|
||||
void (*destroy)(struct drm_pending_event *event);
|
||||
};
|
||||
|
||||
-/* initial implementaton using a linked list - todo hashtab */
|
||||
struct drm_prime_file_private {
|
||||
- struct list_head head;
|
||||
struct mutex lock;
|
||||
+ struct rb_root dmabufs;
|
||||
+ struct rb_root handles;
|
||||
};
|
||||
|
||||
/** File private data */
|
||||
|
||||
From f977098a9a02ac2df267eafe860370cb4c407d69 Mon Sep 17 00:00:00 2001
|
||||
From: Chris Wilson <chris@chris-wilson.co.uk>
|
||||
Date: Wed, 5 Oct 2016 13:21:44 +0100
|
||||
Subject: [PATCH] UPSTREAM: drm/prime: Take a ref on the drm_dev when exporting
|
||||
a dma_buf
|
||||
MIME-Version: 1.0
|
||||
Content-Type: text/plain; charset=UTF-8
|
||||
Content-Transfer-Encoding: 8bit
|
||||
|
||||
dma_buf may live a long time, longer than the last direct user of the
|
||||
driver. We already hold a reference to the owner module (that prevents
|
||||
the object code from disappearing), but there is no reference to the
|
||||
drm_dev - so the pointers to the driver backend themselves may vanish.
|
||||
|
||||
v2: Resist temptation to fix the bug in armada_gem.c not setting the
|
||||
correct flags on the exported dma-buf (it should pass the flags through
|
||||
and not be arbitrarily setting O_RDWR).
|
||||
|
||||
Use a common wrapper for exporting the dmabuf and acquiring the
|
||||
reference to the drm_device.
|
||||
|
||||
Testcase: igt/vgem_basic/unload
|
||||
Suggested-by: Daniel Vetter <daniel.vetter@ffwll.ch>
|
||||
Signed-off-by: Chris Wilson <chris@chris-wilson.co.uk>
|
||||
Cc: Petri Latvala <petri.latvala@intel.com>
|
||||
Cc: Daniel Vetter <daniel.vetter@ffwll.ch>
|
||||
Cc: stable@vger.kernel.org
|
||||
Tested-by: Petri Latvala <petri.latvala@intel.com>
|
||||
Reviewed-by: Christian König <christian.koenig@amd.com>
|
||||
Signed-off-by: Daniel Vetter <daniel.vetter@ffwll.ch>
|
||||
Link: http://patchwork.freedesktop.org/patch/msgid/20161005122145.1507-2-chris@chris-wilson.co.uk
|
||||
(cherry picked from commit a4fce9cb782ad340ee5576a38e934e5e75832dc6)
|
||||
---
|
||||
drivers/gpu/drm/armada/armada_gem.c | 2 +-
|
||||
drivers/gpu/drm/drm_prime.c | 30 +++++++++++++++++++++++++++++-
|
||||
drivers/gpu/drm/i915/i915_gem_dmabuf.c | 2 +-
|
||||
drivers/gpu/drm/tegra/gem.c | 2 +-
|
||||
drivers/gpu/drm/udl/udl_dmabuf.c | 2 +-
|
||||
include/drm/drmP.h | 4 ++++
|
||||
6 files changed, 37 insertions(+), 5 deletions(-)
|
||||
|
||||
diff --git a/drivers/gpu/drm/armada/armada_gem.c b/drivers/gpu/drm/armada/armada_gem.c
|
||||
index 60a688ef81c7..cd5bb991f49a 100644
|
||||
--- a/drivers/gpu/drm/armada/armada_gem.c
|
||||
+++ b/drivers/gpu/drm/armada/armada_gem.c
|
||||
@@ -546,7 +546,7 @@ armada_gem_prime_export(struct drm_device *dev, struct drm_gem_object *obj,
|
||||
exp_info.flags = O_RDWR;
|
||||
exp_info.priv = obj;
|
||||
|
||||
- return dma_buf_export(&exp_info);
|
||||
+ return drm_gem_dmabuf_export(dev, &exp_info);
|
||||
}
|
||||
|
||||
struct drm_gem_object *
|
||||
diff --git a/drivers/gpu/drm/drm_prime.c b/drivers/gpu/drm/drm_prime.c
|
||||
index 4c49e736bc9c..94b4872255c8 100644
|
||||
--- a/drivers/gpu/drm/drm_prime.c
|
||||
+++ b/drivers/gpu/drm/drm_prime.c
|
||||
@@ -283,19 +283,47 @@ static void drm_gem_unmap_dma_buf(struct dma_buf_attachment *attach,
|
||||
/* nothing to be done here */
|
||||
}
|
||||
|
||||
+/**
|
||||
+ * drm_gem_dmabuf_export - dma_buf export implementation for GEM
|
||||
+ * @dma_buf: buffer to be exported
|
||||
+ *
|
||||
+ * This wraps dma_buf_export() for use by generic GEM drivers that are using
|
||||
+ * drm_gem_dmabuf_release(). In addition to calling dma_buf_export(), we take
|
||||
+ * a reference to the drm_device which is released by drm_gem_dmabuf_release().
|
||||
+ *
|
||||
+ * Returns the new dmabuf.
|
||||
+ */
|
||||
+struct dma_buf *drm_gem_dmabuf_export(struct drm_device *dev,
|
||||
+ struct dma_buf_export_info *exp_info)
|
||||
+{
|
||||
+ struct dma_buf *dma_buf;
|
||||
+
|
||||
+ dma_buf = dma_buf_export(exp_info);
|
||||
+ if (!IS_ERR(dma_buf))
|
||||
+ drm_dev_ref(dev);
|
||||
+
|
||||
+ return dma_buf;
|
||||
+}
|
||||
+EXPORT_SYMBOL(drm_gem_dmabuf_export);
|
||||
+
|
||||
/**
|
||||
* drm_gem_dmabuf_release - dma_buf release implementation for GEM
|
||||
* @dma_buf: buffer to be released
|
||||
*
|
||||
* Generic release function for dma_bufs exported as PRIME buffers. GEM drivers
|
||||
* must use this in their dma_buf ops structure as the release callback.
|
||||
+ * drm_gem_dmabuf_release() should be used in conjunction with
|
||||
+ * drm_gem_dmabuf_export().
|
||||
*/
|
||||
void drm_gem_dmabuf_release(struct dma_buf *dma_buf)
|
||||
{
|
||||
struct drm_gem_object *obj = dma_buf->priv;
|
||||
+ struct drm_device *dev = obj->dev;
|
||||
|
||||
/* drop the reference on the export fd holds */
|
||||
drm_gem_object_unreference_unlocked(obj);
|
||||
+
|
||||
+ drm_dev_unref(dev);
|
||||
}
|
||||
EXPORT_SYMBOL(drm_gem_dmabuf_release);
|
||||
|
||||
@@ -444,7 +472,7 @@ struct dma_buf *drm_gem_prime_export(struct drm_device *dev,
|
||||
if (dev->driver->gem_prime_res_obj)
|
||||
exp_info.resv = dev->driver->gem_prime_res_obj(obj);
|
||||
|
||||
- return dma_buf_export(&exp_info);
|
||||
+ return drm_gem_dmabuf_export(dev, &exp_info);
|
||||
}
|
||||
EXPORT_SYMBOL(drm_gem_prime_export);
|
||||
|
||||
diff --git a/drivers/gpu/drm/i915/i915_gem_dmabuf.c b/drivers/gpu/drm/i915/i915_gem_dmabuf.c
|
||||
index e9c2bfd85b52..d4a021629bd6 100644
|
||||
--- a/drivers/gpu/drm/i915/i915_gem_dmabuf.c
|
||||
+++ b/drivers/gpu/drm/i915/i915_gem_dmabuf.c
|
||||
@@ -244,7 +244,7 @@ struct dma_buf *i915_gem_prime_export(struct drm_device *dev,
|
||||
return ERR_PTR(ret);
|
||||
}
|
||||
|
||||
- return dma_buf_export(&exp_info);
|
||||
+ return drm_gem_dmabuf_export(dev, &exp_info);
|
||||
}
|
||||
|
||||
static int i915_gem_object_get_pages_dmabuf(struct drm_i915_gem_object *obj)
|
||||
diff --git a/drivers/gpu/drm/tegra/gem.c b/drivers/gpu/drm/tegra/gem.c
|
||||
index 01e16e146bfe..da06f1c1ee0f 100644
|
||||
--- a/drivers/gpu/drm/tegra/gem.c
|
||||
+++ b/drivers/gpu/drm/tegra/gem.c
|
||||
@@ -625,7 +625,7 @@ struct dma_buf *tegra_gem_prime_export(struct drm_device *drm,
|
||||
exp_info.flags = flags;
|
||||
exp_info.priv = gem;
|
||||
|
||||
- return dma_buf_export(&exp_info);
|
||||
+ return drm_gem_dmabuf_export(drm, &exp_info);
|
||||
}
|
||||
|
||||
struct drm_gem_object *tegra_gem_prime_import(struct drm_device *drm,
|
||||
diff --git a/drivers/gpu/drm/udl/udl_dmabuf.c b/drivers/gpu/drm/udl/udl_dmabuf.c
|
||||
index e2243edd1ce3..ac90ffdb5912 100644
|
||||
--- a/drivers/gpu/drm/udl/udl_dmabuf.c
|
||||
+++ b/drivers/gpu/drm/udl/udl_dmabuf.c
|
||||
@@ -209,7 +209,7 @@ struct dma_buf *udl_gem_prime_export(struct drm_device *dev,
|
||||
exp_info.flags = flags;
|
||||
exp_info.priv = obj;
|
||||
|
||||
- return dma_buf_export(&exp_info);
|
||||
+ return drm_gem_dmabuf_export(dev, &exp_info);
|
||||
}
|
||||
|
||||
static int udl_prime_create(struct drm_device *dev,
|
||||
diff --git a/include/drm/drmP.h b/include/drm/drmP.h
|
||||
index 93da65df2e7e..4aba6478d718 100644
|
||||
--- a/include/drm/drmP.h
|
||||
+++ b/include/drm/drmP.h
|
||||
@@ -1124,6 +1124,8 @@ static inline int drm_debugfs_remove_files(const struct drm_info_list *files,
|
||||
}
|
||||
#endif
|
||||
|
||||
+struct dma_buf_export_info;
|
||||
+
|
||||
extern struct dma_buf *drm_gem_prime_export(struct drm_device *dev,
|
||||
struct drm_gem_object *obj,
|
||||
int flags);
|
||||
@@ -1134,6 +1136,8 @@ extern struct drm_gem_object *drm_gem_prime_import(struct drm_device *dev,
|
||||
struct dma_buf *dma_buf);
|
||||
extern int drm_gem_prime_fd_to_handle(struct drm_device *dev,
|
||||
struct drm_file *file_priv, int prime_fd, uint32_t *handle);
|
||||
+struct dma_buf *drm_gem_dmabuf_export(struct drm_device *dev,
|
||||
+ struct dma_buf_export_info *exp_info);
|
||||
extern void drm_gem_dmabuf_release(struct dma_buf *dma_buf);
|
||||
|
||||
extern int drm_prime_sg_to_page_addr_arrays(struct sg_table *sgt, struct page **pages,
|
||||
|
||||
From f30ee0d19425a6c21a9959513e482282ba08dd6a Mon Sep 17 00:00:00 2001
|
||||
From: Chris Wilson <chris@chris-wilson.co.uk>
|
||||
Date: Wed, 7 Dec 2016 21:45:27 +0000
|
||||
Subject: [PATCH] UPSTREAM: drm: Take ownership of the dmabuf->obj when
|
||||
exporting
|
||||
|
||||
Currently the reference for the dmabuf->obj is incremented for the
|
||||
dmabuf in drm_gem_prime_handle_to_fd() (at the high level userspace
|
||||
interface), but is released in drm_gem_dmabuf_release() (the lowlevel
|
||||
handler). Improve the symmetry of the dmabuf->obj ownership by acquiring
|
||||
the reference in drm_gem_dmabuf_export(). This makes it easier to use
|
||||
the prime functions directly.
|
||||
|
||||
Signed-off-by: Chris Wilson <chris@chris-wilson.co.uk>
|
||||
[danvet: Update kerneldoc.]
|
||||
Signed-off-by: Daniel Vetter <daniel.vetter@ffwll.ch>
|
||||
Link: http://patchwork.freedesktop.org/patch/msgid/20161207214527.22533-1-chris@chris-wilson.co.uk
|
||||
(cherry picked from commit 72a93e8dd52c9feea42f1258d555e6070680a347)
|
||||
---
|
||||
drivers/gpu/drm/drm_prime.c | 12 +++++++-----
|
||||
1 file changed, 7 insertions(+), 5 deletions(-)
|
||||
|
||||
diff --git a/drivers/gpu/drm/drm_prime.c b/drivers/gpu/drm/drm_prime.c
|
||||
index 94b4872255c8..dbd34fa7f71c 100644
|
||||
--- a/drivers/gpu/drm/drm_prime.c
|
||||
+++ b/drivers/gpu/drm/drm_prime.c
|
||||
@@ -289,7 +289,8 @@ static void drm_gem_unmap_dma_buf(struct dma_buf_attachment *attach,
|
||||
*
|
||||
* This wraps dma_buf_export() for use by generic GEM drivers that are using
|
||||
* drm_gem_dmabuf_release(). In addition to calling dma_buf_export(), we take
|
||||
- * a reference to the drm_device which is released by drm_gem_dmabuf_release().
|
||||
+ * a reference to the &drm_device and the exported &drm_gem_object (stored in
|
||||
+ * exp_info->priv) which is released by drm_gem_dmabuf_release().
|
||||
*
|
||||
* Returns the new dmabuf.
|
||||
*/
|
||||
@@ -299,8 +300,11 @@ struct dma_buf *drm_gem_dmabuf_export(struct drm_device *dev,
|
||||
struct dma_buf *dma_buf;
|
||||
|
||||
dma_buf = dma_buf_export(exp_info);
|
||||
- if (!IS_ERR(dma_buf))
|
||||
- drm_dev_ref(dev);
|
||||
+ if (IS_ERR(dma_buf))
|
||||
+ return dma_buf;
|
||||
+
|
||||
+ drm_dev_ref(dev);
|
||||
+ drm_gem_object_reference(exp_info->priv);
|
||||
|
||||
return dma_buf;
|
||||
}
|
||||
@@ -503,8 +507,6 @@ static struct dma_buf *export_and_register_object(struct drm_device *dev,
|
||||
*/
|
||||
obj->dma_buf = dmabuf;
|
||||
get_dma_buf(obj->dma_buf);
|
||||
- /* Grab a new ref since the callers is now used by the dma-buf */
|
||||
- drm_gem_object_reference(obj);
|
||||
|
||||
return dmabuf;
|
||||
}
|
||||
|
||||
From a1fe1ad6076ec27f60555a9393f40959cea94bff Mon Sep 17 00:00:00 2001
|
||||
From: Lucas Stach <l.stach@pengutronix.de>
|
||||
Date: Thu, 30 Nov 2017 18:34:28 +0100
|
||||
Subject: [PATCH] UPSTREAM: drm/prime: skip CPU sync in map/unmap dma_buf
|
||||
|
||||
Dma-bufs should already be device coherent, as they are only pulled in the
|
||||
CPU domain via the begin/end cpu_access calls. As we cache the mapping set
|
||||
up by dma_map_sg a CPU sync at this point will not actually guarantee proper
|
||||
coherency on non-coherent architectures, so we can as well stop pretending.
|
||||
|
||||
This is an important performance fix for architectures which need explicit
|
||||
cache synchronization and userspace doing lots of dma-buf imports.
|
||||
Improves Weston on Etnaviv performance 5x, where before this patch > 90%
|
||||
of Weston CPU time was spent synchronizing caches for buffers which are
|
||||
already device coherent.
|
||||
|
||||
Signed-off-by: Lucas Stach <l.stach@pengutronix.de>
|
||||
Reviewed-by: Chris Wilson <chris@chris-wilson.co.uk>
|
||||
Signed-off-by: Daniel Vetter <daniel.vetter@ffwll.ch>
|
||||
Link: https://patchwork.freedesktop.org/patch/msgid/20171130173428.8666-1-l.stach@pengutronix.de
|
||||
(cherry picked from commit ca0e68e21aae10220eff71a297e7d794425add77)
|
||||
---
|
||||
drivers/gpu/drm/drm_prime.c | 11 ++++++++---
|
||||
1 file changed, 8 insertions(+), 3 deletions(-)
|
||||
|
||||
diff --git a/drivers/gpu/drm/drm_prime.c b/drivers/gpu/drm/drm_prime.c
|
||||
index dbd34fa7f71c..133362279591 100644
|
||||
--- a/drivers/gpu/drm/drm_prime.c
|
||||
+++ b/drivers/gpu/drm/drm_prime.c
|
||||
@@ -203,9 +203,12 @@ static void drm_gem_map_detach(struct dma_buf *dma_buf,
|
||||
|
||||
sgt = prime_attach->sgt;
|
||||
if (sgt) {
|
||||
+ DEFINE_DMA_ATTRS(attrs);
|
||||
+ dma_set_attr(DMA_ATTR_SKIP_CPU_SYNC, &attrs);
|
||||
if (prime_attach->dir != DMA_NONE)
|
||||
- dma_unmap_sg(attach->dev, sgt->sgl, sgt->nents,
|
||||
- prime_attach->dir);
|
||||
+ dma_unmap_sg_attrs(attach->dev, sgt->sgl, sgt->nents,
|
||||
+ prime_attach->dir,
|
||||
+ &attrs);
|
||||
sg_free_table(sgt);
|
||||
}
|
||||
|
||||
@@ -263,7 +266,9 @@ static struct sg_table *drm_gem_map_dma_buf(struct dma_buf_attachment *attach,
|
||||
sgt = obj->dev->driver->gem_prime_get_sg_table(obj);
|
||||
|
||||
if (!IS_ERR(sgt)) {
|
||||
- if (!dma_map_sg(attach->dev, sgt->sgl, sgt->nents, dir)) {
|
||||
+ DEFINE_DMA_ATTRS(attrs);
|
||||
+ dma_set_attr(DMA_ATTR_SKIP_CPU_SYNC, &attrs);
|
||||
+ if (!dma_map_sg_attrs(attach->dev, sgt->sgl, sgt->nents, dir, &attrs)) {
|
||||
sg_free_table(sgt);
|
||||
kfree(sgt);
|
||||
sgt = ERR_PTR(-ENOMEM);
|
||||
|
||||
From bdfc956545f8292cf462a7feee96d811f5d34414 Mon Sep 17 00:00:00 2001
|
||||
From: =?UTF-8?q?Christian=20K=C3=B6nig?= <ckoenig.leichtzumerken@gmail.com>
|
||||
Date: Tue, 27 Feb 2018 12:49:56 +0100
|
||||
Subject: [PATCH] UPSTREAM: drm/prime: fix potential race in drm_gem_map_detach
|
||||
MIME-Version: 1.0
|
||||
Content-Type: text/plain; charset=UTF-8
|
||||
Content-Transfer-Encoding: 8bit
|
||||
|
||||
Unpin the GEM object only after freeing the sg table.
|
||||
|
||||
Signed-off-by: Christian König <christian.koenig@amd.com>
|
||||
Reviewed-by: Daniel Vetter <daniel.vetter@ffwll.ch>
|
||||
Acked-by: Roger He <Hongbo.He@amd.com>
|
||||
Signed-off-by: Alex Deucher <alexander.deucher@amd.com>
|
||||
Link: https://patchwork.freedesktop.org/patch/msgid/20180227115000.4105-1-christian.koenig@amd.com
|
||||
(cherry picked from commit 681066ec1d41e4b299146bada52cef846b323c04)
|
||||
---
|
||||
drivers/gpu/drm/drm_prime.c | 36 ++++++++++++++++++------------------
|
||||
1 file changed, 18 insertions(+), 18 deletions(-)
|
||||
|
||||
diff --git a/drivers/gpu/drm/drm_prime.c b/drivers/gpu/drm/drm_prime.c
|
||||
index 133362279591..95ecc69d03a0 100644
|
||||
--- a/drivers/gpu/drm/drm_prime.c
|
||||
+++ b/drivers/gpu/drm/drm_prime.c
|
||||
@@ -193,28 +193,28 @@ static void drm_gem_map_detach(struct dma_buf *dma_buf,
|
||||
struct drm_prime_attachment *prime_attach = attach->priv;
|
||||
struct drm_gem_object *obj = dma_buf->priv;
|
||||
struct drm_device *dev = obj->dev;
|
||||
- struct sg_table *sgt;
|
||||
-
|
||||
- if (dev->driver->gem_prime_unpin)
|
||||
- dev->driver->gem_prime_unpin(obj);
|
||||
|
||||
- if (!prime_attach)
|
||||
- return;
|
||||
+ if (prime_attach) {
|
||||
+ struct sg_table *sgt = prime_attach->sgt;
|
||||
+
|
||||
+ if (sgt) {
|
||||
+ DEFINE_DMA_ATTRS(attrs);
|
||||
+ dma_set_attr(DMA_ATTR_SKIP_CPU_SYNC, &attrs);
|
||||
+ if (prime_attach->dir != DMA_NONE)
|
||||
+ dma_unmap_sg_attrs(attach->dev, sgt->sgl,
|
||||
+ sgt->nents,
|
||||
+ prime_attach->dir,
|
||||
+ &attrs);
|
||||
+ sg_free_table(sgt);
|
||||
+ }
|
||||
|
||||
- sgt = prime_attach->sgt;
|
||||
- if (sgt) {
|
||||
- DEFINE_DMA_ATTRS(attrs);
|
||||
- dma_set_attr(DMA_ATTR_SKIP_CPU_SYNC, &attrs);
|
||||
- if (prime_attach->dir != DMA_NONE)
|
||||
- dma_unmap_sg_attrs(attach->dev, sgt->sgl, sgt->nents,
|
||||
- prime_attach->dir,
|
||||
- &attrs);
|
||||
- sg_free_table(sgt);
|
||||
+ kfree(sgt);
|
||||
+ kfree(prime_attach);
|
||||
+ attach->priv = NULL;
|
||||
}
|
||||
|
||||
- kfree(sgt);
|
||||
- kfree(prime_attach);
|
||||
- attach->priv = NULL;
|
||||
+ if (dev->driver->gem_prime_unpin)
|
||||
+ dev->driver->gem_prime_unpin(obj);
|
||||
}
|
||||
|
||||
void drm_prime_remove_buf_handle_locked(struct drm_prime_file_private *prime_fpriv,
|
||||
|
||||
From 54f13f6370c654d59a9a5938e5953888a65c1980 Mon Sep 17 00:00:00 2001
|
||||
From: =?UTF-8?q?Christian=20K=C3=B6nig?= <ckoenig.leichtzumerken@gmail.com>
|
||||
Date: Tue, 27 Feb 2018 12:49:57 +0100
|
||||
Subject: [PATCH] UPSTREAM: drm/prime: make the pages array optional for
|
||||
drm_prime_sg_to_page_addr_arrays
|
||||
MIME-Version: 1.0
|
||||
Content-Type: text/plain; charset=UTF-8
|
||||
Content-Transfer-Encoding: 8bit
|
||||
|
||||
Most of the time we only need the dma addresses.
|
||||
|
||||
Signed-off-by: Christian König <christian.koenig@amd.com>
|
||||
Reviewed-by: Roger He <Hongbo.He@amd.com>
|
||||
Signed-off-by: Alex Deucher <alexander.deucher@amd.com>
|
||||
Link: https://patchwork.freedesktop.org/patch/msgid/20180227115000.4105-2-christian.koenig@amd.com
|
||||
Link: https://patchwork.freedesktop.org/patch/msgid/20180227115000.4105-3-christian.koenig@amd.com
|
||||
Link: https://patchwork.freedesktop.org/patch/msgid/20180227115000.4105-4-christian.koenig@amd.com
|
||||
Link: https://patchwork.freedesktop.org/patch/msgid/20180227115000.4105-5-christian.koenig@amd.com
|
||||
Link: https://patchwork.freedesktop.org/patch/msgid/BN6PR12MB18262C0DE9B5F07B9A42EAE7F2C60@BN6PR12MB1826.namprd12.prod.outlook.com
|
||||
(cherry picked from commit 186ca446aea19e49d2e1433dd170c6e1c211a52a)
|
||||
---
|
||||
drivers/gpu/drm/drm_prime.c | 20 ++++++++++----------
|
||||
1 file changed, 10 insertions(+), 10 deletions(-)
|
||||
|
||||
diff --git a/drivers/gpu/drm/drm_prime.c b/drivers/gpu/drm/drm_prime.c
|
||||
index 95ecc69d03a0..7ea65c4105c1 100644
|
||||
--- a/drivers/gpu/drm/drm_prime.c
|
||||
+++ b/drivers/gpu/drm/drm_prime.c
|
||||
@@ -827,40 +827,40 @@ EXPORT_SYMBOL(drm_prime_pages_to_sg);
|
||||
/**
|
||||
* drm_prime_sg_to_page_addr_arrays - convert an sg table into a page array
|
||||
* @sgt: scatter-gather table to convert
|
||||
- * @pages: array of page pointers to store the page array in
|
||||
+ * @pages: optional array of page pointers to store the page array in
|
||||
* @addrs: optional array to store the dma bus address of each page
|
||||
- * @max_pages: size of both the passed-in arrays
|
||||
+ * @max_entries: size of both the passed-in arrays
|
||||
*
|
||||
* Exports an sg table into an array of pages and addresses. This is currently
|
||||
* required by the TTM driver in order to do correct fault handling.
|
||||
*/
|
||||
int drm_prime_sg_to_page_addr_arrays(struct sg_table *sgt, struct page **pages,
|
||||
- dma_addr_t *addrs, int max_pages)
|
||||
+ dma_addr_t *addrs, int max_entries)
|
||||
{
|
||||
unsigned count;
|
||||
struct scatterlist *sg;
|
||||
struct page *page;
|
||||
- u32 len;
|
||||
- int pg_index;
|
||||
+ u32 len, index;
|
||||
dma_addr_t addr;
|
||||
|
||||
- pg_index = 0;
|
||||
+ index = 0;
|
||||
for_each_sg(sgt->sgl, sg, sgt->nents, count) {
|
||||
len = sg->length;
|
||||
page = sg_page(sg);
|
||||
addr = sg_dma_address(sg);
|
||||
|
||||
while (len > 0) {
|
||||
- if (WARN_ON(pg_index >= max_pages))
|
||||
+ if (WARN_ON(index >= max_entries))
|
||||
return -1;
|
||||
- pages[pg_index] = page;
|
||||
+ if (pages)
|
||||
+ pages[index] = page;
|
||||
if (addrs)
|
||||
- addrs[pg_index] = addr;
|
||||
+ addrs[index] = addr;
|
||||
|
||||
page++;
|
||||
addr += PAGE_SIZE;
|
||||
len -= PAGE_SIZE;
|
||||
- pg_index++;
|
||||
+ index++;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
|
||||
From c5e39a7e46511dffadabea97e3d74310561d1ba0 Mon Sep 17 00:00:00 2001
|
||||
From: Chris Wilson <chris@chris-wilson.co.uk>
|
||||
Date: Sat, 19 Aug 2017 13:05:58 +0100
|
||||
Subject: [PATCH] UPSTREAM: drm: Release driver tracking before making the
|
||||
object available again
|
||||
MIME-Version: 1.0
|
||||
Content-Type: text/plain; charset=UTF-8
|
||||
Content-Transfer-Encoding: 8bit
|
||||
|
||||
This is the same bug as we fixed in commit f6cd7daecff5 ("drm: Release
|
||||
driver references to handle before making it available again"), but now
|
||||
the exposure is via the PRIME lookup tables. If we remove the
|
||||
object/handle from the PRIME lut, then a new request for the same
|
||||
object/fd will generate a new handle, thus for a short window that
|
||||
object is known to userspace by two different handles. Fix this by
|
||||
releasing the driver tracking before PRIME.
|
||||
|
||||
Fixes: 0ff926c7d4f0 ("drm/prime: add exported buffers to current fprivs
|
||||
imported buffer list (v2)")
|
||||
Signed-off-by: Chris Wilson <chris@chris-wilson.co.uk>
|
||||
Cc: David Airlie <airlied@linux.ie>
|
||||
Cc: Daniel Vetter <daniel.vetter@intel.com>
|
||||
Cc: Rob Clark <robdclark@gmail.com>
|
||||
Cc: Ville Syrjälä <ville.syrjala@linux.intel.com>
|
||||
Cc: Thierry Reding <treding@nvidia.com>
|
||||
Cc: stable@vger.kernel.org
|
||||
Reviewed-by: Daniel Vetter <daniel.vetter@ffwll.ch>
|
||||
Signed-off-by: Joonas Lahtinen <joonas.lahtinen@linux.intel.com>
|
||||
Link: https://patchwork.freedesktop.org/patch/msgid/20170819120558.6465-1-chris@chris-wilson.co.uk
|
||||
(cherry picked from commit d0a133f7f5bc3583e460ba6bb54474a50ada5201)
|
||||
---
|
||||
drivers/gpu/drm/drm_gem.c | 6 +++---
|
||||
1 file changed, 3 insertions(+), 3 deletions(-)
|
||||
|
||||
diff --git a/drivers/gpu/drm/drm_gem.c b/drivers/gpu/drm/drm_gem.c
|
||||
index d7f39a03c2c9..966ea63581b1 100644
|
||||
--- a/drivers/gpu/drm/drm_gem.c
|
||||
+++ b/drivers/gpu/drm/drm_gem.c
|
||||
@@ -255,13 +255,13 @@ drm_gem_object_release_handle(int id, void *ptr, void *data)
|
||||
struct drm_gem_object *obj = ptr;
|
||||
struct drm_device *dev = obj->dev;
|
||||
|
||||
+ if (dev->driver->gem_close_object)
|
||||
+ dev->driver->gem_close_object(obj, file_priv);
|
||||
+
|
||||
if (drm_core_check_feature(dev, DRIVER_PRIME))
|
||||
drm_gem_remove_prime_handles(obj, file_priv);
|
||||
drm_vma_node_revoke(&obj->vma_node, file_priv->filp);
|
||||
|
||||
- if (dev->driver->gem_close_object)
|
||||
- dev->driver->gem_close_object(obj, file_priv);
|
||||
-
|
||||
drm_gem_object_handle_unreference_unlocked(obj);
|
||||
|
||||
return 0;
|
||||
|
||||
From 42f26aa9c8d429886b0af174b740f72741e571e2 Mon Sep 17 00:00:00 2001
|
||||
From: Jonas Karlman <jonas@kwiboo.se>
|
||||
Date: Sat, 17 Feb 2018 05:30:36 +0100
|
||||
Subject: [PATCH] vcodec: skip reduce freq
|
||||
|
||||
---
|
||||
drivers/video/rockchip/vcodec/vcodec_service.c | 4 +---
|
||||
1 file changed, 1 insertion(+), 3 deletions(-)
|
||||
|
||||
diff --git a/drivers/video/rockchip/vcodec/vcodec_service.c b/drivers/video/rockchip/vcodec/vcodec_service.c
|
||||
index 0f177d9ab4c2..903ea8554649 100644
|
||||
--- a/drivers/video/rockchip/vcodec/vcodec_service.c
|
||||
+++ b/drivers/video/rockchip/vcodec/vcodec_service.c
|
||||
@@ -1602,9 +1602,6 @@ static void try_set_reg(struct vpu_subdev_data *data)
|
||||
reg_from_wait_to_run(pservice, reg);
|
||||
reg_copy_to_hw(reg->data, reg);
|
||||
}
|
||||
- } else {
|
||||
- if (pservice->hw_ops->reduce_freq)
|
||||
- pservice->hw_ops->reduce_freq(pservice);
|
||||
}
|
||||
|
||||
mutex_unlock(&pservice->shutdown_lock);
|
||||
@@ -2353,6 +2350,7 @@ static void vcodec_set_freq_rk3328(struct vpu_service_info *pservice,
|
||||
if (curr == reg->freq)
|
||||
return;
|
||||
|
||||
+ atomic_set(&pservice->freq_status, reg->freq);
|
||||
if (pservice->dev_id == VCODEC_DEVICE_ID_RKVDEC) {
|
||||
if (reg->reg[1] & 0x00800000) {
|
||||
if (rkv_dec_get_fmt(reg->reg) == FMT_H264D)
|
|
@ -1,26 +0,0 @@
|
|||
diff --git a/arch/arm/boot/dts/rk3288.dtsi b/arch/arm/boot/dts/rk3288.dtsi
|
||||
index 4a428bf..6708434 100644
|
||||
--- a/arch/arm/boot/dts/rk3288.dtsi
|
||||
+++ b/arch/arm/boot/dts/rk3288.dtsi
|
||||
@@ -597,7 +615,7 @@
|
||||
type = "passive";
|
||||
};
|
||||
target: trip-point@1 {
|
||||
- temperature = <85000>; /* millicelsius */
|
||||
+ temperature = <80000>; /* millicelsius */
|
||||
hysteresis = <2000>; /* millicelsius */
|
||||
type = "passive";
|
||||
};
|
||||
diff --git a/arch/arm/boot/dts/rk3288-miniarm.dts b/arch/arm/boot/dts/rk3288-miniarm.dts
|
||||
index de6c4a6..30f0c46 100644
|
||||
--- a/arch/arm/boot/dts/rk3288-miniarm.dts
|
||||
+++ b/arch/arm/boot/dts/rk3288-miniarm.dts
|
||||
@@ -42,7 +42,7 @@
|
||||
#include <dt-bindings/clock/rockchip,rk808.h>
|
||||
#include "rk3288.dtsi"
|
||||
#include "rk3288-rkisp1.dtsi"
|
||||
-#include "rk3288-linux.dtsi"
|
||||
+#include "rk3288cg-opp.dtsi"
|
||||
|
||||
/ {
|
||||
compatible = "rockchip,rk3288-miniarm", "rockchip,rk3288";
|
|
@ -1,13 +0,0 @@
|
|||
diff --git a/arch/arm/boot/dts/rk3288-miniarm.dts b/arch/arm/boot/dts/rk3288-miniarm.dts
|
||||
index 16995ca..553f091 100644
|
||||
--- a/arch/arm/boot/dts/rk3288-miniarm.dts
|
||||
+++ b/arch/arm/boot/dts/rk3288-miniarm.dts
|
||||
@@ -70,7 +70,7 @@
|
||||
wireless-wlan {
|
||||
compatible = "wlan-platdata";
|
||||
rockchip,grf = <&grf>;
|
||||
- wifi_chip_type = "ap6212";
|
||||
+ wifi_chip_type = "8723bs";
|
||||
sdio_vref = <1800>;
|
||||
WIFI,host_wake_irq = <&gpio4 30 GPIO_ACTIVE_HIGH>;
|
||||
status = "okay";
|
|
@ -1,13 +0,0 @@
|
|||
diff --git a/arch/arm/boot/dts/rk3288-miniarm.dts b/arch/arm/boot/dts/rk3288-miniarm.dts
|
||||
index 553f091..de6c4a6 100644
|
||||
--- a/arch/arm/boot/dts/rk3288-miniarm.dts
|
||||
+++ b/arch/arm/boot/dts/rk3288-miniarm.dts
|
||||
@@ -134,7 +134,7 @@
|
||||
|
||||
led1-led {
|
||||
gpios=<&gpio1 25 GPIO_ACTIVE_HIGH>;
|
||||
- linux,default-trigger="default-off";
|
||||
+ linux,default-trigger="heartbeat";
|
||||
};
|
||||
};
|
||||
|
|
@ -1,426 +0,0 @@
|
|||
From f875ad99fe6d44c7683954b3023209d3d84dbf2d Mon Sep 17 00:00:00 2001
|
||||
From: andy_chi <andy_chi@asus.com>
|
||||
Date: Wed, 21 Jun 2017 15:52:19 +0800
|
||||
Subject: [PATCH] Enable a simple user-space driven DT overlay interface
|
||||
|
||||
Change-Id: I6e9f71d8b46df65abd698378b8994988c7fa5651
|
||||
---
|
||||
drivers/of/Kconfig | 7 +
|
||||
drivers/of/Makefile | 1 +
|
||||
drivers/of/dtbocfg.c | 381 +++++++++++++++++++++++++++++++++++++++++++++++++++
|
||||
3 files changed, 389 insertions(+)
|
||||
create mode 100644 drivers/of/dtbocfg.c
|
||||
|
||||
diff --git a/drivers/of/Kconfig b/drivers/of/Kconfig
|
||||
index e2a48415d969..7e5e6c4e77e0 100644
|
||||
--- a/drivers/of/Kconfig
|
||||
+++ b/drivers/of/Kconfig
|
||||
@@ -112,4 +112,11 @@ config OF_OVERLAY
|
||||
While this option is selected automatically when needed, you can
|
||||
enable it manually to improve device tree unit test coverage.
|
||||
|
||||
+config OF_CONFIGFS
|
||||
+ bool "Device Tree Overlay ConfigFS interface"
|
||||
+ select CONFIGFS_FS
|
||||
+ select OF_OVERLAY
|
||||
+ help
|
||||
+ Enable a simple user-space driven DT overlay interface.
|
||||
+
|
||||
endif # OF
|
||||
diff --git a/drivers/of/Makefile b/drivers/of/Makefile
|
||||
index 156c072b3117..413b0fe675c4 100644
|
||||
--- a/drivers/of/Makefile
|
||||
+++ b/drivers/of/Makefile
|
||||
@@ -1,4 +1,5 @@
|
||||
obj-y = base.o device.o platform.o property.o
|
||||
+obj-$(CONFIG_OF_CONFIGFS) += dtbocfg.o
|
||||
obj-$(CONFIG_OF_DYNAMIC) += dynamic.o
|
||||
obj-$(CONFIG_OF_FLATTREE) += fdt.o
|
||||
obj-$(CONFIG_OF_EARLY_FLATTREE) += fdt_address.o
|
||||
diff --git a/drivers/of/dtbocfg.c b/drivers/of/dtbocfg.c
|
||||
new file mode 100644
|
||||
index 000000000000..1f715ea3895c
|
||||
--- /dev/null
|
||||
+++ b/drivers/of/dtbocfg.c
|
||||
@@ -0,0 +1,381 @@
|
||||
+/*********************************************************************************
|
||||
+ *
|
||||
+ * Copyright (C) 2016-2017 Ichiro Kawazome
|
||||
+ * All rights reserved.
|
||||
+ *
|
||||
+ * Redistribution and use in source and binary forms, with or without
|
||||
+ * modification, are permitted provided that the following conditions
|
||||
+ * are met:
|
||||
+ *
|
||||
+ * 1. Redistributions of source code must retain the above copyright
|
||||
+ * notice, this list of conditions and the following disclaimer.
|
||||
+ *
|
||||
+ * 2. Redistributions in binary form must reproduce the above copyright
|
||||
+ * notice, this list of conditions and the following disclaimer in
|
||||
+ * the documentation and/or other materials provided with the
|
||||
+ * distribution.
|
||||
+ *
|
||||
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
+ *
|
||||
+ ********************************************************************************/
|
||||
+#include <linux/slab.h>
|
||||
+#include <linux/module.h>
|
||||
+#include <linux/of.h>
|
||||
+#include <linux/of_fdt.h>
|
||||
+#include <linux/configfs.h>
|
||||
+#include <linux/types.h>
|
||||
+#include <linux/stat.h>
|
||||
+#include <linux/limits.h>
|
||||
+#include <linux/file.h>
|
||||
+#include <linux/version.h>
|
||||
+
|
||||
+/**
|
||||
+ * Device Tree Overlay Item Structure
|
||||
+ */
|
||||
+struct dtbocfg_overlay_item {
|
||||
+ struct config_item item;
|
||||
+ struct device_node* node;
|
||||
+ int id;
|
||||
+ void* dtbo;
|
||||
+ int dtbo_size;
|
||||
+};
|
||||
+
|
||||
+/**
|
||||
+ * dtbocfg_overlay_create() - Create Device Tree Overlay
|
||||
+ * @overlay: Pointer to Device Tree Overlay Item
|
||||
+ * return Success(0) or Error Status.
|
||||
+ */
|
||||
+static int dtbocfg_overlay_item_create(struct dtbocfg_overlay_item *overlay)
|
||||
+{
|
||||
+ int ret_val;
|
||||
+
|
||||
+#if (LINUX_VERSION_CODE >= 0x040700)
|
||||
+ of_fdt_unflatten_tree(overlay->dtbo, NULL, &overlay->node);
|
||||
+#else
|
||||
+ of_fdt_unflatten_tree(overlay->dtbo, &overlay->node);
|
||||
+#endif
|
||||
+ if (overlay->node == NULL) {
|
||||
+ pr_err("%s: failed to unflatten tree\n", __func__);
|
||||
+ ret_val = -EINVAL;
|
||||
+ goto failed;
|
||||
+ }
|
||||
+ pr_debug("%s: unflattened OK\n", __func__);
|
||||
+
|
||||
+ of_node_set_flag(overlay->node, OF_DETACHED);
|
||||
+
|
||||
+ ret_val = of_resolve_phandles(overlay->node);
|
||||
+ if (ret_val != 0) {
|
||||
+ pr_err("%s: Failed to resolve tree\n", __func__);
|
||||
+ goto failed;
|
||||
+ }
|
||||
+ pr_debug("%s: resolved OK\n", __func__);
|
||||
+
|
||||
+ ret_val = of_overlay_create(overlay->node);
|
||||
+ if (ret_val < 0) {
|
||||
+ pr_err("%s: Failed to create overlay (ret_val=%d)\n", __func__, ret_val);
|
||||
+ goto failed;
|
||||
+ }
|
||||
+ overlay->id = ret_val;
|
||||
+ pr_debug("%s: create OK\n", __func__);
|
||||
+ return 0;
|
||||
+
|
||||
+ failed:
|
||||
+ return ret_val;
|
||||
+}
|
||||
+
|
||||
+/**
|
||||
+ * dtbocfg_overlay_item_release() - Relase Device Tree Overlay
|
||||
+ * @overlay: Pointer to Device Tree Overlay Item
|
||||
+ * return none
|
||||
+ */
|
||||
+static void dtbocfg_overlay_item_release(struct dtbocfg_overlay_item *overlay)
|
||||
+{
|
||||
+ if (overlay->id >= 0) {
|
||||
+ of_overlay_destroy(overlay->id);
|
||||
+ overlay->id = -1;
|
||||
+ }
|
||||
+}
|
||||
+
|
||||
+/**
|
||||
+ * container_of_dtbocfg_overlay_item() - Get Device Tree Overlay Item Pointer from Configuration Item
|
||||
+ * @item: Pointer to Configuration Item
|
||||
+ * return Pointer to Device Tree Overlay Item
|
||||
+ */
|
||||
+static inline struct dtbocfg_overlay_item* container_of_dtbocfg_overlay_item(struct config_item *item)
|
||||
+{
|
||||
+ return item ? container_of(item, struct dtbocfg_overlay_item, item) : NULL;
|
||||
+}
|
||||
+
|
||||
+/**
|
||||
+ * dtbocfg_overlay_item_status_store() - Set Status Attibute
|
||||
+ * @item: Pointer to Configuration Item
|
||||
+ * @page: Pointer to Value Buffer
|
||||
+ * @count: Size of Value Buffer Size
|
||||
+ * return Stored Size or Error Status.
|
||||
+ */
|
||||
+static ssize_t dtbocfg_overlay_item_status_store(struct config_item *item, const char *buf, size_t count)
|
||||
+{
|
||||
+ struct dtbocfg_overlay_item *overlay = container_of_dtbocfg_overlay_item(item);
|
||||
+ ssize_t status;
|
||||
+ unsigned long value;
|
||||
+ if (0 != (status = kstrtoul(buf, 10, &value))) {
|
||||
+ goto failed;
|
||||
+ }
|
||||
+ if (value == 0) {
|
||||
+ if (overlay->id >= 0) {
|
||||
+ dtbocfg_overlay_item_release(overlay);
|
||||
+ }
|
||||
+ } else {
|
||||
+ if (overlay->id < 0) {
|
||||
+ dtbocfg_overlay_item_create(overlay);
|
||||
+ }
|
||||
+ }
|
||||
+ return count;
|
||||
+ failed:
|
||||
+ return -EPERM;
|
||||
+}
|
||||
+
|
||||
+/**
|
||||
+ * dtbocfg_overlay_item_status_show() - Show Status Attibute
|
||||
+ * @item : Pointer to Configuration Item
|
||||
+ * @page : Pointer to Value for Store
|
||||
+ * return String Size or Error Status.
|
||||
+ */
|
||||
+static ssize_t dtbocfg_overlay_item_status_show(struct config_item *item, char *page)
|
||||
+{
|
||||
+ struct dtbocfg_overlay_item *overlay = container_of_dtbocfg_overlay_item(item);
|
||||
+ return sprintf(page, "%d\n", overlay->id >= 0 ? 1 : 0);
|
||||
+}
|
||||
+
|
||||
+/**
|
||||
+ * dtbocfg_overlay_item_dtbo_store() - Store Device Tree Blob to Configuration Item
|
||||
+ * @item : Pointer to Configuration Item
|
||||
+ * @page : Pointer to Value Buffer
|
||||
+ * @count: Size of Value Buffer
|
||||
+ * return Stored Size or Error Status.
|
||||
+ */
|
||||
+static ssize_t dtbocfg_overlay_item_dtbo_store(struct config_item *item, const char *buf, size_t count)
|
||||
+{
|
||||
+ struct dtbocfg_overlay_item *overlay = container_of_dtbocfg_overlay_item(item);
|
||||
+
|
||||
+ if (overlay->dtbo_size > 0) {
|
||||
+ if (overlay->id >= 0) {
|
||||
+ return -EPERM;
|
||||
+ }
|
||||
+ kfree(overlay->dtbo);
|
||||
+ overlay->dtbo = NULL;
|
||||
+ overlay->dtbo_size = 0;
|
||||
+ }
|
||||
+
|
||||
+ overlay->dtbo = kmemdup(buf, count, GFP_KERNEL);
|
||||
+ if (overlay->dtbo == NULL) {
|
||||
+ overlay->dtbo_size = 0;
|
||||
+ return -ENOMEM;
|
||||
+ } else {
|
||||
+ overlay->dtbo_size = count;
|
||||
+ return count;
|
||||
+ }
|
||||
+}
|
||||
+
|
||||
+/**
|
||||
+ * dtbocfg_overlay_item_dtbo_show() - Read Device Tree Blob from Configuration Item
|
||||
+ * @item : Pointer to Configuration Item
|
||||
+ * @page : Pointer to Value for Store
|
||||
+ * return Read Size
|
||||
+ */
|
||||
+static ssize_t dtbocfg_overlay_item_dtbo_show(struct config_item *item, char *buf)
|
||||
+{
|
||||
+ struct dtbocfg_overlay_item *overlay = container_of_dtbocfg_overlay_item(item);
|
||||
+
|
||||
+ if (overlay->dtbo == NULL)
|
||||
+ return 0;
|
||||
+
|
||||
+ if (overlay->dtbo_size > PAGE_SIZE)
|
||||
+ return -EINVAL;
|
||||
+
|
||||
+ if (buf != NULL)
|
||||
+ memcpy(buf, overlay->dtbo, overlay->dtbo_size);
|
||||
+
|
||||
+ return overlay->dtbo_size;
|
||||
+}
|
||||
+
|
||||
+/**
|
||||
+ * Device Tree Blob Overlay Attribute Structure
|
||||
+ */
|
||||
+CONFIGFS_ATTR(dtbocfg_overlay_item_, dtbo );
|
||||
+CONFIGFS_ATTR(dtbocfg_overlay_item_, status);
|
||||
+
|
||||
+static struct configfs_attribute *dtbocfg_overlay_attrs[] = {
|
||||
+ &dtbocfg_overlay_item_attr_status,
|
||||
+ &dtbocfg_overlay_item_attr_dtbo,
|
||||
+ NULL,
|
||||
+};
|
||||
+
|
||||
+/**
|
||||
+ * dtbocfg_overlay_release() - Release Device Tree Overlay Item
|
||||
+ * @item : Pointer to Configuration Item
|
||||
+ * Return None
|
||||
+ */
|
||||
+static void dtbocfg_overlay_release(struct config_item *item)
|
||||
+{
|
||||
+ struct dtbocfg_overlay_item *overlay = container_of_dtbocfg_overlay_item(item);
|
||||
+
|
||||
+ pr_debug("%s\n", __func__);
|
||||
+
|
||||
+ dtbocfg_overlay_item_release(overlay);
|
||||
+
|
||||
+ if (overlay->dtbo) {
|
||||
+ kfree(overlay->dtbo);
|
||||
+ overlay->dtbo = NULL;
|
||||
+ overlay->dtbo_size = 0;
|
||||
+ }
|
||||
+
|
||||
+ kfree(overlay);
|
||||
+}
|
||||
+
|
||||
+/**
|
||||
+ * Device Tree Blob Overlay Item Structure
|
||||
+ */
|
||||
+static struct configfs_item_operations dtbocfg_overlay_item_ops = {
|
||||
+ .release = dtbocfg_overlay_release,
|
||||
+};
|
||||
+
|
||||
+static struct config_item_type dtbocfg_overlay_item_type = {
|
||||
+ .ct_item_ops = &dtbocfg_overlay_item_ops,
|
||||
+ .ct_attrs = dtbocfg_overlay_attrs,
|
||||
+ .ct_owner = THIS_MODULE,
|
||||
+};
|
||||
+
|
||||
+/**
|
||||
+ * dtbocfg_overlay_group_make_item() - Make Device Tree Overlay Group Item
|
||||
+ * @group: Pointer to Configuration Group
|
||||
+ * @name : Pointer to Group Name
|
||||
+ * Return Pointer to Device Tree Overlay Group Item
|
||||
+ */
|
||||
+static struct config_item *dtbocfg_overlay_group_make_item(struct config_group *group, const char *name)
|
||||
+{
|
||||
+ struct dtbocfg_overlay_item *overlay;
|
||||
+
|
||||
+ pr_debug("%s\n", __func__);
|
||||
+
|
||||
+ overlay = kzalloc(sizeof(*overlay), GFP_KERNEL);
|
||||
+
|
||||
+ if (!overlay)
|
||||
+ return ERR_PTR(-ENOMEM);
|
||||
+ overlay->id = -1;
|
||||
+ overlay->dtbo = NULL;
|
||||
+ overlay->dtbo_size = 0;
|
||||
+
|
||||
+ config_item_init_type_name(&overlay->item, name, &dtbocfg_overlay_item_type);
|
||||
+ return &overlay->item;
|
||||
+}
|
||||
+
|
||||
+/**
|
||||
+ * dtbocfg_overlay_group_drop_item() - Drop Device Tree Overlay Group Item
|
||||
+ * @group: Pointer to Configuration Group
|
||||
+ * @item : Pointer to Device Tree Overlay Group Item
|
||||
+ */
|
||||
+static void dtbocfg_overlay_group_drop_item(struct config_group *group, struct config_item *item)
|
||||
+{
|
||||
+ struct dtbocfg_overlay_item *overlay = container_of_dtbocfg_overlay_item(item);
|
||||
+
|
||||
+ pr_debug("%s\n", __func__);
|
||||
+
|
||||
+ config_item_put(&overlay->item);
|
||||
+}
|
||||
+
|
||||
+/**
|
||||
+ * Device Tree Blob Overlay Sub Group Structures
|
||||
+ */
|
||||
+static struct configfs_group_operations dtbocfg_overlays_ops = {
|
||||
+ .make_item = dtbocfg_overlay_group_make_item,
|
||||
+ .drop_item = dtbocfg_overlay_group_drop_item,
|
||||
+};
|
||||
+
|
||||
+static struct config_item_type dtbocfg_overlays_type = {
|
||||
+ .ct_group_ops = &dtbocfg_overlays_ops,
|
||||
+ .ct_owner = THIS_MODULE,
|
||||
+};
|
||||
+
|
||||
+static struct config_group dtbocfg_overlay_group;
|
||||
+
|
||||
+/**
|
||||
+ * Device Tree Blob Overlay Root Sub System Structures
|
||||
+ */
|
||||
+static struct configfs_group_operations dtbocfg_root_ops = {
|
||||
+ /* empty - we don't allow anything to be created */
|
||||
+};
|
||||
+
|
||||
+static struct config_item_type dtbocfg_root_type = {
|
||||
+ .ct_group_ops = &dtbocfg_root_ops,
|
||||
+ .ct_owner = THIS_MODULE,
|
||||
+};
|
||||
+
|
||||
+static struct configfs_subsystem dtbocfg_root_subsys = {
|
||||
+ .su_group = {
|
||||
+ .cg_item = {
|
||||
+ .ci_namebuf = "device-tree",
|
||||
+ .ci_type = &dtbocfg_root_type,
|
||||
+ },
|
||||
+ },
|
||||
+ .su_mutex = __MUTEX_INITIALIZER(dtbocfg_root_subsys.su_mutex),
|
||||
+};
|
||||
+
|
||||
+/**
|
||||
+ * dtbocfg_module_init()
|
||||
+ */
|
||||
+static int __init dtbocfg_module_init(void)
|
||||
+{
|
||||
+ int retval = 0;
|
||||
+
|
||||
+ pr_info("%s\n", __func__);
|
||||
+
|
||||
+ config_group_init(&dtbocfg_root_subsys.su_group);
|
||||
+ config_group_init_type_name(&dtbocfg_overlay_group, "overlays", &dtbocfg_overlays_type);
|
||||
+
|
||||
+ retval = configfs_register_subsystem(&dtbocfg_root_subsys);
|
||||
+ if (retval != 0) {
|
||||
+ pr_err( "%s: couldn't register subsys\n", __func__);
|
||||
+ goto register_subsystem_failed;
|
||||
+ }
|
||||
+
|
||||
+ retval = configfs_register_group(&dtbocfg_root_subsys.su_group, &dtbocfg_overlay_group);
|
||||
+ if (retval != 0) {
|
||||
+ pr_err( "%s: couldn't register group\n", __func__);
|
||||
+ goto register_group_failed;
|
||||
+ }
|
||||
+
|
||||
+ pr_info("%s: OK\n", __func__);
|
||||
+ return 0;
|
||||
+
|
||||
+ register_group_failed:
|
||||
+ configfs_unregister_subsystem(&dtbocfg_root_subsys);
|
||||
+ register_subsystem_failed:
|
||||
+ return retval;
|
||||
+}
|
||||
+
|
||||
+/**
|
||||
+ * dtbocfg_module_exit()
|
||||
+ */
|
||||
+static void __exit dtbocfg_module_exit(void)
|
||||
+{
|
||||
+ configfs_unregister_group(&dtbocfg_overlay_group);
|
||||
+ configfs_unregister_subsystem(&dtbocfg_root_subsys);
|
||||
+}
|
||||
+
|
||||
+module_init(dtbocfg_module_init);
|
||||
+module_exit(dtbocfg_module_exit);
|
||||
+
|
||||
+MODULE_AUTHOR("ikwzm");
|
||||
+MODULE_DESCRIPTION("Device Tree Overlay Configuration File System");
|
||||
+MODULE_LICENSE("Dual BSD/GPL");
|
|
@ -1,13 +0,0 @@
|
|||
diff --git a/arch/arm/mm/dma-mapping.c b/arch/arm/mm/dma-mapping.c
|
||||
index bd83c53..af7cfe3
|
||||
--- a/arch/arm/mm/dma-mapping.c
|
||||
+++ b/arch/arm/mm/dma-mapping.c
|
||||
@@ -374,7 +374,7 @@ static void __dma_free_remap(void *cpu_addr, size_t size)
|
||||
VM_ARM_DMA_CONSISTENT | VM_USERMAP);
|
||||
}
|
||||
|
||||
-#define DEFAULT_DMA_COHERENT_POOL_SIZE SZ_256K
|
||||
+#define DEFAULT_DMA_COHERENT_POOL_SIZE SZ_2M
|
||||
static struct gen_pool *atomic_pool;
|
||||
|
||||
static size_t atomic_pool_size = DEFAULT_DMA_COHERENT_POOL_SIZE;
|
Loading…
Add table
Reference in a new issue