Linux-ARM-Kernel Archive on lore.kernel.org
 help / color / mirror / Atom feed
* Re: [PATCH v2 02/18] PCI: endpoint: Introduce pci_epc_map_align()
From: Manivannan Sadhasivam @ 2024-04-03  7:45 UTC (permalink / raw)
  To: Damien Le Moal
  Cc: Lorenzo Pieralisi, Kishon Vijay Abraham I, Shawn Lin,
	Krzysztof Wilczyński, Bjorn Helgaas, Heiko Stuebner,
	linux-pci, Rob Herring, Krzysztof Kozlowski, Conor Dooley,
	devicetree, linux-rockchip, linux-arm-kernel, Rick Wertenbroek,
	Wilfred Mallawa, Niklas Cassel
In-Reply-To: <20240330041928.1555578-3-dlemoal@kernel.org>

On Sat, Mar 30, 2024 at 01:19:12PM +0900, Damien Le Moal wrote:
> Some endpoint controllers have requirements on the alignment of the
> controller physical memory address that must be used to map a RC PCI
> address region. For instance, the rockchip endpoint controller uses
> at most the lower 20 bits of a physical memory address region as the
> lower bits of an RC PCI address. For mapping a PCI address region of
> size bytes starting from pci_addr, the exact number of address bits
> used is the number of address bits changing in the address range
> [pci_addr..pci_addr + size - 1].
> 
> For this example, this creates the following constraints:
> 1) The offset into the controller physical memory allocated for a
>    mapping depends on the mapping size *and* the starting PCI address
>    for the mapping.
> 2) A mapping size cannot exceed the controller windows size (1MB) minus
>    the offset needed into the allocated physical memory, which can end
>    up being a smaller size than the desired mapping size.
> 
> Handling these constraints independently of the controller being used in
> a PCI EP function driver is not possible with the current EPC API as
> it only provides the ->align field in struct pci_epc_features.
> Furthermore, this alignment is static and does not depend on a mapping
> pci address and size.
> 
> Solve this by introducing the function pci_epc_map_align() and the
> endpoint controller operation ->map_align to allow endpoint function
> drivers to obtain the size and the offset into a controller address
> region that must be used to map an RC PCI address region. The size
> of the physical address region provided by pci_epc_map_align() can then
> be used as the size argument for the function pci_epc_mem_alloc_addr().
> The offset into the allocated controller memory can be used to
> correctly handle data transfers. Of note is that pci_epc_map_align() may
> indicate upon return a mapping size that is smaller (but not 0) than the
> requested PCI address region size. For such case, an endpoint function
> driver must handle data transfers in fragments.
> 

Is there any incentive in exposing pci_epc_map_align()? I mean, why can't it be
hidden inside the new alloc() API itself?

Furthermore, is it possible to avoid the map_align() callback and handle the
alignment within the EPC driver?

- Mani

> The controller operation ->map_align is optional: controllers that do
> not have any address alignment constraints for mapping a RC PCI address
> region do not need to implement this operation. For such controllers,
> pci_epc_map_align() always returns the mapping size as equal
> to the requested size and an offset equal to 0.
> 
> The structure pci_epc_map is introduced to represent a mapping start PCI
> address, size and the size and offset into the controller memory needed
> for mapping the PCI address region.
> 
> Signed-off-by: Damien Le Moal <dlemoal@kernel.org>
> ---
>  drivers/pci/endpoint/pci-epc-core.c | 66 +++++++++++++++++++++++++++++
>  include/linux/pci-epc.h             | 33 +++++++++++++++
>  2 files changed, 99 insertions(+)
> 
> diff --git a/drivers/pci/endpoint/pci-epc-core.c b/drivers/pci/endpoint/pci-epc-core.c
> index 754afd115bbd..37758ca91d7f 100644
> --- a/drivers/pci/endpoint/pci-epc-core.c
> +++ b/drivers/pci/endpoint/pci-epc-core.c
> @@ -433,6 +433,72 @@ void pci_epc_unmap_addr(struct pci_epc *epc, u8 func_no, u8 vfunc_no,
>  }
>  EXPORT_SYMBOL_GPL(pci_epc_unmap_addr);
>  
> +/**
> + * pci_epc_map_align() - Get the offset into and the size of a controller memory
> + *			 address region needed to map a RC PCI address region
> + * @epc: the EPC device on which address is allocated
> + * @func_no: the physical endpoint function number in the EPC device
> + * @vfunc_no: the virtual endpoint function number in the physical function
> + * @pci_addr: PCI address to which the physical address should be mapped
> + * @size: the size of the mapping starting from @pci_addr
> + * @map: populate here the actual size and offset into the controller memory
> + *       that must be allocated for the mapping
> + *
> + * Invoke the controller map_align operation to obtain the size and the offset
> + * into a controller address region that must be allocated to map @size
> + * bytes of the RC PCI address space starting from @pci_addr.
> + *
> + * The size of the mapping that can be handled by the controller is indicated
> + * using the pci_size field of @map. This size may be smaller than the requested
> + * @size. In such case, the function driver must handle the mapping using
> + * several fragments. The offset into the controller memory for the effective
> + * mapping of the @pci_addr..@pci_addr+@map->pci_size address range is indicated
> + * using the map_ofst field of @map.
> + */
> +int pci_epc_map_align(struct pci_epc *epc, u8 func_no, u8 vfunc_no,
> +		      u64 pci_addr, size_t size, struct pci_epc_map *map)
> +{
> +	const struct pci_epc_features *features;
> +	size_t mask;
> +	int ret;
> +
> +	if (!pci_epc_function_is_valid(epc, func_no, vfunc_no))
> +		return -EINVAL;
> +
> +	if (!size || !map)
> +		return -EINVAL;
> +
> +	memset(map, 0, sizeof(*map));
> +	map->pci_addr = pci_addr;
> +	map->pci_size = size;
> +
> +	if (epc->ops->map_align) {
> +		mutex_lock(&epc->lock);
> +		ret = epc->ops->map_align(epc, func_no, vfunc_no, map);
> +		mutex_unlock(&epc->lock);
> +		return ret;
> +	}
> +
> +	/*
> +	 * Assume a fixed alignment constraint as specified by the controller
> +	 * features.
> +	 */
> +	features = pci_epc_get_features(epc, func_no, vfunc_no);
> +	if (!features || !features->align) {
> +		map->map_pci_addr = pci_addr;
> +		map->map_size = size;
> +		map->map_ofst = 0;

These values are overwritten anyway below.

> +	}
> +
> +	mask = features->align - 1;
> +	map->map_pci_addr = map->pci_addr & ~mask;
> +	map->map_ofst = map->pci_addr & mask;
> +	map->map_size = ALIGN(map->map_ofst + map->pci_size, features->align);
> +
> +	return 0;
> +}
> +EXPORT_SYMBOL_GPL(pci_epc_map_align);
> +
>  /**
>   * pci_epc_map_addr() - map CPU address to PCI address
>   * @epc: the EPC device on which address is allocated
> diff --git a/include/linux/pci-epc.h b/include/linux/pci-epc.h
> index cc2f70d061c8..8cfb4aaf2628 100644
> --- a/include/linux/pci-epc.h
> +++ b/include/linux/pci-epc.h
> @@ -32,11 +32,40 @@ pci_epc_interface_string(enum pci_epc_interface_type type)
>  	}
>  }
>  
> +/**
> + * struct pci_epc_map - information about EPC memory for mapping a RC PCI
> + *                      address range
> + * @pci_addr: start address of the RC PCI address range to map
> + * @pci_size: size of the RC PCI address range to map
> + * @map_pci_addr: RC PCI address used as the first address mapped
> + * @map_size: size of the controller memory needed for the mapping
> + * @map_ofst: offset into the controller memory needed for the mapping
> + * @phys_base: base physical address of the allocated EPC memory
> + * @phys_addr: physical address at which @pci_addr is mapped
> + * @virt_base: base virtual address of the allocated EPC memory
> + * @virt_addr: virtual address at which @pci_addr is mapped
> + */
> +struct pci_epc_map {
> +	phys_addr_t	pci_addr;
> +	size_t		pci_size;
> +
> +	phys_addr_t	map_pci_addr;
> +	size_t		map_size;
> +	phys_addr_t	map_ofst;
> +
> +	phys_addr_t	phys_base;
> +	phys_addr_t	phys_addr;
> +	void __iomem	*virt_base;
> +	void __iomem	*virt_addr;
> +};
> +
>  /**
>   * struct pci_epc_ops - set of function pointers for performing EPC operations
>   * @write_header: ops to populate configuration space header
>   * @set_bar: ops to configure the BAR
>   * @clear_bar: ops to reset the BAR
> + * @map_align: operation to get the size and offset into a controller memory
> + *             window needed to map an RC PCI address region
>   * @map_addr: ops to map CPU address to PCI address
>   * @unmap_addr: ops to unmap CPU address and PCI address
>   * @set_msi: ops to set the requested number of MSI interrupts in the MSI
> @@ -61,6 +90,8 @@ struct pci_epc_ops {
>  			   struct pci_epf_bar *epf_bar);
>  	void	(*clear_bar)(struct pci_epc *epc, u8 func_no, u8 vfunc_no,
>  			     struct pci_epf_bar *epf_bar);
> +	int	(*map_align)(struct pci_epc *epc, u8 func_no, u8 vfunc_no,
> +			    struct pci_epc_map *map);
>  	int	(*map_addr)(struct pci_epc *epc, u8 func_no, u8 vfunc_no,
>  			    phys_addr_t addr, u64 pci_addr, size_t size);
>  	void	(*unmap_addr)(struct pci_epc *epc, u8 func_no, u8 vfunc_no,
> @@ -234,6 +265,8 @@ int pci_epc_set_bar(struct pci_epc *epc, u8 func_no, u8 vfunc_no,
>  		    struct pci_epf_bar *epf_bar);
>  void pci_epc_clear_bar(struct pci_epc *epc, u8 func_no, u8 vfunc_no,
>  		       struct pci_epf_bar *epf_bar);
> +int pci_epc_map_align(struct pci_epc *epc, u8 func_no, u8 vfunc_no,
> +		      u64 pci_addr, size_t size, struct pci_epc_map *map);
>  int pci_epc_map_addr(struct pci_epc *epc, u8 func_no, u8 vfunc_no,
>  		     phys_addr_t phys_addr,
>  		     u64 pci_addr, size_t size);
> -- 
> 2.44.0
> 

-- 
மணிவண்ணன் சதாசிவம்

_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

^ permalink raw reply

* Re: [PATCH v8 7/7] spmi: pmic-arb: Add multi bus support
From: Neil Armstrong @ 2024-04-03  7:37 UTC (permalink / raw)
  To: Abel Vesa, Stephen Boyd, Matthias Brugger, Bjorn Andersson,
	Konrad Dybcio, Dmitry Baryshkov, AngeloGioacchino Del Regno,
	Rob Herring, Krzysztof Kozlowski, Conor Dooley
  Cc: Srini Kandagatla, Johan Hovold, linux-kernel, linux-arm-kernel,
	linux-arm-msm, linux-mediatek, devicetree
In-Reply-To: <20240402-spmi-multi-master-support-v8-7-ce6f2d14a058@linaro.org>

On 02/04/2024 14:07, Abel Vesa wrote:
> Starting with HW version 7, there are actually two separate buses
> (with two separate sets of wires). So add support for the second bus.
> The first platform that needs this support for the second bus is the
> Qualcomm X1 Elite, so add the compatible for it as well.
> 
> Signed-off-by: Abel Vesa <abel.vesa@linaro.org>
> ---
>   drivers/spmi/spmi-pmic-arb.c | 138 +++++++++++++++++++++++++++++++++++++------
>   1 file changed, 120 insertions(+), 18 deletions(-)
> 
> diff --git a/drivers/spmi/spmi-pmic-arb.c b/drivers/spmi/spmi-pmic-arb.c
> index 3db622ed80de..52b9e275a7b2 100644
> --- a/drivers/spmi/spmi-pmic-arb.c
> +++ b/drivers/spmi/spmi-pmic-arb.c
> @@ -13,6 +13,7 @@
>   #include <linux/kernel.h>
>   #include <linux/module.h>
>   #include <linux/of.h>
> +#include <linux/of_address.h>
>   #include <linux/of_irq.h>
>   #include <linux/platform_device.h>
>   #include <linux/slab.h>
> @@ -95,6 +96,8 @@ enum pmic_arb_channel {
>   	PMIC_ARB_CHANNEL_OBS,
>   };
>   
> +#define PMIC_ARB_MAX_BUSES		2
> +
>   /* Maximum number of support PMIC peripherals */
>   #define PMIC_ARB_MAX_PERIPHS		512
>   #define PMIC_ARB_MAX_PERIPHS_V7		1024
> @@ -148,6 +151,7 @@ struct spmi_pmic_arb;
>    * @min_apid:		minimum APID (used for bounding IRQ search)
>    * @max_apid:		maximum APID
>    * @irq:		PMIC ARB interrupt.
> + * @id:			unique ID of the bus
>    */
>   struct spmi_pmic_arb_bus {
>   	struct spmi_pmic_arb	*pmic_arb;
> @@ -165,6 +169,7 @@ struct spmi_pmic_arb_bus {
>   	u16			min_apid;
>   	u16			max_apid;
>   	int			irq;
> +	u8			id;
>   };
>   
>   /**
> @@ -179,7 +184,8 @@ struct spmi_pmic_arb_bus {
>    * @ee:			the current Execution Environment
>    * @ver_ops:		version dependent operations.
>    * @max_periphs:	Number of elements in apid_data[]
> - * @bus:		per arbiter bus instance
> + * @buses:		per arbiter buses instances
> + * @buses_available:	number of buses registered
>    */
>   struct spmi_pmic_arb {
>   	void __iomem		*rd_base;
> @@ -191,7 +197,8 @@ struct spmi_pmic_arb {
>   	u8			ee;
>   	const struct pmic_arb_ver_ops *ver_ops;
>   	int			max_periphs;
> -	struct spmi_pmic_arb_bus *bus;
> +	struct spmi_pmic_arb_bus *buses[PMIC_ARB_MAX_BUSES];
> +	int			buses_available;
>   };
>   
>   /**
> @@ -220,7 +227,7 @@ struct spmi_pmic_arb {
>   struct pmic_arb_ver_ops {
>   	const char *ver_str;
>   	int (*get_core_resources)(struct platform_device *pdev, void __iomem *core);
> -	int (*init_apid)(struct spmi_pmic_arb_bus *bus);
> +	int (*init_apid)(struct spmi_pmic_arb_bus *bus, int index);
>   	int (*ppid_to_apid)(struct spmi_pmic_arb_bus *bus, u16 ppid);
>   	/* spmi commands (read_cmd, write_cmd, cmd) functionality */
>   	int (*offset)(struct spmi_pmic_arb_bus *bus, u8 sid, u16 addr,
> @@ -309,8 +316,8 @@ static int pmic_arb_wait_for_done(struct spmi_controller *ctrl,
>   			}
>   
>   			if (status & PMIC_ARB_STATUS_FAILURE) {
> -				dev_err(&ctrl->dev, "%s: %#x %#x: transaction failed (%#x)\n",
> -					__func__, sid, addr, status);
> +				dev_err(&ctrl->dev, "%s: %#x %#x: transaction failed (%#x) reg: 0x%x\n",
> +					__func__, sid, addr, status, offset);
>   				WARN_ON(1);
>   				return -EIO;
>   			}
> @@ -326,8 +333,8 @@ static int pmic_arb_wait_for_done(struct spmi_controller *ctrl,
>   		udelay(1);
>   	}
>   
> -	dev_err(&ctrl->dev, "%s: %#x %#x: timeout, status %#x\n",
> -		__func__, sid, addr, status);
> +	dev_err(&ctrl->dev, "%s: %#x %#x %#x: timeout, status %#x\n",
> +		__func__, bus->id, sid, addr, status);
>   	return -ETIMEDOUT;
>   }
>   
> @@ -1006,11 +1013,17 @@ static int pmic_arb_get_core_resources_v1(struct platform_device *pdev,
>   	return 0;
>   }
>   
> -static int pmic_arb_init_apid_v1(struct spmi_pmic_arb_bus *bus)
> +static int pmic_arb_init_apid_v1(struct spmi_pmic_arb_bus *bus, int index)
>   {
>   	struct spmi_pmic_arb *pmic_arb = bus->pmic_arb;
>   	u32 *mapping_table;
>   
> +	if (index) {
> +		dev_err(&bus->spmic->dev, "Unsupported buses count %d detected\n",
> +			index);
> +		return -EINVAL;
> +	}
> +
>   	mapping_table = devm_kcalloc(&bus->spmic->dev, pmic_arb->max_periphs,
>   				     sizeof(*mapping_table), GFP_KERNEL);
>   	if (!mapping_table)
> @@ -1253,11 +1266,17 @@ static int pmic_arb_offset_v2(struct spmi_pmic_arb_bus *bus, u8 sid, u16 addr,
>   	return 0x1000 * pmic_arb->ee + 0x8000 * apid;
>   }
>   
> -static int pmic_arb_init_apid_v5(struct spmi_pmic_arb_bus *bus)
> +static int pmic_arb_init_apid_v5(struct spmi_pmic_arb_bus *bus, int index)
>   {
>   	struct spmi_pmic_arb *pmic_arb = bus->pmic_arb;
>   	int ret;
>   
> +	if (index) {
> +		dev_err(&bus->spmic->dev, "Unsupported buses count %d detected\n",
> +			index);
> +		return -EINVAL;
> +	}
> +
>   	bus->base_apid = 0;
>   	bus->apid_count = readl_relaxed(pmic_arb->core + PMIC_ARB_FEATURES) &
>   					PMIC_ARB_FEATURES_PERIPH_MASK;
> @@ -1329,6 +1348,50 @@ static int pmic_arb_get_core_resources_v7(struct platform_device *pdev,
>   	return pmic_arb_get_obsrvr_chnls_v2(pdev);
>   }
>   
> +/*
> + * Only v7 supports 2 buses. Each bus will get a different apid count, read
> + * from different registers.
> + */
> +static int pmic_arb_init_apid_v7(struct spmi_pmic_arb_bus *bus, int index)
> +{
> +	struct spmi_pmic_arb *pmic_arb = bus->pmic_arb;
> +	int ret;
> +
> +	if (index == 0) {
> +		bus->base_apid = 0;
> +		bus->apid_count = readl_relaxed(pmic_arb->core + PMIC_ARB_FEATURES) &
> +						   PMIC_ARB_FEATURES_PERIPH_MASK;
> +	} else if (index == 1) {
> +		bus->base_apid = readl_relaxed(pmic_arb->core + PMIC_ARB_FEATURES) &
> +						  PMIC_ARB_FEATURES_PERIPH_MASK;
> +		bus->apid_count = readl_relaxed(pmic_arb->core + PMIC_ARB_FEATURES1) &
> +						   PMIC_ARB_FEATURES_PERIPH_MASK;
> +	} else {
> +		dev_err(&bus->spmic->dev, "Unsupported buses count %d detected\n",
> +			bus->id);
> +		return -EINVAL;
> +	}
> +
> +	if (bus->base_apid + bus->apid_count > pmic_arb->max_periphs) {
> +		dev_err(&bus->spmic->dev, "Unsupported APID count %d detected\n",
> +			bus->base_apid + bus->apid_count);
> +		return -EINVAL;
> +	}
> +
> +	ret = pmic_arb_init_apid_min_max(bus);
> +	if (ret)
> +		return ret;
> +
> +	ret = pmic_arb_read_apid_map_v5(bus);
> +	if (ret) {
> +		dev_err(&bus->spmic->dev, "could not read APID->PPID mapping table, rc= %d\n",
> +			ret);
> +		return ret;
> +	}
> +
> +	return 0;
> +}
> +
>   /*
>    * v7 offset per ee and per apid for observer channels and per apid for
>    * read/write channels.
> @@ -1581,7 +1644,7 @@ static const struct pmic_arb_ver_ops pmic_arb_v5 = {
>   static const struct pmic_arb_ver_ops pmic_arb_v7 = {
>   	.ver_str		= "v7",
>   	.get_core_resources	= pmic_arb_get_core_resources_v7,
> -	.init_apid		= pmic_arb_init_apid_v5,
> +	.init_apid		= pmic_arb_init_apid_v7,
>   	.ppid_to_apid		= pmic_arb_ppid_to_apid_v5,
>   	.non_data_cmd		= pmic_arb_non_data_cmd_v2,
>   	.offset			= pmic_arb_offset_v7,
> @@ -1605,6 +1668,7 @@ static int spmi_pmic_arb_bus_init(struct platform_device *pdev,
>   				  struct device_node *node,
>   				  struct spmi_pmic_arb *pmic_arb)
>   {
> +	int bus_index = pmic_arb->buses_available;
>   	struct spmi_pmic_arb_bus *bus;
>   	struct device *dev = &pdev->dev;
>   	struct spmi_controller *ctrl;
> @@ -1623,7 +1687,7 @@ static int spmi_pmic_arb_bus_init(struct platform_device *pdev,
>   
>   	bus = spmi_controller_get_drvdata(ctrl);
>   
> -	pmic_arb->bus = bus;
> +	pmic_arb->buses[bus_index] = bus;
>   
>   	bus->ppid_to_apid = devm_kcalloc(dev, PMIC_ARB_MAX_PPID,
>   					 sizeof(*bus->ppid_to_apid),
> @@ -1666,12 +1730,13 @@ static int spmi_pmic_arb_bus_init(struct platform_device *pdev,
>   	bus->cnfg = cnfg;
>   	bus->irq = irq;
>   	bus->spmic = ctrl;
> +	bus->id = bus_index;
>   
> -	ret = pmic_arb->ver_ops->init_apid(bus);
> +	ret = pmic_arb->ver_ops->init_apid(bus, bus_index);
>   	if (ret)
>   		return ret;
>   
> -	dev_dbg(&pdev->dev, "adding irq domain\n");
> +	dev_dbg(&pdev->dev, "adding irq domain for bus %d\n", bus_index);
>   
>   	bus->domain = irq_domain_add_tree(dev->of_node,
>   					  &pmic_arb_irq_domain_ops, bus);
> @@ -1684,14 +1749,53 @@ static int spmi_pmic_arb_bus_init(struct platform_device *pdev,
>   					 pmic_arb_chained_irq, bus);
>   
>   	ctrl->dev.of_node = node;
> +	dev_set_name(&ctrl->dev, "spmi-%d", bus_index);
>   
>   	ret = devm_spmi_controller_add(dev, ctrl);
>   	if (ret)
>   		return ret;
>   
> +	pmic_arb->buses_available++;
> +
>   	return 0;
>   }
>   
> +static int spmi_pmic_arb_register_buses(struct spmi_pmic_arb *pmic_arb,
> +					struct platform_device *pdev)
> +{
> +	struct device *dev = &pdev->dev;
> +	struct device_node *node = dev->of_node;
> +	struct device_node *child;
> +	int ret;
> +
> +	/* legacy mode doesn't provide child node for the bus */
> +	if (of_device_is_compatible(node, "qcom,spmi-pmic-arb"))
> +		return spmi_pmic_arb_bus_init(pdev, node, pmic_arb);
> +
> +	for_each_available_child_of_node(node, child) {
> +		if (of_node_name_eq(child, "spmi")) {
> +			ret = spmi_pmic_arb_bus_init(pdev, child, pmic_arb);
> +			if (ret)
> +				return ret;
> +		}
> +	}
> +
> +	return ret;
> +}
> +
> +static void spmi_pmic_arb_deregister_buses(struct spmi_pmic_arb *pmic_arb)
> +{
> +	int i;
> +
> +	for (i = 0; i < PMIC_ARB_MAX_BUSES; i++) {
> +		struct spmi_pmic_arb_bus *bus = pmic_arb->buses[i];
> +
> +		irq_set_chained_handler_and_data(bus->irq,
> +						 NULL, NULL);
> +		irq_domain_remove(bus->domain);
> +	}
> +}
> +
>   static int spmi_pmic_arb_probe(struct platform_device *pdev)
>   {
>   	struct spmi_pmic_arb *pmic_arb;
> @@ -1762,21 +1866,19 @@ static int spmi_pmic_arb_probe(struct platform_device *pdev)
>   
>   	pmic_arb->ee = ee;
>   
> -	return spmi_pmic_arb_bus_init(pdev, dev->of_node, pmic_arb);
> +	return spmi_pmic_arb_register_buses(pmic_arb, pdev);
>   }
>   
>   static void spmi_pmic_arb_remove(struct platform_device *pdev)
>   {
>   	struct spmi_pmic_arb *pmic_arb = platform_get_drvdata(pdev);
> -	struct spmi_pmic_arb_bus *bus = pmic_arb->bus;
>   
> -	irq_set_chained_handler_and_data(bus->irq,
> -					 NULL, NULL);
> -	irq_domain_remove(bus->domain);
> +	spmi_pmic_arb_deregister_buses(pmic_arb);
>   }
>   
>   static const struct of_device_id spmi_pmic_arb_match_table[] = {
>   	{ .compatible = "qcom,spmi-pmic-arb", },
> +	{ .compatible = "qcom,x1e80100-spmi-pmic-arb", },
>   	{},
>   };
>   MODULE_DEVICE_TABLE(of, spmi_pmic_arb_match_table);
> 

Reviewed-by: Neil Armstrong <neil.armstrong@linaro.org>

_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

^ permalink raw reply

* Re: [PATCH v8 6/7] spmi: pmic-arb: Register controller for bus instead of arbiter
From: Neil Armstrong @ 2024-04-03  7:37 UTC (permalink / raw)
  To: Abel Vesa, Stephen Boyd, Matthias Brugger, Bjorn Andersson,
	Konrad Dybcio, Dmitry Baryshkov, AngeloGioacchino Del Regno,
	Rob Herring, Krzysztof Kozlowski, Conor Dooley
  Cc: Srini Kandagatla, Johan Hovold, linux-kernel, linux-arm-kernel,
	linux-arm-msm, linux-mediatek, devicetree
In-Reply-To: <20240402-spmi-multi-master-support-v8-6-ce6f2d14a058@linaro.org>

On 02/04/2024 14:07, Abel Vesa wrote:
> Introduce the bus object in order to decouple the resources
> that are bus specific from the arbiter. This way the SPMI controller
> is registered with the generic framework at a bus level rather than
> arbiter. This is needed in order to prepare for multi bus support.
> 
> Signed-off-by: Abel Vesa <abel.vesa@linaro.org>
> ---
>   drivers/spmi/spmi-pmic-arb.c | 647 ++++++++++++++++++++++++-------------------
>   1 file changed, 369 insertions(+), 278 deletions(-)
> 
> diff --git a/drivers/spmi/spmi-pmic-arb.c b/drivers/spmi/spmi-pmic-arb.c
> index ff777b4a6f33..3db622ed80de 100644
> --- a/drivers/spmi/spmi-pmic-arb.c
> +++ b/drivers/spmi/spmi-pmic-arb.c
> @@ -13,6 +13,7 @@
>   #include <linux/kernel.h>
>   #include <linux/module.h>
>   #include <linux/of.h>
> +#include <linux/of_irq.h>
>   #include <linux/platform_device.h>
>   #include <linux/slab.h>
>   #include <linux/spmi.h>
> @@ -125,61 +126,72 @@ struct apid_data {
>   	u8		irq_ee;
>   };
>   
> +struct spmi_pmic_arb;
> +
>   /**
> - * struct spmi_pmic_arb - SPMI PMIC Arbiter object
> + * struct spmi_pmic_arb_bus - SPMI PMIC Arbiter Bus object
>    *
> - * @rd_base:		on v1 "core", on v2 "observer" register base off DT.
> - * @wr_base:		on v1 "core", on v2 "chnls"    register base off DT.
> + * @pmic_arb:		the SPMI PMIC Arbiter the bus belongs to.
> + * @domain:		irq domain object for PMIC IRQ domain
>    * @intr:		address of the SPMI interrupt control registers.
>    * @cnfg:		address of the PMIC Arbiter configuration registers.
> - * @core:		core register base for v2 and above only (see above)
> - * @core_size:		core register base size
> - * @lock:		lock to synchronize accesses.
> - * @channel:		execution environment channel to use for accesses.
> - * @irq:		PMIC ARB interrupt.
> - * @ee:			the current Execution Environment
> - * @bus_instance:	on v7: 0 = primary SPMI bus, 1 = secondary SPMI bus
> - * @min_apid:		minimum APID (used for bounding IRQ search)
> - * @max_apid:		maximum APID
> + * @spmic:		spmi controller registered for this bus
>    * @base_apid:		on v7: minimum APID associated with the particular SPMI
>    *			bus instance
>    * @apid_count:		on v5 and v7: number of APIDs associated with the
>    *			particular SPMI bus instance
>    * @mapping_table:	in-memory copy of PPID -> APID mapping table.
>    * @mapping_table_valid:bitmap containing valid-only periphs
> - * @domain:		irq domain object for PMIC IRQ domain
> - * @spmic:		SPMI controller object
> - * @ver_ops:		version dependent operations.
>    * @ppid_to_apid:	in-memory copy of PPID -> APID mapping table.
>    * @last_apid:		Highest value APID in use
>    * @apid_data:		Table of data for all APIDs
> + * @min_apid:		minimum APID (used for bounding IRQ search)
> + * @max_apid:		maximum APID
> + * @irq:		PMIC ARB interrupt.
> + */
> +struct spmi_pmic_arb_bus {
> +	struct spmi_pmic_arb	*pmic_arb;
> +	struct irq_domain	*domain;
> +	void __iomem		*intr;
> +	void __iomem		*cnfg;
> +	struct spmi_controller	*spmic;
> +	u16			base_apid;
> +	int			apid_count;
> +	u32			*mapping_table;
> +	DECLARE_BITMAP(mapping_table_valid, PMIC_ARB_MAX_PERIPHS);
> +	u16			*ppid_to_apid;
> +	u16			last_apid;
> +	struct apid_data	*apid_data;
> +	u16			min_apid;
> +	u16			max_apid;
> +	int			irq;
> +};
> +
> +/**
> + * struct spmi_pmic_arb - SPMI PMIC Arbiter object
> + *
> + * @rd_base:		on v1 "core", on v2 "observer" register base off DT.
> + * @wr_base:		on v1 "core", on v2 "chnls"    register base off DT.
> + * @core:		core register base for v2 and above only (see above)
> + * @core_size:		core register base size
> + * @lock:		lock to synchronize accesses.
> + * @channel:		execution environment channel to use for accesses.
> + * @ee:			the current Execution Environment
> + * @ver_ops:		version dependent operations.
>    * @max_periphs:	Number of elements in apid_data[]
> + * @bus:		per arbiter bus instance
>    */
>   struct spmi_pmic_arb {
>   	void __iomem		*rd_base;
>   	void __iomem		*wr_base;
> -	void __iomem		*intr;
> -	void __iomem		*cnfg;
>   	void __iomem		*core;
>   	resource_size_t		core_size;
>   	raw_spinlock_t		lock;
>   	u8			channel;
> -	int			irq;
>   	u8			ee;
> -	u32			bus_instance;
> -	u16			min_apid;
> -	u16			max_apid;
> -	u16			base_apid;
> -	int			apid_count;
> -	u32			*mapping_table;
> -	DECLARE_BITMAP(mapping_table_valid, PMIC_ARB_MAX_PERIPHS);
> -	struct irq_domain	*domain;
> -	struct spmi_controller	*spmic;
>   	const struct pmic_arb_ver_ops *ver_ops;
> -	u16			*ppid_to_apid;
> -	u16			last_apid;
> -	struct apid_data	*apid_data;
>   	int			max_periphs;
> +	struct spmi_pmic_arb_bus *bus;
>   };
>   
>   /**
> @@ -208,21 +220,21 @@ struct spmi_pmic_arb {
>   struct pmic_arb_ver_ops {
>   	const char *ver_str;
>   	int (*get_core_resources)(struct platform_device *pdev, void __iomem *core);
> -	int (*init_apid)(struct spmi_pmic_arb *pmic_arb);
> -	int (*ppid_to_apid)(struct spmi_pmic_arb *pmic_arb, u16 ppid);
> +	int (*init_apid)(struct spmi_pmic_arb_bus *bus);
> +	int (*ppid_to_apid)(struct spmi_pmic_arb_bus *bus, u16 ppid);
>   	/* spmi commands (read_cmd, write_cmd, cmd) functionality */
> -	int (*offset)(struct spmi_pmic_arb *pmic_arb, u8 sid, u16 addr,
> -			enum pmic_arb_channel ch_type);
> +	int (*offset)(struct spmi_pmic_arb_bus *bus, u8 sid, u16 addr,
> +		      enum pmic_arb_channel ch_type);
>   	u32 (*fmt_cmd)(u8 opc, u8 sid, u16 addr, u8 bc);
>   	int (*non_data_cmd)(struct spmi_controller *ctrl, u8 opc, u8 sid);
>   	/* Interrupts controller functionality (offset of PIC registers) */
> -	void __iomem *(*owner_acc_status)(struct spmi_pmic_arb *pmic_arb, u8 m,
> +	void __iomem *(*owner_acc_status)(struct spmi_pmic_arb_bus *bus, u8 m,
>   					  u16 n);
> -	void __iomem *(*acc_enable)(struct spmi_pmic_arb *pmic_arb, u16 n);
> -	void __iomem *(*irq_status)(struct spmi_pmic_arb *pmic_arb, u16 n);
> -	void __iomem *(*irq_clear)(struct spmi_pmic_arb *pmic_arb, u16 n);
> +	void __iomem *(*acc_enable)(struct spmi_pmic_arb_bus *bus, u16 n);
> +	void __iomem *(*irq_status)(struct spmi_pmic_arb_bus *bus, u16 n);
> +	void __iomem *(*irq_clear)(struct spmi_pmic_arb_bus *bus, u16 n);
>   	u32 (*apid_map_offset)(u16 n);
> -	void __iomem *(*apid_owner)(struct spmi_pmic_arb *pmic_arb, u16 n);
> +	void __iomem *(*apid_owner)(struct spmi_pmic_arb_bus *bus, u16 n);
>   };
>   
>   static inline void pmic_arb_base_write(struct spmi_pmic_arb *pmic_arb,
> @@ -272,13 +284,14 @@ static int pmic_arb_wait_for_done(struct spmi_controller *ctrl,
>   				  void __iomem *base, u8 sid, u16 addr,
>   				  enum pmic_arb_channel ch_type)
>   {
> -	struct spmi_pmic_arb *pmic_arb = spmi_controller_get_drvdata(ctrl);
> +	struct spmi_pmic_arb_bus *bus = spmi_controller_get_drvdata(ctrl);
> +	struct spmi_pmic_arb *pmic_arb = bus->pmic_arb;
>   	u32 status = 0;
>   	u32 timeout = PMIC_ARB_TIMEOUT_US;
>   	u32 offset;
>   	int rc;
>   
> -	rc = pmic_arb->ver_ops->offset(pmic_arb, sid, addr, ch_type);
> +	rc = pmic_arb->ver_ops->offset(bus, sid, addr, ch_type);
>   	if (rc < 0)
>   		return rc;
>   
> @@ -321,13 +334,14 @@ static int pmic_arb_wait_for_done(struct spmi_controller *ctrl,
>   static int
>   pmic_arb_non_data_cmd_v1(struct spmi_controller *ctrl, u8 opc, u8 sid)
>   {
> -	struct spmi_pmic_arb *pmic_arb = spmi_controller_get_drvdata(ctrl);
> +	struct spmi_pmic_arb_bus *bus = spmi_controller_get_drvdata(ctrl);
> +	struct spmi_pmic_arb *pmic_arb = bus->pmic_arb;
>   	unsigned long flags;
>   	u32 cmd;
>   	int rc;
>   	u32 offset;
>   
> -	rc = pmic_arb->ver_ops->offset(pmic_arb, sid, 0, PMIC_ARB_CHANNEL_RW);
> +	rc = pmic_arb->ver_ops->offset(bus, sid, 0, PMIC_ARB_CHANNEL_RW);
>   	if (rc < 0)
>   		return rc;
>   
> @@ -363,20 +377,21 @@ static int pmic_arb_cmd(struct spmi_controller *ctrl, u8 opc, u8 sid)
>   	return pmic_arb->ver_ops->non_data_cmd(ctrl, opc, sid);
>   }
>   
> -static int pmic_arb_fmt_read_cmd(struct spmi_pmic_arb *pmic_arb, u8 opc, u8 sid,
> +static int pmic_arb_fmt_read_cmd(struct spmi_pmic_arb_bus *bus, u8 opc, u8 sid,
>   				 u16 addr, size_t len, u32 *cmd, u32 *offset)
>   {
> +	struct spmi_pmic_arb *pmic_arb = bus->pmic_arb;
>   	u8 bc = len - 1;
>   	int rc;
>   
> -	rc = pmic_arb->ver_ops->offset(pmic_arb, sid, addr,
> +	rc = pmic_arb->ver_ops->offset(bus, sid, addr,
>   				       PMIC_ARB_CHANNEL_OBS);
>   	if (rc < 0)
>   		return rc;
>   
>   	*offset = rc;
>   	if (bc >= PMIC_ARB_MAX_TRANS_BYTES) {
> -		dev_err(&pmic_arb->spmic->dev, "pmic-arb supports 1..%d bytes per trans, but:%zu requested",
> +		dev_err(&bus->spmic->dev, "pmic-arb supports 1..%d bytes per trans, but:%zu requested",
>   			PMIC_ARB_MAX_TRANS_BYTES, len);
>   		return  -EINVAL;
>   	}
> @@ -400,7 +415,8 @@ static int pmic_arb_read_cmd_unlocked(struct spmi_controller *ctrl, u32 cmd,
>   				      u32 offset, u8 sid, u16 addr, u8 *buf,
>   				      size_t len)
>   {
> -	struct spmi_pmic_arb *pmic_arb = spmi_controller_get_drvdata(ctrl);
> +	struct spmi_pmic_arb_bus *bus = spmi_controller_get_drvdata(ctrl);
> +	struct spmi_pmic_arb *pmic_arb = bus->pmic_arb;
>   	u8 bc = len - 1;
>   	int rc;
>   
> @@ -422,12 +438,13 @@ static int pmic_arb_read_cmd_unlocked(struct spmi_controller *ctrl, u32 cmd,
>   static int pmic_arb_read_cmd(struct spmi_controller *ctrl, u8 opc, u8 sid,
>   			     u16 addr, u8 *buf, size_t len)
>   {
> -	struct spmi_pmic_arb *pmic_arb = spmi_controller_get_drvdata(ctrl);
> +	struct spmi_pmic_arb_bus *bus = spmi_controller_get_drvdata(ctrl);
> +	struct spmi_pmic_arb *pmic_arb = bus->pmic_arb;
>   	unsigned long flags;
>   	u32 cmd, offset;
>   	int rc;
>   
> -	rc = pmic_arb_fmt_read_cmd(pmic_arb, opc, sid, addr, len, &cmd,
> +	rc = pmic_arb_fmt_read_cmd(bus, opc, sid, addr, len, &cmd,
>   				   &offset);
>   	if (rc)
>   		return rc;
> @@ -439,21 +456,22 @@ static int pmic_arb_read_cmd(struct spmi_controller *ctrl, u8 opc, u8 sid,
>   	return rc;
>   }
>   
> -static int pmic_arb_fmt_write_cmd(struct spmi_pmic_arb *pmic_arb, u8 opc,
> +static int pmic_arb_fmt_write_cmd(struct spmi_pmic_arb_bus *bus, u8 opc,
>   				  u8 sid, u16 addr, size_t len, u32 *cmd,
>   				  u32 *offset)
>   {
> +	struct spmi_pmic_arb *pmic_arb = bus->pmic_arb;
>   	u8 bc = len - 1;
>   	int rc;
>   
> -	rc = pmic_arb->ver_ops->offset(pmic_arb, sid, addr,
> +	rc = pmic_arb->ver_ops->offset(bus, sid, addr,
>   					PMIC_ARB_CHANNEL_RW);
>   	if (rc < 0)
>   		return rc;
>   
>   	*offset = rc;
>   	if (bc >= PMIC_ARB_MAX_TRANS_BYTES) {
> -		dev_err(&pmic_arb->spmic->dev, "pmic-arb supports 1..%d bytes per trans, but:%zu requested",
> +		dev_err(&bus->spmic->dev, "pmic-arb supports 1..%d bytes per trans, but:%zu requested",
>   			PMIC_ARB_MAX_TRANS_BYTES, len);
>   		return  -EINVAL;
>   	}
> @@ -479,7 +497,8 @@ static int pmic_arb_write_cmd_unlocked(struct spmi_controller *ctrl, u32 cmd,
>   				      u32 offset, u8 sid, u16 addr,
>   				      const u8 *buf, size_t len)
>   {
> -	struct spmi_pmic_arb *pmic_arb = spmi_controller_get_drvdata(ctrl);
> +	struct spmi_pmic_arb_bus *bus = spmi_controller_get_drvdata(ctrl);
> +	struct spmi_pmic_arb *pmic_arb = bus->pmic_arb;
>   	u8 bc = len - 1;
>   
>   	/* Write data to FIFOs */
> @@ -498,12 +517,13 @@ static int pmic_arb_write_cmd_unlocked(struct spmi_controller *ctrl, u32 cmd,
>   static int pmic_arb_write_cmd(struct spmi_controller *ctrl, u8 opc, u8 sid,
>   			      u16 addr, const u8 *buf, size_t len)
>   {
> -	struct spmi_pmic_arb *pmic_arb = spmi_controller_get_drvdata(ctrl);
> +	struct spmi_pmic_arb_bus *bus = spmi_controller_get_drvdata(ctrl);
> +	struct spmi_pmic_arb *pmic_arb = bus->pmic_arb;
>   	unsigned long flags;
>   	u32 cmd, offset;
>   	int rc;
>   
> -	rc = pmic_arb_fmt_write_cmd(pmic_arb, opc, sid, addr, len, &cmd,
> +	rc = pmic_arb_fmt_write_cmd(bus, opc, sid, addr, len, &cmd,
>   				    &offset);
>   	if (rc)
>   		return rc;
> @@ -519,18 +539,19 @@ static int pmic_arb_write_cmd(struct spmi_controller *ctrl, u8 opc, u8 sid,
>   static int pmic_arb_masked_write(struct spmi_controller *ctrl, u8 sid, u16 addr,
>   				 const u8 *buf, const u8 *mask, size_t len)
>   {
> -	struct spmi_pmic_arb *pmic_arb = spmi_controller_get_drvdata(ctrl);
> +	struct spmi_pmic_arb_bus *bus = spmi_controller_get_drvdata(ctrl);
> +	struct spmi_pmic_arb *pmic_arb = bus->pmic_arb;
>   	u32 read_cmd, read_offset, write_cmd, write_offset;
>   	u8 temp[PMIC_ARB_MAX_TRANS_BYTES];
>   	unsigned long flags;
>   	int rc, i;
>   
> -	rc = pmic_arb_fmt_read_cmd(pmic_arb, SPMI_CMD_EXT_READL, sid, addr, len,
> +	rc = pmic_arb_fmt_read_cmd(bus, SPMI_CMD_EXT_READL, sid, addr, len,
>   				   &read_cmd, &read_offset);
>   	if (rc)
>   		return rc;
>   
> -	rc = pmic_arb_fmt_write_cmd(pmic_arb, SPMI_CMD_EXT_WRITEL, sid, addr,
> +	rc = pmic_arb_fmt_write_cmd(bus, SPMI_CMD_EXT_WRITEL, sid, addr,
>   				    len, &write_cmd, &write_offset);
>   	if (rc)
>   		return rc;
> @@ -573,25 +594,25 @@ struct spmi_pmic_arb_qpnpint_type {
>   static void qpnpint_spmi_write(struct irq_data *d, u8 reg, void *buf,
>   			       size_t len)
>   {
> -	struct spmi_pmic_arb *pmic_arb = irq_data_get_irq_chip_data(d);
> +	struct spmi_pmic_arb_bus *bus = irq_data_get_irq_chip_data(d);
>   	u8 sid = hwirq_to_sid(d->hwirq);
>   	u8 per = hwirq_to_per(d->hwirq);
>   
> -	if (pmic_arb_write_cmd(pmic_arb->spmic, SPMI_CMD_EXT_WRITEL, sid,
> +	if (pmic_arb_write_cmd(bus->spmic, SPMI_CMD_EXT_WRITEL, sid,
>   			       (per << 8) + reg, buf, len))
> -		dev_err_ratelimited(&pmic_arb->spmic->dev, "failed irqchip transaction on %x\n",
> +		dev_err_ratelimited(&bus->spmic->dev, "failed irqchip transaction on %x\n",
>   				    d->irq);
>   }
>   
>   static void qpnpint_spmi_read(struct irq_data *d, u8 reg, void *buf, size_t len)
>   {
> -	struct spmi_pmic_arb *pmic_arb = irq_data_get_irq_chip_data(d);
> +	struct spmi_pmic_arb_bus *bus = irq_data_get_irq_chip_data(d);
>   	u8 sid = hwirq_to_sid(d->hwirq);
>   	u8 per = hwirq_to_per(d->hwirq);
>   
> -	if (pmic_arb_read_cmd(pmic_arb->spmic, SPMI_CMD_EXT_READL, sid,
> +	if (pmic_arb_read_cmd(bus->spmic, SPMI_CMD_EXT_READL, sid,
>   			      (per << 8) + reg, buf, len))
> -		dev_err_ratelimited(&pmic_arb->spmic->dev, "failed irqchip transaction on %x\n",
> +		dev_err_ratelimited(&bus->spmic->dev, "failed irqchip transaction on %x\n",
>   				    d->irq);
>   }
>   
> @@ -599,47 +620,49 @@ static int qpnpint_spmi_masked_write(struct irq_data *d, u8 reg,
>   				     const void *buf, const void *mask,
>   				     size_t len)
>   {
> -	struct spmi_pmic_arb *pmic_arb = irq_data_get_irq_chip_data(d);
> +	struct spmi_pmic_arb_bus *bus = irq_data_get_irq_chip_data(d);
>   	u8 sid = hwirq_to_sid(d->hwirq);
>   	u8 per = hwirq_to_per(d->hwirq);
>   	int rc;
>   
> -	rc = pmic_arb_masked_write(pmic_arb->spmic, sid, (per << 8) + reg, buf,
> +	rc = pmic_arb_masked_write(bus->spmic, sid, (per << 8) + reg, buf,
>   				   mask, len);
>   	if (rc)
> -		dev_err_ratelimited(&pmic_arb->spmic->dev, "failed irqchip transaction on %x rc=%d\n",
> +		dev_err_ratelimited(&bus->spmic->dev, "failed irqchip transaction on %x rc=%d\n",
>   				    d->irq, rc);
>   	return rc;
>   }
>   
> -static void cleanup_irq(struct spmi_pmic_arb *pmic_arb, u16 apid, int id)
> +static void cleanup_irq(struct spmi_pmic_arb_bus *bus, u16 apid, int id)
>   {
> -	u16 ppid = pmic_arb->apid_data[apid].ppid;
> +	struct spmi_pmic_arb *pmic_arb = bus->pmic_arb;
> +	u16 ppid = bus->apid_data[apid].ppid;
>   	u8 sid = ppid >> 8;
>   	u8 per = ppid & 0xFF;
>   	u8 irq_mask = BIT(id);
>   
> -	dev_err_ratelimited(&pmic_arb->spmic->dev, "%s apid=%d sid=0x%x per=0x%x irq=%d\n",
> -			__func__, apid, sid, per, id);
> -	writel_relaxed(irq_mask, pmic_arb->ver_ops->irq_clear(pmic_arb, apid));
> +	dev_err_ratelimited(&bus->spmic->dev, "%s apid=%d sid=0x%x per=0x%x irq=%d\n",
> +			    __func__, apid, sid, per, id);
> +	writel_relaxed(irq_mask, pmic_arb->ver_ops->irq_clear(bus, apid));
>   }
>   
> -static int periph_interrupt(struct spmi_pmic_arb *pmic_arb, u16 apid)
> +static int periph_interrupt(struct spmi_pmic_arb_bus *bus, u16 apid)
>   {
> +	struct spmi_pmic_arb *pmic_arb = bus->pmic_arb;
>   	unsigned int irq;
>   	u32 status, id;
>   	int handled = 0;
> -	u8 sid = (pmic_arb->apid_data[apid].ppid >> 8) & 0xF;
> -	u8 per = pmic_arb->apid_data[apid].ppid & 0xFF;
> +	u8 sid = (bus->apid_data[apid].ppid >> 8) & 0xF;
> +	u8 per = bus->apid_data[apid].ppid & 0xFF;
>   
> -	status = readl_relaxed(pmic_arb->ver_ops->irq_status(pmic_arb, apid));
> +	status = readl_relaxed(pmic_arb->ver_ops->irq_status(bus, apid));
>   	while (status) {
>   		id = ffs(status) - 1;
>   		status &= ~BIT(id);
> -		irq = irq_find_mapping(pmic_arb->domain,
> -					spec_to_hwirq(sid, per, id, apid));
> +		irq = irq_find_mapping(bus->domain,
> +				       spec_to_hwirq(sid, per, id, apid));
>   		if (irq == 0) {
> -			cleanup_irq(pmic_arb, apid, id);
> +			cleanup_irq(bus, apid, id);
>   			continue;
>   		}
>   		generic_handle_irq(irq);
> @@ -651,16 +674,17 @@ static int periph_interrupt(struct spmi_pmic_arb *pmic_arb, u16 apid)
>   
>   static void pmic_arb_chained_irq(struct irq_desc *desc)
>   {
> -	struct spmi_pmic_arb *pmic_arb = irq_desc_get_handler_data(desc);
> +	struct spmi_pmic_arb_bus *bus = irq_desc_get_handler_data(desc);
> +	struct spmi_pmic_arb *pmic_arb = bus->pmic_arb;
>   	const struct pmic_arb_ver_ops *ver_ops = pmic_arb->ver_ops;
>   	struct irq_chip *chip = irq_desc_get_chip(desc);
> -	int first = pmic_arb->min_apid;
> -	int last = pmic_arb->max_apid;
> +	int first = bus->min_apid;
> +	int last = bus->max_apid;
>   	/*
>   	 * acc_offset will be non-zero for the secondary SPMI bus instance on
>   	 * v7 controllers.
>   	 */
> -	int acc_offset = pmic_arb->base_apid >> 5;
> +	int acc_offset = bus->base_apid >> 5;
>   	u8 ee = pmic_arb->ee;
>   	u32 status, enable, handled = 0;
>   	int i, id, apid;
> @@ -671,7 +695,7 @@ static void pmic_arb_chained_irq(struct irq_desc *desc)
>   	chained_irq_enter(chip, desc);
>   
>   	for (i = first >> 5; i <= last >> 5; ++i) {
> -		status = readl_relaxed(ver_ops->owner_acc_status(pmic_arb, ee, i - acc_offset));
> +		status = readl_relaxed(ver_ops->owner_acc_status(bus, ee, i - acc_offset));
>   		if (status)
>   			acc_valid = true;
>   
> @@ -685,9 +709,9 @@ static void pmic_arb_chained_irq(struct irq_desc *desc)
>   				continue;
>   			}
>   			enable = readl_relaxed(
> -					ver_ops->acc_enable(pmic_arb, apid));
> +					ver_ops->acc_enable(bus, apid));
>   			if (enable & SPMI_PIC_ACC_ENABLE_BIT)
> -				if (periph_interrupt(pmic_arb, apid) != 0)
> +				if (periph_interrupt(bus, apid) != 0)
>   					handled++;
>   		}
>   	}
> @@ -696,19 +720,19 @@ static void pmic_arb_chained_irq(struct irq_desc *desc)
>   	if (!acc_valid) {
>   		for (i = first; i <= last; i++) {
>   			/* skip if APPS is not irq owner */
> -			if (pmic_arb->apid_data[i].irq_ee != pmic_arb->ee)
> +			if (bus->apid_data[i].irq_ee != pmic_arb->ee)
>   				continue;
>   
>   			irq_status = readl_relaxed(
> -					     ver_ops->irq_status(pmic_arb, i));
> +					     ver_ops->irq_status(bus, i));
>   			if (irq_status) {
>   				enable = readl_relaxed(
> -					     ver_ops->acc_enable(pmic_arb, i));
> +					     ver_ops->acc_enable(bus, i));
>   				if (enable & SPMI_PIC_ACC_ENABLE_BIT) {
> -					dev_dbg(&pmic_arb->spmic->dev,
> +					dev_dbg(&bus->spmic->dev,
>   						"Dispatching IRQ for apid=%d status=%x\n",
>   						i, irq_status);
> -					if (periph_interrupt(pmic_arb, i) != 0)
> +					if (periph_interrupt(bus, i) != 0)
>   						handled++;
>   				}
>   			}
> @@ -723,12 +747,13 @@ static void pmic_arb_chained_irq(struct irq_desc *desc)
>   
>   static void qpnpint_irq_ack(struct irq_data *d)
>   {
> -	struct spmi_pmic_arb *pmic_arb = irq_data_get_irq_chip_data(d);
> +	struct spmi_pmic_arb_bus *bus = irq_data_get_irq_chip_data(d);
> +	struct spmi_pmic_arb *pmic_arb = bus->pmic_arb;
>   	u8 irq = hwirq_to_irq(d->hwirq);
>   	u16 apid = hwirq_to_apid(d->hwirq);
>   	u8 data;
>   
> -	writel_relaxed(BIT(irq), pmic_arb->ver_ops->irq_clear(pmic_arb, apid));
> +	writel_relaxed(BIT(irq), pmic_arb->ver_ops->irq_clear(bus, apid));
>   
>   	data = BIT(irq);
>   	qpnpint_spmi_write(d, QPNPINT_REG_LATCHED_CLR, &data, 1);
> @@ -744,14 +769,15 @@ static void qpnpint_irq_mask(struct irq_data *d)
>   
>   static void qpnpint_irq_unmask(struct irq_data *d)
>   {
> -	struct spmi_pmic_arb *pmic_arb = irq_data_get_irq_chip_data(d);
> +	struct spmi_pmic_arb_bus *bus = irq_data_get_irq_chip_data(d);
> +	struct spmi_pmic_arb *pmic_arb = bus->pmic_arb;
>   	const struct pmic_arb_ver_ops *ver_ops = pmic_arb->ver_ops;
>   	u8 irq = hwirq_to_irq(d->hwirq);
>   	u16 apid = hwirq_to_apid(d->hwirq);
>   	u8 buf[2];
>   
>   	writel_relaxed(SPMI_PIC_ACC_ENABLE_BIT,
> -			ver_ops->acc_enable(pmic_arb, apid));
> +			ver_ops->acc_enable(bus, apid));
>   
>   	qpnpint_spmi_read(d, QPNPINT_REG_EN_SET, &buf[0], 1);
>   	if (!(buf[0] & BIT(irq))) {
> @@ -808,9 +834,9 @@ static int qpnpint_irq_set_type(struct irq_data *d, unsigned int flow_type)
>   
>   static int qpnpint_irq_set_wake(struct irq_data *d, unsigned int on)
>   {
> -	struct spmi_pmic_arb *pmic_arb = irq_data_get_irq_chip_data(d);
> +	struct spmi_pmic_arb_bus *bus = irq_data_get_irq_chip_data(d);
>   
> -	return irq_set_irq_wake(pmic_arb->irq, on);
> +	return irq_set_irq_wake(bus->irq, on);
>   }
>   
>   static int qpnpint_get_irqchip_state(struct irq_data *d,
> @@ -832,17 +858,18 @@ static int qpnpint_get_irqchip_state(struct irq_data *d,
>   static int qpnpint_irq_domain_activate(struct irq_domain *domain,
>   				       struct irq_data *d, bool reserve)
>   {
> -	struct spmi_pmic_arb *pmic_arb = irq_data_get_irq_chip_data(d);
> +	struct spmi_pmic_arb_bus *bus = irq_data_get_irq_chip_data(d);
> +	struct spmi_pmic_arb *pmic_arb = bus->pmic_arb;
>   	u16 periph = hwirq_to_per(d->hwirq);
>   	u16 apid = hwirq_to_apid(d->hwirq);
>   	u16 sid = hwirq_to_sid(d->hwirq);
>   	u16 irq = hwirq_to_irq(d->hwirq);
>   	u8 buf;
>   
> -	if (pmic_arb->apid_data[apid].irq_ee != pmic_arb->ee) {
> -		dev_err(&pmic_arb->spmic->dev, "failed to xlate sid = %#x, periph = %#x, irq = %u: ee=%u but owner=%u\n",
> +	if (bus->apid_data[apid].irq_ee != pmic_arb->ee) {
> +		dev_err(&bus->spmic->dev, "failed to xlate sid = %#x, periph = %#x, irq = %u: ee=%u but owner=%u\n",
>   			sid, periph, irq, pmic_arb->ee,
> -			pmic_arb->apid_data[apid].irq_ee);
> +			bus->apid_data[apid].irq_ee);
>   		return -ENODEV;
>   	}
>   
> @@ -869,15 +896,16 @@ static int qpnpint_irq_domain_translate(struct irq_domain *d,
>   					unsigned long *out_hwirq,
>   					unsigned int *out_type)
>   {
> -	struct spmi_pmic_arb *pmic_arb = d->host_data;
> +	struct spmi_pmic_arb_bus *bus = d->host_data;
> +	struct spmi_pmic_arb *pmic_arb = bus->pmic_arb;
>   	u32 *intspec = fwspec->param;
>   	u16 apid, ppid;
>   	int rc;
>   
> -	dev_dbg(&pmic_arb->spmic->dev, "intspec[0] 0x%1x intspec[1] 0x%02x intspec[2] 0x%02x\n",
> +	dev_dbg(&bus->spmic->dev, "intspec[0] 0x%1x intspec[1] 0x%02x intspec[2] 0x%02x\n",
>   		intspec[0], intspec[1], intspec[2]);
>   
> -	if (irq_domain_get_of_node(d) != pmic_arb->spmic->dev.of_node)
> +	if (irq_domain_get_of_node(d) != bus->spmic->dev.of_node)
>   		return -EINVAL;
>   	if (fwspec->param_count != 4)
>   		return -EINVAL;
> @@ -885,37 +913,37 @@ static int qpnpint_irq_domain_translate(struct irq_domain *d,
>   		return -EINVAL;
>   
>   	ppid = intspec[0] << 8 | intspec[1];
> -	rc = pmic_arb->ver_ops->ppid_to_apid(pmic_arb, ppid);
> +	rc = pmic_arb->ver_ops->ppid_to_apid(bus, ppid);
>   	if (rc < 0) {
> -		dev_err(&pmic_arb->spmic->dev, "failed to xlate sid = %#x, periph = %#x, irq = %u rc = %d\n",
> -		intspec[0], intspec[1], intspec[2], rc);
> +		dev_err(&bus->spmic->dev, "failed to xlate sid = %#x, periph = %#x, irq = %u rc = %d\n",
> +			intspec[0], intspec[1], intspec[2], rc);
>   		return rc;
>   	}
>   
>   	apid = rc;
>   	/* Keep track of {max,min}_apid for bounding search during interrupt */
> -	if (apid > pmic_arb->max_apid)
> -		pmic_arb->max_apid = apid;
> -	if (apid < pmic_arb->min_apid)
> -		pmic_arb->min_apid = apid;
> +	if (apid > bus->max_apid)
> +		bus->max_apid = apid;
> +	if (apid < bus->min_apid)
> +		bus->min_apid = apid;
>   
>   	*out_hwirq = spec_to_hwirq(intspec[0], intspec[1], intspec[2], apid);
>   	*out_type  = intspec[3] & IRQ_TYPE_SENSE_MASK;
>   
> -	dev_dbg(&pmic_arb->spmic->dev, "out_hwirq = %lu\n", *out_hwirq);
> +	dev_dbg(&bus->spmic->dev, "out_hwirq = %lu\n", *out_hwirq);
>   
>   	return 0;
>   }
>   
>   static struct lock_class_key qpnpint_irq_lock_class, qpnpint_irq_request_class;
>   
> -static void qpnpint_irq_domain_map(struct spmi_pmic_arb *pmic_arb,
> +static void qpnpint_irq_domain_map(struct spmi_pmic_arb_bus *bus,
>   				   struct irq_domain *domain, unsigned int virq,
>   				   irq_hw_number_t hwirq, unsigned int type)
>   {
>   	irq_flow_handler_t handler;
>   
> -	dev_dbg(&pmic_arb->spmic->dev, "virq = %u, hwirq = %lu, type = %u\n",
> +	dev_dbg(&bus->spmic->dev, "virq = %u, hwirq = %lu, type = %u\n",
>   		virq, hwirq, type);
>   
>   	if (type & IRQ_TYPE_EDGE_BOTH)
> @@ -926,7 +954,7 @@ static void qpnpint_irq_domain_map(struct spmi_pmic_arb *pmic_arb,
>   
>   	irq_set_lockdep_class(virq, &qpnpint_irq_lock_class,
>   			      &qpnpint_irq_request_class);
> -	irq_domain_set_info(domain, virq, hwirq, &pmic_arb_irqchip, pmic_arb,
> +	irq_domain_set_info(domain, virq, hwirq, &pmic_arb_irqchip, bus,
>   			    handler, NULL, NULL);
>   }
>   
> @@ -934,7 +962,7 @@ static int qpnpint_irq_domain_alloc(struct irq_domain *domain,
>   				    unsigned int virq, unsigned int nr_irqs,
>   				    void *data)
>   {
> -	struct spmi_pmic_arb *pmic_arb = domain->host_data;
> +	struct spmi_pmic_arb_bus *bus = domain->host_data;
>   	struct irq_fwspec *fwspec = data;
>   	irq_hw_number_t hwirq;
>   	unsigned int type;
> @@ -945,20 +973,22 @@ static int qpnpint_irq_domain_alloc(struct irq_domain *domain,
>   		return ret;
>   
>   	for (i = 0; i < nr_irqs; i++)
> -		qpnpint_irq_domain_map(pmic_arb, domain, virq + i, hwirq + i,
> +		qpnpint_irq_domain_map(bus, domain, virq + i, hwirq + i,
>   				       type);
>   
>   	return 0;
>   }
>   
> -static int pmic_arb_init_apid_min_max(struct spmi_pmic_arb *pmic_arb)
> +static int pmic_arb_init_apid_min_max(struct spmi_pmic_arb_bus *bus)
>   {
> +	struct spmi_pmic_arb *pmic_arb = bus->pmic_arb;
> +
>   	/*
>   	 * Initialize max_apid/min_apid to the opposite bounds, during
>   	 * the irq domain translation, we are sure to update these
>   	 */
> -	pmic_arb->max_apid = 0;
> -	pmic_arb->min_apid = pmic_arb->max_periphs - 1;
> +	bus->max_apid = 0;
> +	bus->min_apid = pmic_arb->max_periphs - 1;
>   
>   	return 0;
>   }
> @@ -976,37 +1006,38 @@ static int pmic_arb_get_core_resources_v1(struct platform_device *pdev,
>   	return 0;
>   }
>   
> -static int pmic_arb_init_apid_v1(struct spmi_pmic_arb *pmic_arb)
> +static int pmic_arb_init_apid_v1(struct spmi_pmic_arb_bus *bus)
>   {
> +	struct spmi_pmic_arb *pmic_arb = bus->pmic_arb;
>   	u32 *mapping_table;
>   
> -	mapping_table = devm_kcalloc(&pmic_arb->spmic->dev, pmic_arb->max_periphs,
> +	mapping_table = devm_kcalloc(&bus->spmic->dev, pmic_arb->max_periphs,
>   				     sizeof(*mapping_table), GFP_KERNEL);
>   	if (!mapping_table)
>   		return -ENOMEM;
>   
> -	pmic_arb->mapping_table = mapping_table;
> +	bus->mapping_table = mapping_table;
>   
> -	return pmic_arb_init_apid_min_max(pmic_arb);
> +	return pmic_arb_init_apid_min_max(bus);
>   }
>   
> -static int pmic_arb_ppid_to_apid_v1(struct spmi_pmic_arb *pmic_arb, u16 ppid)
> +static int pmic_arb_ppid_to_apid_v1(struct spmi_pmic_arb_bus *bus, u16 ppid)
>   {
> -	u32 *mapping_table = pmic_arb->mapping_table;
> +	u32 *mapping_table = bus->mapping_table;
>   	int index = 0, i;
>   	u16 apid_valid;
>   	u16 apid;
>   	u32 data;
>   
> -	apid_valid = pmic_arb->ppid_to_apid[ppid];
> +	apid_valid = bus->ppid_to_apid[ppid];
>   	if (apid_valid & PMIC_ARB_APID_VALID) {
>   		apid = apid_valid & ~PMIC_ARB_APID_VALID;
>   		return apid;
>   	}
>   
>   	for (i = 0; i < SPMI_MAPPING_TABLE_TREE_DEPTH; ++i) {
> -		if (!test_and_set_bit(index, pmic_arb->mapping_table_valid))
> -			mapping_table[index] = readl_relaxed(pmic_arb->cnfg +
> +		if (!test_and_set_bit(index, bus->mapping_table_valid))
> +			mapping_table[index] = readl_relaxed(bus->cnfg +
>   						SPMI_MAPPING_TABLE_REG(index));
>   
>   		data = mapping_table[index];
> @@ -1016,9 +1047,9 @@ static int pmic_arb_ppid_to_apid_v1(struct spmi_pmic_arb *pmic_arb, u16 ppid)
>   				index = SPMI_MAPPING_BIT_IS_1_RESULT(data);
>   			} else {
>   				apid = SPMI_MAPPING_BIT_IS_1_RESULT(data);
> -				pmic_arb->ppid_to_apid[ppid]
> +				bus->ppid_to_apid[ppid]
>   					= apid | PMIC_ARB_APID_VALID;
> -				pmic_arb->apid_data[apid].ppid = ppid;
> +				bus->apid_data[apid].ppid = ppid;
>   				return apid;
>   			}
>   		} else {
> @@ -1026,9 +1057,9 @@ static int pmic_arb_ppid_to_apid_v1(struct spmi_pmic_arb *pmic_arb, u16 ppid)
>   				index = SPMI_MAPPING_BIT_IS_0_RESULT(data);
>   			} else {
>   				apid = SPMI_MAPPING_BIT_IS_0_RESULT(data);
> -				pmic_arb->ppid_to_apid[ppid]
> +				bus->ppid_to_apid[ppid]
>   					= apid | PMIC_ARB_APID_VALID;
> -				pmic_arb->apid_data[apid].ppid = ppid;
> +				bus->apid_data[apid].ppid = ppid;
>   				return apid;
>   			}
>   		}
> @@ -1038,24 +1069,26 @@ static int pmic_arb_ppid_to_apid_v1(struct spmi_pmic_arb *pmic_arb, u16 ppid)
>   }
>   
>   /* v1 offset per ee */
> -static int pmic_arb_offset_v1(struct spmi_pmic_arb *pmic_arb, u8 sid, u16 addr,
> -			enum pmic_arb_channel ch_type)
> +static int pmic_arb_offset_v1(struct spmi_pmic_arb_bus *bus, u8 sid, u16 addr,
> +			      enum pmic_arb_channel ch_type)
>   {
> +	struct spmi_pmic_arb *pmic_arb = bus->pmic_arb;
>   	return 0x800 + 0x80 * pmic_arb->channel;
>   }
>   
> -static u16 pmic_arb_find_apid(struct spmi_pmic_arb *pmic_arb, u16 ppid)
> +static u16 pmic_arb_find_apid(struct spmi_pmic_arb_bus *bus, u16 ppid)
>   {
> -	struct apid_data *apidd = &pmic_arb->apid_data[pmic_arb->last_apid];
> +	struct spmi_pmic_arb *pmic_arb = bus->pmic_arb;
> +	struct apid_data *apidd = &bus->apid_data[bus->last_apid];
>   	u32 regval, offset;
>   	u16 id, apid;
>   
> -	for (apid = pmic_arb->last_apid; ; apid++, apidd++) {
> +	for (apid = bus->last_apid; ; apid++, apidd++) {
>   		offset = pmic_arb->ver_ops->apid_map_offset(apid);
>   		if (offset >= pmic_arb->core_size)
>   			break;
>   
> -		regval = readl_relaxed(pmic_arb->ver_ops->apid_owner(pmic_arb,
> +		regval = readl_relaxed(pmic_arb->ver_ops->apid_owner(bus,
>   								     apid));
>   		apidd->irq_ee = SPMI_OWNERSHIP_PERIPH2OWNER(regval);
>   		apidd->write_ee = apidd->irq_ee;
> @@ -1065,14 +1098,14 @@ static u16 pmic_arb_find_apid(struct spmi_pmic_arb *pmic_arb, u16 ppid)
>   			continue;
>   
>   		id = (regval >> 8) & PMIC_ARB_PPID_MASK;
> -		pmic_arb->ppid_to_apid[id] = apid | PMIC_ARB_APID_VALID;
> +		bus->ppid_to_apid[id] = apid | PMIC_ARB_APID_VALID;
>   		apidd->ppid = id;
>   		if (id == ppid) {
>   			apid |= PMIC_ARB_APID_VALID;
>   			break;
>   		}
>   	}
> -	pmic_arb->last_apid = apid & ~PMIC_ARB_APID_VALID;
> +	bus->last_apid = apid & ~PMIC_ARB_APID_VALID;
>   
>   	return apid;
>   }
> @@ -1104,21 +1137,22 @@ static int pmic_arb_get_core_resources_v2(struct platform_device *pdev,
>   	return pmic_arb_get_obsrvr_chnls_v2(pdev);
>   }
>   
> -static int pmic_arb_ppid_to_apid_v2(struct spmi_pmic_arb *pmic_arb, u16 ppid)
> +static int pmic_arb_ppid_to_apid_v2(struct spmi_pmic_arb_bus *bus, u16 ppid)
>   {
>   	u16 apid_valid;
>   
> -	apid_valid = pmic_arb->ppid_to_apid[ppid];
> +	apid_valid = bus->ppid_to_apid[ppid];
>   	if (!(apid_valid & PMIC_ARB_APID_VALID))
> -		apid_valid = pmic_arb_find_apid(pmic_arb, ppid);
> +		apid_valid = pmic_arb_find_apid(bus, ppid);
>   	if (!(apid_valid & PMIC_ARB_APID_VALID))
>   		return -ENODEV;
>   
>   	return apid_valid & ~PMIC_ARB_APID_VALID;
>   }
>   
> -static int pmic_arb_read_apid_map_v5(struct spmi_pmic_arb *pmic_arb)
> +static int pmic_arb_read_apid_map_v5(struct spmi_pmic_arb_bus *bus)
>   {
> +	struct spmi_pmic_arb *pmic_arb = bus->pmic_arb;
>   	struct apid_data *apidd;
>   	struct apid_data *prev_apidd;
>   	u16 i, apid, ppid, apid_max;
> @@ -1140,9 +1174,9 @@ static int pmic_arb_read_apid_map_v5(struct spmi_pmic_arb *pmic_arb)
>   	 * where N = number of APIDs supported by the primary bus and
>   	 *       M = number of APIDs supported by the secondary bus
>   	 */
> -	apidd = &pmic_arb->apid_data[pmic_arb->base_apid];
> -	apid_max = pmic_arb->base_apid + pmic_arb->apid_count;
> -	for (i = pmic_arb->base_apid; i < apid_max; i++, apidd++) {
> +	apidd = &bus->apid_data[bus->base_apid];
> +	apid_max = bus->base_apid + bus->apid_count;
> +	for (i = bus->base_apid; i < apid_max; i++, apidd++) {
>   		offset = pmic_arb->ver_ops->apid_map_offset(i);
>   		if (offset >= pmic_arb->core_size)
>   			break;
> @@ -1153,19 +1187,18 @@ static int pmic_arb_read_apid_map_v5(struct spmi_pmic_arb *pmic_arb)
>   		ppid = (regval >> 8) & PMIC_ARB_PPID_MASK;
>   		is_irq_ee = PMIC_ARB_CHAN_IS_IRQ_OWNER(regval);
>   
> -		regval = readl_relaxed(pmic_arb->ver_ops->apid_owner(pmic_arb,
> -								     i));
> +		regval = readl_relaxed(pmic_arb->ver_ops->apid_owner(bus, i));
>   		apidd->write_ee = SPMI_OWNERSHIP_PERIPH2OWNER(regval);
>   
>   		apidd->irq_ee = is_irq_ee ? apidd->write_ee : INVALID_EE;
>   
> -		valid = pmic_arb->ppid_to_apid[ppid] & PMIC_ARB_APID_VALID;
> -		apid = pmic_arb->ppid_to_apid[ppid] & ~PMIC_ARB_APID_VALID;
> -		prev_apidd = &pmic_arb->apid_data[apid];
> +		valid = bus->ppid_to_apid[ppid] & PMIC_ARB_APID_VALID;
> +		apid = bus->ppid_to_apid[ppid] & ~PMIC_ARB_APID_VALID;
> +		prev_apidd = &bus->apid_data[apid];
>   
>   		if (!valid || apidd->write_ee == pmic_arb->ee) {
>   			/* First PPID mapping or one for this EE */
> -			pmic_arb->ppid_to_apid[ppid] = i | PMIC_ARB_APID_VALID;
> +			bus->ppid_to_apid[ppid] = i | PMIC_ARB_APID_VALID;
>   		} else if (valid && is_irq_ee &&
>   			   prev_apidd->write_ee == pmic_arb->ee) {
>   			/*
> @@ -1176,42 +1209,43 @@ static int pmic_arb_read_apid_map_v5(struct spmi_pmic_arb *pmic_arb)
>   		}
>   
>   		apidd->ppid = ppid;
> -		pmic_arb->last_apid = i;
> +		bus->last_apid = i;
>   	}
>   
>   	/* Dump the mapping table for debug purposes. */
> -	dev_dbg(&pmic_arb->spmic->dev, "PPID APID Write-EE IRQ-EE\n");
> +	dev_dbg(&bus->spmic->dev, "PPID APID Write-EE IRQ-EE\n");
>   	for (ppid = 0; ppid < PMIC_ARB_MAX_PPID; ppid++) {
> -		apid = pmic_arb->ppid_to_apid[ppid];
> +		apid = bus->ppid_to_apid[ppid];
>   		if (apid & PMIC_ARB_APID_VALID) {
>   			apid &= ~PMIC_ARB_APID_VALID;
> -			apidd = &pmic_arb->apid_data[apid];
> -			dev_dbg(&pmic_arb->spmic->dev, "%#03X %3u %2u %2u\n",
> -			      ppid, apid, apidd->write_ee, apidd->irq_ee);
> +			apidd = &bus->apid_data[apid];
> +			dev_dbg(&bus->spmic->dev, "%#03X %3u %2u %2u\n",
> +				ppid, apid, apidd->write_ee, apidd->irq_ee);
>   		}
>   	}
>   
>   	return 0;
>   }
>   
> -static int pmic_arb_ppid_to_apid_v5(struct spmi_pmic_arb *pmic_arb, u16 ppid)
> +static int pmic_arb_ppid_to_apid_v5(struct spmi_pmic_arb_bus *bus, u16 ppid)
>   {
> -	if (!(pmic_arb->ppid_to_apid[ppid] & PMIC_ARB_APID_VALID))
> +	if (!(bus->ppid_to_apid[ppid] & PMIC_ARB_APID_VALID))
>   		return -ENODEV;
>   
> -	return pmic_arb->ppid_to_apid[ppid] & ~PMIC_ARB_APID_VALID;
> +	return bus->ppid_to_apid[ppid] & ~PMIC_ARB_APID_VALID;
>   }
>   
>   /* v2 offset per ppid and per ee */
> -static int pmic_arb_offset_v2(struct spmi_pmic_arb *pmic_arb, u8 sid, u16 addr,
> -			   enum pmic_arb_channel ch_type)
> +static int pmic_arb_offset_v2(struct spmi_pmic_arb_bus *bus, u8 sid, u16 addr,
> +			      enum pmic_arb_channel ch_type)
>   {
> +	struct spmi_pmic_arb *pmic_arb = bus->pmic_arb;
>   	u16 apid;
>   	u16 ppid;
>   	int rc;
>   
>   	ppid = sid << 8 | ((addr >> 8) & 0xFF);
> -	rc = pmic_arb_ppid_to_apid_v2(pmic_arb, ppid);
> +	rc = pmic_arb_ppid_to_apid_v2(bus, ppid);
>   	if (rc < 0)
>   		return rc;
>   
> @@ -1219,27 +1253,28 @@ static int pmic_arb_offset_v2(struct spmi_pmic_arb *pmic_arb, u8 sid, u16 addr,
>   	return 0x1000 * pmic_arb->ee + 0x8000 * apid;
>   }
>   
> -static int pmic_arb_init_apid_v5(struct spmi_pmic_arb *pmic_arb)
> +static int pmic_arb_init_apid_v5(struct spmi_pmic_arb_bus *bus)
>   {
> +	struct spmi_pmic_arb *pmic_arb = bus->pmic_arb;
>   	int ret;
>   
> -	pmic_arb->base_apid = 0;
> -	pmic_arb->apid_count = readl_relaxed(pmic_arb->core + PMIC_ARB_FEATURES) &
> -					   PMIC_ARB_FEATURES_PERIPH_MASK;
> +	bus->base_apid = 0;
> +	bus->apid_count = readl_relaxed(pmic_arb->core + PMIC_ARB_FEATURES) &
> +					PMIC_ARB_FEATURES_PERIPH_MASK;
>   
> -	if (pmic_arb->base_apid + pmic_arb->apid_count > pmic_arb->max_periphs) {
> -		dev_err(&pmic_arb->spmic->dev, "Unsupported APID count %d detected\n",
> -			pmic_arb->base_apid + pmic_arb->apid_count);
> +	if (bus->base_apid + bus->apid_count > pmic_arb->max_periphs) {
> +		dev_err(&bus->spmic->dev, "Unsupported APID count %d detected\n",
> +			bus->base_apid + bus->apid_count);
>   		return -EINVAL;
>   	}
>   
> -	ret = pmic_arb_init_apid_min_max(pmic_arb);
> +	ret = pmic_arb_init_apid_min_max(bus);
>   	if (ret)
>   		return ret;
>   
> -	ret = pmic_arb_read_apid_map_v5(pmic_arb);
> +	ret = pmic_arb_read_apid_map_v5(bus);
>   	if (ret) {
> -		dev_err(&pmic_arb->spmic->dev, "could not read APID->PPID mapping table, rc= %d\n",
> +		dev_err(&bus->spmic->dev, "could not read APID->PPID mapping table, rc= %d\n",
>   			ret);
>   		return ret;
>   	}
> @@ -1251,15 +1286,16 @@ static int pmic_arb_init_apid_v5(struct spmi_pmic_arb *pmic_arb)
>    * v5 offset per ee and per apid for observer channels and per apid for
>    * read/write channels.
>    */
> -static int pmic_arb_offset_v5(struct spmi_pmic_arb *pmic_arb, u8 sid, u16 addr,
> -			   enum pmic_arb_channel ch_type)
> +static int pmic_arb_offset_v5(struct spmi_pmic_arb_bus *bus, u8 sid, u16 addr,
> +			      enum pmic_arb_channel ch_type)
>   {
> +	struct spmi_pmic_arb *pmic_arb = bus->pmic_arb;
>   	u16 apid;
>   	int rc;
>   	u32 offset = 0;
>   	u16 ppid = (sid << 8) | (addr >> 8);
>   
> -	rc = pmic_arb_ppid_to_apid_v5(pmic_arb, ppid);
> +	rc = pmic_arb_ppid_to_apid_v5(bus, ppid);
>   	if (rc < 0)
>   		return rc;
>   
> @@ -1269,8 +1305,8 @@ static int pmic_arb_offset_v5(struct spmi_pmic_arb *pmic_arb, u8 sid, u16 addr,
>   		offset = 0x10000 * pmic_arb->ee + 0x80 * apid;
>   		break;
>   	case PMIC_ARB_CHANNEL_RW:
> -		if (pmic_arb->apid_data[apid].write_ee != pmic_arb->ee) {
> -			dev_err(&pmic_arb->spmic->dev, "disallowed SPMI write to sid=%u, addr=0x%04X\n",
> +		if (bus->apid_data[apid].write_ee != pmic_arb->ee) {
> +			dev_err(&bus->spmic->dev, "disallowed SPMI write to sid=%u, addr=0x%04X\n",
>   				sid, addr);
>   			return -EPERM;
>   		}
> @@ -1297,15 +1333,16 @@ static int pmic_arb_get_core_resources_v7(struct platform_device *pdev,
>    * v7 offset per ee and per apid for observer channels and per apid for
>    * read/write channels.
>    */
> -static int pmic_arb_offset_v7(struct spmi_pmic_arb *pmic_arb, u8 sid, u16 addr,
> -			   enum pmic_arb_channel ch_type)
> +static int pmic_arb_offset_v7(struct spmi_pmic_arb_bus *bus, u8 sid, u16 addr,
> +			      enum pmic_arb_channel ch_type)
>   {
> +	struct spmi_pmic_arb *pmic_arb = bus->pmic_arb;
>   	u16 apid;
>   	int rc;
>   	u32 offset = 0;
>   	u16 ppid = (sid << 8) | (addr >> 8);
>   
> -	rc = pmic_arb->ver_ops->ppid_to_apid(pmic_arb, ppid);
> +	rc = pmic_arb->ver_ops->ppid_to_apid(bus, ppid);
>   	if (rc < 0)
>   		return rc;
>   
> @@ -1315,8 +1352,8 @@ static int pmic_arb_offset_v7(struct spmi_pmic_arb *pmic_arb, u8 sid, u16 addr,
>   		offset = 0x8000 * pmic_arb->ee + 0x20 * apid;
>   		break;
>   	case PMIC_ARB_CHANNEL_RW:
> -		if (pmic_arb->apid_data[apid].write_ee != pmic_arb->ee) {
> -			dev_err(&pmic_arb->spmic->dev, "disallowed SPMI write to sid=%u, addr=0x%04X\n",
> +		if (bus->apid_data[apid].write_ee != pmic_arb->ee) {
> +			dev_err(&bus->spmic->dev, "disallowed SPMI write to sid=%u, addr=0x%04X\n",
>   				sid, addr);
>   			return -EPERM;
>   		}
> @@ -1338,104 +1375,110 @@ static u32 pmic_arb_fmt_cmd_v2(u8 opc, u8 sid, u16 addr, u8 bc)
>   }
>   
>   static void __iomem *
> -pmic_arb_owner_acc_status_v1(struct spmi_pmic_arb *pmic_arb, u8 m, u16 n)
> +pmic_arb_owner_acc_status_v1(struct spmi_pmic_arb_bus *bus, u8 m, u16 n)
>   {
> -	return pmic_arb->intr + 0x20 * m + 0x4 * n;
> +	return bus->intr + 0x20 * m + 0x4 * n;
>   }
>   
>   static void __iomem *
> -pmic_arb_owner_acc_status_v2(struct spmi_pmic_arb *pmic_arb, u8 m, u16 n)
> +pmic_arb_owner_acc_status_v2(struct spmi_pmic_arb_bus *bus, u8 m, u16 n)
>   {
> -	return pmic_arb->intr + 0x100000 + 0x1000 * m + 0x4 * n;
> +	return bus->intr + 0x100000 + 0x1000 * m + 0x4 * n;
>   }
>   
>   static void __iomem *
> -pmic_arb_owner_acc_status_v3(struct spmi_pmic_arb *pmic_arb, u8 m, u16 n)
> +pmic_arb_owner_acc_status_v3(struct spmi_pmic_arb_bus *bus, u8 m, u16 n)
>   {
> -	return pmic_arb->intr + 0x200000 + 0x1000 * m + 0x4 * n;
> +	return bus->intr + 0x200000 + 0x1000 * m + 0x4 * n;
>   }
>   
>   static void __iomem *
> -pmic_arb_owner_acc_status_v5(struct spmi_pmic_arb *pmic_arb, u8 m, u16 n)
> +pmic_arb_owner_acc_status_v5(struct spmi_pmic_arb_bus *bus, u8 m, u16 n)
>   {
> -	return pmic_arb->intr + 0x10000 * m + 0x4 * n;
> +	return bus->intr + 0x10000 * m + 0x4 * n;
>   }
>   
>   static void __iomem *
> -pmic_arb_owner_acc_status_v7(struct spmi_pmic_arb *pmic_arb, u8 m, u16 n)
> +pmic_arb_owner_acc_status_v7(struct spmi_pmic_arb_bus *bus, u8 m, u16 n)
>   {
> -	return pmic_arb->intr + 0x1000 * m + 0x4 * n;
> +	return bus->intr + 0x1000 * m + 0x4 * n;
>   }
>   
>   static void __iomem *
> -pmic_arb_acc_enable_v1(struct spmi_pmic_arb *pmic_arb, u16 n)
> +pmic_arb_acc_enable_v1(struct spmi_pmic_arb_bus *bus, u16 n)
>   {
> -	return pmic_arb->intr + 0x200 + 0x4 * n;
> +	return bus->intr + 0x200 + 0x4 * n;
>   }
>   
>   static void __iomem *
> -pmic_arb_acc_enable_v2(struct spmi_pmic_arb *pmic_arb, u16 n)
> +pmic_arb_acc_enable_v2(struct spmi_pmic_arb_bus *bus, u16 n)
>   {
> -	return pmic_arb->intr + 0x1000 * n;
> +	return bus->intr + 0x1000 * n;
>   }
>   
>   static void __iomem *
> -pmic_arb_acc_enable_v5(struct spmi_pmic_arb *pmic_arb, u16 n)
> +pmic_arb_acc_enable_v5(struct spmi_pmic_arb_bus *bus, u16 n)
>   {
> +	struct spmi_pmic_arb *pmic_arb = bus->pmic_arb;
>   	return pmic_arb->wr_base + 0x100 + 0x10000 * n;
>   }
>   
>   static void __iomem *
> -pmic_arb_acc_enable_v7(struct spmi_pmic_arb *pmic_arb, u16 n)
> +pmic_arb_acc_enable_v7(struct spmi_pmic_arb_bus *bus, u16 n)
>   {
> +	struct spmi_pmic_arb *pmic_arb = bus->pmic_arb;
>   	return pmic_arb->wr_base + 0x100 + 0x1000 * n;
>   }
>   
>   static void __iomem *
> -pmic_arb_irq_status_v1(struct spmi_pmic_arb *pmic_arb, u16 n)
> +pmic_arb_irq_status_v1(struct spmi_pmic_arb_bus *bus, u16 n)
>   {
> -	return pmic_arb->intr + 0x600 + 0x4 * n;
> +	return bus->intr + 0x600 + 0x4 * n;
>   }
>   
>   static void __iomem *
> -pmic_arb_irq_status_v2(struct spmi_pmic_arb *pmic_arb, u16 n)
> +pmic_arb_irq_status_v2(struct spmi_pmic_arb_bus *bus, u16 n)
>   {
> -	return pmic_arb->intr + 0x4 + 0x1000 * n;
> +	return bus->intr + 0x4 + 0x1000 * n;
>   }
>   
>   static void __iomem *
> -pmic_arb_irq_status_v5(struct spmi_pmic_arb *pmic_arb, u16 n)
> +pmic_arb_irq_status_v5(struct spmi_pmic_arb_bus *bus, u16 n)
>   {
> +	struct spmi_pmic_arb *pmic_arb = bus->pmic_arb;
>   	return pmic_arb->wr_base + 0x104 + 0x10000 * n;
>   }
>   
>   static void __iomem *
> -pmic_arb_irq_status_v7(struct spmi_pmic_arb *pmic_arb, u16 n)
> +pmic_arb_irq_status_v7(struct spmi_pmic_arb_bus *bus, u16 n)
>   {
> +	struct spmi_pmic_arb *pmic_arb = bus->pmic_arb;
>   	return pmic_arb->wr_base + 0x104 + 0x1000 * n;
>   }
>   
>   static void __iomem *
> -pmic_arb_irq_clear_v1(struct spmi_pmic_arb *pmic_arb, u16 n)
> +pmic_arb_irq_clear_v1(struct spmi_pmic_arb_bus *bus, u16 n)
>   {
> -	return pmic_arb->intr + 0xA00 + 0x4 * n;
> +	return bus->intr + 0xA00 + 0x4 * n;
>   }
>   
>   static void __iomem *
> -pmic_arb_irq_clear_v2(struct spmi_pmic_arb *pmic_arb, u16 n)
> +pmic_arb_irq_clear_v2(struct spmi_pmic_arb_bus *bus, u16 n)
>   {
> -	return pmic_arb->intr + 0x8 + 0x1000 * n;
> +	return bus->intr + 0x8 + 0x1000 * n;
>   }
>   
>   static void __iomem *
> -pmic_arb_irq_clear_v5(struct spmi_pmic_arb *pmic_arb, u16 n)
> +pmic_arb_irq_clear_v5(struct spmi_pmic_arb_bus *bus, u16 n)
>   {
> +	struct spmi_pmic_arb *pmic_arb = bus->pmic_arb;
>   	return pmic_arb->wr_base + 0x108 + 0x10000 * n;
>   }
>   
>   static void __iomem *
> -pmic_arb_irq_clear_v7(struct spmi_pmic_arb *pmic_arb, u16 n)
> +pmic_arb_irq_clear_v7(struct spmi_pmic_arb_bus *bus, u16 n)
>   {
> +	struct spmi_pmic_arb *pmic_arb = bus->pmic_arb;
>   	return pmic_arb->wr_base + 0x108 + 0x1000 * n;
>   }
>   
> @@ -1455,9 +1498,9 @@ static u32 pmic_arb_apid_map_offset_v7(u16 n)
>   }
>   
>   static void __iomem *
> -pmic_arb_apid_owner_v2(struct spmi_pmic_arb *pmic_arb, u16 n)
> +pmic_arb_apid_owner_v2(struct spmi_pmic_arb_bus *bus, u16 n)
>   {
> -	return pmic_arb->cnfg + 0x700 + 0x4 * n;
> +	return bus->cnfg + 0x700 + 0x4 * n;
>   }
>   
>   /*
> @@ -1466,9 +1509,9 @@ pmic_arb_apid_owner_v2(struct spmi_pmic_arb *pmic_arb, u16 n)
>    * 0.
>    */
>   static void __iomem *
> -pmic_arb_apid_owner_v7(struct spmi_pmic_arb *pmic_arb, u16 n)
> +pmic_arb_apid_owner_v7(struct spmi_pmic_arb_bus *bus, u16 n)
>   {
> -	return pmic_arb->cnfg + 0x4 * (n - pmic_arb->base_apid);
> +	return bus->cnfg + 0x4 * (n - bus->base_apid);
>   }
>   
>   static const struct pmic_arb_ver_ops pmic_arb_v1 = {
> @@ -1558,29 +1601,120 @@ static const struct irq_domain_ops pmic_arb_irq_domain_ops = {
>   	.translate = qpnpint_irq_domain_translate,
>   };
>   
> +static int spmi_pmic_arb_bus_init(struct platform_device *pdev,
> +				  struct device_node *node,
> +				  struct spmi_pmic_arb *pmic_arb)
> +{
> +	struct spmi_pmic_arb_bus *bus;
> +	struct device *dev = &pdev->dev;
> +	struct spmi_controller *ctrl;
> +	void __iomem *intr;
> +	void __iomem *cnfg;
> +	int index, ret;
> +	u32 irq;
> +
> +	ctrl = devm_spmi_controller_alloc(dev, sizeof(*bus));
> +	if (IS_ERR(ctrl))
> +		return PTR_ERR(ctrl);
> +
> +	ctrl->cmd = pmic_arb_cmd;
> +	ctrl->read_cmd = pmic_arb_read_cmd;
> +	ctrl->write_cmd = pmic_arb_write_cmd;
> +
> +	bus = spmi_controller_get_drvdata(ctrl);
> +
> +	pmic_arb->bus = bus;
> +
> +	bus->ppid_to_apid = devm_kcalloc(dev, PMIC_ARB_MAX_PPID,
> +					 sizeof(*bus->ppid_to_apid),
> +					 GFP_KERNEL);
> +	if (!bus->ppid_to_apid)
> +		return -ENOMEM;
> +
> +	bus->apid_data = devm_kcalloc(dev, pmic_arb->max_periphs,
> +				      sizeof(*bus->apid_data),
> +				      GFP_KERNEL);
> +	if (!bus->apid_data)
> +		return -ENOMEM;
> +
> +	index = of_property_match_string(node, "reg-names", "cnfg");
> +	if (index < 0) {
> +		dev_err(dev, "cnfg reg region missing");
> +		return -EINVAL;
> +	}
> +
> +	cnfg = devm_of_iomap(dev, node, index, NULL);
> +	if (IS_ERR(cnfg))
> +		return PTR_ERR(cnfg);
> +
> +	index = of_property_match_string(node, "reg-names", "intr");
> +	if (index < 0) {
> +		dev_err(dev, "intr reg region missing");
> +		return -EINVAL;
> +	}
> +
> +	intr = devm_of_iomap(dev, node, index, NULL);
> +	if (IS_ERR(intr))
> +		return PTR_ERR(intr);
> +
> +	irq = of_irq_get_byname(node, "periph_irq");
> +	if (irq < 0)
> +		return irq;
> +
> +	bus->pmic_arb = pmic_arb;
> +	bus->intr = intr;
> +	bus->cnfg = cnfg;
> +	bus->irq = irq;
> +	bus->spmic = ctrl;
> +
> +	ret = pmic_arb->ver_ops->init_apid(bus);
> +	if (ret)
> +		return ret;
> +
> +	dev_dbg(&pdev->dev, "adding irq domain\n");
> +
> +	bus->domain = irq_domain_add_tree(dev->of_node,
> +					  &pmic_arb_irq_domain_ops, bus);
> +	if (!bus->domain) {
> +		dev_err(&pdev->dev, "unable to create irq_domain\n");
> +		return -ENOMEM;
> +	}
> +
> +	irq_set_chained_handler_and_data(bus->irq,
> +					 pmic_arb_chained_irq, bus);
> +
> +	ctrl->dev.of_node = node;
> +
> +	ret = devm_spmi_controller_add(dev, ctrl);
> +	if (ret)
> +		return ret;
> +
> +	return 0;
> +}
> +
>   static int spmi_pmic_arb_probe(struct platform_device *pdev)
>   {
>   	struct spmi_pmic_arb *pmic_arb;
> -	struct spmi_controller *ctrl;
> +	struct device *dev = &pdev->dev;
>   	struct resource *res;
>   	void __iomem *core;
>   	u32 channel, ee, hw_ver;
>   	int err;
>   
> -	ctrl = devm_spmi_controller_alloc(&pdev->dev, sizeof(*pmic_arb));
> -	if (IS_ERR(ctrl))
> -		return PTR_ERR(ctrl);
> -
> -	pmic_arb = spmi_controller_get_drvdata(ctrl);
> -	pmic_arb->spmic = ctrl;
> +	pmic_arb = devm_kzalloc(dev, sizeof(*pmic_arb), GFP_KERNEL);
> +	if (!pmic_arb)
> +		return -ENOMEM;
>   
>   	res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "core");
> -	core = devm_ioremap(&ctrl->dev, res->start, resource_size(res));
> +	core = devm_ioremap(dev, res->start, resource_size(res));
>   	if (IS_ERR(core))
>   		return PTR_ERR(core);
>   
>   	pmic_arb->core_size = resource_size(res);
>   
> +	platform_set_drvdata(pdev, pmic_arb);
> +	raw_spin_lock_init(&pmic_arb->lock);
> +
>   	hw_ver = readl_relaxed(core + PMIC_ARB_VERSION);
>   
>   	if (hw_ver < PMIC_ARB_VERSION_V2_MIN)
> @@ -1594,30 +1728,12 @@ static int spmi_pmic_arb_probe(struct platform_device *pdev)
>   	else
>   		pmic_arb->ver_ops = &pmic_arb_v7;
>   
> -	dev_info(&ctrl->dev, "PMIC arbiter version %s (0x%x)\n",
> -		 pmic_arb->ver_ops->ver_str, hw_ver);
> -
>   	err = pmic_arb->ver_ops->get_core_resources(pdev, core);
>   	if (err)
>   		return err;
>   
> -	err = pmic_arb->ver_ops->init_apid(pmic_arb);
> -	if (err)
> -		return err;
> -
> -	res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "intr");
> -	pmic_arb->intr = devm_ioremap_resource(&ctrl->dev, res);
> -	if (IS_ERR(pmic_arb->intr))
> -		return PTR_ERR(pmic_arb->intr);
> -
> -	res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "cnfg");
> -	pmic_arb->cnfg = devm_ioremap_resource(&ctrl->dev, res);
> -	if (IS_ERR(pmic_arb->cnfg))
> -		return PTR_ERR(pmic_arb->cnfg);
> -
> -	pmic_arb->irq = platform_get_irq_byname(pdev, "periph_irq");
> -	if (pmic_arb->irq < 0)
> -		return pmic_arb->irq;
> +	dev_info(dev, "PMIC arbiter version %s (0x%x)\n",
> +		 pmic_arb->ver_ops->ver_str, hw_ver);
>   
>   	err = of_property_read_u32(pdev->dev.of_node, "qcom,channel", &channel);
>   	if (err) {
> @@ -1646,42 +1762,17 @@ static int spmi_pmic_arb_probe(struct platform_device *pdev)
>   
>   	pmic_arb->ee = ee;
>   
> -	platform_set_drvdata(pdev, ctrl);
> -	raw_spin_lock_init(&pmic_arb->lock);
> -
> -	ctrl->cmd = pmic_arb_cmd;
> -	ctrl->read_cmd = pmic_arb_read_cmd;
> -	ctrl->write_cmd = pmic_arb_write_cmd;
> -
> -	dev_dbg(&pdev->dev, "adding irq domain\n");
> -	pmic_arb->domain = irq_domain_add_tree(pdev->dev.of_node,
> -					 &pmic_arb_irq_domain_ops, pmic_arb);
> -	if (!pmic_arb->domain) {
> -		dev_err(&pdev->dev, "unable to create irq_domain\n");
> -		return -ENOMEM;
> -	}
> -
> -	irq_set_chained_handler_and_data(pmic_arb->irq, pmic_arb_chained_irq,
> -					pmic_arb);
> -	err = spmi_controller_add(ctrl);
> -	if (err)
> -		goto err_domain_remove;
> -
> -	return 0;
> -
> -err_domain_remove:
> -	irq_set_chained_handler_and_data(pmic_arb->irq, NULL, NULL);
> -	irq_domain_remove(pmic_arb->domain);
> -	return err;
> +	return spmi_pmic_arb_bus_init(pdev, dev->of_node, pmic_arb);
>   }
>   
>   static void spmi_pmic_arb_remove(struct platform_device *pdev)
>   {
> -	struct spmi_controller *ctrl = platform_get_drvdata(pdev);
> -	struct spmi_pmic_arb *pmic_arb = spmi_controller_get_drvdata(ctrl);
> -	spmi_controller_remove(ctrl);
> -	irq_set_chained_handler_and_data(pmic_arb->irq, NULL, NULL);
> -	irq_domain_remove(pmic_arb->domain);
> +	struct spmi_pmic_arb *pmic_arb = platform_get_drvdata(pdev);
> +	struct spmi_pmic_arb_bus *bus = pmic_arb->bus;
> +
> +	irq_set_chained_handler_and_data(bus->irq,
> +					 NULL, NULL);
> +	irq_domain_remove(bus->domain);
>   }
>   
>   static const struct of_device_id spmi_pmic_arb_match_table[] = {
> 

Reviewed-by: Neil Armstrong <neil.armstrong@linaro.org>

_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

^ permalink raw reply

* Re: [PATCH] arm64: dts: ti: k3-j722s: Disable ethernet ports by default
From: Michael Walle @ 2024-04-03  7:35 UTC (permalink / raw)
  To: Francesco Dolcini
  Cc: Nishanth Menon, Vignesh Raghavendra, Tero Kristo, Rob Herring,
	Krzysztof Kozlowski, Conor Dooley, linux-arm-kernel, devicetree,
	linux-kernel
In-Reply-To: <20240402165824.GA32125@francesco-nb>


[-- Attachment #1.1: Type: text/plain, Size: 1881 bytes --]

Hi Francesco,

On Tue Apr 2, 2024 at 6:58 PM CEST, Francesco Dolcini wrote:
> On Tue, Apr 02, 2024 at 05:18:02PM +0200, Michael Walle wrote:
> > Device tree best practice is to disable any external interface in the
> > dtsi and just enable them if needed in the device tree. Thus, disable
> > both ethernet ports by default and just enable the one used by the EVM
> > in its device tree.
> > 
> > There is no functional change.
> > 
> > Signed-off-by: Michael Walle <mwalle@kernel.org>
> > ---
> > This should also be true for all the other SoCs. But I don't wanted to
> > touch all the (older) device trees. j722s is pretty new, so there we
> > should get it right.
> > ---
> >  arch/arm64/boot/dts/ti/k3-j722s-evm.dts | 5 +----
> >  arch/arm64/boot/dts/ti/k3-j722s.dtsi    | 8 ++++++++
> >  2 files changed, 9 insertions(+), 4 deletions(-)
> > 
> > diff --git a/arch/arm64/boot/dts/ti/k3-j722s-evm.dts b/arch/arm64/boot/dts/ti/k3-j722s-evm.dts
> > index d045dc7dde0c..afe7f68e6a4b 100644
> > --- a/arch/arm64/boot/dts/ti/k3-j722s-evm.dts
> > +++ b/arch/arm64/boot/dts/ti/k3-j722s-evm.dts
> > @@ -224,14 +224,11 @@ cpsw3g_phy0: ethernet-phy@0 {
> >  };
> >  
> >  &cpsw_port1 {
> > +	status = "okay";
>
> status should be the last property, according to the dts coding guidelines.

Thanks for pointing that out. There is
devicetree/bindings/dts-coding-style.rst, which is in fact new to
me. Up until now, I was under the impression that how this is
handled is up to the maintainer of the SoC. I know that for the NXP
Layerscape for example, the maintainer will have an eye esp. for
that. But here it seems kinda random/all over the place. That being
said, I tried to be consistent with the other cpsw* nodes.

Anyway, I'll change it to come last.

> >  	phy-mode = "rgmii-rxid";
> >  	phy-handle = <&cpsw3g_phy0>;
> >  };

-michael

[-- Attachment #1.2: signature.asc --]
[-- Type: application/pgp-signature, Size: 297 bytes --]

[-- Attachment #2: Type: text/plain, Size: 176 bytes --]

_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

^ permalink raw reply

* Re: [PATCH 5/5] arm64: dts: Add device tree source for the Au-Zone Maivin Starter Kit
From: Laurent Pinchart @ 2024-04-03  7:35 UTC (permalink / raw)
  To: Francesco Dolcini
  Cc: Shawn Guo, devicetree, imx, linux-arm-kernel, Trevor Zaharichuk,
	Greg Lytle, Shawn Guo, Sascha Hauer, Pengutronix Kernel Team,
	Fabio Estevam, Rob Herring, Krzysztof Kozlowski, Conor Dooley
In-Reply-To: <20240403070651.GB5070@francesco-nb>

On Wed, Apr 03, 2024 at 09:06:51AM +0200, Francesco Dolcini wrote:
> Hello Laurent,
> 
> On Wed, Apr 03, 2024 at 08:30:11AM +0800, Shawn Guo wrote:
> > On Mon, Mar 25, 2024 at 10:32:45PM +0200, Laurent Pinchart wrote:
> > > diff --git a/arch/arm64/boot/dts/freescale/imx8mp-maivin.dts b/arch/arm64/boot/dts/freescale/imx8mp-maivin.dts
> > > new file mode 100644
> > > index 000000000000..2d1c8e782465
> > > --- /dev/null
> > > +++ b/arch/arm64/boot/dts/freescale/imx8mp-maivin.dts
> > > @@ -0,0 +1,236 @@
> 
> [...]
> 
> > > +/* Verdin I2C_2_DSI */
> > > +&i2c2 {
> > > +	status = "okay";
> > > +
> > > +	clock-frequency = <400000>;
> > > +	scl-gpios = <&gpio5 16 (GPIO_ACTIVE_HIGH | GPIO_OPEN_DRAIN)>;
> > > +	sda-gpios = <&gpio5 17 (GPIO_ACTIVE_HIGH | GPIO_OPEN_DRAIN)>;
> > 
> > We usually end property list with 'status'.
> 
> This is now a written and explicit guideline, no longer tribal knowledge,
> see https://docs.kernel.org/devicetree/bindings/dts-coding-style.html#order-of-properties-in-device-node

Thanks.

Any chance to teach checkpatch.pl (and/or the DT checker) about that ? :-)

-- 
Regards,

Laurent Pinchart

_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

^ permalink raw reply

* Re: [PATCH v8 3/7] spmi: pmic-arb: Fix some compile warnings about members not being described
From: Neil Armstrong @ 2024-04-03  7:35 UTC (permalink / raw)
  To: Abel Vesa, Stephen Boyd, Matthias Brugger, Bjorn Andersson,
	Konrad Dybcio, Dmitry Baryshkov, AngeloGioacchino Del Regno,
	Rob Herring, Krzysztof Kozlowski, Conor Dooley
  Cc: Srini Kandagatla, Johan Hovold, linux-kernel, linux-arm-kernel,
	linux-arm-msm, linux-mediatek, devicetree
In-Reply-To: <20240402-spmi-multi-master-support-v8-3-ce6f2d14a058@linaro.org>

On 02/04/2024 14:07, Abel Vesa wrote:
> Fix the following compile warnings:
> 
>   warning: Function parameter or struct member 'core' not described in 'spmi_pmic_arb'
>   warning: Function parameter or struct member 'core_size' not described in 'spmi_pmic_arb'
>   warning: Function parameter or struct member 'mapping_table_valid' not described in 'spmi_pmic_arb'
>   warning: Function parameter or struct member 'pmic_arb' not described in 'pmic_arb_read_data'
>   warning: Function parameter or struct member 'pmic_arb' not described in 'pmic_arb_write_data'
> 
> Signed-off-by: Abel Vesa <abel.vesa@linaro.org>
> ---
>   drivers/spmi/spmi-pmic-arb.c | 5 +++++
>   1 file changed, 5 insertions(+)
> 
> diff --git a/drivers/spmi/spmi-pmic-arb.c b/drivers/spmi/spmi-pmic-arb.c
> index 9ed1180fe31f..704fd4506971 100644
> --- a/drivers/spmi/spmi-pmic-arb.c
> +++ b/drivers/spmi/spmi-pmic-arb.c
> @@ -132,6 +132,8 @@ struct apid_data {
>    * @wr_base:		on v1 "core", on v2 "chnls"    register base off DT.
>    * @intr:		address of the SPMI interrupt control registers.
>    * @cnfg:		address of the PMIC Arbiter configuration registers.
> + * @core:		core register base for v2 and above only (see above)
> + * @core_size:		core register base size
>    * @lock:		lock to synchronize accesses.
>    * @channel:		execution environment channel to use for accesses.
>    * @irq:		PMIC ARB interrupt.
> @@ -144,6 +146,7 @@ struct apid_data {
>    * @apid_count:		on v5 and v7: number of APIDs associated with the
>    *			particular SPMI bus instance
>    * @mapping_table:	in-memory copy of PPID -> APID mapping table.
> + * @mapping_table_valid:bitmap containing valid-only periphs
>    * @domain:		irq domain object for PMIC IRQ domain
>    * @spmic:		SPMI controller object
>    * @ver_ops:		version dependent operations.
> @@ -232,6 +235,7 @@ static inline void pmic_arb_set_rd_cmd(struct spmi_pmic_arb *pmic_arb,
>   
>   /**
>    * pmic_arb_read_data: reads pmic-arb's register and copy 1..4 bytes to buf
> + * @pmic_arb:	the SPMI PMIC arbiter
>    * @bc:		byte count -1. range: 0..3
>    * @reg:	register's address
>    * @buf:	output parameter, length must be bc + 1
> @@ -246,6 +250,7 @@ pmic_arb_read_data(struct spmi_pmic_arb *pmic_arb, u8 *buf, u32 reg, u8 bc)
>   
>   /**
>    * pmic_arb_write_data: write 1..4 bytes from buf to pmic-arb's register
> + * @pmic_arb:	the SPMI PMIC arbiter
>    * @bc:		byte-count -1. range: 0..3.
>    * @reg:	register's address.
>    * @buf:	buffer to write. length must be bc + 1.
> 

Reviewed-by: Neil Armstrong <neil.armstrong@linaro.org>

_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

^ permalink raw reply

* [PATCH v8 6/6] docs: trusted-encrypted: add DCP as new trust source
From: David Gstir @ 2024-04-03  7:21 UTC (permalink / raw)
  To: Mimi Zohar, James Bottomley, Jarkko Sakkinen, Herbert Xu,
	David S. Miller
  Cc: David Gstir, Shawn Guo, Jonathan Corbet, Sascha Hauer,
	Pengutronix Kernel Team, Fabio Estevam, NXP Linux Team,
	Ahmad Fatoum, sigma star Kernel Team, David Howells, Li Yang,
	Paul Moore, James Morris, Serge E. Hallyn, Paul E. McKenney,
	Randy Dunlap, Catalin Marinas, Rafael J. Wysocki, Tejun Heo,
	Steven Rostedt (Google), linux-doc, linux-kernel, linux-integrity,
	keyrings, linux-crypto, linux-arm-kernel, linuxppc-dev,
	linux-security-module, Richard Weinberger, David Oberhollenzer
In-Reply-To: <20240403072131.54935-1-david@sigma-star.at>

Update the documentation for trusted and encrypted KEYS with DCP as new
trust source:

- Describe security properties of DCP trust source
- Describe key usage
- Document blob format

Co-developed-by: Richard Weinberger <richard@nod.at>
Signed-off-by: Richard Weinberger <richard@nod.at>
Co-developed-by: David Oberhollenzer <david.oberhollenzer@sigma-star.at>
Signed-off-by: David Oberhollenzer <david.oberhollenzer@sigma-star.at>
Signed-off-by: David Gstir <david@sigma-star.at>
---
 .../security/keys/trusted-encrypted.rst       | 53 +++++++++++++++++++
 security/keys/trusted-keys/trusted_dcp.c      | 19 +++++++
 2 files changed, 72 insertions(+)

diff --git a/Documentation/security/keys/trusted-encrypted.rst b/Documentation/security/keys/trusted-encrypted.rst
index e989b9802f92..f4d7e162d5e4 100644
--- a/Documentation/security/keys/trusted-encrypted.rst
+++ b/Documentation/security/keys/trusted-encrypted.rst
@@ -42,6 +42,14 @@ safe.
          randomly generated and fused into each SoC at manufacturing time.
          Otherwise, a common fixed test key is used instead.
 
+     (4) DCP (Data Co-Processor: crypto accelerator of various i.MX SoCs)
+
+         Rooted to a one-time programmable key (OTP) that is generally burnt
+         in the on-chip fuses and is accessible to the DCP encryption engine only.
+         DCP provides two keys that can be used as root of trust: the OTP key
+         and the UNIQUE key. Default is to use the UNIQUE key, but selecting
+         the OTP key can be done via a module parameter (dcp_use_otp_key).
+
   *  Execution isolation
 
      (1) TPM
@@ -57,6 +65,12 @@ safe.
 
          Fixed set of operations running in isolated execution environment.
 
+     (4) DCP
+
+         Fixed set of cryptographic operations running in isolated execution
+         environment. Only basic blob key encryption is executed there.
+         The actual key sealing/unsealing is done on main processor/kernel space.
+
   * Optional binding to platform integrity state
 
      (1) TPM
@@ -79,6 +93,11 @@ safe.
          Relies on the High Assurance Boot (HAB) mechanism of NXP SoCs
          for platform integrity.
 
+     (4) DCP
+
+         Relies on Secure/Trusted boot process (called HAB by vendor) for
+         platform integrity.
+
   *  Interfaces and APIs
 
      (1) TPM
@@ -94,6 +113,11 @@ safe.
 
          Interface is specific to silicon vendor.
 
+     (4) DCP
+
+         Vendor-specific API that is implemented as part of the DCP crypto driver in
+         ``drivers/crypto/mxs-dcp.c``.
+
   *  Threat model
 
      The strength and appropriateness of a particular trust source for a given
@@ -129,6 +153,13 @@ selected trust source:
      CAAM HWRNG, enable CRYPTO_DEV_FSL_CAAM_RNG_API and ensure the device
      is probed.
 
+  *  DCP (Data Co-Processor: crypto accelerator of various i.MX SoCs)
+
+     The DCP hardware device itself does not provide a dedicated RNG interface,
+     so the kernel default RNG is used. SoCs with DCP like the i.MX6ULL do have
+     a dedicated hardware RNG that is independent from DCP which can be enabled
+     to back the kernel RNG.
+
 Users may override this by specifying ``trusted.rng=kernel`` on the kernel
 command-line to override the used RNG with the kernel's random number pool.
 
@@ -231,6 +262,19 @@ Usage::
 CAAM-specific format.  The key length for new keys is always in bytes.
 Trusted Keys can be 32 - 128 bytes (256 - 1024 bits).
 
+Trusted Keys usage: DCP
+-----------------------
+
+Usage::
+
+    keyctl add trusted name "new keylen" ring
+    keyctl add trusted name "load hex_blob" ring
+    keyctl print keyid
+
+"keyctl print" returns an ASCII hex copy of the sealed key, which is in format
+specific to this DCP key-blob implementation.  The key length for new keys is
+always in bytes. Trusted Keys can be 32 - 128 bytes (256 - 1024 bits).
+
 Encrypted Keys usage
 --------------------
 
@@ -426,3 +470,12 @@ string length.
 privkey is the binary representation of TPM2B_PUBLIC excluding the
 initial TPM2B header which can be reconstructed from the ASN.1 octed
 string length.
+
+DCP Blob Format
+---------------
+
+.. kernel-doc:: security/keys/trusted-keys/trusted_dcp.c
+   :doc: dcp blob format
+
+.. kernel-doc:: security/keys/trusted-keys/trusted_dcp.c
+   :identifiers: struct dcp_blob_fmt
diff --git a/security/keys/trusted-keys/trusted_dcp.c b/security/keys/trusted-keys/trusted_dcp.c
index 16c44aafeab3..b5f81a05be36 100644
--- a/security/keys/trusted-keys/trusted_dcp.c
+++ b/security/keys/trusted-keys/trusted_dcp.c
@@ -19,6 +19,25 @@
 #define DCP_BLOB_VERSION 1
 #define DCP_BLOB_AUTHLEN 16
 
+/**
+ * DOC: dcp blob format
+ *
+ * The Data Co-Processor (DCP) provides hardware-bound AES keys using its
+ * AES encryption engine only. It does not provide direct key sealing/unsealing.
+ * To make DCP hardware encryption keys usable as trust source, we define
+ * our own custom format that uses a hardware-bound key to secure the sealing
+ * key stored in the key blob.
+ *
+ * Whenever a new trusted key using DCP is generated, we generate a random 128-bit
+ * blob encryption key (BEK) and 128-bit nonce. The BEK and nonce are used to
+ * encrypt the trusted key payload using AES-128-GCM.
+ *
+ * The BEK itself is encrypted using the hardware-bound key using the DCP's AES
+ * encryption engine with AES-128-ECB. The encrypted BEK, generated nonce,
+ * BEK-encrypted payload and authentication tag make up the blob format together
+ * with a version number, payload length and authentication tag.
+ */
+
 /**
  * struct dcp_blob_fmt - DCP BLOB format.
  *
-- 
2.35.3


_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

^ permalink raw reply related

* [PATCH v8 4/6] MAINTAINERS: add entry for DCP-based trusted keys
From: David Gstir @ 2024-04-03  7:21 UTC (permalink / raw)
  To: Mimi Zohar, James Bottomley, Jarkko Sakkinen, Herbert Xu,
	David S. Miller
  Cc: David Gstir, Shawn Guo, Jonathan Corbet, Sascha Hauer,
	Pengutronix Kernel Team, Fabio Estevam, NXP Linux Team,
	Ahmad Fatoum, sigma star Kernel Team, David Howells, Li Yang,
	Paul Moore, James Morris, Serge E. Hallyn, Paul E. McKenney,
	Randy Dunlap, Catalin Marinas, Rafael J. Wysocki, Tejun Heo,
	Steven Rostedt (Google), linux-doc, linux-kernel, linux-integrity,
	keyrings, linux-crypto, linux-arm-kernel, linuxppc-dev,
	linux-security-module
In-Reply-To: <20240403072131.54935-1-david@sigma-star.at>

This covers trusted keys backed by NXP's DCP (Data Co-Processor) chip
found in smaller i.MX SoCs.

Signed-off-by: David Gstir <david@sigma-star.at>
Acked-by: Jarkko Sakkinen <jarkko@kernel.org>
---
 MAINTAINERS | 9 +++++++++
 1 file changed, 9 insertions(+)

diff --git a/MAINTAINERS b/MAINTAINERS
index 976a5cea1577..ca7f42ca9338 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -12019,6 +12019,15 @@ S:	Maintained
 F:	include/keys/trusted_caam.h
 F:	security/keys/trusted-keys/trusted_caam.c
 
+KEYS-TRUSTED-DCP
+M:	David Gstir <david@sigma-star.at>
+R:	sigma star Kernel Team <upstream+dcp@sigma-star.at>
+L:	linux-integrity@vger.kernel.org
+L:	keyrings@vger.kernel.org
+S:	Supported
+F:	include/keys/trusted_dcp.h
+F:	security/keys/trusted-keys/trusted_dcp.c
+
 KEYS-TRUSTED-TEE
 M:	Sumit Garg <sumit.garg@linaro.org>
 L:	linux-integrity@vger.kernel.org
-- 
2.35.3


_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

^ permalink raw reply related

* [PATCH v8 3/6] KEYS: trusted: Introduce NXP DCP-backed trusted keys
From: David Gstir @ 2024-04-03  7:21 UTC (permalink / raw)
  To: Mimi Zohar, James Bottomley, Jarkko Sakkinen, Herbert Xu,
	David S. Miller
  Cc: David Gstir, Shawn Guo, Jonathan Corbet, Sascha Hauer,
	Pengutronix Kernel Team, Fabio Estevam, NXP Linux Team,
	Ahmad Fatoum, sigma star Kernel Team, David Howells, Li Yang,
	Paul Moore, James Morris, Serge E. Hallyn, Paul E. McKenney,
	Randy Dunlap, Catalin Marinas, Rafael J. Wysocki, Tejun Heo,
	Steven Rostedt (Google), linux-doc, linux-kernel, linux-integrity,
	keyrings, linux-crypto, linux-arm-kernel, linuxppc-dev,
	linux-security-module, Richard Weinberger, David Oberhollenzer
In-Reply-To: <20240403072131.54935-1-david@sigma-star.at>

DCP (Data Co-Processor) is the little brother of NXP's CAAM IP.
Beside of accelerated crypto operations, it also offers support for
hardware-bound keys. Using this feature it is possible to implement a blob
mechanism similar to what CAAM offers. Unlike on CAAM, constructing and
parsing the blob has to happen in software (i.e. the kernel).

The software-based blob format used by DCP trusted keys encrypts
the payload using AES-128-GCM with a freshly generated random key and nonce.
The random key itself is AES-128-ECB encrypted using the DCP unique
or OTP key.

The DCP trusted key blob format is:
/*
 * struct dcp_blob_fmt - DCP BLOB format.
 *
 * @fmt_version: Format version, currently being %1
 * @blob_key: Random AES 128 key which is used to encrypt @payload,
 *            @blob_key itself is encrypted with OTP or UNIQUE device key in
 *            AES-128-ECB mode by DCP.
 * @nonce: Random nonce used for @payload encryption.
 * @payload_len: Length of the plain text @payload.
 * @payload: The payload itself, encrypted using AES-128-GCM and @blob_key,
 *           GCM auth tag of size AES_BLOCK_SIZE is attached at the end of it.
 *
 * The total size of a DCP BLOB is sizeof(struct dcp_blob_fmt) + @payload_len +
 * AES_BLOCK_SIZE.
 */
struct dcp_blob_fmt {
	__u8 fmt_version;
	__u8 blob_key[AES_KEYSIZE_128];
	__u8 nonce[AES_KEYSIZE_128];
	__le32 payload_len;
	__u8 payload[];
} __packed;

By default the unique key is used. It is also possible to use the
OTP key. While the unique key should be unique it is not documented how
this key is derived. Therefore selection the OTP key is supported as
well via the use_otp_key module parameter.

Co-developed-by: Richard Weinberger <richard@nod.at>
Signed-off-by: Richard Weinberger <richard@nod.at>
Co-developed-by: David Oberhollenzer <david.oberhollenzer@sigma-star.at>
Signed-off-by: David Oberhollenzer <david.oberhollenzer@sigma-star.at>
Signed-off-by: David Gstir <david@sigma-star.at>
Reviewed-by: Jarkko Sakkinen <jarkko@kernel.org>
---
 include/keys/trusted_dcp.h                |  11 +
 security/keys/trusted-keys/Kconfig        |   8 +
 security/keys/trusted-keys/Makefile       |   2 +
 security/keys/trusted-keys/trusted_core.c |   6 +-
 security/keys/trusted-keys/trusted_dcp.c  | 313 ++++++++++++++++++++++
 5 files changed, 339 insertions(+), 1 deletion(-)
 create mode 100644 include/keys/trusted_dcp.h
 create mode 100644 security/keys/trusted-keys/trusted_dcp.c

diff --git a/include/keys/trusted_dcp.h b/include/keys/trusted_dcp.h
new file mode 100644
index 000000000000..9aaa42075b40
--- /dev/null
+++ b/include/keys/trusted_dcp.h
@@ -0,0 +1,11 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+/*
+ * Copyright (C) 2021 sigma star gmbh
+ */
+
+#ifndef TRUSTED_DCP_H
+#define TRUSTED_DCP_H
+
+extern struct trusted_key_ops dcp_trusted_key_ops;
+
+#endif
diff --git a/security/keys/trusted-keys/Kconfig b/security/keys/trusted-keys/Kconfig
index 553dc117f385..1fb8aa001995 100644
--- a/security/keys/trusted-keys/Kconfig
+++ b/security/keys/trusted-keys/Kconfig
@@ -39,6 +39,14 @@ config TRUSTED_KEYS_CAAM
 	  Enable use of NXP's Cryptographic Accelerator and Assurance Module
 	  (CAAM) as trusted key backend.
 
+config TRUSTED_KEYS_DCP
+	bool "DCP-based trusted keys"
+	depends on CRYPTO_DEV_MXS_DCP >= TRUSTED_KEYS
+	default y
+	select HAVE_TRUSTED_KEYS
+	help
+	  Enable use of NXP's DCP (Data Co-Processor) as trusted key backend.
+
 if !HAVE_TRUSTED_KEYS
 	comment "No trust source selected!"
 endif
diff --git a/security/keys/trusted-keys/Makefile b/security/keys/trusted-keys/Makefile
index 735aa0bc08ef..f0f3b27f688b 100644
--- a/security/keys/trusted-keys/Makefile
+++ b/security/keys/trusted-keys/Makefile
@@ -14,3 +14,5 @@ trusted-$(CONFIG_TRUSTED_KEYS_TPM) += tpm2key.asn1.o
 trusted-$(CONFIG_TRUSTED_KEYS_TEE) += trusted_tee.o
 
 trusted-$(CONFIG_TRUSTED_KEYS_CAAM) += trusted_caam.o
+
+trusted-$(CONFIG_TRUSTED_KEYS_DCP) += trusted_dcp.o
diff --git a/security/keys/trusted-keys/trusted_core.c b/security/keys/trusted-keys/trusted_core.c
index fee1ab2c734d..5113aeae5628 100644
--- a/security/keys/trusted-keys/trusted_core.c
+++ b/security/keys/trusted-keys/trusted_core.c
@@ -10,6 +10,7 @@
 #include <keys/trusted-type.h>
 #include <keys/trusted_tee.h>
 #include <keys/trusted_caam.h>
+#include <keys/trusted_dcp.h>
 #include <keys/trusted_tpm.h>
 #include <linux/capability.h>
 #include <linux/err.h>
@@ -30,7 +31,7 @@ MODULE_PARM_DESC(rng, "Select trusted key RNG");
 
 static char *trusted_key_source;
 module_param_named(source, trusted_key_source, charp, 0);
-MODULE_PARM_DESC(source, "Select trusted keys source (tpm, tee or caam)");
+MODULE_PARM_DESC(source, "Select trusted keys source (tpm, tee, caam or dcp)");
 
 static const struct trusted_key_source trusted_key_sources[] = {
 #if defined(CONFIG_TRUSTED_KEYS_TPM)
@@ -42,6 +43,9 @@ static const struct trusted_key_source trusted_key_sources[] = {
 #if defined(CONFIG_TRUSTED_KEYS_CAAM)
 	{ "caam", &trusted_key_caam_ops },
 #endif
+#if defined(CONFIG_TRUSTED_KEYS_DCP)
+	{ "dcp", &dcp_trusted_key_ops },
+#endif
 };
 
 DEFINE_STATIC_CALL_NULL(trusted_key_seal, *trusted_key_sources[0].ops->seal);
diff --git a/security/keys/trusted-keys/trusted_dcp.c b/security/keys/trusted-keys/trusted_dcp.c
new file mode 100644
index 000000000000..16c44aafeab3
--- /dev/null
+++ b/security/keys/trusted-keys/trusted_dcp.c
@@ -0,0 +1,313 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Copyright (C) 2021 sigma star gmbh
+ */
+
+#include <crypto/aead.h>
+#include <crypto/aes.h>
+#include <crypto/algapi.h>
+#include <crypto/gcm.h>
+#include <crypto/skcipher.h>
+#include <keys/trusted-type.h>
+#include <linux/key-type.h>
+#include <linux/module.h>
+#include <linux/printk.h>
+#include <linux/random.h>
+#include <linux/scatterlist.h>
+#include <soc/fsl/dcp.h>
+
+#define DCP_BLOB_VERSION 1
+#define DCP_BLOB_AUTHLEN 16
+
+/**
+ * struct dcp_blob_fmt - DCP BLOB format.
+ *
+ * @fmt_version: Format version, currently being %1.
+ * @blob_key: Random AES 128 key which is used to encrypt @payload,
+ *            @blob_key itself is encrypted with OTP or UNIQUE device key in
+ *            AES-128-ECB mode by DCP.
+ * @nonce: Random nonce used for @payload encryption.
+ * @payload_len: Length of the plain text @payload.
+ * @payload: The payload itself, encrypted using AES-128-GCM and @blob_key,
+ *           GCM auth tag of size DCP_BLOB_AUTHLEN is attached at the end of it.
+ *
+ * The total size of a DCP BLOB is sizeof(struct dcp_blob_fmt) + @payload_len +
+ * DCP_BLOB_AUTHLEN.
+ */
+struct dcp_blob_fmt {
+	__u8 fmt_version;
+	__u8 blob_key[AES_KEYSIZE_128];
+	__u8 nonce[AES_KEYSIZE_128];
+	__le32 payload_len;
+	__u8 payload[];
+} __packed;
+
+static bool use_otp_key;
+module_param_named(dcp_use_otp_key, use_otp_key, bool, 0);
+MODULE_PARM_DESC(dcp_use_otp_key, "Use OTP instead of UNIQUE key for sealing");
+
+static bool skip_zk_test;
+module_param_named(dcp_skip_zk_test, skip_zk_test, bool, 0);
+MODULE_PARM_DESC(dcp_skip_zk_test, "Don't test whether device keys are zero'ed");
+
+static unsigned int calc_blob_len(unsigned int payload_len)
+{
+	return sizeof(struct dcp_blob_fmt) + payload_len + DCP_BLOB_AUTHLEN;
+}
+
+static int do_dcp_crypto(u8 *in, u8 *out, bool do_encrypt)
+{
+	struct skcipher_request *req = NULL;
+	struct scatterlist src_sg, dst_sg;
+	struct crypto_skcipher *tfm;
+	u8 paes_key[DCP_PAES_KEYSIZE];
+	DECLARE_CRYPTO_WAIT(wait);
+	int res = 0;
+
+	if (use_otp_key)
+		paes_key[0] = DCP_PAES_KEY_OTP;
+	else
+		paes_key[0] = DCP_PAES_KEY_UNIQUE;
+
+	tfm = crypto_alloc_skcipher("ecb-paes-dcp", CRYPTO_ALG_INTERNAL,
+				    CRYPTO_ALG_INTERNAL);
+	if (IS_ERR(tfm)) {
+		res = PTR_ERR(tfm);
+		tfm = NULL;
+		goto out;
+	}
+
+	req = skcipher_request_alloc(tfm, GFP_NOFS);
+	if (!req) {
+		res = -ENOMEM;
+		goto out;
+	}
+
+	skcipher_request_set_callback(req, CRYPTO_TFM_REQ_MAY_BACKLOG |
+				      CRYPTO_TFM_REQ_MAY_SLEEP,
+				      crypto_req_done, &wait);
+	res = crypto_skcipher_setkey(tfm, paes_key, sizeof(paes_key));
+	if (res < 0)
+		goto out;
+
+	sg_init_one(&src_sg, in, AES_KEYSIZE_128);
+	sg_init_one(&dst_sg, out, AES_KEYSIZE_128);
+	skcipher_request_set_crypt(req, &src_sg, &dst_sg, AES_KEYSIZE_128,
+				   NULL);
+
+	if (do_encrypt)
+		res = crypto_wait_req(crypto_skcipher_encrypt(req), &wait);
+	else
+		res = crypto_wait_req(crypto_skcipher_decrypt(req), &wait);
+
+out:
+	skcipher_request_free(req);
+	crypto_free_skcipher(tfm);
+
+	return res;
+}
+
+static int do_aead_crypto(u8 *in, u8 *out, size_t len, u8 *key, u8 *nonce,
+			  bool do_encrypt)
+{
+	struct aead_request *aead_req = NULL;
+	struct scatterlist src_sg, dst_sg;
+	struct crypto_aead *aead;
+	int ret;
+
+	aead = crypto_alloc_aead("gcm(aes)", 0, CRYPTO_ALG_ASYNC);
+	if (IS_ERR(aead)) {
+		ret = PTR_ERR(aead);
+		goto out;
+	}
+
+	ret = crypto_aead_setauthsize(aead, DCP_BLOB_AUTHLEN);
+	if (ret < 0) {
+		pr_err("Can't set crypto auth tag len: %d\n", ret);
+		goto free_aead;
+	}
+
+	aead_req = aead_request_alloc(aead, GFP_KERNEL);
+	if (!aead_req) {
+		ret = -ENOMEM;
+		goto free_aead;
+	}
+
+	sg_init_one(&src_sg, in, len);
+	if (do_encrypt) {
+		/*
+		 * If we encrypt our buffer has extra space for the auth tag.
+		 */
+		sg_init_one(&dst_sg, out, len + DCP_BLOB_AUTHLEN);
+	} else {
+		sg_init_one(&dst_sg, out, len);
+	}
+
+	aead_request_set_crypt(aead_req, &src_sg, &dst_sg, len, nonce);
+	aead_request_set_callback(aead_req, CRYPTO_TFM_REQ_MAY_SLEEP, NULL,
+				  NULL);
+	aead_request_set_ad(aead_req, 0);
+
+	if (crypto_aead_setkey(aead, key, AES_KEYSIZE_128)) {
+		pr_err("Can't set crypto AEAD key\n");
+		ret = -EINVAL;
+		goto free_req;
+	}
+
+	if (do_encrypt)
+		ret = crypto_aead_encrypt(aead_req);
+	else
+		ret = crypto_aead_decrypt(aead_req);
+
+free_req:
+	aead_request_free(aead_req);
+free_aead:
+	crypto_free_aead(aead);
+out:
+	return ret;
+}
+
+static int decrypt_blob_key(u8 *key)
+{
+	return do_dcp_crypto(key, key, false);
+}
+
+static int encrypt_blob_key(u8 *key)
+{
+	return do_dcp_crypto(key, key, true);
+}
+
+static int trusted_dcp_seal(struct trusted_key_payload *p, char *datablob)
+{
+	struct dcp_blob_fmt *b = (struct dcp_blob_fmt *)p->blob;
+	int blen, ret;
+
+	blen = calc_blob_len(p->key_len);
+	if (blen > MAX_BLOB_SIZE)
+		return -E2BIG;
+
+	b->fmt_version = DCP_BLOB_VERSION;
+	get_random_bytes(b->nonce, AES_KEYSIZE_128);
+	get_random_bytes(b->blob_key, AES_KEYSIZE_128);
+
+	ret = do_aead_crypto(p->key, b->payload, p->key_len, b->blob_key,
+			     b->nonce, true);
+	if (ret) {
+		pr_err("Unable to encrypt blob payload: %i\n", ret);
+		return ret;
+	}
+
+	ret = encrypt_blob_key(b->blob_key);
+	if (ret) {
+		pr_err("Unable to encrypt blob key: %i\n", ret);
+		return ret;
+	}
+
+	b->payload_len = get_unaligned_le32(&p->key_len);
+	p->blob_len = blen;
+	return 0;
+}
+
+static int trusted_dcp_unseal(struct trusted_key_payload *p, char *datablob)
+{
+	struct dcp_blob_fmt *b = (struct dcp_blob_fmt *)p->blob;
+	int blen, ret;
+
+	if (b->fmt_version != DCP_BLOB_VERSION) {
+		pr_err("DCP blob has bad version: %i, expected %i\n",
+		       b->fmt_version, DCP_BLOB_VERSION);
+		ret = -EINVAL;
+		goto out;
+	}
+
+	p->key_len = le32_to_cpu(b->payload_len);
+	blen = calc_blob_len(p->key_len);
+	if (blen != p->blob_len) {
+		pr_err("DCP blob has bad length: %i != %i\n", blen,
+		       p->blob_len);
+		ret = -EINVAL;
+		goto out;
+	}
+
+	ret = decrypt_blob_key(b->blob_key);
+	if (ret) {
+		pr_err("Unable to decrypt blob key: %i\n", ret);
+		goto out;
+	}
+
+	ret = do_aead_crypto(b->payload, p->key, p->key_len + DCP_BLOB_AUTHLEN,
+			     b->blob_key, b->nonce, false);
+	if (ret) {
+		pr_err("Unwrap of DCP payload failed: %i\n", ret);
+		goto out;
+	}
+
+	ret = 0;
+out:
+	return ret;
+}
+
+static int test_for_zero_key(void)
+{
+	/*
+	 * Encrypting a plaintext of all 0x55 bytes will yield
+	 * this ciphertext in case the DCP test key is used.
+	 */
+	static const u8 bad[] = {0x9a, 0xda, 0xe0, 0x54, 0xf6, 0x3d, 0xfa, 0xff,
+				 0x5e, 0xa1, 0x8e, 0x45, 0xed, 0xf6, 0xea, 0x6f};
+	void *buf = NULL;
+	int ret = 0;
+
+	if (skip_zk_test)
+		goto out;
+
+	buf = kmalloc(AES_BLOCK_SIZE, GFP_KERNEL);
+	if (!buf) {
+		ret = -ENOMEM;
+		goto out;
+	}
+
+	memset(buf, 0x55, AES_BLOCK_SIZE);
+
+	ret = do_dcp_crypto(buf, buf, true);
+	if (ret)
+		goto out;
+
+	if (memcmp(buf, bad, AES_BLOCK_SIZE) == 0) {
+		pr_warn("Device neither in secure nor trusted mode!\n");
+		ret = -EINVAL;
+	}
+out:
+	kfree(buf);
+	return ret;
+}
+
+static int trusted_dcp_init(void)
+{
+	int ret;
+
+	if (use_otp_key)
+		pr_info("Using DCP OTP key\n");
+
+	ret = test_for_zero_key();
+	if (ret) {
+		pr_warn("Test for zero'ed keys failed: %i\n", ret);
+
+		return -EINVAL;
+	}
+
+	return register_key_type(&key_type_trusted);
+}
+
+static void trusted_dcp_exit(void)
+{
+	unregister_key_type(&key_type_trusted);
+}
+
+struct trusted_key_ops dcp_trusted_key_ops = {
+	.exit = trusted_dcp_exit,
+	.init = trusted_dcp_init,
+	.seal = trusted_dcp_seal,
+	.unseal = trusted_dcp_unseal,
+	.migratable = 0,
+};
-- 
2.35.3


_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

^ permalink raw reply related

* [PATCH v8 1/6] crypto: mxs-dcp: Add support for hardware-bound keys
From: David Gstir @ 2024-04-03  7:21 UTC (permalink / raw)
  To: Mimi Zohar, James Bottomley, Jarkko Sakkinen, Herbert Xu,
	David S. Miller
  Cc: David Gstir, Shawn Guo, Jonathan Corbet, Sascha Hauer,
	Pengutronix Kernel Team, Fabio Estevam, NXP Linux Team,
	Ahmad Fatoum, sigma star Kernel Team, David Howells, Li Yang,
	Paul Moore, James Morris, Serge E. Hallyn, Paul E. McKenney,
	Randy Dunlap, Catalin Marinas, Rafael J. Wysocki, Tejun Heo,
	Steven Rostedt (Google), linux-doc, linux-kernel, linux-integrity,
	keyrings, linux-crypto, linux-arm-kernel, linuxppc-dev,
	linux-security-module, Richard Weinberger, David Oberhollenzer
In-Reply-To: <20240403072131.54935-1-david@sigma-star.at>

DCP (Data Co-Processor) is able to derive private keys for a fused
random seed, which can be referenced by handle but not accessed by
the CPU. Similarly, DCP is able to store arbitrary keys in four
dedicated key slots located in its secure memory area (internal SRAM).
These keys can be used to perform AES encryption.

Expose these derived keys and key slots through the crypto API via their
handle. The main purpose is to add DCP-backed trusted keys. Other
use cases are possible too (see similar existing paes implementations),
but these should carefully be evaluated as e.g. enabling AF_ALG will
give userspace full access to use keys. In scenarios with untrustworthy
userspace, this will enable en-/decryption oracles.

Co-developed-by: Richard Weinberger <richard@nod.at>
Signed-off-by: Richard Weinberger <richard@nod.at>
Co-developed-by: David Oberhollenzer <david.oberhollenzer@sigma-star.at>
Signed-off-by: David Oberhollenzer <david.oberhollenzer@sigma-star.at>
Signed-off-by: David Gstir <david@sigma-star.at>
Acked-by: Herbert Xu <herbert@gondor.apana.org.au>
Reviewed-by: Jarkko Sakkinen <jarkko@kernel.org>
---
 drivers/crypto/mxs-dcp.c | 104 ++++++++++++++++++++++++++++++++++-----
 include/soc/fsl/dcp.h    |  20 ++++++++
 2 files changed, 113 insertions(+), 11 deletions(-)
 create mode 100644 include/soc/fsl/dcp.h

diff --git a/drivers/crypto/mxs-dcp.c b/drivers/crypto/mxs-dcp.c
index 2b3ebe0db3a6..057d73c370b7 100644
--- a/drivers/crypto/mxs-dcp.c
+++ b/drivers/crypto/mxs-dcp.c
@@ -15,6 +15,7 @@
 #include <linux/platform_device.h>
 #include <linux/stmp_device.h>
 #include <linux/clk.h>
+#include <soc/fsl/dcp.h>
 
 #include <crypto/aes.h>
 #include <crypto/sha1.h>
@@ -101,6 +102,7 @@ struct dcp_async_ctx {
 	struct crypto_skcipher		*fallback;
 	unsigned int			key_len;
 	uint8_t				key[AES_KEYSIZE_128];
+	bool				key_referenced;
 };
 
 struct dcp_aes_req_ctx {
@@ -155,6 +157,7 @@ static struct dcp *global_sdcp;
 #define MXS_DCP_CONTROL0_HASH_TERM		(1 << 13)
 #define MXS_DCP_CONTROL0_HASH_INIT		(1 << 12)
 #define MXS_DCP_CONTROL0_PAYLOAD_KEY		(1 << 11)
+#define MXS_DCP_CONTROL0_OTP_KEY		(1 << 10)
 #define MXS_DCP_CONTROL0_CIPHER_ENCRYPT		(1 << 8)
 #define MXS_DCP_CONTROL0_CIPHER_INIT		(1 << 9)
 #define MXS_DCP_CONTROL0_ENABLE_HASH		(1 << 6)
@@ -168,6 +171,8 @@ static struct dcp *global_sdcp;
 #define MXS_DCP_CONTROL1_CIPHER_MODE_ECB	(0 << 4)
 #define MXS_DCP_CONTROL1_CIPHER_SELECT_AES128	(0 << 0)
 
+#define MXS_DCP_CONTROL1_KEY_SELECT_SHIFT	8
+
 static int mxs_dcp_start_dma(struct dcp_async_ctx *actx)
 {
 	int dma_err;
@@ -224,13 +229,16 @@ static int mxs_dcp_run_aes(struct dcp_async_ctx *actx,
 	struct dcp *sdcp = global_sdcp;
 	struct dcp_dma_desc *desc = &sdcp->coh->desc[actx->chan];
 	struct dcp_aes_req_ctx *rctx = skcipher_request_ctx(req);
+	bool key_referenced = actx->key_referenced;
 	int ret;
 
-	key_phys = dma_map_single(sdcp->dev, sdcp->coh->aes_key,
-				  2 * AES_KEYSIZE_128, DMA_TO_DEVICE);
-	ret = dma_mapping_error(sdcp->dev, key_phys);
-	if (ret)
-		return ret;
+	if (!key_referenced) {
+		key_phys = dma_map_single(sdcp->dev, sdcp->coh->aes_key,
+					  2 * AES_KEYSIZE_128, DMA_TO_DEVICE);
+		ret = dma_mapping_error(sdcp->dev, key_phys);
+		if (ret)
+			return ret;
+	}
 
 	src_phys = dma_map_single(sdcp->dev, sdcp->coh->aes_in_buf,
 				  DCP_BUF_SZ, DMA_TO_DEVICE);
@@ -255,8 +263,12 @@ static int mxs_dcp_run_aes(struct dcp_async_ctx *actx,
 		    MXS_DCP_CONTROL0_INTERRUPT |
 		    MXS_DCP_CONTROL0_ENABLE_CIPHER;
 
-	/* Payload contains the key. */
-	desc->control0 |= MXS_DCP_CONTROL0_PAYLOAD_KEY;
+	if (key_referenced)
+		/* Set OTP key bit to select the key via KEY_SELECT. */
+		desc->control0 |= MXS_DCP_CONTROL0_OTP_KEY;
+	else
+		/* Payload contains the key. */
+		desc->control0 |= MXS_DCP_CONTROL0_PAYLOAD_KEY;
 
 	if (rctx->enc)
 		desc->control0 |= MXS_DCP_CONTROL0_CIPHER_ENCRYPT;
@@ -270,6 +282,9 @@ static int mxs_dcp_run_aes(struct dcp_async_ctx *actx,
 	else
 		desc->control1 |= MXS_DCP_CONTROL1_CIPHER_MODE_CBC;
 
+	if (key_referenced)
+		desc->control1 |= sdcp->coh->aes_key[0] << MXS_DCP_CONTROL1_KEY_SELECT_SHIFT;
+
 	desc->next_cmd_addr = 0;
 	desc->source = src_phys;
 	desc->destination = dst_phys;
@@ -284,9 +299,9 @@ static int mxs_dcp_run_aes(struct dcp_async_ctx *actx,
 err_dst:
 	dma_unmap_single(sdcp->dev, src_phys, DCP_BUF_SZ, DMA_TO_DEVICE);
 err_src:
-	dma_unmap_single(sdcp->dev, key_phys, 2 * AES_KEYSIZE_128,
-			 DMA_TO_DEVICE);
-
+	if (!key_referenced)
+		dma_unmap_single(sdcp->dev, key_phys, 2 * AES_KEYSIZE_128,
+				 DMA_TO_DEVICE);
 	return ret;
 }
 
@@ -453,7 +468,7 @@ static int mxs_dcp_aes_enqueue(struct skcipher_request *req, int enc, int ecb)
 	struct dcp_aes_req_ctx *rctx = skcipher_request_ctx(req);
 	int ret;
 
-	if (unlikely(actx->key_len != AES_KEYSIZE_128))
+	if (unlikely(actx->key_len != AES_KEYSIZE_128 && !actx->key_referenced))
 		return mxs_dcp_block_fallback(req, enc);
 
 	rctx->enc = enc;
@@ -500,6 +515,7 @@ static int mxs_dcp_aes_setkey(struct crypto_skcipher *tfm, const u8 *key,
 	 * there can still be an operation in progress.
 	 */
 	actx->key_len = len;
+	actx->key_referenced = false;
 	if (len == AES_KEYSIZE_128) {
 		memcpy(actx->key, key, len);
 		return 0;
@@ -516,6 +532,32 @@ static int mxs_dcp_aes_setkey(struct crypto_skcipher *tfm, const u8 *key,
 	return crypto_skcipher_setkey(actx->fallback, key, len);
 }
 
+static int mxs_dcp_aes_setrefkey(struct crypto_skcipher *tfm, const u8 *key,
+				 unsigned int len)
+{
+	struct dcp_async_ctx *actx = crypto_skcipher_ctx(tfm);
+
+	if (len != DCP_PAES_KEYSIZE)
+		return -EINVAL;
+
+	switch (key[0]) {
+	case DCP_PAES_KEY_SLOT0:
+	case DCP_PAES_KEY_SLOT1:
+	case DCP_PAES_KEY_SLOT2:
+	case DCP_PAES_KEY_SLOT3:
+	case DCP_PAES_KEY_UNIQUE:
+	case DCP_PAES_KEY_OTP:
+		memcpy(actx->key, key, len);
+		actx->key_len = len;
+		actx->key_referenced = true;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
 static int mxs_dcp_aes_fallback_init_tfm(struct crypto_skcipher *tfm)
 {
 	const char *name = crypto_tfm_alg_name(crypto_skcipher_tfm(tfm));
@@ -539,6 +581,13 @@ static void mxs_dcp_aes_fallback_exit_tfm(struct crypto_skcipher *tfm)
 	crypto_free_skcipher(actx->fallback);
 }
 
+static int mxs_dcp_paes_init_tfm(struct crypto_skcipher *tfm)
+{
+	crypto_skcipher_set_reqsize(tfm, sizeof(struct dcp_aes_req_ctx));
+
+	return 0;
+}
+
 /*
  * Hashing (SHA1/SHA256)
  */
@@ -889,6 +938,39 @@ static struct skcipher_alg dcp_aes_algs[] = {
 		.ivsize			= AES_BLOCK_SIZE,
 		.init			= mxs_dcp_aes_fallback_init_tfm,
 		.exit			= mxs_dcp_aes_fallback_exit_tfm,
+	}, {
+		.base.cra_name		= "ecb(paes)",
+		.base.cra_driver_name	= "ecb-paes-dcp",
+		.base.cra_priority	= 401,
+		.base.cra_alignmask	= 15,
+		.base.cra_flags		= CRYPTO_ALG_ASYNC | CRYPTO_ALG_INTERNAL,
+		.base.cra_blocksize	= AES_BLOCK_SIZE,
+		.base.cra_ctxsize	= sizeof(struct dcp_async_ctx),
+		.base.cra_module	= THIS_MODULE,
+
+		.min_keysize		= DCP_PAES_KEYSIZE,
+		.max_keysize		= DCP_PAES_KEYSIZE,
+		.setkey			= mxs_dcp_aes_setrefkey,
+		.encrypt		= mxs_dcp_aes_ecb_encrypt,
+		.decrypt		= mxs_dcp_aes_ecb_decrypt,
+		.init			= mxs_dcp_paes_init_tfm,
+	}, {
+		.base.cra_name		= "cbc(paes)",
+		.base.cra_driver_name	= "cbc-paes-dcp",
+		.base.cra_priority	= 401,
+		.base.cra_alignmask	= 15,
+		.base.cra_flags		= CRYPTO_ALG_ASYNC | CRYPTO_ALG_INTERNAL,
+		.base.cra_blocksize	= AES_BLOCK_SIZE,
+		.base.cra_ctxsize	= sizeof(struct dcp_async_ctx),
+		.base.cra_module	= THIS_MODULE,
+
+		.min_keysize		= DCP_PAES_KEYSIZE,
+		.max_keysize		= DCP_PAES_KEYSIZE,
+		.setkey			= mxs_dcp_aes_setrefkey,
+		.encrypt		= mxs_dcp_aes_cbc_encrypt,
+		.decrypt		= mxs_dcp_aes_cbc_decrypt,
+		.ivsize			= AES_BLOCK_SIZE,
+		.init			= mxs_dcp_paes_init_tfm,
 	},
 };
 
diff --git a/include/soc/fsl/dcp.h b/include/soc/fsl/dcp.h
new file mode 100644
index 000000000000..3ec335d8ca8b
--- /dev/null
+++ b/include/soc/fsl/dcp.h
@@ -0,0 +1,20 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+/*
+ * Copyright (C) 2021 sigma star gmbh
+ *
+ * Specifies paes key slot handles for NXP's DCP (Data Co-Processor) to be used
+ * with the crypto_skcipher_setkey().
+ */
+
+#ifndef MXS_DCP_H
+#define MXS_DCP_H
+
+#define DCP_PAES_KEYSIZE 1
+#define DCP_PAES_KEY_SLOT0 0x00
+#define DCP_PAES_KEY_SLOT1 0x01
+#define DCP_PAES_KEY_SLOT2 0x02
+#define DCP_PAES_KEY_SLOT3 0x03
+#define DCP_PAES_KEY_UNIQUE 0xfe
+#define DCP_PAES_KEY_OTP 0xff
+
+#endif /* MXS_DCP_H */
-- 
2.35.3


_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

^ permalink raw reply related

* [PATCH v8 5/6] docs: document DCP-backed trusted keys kernel params
From: David Gstir @ 2024-04-03  7:21 UTC (permalink / raw)
  To: Mimi Zohar, James Bottomley, Jarkko Sakkinen, Herbert Xu,
	David S. Miller
  Cc: David Gstir, Shawn Guo, Jonathan Corbet, Sascha Hauer,
	Pengutronix Kernel Team, Fabio Estevam, NXP Linux Team,
	Ahmad Fatoum, sigma star Kernel Team, David Howells, Li Yang,
	Paul Moore, James Morris, Serge E. Hallyn, Paul E. McKenney,
	Randy Dunlap, Catalin Marinas, Rafael J. Wysocki, Tejun Heo,
	Steven Rostedt (Google), linux-doc, linux-kernel, linux-integrity,
	keyrings, linux-crypto, linux-arm-kernel, linuxppc-dev,
	linux-security-module, Richard Weinberger, David Oberhollenzer
In-Reply-To: <20240403072131.54935-1-david@sigma-star.at>

Document the kernel parameters trusted.dcp_use_otp_key
and trusted.dcp_skip_zk_test for DCP-backed trusted keys.

Co-developed-by: Richard Weinberger <richard@nod.at>
Signed-off-by: Richard Weinberger <richard@nod.at>
Co-developed-by: David Oberhollenzer <david.oberhollenzer@sigma-star.at>
Signed-off-by: David Oberhollenzer <david.oberhollenzer@sigma-star.at>
Signed-off-by: David Gstir <david@sigma-star.at>
Reviewed-by: Jarkko Sakkinen <jarkko@kernel.org>
---
 Documentation/admin-guide/kernel-parameters.txt | 13 +++++++++++++
 1 file changed, 13 insertions(+)

diff --git a/Documentation/admin-guide/kernel-parameters.txt b/Documentation/admin-guide/kernel-parameters.txt
index 24c02c704049..3a59abf06039 100644
--- a/Documentation/admin-guide/kernel-parameters.txt
+++ b/Documentation/admin-guide/kernel-parameters.txt
@@ -6698,6 +6698,7 @@
 			- "tpm"
 			- "tee"
 			- "caam"
+			- "dcp"
 			If not specified then it defaults to iterating through
 			the trust source list starting with TPM and assigns the
 			first trust source as a backend which is initialized
@@ -6713,6 +6714,18 @@
 			If not specified, "default" is used. In this case,
 			the RNG's choice is left to each individual trust source.
 
+	trusted.dcp_use_otp_key
+			This is intended to be used in combination with
+			trusted.source=dcp and will select the DCP OTP key
+			instead of the DCP UNIQUE key blob encryption.
+
+	trusted.dcp_skip_zk_test
+			This is intended to be used in combination with
+			trusted.source=dcp and will disable the check if the
+			blob key is all zeros. This is helpful for situations where
+			having this key zero'ed is acceptable. E.g. in testing
+			scenarios.
+
 	tsc=		Disable clocksource stability checks for TSC.
 			Format: <string>
 			[x86] reliable: mark tsc clocksource as reliable, this
-- 
2.35.3


_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

^ permalink raw reply related

* [PATCH v8 2/6] KEYS: trusted: improve scalability of trust source config
From: David Gstir @ 2024-04-03  7:21 UTC (permalink / raw)
  To: Mimi Zohar, James Bottomley, Jarkko Sakkinen, Herbert Xu,
	David S. Miller
  Cc: David Gstir, Shawn Guo, Jonathan Corbet, Sascha Hauer,
	Pengutronix Kernel Team, Fabio Estevam, NXP Linux Team,
	Ahmad Fatoum, sigma star Kernel Team, David Howells, Li Yang,
	Paul Moore, James Morris, Serge E. Hallyn, Paul E. McKenney,
	Randy Dunlap, Catalin Marinas, Rafael J. Wysocki, Tejun Heo,
	Steven Rostedt (Google), linux-doc, linux-kernel, linux-integrity,
	keyrings, linux-crypto, linux-arm-kernel, linuxppc-dev,
	linux-security-module
In-Reply-To: <20240403072131.54935-1-david@sigma-star.at>

Enabling trusted keys requires at least one trust source implementation
(currently TPM, TEE or CAAM) to be enabled. Currently, this is
done by checking each trust source's config option individually.
This does not scale when more trust sources like the one for DCP
are added, because the condition will get long and hard to read.

Add config HAVE_TRUSTED_KEYS which is set to true by each trust source
once its enabled and adapt the check for having at least one active trust
source to use this option. Whenever a new trust source is added, it now
needs to select HAVE_TRUSTED_KEYS.

Signed-off-by: David Gstir <david@sigma-star.at>
Tested-by: Jarkko Sakkinen <jarkko@kernel.org> # for TRUSTED_KEYS_TPM
Reviewed-by: Jarkko Sakkinen <jarkko@kernel.org>
---
 security/keys/trusted-keys/Kconfig | 10 ++++++++--
 1 file changed, 8 insertions(+), 2 deletions(-)

diff --git a/security/keys/trusted-keys/Kconfig b/security/keys/trusted-keys/Kconfig
index dbfdd8536468..553dc117f385 100644
--- a/security/keys/trusted-keys/Kconfig
+++ b/security/keys/trusted-keys/Kconfig
@@ -1,3 +1,6 @@
+config HAVE_TRUSTED_KEYS
+	bool
+
 config TRUSTED_KEYS_TPM
 	bool "TPM-based trusted keys"
 	depends on TCG_TPM >= TRUSTED_KEYS
@@ -9,6 +12,7 @@ config TRUSTED_KEYS_TPM
 	select ASN1_ENCODER
 	select OID_REGISTRY
 	select ASN1
+	select HAVE_TRUSTED_KEYS
 	help
 	  Enable use of the Trusted Platform Module (TPM) as trusted key
 	  backend. Trusted keys are random number symmetric keys,
@@ -20,6 +24,7 @@ config TRUSTED_KEYS_TEE
 	bool "TEE-based trusted keys"
 	depends on TEE >= TRUSTED_KEYS
 	default y
+	select HAVE_TRUSTED_KEYS
 	help
 	  Enable use of the Trusted Execution Environment (TEE) as trusted
 	  key backend.
@@ -29,10 +34,11 @@ config TRUSTED_KEYS_CAAM
 	depends on CRYPTO_DEV_FSL_CAAM_JR >= TRUSTED_KEYS
 	select CRYPTO_DEV_FSL_CAAM_BLOB_GEN
 	default y
+	select HAVE_TRUSTED_KEYS
 	help
 	  Enable use of NXP's Cryptographic Accelerator and Assurance Module
 	  (CAAM) as trusted key backend.
 
-if !TRUSTED_KEYS_TPM && !TRUSTED_KEYS_TEE && !TRUSTED_KEYS_CAAM
-comment "No trust source selected!"
+if !HAVE_TRUSTED_KEYS
+	comment "No trust source selected!"
 endif
-- 
2.35.3


_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

^ permalink raw reply related

* [PATCH v8 0/6] DCP as trusted keys backend
From: David Gstir @ 2024-04-03  7:21 UTC (permalink / raw)
  To: Mimi Zohar, James Bottomley, Jarkko Sakkinen, Herbert Xu,
	David S. Miller
  Cc: David Gstir, Shawn Guo, Jonathan Corbet, Sascha Hauer,
	Pengutronix Kernel Team, Fabio Estevam, NXP Linux Team,
	Ahmad Fatoum, sigma star Kernel Team, David Howells, Li Yang,
	Paul Moore, James Morris, Serge E. Hallyn, Paul E. McKenney,
	Randy Dunlap, Catalin Marinas, Rafael J. Wysocki, Tejun Heo,
	Steven Rostedt (Google), linux-doc, linux-kernel, linux-integrity,
	keyrings, linux-crypto, linux-arm-kernel, linuxppc-dev,
	linux-security-module

This is a revival of the previous patch set submitted by Richard Weinberger:
https://lore.kernel.org/linux-integrity/20210614201620.30451-1-richard@nod.at/

After having been thoroughly reviewed by Jarkko, it would be great if this
could go into 6.10. :-)

v7 is here:
https://lore.kernel.org/keyrings/20240327082454.13729-1-david@sigma-star.at/

v7 -> v8:
- Add Reviewed-by from Jarkko Sakkinen for patches #2 and #5
- Use kernel-doc for DCP blob format documentation instead of copy-pasting as
  suggested by Jarkko Sakkinen
- Fix wording in docs for trusted.dcp_skip_zk_test kernel param
v6 -> v7:
- Add Reviewed-by from Jarkko Sakkinen for patches #1 and #3
- Improved commit messages
- Changed log level for non-trusted/secure mode check from error to warning
v5 -> v6:
- Cleaned up coding style and commit messages to make the whole series more
  coherent as suggested by Jarkko Sakkinen
- Added Acked-By from Jarkko Sakkinen to patch #4 - thanks!
- Rebased against next-20240307
v4 -> v5:
- Make Kconfig for trust source check scalable as suggested by Jarkko Sakkinen
- Add Acked-By from Herbert Xu to patch #1 - thanks!
v3 -> v4:
- Split changes on MAINTAINERS and documentation into dedicated patches
- Use more concise wording in commit messages as suggested by Jarkko Sakkinen
v2 -> v3:
- Addressed review comments from Jarkko Sakkinen
v1 -> v2:
- Revive and rebase to latest version
- Include review comments from Ahmad Fatoum

The Data Co-Processor (DCP) is an IP core built into many NXP SoCs such
as i.mx6ull.

Similar to the CAAM engine used in more powerful SoCs, DCP can AES-
encrypt/decrypt user data using a unique, never-disclosed,
device-specific key. Unlike CAAM though, it cannot directly wrap and
unwrap blobs in hardware. As DCP offers only the bare minimum feature
set and a blob mechanism needs aid from software. A blob in this case
is a piece of sensitive data (e.g. a key) that is encrypted and
authenticated using the device-specific key so that unwrapping can only
be done on the hardware where the blob was wrapped.

This patch series adds a DCP based, trusted-key backend and is similar
in spirit to the one by Ahmad Fatoum [0] that does the same for CAAM.
It is of interest for similar use cases as the CAAM patch set, but for
lower end devices, where CAAM is not available.

Because constructing and parsing the blob has to happen in software,
we needed to decide on a blob format and chose the following:

struct dcp_blob_fmt {
	__u8 fmt_version;
	__u8 blob_key[AES_KEYSIZE_128];
	__u8 nonce[AES_KEYSIZE_128];
	__le32 payload_len;
	__u8 payload[];
} __packed;

The `fmt_version` is currently 1.

The encrypted key is stored in the payload area. It is AES-128-GCM
encrypted using `blob_key` and `nonce`, GCM auth tag is attached at
the end of the payload (`payload_len` does not include the size of
the auth tag).

The `blob_key` itself is encrypted in AES-128-ECB mode by DCP using
the OTP or UNIQUE device key. A new `blob_key` and `nonce` are generated
randomly, when sealing/exporting the DCP blob.

This patchset was tested with dm-crypt on an i.MX6ULL board.

[0] https://lore.kernel.org/keyrings/20220513145705.2080323-1-a.fatoum@pengutronix.de/

David Gstir (6):
  crypto: mxs-dcp: Add support for hardware-bound keys
  KEYS: trusted: improve scalability of trust source config
  KEYS: trusted: Introduce NXP DCP-backed trusted keys
  MAINTAINERS: add entry for DCP-based trusted keys
  docs: document DCP-backed trusted keys kernel params
  docs: trusted-encrypted: add DCP as new trust source

 .../admin-guide/kernel-parameters.txt         |  13 +
 .../security/keys/trusted-encrypted.rst       |  53 +++
 MAINTAINERS                                   |   9 +
 drivers/crypto/mxs-dcp.c                      | 104 +++++-
 include/keys/trusted_dcp.h                    |  11 +
 include/soc/fsl/dcp.h                         |  20 ++
 security/keys/trusted-keys/Kconfig            |  18 +-
 security/keys/trusted-keys/Makefile           |   2 +
 security/keys/trusted-keys/trusted_core.c     |   6 +-
 security/keys/trusted-keys/trusted_dcp.c      | 332 ++++++++++++++++++
 10 files changed, 554 insertions(+), 14 deletions(-)
 create mode 100644 include/keys/trusted_dcp.h
 create mode 100644 include/soc/fsl/dcp.h
 create mode 100644 security/keys/trusted-keys/trusted_dcp.c

-- 
2.35.3


_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

^ permalink raw reply

* [PATCH v4 7/9] drm/mediatek: Add secure layer config support for ovl
From: Shawn Sung @ 2024-04-03  7:07 UTC (permalink / raw)
  To: Chun-Kuang Hu
  Cc: Philipp Zabel, David Airlie, Daniel Vetter, Matthias Brugger,
	AngeloGioacchino Del Regno, Maarten Lankhorst, Maxime Ripard,
	Thomas Zimmermann, Sumit Semwal, Christian König, dri-devel,
	linux-mediatek, linux-kernel, linux-arm-kernel, linux-media,
	linaro-mm-sig, Jason-JH.Lin, Hsiao Chien Sung
In-Reply-To: <20240403070732.22085-1-shawn.sung@mediatek.com>

From: "Jason-JH.Lin" <jason-jh.lin@mediatek.com>

Add secure layer config support for ovl.

TODO:
1. Move DISP_REG_OVL_SECURE setting to secure world.
2. Change the parameter register address in mtk_ddp_sec_write()
   from "u32 addr" to "struct cmdq_client_reg *cmdq_reg".

Signed-off-by: Jason-JH.Lin <jason-jh.lin@mediatek.com>
Signed-off-by: Hsiao Chien Sung <shawn.sung@mediatek.com>
---
 drivers/gpu/drm/mediatek/mtk_ddp_comp.c |  1 +
 drivers/gpu/drm/mediatek/mtk_disp_drv.h |  2 ++
 drivers/gpu/drm/mediatek/mtk_disp_ovl.c | 30 +++++++++++++++++++++++--
 3 files changed, 31 insertions(+), 2 deletions(-)

diff --git a/drivers/gpu/drm/mediatek/mtk_ddp_comp.c b/drivers/gpu/drm/mediatek/mtk_ddp_comp.c
index cda0da4848029..b2f59e54c3f4b 100644
--- a/drivers/gpu/drm/mediatek/mtk_ddp_comp.c
+++ b/drivers/gpu/drm/mediatek/mtk_ddp_comp.c
@@ -382,6 +382,7 @@ static const struct mtk_ddp_comp_funcs ddp_ovl = {
 	.bgclr_in_off = mtk_ovl_bgclr_in_off,
 	.get_formats = mtk_ovl_get_formats,
 	.get_num_formats = mtk_ovl_get_num_formats,
+	.get_sec_port = mtk_ovl_get_sec_port,
 };
 
 static const struct mtk_ddp_comp_funcs ddp_postmask = {
diff --git a/drivers/gpu/drm/mediatek/mtk_disp_drv.h b/drivers/gpu/drm/mediatek/mtk_disp_drv.h
index d2c8fac468798..c4e1b5b8a2e31 100644
--- a/drivers/gpu/drm/mediatek/mtk_disp_drv.h
+++ b/drivers/gpu/drm/mediatek/mtk_disp_drv.h
@@ -9,6 +9,7 @@
 #include <linux/soc/mediatek/mtk-cmdq.h>
 #include <linux/soc/mediatek/mtk-mmsys.h>
 #include <linux/soc/mediatek/mtk-mutex.h>
+#include "mtk_ddp_comp.h"
 #include "mtk_mdp_rdma.h"
 #include "mtk_plane.h"
 
@@ -84,6 +85,7 @@ void mtk_ovl_clk_disable(struct device *dev);
 void mtk_ovl_config(struct device *dev, unsigned int w,
 		    unsigned int h, unsigned int vrefresh,
 		    unsigned int bpc, struct cmdq_pkt *cmdq_pkt);
+u64 mtk_ovl_get_sec_port(struct mtk_ddp_comp *comp, unsigned int idx);
 int mtk_ovl_layer_check(struct device *dev, unsigned int idx,
 			struct mtk_plane_state *mtk_state);
 void mtk_ovl_layer_config(struct device *dev, unsigned int idx,
diff --git a/drivers/gpu/drm/mediatek/mtk_disp_ovl.c b/drivers/gpu/drm/mediatek/mtk_disp_ovl.c
index 279e6193e7975..8cee64495cd04 100644
--- a/drivers/gpu/drm/mediatek/mtk_disp_ovl.c
+++ b/drivers/gpu/drm/mediatek/mtk_disp_ovl.c
@@ -74,6 +74,7 @@
 #define DISP_REG_OVL_ADDR(ovl, n)		((ovl)->data->addr + 0x20 * (n))
 #define DISP_REG_OVL_HDR_ADDR(ovl, n)		((ovl)->data->addr + 0x20 * (n) + 0x04)
 #define DISP_REG_OVL_HDR_PITCH(ovl, n)		((ovl)->data->addr + 0x20 * (n) + 0x08)
+#define DISP_REG_OVL_SECURE			0x0fc0
 
 #define GMC_THRESHOLD_BITS	16
 #define GMC_THRESHOLD_HIGH	((1 << GMC_THRESHOLD_BITS) / 4)
@@ -218,6 +219,16 @@ void mtk_ovl_crc_read(struct device *dev)
 	mtk_crtc_read_crc(&ovl->crc, ovl->regs);
 }
 
+u64 mtk_ovl_get_sec_port(struct mtk_ddp_comp *comp, unsigned int idx)
+{
+	if (comp->id == DDP_COMPONENT_OVL0)
+		return BIT_ULL(CMDQ_SEC_DISP_OVL0);
+	else if (comp->id == DDP_COMPONENT_OVL1)
+		return BIT_ULL(CMDQ_SEC_DISP_OVL1);
+
+	return 0;
+}
+
 static irqreturn_t mtk_disp_ovl_irq_handler(int irq, void *dev_id)
 {
 	struct mtk_disp_ovl *priv = dev_id;
@@ -665,8 +676,22 @@ void mtk_ovl_layer_config(struct device *dev, unsigned int idx,
 			      DISP_REG_OVL_SRC_SIZE(idx));
 	mtk_ddp_write_relaxed(cmdq_pkt, offset, &ovl->cmdq_reg, ovl->regs,
 			      DISP_REG_OVL_OFFSET(idx));
-	mtk_ddp_write_relaxed(cmdq_pkt, addr, &ovl->cmdq_reg, ovl->regs,
-			      DISP_REG_OVL_ADDR(ovl, idx));
+
+	if (state->pending.is_secure) {
+		const struct drm_format_info *fmt_info = drm_format_info(fmt);
+		unsigned int buf_size = (pending->height - 1) * pending->pitch +
+					pending->width * fmt_info->cpp[0];
+
+		mtk_ddp_write_mask(cmdq_pkt, BIT(idx), &ovl->cmdq_reg, ovl->regs,
+				   DISP_REG_OVL_SECURE, BIT(idx));
+		mtk_ddp_sec_write(cmdq_pkt, ovl->regs_pa + DISP_REG_OVL_ADDR(ovl, idx),
+				  pending->addr, CMDQ_IWC_H_2_MVA, 0, buf_size, 0);
+	} else {
+		mtk_ddp_write_mask(cmdq_pkt, 0, &ovl->cmdq_reg, ovl->regs,
+				   DISP_REG_OVL_SECURE, BIT(idx));
+		mtk_ddp_write_relaxed(cmdq_pkt, addr, &ovl->cmdq_reg, ovl->regs,
+				      DISP_REG_OVL_ADDR(ovl, idx));
+	}
 
 	if (is_afbc) {
 		mtk_ddp_write_relaxed(cmdq_pkt, hdr_addr, &ovl->cmdq_reg, ovl->regs,
@@ -745,6 +770,7 @@ static int mtk_disp_ovl_probe(struct platform_device *pdev)
 	}
 
 	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	priv->regs_pa = res->start;
 	priv->regs = devm_ioremap_resource(dev, res);
 	if (IS_ERR(priv->regs)) {
 		dev_err(dev, "failed to ioremap ovl\n");
-- 
2.18.0


_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

^ permalink raw reply related

* [PATCH v4 2/9] dt-bindings: mailbox: Add mboxes property for CMDQ secure driver
From: Shawn Sung @ 2024-04-03  6:55 UTC (permalink / raw)
  To: CK Hu, Jassi Brar, AngeloGioacchino Del Regno
  Cc: Rob Herring, Krzysztof Kozlowski, Conor Dooley, Matthias Brugger,
	Hsiao Chien Sung, Jason-JH . Lin, Houlong Wei, linux-kernel,
	devicetree, linux-arm-kernel, linux-mediatek
In-Reply-To: <20240403065603.21920-1-shawn.sung@mediatek.com>

From: "Jason-JH.Lin" <jason-jh.lin@mediatek.com>

Add mboxes to define a GCE loopping thread as a secure irq handler.
This property is only required if CMDQ secure driver is supported.

Signed-off-by: Jason-JH.Lin <jason-jh.lin@mediatek.com>
Signed-off-by: Hsiao Chien Sung <shawn.sung@mediatek.com>
---
 .../devicetree/bindings/mailbox/mediatek,gce-mailbox.yaml      | 3 +++
 1 file changed, 3 insertions(+)

diff --git a/Documentation/devicetree/bindings/mailbox/mediatek,gce-mailbox.yaml b/Documentation/devicetree/bindings/mailbox/mediatek,gce-mailbox.yaml
index cef9d76013985..cf39e70747de6 100644
--- a/Documentation/devicetree/bindings/mailbox/mediatek,gce-mailbox.yaml
+++ b/Documentation/devicetree/bindings/mailbox/mediatek,gce-mailbox.yaml
@@ -49,6 +49,9 @@ properties:
     items:
       - const: gce
 
+  mboxes:
+    maxItems: 1
+
 required:
   - compatible
   - "#mbox-cells"
-- 
2.18.0


_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

^ permalink raw reply related

* [PATCH v4 2/9] drm/mediatek: Add secure buffer control flow to mtk_drm_gem
From: Shawn Sung @ 2024-04-03  7:07 UTC (permalink / raw)
  To: Chun-Kuang Hu
  Cc: Philipp Zabel, David Airlie, Daniel Vetter, Matthias Brugger,
	AngeloGioacchino Del Regno, Maarten Lankhorst, Maxime Ripard,
	Thomas Zimmermann, Sumit Semwal, Christian König, dri-devel,
	linux-mediatek, linux-kernel, linux-arm-kernel, linux-media,
	linaro-mm-sig, Jason-JH.Lin, Hsiao Chien Sung
In-Reply-To: <20240403070732.22085-1-shawn.sung@mediatek.com>

From: "Jason-JH.Lin" <jason-jh.lin@mediatek.com>

Add secure buffer control flow to mtk_drm_gem.

When user space takes DRM_MTK_GEM_CREATE_ENCRYPTED flag and size
to create a mtk_drm_gem object, mtk_drm_gem will find a matched size
dma buffer from secure dma-heap and bind it to mtk_drm_gem object.

Signed-off-by: Jason-JH.Lin <jason-jh.lin@mediatek.com>
Signed-off-by: Hsiao Chien Sung <shawn.sung@mediatek.com>
---
 drivers/gpu/drm/mediatek/mtk_gem.c | 85 +++++++++++++++++++++++++++++-
 drivers/gpu/drm/mediatek/mtk_gem.h |  4 ++
 2 files changed, 88 insertions(+), 1 deletion(-)

diff --git a/drivers/gpu/drm/mediatek/mtk_gem.c b/drivers/gpu/drm/mediatek/mtk_gem.c
index e59e0727717b7..ec34d02c14377 100644
--- a/drivers/gpu/drm/mediatek/mtk_gem.c
+++ b/drivers/gpu/drm/mediatek/mtk_gem.c
@@ -4,6 +4,8 @@
  */
 
 #include <linux/dma-buf.h>
+#include <linux/dma-heap.h>
+#include <uapi/linux/dma-heap.h>
 #include <drm/mediatek_drm.h>
 
 #include <drm/drm.h>
@@ -102,6 +104,81 @@ struct mtk_gem_obj *mtk_gem_create(struct drm_device *dev,
 	return ERR_PTR(ret);
 }
 
+struct mtk_gem_obj *mtk_gem_create_from_heap(struct drm_device *dev,
+					     const char *heap, size_t size)
+{
+	struct mtk_drm_private *priv = dev->dev_private;
+	struct mtk_gem_obj *mtk_gem;
+	struct drm_gem_object *obj;
+	struct dma_heap *dma_heap;
+	struct dma_buf *dma_buf;
+	struct dma_buf_attachment *attach;
+	struct sg_table *sgt;
+	struct iosys_map map = {};
+	int ret;
+
+	mtk_gem = mtk_gem_init(dev, size);
+	if (IS_ERR(mtk_gem))
+		return ERR_CAST(mtk_gem);
+
+	obj = &mtk_gem->base;
+
+	dma_heap = dma_heap_find(heap);
+	if (!dma_heap) {
+		DRM_ERROR("heap find fail\n");
+		goto err_gem_free;
+	}
+	dma_buf = dma_heap_buffer_alloc(dma_heap, size,
+					O_RDWR | O_CLOEXEC, DMA_HEAP_VALID_HEAP_FLAGS);
+	if (IS_ERR(dma_buf)) {
+		DRM_ERROR("buffer alloc fail\n");
+		dma_heap_put(dma_heap);
+		goto err_gem_free;
+	}
+	dma_heap_put(dma_heap);
+
+	attach = dma_buf_attach(dma_buf, priv->dma_dev);
+	if (IS_ERR(attach)) {
+		DRM_ERROR("attach fail, return\n");
+		dma_buf_put(dma_buf);
+		goto err_gem_free;
+	}
+
+	sgt = dma_buf_map_attachment(attach, DMA_BIDIRECTIONAL);
+	if (IS_ERR(sgt)) {
+		DRM_ERROR("map failed, detach and return\n");
+		dma_buf_detach(dma_buf, attach);
+		dma_buf_put(dma_buf);
+		goto err_gem_free;
+	}
+	obj->import_attach = attach;
+	mtk_gem->dma_addr = sg_dma_address(sgt->sgl);
+	mtk_gem->sg = sgt;
+	mtk_gem->size = dma_buf->size;
+
+	if (!strcmp(heap, "mtk_svp") || !strcmp(heap, "mtk_svp_cma")) {
+		/* secure buffer can not be mapped */
+		mtk_gem->secure = true;
+	} else {
+		ret = dma_buf_vmap(dma_buf, &map);
+		mtk_gem->kvaddr = map.vaddr;
+		if (ret) {
+			DRM_ERROR("map failed, ret=%d\n", ret);
+			dma_buf_unmap_attachment(attach, sgt, DMA_BIDIRECTIONAL);
+			dma_buf_detach(dma_buf, attach);
+			dma_buf_put(dma_buf);
+			mtk_gem->kvaddr = NULL;
+		}
+	}
+
+	return mtk_gem;
+
+err_gem_free:
+	drm_gem_object_release(obj);
+	kfree(mtk_gem);
+	return ERR_PTR(-ENOMEM);
+}
+
 void mtk_gem_free_object(struct drm_gem_object *obj)
 {
 	struct mtk_gem_obj *mtk_gem = to_mtk_gem_obj(obj);
@@ -229,7 +306,9 @@ struct drm_gem_object *mtk_gem_prime_import_sg_table(struct drm_device *dev,
 	if (IS_ERR(mtk_gem))
 		return ERR_CAST(mtk_gem);
 
+	mtk_gem->secure = !sg_page(sg->sgl);
 	mtk_gem->dma_addr = sg_dma_address(sg->sgl);
+	mtk_gem->size = attach->dmabuf->size;
 	mtk_gem->sg = sg;
 
 	return &mtk_gem->base;
@@ -304,7 +383,11 @@ int mtk_gem_create_ioctl(struct drm_device *dev, void *data,
 	struct drm_mtk_gem_create *args = data;
 	int ret;
 
-	mtk_gem = mtk_gem_create(dev, args->size, false);
+	if (args->flags & DRM_MTK_GEM_CREATE_ENCRYPTED)
+		mtk_gem = mtk_gem_create_from_heap(dev, "mtk_svp_cma", args->size);
+	else
+		mtk_gem = mtk_gem_create(dev, args->size, false);
+
 	if (IS_ERR(mtk_gem))
 		return PTR_ERR(mtk_gem);
 
diff --git a/drivers/gpu/drm/mediatek/mtk_gem.h b/drivers/gpu/drm/mediatek/mtk_gem.h
index 4d7598220ca8f..e1d3537a55ecb 100644
--- a/drivers/gpu/drm/mediatek/mtk_gem.h
+++ b/drivers/gpu/drm/mediatek/mtk_gem.h
@@ -27,9 +27,11 @@ struct mtk_gem_obj {
 	void			*cookie;
 	void			*kvaddr;
 	dma_addr_t		dma_addr;
+	size_t			size;
 	unsigned long		dma_attrs;
 	struct sg_table		*sg;
 	struct page		**pages;
+	bool			secure;
 };
 
 #define to_mtk_gem_obj(x) container_of(x, struct mtk_gem_obj, base)
@@ -39,6 +41,8 @@ struct mtk_gem_obj *mtk_gem_create(struct drm_device *dev, size_t size,
 				   bool alloc_kmap);
 int mtk_gem_dumb_create(struct drm_file *file_priv, struct drm_device *dev,
 			struct drm_mode_create_dumb *args);
+struct mtk_gem_obj *mtk_gem_create_from_heap(struct drm_device *dev,
+					     const char *heap, size_t size);
 struct sg_table *mtk_gem_prime_get_sg_table(struct drm_gem_object *obj);
 struct drm_gem_object *mtk_gem_prime_import_sg_table(struct drm_device *dev,
 			struct dma_buf_attachment *attach, struct sg_table *sg);
-- 
2.18.0


_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

^ permalink raw reply related

* [PATCH v4 8/9] drm/mediatek: Add secure flow support to mediatek-drm
From: Shawn Sung @ 2024-04-03  7:07 UTC (permalink / raw)
  To: Chun-Kuang Hu
  Cc: Philipp Zabel, David Airlie, Daniel Vetter, Matthias Brugger,
	AngeloGioacchino Del Regno, Maarten Lankhorst, Maxime Ripard,
	Thomas Zimmermann, Sumit Semwal, Christian König, dri-devel,
	linux-mediatek, linux-kernel, linux-arm-kernel, linux-media,
	linaro-mm-sig, Jason-JH.Lin, Hsiao Chien Sung
In-Reply-To: <20240403070732.22085-1-shawn.sung@mediatek.com>

From: "Jason-JH.Lin" <jason-jh.lin@mediatek.com>

To add secure flow support for mediatek-drm, each crtc have to
create a secure cmdq mailbox channel. Then cmdq packets with
display HW configuration will be sent to secure cmdq mailbox channel
and configured in the secure world.

Each crtc have to use secure cmdq interface to configure some secure
settings for display HW before sending cmdq packets to secure cmdq
mailbox channel.

If any of fb get from current drm_atomic_state is secure, then crtc
will switch to the secure flow to configure display HW.
If all fbs are not secure in current drm_atomic_state, then crtc will
switch to the normal flow.

TODO:
1. Remove get sec larb port interface in ddp_comp, ovl and ovl_adaptor.
2. Verify instruction for enabling/disabling dapc and larb port in TEE
   drop the sec_engine flags in normal world.

Signed-off-by: Jason-JH.Lin <jason-jh.lin@mediatek.com>
Signed-off-by: Hsiao Chien Sung <shawn.sung@mediatek.com>
---
 drivers/gpu/drm/mediatek/mtk_crtc.c  | 271 ++++++++++++++++++++++++++-
 drivers/gpu/drm/mediatek/mtk_crtc.h  |   1 +
 drivers/gpu/drm/mediatek/mtk_plane.c |   7 +
 3 files changed, 269 insertions(+), 10 deletions(-)

diff --git a/drivers/gpu/drm/mediatek/mtk_crtc.c b/drivers/gpu/drm/mediatek/mtk_crtc.c
index 29d00d11224b0..a6ba9965500f0 100644
--- a/drivers/gpu/drm/mediatek/mtk_crtc.c
+++ b/drivers/gpu/drm/mediatek/mtk_crtc.c
@@ -57,6 +57,11 @@ struct mtk_crtc {
 	u32				cmdq_event;
 	u32				cmdq_vblank_cnt;
 	wait_queue_head_t		cb_blocking_queue;
+
+	struct cmdq_client		sec_cmdq_client;
+	struct cmdq_pkt			sec_cmdq_handle;
+	bool				sec_cmdq_working;
+	wait_queue_head_t		sec_cb_blocking_queue;
 #endif

 	struct device			*mmsys_dev;
@@ -73,6 +78,8 @@ struct mtk_crtc {

 	struct mtk_ddp_comp		*crc_provider;
 	struct drm_vblank_work		crc_work;
+
+	bool				sec_on;
 };

 struct mtk_crtc_state {
@@ -117,6 +124,154 @@ static void mtk_drm_finish_page_flip(struct mtk_crtc *mtk_crtc)
 	}
 }

+void mtk_crtc_disable_secure_state(struct drm_crtc *crtc)
+{
+#if IS_REACHABLE(CONFIG_MTK_CMDQ)
+	enum cmdq_sec_scenario sec_scn = CMDQ_SEC_SCNR_MAX;
+	int i;
+	struct mtk_ddp_comp *ddp_first_comp;
+	struct mtk_crtc *mtk_crtc = to_mtk_crtc(crtc);
+	u64 sec_engine = 0; /* for hw engine write output secure fb */
+	u64 sec_port = 0; /* for larb port read input secure fb */
+
+	mutex_lock(&mtk_crtc->hw_lock);
+
+	if (!mtk_crtc->sec_cmdq_client.chan) {
+		pr_err("crtc-%d secure mbox channel is NULL\n", drm_crtc_index(crtc));
+		goto err;
+	}
+
+	if (!mtk_crtc->sec_on) {
+		pr_debug("crtc-%d is already disabled!\n", drm_crtc_index(crtc));
+		goto err;
+	}
+
+	mbox_flush(mtk_crtc->sec_cmdq_client.chan, 0);
+	mtk_crtc->sec_cmdq_handle.cmd_buf_size = 0;
+
+	if (mtk_crtc->sec_cmdq_handle.sec_data) {
+		struct cmdq_sec_data *sec_data;
+
+		sec_data = mtk_crtc->sec_cmdq_handle.sec_data;
+		sec_data->addr_metadata_cnt = 0;
+		sec_data->addr_metadatas = (uintptr_t)NULL;
+	}
+
+	/*
+	 * Secure path only support DL mode, so we just wait
+	 * the first path frame done here
+	 */
+	cmdq_pkt_wfe(&mtk_crtc->sec_cmdq_handle, mtk_crtc->cmdq_event, false);
+
+	ddp_first_comp = mtk_crtc->ddp_comp[0];
+	for (i = 0; i < mtk_crtc->layer_nr; i++) {
+		struct drm_plane *plane = &mtk_crtc->planes[i];
+
+		sec_port |= mtk_ddp_comp_layer_get_sec_port(ddp_first_comp, i);
+
+		/* make sure secure layer off before switching secure state */
+		if (!mtk_plane_fb_is_secure(plane->state->fb)) {
+			struct mtk_plane_state *plane_state = to_mtk_plane_state(plane->state);
+
+			plane_state->pending.enable = false;
+			mtk_ddp_comp_layer_config(ddp_first_comp, i, plane_state,
+						  &mtk_crtc->sec_cmdq_handle);
+		}
+	}
+
+	/* Disable secure path */
+	if (drm_crtc_index(crtc) == 0)
+		sec_scn = CMDQ_SEC_SCNR_PRIMARY_DISP_DISABLE;
+	else if (drm_crtc_index(crtc) == 1)
+		sec_scn = CMDQ_SEC_SCNR_SUB_DISP_DISABLE;
+
+	cmdq_sec_pkt_set_data(&mtk_crtc->sec_cmdq_handle, sec_engine, sec_engine, sec_scn);
+
+	cmdq_pkt_finalize(&mtk_crtc->sec_cmdq_handle);
+	dma_sync_single_for_device(mtk_crtc->sec_cmdq_client.chan->mbox->dev,
+				   mtk_crtc->sec_cmdq_handle.pa_base,
+				   mtk_crtc->sec_cmdq_handle.cmd_buf_size,
+				   DMA_TO_DEVICE);
+
+	mtk_crtc->sec_cmdq_working = true;
+	mbox_send_message(mtk_crtc->sec_cmdq_client.chan, &mtk_crtc->sec_cmdq_handle);
+	mbox_client_txdone(mtk_crtc->sec_cmdq_client.chan, 0);
+
+	// Wait for sec state to be disabled by cmdq
+	wait_event_timeout(mtk_crtc->sec_cb_blocking_queue,
+			   !mtk_crtc->sec_cmdq_working,
+			   msecs_to_jiffies(500));
+
+	mtk_crtc->sec_on = false;
+	pr_debug("crtc-%d disable secure plane!\n", drm_crtc_index(crtc));
+
+err:
+	mutex_unlock(&mtk_crtc->hw_lock);
+#endif
+}
+
+#if IS_REACHABLE(CONFIG_MTK_CMDQ)
+static void mtk_crtc_enable_secure_state(struct drm_crtc *crtc)
+{
+	enum cmdq_sec_scenario sec_scn = CMDQ_SEC_SCNR_MAX;
+	int i;
+	struct mtk_ddp_comp *ddp_first_comp;
+	struct mtk_crtc *mtk_crtc = to_mtk_crtc(crtc);
+	u64 sec_engine = 0; /* for hw engine write output secure fb */
+	u64 sec_port = 0; /* for larb port read input secure fb */
+
+	cmdq_pkt_wfe(&mtk_crtc->sec_cmdq_handle, mtk_crtc->cmdq_event, false);
+
+	ddp_first_comp = mtk_crtc->ddp_comp[0];
+	for (i = 0; i < mtk_crtc->layer_nr; i++)
+		if (mtk_crtc->planes[i].type == DRM_PLANE_TYPE_CURSOR)
+			sec_port |= mtk_ddp_comp_layer_get_sec_port(ddp_first_comp, i);
+
+	if (drm_crtc_index(crtc) == 0)
+		sec_scn = CMDQ_SEC_SCNR_PRIMARY_DISP;
+	else if (drm_crtc_index(crtc) == 1)
+		sec_scn = CMDQ_SEC_SCNR_SUB_DISP;
+
+	cmdq_sec_pkt_set_data(&mtk_crtc->sec_cmdq_handle, sec_engine, sec_port, sec_scn);
+
+	pr_debug("crtc-%d enable secure plane!\n", drm_crtc_index(crtc));
+}
+#endif
+
+static void mtk_crtc_plane_switch_sec_state(struct drm_crtc *crtc,
+					    struct drm_atomic_state *state)
+{
+#if IS_REACHABLE(CONFIG_MTK_CMDQ)
+	bool sec_on[MAX_CRTC] = {0};
+	int i;
+	struct drm_crtc_state *crtc_state;
+	struct mtk_crtc *mtk_crtc = to_mtk_crtc(crtc);
+	struct drm_plane *plane;
+	struct drm_plane_state *old_plane_state;
+
+	for_each_old_plane_in_state(state, plane, old_plane_state, i) {
+		if (!plane->state->crtc)
+			continue;
+
+		if (plane->state->fb &&
+		    mtk_plane_fb_is_secure(plane->state->fb) &&
+		    mtk_crtc->sec_cmdq_client.chan)
+			sec_on[drm_crtc_index(plane->state->crtc)] = true;
+	}
+
+	for_each_old_crtc_in_state(state, crtc, crtc_state, i) {
+		mtk_crtc = to_mtk_crtc(crtc);
+
+		if (!sec_on[i])
+			mtk_crtc_disable_secure_state(crtc);
+
+		mutex_lock(&mtk_crtc->hw_lock);
+		mtk_crtc->sec_on = true;
+		mutex_unlock(&mtk_crtc->hw_lock);
+	}
+#endif
+}
+
 #if IS_REACHABLE(CONFIG_MTK_CMDQ)
 static int mtk_drm_cmdq_pkt_create(struct cmdq_client *client, struct cmdq_pkt *pkt,
 				   size_t size)
@@ -152,22 +307,33 @@ static void mtk_drm_cmdq_pkt_destroy(struct cmdq_pkt *pkt)
 	dma_unmap_single(client->chan->mbox->dev, pkt->pa_base, pkt->buf_size,
 			 DMA_TO_DEVICE);
 	kfree(pkt->va_base);
+	kfree(pkt->sec_data);
 }
 #endif

 static void mtk_crtc_destroy(struct drm_crtc *crtc)
 {
 	struct mtk_crtc *mtk_crtc = to_mtk_crtc(crtc);
+	struct mtk_drm_private *priv = crtc->dev->dev_private;
 	int i;

+	priv = priv->all_drm_private[drm_crtc_index(crtc)];
+
 	mtk_mutex_put(mtk_crtc->mutex);
 #if IS_REACHABLE(CONFIG_MTK_CMDQ)
 	mtk_drm_cmdq_pkt_destroy(&mtk_crtc->cmdq_handle);
+	mtk_drm_cmdq_pkt_destroy(&mtk_crtc->sec_cmdq_handle);

 	if (mtk_crtc->cmdq_client.chan) {
 		mbox_free_channel(mtk_crtc->cmdq_client.chan);
 		mtk_crtc->cmdq_client.chan = NULL;
 	}
+
+	if (mtk_crtc->sec_cmdq_client.chan) {
+		device_link_remove(priv->dev, mtk_crtc->sec_cmdq_client.chan->mbox->dev);
+		mbox_free_channel(mtk_crtc->sec_cmdq_client.chan);
+		mtk_crtc->sec_cmdq_client.chan = NULL;
+	}
 #endif

 	for (i = 0; i < mtk_crtc->ddp_comp_nr; i++) {
@@ -316,6 +482,11 @@ static void ddp_cmdq_cb(struct mbox_client *cl, void *mssg)
 	if (data->sta < 0)
 		return;

+	if (!data->pkt || !data->pkt->sec_data)
+		mtk_crtc = container_of(cmdq_cl, struct mtk_crtc, cmdq_client);
+	else
+		mtk_crtc = container_of(cmdq_cl, struct mtk_crtc, sec_cmdq_client);
+
 	state = to_mtk_crtc_state(mtk_crtc->base.state);

 	state->pending_config = false;
@@ -344,6 +515,11 @@ static void ddp_cmdq_cb(struct mbox_client *cl, void *mssg)
 		mtk_crtc->pending_async_planes = false;
 	}

+	if (mtk_crtc->sec_cmdq_working) {
+		mtk_crtc->sec_cmdq_working = false;
+		wake_up(&mtk_crtc->sec_cb_blocking_queue);
+	}
+
 	mtk_crtc->cmdq_vblank_cnt = 0;
 	wake_up(&mtk_crtc->cb_blocking_queue);
 }
@@ -567,7 +743,8 @@ static void mtk_crtc_ddp_config(struct drm_crtc *crtc,
 static void mtk_crtc_update_config(struct mtk_crtc *mtk_crtc, bool needs_vblank)
 {
 #if IS_REACHABLE(CONFIG_MTK_CMDQ)
-	struct cmdq_pkt *cmdq_handle = &mtk_crtc->cmdq_handle;
+	struct cmdq_client cmdq_client;
+	struct cmdq_pkt *cmdq_handle;
 #endif
 	struct drm_crtc *crtc = &mtk_crtc->base;
 	struct mtk_drm_private *priv = crtc->dev->dev_private;
@@ -605,14 +782,36 @@ static void mtk_crtc_update_config(struct mtk_crtc *mtk_crtc, bool needs_vblank)
 		mtk_mutex_release(mtk_crtc->mutex);
 	}
 #if IS_REACHABLE(CONFIG_MTK_CMDQ)
-	if (mtk_crtc->cmdq_client.chan) {
+	if (mtk_crtc->sec_on) {
+		mbox_flush(mtk_crtc->sec_cmdq_client.chan, 0);
+		mtk_crtc->sec_cmdq_handle.cmd_buf_size = 0;
+
+		if (mtk_crtc->sec_cmdq_handle.sec_data) {
+			struct cmdq_sec_data *sec_data;
+
+			sec_data = mtk_crtc->sec_cmdq_handle.sec_data;
+			sec_data->addr_metadata_cnt = 0;
+			sec_data->addr_metadatas = (uintptr_t)NULL;
+		}
+
+		mtk_crtc_enable_secure_state(crtc);
+
+		cmdq_client = mtk_crtc->sec_cmdq_client;
+		cmdq_handle = &mtk_crtc->sec_cmdq_handle;
+	} else if (mtk_crtc->cmdq_client.chan) {
 		mbox_flush(mtk_crtc->cmdq_client.chan, 2000);
-		cmdq_handle->cmd_buf_size = 0;
+		mtk_crtc->cmdq_handle.cmd_buf_size = 0;
+
+		cmdq_client =  mtk_crtc->cmdq_client;
+		cmdq_handle = &mtk_crtc->cmdq_handle;
+	}
+
+	if (cmdq_client.chan) {
 		cmdq_pkt_clear_event(cmdq_handle, mtk_crtc->cmdq_event);
 		cmdq_pkt_wfe(cmdq_handle, mtk_crtc->cmdq_event, false);
 		mtk_crtc_ddp_config(crtc, cmdq_handle);
 		cmdq_pkt_finalize(cmdq_handle);
-		dma_sync_single_for_device(mtk_crtc->cmdq_client.chan->mbox->dev,
+		dma_sync_single_for_device(cmdq_client.chan->mbox->dev,
 					   cmdq_handle->pa_base,
 					   cmdq_handle->cmd_buf_size,
 					   DMA_TO_DEVICE);
@@ -625,8 +824,8 @@ static void mtk_crtc_update_config(struct mtk_crtc *mtk_crtc, bool needs_vblank)
 		 */
 		mtk_crtc->cmdq_vblank_cnt = 3;

-		mbox_send_message(mtk_crtc->cmdq_client.chan, cmdq_handle);
-		mbox_client_txdone(mtk_crtc->cmdq_client.chan, 0);
+		mbox_send_message(cmdq_client.chan, cmdq_handle);
+		mbox_client_txdone(cmdq_client.chan, 0);
 	}
 #endif
 	mtk_crtc->config_updating = false;
@@ -835,6 +1034,8 @@ static void mtk_crtc_atomic_disable(struct drm_crtc *crtc,
 	if (!mtk_crtc->enabled)
 		return;

+	mtk_crtc_disable_secure_state(crtc);
+
 	/* Set all pending plane state to disabled */
 	for (i = 0; i < mtk_crtc->layer_nr; i++) {
 		struct drm_plane *plane = &mtk_crtc->planes[i];
@@ -873,6 +1074,8 @@ static void mtk_crtc_atomic_begin(struct drm_crtc *crtc,
 	struct mtk_crtc *mtk_crtc = to_mtk_crtc(crtc);
 	unsigned long flags;

+	mtk_crtc_plane_switch_sec_state(crtc, state);
+
 	if (mtk_crtc->event && mtk_crtc_state->base.event)
 		DRM_ERROR("new event while there is still a pending event\n");

@@ -1169,8 +1372,7 @@ int mtk_crtc_create(struct drm_device *drm_dev, const unsigned int *path,
 		if (ret) {
 			dev_dbg(dev, "mtk_crtc %d failed to get mediatek,gce-events property\n",
 				drm_crtc_index(&mtk_crtc->base));
-			mbox_free_channel(mtk_crtc->cmdq_client.chan);
-			mtk_crtc->cmdq_client.chan = NULL;
+			goto cmdq_err;
 		} else {
 			ret = mtk_drm_cmdq_pkt_create(&mtk_crtc->cmdq_client,
 						      &mtk_crtc->cmdq_handle,
@@ -1178,14 +1380,63 @@ int mtk_crtc_create(struct drm_device *drm_dev, const unsigned int *path,
 			if (ret) {
 				dev_dbg(dev, "mtk_crtc %d failed to create cmdq packet\n",
 					drm_crtc_index(&mtk_crtc->base));
-				mbox_free_channel(mtk_crtc->cmdq_client.chan);
-				mtk_crtc->cmdq_client.chan = NULL;
+				goto cmdq_err;
 			}
 		}

 		/* for sending blocking cmd in crtc disable */
 		init_waitqueue_head(&mtk_crtc->cb_blocking_queue);
 	}
+
+	mtk_crtc->sec_cmdq_client.client.dev = mtk_crtc->mmsys_dev;
+	mtk_crtc->sec_cmdq_client.client.tx_block = false;
+	mtk_crtc->sec_cmdq_client.client.knows_txdone = true;
+	mtk_crtc->sec_cmdq_client.client.rx_callback = ddp_cmdq_cb;
+	mtk_crtc->sec_cmdq_client.chan =
+			mbox_request_channel(&mtk_crtc->sec_cmdq_client.client, i + 1);
+	if (IS_ERR(mtk_crtc->sec_cmdq_client.chan)) {
+		dev_err(dev, "mtk_crtc %d failed to create sec mailbox client\n",
+			drm_crtc_index(&mtk_crtc->base));
+		mtk_crtc->sec_cmdq_client.chan = NULL;
+	}
+
+	if (mtk_crtc->sec_cmdq_client.chan) {
+		struct device_link *link;
+
+		/* add devlink to cmdq dev to make sure suspend/resume order is correct */
+		link = device_link_add(priv->dev, mtk_crtc->sec_cmdq_client.chan->mbox->dev,
+				       DL_FLAG_PM_RUNTIME | DL_FLAG_STATELESS);
+		if (!link) {
+			dev_err(priv->dev, "Unable to link dev=%s\n",
+				dev_name(mtk_crtc->sec_cmdq_client.chan->mbox->dev));
+			ret = -ENODEV;
+			goto cmdq_err;
+		}
+
+		ret = mtk_drm_cmdq_pkt_create(&mtk_crtc->sec_cmdq_client,
+					      &mtk_crtc->sec_cmdq_handle,
+					      PAGE_SIZE);
+		if (ret) {
+			dev_dbg(dev, "mtk_crtc %d failed to create cmdq secure packet\n",
+				drm_crtc_index(&mtk_crtc->base));
+			goto cmdq_err;
+		}
+
+		/* for sending blocking cmd in crtc disable */
+		init_waitqueue_head(&mtk_crtc->sec_cb_blocking_queue);
+	}
+
+cmdq_err:
+	if (ret) {
+		if (mtk_crtc->cmdq_client.chan) {
+			mbox_free_channel(mtk_crtc->cmdq_client.chan);
+			mtk_crtc->cmdq_client.chan = NULL;
+		}
+		if (mtk_crtc->sec_cmdq_client.chan) {
+			mbox_free_channel(mtk_crtc->sec_cmdq_client.chan);
+			mtk_crtc->sec_cmdq_client.chan = NULL;
+		}
+	}
 #endif

 	if (conn_routes) {
diff --git a/drivers/gpu/drm/mediatek/mtk_crtc.h b/drivers/gpu/drm/mediatek/mtk_crtc.h
index a79c4611754e4..340217d6acd3c 100644
--- a/drivers/gpu/drm/mediatek/mtk_crtc.h
+++ b/drivers/gpu/drm/mediatek/mtk_crtc.h
@@ -62,5 +62,6 @@ void mtk_crtc_create_crc_cmdq(struct device *dev, struct mtk_crtc_crc *crc);
 void mtk_crtc_start_crc_cmdq(struct mtk_crtc_crc *crc);
 void mtk_crtc_stop_crc_cmdq(struct mtk_crtc_crc *crc);
 #endif
+void mtk_crtc_disable_secure_state(struct drm_crtc *crtc);

 #endif /* MTK_CRTC_H */
diff --git a/drivers/gpu/drm/mediatek/mtk_plane.c b/drivers/gpu/drm/mediatek/mtk_plane.c
index 021148d4b5d4a..9762bba23273b 100644
--- a/drivers/gpu/drm/mediatek/mtk_plane.c
+++ b/drivers/gpu/drm/mediatek/mtk_plane.c
@@ -289,6 +289,13 @@ static void mtk_plane_atomic_disable(struct drm_plane *plane,
 	mtk_plane_state->pending.enable = false;
 	wmb(); /* Make sure the above parameter is set before update */
 	mtk_plane_state->pending.dirty = true;
+
+	if (mtk_plane_state->pending.is_secure) {
+		struct drm_plane_state *old_state = drm_atomic_get_old_plane_state(state, plane);
+
+		if (old_state->crtc)
+			mtk_crtc_disable_secure_state(old_state->crtc);
+	}
 }

 static void mtk_plane_atomic_update(struct drm_plane *plane,
--
2.18.0


_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

^ permalink raw reply related

* [PATCH v4 5/9] drm/mediatek: Add get_sec_port interface to mtk_ddp_comp
From: Shawn Sung @ 2024-04-03  7:07 UTC (permalink / raw)
  To: Chun-Kuang Hu
  Cc: Philipp Zabel, David Airlie, Daniel Vetter, Matthias Brugger,
	AngeloGioacchino Del Regno, Maarten Lankhorst, Maxime Ripard,
	Thomas Zimmermann, Sumit Semwal, Christian König, dri-devel,
	linux-mediatek, linux-kernel, linux-arm-kernel, linux-media,
	linaro-mm-sig, Jason-JH.Lin, Hsiao Chien Sung
In-Reply-To: <20240403070732.22085-1-shawn.sung@mediatek.com>

From: "Jason-JH.Lin" <jason-jh.lin@mediatek.com>

Add get_sec_port interface to ddp_comp to get the secure port settings
from ovl and ovl_adaptor.
Then mediatek-drm will use secure cmdq driver to configure DRAM access
permission in secure world by their secure port settings.

Signed-off-by: Jason-JH.Lin <jason-jh.lin@mediatek.com>
Signed-off-by: Hsiao Chien Sung <shawn.sung@mediatek.com>
---
 drivers/gpu/drm/mediatek/mtk_ddp_comp.h | 9 +++++++++
 1 file changed, 9 insertions(+)

diff --git a/drivers/gpu/drm/mediatek/mtk_ddp_comp.h b/drivers/gpu/drm/mediatek/mtk_ddp_comp.h
index a00258a5cefda..a22725e5cdce9 100644
--- a/drivers/gpu/drm/mediatek/mtk_ddp_comp.h
+++ b/drivers/gpu/drm/mediatek/mtk_ddp_comp.h
@@ -92,6 +92,7 @@ struct mtk_ddp_comp_funcs {
 	size_t (*crc_cnt)(struct device *dev);
 	u32 *(*crc_entry)(struct device *dev);
 	void (*crc_read)(struct device *dev);
+	u64 (*get_sec_port)(struct mtk_ddp_comp *comp, unsigned int idx);
 };
 
 struct mtk_ddp_comp {
@@ -237,6 +238,14 @@ static inline unsigned int mtk_ddp_gamma_get_lut_size(struct mtk_ddp_comp *comp)
 	return 0;
 }
 
+static inline u64 mtk_ddp_comp_layer_get_sec_port(struct mtk_ddp_comp *comp,
+						  unsigned int idx)
+{
+	if (comp->funcs && comp->funcs->get_sec_port)
+		return comp->funcs->get_sec_port(comp, idx);
+	return 0;
+}
+
 static inline void mtk_ddp_gamma_set(struct mtk_ddp_comp *comp,
 				     struct drm_crtc_state *state)
 {
-- 
2.18.0


_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

^ permalink raw reply related

* [PATCH v4 0/9] Add mediate-drm secure flow for SVP
From: Shawn Sung @ 2024-04-03  7:07 UTC (permalink / raw)
  To: Chun-Kuang Hu
  Cc: Philipp Zabel, David Airlie, Daniel Vetter, Matthias Brugger,
	AngeloGioacchino Del Regno, Maarten Lankhorst, Maxime Ripard,
	Thomas Zimmermann, Sumit Semwal, Christian König, dri-devel,
	linux-mediatek, linux-kernel, linux-arm-kernel, linux-media,
	linaro-mm-sig, Hsiao Chien Sung

From: Hsiao Chien Sung <shawn.sung@mediatek.corp-partner.google.com>

Memory Definitions:
secure memory - Memory allocated in the TEE (Trusted Execution
Environment) which is inaccessible in the REE (Rich Execution
Environment, i.e. linux kernel/userspace).
secure handle - Integer value which acts as reference to 'secure
memory'. Used in communication between TEE and REE to reference
'secure memory'.
secure buffer - 'secure memory' that is used to store decrypted,
compressed video or for other general purposes in the TEE.
secure surface - 'secure memory' that is used to store graphic buffers.

Memory Usage in SVP:
The overall flow of SVP starts with encrypted video coming in from an
outside source into the REE. The REE will then allocate a 'secure
buffer' and send the corresponding 'secure handle' along with the
encrypted, compressed video data to the TEE. The TEE will then decrypt
the video and store the result in the 'secure buffer'. The REE will
then allocate a 'secure surface'. The REE will pass the 'secure
handles' for both the 'secure buffer' and 'secure surface' into the
TEE for video decoding. The video decoder HW will then decode the
contents of the 'secure buffer' and place the result in the 'secure
surface'. The REE will then attach the 'secure surface' to the overlay
plane for rendering of the video.

Everything relating to ensuring security of the actual contents of the
'secure buffer' and 'secure surface' is out of scope for the REE and
is the responsibility of the TEE.

DRM driver handles allocation of gem objects that are backed by a 'secure
surface' and for displaying a 'secure surface' on the overlay plane.
This introduces a new flag for object creation called
DRM_MTK_GEM_CREATE_ENCRYPTED which indicates it should be a 'secure
surface'. All changes here are in MediaTek specific code.
---
TODO:
1) Remove get sec larb port interface in ddp_comp, ovl and ovl_adaptor.
2) Verify instruction for enabling/disabling dapc and larb port in TEE
   drop the sec_engine flags in normal world and.
3) Move DISP_REG_OVL_SECURE setting to secure world for mtk_disp_ovl.c.
4) Change the parameter register address in mtk_ddp_sec_write()
   from "u32 addr" to "struct cmdq_client_reg *cmdq_reg".
5) Implement setting mmsys routing table in the secure world series.
---
Based on 5 series and 1 patch:
[1] v3 dma-buf: heaps: Add MediaTek secure heap
- https://patchwork.kernel.org/project/linux-mediatek/list/?series=809023
[2] v3 add driver to support secure video decoder
- https://patchwork.kernel.org/project/linux-mediatek/list/?series=807308
[3] v4 soc: mediatek: Add register definitions for GCE
- https://patchwork.kernel.org/project/linux-mediatek/patch/20231212121957.19231-2-shawn.sung@mediatek.com/
[4] v2 Add CMDQ driver support for mt8188
- https://patchwork.kernel.org/project/linux-mediatek/list/?series=810302
[5] Add mediatek,gce-events definition to mediatek,gce-mailbox bindings
- https://patchwork.kernel.org/project/linux-mediatek/list/?series=810938
[6] v3 Add CMDQ secure driver for SVP
- https://patchwork.kernel.org/project/linux-mediatek/list/?series=812379
---
Changes in v4:
1. Rebase on mediatek-drm-next(278640d4d74cd) and fix the conflicts
2. This series is based on 20240129063025.29251-1-yunfei.dong@mediatek.com
3. This series is based on 20240322052829.9893-1-shawn.sung@mediatek.com
4. This series is based on 20240403065603.21920-1-shawn.sung@mediatek.com

Changes in v3:
1. fix kerneldoc problems
2. fix typo in title and commit message
3. adjust naming for secure variable
4. add the missing part for is_suecure plane implementation
5. use BIT_ULL macro to replace bit shifting
6. move modification of ovl_adaptor part to the correct patch
7. add TODO list in commit message
8. add commit message for using share memory to store execute count

Changes in v2:

1. remove the DRIVER_RDNDER flag for mtk_drm_ioctl
2. move cmdq_insert_backup_cookie into client driver
3. move secure gce node define from mt8195-cherry.dtsi to mt8195.dtsi
---
CK Hu (1):
  drm/mediatek: Add interface to allocate MediaTek GEM buffer.

Jason-JH.Lin (9):
  drm/mediatek/uapi: Add DRM_MTK_GEM_CREATE_ENCRYPTED flag
  drm/mediatek: Add secure buffer control flow to mtk_drm_gem
  drm/mediatek: Add secure identify flag and funcution to mtk_drm_plane
  drm/mediatek: Add mtk_ddp_sec_write to config secure buffer info
  drm/mediatek: Add get_sec_port interface to mtk_ddp_comp
  drm/mediatek: Add secure layer config support for ovl_adaptor
  drm/mediatek: Add secure layer config support for ovl
  drm/mediatek: Add secure flow support to mediatek-drm
  drm/mediatek: Add cmdq_insert_backup_cookie before secure pkt finalize

 drivers/gpu/drm/mediatek/mtk_crtc.c           | 273 +++++++++++++++++-
 drivers/gpu/drm/mediatek/mtk_crtc.h           |   1 +
 drivers/gpu/drm/mediatek/mtk_ddp_comp.c       |  16 +
 drivers/gpu/drm/mediatek/mtk_ddp_comp.h       |  13 +
 drivers/gpu/drm/mediatek/mtk_disp_drv.h       |   3 +
 drivers/gpu/drm/mediatek/mtk_disp_ovl.c       |  30 +-
 .../gpu/drm/mediatek/mtk_disp_ovl_adaptor.c   |  15 +
 drivers/gpu/drm/mediatek/mtk_gem.c            |  85 +++++-
 drivers/gpu/drm/mediatek/mtk_gem.h            |   4 +
 drivers/gpu/drm/mediatek/mtk_mdp_rdma.c       |  11 +-
 drivers/gpu/drm/mediatek/mtk_mdp_rdma.h       |   2 +
 drivers/gpu/drm/mediatek/mtk_plane.c          |  25 ++
 drivers/gpu/drm/mediatek/mtk_plane.h          |   2 +
 include/uapi/drm/mediatek_drm.h               |   1 +
 14 files changed, 465 insertions(+), 16 deletions(-)

--
2.18.0


_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

^ permalink raw reply

* [PATCH v4 4/9] drm/mediatek: Add mtk_ddp_sec_write to config secure buffer info
From: Shawn Sung @ 2024-04-03  7:07 UTC (permalink / raw)
  To: Chun-Kuang Hu
  Cc: Philipp Zabel, David Airlie, Daniel Vetter, Matthias Brugger,
	AngeloGioacchino Del Regno, Maarten Lankhorst, Maxime Ripard,
	Thomas Zimmermann, Sumit Semwal, Christian König, dri-devel,
	linux-mediatek, linux-kernel, linux-arm-kernel, linux-media,
	linaro-mm-sig, Jason-JH.Lin, Hsiao Chien Sung
In-Reply-To: <20240403070732.22085-1-shawn.sung@mediatek.com>

From: "Jason-JH.Lin" <jason-jh.lin@mediatek.com>

Add mtk_ddp_sec_write to configure secure buffer information to
cmdq secure packet data.
Then secure cmdq driver will use these information to configure
curresponding secure DRAM address to HW overlay in secure world.

Signed-off-by: Jason-JH.Lin <jason-jh.lin@mediatek.com>
Signed-off-by: Hsiao Chien Sung <shawn.sung@mediatek.com>
---
 drivers/gpu/drm/mediatek/mtk_ddp_comp.c | 14 ++++++++++++++
 drivers/gpu/drm/mediatek/mtk_ddp_comp.h |  4 ++++
 2 files changed, 18 insertions(+)

diff --git a/drivers/gpu/drm/mediatek/mtk_ddp_comp.c b/drivers/gpu/drm/mediatek/mtk_ddp_comp.c
index 8aab373ce67c9..0ee9e42cdf0a0 100644
--- a/drivers/gpu/drm/mediatek/mtk_ddp_comp.c
+++ b/drivers/gpu/drm/mediatek/mtk_ddp_comp.c
@@ -111,6 +111,20 @@ void mtk_ddp_write_mask(struct cmdq_pkt *cmdq_pkt, unsigned int value,
 #endif
 }
 
+void mtk_ddp_sec_write(struct cmdq_pkt *cmdq_pkt, u32 addr, u64 base,
+		       const enum cmdq_iwc_addr_metadata_type type,
+		       const u32 offset, const u32 size, const u32 port)
+{
+#if IS_REACHABLE(CONFIG_MTK_CMDQ)
+	if (!cmdq_pkt)
+		return;
+
+	/* secure buffer will be 4K alignment */
+	cmdq_sec_pkt_write(cmdq_pkt, addr, base, type,
+			   offset, ALIGN(size, PAGE_SIZE), port);
+#endif
+}
+
 static int mtk_ddp_clk_enable(struct device *dev)
 {
 	struct mtk_ddp_comp_dev *priv = dev_get_drvdata(dev);
diff --git a/drivers/gpu/drm/mediatek/mtk_ddp_comp.h b/drivers/gpu/drm/mediatek/mtk_ddp_comp.h
index b9c79e740abe0..a00258a5cefda 100644
--- a/drivers/gpu/drm/mediatek/mtk_ddp_comp.h
+++ b/drivers/gpu/drm/mediatek/mtk_ddp_comp.h
@@ -8,6 +8,7 @@
 
 #include <linux/io.h>
 #include <linux/pm_runtime.h>
+#include <linux/mailbox/mtk-cmdq-sec-mailbox.h>
 #include <linux/soc/mediatek/mtk-cmdq.h>
 #include <linux/soc/mediatek/mtk-mmsys.h>
 #include <linux/soc/mediatek/mtk-mutex.h>
@@ -346,4 +347,7 @@ void mtk_ddp_write_relaxed(struct cmdq_pkt *cmdq_pkt, unsigned int value,
 void mtk_ddp_write_mask(struct cmdq_pkt *cmdq_pkt, unsigned int value,
 			struct cmdq_client_reg *cmdq_reg, void __iomem *regs,
 			unsigned int offset, unsigned int mask);
+void mtk_ddp_sec_write(struct cmdq_pkt *cmdq_pkt, u32 addr, u64 base,
+		       const enum cmdq_iwc_addr_metadata_type type,
+		       const u32 offset, const u32 size, const u32 port);
 #endif /* MTK_DDP_COMP_H */
-- 
2.18.0


_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

^ permalink raw reply related

* [PATCH v4 9/9] drm/mediatek: Add cmdq_insert_backup_cookie before secure pkt finalize
From: Shawn Sung @ 2024-04-03  7:07 UTC (permalink / raw)
  To: Chun-Kuang Hu
  Cc: Philipp Zabel, David Airlie, Daniel Vetter, Matthias Brugger,
	AngeloGioacchino Del Regno, Maarten Lankhorst, Maxime Ripard,
	Thomas Zimmermann, Sumit Semwal, Christian König, dri-devel,
	linux-mediatek, linux-kernel, linux-arm-kernel, linux-media,
	linaro-mm-sig, Jason-JH.Lin, Hsiao Chien Sung
In-Reply-To: <20240403070732.22085-1-shawn.sung@mediatek.com>

From: "Jason-JH.Lin" <jason-jh.lin@mediatek.com>

Add cmdq_insert_backup_cookie to append some commands before EOC:
1. Get GCE HW thread execute count from the GCE HW register.
2. Add 1 to the execute count and then store into a shared memory.
3. Set a software event siganl as secure irq to GCE HW.

Since the value of execute count + 1 is stored in a shared memory,
CMDQ driver in the normal world can use it to handle task done in irq
handler and CMDQ driver in the secure world will use it to schedule
the task slot for each secure thread.

The reason why we use shared memory to record execute count here is:
1. normal world can not access the register of secure GCE thread in
normal world.
2. calling TEE invoke cmd in the irq handler would be expensive and not
stable. I've tested that a single TEE invloke cmd to CMDQ PTA costs
19~53 us. Maybe it would cost more during the scenario that needs more
CPU loading.

Signed-off-by: Jason-JH.Lin <jason-jh.lin@mediatek.com>
Signed-off-by: Hsiao Chien Sung <shawn.sung@mediatek.com>
---
 drivers/gpu/drm/mediatek/mtk_crtc.c | 4 +++-
 1 file changed, 3 insertions(+), 1 deletion(-)

diff --git a/drivers/gpu/drm/mediatek/mtk_crtc.c b/drivers/gpu/drm/mediatek/mtk_crtc.c
index a6ba9965500f0..2fb52928a3055 100644
--- a/drivers/gpu/drm/mediatek/mtk_crtc.c
+++ b/drivers/gpu/drm/mediatek/mtk_crtc.c
@@ -186,7 +186,7 @@ void mtk_crtc_disable_secure_state(struct drm_crtc *crtc)
 		sec_scn = CMDQ_SEC_SCNR_SUB_DISP_DISABLE;
 
 	cmdq_sec_pkt_set_data(&mtk_crtc->sec_cmdq_handle, sec_engine, sec_engine, sec_scn);
-
+	cmdq_sec_insert_backup_cookie(&mtk_crtc->sec_cmdq_handle);
 	cmdq_pkt_finalize(&mtk_crtc->sec_cmdq_handle);
 	dma_sync_single_for_device(mtk_crtc->sec_cmdq_client.chan->mbox->dev,
 				   mtk_crtc->sec_cmdq_handle.pa_base,
@@ -810,6 +810,8 @@ static void mtk_crtc_update_config(struct mtk_crtc *mtk_crtc, bool needs_vblank)
 		cmdq_pkt_clear_event(cmdq_handle, mtk_crtc->cmdq_event);
 		cmdq_pkt_wfe(cmdq_handle, mtk_crtc->cmdq_event, false);
 		mtk_crtc_ddp_config(crtc, cmdq_handle);
+		if (cmdq_handle->sec_data)
+			cmdq_sec_insert_backup_cookie(cmdq_handle);
 		cmdq_pkt_finalize(cmdq_handle);
 		dma_sync_single_for_device(cmdq_client.chan->mbox->dev,
 					   cmdq_handle->pa_base,
-- 
2.18.0


_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

^ permalink raw reply related

* [PATCH v4 3/9] drm/mediatek: Add secure identify flag and funcution to mtk_drm_plane
From: Shawn Sung @ 2024-04-03  7:07 UTC (permalink / raw)
  To: Chun-Kuang Hu
  Cc: Philipp Zabel, David Airlie, Daniel Vetter, Matthias Brugger,
	AngeloGioacchino Del Regno, Maarten Lankhorst, Maxime Ripard,
	Thomas Zimmermann, Sumit Semwal, Christian König, dri-devel,
	linux-mediatek, linux-kernel, linux-arm-kernel, linux-media,
	linaro-mm-sig, Jason-JH.Lin, Hsiao Chien Sung
In-Reply-To: <20240403070732.22085-1-shawn.sung@mediatek.com>

From: "Jason-JH.Lin" <jason-jh.lin@mediatek.com>

Add is_sec flag to identify current mtk_drm_plane is secure.
Add mtk_plane_is_sec_fb() to check current drm_framebuffer is secure.

Signed-off-by: Jason-JH.Lin <jason-jh.lin@mediatek.com>
Signed-off-by: Hsiao Chien Sung <shawn.sung@mediatek.com>
---
 drivers/gpu/drm/mediatek/mtk_plane.c | 18 ++++++++++++++++++
 drivers/gpu/drm/mediatek/mtk_plane.h |  2 ++
 2 files changed, 20 insertions(+)

diff --git a/drivers/gpu/drm/mediatek/mtk_plane.c b/drivers/gpu/drm/mediatek/mtk_plane.c
index 5bf757a3ef202..021148d4b5d4a 100644
--- a/drivers/gpu/drm/mediatek/mtk_plane.c
+++ b/drivers/gpu/drm/mediatek/mtk_plane.c
@@ -210,6 +210,7 @@ static void mtk_plane_update_new_state(struct drm_plane_state *new_state,
 	mtk_plane_state->pending.height = drm_rect_height(&new_state->dst);
 	mtk_plane_state->pending.rotation = new_state->rotation;
 	mtk_plane_state->pending.color_encoding = new_state->color_encoding;
+	mtk_plane_state->pending.is_secure = mtk_plane_fb_is_secure(fb);
 }
 
 static void mtk_plane_atomic_async_update(struct drm_plane *plane,
@@ -361,3 +362,20 @@ int mtk_plane_init(struct drm_device *dev, struct drm_plane *plane,
 
 	return 0;
 }
+
+bool mtk_plane_fb_is_secure(struct drm_framebuffer *fb)
+{
+	struct drm_gem_object *gem = NULL;
+	struct mtk_gem_obj *mtk_gem = NULL;
+
+	if (!fb)
+		return false;
+
+	gem = fb->obj[0];
+	if (!gem)
+		return false;
+
+	mtk_gem = to_mtk_gem_obj(gem);
+
+	return mtk_gem->secure;
+}
diff --git a/drivers/gpu/drm/mediatek/mtk_plane.h b/drivers/gpu/drm/mediatek/mtk_plane.h
index 231bb7aac9473..a7779a91f0a20 100644
--- a/drivers/gpu/drm/mediatek/mtk_plane.h
+++ b/drivers/gpu/drm/mediatek/mtk_plane.h
@@ -33,6 +33,7 @@ struct mtk_plane_pending_state {
 	bool				async_dirty;
 	bool				async_config;
 	enum drm_color_encoding		color_encoding;
+	bool				is_secure;
 };
 
 struct mtk_plane_state {
@@ -46,6 +47,7 @@ to_mtk_plane_state(struct drm_plane_state *state)
 	return container_of(state, struct mtk_plane_state, base);
 }
 
+bool mtk_plane_fb_is_secure(struct drm_framebuffer *fb);
 int mtk_plane_init(struct drm_device *dev, struct drm_plane *plane,
 		   unsigned long possible_crtcs, enum drm_plane_type type,
 		   unsigned int supported_rotations, const u32 *formats,
-- 
2.18.0


_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

^ permalink raw reply related

* [PATCH v4 1/9] drm/mediatek/uapi: Add DRM_MTK_GEM_CREATE_ENCRYPTED flag
From: Shawn Sung @ 2024-04-03  7:07 UTC (permalink / raw)
  To: Chun-Kuang Hu
  Cc: Philipp Zabel, David Airlie, Daniel Vetter, Matthias Brugger,
	AngeloGioacchino Del Regno, Maarten Lankhorst, Maxime Ripard,
	Thomas Zimmermann, Sumit Semwal, Christian König, dri-devel,
	linux-mediatek, linux-kernel, linux-arm-kernel, linux-media,
	linaro-mm-sig, Jason-JH.Lin, Hsiao Chien Sung
In-Reply-To: <20240403070732.22085-1-shawn.sung@mediatek.com>

From: "Jason-JH.Lin" <jason-jh.lin@mediatek.com>

Add DRM_MTK_GEM_CREATE_ENCRYPTED flag to allow user to allocate
a secure buffer to support secure video path feature.

Signed-off-by: Jason-JH.Lin <jason-jh.lin@mediatek.com>
Signed-off-by: Hsiao Chien Sung <shawn.sung@mediatek.com>
---
 include/uapi/drm/mediatek_drm.h | 1 +
 1 file changed, 1 insertion(+)

diff --git a/include/uapi/drm/mediatek_drm.h b/include/uapi/drm/mediatek_drm.h
index b0dea00bacbc4..e9125de3a24ad 100644
--- a/include/uapi/drm/mediatek_drm.h
+++ b/include/uapi/drm/mediatek_drm.h
@@ -54,6 +54,7 @@ struct drm_mtk_gem_map_off {
 
 #define DRM_MTK_GEM_CREATE		0x00
 #define DRM_MTK_GEM_MAP_OFFSET		0x01
+#define DRM_MTK_GEM_CREATE_ENCRYPTED	0x02
 
 #define DRM_IOCTL_MTK_GEM_CREATE	DRM_IOWR(DRM_COMMAND_BASE + \
 		DRM_MTK_GEM_CREATE, struct drm_mtk_gem_create)
-- 
2.18.0


_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

^ permalink raw reply related

* Re: [PATCH] dt-bindings: mfd: syscon: Add missing simple syscon compatibles
From: Krzysztof Kozlowski @ 2024-04-03  7:07 UTC (permalink / raw)
  To: Rob Herring, Krzysztof Kozlowski, Conor Dooley, Andrew Lunn,
	Gregory Clement, Sebastian Hesselbarth, Lee Jones, Ray Jui,
	Scott Branden, Broadcom internal kernel review list,
	Matthias Brugger, AngeloGioacchino Del Regno
  Cc: devicetree, linux-kernel, linux-arm-kernel, linux-mediatek
In-Reply-To: <20240402202413.757283-1-robh@kernel.org>

On 02/04/2024 22:24, Rob Herring wrote:
> Add various "simple" syscon compatibles which were undocumented or
> still documented with old text bindings.
> 
> apm,xgene-csw, apm,xgene-efuse, apm,xgene-mcb, apm,xgene-rb,
> fsl,ls1088a-reset, marvell,armada-3700-cpu-misc,
> mediatek,mt2712-pctl-a-syscfg, mediatek,mt6397-pctl-pmic-syscfg, and
> mediatek,mt8173-pctl-a-syscfg were all undocumented, but are in use
> already. Remove the old text binding docs for the others.
> 
> Signed-off-by: Rob Herring <robh@kernel.org>
> ---

Reviewed-by: Krzysztof Kozlowski <krzysztof.kozlowski@linaro.org>


Best regards,
Krzysztof


_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

^ permalink raw reply

* Re: [PATCH 5/5] arm64: dts: Add device tree source for the Au-Zone Maivin Starter Kit
From: Francesco Dolcini @ 2024-04-03  7:06 UTC (permalink / raw)
  To: Laurent Pinchart, Shawn Guo
  Cc: devicetree, imx, linux-arm-kernel, Trevor Zaharichuk, Greg Lytle,
	Shawn Guo, Sascha Hauer, Pengutronix Kernel Team, Fabio Estevam,
	Rob Herring, Krzysztof Kozlowski, Conor Dooley
In-Reply-To: <ZgyjE05p/1NZnzaK@dragon>

Hello Laurent,

On Wed, Apr 03, 2024 at 08:30:11AM +0800, Shawn Guo wrote:
> On Mon, Mar 25, 2024 at 10:32:45PM +0200, Laurent Pinchart wrote:
> > diff --git a/arch/arm64/boot/dts/freescale/imx8mp-maivin.dts b/arch/arm64/boot/dts/freescale/imx8mp-maivin.dts
> > new file mode 100644
> > index 000000000000..2d1c8e782465
> > --- /dev/null
> > +++ b/arch/arm64/boot/dts/freescale/imx8mp-maivin.dts
> > @@ -0,0 +1,236 @@

[...]

> > +/* Verdin I2C_2_DSI */
> > +&i2c2 {
> > +	status = "okay";
> > +
> > +	clock-frequency = <400000>;
> > +	scl-gpios = <&gpio5 16 (GPIO_ACTIVE_HIGH | GPIO_OPEN_DRAIN)>;
> > +	sda-gpios = <&gpio5 17 (GPIO_ACTIVE_HIGH | GPIO_OPEN_DRAIN)>;
> 
> We usually end property list with 'status'.

This is now a written and explicit guideline, no longer tribal knowledge,
see https://docs.kernel.org/devicetree/bindings/dts-coding-style.html#order-of-properties-in-device-node

Francesco


_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

^ permalink raw reply


This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox