1263 lines · 28.9 KB · C
RawDownload
// SPDX-License-Identifier: GPL-2.0/* * Greybus interface code * * Copyright 2014 Google Inc. * Copyright 2014 Linaro Ltd. */ #include <linux/delay.h>#include <linux/greybus.h> #include "greybus_trace.h" #define GB_INTERFACE_MODE_SWITCH_TIMEOUT	2000 #define GB_INTERFACE_DEVICE_ID_BAD	0xff #define GB_INTERFACE_AUTOSUSPEND_MS			3000 /* Time required for interface to enter standby before disabling REFCLK */#define GB_INTERFACE_SUSPEND_HIBERNATE_DELAY_MS			20 /* Don't-care selector index */#define DME_SELECTOR_INDEX_NULL		0 /* DME attributes *//* FIXME: remove ES2 support and DME_T_TST_SRC_INCREMENT */#define DME_T_TST_SRC_INCREMENT		0x4083 #define DME_DDBL1_MANUFACTURERID	0x5003#define DME_DDBL1_PRODUCTID		0x5004 #define DME_TOSHIBA_GMP_VID		0x6000#define DME_TOSHIBA_GMP_PID		0x6001#define DME_TOSHIBA_GMP_SN0		0x6002#define DME_TOSHIBA_GMP_SN1		0x6003#define DME_TOSHIBA_GMP_INIT_STATUS	0x6101 /* DDBL1 Manufacturer and Product ids */#define TOSHIBA_DMID			0x0126#define TOSHIBA_ES2_BRIDGE_DPID		0x1000#define TOSHIBA_ES3_APBRIDGE_DPID	0x1001#define TOSHIBA_ES3_GBPHY_DPID	0x1002 static int gb_interface_hibernate_link(struct gb_interface *intf);static int gb_interface_refclk_set(struct gb_interface *intf, bool enable); static int gb_interface_dme_attr_get(struct gb_interface *intf,				     u16 attr, u32 *val){	return gb_svc_dme_peer_get(intf->hd->svc, intf->interface_id,					attr, DME_SELECTOR_INDEX_NULL, val);} static int gb_interface_read_ara_dme(struct gb_interface *intf){	u32 sn0, sn1;	int ret; 	/*	 * Unless this is a Toshiba bridge, bail out until we have defined	 * standard GMP attributes.	 */	if (intf->ddbl1_manufacturer_id != TOSHIBA_DMID) {		dev_err(&intf->dev, "unknown manufacturer %08x\n",			intf->ddbl1_manufacturer_id);		return -ENODEV;	} 	ret = gb_interface_dme_attr_get(intf, DME_TOSHIBA_GMP_VID,					&intf->vendor_id);	if (ret)		return ret; 	ret = gb_interface_dme_attr_get(intf, DME_TOSHIBA_GMP_PID,					&intf->product_id);	if (ret)		return ret; 	ret = gb_interface_dme_attr_get(intf, DME_TOSHIBA_GMP_SN0, &sn0);	if (ret)		return ret; 	ret = gb_interface_dme_attr_get(intf, DME_TOSHIBA_GMP_SN1, &sn1);	if (ret)		return ret; 	intf->serial_number = (u64)sn1 << 32 | sn0; 	return 0;} static int gb_interface_read_dme(struct gb_interface *intf){	int ret; 	/* DME attributes have already been read */	if (intf->dme_read)		return 0; 	ret = gb_interface_dme_attr_get(intf, DME_DDBL1_MANUFACTURERID,					&intf->ddbl1_manufacturer_id);	if (ret)		return ret; 	ret = gb_interface_dme_attr_get(intf, DME_DDBL1_PRODUCTID,					&intf->ddbl1_product_id);	if (ret)		return ret; 	if (intf->ddbl1_manufacturer_id == TOSHIBA_DMID &&	    intf->ddbl1_product_id == TOSHIBA_ES2_BRIDGE_DPID) {		intf->quirks |= GB_INTERFACE_QUIRK_NO_GMP_IDS;		intf->quirks |= GB_INTERFACE_QUIRK_NO_INIT_STATUS;	} 	ret = gb_interface_read_ara_dme(intf);	if (ret)		return ret; 	intf->dme_read = true; 	return 0;} static int gb_interface_route_create(struct gb_interface *intf){	struct gb_svc *svc = intf->hd->svc;	u8 intf_id = intf->interface_id;	u8 device_id;	int ret; 	/* Allocate an interface device id. */	ret = ida_alloc_range(&svc->device_id_map, GB_SVC_DEVICE_ID_MIN,			      GB_SVC_DEVICE_ID_MAX, GFP_KERNEL);	if (ret < 0) {		dev_err(&intf->dev, "failed to allocate device id: %d\n", ret);		return ret;	}	device_id = ret; 	ret = gb_svc_intf_device_id(svc, intf_id, device_id);	if (ret) {		dev_err(&intf->dev, "failed to set device id %u: %d\n",			device_id, ret);		goto err_ida_remove;	} 	/* FIXME: Hard-coded AP device id. */	ret = gb_svc_route_create(svc, svc->ap_intf_id, GB_SVC_DEVICE_ID_AP,				  intf_id, device_id);	if (ret) {		dev_err(&intf->dev, "failed to create route: %d\n", ret);		goto err_svc_id_free;	} 	intf->device_id = device_id; 	return 0; err_svc_id_free:	/*	 * XXX Should we tell SVC that this id doesn't belong to interface	 * XXX anymore.	 */err_ida_remove:	ida_free(&svc->device_id_map, device_id); 	return ret;} static void gb_interface_route_destroy(struct gb_interface *intf){	struct gb_svc *svc = intf->hd->svc; 	if (intf->device_id == GB_INTERFACE_DEVICE_ID_BAD)		return; 	gb_svc_route_destroy(svc, svc->ap_intf_id, intf->interface_id);	ida_free(&svc->device_id_map, intf->device_id);	intf->device_id = GB_INTERFACE_DEVICE_ID_BAD;} /* Locking: Caller holds the interface mutex. */static int gb_interface_legacy_mode_switch(struct gb_interface *intf){	int ret; 	dev_info(&intf->dev, "legacy mode switch detected\n"); 	/* Mark as disconnected to prevent I/O during disable. */	intf->disconnected = true;	gb_interface_disable(intf);	intf->disconnected = false; 	ret = gb_interface_enable(intf);	if (ret) {		dev_err(&intf->dev, "failed to re-enable interface: %d\n", ret);		gb_interface_deactivate(intf);	} 	return ret;} void gb_interface_mailbox_event(struct gb_interface *intf, u16 result,				u32 mailbox){	mutex_lock(&intf->mutex); 	if (result) {		dev_warn(&intf->dev,			 "mailbox event with UniPro error: 0x%04x\n",			 result);		goto err_disable;	} 	if (mailbox != GB_SVC_INTF_MAILBOX_GREYBUS) {		dev_warn(&intf->dev,			 "mailbox event with unexpected value: 0x%08x\n",			 mailbox);		goto err_disable;	} 	if (intf->quirks & GB_INTERFACE_QUIRK_LEGACY_MODE_SWITCH) {		gb_interface_legacy_mode_switch(intf);		goto out_unlock;	} 	if (!intf->mode_switch) {		dev_warn(&intf->dev, "unexpected mailbox event: 0x%08x\n",			 mailbox);		goto err_disable;	} 	dev_info(&intf->dev, "mode switch detected\n"); 	complete(&intf->mode_switch_completion); out_unlock:	mutex_unlock(&intf->mutex); 	return; err_disable:	gb_interface_disable(intf);	gb_interface_deactivate(intf);	mutex_unlock(&intf->mutex);} static void gb_interface_mode_switch_work(struct work_struct *work){	struct gb_interface *intf;	struct gb_control *control;	unsigned long timeout;	int ret; 	intf = container_of(work, struct gb_interface, mode_switch_work); 	mutex_lock(&intf->mutex);	/* Make sure interface is still enabled. */	if (!intf->enabled) {		dev_dbg(&intf->dev, "mode switch aborted\n");		intf->mode_switch = false;		mutex_unlock(&intf->mutex);		goto out_interface_put;	} 	/*	 * Prepare the control device for mode switch and make sure to get an	 * extra reference before it goes away during interface disable.	 */	control = gb_control_get(intf->control);	gb_control_mode_switch_prepare(control);	gb_interface_disable(intf);	mutex_unlock(&intf->mutex); 	timeout = msecs_to_jiffies(GB_INTERFACE_MODE_SWITCH_TIMEOUT);	ret = wait_for_completion_interruptible_timeout(			&intf->mode_switch_completion, timeout); 	/* Finalise control-connection mode switch. */	gb_control_mode_switch_complete(control);	gb_control_put(control); 	if (ret < 0) {		dev_err(&intf->dev, "mode switch interrupted\n");		goto err_deactivate;	} else if (ret == 0) {		dev_err(&intf->dev, "mode switch timed out\n");		goto err_deactivate;	} 	/* Re-enable (re-enumerate) interface if still active. */	mutex_lock(&intf->mutex);	intf->mode_switch = false;	if (intf->active) {		ret = gb_interface_enable(intf);		if (ret) {			dev_err(&intf->dev, "failed to re-enable interface: %d\n",				ret);			gb_interface_deactivate(intf);		}	}	mutex_unlock(&intf->mutex); out_interface_put:	gb_interface_put(intf); 	return; err_deactivate:	mutex_lock(&intf->mutex);	intf->mode_switch = false;	gb_interface_deactivate(intf);	mutex_unlock(&intf->mutex); 	gb_interface_put(intf);} int gb_interface_request_mode_switch(struct gb_interface *intf){	int ret = 0; 	mutex_lock(&intf->mutex);	if (intf->mode_switch) {		ret = -EBUSY;		goto out_unlock;	} 	intf->mode_switch = true;	reinit_completion(&intf->mode_switch_completion); 	/*	 * Get a reference to the interface device, which will be put once the	 * mode switch is complete.	 */	get_device(&intf->dev); 	if (!queue_work(system_long_wq, &intf->mode_switch_work)) {		put_device(&intf->dev);		ret = -EBUSY;		goto out_unlock;	} out_unlock:	mutex_unlock(&intf->mutex); 	return ret;}EXPORT_SYMBOL_GPL(gb_interface_request_mode_switch); /* * T_TstSrcIncrement is written by the module on ES2 as a stand-in for the * init-status attribute DME_TOSHIBA_INIT_STATUS. The AP needs to read and * clear it after reading a non-zero value from it. * * FIXME: This is module-hardware dependent and needs to be extended for every * type of module we want to support. */static int gb_interface_read_and_clear_init_status(struct gb_interface *intf){	struct gb_host_device *hd = intf->hd;	unsigned long bootrom_quirks;	unsigned long s2l_quirks;	int ret;	u32 value;	u16 attr;	u8 init_status; 	/*	 * ES2 bridges use T_TstSrcIncrement for the init status.	 *	 * FIXME: Remove ES2 support	 */	if (intf->quirks & GB_INTERFACE_QUIRK_NO_INIT_STATUS)		attr = DME_T_TST_SRC_INCREMENT;	else		attr = DME_TOSHIBA_GMP_INIT_STATUS; 	ret = gb_svc_dme_peer_get(hd->svc, intf->interface_id, attr,				  DME_SELECTOR_INDEX_NULL, &value);	if (ret)		return ret; 	/*	 * A nonzero init status indicates the module has finished	 * initializing.	 */	if (!value) {		dev_err(&intf->dev, "invalid init status\n");		return -ENODEV;	} 	/*	 * Extract the init status.	 *	 * For ES2: We need to check lowest 8 bits of 'value'.	 * For ES3: We need to check highest 8 bits out of 32 of 'value'.	 *	 * FIXME: Remove ES2 support	 */	if (intf->quirks & GB_INTERFACE_QUIRK_NO_INIT_STATUS)		init_status = value & 0xff;	else		init_status = value >> 24; 	/*	 * Check if the interface is executing the quirky ES3 bootrom that,	 * for example, requires E2EFC, CSD and CSV to be disabled.	 */	bootrom_quirks = GB_INTERFACE_QUIRK_NO_CPORT_FEATURES |				GB_INTERFACE_QUIRK_FORCED_DISABLE |				GB_INTERFACE_QUIRK_LEGACY_MODE_SWITCH |				GB_INTERFACE_QUIRK_NO_BUNDLE_ACTIVATE; 	s2l_quirks = GB_INTERFACE_QUIRK_NO_PM; 	switch (init_status) {	case GB_INIT_BOOTROM_UNIPRO_BOOT_STARTED:	case GB_INIT_BOOTROM_FALLBACK_UNIPRO_BOOT_STARTED:		intf->quirks |= bootrom_quirks;		break;	case GB_INIT_S2_LOADER_BOOT_STARTED:		/* S2 Loader doesn't support runtime PM */		intf->quirks &= ~bootrom_quirks;		intf->quirks |= s2l_quirks;		break;	default:		intf->quirks &= ~bootrom_quirks;		intf->quirks &= ~s2l_quirks;	} 	/* Clear the init status. */	return gb_svc_dme_peer_set(hd->svc, intf->interface_id, attr,				   DME_SELECTOR_INDEX_NULL, 0);} /* interface sysfs attributes */#define gb_interface_attr(field, type)					\static ssize_t field##_show(struct device *dev,				\			    struct device_attribute *attr,		\			    char *buf)					\{									\	struct gb_interface *intf = to_gb_interface(dev);		\	return scnprintf(buf, PAGE_SIZE, type"\n", intf->field);	\}									\static DEVICE_ATTR_RO(field) gb_interface_attr(ddbl1_manufacturer_id, "0x%08x");gb_interface_attr(ddbl1_product_id, "0x%08x");gb_interface_attr(interface_id, "%u");gb_interface_attr(vendor_id, "0x%08x");gb_interface_attr(product_id, "0x%08x");gb_interface_attr(serial_number, "0x%016llx"); static ssize_t voltage_now_show(struct device *dev,				struct device_attribute *attr, char *buf){	struct gb_interface *intf = to_gb_interface(dev);	int ret;	u32 measurement; 	ret = gb_svc_pwrmon_intf_sample_get(intf->hd->svc, intf->interface_id,					    GB_SVC_PWRMON_TYPE_VOL,					    &measurement);	if (ret) {		dev_err(&intf->dev, "failed to get voltage sample (%d)\n", ret);		return ret;	} 	return sprintf(buf, "%u\n", measurement);}static DEVICE_ATTR_RO(voltage_now); static ssize_t current_now_show(struct device *dev,				struct device_attribute *attr, char *buf){	struct gb_interface *intf = to_gb_interface(dev);	int ret;	u32 measurement; 	ret = gb_svc_pwrmon_intf_sample_get(intf->hd->svc, intf->interface_id,					    GB_SVC_PWRMON_TYPE_CURR,					    &measurement);	if (ret) {		dev_err(&intf->dev, "failed to get current sample (%d)\n", ret);		return ret;	} 	return sprintf(buf, "%u\n", measurement);}static DEVICE_ATTR_RO(current_now); static ssize_t power_now_show(struct device *dev,			      struct device_attribute *attr, char *buf){	struct gb_interface *intf = to_gb_interface(dev);	int ret;	u32 measurement; 

Lines 1–500 of 1263.