mirror of
https://git.openwrt.org/openwrt/openwrt.git/
synced 2025-10-06 03:32:41 +02:00
rockchip: backport driver updates for rk3576
Backport clk/phy/rng/ufs/usb driver updates for rk3576. Signed-off-by: Tianling Shen <cnsztl@immortalwrt.org> Link: https://github.com/openwrt/openwrt/pull/20041 Signed-off-by: Hauke Mehrtens <hauke@hauke-m.de>
This commit is contained in:
committed by
Hauke Mehrtens
parent
cf4365e767
commit
0a6ed6db26
@@ -0,0 +1,199 @@
|
||||
From 02ac5f9d6caec96071103f7c62b5117526e47b64 Mon Sep 17 00:00:00 2001
|
||||
From: Kuninori Morimoto <kuninori.morimoto.gx@renesas.com>
|
||||
Date: Thu, 24 Oct 2024 02:20:02 +0000
|
||||
Subject: [PATCH] of: property: add of_graph_get_next_port()
|
||||
|
||||
We have endpoint base functions
|
||||
- of_graph_get_next_endpoint()
|
||||
- of_graph_get_endpoint_count()
|
||||
- for_each_endpoint_of_node()
|
||||
|
||||
Here, for_each_endpoint_of_node() loop finds each endpoints
|
||||
|
||||
ports {
|
||||
port@0 {
|
||||
(1) endpoint {...};
|
||||
};
|
||||
port@1 {
|
||||
(2) endpoint {...};
|
||||
};
|
||||
...
|
||||
};
|
||||
|
||||
In above case, it finds endpoint as (1) -> (2) -> ...
|
||||
|
||||
Basically, user/driver knows which port is used for what, but not in
|
||||
all cases. For example on flexible/generic driver case, how many ports
|
||||
are used is not fixed.
|
||||
|
||||
For example Sound Generic Card driver which is very flexible/generic and
|
||||
used from many venders can't know how many ports are used, and used for
|
||||
what, because it depends on each vender SoC and/or its used board.
|
||||
|
||||
And more, the port can have multi endpoints. For example Generic Sound
|
||||
Card case, it supports many type of connection between CPU / Codec, and
|
||||
some of them uses multi endpoint in one port. see below.
|
||||
|
||||
ports {
|
||||
(A) port@0 {
|
||||
(1) endpoint@0 {...};
|
||||
(2) endpoint@1 {...};
|
||||
};
|
||||
(B) port@1 {
|
||||
(3) endpoint {...};
|
||||
};
|
||||
...
|
||||
};
|
||||
|
||||
Generic Sound Card want to handle each connection via "port" base instead
|
||||
of "endpoint" base. But, it is very difficult to handle each "port" via
|
||||
existing for_each_endpoint_of_node(). Because getting each "port" via
|
||||
of_get_parent() from each "endpoint" doesn't work. For example in above
|
||||
case, both (1) (2) endpoint has same "port" (= A).
|
||||
|
||||
Add "port" base functions.
|
||||
|
||||
Signed-off-by: Kuninori Morimoto <kuninori.morimoto.gx@renesas.com>
|
||||
Link: https://lore.kernel.org/r/87ldyeb5t9.wl-kuninori.morimoto.gx@renesas.com
|
||||
Signed-off-by: Rob Herring (Arm) <robh@kernel.org>
|
||||
---
|
||||
drivers/of/property.c | 54 ++++++++++++++++++++++++++++++++++++++++
|
||||
include/linux/of_graph.h | 28 +++++++++++++++++++++
|
||||
2 files changed, 82 insertions(+)
|
||||
|
||||
--- a/drivers/of/property.c
|
||||
+++ b/drivers/of/property.c
|
||||
@@ -631,6 +631,43 @@ struct device_node *of_graph_get_port_by
|
||||
EXPORT_SYMBOL(of_graph_get_port_by_id);
|
||||
|
||||
/**
|
||||
+ * of_graph_get_next_port() - get next port node.
|
||||
+ * @parent: pointer to the parent device node, or parent ports node
|
||||
+ * @prev: previous port node, or NULL to get first
|
||||
+ *
|
||||
+ * Parent device node can be used as @parent whether device node has ports node
|
||||
+ * or not. It will work same as ports@0 node.
|
||||
+ *
|
||||
+ * Return: A 'port' node pointer with refcount incremented. Refcount
|
||||
+ * of the passed @prev node is decremented.
|
||||
+ */
|
||||
+struct device_node *of_graph_get_next_port(const struct device_node *parent,
|
||||
+ struct device_node *prev)
|
||||
+{
|
||||
+ if (!parent)
|
||||
+ return NULL;
|
||||
+
|
||||
+ if (!prev) {
|
||||
+ struct device_node *node __free(device_node) =
|
||||
+ of_get_child_by_name(parent, "ports");
|
||||
+
|
||||
+ if (node)
|
||||
+ parent = node;
|
||||
+
|
||||
+ return of_get_child_by_name(parent, "port");
|
||||
+ }
|
||||
+
|
||||
+ do {
|
||||
+ prev = of_get_next_child(parent, prev);
|
||||
+ if (!prev)
|
||||
+ break;
|
||||
+ } while (!of_node_name_eq(prev, "port"));
|
||||
+
|
||||
+ return prev;
|
||||
+}
|
||||
+EXPORT_SYMBOL(of_graph_get_next_port);
|
||||
+
|
||||
+/**
|
||||
* of_graph_get_next_endpoint() - get next endpoint node
|
||||
* @parent: pointer to the parent device node
|
||||
* @prev: previous endpoint node, or NULL to get first
|
||||
@@ -824,6 +861,23 @@ unsigned int of_graph_get_endpoint_count
|
||||
EXPORT_SYMBOL(of_graph_get_endpoint_count);
|
||||
|
||||
/**
|
||||
+ * of_graph_get_port_count() - get the number of port in a device or ports node
|
||||
+ * @np: pointer to the device or ports node
|
||||
+ *
|
||||
+ * Return: count of port of this device or ports node
|
||||
+ */
|
||||
+unsigned int of_graph_get_port_count(struct device_node *np)
|
||||
+{
|
||||
+ unsigned int num = 0;
|
||||
+
|
||||
+ for_each_of_graph_port(np, port)
|
||||
+ num++;
|
||||
+
|
||||
+ return num;
|
||||
+}
|
||||
+EXPORT_SYMBOL(of_graph_get_port_count);
|
||||
+
|
||||
+/**
|
||||
* of_graph_get_remote_node() - get remote parent device_node for given port/endpoint
|
||||
* @node: pointer to parent device_node containing graph port/endpoint
|
||||
* @port: identifier (value of reg property) of the parent port node
|
||||
--- a/include/linux/of_graph.h
|
||||
+++ b/include/linux/of_graph.h
|
||||
@@ -11,6 +11,7 @@
|
||||
#ifndef __LINUX_OF_GRAPH_H
|
||||
#define __LINUX_OF_GRAPH_H
|
||||
|
||||
+#include <linux/cleanup.h>
|
||||
#include <linux/types.h>
|
||||
#include <linux/errno.h>
|
||||
|
||||
@@ -37,14 +38,29 @@ struct of_endpoint {
|
||||
for (child = of_graph_get_next_endpoint(parent, NULL); child != NULL; \
|
||||
child = of_graph_get_next_endpoint(parent, child))
|
||||
|
||||
+/**
|
||||
+ * for_each_of_graph_port - iterate over every port in a device or ports node
|
||||
+ * @parent: parent device or ports node containing port
|
||||
+ * @child: loop variable pointing to the current port node
|
||||
+ *
|
||||
+ * When breaking out of the loop, and continue to use the @child, you need to
|
||||
+ * use return_ptr(@child) or no_free_ptr(@child) not to call __free() for it.
|
||||
+ */
|
||||
+#define for_each_of_graph_port(parent, child) \
|
||||
+ for (struct device_node *child __free(device_node) = of_graph_get_next_port(parent, NULL);\
|
||||
+ child != NULL; child = of_graph_get_next_port(parent, child))
|
||||
+
|
||||
#ifdef CONFIG_OF
|
||||
bool of_graph_is_present(const struct device_node *node);
|
||||
int of_graph_parse_endpoint(const struct device_node *node,
|
||||
struct of_endpoint *endpoint);
|
||||
unsigned int of_graph_get_endpoint_count(const struct device_node *np);
|
||||
+unsigned int of_graph_get_port_count(struct device_node *np);
|
||||
struct device_node *of_graph_get_port_by_id(struct device_node *node, u32 id);
|
||||
struct device_node *of_graph_get_next_endpoint(const struct device_node *parent,
|
||||
struct device_node *previous);
|
||||
+struct device_node *of_graph_get_next_port(const struct device_node *parent,
|
||||
+ struct device_node *port);
|
||||
struct device_node *of_graph_get_endpoint_by_regs(
|
||||
const struct device_node *parent, int port_reg, int reg);
|
||||
struct device_node *of_graph_get_remote_endpoint(
|
||||
@@ -73,6 +89,11 @@ static inline unsigned int of_graph_get_
|
||||
return 0;
|
||||
}
|
||||
|
||||
+static inline unsigned int of_graph_get_port_count(struct device_node *np)
|
||||
+{
|
||||
+ return 0;
|
||||
+}
|
||||
+
|
||||
static inline struct device_node *of_graph_get_port_by_id(
|
||||
struct device_node *node, u32 id)
|
||||
{
|
||||
@@ -83,6 +104,13 @@ static inline struct device_node *of_gra
|
||||
const struct device_node *parent,
|
||||
struct device_node *previous)
|
||||
{
|
||||
+ return NULL;
|
||||
+}
|
||||
+
|
||||
+static inline struct device_node *of_graph_get_next_port(
|
||||
+ const struct device_node *parent,
|
||||
+ struct device_node *previous)
|
||||
+{
|
||||
return NULL;
|
||||
}
|
||||
|
@@ -0,0 +1,118 @@
|
||||
From 51e32e897539663957f7a0950f66b48f8896efee Mon Sep 17 00:00:00 2001
|
||||
From: Cristian Ciocaltea <cristian.ciocaltea@collabora.com>
|
||||
Date: Sat, 19 Oct 2024 14:16:00 +0300
|
||||
Subject: [PATCH] clk: Provide devm_clk_bulk_get_all_enabled() helper
|
||||
|
||||
Commit 265b07df758a ("clk: Provide managed helper to get and enable bulk
|
||||
clocks") added devm_clk_bulk_get_all_enable() function, but missed to
|
||||
return the number of clocks stored in the clk_bulk_data table referenced
|
||||
by the clks argument. Without knowing the number, it's not possible to
|
||||
iterate these clocks when needed, hence the argument is useless and
|
||||
could have been simply removed.
|
||||
|
||||
Introduce devm_clk_bulk_get_all_enabled() variant, which is consistent
|
||||
with devm_clk_bulk_get_all() in terms of the returned value:
|
||||
|
||||
> 0 if one or more clocks have been stored
|
||||
= 0 if there are no clocks
|
||||
< 0 if an error occurred
|
||||
|
||||
Moreover, the naming is consistent with devm_clk_get_enabled(), i.e. use
|
||||
the past form of 'enable'.
|
||||
|
||||
To reduce code duplication and improve patch readability, make
|
||||
devm_clk_bulk_get_all_enable() use the new helper, as suggested by
|
||||
Stephen Boyd.
|
||||
|
||||
Reviewed-by: AngeloGioacchino Del Regno <angelogioacchino.delregno@collabora.com>
|
||||
Reviewed-by: Manivannan Sadhasivam <manivannan.sadhasivam@linaro.org>
|
||||
Signed-off-by: Cristian Ciocaltea <cristian.ciocaltea@collabora.com>
|
||||
Link: https://lore.kernel.org/r/20241019-clk_bulk_ena_fix-v4-1-57f108f64e70@collabora.com
|
||||
Signed-off-by: Stephen Boyd <sboyd@kernel.org>
|
||||
---
|
||||
drivers/clk/clk-devres.c | 9 +++++----
|
||||
include/linux/clk.h | 21 ++++++++++++++++-----
|
||||
2 files changed, 21 insertions(+), 9 deletions(-)
|
||||
|
||||
--- a/drivers/clk/clk-devres.c
|
||||
+++ b/drivers/clk/clk-devres.c
|
||||
@@ -218,8 +218,8 @@ static void devm_clk_bulk_release_all_en
|
||||
clk_bulk_put_all(devres->num_clks, devres->clks);
|
||||
}
|
||||
|
||||
-int __must_check devm_clk_bulk_get_all_enable(struct device *dev,
|
||||
- struct clk_bulk_data **clks)
|
||||
+int __must_check devm_clk_bulk_get_all_enabled(struct device *dev,
|
||||
+ struct clk_bulk_data **clks)
|
||||
{
|
||||
struct clk_bulk_devres *devres;
|
||||
int ret;
|
||||
@@ -244,11 +244,12 @@ int __must_check devm_clk_bulk_get_all_e
|
||||
} else {
|
||||
clk_bulk_put_all(devres->num_clks, devres->clks);
|
||||
devres_free(devres);
|
||||
+ return ret;
|
||||
}
|
||||
|
||||
- return ret;
|
||||
+ return devres->num_clks;
|
||||
}
|
||||
-EXPORT_SYMBOL_GPL(devm_clk_bulk_get_all_enable);
|
||||
+EXPORT_SYMBOL_GPL(devm_clk_bulk_get_all_enabled);
|
||||
|
||||
static int devm_clk_match(struct device *dev, void *res, void *data)
|
||||
{
|
||||
--- a/include/linux/clk.h
|
||||
+++ b/include/linux/clk.h
|
||||
@@ -496,11 +496,13 @@ int __must_check devm_clk_bulk_get_all(s
|
||||
struct clk_bulk_data **clks);
|
||||
|
||||
/**
|
||||
- * devm_clk_bulk_get_all_enable - Get and enable all clocks of the consumer (managed)
|
||||
+ * devm_clk_bulk_get_all_enabled - Get and enable all clocks of the consumer (managed)
|
||||
* @dev: device for clock "consumer"
|
||||
* @clks: pointer to the clk_bulk_data table of consumer
|
||||
*
|
||||
- * Returns success (0) or negative errno.
|
||||
+ * Returns a positive value for the number of clocks obtained while the
|
||||
+ * clock references are stored in the clk_bulk_data table in @clks field.
|
||||
+ * Returns 0 if there're none and a negative value if something failed.
|
||||
*
|
||||
* This helper function allows drivers to get all clocks of the
|
||||
* consumer and enables them in one operation with management.
|
||||
@@ -508,8 +510,8 @@ int __must_check devm_clk_bulk_get_all(s
|
||||
* is unbound.
|
||||
*/
|
||||
|
||||
-int __must_check devm_clk_bulk_get_all_enable(struct device *dev,
|
||||
- struct clk_bulk_data **clks);
|
||||
+int __must_check devm_clk_bulk_get_all_enabled(struct device *dev,
|
||||
+ struct clk_bulk_data **clks);
|
||||
|
||||
/**
|
||||
* devm_clk_get - lookup and obtain a managed reference to a clock producer.
|
||||
@@ -1034,7 +1036,7 @@ static inline int __must_check devm_clk_
|
||||
return 0;
|
||||
}
|
||||
|
||||
-static inline int __must_check devm_clk_bulk_get_all_enable(struct device *dev,
|
||||
+static inline int __must_check devm_clk_bulk_get_all_enabled(struct device *dev,
|
||||
struct clk_bulk_data **clks)
|
||||
{
|
||||
return 0;
|
||||
@@ -1136,6 +1138,15 @@ static inline void clk_restore_context(v
|
||||
|
||||
#endif
|
||||
|
||||
+/* Deprecated. Use devm_clk_bulk_get_all_enabled() */
|
||||
+static inline int __must_check
|
||||
+devm_clk_bulk_get_all_enable(struct device *dev, struct clk_bulk_data **clks)
|
||||
+{
|
||||
+ int ret = devm_clk_bulk_get_all_enabled(dev, clks);
|
||||
+
|
||||
+ return ret > 0 ? 0 : ret;
|
||||
+}
|
||||
+
|
||||
/* clk_prepare_enable helps cases using clk_enable in non-atomic context. */
|
||||
static inline int clk_prepare_enable(struct clk *clk)
|
||||
{
|
@@ -5443,6 +5443,22 @@ CONFIG_SCSI_PROC_FS=y
|
||||
# CONFIG_SCSI_STEX is not set
|
||||
# CONFIG_SCSI_SYM53C8XX_2 is not set
|
||||
# CONFIG_SCSI_UFSHCD is not set
|
||||
# CONFIG_SCSI_UFSHCD_PCI is not set
|
||||
# CONFIG_SCSI_UFSHCD_PLATFORM is not set
|
||||
# CONFIG_SCSI_UFS_BSG is not set
|
||||
# CONFIG_SCSI_UFS_CDNS_PLATFORM is not set
|
||||
# CONFIG_SCSI_UFS_CRYPTO is not set
|
||||
# CONFIG_SCSI_UFS_DWC_TC_PLATFORM is not set
|
||||
# CONFIG_SCSI_UFS_EXYNOS is not set
|
||||
# CONFIG_SCSI_UFS_FAULT_INJECTION is not set
|
||||
# CONFIG_SCSI_UFS_HISI is not set
|
||||
# CONFIG_SCSI_UFS_HWMON is not set
|
||||
# CONFIG_SCSI_UFS_MEDIATEK is not set
|
||||
# CONFIG_SCSI_UFS_QCOM is not set
|
||||
# CONFIG_SCSI_UFS_RENESAS is not set
|
||||
# CONFIG_SCSI_UFS_ROCKCHIP is not set
|
||||
# CONFIG_SCSI_UFS_SPRD is not set
|
||||
# CONFIG_SCSI_UFS_TI_J721E is not set
|
||||
# CONFIG_SCSI_VIRTIO is not set
|
||||
# CONFIG_SCSI_WD719X is not set
|
||||
# CONFIG_SC_CAMCC_7180 is not set
|
||||
|
@@ -5300,6 +5300,21 @@ CONFIG_SCSI_PROC_FS=y
|
||||
# CONFIG_SCSI_STEX is not set
|
||||
# CONFIG_SCSI_SYM53C8XX_2 is not set
|
||||
# CONFIG_SCSI_UFSHCD is not set
|
||||
# CONFIG_SCSI_UFSHCD_PCI is not set
|
||||
# CONFIG_SCSI_UFSHCD_PLATFORM is not set
|
||||
# CONFIG_SCSI_UFS_BSG is not set
|
||||
# CONFIG_SCSI_UFS_CDNS_PLATFORM is not set
|
||||
# CONFIG_SCSI_UFS_CRYPTO is not set
|
||||
# CONFIG_SCSI_UFS_DWC_TC_PLATFORM is not set
|
||||
# CONFIG_SCSI_UFS_EXYNOS is not set
|
||||
# CONFIG_SCSI_UFS_FAULT_INJECTION is not set
|
||||
# CONFIG_SCSI_UFS_HISI is not set
|
||||
# CONFIG_SCSI_UFS_HWMON is not set
|
||||
# CONFIG_SCSI_UFS_MEDIATEK is not set
|
||||
# CONFIG_SCSI_UFS_QCOM is not set
|
||||
# CONFIG_SCSI_UFS_RENESAS is not set
|
||||
# CONFIG_SCSI_UFS_SPRD is not set
|
||||
# CONFIG_SCSI_UFS_TI_J721E is not set
|
||||
# CONFIG_SCSI_VIRTIO is not set
|
||||
# CONFIG_SCSI_WD719X is not set
|
||||
# CONFIG_SC_CAMCC_7180 is not set
|
||||
|
@@ -72,6 +72,19 @@ Signed-off-by: Christian Marangi <ansuelsmth@gmail.com>
|
||||
&target_freq, false);
|
||||
goto put_opp_table;
|
||||
}
|
||||
--- a/drivers/ufs/core/ufshcd.c
|
||||
+++ b/drivers/ufs/core/ufshcd.c
|
||||
@@ -1119,8 +1119,8 @@ out:
|
||||
}
|
||||
|
||||
int ufshcd_opp_config_clks(struct device *dev, struct opp_table *opp_table,
|
||||
- struct dev_pm_opp *opp, void *data,
|
||||
- bool scaling_down)
|
||||
+ struct dev_pm_opp *old_opp, struct dev_pm_opp *opp,
|
||||
+ void *data, bool scaling_down)
|
||||
{
|
||||
struct ufs_hba *hba = dev_get_drvdata(dev);
|
||||
struct list_head *head = &hba->clk_list_head;
|
||||
--- a/include/linux/pm_opp.h
|
||||
+++ b/include/linux/pm_opp.h
|
||||
@@ -50,7 +50,8 @@ typedef int (*config_regulators_t)(struc
|
||||
@@ -106,3 +119,16 @@ Signed-off-by: Christian Marangi <ansuelsmth@gmail.com>
|
||||
{
|
||||
return -EOPNOTSUPP;
|
||||
}
|
||||
--- a/include/ufs/ufshcd.h
|
||||
+++ b/include/ufs/ufshcd.h
|
||||
@@ -1326,8 +1326,8 @@ void ufshcd_mcq_enable(struct ufs_hba *h
|
||||
void ufshcd_mcq_config_esi(struct ufs_hba *hba, struct msi_msg *msg);
|
||||
|
||||
int ufshcd_opp_config_clks(struct device *dev, struct opp_table *opp_table,
|
||||
- struct dev_pm_opp *opp, void *data,
|
||||
- bool scaling_down);
|
||||
+ struct dev_pm_opp *old_opp, struct dev_pm_opp *opp,
|
||||
+ void *data, bool scaling_down);
|
||||
/**
|
||||
* ufshcd_set_variant - set variant specific data to the hba
|
||||
* @hba: per adapter instance
|
||||
|
@@ -603,6 +603,10 @@ CONFIG_SCSI_COMMON=y
|
||||
CONFIG_SCSI_SAS_ATTRS=y
|
||||
CONFIG_SCSI_SAS_HOST_SMP=y
|
||||
CONFIG_SCSI_SAS_LIBSAS=y
|
||||
CONFIG_SCSI_UFSHCD=y
|
||||
CONFIG_SCSI_UFSHCD_PLATFORM=y
|
||||
CONFIG_SCSI_UFS_HWMON=y
|
||||
CONFIG_SCSI_UFS_ROCKCHIP=y
|
||||
# CONFIG_SECURITY_DMESG_RESTRICT is not set
|
||||
CONFIG_SENSORS_ARM_SCMI=y
|
||||
CONFIG_SENSORS_ARM_SCPI=y
|
||||
@@ -612,10 +616,10 @@ CONFIG_SERIAL_8250_DWLIB=y
|
||||
CONFIG_SERIAL_8250_EXAR=y
|
||||
CONFIG_SERIAL_8250_EXTENDED=y
|
||||
CONFIG_SERIAL_8250_FSL=y
|
||||
CONFIG_SERIAL_8250_NR_UARTS=10
|
||||
CONFIG_SERIAL_8250_NR_UARTS=12
|
||||
CONFIG_SERIAL_8250_PCI=y
|
||||
CONFIG_SERIAL_8250_PCILIB=y
|
||||
CONFIG_SERIAL_8250_RUNTIME_UARTS=10
|
||||
CONFIG_SERIAL_8250_RUNTIME_UARTS=12
|
||||
CONFIG_SERIAL_8250_SHARE_IRQ=y
|
||||
CONFIG_SERIAL_AMBA_PL011=y
|
||||
CONFIG_SERIAL_AMBA_PL011_CONSOLE=y
|
||||
|
@@ -0,0 +1,164 @@
|
||||
From 8f66ccbd8f67ab41b29f54f383f8a8516be7696c Mon Sep 17 00:00:00 2001
|
||||
From: Nicolas Frattaroli <nicolas.frattaroli@collabora.com>
|
||||
Date: Wed, 30 Apr 2025 18:16:35 +0200
|
||||
Subject: [PATCH] hwrng: rockchip - add support for RK3576's RNG
|
||||
|
||||
The Rockchip RK3576 SoC uses a new hardware random number generator IP.
|
||||
It's also used on the Rockchip RK3562 and the Rockchip RK3528.
|
||||
|
||||
It has several modes of operation and self-checking features that are
|
||||
not implemented here. For starters, it has a DRNG output, which is an
|
||||
AES-CTR pseudo-random number generator that can be reseeded from the
|
||||
true entropy regularly.
|
||||
|
||||
However, it also allows for access of the true entropy generator
|
||||
directly. This entropy is generated from an oscillator.
|
||||
|
||||
There are several configuration registers which we don't touch here. The
|
||||
oscillator can be switched between a "CRO" and "STR" oscillator, and the
|
||||
length of the oscillator can be configured.
|
||||
|
||||
The hardware also supports some automatic continuous entropy quality
|
||||
checking, which is also not implemented in this driver for the time
|
||||
being.
|
||||
|
||||
The output as-is has been deemed sufficient to be useful:
|
||||
|
||||
rngtest: starting FIPS tests...
|
||||
rngtest: bits received from input: 20000032
|
||||
rngtest: FIPS 140-2 successes: 997
|
||||
rngtest: FIPS 140-2 failures: 3
|
||||
rngtest: FIPS 140-2(2001-10-10) Monobit: 0
|
||||
rngtest: FIPS 140-2(2001-10-10) Poker: 1
|
||||
rngtest: FIPS 140-2(2001-10-10) Runs: 1
|
||||
rngtest: FIPS 140-2(2001-10-10) Long run: 1
|
||||
rngtest: FIPS 140-2(2001-10-10) Continuous run: 0
|
||||
rngtest: input channel speed: (min=17.050; avg=1897.272;
|
||||
max=19531250.000)Kibits/s
|
||||
rngtest: FIPS tests speed: (min=44.773; avg=71.179; max=96.820)Mibits/s
|
||||
rngtest: Program run time: 11760715 microseconds
|
||||
rngtest: bits received from input: 40000032
|
||||
rngtest: FIPS 140-2 successes: 1997
|
||||
rngtest: FIPS 140-2 failures: 3
|
||||
rngtest: FIPS 140-2(2001-10-10) Monobit: 0
|
||||
rngtest: FIPS 140-2(2001-10-10) Poker: 1
|
||||
rngtest: FIPS 140-2(2001-10-10) Runs: 1
|
||||
rngtest: FIPS 140-2(2001-10-10) Long run: 1
|
||||
rngtest: FIPS 140-2(2001-10-10) Continuous run: 0
|
||||
rngtest: input channel speed: (min=17.050; avg=1798.618;
|
||||
max=19531250.000)Kibits/s
|
||||
rngtest: FIPS tests speed: (min=44.773; avg=64.561; max=96.820)Mibits/s
|
||||
rngtest: Program run time: 23507723 microseconds
|
||||
|
||||
Stretching the entropy can then be left up to Linux's actual entropy
|
||||
pool.
|
||||
|
||||
Signed-off-by: Nicolas Frattaroli <nicolas.frattaroli@collabora.com>
|
||||
Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au>
|
||||
---
|
||||
drivers/char/hw_random/rockchip-rng.c | 73 +++++++++++++++++++++++++++
|
||||
1 file changed, 73 insertions(+)
|
||||
|
||||
--- a/drivers/char/hw_random/rockchip-rng.c
|
||||
+++ b/drivers/char/hw_random/rockchip-rng.c
|
||||
@@ -93,6 +93,30 @@
|
||||
#define TRNG_v1_VERSION_CODE 0x46bc
|
||||
/* end of TRNG_V1 register definitions */
|
||||
|
||||
+/*
|
||||
+ * RKRNG register definitions
|
||||
+ * The RKRNG IP is a stand-alone TRNG implementation (not part of a crypto IP)
|
||||
+ * and can be found in the Rockchip RK3576, Rockchip RK3562 and Rockchip RK3528
|
||||
+ * SoCs. It can either output true randomness (TRNG) or "deterministic"
|
||||
+ * randomness derived from hashing the true entropy (DRNG). This driver
|
||||
+ * implementation uses just the true entropy, and leaves stretching the entropy
|
||||
+ * up to Linux.
|
||||
+ */
|
||||
+#define RKRNG_CFG 0x0000
|
||||
+#define RKRNG_CTRL 0x0010
|
||||
+#define RKRNG_CTRL_REQ_TRNG BIT(4)
|
||||
+#define RKRNG_STATE 0x0014
|
||||
+#define RKRNG_STATE_TRNG_RDY BIT(4)
|
||||
+#define RKRNG_TRNG_DATA0 0x0050
|
||||
+#define RKRNG_TRNG_DATA1 0x0054
|
||||
+#define RKRNG_TRNG_DATA2 0x0058
|
||||
+#define RKRNG_TRNG_DATA3 0x005C
|
||||
+#define RKRNG_TRNG_DATA4 0x0060
|
||||
+#define RKRNG_TRNG_DATA5 0x0064
|
||||
+#define RKRNG_TRNG_DATA6 0x0068
|
||||
+#define RKRNG_TRNG_DATA7 0x006C
|
||||
+#define RKRNG_READ_LEN 32
|
||||
+
|
||||
/* Before removing this assert, give rk3588_rng_read an upper bound of 32 */
|
||||
static_assert(RK_RNG_MAX_BYTE <= (TRNG_V1_RAND7 + 4 - TRNG_V1_RAND0),
|
||||
"You raised RK_RNG_MAX_BYTE and broke rk3588-rng, congrats.");
|
||||
@@ -205,6 +229,46 @@ out:
|
||||
return (ret < 0) ? ret : to_read;
|
||||
}
|
||||
|
||||
+static int rk3576_rng_init(struct hwrng *rng)
|
||||
+{
|
||||
+ struct rk_rng *rk_rng = container_of(rng, struct rk_rng, rng);
|
||||
+
|
||||
+ return rk_rng_enable_clks(rk_rng);
|
||||
+}
|
||||
+
|
||||
+static int rk3576_rng_read(struct hwrng *rng, void *buf, size_t max, bool wait)
|
||||
+{
|
||||
+ struct rk_rng *rk_rng = container_of(rng, struct rk_rng, rng);
|
||||
+ size_t to_read = min_t(size_t, max, RKRNG_READ_LEN);
|
||||
+ int ret = 0;
|
||||
+ u32 val;
|
||||
+
|
||||
+ ret = pm_runtime_resume_and_get(rk_rng->dev);
|
||||
+ if (ret < 0)
|
||||
+ return ret;
|
||||
+
|
||||
+ rk_rng_writel(rk_rng, RKRNG_CTRL_REQ_TRNG | (RKRNG_CTRL_REQ_TRNG << 16),
|
||||
+ RKRNG_CTRL);
|
||||
+
|
||||
+ if (readl_poll_timeout(rk_rng->base + RKRNG_STATE, val,
|
||||
+ (val & RKRNG_STATE_TRNG_RDY), RK_RNG_POLL_PERIOD_US,
|
||||
+ RK_RNG_POLL_TIMEOUT_US)) {
|
||||
+ dev_err(rk_rng->dev, "timed out waiting for data\n");
|
||||
+ ret = -ETIMEDOUT;
|
||||
+ goto out;
|
||||
+ }
|
||||
+
|
||||
+ rk_rng_writel(rk_rng, RKRNG_STATE_TRNG_RDY, RKRNG_STATE);
|
||||
+
|
||||
+ memcpy_fromio(buf, rk_rng->base + RKRNG_TRNG_DATA0, to_read);
|
||||
+
|
||||
+out:
|
||||
+ pm_runtime_mark_last_busy(rk_rng->dev);
|
||||
+ pm_runtime_put_sync_autosuspend(rk_rng->dev);
|
||||
+
|
||||
+ return (ret < 0) ? ret : to_read;
|
||||
+}
|
||||
+
|
||||
static int rk3588_rng_init(struct hwrng *rng)
|
||||
{
|
||||
struct rk_rng *rk_rng = container_of(rng, struct rk_rng, rng);
|
||||
@@ -305,6 +369,14 @@ static const struct rk_rng_soc_data rk35
|
||||
.reset_optional = false,
|
||||
};
|
||||
|
||||
+static const struct rk_rng_soc_data rk3576_soc_data = {
|
||||
+ .rk_rng_init = rk3576_rng_init,
|
||||
+ .rk_rng_read = rk3576_rng_read,
|
||||
+ .rk_rng_cleanup = rk3588_rng_cleanup,
|
||||
+ .quality = 999, /* as determined by actual testing */
|
||||
+ .reset_optional = true,
|
||||
+};
|
||||
+
|
||||
static const struct rk_rng_soc_data rk3588_soc_data = {
|
||||
.rk_rng_init = rk3588_rng_init,
|
||||
.rk_rng_read = rk3588_rng_read,
|
||||
@@ -397,6 +469,7 @@ static const struct dev_pm_ops rk_rng_pm
|
||||
|
||||
static const struct of_device_id rk_rng_dt_match[] = {
|
||||
{ .compatible = "rockchip,rk3568-rng", .data = (void *)&rk3568_soc_data },
|
||||
+ { .compatible = "rockchip,rk3576-rng", .data = (void *)&rk3576_soc_data },
|
||||
{ .compatible = "rockchip,rk3588-rng", .data = (void *)&rk3588_soc_data },
|
||||
{ /* sentinel */ },
|
||||
};
|
@@ -0,0 +1,29 @@
|
||||
From 184055a9ae2b7b19f6fd6e9c0b7e1edce6930b2f Mon Sep 17 00:00:00 2001
|
||||
From: Shawn Lin <shawn.lin@rock-chips.com>
|
||||
Date: Wed, 5 Feb 2025 14:15:51 +0800
|
||||
Subject: [PATCH] soc: rockchip: add header for suspend mode SIP interface
|
||||
|
||||
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>
|
||||
Acked-by: Heiko Stuebner <heiko@sntech.de>
|
||||
Link: https://lore.kernel.org/r/1738736156-119203-3-git-send-email-shawn.lin@rock-chips.com
|
||||
Signed-off-by: Ulf Hansson <ulf.hansson@linaro.org>
|
||||
---
|
||||
include/soc/rockchip/rockchip_sip.h | 3 +++
|
||||
1 file changed, 3 insertions(+)
|
||||
|
||||
--- 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
|
@@ -0,0 +1,27 @@
|
||||
From d934a93bbcccd551c142206b8129903d18126261 Mon Sep 17 00:00:00 2001
|
||||
From: Heiko Stuebner <heiko@sntech.de>
|
||||
Date: Mon, 10 Feb 2025 23:45:05 +0100
|
||||
Subject: [PATCH] clk: rockchip: rk3576: define clk_otp_phy_g
|
||||
|
||||
The phy clock of the OTP block is also present, but was not defined
|
||||
so far. Though its clk-id already existed, so just define its location.
|
||||
|
||||
Tested-by: Nicolas Frattaroli <nicolas.frattaroli@collabora.com>
|
||||
Signed-off-by: Heiko Stuebner <heiko@sntech.de>
|
||||
Link: https://lore.kernel.org/r/20250210224510.1194963-2-heiko@sntech.de
|
||||
Signed-off-by: Heiko Stuebner <heiko@sntech.de>
|
||||
---
|
||||
drivers/clk/rockchip/clk-rk3576.c | 2 ++
|
||||
1 file changed, 2 insertions(+)
|
||||
|
||||
--- a/drivers/clk/rockchip/clk-rk3576.c
|
||||
+++ b/drivers/clk/rockchip/clk-rk3576.c
|
||||
@@ -541,6 +541,8 @@ static struct rockchip_clk_branch rk3576
|
||||
RK3576_CLKGATE_CON(5), 14, GFLAGS),
|
||||
GATE(CLK_OTPC_AUTO_RD_G, "clk_otpc_auto_rd_g", "xin24m", 0,
|
||||
RK3576_CLKGATE_CON(5), 15, GFLAGS),
|
||||
+ GATE(CLK_OTP_PHY_G, "clk_otp_phy_g", "xin24m", 0,
|
||||
+ RK3576_CLKGATE_CON(6), 0, GFLAGS),
|
||||
COMPOSITE(CLK_MIPI_CAMERAOUT_M0, "clk_mipi_cameraout_m0", mux_24m_spll_gpll_cpll_p, 0,
|
||||
RK3576_CLKSEL_CON(38), 8, 2, MFLAGS, 0, 8, DFLAGS,
|
||||
RK3576_CLKGATE_CON(6), 3, GFLAGS),
|
@@ -0,0 +1,31 @@
|
||||
From 28699ca6d9018201674787e7b6bdce68d9cf7256 Mon Sep 17 00:00:00 2001
|
||||
From: Nicolas Frattaroli <nicolas.frattaroli@collabora.com>
|
||||
Date: Mon, 10 Mar 2025 10:59:56 +0100
|
||||
Subject: [PATCH] dt-bindings: clock: rk3576: add SCMI clocks
|
||||
|
||||
Mainline Linux uses different clock IDs from both downstream and
|
||||
mainline TF-A, which both got them from downstream Linux. If we want to
|
||||
control clocks through SCMI, we'll need to know about these IDs.
|
||||
|
||||
Add the relevant ones prefixed with SCMI_ to the header.
|
||||
|
||||
Signed-off-by: Nicolas Frattaroli <nicolas.frattaroli@collabora.com>
|
||||
Acked-by: "Rob Herring (Arm)" <robh@kernel.org>
|
||||
Link: https://lore.kernel.org/r/20250310-rk3576-scmi-clocks-v1-1-e165deb034e8@collabora.com
|
||||
Signed-off-by: Heiko Stuebner <heiko@sntech.de>
|
||||
---
|
||||
include/dt-bindings/clock/rockchip,rk3576-cru.h | 5 +++++
|
||||
1 file changed, 5 insertions(+)
|
||||
|
||||
--- a/include/dt-bindings/clock/rockchip,rk3576-cru.h
|
||||
+++ b/include/dt-bindings/clock/rockchip,rk3576-cru.h
|
||||
@@ -589,4 +589,9 @@
|
||||
#define PCLK_EDP_S 569
|
||||
#define ACLK_KLAD 570
|
||||
|
||||
+/* SCMI clocks, use these when changing clocks through SCMI */
|
||||
+#define SCMI_ARMCLK_L 10
|
||||
+#define SCMI_ARMCLK_B 11
|
||||
+#define SCMI_CLK_GPU 456
|
||||
+
|
||||
#endif
|
@@ -0,0 +1,39 @@
|
||||
From 4210f21c004a18aad11c55bdaf552e649a4fd286 Mon Sep 17 00:00:00 2001
|
||||
From: Nicolas Frattaroli <nicolas.frattaroli@collabora.com>
|
||||
Date: Fri, 2 May 2025 13:03:07 +0200
|
||||
Subject: [PATCH] dt-bindings: clock: rk3576: add IOC gated clocks
|
||||
|
||||
Certain clocks on the RK3576 are additionally essentially "gated" behind
|
||||
some bit toggles in the IOC GRF range. Downstream ungates these by
|
||||
adding a separate clock driver that maps over the GRF range and leaks
|
||||
their implementation of this into the DT.
|
||||
|
||||
Instead, define some new clock IDs for these, so that consumers of these
|
||||
types of clocks can properly articulate which clock they're using, so
|
||||
that we can then add them to the clock driver for SoCs that need them.
|
||||
|
||||
Acked-by: Krzysztof Kozlowski <krzysztof.kozlowski@linaro.org>
|
||||
Signed-off-by: Nicolas Frattaroli <nicolas.frattaroli@collabora.com>
|
||||
Link: https://lore.kernel.org/r/20250502-rk3576-sai-v3-1-376cef19dd7c@collabora.com
|
||||
Signed-off-by: Heiko Stuebner <heiko@sntech.de>
|
||||
---
|
||||
include/dt-bindings/clock/rockchip,rk3576-cru.h | 10 ++++++++++
|
||||
1 file changed, 10 insertions(+)
|
||||
|
||||
--- a/include/dt-bindings/clock/rockchip,rk3576-cru.h
|
||||
+++ b/include/dt-bindings/clock/rockchip,rk3576-cru.h
|
||||
@@ -594,4 +594,14 @@
|
||||
#define SCMI_ARMCLK_B 11
|
||||
#define SCMI_CLK_GPU 456
|
||||
|
||||
+/* IOC-controlled output clocks */
|
||||
+#define CLK_SAI0_MCLKOUT_TO_IO 571
|
||||
+#define CLK_SAI1_MCLKOUT_TO_IO 572
|
||||
+#define CLK_SAI2_MCLKOUT_TO_IO 573
|
||||
+#define CLK_SAI3_MCLKOUT_TO_IO 574
|
||||
+#define CLK_SAI4_MCLKOUT_TO_IO 575
|
||||
+#define CLK_SAI4_MCLKOUT_TO_IO 575
|
||||
+#define CLK_FSPI0_TO_IO 576
|
||||
+#define CLK_FSPI1_TO_IO 577
|
||||
+
|
||||
#endif
|
@@ -0,0 +1,299 @@
|
||||
From 70a114daf2077472e58b3cac23ba8998e35352f4 Mon Sep 17 00:00:00 2001
|
||||
From: Nicolas Frattaroli <nicolas.frattaroli@collabora.com>
|
||||
Date: Fri, 2 May 2025 13:03:08 +0200
|
||||
Subject: [PATCH] clk: rockchip: introduce auxiliary GRFs
|
||||
|
||||
The MUXGRF clock branch type depends on having access to some sort of
|
||||
GRF as a regmap to be registered. So far, we could easily get away with
|
||||
only ever having one GRF stowed away in the context.
|
||||
|
||||
However, newer Rockchip SoCs, such as the RK3576, have several GRFs
|
||||
which are relevant for clock purposes. It already depends on the pmu0
|
||||
GRF for MUXGRF reasons, but could get away with not refactoring this
|
||||
because it didn't need the sysgrf at all, so could overwrite the pointer
|
||||
in the clock provider to the pmu0 grf regmap handle.
|
||||
|
||||
In preparation for needing to finally access more than one GRF per SoC,
|
||||
let's untangle this. Introduce an auxiliary GRF hashmap, and a GRF type
|
||||
enum. The hashmap is keyed by the enum, and clock branches now have a
|
||||
struct member to store the value of that enum, which defaults to the
|
||||
system GRF.
|
||||
|
||||
The SoC-specific _clk_init function can then insert pointers to GRF
|
||||
regmaps into the hashmap based on the grf type.
|
||||
|
||||
During clock branch registration, we then pick the right GRF for each
|
||||
branch from the hashmap if something other than the sys GRF is
|
||||
requested.
|
||||
|
||||
The reason for doing it with this grf type indirection in the clock
|
||||
branches is so that we don't need to define the MUXGRF branches in a
|
||||
separate step, just to have a direct pointer to a regmap available
|
||||
already.
|
||||
|
||||
Signed-off-by: Nicolas Frattaroli <nicolas.frattaroli@collabora.com>
|
||||
Link: https://lore.kernel.org/r/20250502-rk3576-sai-v3-2-376cef19dd7c@collabora.com
|
||||
Signed-off-by: Heiko Stuebner <heiko@sntech.de>
|
||||
---
|
||||
drivers/clk/rockchip/clk-rk3288.c | 2 +-
|
||||
drivers/clk/rockchip/clk-rk3328.c | 6 +++---
|
||||
drivers/clk/rockchip/clk-rk3568.c | 2 +-
|
||||
drivers/clk/rockchip/clk-rk3576.c | 32 +++++++++++++++++++++----------
|
||||
drivers/clk/rockchip/clk-rv1126.c | 2 +-
|
||||
drivers/clk/rockchip/clk.c | 17 +++++++++++++++-
|
||||
drivers/clk/rockchip/clk.h | 29 +++++++++++++++++++++++++++-
|
||||
7 files changed, 72 insertions(+), 18 deletions(-)
|
||||
|
||||
--- a/drivers/clk/rockchip/clk-rk3288.c
|
||||
+++ b/drivers/clk/rockchip/clk-rk3288.c
|
||||
@@ -418,7 +418,7 @@ static struct rockchip_clk_branch rk3288
|
||||
RK3288_CLKSEL_CON(32), 14, 2, MFLAGS, 8, 5, DFLAGS,
|
||||
RK3288_CLKGATE_CON(3), 11, GFLAGS),
|
||||
MUXGRF(0, "aclk_vcodec_pre", mux_aclk_vcodec_pre_p, CLK_SET_RATE_PARENT,
|
||||
- RK3288_GRF_SOC_CON(0), 7, 1, MFLAGS),
|
||||
+ RK3288_GRF_SOC_CON(0), 7, 1, MFLAGS, grf_type_sys),
|
||||
GATE(ACLK_VCODEC, "aclk_vcodec", "aclk_vcodec_pre", 0,
|
||||
RK3288_CLKGATE_CON(9), 0, GFLAGS),
|
||||
|
||||
--- a/drivers/clk/rockchip/clk-rk3328.c
|
||||
+++ b/drivers/clk/rockchip/clk-rk3328.c
|
||||
@@ -677,9 +677,9 @@ static struct rockchip_clk_branch rk3328
|
||||
RK3328_CLKSEL_CON(27), 15, 1, MFLAGS, 8, 5, DFLAGS,
|
||||
RK3328_CLKGATE_CON(3), 5, GFLAGS),
|
||||
MUXGRF(SCLK_MAC2IO, "clk_mac2io", mux_mac2io_src_p, CLK_SET_RATE_NO_REPARENT,
|
||||
- RK3328_GRF_MAC_CON1, 10, 1, MFLAGS),
|
||||
+ RK3328_GRF_MAC_CON1, 10, 1, MFLAGS, grf_type_sys),
|
||||
MUXGRF(SCLK_MAC2IO_EXT, "clk_mac2io_ext", mux_mac2io_ext_p, CLK_SET_RATE_NO_REPARENT,
|
||||
- RK3328_GRF_SOC_CON4, 14, 1, MFLAGS),
|
||||
+ RK3328_GRF_SOC_CON4, 14, 1, MFLAGS, grf_type_sys),
|
||||
|
||||
COMPOSITE(SCLK_MAC2PHY_SRC, "clk_mac2phy_src", mux_2plls_p, 0,
|
||||
RK3328_CLKSEL_CON(26), 7, 1, MFLAGS, 0, 5, DFLAGS,
|
||||
@@ -692,7 +692,7 @@ static struct rockchip_clk_branch rk3328
|
||||
RK3328_CLKSEL_CON(26), 8, 2, DFLAGS,
|
||||
RK3328_CLKGATE_CON(9), 2, GFLAGS),
|
||||
MUXGRF(SCLK_MAC2PHY, "clk_mac2phy", mux_mac2phy_src_p, CLK_SET_RATE_NO_REPARENT,
|
||||
- RK3328_GRF_MAC_CON2, 10, 1, MFLAGS),
|
||||
+ RK3328_GRF_MAC_CON2, 10, 1, MFLAGS, grf_type_sys),
|
||||
|
||||
FACTOR(0, "xin12m", "xin24m", 0, 1, 2),
|
||||
|
||||
--- a/drivers/clk/rockchip/clk-rk3568.c
|
||||
+++ b/drivers/clk/rockchip/clk-rk3568.c
|
||||
@@ -590,7 +590,7 @@ static struct rockchip_clk_branch rk3568
|
||||
RK3568_CLKSEL_CON(9), 6, 2, MFLAGS, 0, 5, DFLAGS,
|
||||
RK3568_CLKGATE_CON(4), 0, GFLAGS),
|
||||
MUXGRF(CLK_DDR1X, "clk_ddr1x", clk_ddr1x_p, CLK_SET_RATE_PARENT,
|
||||
- RK3568_CLKSEL_CON(9), 15, 1, MFLAGS),
|
||||
+ RK3568_CLKSEL_CON(9), 15, 1, MFLAGS, grf_type_sys),
|
||||
|
||||
COMPOSITE_NOMUX(CLK_MSCH, "clk_msch", "clk_ddr1x", CLK_IGNORE_UNUSED,
|
||||
RK3568_CLKSEL_CON(10), 0, 2, DFLAGS,
|
||||
--- a/drivers/clk/rockchip/clk-rk3576.c
|
||||
+++ b/drivers/clk/rockchip/clk-rk3576.c
|
||||
@@ -1678,13 +1678,13 @@ static struct rockchip_clk_branch rk3576
|
||||
|
||||
/* phy ref */
|
||||
MUXGRF(CLK_PHY_REF_SRC, "clk_phy_ref_src", clk_phy_ref_src_p, 0,
|
||||
- RK3576_PMU0_GRF_OSC_CON6, 4, 1, MFLAGS),
|
||||
+ RK3576_PMU0_GRF_OSC_CON6, 4, 1, MFLAGS, grf_type_pmu0),
|
||||
MUXGRF(CLK_USBPHY_REF_SRC, "clk_usbphy_ref_src", clk_usbphy_ref_src_p, 0,
|
||||
- RK3576_PMU0_GRF_OSC_CON6, 2, 1, MFLAGS),
|
||||
+ RK3576_PMU0_GRF_OSC_CON6, 2, 1, MFLAGS, grf_type_pmu0),
|
||||
MUXGRF(CLK_CPLL_REF_SRC, "clk_cpll_ref_src", clk_cpll_ref_src_p, 0,
|
||||
- RK3576_PMU0_GRF_OSC_CON6, 1, 1, MFLAGS),
|
||||
+ RK3576_PMU0_GRF_OSC_CON6, 1, 1, MFLAGS, grf_type_pmu0),
|
||||
MUXGRF(CLK_AUPLL_REF_SRC, "clk_aupll_ref_src", clk_aupll_ref_src_p, 0,
|
||||
- RK3576_PMU0_GRF_OSC_CON6, 0, 1, MFLAGS),
|
||||
+ RK3576_PMU0_GRF_OSC_CON6, 0, 1, MFLAGS, grf_type_pmu0),
|
||||
|
||||
/* secure ns */
|
||||
COMPOSITE_NODIV(ACLK_SECURE_NS, "aclk_secure_ns", mux_350m_175m_116m_24m_p, CLK_IS_CRITICAL,
|
||||
@@ -1727,13 +1727,14 @@ static void __init rk3576_clk_init(struc
|
||||
struct rockchip_clk_provider *ctx;
|
||||
unsigned long clk_nr_clks;
|
||||
void __iomem *reg_base;
|
||||
- struct regmap *grf;
|
||||
+ struct rockchip_aux_grf *pmu0_grf_e;
|
||||
+ struct regmap *pmu0_grf;
|
||||
|
||||
clk_nr_clks = rockchip_clk_find_max_clk_id(rk3576_clk_branches,
|
||||
ARRAY_SIZE(rk3576_clk_branches)) + 1;
|
||||
|
||||
- grf = syscon_regmap_lookup_by_compatible("rockchip,rk3576-pmu0-grf");
|
||||
- if (IS_ERR(grf)) {
|
||||
+ pmu0_grf = syscon_regmap_lookup_by_compatible("rockchip,rk3576-pmu0-grf");
|
||||
+ if (IS_ERR(pmu0_grf)) {
|
||||
pr_err("%s: could not get PMU0 GRF syscon\n", __func__);
|
||||
return;
|
||||
}
|
||||
@@ -1747,11 +1748,16 @@ static void __init rk3576_clk_init(struc
|
||||
ctx = rockchip_clk_init(np, reg_base, clk_nr_clks);
|
||||
if (IS_ERR(ctx)) {
|
||||
pr_err("%s: rockchip clk init failed\n", __func__);
|
||||
- iounmap(reg_base);
|
||||
- return;
|
||||
+ goto err_unmap;
|
||||
}
|
||||
|
||||
- ctx->grf = grf;
|
||||
+ pmu0_grf_e = kzalloc(sizeof(*pmu0_grf_e), GFP_KERNEL);
|
||||
+ if (!pmu0_grf_e)
|
||||
+ goto err_unmap;
|
||||
+
|
||||
+ pmu0_grf_e->grf = pmu0_grf;
|
||||
+ pmu0_grf_e->type = grf_type_pmu0;
|
||||
+ hash_add(ctx->aux_grf_table, &pmu0_grf_e->node, grf_type_pmu0);
|
||||
|
||||
rockchip_clk_register_plls(ctx, rk3576_pll_clks,
|
||||
ARRAY_SIZE(rk3576_pll_clks),
|
||||
@@ -1774,6 +1780,12 @@ static void __init rk3576_clk_init(struc
|
||||
rockchip_register_restart_notifier(ctx, RK3576_GLB_SRST_FST, NULL);
|
||||
|
||||
rockchip_clk_of_add_provider(np, ctx);
|
||||
+
|
||||
+ return;
|
||||
+
|
||||
+err_unmap:
|
||||
+ iounmap(reg_base);
|
||||
+ return;
|
||||
}
|
||||
|
||||
CLK_OF_DECLARE(rk3576_cru, "rockchip,rk3576-cru", rk3576_clk_init);
|
||||
--- a/drivers/clk/rockchip/clk-rv1126.c
|
||||
+++ b/drivers/clk/rockchip/clk-rv1126.c
|
||||
@@ -857,7 +857,7 @@ static struct rockchip_clk_branch rv1126
|
||||
RV1126_GMAC_CON, 5, 1, MFLAGS),
|
||||
MUXGRF(CLK_GMAC_SRC, "clk_gmac_src", mux_clk_gmac_src_p, CLK_SET_RATE_PARENT |
|
||||
CLK_SET_RATE_NO_REPARENT,
|
||||
- RV1126_GRF_IOFUNC_CON1, 12, 1, MFLAGS),
|
||||
+ RV1126_GRF_IOFUNC_CON1, 12, 1, MFLAGS, grf_type_sys),
|
||||
|
||||
GATE(CLK_GMAC_REF, "clk_gmac_ref", "clk_gmac_src", 0,
|
||||
RV1126_CLKGATE_CON(20), 7, GFLAGS),
|
||||
--- a/drivers/clk/rockchip/clk.c
|
||||
+++ b/drivers/clk/rockchip/clk.c
|
||||
@@ -382,6 +382,8 @@ static struct rockchip_clk_provider *roc
|
||||
ctx->cru_node = np;
|
||||
spin_lock_init(&ctx->lock);
|
||||
|
||||
+ hash_init(ctx->aux_grf_table);
|
||||
+
|
||||
ctx->grf = syscon_regmap_lookup_by_phandle(ctx->cru_node,
|
||||
"rockchip,grf");
|
||||
|
||||
@@ -496,6 +498,8 @@ void rockchip_clk_register_branches(stru
|
||||
struct rockchip_clk_branch *list,
|
||||
unsigned int nr_clk)
|
||||
{
|
||||
+ struct regmap *grf = ctx->grf;
|
||||
+ struct rockchip_aux_grf *agrf;
|
||||
struct clk *clk;
|
||||
unsigned int idx;
|
||||
unsigned long flags;
|
||||
@@ -504,6 +508,17 @@ void rockchip_clk_register_branches(stru
|
||||
flags = list->flags;
|
||||
clk = NULL;
|
||||
|
||||
+ /* for GRF-dependent branches, choose the right grf first */
|
||||
+ if (list->branch_type == branch_muxgrf &&
|
||||
+ list->grf_type != grf_type_sys) {
|
||||
+ hash_for_each_possible(ctx->aux_grf_table, agrf, node, list->grf_type) {
|
||||
+ if (agrf->type == list->grf_type) {
|
||||
+ grf = agrf->grf;
|
||||
+ break;
|
||||
+ }
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
/* catch simple muxes */
|
||||
switch (list->branch_type) {
|
||||
case branch_mux:
|
||||
@@ -526,7 +541,7 @@ void rockchip_clk_register_branches(stru
|
||||
case branch_muxgrf:
|
||||
clk = rockchip_clk_register_muxgrf(list->name,
|
||||
list->parent_names, list->num_parents,
|
||||
- flags, ctx->grf, list->muxdiv_offset,
|
||||
+ flags, grf, list->muxdiv_offset,
|
||||
list->mux_shift, list->mux_width,
|
||||
list->mux_flags);
|
||||
break;
|
||||
--- a/drivers/clk/rockchip/clk.h
|
||||
+++ b/drivers/clk/rockchip/clk.h
|
||||
@@ -19,6 +19,7 @@
|
||||
|
||||
#include <linux/io.h>
|
||||
#include <linux/clk-provider.h>
|
||||
+#include <linux/hashtable.h>
|
||||
|
||||
struct clk;
|
||||
|
||||
@@ -381,12 +382,35 @@ enum rockchip_pll_type {
|
||||
.k = _k, \
|
||||
}
|
||||
|
||||
+enum rockchip_grf_type {
|
||||
+ grf_type_sys = 0,
|
||||
+ grf_type_pmu0,
|
||||
+ grf_type_pmu1,
|
||||
+ grf_type_ioc,
|
||||
+};
|
||||
+
|
||||
+/* ceil(sqrt(enums in rockchip_grf_type - 1)) */
|
||||
+#define GRF_HASH_ORDER 2
|
||||
+
|
||||
+/**
|
||||
+ * struct rockchip_aux_grf - entry for the aux_grf_table hashtable
|
||||
+ * @grf: pointer to the grf this entry references
|
||||
+ * @type: what type of GRF this is
|
||||
+ * @node: hlist node
|
||||
+ */
|
||||
+struct rockchip_aux_grf {
|
||||
+ struct regmap *grf;
|
||||
+ enum rockchip_grf_type type;
|
||||
+ struct hlist_node node;
|
||||
+};
|
||||
+
|
||||
/**
|
||||
* struct rockchip_clk_provider - information about clock provider
|
||||
* @reg_base: virtual address for the register base.
|
||||
* @clk_data: holds clock related data like clk* and number of clocks.
|
||||
* @cru_node: device-node of the clock-provider
|
||||
* @grf: regmap of the general-register-files syscon
|
||||
+ * @aux_grf_table: hashtable of auxiliary GRF regmaps, indexed by grf_type
|
||||
* @lock: maintains exclusion between callbacks for a given clock-provider.
|
||||
*/
|
||||
struct rockchip_clk_provider {
|
||||
@@ -394,6 +418,7 @@ struct rockchip_clk_provider {
|
||||
struct clk_onecell_data clk_data;
|
||||
struct device_node *cru_node;
|
||||
struct regmap *grf;
|
||||
+ DECLARE_HASHTABLE(aux_grf_table, GRF_HASH_ORDER);
|
||||
spinlock_t lock;
|
||||
};
|
||||
|
||||
@@ -599,6 +624,7 @@ struct rockchip_clk_branch {
|
||||
u8 gate_shift;
|
||||
u8 gate_flags;
|
||||
unsigned int linked_clk_id;
|
||||
+ enum rockchip_grf_type grf_type;
|
||||
struct rockchip_clk_branch *child;
|
||||
};
|
||||
|
||||
@@ -839,7 +865,7 @@ struct rockchip_clk_branch {
|
||||
.mux_table = mt, \
|
||||
}
|
||||
|
||||
-#define MUXGRF(_id, cname, pnames, f, o, s, w, mf) \
|
||||
+#define MUXGRF(_id, cname, pnames, f, o, s, w, mf, gt) \
|
||||
{ \
|
||||
.id = _id, \
|
||||
.branch_type = branch_muxgrf, \
|
||||
@@ -852,6 +878,7 @@ struct rockchip_clk_branch {
|
||||
.mux_width = w, \
|
||||
.mux_flags = mf, \
|
||||
.gate_offset = -1, \
|
||||
+ .grf_type = gt, \
|
||||
}
|
||||
|
||||
#define DIV(_id, cname, pname, f, o, s, w, df) \
|
@@ -0,0 +1,213 @@
|
||||
From e277168cabe9fd99e647f5dad0bc846d5d6b0093 Mon Sep 17 00:00:00 2001
|
||||
From: Nicolas Frattaroli <nicolas.frattaroli@collabora.com>
|
||||
Date: Fri, 2 May 2025 13:03:09 +0200
|
||||
Subject: [PATCH] clk: rockchip: introduce GRF gates
|
||||
|
||||
Some rockchip SoCs, namely the RK3576, have bits in a General Register
|
||||
File (GRF) that act just like clock gates. The downstream vendor kernel
|
||||
simply maps over the already mapped GRF range with a generic clock gate
|
||||
driver. This solution isn't suitable for upstream, as a memory range
|
||||
will be in use by multiple drivers at the same time, and it leaks
|
||||
implementation details into the device tree.
|
||||
|
||||
Instead, implement this with a new clock branch type in the Rockchip
|
||||
clock driver: GRF gates. Somewhat akin to MUXGRF, this clock branch
|
||||
depends on the type of GRF, but functions like a gate instead.
|
||||
|
||||
Signed-off-by: Nicolas Frattaroli <nicolas.frattaroli@collabora.com>
|
||||
Link: https://lore.kernel.org/r/20250502-rk3576-sai-v3-3-376cef19dd7c@collabora.com
|
||||
Signed-off-by: Heiko Stuebner <heiko@sntech.de>
|
||||
---
|
||||
drivers/clk/rockchip/Makefile | 1 +
|
||||
drivers/clk/rockchip/clk.c | 9 ++-
|
||||
drivers/clk/rockchip/clk.h | 20 ++++++
|
||||
drivers/clk/rockchip/gate-grf.c | 105 ++++++++++++++++++++++++++++++++
|
||||
4 files changed, 134 insertions(+), 1 deletion(-)
|
||||
create mode 100644 drivers/clk/rockchip/gate-grf.c
|
||||
|
||||
--- a/drivers/clk/rockchip/Makefile
|
||||
+++ b/drivers/clk/rockchip/Makefile
|
||||
@@ -14,6 +14,7 @@ clk-rockchip-y += clk-mmc-phase.o
|
||||
clk-rockchip-y += clk-muxgrf.o
|
||||
clk-rockchip-y += clk-ddr.o
|
||||
clk-rockchip-y += gate-link.o
|
||||
+clk-rockchip-y += gate-grf.o
|
||||
clk-rockchip-$(CONFIG_RESET_CONTROLLER) += softrst.o
|
||||
|
||||
obj-$(CONFIG_CLK_PX30) += clk-px30.o
|
||||
--- a/drivers/clk/rockchip/clk.c
|
||||
+++ b/drivers/clk/rockchip/clk.c
|
||||
@@ -509,7 +509,7 @@ void rockchip_clk_register_branches(stru
|
||||
clk = NULL;
|
||||
|
||||
/* for GRF-dependent branches, choose the right grf first */
|
||||
- if (list->branch_type == branch_muxgrf &&
|
||||
+ if ((list->branch_type == branch_muxgrf || list->branch_type == branch_grf_gate) &&
|
||||
list->grf_type != grf_type_sys) {
|
||||
hash_for_each_possible(ctx->aux_grf_table, agrf, node, list->grf_type) {
|
||||
if (agrf->type == list->grf_type) {
|
||||
@@ -588,6 +588,13 @@ void rockchip_clk_register_branches(stru
|
||||
ctx->reg_base + list->gate_offset,
|
||||
list->gate_shift, list->gate_flags, &ctx->lock);
|
||||
break;
|
||||
+ case branch_grf_gate:
|
||||
+ flags |= CLK_SET_RATE_PARENT;
|
||||
+ clk = rockchip_clk_register_gate_grf(list->name,
|
||||
+ list->parent_names[0], flags, grf,
|
||||
+ list->gate_offset, list->gate_shift,
|
||||
+ list->gate_flags);
|
||||
+ break;
|
||||
case branch_composite:
|
||||
clk = rockchip_clk_register_branch(list->name,
|
||||
list->parent_names, list->num_parents,
|
||||
--- a/drivers/clk/rockchip/clk.h
|
||||
+++ b/drivers/clk/rockchip/clk.h
|
||||
@@ -586,6 +586,11 @@ struct clk *rockchip_clk_register_muxgrf
|
||||
int flags, struct regmap *grf, int reg,
|
||||
int shift, int width, int mux_flags);
|
||||
|
||||
+struct clk *rockchip_clk_register_gate_grf(const char *name,
|
||||
+ const char *parent_name, unsigned long flags,
|
||||
+ struct regmap *regmap, unsigned int reg,
|
||||
+ unsigned int shift, u8 gate_flags);
|
||||
+
|
||||
#define PNAME(x) static const char *const x[] __initconst
|
||||
|
||||
enum rockchip_clk_branch_type {
|
||||
@@ -595,6 +600,7 @@ enum rockchip_clk_branch_type {
|
||||
branch_divider,
|
||||
branch_fraction_divider,
|
||||
branch_gate,
|
||||
+ branch_grf_gate,
|
||||
branch_linked_gate,
|
||||
branch_mmc,
|
||||
branch_inverter,
|
||||
@@ -924,6 +930,20 @@ struct rockchip_clk_branch {
|
||||
.gate_flags = gf, \
|
||||
}
|
||||
|
||||
+#define GATE_GRF(_id, cname, pname, f, o, b, gf, gt) \
|
||||
+ { \
|
||||
+ .id = _id, \
|
||||
+ .branch_type = branch_grf_gate, \
|
||||
+ .name = cname, \
|
||||
+ .parent_names = (const char *[]){ pname }, \
|
||||
+ .num_parents = 1, \
|
||||
+ .flags = f, \
|
||||
+ .gate_offset = o, \
|
||||
+ .gate_shift = b, \
|
||||
+ .gate_flags = gf, \
|
||||
+ .grf_type = gt, \
|
||||
+ }
|
||||
+
|
||||
#define GATE_LINK(_id, cname, pname, linkedclk, f, o, b, gf) \
|
||||
{ \
|
||||
.id = _id, \
|
||||
--- /dev/null
|
||||
+++ b/drivers/clk/rockchip/gate-grf.c
|
||||
@@ -0,0 +1,105 @@
|
||||
+// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
+/*
|
||||
+ * Copyright (c) 2025 Collabora Ltd.
|
||||
+ * Author: Nicolas Frattaroli <nicolas.frattaroli@collabora.com>
|
||||
+ *
|
||||
+ * Certain clocks on Rockchip are "gated" behind an additional register bit
|
||||
+ * write in a GRF register, such as the SAI MCLKs on RK3576. This code
|
||||
+ * implements a clock driver for these types of gates, based on regmaps.
|
||||
+ */
|
||||
+
|
||||
+#include <linux/clk.h>
|
||||
+#include <linux/clk-provider.h>
|
||||
+#include <linux/regmap.h>
|
||||
+#include <linux/slab.h>
|
||||
+#include "clk.h"
|
||||
+
|
||||
+struct rockchip_gate_grf {
|
||||
+ struct clk_hw hw;
|
||||
+ struct regmap *regmap;
|
||||
+ unsigned int reg;
|
||||
+ unsigned int shift;
|
||||
+ u8 flags;
|
||||
+};
|
||||
+
|
||||
+#define to_gate_grf(_hw) container_of(_hw, struct rockchip_gate_grf, hw)
|
||||
+
|
||||
+static int rockchip_gate_grf_enable(struct clk_hw *hw)
|
||||
+{
|
||||
+ struct rockchip_gate_grf *gate = to_gate_grf(hw);
|
||||
+ u32 val = !(gate->flags & CLK_GATE_SET_TO_DISABLE) ? BIT(gate->shift) : 0;
|
||||
+ u32 hiword = ((gate->flags & CLK_GATE_HIWORD_MASK) ? 1 : 0) << (gate->shift + 16);
|
||||
+ int ret;
|
||||
+
|
||||
+ ret = regmap_update_bits(gate->regmap, gate->reg,
|
||||
+ hiword | BIT(gate->shift), hiword | val);
|
||||
+
|
||||
+ return ret;
|
||||
+}
|
||||
+
|
||||
+static void rockchip_gate_grf_disable(struct clk_hw *hw)
|
||||
+{
|
||||
+ struct rockchip_gate_grf *gate = to_gate_grf(hw);
|
||||
+ u32 val = !(gate->flags & CLK_GATE_SET_TO_DISABLE) ? 0 : BIT(gate->shift);
|
||||
+ u32 hiword = ((gate->flags & CLK_GATE_HIWORD_MASK) ? 1 : 0) << (gate->shift + 16);
|
||||
+
|
||||
+ regmap_update_bits(gate->regmap, gate->reg,
|
||||
+ hiword | BIT(gate->shift), hiword | val);
|
||||
+}
|
||||
+
|
||||
+static int rockchip_gate_grf_is_enabled(struct clk_hw *hw)
|
||||
+{
|
||||
+ struct rockchip_gate_grf *gate = to_gate_grf(hw);
|
||||
+ bool invert = !!(gate->flags & CLK_GATE_SET_TO_DISABLE);
|
||||
+ int ret;
|
||||
+
|
||||
+ ret = regmap_test_bits(gate->regmap, gate->reg, BIT(gate->shift));
|
||||
+ if (ret < 0)
|
||||
+ ret = 0;
|
||||
+
|
||||
+ return invert ? 1 - ret : ret;
|
||||
+
|
||||
+}
|
||||
+
|
||||
+static const struct clk_ops rockchip_gate_grf_ops = {
|
||||
+ .enable = rockchip_gate_grf_enable,
|
||||
+ .disable = rockchip_gate_grf_disable,
|
||||
+ .is_enabled = rockchip_gate_grf_is_enabled,
|
||||
+};
|
||||
+
|
||||
+struct clk *rockchip_clk_register_gate_grf(const char *name,
|
||||
+ const char *parent_name, unsigned long flags,
|
||||
+ struct regmap *regmap, unsigned int reg, unsigned int shift,
|
||||
+ u8 gate_flags)
|
||||
+{
|
||||
+ struct rockchip_gate_grf *gate;
|
||||
+ struct clk_init_data init;
|
||||
+ struct clk *clk;
|
||||
+
|
||||
+ if (IS_ERR(regmap)) {
|
||||
+ pr_err("%s: regmap not available\n", __func__);
|
||||
+ return ERR_PTR(-EOPNOTSUPP);
|
||||
+ }
|
||||
+
|
||||
+ gate = kzalloc(sizeof(*gate), GFP_KERNEL);
|
||||
+ if (!gate)
|
||||
+ return ERR_PTR(-ENOMEM);
|
||||
+
|
||||
+ init.name = name;
|
||||
+ init.flags = flags;
|
||||
+ init.num_parents = parent_name ? 1 : 0;
|
||||
+ init.parent_names = parent_name ? &parent_name : NULL;
|
||||
+ init.ops = &rockchip_gate_grf_ops;
|
||||
+
|
||||
+ gate->hw.init = &init;
|
||||
+ gate->regmap = regmap;
|
||||
+ gate->reg = reg;
|
||||
+ gate->shift = shift;
|
||||
+ gate->flags = gate_flags;
|
||||
+
|
||||
+ clk = clk_register(NULL, &gate->hw);
|
||||
+ if (IS_ERR(clk))
|
||||
+ kfree(gate);
|
||||
+
|
||||
+ return clk;
|
||||
+}
|
@@ -0,0 +1,90 @@
|
||||
From 9199ec29f0977efee223791c9ee3eb402d23f8ba Mon Sep 17 00:00:00 2001
|
||||
From: Nicolas Frattaroli <nicolas.frattaroli@collabora.com>
|
||||
Date: Fri, 2 May 2025 13:03:10 +0200
|
||||
Subject: [PATCH] clk: rockchip: add GATE_GRFs for SAI MCLKOUT to rk3576
|
||||
|
||||
The Rockchip RK3576 gates the SAI MCLKOUT clocks behind some IOC GRF
|
||||
writes.
|
||||
|
||||
Add these clock branches, and add the IOC GRF to the auxiliary GRF
|
||||
hashtable.
|
||||
|
||||
Signed-off-by: Nicolas Frattaroli <nicolas.frattaroli@collabora.com>
|
||||
Link: https://lore.kernel.org/r/20250502-rk3576-sai-v3-4-376cef19dd7c@collabora.com
|
||||
Signed-off-by: Heiko Stuebner <heiko@sntech.de>
|
||||
---
|
||||
drivers/clk/rockchip/clk-rk3576.c | 27 +++++++++++++++++++++++++++
|
||||
1 file changed, 27 insertions(+)
|
||||
|
||||
--- a/drivers/clk/rockchip/clk-rk3576.c
|
||||
+++ b/drivers/clk/rockchip/clk-rk3576.c
|
||||
@@ -15,6 +15,7 @@
|
||||
|
||||
#define RK3576_GRF_SOC_STATUS0 0x600
|
||||
#define RK3576_PMU0_GRF_OSC_CON6 0x18
|
||||
+#define RK3576_VCCIO_IOC_MISC_CON0 0x6400
|
||||
|
||||
enum rk3576_plls {
|
||||
bpll, lpll, vpll, aupll, cpll, gpll, ppll,
|
||||
@@ -1481,6 +1482,14 @@ static struct rockchip_clk_branch rk3576
|
||||
RK3576_CLKGATE_CON(10), 0, GFLAGS),
|
||||
GATE(CLK_SAI0_MCLKOUT, "clk_sai0_mclkout", "mclk_sai0_8ch", 0,
|
||||
RK3576_CLKGATE_CON(10), 1, GFLAGS),
|
||||
+ GATE_GRF(CLK_SAI0_MCLKOUT_TO_IO, "mclk_sai0_to_io", "clk_sai0_mclkout",
|
||||
+ 0, RK3576_VCCIO_IOC_MISC_CON0, 0, GFLAGS, grf_type_ioc),
|
||||
+ GATE_GRF(CLK_SAI1_MCLKOUT_TO_IO, "mclk_sai1_to_io", "clk_sai1_mclkout",
|
||||
+ 0, RK3576_VCCIO_IOC_MISC_CON0, 1, GFLAGS, grf_type_ioc),
|
||||
+ GATE_GRF(CLK_SAI2_MCLKOUT_TO_IO, "mclk_sai2_to_io", "clk_sai2_mclkout",
|
||||
+ 0, RK3576_VCCIO_IOC_MISC_CON0, 2, GFLAGS, grf_type_ioc),
|
||||
+ GATE_GRF(CLK_SAI3_MCLKOUT_TO_IO, "mclk_sai3_to_io", "clk_sai3_mclkout",
|
||||
+ 0, RK3576_VCCIO_IOC_MISC_CON0, 3, GFLAGS, grf_type_ioc),
|
||||
|
||||
/* sdgmac */
|
||||
COMPOSITE_NODIV(HCLK_SDGMAC_ROOT, "hclk_sdgmac_root", mux_200m_100m_50m_24m_p, 0,
|
||||
@@ -1727,7 +1736,9 @@ static void __init rk3576_clk_init(struc
|
||||
struct rockchip_clk_provider *ctx;
|
||||
unsigned long clk_nr_clks;
|
||||
void __iomem *reg_base;
|
||||
+ struct rockchip_aux_grf *ioc_grf_e;
|
||||
struct rockchip_aux_grf *pmu0_grf_e;
|
||||
+ struct regmap *ioc_grf;
|
||||
struct regmap *pmu0_grf;
|
||||
|
||||
clk_nr_clks = rockchip_clk_find_max_clk_id(rk3576_clk_branches,
|
||||
@@ -1739,6 +1750,12 @@ static void __init rk3576_clk_init(struc
|
||||
return;
|
||||
}
|
||||
|
||||
+ ioc_grf = syscon_regmap_lookup_by_compatible("rockchip,rk3576-ioc-grf");
|
||||
+ if (IS_ERR(ioc_grf)) {
|
||||
+ pr_err("%s: could not get IOC GRF syscon\n", __func__);
|
||||
+ return;
|
||||
+ }
|
||||
+
|
||||
reg_base = of_iomap(np, 0);
|
||||
if (!reg_base) {
|
||||
pr_err("%s: could not map cru region\n", __func__);
|
||||
@@ -1759,6 +1776,14 @@ static void __init rk3576_clk_init(struc
|
||||
pmu0_grf_e->type = grf_type_pmu0;
|
||||
hash_add(ctx->aux_grf_table, &pmu0_grf_e->node, grf_type_pmu0);
|
||||
|
||||
+ ioc_grf_e = kzalloc(sizeof(*ioc_grf_e), GFP_KERNEL);
|
||||
+ if (!ioc_grf_e)
|
||||
+ goto err_free_pmu0;
|
||||
+
|
||||
+ ioc_grf_e->grf = ioc_grf;
|
||||
+ ioc_grf_e->type = grf_type_ioc;
|
||||
+ hash_add(ctx->aux_grf_table, &ioc_grf_e->node, grf_type_ioc);
|
||||
+
|
||||
rockchip_clk_register_plls(ctx, rk3576_pll_clks,
|
||||
ARRAY_SIZE(rk3576_pll_clks),
|
||||
RK3576_GRF_SOC_STATUS0);
|
||||
@@ -1783,6 +1808,8 @@ static void __init rk3576_clk_init(struc
|
||||
|
||||
return;
|
||||
|
||||
+err_free_pmu0:
|
||||
+ kfree(pmu0_grf_e);
|
||||
err_unmap:
|
||||
iounmap(reg_base);
|
||||
return;
|
@@ -0,0 +1,27 @@
|
||||
From 92da5c3cba23ee4be2c043bb63a551c89c48de18 Mon Sep 17 00:00:00 2001
|
||||
From: Heiko Stuebner <heiko@sntech.de>
|
||||
Date: Thu, 15 May 2025 10:26:51 +0200
|
||||
Subject: [PATCH] clk: rockchip: rk3576: add missing slab.h include
|
||||
|
||||
The change for auxiliary GRFs introduced kzalloc usage into the rk3576 clock
|
||||
driver, but missed adding the header for its prototype. Add it now.
|
||||
|
||||
Reported-by: kernel test robot <lkp@intel.com>
|
||||
Closes: https://lore.kernel.org/oe-kbuild-all/202505150941.KWKskr2c-lkp@intel.com/
|
||||
Fixes: 70a114daf207 ("clk: rockchip: introduce auxiliary GRFs")
|
||||
Signed-off-by: Heiko Stuebner <heiko@sntech.de>
|
||||
Link: https://lore.kernel.org/r/20250515082652.2503063-1-heiko@sntech.de
|
||||
---
|
||||
drivers/clk/rockchip/clk-rk3576.c | 1 +
|
||||
1 file changed, 1 insertion(+)
|
||||
|
||||
--- a/drivers/clk/rockchip/clk-rk3576.c
|
||||
+++ b/drivers/clk/rockchip/clk-rk3576.c
|
||||
@@ -10,6 +10,7 @@
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/syscore_ops.h>
|
||||
#include <linux/mfd/syscon.h>
|
||||
+#include <linux/slab.h>
|
||||
#include <dt-bindings/clock/rockchip,rk3576-cru.h>
|
||||
#include "clk.h"
|
||||
|
@@ -0,0 +1,55 @@
|
||||
From 58ebba35ddab4868c921f970b60a77032362ef4c Mon Sep 17 00:00:00 2001
|
||||
From: Shawn Lin <shawn.lin@rock-chips.com>
|
||||
Date: Wed, 5 Feb 2025 14:15:53 +0800
|
||||
Subject: [PATCH] pmdomain: rockchip: Add smc call to inform firmware
|
||||
|
||||
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>
|
||||
Reviewed-by: Ulf Hansson <ulf.hansson@linaro.org>
|
||||
Acked-by: Heiko Stuebner <heiko@sntech.de>
|
||||
Link: https://lore.kernel.org/r/1738736156-119203-5-git-send-email-shawn.lin@rock-chips.com
|
||||
Signed-off-by: Ulf Hansson <ulf.hansson@linaro.org>
|
||||
---
|
||||
drivers/pmdomain/rockchip/pm-domains.c | 8 ++++++++
|
||||
1 file changed, 8 insertions(+)
|
||||
|
||||
--- 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_do
|
||||
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_do
|
||||
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)
|
@@ -0,0 +1,37 @@
|
||||
From 61eeb9678789644f118eff608d9031b5de4f719d Mon Sep 17 00:00:00 2001
|
||||
From: Shawn Lin <shawn.lin@rock-chips.com>
|
||||
Date: Wed, 19 Feb 2025 08:58:09 +0800
|
||||
Subject: [PATCH] pmdomain: rockchip: Check if SMC could be handled by TA
|
||||
|
||||
Non-existent trusted-firmware could lead to SMC calls into some unset
|
||||
location, that breaks the system. Let's check that it's supported before
|
||||
executing the SMC.
|
||||
|
||||
Reported-by: Steven Price <steven.price@arm.com>
|
||||
Suggested-by: Heiko Stuebner <heiko@sntech.de>
|
||||
Fixes: 58ebba35ddab ("pmdomain: rockchip: Add smc call to inform firmware")
|
||||
Signed-off-by: Shawn Lin <shawn.lin@rock-chips.com>
|
||||
Reviewed-by: Heiko Stuebner <heiko@sntech.de>
|
||||
Tested-by: Steven Price <steven.price@arm.com>
|
||||
Link: https://lore.kernel.org/r/1739926689-151827-1-git-send-email-shawn.lin@rock-chips.com
|
||||
Signed-off-by: Ulf Hansson <ulf.hansson@linaro.org>
|
||||
---
|
||||
drivers/pmdomain/rockchip/pm-domains.c | 7 ++++---
|
||||
1 file changed, 4 insertions(+), 3 deletions(-)
|
||||
|
||||
--- a/drivers/pmdomain/rockchip/pm-domains.c
|
||||
+++ b/drivers/pmdomain/rockchip/pm-domains.c
|
||||
@@ -572,9 +572,10 @@ static void rockchip_do_pmu_set_power_do
|
||||
}
|
||||
|
||||
/* 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);
|
||||
+ if (arm_smccc_1_1_get_conduit() != SMCCC_CONDUIT_NONE)
|
||||
+ 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)
|
@@ -0,0 +1,26 @@
|
||||
From bc4bc2a1609712e6c5de01be8a20341b710dc99b Mon Sep 17 00:00:00 2001
|
||||
From: Ulf Hansson <ulf.hansson@linaro.org>
|
||||
Date: Mon, 24 Feb 2025 13:05:29 +0100
|
||||
Subject: [PATCH] pmdomain: rockchip: Fix build error
|
||||
|
||||
To resolve the build error with undefined reference to
|
||||
`arm_smccc_1_1_get_conduit', let's add a build dependency to
|
||||
HAVE_ARM_SMCCC_DISCOVERY.
|
||||
|
||||
Reported-by: Stephen Rothwell <sfr@canb.auug.org.au>
|
||||
Fixes: 61eeb9678789 ("pmdomain: rockchip: Check if SMC could be handled by TA")
|
||||
Signed-off-by: Ulf Hansson <ulf.hansson@linaro.org>
|
||||
---
|
||||
drivers/pmdomain/rockchip/Kconfig | 1 +
|
||||
1 file changed, 1 insertion(+)
|
||||
|
||||
--- a/drivers/pmdomain/rockchip/Kconfig
|
||||
+++ b/drivers/pmdomain/rockchip/Kconfig
|
||||
@@ -4,6 +4,7 @@ if ARCH_ROCKCHIP || COMPILE_TEST
|
||||
config ROCKCHIP_PM_DOMAINS
|
||||
bool "Rockchip generic power domain"
|
||||
depends on PM
|
||||
+ depends on HAVE_ARM_SMCCC_DISCOVERY
|
||||
select PM_GENERIC_DOMAINS
|
||||
help
|
||||
Say y here to enable power domain support.
|
@@ -0,0 +1,40 @@
|
||||
From 9a9f71b2a3a7491c10ceea699e1999298db5c596 Mon Sep 17 00:00:00 2001
|
||||
From: Nicolas Frattaroli <nicolas.frattaroli@collabora.com>
|
||||
Date: Tue, 10 Jun 2025 14:32:37 +0200
|
||||
Subject: [PATCH] thermal/drivers/rockchip: Rename rk_tsadcv3_tshut_mode
|
||||
|
||||
The "v" version specifier here refers to the hardware IP revision.
|
||||
Mainline deviated from downstream here by calling the v4 revision v3 as
|
||||
it didn't support the v3 hardware revision at all.
|
||||
|
||||
This creates needless confusion, so rename it to rk_tsadcv4_tshut_mode
|
||||
to be consistent with what the hardware wants to be called.
|
||||
|
||||
Signed-off-by: Nicolas Frattaroli <nicolas.frattaroli@collabora.com>
|
||||
Reviewed-by: Heiko Stuebner <heiko@sntech.de>
|
||||
Link: https://lore.kernel.org/r/20250610-rk3576-tsadc-upstream-v6-1-b6e9efbf1015@collabora.com
|
||||
Signed-off-by: Daniel Lezcano <daniel.lezcano@linaro.org>
|
||||
---
|
||||
drivers/thermal/rockchip_thermal.c | 4 ++--
|
||||
1 file changed, 2 insertions(+), 2 deletions(-)
|
||||
|
||||
--- a/drivers/thermal/rockchip_thermal.c
|
||||
+++ b/drivers/thermal/rockchip_thermal.c
|
||||
@@ -1045,7 +1045,7 @@ static void rk_tsadcv2_tshut_mode(int ch
|
||||
writel_relaxed(val, regs + TSADCV2_INT_EN);
|
||||
}
|
||||
|
||||
-static void rk_tsadcv3_tshut_mode(int chn, void __iomem *regs,
|
||||
+static void rk_tsadcv4_tshut_mode(int chn, void __iomem *regs,
|
||||
enum tshut_mode mode)
|
||||
{
|
||||
u32 val_gpio, val_cru;
|
||||
@@ -1297,7 +1297,7 @@ static const struct rockchip_tsadc_chip
|
||||
.get_temp = rk_tsadcv4_get_temp,
|
||||
.set_alarm_temp = rk_tsadcv3_alarm_temp,
|
||||
.set_tshut_temp = rk_tsadcv3_tshut_temp,
|
||||
- .set_tshut_mode = rk_tsadcv3_tshut_mode,
|
||||
+ .set_tshut_mode = rk_tsadcv4_tshut_mode,
|
||||
.table = {
|
||||
.id = rk3588_code_table,
|
||||
.length = ARRAY_SIZE(rk3588_code_table),
|
@@ -0,0 +1,61 @@
|
||||
From feb69bccf5d3eb31918df86638abc82594390ba5 Mon Sep 17 00:00:00 2001
|
||||
From: Ye Zhang <ye.zhang@rock-chips.com>
|
||||
Date: Tue, 10 Jun 2025 14:32:39 +0200
|
||||
Subject: [PATCH] thermal/drivers/rockchip: Support RK3576 SoC in the thermal
|
||||
driver
|
||||
|
||||
The RK3576 SoC has six TS-ADC channels: TOP, BIG_CORE, LITTLE_CORE,
|
||||
DDR, NPU and GPU.
|
||||
|
||||
Signed-off-by: Ye Zhang <ye.zhang@rock-chips.com>
|
||||
[ported to mainline, reworded commit message]
|
||||
Signed-off-by: Nicolas Frattaroli <nicolas.frattaroli@collabora.com>
|
||||
Reviewed-by: Heiko Stuebner <heiko@sntech.de>
|
||||
Link: https://lore.kernel.org/r/20250610-rk3576-tsadc-upstream-v6-3-b6e9efbf1015@collabora.com
|
||||
Signed-off-by: Daniel Lezcano <daniel.lezcano@linaro.org>
|
||||
---
|
||||
drivers/thermal/rockchip_thermal.c | 26 ++++++++++++++++++++++++++
|
||||
1 file changed, 26 insertions(+)
|
||||
|
||||
--- a/drivers/thermal/rockchip_thermal.c
|
||||
+++ b/drivers/thermal/rockchip_thermal.c
|
||||
@@ -1284,6 +1284,28 @@ static const struct rockchip_tsadc_chip
|
||||
},
|
||||
};
|
||||
|
||||
+static const struct rockchip_tsadc_chip rk3576_tsadc_data = {
|
||||
+ /* top, big_core, little_core, ddr, npu, gpu */
|
||||
+ .chn_offset = 0,
|
||||
+ .chn_num = 6, /* six channels for tsadc */
|
||||
+ .tshut_mode = TSHUT_MODE_GPIO, /* default TSHUT via GPIO give PMIC */
|
||||
+ .tshut_polarity = TSHUT_LOW_ACTIVE, /* default TSHUT LOW ACTIVE */
|
||||
+ .tshut_temp = 95000,
|
||||
+ .initialize = rk_tsadcv8_initialize,
|
||||
+ .irq_ack = rk_tsadcv4_irq_ack,
|
||||
+ .control = rk_tsadcv4_control,
|
||||
+ .get_temp = rk_tsadcv4_get_temp,
|
||||
+ .set_alarm_temp = rk_tsadcv3_alarm_temp,
|
||||
+ .set_tshut_temp = rk_tsadcv3_tshut_temp,
|
||||
+ .set_tshut_mode = rk_tsadcv4_tshut_mode,
|
||||
+ .table = {
|
||||
+ .id = rk3588_code_table,
|
||||
+ .length = ARRAY_SIZE(rk3588_code_table),
|
||||
+ .data_mask = TSADCV4_DATA_MASK,
|
||||
+ .mode = ADC_INCREMENT,
|
||||
+ },
|
||||
+};
|
||||
+
|
||||
static const struct rockchip_tsadc_chip rk3588_tsadc_data = {
|
||||
/* top, big_core0, big_core1, little_core, center, gpu, npu */
|
||||
.chn_offset = 0,
|
||||
@@ -1343,6 +1365,10 @@ static const struct of_device_id of_rock
|
||||
.data = (void *)&rk3568_tsadc_data,
|
||||
},
|
||||
{
|
||||
+ .compatible = "rockchip,rk3576-tsadc",
|
||||
+ .data = (void *)&rk3576_tsadc_data,
|
||||
+ },
|
||||
+ {
|
||||
.compatible = "rockchip,rk3588-tsadc",
|
||||
.data = (void *)&rk3588_tsadc_data,
|
||||
},
|
@@ -0,0 +1,431 @@
|
||||
From ae332ec0009d762982540635411caefeafa92a5b Mon Sep 17 00:00:00 2001
|
||||
From: Nicolas Frattaroli <nicolas.frattaroli@collabora.com>
|
||||
Date: Tue, 10 Jun 2025 14:32:41 +0200
|
||||
Subject: [PATCH] thermal/drivers/rockchip: Support reading trim values from
|
||||
OTP
|
||||
|
||||
Many of the Rockchip SoCs support storing trim values for the sensors in
|
||||
factory programmable memory. These values specify a fixed offset from
|
||||
the sensor's returned temperature to get a more accurate picture of what
|
||||
temperature the silicon is actually at.
|
||||
|
||||
The way this is implemented is with various OTP cells, which may be
|
||||
absent. There may both be whole-TSADC trim values, as well as per-sensor
|
||||
trim values.
|
||||
|
||||
In the downstream driver, whole-chip trim values override the per-sensor
|
||||
trim values. This rewrite of the functionality changes the semantics to
|
||||
something I see as slightly more useful: allow the whole-chip trim
|
||||
values to serve as a fallback for lacking per-sensor trim values,
|
||||
instead of overriding already present sensor trim values.
|
||||
|
||||
Additionally, the chip may specify an offset (trim_base, trim_base_frac)
|
||||
in degrees celsius and degrees decicelsius respectively which defines
|
||||
what the basis is from which the trim, if any, should be calculated
|
||||
from. By default, this is 30 degrees Celsius, but the chip can once
|
||||
again specify a different value through OTP cells.
|
||||
|
||||
The implementation of these trim calculations have been tested
|
||||
extensively on an RK3576, where it was confirmed to get rid of pesky 1.8
|
||||
degree Celsius offsets between certain sensors.
|
||||
|
||||
Signed-off-by: Nicolas Frattaroli <nicolas.frattaroli@collabora.com>
|
||||
Link: https://lore.kernel.org/r/20250610-rk3576-tsadc-upstream-v6-5-b6e9efbf1015@collabora.com
|
||||
Signed-off-by: Daniel Lezcano <daniel.lezcano@linaro.org>
|
||||
---
|
||||
drivers/thermal/rockchip_thermal.c | 221 ++++++++++++++++++++++++++---
|
||||
1 file changed, 202 insertions(+), 19 deletions(-)
|
||||
|
||||
--- a/drivers/thermal/rockchip_thermal.c
|
||||
+++ b/drivers/thermal/rockchip_thermal.c
|
||||
@@ -9,6 +9,7 @@
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/io.h>
|
||||
#include <linux/module.h>
|
||||
+#include <linux/nvmem-consumer.h>
|
||||
#include <linux/of.h>
|
||||
#include <linux/of_address.h>
|
||||
#include <linux/of_irq.h>
|
||||
@@ -69,16 +70,18 @@ struct chip_tsadc_table {
|
||||
* struct rockchip_tsadc_chip - hold the private data of tsadc chip
|
||||
* @chn_offset: the channel offset of the first channel
|
||||
* @chn_num: the channel number of tsadc chip
|
||||
- * @tshut_temp: the hardware-controlled shutdown temperature value
|
||||
+ * @trim_slope: used to convert the trim code to a temperature in millicelsius
|
||||
+ * @tshut_temp: the hardware-controlled shutdown temperature value, with no trim
|
||||
* @tshut_mode: the hardware-controlled shutdown mode (0:CRU 1:GPIO)
|
||||
* @tshut_polarity: the hardware-controlled active polarity (0:LOW 1:HIGH)
|
||||
* @initialize: SoC special initialize tsadc controller method
|
||||
* @irq_ack: clear the interrupt
|
||||
* @control: enable/disable method for the tsadc controller
|
||||
- * @get_temp: get the temperature
|
||||
+ * @get_temp: get the raw temperature, unadjusted by trim
|
||||
* @set_alarm_temp: set the high temperature interrupt
|
||||
* @set_tshut_temp: set the hardware-controlled shutdown temperature
|
||||
* @set_tshut_mode: set the hardware-controlled shutdown mode
|
||||
+ * @get_trim_code: convert a hardware temperature code to one adjusted for by trim
|
||||
* @table: the chip-specific conversion table
|
||||
*/
|
||||
struct rockchip_tsadc_chip {
|
||||
@@ -86,6 +89,9 @@ struct rockchip_tsadc_chip {
|
||||
int chn_offset;
|
||||
int chn_num;
|
||||
|
||||
+ /* Used to convert trim code to trim temp */
|
||||
+ int trim_slope;
|
||||
+
|
||||
/* The hardware-controlled tshut property */
|
||||
int tshut_temp;
|
||||
enum tshut_mode tshut_mode;
|
||||
@@ -105,6 +111,8 @@ struct rockchip_tsadc_chip {
|
||||
int (*set_tshut_temp)(const struct chip_tsadc_table *table,
|
||||
int chn, void __iomem *reg, int temp);
|
||||
void (*set_tshut_mode)(int chn, void __iomem *reg, enum tshut_mode m);
|
||||
+ int (*get_trim_code)(const struct chip_tsadc_table *table,
|
||||
+ int code, int trim_base, int trim_base_frac);
|
||||
|
||||
/* Per-table methods */
|
||||
struct chip_tsadc_table table;
|
||||
@@ -114,12 +122,16 @@ struct rockchip_tsadc_chip {
|
||||
* struct rockchip_thermal_sensor - hold the information of thermal sensor
|
||||
* @thermal: pointer to the platform/configuration data
|
||||
* @tzd: pointer to a thermal zone
|
||||
+ * @of_node: pointer to the device_node representing this sensor, if any
|
||||
* @id: identifier of the thermal sensor
|
||||
+ * @trim_temp: per-sensor trim temperature value
|
||||
*/
|
||||
struct rockchip_thermal_sensor {
|
||||
struct rockchip_thermal_data *thermal;
|
||||
struct thermal_zone_device *tzd;
|
||||
+ struct device_node *of_node;
|
||||
int id;
|
||||
+ int trim_temp;
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -132,7 +144,11 @@ struct rockchip_thermal_sensor {
|
||||
* @pclk: the advanced peripherals bus clock
|
||||
* @grf: the general register file will be used to do static set by software
|
||||
* @regs: the base address of tsadc controller
|
||||
- * @tshut_temp: the hardware-controlled shutdown temperature value
|
||||
+ * @trim_base: major component of sensor trim value, in Celsius
|
||||
+ * @trim_base_frac: minor component of sensor trim value, in Decicelsius
|
||||
+ * @trim: fallback thermal trim value for each channel
|
||||
+ * @tshut_temp: the hardware-controlled shutdown temperature value, with no trim
|
||||
+ * @trim_temp: the fallback trim temperature for the whole sensor
|
||||
* @tshut_mode: the hardware-controlled shutdown mode (0:CRU 1:GPIO)
|
||||
* @tshut_polarity: the hardware-controlled active polarity (0:LOW 1:HIGH)
|
||||
*/
|
||||
@@ -149,7 +165,12 @@ struct rockchip_thermal_data {
|
||||
struct regmap *grf;
|
||||
void __iomem *regs;
|
||||
|
||||
+ int trim_base;
|
||||
+ int trim_base_frac;
|
||||
+ int trim;
|
||||
+
|
||||
int tshut_temp;
|
||||
+ int trim_temp;
|
||||
enum tshut_mode tshut_mode;
|
||||
enum tshut_polarity tshut_polarity;
|
||||
};
|
||||
@@ -249,6 +270,9 @@ struct rockchip_thermal_data {
|
||||
|
||||
#define GRF_CON_TSADC_CH_INV (0x10001 << 1)
|
||||
|
||||
+
|
||||
+#define RK_MAX_TEMP (180000)
|
||||
+
|
||||
/**
|
||||
* struct tsadc_table - code to temperature conversion table
|
||||
* @code: the value of adc channel
|
||||
@@ -1061,6 +1085,15 @@ static void rk_tsadcv4_tshut_mode(int ch
|
||||
writel_relaxed(val_cru, regs + TSADCV3_HSHUT_CRU_INT_EN);
|
||||
}
|
||||
|
||||
+static int rk_tsadcv2_get_trim_code(const struct chip_tsadc_table *table,
|
||||
+ int code, int trim_base, int trim_base_frac)
|
||||
+{
|
||||
+ int temp = trim_base * 1000 + trim_base_frac * 100;
|
||||
+ u32 base_code = rk_tsadcv2_temp_to_code(table, temp);
|
||||
+
|
||||
+ return code - base_code;
|
||||
+}
|
||||
+
|
||||
static const struct rockchip_tsadc_chip px30_tsadc_data = {
|
||||
/* cpu, gpu */
|
||||
.chn_offset = 0,
|
||||
@@ -1298,6 +1331,8 @@ static const struct rockchip_tsadc_chip
|
||||
.set_alarm_temp = rk_tsadcv3_alarm_temp,
|
||||
.set_tshut_temp = rk_tsadcv3_tshut_temp,
|
||||
.set_tshut_mode = rk_tsadcv4_tshut_mode,
|
||||
+ .get_trim_code = rk_tsadcv2_get_trim_code,
|
||||
+ .trim_slope = 923,
|
||||
.table = {
|
||||
.id = rk3588_code_table,
|
||||
.length = ARRAY_SIZE(rk3588_code_table),
|
||||
@@ -1413,7 +1448,7 @@ static int rockchip_thermal_set_trips(st
|
||||
__func__, sensor->id, low, high);
|
||||
|
||||
return tsadc->set_alarm_temp(&tsadc->table,
|
||||
- sensor->id, thermal->regs, high);
|
||||
+ sensor->id, thermal->regs, high + sensor->trim_temp);
|
||||
}
|
||||
|
||||
static int rockchip_thermal_get_temp(struct thermal_zone_device *tz, int *out_temp)
|
||||
@@ -1425,6 +1460,8 @@ static int rockchip_thermal_get_temp(str
|
||||
|
||||
retval = tsadc->get_temp(&tsadc->table,
|
||||
sensor->id, thermal->regs, out_temp);
|
||||
+ *out_temp -= sensor->trim_temp;
|
||||
+
|
||||
return retval;
|
||||
}
|
||||
|
||||
@@ -1433,6 +1470,104 @@ static const struct thermal_zone_device_
|
||||
.set_trips = rockchip_thermal_set_trips,
|
||||
};
|
||||
|
||||
+/**
|
||||
+ * rockchip_get_efuse_value - read an OTP cell from a device node
|
||||
+ * @np: pointer to the device node with the nvmem-cells property
|
||||
+ * @cell_name: name of cell that should be read
|
||||
+ * @value: pointer to where the read value will be placed
|
||||
+ *
|
||||
+ * Return: Negative errno on failure, during which *value will not be touched,
|
||||
+ * or 0 on success.
|
||||
+ */
|
||||
+static int rockchip_get_efuse_value(struct device_node *np, const char *cell_name,
|
||||
+ int *value)
|
||||
+{
|
||||
+ struct nvmem_cell *cell;
|
||||
+ int ret = 0;
|
||||
+ size_t len;
|
||||
+ u8 *buf;
|
||||
+ int i;
|
||||
+
|
||||
+ cell = of_nvmem_cell_get(np, cell_name);
|
||||
+ if (IS_ERR(cell))
|
||||
+ return PTR_ERR(cell);
|
||||
+
|
||||
+ buf = nvmem_cell_read(cell, &len);
|
||||
+
|
||||
+ nvmem_cell_put(cell);
|
||||
+
|
||||
+ if (IS_ERR(buf))
|
||||
+ return PTR_ERR(buf);
|
||||
+
|
||||
+ if (len > sizeof(*value)) {
|
||||
+ ret = -ERANGE;
|
||||
+ goto exit;
|
||||
+ }
|
||||
+
|
||||
+ /* Copy with implicit endian conversion */
|
||||
+ *value = 0;
|
||||
+ for (i = 0; i < len; i++)
|
||||
+ *value |= (int) buf[i] << (8 * i);
|
||||
+
|
||||
+exit:
|
||||
+ kfree(buf);
|
||||
+ return ret;
|
||||
+}
|
||||
+
|
||||
+static int rockchip_get_trim_configuration(struct device *dev, struct device_node *np,
|
||||
+ struct rockchip_thermal_data *thermal)
|
||||
+{
|
||||
+ const struct rockchip_tsadc_chip *tsadc = thermal->chip;
|
||||
+ int trim_base = 0, trim_base_frac = 0, trim = 0;
|
||||
+ int trim_code;
|
||||
+ int ret;
|
||||
+
|
||||
+ thermal->trim_base = 0;
|
||||
+ thermal->trim_base_frac = 0;
|
||||
+ thermal->trim = 0;
|
||||
+
|
||||
+ if (!tsadc->get_trim_code)
|
||||
+ return 0;
|
||||
+
|
||||
+ ret = rockchip_get_efuse_value(np, "trim_base", &trim_base);
|
||||
+ if (ret < 0) {
|
||||
+ if (ret == -ENOENT) {
|
||||
+ trim_base = 30;
|
||||
+ dev_dbg(dev, "trim_base is absent, defaulting to 30\n");
|
||||
+ } else {
|
||||
+ dev_err(dev, "failed reading nvmem value of trim_base: %pe\n",
|
||||
+ ERR_PTR(ret));
|
||||
+ return ret;
|
||||
+ }
|
||||
+ }
|
||||
+ ret = rockchip_get_efuse_value(np, "trim_base_frac", &trim_base_frac);
|
||||
+ if (ret < 0) {
|
||||
+ if (ret == -ENOENT) {
|
||||
+ dev_dbg(dev, "trim_base_frac is absent, defaulting to 0\n");
|
||||
+ } else {
|
||||
+ dev_err(dev, "failed reading nvmem value of trim_base_frac: %pe\n",
|
||||
+ ERR_PTR(ret));
|
||||
+ return ret;
|
||||
+ }
|
||||
+ }
|
||||
+ thermal->trim_base = trim_base;
|
||||
+ thermal->trim_base_frac = trim_base_frac;
|
||||
+
|
||||
+ /*
|
||||
+ * If the tsadc node contains the trim property, then it is used in the
|
||||
+ * absence of per-channel trim values
|
||||
+ */
|
||||
+ if (!rockchip_get_efuse_value(np, "trim", &trim))
|
||||
+ thermal->trim = trim;
|
||||
+ if (trim) {
|
||||
+ trim_code = tsadc->get_trim_code(&tsadc->table, trim,
|
||||
+ trim_base, trim_base_frac);
|
||||
+ thermal->trim_temp = thermal->chip->trim_slope * trim_code;
|
||||
+ }
|
||||
+
|
||||
+ return 0;
|
||||
+}
|
||||
+
|
||||
static int rockchip_configure_from_dt(struct device *dev,
|
||||
struct device_node *np,
|
||||
struct rockchip_thermal_data *thermal)
|
||||
@@ -1493,6 +1628,8 @@ static int rockchip_configure_from_dt(st
|
||||
if (IS_ERR(thermal->grf))
|
||||
dev_warn(dev, "Missing rockchip,grf property\n");
|
||||
|
||||
+ rockchip_get_trim_configuration(dev, np, thermal);
|
||||
+
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -1503,23 +1640,50 @@ rockchip_thermal_register_sensor(struct
|
||||
int id)
|
||||
{
|
||||
const struct rockchip_tsadc_chip *tsadc = thermal->chip;
|
||||
+ struct device *dev = &pdev->dev;
|
||||
+ int trim = thermal->trim;
|
||||
+ int trim_code, tshut_temp;
|
||||
+ int trim_temp = 0;
|
||||
int error;
|
||||
|
||||
+ if (thermal->trim_temp)
|
||||
+ trim_temp = thermal->trim_temp;
|
||||
+
|
||||
+ if (tsadc->get_trim_code && sensor->of_node) {
|
||||
+ error = rockchip_get_efuse_value(sensor->of_node, "trim", &trim);
|
||||
+ if (error < 0 && error != -ENOENT) {
|
||||
+ dev_err(dev, "failed reading trim of sensor %d: %pe\n",
|
||||
+ id, ERR_PTR(error));
|
||||
+ return error;
|
||||
+ }
|
||||
+ if (trim) {
|
||||
+ trim_code = tsadc->get_trim_code(&tsadc->table, trim,
|
||||
+ thermal->trim_base,
|
||||
+ thermal->trim_base_frac);
|
||||
+ trim_temp = thermal->chip->trim_slope * trim_code;
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+ sensor->trim_temp = trim_temp;
|
||||
+
|
||||
+ dev_dbg(dev, "trim of sensor %d is %d\n", id, sensor->trim_temp);
|
||||
+
|
||||
+ tshut_temp = min(thermal->tshut_temp + sensor->trim_temp, RK_MAX_TEMP);
|
||||
+
|
||||
tsadc->set_tshut_mode(id, thermal->regs, thermal->tshut_mode);
|
||||
|
||||
- error = tsadc->set_tshut_temp(&tsadc->table, id, thermal->regs,
|
||||
- thermal->tshut_temp);
|
||||
+ error = tsadc->set_tshut_temp(&tsadc->table, id, thermal->regs, tshut_temp);
|
||||
if (error)
|
||||
- dev_err(&pdev->dev, "%s: invalid tshut=%d, error=%d\n",
|
||||
- __func__, thermal->tshut_temp, error);
|
||||
+ dev_err(dev, "%s: invalid tshut=%d, error=%d\n",
|
||||
+ __func__, tshut_temp, error);
|
||||
|
||||
sensor->thermal = thermal;
|
||||
sensor->id = id;
|
||||
- sensor->tzd = devm_thermal_of_zone_register(&pdev->dev, id, sensor,
|
||||
+ sensor->tzd = devm_thermal_of_zone_register(dev, id, sensor,
|
||||
&rockchip_of_thermal_ops);
|
||||
if (IS_ERR(sensor->tzd)) {
|
||||
error = PTR_ERR(sensor->tzd);
|
||||
- dev_err(&pdev->dev, "failed to register sensor %d: %d\n",
|
||||
+ dev_err(dev, "failed to register sensor %d: %d\n",
|
||||
id, error);
|
||||
return error;
|
||||
}
|
||||
@@ -1542,9 +1706,11 @@ static int rockchip_thermal_probe(struct
|
||||
{
|
||||
struct device_node *np = pdev->dev.of_node;
|
||||
struct rockchip_thermal_data *thermal;
|
||||
+ struct device_node *child;
|
||||
int irq;
|
||||
int i;
|
||||
int error;
|
||||
+ u32 chn;
|
||||
|
||||
irq = platform_get_irq(pdev, 0);
|
||||
if (irq < 0)
|
||||
@@ -1595,6 +1761,18 @@ static int rockchip_thermal_probe(struct
|
||||
thermal->chip->initialize(thermal->grf, thermal->regs,
|
||||
thermal->tshut_polarity);
|
||||
|
||||
+ for_each_available_child_of_node(np, child) {
|
||||
+ if (!of_property_read_u32(child, "reg", &chn)) {
|
||||
+ if (chn < thermal->chip->chn_num)
|
||||
+ thermal->sensors[chn].of_node = child;
|
||||
+ else
|
||||
+ dev_warn(&pdev->dev,
|
||||
+ "sensor address (%d) too large, ignoring its trim\n",
|
||||
+ chn);
|
||||
+ }
|
||||
+
|
||||
+ }
|
||||
+
|
||||
for (i = 0; i < thermal->chip->chn_num; i++) {
|
||||
error = rockchip_thermal_register_sensor(pdev, thermal,
|
||||
&thermal->sensors[i],
|
||||
@@ -1664,8 +1842,11 @@ static int __maybe_unused rockchip_therm
|
||||
static int __maybe_unused rockchip_thermal_resume(struct device *dev)
|
||||
{
|
||||
struct rockchip_thermal_data *thermal = dev_get_drvdata(dev);
|
||||
- int i;
|
||||
+ const struct rockchip_tsadc_chip *tsadc = thermal->chip;
|
||||
+ struct rockchip_thermal_sensor *sensor;
|
||||
+ int tshut_temp;
|
||||
int error;
|
||||
+ int i;
|
||||
|
||||
error = clk_enable(thermal->clk);
|
||||
if (error)
|
||||
@@ -1679,21 +1860,23 @@ static int __maybe_unused rockchip_therm
|
||||
|
||||
rockchip_thermal_reset_controller(thermal->reset);
|
||||
|
||||
- thermal->chip->initialize(thermal->grf, thermal->regs,
|
||||
- thermal->tshut_polarity);
|
||||
+ tsadc->initialize(thermal->grf, thermal->regs, thermal->tshut_polarity);
|
||||
|
||||
for (i = 0; i < thermal->chip->chn_num; i++) {
|
||||
- int id = thermal->sensors[i].id;
|
||||
+ sensor = &thermal->sensors[i];
|
||||
+
|
||||
+ tshut_temp = min(thermal->tshut_temp + sensor->trim_temp,
|
||||
+ RK_MAX_TEMP);
|
||||
|
||||
- thermal->chip->set_tshut_mode(id, thermal->regs,
|
||||
+ tsadc->set_tshut_mode(sensor->id, thermal->regs,
|
||||
thermal->tshut_mode);
|
||||
|
||||
- error = thermal->chip->set_tshut_temp(&thermal->chip->table,
|
||||
- id, thermal->regs,
|
||||
- thermal->tshut_temp);
|
||||
+ error = tsadc->set_tshut_temp(&thermal->chip->table,
|
||||
+ sensor->id, thermal->regs,
|
||||
+ tshut_temp);
|
||||
if (error)
|
||||
dev_err(dev, "%s: invalid tshut=%d, error=%d\n",
|
||||
- __func__, thermal->tshut_temp, error);
|
||||
+ __func__, tshut_temp, error);
|
||||
}
|
||||
|
||||
thermal->chip->control(thermal->regs, true);
|
@@ -0,0 +1,37 @@
|
||||
From 591ae6bed250e4067db926313ff7279d23a1c7d1 Mon Sep 17 00:00:00 2001
|
||||
From: Ye Zhang <ye.zhang@rock-chips.com>
|
||||
Date: Tue, 12 Nov 2024 09:54:05 +0800
|
||||
Subject: [PATCH] gpio: rockchip: explan the format of the GPIO version ID
|
||||
|
||||
Remove redundant comments and provide a detailed explanation of the
|
||||
GPIO version ID.
|
||||
|
||||
Signed-off-by: Ye Zhang <ye.zhang@rock-chips.com>
|
||||
Reviewed-by: Andy Shevchenko <andriy.shevchenko@linux.intel.com>
|
||||
Reviewed-by: Sebastian Reichel <sebastian.reichel@collabora.com>
|
||||
Link: https://lore.kernel.org/r/20241112015408.3139996-2-ye.zhang@rock-chips.com
|
||||
Signed-off-by: Bartosz Golaszewski <bartosz.golaszewski@linaro.org>
|
||||
---
|
||||
drivers/gpio/gpio-rockchip.c | 10 ++++++++--
|
||||
1 file changed, 8 insertions(+), 2 deletions(-)
|
||||
|
||||
--- a/drivers/gpio/gpio-rockchip.c
|
||||
+++ b/drivers/gpio/gpio-rockchip.c
|
||||
@@ -26,9 +26,15 @@
|
||||
#include "../pinctrl/core.h"
|
||||
#include "../pinctrl/pinctrl-rockchip.h"
|
||||
|
||||
+/*
|
||||
+ * Version ID Register
|
||||
+ * Bits [31:24] - Major Version
|
||||
+ * Bits [23:16] - Minor Version
|
||||
+ * Bits [15:0] - Revision Number
|
||||
+ */
|
||||
#define GPIO_TYPE_V1 (0) /* GPIO Version ID reserved */
|
||||
-#define GPIO_TYPE_V2 (0x01000C2B) /* GPIO Version ID 0x01000C2B */
|
||||
-#define GPIO_TYPE_V2_1 (0x0101157C) /* GPIO Version ID 0x0101157C */
|
||||
+#define GPIO_TYPE_V2 (0x01000C2B)
|
||||
+#define GPIO_TYPE_V2_1 (0x0101157C)
|
||||
|
||||
static const struct rockchip_gpio_regs gpio_regs_v1 = {
|
||||
.port_dr = 0x00,
|
@@ -0,0 +1,46 @@
|
||||
From 41209307cad7f14c387c68375a93b50e54261a53 Mon Sep 17 00:00:00 2001
|
||||
From: Ye Zhang <ye.zhang@rock-chips.com>
|
||||
Date: Tue, 12 Nov 2024 09:54:06 +0800
|
||||
Subject: [PATCH] gpio: rockchip: change the GPIO version judgment logic
|
||||
|
||||
Have a list of valid IDs and default to -ENODEV.
|
||||
|
||||
Signed-off-by: Ye Zhang <ye.zhang@rock-chips.com>
|
||||
Reviewed-by: Sebastian Reichel <sebastian.reichel@collabora.com>
|
||||
Reviewed-by: Andy Shevchenko <andriy.shevchenko@linux.intel.com>
|
||||
Link: https://lore.kernel.org/r/20241112015408.3139996-3-ye.zhang@rock-chips.com
|
||||
Signed-off-by: Bartosz Golaszewski <bartosz.golaszewski@linaro.org>
|
||||
---
|
||||
drivers/gpio/gpio-rockchip.c | 12 +++++++++---
|
||||
1 file changed, 9 insertions(+), 3 deletions(-)
|
||||
|
||||
--- a/drivers/gpio/gpio-rockchip.c
|
||||
+++ b/drivers/gpio/gpio-rockchip.c
|
||||
@@ -667,8 +667,9 @@ static int rockchip_get_bank_data(struct
|
||||
clk_prepare_enable(bank->clk);
|
||||
id = readl(bank->reg_base + gpio_regs_v2.version_id);
|
||||
|
||||
- /* If not gpio v2, that is default to v1. */
|
||||
- if (id == GPIO_TYPE_V2 || id == GPIO_TYPE_V2_1) {
|
||||
+ switch (id) {
|
||||
+ case GPIO_TYPE_V2:
|
||||
+ case GPIO_TYPE_V2_1:
|
||||
bank->gpio_regs = &gpio_regs_v2;
|
||||
bank->gpio_type = GPIO_TYPE_V2;
|
||||
bank->db_clk = of_clk_get(bank->of_node, 1);
|
||||
@@ -677,9 +678,14 @@ static int rockchip_get_bank_data(struct
|
||||
clk_disable_unprepare(bank->clk);
|
||||
return -EINVAL;
|
||||
}
|
||||
- } else {
|
||||
+ break;
|
||||
+ case GPIO_TYPE_V1:
|
||||
bank->gpio_regs = &gpio_regs_v1;
|
||||
bank->gpio_type = GPIO_TYPE_V1;
|
||||
+ break;
|
||||
+ default:
|
||||
+ dev_err(bank->dev, "unsupported version ID: 0x%08x\n", id);
|
||||
+ return -ENODEV;
|
||||
}
|
||||
|
||||
return 0;
|
@@ -0,0 +1,34 @@
|
||||
From 8bcbd0379c05c66ce2e842c7e8901aa317cdf04e Mon Sep 17 00:00:00 2001
|
||||
From: Ye Zhang <ye.zhang@rock-chips.com>
|
||||
Date: Tue, 12 Nov 2024 09:54:07 +0800
|
||||
Subject: [PATCH] gpio: rockchip: support new version GPIO
|
||||
|
||||
Support the next version GPIO controller on SoCs like rk3576.
|
||||
|
||||
Signed-off-by: Ye Zhang <ye.zhang@rock-chips.com>
|
||||
Reviewed-by: Andy Shevchenko <andriy.shevchenko@linux.intel.com>
|
||||
Reviewed-by: Sebastian Reichel <sebastian.reichel@collabora.com>
|
||||
Link: https://lore.kernel.org/r/20241112015408.3139996-4-ye.zhang@rock-chips.com
|
||||
Signed-off-by: Bartosz Golaszewski <bartosz.golaszewski@linaro.org>
|
||||
---
|
||||
drivers/gpio/gpio-rockchip.c | 2 ++
|
||||
1 file changed, 2 insertions(+)
|
||||
|
||||
--- a/drivers/gpio/gpio-rockchip.c
|
||||
+++ b/drivers/gpio/gpio-rockchip.c
|
||||
@@ -35,6 +35,7 @@
|
||||
#define GPIO_TYPE_V1 (0) /* GPIO Version ID reserved */
|
||||
#define GPIO_TYPE_V2 (0x01000C2B)
|
||||
#define GPIO_TYPE_V2_1 (0x0101157C)
|
||||
+#define GPIO_TYPE_V2_2 (0x010219C8)
|
||||
|
||||
static const struct rockchip_gpio_regs gpio_regs_v1 = {
|
||||
.port_dr = 0x00,
|
||||
@@ -670,6 +671,7 @@ static int rockchip_get_bank_data(struct
|
||||
switch (id) {
|
||||
case GPIO_TYPE_V2:
|
||||
case GPIO_TYPE_V2_1:
|
||||
+ case GPIO_TYPE_V2_2:
|
||||
bank->gpio_regs = &gpio_regs_v2;
|
||||
bank->gpio_type = GPIO_TYPE_V2;
|
||||
bank->db_clk = of_clk_get(bank->of_node, 1);
|
@@ -0,0 +1,31 @@
|
||||
From 595ad7a336bf21f9d111a033820cd95d70343bd1 Mon Sep 17 00:00:00 2001
|
||||
From: Dragan Simic <dsimic@manjaro.org>
|
||||
Date: Thu, 5 Sep 2024 10:28:23 +0200
|
||||
Subject: [PATCH] phy: phy-rockchip-inno-usb2: Handle failed extcon allocation
|
||||
better
|
||||
|
||||
Return the actual error code upon failure to allocate extcon device, instead
|
||||
of hardcoding -ENOMEM. Use dev_err_probe() to also log appropriate messages,
|
||||
which is fine because the containing function is used in the probe path.
|
||||
|
||||
Helped-by: Heiko Stubner <heiko@sntech.de>
|
||||
Reviewed-by: Heiko Stuebner <heiko@sntech.de>
|
||||
Signed-off-by: Dragan Simic <dsimic@manjaro.org>
|
||||
Link: https://lore.kernel.org/r/cc4995aa3e569be6bc23ca126b41fba82d50eeee.1725524802.git.dsimic@manjaro.org
|
||||
Signed-off-by: Vinod Koul <vkoul@kernel.org>
|
||||
---
|
||||
drivers/phy/rockchip/phy-rockchip-inno-usb2.c | 3 ++-
|
||||
1 file changed, 2 insertions(+), 1 deletion(-)
|
||||
|
||||
--- a/drivers/phy/rockchip/phy-rockchip-inno-usb2.c
|
||||
+++ b/drivers/phy/rockchip/phy-rockchip-inno-usb2.c
|
||||
@@ -435,7 +435,8 @@ static int rockchip_usb2phy_extcon_regis
|
||||
rockchip_usb2phy_extcon_cable);
|
||||
|
||||
if (IS_ERR(edev))
|
||||
- return -ENOMEM;
|
||||
+ return dev_err_probe(rphy->dev, PTR_ERR(edev),
|
||||
+ "failed to allocate extcon device\n");
|
||||
|
||||
ret = devm_extcon_dev_register(rphy->dev, edev);
|
||||
if (ret) {
|
@@ -0,0 +1,119 @@
|
||||
From 86e2ed4e9a9680013ec9ab7c0428c9b8c5108efe Mon Sep 17 00:00:00 2001
|
||||
From: Frank Wang <frank.wang@rock-chips.com>
|
||||
Date: Wed, 16 Oct 2024 15:37:10 +0800
|
||||
Subject: [PATCH] phy: rockchip: inno-usb2: convert clock management to bulk
|
||||
|
||||
Since some Rockchip SoCs (e.g RK3576) have more than one clock,
|
||||
this converts the clock management from single to bulk method to
|
||||
make the driver more flexible.
|
||||
|
||||
Signed-off-by: Frank Wang <frank.wang@rock-chips.com>
|
||||
Reviewed-by: Heiko Stuebner <heiko@sntech.de>
|
||||
Link: https://lore.kernel.org/r/20241016073713.14133-1-frawang.cn@gmail.com
|
||||
Signed-off-by: Vinod Koul <vkoul@kernel.org>
|
||||
---
|
||||
drivers/phy/rockchip/phy-rockchip-inno-usb2.c | 45 +++++++++++++++----
|
||||
1 file changed, 37 insertions(+), 8 deletions(-)
|
||||
|
||||
--- a/drivers/phy/rockchip/phy-rockchip-inno-usb2.c
|
||||
+++ b/drivers/phy/rockchip/phy-rockchip-inno-usb2.c
|
||||
@@ -229,9 +229,10 @@ struct rockchip_usb2phy_port {
|
||||
* @dev: pointer to device.
|
||||
* @grf: General Register Files regmap.
|
||||
* @usbgrf: USB General Register Files regmap.
|
||||
- * @clk: clock struct of phy input clk.
|
||||
+ * @clks: array of phy input clocks.
|
||||
* @clk480m: clock struct of phy output clk.
|
||||
* @clk480m_hw: clock struct of phy output clk management.
|
||||
+ * @num_clks: number of phy input clocks.
|
||||
* @phy_reset: phy reset control.
|
||||
* @chg_state: states involved in USB charger detection.
|
||||
* @chg_type: USB charger types.
|
||||
@@ -246,9 +247,10 @@ struct rockchip_usb2phy {
|
||||
struct device *dev;
|
||||
struct regmap *grf;
|
||||
struct regmap *usbgrf;
|
||||
- struct clk *clk;
|
||||
+ struct clk_bulk_data *clks;
|
||||
struct clk *clk480m;
|
||||
struct clk_hw clk480m_hw;
|
||||
+ int num_clks;
|
||||
struct reset_control *phy_reset;
|
||||
enum usb_chg_state chg_state;
|
||||
enum power_supply_type chg_type;
|
||||
@@ -310,6 +312,13 @@ static int rockchip_usb2phy_reset(struct
|
||||
return 0;
|
||||
}
|
||||
|
||||
+static void rockchip_usb2phy_clk_bulk_disable(void *data)
|
||||
+{
|
||||
+ struct rockchip_usb2phy *rphy = data;
|
||||
+
|
||||
+ clk_bulk_disable_unprepare(rphy->num_clks, rphy->clks);
|
||||
+}
|
||||
+
|
||||
static int rockchip_usb2phy_clk480m_prepare(struct clk_hw *hw)
|
||||
{
|
||||
struct rockchip_usb2phy *rphy =
|
||||
@@ -376,7 +385,9 @@ rockchip_usb2phy_clk480m_register(struct
|
||||
{
|
||||
struct device_node *node = rphy->dev->of_node;
|
||||
struct clk_init_data init;
|
||||
+ struct clk *refclk = NULL;
|
||||
const char *clk_name;
|
||||
+ int i;
|
||||
int ret = 0;
|
||||
|
||||
init.flags = 0;
|
||||
@@ -386,8 +397,15 @@ rockchip_usb2phy_clk480m_register(struct
|
||||
/* optional override of the clockname */
|
||||
of_property_read_string(node, "clock-output-names", &init.name);
|
||||
|
||||
- if (rphy->clk) {
|
||||
- clk_name = __clk_get_name(rphy->clk);
|
||||
+ for (i = 0; i < rphy->num_clks; i++) {
|
||||
+ if (!strncmp(rphy->clks[i].id, "phyclk", 6)) {
|
||||
+ refclk = rphy->clks[i].clk;
|
||||
+ break;
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+ if (!IS_ERR(refclk)) {
|
||||
+ clk_name = __clk_get_name(refclk);
|
||||
init.parent_names = &clk_name;
|
||||
init.num_parents = 1;
|
||||
} else {
|
||||
@@ -1407,11 +1425,13 @@ static int rockchip_usb2phy_probe(struct
|
||||
if (IS_ERR(rphy->phy_reset))
|
||||
return PTR_ERR(rphy->phy_reset);
|
||||
|
||||
- rphy->clk = devm_clk_get_optional_enabled(dev, "phyclk");
|
||||
- if (IS_ERR(rphy->clk)) {
|
||||
- return dev_err_probe(&pdev->dev, PTR_ERR(rphy->clk),
|
||||
- "failed to get phyclk\n");
|
||||
- }
|
||||
+ ret = devm_clk_bulk_get_all(dev, &rphy->clks);
|
||||
+ if (ret == -EPROBE_DEFER)
|
||||
+ return dev_err_probe(&pdev->dev, -EPROBE_DEFER,
|
||||
+ "failed to get phy clock\n");
|
||||
+
|
||||
+ /* Clocks are optional */
|
||||
+ rphy->num_clks = ret < 0 ? 0 : ret;
|
||||
|
||||
ret = rockchip_usb2phy_clk480m_register(rphy);
|
||||
if (ret) {
|
||||
@@ -1419,6 +1439,14 @@ static int rockchip_usb2phy_probe(struct
|
||||
return ret;
|
||||
}
|
||||
|
||||
+ ret = clk_bulk_prepare_enable(rphy->num_clks, rphy->clks);
|
||||
+ if (ret)
|
||||
+ return dev_err_probe(dev, ret, "failed to enable phy clock\n");
|
||||
+
|
||||
+ ret = devm_add_action_or_reset(dev, rockchip_usb2phy_clk_bulk_disable, rphy);
|
||||
+ if (ret)
|
||||
+ return ret;
|
||||
+
|
||||
if (rphy->phy_cfg->phy_tuning) {
|
||||
ret = rphy->phy_cfg->phy_tuning(rphy);
|
||||
if (ret)
|
@@ -0,0 +1,143 @@
|
||||
From 3d7de6e870ece5a32153382df9df6fb87613335e Mon Sep 17 00:00:00 2001
|
||||
From: William Wu <william.wu@rock-chips.com>
|
||||
Date: Wed, 16 Oct 2024 15:37:13 +0800
|
||||
Subject: [PATCH] phy: rockchip: inno-usb2: Add usb2 phys support for rk3576
|
||||
|
||||
The RK3576 SoC has two independent USB2.0 PHYs, and each PHY has
|
||||
one port. This adds device specific data for it.
|
||||
|
||||
Signed-off-by: William Wu <william.wu@rock-chips.com>
|
||||
Signed-off-by: Frank Wang <frank.wang@rock-chips.com>
|
||||
Reviewed-by: Heiko Stuebner <heiko@sntech.de>
|
||||
Link: https://lore.kernel.org/r/20241016073713.14133-4-frawang.cn@gmail.com
|
||||
Signed-off-by: Vinod Koul <vkoul@kernel.org>
|
||||
---
|
||||
drivers/phy/rockchip/phy-rockchip-inno-usb2.c | 103 ++++++++++++++++++
|
||||
1 file changed, 103 insertions(+)
|
||||
|
||||
--- a/drivers/phy/rockchip/phy-rockchip-inno-usb2.c
|
||||
+++ b/drivers/phy/rockchip/phy-rockchip-inno-usb2.c
|
||||
@@ -1524,6 +1524,30 @@ static int rk3128_usb2phy_tuning(struct
|
||||
BIT(2) << BIT_WRITEABLE_SHIFT | 0);
|
||||
}
|
||||
|
||||
+static int rk3576_usb2phy_tuning(struct rockchip_usb2phy *rphy)
|
||||
+{
|
||||
+ int ret;
|
||||
+ u32 reg = rphy->phy_cfg->reg;
|
||||
+
|
||||
+ /* Deassert SIDDQ to power on analog block */
|
||||
+ ret = regmap_write(rphy->grf, reg + 0x0010, GENMASK(29, 29) | 0x0000);
|
||||
+ if (ret)
|
||||
+ return ret;
|
||||
+
|
||||
+ /* Do reset after exit IDDQ mode */
|
||||
+ ret = rockchip_usb2phy_reset(rphy);
|
||||
+ if (ret)
|
||||
+ return ret;
|
||||
+
|
||||
+ /* HS DC Voltage Level Adjustment 4'b1001 : +5.89% */
|
||||
+ ret |= regmap_write(rphy->grf, reg + 0x000c, GENMASK(27, 24) | 0x0900);
|
||||
+
|
||||
+ /* HS Transmitter Pre-Emphasis Current Control 2'b10 : 2x */
|
||||
+ ret |= regmap_write(rphy->grf, reg + 0x0010, GENMASK(20, 19) | 0x0010);
|
||||
+
|
||||
+ return ret;
|
||||
+}
|
||||
+
|
||||
static int rk3588_usb2phy_tuning(struct rockchip_usb2phy *rphy)
|
||||
{
|
||||
int ret;
|
||||
@@ -1952,6 +1976,84 @@ static const struct rockchip_usb2phy_cfg
|
||||
{ /* sentinel */ }
|
||||
};
|
||||
|
||||
+static const struct rockchip_usb2phy_cfg rk3576_phy_cfgs[] = {
|
||||
+ {
|
||||
+ .reg = 0x0,
|
||||
+ .num_ports = 1,
|
||||
+ .phy_tuning = rk3576_usb2phy_tuning,
|
||||
+ .clkout_ctl = { 0x0008, 0, 0, 1, 0 },
|
||||
+ .port_cfgs = {
|
||||
+ [USB2PHY_PORT_OTG] = {
|
||||
+ .phy_sus = { 0x0000, 8, 0, 0, 0x1d1 },
|
||||
+ .bvalid_det_en = { 0x00c0, 1, 1, 0, 1 },
|
||||
+ .bvalid_det_st = { 0x00c4, 1, 1, 0, 1 },
|
||||
+ .bvalid_det_clr = { 0x00c8, 1, 1, 0, 1 },
|
||||
+ .ls_det_en = { 0x00c0, 0, 0, 0, 1 },
|
||||
+ .ls_det_st = { 0x00c4, 0, 0, 0, 1 },
|
||||
+ .ls_det_clr = { 0x00c8, 0, 0, 0, 1 },
|
||||
+ .disfall_en = { 0x00c0, 6, 6, 0, 1 },
|
||||
+ .disfall_st = { 0x00c4, 6, 6, 0, 1 },
|
||||
+ .disfall_clr = { 0x00c8, 6, 6, 0, 1 },
|
||||
+ .disrise_en = { 0x00c0, 5, 5, 0, 1 },
|
||||
+ .disrise_st = { 0x00c4, 5, 5, 0, 1 },
|
||||
+ .disrise_clr = { 0x00c8, 5, 5, 0, 1 },
|
||||
+ .utmi_avalid = { 0x0080, 1, 1, 0, 1 },
|
||||
+ .utmi_bvalid = { 0x0080, 0, 0, 0, 1 },
|
||||
+ .utmi_ls = { 0x0080, 5, 4, 0, 1 },
|
||||
+ }
|
||||
+ },
|
||||
+ .chg_det = {
|
||||
+ .cp_det = { 0x0080, 8, 8, 0, 1 },
|
||||
+ .dcp_det = { 0x0080, 8, 8, 0, 1 },
|
||||
+ .dp_det = { 0x0080, 9, 9, 1, 0 },
|
||||
+ .idm_sink_en = { 0x0010, 5, 5, 1, 0 },
|
||||
+ .idp_sink_en = { 0x0010, 5, 5, 0, 1 },
|
||||
+ .idp_src_en = { 0x0010, 14, 14, 0, 1 },
|
||||
+ .rdm_pdwn_en = { 0x0010, 14, 14, 0, 1 },
|
||||
+ .vdm_src_en = { 0x0010, 7, 6, 0, 3 },
|
||||
+ .vdp_src_en = { 0x0010, 7, 6, 0, 3 },
|
||||
+ },
|
||||
+ },
|
||||
+ {
|
||||
+ .reg = 0x2000,
|
||||
+ .num_ports = 1,
|
||||
+ .phy_tuning = rk3576_usb2phy_tuning,
|
||||
+ .clkout_ctl = { 0x2008, 0, 0, 1, 0 },
|
||||
+ .port_cfgs = {
|
||||
+ [USB2PHY_PORT_OTG] = {
|
||||
+ .phy_sus = { 0x2000, 8, 0, 0, 0x1d1 },
|
||||
+ .bvalid_det_en = { 0x20c0, 1, 1, 0, 1 },
|
||||
+ .bvalid_det_st = { 0x20c4, 1, 1, 0, 1 },
|
||||
+ .bvalid_det_clr = { 0x20c8, 1, 1, 0, 1 },
|
||||
+ .ls_det_en = { 0x20c0, 0, 0, 0, 1 },
|
||||
+ .ls_det_st = { 0x20c4, 0, 0, 0, 1 },
|
||||
+ .ls_det_clr = { 0x20c8, 0, 0, 0, 1 },
|
||||
+ .disfall_en = { 0x20c0, 6, 6, 0, 1 },
|
||||
+ .disfall_st = { 0x20c4, 6, 6, 0, 1 },
|
||||
+ .disfall_clr = { 0x20c8, 6, 6, 0, 1 },
|
||||
+ .disrise_en = { 0x20c0, 5, 5, 0, 1 },
|
||||
+ .disrise_st = { 0x20c4, 5, 5, 0, 1 },
|
||||
+ .disrise_clr = { 0x20c8, 5, 5, 0, 1 },
|
||||
+ .utmi_avalid = { 0x2080, 1, 1, 0, 1 },
|
||||
+ .utmi_bvalid = { 0x2080, 0, 0, 0, 1 },
|
||||
+ .utmi_ls = { 0x2080, 5, 4, 0, 1 },
|
||||
+ }
|
||||
+ },
|
||||
+ .chg_det = {
|
||||
+ .cp_det = { 0x2080, 8, 8, 0, 1 },
|
||||
+ .dcp_det = { 0x2080, 8, 8, 0, 1 },
|
||||
+ .dp_det = { 0x2080, 9, 9, 1, 0 },
|
||||
+ .idm_sink_en = { 0x2010, 5, 5, 1, 0 },
|
||||
+ .idp_sink_en = { 0x2010, 5, 5, 0, 1 },
|
||||
+ .idp_src_en = { 0x2010, 14, 14, 0, 1 },
|
||||
+ .rdm_pdwn_en = { 0x2010, 14, 14, 0, 1 },
|
||||
+ .vdm_src_en = { 0x2010, 7, 6, 0, 3 },
|
||||
+ .vdp_src_en = { 0x2010, 7, 6, 0, 3 },
|
||||
+ },
|
||||
+ },
|
||||
+ { /* sentinel */ }
|
||||
+};
|
||||
+
|
||||
static const struct rockchip_usb2phy_cfg rk3588_phy_cfgs[] = {
|
||||
{
|
||||
.reg = 0x0000,
|
||||
@@ -2123,6 +2225,7 @@ static const struct of_device_id rockchi
|
||||
{ .compatible = "rockchip,rk3366-usb2phy", .data = &rk3366_phy_cfgs },
|
||||
{ .compatible = "rockchip,rk3399-usb2phy", .data = &rk3399_phy_cfgs },
|
||||
{ .compatible = "rockchip,rk3568-usb2phy", .data = &rk3568_phy_cfgs },
|
||||
+ { .compatible = "rockchip,rk3576-usb2phy", .data = &rk3576_phy_cfgs },
|
||||
{ .compatible = "rockchip,rk3588-usb2phy", .data = &rk3588_phy_cfgs },
|
||||
{ .compatible = "rockchip,rv1108-usb2phy", .data = &rv1108_phy_cfgs },
|
||||
{}
|
@@ -0,0 +1,73 @@
|
||||
From a76de028c619dd18f89786805bcc7bb4d379ea9f Mon Sep 17 00:00:00 2001
|
||||
From: Frank Wang <frank.wang@rock-chips.com>
|
||||
Date: Mon, 14 Oct 2024 10:03:42 +0800
|
||||
Subject: [PATCH] phy: rockchip: usbdp: add rk3576 device match data
|
||||
|
||||
This adds RK3576 device match data support.
|
||||
|
||||
Signed-off-by: Frank Wang <frank.wang@rock-chips.com>
|
||||
Acked-by: Dragan Simic <dsimic@manjaro.org>
|
||||
Reviewed-by: Heiko Stuebner <heiko@sntech.de>
|
||||
Link: https://lore.kernel.org/r/20241014020342.15974-2-frawang.cn@gmail.com
|
||||
Signed-off-by: Vinod Koul <vkoul@kernel.org>
|
||||
---
|
||||
drivers/phy/rockchip/phy-rockchip-usbdp.c | 41 +++++++++++++++++++++++
|
||||
1 file changed, 41 insertions(+)
|
||||
|
||||
--- a/drivers/phy/rockchip/phy-rockchip-usbdp.c
|
||||
+++ b/drivers/phy/rockchip/phy-rockchip-usbdp.c
|
||||
@@ -1556,6 +1556,43 @@ static const char * const rk_udphy_rst_l
|
||||
"init", "cmn", "lane", "pcs_apb", "pma_apb"
|
||||
};
|
||||
|
||||
+static const struct rk_udphy_cfg rk3576_udphy_cfgs = {
|
||||
+ .num_phys = 1,
|
||||
+ .phy_ids = { 0x2b010000 },
|
||||
+ .num_rsts = ARRAY_SIZE(rk_udphy_rst_list),
|
||||
+ .rst_list = rk_udphy_rst_list,
|
||||
+ .grfcfg = {
|
||||
+ /* u2phy-grf */
|
||||
+ .bvalid_phy_con = RK_UDPHY_GEN_GRF_REG(0x0010, 1, 0, 0x2, 0x3),
|
||||
+ .bvalid_grf_con = RK_UDPHY_GEN_GRF_REG(0x0000, 15, 14, 0x1, 0x3),
|
||||
+
|
||||
+ /* usb-grf */
|
||||
+ .usb3otg0_cfg = RK_UDPHY_GEN_GRF_REG(0x0030, 15, 0, 0x1100, 0x0188),
|
||||
+
|
||||
+ /* usbdpphy-grf */
|
||||
+ .low_pwrn = RK_UDPHY_GEN_GRF_REG(0x0004, 13, 13, 0, 1),
|
||||
+ .rx_lfps = RK_UDPHY_GEN_GRF_REG(0x0004, 14, 14, 0, 1),
|
||||
+ },
|
||||
+ .vogrfcfg = {
|
||||
+ {
|
||||
+ .hpd_trigger = RK_UDPHY_GEN_GRF_REG(0x0000, 11, 10, 1, 3),
|
||||
+ .dp_lane_reg = 0x0000,
|
||||
+ },
|
||||
+ },
|
||||
+ .dp_tx_ctrl_cfg = {
|
||||
+ rk3588_dp_tx_drv_ctrl_rbr_hbr_typec,
|
||||
+ rk3588_dp_tx_drv_ctrl_rbr_hbr_typec,
|
||||
+ rk3588_dp_tx_drv_ctrl_hbr2,
|
||||
+ rk3588_dp_tx_drv_ctrl_hbr3,
|
||||
+ },
|
||||
+ .dp_tx_ctrl_cfg_typec = {
|
||||
+ rk3588_dp_tx_drv_ctrl_rbr_hbr_typec,
|
||||
+ rk3588_dp_tx_drv_ctrl_rbr_hbr_typec,
|
||||
+ rk3588_dp_tx_drv_ctrl_hbr2,
|
||||
+ rk3588_dp_tx_drv_ctrl_hbr3,
|
||||
+ },
|
||||
+};
|
||||
+
|
||||
static const struct rk_udphy_cfg rk3588_udphy_cfgs = {
|
||||
.num_phys = 2,
|
||||
.phy_ids = {
|
||||
@@ -1603,6 +1640,10 @@ static const struct rk_udphy_cfg rk3588_
|
||||
|
||||
static const struct of_device_id rk_udphy_dt_match[] = {
|
||||
{
|
||||
+ .compatible = "rockchip,rk3576-usbdp-phy",
|
||||
+ .data = &rk3576_udphy_cfgs
|
||||
+ },
|
||||
+ {
|
||||
.compatible = "rockchip,rk3588-usbdp-phy",
|
||||
.data = &rk3588_udphy_cfgs
|
||||
},
|
@@ -0,0 +1,355 @@
|
||||
From ba8ad7eece66ac5c579dd8de39efc72770e7cf64 Mon Sep 17 00:00:00 2001
|
||||
From: Kever Yang <kever.yang@rock-chips.com>
|
||||
Date: Wed, 6 Nov 2024 10:13:57 +0800
|
||||
Subject: [PATCH] phy: rockchip-naneng-combo: add rk3576 support
|
||||
|
||||
Rockchip RK3576 integrates two naneng-combo PHY, PHY0 is used for
|
||||
PCIE and SATA, PHY1 is used for PCIE, SATA and USB3.
|
||||
|
||||
This adds device specific data support.
|
||||
|
||||
Signed-off-by: Kever Yang <kever.yang@rock-chips.com>
|
||||
Signed-off-by: William Wu <william.wu@rock-chips.com>
|
||||
Signed-off-by: Frank Wang <frank.wang@rock-chips.com>
|
||||
Reviewed-by: Heiko Stuebner <heiko@sntech.de>
|
||||
Test-by: Kever Yang <kever.yang@rock-chips.com>
|
||||
Link: https://lore.kernel.org/r/20241106021357.19782-2-frawang.cn@gmail.com
|
||||
Signed-off-by: Vinod Koul <vkoul@kernel.org>
|
||||
---
|
||||
.../rockchip/phy-rockchip-naneng-combphy.c | 279 ++++++++++++++++++
|
||||
1 file changed, 279 insertions(+)
|
||||
|
||||
--- a/drivers/phy/rockchip/phy-rockchip-naneng-combphy.c
|
||||
+++ b/drivers/phy/rockchip/phy-rockchip-naneng-combphy.c
|
||||
@@ -37,6 +37,10 @@
|
||||
#define PHYREG8 0x1C
|
||||
#define PHYREG8_SSC_EN BIT(4)
|
||||
|
||||
+#define PHYREG10 0x24
|
||||
+#define PHYREG10_SSC_PCM_MASK GENMASK(3, 0)
|
||||
+#define PHYREG10_SSC_PCM_3500PPM 7
|
||||
+
|
||||
#define PHYREG11 0x28
|
||||
#define PHYREG11_SU_TRIM_0_7 0xF0
|
||||
|
||||
@@ -61,17 +65,26 @@
|
||||
#define PHYREG16 0x3C
|
||||
#define PHYREG16_SSC_CNT_VALUE 0x5f
|
||||
|
||||
+#define PHYREG17 0x40
|
||||
+
|
||||
#define PHYREG18 0x44
|
||||
#define PHYREG18_PLL_LOOP 0x32
|
||||
|
||||
+#define PHYREG21 0x50
|
||||
+#define PHYREG21_RX_SQUELCH_VAL 0x0D
|
||||
+
|
||||
#define PHYREG27 0x6C
|
||||
#define PHYREG27_RX_TRIM_RK3588 0x4C
|
||||
|
||||
+#define PHYREG30 0x74
|
||||
+
|
||||
#define PHYREG32 0x7C
|
||||
#define PHYREG32_SSC_MASK GENMASK(7, 4)
|
||||
+#define PHYREG32_SSC_DIR_MASK GENMASK(5, 4)
|
||||
#define PHYREG32_SSC_DIR_SHIFT 4
|
||||
#define PHYREG32_SSC_UPWARD 0
|
||||
#define PHYREG32_SSC_DOWNWARD 1
|
||||
+#define PHYREG32_SSC_OFFSET_MASK GENMASK(7, 6)
|
||||
#define PHYREG32_SSC_OFFSET_SHIFT 6
|
||||
#define PHYREG32_SSC_OFFSET_500PPM 1
|
||||
|
||||
@@ -79,6 +92,7 @@
|
||||
#define PHYREG33_PLL_KVCO_MASK GENMASK(4, 2)
|
||||
#define PHYREG33_PLL_KVCO_SHIFT 2
|
||||
#define PHYREG33_PLL_KVCO_VALUE 2
|
||||
+#define PHYREG33_PLL_KVCO_VALUE_RK3576 4
|
||||
|
||||
struct rockchip_combphy_priv;
|
||||
|
||||
@@ -98,6 +112,7 @@ struct rockchip_combphy_grfcfg {
|
||||
struct combphy_reg pipe_rxterm_set;
|
||||
struct combphy_reg pipe_txelec_set;
|
||||
struct combphy_reg pipe_txcomp_set;
|
||||
+ struct combphy_reg pipe_clk_24m;
|
||||
struct combphy_reg pipe_clk_25m;
|
||||
struct combphy_reg pipe_clk_100m;
|
||||
struct combphy_reg pipe_phymode_sel;
|
||||
@@ -587,6 +602,266 @@ static const struct rockchip_combphy_cfg
|
||||
.combphy_cfg = rk3568_combphy_cfg,
|
||||
};
|
||||
|
||||
+static int rk3576_combphy_cfg(struct rockchip_combphy_priv *priv)
|
||||
+{
|
||||
+ const struct rockchip_combphy_grfcfg *cfg = priv->cfg->grfcfg;
|
||||
+ unsigned long rate;
|
||||
+ u32 val;
|
||||
+
|
||||
+ switch (priv->type) {
|
||||
+ case PHY_TYPE_PCIE:
|
||||
+ /* Set SSC downward spread spectrum */
|
||||
+ val = FIELD_PREP(PHYREG32_SSC_MASK, PHYREG32_SSC_DOWNWARD);
|
||||
+ rockchip_combphy_updatel(priv, PHYREG32_SSC_MASK, val, PHYREG32);
|
||||
+
|
||||
+ rockchip_combphy_param_write(priv->phy_grf, &cfg->con0_for_pcie, true);
|
||||
+ rockchip_combphy_param_write(priv->phy_grf, &cfg->con1_for_pcie, true);
|
||||
+ rockchip_combphy_param_write(priv->phy_grf, &cfg->con2_for_pcie, true);
|
||||
+ rockchip_combphy_param_write(priv->phy_grf, &cfg->con3_for_pcie, true);
|
||||
+ break;
|
||||
+
|
||||
+ case PHY_TYPE_USB3:
|
||||
+ /* Set SSC downward spread spectrum */
|
||||
+ val = FIELD_PREP(PHYREG32_SSC_MASK, PHYREG32_SSC_DOWNWARD);
|
||||
+ rockchip_combphy_updatel(priv, PHYREG32_SSC_MASK, val, PHYREG32);
|
||||
+
|
||||
+ /* Enable adaptive CTLE for USB3.0 Rx */
|
||||
+ val = readl(priv->mmio + PHYREG15);
|
||||
+ val |= PHYREG15_CTLE_EN;
|
||||
+ writel(val, priv->mmio + PHYREG15);
|
||||
+
|
||||
+ /* Set PLL KVCO fine tuning signals */
|
||||
+ rockchip_combphy_updatel(priv, PHYREG33_PLL_KVCO_MASK, BIT(3), PHYREG33);
|
||||
+
|
||||
+ /* Set PLL LPF R1 to su_trim[10:7]=1001 */
|
||||
+ writel(PHYREG12_PLL_LPF_ADJ_VALUE, priv->mmio + PHYREG12);
|
||||
+
|
||||
+ /* Set PLL input clock divider 1/2 */
|
||||
+ val = FIELD_PREP(PHYREG6_PLL_DIV_MASK, PHYREG6_PLL_DIV_2);
|
||||
+ rockchip_combphy_updatel(priv, PHYREG6_PLL_DIV_MASK, val, PHYREG6);
|
||||
+
|
||||
+ /* Set PLL loop divider */
|
||||
+ writel(PHYREG18_PLL_LOOP, priv->mmio + PHYREG18);
|
||||
+
|
||||
+ /* Set PLL KVCO to min and set PLL charge pump current to max */
|
||||
+ writel(PHYREG11_SU_TRIM_0_7, priv->mmio + PHYREG11);
|
||||
+
|
||||
+ /* Set Rx squelch input filler bandwidth */
|
||||
+ writel(PHYREG21_RX_SQUELCH_VAL, priv->mmio + PHYREG21);
|
||||
+
|
||||
+ rockchip_combphy_param_write(priv->phy_grf, &cfg->pipe_txcomp_sel, false);
|
||||
+ rockchip_combphy_param_write(priv->phy_grf, &cfg->pipe_txelec_sel, false);
|
||||
+ rockchip_combphy_param_write(priv->phy_grf, &cfg->usb_mode_set, true);
|
||||
+ break;
|
||||
+
|
||||
+ case PHY_TYPE_SATA:
|
||||
+ /* Enable adaptive CTLE for SATA Rx */
|
||||
+ val = readl(priv->mmio + PHYREG15);
|
||||
+ val |= PHYREG15_CTLE_EN;
|
||||
+ writel(val, priv->mmio + PHYREG15);
|
||||
+
|
||||
+ /* Set tx_rterm = 50 ohm and rx_rterm = 43.5 ohm */
|
||||
+ val = PHYREG7_TX_RTERM_50OHM << PHYREG7_TX_RTERM_SHIFT;
|
||||
+ val |= PHYREG7_RX_RTERM_44OHM << PHYREG7_RX_RTERM_SHIFT;
|
||||
+ writel(val, priv->mmio + PHYREG7);
|
||||
+
|
||||
+ rockchip_combphy_param_write(priv->phy_grf, &cfg->con0_for_sata, true);
|
||||
+ rockchip_combphy_param_write(priv->phy_grf, &cfg->con1_for_sata, true);
|
||||
+ rockchip_combphy_param_write(priv->phy_grf, &cfg->con2_for_sata, true);
|
||||
+ rockchip_combphy_param_write(priv->phy_grf, &cfg->con3_for_sata, true);
|
||||
+ rockchip_combphy_param_write(priv->pipe_grf, &cfg->pipe_con0_for_sata, true);
|
||||
+ rockchip_combphy_param_write(priv->pipe_grf, &cfg->pipe_con1_for_sata, true);
|
||||
+ break;
|
||||
+
|
||||
+ default:
|
||||
+ dev_err(priv->dev, "incompatible PHY type\n");
|
||||
+ return -EINVAL;
|
||||
+ }
|
||||
+
|
||||
+ rate = clk_get_rate(priv->refclk);
|
||||
+
|
||||
+ switch (rate) {
|
||||
+ case REF_CLOCK_24MHz:
|
||||
+ rockchip_combphy_param_write(priv->phy_grf, &cfg->pipe_clk_24m, true);
|
||||
+ if (priv->type == PHY_TYPE_USB3 || priv->type == PHY_TYPE_SATA) {
|
||||
+ /* Set ssc_cnt[9:0]=0101111101 & 31.5KHz */
|
||||
+ val = FIELD_PREP(PHYREG15_SSC_CNT_MASK, PHYREG15_SSC_CNT_VALUE);
|
||||
+ rockchip_combphy_updatel(priv, PHYREG15_SSC_CNT_MASK,
|
||||
+ val, PHYREG15);
|
||||
+
|
||||
+ writel(PHYREG16_SSC_CNT_VALUE, priv->mmio + PHYREG16);
|
||||
+ } else if (priv->type == PHY_TYPE_PCIE) {
|
||||
+ /* PLL KVCO tuning fine */
|
||||
+ val = FIELD_PREP(PHYREG33_PLL_KVCO_MASK, PHYREG33_PLL_KVCO_VALUE_RK3576);
|
||||
+ rockchip_combphy_updatel(priv, PHYREG33_PLL_KVCO_MASK,
|
||||
+ val, PHYREG33);
|
||||
+
|
||||
+ /* Set up rx_pck invert and rx msb to disable */
|
||||
+ writel(0x00, priv->mmio + PHYREG27);
|
||||
+
|
||||
+ /*
|
||||
+ * Set up SU adjust signal:
|
||||
+ * su_trim[7:0], PLL KVCO adjust bits[2:0] to min
|
||||
+ * su_trim[15:8], PLL LPF R1 adujst bits[9:7]=3'b011
|
||||
+ * su_trim[31:24], CKDRV adjust
|
||||
+ */
|
||||
+ writel(0x90, priv->mmio + PHYREG11);
|
||||
+ writel(0x02, priv->mmio + PHYREG12);
|
||||
+ writel(0x57, priv->mmio + PHYREG14);
|
||||
+
|
||||
+ writel(PHYREG16_SSC_CNT_VALUE, priv->mmio + PHYREG16);
|
||||
+ }
|
||||
+ break;
|
||||
+
|
||||
+ case REF_CLOCK_25MHz:
|
||||
+ rockchip_combphy_param_write(priv->phy_grf, &cfg->pipe_clk_25m, true);
|
||||
+ break;
|
||||
+
|
||||
+ case REF_CLOCK_100MHz:
|
||||
+ rockchip_combphy_param_write(priv->phy_grf, &cfg->pipe_clk_100m, true);
|
||||
+ if (priv->type == PHY_TYPE_PCIE) {
|
||||
+ /* gate_tx_pck_sel length select work for L1SS */
|
||||
+ writel(0xc0, priv->mmio + PHYREG30);
|
||||
+
|
||||
+ /* PLL KVCO tuning fine */
|
||||
+ val = FIELD_PREP(PHYREG33_PLL_KVCO_MASK, PHYREG33_PLL_KVCO_VALUE_RK3576);
|
||||
+ rockchip_combphy_updatel(priv, PHYREG33_PLL_KVCO_MASK,
|
||||
+ val, PHYREG33);
|
||||
+
|
||||
+ /* Set up rx_trim: PLL LPF C1 85pf R1 1.25kohm */
|
||||
+ writel(0x4c, priv->mmio + PHYREG27);
|
||||
+
|
||||
+ /*
|
||||
+ * Set up SU adjust signal:
|
||||
+ * su_trim[7:0], PLL KVCO adjust bits[2:0] to min
|
||||
+ * su_trim[15:8], bypass PLL loop divider code, and
|
||||
+ * PLL LPF R1 adujst bits[9:7]=3'b101
|
||||
+ * su_trim[23:16], CKRCV adjust
|
||||
+ * su_trim[31:24], CKDRV adjust
|
||||
+ */
|
||||
+ writel(0x90, priv->mmio + PHYREG11);
|
||||
+ writel(0x43, priv->mmio + PHYREG12);
|
||||
+ writel(0x88, priv->mmio + PHYREG13);
|
||||
+ writel(0x56, priv->mmio + PHYREG14);
|
||||
+ } else if (priv->type == PHY_TYPE_SATA) {
|
||||
+ /* downward spread spectrum +500ppm */
|
||||
+ val = FIELD_PREP(PHYREG32_SSC_DIR_MASK, PHYREG32_SSC_DOWNWARD);
|
||||
+ val |= FIELD_PREP(PHYREG32_SSC_OFFSET_MASK, PHYREG32_SSC_OFFSET_500PPM);
|
||||
+ rockchip_combphy_updatel(priv, PHYREG32_SSC_MASK, val, PHYREG32);
|
||||
+
|
||||
+ /* ssc ppm adjust to 3500ppm */
|
||||
+ rockchip_combphy_updatel(priv, PHYREG10_SSC_PCM_MASK,
|
||||
+ PHYREG10_SSC_PCM_3500PPM,
|
||||
+ PHYREG10);
|
||||
+ }
|
||||
+ break;
|
||||
+
|
||||
+ default:
|
||||
+ dev_err(priv->dev, "Unsupported rate: %lu\n", rate);
|
||||
+ return -EINVAL;
|
||||
+ }
|
||||
+
|
||||
+ if (priv->ext_refclk) {
|
||||
+ rockchip_combphy_param_write(priv->phy_grf, &cfg->pipe_clk_ext, true);
|
||||
+ if (priv->type == PHY_TYPE_PCIE && rate == REF_CLOCK_100MHz) {
|
||||
+ val = FIELD_PREP(PHYREG33_PLL_KVCO_MASK, PHYREG33_PLL_KVCO_VALUE_RK3576);
|
||||
+ rockchip_combphy_updatel(priv, PHYREG33_PLL_KVCO_MASK,
|
||||
+ val, PHYREG33);
|
||||
+
|
||||
+ /* Set up rx_trim: PLL LPF C1 85pf R1 2.5kohm */
|
||||
+ writel(0x0c, priv->mmio + PHYREG27);
|
||||
+
|
||||
+ /*
|
||||
+ * Set up SU adjust signal:
|
||||
+ * su_trim[7:0], PLL KVCO adjust bits[2:0] to min
|
||||
+ * su_trim[15:8], bypass PLL loop divider code, and
|
||||
+ * PLL LPF R1 adujst bits[9:7]=3'b101.
|
||||
+ * su_trim[23:16], CKRCV adjust
|
||||
+ * su_trim[31:24], CKDRV adjust
|
||||
+ */
|
||||
+ writel(0x90, priv->mmio + PHYREG11);
|
||||
+ writel(0x43, priv->mmio + PHYREG12);
|
||||
+ writel(0x88, priv->mmio + PHYREG13);
|
||||
+ writel(0x56, priv->mmio + PHYREG14);
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+ if (priv->enable_ssc) {
|
||||
+ val = readl(priv->mmio + PHYREG8);
|
||||
+ val |= PHYREG8_SSC_EN;
|
||||
+ writel(val, priv->mmio + PHYREG8);
|
||||
+
|
||||
+ if (priv->type == PHY_TYPE_PCIE && rate == REF_CLOCK_24MHz) {
|
||||
+ /* Set PLL loop divider */
|
||||
+ writel(0x00, priv->mmio + PHYREG17);
|
||||
+ writel(PHYREG18_PLL_LOOP, priv->mmio + PHYREG18);
|
||||
+
|
||||
+ /* Set up rx_pck invert and rx msb to disable */
|
||||
+ writel(0x00, priv->mmio + PHYREG27);
|
||||
+
|
||||
+ /*
|
||||
+ * Set up SU adjust signal:
|
||||
+ * su_trim[7:0], PLL KVCO adjust bits[2:0] to min
|
||||
+ * su_trim[15:8], PLL LPF R1 adujst bits[9:7]=3'b101
|
||||
+ * su_trim[23:16], CKRCV adjust
|
||||
+ * su_trim[31:24], CKDRV adjust
|
||||
+ */
|
||||
+ writel(0x90, priv->mmio + PHYREG11);
|
||||
+ writel(0x02, priv->mmio + PHYREG12);
|
||||
+ writel(0x08, priv->mmio + PHYREG13);
|
||||
+ writel(0x57, priv->mmio + PHYREG14);
|
||||
+ writel(0x40, priv->mmio + PHYREG15);
|
||||
+
|
||||
+ writel(PHYREG16_SSC_CNT_VALUE, priv->mmio + PHYREG16);
|
||||
+
|
||||
+ val = FIELD_PREP(PHYREG33_PLL_KVCO_MASK, PHYREG33_PLL_KVCO_VALUE_RK3576);
|
||||
+ writel(val, priv->mmio + PHYREG33);
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+ return 0;
|
||||
+}
|
||||
+
|
||||
+static const struct rockchip_combphy_grfcfg rk3576_combphy_grfcfgs = {
|
||||
+ /* pipe-phy-grf */
|
||||
+ .pcie_mode_set = { 0x0000, 5, 0, 0x00, 0x11 },
|
||||
+ .usb_mode_set = { 0x0000, 5, 0, 0x00, 0x04 },
|
||||
+ .pipe_rxterm_set = { 0x0000, 12, 12, 0x00, 0x01 },
|
||||
+ .pipe_txelec_set = { 0x0004, 1, 1, 0x00, 0x01 },
|
||||
+ .pipe_txcomp_set = { 0x0004, 4, 4, 0x00, 0x01 },
|
||||
+ .pipe_clk_24m = { 0x0004, 14, 13, 0x00, 0x00 },
|
||||
+ .pipe_clk_25m = { 0x0004, 14, 13, 0x00, 0x01 },
|
||||
+ .pipe_clk_100m = { 0x0004, 14, 13, 0x00, 0x02 },
|
||||
+ .pipe_phymode_sel = { 0x0008, 1, 1, 0x00, 0x01 },
|
||||
+ .pipe_rate_sel = { 0x0008, 2, 2, 0x00, 0x01 },
|
||||
+ .pipe_rxterm_sel = { 0x0008, 8, 8, 0x00, 0x01 },
|
||||
+ .pipe_txelec_sel = { 0x0008, 12, 12, 0x00, 0x01 },
|
||||
+ .pipe_txcomp_sel = { 0x0008, 15, 15, 0x00, 0x01 },
|
||||
+ .pipe_clk_ext = { 0x000c, 9, 8, 0x02, 0x01 },
|
||||
+ .pipe_phy_status = { 0x0034, 6, 6, 0x01, 0x00 },
|
||||
+ .con0_for_pcie = { 0x0000, 15, 0, 0x00, 0x1000 },
|
||||
+ .con1_for_pcie = { 0x0004, 15, 0, 0x00, 0x0000 },
|
||||
+ .con2_for_pcie = { 0x0008, 15, 0, 0x00, 0x0101 },
|
||||
+ .con3_for_pcie = { 0x000c, 15, 0, 0x00, 0x0200 },
|
||||
+ .con0_for_sata = { 0x0000, 15, 0, 0x00, 0x0129 },
|
||||
+ .con1_for_sata = { 0x0004, 15, 0, 0x00, 0x0000 },
|
||||
+ .con2_for_sata = { 0x0008, 15, 0, 0x00, 0x80c1 },
|
||||
+ .con3_for_sata = { 0x000c, 15, 0, 0x00, 0x0407 },
|
||||
+ /* php-grf */
|
||||
+ .pipe_con0_for_sata = { 0x001C, 2, 0, 0x00, 0x2 },
|
||||
+ .pipe_con1_for_sata = { 0x0020, 2, 0, 0x00, 0x2 },
|
||||
+};
|
||||
+
|
||||
+static const struct rockchip_combphy_cfg rk3576_combphy_cfgs = {
|
||||
+ .num_phys = 2,
|
||||
+ .phy_ids = {
|
||||
+ 0x2b050000,
|
||||
+ 0x2b060000
|
||||
+ },
|
||||
+ .grfcfg = &rk3576_combphy_grfcfgs,
|
||||
+ .combphy_cfg = rk3576_combphy_cfg,
|
||||
+};
|
||||
+
|
||||
static int rk3588_combphy_cfg(struct rockchip_combphy_priv *priv)
|
||||
{
|
||||
const struct rockchip_combphy_grfcfg *cfg = priv->cfg->grfcfg;
|
||||
@@ -779,6 +1054,10 @@ static const struct of_device_id rockchi
|
||||
.data = &rk3568_combphy_cfgs,
|
||||
},
|
||||
{
|
||||
+ .compatible = "rockchip,rk3576-naneng-combphy",
|
||||
+ .data = &rk3576_combphy_cfgs,
|
||||
+ },
|
||||
+ {
|
||||
.compatible = "rockchip,rk3588-naneng-combphy",
|
||||
.data = &rk3588_combphy_cfgs,
|
||||
},
|
@@ -0,0 +1,66 @@
|
||||
From 6b070711b702638622f4b7072e36328a47356576 Mon Sep 17 00:00:00 2001
|
||||
From: Shawn Lin <shawn.lin@rock-chips.com>
|
||||
Date: Wed, 5 Feb 2025 14:15:54 +0800
|
||||
Subject: [PATCH] scsi: ufs: core: Export ufshcd_dme_reset() and
|
||||
ufshcd_dme_enable()
|
||||
|
||||
These two APIs will be used by glue driver if they need a different HCE
|
||||
process.
|
||||
|
||||
Reviewed-by: Manivannan Sadhasivam <manivannan.sadhasivam@linaro.org>
|
||||
Signed-off-by: Shawn Lin <shawn.lin@rock-chips.com>
|
||||
Link: https://lore.kernel.org/r/1738736156-119203-6-git-send-email-shawn.lin@rock-chips.com
|
||||
Reviewed-by: Bart Van Assche <bvanassche@acm.org>
|
||||
Signed-off-by: Martin K. Petersen <martin.petersen@oracle.com>
|
||||
---
|
||||
drivers/ufs/core/ufshcd.c | 6 ++++--
|
||||
include/ufs/ufshcd.h | 2 ++
|
||||
2 files changed, 6 insertions(+), 2 deletions(-)
|
||||
|
||||
--- a/drivers/ufs/core/ufshcd.c
|
||||
+++ b/drivers/ufs/core/ufshcd.c
|
||||
@@ -4043,7 +4043,7 @@ static int ufshcd_dme_link_startup(struc
|
||||
*
|
||||
* 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,
|
||||
@@ -4057,6 +4057,7 @@ static int ufshcd_dme_reset(struct ufs_h
|
||||
|
||||
return ret;
|
||||
}
|
||||
+EXPORT_SYMBOL_GPL(ufshcd_dme_reset);
|
||||
|
||||
int ufshcd_dme_configure_adapt(struct ufs_hba *hba,
|
||||
int agreed_gear,
|
||||
@@ -4082,7 +4083,7 @@ EXPORT_SYMBOL_GPL(ufshcd_dme_configure_a
|
||||
*
|
||||
* 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,
|
||||
@@ -4096,6 +4097,7 @@ static int ufshcd_dme_enable(struct ufs_
|
||||
|
||||
return ret;
|
||||
}
|
||||
+EXPORT_SYMBOL_GPL(ufshcd_dme_enable);
|
||||
|
||||
static inline void ufshcd_add_delay_before_dme_cmd(struct ufs_hba *hba)
|
||||
{
|
||||
--- a/include/ufs/ufshcd.h
|
||||
+++ b/include/ufs/ufshcd.h
|
||||
@@ -1361,6 +1361,8 @@ extern int ufshcd_system_thaw(struct 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);
|
@@ -0,0 +1,511 @@
|
||||
From d3cbe455d6eb600dee27bf5294f6fe8c2bb06b5f Mon Sep 17 00:00:00 2001
|
||||
From: Shawn Lin <shawn.lin@rock-chips.com>
|
||||
Date: Wed, 5 Feb 2025 14:15:55 +0800
|
||||
Subject: [PATCH] scsi: ufs: rockchip: Initial support for UFS
|
||||
|
||||
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
|
||||
|
||||
[mkp: fix build errors]
|
||||
|
||||
Signed-off-by: Shawn Lin <shawn.lin@rock-chips.com>
|
||||
Link: https://lore.kernel.org/r/1738736156-119203-7-git-send-email-shawn.lin@rock-chips.com
|
||||
Reviewed-by: Manivannan Sadhasivam <manivannan.sadhasivam@linaro.org>
|
||||
Reviewed-by: Ulf Hansson <ulf.hansson@linaro.org>
|
||||
Signed-off-by: Martin K. Petersen <martin.petersen@oracle.com>
|
||||
---
|
||||
drivers/ufs/host/Kconfig | 12 ++
|
||||
drivers/ufs/host/Makefile | 1 +
|
||||
drivers/ufs/host/ufs-rockchip.c | 354 ++++++++++++++++++++++++++++++++
|
||||
drivers/ufs/host/ufs-rockchip.h | 90 ++++++++
|
||||
4 files changed, 457 insertions(+)
|
||||
create mode 100644 drivers/ufs/host/ufs-rockchip.c
|
||||
create mode 100644 drivers/ufs/host/ufs-rockchip.h
|
||||
|
||||
--- 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.
|
||||
--- a/drivers/ufs/host/Makefile
|
||||
+++ b/drivers/ufs/host/Makefile
|
||||
@@ -10,5 +10,6 @@ obj-$(CONFIG_SCSI_UFSHCD_PLATFORM) += uf
|
||||
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
|
||||
--- /dev/null
|
||||
+++ b/drivers/ufs/host/ufs-rockchip.c
|
||||
@@ -0,0 +1,354 @@
|
||||
+// SPDX-License-Identifier: GPL-2.0-only
|
||||
+/*
|
||||
+ * Rockchip UFS Host Controller driver
|
||||
+ *
|
||||
+ * Copyright (C) 2025 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;
|
||||
+
|
||||
+ return ufshcd_vops_phy_initialization(hba);
|
||||
+ }
|
||||
+
|
||||
+ return 0;
|
||||
+}
|
||||
+
|
||||
+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(MPHY_CFG, 0x0), MPHY_CFG_ENABLE);
|
||||
+ for (int i = 0; i < 2; i++) {
|
||||
+ /* Configuration M - TX */
|
||||
+ ufshcd_dme_set(hba, UIC_ARG_MIB_SEL(VND_TX_CLK_PRD, SEL_TX_LANE0 + i), 0x06);
|
||||
+ ufshcd_dme_set(hba, UIC_ARG_MIB_SEL(VND_TX_CLK_PRD_EN, SEL_TX_LANE0 + i), 0x02);
|
||||
+ ufshcd_dme_set(hba, UIC_ARG_MIB_SEL(VND_TX_LINERESET_VALUE, SEL_TX_LANE0 + i), 0x44);
|
||||
+ ufshcd_dme_set(hba, UIC_ARG_MIB_SEL(VND_TX_LINERESET_PVALUE1, SEL_TX_LANE0 + i), 0xe6);
|
||||
+ ufshcd_dme_set(hba, UIC_ARG_MIB_SEL(VND_TX_LINERESET_PVALUE2, SEL_TX_LANE0 + i), 0x07);
|
||||
+ ufshcd_dme_set(hba, UIC_ARG_MIB_SEL(VND_TX_TASE_VALUE, SEL_TX_LANE0 + i), 0x93);
|
||||
+ ufshcd_dme_set(hba, UIC_ARG_MIB_SEL(VND_TX_BASE_NVALUE, SEL_TX_LANE0 + i), 0xc9);
|
||||
+ ufshcd_dme_set(hba, UIC_ARG_MIB_SEL(VND_TX_POWER_SAVING_CTRL, SEL_TX_LANE0 + i), 0x00);
|
||||
+ /* Configuration M - RX */
|
||||
+ ufshcd_dme_set(hba, UIC_ARG_MIB_SEL(VND_RX_CLK_PRD, SEL_RX_LANE0 + i), 0x06);
|
||||
+ ufshcd_dme_set(hba, UIC_ARG_MIB_SEL(VND_RX_CLK_PRD_EN, SEL_RX_LANE0 + i), 0x00);
|
||||
+ ufshcd_dme_set(hba, UIC_ARG_MIB_SEL(VND_RX_LINERESET_VALUE, SEL_RX_LANE0 + i), 0x58);
|
||||
+ ufshcd_dme_set(hba, UIC_ARG_MIB_SEL(VND_RX_LINERESET_PVALUE1, SEL_RX_LANE0 + i), 0x8c);
|
||||
+ ufshcd_dme_set(hba, UIC_ARG_MIB_SEL(VND_RX_LINERESET_PVALUE2, SEL_RX_LANE0 + i), 0x02);
|
||||
+ ufshcd_dme_set(hba, UIC_ARG_MIB_SEL(VND_RX_LINERESET_OPTION, SEL_RX_LANE0 + i), 0xf6);
|
||||
+ ufshcd_dme_set(hba, UIC_ARG_MIB_SEL(VND_RX_POWER_SAVING_CTRL, SEL_RX_LANE0 + i), 0x69);
|
||||
+ }
|
||||
+
|
||||
+ /* disable the mphy DME_SET cfg */
|
||||
+ ufshcd_dme_set(hba, UIC_ARG_MIB_SEL(MPHY_CFG, 0x0), MPHY_CFG_DISABLE);
|
||||
+
|
||||
+ ufs_sys_writel(host->mphy_base, 0x80, CMN_REG23);
|
||||
+ ufs_sys_writel(host->mphy_base, 0xB5, TRSV0_REG14);
|
||||
+ ufs_sys_writel(host->mphy_base, 0xB5, TRSV1_REG14);
|
||||
+
|
||||
+ ufs_sys_writel(host->mphy_base, 0x03, TRSV0_REG15);
|
||||
+ ufs_sys_writel(host->mphy_base, 0x03, TRSV1_REG15);
|
||||
+
|
||||
+ ufs_sys_writel(host->mphy_base, 0x38, TRSV0_REG08);
|
||||
+ ufs_sys_writel(host->mphy_base, 0x38, TRSV1_REG08);
|
||||
+
|
||||
+ ufs_sys_writel(host->mphy_base, 0x50, TRSV0_REG29);
|
||||
+ ufs_sys_writel(host->mphy_base, 0x50, TRSV1_REG29);
|
||||
+
|
||||
+ ufs_sys_writel(host->mphy_base, 0x80, TRSV0_REG2E);
|
||||
+ ufs_sys_writel(host->mphy_base, 0x80, TRSV1_REG2E);
|
||||
+
|
||||
+ ufs_sys_writel(host->mphy_base, 0x18, TRSV0_REG3C);
|
||||
+ ufs_sys_writel(host->mphy_base, 0x18, TRSV1_REG3C);
|
||||
+
|
||||
+ ufs_sys_writel(host->mphy_base, 0x03, TRSV0_REG16);
|
||||
+ ufs_sys_writel(host->mphy_base, 0x03, TRSV1_REG16);
|
||||
+
|
||||
+ ufs_sys_writel(host->mphy_base, 0x20, TRSV0_REG17);
|
||||
+ ufs_sys_writel(host->mphy_base, 0x20, TRSV1_REG17);
|
||||
+
|
||||
+ ufs_sys_writel(host->mphy_base, 0xC0, TRSV0_REG18);
|
||||
+ ufs_sys_writel(host->mphy_base, 0xC0, TRSV1_REG18);
|
||||
+
|
||||
+ ufs_sys_writel(host->mphy_base, 0x03, CMN_REG25);
|
||||
+
|
||||
+ ufs_sys_writel(host->mphy_base, 0x03, TRSV0_REG3D);
|
||||
+ ufs_sys_writel(host->mphy_base, 0x03, TRSV1_REG3D);
|
||||
+
|
||||
+ ufs_sys_writel(host->mphy_base, 0xC0, CMN_REG23);
|
||||
+ udelay(1);
|
||||
+ ufs_sys_writel(host->mphy_base, 0x00, CMN_REG23);
|
||||
+
|
||||
+ 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;
|
||||
+
|
||||
+ 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),
|
||||
+ "Failed to map HCI system control registers\n");
|
||||
+
|
||||
+ 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),
|
||||
+ "Failed to map mphy system control registers\n");
|
||||
+
|
||||
+ 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),
|
||||
+ "Failed to map mphy base registers\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);
|
||||
+ udelay(1);
|
||||
+ 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 clock unavailable\n");
|
||||
+
|
||||
+ host->rst_gpio = devm_gpiod_get(dev, "reset", GPIOD_OUT_LOW);
|
||||
+ if (IS_ERR(host->rst_gpio))
|
||||
+ return dev_err_probe(dev, PTR_ERR(host->rst_gpio),
|
||||
+ "failed to get reset gpio\n");
|
||||
+
|
||||
+ err = devm_clk_bulk_get_all_enabled(dev, &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;
|
||||
+
|
||||
+ /* Set the default desired pm level in case no users set via sysfs */
|
||||
+ ufs_rockchip_set_pm_lvl(hba);
|
||||
+
|
||||
+ 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);
|
||||
+
|
||||
+ gpiod_set_value_cansleep(host->rst_gpio, 1);
|
||||
+ usleep_range(20, 25);
|
||||
+
|
||||
+ 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;
|
||||
+ int err;
|
||||
+
|
||||
+ vops = device_get_match_data(dev);
|
||||
+ if (!vops)
|
||||
+ return dev_err_probe(dev, -ENODATA, "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");
|
||||
+
|
||||
+ return 0;
|
||||
+}
|
||||
+
|
||||
+static void ufs_rockchip_remove(struct platform_device *pdev)
|
||||
+{
|
||||
+ ufshcd_pltfrm_remove(pdev);
|
||||
+}
|
||||
+
|
||||
+#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);
|
||||
+
|
||||
+ /* Do not power down the genpd 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);
|
||||
+ udelay(1);
|
||||
+ 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 spm_lvl is less than level 5, it means we need to keep the host
|
||||
+ * controller in powered-on state. So device_set_awake_path() is
|
||||
+ * calling pm core to notify the genpd provider to meet this requirement
|
||||
+ */
|
||||
+ if (hba->spm_lvl < UFS_PM_LVL_5)
|
||||
+ device_set_awake_path(dev);
|
||||
+
|
||||
+ err = ufshcd_system_suspend(dev);
|
||||
+ if (err) {
|
||||
+ dev_err(hba->dev, "UFSHCD 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");
|
||||
--- /dev/null
|
||||
+++ b/drivers/ufs/host/ufs-rockchip.h
|
||||
@@ -0,0 +1,90 @@
|
||||
+/* SPDX-License-Identifier: GPL-2.0-only */
|
||||
+/*
|
||||
+ * Rockchip UFS Host Controller driver
|
||||
+ *
|
||||
+ * Copyright (C) 2025 Rockchip Electronics Co., Ltd.
|
||||
+ */
|
||||
+
|
||||
+#ifndef _UFS_ROCKCHIP_H_
|
||||
+#define _UFS_ROCKCHIP_H_
|
||||
+
|
||||
+#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 VND_TX_CLK_PRD 0xAA
|
||||
+#define VND_TX_CLK_PRD_EN 0xA9
|
||||
+#define VND_TX_LINERESET_PVALUE2 0xAB
|
||||
+#define VND_TX_LINERESET_PVALUE1 0xAC
|
||||
+#define VND_TX_LINERESET_VALUE 0xAD
|
||||
+#define VND_TX_BASE_NVALUE 0x93
|
||||
+#define VND_TX_TASE_VALUE 0x94
|
||||
+#define VND_TX_POWER_SAVING_CTRL 0x7F
|
||||
+#define VND_RX_CLK_PRD 0x12
|
||||
+#define VND_RX_CLK_PRD_EN 0x11
|
||||
+#define VND_RX_LINERESET_PVALUE2 0x1B
|
||||
+#define VND_RX_LINERESET_PVALUE1 0x1C
|
||||
+#define VND_RX_LINERESET_VALUE 0x1D
|
||||
+#define VND_RX_LINERESET_OPTION 0x25
|
||||
+#define VND_RX_POWER_SAVING_CTRL 0x2F
|
||||
+#define VND_RX_SAVE_DET_CTRL 0x1E
|
||||
+
|
||||
+#define CMN_REG23 0x8C
|
||||
+#define CMN_REG25 0x94
|
||||
+#define TRSV0_REG08 0xE0
|
||||
+#define TRSV1_REG08 0x220
|
||||
+#define TRSV0_REG14 0x110
|
||||
+#define TRSV1_REG14 0x250
|
||||
+#define TRSV0_REG15 0x134
|
||||
+#define TRSV1_REG15 0x274
|
||||
+#define TRSV0_REG16 0x128
|
||||
+#define TRSV1_REG16 0x268
|
||||
+#define TRSV0_REG17 0x12C
|
||||
+#define TRSV1_REG17 0x26c
|
||||
+#define TRSV0_REG18 0x120
|
||||
+#define TRSV1_REG18 0x260
|
||||
+#define TRSV0_REG29 0x164
|
||||
+#define TRSV1_REG29 0x2A4
|
||||
+#define TRSV0_REG2E 0x178
|
||||
+#define TRSV1_REG2E 0x2B8
|
||||
+#define TRSV0_REG3C 0x1B0
|
||||
+#define TRSV1_REG3C 0x2F0
|
||||
+#define TRSV0_REG3D 0x1B4
|
||||
+#define TRSV1_REG3D 0x2F4
|
||||
+
|
||||
+#define MPHY_CFG 0x200
|
||||
+#define MPHY_CFG_ENABLE 0x40
|
||||
+#define MPHY_CFG_DISABLE 0x0
|
||||
+
|
||||
+#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;
|
||||
+ 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_ */
|
@@ -0,0 +1,26 @@
|
||||
From 4fffffd3b13439980d778c58b1f63439287b9fdc Mon Sep 17 00:00:00 2001
|
||||
From: Shawn Lin <shawn.lin@rock-chips.com>
|
||||
Date: Wed, 26 Feb 2025 14:52:13 +0800
|
||||
Subject: [PATCH] scsi: ufs: rockchip: Fix devm_clk_bulk_get_all_enabled()
|
||||
return value
|
||||
|
||||
A positive value is for the number of clocks obtained if assigned.
|
||||
|
||||
Signed-off-by: Shawn Lin <shawn.lin@rock-chips.com>
|
||||
Link: https://lore.kernel.org/r/1740552733-182527-1-git-send-email-shawn.lin@rock-chips.com
|
||||
Signed-off-by: Martin K. Petersen <martin.petersen@oracle.com>
|
||||
---
|
||||
drivers/ufs/host/ufs-rockchip.c | 2 +-
|
||||
1 file changed, 1 insertion(+), 1 deletion(-)
|
||||
|
||||
--- a/drivers/ufs/host/ufs-rockchip.c
|
||||
+++ b/drivers/ufs/host/ufs-rockchip.c
|
||||
@@ -171,7 +171,7 @@ static int ufs_rockchip_common_init(stru
|
||||
"failed to get reset gpio\n");
|
||||
|
||||
err = devm_clk_bulk_get_all_enabled(dev, &host->clks);
|
||||
- if (err)
|
||||
+ if (err < 0)
|
||||
return dev_err_probe(dev, err, "failed to enable clocks\n");
|
||||
|
||||
host->hba = hba;
|
Reference in New Issue
Block a user