Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit a961bf24 authored by Olof Johansson's avatar Olof Johansson
Browse files

Merge tag 'v4.7-rockchip-drivers-1' of...

Merge tag 'v4.7-rockchip-drivers-1' of git://git.kernel.org/pub/scm/linux/kernel/git/mmind/linux-rockchip into next/drivers

Rockchip soc-specific driver changes containing support for the
rk3399 powerdomains and necessary infrastructure changes to
accomodate them - like supporting nested powerdomains here.

* tag 'v4.7-rockchip-drivers-1' of git://git.kernel.org/pub/scm/linux/kernel/git/mmind/linux-rockchip

:
  soc: rockchip: power-domain: check the existing of regmap
  soc: rockchip: power-domain: Modify power domain driver for rk3399
  dt-bindings: add binding for rk3399 power domains
  dt-bindings: add power-domain header for RK3399 SoCs
  soc: rockchip: power-domain: add support for sub-power domains
  soc: rockchip: power-domain: allow domains only handling idle requests
  soc: rockchip: power-domain: make idle handling optional

Signed-off-by: default avatarOlof Johansson <olof@lixom.net>
parents 41f81a51 4506697d
Loading
Loading
Loading
Loading
+37 −0
Original line number Diff line number Diff line
@@ -7,6 +7,7 @@ Required properties for power domain controller:
- compatible: Should be one of the following.
	"rockchip,rk3288-power-controller" - for RK3288 SoCs.
	"rockchip,rk3368-power-controller" - for RK3368 SoCs.
	"rockchip,rk3399-power-controller" - for RK3399 SoCs.
- #power-domain-cells: Number of cells in a power-domain specifier.
	Should be 1 for multiple PM domains.
- #address-cells: Should be 1.
@@ -16,6 +17,7 @@ Required properties for power domain sub nodes:
- reg: index of the power domain, should use macros in:
	"include/dt-bindings/power/rk3288-power.h" - for RK3288 type power domain.
	"include/dt-bindings/power/rk3368-power.h" - for RK3368 type power domain.
	"include/dt-bindings/power/rk3399-power.h" - for RK3399 type power domain.
- clocks (optional): phandles to clocks which need to be enabled while power domain
	switches state.

@@ -45,12 +47,41 @@ Example:
                };
        };

Example 2:
		power: power-controller {
			compatible = "rockchip,rk3399-power-controller";
			#power-domain-cells = <1>;
			#address-cells = <1>;
			#size-cells = <0>;

			pd_vio {
				#address-cells = <1>;
				#size-cells = <0>;
				reg = <RK3399_PD_VIO>;

				pd_vo {
					#address-cells = <1>;
					#size-cells = <0>;
					reg = <RK3399_PD_VO>;

					pd_vopb {
						reg = <RK3399_PD_VOPB>;
					};

					pd_vopl {
						reg = <RK3399_PD_VOPL>;
					};
				};
			};
		};

Node of a device using power domains must have a power-domains property,
containing a phandle to the power device node and an index specifying which
power domain to use.
The index should use macros in:
	"include/dt-bindings/power/rk3288-power.h" - for rk3288 type power domain.
	"include/dt-bindings/power/rk3368-power.h" - for rk3368 type power domain.
	"include/dt-bindings/power/rk3399-power.h" - for rk3399 type power domain.

Example of the node using power domain:

@@ -65,3 +96,9 @@ Example of the node using power domain:
                power-domains = <&power RK3368_PD_GPU_1>;
                /* ... */
        };

	node {
		/* ... */
		power-domains = <&power RK3399_PD_VOPB>;
		/* ... */
	};
+137 −5
Original line number Diff line number Diff line
@@ -19,6 +19,7 @@
#include <linux/mfd/syscon.h>
#include <dt-bindings/power/rk3288-power.h>
#include <dt-bindings/power/rk3368-power.h>
#include <dt-bindings/power/rk3399-power.h>

struct rockchip_domain_info {
	int pwr_mask;
@@ -66,11 +67,11 @@ struct rockchip_pmu {

#define DOMAIN(pwr, status, req, idle, ack)	\
{						\
	.pwr_mask = BIT(pwr),			\
	.status_mask = BIT(status),		\
	.req_mask = BIT(req),			\
	.idle_mask = BIT(idle),			\
	.ack_mask = BIT(ack),			\
	.pwr_mask = (pwr >= 0) ? BIT(pwr) : 0,		\
	.status_mask = (status >= 0) ? BIT(status) : 0,	\
	.req_mask = (req >= 0) ? BIT(req) : 0,		\
	.idle_mask = (idle >= 0) ? BIT(idle) : 0,	\
	.ack_mask = (ack >= 0) ? BIT(ack) : 0,		\
}

#define DOMAIN_RK3288(pwr, status, req)		\
@@ -79,6 +80,9 @@ struct rockchip_pmu {
#define DOMAIN_RK3368(pwr, status, req)		\
	DOMAIN(pwr, status, req, (req) + 16, req)

#define DOMAIN_RK3399(pwr, status, req)                \
	DOMAIN(pwr, status, req, req, req)

static bool rockchip_pmu_domain_is_idle(struct rockchip_pm_domain *pd)
{
	struct rockchip_pmu *pmu = pd->pmu;
@@ -96,6 +100,9 @@ static int rockchip_pmu_set_idle_request(struct rockchip_pm_domain *pd,
	struct rockchip_pmu *pmu = pd->pmu;
	unsigned int val;

	if (pd_info->req_mask == 0)
		return 0;

	regmap_update_bits(pmu->regmap, pmu->info->req_offset,
			   pd_info->req_mask, idle ? -1U : 0);

@@ -116,6 +123,10 @@ static bool rockchip_pmu_domain_is_on(struct rockchip_pm_domain *pd)
	struct rockchip_pmu *pmu = pd->pmu;
	unsigned int val;

	/* check idle status for idle-only domains */
	if (pd->info->status_mask == 0)
		return !rockchip_pmu_domain_is_idle(pd);

	regmap_read(pmu->regmap, pmu->info->status_offset, &val);

	/* 1'b0: power on, 1'b1: power off */
@@ -127,6 +138,9 @@ static void rockchip_do_pmu_set_power_domain(struct rockchip_pm_domain *pd,
{
	struct rockchip_pmu *pmu = pd->pmu;

	if (pd->info->pwr_mask == 0)
		return;

	regmap_update_bits(pmu->regmap, pmu->info->pwr_offset,
			   pd->info->pwr_mask, on ? 0 : -1U);

@@ -360,6 +374,61 @@ static void rockchip_configure_pd_cnt(struct rockchip_pmu *pmu,
	regmap_write(pmu->regmap, domain_reg_offset + 4, count);
}

static int rockchip_pm_add_subdomain(struct rockchip_pmu *pmu,
				     struct device_node *parent)
{
	struct device_node *np;
	struct generic_pm_domain *child_domain, *parent_domain;
	int error;

	for_each_child_of_node(parent, np) {
		u32 idx;

		error = of_property_read_u32(parent, "reg", &idx);
		if (error) {
			dev_err(pmu->dev,
				"%s: failed to retrieve domain id (reg): %d\n",
				parent->name, error);
			goto err_out;
		}
		parent_domain = pmu->genpd_data.domains[idx];

		error = rockchip_pm_add_one_domain(pmu, np);
		if (error) {
			dev_err(pmu->dev, "failed to handle node %s: %d\n",
				np->name, error);
			goto err_out;
		}

		error = of_property_read_u32(np, "reg", &idx);
		if (error) {
			dev_err(pmu->dev,
				"%s: failed to retrieve domain id (reg): %d\n",
				np->name, error);
			goto err_out;
		}
		child_domain = pmu->genpd_data.domains[idx];

		error = pm_genpd_add_subdomain(parent_domain, child_domain);
		if (error) {
			dev_err(pmu->dev, "%s failed to add subdomain %s: %d\n",
				parent_domain->name, child_domain->name, error);
			goto err_out;
		} else {
			dev_dbg(pmu->dev, "%s add subdomain: %s\n",
				parent_domain->name, child_domain->name);
		}

		rockchip_pm_add_subdomain(pmu, np);
	}

	return 0;

err_out:
	of_node_put(np);
	return error;
}

static int rockchip_pm_domain_probe(struct platform_device *pdev)
{
	struct device *dev = &pdev->dev;
@@ -406,6 +475,10 @@ static int rockchip_pm_domain_probe(struct platform_device *pdev)
	}

	pmu->regmap = syscon_node_to_regmap(parent->of_node);
	if (IS_ERR(pmu->regmap)) {
		dev_err(dev, "no regmap available\n");
		return PTR_ERR(pmu->regmap);
	}

	/*
	 * Configure power up and down transition delays for CORE
@@ -426,6 +499,14 @@ static int rockchip_pm_domain_probe(struct platform_device *pdev)
			of_node_put(node);
			goto err_out;
		}

		error = rockchip_pm_add_subdomain(pmu, node);
		if (error < 0) {
			dev_err(dev, "failed to handle subdomain node %s: %d\n",
				node->name, error);
			of_node_put(node);
			goto err_out;
		}
	}

	if (error) {
@@ -457,6 +538,36 @@ static const struct rockchip_domain_info rk3368_pm_domains[] = {
	[RK3368_PD_GPU_1]	= DOMAIN_RK3368(17, 16, 2),
};

static const struct rockchip_domain_info rk3399_pm_domains[] = {
	[RK3399_PD_TCPD0]	= DOMAIN_RK3399(8, 8, -1),
	[RK3399_PD_TCPD1]	= DOMAIN_RK3399(9, 9, -1),
	[RK3399_PD_CCI]		= DOMAIN_RK3399(10, 10, -1),
	[RK3399_PD_CCI0]	= DOMAIN_RK3399(-1, -1, 15),
	[RK3399_PD_CCI1]	= DOMAIN_RK3399(-1, -1, 16),
	[RK3399_PD_PERILP]	= DOMAIN_RK3399(11, 11, 1),
	[RK3399_PD_PERIHP]	= DOMAIN_RK3399(12, 12, 2),
	[RK3399_PD_CENTER]	= DOMAIN_RK3399(13, 13, 14),
	[RK3399_PD_VIO]		= DOMAIN_RK3399(14, 14, 17),
	[RK3399_PD_GPU]		= DOMAIN_RK3399(15, 15, 0),
	[RK3399_PD_VCODEC]	= DOMAIN_RK3399(16, 16, 3),
	[RK3399_PD_VDU]		= DOMAIN_RK3399(17, 17, 4),
	[RK3399_PD_RGA]		= DOMAIN_RK3399(18, 18, 5),
	[RK3399_PD_IEP]		= DOMAIN_RK3399(19, 19, 6),
	[RK3399_PD_VO]		= DOMAIN_RK3399(20, 20, -1),
	[RK3399_PD_VOPB]	= DOMAIN_RK3399(-1, -1, 7),
	[RK3399_PD_VOPL]	= DOMAIN_RK3399(-1, -1, 8),
	[RK3399_PD_ISP0]	= DOMAIN_RK3399(22, 22, 9),
	[RK3399_PD_ISP1]	= DOMAIN_RK3399(23, 23, 10),
	[RK3399_PD_HDCP]	= DOMAIN_RK3399(24, 24, 11),
	[RK3399_PD_GMAC]	= DOMAIN_RK3399(25, 25, 23),
	[RK3399_PD_EMMC]	= DOMAIN_RK3399(26, 26, 24),
	[RK3399_PD_USB3]	= DOMAIN_RK3399(27, 27, 12),
	[RK3399_PD_EDP]		= DOMAIN_RK3399(28, 28, 22),
	[RK3399_PD_GIC]		= DOMAIN_RK3399(29, 29, 27),
	[RK3399_PD_SD]		= DOMAIN_RK3399(30, 30, 28),
	[RK3399_PD_SDIOAUDIO]	= DOMAIN_RK3399(31, 31, 29),
};

static const struct rockchip_pmu_info rk3288_pmu = {
	.pwr_offset = 0x08,
	.status_offset = 0x0c,
@@ -491,6 +602,23 @@ static const struct rockchip_pmu_info rk3368_pmu = {
	.domain_info = rk3368_pm_domains,
};

static const struct rockchip_pmu_info rk3399_pmu = {
	.pwr_offset = 0x14,
	.status_offset = 0x18,
	.req_offset = 0x60,
	.idle_offset = 0x64,
	.ack_offset = 0x68,

	.core_pwrcnt_offset = 0x9c,
	.gpu_pwrcnt_offset = 0xa4,

	.core_power_transition_time = 24,
	.gpu_power_transition_time = 24,

	.num_domains = ARRAY_SIZE(rk3399_pm_domains),
	.domain_info = rk3399_pm_domains,
};

static const struct of_device_id rockchip_pm_domain_dt_match[] = {
	{
		.compatible = "rockchip,rk3288-power-controller",
@@ -500,6 +628,10 @@ static const struct of_device_id rockchip_pm_domain_dt_match[] = {
		.compatible = "rockchip,rk3368-power-controller",
		.data = (void *)&rk3368_pmu,
	},
	{
		.compatible = "rockchip,rk3399-power-controller",
		.data = (void *)&rk3399_pmu,
	},
	{ /* sentinel */ },
};

+53 −0
Original line number Diff line number Diff line
#ifndef __DT_BINDINGS_POWER_RK3399_POWER_H__
#define __DT_BINDINGS_POWER_RK3399_POWER_H__

/* VD_CORE_L */
#define RK3399_PD_A53_L0	0
#define RK3399_PD_A53_L1	1
#define RK3399_PD_A53_L2	2
#define RK3399_PD_A53_L3	3
#define RK3399_PD_SCU_L		4

/* VD_CORE_B */
#define RK3399_PD_A72_B0	5
#define RK3399_PD_A72_B1	6
#define RK3399_PD_SCU_B		7

/* VD_LOGIC */
#define RK3399_PD_TCPD0		8
#define RK3399_PD_TCPD1		9
#define RK3399_PD_CCI		10
#define RK3399_PD_CCI0		11
#define RK3399_PD_CCI1		12
#define RK3399_PD_PERILP	13
#define RK3399_PD_PERIHP	14
#define RK3399_PD_VIO		15
#define RK3399_PD_VO		16
#define RK3399_PD_VOPB		17
#define RK3399_PD_VOPL		18
#define RK3399_PD_ISP0		19
#define RK3399_PD_ISP1		20
#define RK3399_PD_HDCP		21
#define RK3399_PD_GMAC		22
#define RK3399_PD_EMMC		23
#define RK3399_PD_USB3		24
#define RK3399_PD_EDP		25
#define RK3399_PD_GIC		26
#define RK3399_PD_SD		27
#define RK3399_PD_SDIOAUDIO	28
#define RK3399_PD_ALIVE		29

/* VD_CENTER */
#define RK3399_PD_CENTER	30
#define RK3399_PD_VCODEC	31
#define RK3399_PD_VDU		32
#define RK3399_PD_RGA		33
#define RK3399_PD_IEP		34

/* VD_GPU */
#define RK3399_PD_GPU		35

/* VD_PMU */
#define RK3399_PD_PMU		36

#endif