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:
Thomas McKahan 2018-08-21 00:16:59 -04:00
parent f3d0fce4bc
commit 96135c6065
20 changed files with 17035 additions and 491 deletions

View file

@ -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

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

View 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

File diff suppressed because it is too large Load diff

View 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;

View 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;

View 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);
}
/*

File diff suppressed because it is too large Load diff

View 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)

View file

@ -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";

View file

@ -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";

View file

@ -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";
};
};

View file

@ -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");

View file

@ -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;