Orange Pi5 kernel

Deprecated Linux kernel 5.10.110 for OrangePi 5/5B/5+ boards

3 Commits   0 Branches   0 Tags
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300   1) // SPDX-License-Identifier: (GPL-2.0+ OR MIT)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300   2) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300   3)  * Copyright (c) 2019 Amlogic, Inc.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300   4)  * Author: Jianxin Pan <jianxin.pan@amlogic.com>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300   5)  */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300   6) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300   7) #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300   8) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300   9) #include <linux/io.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  10) #include <linux/of_device.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  11) #include <linux/platform_device.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  12) #include <linux/pm_domain.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  13) #include <dt-bindings/power/meson-a1-power.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  14) #include <linux/arm-smccc.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  15) #include <linux/firmware/meson/meson_sm.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  16) #include <linux/module.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  17) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  18) #define PWRC_ON		1
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  19) #define PWRC_OFF	0
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  20) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  21) struct meson_secure_pwrc_domain {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  22) 	struct generic_pm_domain base;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  23) 	unsigned int index;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  24) 	struct meson_secure_pwrc *pwrc;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  25) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  26) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  27) struct meson_secure_pwrc {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  28) 	struct meson_secure_pwrc_domain *domains;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  29) 	struct genpd_onecell_data xlate;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  30) 	struct meson_sm_firmware *fw;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  31) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  32) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  33) struct meson_secure_pwrc_domain_desc {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  34) 	unsigned int index;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  35) 	unsigned int flags;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  36) 	char *name;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  37) 	bool (*is_off)(struct meson_secure_pwrc_domain *pwrc_domain);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  38) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  39) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  40) struct meson_secure_pwrc_domain_data {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  41) 	unsigned int count;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  42) 	struct meson_secure_pwrc_domain_desc *domains;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  43) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  44) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  45) static bool pwrc_secure_is_off(struct meson_secure_pwrc_domain *pwrc_domain)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  46) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  47) 	int is_off = 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  48) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  49) 	if (meson_sm_call(pwrc_domain->pwrc->fw, SM_A1_PWRC_GET, &is_off,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  50) 			  pwrc_domain->index, 0, 0, 0, 0) < 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  51) 		pr_err("failed to get power domain status\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  52) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  53) 	return is_off;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  54) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  55) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  56) static int meson_secure_pwrc_off(struct generic_pm_domain *domain)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  57) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  58) 	int ret = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  59) 	struct meson_secure_pwrc_domain *pwrc_domain =
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  60) 		container_of(domain, struct meson_secure_pwrc_domain, base);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  61) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  62) 	if (meson_sm_call(pwrc_domain->pwrc->fw, SM_A1_PWRC_SET, NULL,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  63) 			  pwrc_domain->index, PWRC_OFF, 0, 0, 0) < 0) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  64) 		pr_err("failed to set power domain off\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  65) 		ret = -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  66) 	}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  67) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  68) 	return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  69) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  70) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  71) static int meson_secure_pwrc_on(struct generic_pm_domain *domain)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  72) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  73) 	int ret = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  74) 	struct meson_secure_pwrc_domain *pwrc_domain =
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  75) 		container_of(domain, struct meson_secure_pwrc_domain, base);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  76) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  77) 	if (meson_sm_call(pwrc_domain->pwrc->fw, SM_A1_PWRC_SET, NULL,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  78) 			  pwrc_domain->index, PWRC_ON, 0, 0, 0) < 0) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  79) 		pr_err("failed to set power domain on\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  80) 		ret = -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  81) 	}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  82) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  83) 	return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  84) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  85) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  86) #define SEC_PD(__name, __flag)			\
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  87) [PWRC_##__name##_ID] =				\
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  88) {						\
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  89) 	.name = #__name,			\
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  90) 	.index = PWRC_##__name##_ID,		\
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  91) 	.is_off = pwrc_secure_is_off,	\
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  92) 	.flags = __flag,			\
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  93) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  94) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  95) static struct meson_secure_pwrc_domain_desc a1_pwrc_domains[] = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  96) 	SEC_PD(DSPA,	0),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  97) 	SEC_PD(DSPB,	0),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  98) 	/* UART should keep working in ATF after suspend and before resume */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  99) 	SEC_PD(UART,	GENPD_FLAG_ALWAYS_ON),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 100) 	/* DMC is for DDR PHY ana/dig and DMC, and should be always on */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 101) 	SEC_PD(DMC,	GENPD_FLAG_ALWAYS_ON),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 102) 	SEC_PD(I2C,	0),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 103) 	SEC_PD(PSRAM,	0),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 104) 	SEC_PD(ACODEC,	0),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 105) 	SEC_PD(AUDIO,	0),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 106) 	SEC_PD(OTP,	0),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 107) 	SEC_PD(DMA,	0),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 108) 	SEC_PD(SD_EMMC,	0),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 109) 	SEC_PD(RAMA,	0),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 110) 	/* SRAMB is used as ATF runtime memory, and should be always on */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 111) 	SEC_PD(RAMB,	GENPD_FLAG_ALWAYS_ON),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 112) 	SEC_PD(IR,	0),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 113) 	SEC_PD(SPICC,	0),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 114) 	SEC_PD(SPIFC,	0),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 115) 	SEC_PD(USB,	0),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 116) 	/* NIC is for the Arm NIC-400 interconnect, and should be always on */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 117) 	SEC_PD(NIC,	GENPD_FLAG_ALWAYS_ON),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 118) 	SEC_PD(PDMIN,	0),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 119) 	SEC_PD(RSA,	0),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 120) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 121) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 122) static int meson_secure_pwrc_probe(struct platform_device *pdev)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 123) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 124) 	int i;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 125) 	struct device_node *sm_np;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 126) 	struct meson_secure_pwrc *pwrc;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 127) 	const struct meson_secure_pwrc_domain_data *match;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 128) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 129) 	match = of_device_get_match_data(&pdev->dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 130) 	if (!match) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 131) 		dev_err(&pdev->dev, "failed to get match data\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 132) 		return -ENODEV;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 133) 	}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 134) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 135) 	sm_np = of_find_compatible_node(NULL, NULL, "amlogic,meson-gxbb-sm");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 136) 	if (!sm_np) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 137) 		dev_err(&pdev->dev, "no secure-monitor node\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 138) 		return -ENODEV;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 139) 	}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 140) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 141) 	pwrc = devm_kzalloc(&pdev->dev, sizeof(*pwrc), GFP_KERNEL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 142) 	if (!pwrc)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 143) 		return -ENOMEM;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 144) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 145) 	pwrc->fw = meson_sm_get(sm_np);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 146) 	of_node_put(sm_np);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 147) 	if (!pwrc->fw)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 148) 		return -EPROBE_DEFER;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 149) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 150) 	pwrc->xlate.domains = devm_kcalloc(&pdev->dev, match->count,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 151) 					   sizeof(*pwrc->xlate.domains),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 152) 					   GFP_KERNEL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 153) 	if (!pwrc->xlate.domains)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 154) 		return -ENOMEM;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 155) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 156) 	pwrc->domains = devm_kcalloc(&pdev->dev, match->count,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 157) 				     sizeof(*pwrc->domains), GFP_KERNEL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 158) 	if (!pwrc->domains)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 159) 		return -ENOMEM;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 160) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 161) 	pwrc->xlate.num_domains = match->count;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 162) 	platform_set_drvdata(pdev, pwrc);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 163) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 164) 	for (i = 0 ; i < match->count ; ++i) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 165) 		struct meson_secure_pwrc_domain *dom = &pwrc->domains[i];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 166) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 167) 		if (!match->domains[i].index)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 168) 			continue;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 169) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 170) 		dom->pwrc = pwrc;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 171) 		dom->index = match->domains[i].index;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 172) 		dom->base.name = match->domains[i].name;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 173) 		dom->base.flags = match->domains[i].flags;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 174) 		dom->base.power_on = meson_secure_pwrc_on;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 175) 		dom->base.power_off = meson_secure_pwrc_off;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 176) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 177) 		pm_genpd_init(&dom->base, NULL, match->domains[i].is_off(dom));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 178) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 179) 		pwrc->xlate.domains[i] = &dom->base;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 180) 	}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 181) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 182) 	return of_genpd_add_provider_onecell(pdev->dev.of_node, &pwrc->xlate);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 183) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 184) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 185) static struct meson_secure_pwrc_domain_data meson_secure_a1_pwrc_data = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 186) 	.domains = a1_pwrc_domains,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 187) 	.count = ARRAY_SIZE(a1_pwrc_domains),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 188) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 189) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 190) static const struct of_device_id meson_secure_pwrc_match_table[] = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 191) 	{
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 192) 		.compatible = "amlogic,meson-a1-pwrc",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 193) 		.data = &meson_secure_a1_pwrc_data,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 194) 	},
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 195) 	{ /* sentinel */ }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 196) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 197) MODULE_DEVICE_TABLE(of, meson_secure_pwrc_match_table);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 198) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 199) static struct platform_driver meson_secure_pwrc_driver = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 200) 	.probe = meson_secure_pwrc_probe,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 201) 	.driver = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 202) 		.name		= "meson_secure_pwrc",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 203) 		.of_match_table	= meson_secure_pwrc_match_table,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 204) 	},
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 205) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 206) module_platform_driver(meson_secure_pwrc_driver);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 207) MODULE_LICENSE("Dual MIT/GPL");