mirror of
https://github.com/coolsnowwolf/lede.git
synced 2025-04-19 14:13:30 +00:00
rockchip: initial support for RK3576 UFS controller for 6.12
This commit is contained in:
parent
968e885b20
commit
a3a98e1233
@ -0,0 +1,138 @@
|
||||
Document Rockchip UFS host controller for RK3576 SoC.
|
||||
|
||||
Reviewed-by: Krzysztof Kozlowski <krzysztof.kozlowski@linaro.org>
|
||||
Signed-off-by: Shawn Lin <shawn.lin@rock-chips.com>
|
||||
---
|
||||
|
||||
Changes in v5:
|
||||
- use ufshc for devicetree example suggested by Mani
|
||||
|
||||
Changes in v4:
|
||||
- properly describe reset-gpios
|
||||
|
||||
Changes in v3:
|
||||
- rename the file to rockchip,rk3576-ufshc.yaml
|
||||
- add description for reset-gpios
|
||||
- use rockchip,rk3576-ufshc as compatible
|
||||
|
||||
Changes in v2:
|
||||
- rename the file
|
||||
- add reset-gpios
|
||||
|
||||
.../bindings/ufs/rockchip,rk3576-ufshc.yaml | 105 +++++++++++++++++++++
|
||||
1 file changed, 105 insertions(+)
|
||||
create mode 100644 Documentation/devicetree/bindings/ufs/rockchip,rk3576-ufshc.yaml
|
||||
|
||||
diff --git a/Documentation/devicetree/bindings/ufs/rockchip,rk3576-ufshc.yaml b/Documentation/devicetree/bindings/ufs/rockchip,rk3576-ufshc.yaml
|
||||
new file mode 100644
|
||||
index 0000000..7d6c038
|
||||
--- /dev/null
|
||||
+++ b/Documentation/devicetree/bindings/ufs/rockchip,rk3576-ufshc.yaml
|
||||
@@ -0,0 +1,105 @@
|
||||
+# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
|
||||
+%YAML 1.2
|
||||
+---
|
||||
+$id: http://devicetree.org/schemas/ufs/rockchip,rk3576-ufshc.yaml#
|
||||
+$schema: http://devicetree.org/meta-schemas/core.yaml#
|
||||
+
|
||||
+title: Rockchip UFS Host Controller
|
||||
+
|
||||
+maintainers:
|
||||
+ - Shawn Lin <shawn.lin@rock-chips.com>
|
||||
+
|
||||
+allOf:
|
||||
+ - $ref: ufs-common.yaml
|
||||
+
|
||||
+properties:
|
||||
+ compatible:
|
||||
+ const: rockchip,rk3576-ufshc
|
||||
+
|
||||
+ reg:
|
||||
+ maxItems: 5
|
||||
+
|
||||
+ reg-names:
|
||||
+ items:
|
||||
+ - const: hci
|
||||
+ - const: mphy
|
||||
+ - const: hci_grf
|
||||
+ - const: mphy_grf
|
||||
+ - const: hci_apb
|
||||
+
|
||||
+ clocks:
|
||||
+ maxItems: 4
|
||||
+
|
||||
+ clock-names:
|
||||
+ items:
|
||||
+ - const: core
|
||||
+ - const: pclk
|
||||
+ - const: pclk_mphy
|
||||
+ - const: ref_out
|
||||
+
|
||||
+ power-domains:
|
||||
+ maxItems: 1
|
||||
+
|
||||
+ resets:
|
||||
+ maxItems: 4
|
||||
+
|
||||
+ reset-names:
|
||||
+ items:
|
||||
+ - const: biu
|
||||
+ - const: sys
|
||||
+ - const: ufs
|
||||
+ - const: grf
|
||||
+
|
||||
+ reset-gpios:
|
||||
+ maxItems: 1
|
||||
+ description: |
|
||||
+ GPIO specifiers for host to reset the whole UFS device including PHY and
|
||||
+ memory. This gpio is active low and should choose the one whose high output
|
||||
+ voltage is lower than 1.5V based on the UFS spec.
|
||||
+
|
||||
+required:
|
||||
+ - compatible
|
||||
+ - reg
|
||||
+ - reg-names
|
||||
+ - clocks
|
||||
+ - clock-names
|
||||
+ - interrupts
|
||||
+ - power-domains
|
||||
+ - resets
|
||||
+ - reset-names
|
||||
+ - reset-gpios
|
||||
+
|
||||
+unevaluatedProperties: false
|
||||
+
|
||||
+examples:
|
||||
+ - |
|
||||
+ #include <dt-bindings/clock/rockchip,rk3576-cru.h>
|
||||
+ #include <dt-bindings/reset/rockchip,rk3576-cru.h>
|
||||
+ #include <dt-bindings/interrupt-controller/arm-gic.h>
|
||||
+ #include <dt-bindings/power/rockchip,rk3576-power.h>
|
||||
+ #include <dt-bindings/pinctrl/rockchip.h>
|
||||
+ #include <dt-bindings/gpio/gpio.h>
|
||||
+
|
||||
+ soc {
|
||||
+ #address-cells = <2>;
|
||||
+ #size-cells = <2>;
|
||||
+
|
||||
+ ufshc: ufshc@2a2d0000 {
|
||||
+ compatible = "rockchip,rk3576-ufshc";
|
||||
+ reg = <0x0 0x2a2d0000 0x0 0x10000>,
|
||||
+ <0x0 0x2b040000 0x0 0x10000>,
|
||||
+ <0x0 0x2601f000 0x0 0x1000>,
|
||||
+ <0x0 0x2603c000 0x0 0x1000>,
|
||||
+ <0x0 0x2a2e0000 0x0 0x10000>;
|
||||
+ reg-names = "hci", "mphy", "hci_grf", "mphy_grf", "hci_apb";
|
||||
+ clocks = <&cru ACLK_UFS_SYS>, <&cru PCLK_USB_ROOT>, <&cru PCLK_MPHY>,
|
||||
+ <&cru CLK_REF_UFS_CLKOUT>;
|
||||
+ clock-names = "core", "pclk", "pclk_mphy", "ref_out";
|
||||
+ interrupts = <GIC_SPI 361 IRQ_TYPE_LEVEL_HIGH>;
|
||||
+ power-domains = <&power RK3576_PD_USB>;
|
||||
+ resets = <&cru SRST_A_UFS_BIU>, <&cru SRST_A_UFS_SYS>, <&cru SRST_A_UFS>,
|
||||
+ <&cru SRST_P_UFS_GRF>;
|
||||
+ reset-names = "biu", "sys", "ufs", "grf";
|
||||
+ reset-gpios = <&gpio4 RK_PD0 GPIO_ACTIVE_LOW>;
|
||||
+ };
|
||||
+ };
|
||||
--
|
||||
2.7.4
|
@ -0,0 +1,31 @@
|
||||
Add ROCKCHIP_SIP_SUSPEND_MODE to pass down parameters to Trusted Firmware
|
||||
in order to decide suspend mode. Currently only add ROCKCHIP_SLEEP_PD_CONFIG
|
||||
which teaches firmware to power down controllers or not.
|
||||
|
||||
Signed-off-by: Shawn Lin <shawn.lin@rock-chips.com>
|
||||
---
|
||||
|
||||
Changes in v5: None
|
||||
Changes in v4: None
|
||||
Changes in v3: None
|
||||
Changes in v2: None
|
||||
|
||||
include/soc/rockchip/rockchip_sip.h | 3 +++
|
||||
1 file changed, 3 insertions(+)
|
||||
|
||||
diff --git a/include/soc/rockchip/rockchip_sip.h b/include/soc/rockchip/rockchip_sip.h
|
||||
index c46a9ae..501ad1f 100644
|
||||
--- a/include/soc/rockchip/rockchip_sip.h
|
||||
+++ b/include/soc/rockchip/rockchip_sip.h
|
||||
@@ -6,6 +6,9 @@
|
||||
#ifndef __SOC_ROCKCHIP_SIP_H
|
||||
#define __SOC_ROCKCHIP_SIP_H
|
||||
|
||||
+#define ROCKCHIP_SIP_SUSPEND_MODE 0x82000003
|
||||
+#define ROCKCHIP_SLEEP_PD_CONFIG 0xff
|
||||
+
|
||||
#define ROCKCHIP_SIP_DRAM_FREQ 0x82000008
|
||||
#define ROCKCHIP_SIP_CONFIG_DRAM_INIT 0x00
|
||||
#define ROCKCHIP_SIP_CONFIG_DRAM_SET_RATE 0x01
|
||||
--
|
||||
2.7.4
|
@ -0,0 +1,110 @@
|
||||
From: Ulf Hansson <ulf.hansson@linaro.org>
|
||||
|
||||
For some usecases a consumer driver requires its device to remain power-on
|
||||
from the PM domain perspective during runtime. Using dev PM qos along with
|
||||
the genpd governors, doesn't work for this case as would potentially
|
||||
prevent the device from being runtime suspended too.
|
||||
|
||||
To support these usecases, let's introduce dev_pm_genpd_rpm_always_on() to
|
||||
allow consumers drivers to dynamically control the behaviour in genpd for a
|
||||
device that is attached to it.
|
||||
|
||||
Signed-off-by: Ulf Hansson <ulf.hansson@linaro.org>
|
||||
Signed-off-by: Shawn Lin <shawn.lin@rock-chips.com>
|
||||
---
|
||||
|
||||
Changes in v5: None
|
||||
Changes in v4: None
|
||||
Changes in v3: None
|
||||
Changes in v2: None
|
||||
|
||||
drivers/pmdomain/core.c | 34 ++++++++++++++++++++++++++++++++++
|
||||
include/linux/pm_domain.h | 7 +++++++
|
||||
2 files changed, 41 insertions(+)
|
||||
|
||||
diff --git a/drivers/pmdomain/core.c b/drivers/pmdomain/core.c
|
||||
index 5ede0f7..2ccfcb7 100644
|
||||
--- a/drivers/pmdomain/core.c
|
||||
+++ b/drivers/pmdomain/core.c
|
||||
@@ -692,6 +692,36 @@ bool dev_pm_genpd_get_hwmode(struct device *dev)
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(dev_pm_genpd_get_hwmode);
|
||||
|
||||
+/**
|
||||
+ * dev_pm_genpd_rpm_always_on() - Control if the PM domain can be powered off.
|
||||
+ *
|
||||
+ * @dev: Device for which the PM domain may need to stay on for.
|
||||
+ * @on: Value to set or unset for the condition.
|
||||
+ *
|
||||
+ * For some usecases a consumer driver requires its device to remain power-on
|
||||
+ * from the PM domain perspective during runtime. This function allows the
|
||||
+ * behaviour to be dynamically controlled for a device attached to a genpd.
|
||||
+ *
|
||||
+ * It is assumed that the users guarantee that the genpd wouldn't be detached
|
||||
+ * while this routine is getting called.
|
||||
+ *
|
||||
+ * Return: Returns 0 on success and negative error values on failures.
|
||||
+ */
|
||||
+int dev_pm_genpd_rpm_always_on(struct device *dev, bool on)
|
||||
+{
|
||||
+ struct generic_pm_domain *genpd;
|
||||
+
|
||||
+ genpd = dev_to_genpd_safe(dev);
|
||||
+ if (!genpd)
|
||||
+ return -ENODEV;
|
||||
+
|
||||
+ genpd_lock(genpd);
|
||||
+ dev_gpd_data(dev)->rpm_always_on = on;
|
||||
+ genpd_unlock(genpd);
|
||||
+
|
||||
+ return 0;
|
||||
+}
|
||||
+
|
||||
static int _genpd_power_on(struct generic_pm_domain *genpd, bool timed)
|
||||
{
|
||||
unsigned int state_idx = genpd->state_idx;
|
||||
@@ -863,6 +893,10 @@ static int genpd_power_off(struct generic_pm_domain *genpd, bool one_dev_on,
|
||||
if (!pm_runtime_suspended(pdd->dev) ||
|
||||
irq_safe_dev_in_sleep_domain(pdd->dev, genpd))
|
||||
not_suspended++;
|
||||
+
|
||||
+ /* The device may need its PM domain to stay powered on. */
|
||||
+ if (to_gpd_data(pdd)->rpm_always_on)
|
||||
+ return -EBUSY;
|
||||
}
|
||||
|
||||
if (not_suspended > 1 || (not_suspended == 1 && !one_dev_on))
|
||||
diff --git a/include/linux/pm_domain.h b/include/linux/pm_domain.h
|
||||
index b637ec1..30186ad 100644
|
||||
--- a/include/linux/pm_domain.h
|
||||
+++ b/include/linux/pm_domain.h
|
||||
@@ -245,6 +245,7 @@ struct generic_pm_domain_data {
|
||||
unsigned int default_pstate;
|
||||
unsigned int rpm_pstate;
|
||||
bool hw_mode;
|
||||
+ bool rpm_always_on;
|
||||
void *data;
|
||||
};
|
||||
|
||||
@@ -277,6 +278,7 @@ ktime_t dev_pm_genpd_get_next_hrtimer(struct device *dev);
|
||||
void dev_pm_genpd_synced_poweroff(struct device *dev);
|
||||
int dev_pm_genpd_set_hwmode(struct device *dev, bool enable);
|
||||
bool dev_pm_genpd_get_hwmode(struct device *dev);
|
||||
+int dev_pm_genpd_rpm_always_on(struct device *dev, bool on);
|
||||
|
||||
extern struct dev_power_governor simple_qos_governor;
|
||||
extern struct dev_power_governor pm_domain_always_on_gov;
|
||||
@@ -360,6 +362,11 @@ static inline bool dev_pm_genpd_get_hwmode(struct device *dev)
|
||||
return false;
|
||||
}
|
||||
|
||||
+static inline int dev_pm_genpd_rpm_always_on(struct device *dev, bool on)
|
||||
+{
|
||||
+ return -EOPNOTSUPP;
|
||||
+}
|
||||
+
|
||||
#define simple_qos_governor (*(struct dev_power_governor *)(NULL))
|
||||
#define pm_domain_always_on_gov (*(struct dev_power_governor *)(NULL))
|
||||
#endif
|
||||
--
|
||||
2.7.4
|
@ -0,0 +1,58 @@
|
||||
Inform firmware to keep the power domain on or off.
|
||||
|
||||
Suggested-by: Ulf Hansson <ulf.hansson@linaro.org>
|
||||
Signed-off-by: Shawn Lin <shawn.lin@rock-chips.com>
|
||||
---
|
||||
|
||||
Changes in v5:
|
||||
- fix a compile warning
|
||||
|
||||
Changes in v4: None
|
||||
Changes in v3: None
|
||||
Changes in v2: None
|
||||
|
||||
drivers/pmdomain/rockchip/pm-domains.c | 8 ++++++++
|
||||
1 file changed, 8 insertions(+)
|
||||
|
||||
diff --git a/drivers/pmdomain/rockchip/pm-domains.c b/drivers/pmdomain/rockchip/pm-domains.c
|
||||
index cb0f938..49842f1 100644
|
||||
--- a/drivers/pmdomain/rockchip/pm-domains.c
|
||||
+++ b/drivers/pmdomain/rockchip/pm-domains.c
|
||||
@@ -5,6 +5,7 @@
|
||||
* Copyright (c) 2015 ROCKCHIP, Co. Ltd.
|
||||
*/
|
||||
|
||||
+#include <linux/arm-smccc.h>
|
||||
#include <linux/io.h>
|
||||
#include <linux/iopoll.h>
|
||||
#include <linux/err.h>
|
||||
@@ -20,6 +21,7 @@
|
||||
#include <linux/regmap.h>
|
||||
#include <linux/mfd/syscon.h>
|
||||
#include <soc/rockchip/pm_domains.h>
|
||||
+#include <soc/rockchip/rockchip_sip.h>
|
||||
#include <dt-bindings/power/px30-power.h>
|
||||
#include <dt-bindings/power/rockchip,rv1126-power.h>
|
||||
#include <dt-bindings/power/rk3036-power.h>
|
||||
@@ -540,6 +542,7 @@ static void rockchip_do_pmu_set_power_domain(struct rockchip_pm_domain *pd,
|
||||
struct generic_pm_domain *genpd = &pd->genpd;
|
||||
u32 pd_pwr_offset = pd->info->pwr_offset;
|
||||
bool is_on, is_mem_on = false;
|
||||
+ struct arm_smccc_res res;
|
||||
|
||||
if (pd->info->pwr_mask == 0)
|
||||
return;
|
||||
@@ -567,6 +570,11 @@ static void rockchip_do_pmu_set_power_domain(struct rockchip_pm_domain *pd,
|
||||
genpd->name, is_on);
|
||||
return;
|
||||
}
|
||||
+
|
||||
+ /* Inform firmware to keep this pd on or off */
|
||||
+ arm_smccc_smc(ROCKCHIP_SIP_SUSPEND_MODE, ROCKCHIP_SLEEP_PD_CONFIG,
|
||||
+ pmu->info->pwr_offset + pd_pwr_offset,
|
||||
+ pd->info->pwr_mask, on, 0, 0, 0, &res);
|
||||
}
|
||||
|
||||
static int rockchip_pd_power(struct rockchip_pm_domain *pd, bool power_on)
|
||||
--
|
||||
2.7.4
|
@ -0,0 +1,68 @@
|
||||
These two APIs will be used by host driver if they need a different
|
||||
HCE process.
|
||||
|
||||
Signed-off-by: Shawn Lin <shawn.lin@rock-chips.com>
|
||||
---
|
||||
|
||||
Changes in v5: None
|
||||
Changes in v4: None
|
||||
Changes in v3: None
|
||||
Changes in v2: None
|
||||
|
||||
drivers/ufs/core/ufshcd.c | 6 ++++--
|
||||
include/ufs/ufshcd.h | 2 ++
|
||||
2 files changed, 6 insertions(+), 2 deletions(-)
|
||||
|
||||
diff --git a/drivers/ufs/core/ufshcd.c b/drivers/ufs/core/ufshcd.c
|
||||
index 24a32e2..9d1d56d 100644
|
||||
--- a/drivers/ufs/core/ufshcd.c
|
||||
+++ b/drivers/ufs/core/ufshcd.c
|
||||
@@ -4039,7 +4039,7 @@ static int ufshcd_dme_link_startup(struct ufs_hba *hba)
|
||||
*
|
||||
* Return: 0 on success, non-zero value on failure.
|
||||
*/
|
||||
-static int ufshcd_dme_reset(struct ufs_hba *hba)
|
||||
+int ufshcd_dme_reset(struct ufs_hba *hba)
|
||||
{
|
||||
struct uic_command uic_cmd = {
|
||||
.command = UIC_CMD_DME_RESET,
|
||||
@@ -4053,6 +4053,7 @@ static int ufshcd_dme_reset(struct ufs_hba *hba)
|
||||
|
||||
return ret;
|
||||
}
|
||||
+EXPORT_SYMBOL_GPL(ufshcd_dme_reset);
|
||||
|
||||
int ufshcd_dme_configure_adapt(struct ufs_hba *hba,
|
||||
int agreed_gear,
|
||||
@@ -4078,7 +4079,7 @@ EXPORT_SYMBOL_GPL(ufshcd_dme_configure_adapt);
|
||||
*
|
||||
* Return: 0 on success, non-zero value on failure.
|
||||
*/
|
||||
-static int ufshcd_dme_enable(struct ufs_hba *hba)
|
||||
+int ufshcd_dme_enable(struct ufs_hba *hba)
|
||||
{
|
||||
struct uic_command uic_cmd = {
|
||||
.command = UIC_CMD_DME_ENABLE,
|
||||
@@ -4092,6 +4093,7 @@ static int ufshcd_dme_enable(struct ufs_hba *hba)
|
||||
|
||||
return ret;
|
||||
}
|
||||
+EXPORT_SYMBOL_GPL(ufshcd_dme_enable);
|
||||
|
||||
static inline void ufshcd_add_delay_before_dme_cmd(struct ufs_hba *hba)
|
||||
{
|
||||
diff --git a/include/ufs/ufshcd.h b/include/ufs/ufshcd.h
|
||||
index 3f68ae3e4..b9733dc 100644
|
||||
--- a/include/ufs/ufshcd.h
|
||||
+++ b/include/ufs/ufshcd.h
|
||||
@@ -1360,6 +1360,8 @@ extern int ufshcd_system_thaw(struct device *dev);
|
||||
extern int ufshcd_system_restore(struct device *dev);
|
||||
#endif
|
||||
|
||||
+extern int ufshcd_dme_reset(struct ufs_hba *hba);
|
||||
+extern int ufshcd_dme_enable(struct ufs_hba *hba);
|
||||
extern int ufshcd_dme_configure_adapt(struct ufs_hba *hba,
|
||||
int agreed_gear,
|
||||
int adapt_val);
|
||||
--
|
||||
2.7.4
|
@ -0,0 +1,515 @@
|
||||
RK3576 SoC contains a UFS controller, add initial support for it.
|
||||
The features are:
|
||||
(1) support UFS 2.0 features
|
||||
(2) High speed up to HS-G3
|
||||
(3) 2RX-2TX lanes
|
||||
(4) auto H8 entry and exit
|
||||
|
||||
Software limitation:
|
||||
(1) HCE procedure: enable controller->enable intr->dme_reset->dme_enable
|
||||
(2) disable unipro timeout values before power mode change
|
||||
|
||||
Signed-off-by: Shawn Lin <shawn.lin@rock-chips.com>
|
||||
---
|
||||
|
||||
Changes in v5:
|
||||
- use device_set_awake_path() and disable ref_out_clk in suspend
|
||||
- remove pd_id from header
|
||||
- recontruct ufs_rockchip_hce_enable_notify() to workaround hce enable
|
||||
without using new quirk
|
||||
|
||||
Changes in v4:
|
||||
- deal with power domain of rpm and spm suggested by Ulf
|
||||
- Fix typo and disable clks in ufs_rockchip_remove
|
||||
- remove clk_disable_unprepare(host->ref_out_clk) from
|
||||
ufs_rockchip_remove
|
||||
|
||||
Changes in v3:
|
||||
- reword Kconfig description
|
||||
- elaborate more about controller in commit msg
|
||||
- use rockchip,rk3576-ufshc for compatible
|
||||
- remove useless header file
|
||||
- remove inline for ufshcd_is_device_present
|
||||
- use usleep_range instead
|
||||
- remove initialization, reverse Xmas order
|
||||
- remove useless varibles
|
||||
- check vops for null
|
||||
- other small fixes for err path
|
||||
- remove pm_runtime_set_active
|
||||
- fix the active and inactive reset-gpios logic
|
||||
- fix rpm_lvl and spm_lvl to 5 and move to end of probe path
|
||||
- remove unnecessary system PM callbacks
|
||||
- use UFSHCI_QUIRK_DME_RESET_ENABLE_AFTER_HCE instead
|
||||
of UFSHCI_QUIRK_BROKEN_HCE
|
||||
|
||||
Changes in v2: None
|
||||
|
||||
drivers/ufs/host/Kconfig | 12 ++
|
||||
drivers/ufs/host/Makefile | 1 +
|
||||
drivers/ufs/host/ufs-rockchip.c | 368 ++++++++++++++++++++++++++++++++++++++++
|
||||
drivers/ufs/host/ufs-rockchip.h | 48 ++++++
|
||||
4 files changed, 429 insertions(+)
|
||||
create mode 100644 drivers/ufs/host/ufs-rockchip.c
|
||||
create mode 100644 drivers/ufs/host/ufs-rockchip.h
|
||||
|
||||
diff --git a/drivers/ufs/host/Kconfig b/drivers/ufs/host/Kconfig
|
||||
index 580c8d0..191fbd7 100644
|
||||
--- a/drivers/ufs/host/Kconfig
|
||||
+++ b/drivers/ufs/host/Kconfig
|
||||
@@ -142,3 +142,15 @@ config SCSI_UFS_SPRD
|
||||
|
||||
Select this if you have UFS controller on Unisoc chipset.
|
||||
If unsure, say N.
|
||||
+
|
||||
+config SCSI_UFS_ROCKCHIP
|
||||
+ tristate "Rockchip UFS host controller driver"
|
||||
+ depends on SCSI_UFSHCD_PLATFORM && (ARCH_ROCKCHIP || COMPILE_TEST)
|
||||
+ help
|
||||
+ This selects the Rockchip specific additions to UFSHCD platform driver.
|
||||
+ UFS host on Rockchip needs some vendor specific configuration before
|
||||
+ accessing the hardware which includes PHY configuration and vendor
|
||||
+ specific registers.
|
||||
+
|
||||
+ Select this if you have UFS controller on Rockchip chipset.
|
||||
+ If unsure, say N.
|
||||
diff --git a/drivers/ufs/host/Makefile b/drivers/ufs/host/Makefile
|
||||
index 4573aea..2f97feb 100644
|
||||
--- a/drivers/ufs/host/Makefile
|
||||
+++ b/drivers/ufs/host/Makefile
|
||||
@@ -10,5 +10,6 @@ obj-$(CONFIG_SCSI_UFSHCD_PLATFORM) += ufshcd-pltfrm.o
|
||||
obj-$(CONFIG_SCSI_UFS_HISI) += ufs-hisi.o
|
||||
obj-$(CONFIG_SCSI_UFS_MEDIATEK) += ufs-mediatek.o
|
||||
obj-$(CONFIG_SCSI_UFS_RENESAS) += ufs-renesas.o
|
||||
+obj-$(CONFIG_SCSI_UFS_ROCKCHIP) += ufs-rockchip.o
|
||||
obj-$(CONFIG_SCSI_UFS_SPRD) += ufs-sprd.o
|
||||
obj-$(CONFIG_SCSI_UFS_TI_J721E) += ti-j721e-ufs.o
|
||||
diff --git a/drivers/ufs/host/ufs-rockchip.c b/drivers/ufs/host/ufs-rockchip.c
|
||||
new file mode 100644
|
||||
index 0000000..b087ce0
|
||||
--- /dev/null
|
||||
+++ b/drivers/ufs/host/ufs-rockchip.c
|
||||
@@ -0,0 +1,368 @@
|
||||
+// SPDX-License-Identifier: GPL-2.0-only
|
||||
+/*
|
||||
+ * Rockchip UFS Host Controller driver
|
||||
+ *
|
||||
+ * Copyright (C) 2024 Rockchip Electronics Co.Ltd.
|
||||
+ */
|
||||
+
|
||||
+#include <linux/clk.h>
|
||||
+#include <linux/gpio.h>
|
||||
+#include <linux/mfd/syscon.h>
|
||||
+#include <linux/of.h>
|
||||
+#include <linux/platform_device.h>
|
||||
+#include <linux/pm_domain.h>
|
||||
+#include <linux/pm_wakeup.h>
|
||||
+#include <linux/regmap.h>
|
||||
+#include <linux/reset.h>
|
||||
+
|
||||
+#include <ufs/ufshcd.h>
|
||||
+#include <ufs/unipro.h>
|
||||
+#include "ufshcd-pltfrm.h"
|
||||
+#include "ufs-rockchip.h"
|
||||
+
|
||||
+static int ufs_rockchip_hce_enable_notify(struct ufs_hba *hba,
|
||||
+ enum ufs_notify_change_status status)
|
||||
+{
|
||||
+ int err = 0;
|
||||
+
|
||||
+ if (status == POST_CHANGE) {
|
||||
+ err = ufshcd_dme_reset(hba);
|
||||
+ if (err)
|
||||
+ return err;
|
||||
+
|
||||
+ err = ufshcd_dme_enable(hba);
|
||||
+ if (err)
|
||||
+ return err;
|
||||
+
|
||||
+ err = ufshcd_vops_phy_initialization(hba);
|
||||
+ }
|
||||
+
|
||||
+ return err;
|
||||
+}
|
||||
+
|
||||
+static void ufs_rockchip_set_pm_lvl(struct ufs_hba *hba)
|
||||
+{
|
||||
+ hba->rpm_lvl = UFS_PM_LVL_5;
|
||||
+ hba->spm_lvl = UFS_PM_LVL_5;
|
||||
+}
|
||||
+
|
||||
+static int ufs_rockchip_rk3576_phy_init(struct ufs_hba *hba)
|
||||
+{
|
||||
+ struct ufs_rockchip_host *host = ufshcd_get_variant(hba);
|
||||
+
|
||||
+ ufshcd_dme_set(hba, UIC_ARG_MIB_SEL(PA_LOCAL_TX_LCC_ENABLE, 0x0), 0x0);
|
||||
+ /* enable the mphy DME_SET cfg */
|
||||
+ ufshcd_dme_set(hba, UIC_ARG_MIB_SEL(0x200, 0x0), 0x40);
|
||||
+ for (int i = 0; i < 2; i++) {
|
||||
+ /* Configuration M-TX */
|
||||
+ ufshcd_dme_set(hba, UIC_ARG_MIB_SEL(0xaa, SEL_TX_LANE0 + i), 0x06);
|
||||
+ ufshcd_dme_set(hba, UIC_ARG_MIB_SEL(0xa9, SEL_TX_LANE0 + i), 0x02);
|
||||
+ ufshcd_dme_set(hba, UIC_ARG_MIB_SEL(0xad, SEL_TX_LANE0 + i), 0x44);
|
||||
+ ufshcd_dme_set(hba, UIC_ARG_MIB_SEL(0xac, SEL_TX_LANE0 + i), 0xe6);
|
||||
+ ufshcd_dme_set(hba, UIC_ARG_MIB_SEL(0xab, SEL_TX_LANE0 + i), 0x07);
|
||||
+ ufshcd_dme_set(hba, UIC_ARG_MIB_SEL(0x94, SEL_TX_LANE0 + i), 0x93);
|
||||
+ ufshcd_dme_set(hba, UIC_ARG_MIB_SEL(0x93, SEL_TX_LANE0 + i), 0xc9);
|
||||
+ ufshcd_dme_set(hba, UIC_ARG_MIB_SEL(0x7f, SEL_TX_LANE0 + i), 0x00);
|
||||
+ /* Configuration M-RX */
|
||||
+ ufshcd_dme_set(hba, UIC_ARG_MIB_SEL(0x12, SEL_RX_LANE0 + i), 0x06);
|
||||
+ ufshcd_dme_set(hba, UIC_ARG_MIB_SEL(0x11, SEL_RX_LANE0 + i), 0x00);
|
||||
+ ufshcd_dme_set(hba, UIC_ARG_MIB_SEL(0x1d, SEL_RX_LANE0 + i), 0x58);
|
||||
+ ufshcd_dme_set(hba, UIC_ARG_MIB_SEL(0x1c, SEL_RX_LANE0 + i), 0x8c);
|
||||
+ ufshcd_dme_set(hba, UIC_ARG_MIB_SEL(0x1b, SEL_RX_LANE0 + i), 0x02);
|
||||
+ ufshcd_dme_set(hba, UIC_ARG_MIB_SEL(0x25, SEL_RX_LANE0 + i), 0xf6);
|
||||
+ ufshcd_dme_set(hba, UIC_ARG_MIB_SEL(0x2f, SEL_RX_LANE0 + i), 0x69);
|
||||
+ }
|
||||
+ /* disable the mphy DME_SET cfg */
|
||||
+ ufshcd_dme_set(hba, UIC_ARG_MIB_SEL(0x200, 0x0), 0x00);
|
||||
+
|
||||
+ ufs_sys_writel(host->mphy_base, 0x80, 0x08C);
|
||||
+ ufs_sys_writel(host->mphy_base, 0xB5, 0x110);
|
||||
+ ufs_sys_writel(host->mphy_base, 0xB5, 0x250);
|
||||
+
|
||||
+ ufs_sys_writel(host->mphy_base, 0x03, 0x134);
|
||||
+ ufs_sys_writel(host->mphy_base, 0x03, 0x274);
|
||||
+
|
||||
+ ufs_sys_writel(host->mphy_base, 0x38, 0x0E0);
|
||||
+ ufs_sys_writel(host->mphy_base, 0x38, 0x220);
|
||||
+
|
||||
+ ufs_sys_writel(host->mphy_base, 0x50, 0x164);
|
||||
+ ufs_sys_writel(host->mphy_base, 0x50, 0x2A4);
|
||||
+
|
||||
+ ufs_sys_writel(host->mphy_base, 0x80, 0x178);
|
||||
+ ufs_sys_writel(host->mphy_base, 0x80, 0x2B8);
|
||||
+
|
||||
+ ufs_sys_writel(host->mphy_base, 0x18, 0x1B0);
|
||||
+ ufs_sys_writel(host->mphy_base, 0x18, 0x2F0);
|
||||
+
|
||||
+ ufs_sys_writel(host->mphy_base, 0x03, 0x128);
|
||||
+ ufs_sys_writel(host->mphy_base, 0x03, 0x268);
|
||||
+
|
||||
+ ufs_sys_writel(host->mphy_base, 0x20, 0x12C);
|
||||
+ ufs_sys_writel(host->mphy_base, 0x20, 0x26C);
|
||||
+
|
||||
+ ufs_sys_writel(host->mphy_base, 0xC0, 0x120);
|
||||
+ ufs_sys_writel(host->mphy_base, 0xC0, 0x260);
|
||||
+
|
||||
+ ufs_sys_writel(host->mphy_base, 0x03, 0x094);
|
||||
+
|
||||
+ ufs_sys_writel(host->mphy_base, 0x03, 0x1B4);
|
||||
+ ufs_sys_writel(host->mphy_base, 0x03, 0x2F4);
|
||||
+
|
||||
+ ufs_sys_writel(host->mphy_base, 0xC0, 0x08C);
|
||||
+ usleep_range(1, 2);
|
||||
+ ufs_sys_writel(host->mphy_base, 0x00, 0x08C);
|
||||
+
|
||||
+ usleep_range(200, 250);
|
||||
+ /* start link up */
|
||||
+ ufshcd_dme_set(hba, UIC_ARG_MIB_SEL(MIB_T_DBG_CPORT_TX_ENDIAN, 0), 0x0);
|
||||
+ ufshcd_dme_set(hba, UIC_ARG_MIB_SEL(MIB_T_DBG_CPORT_RX_ENDIAN, 0), 0x0);
|
||||
+ ufshcd_dme_set(hba, UIC_ARG_MIB_SEL(N_DEVICEID, 0), 0x0);
|
||||
+ ufshcd_dme_set(hba, UIC_ARG_MIB_SEL(N_DEVICEID_VALID, 0), 0x1);
|
||||
+ ufshcd_dme_set(hba, UIC_ARG_MIB_SEL(T_PEERDEVICEID, 0), 0x1);
|
||||
+ ufshcd_dme_set(hba, UIC_ARG_MIB_SEL(T_CONNECTIONSTATE, 0), 0x1);
|
||||
+
|
||||
+ return 0;
|
||||
+}
|
||||
+
|
||||
+static int ufs_rockchip_common_init(struct ufs_hba *hba)
|
||||
+{
|
||||
+ struct device *dev = hba->dev;
|
||||
+ struct platform_device *pdev = to_platform_device(dev);
|
||||
+ struct ufs_rockchip_host *host;
|
||||
+ int err;
|
||||
+
|
||||
+ host = devm_kzalloc(dev, sizeof(*host), GFP_KERNEL);
|
||||
+ if (!host)
|
||||
+ return -ENOMEM;
|
||||
+
|
||||
+ /* system control register for hci */
|
||||
+ host->ufs_sys_ctrl = devm_platform_ioremap_resource_byname(pdev, "hci_grf");
|
||||
+ if (IS_ERR(host->ufs_sys_ctrl))
|
||||
+ return dev_err_probe(dev, PTR_ERR(host->ufs_sys_ctrl),
|
||||
+ "cannot ioremap for hci system control register\n");
|
||||
+
|
||||
+ /* system control register for mphy */
|
||||
+ host->ufs_phy_ctrl = devm_platform_ioremap_resource_byname(pdev, "mphy_grf");
|
||||
+ if (IS_ERR(host->ufs_phy_ctrl))
|
||||
+ return dev_err_probe(dev, PTR_ERR(host->ufs_phy_ctrl),
|
||||
+ "cannot ioremap for mphy system control register\n");
|
||||
+
|
||||
+ /* mphy base register */
|
||||
+ host->mphy_base = devm_platform_ioremap_resource_byname(pdev, "mphy");
|
||||
+ if (IS_ERR(host->mphy_base))
|
||||
+ return dev_err_probe(dev, PTR_ERR(host->mphy_base),
|
||||
+ "cannot ioremap for mphy base register\n");
|
||||
+
|
||||
+ host->rst = devm_reset_control_array_get_exclusive(dev);
|
||||
+ if (IS_ERR(host->rst))
|
||||
+ return dev_err_probe(dev, PTR_ERR(host->rst),
|
||||
+ "failed to get reset control\n");
|
||||
+
|
||||
+ reset_control_assert(host->rst);
|
||||
+ usleep_range(1, 2);
|
||||
+ reset_control_deassert(host->rst);
|
||||
+
|
||||
+ host->ref_out_clk = devm_clk_get_enabled(dev, "ref_out");
|
||||
+ if (IS_ERR(host->ref_out_clk))
|
||||
+ return dev_err_probe(dev, PTR_ERR(host->ref_out_clk),
|
||||
+ "ref_out unavailable\n");
|
||||
+
|
||||
+ host->rst_gpio = devm_gpiod_get(&pdev->dev, "reset", GPIOD_OUT_LOW);
|
||||
+ if (IS_ERR(host->rst_gpio))
|
||||
+ return dev_err_probe(&pdev->dev, PTR_ERR(host->rst_gpio),
|
||||
+ "invalid reset-gpios property in node\n");
|
||||
+
|
||||
+ host->clks[0].id = "core";
|
||||
+ host->clks[1].id = "pclk";
|
||||
+ host->clks[2].id = "pclk_mphy";
|
||||
+ err = devm_clk_bulk_get_optional(dev, UFS_MAX_CLKS, host->clks);
|
||||
+ if (err)
|
||||
+ return dev_err_probe(dev, err, "failed to get clocks\n");
|
||||
+
|
||||
+ err = clk_bulk_prepare_enable(UFS_MAX_CLKS, host->clks);
|
||||
+ if (err)
|
||||
+ return dev_err_probe(dev, err, "failed to enable clocks\n");
|
||||
+
|
||||
+ host->hba = hba;
|
||||
+
|
||||
+ ufshcd_set_variant(hba, host);
|
||||
+
|
||||
+ return 0;
|
||||
+}
|
||||
+
|
||||
+static int ufs_rockchip_rk3576_init(struct ufs_hba *hba)
|
||||
+{
|
||||
+ struct device *dev = hba->dev;
|
||||
+ int ret;
|
||||
+
|
||||
+ hba->quirks = UFSHCD_QUIRK_SKIP_DEF_UNIPRO_TIMEOUT_SETTING;
|
||||
+
|
||||
+ /* Enable BKOPS when suspend */
|
||||
+ hba->caps |= UFSHCD_CAP_AUTO_BKOPS_SUSPEND;
|
||||
+ /* Enable putting device into deep sleep */
|
||||
+ hba->caps |= UFSHCD_CAP_DEEPSLEEP;
|
||||
+ /* Enable devfreq of UFS */
|
||||
+ hba->caps |= UFSHCD_CAP_CLK_SCALING;
|
||||
+ /* Enable WriteBooster */
|
||||
+ hba->caps |= UFSHCD_CAP_WB_EN;
|
||||
+
|
||||
+ ret = ufs_rockchip_common_init(hba);
|
||||
+ if (ret)
|
||||
+ return dev_err_probe(dev, ret, "ufs common init fail\n");
|
||||
+
|
||||
+ return 0;
|
||||
+}
|
||||
+
|
||||
+static int ufs_rockchip_device_reset(struct ufs_hba *hba)
|
||||
+{
|
||||
+ struct ufs_rockchip_host *host = ufshcd_get_variant(hba);
|
||||
+
|
||||
+ /* Active the reset-gpios */
|
||||
+ gpiod_set_value_cansleep(host->rst_gpio, 1);
|
||||
+ usleep_range(20, 25);
|
||||
+
|
||||
+ /* Inactive the reset-gpios */
|
||||
+ gpiod_set_value_cansleep(host->rst_gpio, 0);
|
||||
+ usleep_range(20, 25);
|
||||
+
|
||||
+ return 0;
|
||||
+}
|
||||
+
|
||||
+static const struct ufs_hba_variant_ops ufs_hba_rk3576_vops = {
|
||||
+ .name = "rk3576",
|
||||
+ .init = ufs_rockchip_rk3576_init,
|
||||
+ .device_reset = ufs_rockchip_device_reset,
|
||||
+ .hce_enable_notify = ufs_rockchip_hce_enable_notify,
|
||||
+ .phy_initialization = ufs_rockchip_rk3576_phy_init,
|
||||
+};
|
||||
+
|
||||
+static const struct of_device_id ufs_rockchip_of_match[] = {
|
||||
+ { .compatible = "rockchip,rk3576-ufshc", .data = &ufs_hba_rk3576_vops },
|
||||
+};
|
||||
+MODULE_DEVICE_TABLE(of, ufs_rockchip_of_match);
|
||||
+
|
||||
+static int ufs_rockchip_probe(struct platform_device *pdev)
|
||||
+{
|
||||
+ struct device *dev = &pdev->dev;
|
||||
+ const struct ufs_hba_variant_ops *vops;
|
||||
+ struct ufs_hba *hba;
|
||||
+ int err;
|
||||
+
|
||||
+ vops = device_get_match_data(dev);
|
||||
+ if (!vops)
|
||||
+ return dev_err_probe(dev, -EINVAL, "ufs_hba_variant_ops not defined.\n");
|
||||
+
|
||||
+ err = ufshcd_pltfrm_init(pdev, vops);
|
||||
+ if (err)
|
||||
+ return dev_err_probe(dev, err, "ufshcd_pltfrm_init failed\n");
|
||||
+
|
||||
+ hba = platform_get_drvdata(pdev);
|
||||
+ /* Set the default desired pm level in case no users set via sysfs */
|
||||
+ ufs_rockchip_set_pm_lvl(hba);
|
||||
+
|
||||
+ return 0;
|
||||
+}
|
||||
+
|
||||
+static void ufs_rockchip_remove(struct platform_device *pdev)
|
||||
+{
|
||||
+ struct ufs_hba *hba = platform_get_drvdata(pdev);
|
||||
+ struct ufs_rockchip_host *host = ufshcd_get_variant(hba);
|
||||
+
|
||||
+ pm_runtime_forbid(&pdev->dev);
|
||||
+ pm_runtime_get_noresume(&pdev->dev);
|
||||
+ ufshcd_remove(hba);
|
||||
+ ufshcd_dealloc_host(hba);
|
||||
+ clk_bulk_disable_unprepare(UFS_MAX_CLKS, host->clks);
|
||||
+}
|
||||
+
|
||||
+#ifdef CONFIG_PM
|
||||
+static int ufs_rockchip_runtime_suspend(struct device *dev)
|
||||
+{
|
||||
+ struct ufs_hba *hba = dev_get_drvdata(dev);
|
||||
+ struct ufs_rockchip_host *host = ufshcd_get_variant(hba);
|
||||
+
|
||||
+ clk_disable_unprepare(host->ref_out_clk);
|
||||
+
|
||||
+ /* Shouldn't power down if rpm_lvl is less than level 5. */
|
||||
+ dev_pm_genpd_rpm_always_on(dev, hba->rpm_lvl < UFS_PM_LVL_5 ? true : false);
|
||||
+
|
||||
+ return ufshcd_runtime_suspend(dev);
|
||||
+}
|
||||
+
|
||||
+static int ufs_rockchip_runtime_resume(struct device *dev)
|
||||
+{
|
||||
+ struct ufs_hba *hba = dev_get_drvdata(dev);
|
||||
+ struct ufs_rockchip_host *host = ufshcd_get_variant(hba);
|
||||
+ int err;
|
||||
+
|
||||
+ err = clk_prepare_enable(host->ref_out_clk);
|
||||
+ if (err) {
|
||||
+ dev_err(hba->dev, "failed to enable ref out clock %d\n", err);
|
||||
+ return err;
|
||||
+ }
|
||||
+
|
||||
+ reset_control_assert(host->rst);
|
||||
+ usleep_range(1, 2);
|
||||
+ reset_control_deassert(host->rst);
|
||||
+
|
||||
+ return ufshcd_runtime_resume(dev);
|
||||
+}
|
||||
+#endif
|
||||
+
|
||||
+#ifdef CONFIG_PM_SLEEP
|
||||
+static int ufs_rockchip_system_suspend(struct device *dev)
|
||||
+{
|
||||
+ struct ufs_hba *hba = dev_get_drvdata(dev);
|
||||
+ struct ufs_rockchip_host *host = ufshcd_get_variant(hba);
|
||||
+ int err;
|
||||
+
|
||||
+ if (hba->spm_lvl < UFS_PM_LVL_5)
|
||||
+ device_set_awake_path(dev);
|
||||
+
|
||||
+ err = ufshcd_system_suspend(dev);
|
||||
+ if (err) {
|
||||
+ dev_err(hba->dev, "system susped failed %d\n", err);
|
||||
+ return err;
|
||||
+ }
|
||||
+
|
||||
+ clk_disable_unprepare(host->ref_out_clk);
|
||||
+
|
||||
+ return 0;
|
||||
+}
|
||||
+
|
||||
+static int ufs_rockchip_system_resume(struct device *dev)
|
||||
+{
|
||||
+ struct ufs_hba *hba = dev_get_drvdata(dev);
|
||||
+ struct ufs_rockchip_host *host = ufshcd_get_variant(hba);
|
||||
+ int err;
|
||||
+
|
||||
+ err = clk_prepare_enable(host->ref_out_clk);
|
||||
+ if (err) {
|
||||
+ dev_err(hba->dev, "failed to enable ref out clock %d\n", err);
|
||||
+ return err;
|
||||
+ }
|
||||
+
|
||||
+ return ufshcd_system_resume(dev);
|
||||
+}
|
||||
+#endif
|
||||
+
|
||||
+static const struct dev_pm_ops ufs_rockchip_pm_ops = {
|
||||
+ SET_SYSTEM_SLEEP_PM_OPS(ufs_rockchip_system_suspend, ufs_rockchip_system_resume)
|
||||
+ SET_RUNTIME_PM_OPS(ufs_rockchip_runtime_suspend, ufs_rockchip_runtime_resume, NULL)
|
||||
+ .prepare = ufshcd_suspend_prepare,
|
||||
+ .complete = ufshcd_resume_complete,
|
||||
+};
|
||||
+
|
||||
+static struct platform_driver ufs_rockchip_pltform = {
|
||||
+ .probe = ufs_rockchip_probe,
|
||||
+ .remove = ufs_rockchip_remove,
|
||||
+ .driver = {
|
||||
+ .name = "ufshcd-rockchip",
|
||||
+ .pm = &ufs_rockchip_pm_ops,
|
||||
+ .of_match_table = ufs_rockchip_of_match,
|
||||
+ },
|
||||
+};
|
||||
+module_platform_driver(ufs_rockchip_pltform);
|
||||
+
|
||||
+MODULE_LICENSE("GPL");
|
||||
+MODULE_DESCRIPTION("Rockchip UFS Host Driver");
|
||||
diff --git a/drivers/ufs/host/ufs-rockchip.h b/drivers/ufs/host/ufs-rockchip.h
|
||||
new file mode 100644
|
||||
index 0000000..768dbe3
|
||||
--- /dev/null
|
||||
+++ b/drivers/ufs/host/ufs-rockchip.h
|
||||
@@ -0,0 +1,48 @@
|
||||
+/* SPDX-License-Identifier: GPL-2.0-only */
|
||||
+/*
|
||||
+ * Rockchip UFS Host Controller driver
|
||||
+ *
|
||||
+ * Copyright (C) 2024 Rockchip Electronics Co.Ltd.
|
||||
+ */
|
||||
+
|
||||
+#ifndef _UFS_ROCKCHIP_H_
|
||||
+#define _UFS_ROCKCHIP_H_
|
||||
+
|
||||
+#define UFS_MAX_CLKS 3
|
||||
+
|
||||
+#define SEL_TX_LANE0 0x0
|
||||
+#define SEL_TX_LANE1 0x1
|
||||
+#define SEL_TX_LANE2 0x2
|
||||
+#define SEL_TX_LANE3 0x3
|
||||
+#define SEL_RX_LANE0 0x4
|
||||
+#define SEL_RX_LANE1 0x5
|
||||
+#define SEL_RX_LANE2 0x6
|
||||
+#define SEL_RX_LANE3 0x7
|
||||
+
|
||||
+#define MIB_T_DBG_CPORT_TX_ENDIAN 0xc022
|
||||
+#define MIB_T_DBG_CPORT_RX_ENDIAN 0xc023
|
||||
+
|
||||
+struct ufs_rockchip_host {
|
||||
+ struct ufs_hba *hba;
|
||||
+ void __iomem *ufs_phy_ctrl;
|
||||
+ void __iomem *ufs_sys_ctrl;
|
||||
+ void __iomem *mphy_base;
|
||||
+ struct gpio_desc *rst_gpio;
|
||||
+ struct reset_control *rst;
|
||||
+ struct clk *ref_out_clk;
|
||||
+ struct clk_bulk_data clks[UFS_MAX_CLKS];
|
||||
+ uint64_t caps;
|
||||
+};
|
||||
+
|
||||
+#define ufs_sys_writel(base, val, reg) \
|
||||
+ writel((val), (base) + (reg))
|
||||
+#define ufs_sys_readl(base, reg) readl((base) + (reg))
|
||||
+#define ufs_sys_set_bits(base, mask, reg) \
|
||||
+ ufs_sys_writel( \
|
||||
+ (base), ((mask) | (ufs_sys_readl((base), (reg)))), (reg))
|
||||
+#define ufs_sys_ctrl_clr_bits(base, mask, reg) \
|
||||
+ ufs_sys_writel((base), \
|
||||
+ ((~(mask)) & (ufs_sys_readl((base), (reg)))), \
|
||||
+ (reg))
|
||||
+
|
||||
+#endif /* _UFS_ROCKCHIP_H_ */
|
||||
--
|
||||
2.7.4
|
@ -0,0 +1,51 @@
|
||||
Add ufshc node to rk3576.dtsi, so the board using UFS could
|
||||
enable it.
|
||||
|
||||
Signed-off-by: Shawn Lin <shawn.lin@rock-chips.com>
|
||||
---
|
||||
|
||||
Changes in v5: None
|
||||
Changes in v4: None
|
||||
Changes in v3: None
|
||||
Changes in v2: None
|
||||
|
||||
arch/arm64/boot/dts/rockchip/rk3576.dtsi | 25 +++++++++++++++++++++++++
|
||||
1 file changed, 25 insertions(+)
|
||||
|
||||
diff --git a/arch/arm64/boot/dts/rockchip/rk3576.dtsi b/arch/arm64/boot/dts/rockchip/rk3576.dtsi
|
||||
index 436232f..32beda2 100644
|
||||
--- a/arch/arm64/boot/dts/rockchip/rk3576.dtsi
|
||||
+++ b/arch/arm64/boot/dts/rockchip/rk3576.dtsi
|
||||
@@ -1110,6 +1110,30 @@
|
||||
};
|
||||
};
|
||||
|
||||
+ ufshc: ufshc@2a2d0000 {
|
||||
+ compatible = "rockchip,rk3576-ufshc";
|
||||
+ reg = <0x0 0x2a2d0000 0 0x10000>, /* 0: HCI standard */
|
||||
+ <0x0 0x2b040000 0 0x10000>, /* 1: Mphy */
|
||||
+ <0x0 0x2601f000 0 0x1000>, /* 2: HCI Vendor specified */
|
||||
+ <0x0 0x2603c000 0 0x1000>, /* 3: Mphy Vendor specified */
|
||||
+ <0x0 0x2a2e0000 0 0x10000>; /* 4: HCI apb */
|
||||
+ reg-names = "hci", "mphy", "hci_grf", "mphy_grf", "hci_apb";
|
||||
+ clocks = <&cru ACLK_UFS_SYS>, <&cru PCLK_USB_ROOT>, <&cru PCLK_MPHY>,
|
||||
+ <&cru CLK_REF_UFS_CLKOUT>;
|
||||
+ clock-names = "core", "pclk", "pclk_mphy", "ref_out";
|
||||
+ assigned-clocks = <&cru CLK_REF_OSC_MPHY>;
|
||||
+ assigned-clock-parents = <&cru CLK_REF_MPHY_26M>;
|
||||
+ interrupts = <GIC_SPI 361 IRQ_TYPE_LEVEL_HIGH>;
|
||||
+ power-domains = <&power RK3576_PD_USB>;
|
||||
+ pinctrl-0 = <&ufs_refclk>;
|
||||
+ pinctrl-names = "default";
|
||||
+ resets = <&cru SRST_A_UFS_BIU>, <&cru SRST_A_UFS_SYS>,
|
||||
+ <&cru SRST_A_UFS>, <&cru SRST_P_UFS_GRF>;
|
||||
+ reset-names = "biu", "sys", "ufs", "grf";
|
||||
+ reset-gpios = <&gpio4 RK_PD0 GPIO_ACTIVE_LOW>;
|
||||
+ status = "disabled";
|
||||
+ };
|
||||
+
|
||||
sdmmc: mmc@2a310000 {
|
||||
compatible = "rockchip,rk3576-dw-mshc";
|
||||
reg = <0x0 0x2a310000 0x0 0x4000>;
|
||||
--
|
||||
2.7.4
|
Loading…
Reference in New Issue
Block a user