// 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_simple_get(&svc->device_id_map,
GB_SVC_DEVICE_ID_MIN, GB_SVC_DEVICE_ID_MAX + 1,
GFP_KERNEL);
if (ret < 0) {