summaryrefslogtreecommitdiff
path: root/drivers
diff options
context:
space:
mode:
Diffstat (limited to 'drivers')
-rw-r--r--drivers/misc/Kconfig9
-rw-r--r--drivers/misc/Makefile1
-rw-r--r--drivers/misc/rockchip-io-domain.c167
-rw-r--r--drivers/net/Kconfig8
-rw-r--r--drivers/net/Makefile1
-rw-r--r--drivers/net/dwc_eth_qos.c33
-rw-r--r--drivers/net/dwc_eth_qos.h3
-rw-r--r--drivers/net/dwc_eth_qos_rockchip.c531
-rw-r--r--drivers/pci/pcie_dw_rockchip.c58
-rw-r--r--drivers/phy/rockchip/phy-rockchip-naneng-combphy.c6
-rw-r--r--drivers/phy/rockchip/phy-rockchip-snps-pcie3.c230
-rw-r--r--drivers/power/pmic/Kconfig1
-rw-r--r--drivers/power/pmic/rk8xx.c20
-rw-r--r--drivers/power/regulator/regulator-uclass.c18
-rw-r--r--drivers/power/regulator/rk8xx.c95
15 files changed, 1053 insertions, 128 deletions
diff --git a/drivers/misc/Kconfig b/drivers/misc/Kconfig
index c930e4a361b..fccd9b89b81 100644
--- a/drivers/misc/Kconfig
+++ b/drivers/misc/Kconfig
@@ -101,6 +101,15 @@ config ROCKCHIP_OTP
addressing and a length or through child-nodes that are generated
based on the e-fuse map retrieved from the DTS.
+config ROCKCHIP_IODOMAIN
+ bool "Rockchip IO-domain driver support"
+ depends on DM_REGULATOR && ARCH_ROCKCHIP
+ default y if ROCKCHIP_RK3568
+ help
+ Enable support for IO-domains in Rockchip SoCs. It is necessary
+ for the IO-domain setting of the SoC to match the voltage supplied
+ by the regulators.
+
config SIFIVE_OTP
bool "SiFive eMemory OTP driver"
depends on MISC
diff --git a/drivers/misc/Makefile b/drivers/misc/Makefile
index fd8805f34bd..b67b82358a6 100644
--- a/drivers/misc/Makefile
+++ b/drivers/misc/Makefile
@@ -69,6 +69,7 @@ obj-$(CONFIG_SANDBOX) += qfw_sandbox.o
endif
obj-$(CONFIG_ROCKCHIP_EFUSE) += rockchip-efuse.o
obj-$(CONFIG_ROCKCHIP_OTP) += rockchip-otp.o
+obj-$(CONFIG_$(SPL_TPL_)ROCKCHIP_IODOMAIN) += rockchip-io-domain.o
obj-$(CONFIG_SANDBOX) += syscon_sandbox.o misc_sandbox.o
obj-$(CONFIG_SIFIVE_OTP) += sifive-otp.o
obj-$(CONFIG_SMSC_LPC47M) += smsc_lpc47m.o
diff --git a/drivers/misc/rockchip-io-domain.c b/drivers/misc/rockchip-io-domain.c
new file mode 100644
index 00000000000..3f6227f993f
--- /dev/null
+++ b/drivers/misc/rockchip-io-domain.c
@@ -0,0 +1,167 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Rockchip IO Voltage Domain driver
+ *
+ * Ported from linux drivers/soc/rockchip/io-domain.c
+ */
+
+#include <common.h>
+#include <dm.h>
+#include <dm/device_compat.h>
+#include <regmap.h>
+#include <syscon.h>
+#include <power/regulator.h>
+
+#define MAX_SUPPLIES 16
+
+/*
+ * The max voltage for 1.8V and 3.3V come from the Rockchip datasheet under
+ * "Recommended Operating Conditions" for "Digital GPIO". When the typical
+ * is 3.3V the max is 3.6V. When the typical is 1.8V the max is 1.98V.
+ *
+ * They are used like this:
+ * - If the voltage on a rail is above the "1.8" voltage (1.98V) we'll tell the
+ * SoC we're at 3.3.
+ * - If the voltage on a rail is above the "3.3" voltage (3.6V) we'll consider
+ * that to be an error.
+ */
+#define MAX_VOLTAGE_1_8 1980000
+#define MAX_VOLTAGE_3_3 3600000
+
+#define RK3568_PMU_GRF_IO_VSEL0 0x0140
+#define RK3568_PMU_GRF_IO_VSEL1 0x0144
+#define RK3568_PMU_GRF_IO_VSEL2 0x0148
+
+struct rockchip_iodomain_soc_data {
+ int grf_offset;
+ const char *supply_names[MAX_SUPPLIES];
+ int (*write)(struct regmap *grf, int idx, int uV);
+};
+
+static int rk3568_iodomain_write(struct regmap *grf, int idx, int uV)
+{
+ u32 is_3v3 = uV > MAX_VOLTAGE_1_8;
+ u32 val0, val1;
+ int b;
+
+ switch (idx) {
+ case 0: /* pmuio1 */
+ break;
+ case 1: /* pmuio2 */
+ b = idx;
+ val0 = BIT(16 + b) | (is_3v3 ? 0 : BIT(b));
+ b = idx + 4;
+ val1 = BIT(16 + b) | (is_3v3 ? BIT(b) : 0);
+
+ regmap_write(grf, RK3568_PMU_GRF_IO_VSEL2, val0);
+ regmap_write(grf, RK3568_PMU_GRF_IO_VSEL2, val1);
+ break;
+ case 3: /* vccio2 */
+ break;
+ case 2: /* vccio1 */
+ case 4: /* vccio3 */
+ case 5: /* vccio4 */
+ case 6: /* vccio5 */
+ case 7: /* vccio6 */
+ case 8: /* vccio7 */
+ b = idx - 1;
+ val0 = BIT(16 + b) | (is_3v3 ? 0 : BIT(b));
+ val1 = BIT(16 + b) | (is_3v3 ? BIT(b) : 0);
+
+ regmap_write(grf, RK3568_PMU_GRF_IO_VSEL0, val0);
+ regmap_write(grf, RK3568_PMU_GRF_IO_VSEL1, val1);
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+static const struct rockchip_iodomain_soc_data soc_data_rk3568_pmu = {
+ .grf_offset = 0x140,
+ .supply_names = {
+ NULL,
+ "pmuio2-supply",
+ "vccio1-supply",
+ NULL,
+ "vccio3-supply",
+ "vccio4-supply",
+ "vccio5-supply",
+ "vccio6-supply",
+ "vccio7-supply",
+ },
+ .write = rk3568_iodomain_write,
+};
+
+static const struct udevice_id rockchip_iodomain_ids[] = {
+ {
+ .compatible = "rockchip,rk3568-pmu-io-voltage-domain",
+ .data = (ulong)&soc_data_rk3568_pmu,
+ },
+ { }
+};
+
+static int rockchip_iodomain_bind(struct udevice *dev)
+{
+ /*
+ * According to the Hardware Design Guide, IO-domain configuration must
+ * be consistent with the power supply voltage (1.8V or 3.3V).
+ * Probe after bind to configure IO-domain voltage early during boot.
+ */
+ dev_or_flags(dev, DM_FLAG_PROBE_AFTER_BIND);
+
+ return 0;
+}
+
+static int rockchip_iodomain_probe(struct udevice *dev)
+{
+ struct rockchip_iodomain_soc_data *soc_data =
+ (struct rockchip_iodomain_soc_data *)dev_get_driver_data(dev);
+ struct regmap *grf;
+ int ret;
+
+ grf = syscon_get_regmap(dev_get_parent(dev));
+ if (IS_ERR(grf))
+ return PTR_ERR(grf);
+
+ for (int i = 0; i < MAX_SUPPLIES; i++) {
+ const char *supply_name = soc_data->supply_names[i];
+ struct udevice *reg;
+ int uV;
+
+ if (!supply_name)
+ continue;
+
+ ret = device_get_supply_regulator(dev, supply_name, &reg);
+ if (ret)
+ continue;
+
+ ret = regulator_autoset(reg);
+ if (ret && ret != -EALREADY && ret != -EMEDIUMTYPE &&
+ ret != -ENOSYS)
+ continue;
+
+ uV = regulator_get_value(reg);
+ if (uV <= 0)
+ continue;
+
+ if (uV > MAX_VOLTAGE_3_3) {
+ dev_crit(dev, "%s: %d uV is too high. May damage SoC!\n",
+ supply_name, uV);
+ continue;
+ }
+
+ soc_data->write(grf, i, uV);
+ }
+
+ return 0;
+}
+
+U_BOOT_DRIVER(rockchip_iodomain) = {
+ .name = "rockchip_iodomain",
+ .id = UCLASS_NOP,
+ .of_match = rockchip_iodomain_ids,
+ .bind = rockchip_iodomain_bind,
+ .probe = rockchip_iodomain_probe,
+};
diff --git a/drivers/net/Kconfig b/drivers/net/Kconfig
index 0ed39a61e4d..29304fd7775 100644
--- a/drivers/net/Kconfig
+++ b/drivers/net/Kconfig
@@ -225,6 +225,14 @@ config DWC_ETH_QOS_IMX
The Synopsys Designware Ethernet QOS IP block with the specific
configuration used in IMX soc.
+config DWC_ETH_QOS_ROCKCHIP
+ bool "Synopsys DWC Ethernet QOS device support for Rockchip SoCs"
+ depends on DWC_ETH_QOS
+ select DM_ETH_PHY
+ help
+ The Synopsys Designware Ethernet QOS IP block with specific
+ configuration used in Rockchip SoCs.
+
config DWC_ETH_QOS_STM32
bool "Synopsys DWC Ethernet QOS device support for STM32"
depends on DWC_ETH_QOS
diff --git a/drivers/net/Makefile b/drivers/net/Makefile
index d4af253b6f2..1d444f5b4a6 100644
--- a/drivers/net/Makefile
+++ b/drivers/net/Makefile
@@ -20,6 +20,7 @@ obj-$(CONFIG_DRIVER_DM9000) += dm9000x.o
obj-$(CONFIG_DSA_SANDBOX) += dsa_sandbox.o
obj-$(CONFIG_DWC_ETH_QOS) += dwc_eth_qos.o
obj-$(CONFIG_DWC_ETH_QOS_IMX) += dwc_eth_qos_imx.o
+obj-$(CONFIG_DWC_ETH_QOS_ROCKCHIP) += dwc_eth_qos_rockchip.o
obj-$(CONFIG_DWC_ETH_QOS_QCOM) += dwc_eth_qos_qcom.o
obj-$(CONFIG_DWC_ETH_QOS_STARFIVE) += dwc_eth_qos_starfive.o
obj-$(CONFIG_E1000) += e1000.o
diff --git a/drivers/net/dwc_eth_qos.c b/drivers/net/dwc_eth_qos.c
index 9b1a9e69bf8..18466cfe257 100644
--- a/drivers/net/dwc_eth_qos.c
+++ b/drivers/net/dwc_eth_qos.c
@@ -812,6 +812,7 @@ static int eqos_start(struct udevice *dev)
if (!eqos->phy) {
pr_err("phy_connect() failed");
+ ret = -ENODEV;
goto err_stop_resets;
}
@@ -839,6 +840,7 @@ static int eqos_start(struct udevice *dev)
if (!eqos->phy->link) {
pr_err("No link");
+ ret = -EAGAIN;
goto err_shutdown_phy;
}
@@ -1192,14 +1194,12 @@ static int eqos_recv(struct udevice *dev, int flags, uchar **packetp)
struct eqos_desc *rx_desc;
int length;
- debug("%s(dev=%p, flags=%x):\n", __func__, dev, flags);
-
rx_desc = eqos_get_desc(eqos, eqos->rx_desc_idx, true);
eqos->config->ops->eqos_inval_desc(rx_desc);
- if (rx_desc->des3 & EQOS_DESC3_OWN) {
- debug("%s: RX packet not available\n", __func__);
+ if (rx_desc->des3 & EQOS_DESC3_OWN)
return -EAGAIN;
- }
+
+ debug("%s(dev=%p, flags=%x):\n", __func__, dev, flags);
*packetp = eqos->rx_dma_buf +
(eqos->rx_desc_idx * EQOS_MAX_PACKET_SIZE);
@@ -1315,22 +1315,12 @@ static int eqos_probe_resources_core(struct udevice *dev)
}
debug("%s: rx_dma_buf=%p\n", __func__, eqos->rx_dma_buf);
- eqos->rx_pkt = malloc(EQOS_MAX_PACKET_SIZE);
- if (!eqos->rx_pkt) {
- debug("%s: malloc(rx_pkt) failed\n", __func__);
- ret = -ENOMEM;
- goto err_free_rx_dma_buf;
- }
- debug("%s: rx_pkt=%p\n", __func__, eqos->rx_pkt);
-
eqos->config->ops->eqos_inval_buffer(eqos->rx_dma_buf,
EQOS_MAX_PACKET_SIZE * EQOS_DESCRIPTORS_RX);
debug("%s: OK\n", __func__);
return 0;
-err_free_rx_dma_buf:
- free(eqos->rx_dma_buf);
err_free_tx_dma_buf:
free(eqos->tx_dma_buf);
err_free_descs:
@@ -1349,7 +1339,6 @@ static int eqos_remove_resources_core(struct udevice *dev)
debug("%s(dev=%p):\n", __func__, dev);
- free(eqos->rx_pkt);
free(eqos->rx_dma_buf);
free(eqos->tx_dma_buf);
eqos_free_descs(eqos->rx_descs);
@@ -1719,7 +1708,16 @@ static const struct udevice_id eqos_ids[] = {
.data = (ulong)&eqos_imx_config
},
#endif
-
+#if IS_ENABLED(CONFIG_DWC_ETH_QOS_ROCKCHIP)
+ {
+ .compatible = "rockchip,rk3568-gmac",
+ .data = (ulong)&eqos_rockchip_config
+ },
+ {
+ .compatible = "rockchip,rk3588-gmac",
+ .data = (ulong)&eqos_rockchip_config
+ },
+#endif
#if IS_ENABLED(CONFIG_DWC_ETH_QOS_QCOM)
{
.compatible = "qcom,qcs404-ethqos",
@@ -1732,7 +1730,6 @@ static const struct udevice_id eqos_ids[] = {
.data = (ulong)&eqos_jh7110_config
},
#endif
-
{ }
};
diff --git a/drivers/net/dwc_eth_qos.h b/drivers/net/dwc_eth_qos.h
index a6b719af809..e3222e1e17e 100644
--- a/drivers/net/dwc_eth_qos.h
+++ b/drivers/net/dwc_eth_qos.h
@@ -82,6 +82,7 @@ struct eqos_mac_regs {
#define EQOS_MAC_MDIO_ADDRESS_PA_SHIFT 21
#define EQOS_MAC_MDIO_ADDRESS_RDA_SHIFT 16
#define EQOS_MAC_MDIO_ADDRESS_CR_SHIFT 8
+#define EQOS_MAC_MDIO_ADDRESS_CR_100_150 1
#define EQOS_MAC_MDIO_ADDRESS_CR_20_35 2
#define EQOS_MAC_MDIO_ADDRESS_CR_250_300 5
#define EQOS_MAC_MDIO_ADDRESS_SKAP BIT(4)
@@ -273,7 +274,6 @@ struct eqos_priv {
unsigned int desc_per_cacheline;
void *tx_dma_buf;
void *rx_dma_buf;
- void *rx_pkt;
bool started;
bool reg_access_ok;
bool clk_ck_enabled;
@@ -288,5 +288,6 @@ void eqos_flush_buffer_generic(void *buf, size_t size);
int eqos_null_ops(struct udevice *dev);
extern struct eqos_config eqos_imx_config;
+extern struct eqos_config eqos_rockchip_config;
extern struct eqos_config eqos_qcom_config;
extern struct eqos_config eqos_jh7110_config;
diff --git a/drivers/net/dwc_eth_qos_rockchip.c b/drivers/net/dwc_eth_qos_rockchip.c
new file mode 100644
index 00000000000..834307a4477
--- /dev/null
+++ b/drivers/net/dwc_eth_qos_rockchip.c
@@ -0,0 +1,531 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * Copyright Contributors to the U-Boot project.
+ *
+ * rk_gmac_ops ported from linux drivers/net/ethernet/stmicro/stmmac/dwmac-rk.c
+ *
+ * Ported code is intentionally left as close as possible with linux counter
+ * part in order to simplify future porting of fixes and support for other SoCs.
+ */
+
+#include <common.h>
+#include <clk.h>
+#include <dm.h>
+#include <dm/device_compat.h>
+#include <net.h>
+#include <phy.h>
+#include <regmap.h>
+#include <reset.h>
+#include <syscon.h>
+#include <asm/gpio.h>
+#include <linux/delay.h>
+
+#include "dwc_eth_qos.h"
+
+struct rk_gmac_ops {
+ const char *compatible;
+ int (*set_to_rgmii)(struct udevice *dev,
+ int tx_delay, int rx_delay);
+ int (*set_to_rmii)(struct udevice *dev);
+ int (*set_gmac_speed)(struct udevice *dev);
+ void (*set_clock_selection)(struct udevice *dev, bool enable);
+ u32 regs[3];
+};
+
+struct rockchip_platform_data {
+ struct reset_ctl_bulk resets;
+ const struct rk_gmac_ops *ops;
+ int id;
+ bool clock_input;
+ struct regmap *grf;
+ struct regmap *php_grf;
+};
+
+#define HIWORD_UPDATE(val, mask, shift) \
+ ((val) << (shift) | (mask) << ((shift) + 16))
+
+#define GRF_BIT(nr) (BIT(nr) | BIT((nr) + 16))
+#define GRF_CLR_BIT(nr) (BIT((nr) + 16))
+
+#define RK3568_GRF_GMAC0_CON0 0x0380
+#define RK3568_GRF_GMAC0_CON1 0x0384
+#define RK3568_GRF_GMAC1_CON0 0x0388
+#define RK3568_GRF_GMAC1_CON1 0x038c
+
+/* RK3568_GRF_GMAC0_CON1 && RK3568_GRF_GMAC1_CON1 */
+#define RK3568_GMAC_PHY_INTF_SEL_RGMII \
+ (GRF_BIT(4) | GRF_CLR_BIT(5) | GRF_CLR_BIT(6))
+#define RK3568_GMAC_PHY_INTF_SEL_RMII \
+ (GRF_CLR_BIT(4) | GRF_CLR_BIT(5) | GRF_BIT(6))
+#define RK3568_GMAC_FLOW_CTRL GRF_BIT(3)
+#define RK3568_GMAC_FLOW_CTRL_CLR GRF_CLR_BIT(3)
+#define RK3568_GMAC_RXCLK_DLY_ENABLE GRF_BIT(1)
+#define RK3568_GMAC_RXCLK_DLY_DISABLE GRF_CLR_BIT(1)
+#define RK3568_GMAC_TXCLK_DLY_ENABLE GRF_BIT(0)
+#define RK3568_GMAC_TXCLK_DLY_DISABLE GRF_CLR_BIT(0)
+
+/* RK3568_GRF_GMAC0_CON0 && RK3568_GRF_GMAC1_CON0 */
+#define RK3568_GMAC_CLK_RX_DL_CFG(val) HIWORD_UPDATE(val, 0x7F, 8)
+#define RK3568_GMAC_CLK_TX_DL_CFG(val) HIWORD_UPDATE(val, 0x7F, 0)
+
+static int rk3568_set_to_rgmii(struct udevice *dev,
+ int tx_delay, int rx_delay)
+{
+ struct eth_pdata *pdata = dev_get_plat(dev);
+ struct rockchip_platform_data *data = pdata->priv_pdata;
+ u32 con0, con1;
+
+ con0 = (data->id == 1) ? RK3568_GRF_GMAC1_CON0 :
+ RK3568_GRF_GMAC0_CON0;
+ con1 = (data->id == 1) ? RK3568_GRF_GMAC1_CON1 :
+ RK3568_GRF_GMAC0_CON1;
+
+ regmap_write(data->grf, con0,
+ RK3568_GMAC_CLK_RX_DL_CFG(rx_delay) |
+ RK3568_GMAC_CLK_TX_DL_CFG(tx_delay));
+
+ regmap_write(data->grf, con1,
+ RK3568_GMAC_PHY_INTF_SEL_RGMII |
+ RK3568_GMAC_RXCLK_DLY_ENABLE |
+ RK3568_GMAC_TXCLK_DLY_ENABLE);
+
+ return 0;
+}
+
+static int rk3568_set_to_rmii(struct udevice *dev)
+{
+ struct eth_pdata *pdata = dev_get_plat(dev);
+ struct rockchip_platform_data *data = pdata->priv_pdata;
+ u32 con1;
+
+ con1 = (data->id == 1) ? RK3568_GRF_GMAC1_CON1 :
+ RK3568_GRF_GMAC0_CON1;
+ regmap_write(data->grf, con1, RK3568_GMAC_PHY_INTF_SEL_RMII);
+
+ return 0;
+}
+
+static int rk3568_set_gmac_speed(struct udevice *dev)
+{
+ struct eqos_priv *eqos = dev_get_priv(dev);
+ ulong rate;
+ int ret;
+
+ switch (eqos->phy->speed) {
+ case SPEED_10:
+ rate = 2500000;
+ break;
+ case SPEED_100:
+ rate = 25000000;
+ break;
+ case SPEED_1000:
+ rate = 125000000;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ ret = clk_set_rate(&eqos->clk_tx, rate);
+ if (ret < 0)
+ return ret;
+
+ return 0;
+}
+
+/* sys_grf */
+#define RK3588_GRF_GMAC_CON7 0x031c
+#define RK3588_GRF_GMAC_CON8 0x0320
+#define RK3588_GRF_GMAC_CON9 0x0324
+
+#define RK3588_GMAC_RXCLK_DLY_ENABLE(id) GRF_BIT(2 * (id) + 3)
+#define RK3588_GMAC_RXCLK_DLY_DISABLE(id) GRF_CLR_BIT(2 * (id) + 3)
+#define RK3588_GMAC_TXCLK_DLY_ENABLE(id) GRF_BIT(2 * (id) + 2)
+#define RK3588_GMAC_TXCLK_DLY_DISABLE(id) GRF_CLR_BIT(2 * (id) + 2)
+
+#define RK3588_GMAC_CLK_RX_DL_CFG(val) HIWORD_UPDATE(val, 0xFF, 8)
+#define RK3588_GMAC_CLK_TX_DL_CFG(val) HIWORD_UPDATE(val, 0xFF, 0)
+
+/* php_grf */
+#define RK3588_GRF_GMAC_CON0 0x0008
+#define RK3588_GRF_CLK_CON1 0x0070
+
+#define RK3588_GMAC_PHY_INTF_SEL_RGMII(id) \
+ (GRF_BIT(3 + (id) * 6) | GRF_CLR_BIT(4 + (id) * 6) | GRF_CLR_BIT(5 + (id) * 6))
+#define RK3588_GMAC_PHY_INTF_SEL_RMII(id) \
+ (GRF_CLR_BIT(3 + (id) * 6) | GRF_CLR_BIT(4 + (id) * 6) | GRF_BIT(5 + (id) * 6))
+
+#define RK3588_GMAC_CLK_RMII_MODE(id) GRF_BIT(5 * (id))
+#define RK3588_GMAC_CLK_RGMII_MODE(id) GRF_CLR_BIT(5 * (id))
+
+#define RK3588_GMAC_CLK_SELET_CRU(id) GRF_BIT(5 * (id) + 4)
+#define RK3588_GMAC_CLK_SELET_IO(id) GRF_CLR_BIT(5 * (id) + 4)
+
+#define RK3588_GMAC_CLK_RMII_DIV2(id) GRF_BIT(5 * (id) + 2)
+#define RK3588_GMAC_CLK_RMII_DIV20(id) GRF_CLR_BIT(5 * (id) + 2)
+
+#define RK3588_GMAC_CLK_RGMII_DIV1(id) \
+ (GRF_CLR_BIT(5 * (id) + 2) | GRF_CLR_BIT(5 * (id) + 3))
+#define RK3588_GMAC_CLK_RGMII_DIV5(id) \
+ (GRF_BIT(5 * (id) + 2) | GRF_BIT(5 * (id) + 3))
+#define RK3588_GMAC_CLK_RGMII_DIV50(id) \
+ (GRF_CLR_BIT(5 * (id) + 2) | GRF_BIT(5 * (id) + 3))
+
+#define RK3588_GMAC_CLK_RMII_GATE(id) GRF_BIT(5 * (id) + 1)
+#define RK3588_GMAC_CLK_RMII_NOGATE(id) GRF_CLR_BIT(5 * (id) + 1)
+
+static int rk3588_set_to_rgmii(struct udevice *dev,
+ int tx_delay, int rx_delay)
+{
+ struct eth_pdata *pdata = dev_get_plat(dev);
+ struct rockchip_platform_data *data = pdata->priv_pdata;
+ u32 offset_con, id = data->id;
+
+ offset_con = data->id == 1 ? RK3588_GRF_GMAC_CON9 :
+ RK3588_GRF_GMAC_CON8;
+
+ regmap_write(data->php_grf, RK3588_GRF_GMAC_CON0,
+ RK3588_GMAC_PHY_INTF_SEL_RGMII(id));
+
+ regmap_write(data->php_grf, RK3588_GRF_CLK_CON1,
+ RK3588_GMAC_CLK_RGMII_MODE(id));
+
+ regmap_write(data->grf, RK3588_GRF_GMAC_CON7,
+ RK3588_GMAC_RXCLK_DLY_ENABLE(id) |
+ RK3588_GMAC_TXCLK_DLY_ENABLE(id));
+
+ regmap_write(data->grf, offset_con,
+ RK3588_GMAC_CLK_RX_DL_CFG(rx_delay) |
+ RK3588_GMAC_CLK_TX_DL_CFG(tx_delay));
+
+ return 0;
+}
+
+static int rk3588_set_to_rmii(struct udevice *dev)
+{
+ struct eth_pdata *pdata = dev_get_plat(dev);
+ struct rockchip_platform_data *data = pdata->priv_pdata;
+
+ regmap_write(data->php_grf, RK3588_GRF_GMAC_CON0,
+ RK3588_GMAC_PHY_INTF_SEL_RMII(data->id));
+
+ regmap_write(data->php_grf, RK3588_GRF_CLK_CON1,
+ RK3588_GMAC_CLK_RMII_MODE(data->id));
+
+ return 0;
+}
+
+static int rk3588_set_gmac_speed(struct udevice *dev)
+{
+ struct eqos_priv *eqos = dev_get_priv(dev);
+ struct eth_pdata *pdata = dev_get_plat(dev);
+ struct rockchip_platform_data *data = pdata->priv_pdata;
+ u32 val = 0, id = data->id;
+
+ switch (eqos->phy->speed) {
+ case SPEED_10:
+ if (pdata->phy_interface == PHY_INTERFACE_MODE_RMII)
+ val = RK3588_GMAC_CLK_RMII_DIV20(id);
+ else
+ val = RK3588_GMAC_CLK_RGMII_DIV50(id);
+ break;
+ case SPEED_100:
+ if (pdata->phy_interface == PHY_INTERFACE_MODE_RMII)
+ val = RK3588_GMAC_CLK_RMII_DIV2(id);
+ else
+ val = RK3588_GMAC_CLK_RGMII_DIV5(id);
+ break;
+ case SPEED_1000:
+ if (pdata->phy_interface != PHY_INTERFACE_MODE_RMII)
+ val = RK3588_GMAC_CLK_RGMII_DIV1(id);
+ else
+ return -EINVAL;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ regmap_write(data->php_grf, RK3588_GRF_CLK_CON1, val);
+
+ return 0;
+}
+
+static void rk3588_set_clock_selection(struct udevice *dev, bool enable)
+{
+ struct eth_pdata *pdata = dev_get_plat(dev);
+ struct rockchip_platform_data *data = pdata->priv_pdata;
+
+ u32 val = data->clock_input ? RK3588_GMAC_CLK_SELET_IO(data->id) :
+ RK3588_GMAC_CLK_SELET_CRU(data->id);
+
+ val |= enable ? RK3588_GMAC_CLK_RMII_NOGATE(data->id) :
+ RK3588_GMAC_CLK_RMII_GATE(data->id);
+
+ regmap_write(data->php_grf, RK3588_GRF_CLK_CON1, val);
+}
+
+static const struct rk_gmac_ops rk_gmac_ops[] = {
+ {
+ .compatible = "rockchip,rk3568-gmac",
+ .set_to_rgmii = rk3568_set_to_rgmii,
+ .set_to_rmii = rk3568_set_to_rmii,
+ .set_gmac_speed = rk3568_set_gmac_speed,
+ .regs = {
+ 0xfe2a0000, /* gmac0 */
+ 0xfe010000, /* gmac1 */
+ 0x0, /* sentinel */
+ },
+ },
+ {
+ .compatible = "rockchip,rk3588-gmac",
+ .set_to_rgmii = rk3588_set_to_rgmii,
+ .set_to_rmii = rk3588_set_to_rmii,
+ .set_gmac_speed = rk3588_set_gmac_speed,
+ .set_clock_selection = rk3588_set_clock_selection,
+ .regs = {
+ 0xfe1b0000, /* gmac0 */
+ 0xfe1c0000, /* gmac1 */
+ 0x0, /* sentinel */
+ },
+ },
+ { }
+};
+
+static const struct rk_gmac_ops *get_rk_gmac_ops(struct udevice *dev)
+{
+ const struct rk_gmac_ops *ops = rk_gmac_ops;
+
+ while (ops->compatible) {
+ if (device_is_compatible(dev, ops->compatible))
+ return ops;
+ ops++;
+ }
+
+ return NULL;
+}
+
+static int eqos_probe_resources_rk(struct udevice *dev)
+{
+ struct eqos_priv *eqos = dev_get_priv(dev);
+ struct eth_pdata *pdata = dev_get_plat(dev);
+ struct rockchip_platform_data *data;
+ const char *clock_in_out;
+ int reset_flags = GPIOD_IS_OUT | GPIOD_IS_OUT_ACTIVE;
+ int ret;
+
+ data = calloc(1, sizeof(struct rockchip_platform_data));
+ if (!data)
+ return -ENOMEM;
+
+ data->ops = get_rk_gmac_ops(dev);
+ if (!data->ops) {
+ ret = -EINVAL;
+ goto err_free;
+ }
+
+ for (int i = 0; data->ops->regs[i]; i++) {
+ if (data->ops->regs[i] == (u32)eqos->regs) {
+ data->id = i;
+ break;
+ }
+ }
+
+ pdata->priv_pdata = data;
+ pdata->phy_interface = eqos->config->interface(dev);
+ pdata->max_speed = eqos->max_speed;
+
+ if (pdata->phy_interface == PHY_INTERFACE_MODE_NA) {
+ pr_err("Invalid PHY interface\n");
+ ret = -EINVAL;
+ goto err_free;
+ }
+
+ data->grf = syscon_regmap_lookup_by_phandle(dev, "rockchip,grf");
+ if (IS_ERR(data->grf)) {
+ dev_err(dev, "Missing rockchip,grf property\n");
+ ret = -EINVAL;
+ goto err_free;
+ }
+
+ if (device_is_compatible(dev, "rockchip,rk3588-gmac")) {
+ data->php_grf =
+ syscon_regmap_lookup_by_phandle(dev, "rockchip,php-grf");
+ if (IS_ERR(data->php_grf)) {
+ dev_err(dev, "Missing rockchip,php-grf property\n");
+ ret = -EINVAL;
+ goto err_free;
+ }
+ }
+
+ ret = reset_get_bulk(dev, &data->resets);
+ if (ret < 0)
+ goto err_free;
+
+ reset_assert_bulk(&data->resets);
+
+ ret = clk_get_by_name(dev, "stmmaceth", &eqos->clk_master_bus);
+ if (ret) {
+ dev_dbg(dev, "clk_get_by_name(stmmaceth) failed: %d", ret);
+ goto err_release_resets;
+ }
+
+ if (device_is_compatible(dev, "rockchip,rk3568-gmac")) {
+ ret = clk_get_by_name(dev, "clk_mac_speed", &eqos->clk_tx);
+ if (ret) {
+ dev_dbg(dev, "clk_get_by_name(clk_mac_speed) failed: %d", ret);
+ goto err_free_clk_master_bus;
+ }
+ }
+
+ clock_in_out = dev_read_string(dev, "clock_in_out");
+ if (clock_in_out && !strcmp(clock_in_out, "input"))
+ data->clock_input = true;
+ else
+ data->clock_input = false;
+
+ /* snps,reset props are deprecated, do bare minimum to support them */
+ if (dev_read_bool(dev, "snps,reset-active-low"))
+ reset_flags |= GPIOD_ACTIVE_LOW;
+
+ dev_read_u32_array(dev, "snps,reset-delays-us", eqos->reset_delays, 3);
+
+ gpio_request_by_name(dev, "snps,reset-gpio", 0,
+ &eqos->phy_reset_gpio, reset_flags);
+
+ return 0;
+
+err_free_clk_master_bus:
+ clk_free(&eqos->clk_master_bus);
+err_release_resets:
+ reset_release_bulk(&data->resets);
+err_free:
+ free(data);
+
+ return ret;
+}
+
+static int eqos_remove_resources_rk(struct udevice *dev)
+{
+ struct eqos_priv *eqos = dev_get_priv(dev);
+ struct eth_pdata *pdata = dev_get_plat(dev);
+ struct rockchip_platform_data *data = pdata->priv_pdata;
+
+ if (dm_gpio_is_valid(&eqos->phy_reset_gpio))
+ dm_gpio_free(dev, &eqos->phy_reset_gpio);
+
+ clk_free(&eqos->clk_tx);
+ clk_free(&eqos->clk_master_bus);
+ reset_release_bulk(&data->resets);
+ free(data);
+
+ return 0;
+}
+
+static int eqos_stop_resets_rk(struct udevice *dev)
+{
+ struct eth_pdata *pdata = dev_get_plat(dev);
+ struct rockchip_platform_data *data = pdata->priv_pdata;
+
+ return reset_assert_bulk(&data->resets);
+}
+
+static int eqos_start_resets_rk(struct udevice *dev)
+{
+ struct eth_pdata *pdata = dev_get_plat(dev);
+ struct rockchip_platform_data *data = pdata->priv_pdata;
+
+ return reset_deassert_bulk(&data->resets);
+}
+
+static int eqos_stop_clks_rk(struct udevice *dev)
+{
+ struct eth_pdata *pdata = dev_get_plat(dev);
+ struct rockchip_platform_data *data = pdata->priv_pdata;
+
+ if (data->ops->set_clock_selection)
+ data->ops->set_clock_selection(dev, false);
+
+ return 0;
+}
+
+static int eqos_start_clks_rk(struct udevice *dev)
+{
+ struct eqos_priv *eqos = dev_get_priv(dev);
+ struct eth_pdata *pdata = dev_get_plat(dev);
+ struct rockchip_platform_data *data = pdata->priv_pdata;
+ int tx_delay, rx_delay, ret;
+
+ if (dm_gpio_is_valid(&eqos->phy_reset_gpio)) {
+ udelay(eqos->reset_delays[1]);
+
+ ret = dm_gpio_set_value(&eqos->phy_reset_gpio, 0);
+ if (ret < 0)
+ return ret;
+
+ udelay(eqos->reset_delays[2]);
+ }
+
+ if (data->ops->set_clock_selection)
+ data->ops->set_clock_selection(dev, true);
+
+ tx_delay = dev_read_u32_default(dev, "tx_delay", 0x30);
+ rx_delay = dev_read_u32_default(dev, "rx_delay", 0x10);
+
+ switch (pdata->phy_interface) {
+ case PHY_INTERFACE_MODE_RGMII:
+ return data->ops->set_to_rgmii(dev, tx_delay, rx_delay);
+ case PHY_INTERFACE_MODE_RGMII_ID:
+ return data->ops->set_to_rgmii(dev, 0, 0);
+ case PHY_INTERFACE_MODE_RGMII_RXID:
+ return data->ops->set_to_rgmii(dev, tx_delay, 0);
+ case PHY_INTERFACE_MODE_RGMII_TXID:
+ return data->ops->set_to_rgmii(dev, 0, rx_delay);
+ case PHY_INTERFACE_MODE_RMII:
+ return data->ops->set_to_rmii(dev);
+ }
+
+ return -EINVAL;
+}
+
+static int eqos_set_tx_clk_speed_rk(struct udevice *dev)
+{
+ struct eth_pdata *pdata = dev_get_plat(dev);
+ struct rockchip_platform_data *data = pdata->priv_pdata;
+
+ return data->ops->set_gmac_speed(dev);
+}
+
+static ulong eqos_get_tick_clk_rate_rk(struct udevice *dev)
+{
+ struct eqos_priv *eqos = dev_get_priv(dev);
+
+ return clk_get_rate(&eqos->clk_master_bus);
+}
+
+static struct eqos_ops eqos_rockchip_ops = {
+ .eqos_inval_desc = eqos_inval_desc_generic,
+ .eqos_flush_desc = eqos_flush_desc_generic,
+ .eqos_inval_buffer = eqos_inval_buffer_generic,
+ .eqos_flush_buffer = eqos_flush_buffer_generic,
+ .eqos_probe_resources = eqos_probe_resources_rk,
+ .eqos_remove_resources = eqos_remove_resources_rk,
+ .eqos_stop_resets = eqos_stop_resets_rk,
+ .eqos_start_resets = eqos_start_resets_rk,
+ .eqos_stop_clks = eqos_stop_clks_rk,
+ .eqos_start_clks = eqos_start_clks_rk,
+ .eqos_calibrate_pads = eqos_null_ops,
+ .eqos_disable_calibration = eqos_null_ops,
+ .eqos_set_tx_clk_speed = eqos_set_tx_clk_speed_rk,
+ .eqos_get_enetaddr = eqos_null_ops,
+ .eqos_get_tick_clk_rate = eqos_get_tick_clk_rate_rk,
+};
+
+struct eqos_config eqos_rockchip_config = {
+ .reg_access_always_ok = false,
+ .mdio_wait = 10,
+ .swr_wait = 50,
+ .config_mac = EQOS_MAC_RXQ_CTRL0_RXQ0EN_ENABLED_DCB,
+ .config_mac_mdio = EQOS_MAC_MDIO_ADDRESS_CR_100_150,
+ .axi_bus_width = EQOS_AXI_WIDTH_64,
+ .interface = dev_read_phy_mode,
+ .ops = &eqos_rockchip_ops,
+};
diff --git a/drivers/pci/pcie_dw_rockchip.c b/drivers/pci/pcie_dw_rockchip.c
index 1a35fae5c3a..bc4635f6713 100644
--- a/drivers/pci/pcie_dw_rockchip.c
+++ b/drivers/pci/pcie_dw_rockchip.c
@@ -18,6 +18,7 @@
#include <asm/io.h>
#include <asm-generic/gpio.h>
#include <dm/device_compat.h>
+#include <linux/bitfield.h>
#include <linux/iopoll.h>
#include <linux/delay.h>
#include <power/regulator.h>
@@ -43,6 +44,7 @@ struct rk_pcie {
struct reset_ctl_bulk rsts;
struct gpio_desc rst_gpio;
u32 gen;
+ u32 num_lanes;
};
/* Parameters for the waiting for iATU enabled routine */
@@ -152,12 +154,13 @@ static inline void rk_pcie_writel_apb(struct rk_pcie *rk_pcie, u32 reg,
* rk_pcie_configure() - Configure link capabilities and speed
*
* @rk_pcie: Pointer to the PCI controller state
- * @cap_speed: The capabilities and speed to configure
*
* Configure the link capabilities and speed in the PCIe root complex.
*/
-static void rk_pcie_configure(struct rk_pcie *pci, u32 cap_speed)
+static void rk_pcie_configure(struct rk_pcie *pci)
{
+ u32 val;
+
dw_pcie_dbi_write_enable(&pci->dw, true);
/* Disable BAR 0 and BAR 1 */
@@ -167,11 +170,49 @@ static void rk_pcie_configure(struct rk_pcie *pci, u32 cap_speed)
PCI_BASE_ADDRESS_1);
clrsetbits_le32(pci->dw.dbi_base + PCIE_LINK_CAPABILITY,
- TARGET_LINK_SPEED_MASK, cap_speed);
+ TARGET_LINK_SPEED_MASK, pci->gen);
clrsetbits_le32(pci->dw.dbi_base + PCIE_LINK_CTL_2,
- TARGET_LINK_SPEED_MASK, cap_speed);
+ TARGET_LINK_SPEED_MASK, pci->gen);
+
+ /* Set the number of lanes */
+ val = readl(pci->dw.dbi_base + PCIE_PORT_LINK_CONTROL);
+ val &= ~PORT_LINK_FAST_LINK_MODE;
+ val |= PORT_LINK_DLL_LINK_EN;
+ val &= ~PORT_LINK_MODE_MASK;
+ switch (pci->num_lanes) {
+ case 1:
+ val |= PORT_LINK_MODE_1_LANES;
+ break;
+ case 2:
+ val |= PORT_LINK_MODE_2_LANES;
+ break;
+ case 4:
+ val |= PORT_LINK_MODE_4_LANES;
+ break;
+ default:
+ dev_err(pci->dw.dev, "num-lanes %u: invalid value\n", pci->num_lanes);
+ goto out;
+ }
+ writel(val, pci->dw.dbi_base + PCIE_PORT_LINK_CONTROL);
+
+ /* Set link width speed control register */
+ val = readl(pci->dw.dbi_base + PCIE_LINK_WIDTH_SPEED_CONTROL);
+ val &= ~PORT_LOGIC_LINK_WIDTH_MASK;
+ switch (pci->num_lanes) {
+ case 1:
+ val |= PORT_LOGIC_LINK_WIDTH_1_LANES;
+ break;
+ case 2:
+ val |= PORT_LOGIC_LINK_WIDTH_2_LANES;
+ break;
+ case 4:
+ val |= PORT_LOGIC_LINK_WIDTH_4_LANES;
+ break;
+ }
+ writel(val, pci->dw.dbi_base + PCIE_LINK_WIDTH_SPEED_CONTROL);
+out:
dw_pcie_dbi_write_enable(&pci->dw, false);
}
@@ -231,11 +272,10 @@ static int is_link_up(struct rk_pcie *priv)
* rk_pcie_link_up() - Wait for the link to come up
*
* @rk_pcie: Pointer to the PCI controller state
- * @cap_speed: Desired link speed
*
* Return: 1 (true) for active line and negetive (false) for no link (timeout)
*/
-static int rk_pcie_link_up(struct rk_pcie *priv, u32 cap_speed)
+static int rk_pcie_link_up(struct rk_pcie *priv)
{
int retries;
@@ -245,7 +285,7 @@ static int rk_pcie_link_up(struct rk_pcie *priv, u32 cap_speed)
}
/* DW pre link configurations */
- rk_pcie_configure(priv, cap_speed);
+ rk_pcie_configure(priv);
rk_pcie_disable_ltssm(priv);
rk_pcie_link_status_clear(priv);
@@ -341,7 +381,7 @@ static int rockchip_pcie_init_port(struct udevice *dev)
rk_pcie_writel_apb(priv, 0x0, 0xf00040);
pcie_dw_setup_host(&priv->dw);
- ret = rk_pcie_link_up(priv, priv->gen);
+ ret = rk_pcie_link_up(priv);
if (ret < 0)
goto err_link_up;
@@ -419,6 +459,8 @@ static int rockchip_pcie_parse_dt(struct udevice *dev)
priv->gen = dev_read_u32_default(dev, "max-link-speed",
LINK_SPEED_GEN_3);
+ priv->num_lanes = dev_read_u32_default(dev, "num-lanes", 1);
+
return 0;
rockchip_pcie_parse_dt_err_phy_get_by_index:
diff --git a/drivers/phy/rockchip/phy-rockchip-naneng-combphy.c b/drivers/phy/rockchip/phy-rockchip-naneng-combphy.c
index d5408ccac97..9ca66bf8db9 100644
--- a/drivers/phy/rockchip/phy-rockchip-naneng-combphy.c
+++ b/drivers/phy/rockchip/phy-rockchip-naneng-combphy.c
@@ -61,6 +61,8 @@ struct rockchip_combphy_grfcfg {
struct combphy_reg pipe_con1_for_sata;
struct combphy_reg pipe_sgmii_mac_sel;
struct combphy_reg pipe_xpcs_phy_ready;
+ struct combphy_reg pipe_pcie1l0_sel;
+ struct combphy_reg pipe_pcie1l1_sel;
struct combphy_reg u3otg0_port_en;
struct combphy_reg u3otg1_port_en;
};
@@ -435,6 +437,8 @@ static int rk3588_combphy_cfg(struct rockchip_combphy_priv *priv)
param_write(priv->phy_grf, &cfg->con1_for_pcie, true);
param_write(priv->phy_grf, &cfg->con2_for_pcie, true);
param_write(priv->phy_grf, &cfg->con3_for_pcie, true);
+ param_write(priv->pipe_grf, &cfg->pipe_pcie1l0_sel, true);
+ param_write(priv->pipe_grf, &cfg->pipe_pcie1l1_sel, true);
break;
case PHY_TYPE_USB3:
param_write(priv->phy_grf, &cfg->pipe_txcomp_sel, false);
@@ -507,6 +511,8 @@ static const struct rockchip_combphy_grfcfg rk3588_combphy_grfcfgs = {
/* pipe-grf */
.pipe_con0_for_sata = { 0x0000, 11, 5, 0x00, 0x22 },
.pipe_con1_for_sata = { 0x0000, 2, 0, 0x00, 0x2 },
+ .pipe_pcie1l0_sel = { 0x0100, 0, 0, 0x01, 0x0 },
+ .pipe_pcie1l1_sel = { 0x0100, 1, 1, 0x01, 0x0 },
};
static const struct rockchip_combphy_cfg rk3588_combphy_cfgs = {
diff --git a/drivers/phy/rockchip/phy-rockchip-snps-pcie3.c b/drivers/phy/rockchip/phy-rockchip-snps-pcie3.c
index 66c75f98e6d..a4392daf4c9 100644
--- a/drivers/phy/rockchip/phy-rockchip-snps-pcie3.c
+++ b/drivers/phy/rockchip/phy-rockchip-snps-pcie3.c
@@ -16,9 +16,27 @@
#include <dm/device_compat.h>
#include <dm/lists.h>
-#define GRF_PCIE30PHY_CON1 0x4
-#define GRF_PCIE30PHY_CON6 0x18
-#define GRF_PCIE30PHY_CON9 0x24
+/* Register for RK3568 */
+#define GRF_PCIE30PHY_CON1 0x4
+#define GRF_PCIE30PHY_CON6 0x18
+#define GRF_PCIE30PHY_CON9 0x24
+#define GRF_PCIE30PHY_DA_OCM (BIT(15) | BIT(31))
+#define GRF_PCIE30PHY_STATUS0 0x80
+#define GRF_PCIE30PHY_WR_EN (0xf << 16)
+#define SRAM_INIT_DONE(reg) (reg & BIT(14))
+
+#define RK3568_BIFURCATION_LANE_0_1 BIT(0)
+
+/* Register for RK3588 */
+#define PHP_GRF_PCIESEL_CON 0x100
+#define RK3588_PCIE3PHY_GRF_CMN_CON0 0x0
+#define RK3588_PCIE3PHY_GRF_PHY0_STATUS1 0x904
+#define RK3588_PCIE3PHY_GRF_PHY1_STATUS1 0xa04
+#define RK3588_SRAM_INIT_DONE(reg) (reg & BIT(0))
+
+#define RK3588_BIFURCATION_LANE_0_1 BIT(0)
+#define RK3588_BIFURCATION_LANE_2_3 BIT(1)
+#define RK3588_LANE_AGGREGATION BIT(2)
/**
* struct rockchip_p3phy_priv - RK DW PCIe PHY state
@@ -26,51 +44,144 @@
* @mmio: The base address of PHY internal registers
* @phy_grf: The regmap for controlling pipe signal
* @p30phy: The reset signal for PHY
- * @ref_clk_m: The reference clock of M for PHY
- * @ref_clk_n: The reference clock of N for PHY
- * @pclk: The clock for accessing PHY blocks
+ * @clks: The clocks for PHY
+ * @num_lanes: The number of lane to controller mappings
+ * @lanes: The lane to controller mapping
*/
struct rockchip_p3phy_priv {
void __iomem *mmio;
struct regmap *phy_grf;
+ struct regmap *pipe_grf;
struct reset_ctl p30phy;
- struct clk ref_clk_m;
- struct clk ref_clk_n;
- struct clk pclk;
+ struct clk_bulk clks;
+ int num_lanes;
+ u32 lanes[4];
};
-static int rochchip_p3phy_init(struct phy *phy)
+struct rockchip_p3phy_ops {
+ int (*phy_init)(struct phy *phy);
+};
+
+static int rockchip_p3phy_rk3568_init(struct phy *phy)
{
struct rockchip_p3phy_priv *priv = dev_get_priv(phy->dev);
+ bool bifurcation = false;
int ret;
+ u32 reg;
- ret = clk_enable(&priv->ref_clk_m);
- if (ret < 0 && ret != -ENOSYS)
- return ret;
+ /* Deassert PCIe PMA output clamp mode */
+ regmap_write(priv->phy_grf, GRF_PCIE30PHY_CON9, GRF_PCIE30PHY_DA_OCM);
- ret = clk_enable(&priv->ref_clk_n);
- if (ret < 0 && ret != -ENOSYS)
- goto err_ref;
+ for (int i = 0; i < priv->num_lanes; i++) {
+ if (priv->lanes[i] > 1)
+ bifurcation = true;
+ }
- ret = clk_enable(&priv->pclk);
- if (ret < 0 && ret != -ENOSYS)
- goto err_pclk;
+ /* Set bifurcation if needed, and it doesn't care RC/EP */
+ if (bifurcation) {
+ regmap_write(priv->phy_grf, GRF_PCIE30PHY_CON6,
+ GRF_PCIE30PHY_WR_EN | RK3568_BIFURCATION_LANE_0_1);
+ regmap_write(priv->phy_grf, GRF_PCIE30PHY_CON1,
+ GRF_PCIE30PHY_DA_OCM);
+ } else {
+ regmap_write(priv->phy_grf, GRF_PCIE30PHY_CON6,
+ GRF_PCIE30PHY_WR_EN & ~RK3568_BIFURCATION_LANE_0_1);
+ }
- reset_assert(&priv->p30phy);
+ reset_deassert(&priv->p30phy);
udelay(1);
+ ret = regmap_read_poll_timeout(priv->phy_grf,
+ GRF_PCIE30PHY_STATUS0,
+ reg, SRAM_INIT_DONE(reg),
+ 0, 500);
+ if (ret)
+ dev_err(phy->dev, "lock failed 0x%x\n", reg);
+
+ return ret;
+}
+
+static const struct rockchip_p3phy_ops rk3568_ops = {
+ .phy_init = rockchip_p3phy_rk3568_init,
+};
+
+static int rockchip_p3phy_rk3588_init(struct phy *phy)
+{
+ struct rockchip_p3phy_priv *priv = dev_get_priv(phy->dev);
+ u32 reg = 0;
+ u8 mode = 0;
+ int ret;
+
/* Deassert PCIe PMA output clamp mode */
- regmap_write(priv->phy_grf, GRF_PCIE30PHY_CON9,
- (0x1 << 15) | (0x1 << 31));
+ regmap_write(priv->phy_grf, RK3588_PCIE3PHY_GRF_CMN_CON0,
+ BIT(8) | BIT(24));
+
+ /* Set bifurcation if needed */
+ for (int i = 0; i < priv->num_lanes; i++) {
+ if (!priv->lanes[i])
+ mode |= (BIT(i) << 3);
+
+ if (priv->lanes[i] > 1)
+ mode |= (BIT(i) >> 1);
+ }
+
+ if (!mode) {
+ reg = RK3588_LANE_AGGREGATION;
+ } else {
+ if (mode & (BIT(0) | BIT(1)))
+ reg |= RK3588_BIFURCATION_LANE_0_1;
+
+ if (mode & (BIT(2) | BIT(3)))
+ reg |= RK3588_BIFURCATION_LANE_2_3;
+ }
+
+ regmap_write(priv->phy_grf, RK3588_PCIE3PHY_GRF_CMN_CON0,
+ (0x7 << 16) | reg);
+
+ /* Set pcie1ln_sel in PHP_GRF_PCIESEL_CON */
+ reg = (mode & (BIT(6) | BIT(7))) >> 6;
+ if (reg)
+ regmap_write(priv->pipe_grf, PHP_GRF_PCIESEL_CON,
+ (reg << 16) | reg);
reset_deassert(&priv->p30phy);
udelay(1);
- return 0;
-err_pclk:
- clk_disable(&priv->ref_clk_n);
-err_ref:
- clk_disable(&priv->ref_clk_m);
+ ret = regmap_read_poll_timeout(priv->phy_grf,
+ RK3588_PCIE3PHY_GRF_PHY0_STATUS1,
+ reg, RK3588_SRAM_INIT_DONE(reg),
+ 0, 500);
+ ret |= regmap_read_poll_timeout(priv->phy_grf,
+ RK3588_PCIE3PHY_GRF_PHY1_STATUS1,
+ reg, RK3588_SRAM_INIT_DONE(reg),
+ 0, 500);
+ if (ret)
+ dev_err(phy->dev, "lock failed 0x%x\n", reg);
+
+ return ret;
+}
+
+static const struct rockchip_p3phy_ops rk3588_ops = {
+ .phy_init = rockchip_p3phy_rk3588_init,
+};
+
+static int rochchip_p3phy_init(struct phy *phy)
+{
+ struct rockchip_p3phy_ops *ops =
+ (struct rockchip_p3phy_ops *)dev_get_driver_data(phy->dev);
+ struct rockchip_p3phy_priv *priv = dev_get_priv(phy->dev);
+ int ret;
+
+ ret = clk_enable_bulk(&priv->clks);
+ if (ret)
+ return ret;
+
+ reset_assert(&priv->p30phy);
+ udelay(1);
+
+ ret = ops->phy_init(phy);
+ if (ret)
+ clk_disable_bulk(&priv->clks);
return ret;
}
@@ -79,9 +190,7 @@ static int rochchip_p3phy_exit(struct phy *phy)
{
struct rockchip_p3phy_priv *priv = dev_get_priv(phy->dev);
- clk_disable(&priv->ref_clk_m);
- clk_disable(&priv->ref_clk_n);
- clk_disable(&priv->pclk);
+ clk_disable_bulk(&priv->clks);
reset_assert(&priv->p30phy);
return 0;
@@ -90,48 +199,54 @@ static int rochchip_p3phy_exit(struct phy *phy)
static int rockchip_p3phy_probe(struct udevice *dev)
{
struct rockchip_p3phy_priv *priv = dev_get_priv(dev);
- struct udevice *syscon;
int ret;
priv->mmio = dev_read_addr_ptr(dev);
if (!priv->mmio)
return -EINVAL;
- ret = uclass_get_device_by_phandle(UCLASS_SYSCON, dev,
- "rockchip,phy-grf", &syscon);
- if (ret) {
- pr_err("unable to find syscon device for rockchip,phy-grf\n");
- return ret;
- }
-
- priv->phy_grf = syscon_get_regmap(syscon);
+ priv->phy_grf = syscon_regmap_lookup_by_phandle(dev, "rockchip,phy-grf");
if (IS_ERR(priv->phy_grf)) {
dev_err(dev, "failed to find rockchip,phy_grf regmap\n");
return PTR_ERR(priv->phy_grf);
}
- ret = reset_get_by_name(dev, "phy", &priv->p30phy);
- if (ret) {
- dev_err(dev, "no phy reset control specified\n");
- return ret;
+ if (device_is_compatible(dev, "rockchip,rk3588-pcie3-phy")) {
+ priv->pipe_grf =
+ syscon_regmap_lookup_by_phandle(dev, "rockchip,pipe-grf");
+ if (IS_ERR(priv->pipe_grf)) {
+ dev_err(dev, "failed to find rockchip,pipe_grf regmap\n");
+ return PTR_ERR(priv->pipe_grf);
+ }
}
- ret = clk_get_by_name(dev, "refclk_m", &priv->ref_clk_m);
- if (ret) {
- dev_err(dev, "failed to find ref clock M\n");
- return PTR_ERR(&priv->ref_clk_m);
+ ret = dev_read_size(dev, "data-lanes");
+ if (ret > 0) {
+ priv->num_lanes = ret / sizeof(u32);
+ if (priv->num_lanes < 2 ||
+ priv->num_lanes > ARRAY_SIZE(priv->lanes)) {
+ dev_err(dev, "unsupported data-lanes property size\n");
+ return -EINVAL;
+ }
+
+ ret = dev_read_u32_array(dev, "data-lanes", priv->lanes,
+ priv->num_lanes);
+ if (ret) {
+ dev_err(dev, "failed to read data-lanes property\n");
+ return ret;
+ }
}
- ret = clk_get_by_name(dev, "refclk_n", &priv->ref_clk_n);
+ ret = reset_get_by_name(dev, "phy", &priv->p30phy);
if (ret) {
- dev_err(dev, "failed to find ref clock N\n");
- return PTR_ERR(&priv->ref_clk_n);
+ dev_err(dev, "no phy reset control specified\n");
+ return ret;
}
- ret = clk_get_by_name(dev, "pclk", &priv->pclk);
+ ret = clk_get_bulk(dev, &priv->clks);
if (ret) {
- dev_err(dev, "failed to find pclk\n");
- return PTR_ERR(&priv->pclk);
+ dev_err(dev, "failed to get clocks\n");
+ return ret;
}
return 0;
@@ -143,7 +258,14 @@ static struct phy_ops rochchip_p3phy_ops = {
};
static const struct udevice_id rockchip_p3phy_of_match[] = {
- { .compatible = "rockchip,rk3568-pcie3-phy" },
+ {
+ .compatible = "rockchip,rk3568-pcie3-phy",
+ .data = (ulong)&rk3568_ops,
+ },
+ {
+ .compatible = "rockchip,rk3588-pcie3-phy",
+ .data = (ulong)&rk3588_ops,
+ },
{ },
};
diff --git a/drivers/power/pmic/Kconfig b/drivers/power/pmic/Kconfig
index 176fb07c651..4a6f0ce093a 100644
--- a/drivers/power/pmic/Kconfig
+++ b/drivers/power/pmic/Kconfig
@@ -233,6 +233,7 @@ config PMIC_QCOM
config PMIC_RK8XX
bool "Enable support for Rockchip PMIC RK8XX"
+ select SYSRESET_CMD_POWEROFF if SYSRESET && CMD_POWEROFF
---help---
The Rockchip RK808 PMIC provides four buck DC-DC convertors, 8 LDOs,
an RTC and two low Rds (resistance (drain to source)) switches. It is
diff --git a/drivers/power/pmic/rk8xx.c b/drivers/power/pmic/rk8xx.c
index 25ef621f8df..4e3a17337ee 100644
--- a/drivers/power/pmic/rk8xx.c
+++ b/drivers/power/pmic/rk8xx.c
@@ -156,6 +156,10 @@ static int rk8xx_bind(struct udevice *dev)
if (!children)
debug("%s: %s - no child found\n", __func__, dev->name);
+ if (IS_ENABLED(CONFIG_SPL_BUILD) &&
+ IS_ENABLED(CONFIG_ROCKCHIP_RK8XX_DISABLE_BOOT_ON_POWERON))
+ dev_or_flags(dev, DM_FLAG_PROBE_AFTER_BIND);
+
/* Always return success for this device */
return 0;
}
@@ -236,14 +240,16 @@ static int rk8xx_probe(struct udevice *dev)
pmic_reg_read(dev, init_data[i].reg));
}
- printf("PMIC: RK%x ", show_variant);
+ if (!IS_ENABLED(CONFIG_SPL_BUILD)) {
+ printf("PMIC: RK%x ", show_variant);
+ if (on_source && off_source)
+ printf("(on=0x%02x, off=0x%02x)",
+ pmic_reg_read(dev, on_source),
+ pmic_reg_read(dev, off_source));
+ printf("\n");
+ }
- if (on_source && off_source)
- printf("(on=0x%02x, off=0x%02x)",
- pmic_reg_read(dev, on_source),
- pmic_reg_read(dev, off_source));
- printf("\n");
- if (CONFIG_IS_ENABLED(ROCKCHIP_RK8XX_DISABLE_BOOT_ON_POWERON))
+ if (IS_ENABLED(CONFIG_ROCKCHIP_RK8XX_DISABLE_BOOT_ON_POWERON))
rk8xx_off_for_plugin(dev);
return 0;
diff --git a/drivers/power/regulator/regulator-uclass.c b/drivers/power/regulator/regulator-uclass.c
index 3a6ba69f6d5..77d101f262e 100644
--- a/drivers/power/regulator/regulator-uclass.c
+++ b/drivers/power/regulator/regulator-uclass.c
@@ -293,6 +293,9 @@ int regulator_autoset(struct udevice *dev)
uc_pdata = dev_get_uclass_plat(dev);
+ if (uc_pdata->flags & REGULATOR_FLAG_AUTOSET_DONE)
+ return -EALREADY;
+
ret = regulator_set_suspend_enable(dev, uc_pdata->suspend_on);
if (ret == -ENOSYS)
ret = 0;
@@ -306,11 +309,15 @@ int regulator_autoset(struct udevice *dev)
return ret;
}
- if (!uc_pdata->always_on && !uc_pdata->boot_on)
- return -EMEDIUMTYPE;
+ if (!uc_pdata->always_on && !uc_pdata->boot_on) {
+ ret = -EMEDIUMTYPE;
+ goto out;
+ }
- if (uc_pdata->type == REGULATOR_TYPE_FIXED)
- return regulator_set_enable(dev, true);
+ if (uc_pdata->type == REGULATOR_TYPE_FIXED) {
+ ret = regulator_set_enable(dev, true);
+ goto out;
+ }
if (uc_pdata->flags & REGULATOR_FLAG_AUTOSET_UV)
ret = regulator_set_value(dev, uc_pdata->min_uV);
@@ -322,6 +329,9 @@ int regulator_autoset(struct udevice *dev)
if (!ret)
ret = regulator_set_enable(dev, true);
+out:
+ uc_pdata->flags |= REGULATOR_FLAG_AUTOSET_DONE;
+
return ret;
}
diff --git a/drivers/power/regulator/rk8xx.c b/drivers/power/regulator/rk8xx.c
index e95640a39b0..e80bd6c3723 100644
--- a/drivers/power/regulator/rk8xx.c
+++ b/drivers/power/regulator/rk8xx.c
@@ -88,62 +88,63 @@ struct rk8xx_reg_info {
u8 config_reg;
u8 vsel_mask;
u8 min_sel;
+ u8 max_sel;
};
static const struct rk8xx_reg_info rk808_buck[] = {
- { 712500, 12500, REG_BUCK1_ON_VSEL, REG_BUCK1_SLP_VSEL, REG_BUCK1_CONFIG, RK808_BUCK_VSEL_MASK, },
- { 712500, 12500, REG_BUCK2_ON_VSEL, REG_BUCK2_SLP_VSEL, REG_BUCK2_CONFIG, RK808_BUCK_VSEL_MASK, },
- { 712500, 12500, NA, NA, REG_BUCK3_CONFIG, RK808_BUCK_VSEL_MASK, },
- { 1800000, 100000, REG_BUCK4_ON_VSEL, REG_BUCK4_SLP_VSEL, REG_BUCK4_CONFIG, RK808_BUCK4_VSEL_MASK, },
+ { 712500, 12500, REG_BUCK1_ON_VSEL, REG_BUCK1_SLP_VSEL, REG_BUCK1_CONFIG, RK808_BUCK_VSEL_MASK, 0x00, 0x3f },
+ { 712500, 12500, REG_BUCK2_ON_VSEL, REG_BUCK2_SLP_VSEL, REG_BUCK2_CONFIG, RK808_BUCK_VSEL_MASK, 0x00, 0x3f },
+ { NA, NA, NA, NA, REG_BUCK3_CONFIG, NA, NA, NA },
+ { 1800000, 100000, REG_BUCK4_ON_VSEL, REG_BUCK4_SLP_VSEL, REG_BUCK4_CONFIG, RK808_BUCK4_VSEL_MASK, 0x00, 0x0f },
};
static const struct rk8xx_reg_info rk816_buck[] = {
/* buck 1 */
- { 712500, 12500, REG_BUCK1_ON_VSEL, REG_BUCK1_SLP_VSEL, REG_BUCK1_CONFIG, RK818_BUCK_VSEL_MASK, 0x00, },
- { 1800000, 200000, REG_BUCK1_ON_VSEL, REG_BUCK1_SLP_VSEL, REG_BUCK1_CONFIG, RK818_BUCK_VSEL_MASK, 0x3c, },
- { 2300000, 0, REG_BUCK1_ON_VSEL, REG_BUCK1_SLP_VSEL, REG_BUCK1_CONFIG, RK818_BUCK_VSEL_MASK, 0x3f, },
+ { 712500, 12500, REG_BUCK1_ON_VSEL, REG_BUCK1_SLP_VSEL, REG_BUCK1_CONFIG, RK818_BUCK_VSEL_MASK, 0x00, 0x3b },
+ { 1800000, 200000, REG_BUCK1_ON_VSEL, REG_BUCK1_SLP_VSEL, REG_BUCK1_CONFIG, RK818_BUCK_VSEL_MASK, 0x3c, 0x3e },
+ { 2300000, 0, REG_BUCK1_ON_VSEL, REG_BUCK1_SLP_VSEL, REG_BUCK1_CONFIG, RK818_BUCK_VSEL_MASK, 0x3f, 0x3f },
/* buck 2 */
- { 712500, 12500, REG_BUCK2_ON_VSEL, REG_BUCK2_SLP_VSEL, REG_BUCK2_CONFIG, RK818_BUCK_VSEL_MASK, 0x00, },
- { 1800000, 200000, REG_BUCK2_ON_VSEL, REG_BUCK2_SLP_VSEL, REG_BUCK2_CONFIG, RK818_BUCK_VSEL_MASK, 0x3c, },
- { 2300000, 0, REG_BUCK2_ON_VSEL, REG_BUCK2_SLP_VSEL, REG_BUCK2_CONFIG, RK818_BUCK_VSEL_MASK, 0x3f, },
+ { 712500, 12500, REG_BUCK2_ON_VSEL, REG_BUCK2_SLP_VSEL, REG_BUCK2_CONFIG, RK818_BUCK_VSEL_MASK, 0x00, 0x3b },
+ { 1800000, 200000, REG_BUCK2_ON_VSEL, REG_BUCK2_SLP_VSEL, REG_BUCK2_CONFIG, RK818_BUCK_VSEL_MASK, 0x3c, 0x3e },
+ { 2300000, 0, REG_BUCK2_ON_VSEL, REG_BUCK2_SLP_VSEL, REG_BUCK2_CONFIG, RK818_BUCK_VSEL_MASK, 0x3f, 0x3f },
/* buck 3 */
- { 712500, 12500, NA, NA, REG_BUCK3_CONFIG, RK818_BUCK_VSEL_MASK, },
+ { NA, NA, NA, NA, REG_BUCK3_CONFIG, NA, NA, NA },
/* buck 4 */
- { 800000, 100000, REG_BUCK4_ON_VSEL, REG_BUCK4_SLP_VSEL, REG_BUCK4_CONFIG, RK818_BUCK4_VSEL_MASK, },
+ { 800000, 100000, REG_BUCK4_ON_VSEL, REG_BUCK4_SLP_VSEL, REG_BUCK4_CONFIG, RK818_BUCK4_VSEL_MASK, 0x00, 0x1f },
};
static const struct rk8xx_reg_info rk809_buck5[] = {
/* buck 5 */
- { 1500000, 0, RK809_BUCK5_CONFIG(0), RK809_BUCK5_CONFIG(1), NA, RK809_BUCK5_VSEL_MASK, 0x00, },
- { 1800000, 200000, RK809_BUCK5_CONFIG(0), RK809_BUCK5_CONFIG(1), NA, RK809_BUCK5_VSEL_MASK, 0x01, },
- { 2800000, 200000, RK809_BUCK5_CONFIG(0), RK809_BUCK5_CONFIG(1), NA, RK809_BUCK5_VSEL_MASK, 0x04, },
- { 3300000, 300000, RK809_BUCK5_CONFIG(0), RK809_BUCK5_CONFIG(1), NA, RK809_BUCK5_VSEL_MASK, 0x06, },
+ { 1500000, 0, RK809_BUCK5_CONFIG(0), RK809_BUCK5_CONFIG(1), NA, RK809_BUCK5_VSEL_MASK, 0x00, 0x00 },
+ { 1800000, 200000, RK809_BUCK5_CONFIG(0), RK809_BUCK5_CONFIG(1), NA, RK809_BUCK5_VSEL_MASK, 0x01, 0x03 },
+ { 2800000, 200000, RK809_BUCK5_CONFIG(0), RK809_BUCK5_CONFIG(1), NA, RK809_BUCK5_VSEL_MASK, 0x04, 0x05 },
+ { 3300000, 300000, RK809_BUCK5_CONFIG(0), RK809_BUCK5_CONFIG(1), NA, RK809_BUCK5_VSEL_MASK, 0x06, 0x07 },
};
static const struct rk8xx_reg_info rk817_buck[] = {
/* buck 1 */
- { 500000, 12500, RK817_BUCK_ON_VSEL(1), RK817_BUCK_SLP_VSEL(1), RK817_BUCK_CONFIG(1), RK817_BUCK_VSEL_MASK, 0x00, },
- { 1500000, 100000, RK817_BUCK_ON_VSEL(1), RK817_BUCK_SLP_VSEL(1), RK817_BUCK_CONFIG(1), RK817_BUCK_VSEL_MASK, 0x50, },
- { 2400000, 0, RK817_BUCK_ON_VSEL(1), RK817_BUCK_SLP_VSEL(1), RK817_BUCK_CONFIG(1), RK817_BUCK_VSEL_MASK, 0x59, },
+ { 500000, 12500, RK817_BUCK_ON_VSEL(1), RK817_BUCK_SLP_VSEL(1), RK817_BUCK_CONFIG(1), RK817_BUCK_VSEL_MASK, 0x00, 0x4f },
+ { 1500000, 100000, RK817_BUCK_ON_VSEL(1), RK817_BUCK_SLP_VSEL(1), RK817_BUCK_CONFIG(1), RK817_BUCK_VSEL_MASK, 0x50, 0x58 },
+ { 2400000, 0, RK817_BUCK_ON_VSEL(1), RK817_BUCK_SLP_VSEL(1), RK817_BUCK_CONFIG(1), RK817_BUCK_VSEL_MASK, 0x59, 0x7f },
/* buck 2 */
- { 500000, 12500, RK817_BUCK_ON_VSEL(2), RK817_BUCK_SLP_VSEL(2), RK817_BUCK_CONFIG(2), RK817_BUCK_VSEL_MASK, 0x00, },
- { 1500000, 100000, RK817_BUCK_ON_VSEL(2), RK817_BUCK_SLP_VSEL(2), RK817_BUCK_CONFIG(2), RK817_BUCK_VSEL_MASK, 0x50, },
- { 2400000, 0, RK817_BUCK_ON_VSEL(2), RK817_BUCK_SLP_VSEL(2), RK817_BUCK_CONFIG(2), RK817_BUCK_VSEL_MASK, 0x59, },
+ { 500000, 12500, RK817_BUCK_ON_VSEL(2), RK817_BUCK_SLP_VSEL(2), RK817_BUCK_CONFIG(2), RK817_BUCK_VSEL_MASK, 0x00, 0x4f },
+ { 1500000, 100000, RK817_BUCK_ON_VSEL(2), RK817_BUCK_SLP_VSEL(2), RK817_BUCK_CONFIG(2), RK817_BUCK_VSEL_MASK, 0x50, 0x58 },
+ { 2400000, 0, RK817_BUCK_ON_VSEL(2), RK817_BUCK_SLP_VSEL(2), RK817_BUCK_CONFIG(2), RK817_BUCK_VSEL_MASK, 0x59, 0x7f },
/* buck 3 */
- { 500000, 12500, RK817_BUCK_ON_VSEL(3), RK817_BUCK_SLP_VSEL(3), RK817_BUCK_CONFIG(3), RK817_BUCK_VSEL_MASK, 0x00, },
- { 1500000, 100000, RK817_BUCK_ON_VSEL(3), RK817_BUCK_SLP_VSEL(3), RK817_BUCK_CONFIG(3), RK817_BUCK_VSEL_MASK, 0x50, },
- { 2400000, 0, RK817_BUCK_ON_VSEL(3), RK817_BUCK_SLP_VSEL(3), RK817_BUCK_CONFIG(3), RK817_BUCK_VSEL_MASK, 0x59, },
+ { 500000, 12500, RK817_BUCK_ON_VSEL(3), RK817_BUCK_SLP_VSEL(3), RK817_BUCK_CONFIG(3), RK817_BUCK_VSEL_MASK, 0x00, 0x4f },
+ { 1500000, 100000, RK817_BUCK_ON_VSEL(3), RK817_BUCK_SLP_VSEL(3), RK817_BUCK_CONFIG(3), RK817_BUCK_VSEL_MASK, 0x50, 0x58 },
+ { 2400000, 0, RK817_BUCK_ON_VSEL(3), RK817_BUCK_SLP_VSEL(3), RK817_BUCK_CONFIG(3), RK817_BUCK_VSEL_MASK, 0x59, 0x7f },
/* buck 4 */
- { 500000, 12500, RK817_BUCK_ON_VSEL(4), RK817_BUCK_SLP_VSEL(4), RK817_BUCK_CONFIG(4), RK817_BUCK_VSEL_MASK, 0x00, },
- { 1500000, 100000, RK817_BUCK_ON_VSEL(4), RK817_BUCK_SLP_VSEL(4), RK817_BUCK_CONFIG(4), RK817_BUCK_VSEL_MASK, 0x50, },
- { 3400000, 0, RK817_BUCK_ON_VSEL(4), RK817_BUCK_SLP_VSEL(4), RK817_BUCK_CONFIG(4), RK817_BUCK_VSEL_MASK, 0x63, },
+ { 500000, 12500, RK817_BUCK_ON_VSEL(4), RK817_BUCK_SLP_VSEL(4), RK817_BUCK_CONFIG(4), RK817_BUCK_VSEL_MASK, 0x00, 0x4f },
+ { 1500000, 100000, RK817_BUCK_ON_VSEL(4), RK817_BUCK_SLP_VSEL(4), RK817_BUCK_CONFIG(4), RK817_BUCK_VSEL_MASK, 0x50, 0x62 },
+ { 3400000, 0, RK817_BUCK_ON_VSEL(4), RK817_BUCK_SLP_VSEL(4), RK817_BUCK_CONFIG(4), RK817_BUCK_VSEL_MASK, 0x63, 0x7f },
};
static const struct rk8xx_reg_info rk818_buck[] = {
- { 712500, 12500, REG_BUCK1_ON_VSEL, REG_BUCK1_SLP_VSEL, REG_BUCK1_CONFIG, RK818_BUCK_VSEL_MASK, },
- { 712500, 12500, REG_BUCK2_ON_VSEL, REG_BUCK2_SLP_VSEL, REG_BUCK2_CONFIG, RK818_BUCK_VSEL_MASK, },
- { 712500, 12500, NA, NA, REG_BUCK3_CONFIG, RK818_BUCK_VSEL_MASK, },
- { 1800000, 100000, REG_BUCK4_ON_VSEL, REG_BUCK4_SLP_VSEL, REG_BUCK4_CONFIG, RK818_BUCK4_VSEL_MASK, },
+ { 712500, 12500, REG_BUCK1_ON_VSEL, REG_BUCK1_SLP_VSEL, REG_BUCK1_CONFIG, RK818_BUCK_VSEL_MASK, 0x00, 0x3f },
+ { 712500, 12500, REG_BUCK2_ON_VSEL, REG_BUCK2_SLP_VSEL, REG_BUCK2_CONFIG, RK818_BUCK_VSEL_MASK, 0x00, 0x3f },
+ { NA, NA, NA, NA, REG_BUCK3_CONFIG, NA, NA, NA },
+ { 1800000, 100000, REG_BUCK4_ON_VSEL, REG_BUCK4_SLP_VSEL, REG_BUCK4_CONFIG, RK818_BUCK4_VSEL_MASK, 0x00, 0x1f },
};
#ifdef ENABLE_DRIVER
@@ -706,7 +707,6 @@ static int _ldo_get_suspend_enable(struct udevice *pmic, int ldo)
static int buck_get_value(struct udevice *dev)
{
int buck = dev->driver_data - 1;
- /* We assume level-1 voltage is enough for usage in U-Boot */
const struct rk8xx_reg_info *info = get_buck_reg(dev->parent, buck, 0);
int mask = info->vsel_mask;
int ret, val;
@@ -717,9 +717,12 @@ static int buck_get_value(struct udevice *dev)
ret = pmic_reg_read(dev->parent, info->vsel_reg);
if (ret < 0)
return ret;
+
val = ret & mask;
+ while (val > info->max_sel)
+ info++;
- return info->min_uv + val * info->step_uv;
+ return info->min_uv + (val - info->min_sel) * info->step_uv;
}
static int buck_set_value(struct udevice *dev, int uvolt)
@@ -732,7 +735,6 @@ static int buck_set_value(struct udevice *dev, int uvolt)
static int buck_get_suspend_value(struct udevice *dev)
{
int buck = dev->driver_data - 1;
- /* We assume level-1 voltage is enough for usage in U-Boot */
const struct rk8xx_reg_info *info = get_buck_reg(dev->parent, buck, 0);
int mask = info->vsel_mask;
int ret, val;
@@ -745,8 +747,10 @@ static int buck_get_suspend_value(struct udevice *dev)
return ret;
val = ret & mask;
+ while (val > info->max_sel)
+ info++;
- return info->min_uv + val * info->step_uv;
+ return info->min_uv + (val - info->min_sel) * info->step_uv;
}
static int buck_set_suspend_value(struct udevice *dev, int uvolt)
@@ -1028,6 +1032,25 @@ static int switch_get_suspend_enable(struct udevice *dev)
*/
static int switch_get_value(struct udevice *dev)
{
+ static const char * const supply_name_rk809[] = {
+ "vcc9-supply",
+ "vcc8-supply",
+ };
+ struct rk8xx_priv *priv = dev_get_priv(dev->parent);
+ struct udevice *supply;
+ int id = dev->driver_data - 1;
+
+ if (!switch_get_enable(dev))
+ return 0;
+
+ if (priv->variant == RK809_ID) {
+ if (!uclass_get_device_by_phandle(UCLASS_REGULATOR,
+ dev->parent,
+ supply_name_rk809[id],
+ &supply))
+ return regulator_get_value(supply);
+ }
+
return 0;
}