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

gpc.c (13429B)


      1// SPDX-License-Identifier: GPL-2.0+
      2/*
      3 * Copyright 2015-2017 Pengutronix, Lucas Stach <kernel@pengutronix.de>
      4 * Copyright 2011-2013 Freescale Semiconductor, Inc.
      5 */
      6
      7#include <linux/clk.h>
      8#include <linux/delay.h>
      9#include <linux/io.h>
     10#include <linux/of_device.h>
     11#include <linux/platform_device.h>
     12#include <linux/pm_domain.h>
     13#include <linux/regmap.h>
     14#include <linux/regulator/consumer.h>
     15
     16#define GPC_CNTR		0x000
     17
     18#define GPC_PGC_CTRL_OFFS	0x0
     19#define GPC_PGC_PUPSCR_OFFS	0x4
     20#define GPC_PGC_PDNSCR_OFFS	0x8
     21#define GPC_PGC_SW2ISO_SHIFT	0x8
     22#define GPC_PGC_SW_SHIFT	0x0
     23
     24#define GPC_PGC_PCI_PDN		0x200
     25#define GPC_PGC_PCI_SR		0x20c
     26
     27#define GPC_PGC_GPU_PDN		0x260
     28#define GPC_PGC_GPU_PUPSCR	0x264
     29#define GPC_PGC_GPU_PDNSCR	0x268
     30#define GPC_PGC_GPU_SR		0x26c
     31
     32#define GPC_PGC_DISP_PDN	0x240
     33#define GPC_PGC_DISP_SR		0x24c
     34
     35#define GPU_VPU_PUP_REQ		BIT(1)
     36#define GPU_VPU_PDN_REQ		BIT(0)
     37
     38#define GPC_CLK_MAX		7
     39
     40#define PGC_DOMAIN_FLAG_NO_PD		BIT(0)
     41
     42struct imx_pm_domain {
     43	struct generic_pm_domain base;
     44	struct regmap *regmap;
     45	struct regulator *supply;
     46	struct clk *clk[GPC_CLK_MAX];
     47	int num_clks;
     48	unsigned int reg_offs;
     49	signed char cntr_pdn_bit;
     50	unsigned int ipg_rate_mhz;
     51};
     52
     53static inline struct imx_pm_domain *
     54to_imx_pm_domain(struct generic_pm_domain *genpd)
     55{
     56	return container_of(genpd, struct imx_pm_domain, base);
     57}
     58
     59static int imx6_pm_domain_power_off(struct generic_pm_domain *genpd)
     60{
     61	struct imx_pm_domain *pd = to_imx_pm_domain(genpd);
     62	int iso, iso2sw;
     63	u32 val;
     64
     65	/* Read ISO and ISO2SW power down delays */
     66	regmap_read(pd->regmap, pd->reg_offs + GPC_PGC_PDNSCR_OFFS, &val);
     67	iso = val & 0x3f;
     68	iso2sw = (val >> 8) & 0x3f;
     69
     70	/* Gate off domain when powered down */
     71	regmap_update_bits(pd->regmap, pd->reg_offs + GPC_PGC_CTRL_OFFS,
     72			   0x1, 0x1);
     73
     74	/* Request GPC to power down domain */
     75	val = BIT(pd->cntr_pdn_bit);
     76	regmap_update_bits(pd->regmap, GPC_CNTR, val, val);
     77
     78	/* Wait ISO + ISO2SW IPG clock cycles */
     79	udelay(DIV_ROUND_UP(iso + iso2sw, pd->ipg_rate_mhz));
     80
     81	if (pd->supply)
     82		regulator_disable(pd->supply);
     83
     84	return 0;
     85}
     86
     87static int imx6_pm_domain_power_on(struct generic_pm_domain *genpd)
     88{
     89	struct imx_pm_domain *pd = to_imx_pm_domain(genpd);
     90	int i, ret;
     91	u32 val, req;
     92
     93	if (pd->supply) {
     94		ret = regulator_enable(pd->supply);
     95		if (ret) {
     96			pr_err("%s: failed to enable regulator: %d\n",
     97			       __func__, ret);
     98			return ret;
     99		}
    100	}
    101
    102	/* Enable reset clocks for all devices in the domain */
    103	for (i = 0; i < pd->num_clks; i++)
    104		clk_prepare_enable(pd->clk[i]);
    105
    106	/* Gate off domain when powered down */
    107	regmap_update_bits(pd->regmap, pd->reg_offs + GPC_PGC_CTRL_OFFS,
    108			   0x1, 0x1);
    109
    110	/* Request GPC to power up domain */
    111	req = BIT(pd->cntr_pdn_bit + 1);
    112	regmap_update_bits(pd->regmap, GPC_CNTR, req, req);
    113
    114	/* Wait for the PGC to handle the request */
    115	ret = regmap_read_poll_timeout(pd->regmap, GPC_CNTR, val, !(val & req),
    116				       1, 50);
    117	if (ret)
    118		pr_err("powerup request on domain %s timed out\n", genpd->name);
    119
    120	/* Wait for reset to propagate through peripherals */
    121	usleep_range(5, 10);
    122
    123	/* Disable reset clocks for all devices in the domain */
    124	for (i = 0; i < pd->num_clks; i++)
    125		clk_disable_unprepare(pd->clk[i]);
    126
    127	return 0;
    128}
    129
    130static int imx_pgc_get_clocks(struct device *dev, struct imx_pm_domain *domain)
    131{
    132	int i, ret;
    133
    134	for (i = 0; ; i++) {
    135		struct clk *clk = of_clk_get(dev->of_node, i);
    136		if (IS_ERR(clk))
    137			break;
    138		if (i >= GPC_CLK_MAX) {
    139			dev_err(dev, "more than %d clocks\n", GPC_CLK_MAX);
    140			ret = -EINVAL;
    141			goto clk_err;
    142		}
    143		domain->clk[i] = clk;
    144	}
    145	domain->num_clks = i;
    146
    147	return 0;
    148
    149clk_err:
    150	while (i--)
    151		clk_put(domain->clk[i]);
    152
    153	return ret;
    154}
    155
    156static void imx_pgc_put_clocks(struct imx_pm_domain *domain)
    157{
    158	int i;
    159
    160	for (i = domain->num_clks - 1; i >= 0; i--)
    161		clk_put(domain->clk[i]);
    162}
    163
    164static int imx_pgc_parse_dt(struct device *dev, struct imx_pm_domain *domain)
    165{
    166	/* try to get the domain supply regulator */
    167	domain->supply = devm_regulator_get_optional(dev, "power");
    168	if (IS_ERR(domain->supply)) {
    169		if (PTR_ERR(domain->supply) == -ENODEV)
    170			domain->supply = NULL;
    171		else
    172			return PTR_ERR(domain->supply);
    173	}
    174
    175	/* try to get all clocks needed for reset propagation */
    176	return imx_pgc_get_clocks(dev, domain);
    177}
    178
    179static int imx_pgc_power_domain_probe(struct platform_device *pdev)
    180{
    181	struct imx_pm_domain *domain = pdev->dev.platform_data;
    182	struct device *dev = &pdev->dev;
    183	int ret;
    184
    185	/* if this PD is associated with a DT node try to parse it */
    186	if (dev->of_node) {
    187		ret = imx_pgc_parse_dt(dev, domain);
    188		if (ret)
    189			return ret;
    190	}
    191
    192	/* initially power on the domain */
    193	if (domain->base.power_on)
    194		domain->base.power_on(&domain->base);
    195
    196	if (IS_ENABLED(CONFIG_PM_GENERIC_DOMAINS)) {
    197		pm_genpd_init(&domain->base, NULL, false);
    198		ret = of_genpd_add_provider_simple(dev->of_node, &domain->base);
    199		if (ret)
    200			goto genpd_err;
    201	}
    202
    203	device_link_add(dev, dev->parent, DL_FLAG_AUTOREMOVE_CONSUMER);
    204
    205	return 0;
    206
    207genpd_err:
    208	pm_genpd_remove(&domain->base);
    209	imx_pgc_put_clocks(domain);
    210
    211	return ret;
    212}
    213
    214static int imx_pgc_power_domain_remove(struct platform_device *pdev)
    215{
    216	struct imx_pm_domain *domain = pdev->dev.platform_data;
    217
    218	if (IS_ENABLED(CONFIG_PM_GENERIC_DOMAINS)) {
    219		of_genpd_del_provider(pdev->dev.of_node);
    220		pm_genpd_remove(&domain->base);
    221		imx_pgc_put_clocks(domain);
    222	}
    223
    224	return 0;
    225}
    226
    227static const struct platform_device_id imx_pgc_power_domain_id[] = {
    228	{ "imx-pgc-power-domain"},
    229	{ },
    230};
    231
    232static struct platform_driver imx_pgc_power_domain_driver = {
    233	.driver = {
    234		.name = "imx-pgc-pd",
    235	},
    236	.probe = imx_pgc_power_domain_probe,
    237	.remove = imx_pgc_power_domain_remove,
    238	.id_table = imx_pgc_power_domain_id,
    239};
    240builtin_platform_driver(imx_pgc_power_domain_driver)
    241
    242#define GPC_PGC_DOMAIN_ARM	0
    243#define GPC_PGC_DOMAIN_PU	1
    244#define GPC_PGC_DOMAIN_DISPLAY	2
    245#define GPC_PGC_DOMAIN_PCI	3
    246
    247static struct genpd_power_state imx6_pm_domain_pu_state = {
    248	.power_off_latency_ns = 25000,
    249	.power_on_latency_ns = 2000000,
    250};
    251
    252static struct imx_pm_domain imx_gpc_domains[] = {
    253	[GPC_PGC_DOMAIN_ARM] = {
    254		.base = {
    255			.name = "ARM",
    256			.flags = GENPD_FLAG_ALWAYS_ON,
    257		},
    258	},
    259	[GPC_PGC_DOMAIN_PU] = {
    260		.base = {
    261			.name = "PU",
    262			.power_off = imx6_pm_domain_power_off,
    263			.power_on = imx6_pm_domain_power_on,
    264			.states = &imx6_pm_domain_pu_state,
    265			.state_count = 1,
    266		},
    267		.reg_offs = 0x260,
    268		.cntr_pdn_bit = 0,
    269	},
    270	[GPC_PGC_DOMAIN_DISPLAY] = {
    271		.base = {
    272			.name = "DISPLAY",
    273			.power_off = imx6_pm_domain_power_off,
    274			.power_on = imx6_pm_domain_power_on,
    275		},
    276		.reg_offs = 0x240,
    277		.cntr_pdn_bit = 4,
    278	},
    279	[GPC_PGC_DOMAIN_PCI] = {
    280		.base = {
    281			.name = "PCI",
    282			.power_off = imx6_pm_domain_power_off,
    283			.power_on = imx6_pm_domain_power_on,
    284		},
    285		.reg_offs = 0x200,
    286		.cntr_pdn_bit = 6,
    287	},
    288};
    289
    290struct imx_gpc_dt_data {
    291	int num_domains;
    292	bool err009619_present;
    293	bool err006287_present;
    294};
    295
    296static const struct imx_gpc_dt_data imx6q_dt_data = {
    297	.num_domains = 2,
    298	.err009619_present = false,
    299	.err006287_present = false,
    300};
    301
    302static const struct imx_gpc_dt_data imx6qp_dt_data = {
    303	.num_domains = 2,
    304	.err009619_present = true,
    305	.err006287_present = false,
    306};
    307
    308static const struct imx_gpc_dt_data imx6sl_dt_data = {
    309	.num_domains = 3,
    310	.err009619_present = false,
    311	.err006287_present = true,
    312};
    313
    314static const struct imx_gpc_dt_data imx6sx_dt_data = {
    315	.num_domains = 4,
    316	.err009619_present = false,
    317	.err006287_present = false,
    318};
    319
    320static const struct of_device_id imx_gpc_dt_ids[] = {
    321	{ .compatible = "fsl,imx6q-gpc", .data = &imx6q_dt_data },
    322	{ .compatible = "fsl,imx6qp-gpc", .data = &imx6qp_dt_data },
    323	{ .compatible = "fsl,imx6sl-gpc", .data = &imx6sl_dt_data },
    324	{ .compatible = "fsl,imx6sx-gpc", .data = &imx6sx_dt_data },
    325	{ }
    326};
    327
    328static const struct regmap_range yes_ranges[] = {
    329	regmap_reg_range(GPC_CNTR, GPC_CNTR),
    330	regmap_reg_range(GPC_PGC_PCI_PDN, GPC_PGC_PCI_SR),
    331	regmap_reg_range(GPC_PGC_GPU_PDN, GPC_PGC_GPU_SR),
    332	regmap_reg_range(GPC_PGC_DISP_PDN, GPC_PGC_DISP_SR),
    333};
    334
    335static const struct regmap_access_table access_table = {
    336	.yes_ranges	= yes_ranges,
    337	.n_yes_ranges	= ARRAY_SIZE(yes_ranges),
    338};
    339
    340static const struct regmap_config imx_gpc_regmap_config = {
    341	.reg_bits = 32,
    342	.val_bits = 32,
    343	.reg_stride = 4,
    344	.rd_table = &access_table,
    345	.wr_table = &access_table,
    346	.max_register = 0x2ac,
    347	.fast_io = true,
    348};
    349
    350static struct generic_pm_domain *imx_gpc_onecell_domains[] = {
    351	&imx_gpc_domains[GPC_PGC_DOMAIN_ARM].base,
    352	&imx_gpc_domains[GPC_PGC_DOMAIN_PU].base,
    353};
    354
    355static struct genpd_onecell_data imx_gpc_onecell_data = {
    356	.domains = imx_gpc_onecell_domains,
    357	.num_domains = 2,
    358};
    359
    360static int imx_gpc_old_dt_init(struct device *dev, struct regmap *regmap,
    361			       unsigned int num_domains)
    362{
    363	struct imx_pm_domain *domain;
    364	int i, ret;
    365
    366	for (i = 0; i < num_domains; i++) {
    367		domain = &imx_gpc_domains[i];
    368		domain->regmap = regmap;
    369		domain->ipg_rate_mhz = 66;
    370
    371		if (i == 1) {
    372			domain->supply = devm_regulator_get(dev, "pu");
    373			if (IS_ERR(domain->supply))
    374				return PTR_ERR(domain->supply);
    375
    376			ret = imx_pgc_get_clocks(dev, domain);
    377			if (ret)
    378				goto clk_err;
    379
    380			domain->base.power_on(&domain->base);
    381		}
    382	}
    383
    384	for (i = 0; i < num_domains; i++)
    385		pm_genpd_init(&imx_gpc_domains[i].base, NULL, false);
    386
    387	if (IS_ENABLED(CONFIG_PM_GENERIC_DOMAINS)) {
    388		ret = of_genpd_add_provider_onecell(dev->of_node,
    389						    &imx_gpc_onecell_data);
    390		if (ret)
    391			goto genpd_err;
    392	}
    393
    394	return 0;
    395
    396genpd_err:
    397	for (i = 0; i < num_domains; i++)
    398		pm_genpd_remove(&imx_gpc_domains[i].base);
    399	imx_pgc_put_clocks(&imx_gpc_domains[GPC_PGC_DOMAIN_PU]);
    400clk_err:
    401	return ret;
    402}
    403
    404static int imx_gpc_probe(struct platform_device *pdev)
    405{
    406	const struct of_device_id *of_id =
    407			of_match_device(imx_gpc_dt_ids, &pdev->dev);
    408	const struct imx_gpc_dt_data *of_id_data = of_id->data;
    409	struct device_node *pgc_node;
    410	struct regmap *regmap;
    411	void __iomem *base;
    412	int ret;
    413
    414	pgc_node = of_get_child_by_name(pdev->dev.of_node, "pgc");
    415
    416	/* bail out if DT too old and doesn't provide the necessary info */
    417	if (!of_property_read_bool(pdev->dev.of_node, "#power-domain-cells") &&
    418	    !pgc_node)
    419		return 0;
    420
    421	base = devm_platform_ioremap_resource(pdev, 0);
    422	if (IS_ERR(base))
    423		return PTR_ERR(base);
    424
    425	regmap = devm_regmap_init_mmio_clk(&pdev->dev, NULL, base,
    426					   &imx_gpc_regmap_config);
    427	if (IS_ERR(regmap)) {
    428		ret = PTR_ERR(regmap);
    429		dev_err(&pdev->dev, "failed to init regmap: %d\n",
    430			ret);
    431		return ret;
    432	}
    433
    434	/*
    435	 * Disable PU power down by runtime PM if ERR009619 is present.
    436	 *
    437	 * The PRE clock will be paused for several cycles when turning on the
    438	 * PU domain LDO from power down state. If PRE is in use at that time,
    439	 * the IPU/PRG cannot get the correct display data from the PRE.
    440	 *
    441	 * This is not a concern when the whole system enters suspend state, so
    442	 * it's safe to power down PU in this case.
    443	 */
    444	if (of_id_data->err009619_present)
    445		imx_gpc_domains[GPC_PGC_DOMAIN_PU].base.flags |=
    446				GENPD_FLAG_RPM_ALWAYS_ON;
    447
    448	/* Keep DISP always on if ERR006287 is present */
    449	if (of_id_data->err006287_present)
    450		imx_gpc_domains[GPC_PGC_DOMAIN_DISPLAY].base.flags |=
    451				GENPD_FLAG_ALWAYS_ON;
    452
    453	if (!pgc_node) {
    454		ret = imx_gpc_old_dt_init(&pdev->dev, regmap,
    455					  of_id_data->num_domains);
    456		if (ret)
    457			return ret;
    458	} else {
    459		struct imx_pm_domain *domain;
    460		struct platform_device *pd_pdev;
    461		struct device_node *np;
    462		struct clk *ipg_clk;
    463		unsigned int ipg_rate_mhz;
    464		int domain_index;
    465
    466		ipg_clk = devm_clk_get(&pdev->dev, "ipg");
    467		if (IS_ERR(ipg_clk))
    468			return PTR_ERR(ipg_clk);
    469		ipg_rate_mhz = clk_get_rate(ipg_clk) / 1000000;
    470
    471		for_each_child_of_node(pgc_node, np) {
    472			ret = of_property_read_u32(np, "reg", &domain_index);
    473			if (ret) {
    474				of_node_put(np);
    475				return ret;
    476			}
    477			if (domain_index >= of_id_data->num_domains)
    478				continue;
    479
    480			pd_pdev = platform_device_alloc("imx-pgc-power-domain",
    481							domain_index);
    482			if (!pd_pdev) {
    483				of_node_put(np);
    484				return -ENOMEM;
    485			}
    486
    487			ret = platform_device_add_data(pd_pdev,
    488						       &imx_gpc_domains[domain_index],
    489						       sizeof(imx_gpc_domains[domain_index]));
    490			if (ret) {
    491				platform_device_put(pd_pdev);
    492				of_node_put(np);
    493				return ret;
    494			}
    495			domain = pd_pdev->dev.platform_data;
    496			domain->regmap = regmap;
    497			domain->ipg_rate_mhz = ipg_rate_mhz;
    498
    499			pd_pdev->dev.parent = &pdev->dev;
    500			pd_pdev->dev.of_node = np;
    501
    502			ret = platform_device_add(pd_pdev);
    503			if (ret) {
    504				platform_device_put(pd_pdev);
    505				of_node_put(np);
    506				return ret;
    507			}
    508		}
    509	}
    510
    511	return 0;
    512}
    513
    514static int imx_gpc_remove(struct platform_device *pdev)
    515{
    516	struct device_node *pgc_node;
    517	int ret;
    518
    519	pgc_node = of_get_child_by_name(pdev->dev.of_node, "pgc");
    520
    521	/* bail out if DT too old and doesn't provide the necessary info */
    522	if (!of_property_read_bool(pdev->dev.of_node, "#power-domain-cells") &&
    523	    !pgc_node)
    524		return 0;
    525
    526	/*
    527	 * If the old DT binding is used the toplevel driver needs to
    528	 * de-register the power domains
    529	 */
    530	if (!pgc_node) {
    531		of_genpd_del_provider(pdev->dev.of_node);
    532
    533		ret = pm_genpd_remove(&imx_gpc_domains[GPC_PGC_DOMAIN_PU].base);
    534		if (ret)
    535			return ret;
    536		imx_pgc_put_clocks(&imx_gpc_domains[GPC_PGC_DOMAIN_PU]);
    537
    538		ret = pm_genpd_remove(&imx_gpc_domains[GPC_PGC_DOMAIN_ARM].base);
    539		if (ret)
    540			return ret;
    541	}
    542
    543	return 0;
    544}
    545
    546static struct platform_driver imx_gpc_driver = {
    547	.driver = {
    548		.name = "imx-gpc",
    549		.of_match_table = imx_gpc_dt_ids,
    550	},
    551	.probe = imx_gpc_probe,
    552	.remove = imx_gpc_remove,
    553};
    554builtin_platform_driver(imx_gpc_driver)