162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only
262306a36Sopenharmony_ci/*
362306a36Sopenharmony_ci * Copyright (c) 2015 Pengutronix, Sascha Hauer <kernel@pengutronix.de>
462306a36Sopenharmony_ci */
562306a36Sopenharmony_ci
662306a36Sopenharmony_ci#include <linux/export.h>
762306a36Sopenharmony_ci#include <linux/jiffies.h>
862306a36Sopenharmony_ci#include <linux/regmap.h>
962306a36Sopenharmony_ci#include <linux/mfd/syscon.h>
1062306a36Sopenharmony_ci#include <linux/soc/mediatek/infracfg.h>
1162306a36Sopenharmony_ci#include <asm/processor.h>
1262306a36Sopenharmony_ci
1362306a36Sopenharmony_ci#define MTK_POLL_DELAY_US   10
1462306a36Sopenharmony_ci#define MTK_POLL_TIMEOUT    (jiffies_to_usecs(HZ))
1562306a36Sopenharmony_ci
1662306a36Sopenharmony_ci/**
1762306a36Sopenharmony_ci * mtk_infracfg_set_bus_protection - enable bus protection
1862306a36Sopenharmony_ci * @infracfg: The infracfg regmap
1962306a36Sopenharmony_ci * @mask: The mask containing the protection bits to be enabled.
2062306a36Sopenharmony_ci * @reg_update: The boolean flag determines to set the protection bits
2162306a36Sopenharmony_ci *              by regmap_update_bits with enable register(PROTECTEN) or
2262306a36Sopenharmony_ci *              by regmap_write with set register(PROTECTEN_SET).
2362306a36Sopenharmony_ci *
2462306a36Sopenharmony_ci * This function enables the bus protection bits for disabled power
2562306a36Sopenharmony_ci * domains so that the system does not hang when some unit accesses the
2662306a36Sopenharmony_ci * bus while in power down.
2762306a36Sopenharmony_ci */
2862306a36Sopenharmony_ciint mtk_infracfg_set_bus_protection(struct regmap *infracfg, u32 mask,
2962306a36Sopenharmony_ci		bool reg_update)
3062306a36Sopenharmony_ci{
3162306a36Sopenharmony_ci	u32 val;
3262306a36Sopenharmony_ci	int ret;
3362306a36Sopenharmony_ci
3462306a36Sopenharmony_ci	if (reg_update)
3562306a36Sopenharmony_ci		regmap_update_bits(infracfg, INFRA_TOPAXI_PROTECTEN, mask,
3662306a36Sopenharmony_ci				mask);
3762306a36Sopenharmony_ci	else
3862306a36Sopenharmony_ci		regmap_write(infracfg, INFRA_TOPAXI_PROTECTEN_SET, mask);
3962306a36Sopenharmony_ci
4062306a36Sopenharmony_ci	ret = regmap_read_poll_timeout(infracfg, INFRA_TOPAXI_PROTECTSTA1,
4162306a36Sopenharmony_ci				       val, (val & mask) == mask,
4262306a36Sopenharmony_ci				       MTK_POLL_DELAY_US, MTK_POLL_TIMEOUT);
4362306a36Sopenharmony_ci
4462306a36Sopenharmony_ci	return ret;
4562306a36Sopenharmony_ci}
4662306a36Sopenharmony_ci
4762306a36Sopenharmony_ci/**
4862306a36Sopenharmony_ci * mtk_infracfg_clear_bus_protection - disable bus protection
4962306a36Sopenharmony_ci * @infracfg: The infracfg regmap
5062306a36Sopenharmony_ci * @mask: The mask containing the protection bits to be disabled.
5162306a36Sopenharmony_ci * @reg_update: The boolean flag determines to clear the protection bits
5262306a36Sopenharmony_ci *              by regmap_update_bits with enable register(PROTECTEN) or
5362306a36Sopenharmony_ci *              by regmap_write with clear register(PROTECTEN_CLR).
5462306a36Sopenharmony_ci *
5562306a36Sopenharmony_ci * This function disables the bus protection bits previously enabled with
5662306a36Sopenharmony_ci * mtk_infracfg_set_bus_protection.
5762306a36Sopenharmony_ci */
5862306a36Sopenharmony_ci
5962306a36Sopenharmony_ciint mtk_infracfg_clear_bus_protection(struct regmap *infracfg, u32 mask,
6062306a36Sopenharmony_ci		bool reg_update)
6162306a36Sopenharmony_ci{
6262306a36Sopenharmony_ci	int ret;
6362306a36Sopenharmony_ci	u32 val;
6462306a36Sopenharmony_ci
6562306a36Sopenharmony_ci	if (reg_update)
6662306a36Sopenharmony_ci		regmap_update_bits(infracfg, INFRA_TOPAXI_PROTECTEN, mask, 0);
6762306a36Sopenharmony_ci	else
6862306a36Sopenharmony_ci		regmap_write(infracfg, INFRA_TOPAXI_PROTECTEN_CLR, mask);
6962306a36Sopenharmony_ci
7062306a36Sopenharmony_ci	ret = regmap_read_poll_timeout(infracfg, INFRA_TOPAXI_PROTECTSTA1,
7162306a36Sopenharmony_ci				       val, !(val & mask),
7262306a36Sopenharmony_ci				       MTK_POLL_DELAY_US, MTK_POLL_TIMEOUT);
7362306a36Sopenharmony_ci
7462306a36Sopenharmony_ci	return ret;
7562306a36Sopenharmony_ci}
7662306a36Sopenharmony_ci
7762306a36Sopenharmony_cistatic int __init mtk_infracfg_init(void)
7862306a36Sopenharmony_ci{
7962306a36Sopenharmony_ci	struct regmap *infracfg;
8062306a36Sopenharmony_ci
8162306a36Sopenharmony_ci	/*
8262306a36Sopenharmony_ci	 * MT8192 has an experimental path to route GPU traffic to the DSU's
8362306a36Sopenharmony_ci	 * Accelerator Coherency Port, which is inadvertently enabled by
8462306a36Sopenharmony_ci	 * default. It turns out not to work, so disable it to prevent spurious
8562306a36Sopenharmony_ci	 * GPU faults.
8662306a36Sopenharmony_ci	 */
8762306a36Sopenharmony_ci	infracfg = syscon_regmap_lookup_by_compatible("mediatek,mt8192-infracfg");
8862306a36Sopenharmony_ci	if (!IS_ERR(infracfg))
8962306a36Sopenharmony_ci		regmap_set_bits(infracfg, MT8192_INFRA_CTRL,
9062306a36Sopenharmony_ci				MT8192_INFRA_CTRL_DISABLE_MFG2ACP);
9162306a36Sopenharmony_ci	return 0;
9262306a36Sopenharmony_ci}
9362306a36Sopenharmony_cipostcore_initcall(mtk_infracfg_init);
94