From 2bc6b218717b9d08f466f88209251d54bc09b207 Mon Sep 17 00:00:00 2001 From: Fuad Tabba Date: Tue, 22 Sep 2026 19:14:30 +0100 Subject: arm64/boot: Disable trapping of PMZR_EL0 writes to EL2 __init_el2_fgt2() writes one mask to both HDFGRTR2_EL2 and HDFGWTR2_EL2. PMZR_EL0 is write-only, so its trap bit, nPMZR_EL0, exists only in HDFGWTR2_EL2 and is therefore never set: a PMZR_EL0 write from the host traps to EL2, where the nVHE hypervisor has no handler and BUG()s. The kernel never writes PMZR_EL0, but kernel.perf_user_access=1 has the PMU driver set PMUSERENR_EL0.UEN for a task with a user-read event, so a write from EL0 reaches the trap and takes the host down without a panic message. Accumulate the HDFGWTR2_EL2 bits separately, as __init_el2_fgt() already does for HDFGWTR_EL2, and set nPMZR_EL0 with the other FEAT_PMUv3p9 bits. Fixes: 858c7bfcb35e1 ("arm64/boot: Enable EL2 requirements for FEAT_PMUv3p9") Cc: stable@vger.kernel.org Signed-off-by: Fuad Tabba Reviewed-by: Anshuman Khandual Reviewed-by: Oliver Upton Signed-off-by: Will Deacon --- include/media/ipu-bridge.h | 182 +++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 182 insertions(+) create mode 100644 include/media/ipu-bridge.h (limited to 'include/media/ipu-bridge.h') diff --git a/include/media/ipu-bridge.h b/include/media/ipu-bridge.h new file mode 100644 index 000000000..16fac7654 --- /dev/null +++ b/include/media/ipu-bridge.h @@ -0,0 +1,182 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* Author: Dan Scally */ +#ifndef __IPU_BRIDGE_H +#define __IPU_BRIDGE_H + +#include +#include +#include +#include + +#define IPU_HID "INT343E" +#define IPU_MAX_LANES 4 +#define IPU_MAX_PORTS 4 +#define MAX_NUM_LINK_FREQS 3 + +/* Values are educated guesses as we don't have a spec */ +#define IPU_SENSOR_ROTATION_NORMAL 0 +#define IPU_SENSOR_ROTATION_INVERTED 1 + +#define IPU_SENSOR_CONFIG(_HID, _NR, ...) \ + (const struct ipu_sensor_config) { \ + .hid = _HID, \ + .nr_link_freqs = _NR, \ + .link_freqs = { __VA_ARGS__ } \ + } + +#define NODE_SENSOR(_HID, _PROPS) \ + (const struct software_node) { \ + .name = _HID, \ + .properties = _PROPS, \ + } + +#define NODE_PORT(_PORT, _SENSOR_NODE) \ + (const struct software_node) { \ + .name = _PORT, \ + .parent = _SENSOR_NODE, \ + } + +#define NODE_ENDPOINT(_EP, _PORT, _PROPS) \ + (const struct software_node) { \ + .name = _EP, \ + .parent = _PORT, \ + .properties = _PROPS, \ + } + +#define NODE_VCM(_TYPE) \ + (const struct software_node) { \ + .name = _TYPE, \ + } + +enum ipu_sensor_swnodes { + SWNODE_SENSOR_HID, + SWNODE_SENSOR_PORT, + SWNODE_SENSOR_ENDPOINT, + SWNODE_IPU_PORT, + SWNODE_IPU_ENDPOINT, + /* below are optional / maybe empty */ + SWNODE_IVSC_HID, + SWNODE_IVSC_SENSOR_PORT, + SWNODE_IVSC_SENSOR_ENDPOINT, + SWNODE_IVSC_IPU_PORT, + SWNODE_IVSC_IPU_ENDPOINT, + SWNODE_VCM, + SWNODE_COUNT +}; + +/* Data representation as it is in ACPI SSDB buffer */ +struct ipu_sensor_ssdb { + u8 version; + u8 sku; + u8 guid_csi2[16]; + u8 devfunction; + u8 bus; + u32 dphylinkenfuses; + u32 clockdiv; + u8 link; + u8 lanes; + u32 csiparams[10]; + u32 maxlanespeed; + u8 sensorcalibfileidx; + u8 sensorcalibfileidxInMBZ[3]; + u8 romtype; + u8 vcmtype; + u8 platforminfo; + u8 platformsubinfo; + u8 flash; + u8 privacyled; + u8 degree; + u8 mipilinkdefined; + u32 mclkspeed; + u8 controllogicid; + u8 reserved1[3]; + u8 mclkport; + u8 reserved2[13]; +} __packed; + +struct ipu_property_names { + char clock_frequency[16]; + char rotation[9]; + char orientation[12]; + char bus_type[9]; + char data_lanes[11]; + char remote_endpoint[16]; + char link_frequencies[17]; +}; + +struct ipu_node_names { + char port[7]; + char ivsc_sensor_port[7]; + char ivsc_ipu_port[7]; + char endpoint[11]; + char remote_port[9]; + char vcm[16]; +}; + +struct ipu_sensor_config { + const char *hid; + const u8 nr_link_freqs; + const u64 link_freqs[MAX_NUM_LINK_FREQS]; +}; + +struct ipu_sensor { + /* append ssdb.link(u8) in "-%u" format as suffix of HID */ + char name[ACPI_ID_LEN + 4]; + struct acpi_device *adev; + + struct device *csi_dev; + struct acpi_device *ivsc_adev; + char ivsc_name[ACPI_ID_LEN + 4]; + + /* SWNODE_COUNT + 1 for terminating NULL */ + const struct software_node *group[SWNODE_COUNT + 1]; + struct software_node swnodes[SWNODE_COUNT]; + struct ipu_node_names node_names; + + u8 link; + u8 lanes; + u32 mclkspeed; + u32 rotation; + enum v4l2_fwnode_orientation orientation; + const char *vcm_type; + + struct ipu_property_names prop_names; + struct property_entry ep_properties[5]; + struct property_entry dev_properties[5]; + struct property_entry ipu_properties[3]; + struct property_entry ivsc_properties[1]; + struct property_entry ivsc_sensor_ep_properties[4]; + struct property_entry ivsc_ipu_ep_properties[4]; + + struct software_node_ref_args local_ref[1]; + struct software_node_ref_args remote_ref[1]; + struct software_node_ref_args vcm_ref[1]; + struct software_node_ref_args ivsc_sensor_ref[1]; + struct software_node_ref_args ivsc_ipu_ref[1]; +}; + +typedef int (*ipu_parse_sensor_fwnode_t)(struct acpi_device *adev, + struct ipu_sensor *sensor); + +struct ipu_bridge { + struct device *dev; + ipu_parse_sensor_fwnode_t parse_sensor_fwnode; + char ipu_node_name[ACPI_ID_LEN]; + struct software_node ipu_hid_node; + u32 data_lanes[4]; + unsigned int n_sensors; + struct ipu_sensor sensors[IPU_MAX_PORTS]; +}; + +#if IS_ENABLED(CONFIG_IPU_BRIDGE) +int ipu_bridge_init(struct device *dev, + ipu_parse_sensor_fwnode_t parse_sensor_fwnode); +int ipu_bridge_parse_ssdb(struct acpi_device *adev, struct ipu_sensor *sensor); +int ipu_bridge_instantiate_vcm(struct device *sensor); +#else +/* Use a define to avoid the @parse_sensor_fwnode argument getting evaluated */ +#define ipu_bridge_init(dev, parse_sensor_fwnode) (0) +static inline int ipu_bridge_instantiate_vcm(struct device *s) { return 0; } +#endif + +#endif -- cgit v1.3.1