1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182
|
/* SPDX-License-Identifier: GPL-2.0 */
/* Author: Dan Scally <djrscally@gmail.com> */
#ifndef __IPU_BRIDGE_H
#define __IPU_BRIDGE_H
#include <linux/mod_devicetable.h>
#include <linux/property.h>
#include <linux/types.h>
#include <media/v4l2-fwnode.h>
#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
|