cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

bcm63xx-power.c (8232B)


      1// SPDX-License-Identifier: GPL-2.0-or-later
      2/*
      3 * BCM63xx Power Domain Controller Driver
      4 *
      5 * Copyright (C) 2020 Álvaro Fernández Rojas <noltari@gmail.com>
      6 */
      7
      8#include <dt-bindings/soc/bcm6318-pm.h>
      9#include <dt-bindings/soc/bcm6328-pm.h>
     10#include <dt-bindings/soc/bcm6362-pm.h>
     11#include <dt-bindings/soc/bcm63268-pm.h>
     12#include <linux/io.h>
     13#include <linux/module.h>
     14#include <linux/platform_device.h>
     15#include <linux/pm_domain.h>
     16#include <linux/of.h>
     17#include <linux/of_device.h>
     18
     19struct bcm63xx_power_dev {
     20	struct generic_pm_domain genpd;
     21	struct bcm63xx_power *power;
     22	uint32_t mask;
     23};
     24
     25struct bcm63xx_power {
     26	void __iomem *base;
     27	spinlock_t lock;
     28	struct bcm63xx_power_dev *dev;
     29	struct genpd_onecell_data genpd_data;
     30	struct generic_pm_domain **genpd;
     31};
     32
     33struct bcm63xx_power_data {
     34	const char * const name;
     35	uint8_t bit;
     36	unsigned int flags;
     37};
     38
     39static int bcm63xx_power_get_state(struct bcm63xx_power_dev *pmd, bool *is_on)
     40{
     41	struct bcm63xx_power *power = pmd->power;
     42
     43	if (!pmd->mask) {
     44		*is_on = false;
     45		return -EINVAL;
     46	}
     47
     48	*is_on = !(__raw_readl(power->base) & pmd->mask);
     49
     50	return 0;
     51}
     52
     53static int bcm63xx_power_set_state(struct bcm63xx_power_dev *pmd, bool on)
     54{
     55	struct bcm63xx_power *power = pmd->power;
     56	unsigned long flags;
     57	uint32_t val;
     58
     59	if (!pmd->mask)
     60		return -EINVAL;
     61
     62	spin_lock_irqsave(&power->lock, flags);
     63	val = __raw_readl(power->base);
     64	if (on)
     65		val &= ~pmd->mask;
     66	else
     67		val |= pmd->mask;
     68	__raw_writel(val, power->base);
     69	spin_unlock_irqrestore(&power->lock, flags);
     70
     71	return 0;
     72}
     73
     74static int bcm63xx_power_on(struct generic_pm_domain *genpd)
     75{
     76	struct bcm63xx_power_dev *pmd = container_of(genpd,
     77		struct bcm63xx_power_dev, genpd);
     78
     79	return bcm63xx_power_set_state(pmd, true);
     80}
     81
     82static int bcm63xx_power_off(struct generic_pm_domain *genpd)
     83{
     84	struct bcm63xx_power_dev *pmd = container_of(genpd,
     85		struct bcm63xx_power_dev, genpd);
     86
     87	return bcm63xx_power_set_state(pmd, false);
     88}
     89
     90static int bcm63xx_power_probe(struct platform_device *pdev)
     91{
     92	struct device *dev = &pdev->dev;
     93	struct device_node *np = dev->of_node;
     94	const struct bcm63xx_power_data *entry, *table;
     95	struct bcm63xx_power *power;
     96	unsigned int ndom;
     97	uint8_t max_bit = 0;
     98	int ret;
     99
    100	power = devm_kzalloc(dev, sizeof(*power), GFP_KERNEL);
    101	if (!power)
    102		return -ENOMEM;
    103
    104	power->base = devm_platform_ioremap_resource(pdev, 0);
    105	if (IS_ERR(power->base))
    106		return PTR_ERR(power->base);
    107
    108	table = of_device_get_match_data(dev);
    109	if (!table)
    110		return -EINVAL;
    111
    112	power->genpd_data.num_domains = 0;
    113	ndom = 0;
    114	for (entry = table; entry->name; entry++) {
    115		max_bit = max(max_bit, entry->bit);
    116		ndom++;
    117	}
    118
    119	if (!ndom)
    120		return -ENODEV;
    121
    122	power->genpd_data.num_domains = max_bit + 1;
    123
    124	power->dev = devm_kcalloc(dev, power->genpd_data.num_domains,
    125				  sizeof(struct bcm63xx_power_dev),
    126				  GFP_KERNEL);
    127	if (!power->dev)
    128		return -ENOMEM;
    129
    130	power->genpd = devm_kcalloc(dev, power->genpd_data.num_domains,
    131				    sizeof(struct generic_pm_domain *),
    132				    GFP_KERNEL);
    133	if (!power->genpd)
    134		return -ENOMEM;
    135
    136	power->genpd_data.domains = power->genpd;
    137
    138	ndom = 0;
    139	for (entry = table; entry->name; entry++) {
    140		struct bcm63xx_power_dev *pmd = &power->dev[ndom];
    141		bool is_on;
    142
    143		pmd->power = power;
    144		pmd->mask = BIT(entry->bit);
    145		pmd->genpd.name = entry->name;
    146		pmd->genpd.flags = entry->flags;
    147
    148		ret = bcm63xx_power_get_state(pmd, &is_on);
    149		if (ret)
    150			dev_warn(dev, "unable to get current state for %s\n",
    151				 pmd->genpd.name);
    152
    153		pmd->genpd.power_on = bcm63xx_power_on;
    154		pmd->genpd.power_off = bcm63xx_power_off;
    155
    156		pm_genpd_init(&pmd->genpd, NULL, !is_on);
    157		power->genpd[entry->bit] = &pmd->genpd;
    158
    159		ndom++;
    160	}
    161
    162	spin_lock_init(&power->lock);
    163
    164	ret = of_genpd_add_provider_onecell(np, &power->genpd_data);
    165	if (ret) {
    166		dev_err(dev, "failed to register genpd driver: %d\n", ret);
    167		return ret;
    168	}
    169
    170	dev_info(dev, "registered %u power domains\n", ndom);
    171
    172	return 0;
    173}
    174
    175static const struct bcm63xx_power_data bcm6318_power_domains[] = {
    176	{
    177		.name = "pcie",
    178		.bit = BCM6318_POWER_DOMAIN_PCIE,
    179	}, {
    180		.name = "usb",
    181		.bit = BCM6318_POWER_DOMAIN_USB,
    182	}, {
    183		.name = "ephy0",
    184		.bit = BCM6318_POWER_DOMAIN_EPHY0,
    185	}, {
    186		.name = "ephy1",
    187		.bit = BCM6318_POWER_DOMAIN_EPHY1,
    188	}, {
    189		.name = "ephy2",
    190		.bit = BCM6318_POWER_DOMAIN_EPHY2,
    191	}, {
    192		.name = "ephy3",
    193		.bit = BCM6318_POWER_DOMAIN_EPHY3,
    194	}, {
    195		.name = "ldo2p5",
    196		.bit = BCM6318_POWER_DOMAIN_LDO2P5,
    197		.flags = GENPD_FLAG_ALWAYS_ON,
    198	}, {
    199		.name = "ldo2p9",
    200		.bit = BCM6318_POWER_DOMAIN_LDO2P9,
    201		.flags = GENPD_FLAG_ALWAYS_ON,
    202	}, {
    203		.name = "sw1p0",
    204		.bit = BCM6318_POWER_DOMAIN_SW1P0,
    205		.flags = GENPD_FLAG_ALWAYS_ON,
    206	}, {
    207		.name = "pad",
    208		.bit = BCM6318_POWER_DOMAIN_PAD,
    209		.flags = GENPD_FLAG_ALWAYS_ON,
    210	}, {
    211		/* sentinel */
    212	},
    213};
    214
    215static const struct bcm63xx_power_data bcm6328_power_domains[] = {
    216	{
    217		.name = "adsl2-mips",
    218		.bit = BCM6328_POWER_DOMAIN_ADSL2_MIPS,
    219	}, {
    220		.name = "adsl2-phy",
    221		.bit = BCM6328_POWER_DOMAIN_ADSL2_PHY,
    222	}, {
    223		.name = "adsl2-afe",
    224		.bit = BCM6328_POWER_DOMAIN_ADSL2_AFE,
    225	}, {
    226		.name = "sar",
    227		.bit = BCM6328_POWER_DOMAIN_SAR,
    228	}, {
    229		.name = "pcm",
    230		.bit = BCM6328_POWER_DOMAIN_PCM,
    231	}, {
    232		.name = "usbd",
    233		.bit = BCM6328_POWER_DOMAIN_USBD,
    234	}, {
    235		.name = "usbh",
    236		.bit = BCM6328_POWER_DOMAIN_USBH,
    237	}, {
    238		.name = "pcie",
    239		.bit = BCM6328_POWER_DOMAIN_PCIE,
    240	}, {
    241		.name = "robosw",
    242		.bit = BCM6328_POWER_DOMAIN_ROBOSW,
    243	}, {
    244		.name = "ephy",
    245		.bit = BCM6328_POWER_DOMAIN_EPHY,
    246	}, {
    247		/* sentinel */
    248	},
    249};
    250
    251static const struct bcm63xx_power_data bcm6362_power_domains[] = {
    252	{
    253		.name = "sar",
    254		.bit = BCM6362_POWER_DOMAIN_SAR,
    255	}, {
    256		.name = "ipsec",
    257		.bit = BCM6362_POWER_DOMAIN_IPSEC,
    258	}, {
    259		.name = "mips",
    260		.bit = BCM6362_POWER_DOMAIN_MIPS,
    261		.flags = GENPD_FLAG_ALWAYS_ON,
    262	}, {
    263		.name = "dect",
    264		.bit = BCM6362_POWER_DOMAIN_DECT,
    265	}, {
    266		.name = "usbh",
    267		.bit = BCM6362_POWER_DOMAIN_USBH,
    268	}, {
    269		.name = "usbd",
    270		.bit = BCM6362_POWER_DOMAIN_USBD,
    271	}, {
    272		.name = "robosw",
    273		.bit = BCM6362_POWER_DOMAIN_ROBOSW,
    274	}, {
    275		.name = "pcm",
    276		.bit = BCM6362_POWER_DOMAIN_PCM,
    277	}, {
    278		.name = "periph",
    279		.bit = BCM6362_POWER_DOMAIN_PERIPH,
    280		.flags = GENPD_FLAG_ALWAYS_ON,
    281	}, {
    282		.name = "adsl-phy",
    283		.bit = BCM6362_POWER_DOMAIN_ADSL_PHY,
    284	}, {
    285		.name = "gmii-pads",
    286		.bit = BCM6362_POWER_DOMAIN_GMII_PADS,
    287	}, {
    288		.name = "fap",
    289		.bit = BCM6362_POWER_DOMAIN_FAP,
    290	}, {
    291		.name = "pcie",
    292		.bit = BCM6362_POWER_DOMAIN_PCIE,
    293	}, {
    294		.name = "wlan-pads",
    295		.bit = BCM6362_POWER_DOMAIN_WLAN_PADS,
    296	}, {
    297		/* sentinel */
    298	},
    299};
    300
    301static const struct bcm63xx_power_data bcm63268_power_domains[] = {
    302	{
    303		.name = "sar",
    304		.bit = BCM63268_POWER_DOMAIN_SAR,
    305	}, {
    306		.name = "ipsec",
    307		.bit = BCM63268_POWER_DOMAIN_IPSEC,
    308	}, {
    309		.name = "mips",
    310		.bit = BCM63268_POWER_DOMAIN_MIPS,
    311		.flags = GENPD_FLAG_ALWAYS_ON,
    312	}, {
    313		.name = "dect",
    314		.bit = BCM63268_POWER_DOMAIN_DECT,
    315	}, {
    316		.name = "usbh",
    317		.bit = BCM63268_POWER_DOMAIN_USBH,
    318	}, {
    319		.name = "usbd",
    320		.bit = BCM63268_POWER_DOMAIN_USBD,
    321	}, {
    322		.name = "robosw",
    323		.bit = BCM63268_POWER_DOMAIN_ROBOSW,
    324	}, {
    325		.name = "pcm",
    326		.bit = BCM63268_POWER_DOMAIN_PCM,
    327	}, {
    328		.name = "periph",
    329		.bit = BCM63268_POWER_DOMAIN_PERIPH,
    330		.flags = GENPD_FLAG_ALWAYS_ON,
    331	}, {
    332		.name = "vdsl-phy",
    333		.bit = BCM63268_POWER_DOMAIN_VDSL_PHY,
    334	}, {
    335		.name = "vdsl-mips",
    336		.bit = BCM63268_POWER_DOMAIN_VDSL_MIPS,
    337	}, {
    338		.name = "fap",
    339		.bit = BCM63268_POWER_DOMAIN_FAP,
    340	}, {
    341		.name = "pcie",
    342		.bit = BCM63268_POWER_DOMAIN_PCIE,
    343	}, {
    344		.name = "wlan-pads",
    345		.bit = BCM63268_POWER_DOMAIN_WLAN_PADS,
    346	}, {
    347		/* sentinel */
    348	},
    349};
    350
    351static const struct of_device_id bcm63xx_power_of_match[] = {
    352	{
    353		.compatible = "brcm,bcm6318-power-controller",
    354		.data = &bcm6318_power_domains,
    355	}, {
    356		.compatible = "brcm,bcm6328-power-controller",
    357		.data = &bcm6328_power_domains,
    358	}, {
    359		.compatible = "brcm,bcm6362-power-controller",
    360		.data = &bcm6362_power_domains,
    361	}, {
    362		.compatible = "brcm,bcm63268-power-controller",
    363		.data = &bcm63268_power_domains,
    364	}, {
    365		/* sentinel */
    366	}
    367};
    368
    369static struct platform_driver bcm63xx_power_driver = {
    370	.driver = {
    371		.name = "bcm63xx-power-controller",
    372		.of_match_table = bcm63xx_power_of_match,
    373	},
    374	.probe  = bcm63xx_power_probe,
    375};
    376builtin_platform_driver(bcm63xx_power_driver);