cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

ufshcd-dwc.c (4125B)


      1// SPDX-License-Identifier: GPL-2.0-only
      2/*
      3 * UFS Host driver for Synopsys Designware Core
      4 *
      5 * Copyright (C) 2015-2016 Synopsys, Inc. (www.synopsys.com)
      6 *
      7 * Authors: Joao Pinto <jpinto@synopsys.com>
      8 */
      9
     10#include <linux/module.h>
     11
     12#include <ufs/ufshcd.h>
     13#include <ufs/unipro.h>
     14
     15#include "ufshcd-dwc.h"
     16#include "ufshci-dwc.h"
     17
     18int ufshcd_dwc_dme_set_attrs(struct ufs_hba *hba,
     19				const struct ufshcd_dme_attr_val *v, int n)
     20{
     21	int ret = 0;
     22	int attr_node = 0;
     23
     24	for (attr_node = 0; attr_node < n; attr_node++) {
     25		ret = ufshcd_dme_set_attr(hba, v[attr_node].attr_sel,
     26			ATTR_SET_NOR, v[attr_node].mib_val, v[attr_node].peer);
     27
     28		if (ret)
     29			return ret;
     30	}
     31
     32	return 0;
     33}
     34EXPORT_SYMBOL(ufshcd_dwc_dme_set_attrs);
     35
     36/**
     37 * ufshcd_dwc_program_clk_div()
     38 * This function programs the clk divider value. This value is needed to
     39 * provide 1 microsecond tick to unipro layer.
     40 * @hba: Private Structure pointer
     41 * @divider_val: clock divider value to be programmed
     42 *
     43 */
     44static void ufshcd_dwc_program_clk_div(struct ufs_hba *hba, u32 divider_val)
     45{
     46	ufshcd_writel(hba, divider_val, DWC_UFS_REG_HCLKDIV);
     47}
     48
     49/**
     50 * ufshcd_dwc_link_is_up()
     51 * Check if link is up
     52 * @hba: private structure pointer
     53 *
     54 * Returns 0 on success, non-zero value on failure
     55 */
     56static int ufshcd_dwc_link_is_up(struct ufs_hba *hba)
     57{
     58	int dme_result = 0;
     59
     60	ufshcd_dme_get(hba, UIC_ARG_MIB(VS_POWERSTATE), &dme_result);
     61
     62	if (dme_result == UFSHCD_LINK_IS_UP) {
     63		ufshcd_set_link_active(hba);
     64		return 0;
     65	}
     66
     67	return 1;
     68}
     69
     70/**
     71 * ufshcd_dwc_connection_setup()
     72 * This function configures both the local side (host) and the peer side
     73 * (device) unipro attributes to establish the connection to application/
     74 * cport.
     75 * This function is not required if the hardware is properly configured to
     76 * have this connection setup on reset. But invoking this function does no
     77 * harm and should be fine even working with any ufs device.
     78 *
     79 * @hba: pointer to drivers private data
     80 *
     81 * Returns 0 on success non-zero value on failure
     82 */
     83static int ufshcd_dwc_connection_setup(struct ufs_hba *hba)
     84{
     85	static const struct ufshcd_dme_attr_val setup_attrs[] = {
     86		{ UIC_ARG_MIB(T_CONNECTIONSTATE), 0, DME_LOCAL },
     87		{ UIC_ARG_MIB(N_DEVICEID), 0, DME_LOCAL },
     88		{ UIC_ARG_MIB(N_DEVICEID_VALID), 0, DME_LOCAL },
     89		{ UIC_ARG_MIB(T_PEERDEVICEID), 1, DME_LOCAL },
     90		{ UIC_ARG_MIB(T_PEERCPORTID), 0, DME_LOCAL },
     91		{ UIC_ARG_MIB(T_TRAFFICCLASS), 0, DME_LOCAL },
     92		{ UIC_ARG_MIB(T_CPORTFLAGS), 0x6, DME_LOCAL },
     93		{ UIC_ARG_MIB(T_CPORTMODE), 1, DME_LOCAL },
     94		{ UIC_ARG_MIB(T_CONNECTIONSTATE), 1, DME_LOCAL },
     95		{ UIC_ARG_MIB(T_CONNECTIONSTATE), 0, DME_PEER },
     96		{ UIC_ARG_MIB(N_DEVICEID), 1, DME_PEER },
     97		{ UIC_ARG_MIB(N_DEVICEID_VALID), 1, DME_PEER },
     98		{ UIC_ARG_MIB(T_PEERDEVICEID), 1, DME_PEER },
     99		{ UIC_ARG_MIB(T_PEERCPORTID), 0, DME_PEER },
    100		{ UIC_ARG_MIB(T_TRAFFICCLASS), 0, DME_PEER },
    101		{ UIC_ARG_MIB(T_CPORTFLAGS), 0x6, DME_PEER },
    102		{ UIC_ARG_MIB(T_CPORTMODE), 1, DME_PEER },
    103		{ UIC_ARG_MIB(T_CONNECTIONSTATE), 1, DME_PEER }
    104	};
    105
    106	return ufshcd_dwc_dme_set_attrs(hba, setup_attrs, ARRAY_SIZE(setup_attrs));
    107}
    108
    109/**
    110 * ufshcd_dwc_link_startup_notify()
    111 * UFS Host DWC specific link startup sequence
    112 * @hba: private structure pointer
    113 * @status: Callback notify status
    114 *
    115 * Returns 0 on success, non-zero value on failure
    116 */
    117int ufshcd_dwc_link_startup_notify(struct ufs_hba *hba,
    118					enum ufs_notify_change_status status)
    119{
    120	int err = 0;
    121
    122	if (status == PRE_CHANGE) {
    123		ufshcd_dwc_program_clk_div(hba, DWC_UFS_REG_HCLKDIV_DIV_125);
    124
    125		err = ufshcd_vops_phy_initialization(hba);
    126		if (err) {
    127			dev_err(hba->dev, "Phy setup failed (%d)\n", err);
    128			goto out;
    129		}
    130	} else { /* POST_CHANGE */
    131		err = ufshcd_dwc_link_is_up(hba);
    132		if (err) {
    133			dev_err(hba->dev, "Link is not up\n");
    134			goto out;
    135		}
    136
    137		err = ufshcd_dwc_connection_setup(hba);
    138		if (err)
    139			dev_err(hba->dev, "Connection setup failed (%d)\n",
    140									err);
    141	}
    142
    143out:
    144	return err;
    145}
    146EXPORT_SYMBOL(ufshcd_dwc_link_startup_notify);
    147
    148MODULE_AUTHOR("Joao Pinto <Joao.Pinto@synopsys.com>");
    149MODULE_DESCRIPTION("UFS Host driver for Synopsys Designware Core");
    150MODULE_LICENSE("Dual BSD/GPL");