brintos

brintos / linux-shallow public Read only

0
0
Text · 7.2 KiB · 4cf1b60 Raw
253 lines · c
1// SPDX-License-Identifier: GPL-2.0-only2/*3 * Copyright (C) 2023, STMicroelectronics - All Rights Reserved4 */5 6#include <linux/bitfield.h>7#include <linux/bits.h>8#include <linux/device.h>9#include <linux/err.h>10#include <linux/init.h>11#include <linux/io.h>12#include <linux/kernel.h>13#include <linux/module.h>14#include <linux/of.h>15#include <linux/of_platform.h>16#include <linux/platform_device.h>17#include <linux/types.h>18 19#include "stm32_firewall.h"20 21/*22 * RIFSC offset register23 */24#define RIFSC_RISC_SECCFGR0		0x1025#define RIFSC_RISC_PRIVCFGR0		0x3026#define RIFSC_RISC_PER0_CIDCFGR		0x10027#define RIFSC_RISC_PER0_SEMCR		0x10428#define RIFSC_RISC_HWCFGR2		0xFEC29 30/*31 * SEMCR register32 */33#define SEMCR_MUTEX			BIT(0)34 35/*36 * HWCFGR2 register37 */38#define HWCFGR2_CONF1_MASK		GENMASK(15, 0)39#define HWCFGR2_CONF2_MASK		GENMASK(23, 16)40#define HWCFGR2_CONF3_MASK		GENMASK(31, 24)41 42/*43 * RIFSC miscellaneous44 */45#define RIFSC_RISC_CFEN_MASK		BIT(0)46#define RIFSC_RISC_SEM_EN_MASK		BIT(1)47#define RIFSC_RISC_SCID_MASK		GENMASK(6, 4)48#define RIFSC_RISC_SEML_SHIFT		1649#define RIFSC_RISC_SEMWL_MASK		GENMASK(23, 16)50#define RIFSC_RISC_PER_ID_MASK		GENMASK(31, 24)51 52#define RIFSC_RISC_PERx_CID_MASK	(RIFSC_RISC_CFEN_MASK | \53					 RIFSC_RISC_SEM_EN_MASK | \54					 RIFSC_RISC_SCID_MASK | \55					 RIFSC_RISC_SEMWL_MASK)56 57#define IDS_PER_RISC_SEC_PRIV_REGS	3258 59/* RIF miscellaneous */60/*61 * CIDCFGR register fields62 */63#define CIDCFGR_CFEN			BIT(0)64#define CIDCFGR_SEMEN			BIT(1)65#define CIDCFGR_SEMWL(x)		BIT(RIFSC_RISC_SEML_SHIFT + (x))66 67#define SEMWL_SHIFT			1668 69/* Compartiment IDs */70#define RIF_CID0			0x071#define RIF_CID1			0x172 73static bool stm32_rifsc_is_semaphore_available(void __iomem *addr)74{75	return !(readl(addr) & SEMCR_MUTEX);76}77 78static int stm32_rif_acquire_semaphore(struct stm32_firewall_controller *stm32_firewall_controller,79				       int id)80{81	void __iomem *addr = stm32_firewall_controller->mmio + RIFSC_RISC_PER0_SEMCR + 0x8 * id;82 83	writel(SEMCR_MUTEX, addr);84 85	/* Check that CID1 has the semaphore */86	if (stm32_rifsc_is_semaphore_available(addr) ||87	    FIELD_GET(RIFSC_RISC_SCID_MASK, readl(addr)) != RIF_CID1)88		return -EACCES;89 90	return 0;91}92 93static void stm32_rif_release_semaphore(struct stm32_firewall_controller *stm32_firewall_controller,94					int id)95{96	void __iomem *addr = stm32_firewall_controller->mmio + RIFSC_RISC_PER0_SEMCR + 0x8 * id;97 98	if (stm32_rifsc_is_semaphore_available(addr))99		return;100 101	writel(SEMCR_MUTEX, addr);102 103	/* Ok if another compartment takes the semaphore before the check */104	WARN_ON(!stm32_rifsc_is_semaphore_available(addr) &&105		FIELD_GET(RIFSC_RISC_SCID_MASK, readl(addr)) == RIF_CID1);106}107 108static int stm32_rifsc_grant_access(struct stm32_firewall_controller *ctrl, u32 firewall_id)109{110	struct stm32_firewall_controller *rifsc_controller = ctrl;111	u32 reg_offset, reg_id, sec_reg_value, cid_reg_value;112	int rc;113 114	if (firewall_id >= rifsc_controller->max_entries) {115		dev_err(rifsc_controller->dev, "Invalid sys bus ID %u", firewall_id);116		return -EINVAL;117	}118 119	/*120	 * RIFSC_RISC_PRIVCFGRx and RIFSC_RISC_SECCFGRx both handle configuration access for121	 * 32 peripherals. On the other hand, there is one _RIFSC_RISC_PERx_CIDCFGR register122	 * per peripheral123	 */124	reg_id = firewall_id / IDS_PER_RISC_SEC_PRIV_REGS;125	reg_offset = firewall_id % IDS_PER_RISC_SEC_PRIV_REGS;126	sec_reg_value = readl(rifsc_controller->mmio + RIFSC_RISC_SECCFGR0 + 0x4 * reg_id);127	cid_reg_value = readl(rifsc_controller->mmio + RIFSC_RISC_PER0_CIDCFGR + 0x8 * firewall_id);128 129	/* First check conditions for semaphore mode, which doesn't take into account static CID. */130	if ((cid_reg_value & CIDCFGR_SEMEN) && (cid_reg_value & CIDCFGR_CFEN)) {131		if (cid_reg_value & BIT(RIF_CID1 + SEMWL_SHIFT)) {132			/* Static CID is irrelevant if semaphore mode */133			goto skip_cid_check;134		} else {135			dev_dbg(rifsc_controller->dev,136				"Invalid bus semaphore configuration: index %d\n", firewall_id);137			return -EACCES;138		}139	}140 141	/*142	 * Skip CID check if CID filtering isn't enabled or filtering is enabled on CID0, which143	 * corresponds to whatever CID.144	 */145	if (!(cid_reg_value & CIDCFGR_CFEN) ||146	    FIELD_GET(RIFSC_RISC_SCID_MASK, cid_reg_value) == RIF_CID0)147		goto skip_cid_check;148 149	/* Coherency check with the CID configuration */150	if (FIELD_GET(RIFSC_RISC_SCID_MASK, cid_reg_value) != RIF_CID1) {151		dev_dbg(rifsc_controller->dev, "Invalid CID configuration for peripheral: %d\n",152			firewall_id);153		return -EACCES;154	}155 156skip_cid_check:157	/* Check security configuration */158	if (sec_reg_value & BIT(reg_offset)) {159		dev_dbg(rifsc_controller->dev,160			"Invalid security configuration for peripheral: %d\n", firewall_id);161		return -EACCES;162	}163 164	/*165	 * If the peripheral is in semaphore mode, take the semaphore so that166	 * the CID1 has the ownership.167	 */168	if ((cid_reg_value & CIDCFGR_SEMEN) && (cid_reg_value & CIDCFGR_CFEN)) {169		rc = stm32_rif_acquire_semaphore(rifsc_controller, firewall_id);170		if (rc) {171			dev_err(rifsc_controller->dev,172				"Couldn't acquire semaphore for peripheral: %d\n", firewall_id);173			return rc;174		}175	}176 177	return 0;178}179 180static void stm32_rifsc_release_access(struct stm32_firewall_controller *ctrl, u32 firewall_id)181{182	stm32_rif_release_semaphore(ctrl, firewall_id);183}184 185static int stm32_rifsc_probe(struct platform_device *pdev)186{187	struct stm32_firewall_controller *rifsc_controller;188	struct device_node *np = pdev->dev.of_node;189	u32 nb_risup, nb_rimu, nb_risal;190	struct resource *res;191	void __iomem *mmio;192	int rc;193 194	rifsc_controller = devm_kzalloc(&pdev->dev, sizeof(*rifsc_controller), GFP_KERNEL);195	if (!rifsc_controller)196		return -ENOMEM;197 198	mmio = devm_platform_get_and_ioremap_resource(pdev, 0, &res);199	if (IS_ERR(mmio))200		return PTR_ERR(mmio);201 202	rifsc_controller->dev = &pdev->dev;203	rifsc_controller->mmio = mmio;204	rifsc_controller->name = dev_driver_string(rifsc_controller->dev);205	rifsc_controller->type = STM32_PERIPHERAL_FIREWALL | STM32_MEMORY_FIREWALL;206	rifsc_controller->grant_access = stm32_rifsc_grant_access;207	rifsc_controller->release_access = stm32_rifsc_release_access;208 209	/* Get number of RIFSC entries*/210	nb_risup = readl(rifsc_controller->mmio + RIFSC_RISC_HWCFGR2) & HWCFGR2_CONF1_MASK;211	nb_rimu = readl(rifsc_controller->mmio + RIFSC_RISC_HWCFGR2) & HWCFGR2_CONF2_MASK;212	nb_risal = readl(rifsc_controller->mmio + RIFSC_RISC_HWCFGR2) & HWCFGR2_CONF3_MASK;213	rifsc_controller->max_entries = nb_risup + nb_rimu + nb_risal;214 215	platform_set_drvdata(pdev, rifsc_controller);216 217	rc = stm32_firewall_controller_register(rifsc_controller);218	if (rc) {219		dev_err(rifsc_controller->dev, "Couldn't register as a firewall controller: %d",220			rc);221		return rc;222	}223 224	rc = stm32_firewall_populate_bus(rifsc_controller);225	if (rc) {226		dev_err(rifsc_controller->dev, "Couldn't populate RIFSC bus: %d",227			rc);228		return rc;229	}230 231	/* Populate all allowed nodes */232	return of_platform_populate(np, NULL, NULL, &pdev->dev);233}234 235static const struct of_device_id stm32_rifsc_of_match[] = {236	{ .compatible = "st,stm32mp25-rifsc" },237	{}238};239MODULE_DEVICE_TABLE(of, stm32_rifsc_of_match);240 241static struct platform_driver stm32_rifsc_driver = {242	.probe  = stm32_rifsc_probe,243	.driver = {244		.name = "stm32-rifsc",245		.of_match_table = stm32_rifsc_of_match,246	},247};248module_platform_driver(stm32_rifsc_driver);249 250MODULE_AUTHOR("Gatien Chevallier <gatien.chevallier@foss.st.com>");251MODULE_DESCRIPTION("STMicroelectronics RIFSC driver");252MODULE_LICENSE("GPL");253