Re: [PATCH v3 1/2] usb: typec: Add support for UCSI interface

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



On Thu, Jun 15, 2017 at 08:08:19AM -0700, Guenter Roeck wrote:
> On Mon, Jun 12, 2017 at 05:40:08PM +0300, Heikki Krogerus wrote:
> > UCSI - USB Type-C Connector System Software Interface - is a
> > specification that defines set of registers and data
> > structures for controlling the USB Type-C ports. It's
> > designed for systems where an embedded controller (EC) is in
> > charge of the USB Type-C PHY or USB Power Delivery
> > controller. It is designed for systems with EC, but it is
> > not limited to them, and for example some USB Power Delivery
> > controllers will use it as their direct control interface.
> > 
> > With UCSI the EC (or USB PD controller) acts as the port
> > manager, implementing all USB Type-C and Power Delivery state
> > machines. The OS can use the interfaces for reading the
> > status of the ports and controlling basic operations like
> > role swapping.
> > 
> > The UCSI specification highlights the fact that it does not
> > define the interface method (PCI/I2C/ACPI/etc.).
> > Therefore the driver is implemented as library and every
> > supported interface method needs its own driver. Driver for
> > ACPI is provided in separate patch following this one.
> > 
> > The initial driver includes support for all required
> > features from UCSI specification version 1.0 (getting
> > connector capabilities and status, and support for power and
> > data role swapping), but none of the optional UCSI features
> > (alternate modes, power source capabilities, and cable
> > capabilities).
> > 
> > Signed-off-by: Heikki Krogerus <heikki.krogerus@xxxxxxxxxxxxxxx>
> 
> Couple of nitpicks, but I am also still concerned about the use
> of bit fields, epecially when the bit field size does not align
> with register sizes. Maybe my concerns are overblown; if so, I
> would kindly ask for someone from Intel (or any other listener)
> to provide a Reviewed-by: tag.

You do have a point, I will need to fix the structures...

> > diff --git a/drivers/usb/typec/ucsi/trace.c b/drivers/usb/typec/ucsi/trace.c
> > new file mode 100644
> > index 000000000000..006f65c72a34
> > --- /dev/null
> > +++ b/drivers/usb/typec/ucsi/trace.c
> > @@ -0,0 +1,2 @@
> > +#define CREATE_TRACE_POINTS
> > +#include "trace.h"
> > diff --git a/drivers/usb/typec/ucsi/trace.h b/drivers/usb/typec/ucsi/trace.h
> > new file mode 100644
> > index 000000000000..30a24e8fadc7
> > --- /dev/null
> > +++ b/drivers/usb/typec/ucsi/trace.h
> > @@ -0,0 +1,143 @@
> > +
> > +#undef TRACE_SYSTEM
> > +#define TRACE_SYSTEM ucsi
> > +
> > +#if !defined(__UCSI_TRACE_H) || defined(TRACE_HEADER_MULTI_READ)
> > +#define __UCSI_TRACE_H
> > +
> > +#include <linux/tracepoint.h>
> > +#include "ucsi.h"
> > +#include "debug.h"
> > +
> > +DECLARE_EVENT_CLASS(ucsi_log_ack,
> > +	TP_PROTO(u8 ack),
> > +	TP_ARGS(ack),
> > +	TP_STRUCT__entry(
> > +		__field(u8, ack)
> > +	),
> > +	TP_fast_assign(
> > +		__entry->ack = ack;
> > +	),
> > +	TP_printk("ACK %s", ucsi_ack_str(__entry->ack))
> > +);
> > +
> > +DEFINE_EVENT(ucsi_log_ack, ucsi_ack,
> > +	TP_PROTO(u8 ack),
> > +	TP_ARGS(ack)
> > +);
> > +
> > +DECLARE_EVENT_CLASS(ucsi_log_control,
> > +	TP_PROTO(struct ucsi_control *ctrl),
> > +	TP_ARGS(ctrl),
> > +	TP_STRUCT__entry(
> > +		__field(u64, ctrl)
> > +	),
> > +	TP_fast_assign(
> > +		__entry->ctrl = ctrl->raw_cmd;
> > +	),
> > +	TP_printk("control=%08llx (%s)", __entry->ctrl,
> > +		ucsi_cmd_str(__entry->ctrl))
> > +);
> > +
> > +DEFINE_EVENT(ucsi_log_control, ucsi_command,
> > +	TP_PROTO(struct ucsi_control *ctrl),
> > +	TP_ARGS(ctrl)
> > +);
> > +
> > +DECLARE_EVENT_CLASS(ucsi_log_command,
> > +	TP_PROTO(struct ucsi_control *ctrl, int ret),
> > +	TP_ARGS(ctrl, ret),
> > +	TP_STRUCT__entry(
> > +		__field(u64, ctrl)
> > +		__field(int, ret)
> > +	),
> > +	TP_fast_assign(
> > +		__entry->ctrl = ctrl->raw_cmd;
> > +		__entry->ret = ret;
> > +	),
> > +	TP_printk("%s -> %s (err=%d)", ucsi_cmd_str(__entry->ctrl),
> > +		__entry->ret < 0 ? "FAIL" : "OK",
> > +		__entry->ret < 0 ? __entry->ret : 0)
> > +);
> > +
> > +DEFINE_EVENT(ucsi_log_command, ucsi_run_command,
> > +	TP_PROTO(struct ucsi_control *ctrl, int ret),
> > +	TP_ARGS(ctrl, ret)
> > +);
> > +
> > +DEFINE_EVENT(ucsi_log_command, ucsi_reset_ppm,
> > +	TP_PROTO(struct ucsi_control *ctrl, int ret),
> > +	TP_ARGS(ctrl, ret)
> > +);
> > +
> > +DECLARE_EVENT_CLASS(ucsi_log_cci,
> > +	TP_PROTO(u32 cci),
> > +	TP_ARGS(cci),
> > +	TP_STRUCT__entry(
> > +		__field(u32, cci)
> > +	),
> > +	TP_fast_assign(
> > +		__entry->cci = cci;
> > +	),
> > +	TP_printk("CCI=%08x %s", __entry->cci, ucsi_cci_str(__entry->cci))
> > +);
> > +
> > +DEFINE_EVENT(ucsi_log_cci, ucsi_notify,
> > +	TP_PROTO(u32 cci),
> > +	TP_ARGS(cci)
> > +);
> > +
> > +DECLARE_EVENT_CLASS(ucsi_log_connector_status,
> > +	TP_PROTO(int port, struct ucsi_connector_status *status),
> > +	TP_ARGS(port, status),
> > +	TP_STRUCT__entry(
> > +		__field(int, port)
> > +		__field(u16, change)
> > +		__field(u8, opmode)
> > +		__field(u8, connected)
> > +		__field(u8, pwr_dir)
> > +		__field(u8, partner_flags)
> > +		__field(u8, partner_type)
> > +		__field(u32, request_data_obj)
> > +		__field(u8, bc_status)
> > +	),
> > +	TP_fast_assign(
> > +		__entry->port = port - 1;
> > +		__entry->change = status->change;
> > +		__entry->opmode = status->pwr_op_mode;
> > +		__entry->connected = status->connected;
> > +		__entry->pwr_dir = status->pwr_dir;
> > +		__entry->partner_flags = status->partner_flags;
> > +		__entry->partner_type = status->partner_type;
> > +		__entry->request_data_obj = status->request_data_obj;
> > +		__entry->bc_status = status->bc_status;
> > +	),
> > +	TP_printk("port%d status: change=%04x, opmode=%x, connected=%d, "
> > +		"sourcing=%d, partner_flags=%x, partner_type=%x, "
> > +		"reguest_data_obj=%08x, BC status=%x", __entry->port,
> 
> s/reguest_data_obj/request_data_obj/

OK,

<snip>

> > +#define __UCSI_CMD(_ctrl_, _cmd_)					\
> > +{									\
> > +	_ctrl_.raw_cmd = 0;						\
> > +	_ctrl_.cmd.cmd = _cmd_;						\
> 
> (_ctrl_) ?
> 
> > +}
> > +
> > +/* Helper for preparing ucsi_control for CONNECTOR_RESET command. */
> > +#define UCSI_CMD_CONNECTOR_RESET(_ctrl_, _con_, _hard_)			\
> > +{									\
> > +	__UCSI_CMD(_ctrl_, UCSI_CONNECTOR_RESET)			\
> > +	_ctrl_.con_rst.con_num = _con_->num;				\
> 
> (_ctrl_), (_con_) ?
> 
> > +	_ctrl_.con_rst.hard_reset = _hard_;				\
> > +}
> > +
> > +/* Helper for preparing ucsi_control for ACK_CC_CI command. */
> > +#define UCSI_CMD_ACK(_ctrl_, _ack_)					\
> > +{									\
> > +	__UCSI_CMD(_ctrl_, UCSI_ACK_CC_CI)				\
> > +	_ctrl_.ack.cci_ack = (_ack_ == UCSI_ACK_EVENT);			\
> > +	_ctrl_.ack.cmd_ack = (_ack_ == UCSI_ACK_CMD);			\
> 
> ... and so on

Sure, I'll fix all of them.

> > +}
> > +
> > +/* Helper for preparing ucsi_control for SET_NOTIFY_ENABLE command. */
> > +#define UCSI_CMD_SET_NTFY_ENABLE(_ctrl_, _ntfys_)			\
> > +{									\
> > +	__UCSI_CMD(_ctrl_, UCSI_SET_NOTIFICATION_ENABLE)		\
> > +	_ctrl_.cmd.data = _ntfys_;					\
> > +}
> > +
> > +/* Helper for preparing ucsi_control for GET_CAPABILITY command. */
> > +#define UCSI_CMD_GET_CAPABILITY(_ctrl_)					\
> > +{									\
> > +	__UCSI_CMD(_ctrl_, UCSI_GET_CAPABILITY)				\
> > +}
> > +
> > +/* Helper for preparing ucsi_control for GET_CONNECTOR_CAPABILITY command. */
> > +#define UCSI_CMD_GET_CONNECTOR_CAPABILITY(_ctrl_, _con_)		\
> > +{									\
> > +	__UCSI_CMD(_ctrl_, UCSI_GET_CONNECTOR_CAPABILITY)		\
> > +	_ctrl_.cmd.data = _con_;					\
> > +}
> > +
> > +/* Helper for preparing ucsi_control for GET_CONNECTOR_STATUS command. */
> > +#define UCSI_CMD_GET_CONNECTOR_STATUS(_ctrl_, _con_)			\
> > +{									\
> > +	__UCSI_CMD(_ctrl_, UCSI_GET_CONNECTOR_STATUS)			\
> > +	_ctrl_.cmd.data = _con_;					\
> > +}
> > +
> > +#define __UCSI_ROLE(_ctrl_, _cmd_, _con_num_)			\
> > +{									\
> > +	__UCSI_CMD(_ctrl_, _cmd_)					\
> > +	_ctrl_.uor.con_num = _con_num_;					\
> > +	_ctrl_.uor.role = UCSI_UOR_ROLE_DRP;				\
> > +}
> > +
> > +/* Helper for preparing ucsi_control for SET_UOR command. */
> > +#define UCSI_CMD_SET_UOR(_ctrl_, _con_, _role_)				\
> > +{									\
> > +	__UCSI_ROLE(_ctrl_, UCSI_SET_UOR, _con_->num)			\
> > +	_ctrl_.uor.role |= _role_ == TYPEC_HOST ? UCSI_UOR_ROLE_DFP :	\
> > +			UCSI_UOR_ROLE_UFP;				\
> > +}
> > +
> > +/* Helper for preparing ucsi_control for SET_PDR command. */
> > +#define UCSI_CMD_SET_PDR(_ctrl_, _con_, _role_)				\
> > +{									\
> > +	__UCSI_ROLE(_ctrl_, UCSI_SET_PDR, _con_->num)			\
> > +	_ctrl_.uor.role |= _role_ == TYPEC_SOURCE ? UCSI_UOR_ROLE_DFP :	\
> > +			UCSI_UOR_ROLE_UFP;				\
> > +}
> > +
> > +/* Commands */
> > +#define UCSI_PPM_RESET			0x01
> > +#define UCSI_CANCEL			0x02
> > +#define UCSI_CONNECTOR_RESET		0x03
> > +#define UCSI_ACK_CC_CI			0x04
> > +#define UCSI_SET_NOTIFICATION_ENABLE	0x05
> > +#define UCSI_GET_CAPABILITY		0x06
> > +#define UCSI_GET_CONNECTOR_CAPABILITY	0x07
> > +#define UCSI_SET_UOM			0x08
> > +#define UCSI_SET_UOR			0x09
> > +#define UCSI_SET_PDM			0x0a
> > +#define UCSI_SET_PDR			0x0b
> > +#define UCSI_GET_ALTERNATE_MODES	0x0c
> > +#define UCSI_GET_CAM_SUPPORTED		0x0d
> > +#define UCSI_GET_CURRENT_CAM		0x0e
> > +#define UCSI_SET_NEW_CAM		0x0f
> > +#define UCSI_GET_PDOS			0x10
> > +#define UCSI_GET_CABLE_PROPERTY		0x11
> > +#define UCSI_GET_CONNECTOR_STATUS	0x12
> > +#define UCSI_GET_ERROR_STATUS		0x13
> > +
> > +/* ACK_CC_CI commands */
> > +#define UCSI_ACK_EVENT			1
> > +#define UCSI_ACK_CMD			2
> > +
> > +/* Bits for SET_NOTIFICATION_ENABLE command */
> > +#define UCSI_ENABLE_NTFY_CMD_COMPLETE		BIT(0)
> > +#define UCSI_ENABLE_NTFY_EXT_PWR_SRC_CHANGE	BIT(1)
> > +#define UCSI_ENABLE_NTFY_PWR_OPMODE_CHANGE	BIT(2)
> > +#define UCSI_ENABLE_NTFY_CAP_CHANGE		BIT(5)
> > +#define UCSI_ENABLE_NTFY_PWR_LEVEL_CHANGE	BIT(6)
> > +#define UCSI_ENABLE_NTFY_PD_RESET_COMPLETE	BIT(7)
> > +#define UCSI_ENABLE_NTFY_CAM_CHANGE		BIT(8)
> > +#define UCSI_ENABLE_NTFY_BAT_STATUS_CHANGE	BIT(9)
> > +#define UCSI_ENABLE_NTFY_PARTNER_CHANGE		BIT(11)
> > +#define UCSI_ENABLE_NTFY_PWR_DIR_CHANGE		BIT(12)
> > +#define UCSI_ENABLE_NTFY_CONNECTOR_CHANGE	BIT(14)
> > +#define UCSI_ENABLE_NTFY_ERROR			BIT(15)
> > +#define UCSI_ENABLE_NTFY_ALL			0xdbe7
> > +
> > +/* Error information returned by PPM in response to GET_ERROR_STATUS command. */
> > +#define UCSI_ERROR_UNREGONIZED_CMD		BIT(0)
> > +#define UCSI_ERROR_INVALID_CON_NUM		BIT(1)
> > +#define UCSI_ERROR_INVALID_CMD_ARGUMENT		BIT(2)
> > +#define UCSI_ERROR_INCOMPATIBLE_PARTNER		BIT(3)
> > +#define UCSI_ERROR_CC_COMMUNICATION_ERR		BIT(4)
> > +#define UCSI_ERROR_DEAD_BATTERY			BIT(5)
> > +#define UCSI_ERROR_CONTRACT_NEGOTIATION_FAIL	BIT(6)
> > +
> > +/* Data structure filled by PPM in response to GET_CAPABILITY command. */
> > +struct ucsi_capability {
> > +	u32 attributes;
> > +#define UCSI_CAP_ATTR_DISABLE_STATE		BIT(0)
> > +#define UCSI_CAP_ATTR_BATTERY_CHARGING		BIT(1)
> > +#define UCSI_CAP_ATTR_USB_PD			BIT(2)
> > +#define UCSI_CAP_ATTR_TYPEC_CURRENT		BIT(6)
> > +#define UCSI_CAP_ATTR_POWER_AC_SUPPLY		BIT(8)
> > +#define UCSI_CAP_ATTR_POWER_OTHER		BIT(10)
> > +#define UCSI_CAP_ATTR_POWER_VBUS		BIT(14)
> > +	u8 num_connectors;
> > +	u32 features:24;
> 
> Still wonder what this kind of construct is doing.
> Is it guaranteed that it only allocates 24 bit, overlapping
> with num_conectors ? If so, why not "u32 num_connectors:8;" ?

True. I'll fix it.

> Or does it allocate 32 bit, with 8 bit unused ?
> In the latter case, it might be useful to fill the field with
> "u32 unused:8;" or similar for clarification.
> 
> > +#define UCSI_CAP_SET_UOM			BIT(0)
> > +#define UCSI_CAP_SET_PDM			BIT(1)
> > +#define UCSI_CAP_ALT_MODE_DETAILS		BIT(2)
> > +#define UCSI_CAP_ALT_MODE_OVERRIDE		BIT(3)
> > +#define UCSI_CAP_PDO_DETAILS			BIT(4)
> > +#define UCSI_CAP_CABLE_DETAILS			BIT(5)
> > +#define UCSI_CAP_EXT_SUPPLY_NOTIFICATIONS	BIT(6)
> > +#define UCSI_CAP_PD_RESET			BIT(7)
> > +	u8 num_alt_modes;
> > +	u8 reserved;
> > +	u16 bc_version;
> > +	u16 pd_version;
> > +	u16 typec_version;
> > +} __packed;
> > +
> > +/* Data structure filled by PPM in response to GET_CONNECTOR_CAPABILITY cmd. */
> > +struct ucsi_connector_capability {
> > +	u8 op_mode;
> > +#define UCSI_CONCAP_OPMODE_DFP			BIT(0)
> > +#define UCSI_CONCAP_OPMODE_UFP			BIT(1)
> > +#define UCSI_CONCAP_OPMODE_DRP			BIT(2)
> > +#define UCSI_CONCAP_OPMODE_AUDIO_ACCESSORY	BIT(3)
> > +#define UCSI_CONCAP_OPMODE_DEBUG_ACCESSORY	BIT(4)
> > +#define UCSI_CONCAP_OPMODE_USB2			BIT(5)
> > +#define UCSI_CONCAP_OPMODE_USB3			BIT(6)
> > +#define UCSI_CONCAP_OPMODE_ALT_MODE		BIT(7)
> > +	u8 provider:1;
> > +	u8 consumer:1;
> > +} __packed;
> > +
> > +struct ucsi_altmode {
> > +	u16 svid;
> > +	u32 mid;
> > +} __packed;
> > +
> > +/* Data structure filled by PPM in response to GET_CABLE_PROPERTY command. */
> > +struct ucsi_cable_property {
> > +	u16 speed_supported;
> > +	u8 current_capability;
> > +	u8 vbus_in_cable:1;
> > +	u8 active_cable:1;
> > +	u8 directionality:1;
> > +	u8 plug_type:2;
> > +#define UCSI_CABLE_PROPERTY_PLUG_TYPE_A		0
> > +#define UCSI_CABLE_PROPERTY_PLUG_TYPE_B		1
> > +#define UCSI_CABLE_PROPERTY_PLUG_TYPE_C		2
> > +#define UCSI_CABLE_PROPERTY_PLUG_OTHER		3
> > +	u8 mode_support:1;
> > +	u8:2; /* reserved */
> > +	u8 latency:4;
> 
> And another 4 bit reserved ?
> 
> Overall the mixed use of bit fields makes me a bit uneasy.
> The bit fields often don't align with the real world (it is
> unlikely that struct ucsi_cable_property, as defined by the
> protocol, has a length of 36 bit). Since, presumably, the
> structures are supposed to reflect the protocol, I would find
> it useful to have the structures filled with "reserved" fields.
> 
> That is of course just my personal opinion, but I think it would
> be _really_ helpful in cases where an incomplete bit field is followed
> by more variables, like further above. It would also help understanding
> the complete protocol (is the above a 5-byte field per UCSI ? or 6 ? 8 ?).

You are correct. I'll fill the structures with reserved fields.


Thanks,

-- 
heikki
--
To unsubscribe from this list: send the line "unsubscribe linux-usb" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at  http://vger.kernel.org/majordomo-info.html



[Index of Archives]     [Linux Media]     [Linux Input]     [Linux Audio Users]     [Yosemite News]     [Linux Kernel]     [Linux SCSI]     [Old Linux USB Devel Archive]

  Powered by Linux