diff options
Diffstat (limited to 'drivers')
| -rw-r--r-- | drivers/bluetooth/ath3k.c | 18 | ||||
| -rw-r--r-- | drivers/bluetooth/btqca.c | 58 | ||||
| -rw-r--r-- | drivers/media/platform/msm/camera_v2/msm.c | 18 | ||||
| -rw-r--r-- | drivers/net/wireless/ath/ath10k/core.h | 3 | ||||
| -rw-r--r-- | drivers/net/wireless/ath/ath10k/mac.c | 4 | ||||
| -rw-r--r-- | drivers/net/wireless/ath/ath10k/wmi-ops.h | 19 | ||||
| -rw-r--r-- | drivers/net/wireless/ath/ath10k/wmi-tlv.c | 77 | ||||
| -rw-r--r-- | drivers/net/wireless/ath/ath10k/wmi-tlv.h | 6 | ||||
| -rw-r--r-- | drivers/net/wireless/ath/ath10k/wmi.h | 49 | ||||
| -rw-r--r-- | drivers/net/wireless/ath/ath10k/wow.c | 89 | ||||
| -rw-r--r-- | drivers/soc/qcom/msm_bus/msm_bus_dbg_voter.c | 15 | ||||
| -rw-r--r-- | drivers/spi/spi_qsd.c | 104 | ||||
| -rw-r--r-- | drivers/spi/spi_qsd.h | 29 | ||||
| -rw-r--r-- | drivers/video/fbdev/msm/mdss_hdmi_tx.c | 3 |
14 files changed, 461 insertions, 31 deletions
diff --git a/drivers/bluetooth/ath3k.c b/drivers/bluetooth/ath3k.c index 5df8e1234505..071c94457d34 100644 --- a/drivers/bluetooth/ath3k.c +++ b/drivers/bluetooth/ath3k.c @@ -209,13 +209,27 @@ static int ath3k_load_firmware(struct usb_device *udev, { u8 *send_buf; int err, pipe, len, size, sent = 0; - int count = firmware->size; + int count; BT_DBG("udev %p", udev); + if (!firmware || !firmware->data || firmware->size <= 0) { + err = -EINVAL; + BT_ERR("Not a valid FW file"); + return err; + } + + count = firmware->size; + + if (count < FW_HDR_SIZE) { + err = -EINVAL; + BT_ERR("ath3k loading invalid size of file"); + return err; + } + pipe = usb_sndctrlpipe(udev, 0); - send_buf = kmalloc(BULK_SIZE, GFP_KERNEL); + send_buf = kzalloc(BULK_SIZE, GFP_KERNEL); if (!send_buf) { BT_ERR("Can't allocate memory chunk for firmware"); return -ENOMEM; diff --git a/drivers/bluetooth/btqca.c b/drivers/bluetooth/btqca.c index 4a6208168850..0db4a00e7641 100644 --- a/drivers/bluetooth/btqca.c +++ b/drivers/bluetooth/btqca.c @@ -27,6 +27,9 @@ #define VERSION "0.1" +#define MAX_PATCH_FILE_SIZE (100*1024) +#define MAX_NVM_FILE_SIZE (10*1024) + static int rome_patch_ver_req(struct hci_dev *hdev, u32 *rome_version) { struct sk_buff *skb; @@ -285,27 +288,59 @@ static int rome_download_firmware(struct hci_dev *hdev, struct rome_config *config) { const struct firmware *fw; + u32 type_len, length; + struct tlv_type_hdr *tlv; int ret; - BT_INFO("%s: ROME Downloading %s", hdev->name, config->fwname); - + BT_INFO("%s: ROME Downloading file: %s", hdev->name, config->fwname); ret = request_firmware(&fw, config->fwname, &hdev->dev); - if (ret) { - BT_ERR("%s: Failed to request file: %s (%d)", hdev->name, - config->fwname, ret); + + if (ret || !fw || !fw->data || fw->size <= 0) { + BT_ERR("Failed to request file: err = (%d)", ret); + ret = ret ? ret : -EINVAL; return ret; } + if (config->type == TLV_TYPE_PATCH && + (fw->size > MAX_PATCH_FILE_SIZE)) { + ret = -EINVAL; + BT_ERR("TLV_PATCH dload: wrong patch file sizes"); + goto exit; + } else if (config->type == TLV_TYPE_NVM && + (fw->size > MAX_NVM_FILE_SIZE)) { + ret = -EINVAL; + BT_ERR("TLV_NVM dload: wrong NVM file sizes"); + goto exit; + } else { + ret = -EINVAL; + BT_ERR("TLV_NVM dload: wrong config type selected"); + goto exit; + } - rome_tlv_check_data(config, fw); + if (fw->size < sizeof(struct tlv_type_hdr)) { + ret = -EINVAL; + BT_ERR("Firware size smaller to fit minimum value"); + goto exit; + } + tlv = (struct tlv_type_hdr *)fw->data; + type_len = le32_to_cpu(tlv->type_len); + length = (type_len >> 8) & 0x00ffffff; + + if (fw->size - 4 != length) { + ret = -EINVAL; + BT_ERR("Requested size not matching size in header"); + goto exit; + } + + rome_tlv_check_data(config, fw); ret = rome_tlv_download_request(hdev, fw); + if (ret) { - BT_ERR("%s: Failed to download file: %s (%d)", hdev->name, - config->fwname, ret); + BT_ERR("Failed to download FW: error = (%d)", ret); } +exit: release_firmware(fw); - return ret; } @@ -316,8 +351,9 @@ int qca_set_bdaddr_rome(struct hci_dev *hdev, const bdaddr_t *bdaddr) int err; cmd[0] = EDL_NVM_ACCESS_SET_REQ_CMD; - cmd[1] = 0x02; /* TAG ID */ - cmd[2] = sizeof(bdaddr_t); /* size */ + /* Set the TAG ID of 0x02 for NVM set and size of tag */ + cmd[1] = 0x02; + cmd[2] = sizeof(bdaddr_t); memcpy(cmd + 3, bdaddr, sizeof(bdaddr_t)); skb = __hci_cmd_sync_ev(hdev, EDL_NVM_ACCESS_OPCODE, sizeof(cmd), cmd, HCI_VENDOR_PKT, HCI_INIT_TIMEOUT); diff --git a/drivers/media/platform/msm/camera_v2/msm.c b/drivers/media/platform/msm/camera_v2/msm.c index 194a6583103e..6a969401e950 100644 --- a/drivers/media/platform/msm/camera_v2/msm.c +++ b/drivers/media/platform/msm/camera_v2/msm.c @@ -35,6 +35,7 @@ static struct v4l2_device *msm_v4l2_dev; static struct list_head ordered_sd_list; static struct mutex ordered_sd_mtx; +static struct mutex v4l2_event_mtx; static struct pm_qos_request msm_v4l2_pm_qos_request; @@ -852,13 +853,25 @@ static long msm_private_ioctl(struct file *file, void *fh, static int msm_unsubscribe_event(struct v4l2_fh *fh, const struct v4l2_event_subscription *sub) { - return v4l2_event_unsubscribe(fh, sub); + int rc; + + mutex_lock(&v4l2_event_mtx); + rc = v4l2_event_unsubscribe(fh, sub); + mutex_unlock(&v4l2_event_mtx); + + return rc; } static int msm_subscribe_event(struct v4l2_fh *fh, const struct v4l2_event_subscription *sub) { - return v4l2_event_subscribe(fh, sub, 5, NULL); + int rc; + + mutex_lock(&v4l2_event_mtx); + rc = v4l2_event_subscribe(fh, sub, 5, NULL); + mutex_unlock(&v4l2_event_mtx); + + return rc; } static const struct v4l2_ioctl_ops g_msm_ioctl_ops = { @@ -1376,6 +1389,7 @@ static int msm_probe(struct platform_device *pdev) spin_lock_init(&msm_eventq_lock); spin_lock_init(&msm_pid_lock); mutex_init(&ordered_sd_mtx); + mutex_init(&v4l2_event_mtx); INIT_LIST_HEAD(&ordered_sd_list); cam_debugfs_root = debugfs_create_dir(MSM_CAM_LOGSYNC_FILE_BASEDIR, diff --git a/drivers/net/wireless/ath/ath10k/core.h b/drivers/net/wireless/ath/ath10k/core.h index ffcf30756b9e..f194d434b97c 100644 --- a/drivers/net/wireless/ath/ath10k/core.h +++ b/drivers/net/wireless/ath/ath10k/core.h @@ -24,6 +24,7 @@ #include <linux/pci.h> #include <linux/uuid.h> #include <linux/time.h> +#include <linux/inetdevice.h> #include <soc/qcom/socinfo.h> #include "htt.h" @@ -430,6 +431,8 @@ struct ath10k_vif { struct work_struct ap_csa_work; struct delayed_work connection_loss_work; struct cfg80211_bitrate_mask bitrate_mask; + struct wmi_ns_arp_offload_req arp_offload; + struct wmi_ns_arp_offload_req ns_offload; }; struct ath10k_vif_iter { diff --git a/drivers/net/wireless/ath/ath10k/mac.c b/drivers/net/wireless/ath/ath10k/mac.c index 1147dee4051e..9fcc2866d830 100644 --- a/drivers/net/wireless/ath/ath10k/mac.c +++ b/drivers/net/wireless/ath/ath10k/mac.c @@ -1387,6 +1387,10 @@ static int ath10k_vdev_start_restart(struct ath10k_vif *arvif, lockdep_assert_held(&ar->conf_mutex); + /* Clear arp and ns offload cache */ + memset(&arvif->arp_offload, 0, sizeof(arvif->arp_offload)); + memset(&arvif->ns_offload, 0, sizeof(arvif->ns_offload)); + reinit_completion(&ar->vdev_setup_done); reinit_completion(&ar->vdev_delete_done); diff --git a/drivers/net/wireless/ath/ath10k/wmi-ops.h b/drivers/net/wireless/ath/ath10k/wmi-ops.h index 8bb01c1a35f7..dcb0da51530a 100644 --- a/drivers/net/wireless/ath/ath10k/wmi-ops.h +++ b/drivers/net/wireless/ath/ath10k/wmi-ops.h @@ -160,6 +160,8 @@ struct wmi_ops { u32 num_ac); struct sk_buff *(*gen_sta_keepalive)(struct ath10k *ar, const struct wmi_sta_keepalive_arg *arg); + struct sk_buff *(*gen_set_arp_ns_offload)(struct ath10k *ar, + struct ath10k_vif *arvif); struct sk_buff *(*gen_wow_enable)(struct ath10k *ar); struct sk_buff *(*gen_wow_add_wakeup_event)(struct ath10k *ar, u32 vdev_id, enum wmi_wow_wakeup_event event, @@ -1187,6 +1189,23 @@ ath10k_wmi_sta_keepalive(struct ath10k *ar, } static inline int +ath10k_wmi_set_arp_ns_offload(struct ath10k *ar, struct ath10k_vif *arvif) +{ + struct sk_buff *skb; + u32 cmd_id; + + if (!ar->wmi.ops->gen_set_arp_ns_offload) + return -EOPNOTSUPP; + + skb = ar->wmi.ops->gen_set_arp_ns_offload(ar, arvif); + if (IS_ERR(skb)) + return PTR_ERR(skb); + + cmd_id = ar->wmi.cmd->set_arp_ns_offload_cmdid; + return ath10k_wmi_cmd_send(ar, skb, cmd_id); +} + +static inline int ath10k_wmi_wow_enable(struct ath10k *ar) { struct sk_buff *skb; diff --git a/drivers/net/wireless/ath/ath10k/wmi-tlv.c b/drivers/net/wireless/ath/ath10k/wmi-tlv.c index 95bd588e0d2c..b904a0d9d391 100644 --- a/drivers/net/wireless/ath/ath10k/wmi-tlv.c +++ b/drivers/net/wireless/ath/ath10k/wmi-tlv.c @@ -3010,6 +3010,82 @@ ath10k_wmi_tlv_op_gen_tdls_peer_update(struct ath10k *ar, } static struct sk_buff * +ath10k_wmi_tlv_op_gen_set_arp_ns_offload(struct ath10k *ar, + struct ath10k_vif *arvif) +{ + struct wmi_tlv_arp_ns_offload_cmd *cmd; + struct wmi_tlv *tlv; + struct sk_buff *skb; + size_t len; + void *ptr; + int i; + struct wmi_ns_arp_offload_req *arp = &arvif->arp_offload; + struct wmi_ns_offload *ns_tuple[WMI_MAX_NS_OFFLOADS]; + struct wmi_arp_offload *arp_tuple[WMI_MAX_ARP_OFFLOADS]; + + len = sizeof(*cmd) + sizeof(*tlv) + + sizeof(*tlv) + WMI_MAX_NS_OFFLOADS * + (sizeof(struct wmi_ns_offload) + sizeof(*tlv)) + + sizeof(*tlv) + WMI_MAX_ARP_OFFLOADS * + (sizeof(struct wmi_arp_offload) + sizeof(*tlv)); + + skb = ath10k_wmi_alloc_skb(ar, len); + if (!skb) + return ERR_PTR(-ENOMEM); + + ptr = (void *)skb->data; + tlv = ptr; + tlv->tag = __cpu_to_le16(WMI_TLV_TAG_STRUCT_SET_ARP_NS_OFFLOAD_CMD); + tlv->len = __cpu_to_le16(sizeof(*cmd)); + cmd = (struct wmi_tlv_arp_ns_offload_cmd *)tlv->value; + cmd->flags = __cpu_to_le32(0); + cmd->vdev_id = __cpu_to_le32(arvif->vdev_id); + + ptr += (sizeof(*tlv) + sizeof(*cmd)); + tlv = ptr; + tlv->tag = __cpu_to_le16(WMI_TLV_TAG_ARRAY_STRUCT); + tlv->len = __cpu_to_le16(WMI_MAX_NS_OFFLOADS * + (sizeof(struct wmi_ns_offload) + sizeof(*tlv))); + ptr += sizeof(*tlv); + tlv = ptr; + + for (i = 0; i < WMI_MAX_NS_OFFLOADS; i++) { + tlv->tag = __cpu_to_le16(WMI_TLV_TAG_STRUCT_NS_OFFLOAD_TUPLE); + tlv->len = __cpu_to_le16(sizeof(struct wmi_ns_offload)); + ns_tuple[i] = (struct wmi_ns_offload *)tlv->value; + ns_tuple[i]->flags |= __cpu_to_le32(WMI_ARP_NS_OFFLOAD_DISABLE); + ptr += (sizeof(*tlv) + sizeof(struct wmi_ns_offload)); + tlv = ptr; + } + + tlv->tag = __cpu_to_le16(WMI_TLV_TAG_ARRAY_STRUCT); + tlv->len = __cpu_to_le16(WMI_MAX_ARP_OFFLOADS * + (sizeof(struct wmi_arp_offload) + sizeof(*tlv))); + ptr += sizeof(*tlv); + tlv = ptr; + + for (i = 0; i < WMI_MAX_ARP_OFFLOADS; i++) { + tlv->tag = __cpu_to_le16(WMI_TLV_TAG_STRUCT_ARP_OFFLOAD_TUPLE); + tlv->len = __cpu_to_le16(sizeof(struct wmi_arp_offload)); + arp_tuple[i] = (struct wmi_arp_offload *)tlv->value; + if (arp->enable_offload && (i == 0)) { + arp_tuple[i]->flags |= + __cpu_to_le32(WMI_ARPOFF_FLAGS_VALID); + memcpy(&arp_tuple[i]->target_ipaddr, + &arp->params.ipv4_addr, 4); + } else { + arp_tuple[i]->flags |= + __cpu_to_le32(WMI_ARP_NS_OFFLOAD_DISABLE); + } + ptr += (sizeof(*tlv) + sizeof(struct wmi_arp_offload)); + tlv = ptr; + } + + ath10k_dbg(ar, ATH10K_DBG_WMI, "wmi tlv set arp ns offload\n"); + return skb; +} + +static struct sk_buff * ath10k_wmi_tlv_op_gen_wow_enable(struct ath10k *ar) { struct wmi_tlv_wow_enable_cmd *cmd; @@ -3695,6 +3771,7 @@ static const struct wmi_ops wmi_tlv_ops = { .gen_p2p_go_bcn_ie = ath10k_wmi_tlv_op_gen_p2p_go_bcn_ie, .gen_vdev_sta_uapsd = ath10k_wmi_tlv_op_gen_vdev_sta_uapsd, .gen_sta_keepalive = ath10k_wmi_tlv_op_gen_sta_keepalive, + .gen_set_arp_ns_offload = ath10k_wmi_tlv_op_gen_set_arp_ns_offload, .gen_wow_enable = ath10k_wmi_tlv_op_gen_wow_enable, .gen_wow_add_wakeup_event = ath10k_wmi_tlv_op_gen_wow_add_wakeup_event, .gen_wow_host_wakeup_ind = ath10k_wmi_tlv_gen_wow_host_wakeup_ind, diff --git a/drivers/net/wireless/ath/ath10k/wmi-tlv.h b/drivers/net/wireless/ath/ath10k/wmi-tlv.h index 7140e5e23307..1d4aed14fbb4 100644 --- a/drivers/net/wireless/ath/ath10k/wmi-tlv.h +++ b/drivers/net/wireless/ath/ath10k/wmi-tlv.h @@ -1557,6 +1557,12 @@ struct wmi_tlv_wow_enable_cmd { __le32 pause_iface_config; } __packed; +struct wmi_tlv_arp_ns_offload_cmd { + __le32 flags; + __le32 vdev_id; + __le32 num_ns_ext_tuples; +} __packed; + struct wmi_tlv_wow_host_wakeup_ind { __le32 reserved; } __packed; diff --git a/drivers/net/wireless/ath/ath10k/wmi.h b/drivers/net/wireless/ath/ath10k/wmi.h index f59e5f86708b..9b17ef150303 100644 --- a/drivers/net/wireless/ath/ath10k/wmi.h +++ b/drivers/net/wireless/ath/ath10k/wmi.h @@ -20,6 +20,8 @@ #include <linux/types.h> #include <net/mac80211.h> +#include <linux/ipv6.h> +#include <linux/in.h> /* * This file specifies the WMI interface for the Unified Software @@ -2884,6 +2886,53 @@ struct wmi_start_scan_common { __le32 scan_ctrl_flags; } __packed; +/* ARP-NS offload data structure */ +#define WMI_NSOFF_MAX_TARGET_IPS 2 +#define WMI_MAX_NS_OFFLOADS 2 +#define WMI_MAX_ARP_OFFLOADS 2 +#define WMI_ARPOFF_FLAGS_VALID BIT(0) +#define WMI_IPV4_ARP_REPLY_OFFLOAD 0 +#define WMI_ARP_NS_OFFLOAD_DISABLE 0 +#define WMI_ARP_NS_OFFLOAD_ENABLE 1 + +struct wmi_ns_offload_info { + struct in6_addr src_addr; + struct in6_addr self_addr[TARGET_NUM_STATIONS]; + struct in6_addr target_addr[TARGET_NUM_STATIONS]; + struct wmi_mac_addr self_macaddr; + u8 src_ipv6_addr_valid; + struct in6_addr target_addr_valid; + struct in6_addr target_addr_ac_type; + u8 slot_idx; +} __packed; + +struct wmi_ns_arp_offload_req { + u8 offload_type; + u8 enable_offload; + __le32 num_ns_offload_count; + union { + struct in_addr ipv4_addr; + struct in6_addr ipv6_addr; + } params; + struct wmi_ns_offload_info offload_info; + struct wmi_mac_addr bssid; +} __packed; + +struct wmi_ns_offload { + __le32 flags; + struct in6_addr target_ipaddr[WMI_NSOFF_MAX_TARGET_IPS]; + struct in6_addr solicitation_ipaddr; + struct in6_addr remote_ipaddr; + struct wmi_mac_addr target_mac; +} __packed; + +struct wmi_arp_offload { + __le32 flags; + struct in_addr target_ipaddr; + struct in_addr remote_ipaddr; + struct wmi_mac_addr target_mac; +} __packed; + struct wmi_start_scan_tlvs { /* TLV parameters. These includes channel list, ssid list, bssid list, * extra ies. diff --git a/drivers/net/wireless/ath/ath10k/wow.c b/drivers/net/wireless/ath/ath10k/wow.c index de678fd3b801..1a43375c3264 100644 --- a/drivers/net/wireless/ath/ath10k/wow.c +++ b/drivers/net/wireless/ath/ath10k/wow.c @@ -224,6 +224,76 @@ static int ath10k_wow_wakeup(struct ath10k *ar) return 0; } +static int +ath10k_wow_fill_vdev_arp_offload_struct(struct ath10k_vif *arvif, + bool enable_offload) +{ + struct in_device *in_dev; + struct in_ifaddr *ifa; + bool offload_params_found = false; + struct wireless_dev *wdev = ieee80211_vif_to_wdev(arvif->vif); + struct wmi_ns_arp_offload_req *arp = &arvif->arp_offload; + + if (!enable_offload) { + arp->offload_type = __cpu_to_le16(WMI_IPV4_ARP_REPLY_OFFLOAD); + arp->enable_offload = __cpu_to_le16(WMI_ARP_NS_OFFLOAD_DISABLE); + return 0; + } + + if (!wdev) + return -ENODEV; + if (!wdev->netdev) + return -ENODEV; + in_dev = __in_dev_get_rtnl(wdev->netdev); + if (!in_dev) + return -ENODEV; + + arp->offload_type = __cpu_to_le16(WMI_IPV4_ARP_REPLY_OFFLOAD); + arp->enable_offload = __cpu_to_le16(WMI_ARP_NS_OFFLOAD_ENABLE); + for (ifa = in_dev->ifa_list; ifa; ifa = ifa->ifa_next) { + if (!strcmp(ifa->ifa_label, wdev->netdev->name)) { + offload_params_found = true; + break; + } + } + + if (!offload_params_found) + return -ENODEV; + + memcpy(&arp->params.ipv4_addr, &ifa->ifa_local, 4); + return 0; +} + +static int ath10k_wow_enable_ns_arp_offload(struct ath10k *ar, bool offload) +{ + struct ath10k_vif *arvif; + int ret; + + list_for_each_entry(arvif, &ar->arvifs, list) { + if (arvif->vdev_type != WMI_VDEV_TYPE_STA) + continue; + + if (!arvif->is_up) + continue; + + ret = ath10k_wow_fill_vdev_arp_offload_struct(arvif, offload); + if (ret) { + ath10k_err(ar, "ARP-offload config failed, vdev: %d\n", + arvif->vdev_id); + return ret; + } + + ret = ath10k_wmi_set_arp_ns_offload(ar, arvif); + if (ret) { + ath10k_err(ar, "failed to send offload cmd, vdev: %d\n", + arvif->vdev_id); + return ret; + } + } + + return 0; +} + static int ath10k_config_wow_listen_interval(struct ath10k *ar) { int ret; @@ -263,11 +333,17 @@ int ath10k_wow_op_suspend(struct ieee80211_hw *hw, goto exit; } + ret = ath10k_wow_enable_ns_arp_offload(ar, true); + if (ret) { + ath10k_warn(ar, "failed to enable ARP-NS offload: %d\n", ret); + goto exit; + } + ret = ath10k_wow_cleanup(ar); if (ret) { ath10k_warn(ar, "failed to clear wow wakeup events: %d\n", ret); - goto exit; + goto disable_ns_arp_offload; } ret = ath10k_wow_set_wakeups(ar, wowlan); @@ -304,6 +380,9 @@ wakeup: cleanup: ath10k_wow_cleanup(ar); +disable_ns_arp_offload: + ath10k_wow_enable_ns_arp_offload(ar, false); + exit: mutex_unlock(&ar->conf_mutex); return ret ? 1 : 0; @@ -341,8 +420,14 @@ int ath10k_wow_op_resume(struct ieee80211_hw *hw) } ret = ath10k_wow_wakeup(ar); - if (ret) + if (ret) { ath10k_warn(ar, "failed to wakeup from wow: %d\n", ret); + goto exit; + } + + ret = ath10k_wow_enable_ns_arp_offload(ar, false); + if (ret) + ath10k_warn(ar, "failed to disable ARP-NS offload: %d\n", ret); exit: if (ret) { diff --git a/drivers/soc/qcom/msm_bus/msm_bus_dbg_voter.c b/drivers/soc/qcom/msm_bus/msm_bus_dbg_voter.c index a876484859eb..ba1adb8acea7 100644 --- a/drivers/soc/qcom/msm_bus/msm_bus_dbg_voter.c +++ b/drivers/soc/qcom/msm_bus/msm_bus_dbg_voter.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2014-2016, The Linux Foundation. All rights reserved. +/* Copyright (c) 2014-2017, The Linux Foundation. All rights reserved. * * This program is Mree software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -27,6 +27,7 @@ struct msm_bus_floor_client_type { }; static struct class *bus_floor_class; +static DEFINE_RT_MUTEX(msm_bus_floor_vote_lock); #define MAX_VOTER_NAME (50) #define DEFAULT_NODE_WIDTH (8) #define DBG_NAME(s) (strnstr(s, "-", 7) + 1) @@ -64,18 +65,22 @@ static ssize_t bus_floor_active_only_store(struct device *dev, { struct msm_bus_floor_client_type *cl; + rt_mutex_lock(&msm_bus_floor_vote_lock); cl = dev_get_drvdata(dev); if (!cl) { pr_err("%s: Can't find cl", __func__); + rt_mutex_unlock(&msm_bus_floor_vote_lock); return 0; } if (sscanf(buf, "%d", &cl->active_only) != 1) { pr_err("%s:return error", __func__); + rt_mutex_unlock(&msm_bus_floor_vote_lock); return -EINVAL; } + rt_mutex_unlock(&msm_bus_floor_vote_lock); return n; } @@ -100,20 +105,24 @@ static ssize_t bus_floor_vote_store(struct device *dev, struct msm_bus_floor_client_type *cl; int ret = 0; + rt_mutex_lock(&msm_bus_floor_vote_lock); cl = dev_get_drvdata(dev); if (!cl) { pr_err("%s: Can't find cl", __func__); + rt_mutex_unlock(&msm_bus_floor_vote_lock); return 0; } if (sscanf(buf, "%llu", &cl->cur_vote_hz) != 1) { pr_err("%s:return error", __func__); + rt_mutex_unlock(&msm_bus_floor_vote_lock); return -EINVAL; } ret = msm_bus_floor_vote_context(dev_name(dev), cl->cur_vote_hz, cl->active_only); + rt_mutex_unlock(&msm_bus_floor_vote_lock); return n; } @@ -126,15 +135,18 @@ static ssize_t bus_floor_vote_store_api(struct device *dev, char name[10]; u64 vote_khz = 0; + rt_mutex_lock(&msm_bus_floor_vote_lock); cl = dev_get_drvdata(dev); if (!cl) { pr_err("%s: Can't find cl", __func__); + rt_mutex_unlock(&msm_bus_floor_vote_lock); return 0; } if (sscanf(buf, "%9s %llu", name, &vote_khz) != 2) { pr_err("%s:return error", __func__); + rt_mutex_unlock(&msm_bus_floor_vote_lock); return -EINVAL; } @@ -142,6 +154,7 @@ static ssize_t bus_floor_vote_store_api(struct device *dev, __func__, name, vote_khz); ret = msm_bus_floor_vote(name, vote_khz); + rt_mutex_unlock(&msm_bus_floor_vote_lock); return n; } diff --git a/drivers/spi/spi_qsd.c b/drivers/spi/spi_qsd.c index da58f19dd6e6..73396072a052 100644 --- a/drivers/spi/spi_qsd.c +++ b/drivers/spi/spi_qsd.c @@ -33,6 +33,7 @@ #include <linux/debugfs.h> #include <linux/gpio.h> #include <linux/of.h> +#include <linux/of_device.h> #include <linux/of_gpio.h> #include <linux/dma-mapping.h> #include <linux/sched.h> @@ -52,6 +53,7 @@ static int msm_spi_pm_suspend_runtime(struct device *device); static inline void msm_spi_dma_unmap_buffers(struct msm_spi *dd); static int get_local_resources(struct msm_spi *dd); static void put_local_resources(struct msm_spi *dd); +static void msm_spi_slv_setup(struct msm_spi *dd); static inline int msm_spi_configure_gsbi(struct msm_spi *dd, struct platform_device *pdev) @@ -84,7 +86,10 @@ static inline int msm_spi_configure_gsbi(struct msm_spi *dd, static inline void msm_spi_register_init(struct msm_spi *dd) { - writel_relaxed(0x00000001, dd->base + SPI_SW_RESET); + if (dd->pdata->is_slv_ctrl) + writel_relaxed(0x00000002, dd->base + SPI_SW_RESET); + else + writel_relaxed(0x00000001, dd->base + SPI_SW_RESET); msm_spi_set_state(dd, SPI_OP_STATE_RESET); writel_relaxed(0x00000000, dd->base + SPI_OPERATIONAL); writel_relaxed(0x00000000, dd->base + SPI_CONFIG); @@ -932,6 +937,7 @@ static inline void msm_spi_ack_transfer(struct msm_spi *dd) static inline irqreturn_t msm_spi_qup_irq(int irq, void *dev_id) { u32 op, ret = IRQ_NONE; + u32 slv; struct msm_spi *dd = dev_id; if (pm_runtime_suspended(dd->dev)) { @@ -945,7 +951,9 @@ static inline irqreturn_t msm_spi_qup_irq(int irq, void *dev_id) } op = readl_relaxed(dd->base + SPI_OPERATIONAL); + slv = readl_relaxed(dd->base + SPI_SLAVE_IRQ_STATUS); writel_relaxed(op, dd->base + SPI_OPERATIONAL); + writel_relaxed(slv, dd->base + SPI_SLAVE_IRQ_STATUS); /* * Ensure service flag was cleared before further * processing of interrupt. @@ -1234,7 +1242,10 @@ msm_spi_use_dma(struct msm_spi *dd, struct spi_transfer *tr, u8 bpw) static void msm_spi_set_transfer_mode(struct msm_spi *dd, u8 bpw, u32 read_count) { - if (msm_spi_use_dma(dd, dd->cur_transfer, bpw)) { + if (dd->pdata->is_slv_ctrl) { + dd->tx_mode = SPI_BAM_MODE; + dd->rx_mode = SPI_BAM_MODE; + } else if (msm_spi_use_dma(dd, dd->cur_transfer, bpw)) { dd->tx_mode = SPI_BAM_MODE; dd->rx_mode = SPI_BAM_MODE; } else { @@ -1353,7 +1364,7 @@ static void get_transfer_length(struct msm_spi *dd) static int msm_spi_process_transfer(struct msm_spi *dd) { u8 bpw; - u32 max_speed; + u32 max_speed = 0; u32 read_count; u32 timeout; u32 spi_ioc; @@ -1392,7 +1403,7 @@ static int msm_spi_process_transfer(struct msm_spi *dd) DIV_ROUND_UP(max_speed, MSEC_PER_SEC))); read_count = DIV_ROUND_UP(dd->cur_msg_len, dd->bytes_per_word); - if (dd->spi->mode & SPI_LOOP) + if (dd->spi->mode & SPI_LOOP && !dd->pdata->is_slv_ctrl) int_loopback = 1; if (msm_spi_set_state(dd, SPI_OP_STATE_RESET)) @@ -1414,8 +1425,11 @@ static int msm_spi_process_transfer(struct msm_spi *dd) msm_spi_set_qup_io_modes(dd); msm_spi_set_spi_config(dd, bpw); msm_spi_set_qup_config(dd, bpw); - spi_ioc = msm_spi_set_spi_io_control(dd); + if (!dd->pdata->is_slv_ctrl) + spi_ioc = msm_spi_set_spi_io_control(dd); msm_spi_set_qup_op_mask(dd); + if (dd->pdata->is_slv_ctrl) + msm_spi_slv_setup(dd); /* The output fifo interrupt handler will handle all writes after the first. Restricting this to one write avoids contention @@ -1482,12 +1496,20 @@ transfer_end: dd->rx_mode = SPI_MODE_NONE; msm_spi_set_state(dd, SPI_OP_STATE_RESET); - if (!dd->cur_transfer->cs_change) + if (!dd->cur_transfer->cs_change && !dd->pdata->is_slv_ctrl) writel_relaxed(spi_ioc & ~SPI_IO_C_MX_CS_MODE, dd->base + SPI_IO_CONTROL); return status; } +static int msm_spi_slv_abort(struct spi_master *spi) +{ + struct msm_spi *dd = spi_master_get_devdata(spi); + + complete_all(&dd->tx_transfer_complete); + complete_all(&dd->rx_transfer_complete); + return 0; +} static inline void msm_spi_set_cs(struct spi_device *spi, bool set_flag) { @@ -1753,6 +1775,32 @@ static int msm_spi_unprepare_transfer_hardware(struct spi_master *master) return 0; } +static void msm_spi_slv_setup(struct msm_spi *dd) +{ + u32 spi_config = readl_relaxed(dd->base + SPI_CONFIG); + u32 qup_config = readl_relaxed(dd->base + QUP_CONFIG); + u32 irq_en = GENMASK(6, 0); + + qup_config &= ~QUP_CFG_MODE; + qup_config |= QUP_CONFIG_SPI_SLAVE; + qup_config |= (SPI_EN_EXT_OUT_FLAG | APP_CLK_ON_EN | CORE_CLK_ON_EN + | FIFO_CLK_ON_EN | CORE_EX_CLK_ON_EN); + spi_config |= SPI_CFG_SLAVE_OP; + writel_relaxed(qup_config, dd->base + QUP_CONFIG); + writel_relaxed(spi_config, dd->base + SPI_CONFIG); + writel_relaxed(irq_en, (dd->base + SPI_SLAVE_IRQ_EN)); + if (dd->read_buf && !dd->write_buf) { + u32 slv_cfg = + readl_relaxed(dd->base + SPI_SLAVE_CONFIG); + slv_cfg |= (RX_UNBALANCED_MASK | SPI_S_CGC_EN); + writel_relaxed(slv_cfg, (dd->base + SPI_SLAVE_CONFIG)); + } + /* + * Ensure Slave setup completes before returning. + */ + mb(); +} + static int msm_spi_setup(struct spi_device *spi) { struct msm_spi *dd; @@ -2248,6 +2296,8 @@ struct msm_spi_platform_data *msm_spi_dt_to_pdata( &pdata->rt_priority, DT_OPT, DT_BOOL, 0}, {"qcom,shared", &pdata->is_shared, DT_OPT, DT_BOOL, 0}, + {"qcom,slv-ctrl", + &pdata->is_slv_ctrl, DT_OPT, DT_BOOL, 0}, {NULL, NULL, 0, 0, 0}, }; @@ -2451,6 +2501,12 @@ err_clk_get: return rc; } +static const struct of_device_id msm_spi_dt_match[] = { + { .compatible = "qcom,spi-qup-v2", }, + { .compatible = "qcom,qup-v26", }, + {} +}; + static int msm_spi_probe(struct platform_device *pdev) { struct spi_master *master; @@ -2481,6 +2537,9 @@ static int msm_spi_probe(struct platform_device *pdev) dd = spi_master_get_devdata(master); if (pdev->dev.of_node) { + const struct of_device_id *dev_id; + enum msm_spi_qup_version ver; + dd->qup_ver = SPI_QUP_VERSION_BFAM; master->dev.of_node = pdev->dev.of_node; pdata = msm_spi_dt_to_pdata(pdev, dd); @@ -2495,6 +2554,17 @@ static int msm_spi_probe(struct platform_device *pdev) "using default bus_num %d\n", pdev->id); else master->bus_num = pdev->id = rc; + + dev_id = of_match_device(msm_spi_dt_match, &pdev->dev); + if (dev_id) + ver = SPI_QUP_VERSION_SPI_SLV; + else + ver = SPI_QUP_VERSION_BFAM; + + if (ver >= SPI_QUP_VERSION_SPI_SLV) + dd->slv_support = true; + else + dd->slv_support = false; } else { pdata = pdev->dev.platform_data; dd->qup_ver = SPI_QUP_VERSION_NONE; @@ -2553,6 +2623,21 @@ static int msm_spi_probe(struct platform_device *pdev) } spi_dma_mask(&pdev->dev); + + if (pdata && pdata->is_slv_ctrl) { + if (!dd->slv_support) { + rc = -ENXIO; + dev_err(&pdev->dev, "QUP ver %d, no slv support\n", + dd->qup_ver); + goto err_probe_res; + } + + master->slave = true; + master->set_cs = NULL; + master->setup = NULL; + master->slave_abort = msm_spi_slv_abort; + } + skip_dma_resources: spin_lock_init(&dd->queue_lock); @@ -2753,13 +2838,6 @@ static int msm_spi_remove(struct platform_device *pdev) return 0; } -static struct of_device_id msm_spi_dt_match[] = { - { - .compatible = "qcom,spi-qup-v2", - }, - {} -}; - static const struct dev_pm_ops msm_spi_dev_pm_ops = { SET_SYSTEM_SLEEP_PM_OPS(msm_spi_suspend, msm_spi_resume) SET_RUNTIME_PM_OPS(msm_spi_pm_suspend_runtime, diff --git a/drivers/spi/spi_qsd.h b/drivers/spi/spi_qsd.h index 47d69965f18a..6632fe806e41 100644 --- a/drivers/spi/spi_qsd.h +++ b/drivers/spi/spi_qsd.h @@ -38,6 +38,7 @@ #define QUP_MX_WRITE_CNT_CURRENT 0x0154 #define QUP_CONFIG_SPI_MODE 0x0100 +#define QUP_CONFIG_SPI_SLAVE 0x0400 #endif #define GSBI_CTRL_REG 0x0 @@ -72,17 +73,26 @@ #define SPI_OUTPUT_FIFO QSD_REG(0x0100) QUP_REG(0x0110) #define SPI_INPUT_FIFO QSD_REG(0x0200) QUP_REG(0x0218) #define SPI_STATE QSD_REG(SPI_OPERATIONAL) QUP_REG(0x0004) +#define SPI_SLAVE_IRQ_STATUS (0x0330) +#define SPI_SLAVE_IRQ_EN (0x0334) +#define SPI_SLAVE_CONFIG (0x0338) /* QUP_CONFIG fields */ #define SPI_CFG_N 0x0000001F #define SPI_NO_INPUT 0x00000080 #define SPI_NO_OUTPUT 0x00000040 #define SPI_EN_EXT_OUT_FLAG 0x00010000 +#define QUP_CFG_MODE 0x00000F00 +#define APP_CLK_ON_EN BIT(12) +#define CORE_CLK_ON_EN BIT(13) +#define FIFO_CLK_ON_EN BIT(14) +#define CORE_EX_CLK_ON_EN BIT(15) /* SPI_CONFIG fields */ #define SPI_CFG_LOOPBACK 0x00000100 #define SPI_CFG_INPUT_FIRST 0x00000200 #define SPI_CFG_HS_MODE 0x00000400 +#define SPI_CFG_SLAVE_OP 0x00000020 /* SPI_IO_CONTROL fields */ #define SPI_IO_C_FORCE_CS 0x00000800 @@ -128,6 +138,23 @@ #define SPI_OP_STATE_CLEAR_BITS 0x2 +/* SPI SLAVE IRQ_STATUS/EN fields */ +#define CS_N_ASSERT BIT(0) +#define CS_N_DEASSERT BIT(1) +#define CS_N_ETXT BIT(2) +#define TX_UNDERFLOW BIT(3) +#define RX_OVERFLOW_WAIT_EOT BIT(4) +#define RX_OVERFLOW_NO_EOT BIT(5) +#define CS_N_ERXT BIT(6) + +/* SPI_SLAVE_CONFIG Fields */ +#define RX_N_SHIFT BIT(0) +#define PAUSE_ON_ERR_DIS BIT(1) +#define SPI_S_CGC_EN BIT(2) +#define RX_UNBALANCED_MASK BIT(3) +#define SLAVE_DIS_RESET_ST BIT(4) +#define SLAVE_AUTO_PAUSE_EOT BIT(7) + #define SPI_PINCTRL_STATE_DEFAULT "spi_default" #define SPI_PINCTRL_STATE_SLEEP "spi_sleep" @@ -177,6 +204,7 @@ enum msm_spi_state { enum msm_spi_qup_version { SPI_QUP_VERSION_NONE = 0x0, SPI_QUP_VERSION_BFAM = 0x2, + SPI_QUP_VERSION_SPI_SLV = 0x26, }; enum msm_spi_pipe_direction { @@ -376,6 +404,7 @@ struct msm_spi { struct pinctrl_state *pins_sleep; bool is_init_complete; bool pack_words; + bool slv_support; }; /* Forward declaration */ diff --git a/drivers/video/fbdev/msm/mdss_hdmi_tx.c b/drivers/video/fbdev/msm/mdss_hdmi_tx.c index 5eb17ab27e4c..5cb436261115 100644 --- a/drivers/video/fbdev/msm/mdss_hdmi_tx.c +++ b/drivers/video/fbdev/msm/mdss_hdmi_tx.c @@ -2223,6 +2223,9 @@ static int hdmi_tx_read_sink_info(struct hdmi_tx_ctrl *hdmi_ctrl) DSS_REG_W_ND(io, HDMI_DDC_ARBITRATION, DSS_REG_R(io, HDMI_DDC_ARBITRATION) & ~(BIT(4))); + /* Set/Reset HDMI max TMDS clock supported by source */ + hdmi_edid_set_max_pclk_rate(data, hdmi_ctrl->max_pclk_khz); + if (!hdmi_ctrl->custom_edid && !hdmi_ctrl->sim_mode) { hdmi_ddc_config(&hdmi_ctrl->ddc_ctrl); |
