Browse Source

Merge git://git.denx.de/u-boot-rockchip

Tom Rini 7 years ago
parent
commit
98691a60ab

+ 10 - 0
arch/arm/include/asm/arch-rockchip/clock.h

@@ -85,4 +85,14 @@ void rk3288_clk_configure_cpu(struct rk3288_cru *cru, struct rk3288_grf *grf);
 
 int rockchip_get_clk(struct udevice **devp);
 
+/*
+ * rockchip_reset_bind() - Bind soft reset device as child of clock device
+ *
+ * @pdev: clock udevice
+ * @reg_offset: the first offset in cru for softreset registers
+ * @reg_number: the reg numbers of softreset registers
+ * @return 0 success, or error value
+ */
+int rockchip_reset_bind(struct udevice *pdev, u32 reg_offset, u32 reg_number);
+
 #endif

+ 7 - 0
drivers/clk/rockchip/clk_rk3036.c

@@ -347,6 +347,13 @@ static int rk3036_clk_bind(struct udevice *dev)
 		sys_child->priv = priv;
 	}
 
+#if CONFIG_IS_ENABLED(CONFIG_RESET_ROCKCHIP)
+	ret = offsetof(struct rk3036_cru, cru_softrst_con[0]);
+	ret = rockchip_reset_bind(dev, ret, 9);
+	if (ret)
+		debug("Warning: software reset driver bind faile\n");
+#endif
+
 	return 0;
 }
 

+ 7 - 0
drivers/clk/rockchip/clk_rk3188.c

@@ -590,6 +590,13 @@ static int rk3188_clk_bind(struct udevice *dev)
 		sys_child->priv = priv;
 	}
 
+#if CONFIG_IS_ENABLED(CONFIG_RESET_ROCKCHIP)
+	ret = offsetof(struct rk3188_cru, cru_softrst_con[0]);
+	ret = rockchip_reset_bind(dev, ret, 9);
+	if (ret)
+		debug("Warning: software reset driver bind faile\n");
+#endif
+
 	return 0;
 }
 

+ 7 - 0
drivers/clk/rockchip/clk_rk322x.c

@@ -402,6 +402,13 @@ static int rk322x_clk_bind(struct udevice *dev)
 		sys_child->priv = priv;
 	}
 
+#if CONFIG_IS_ENABLED(CONFIG_RESET_ROCKCHIP)
+	ret = offsetof(struct rk322x_cru, cru_softrst_con[0]);
+	ret = rockchip_reset_bind(dev, ret, 9);
+	if (ret)
+		debug("Warning: software reset driver bind faile\n");
+#endif
+
 	return 0;
 }
 

+ 7 - 0
drivers/clk/rockchip/clk_rk3288.c

@@ -876,6 +876,13 @@ static int rk3288_clk_bind(struct udevice *dev)
 		sys_child->priv = priv;
 	}
 
+#if CONFIG_IS_ENABLED(CONFIG_RESET_ROCKCHIP)
+	ret = offsetof(struct rk3288_cru, cru_softrst_con[0]);
+	ret = rockchip_reset_bind(dev, ret, 12);
+	if (ret)
+		debug("Warning: software reset driver bind faile\n");
+#endif
+
 	return 0;
 }
 

+ 7 - 0
drivers/clk/rockchip/clk_rk3328.c

@@ -614,6 +614,13 @@ static int rk3328_clk_bind(struct udevice *dev)
 		sys_child->priv = priv;
 	}
 
+#if CONFIG_IS_ENABLED(CONFIG_RESET_ROCKCHIP)
+	ret = offsetof(struct rk3328_cru, softrst_con[0]);
+	ret = rockchip_reset_bind(dev, ret, 12);
+	if (ret)
+		debug("Warning: software reset driver bind faile\n");
+#endif
+
 	return ret;
 }
 

+ 7 - 0
drivers/clk/rockchip/clk_rk3368.c

@@ -543,6 +543,13 @@ static int rk3368_clk_bind(struct udevice *dev)
 		sys_child->priv = priv;
 	}
 
+#if CONFIG_IS_ENABLED(CONFIG_RESET_ROCKCHIP)
+	ret = offsetof(struct rk3368_cru, softrst_con[0]);
+	ret = rockchip_reset_bind(dev, ret, 15);
+	if (ret)
+		debug("Warning: software reset driver bind faile\n");
+#endif
+
 	return ret;
 }
 

+ 21 - 0
drivers/clk/rockchip/clk_rk3399.c

@@ -1046,6 +1046,13 @@ static int rk3399_clk_bind(struct udevice *dev)
 		sys_child->priv = priv;
 	}
 
+#if CONFIG_IS_ENABLED(CONFIG_RESET_ROCKCHIP)
+	ret = offsetof(struct rk3399_cru, softrst_con[0]);
+	ret = rockchip_reset_bind(dev, ret, 21);
+	if (ret)
+		debug("Warning: software reset driver bind faile\n");
+#endif
+
 	return 0;
 }
 
@@ -1221,6 +1228,19 @@ static int rk3399_pmuclk_ofdata_to_platdata(struct udevice *dev)
 	return 0;
 }
 
+static int rk3399_pmuclk_bind(struct udevice *dev)
+{
+#if CONFIG_IS_ENABLED(CONFIG_RESET_ROCKCHIP)
+	int ret;
+
+	ret = offsetof(struct rk3399_pmucru, pmucru_softrst_con[0]);
+	ret = rockchip_reset_bind(dev, ret, 2);
+	if (ret)
+		debug("Warning: software reset driver bind faile\n");
+#endif
+	return 0;
+}
+
 static const struct udevice_id rk3399_pmuclk_ids[] = {
 	{ .compatible = "rockchip,rk3399-pmucru" },
 	{ }
@@ -1234,6 +1254,7 @@ U_BOOT_DRIVER(rockchip_rk3399_pmuclk) = {
 	.ofdata_to_platdata = rk3399_pmuclk_ofdata_to_platdata,
 	.ops		= &rk3399_pmuclk_ops,
 	.probe		= rk3399_pmuclk_probe,
+	.bind		= rk3399_pmuclk_bind,
 #if CONFIG_IS_ENABLED(OF_PLATDATA)
 	.platdata_auto_alloc_size = sizeof(struct rk3399_pmuclk_plat),
 #endif

+ 7 - 0
drivers/clk/rockchip/clk_rv1108.c

@@ -240,6 +240,13 @@ static int rv1108_clk_bind(struct udevice *dev)
 		sys_child->priv = priv;
 	}
 
+#if CONFIG_IS_ENABLED(CONFIG_RESET_ROCKCHIP)
+	ret = offsetof(struct rk3368_cru, softrst_con[0]);
+	ret = rockchip_reset_bind(dev, ret, 13);
+	if (ret)
+		debug("Warning: software reset driver bind faile\n");
+#endif
+
 	return 0;
 }
 

+ 9 - 0
drivers/reset/Kconfig

@@ -74,4 +74,13 @@ config AST2500_RESET
 	  resets that are supported by watchdog. The main limitation though
 	  is that some reset signals, like I2C or MISC reset multiple devices.
 
+config RESET_ROCKCHIP
+	bool "Reset controller driver for Rockchip SoCs"
+	depends on DM_RESET && ARCH_ROCKCHIP && CLK
+	default y
+	help
+	  Support for reset controller on rockchip SoC. The main limitation
+	  though is that some reset signals, like I2C or MISC reset multiple
+	  devices.
+
 endmenu

+ 1 - 0
drivers/reset/Makefile

@@ -12,3 +12,4 @@ obj-$(CONFIG_TEGRA186_RESET) += tegra186-reset.o
 obj-$(CONFIG_RESET_BCM6345) += reset-bcm6345.o
 obj-$(CONFIG_RESET_UNIPHIER) += reset-uniphier.o
 obj-$(CONFIG_AST2500_RESET) += ast2500-reset.o
+obj-$(CONFIG_RESET_ROCKCHIP) += reset-rockchip.o

+ 133 - 0
drivers/reset/reset-rockchip.c

@@ -0,0 +1,133 @@
+/*
+ * (C) Copyright 2017 Rockchip Electronics Co., Ltd
+ *
+ * SPDX-License-Identifier: GPL-2.0
+ */
+
+#include <common.h>
+#include <dm.h>
+#include <reset-uclass.h>
+#include <linux/io.h>
+#include <asm/arch/hardware.h>
+#include <dm/lists.h>
+/*
+ * Each reg has 16 bits reset signal for devices
+ * Note: Not including rk2818 and older SoCs
+ */
+#define ROCKCHIP_RESET_NUM_IN_REG	16
+
+struct rockchip_reset_priv {
+	void __iomem *base;
+	/* Rockchip reset reg locate at cru controller */
+	u32 reset_reg_offset;
+	/* Rockchip reset reg number */
+	u32 reset_reg_num;
+};
+
+static int rockchip_reset_request(struct reset_ctl *reset_ctl)
+{
+	struct rockchip_reset_priv *priv = dev_get_priv(reset_ctl->dev);
+
+	debug("%s(reset_ctl=%p) (dev=%p, id=%lu) (reg_num=%d)\n", __func__,
+	      reset_ctl, reset_ctl->dev, reset_ctl->id, priv->reset_reg_num);
+
+	if (reset_ctl->id / ROCKCHIP_RESET_NUM_IN_REG >= priv->reset_reg_num)
+		return -EINVAL;
+
+	return 0;
+}
+
+static int rockchip_reset_free(struct reset_ctl *reset_ctl)
+{
+	debug("%s(reset_ctl=%p) (dev=%p, id=%lu)\n", __func__, reset_ctl,
+	      reset_ctl->dev, reset_ctl->id);
+
+	return 0;
+}
+
+static int rockchip_reset_assert(struct reset_ctl *reset_ctl)
+{
+	struct rockchip_reset_priv *priv = dev_get_priv(reset_ctl->dev);
+	int bank =  reset_ctl->id / ROCKCHIP_RESET_NUM_IN_REG;
+	int offset =  reset_ctl->id % ROCKCHIP_RESET_NUM_IN_REG;
+
+	debug("%s(reset_ctl=%p) (dev=%p, id=%lu) (reg_addr=%p)\n", __func__,
+	      reset_ctl, reset_ctl->dev, reset_ctl->id,
+	      priv->base + (bank * 4));
+
+	rk_setreg(priv->base + (bank * 4), BIT(offset));
+
+	return 0;
+}
+
+static int rockchip_reset_deassert(struct reset_ctl *reset_ctl)
+{
+	struct rockchip_reset_priv *priv = dev_get_priv(reset_ctl->dev);
+	int bank =  reset_ctl->id / ROCKCHIP_RESET_NUM_IN_REG;
+	int offset =  reset_ctl->id % ROCKCHIP_RESET_NUM_IN_REG;
+
+	debug("%s(reset_ctl=%p) (dev=%p, id=%lu) (reg_addr=%p)\n", __func__,
+	      reset_ctl, reset_ctl->dev, reset_ctl->id,
+	      priv->base + (bank * 4));
+
+	rk_clrreg(priv->base + (bank * 4), BIT(offset));
+
+	return 0;
+}
+
+struct reset_ops rockchip_reset_ops = {
+	.request = rockchip_reset_request,
+	.free = rockchip_reset_free,
+	.rst_assert = rockchip_reset_assert,
+	.rst_deassert = rockchip_reset_deassert,
+};
+
+static int rockchip_reset_probe(struct udevice *dev)
+{
+	struct rockchip_reset_priv *priv = dev_get_priv(dev);
+	fdt_addr_t addr;
+	fdt_size_t size;
+
+	addr = dev_read_addr_size(dev, "reg", &size);
+	if (addr == FDT_ADDR_T_NONE)
+		return -EINVAL;
+
+	if ((priv->reset_reg_offset == 0) && (priv->reset_reg_num == 0))
+		return -EINVAL;
+
+	addr += priv->reset_reg_offset;
+	priv->base = ioremap(addr, size);
+
+	debug("%s(base=%p) (reg_offset=%x, reg_num=%d)\n", __func__,
+	      priv->base, priv->reset_reg_offset, priv->reset_reg_num);
+
+	return 0;
+}
+
+int rockchip_reset_bind(struct udevice *pdev, u32 reg_offset, u32 reg_number)
+{
+	struct udevice *rst_dev;
+	struct rockchip_reset_priv *priv;
+	int ret;
+
+	 ret = device_bind_driver_to_node(pdev, "rockchip_reset", "reset",
+					  dev_ofnode(pdev), &rst_dev);
+	if (ret) {
+		debug("Warning: No rockchip reset driver: ret=%d\n", ret);
+		return ret;
+	}
+	priv = malloc(sizeof(struct rockchip_reset_priv));
+	priv->reset_reg_offset = reg_offset;
+	priv->reset_reg_num = reg_number;
+	rst_dev->priv = priv;
+
+	return 0;
+}
+
+U_BOOT_DRIVER(rockchip_reset) = {
+	.name = "rockchip_reset",
+	.id = UCLASS_RESET,
+	.probe = rockchip_reset_probe,
+	.ops = &rockchip_reset_ops,
+	.priv_auto_alloc_size = sizeof(struct rockchip_reset_priv),
+};