1*8f7de514SShawn Lin // SPDX-License-Identifier: GPL-2.0+ 2*8f7de514SShawn Lin /** 3*8f7de514SShawn Lin * ufs.c - Universal Flash Subsystem (UFS) driver 4*8f7de514SShawn Lin * 5*8f7de514SShawn Lin * Taken from Linux Kernel v5.2 (drivers/scsi/ufs/ufshcd.c) and ported 6*8f7de514SShawn Lin * to u-boot. 7*8f7de514SShawn Lin * 8*8f7de514SShawn Lin * Copyright (C) 2019 Texas Instruments Incorporated - http://www.ti.com 9*8f7de514SShawn Lin */ 10*8f7de514SShawn Lin #include <charset.h> 11*8f7de514SShawn Lin #include <common.h> 12*8f7de514SShawn Lin #include <dm.h> 13*8f7de514SShawn Lin #include <log.h> 14*8f7de514SShawn Lin #include <dm/lists.h> 15*8f7de514SShawn Lin #include <dm/device-internal.h> 16*8f7de514SShawn Lin #include <malloc.h> 17*8f7de514SShawn Lin #include <hexdump.h> 18*8f7de514SShawn Lin #include <scsi.h> 19*8f7de514SShawn Lin #include <asm/io.h> 20*8f7de514SShawn Lin #include <asm/dma-mapping.h> 21*8f7de514SShawn Lin #include <linux/bitops.h> 22*8f7de514SShawn Lin #include <linux/delay.h> 23*8f7de514SShawn Lin 24*8f7de514SShawn Lin #include "ufs.h" 25*8f7de514SShawn Lin 26*8f7de514SShawn Lin #define UFSHCD_ENABLE_INTRS (UTP_TRANSFER_REQ_COMPL |\ 27*8f7de514SShawn Lin UTP_TASK_REQ_COMPL |\ 28*8f7de514SShawn Lin UFSHCD_ERROR_MASK) 29*8f7de514SShawn Lin /* maximum number of link-startup retries */ 30*8f7de514SShawn Lin #define DME_LINKSTARTUP_RETRIES 3 31*8f7de514SShawn Lin 32*8f7de514SShawn Lin /* maximum number of retries for a general UIC command */ 33*8f7de514SShawn Lin #define UFS_UIC_COMMAND_RETRIES 3 34*8f7de514SShawn Lin 35*8f7de514SShawn Lin /* Query request retries */ 36*8f7de514SShawn Lin #define QUERY_REQ_RETRIES 3 37*8f7de514SShawn Lin /* Query request timeout */ 38*8f7de514SShawn Lin #define QUERY_REQ_TIMEOUT 1500 /* 1.5 seconds */ 39*8f7de514SShawn Lin 40*8f7de514SShawn Lin /* maximum timeout in ms for a general UIC command */ 41*8f7de514SShawn Lin #define UFS_UIC_CMD_TIMEOUT 1000 42*8f7de514SShawn Lin /* NOP OUT retries waiting for NOP IN response */ 43*8f7de514SShawn Lin #define NOP_OUT_RETRIES 10 44*8f7de514SShawn Lin /* Timeout after 30 msecs if NOP OUT hangs without response */ 45*8f7de514SShawn Lin #define NOP_OUT_TIMEOUT 30 /* msecs */ 46*8f7de514SShawn Lin 47*8f7de514SShawn Lin /* Only use one Task Tag for all requests */ 48*8f7de514SShawn Lin #define TASK_TAG 0 49*8f7de514SShawn Lin 50*8f7de514SShawn Lin /* Expose the flag value from utp_upiu_query.value */ 51*8f7de514SShawn Lin #define MASK_QUERY_UPIU_FLAG_LOC 0xFF 52*8f7de514SShawn Lin 53*8f7de514SShawn Lin #define MAX_PRDT_ENTRY 262144 54*8f7de514SShawn Lin 55*8f7de514SShawn Lin /* maximum bytes per request */ 56*8f7de514SShawn Lin #define UFS_MAX_BYTES (128 * 256 * 1024) 57*8f7de514SShawn Lin 58*8f7de514SShawn Lin static inline bool ufshcd_is_hba_active(struct ufs_hba *hba); 59*8f7de514SShawn Lin static inline void ufshcd_hba_stop(struct ufs_hba *hba); 60*8f7de514SShawn Lin static int ufshcd_hba_enable(struct ufs_hba *hba); 61*8f7de514SShawn Lin 62*8f7de514SShawn Lin /* 63*8f7de514SShawn Lin * ufshcd_wait_for_register - wait for register value to change 64*8f7de514SShawn Lin */ 65*8f7de514SShawn Lin static int ufshcd_wait_for_register(struct ufs_hba *hba, u32 reg, u32 mask, 66*8f7de514SShawn Lin u32 val, unsigned long timeout_ms) 67*8f7de514SShawn Lin { 68*8f7de514SShawn Lin int err = 0; 69*8f7de514SShawn Lin unsigned long start = get_timer(0); 70*8f7de514SShawn Lin 71*8f7de514SShawn Lin /* ignore bits that we don't intend to wait on */ 72*8f7de514SShawn Lin val = val & mask; 73*8f7de514SShawn Lin 74*8f7de514SShawn Lin while ((ufshcd_readl(hba, reg) & mask) != val) { 75*8f7de514SShawn Lin if (get_timer(start) > timeout_ms) { 76*8f7de514SShawn Lin if ((ufshcd_readl(hba, reg) & mask) != val) 77*8f7de514SShawn Lin err = -ETIMEDOUT; 78*8f7de514SShawn Lin break; 79*8f7de514SShawn Lin } 80*8f7de514SShawn Lin } 81*8f7de514SShawn Lin 82*8f7de514SShawn Lin return err; 83*8f7de514SShawn Lin } 84*8f7de514SShawn Lin 85*8f7de514SShawn Lin /** 86*8f7de514SShawn Lin * ufshcd_init_pwr_info - setting the POR (power on reset) 87*8f7de514SShawn Lin * values in hba power info 88*8f7de514SShawn Lin */ 89*8f7de514SShawn Lin static void ufshcd_init_pwr_info(struct ufs_hba *hba) 90*8f7de514SShawn Lin { 91*8f7de514SShawn Lin hba->pwr_info.gear_rx = UFS_PWM_G1; 92*8f7de514SShawn Lin hba->pwr_info.gear_tx = UFS_PWM_G1; 93*8f7de514SShawn Lin hba->pwr_info.lane_rx = 1; 94*8f7de514SShawn Lin hba->pwr_info.lane_tx = 1; 95*8f7de514SShawn Lin hba->pwr_info.pwr_rx = SLOWAUTO_MODE; 96*8f7de514SShawn Lin hba->pwr_info.pwr_tx = SLOWAUTO_MODE; 97*8f7de514SShawn Lin hba->pwr_info.hs_rate = 0; 98*8f7de514SShawn Lin } 99*8f7de514SShawn Lin 100*8f7de514SShawn Lin /** 101*8f7de514SShawn Lin * ufshcd_print_pwr_info - print power params as saved in hba 102*8f7de514SShawn Lin * power info 103*8f7de514SShawn Lin */ 104*8f7de514SShawn Lin static void ufshcd_print_pwr_info(struct ufs_hba *hba) 105*8f7de514SShawn Lin { 106*8f7de514SShawn Lin static const char * const names[] = { 107*8f7de514SShawn Lin "INVALID MODE", 108*8f7de514SShawn Lin "FAST MODE", 109*8f7de514SShawn Lin "SLOW_MODE", 110*8f7de514SShawn Lin "INVALID MODE", 111*8f7de514SShawn Lin "FASTAUTO_MODE", 112*8f7de514SShawn Lin "SLOWAUTO_MODE", 113*8f7de514SShawn Lin "INVALID MODE", 114*8f7de514SShawn Lin }; 115*8f7de514SShawn Lin 116*8f7de514SShawn Lin dev_err(hba->dev, "[RX, TX]: gear=[%d, %d], lane[%d, %d], pwr[%s, %s], rate = %d\n", 117*8f7de514SShawn Lin hba->pwr_info.gear_rx, hba->pwr_info.gear_tx, 118*8f7de514SShawn Lin hba->pwr_info.lane_rx, hba->pwr_info.lane_tx, 119*8f7de514SShawn Lin names[hba->pwr_info.pwr_rx], 120*8f7de514SShawn Lin names[hba->pwr_info.pwr_tx], 121*8f7de514SShawn Lin hba->pwr_info.hs_rate); 122*8f7de514SShawn Lin } 123*8f7de514SShawn Lin 124*8f7de514SShawn Lin /** 125*8f7de514SShawn Lin * ufshcd_ready_for_uic_cmd - Check if controller is ready 126*8f7de514SShawn Lin * to accept UIC commands 127*8f7de514SShawn Lin */ 128*8f7de514SShawn Lin static inline bool ufshcd_ready_for_uic_cmd(struct ufs_hba *hba) 129*8f7de514SShawn Lin { 130*8f7de514SShawn Lin if (ufshcd_readl(hba, REG_CONTROLLER_STATUS) & UIC_COMMAND_READY) 131*8f7de514SShawn Lin return true; 132*8f7de514SShawn Lin else 133*8f7de514SShawn Lin return false; 134*8f7de514SShawn Lin } 135*8f7de514SShawn Lin 136*8f7de514SShawn Lin /** 137*8f7de514SShawn Lin * ufshcd_get_uic_cmd_result - Get the UIC command result 138*8f7de514SShawn Lin */ 139*8f7de514SShawn Lin static inline int ufshcd_get_uic_cmd_result(struct ufs_hba *hba) 140*8f7de514SShawn Lin { 141*8f7de514SShawn Lin return ufshcd_readl(hba, REG_UIC_COMMAND_ARG_2) & 142*8f7de514SShawn Lin MASK_UIC_COMMAND_RESULT; 143*8f7de514SShawn Lin } 144*8f7de514SShawn Lin 145*8f7de514SShawn Lin /** 146*8f7de514SShawn Lin * ufshcd_get_dme_attr_val - Get the value of attribute returned by UIC command 147*8f7de514SShawn Lin */ 148*8f7de514SShawn Lin static inline u32 ufshcd_get_dme_attr_val(struct ufs_hba *hba) 149*8f7de514SShawn Lin { 150*8f7de514SShawn Lin return ufshcd_readl(hba, REG_UIC_COMMAND_ARG_3); 151*8f7de514SShawn Lin } 152*8f7de514SShawn Lin 153*8f7de514SShawn Lin /** 154*8f7de514SShawn Lin * ufshcd_is_device_present - Check if any device connected to 155*8f7de514SShawn Lin * the host controller 156*8f7de514SShawn Lin */ 157*8f7de514SShawn Lin static inline bool ufshcd_is_device_present(struct ufs_hba *hba) 158*8f7de514SShawn Lin { 159*8f7de514SShawn Lin return (ufshcd_readl(hba, REG_CONTROLLER_STATUS) & 160*8f7de514SShawn Lin DEVICE_PRESENT) ? true : false; 161*8f7de514SShawn Lin } 162*8f7de514SShawn Lin 163*8f7de514SShawn Lin /** 164*8f7de514SShawn Lin * ufshcd_send_uic_cmd - UFS Interconnect layer command API 165*8f7de514SShawn Lin * 166*8f7de514SShawn Lin */ 167*8f7de514SShawn Lin static int ufshcd_send_uic_cmd(struct ufs_hba *hba, struct uic_command *uic_cmd) 168*8f7de514SShawn Lin { 169*8f7de514SShawn Lin unsigned long start = 0; 170*8f7de514SShawn Lin u32 intr_status; 171*8f7de514SShawn Lin u32 enabled_intr_status; 172*8f7de514SShawn Lin 173*8f7de514SShawn Lin if (!ufshcd_ready_for_uic_cmd(hba)) { 174*8f7de514SShawn Lin dev_err(hba->dev, 175*8f7de514SShawn Lin "Controller not ready to accept UIC commands\n"); 176*8f7de514SShawn Lin return -EIO; 177*8f7de514SShawn Lin } 178*8f7de514SShawn Lin 179*8f7de514SShawn Lin debug("sending uic command:%d\n", uic_cmd->command); 180*8f7de514SShawn Lin 181*8f7de514SShawn Lin /* Write Args */ 182*8f7de514SShawn Lin ufshcd_writel(hba, uic_cmd->argument1, REG_UIC_COMMAND_ARG_1); 183*8f7de514SShawn Lin ufshcd_writel(hba, uic_cmd->argument2, REG_UIC_COMMAND_ARG_2); 184*8f7de514SShawn Lin ufshcd_writel(hba, uic_cmd->argument3, REG_UIC_COMMAND_ARG_3); 185*8f7de514SShawn Lin 186*8f7de514SShawn Lin /* Write UIC Cmd */ 187*8f7de514SShawn Lin ufshcd_writel(hba, uic_cmd->command & COMMAND_OPCODE_MASK, 188*8f7de514SShawn Lin REG_UIC_COMMAND); 189*8f7de514SShawn Lin 190*8f7de514SShawn Lin start = get_timer(0); 191*8f7de514SShawn Lin do { 192*8f7de514SShawn Lin intr_status = ufshcd_readl(hba, REG_INTERRUPT_STATUS); 193*8f7de514SShawn Lin enabled_intr_status = intr_status & hba->intr_mask; 194*8f7de514SShawn Lin ufshcd_writel(hba, intr_status, REG_INTERRUPT_STATUS); 195*8f7de514SShawn Lin 196*8f7de514SShawn Lin if (get_timer(start) > UFS_UIC_CMD_TIMEOUT) { 197*8f7de514SShawn Lin dev_err(hba->dev, 198*8f7de514SShawn Lin "Timedout waiting for UIC response\n"); 199*8f7de514SShawn Lin 200*8f7de514SShawn Lin return -ETIMEDOUT; 201*8f7de514SShawn Lin } 202*8f7de514SShawn Lin 203*8f7de514SShawn Lin if (enabled_intr_status & UFSHCD_ERROR_MASK) { 204*8f7de514SShawn Lin dev_err(hba->dev, "Error in status:%08x\n", 205*8f7de514SShawn Lin enabled_intr_status); 206*8f7de514SShawn Lin 207*8f7de514SShawn Lin return -1; 208*8f7de514SShawn Lin } 209*8f7de514SShawn Lin } while (!(enabled_intr_status & UFSHCD_UIC_MASK)); 210*8f7de514SShawn Lin 211*8f7de514SShawn Lin uic_cmd->argument2 = ufshcd_get_uic_cmd_result(hba); 212*8f7de514SShawn Lin uic_cmd->argument3 = ufshcd_get_dme_attr_val(hba); 213*8f7de514SShawn Lin 214*8f7de514SShawn Lin debug("Sent successfully\n"); 215*8f7de514SShawn Lin 216*8f7de514SShawn Lin return 0; 217*8f7de514SShawn Lin } 218*8f7de514SShawn Lin 219*8f7de514SShawn Lin /** 220*8f7de514SShawn Lin * ufshcd_dme_set_attr - UIC command for DME_SET, DME_PEER_SET 221*8f7de514SShawn Lin * 222*8f7de514SShawn Lin */ 223*8f7de514SShawn Lin int ufshcd_dme_set_attr(struct ufs_hba *hba, u32 attr_sel, u8 attr_set, 224*8f7de514SShawn Lin u32 mib_val, u8 peer) 225*8f7de514SShawn Lin { 226*8f7de514SShawn Lin struct uic_command uic_cmd = {0}; 227*8f7de514SShawn Lin static const char *const action[] = { 228*8f7de514SShawn Lin "dme-set", 229*8f7de514SShawn Lin "dme-peer-set" 230*8f7de514SShawn Lin }; 231*8f7de514SShawn Lin const char *set = action[!!peer]; 232*8f7de514SShawn Lin int ret; 233*8f7de514SShawn Lin int retries = UFS_UIC_COMMAND_RETRIES; 234*8f7de514SShawn Lin 235*8f7de514SShawn Lin uic_cmd.command = peer ? 236*8f7de514SShawn Lin UIC_CMD_DME_PEER_SET : UIC_CMD_DME_SET; 237*8f7de514SShawn Lin uic_cmd.argument1 = attr_sel; 238*8f7de514SShawn Lin uic_cmd.argument2 = UIC_ARG_ATTR_TYPE(attr_set); 239*8f7de514SShawn Lin uic_cmd.argument3 = mib_val; 240*8f7de514SShawn Lin 241*8f7de514SShawn Lin do { 242*8f7de514SShawn Lin /* for peer attributes we retry upon failure */ 243*8f7de514SShawn Lin ret = ufshcd_send_uic_cmd(hba, &uic_cmd); 244*8f7de514SShawn Lin if (ret) 245*8f7de514SShawn Lin dev_dbg(hba->dev, "%s: attr-id 0x%x val 0x%x error code %d\n", 246*8f7de514SShawn Lin set, UIC_GET_ATTR_ID(attr_sel), mib_val, ret); 247*8f7de514SShawn Lin } while (ret && peer && --retries); 248*8f7de514SShawn Lin 249*8f7de514SShawn Lin if (ret) 250*8f7de514SShawn Lin dev_err(hba->dev, "%s: attr-id 0x%x val 0x%x failed %d retries\n", 251*8f7de514SShawn Lin set, UIC_GET_ATTR_ID(attr_sel), mib_val, 252*8f7de514SShawn Lin UFS_UIC_COMMAND_RETRIES - retries); 253*8f7de514SShawn Lin 254*8f7de514SShawn Lin return ret; 255*8f7de514SShawn Lin } 256*8f7de514SShawn Lin 257*8f7de514SShawn Lin /** 258*8f7de514SShawn Lin * ufshcd_dme_get_attr - UIC command for DME_GET, DME_PEER_GET 259*8f7de514SShawn Lin * 260*8f7de514SShawn Lin */ 261*8f7de514SShawn Lin int ufshcd_dme_get_attr(struct ufs_hba *hba, u32 attr_sel, 262*8f7de514SShawn Lin u32 *mib_val, u8 peer) 263*8f7de514SShawn Lin { 264*8f7de514SShawn Lin struct uic_command uic_cmd = {0}; 265*8f7de514SShawn Lin static const char *const action[] = { 266*8f7de514SShawn Lin "dme-get", 267*8f7de514SShawn Lin "dme-peer-get" 268*8f7de514SShawn Lin }; 269*8f7de514SShawn Lin const char *get = action[!!peer]; 270*8f7de514SShawn Lin int ret; 271*8f7de514SShawn Lin int retries = UFS_UIC_COMMAND_RETRIES; 272*8f7de514SShawn Lin 273*8f7de514SShawn Lin uic_cmd.command = peer ? 274*8f7de514SShawn Lin UIC_CMD_DME_PEER_GET : UIC_CMD_DME_GET; 275*8f7de514SShawn Lin uic_cmd.argument1 = attr_sel; 276*8f7de514SShawn Lin 277*8f7de514SShawn Lin do { 278*8f7de514SShawn Lin /* for peer attributes we retry upon failure */ 279*8f7de514SShawn Lin ret = ufshcd_send_uic_cmd(hba, &uic_cmd); 280*8f7de514SShawn Lin if (ret) 281*8f7de514SShawn Lin dev_dbg(hba->dev, "%s: attr-id 0x%x error code %d\n", 282*8f7de514SShawn Lin get, UIC_GET_ATTR_ID(attr_sel), ret); 283*8f7de514SShawn Lin } while (ret && peer && --retries); 284*8f7de514SShawn Lin 285*8f7de514SShawn Lin if (ret) 286*8f7de514SShawn Lin dev_err(hba->dev, "%s: attr-id 0x%x failed %d retries\n", 287*8f7de514SShawn Lin get, UIC_GET_ATTR_ID(attr_sel), 288*8f7de514SShawn Lin UFS_UIC_COMMAND_RETRIES - retries); 289*8f7de514SShawn Lin 290*8f7de514SShawn Lin if (mib_val && !ret) 291*8f7de514SShawn Lin *mib_val = uic_cmd.argument3; 292*8f7de514SShawn Lin 293*8f7de514SShawn Lin return ret; 294*8f7de514SShawn Lin } 295*8f7de514SShawn Lin 296*8f7de514SShawn Lin static int ufshcd_disable_tx_lcc(struct ufs_hba *hba, bool peer) 297*8f7de514SShawn Lin { 298*8f7de514SShawn Lin u32 tx_lanes, i, err = 0; 299*8f7de514SShawn Lin 300*8f7de514SShawn Lin if (!peer) 301*8f7de514SShawn Lin ufshcd_dme_get(hba, UIC_ARG_MIB(PA_CONNECTEDTXDATALANES), 302*8f7de514SShawn Lin &tx_lanes); 303*8f7de514SShawn Lin else 304*8f7de514SShawn Lin ufshcd_dme_peer_get(hba, UIC_ARG_MIB(PA_CONNECTEDTXDATALANES), 305*8f7de514SShawn Lin &tx_lanes); 306*8f7de514SShawn Lin for (i = 0; i < tx_lanes; i++) { 307*8f7de514SShawn Lin if (!peer) 308*8f7de514SShawn Lin err = ufshcd_dme_set(hba, 309*8f7de514SShawn Lin UIC_ARG_MIB_SEL(TX_LCC_ENABLE, 310*8f7de514SShawn Lin UIC_ARG_MPHY_TX_GEN_SEL_INDEX(i)), 311*8f7de514SShawn Lin 0); 312*8f7de514SShawn Lin else 313*8f7de514SShawn Lin err = ufshcd_dme_peer_set(hba, 314*8f7de514SShawn Lin UIC_ARG_MIB_SEL(TX_LCC_ENABLE, 315*8f7de514SShawn Lin UIC_ARG_MPHY_TX_GEN_SEL_INDEX(i)), 316*8f7de514SShawn Lin 0); 317*8f7de514SShawn Lin if (err) { 318*8f7de514SShawn Lin dev_err(hba->dev, "%s: TX LCC Disable failed, peer = %d, lane = %d, err = %d", 319*8f7de514SShawn Lin __func__, peer, i, err); 320*8f7de514SShawn Lin break; 321*8f7de514SShawn Lin } 322*8f7de514SShawn Lin } 323*8f7de514SShawn Lin 324*8f7de514SShawn Lin return err; 325*8f7de514SShawn Lin } 326*8f7de514SShawn Lin 327*8f7de514SShawn Lin static inline int ufshcd_disable_device_tx_lcc(struct ufs_hba *hba) 328*8f7de514SShawn Lin { 329*8f7de514SShawn Lin return ufshcd_disable_tx_lcc(hba, true); 330*8f7de514SShawn Lin } 331*8f7de514SShawn Lin 332*8f7de514SShawn Lin /** 333*8f7de514SShawn Lin * ufshcd_dme_link_startup - Notify Unipro to perform link startup 334*8f7de514SShawn Lin * 335*8f7de514SShawn Lin */ 336*8f7de514SShawn Lin static int ufshcd_dme_link_startup(struct ufs_hba *hba) 337*8f7de514SShawn Lin { 338*8f7de514SShawn Lin struct uic_command uic_cmd = {0}; 339*8f7de514SShawn Lin int ret; 340*8f7de514SShawn Lin 341*8f7de514SShawn Lin uic_cmd.command = UIC_CMD_DME_LINK_STARTUP; 342*8f7de514SShawn Lin 343*8f7de514SShawn Lin ret = ufshcd_send_uic_cmd(hba, &uic_cmd); 344*8f7de514SShawn Lin if (ret) 345*8f7de514SShawn Lin dev_dbg(hba->dev, 346*8f7de514SShawn Lin "dme-link-startup: error code %d\n", ret); 347*8f7de514SShawn Lin return ret; 348*8f7de514SShawn Lin } 349*8f7de514SShawn Lin 350*8f7de514SShawn Lin /** 351*8f7de514SShawn Lin * ufshcd_disable_intr_aggr - Disables interrupt aggregation. 352*8f7de514SShawn Lin * 353*8f7de514SShawn Lin */ 354*8f7de514SShawn Lin static inline void ufshcd_disable_intr_aggr(struct ufs_hba *hba) 355*8f7de514SShawn Lin { 356*8f7de514SShawn Lin ufshcd_writel(hba, 0, REG_UTP_TRANSFER_REQ_INT_AGG_CONTROL); 357*8f7de514SShawn Lin } 358*8f7de514SShawn Lin 359*8f7de514SShawn Lin /** 360*8f7de514SShawn Lin * ufshcd_get_lists_status - Check UCRDY, UTRLRDY and UTMRLRDY 361*8f7de514SShawn Lin */ 362*8f7de514SShawn Lin static inline int ufshcd_get_lists_status(u32 reg) 363*8f7de514SShawn Lin { 364*8f7de514SShawn Lin return !((reg & UFSHCD_STATUS_READY) == UFSHCD_STATUS_READY); 365*8f7de514SShawn Lin } 366*8f7de514SShawn Lin 367*8f7de514SShawn Lin /** 368*8f7de514SShawn Lin * ufshcd_enable_run_stop_reg - Enable run-stop registers, 369*8f7de514SShawn Lin * When run-stop registers are set to 1, it indicates the 370*8f7de514SShawn Lin * host controller that it can process the requests 371*8f7de514SShawn Lin */ 372*8f7de514SShawn Lin static void ufshcd_enable_run_stop_reg(struct ufs_hba *hba) 373*8f7de514SShawn Lin { 374*8f7de514SShawn Lin ufshcd_writel(hba, UTP_TASK_REQ_LIST_RUN_STOP_BIT, 375*8f7de514SShawn Lin REG_UTP_TASK_REQ_LIST_RUN_STOP); 376*8f7de514SShawn Lin ufshcd_writel(hba, UTP_TRANSFER_REQ_LIST_RUN_STOP_BIT, 377*8f7de514SShawn Lin REG_UTP_TRANSFER_REQ_LIST_RUN_STOP); 378*8f7de514SShawn Lin } 379*8f7de514SShawn Lin 380*8f7de514SShawn Lin /** 381*8f7de514SShawn Lin * ufshcd_enable_intr - enable interrupts 382*8f7de514SShawn Lin */ 383*8f7de514SShawn Lin static void ufshcd_enable_intr(struct ufs_hba *hba, u32 intrs) 384*8f7de514SShawn Lin { 385*8f7de514SShawn Lin u32 set = ufshcd_readl(hba, REG_INTERRUPT_ENABLE); 386*8f7de514SShawn Lin u32 rw; 387*8f7de514SShawn Lin 388*8f7de514SShawn Lin if (hba->version == UFSHCI_VERSION_10) { 389*8f7de514SShawn Lin rw = set & INTERRUPT_MASK_RW_VER_10; 390*8f7de514SShawn Lin set = rw | ((set ^ intrs) & intrs); 391*8f7de514SShawn Lin } else { 392*8f7de514SShawn Lin set |= intrs; 393*8f7de514SShawn Lin } 394*8f7de514SShawn Lin 395*8f7de514SShawn Lin ufshcd_writel(hba, set, REG_INTERRUPT_ENABLE); 396*8f7de514SShawn Lin 397*8f7de514SShawn Lin hba->intr_mask = set; 398*8f7de514SShawn Lin } 399*8f7de514SShawn Lin 400*8f7de514SShawn Lin /** 401*8f7de514SShawn Lin * ufshcd_make_hba_operational - Make UFS controller operational 402*8f7de514SShawn Lin * 403*8f7de514SShawn Lin * To bring UFS host controller to operational state, 404*8f7de514SShawn Lin * 1. Enable required interrupts 405*8f7de514SShawn Lin * 2. Configure interrupt aggregation 406*8f7de514SShawn Lin * 3. Program UTRL and UTMRL base address 407*8f7de514SShawn Lin * 4. Configure run-stop-registers 408*8f7de514SShawn Lin * 409*8f7de514SShawn Lin */ 410*8f7de514SShawn Lin static int ufshcd_make_hba_operational(struct ufs_hba *hba) 411*8f7de514SShawn Lin { 412*8f7de514SShawn Lin int err = 0; 413*8f7de514SShawn Lin u32 reg; 414*8f7de514SShawn Lin 415*8f7de514SShawn Lin /* Enable required interrupts */ 416*8f7de514SShawn Lin ufshcd_enable_intr(hba, UFSHCD_ENABLE_INTRS); 417*8f7de514SShawn Lin 418*8f7de514SShawn Lin /* Disable interrupt aggregation */ 419*8f7de514SShawn Lin ufshcd_disable_intr_aggr(hba); 420*8f7de514SShawn Lin 421*8f7de514SShawn Lin /* Configure UTRL and UTMRL base address registers */ 422*8f7de514SShawn Lin ufshcd_writel(hba, lower_32_bits((dma_addr_t)hba->utrdl), 423*8f7de514SShawn Lin REG_UTP_TRANSFER_REQ_LIST_BASE_L); 424*8f7de514SShawn Lin ufshcd_writel(hba, upper_32_bits((dma_addr_t)hba->utrdl), 425*8f7de514SShawn Lin REG_UTP_TRANSFER_REQ_LIST_BASE_H); 426*8f7de514SShawn Lin ufshcd_writel(hba, lower_32_bits((dma_addr_t)hba->utmrdl), 427*8f7de514SShawn Lin REG_UTP_TASK_REQ_LIST_BASE_L); 428*8f7de514SShawn Lin ufshcd_writel(hba, upper_32_bits((dma_addr_t)hba->utmrdl), 429*8f7de514SShawn Lin REG_UTP_TASK_REQ_LIST_BASE_H); 430*8f7de514SShawn Lin 431*8f7de514SShawn Lin /* 432*8f7de514SShawn Lin * UCRDY, UTMRLDY and UTRLRDY bits must be 1 433*8f7de514SShawn Lin */ 434*8f7de514SShawn Lin reg = ufshcd_readl(hba, REG_CONTROLLER_STATUS); 435*8f7de514SShawn Lin if (!(ufshcd_get_lists_status(reg))) { 436*8f7de514SShawn Lin ufshcd_enable_run_stop_reg(hba); 437*8f7de514SShawn Lin } else { 438*8f7de514SShawn Lin dev_err(hba->dev, 439*8f7de514SShawn Lin "Host controller not ready to process requests"); 440*8f7de514SShawn Lin err = -EIO; 441*8f7de514SShawn Lin goto out; 442*8f7de514SShawn Lin } 443*8f7de514SShawn Lin 444*8f7de514SShawn Lin out: 445*8f7de514SShawn Lin return err; 446*8f7de514SShawn Lin } 447*8f7de514SShawn Lin 448*8f7de514SShawn Lin /** 449*8f7de514SShawn Lin * ufshcd_link_startup - Initialize unipro link startup 450*8f7de514SShawn Lin */ 451*8f7de514SShawn Lin static int ufshcd_link_startup(struct ufs_hba *hba) 452*8f7de514SShawn Lin { 453*8f7de514SShawn Lin int ret; 454*8f7de514SShawn Lin int retries = DME_LINKSTARTUP_RETRIES; 455*8f7de514SShawn Lin bool link_startup_again = true; 456*8f7de514SShawn Lin 457*8f7de514SShawn Lin link_startup: 458*8f7de514SShawn Lin do { 459*8f7de514SShawn Lin ufshcd_ops_link_startup_notify(hba, PRE_CHANGE); 460*8f7de514SShawn Lin 461*8f7de514SShawn Lin ret = ufshcd_dme_link_startup(hba); 462*8f7de514SShawn Lin 463*8f7de514SShawn Lin /* check if device is detected by inter-connect layer */ 464*8f7de514SShawn Lin if (!ret && !ufshcd_is_device_present(hba)) { 465*8f7de514SShawn Lin dev_err(hba->dev, "%s: Device not present\n", __func__); 466*8f7de514SShawn Lin ret = -ENXIO; 467*8f7de514SShawn Lin goto out; 468*8f7de514SShawn Lin } 469*8f7de514SShawn Lin 470*8f7de514SShawn Lin /* 471*8f7de514SShawn Lin * DME link lost indication is only received when link is up, 472*8f7de514SShawn Lin * but we can't be sure if the link is up until link startup 473*8f7de514SShawn Lin * succeeds. So reset the local Uni-Pro and try again. 474*8f7de514SShawn Lin */ 475*8f7de514SShawn Lin if (ret && ufshcd_hba_enable(hba)) 476*8f7de514SShawn Lin goto out; 477*8f7de514SShawn Lin } while (ret && retries--); 478*8f7de514SShawn Lin 479*8f7de514SShawn Lin if (ret) 480*8f7de514SShawn Lin /* failed to get the link up... retire */ 481*8f7de514SShawn Lin goto out; 482*8f7de514SShawn Lin 483*8f7de514SShawn Lin if (link_startup_again) { 484*8f7de514SShawn Lin link_startup_again = false; 485*8f7de514SShawn Lin retries = DME_LINKSTARTUP_RETRIES; 486*8f7de514SShawn Lin goto link_startup; 487*8f7de514SShawn Lin } 488*8f7de514SShawn Lin 489*8f7de514SShawn Lin /* Mark that link is up in PWM-G1, 1-lane, SLOW-AUTO mode */ 490*8f7de514SShawn Lin ufshcd_init_pwr_info(hba); 491*8f7de514SShawn Lin 492*8f7de514SShawn Lin if (hba->quirks & UFSHCD_QUIRK_BROKEN_LCC) { 493*8f7de514SShawn Lin ret = ufshcd_disable_device_tx_lcc(hba); 494*8f7de514SShawn Lin if (ret) 495*8f7de514SShawn Lin goto out; 496*8f7de514SShawn Lin } 497*8f7de514SShawn Lin 498*8f7de514SShawn Lin /* Include any host controller configuration via UIC commands */ 499*8f7de514SShawn Lin ret = ufshcd_ops_link_startup_notify(hba, POST_CHANGE); 500*8f7de514SShawn Lin if (ret) 501*8f7de514SShawn Lin goto out; 502*8f7de514SShawn Lin 503*8f7de514SShawn Lin ret = ufshcd_make_hba_operational(hba); 504*8f7de514SShawn Lin out: 505*8f7de514SShawn Lin if (ret) 506*8f7de514SShawn Lin dev_err(hba->dev, "link startup failed %d\n", ret); 507*8f7de514SShawn Lin 508*8f7de514SShawn Lin return ret; 509*8f7de514SShawn Lin } 510*8f7de514SShawn Lin 511*8f7de514SShawn Lin /** 512*8f7de514SShawn Lin * ufshcd_hba_stop - Send controller to reset state 513*8f7de514SShawn Lin */ 514*8f7de514SShawn Lin static inline void ufshcd_hba_stop(struct ufs_hba *hba) 515*8f7de514SShawn Lin { 516*8f7de514SShawn Lin int err; 517*8f7de514SShawn Lin 518*8f7de514SShawn Lin ufshcd_writel(hba, CONTROLLER_DISABLE, REG_CONTROLLER_ENABLE); 519*8f7de514SShawn Lin err = ufshcd_wait_for_register(hba, REG_CONTROLLER_ENABLE, 520*8f7de514SShawn Lin CONTROLLER_ENABLE, CONTROLLER_DISABLE, 521*8f7de514SShawn Lin 10); 522*8f7de514SShawn Lin if (err) 523*8f7de514SShawn Lin dev_err(hba->dev, "%s: Controller disable failed\n", __func__); 524*8f7de514SShawn Lin } 525*8f7de514SShawn Lin 526*8f7de514SShawn Lin /** 527*8f7de514SShawn Lin * ufshcd_is_hba_active - Get controller state 528*8f7de514SShawn Lin */ 529*8f7de514SShawn Lin static inline bool ufshcd_is_hba_active(struct ufs_hba *hba) 530*8f7de514SShawn Lin { 531*8f7de514SShawn Lin return (ufshcd_readl(hba, REG_CONTROLLER_ENABLE) & CONTROLLER_ENABLE) 532*8f7de514SShawn Lin ? false : true; 533*8f7de514SShawn Lin } 534*8f7de514SShawn Lin 535*8f7de514SShawn Lin /** 536*8f7de514SShawn Lin * ufshcd_hba_start - Start controller initialization sequence 537*8f7de514SShawn Lin */ 538*8f7de514SShawn Lin static inline void ufshcd_hba_start(struct ufs_hba *hba) 539*8f7de514SShawn Lin { 540*8f7de514SShawn Lin ufshcd_writel(hba, CONTROLLER_ENABLE, REG_CONTROLLER_ENABLE); 541*8f7de514SShawn Lin } 542*8f7de514SShawn Lin 543*8f7de514SShawn Lin /** 544*8f7de514SShawn Lin * ufshcd_hba_enable - initialize the controller 545*8f7de514SShawn Lin */ 546*8f7de514SShawn Lin static int ufshcd_hba_enable(struct ufs_hba *hba) 547*8f7de514SShawn Lin { 548*8f7de514SShawn Lin int retry; 549*8f7de514SShawn Lin 550*8f7de514SShawn Lin if (!ufshcd_is_hba_active(hba)) 551*8f7de514SShawn Lin /* change controller state to "reset state" */ 552*8f7de514SShawn Lin ufshcd_hba_stop(hba); 553*8f7de514SShawn Lin 554*8f7de514SShawn Lin ufshcd_ops_hce_enable_notify(hba, PRE_CHANGE); 555*8f7de514SShawn Lin 556*8f7de514SShawn Lin /* start controller initialization sequence */ 557*8f7de514SShawn Lin ufshcd_hba_start(hba); 558*8f7de514SShawn Lin 559*8f7de514SShawn Lin /* 560*8f7de514SShawn Lin * To initialize a UFS host controller HCE bit must be set to 1. 561*8f7de514SShawn Lin * During initialization the HCE bit value changes from 1->0->1. 562*8f7de514SShawn Lin * When the host controller completes initialization sequence 563*8f7de514SShawn Lin * it sets the value of HCE bit to 1. The same HCE bit is read back 564*8f7de514SShawn Lin * to check if the controller has completed initialization sequence. 565*8f7de514SShawn Lin * So without this delay the value HCE = 1, set in the previous 566*8f7de514SShawn Lin * instruction might be read back. 567*8f7de514SShawn Lin * This delay can be changed based on the controller. 568*8f7de514SShawn Lin */ 569*8f7de514SShawn Lin mdelay(1); 570*8f7de514SShawn Lin 571*8f7de514SShawn Lin /* wait for the host controller to complete initialization */ 572*8f7de514SShawn Lin retry = 10; 573*8f7de514SShawn Lin while (ufshcd_is_hba_active(hba)) { 574*8f7de514SShawn Lin if (retry) { 575*8f7de514SShawn Lin retry--; 576*8f7de514SShawn Lin } else { 577*8f7de514SShawn Lin dev_err(hba->dev, "Controller enable failed\n"); 578*8f7de514SShawn Lin return -EIO; 579*8f7de514SShawn Lin } 580*8f7de514SShawn Lin mdelay(5); 581*8f7de514SShawn Lin } 582*8f7de514SShawn Lin 583*8f7de514SShawn Lin /* enable UIC related interrupts */ 584*8f7de514SShawn Lin ufshcd_enable_intr(hba, UFSHCD_UIC_MASK); 585*8f7de514SShawn Lin 586*8f7de514SShawn Lin ufshcd_ops_hce_enable_notify(hba, POST_CHANGE); 587*8f7de514SShawn Lin 588*8f7de514SShawn Lin return 0; 589*8f7de514SShawn Lin } 590*8f7de514SShawn Lin 591*8f7de514SShawn Lin /** 592*8f7de514SShawn Lin * ufshcd_host_memory_configure - configure local reference block with 593*8f7de514SShawn Lin * memory offsets 594*8f7de514SShawn Lin */ 595*8f7de514SShawn Lin static void ufshcd_host_memory_configure(struct ufs_hba *hba) 596*8f7de514SShawn Lin { 597*8f7de514SShawn Lin struct utp_transfer_req_desc *utrdlp; 598*8f7de514SShawn Lin dma_addr_t cmd_desc_dma_addr; 599*8f7de514SShawn Lin u16 response_offset; 600*8f7de514SShawn Lin u16 prdt_offset; 601*8f7de514SShawn Lin 602*8f7de514SShawn Lin utrdlp = hba->utrdl; 603*8f7de514SShawn Lin cmd_desc_dma_addr = (dma_addr_t)hba->ucdl; 604*8f7de514SShawn Lin 605*8f7de514SShawn Lin utrdlp->command_desc_base_addr_lo = 606*8f7de514SShawn Lin cpu_to_le32(lower_32_bits(cmd_desc_dma_addr)); 607*8f7de514SShawn Lin utrdlp->command_desc_base_addr_hi = 608*8f7de514SShawn Lin cpu_to_le32(upper_32_bits(cmd_desc_dma_addr)); 609*8f7de514SShawn Lin 610*8f7de514SShawn Lin response_offset = offsetof(struct utp_transfer_cmd_desc, response_upiu); 611*8f7de514SShawn Lin prdt_offset = offsetof(struct utp_transfer_cmd_desc, prd_table); 612*8f7de514SShawn Lin 613*8f7de514SShawn Lin utrdlp->response_upiu_offset = cpu_to_le16(response_offset >> 2); 614*8f7de514SShawn Lin utrdlp->prd_table_offset = cpu_to_le16(prdt_offset >> 2); 615*8f7de514SShawn Lin utrdlp->response_upiu_length = cpu_to_le16(ALIGNED_UPIU_SIZE >> 2); 616*8f7de514SShawn Lin 617*8f7de514SShawn Lin hba->ucd_req_ptr = (struct utp_upiu_req *)hba->ucdl; 618*8f7de514SShawn Lin hba->ucd_rsp_ptr = 619*8f7de514SShawn Lin (struct utp_upiu_rsp *)&hba->ucdl->response_upiu; 620*8f7de514SShawn Lin hba->ucd_prdt_ptr = 621*8f7de514SShawn Lin (struct ufshcd_sg_entry *)&hba->ucdl->prd_table; 622*8f7de514SShawn Lin } 623*8f7de514SShawn Lin 624*8f7de514SShawn Lin /** 625*8f7de514SShawn Lin * ufshcd_memory_alloc - allocate memory for host memory space data structures 626*8f7de514SShawn Lin */ 627*8f7de514SShawn Lin static int ufshcd_memory_alloc(struct ufs_hba *hba) 628*8f7de514SShawn Lin { 629*8f7de514SShawn Lin /* Allocate one Transfer Request Descriptor 630*8f7de514SShawn Lin * Should be aligned to 1k boundary. 631*8f7de514SShawn Lin */ 632*8f7de514SShawn Lin hba->utrdl = memalign(1024, sizeof(struct utp_transfer_req_desc)); 633*8f7de514SShawn Lin if (!hba->utrdl) { 634*8f7de514SShawn Lin dev_err(hba->dev, "Transfer Descriptor memory allocation failed\n"); 635*8f7de514SShawn Lin return -ENOMEM; 636*8f7de514SShawn Lin } 637*8f7de514SShawn Lin 638*8f7de514SShawn Lin /* Allocate one Command Descriptor 639*8f7de514SShawn Lin * Should be aligned to 1k boundary. 640*8f7de514SShawn Lin */ 641*8f7de514SShawn Lin hba->ucdl = memalign(1024, sizeof(struct utp_transfer_cmd_desc)); 642*8f7de514SShawn Lin if (!hba->ucdl) { 643*8f7de514SShawn Lin dev_err(hba->dev, "Command descriptor memory allocation failed\n"); 644*8f7de514SShawn Lin return -ENOMEM; 645*8f7de514SShawn Lin } 646*8f7de514SShawn Lin 647*8f7de514SShawn Lin return 0; 648*8f7de514SShawn Lin } 649*8f7de514SShawn Lin 650*8f7de514SShawn Lin /** 651*8f7de514SShawn Lin * ufshcd_get_intr_mask - Get the interrupt bit mask 652*8f7de514SShawn Lin */ 653*8f7de514SShawn Lin static inline u32 ufshcd_get_intr_mask(struct ufs_hba *hba) 654*8f7de514SShawn Lin { 655*8f7de514SShawn Lin u32 intr_mask = 0; 656*8f7de514SShawn Lin 657*8f7de514SShawn Lin switch (hba->version) { 658*8f7de514SShawn Lin case UFSHCI_VERSION_10: 659*8f7de514SShawn Lin intr_mask = INTERRUPT_MASK_ALL_VER_10; 660*8f7de514SShawn Lin break; 661*8f7de514SShawn Lin case UFSHCI_VERSION_11: 662*8f7de514SShawn Lin case UFSHCI_VERSION_20: 663*8f7de514SShawn Lin intr_mask = INTERRUPT_MASK_ALL_VER_11; 664*8f7de514SShawn Lin break; 665*8f7de514SShawn Lin case UFSHCI_VERSION_21: 666*8f7de514SShawn Lin default: 667*8f7de514SShawn Lin intr_mask = INTERRUPT_MASK_ALL_VER_21; 668*8f7de514SShawn Lin break; 669*8f7de514SShawn Lin } 670*8f7de514SShawn Lin 671*8f7de514SShawn Lin return intr_mask; 672*8f7de514SShawn Lin } 673*8f7de514SShawn Lin 674*8f7de514SShawn Lin /** 675*8f7de514SShawn Lin * ufshcd_get_ufs_version - Get the UFS version supported by the HBA 676*8f7de514SShawn Lin */ 677*8f7de514SShawn Lin static inline u32 ufshcd_get_ufs_version(struct ufs_hba *hba) 678*8f7de514SShawn Lin { 679*8f7de514SShawn Lin return ufshcd_readl(hba, REG_UFS_VERSION); 680*8f7de514SShawn Lin } 681*8f7de514SShawn Lin 682*8f7de514SShawn Lin /** 683*8f7de514SShawn Lin * ufshcd_get_upmcrs - Get the power mode change request status 684*8f7de514SShawn Lin */ 685*8f7de514SShawn Lin static inline u8 ufshcd_get_upmcrs(struct ufs_hba *hba) 686*8f7de514SShawn Lin { 687*8f7de514SShawn Lin return (ufshcd_readl(hba, REG_CONTROLLER_STATUS) >> 8) & 0x7; 688*8f7de514SShawn Lin } 689*8f7de514SShawn Lin 690*8f7de514SShawn Lin /** 691*8f7de514SShawn Lin * ufshcd_prepare_req_desc_hdr() - Fills the requests header 692*8f7de514SShawn Lin * descriptor according to request 693*8f7de514SShawn Lin */ 694*8f7de514SShawn Lin static void ufshcd_prepare_req_desc_hdr(struct utp_transfer_req_desc *req_desc, 695*8f7de514SShawn Lin u32 *upiu_flags, 696*8f7de514SShawn Lin enum dma_data_direction cmd_dir) 697*8f7de514SShawn Lin { 698*8f7de514SShawn Lin u32 data_direction; 699*8f7de514SShawn Lin u32 dword_0; 700*8f7de514SShawn Lin 701*8f7de514SShawn Lin if (cmd_dir == DMA_FROM_DEVICE) { 702*8f7de514SShawn Lin data_direction = UTP_DEVICE_TO_HOST; 703*8f7de514SShawn Lin *upiu_flags = UPIU_CMD_FLAGS_READ; 704*8f7de514SShawn Lin } else if (cmd_dir == DMA_TO_DEVICE) { 705*8f7de514SShawn Lin data_direction = UTP_HOST_TO_DEVICE; 706*8f7de514SShawn Lin *upiu_flags = UPIU_CMD_FLAGS_WRITE; 707*8f7de514SShawn Lin } else { 708*8f7de514SShawn Lin data_direction = UTP_NO_DATA_TRANSFER; 709*8f7de514SShawn Lin *upiu_flags = UPIU_CMD_FLAGS_NONE; 710*8f7de514SShawn Lin } 711*8f7de514SShawn Lin 712*8f7de514SShawn Lin dword_0 = data_direction | (0x1 << UPIU_COMMAND_TYPE_OFFSET); 713*8f7de514SShawn Lin 714*8f7de514SShawn Lin /* Enable Interrupt for command */ 715*8f7de514SShawn Lin dword_0 |= UTP_REQ_DESC_INT_CMD; 716*8f7de514SShawn Lin 717*8f7de514SShawn Lin /* Transfer request descriptor header fields */ 718*8f7de514SShawn Lin req_desc->header.dword_0 = cpu_to_le32(dword_0); 719*8f7de514SShawn Lin /* dword_1 is reserved, hence it is set to 0 */ 720*8f7de514SShawn Lin req_desc->header.dword_1 = 0; 721*8f7de514SShawn Lin /* 722*8f7de514SShawn Lin * assigning invalid value for command status. Controller 723*8f7de514SShawn Lin * updates OCS on command completion, with the command 724*8f7de514SShawn Lin * status 725*8f7de514SShawn Lin */ 726*8f7de514SShawn Lin req_desc->header.dword_2 = 727*8f7de514SShawn Lin cpu_to_le32(OCS_INVALID_COMMAND_STATUS); 728*8f7de514SShawn Lin /* dword_3 is reserved, hence it is set to 0 */ 729*8f7de514SShawn Lin req_desc->header.dword_3 = 0; 730*8f7de514SShawn Lin 731*8f7de514SShawn Lin req_desc->prd_table_length = 0; 732*8f7de514SShawn Lin } 733*8f7de514SShawn Lin 734*8f7de514SShawn Lin static void ufshcd_prepare_utp_query_req_upiu(struct ufs_hba *hba, 735*8f7de514SShawn Lin u32 upiu_flags) 736*8f7de514SShawn Lin { 737*8f7de514SShawn Lin struct utp_upiu_req *ucd_req_ptr = hba->ucd_req_ptr; 738*8f7de514SShawn Lin struct ufs_query *query = &hba->dev_cmd.query; 739*8f7de514SShawn Lin u16 len = be16_to_cpu(query->request.upiu_req.length); 740*8f7de514SShawn Lin 741*8f7de514SShawn Lin /* Query request header */ 742*8f7de514SShawn Lin ucd_req_ptr->header.dword_0 = 743*8f7de514SShawn Lin UPIU_HEADER_DWORD(UPIU_TRANSACTION_QUERY_REQ, 744*8f7de514SShawn Lin upiu_flags, 0, TASK_TAG); 745*8f7de514SShawn Lin ucd_req_ptr->header.dword_1 = 746*8f7de514SShawn Lin UPIU_HEADER_DWORD(0, query->request.query_func, 747*8f7de514SShawn Lin 0, 0); 748*8f7de514SShawn Lin 749*8f7de514SShawn Lin /* Data segment length only need for WRITE_DESC */ 750*8f7de514SShawn Lin if (query->request.upiu_req.opcode == UPIU_QUERY_OPCODE_WRITE_DESC) 751*8f7de514SShawn Lin ucd_req_ptr->header.dword_2 = 752*8f7de514SShawn Lin UPIU_HEADER_DWORD(0, 0, (len >> 8), (u8)len); 753*8f7de514SShawn Lin else 754*8f7de514SShawn Lin ucd_req_ptr->header.dword_2 = 0; 755*8f7de514SShawn Lin 756*8f7de514SShawn Lin /* Copy the Query Request buffer as is */ 757*8f7de514SShawn Lin memcpy(&ucd_req_ptr->qr, &query->request.upiu_req, QUERY_OSF_SIZE); 758*8f7de514SShawn Lin 759*8f7de514SShawn Lin /* Copy the Descriptor */ 760*8f7de514SShawn Lin if (query->request.upiu_req.opcode == UPIU_QUERY_OPCODE_WRITE_DESC) 761*8f7de514SShawn Lin memcpy(ucd_req_ptr + 1, query->descriptor, len); 762*8f7de514SShawn Lin 763*8f7de514SShawn Lin memset(hba->ucd_rsp_ptr, 0, sizeof(struct utp_upiu_rsp)); 764*8f7de514SShawn Lin } 765*8f7de514SShawn Lin 766*8f7de514SShawn Lin static inline void ufshcd_prepare_utp_nop_upiu(struct ufs_hba *hba) 767*8f7de514SShawn Lin { 768*8f7de514SShawn Lin struct utp_upiu_req *ucd_req_ptr = hba->ucd_req_ptr; 769*8f7de514SShawn Lin 770*8f7de514SShawn Lin memset(ucd_req_ptr, 0, sizeof(struct utp_upiu_req)); 771*8f7de514SShawn Lin 772*8f7de514SShawn Lin /* command descriptor fields */ 773*8f7de514SShawn Lin ucd_req_ptr->header.dword_0 = 774*8f7de514SShawn Lin UPIU_HEADER_DWORD(UPIU_TRANSACTION_NOP_OUT, 0, 0, 0x1f); 775*8f7de514SShawn Lin /* clear rest of the fields of basic header */ 776*8f7de514SShawn Lin ucd_req_ptr->header.dword_1 = 0; 777*8f7de514SShawn Lin ucd_req_ptr->header.dword_2 = 0; 778*8f7de514SShawn Lin 779*8f7de514SShawn Lin memset(hba->ucd_rsp_ptr, 0, sizeof(struct utp_upiu_rsp)); 780*8f7de514SShawn Lin } 781*8f7de514SShawn Lin 782*8f7de514SShawn Lin /** 783*8f7de514SShawn Lin * ufshcd_comp_devman_upiu - UFS Protocol Information Unit(UPIU) 784*8f7de514SShawn Lin * for Device Management Purposes 785*8f7de514SShawn Lin */ 786*8f7de514SShawn Lin static int ufshcd_comp_devman_upiu(struct ufs_hba *hba, 787*8f7de514SShawn Lin enum dev_cmd_type cmd_type) 788*8f7de514SShawn Lin { 789*8f7de514SShawn Lin u32 upiu_flags; 790*8f7de514SShawn Lin int ret = 0; 791*8f7de514SShawn Lin struct utp_transfer_req_desc *req_desc = hba->utrdl; 792*8f7de514SShawn Lin 793*8f7de514SShawn Lin hba->dev_cmd.type = cmd_type; 794*8f7de514SShawn Lin 795*8f7de514SShawn Lin ufshcd_prepare_req_desc_hdr(req_desc, &upiu_flags, DMA_NONE); 796*8f7de514SShawn Lin switch (cmd_type) { 797*8f7de514SShawn Lin case DEV_CMD_TYPE_QUERY: 798*8f7de514SShawn Lin ufshcd_prepare_utp_query_req_upiu(hba, upiu_flags); 799*8f7de514SShawn Lin break; 800*8f7de514SShawn Lin case DEV_CMD_TYPE_NOP: 801*8f7de514SShawn Lin ufshcd_prepare_utp_nop_upiu(hba); 802*8f7de514SShawn Lin break; 803*8f7de514SShawn Lin default: 804*8f7de514SShawn Lin ret = -EINVAL; 805*8f7de514SShawn Lin } 806*8f7de514SShawn Lin 807*8f7de514SShawn Lin return ret; 808*8f7de514SShawn Lin } 809*8f7de514SShawn Lin 810*8f7de514SShawn Lin static int ufshcd_send_command(struct ufs_hba *hba, unsigned int task_tag) 811*8f7de514SShawn Lin { 812*8f7de514SShawn Lin unsigned long start; 813*8f7de514SShawn Lin u32 intr_status; 814*8f7de514SShawn Lin u32 enabled_intr_status; 815*8f7de514SShawn Lin 816*8f7de514SShawn Lin ufshcd_writel(hba, 1 << task_tag, REG_UTP_TRANSFER_REQ_DOOR_BELL); 817*8f7de514SShawn Lin 818*8f7de514SShawn Lin start = get_timer(0); 819*8f7de514SShawn Lin do { 820*8f7de514SShawn Lin intr_status = ufshcd_readl(hba, REG_INTERRUPT_STATUS); 821*8f7de514SShawn Lin enabled_intr_status = intr_status & hba->intr_mask; 822*8f7de514SShawn Lin ufshcd_writel(hba, intr_status, REG_INTERRUPT_STATUS); 823*8f7de514SShawn Lin 824*8f7de514SShawn Lin if (get_timer(start) > QUERY_REQ_TIMEOUT) { 825*8f7de514SShawn Lin dev_err(hba->dev, 826*8f7de514SShawn Lin "Timedout waiting for UTP response\n"); 827*8f7de514SShawn Lin 828*8f7de514SShawn Lin return -ETIMEDOUT; 829*8f7de514SShawn Lin } 830*8f7de514SShawn Lin 831*8f7de514SShawn Lin if (enabled_intr_status & UFSHCD_ERROR_MASK) { 832*8f7de514SShawn Lin dev_err(hba->dev, "Error in status:%08x\n", 833*8f7de514SShawn Lin enabled_intr_status); 834*8f7de514SShawn Lin 835*8f7de514SShawn Lin return -1; 836*8f7de514SShawn Lin } 837*8f7de514SShawn Lin } while (!(enabled_intr_status & UTP_TRANSFER_REQ_COMPL)); 838*8f7de514SShawn Lin 839*8f7de514SShawn Lin return 0; 840*8f7de514SShawn Lin } 841*8f7de514SShawn Lin 842*8f7de514SShawn Lin /** 843*8f7de514SShawn Lin * ufshcd_get_req_rsp - returns the TR response transaction type 844*8f7de514SShawn Lin */ 845*8f7de514SShawn Lin static inline int ufshcd_get_req_rsp(struct utp_upiu_rsp *ucd_rsp_ptr) 846*8f7de514SShawn Lin { 847*8f7de514SShawn Lin return be32_to_cpu(ucd_rsp_ptr->header.dword_0) >> 24; 848*8f7de514SShawn Lin } 849*8f7de514SShawn Lin 850*8f7de514SShawn Lin /** 851*8f7de514SShawn Lin * ufshcd_get_tr_ocs - Get the UTRD Overall Command Status 852*8f7de514SShawn Lin * 853*8f7de514SShawn Lin */ 854*8f7de514SShawn Lin static inline int ufshcd_get_tr_ocs(struct ufs_hba *hba) 855*8f7de514SShawn Lin { 856*8f7de514SShawn Lin return le32_to_cpu(hba->utrdl->header.dword_2) & MASK_OCS; 857*8f7de514SShawn Lin } 858*8f7de514SShawn Lin 859*8f7de514SShawn Lin static inline int ufshcd_get_rsp_upiu_result(struct utp_upiu_rsp *ucd_rsp_ptr) 860*8f7de514SShawn Lin { 861*8f7de514SShawn Lin return be32_to_cpu(ucd_rsp_ptr->header.dword_1) & MASK_RSP_UPIU_RESULT; 862*8f7de514SShawn Lin } 863*8f7de514SShawn Lin 864*8f7de514SShawn Lin static int ufshcd_check_query_response(struct ufs_hba *hba) 865*8f7de514SShawn Lin { 866*8f7de514SShawn Lin struct ufs_query_res *query_res = &hba->dev_cmd.query.response; 867*8f7de514SShawn Lin 868*8f7de514SShawn Lin /* Get the UPIU response */ 869*8f7de514SShawn Lin query_res->response = ufshcd_get_rsp_upiu_result(hba->ucd_rsp_ptr) >> 870*8f7de514SShawn Lin UPIU_RSP_CODE_OFFSET; 871*8f7de514SShawn Lin return query_res->response; 872*8f7de514SShawn Lin } 873*8f7de514SShawn Lin 874*8f7de514SShawn Lin /** 875*8f7de514SShawn Lin * ufshcd_copy_query_response() - Copy the Query Response and the data 876*8f7de514SShawn Lin * descriptor 877*8f7de514SShawn Lin */ 878*8f7de514SShawn Lin static int ufshcd_copy_query_response(struct ufs_hba *hba) 879*8f7de514SShawn Lin { 880*8f7de514SShawn Lin struct ufs_query_res *query_res = &hba->dev_cmd.query.response; 881*8f7de514SShawn Lin 882*8f7de514SShawn Lin memcpy(&query_res->upiu_res, &hba->ucd_rsp_ptr->qr, QUERY_OSF_SIZE); 883*8f7de514SShawn Lin 884*8f7de514SShawn Lin /* Get the descriptor */ 885*8f7de514SShawn Lin if (hba->dev_cmd.query.descriptor && 886*8f7de514SShawn Lin hba->ucd_rsp_ptr->qr.opcode == UPIU_QUERY_OPCODE_READ_DESC) { 887*8f7de514SShawn Lin u8 *descp = (u8 *)hba->ucd_rsp_ptr + 888*8f7de514SShawn Lin GENERAL_UPIU_REQUEST_SIZE; 889*8f7de514SShawn Lin u16 resp_len; 890*8f7de514SShawn Lin u16 buf_len; 891*8f7de514SShawn Lin 892*8f7de514SShawn Lin /* data segment length */ 893*8f7de514SShawn Lin resp_len = be32_to_cpu(hba->ucd_rsp_ptr->header.dword_2) & 894*8f7de514SShawn Lin MASK_QUERY_DATA_SEG_LEN; 895*8f7de514SShawn Lin buf_len = 896*8f7de514SShawn Lin be16_to_cpu(hba->dev_cmd.query.request.upiu_req.length); 897*8f7de514SShawn Lin if (likely(buf_len >= resp_len)) { 898*8f7de514SShawn Lin memcpy(hba->dev_cmd.query.descriptor, descp, resp_len); 899*8f7de514SShawn Lin } else { 900*8f7de514SShawn Lin dev_warn(hba->dev, 901*8f7de514SShawn Lin "%s: Response size is bigger than buffer", 902*8f7de514SShawn Lin __func__); 903*8f7de514SShawn Lin return -EINVAL; 904*8f7de514SShawn Lin } 905*8f7de514SShawn Lin } 906*8f7de514SShawn Lin 907*8f7de514SShawn Lin return 0; 908*8f7de514SShawn Lin } 909*8f7de514SShawn Lin 910*8f7de514SShawn Lin /** 911*8f7de514SShawn Lin * ufshcd_exec_dev_cmd - API for sending device management requests 912*8f7de514SShawn Lin */ 913*8f7de514SShawn Lin static int ufshcd_exec_dev_cmd(struct ufs_hba *hba, enum dev_cmd_type cmd_type, 914*8f7de514SShawn Lin int timeout) 915*8f7de514SShawn Lin { 916*8f7de514SShawn Lin int err; 917*8f7de514SShawn Lin int resp; 918*8f7de514SShawn Lin 919*8f7de514SShawn Lin err = ufshcd_comp_devman_upiu(hba, cmd_type); 920*8f7de514SShawn Lin if (err) 921*8f7de514SShawn Lin return err; 922*8f7de514SShawn Lin 923*8f7de514SShawn Lin err = ufshcd_send_command(hba, TASK_TAG); 924*8f7de514SShawn Lin if (err) 925*8f7de514SShawn Lin return err; 926*8f7de514SShawn Lin 927*8f7de514SShawn Lin err = ufshcd_get_tr_ocs(hba); 928*8f7de514SShawn Lin if (err) { 929*8f7de514SShawn Lin dev_err(hba->dev, "Error in OCS:%d\n", err); 930*8f7de514SShawn Lin return -EINVAL; 931*8f7de514SShawn Lin } 932*8f7de514SShawn Lin 933*8f7de514SShawn Lin resp = ufshcd_get_req_rsp(hba->ucd_rsp_ptr); 934*8f7de514SShawn Lin switch (resp) { 935*8f7de514SShawn Lin case UPIU_TRANSACTION_NOP_IN: 936*8f7de514SShawn Lin break; 937*8f7de514SShawn Lin case UPIU_TRANSACTION_QUERY_RSP: 938*8f7de514SShawn Lin err = ufshcd_check_query_response(hba); 939*8f7de514SShawn Lin if (!err) 940*8f7de514SShawn Lin err = ufshcd_copy_query_response(hba); 941*8f7de514SShawn Lin break; 942*8f7de514SShawn Lin case UPIU_TRANSACTION_REJECT_UPIU: 943*8f7de514SShawn Lin /* TODO: handle Reject UPIU Response */ 944*8f7de514SShawn Lin err = -EPERM; 945*8f7de514SShawn Lin dev_err(hba->dev, "%s: Reject UPIU not fully implemented\n", 946*8f7de514SShawn Lin __func__); 947*8f7de514SShawn Lin break; 948*8f7de514SShawn Lin default: 949*8f7de514SShawn Lin err = -EINVAL; 950*8f7de514SShawn Lin dev_err(hba->dev, "%s: Invalid device management cmd response: %x\n", 951*8f7de514SShawn Lin __func__, resp); 952*8f7de514SShawn Lin } 953*8f7de514SShawn Lin 954*8f7de514SShawn Lin return err; 955*8f7de514SShawn Lin } 956*8f7de514SShawn Lin 957*8f7de514SShawn Lin /** 958*8f7de514SShawn Lin * ufshcd_init_query() - init the query response and request parameters 959*8f7de514SShawn Lin */ 960*8f7de514SShawn Lin static inline void ufshcd_init_query(struct ufs_hba *hba, 961*8f7de514SShawn Lin struct ufs_query_req **request, 962*8f7de514SShawn Lin struct ufs_query_res **response, 963*8f7de514SShawn Lin enum query_opcode opcode, 964*8f7de514SShawn Lin u8 idn, u8 index, u8 selector) 965*8f7de514SShawn Lin { 966*8f7de514SShawn Lin *request = &hba->dev_cmd.query.request; 967*8f7de514SShawn Lin *response = &hba->dev_cmd.query.response; 968*8f7de514SShawn Lin memset(*request, 0, sizeof(struct ufs_query_req)); 969*8f7de514SShawn Lin memset(*response, 0, sizeof(struct ufs_query_res)); 970*8f7de514SShawn Lin (*request)->upiu_req.opcode = opcode; 971*8f7de514SShawn Lin (*request)->upiu_req.idn = idn; 972*8f7de514SShawn Lin (*request)->upiu_req.index = index; 973*8f7de514SShawn Lin (*request)->upiu_req.selector = selector; 974*8f7de514SShawn Lin } 975*8f7de514SShawn Lin 976*8f7de514SShawn Lin /** 977*8f7de514SShawn Lin * ufshcd_query_flag() - API function for sending flag query requests 978*8f7de514SShawn Lin */ 979*8f7de514SShawn Lin int ufshcd_query_flag(struct ufs_hba *hba, enum query_opcode opcode, 980*8f7de514SShawn Lin enum flag_idn idn, bool *flag_res) 981*8f7de514SShawn Lin { 982*8f7de514SShawn Lin struct ufs_query_req *request = NULL; 983*8f7de514SShawn Lin struct ufs_query_res *response = NULL; 984*8f7de514SShawn Lin int err, index = 0, selector = 0; 985*8f7de514SShawn Lin int timeout = QUERY_REQ_TIMEOUT; 986*8f7de514SShawn Lin 987*8f7de514SShawn Lin ufshcd_init_query(hba, &request, &response, opcode, idn, index, 988*8f7de514SShawn Lin selector); 989*8f7de514SShawn Lin 990*8f7de514SShawn Lin switch (opcode) { 991*8f7de514SShawn Lin case UPIU_QUERY_OPCODE_SET_FLAG: 992*8f7de514SShawn Lin case UPIU_QUERY_OPCODE_CLEAR_FLAG: 993*8f7de514SShawn Lin case UPIU_QUERY_OPCODE_TOGGLE_FLAG: 994*8f7de514SShawn Lin request->query_func = UPIU_QUERY_FUNC_STANDARD_WRITE_REQUEST; 995*8f7de514SShawn Lin break; 996*8f7de514SShawn Lin case UPIU_QUERY_OPCODE_READ_FLAG: 997*8f7de514SShawn Lin request->query_func = UPIU_QUERY_FUNC_STANDARD_READ_REQUEST; 998*8f7de514SShawn Lin if (!flag_res) { 999*8f7de514SShawn Lin /* No dummy reads */ 1000*8f7de514SShawn Lin dev_err(hba->dev, "%s: Invalid argument for read request\n", 1001*8f7de514SShawn Lin __func__); 1002*8f7de514SShawn Lin err = -EINVAL; 1003*8f7de514SShawn Lin goto out; 1004*8f7de514SShawn Lin } 1005*8f7de514SShawn Lin break; 1006*8f7de514SShawn Lin default: 1007*8f7de514SShawn Lin dev_err(hba->dev, 1008*8f7de514SShawn Lin "%s: Expected query flag opcode but got = %d\n", 1009*8f7de514SShawn Lin __func__, opcode); 1010*8f7de514SShawn Lin err = -EINVAL; 1011*8f7de514SShawn Lin goto out; 1012*8f7de514SShawn Lin } 1013*8f7de514SShawn Lin 1014*8f7de514SShawn Lin err = ufshcd_exec_dev_cmd(hba, DEV_CMD_TYPE_QUERY, timeout); 1015*8f7de514SShawn Lin 1016*8f7de514SShawn Lin if (err) { 1017*8f7de514SShawn Lin dev_err(hba->dev, 1018*8f7de514SShawn Lin "%s: Sending flag query for idn %d failed, err = %d\n", 1019*8f7de514SShawn Lin __func__, idn, err); 1020*8f7de514SShawn Lin goto out; 1021*8f7de514SShawn Lin } 1022*8f7de514SShawn Lin 1023*8f7de514SShawn Lin if (flag_res) 1024*8f7de514SShawn Lin *flag_res = (be32_to_cpu(response->upiu_res.value) & 1025*8f7de514SShawn Lin MASK_QUERY_UPIU_FLAG_LOC) & 0x1; 1026*8f7de514SShawn Lin 1027*8f7de514SShawn Lin out: 1028*8f7de514SShawn Lin return err; 1029*8f7de514SShawn Lin } 1030*8f7de514SShawn Lin 1031*8f7de514SShawn Lin static int ufshcd_query_flag_retry(struct ufs_hba *hba, 1032*8f7de514SShawn Lin enum query_opcode opcode, 1033*8f7de514SShawn Lin enum flag_idn idn, bool *flag_res) 1034*8f7de514SShawn Lin { 1035*8f7de514SShawn Lin int ret; 1036*8f7de514SShawn Lin int retries; 1037*8f7de514SShawn Lin 1038*8f7de514SShawn Lin for (retries = 0; retries < QUERY_REQ_RETRIES; retries++) { 1039*8f7de514SShawn Lin ret = ufshcd_query_flag(hba, opcode, idn, flag_res); 1040*8f7de514SShawn Lin if (ret) 1041*8f7de514SShawn Lin dev_dbg(hba->dev, 1042*8f7de514SShawn Lin "%s: failed with error %d, retries %d\n", 1043*8f7de514SShawn Lin __func__, ret, retries); 1044*8f7de514SShawn Lin else 1045*8f7de514SShawn Lin break; 1046*8f7de514SShawn Lin } 1047*8f7de514SShawn Lin 1048*8f7de514SShawn Lin if (ret) 1049*8f7de514SShawn Lin dev_err(hba->dev, 1050*8f7de514SShawn Lin "%s: query attribute, opcode %d, idn %d, failed with error %d after %d retires\n", 1051*8f7de514SShawn Lin __func__, opcode, idn, ret, retries); 1052*8f7de514SShawn Lin return ret; 1053*8f7de514SShawn Lin } 1054*8f7de514SShawn Lin 1055*8f7de514SShawn Lin static int __ufshcd_query_descriptor(struct ufs_hba *hba, 1056*8f7de514SShawn Lin enum query_opcode opcode, 1057*8f7de514SShawn Lin enum desc_idn idn, u8 index, u8 selector, 1058*8f7de514SShawn Lin u8 *desc_buf, int *buf_len) 1059*8f7de514SShawn Lin { 1060*8f7de514SShawn Lin struct ufs_query_req *request = NULL; 1061*8f7de514SShawn Lin struct ufs_query_res *response = NULL; 1062*8f7de514SShawn Lin int err; 1063*8f7de514SShawn Lin 1064*8f7de514SShawn Lin if (!desc_buf) { 1065*8f7de514SShawn Lin dev_err(hba->dev, "%s: descriptor buffer required for opcode 0x%x\n", 1066*8f7de514SShawn Lin __func__, opcode); 1067*8f7de514SShawn Lin err = -EINVAL; 1068*8f7de514SShawn Lin goto out; 1069*8f7de514SShawn Lin } 1070*8f7de514SShawn Lin 1071*8f7de514SShawn Lin if (*buf_len < QUERY_DESC_MIN_SIZE || *buf_len > QUERY_DESC_MAX_SIZE) { 1072*8f7de514SShawn Lin dev_err(hba->dev, "%s: descriptor buffer size (%d) is out of range\n", 1073*8f7de514SShawn Lin __func__, *buf_len); 1074*8f7de514SShawn Lin err = -EINVAL; 1075*8f7de514SShawn Lin goto out; 1076*8f7de514SShawn Lin } 1077*8f7de514SShawn Lin 1078*8f7de514SShawn Lin ufshcd_init_query(hba, &request, &response, opcode, idn, index, 1079*8f7de514SShawn Lin selector); 1080*8f7de514SShawn Lin hba->dev_cmd.query.descriptor = desc_buf; 1081*8f7de514SShawn Lin request->upiu_req.length = cpu_to_be16(*buf_len); 1082*8f7de514SShawn Lin 1083*8f7de514SShawn Lin switch (opcode) { 1084*8f7de514SShawn Lin case UPIU_QUERY_OPCODE_WRITE_DESC: 1085*8f7de514SShawn Lin request->query_func = UPIU_QUERY_FUNC_STANDARD_WRITE_REQUEST; 1086*8f7de514SShawn Lin break; 1087*8f7de514SShawn Lin case UPIU_QUERY_OPCODE_READ_DESC: 1088*8f7de514SShawn Lin request->query_func = UPIU_QUERY_FUNC_STANDARD_READ_REQUEST; 1089*8f7de514SShawn Lin break; 1090*8f7de514SShawn Lin default: 1091*8f7de514SShawn Lin dev_err(hba->dev, "%s: Expected query descriptor opcode but got = 0x%.2x\n", 1092*8f7de514SShawn Lin __func__, opcode); 1093*8f7de514SShawn Lin err = -EINVAL; 1094*8f7de514SShawn Lin goto out; 1095*8f7de514SShawn Lin } 1096*8f7de514SShawn Lin 1097*8f7de514SShawn Lin err = ufshcd_exec_dev_cmd(hba, DEV_CMD_TYPE_QUERY, QUERY_REQ_TIMEOUT); 1098*8f7de514SShawn Lin 1099*8f7de514SShawn Lin if (err) { 1100*8f7de514SShawn Lin dev_err(hba->dev, "%s: opcode 0x%.2x for idn %d failed, index %d, err = %d\n", 1101*8f7de514SShawn Lin __func__, opcode, idn, index, err); 1102*8f7de514SShawn Lin goto out; 1103*8f7de514SShawn Lin } 1104*8f7de514SShawn Lin 1105*8f7de514SShawn Lin hba->dev_cmd.query.descriptor = NULL; 1106*8f7de514SShawn Lin *buf_len = be16_to_cpu(response->upiu_res.length); 1107*8f7de514SShawn Lin 1108*8f7de514SShawn Lin out: 1109*8f7de514SShawn Lin return err; 1110*8f7de514SShawn Lin } 1111*8f7de514SShawn Lin 1112*8f7de514SShawn Lin /** 1113*8f7de514SShawn Lin * ufshcd_query_descriptor_retry - API function for sending descriptor requests 1114*8f7de514SShawn Lin */ 1115*8f7de514SShawn Lin int ufshcd_query_descriptor_retry(struct ufs_hba *hba, enum query_opcode opcode, 1116*8f7de514SShawn Lin enum desc_idn idn, u8 index, u8 selector, 1117*8f7de514SShawn Lin u8 *desc_buf, int *buf_len) 1118*8f7de514SShawn Lin { 1119*8f7de514SShawn Lin int err; 1120*8f7de514SShawn Lin int retries; 1121*8f7de514SShawn Lin 1122*8f7de514SShawn Lin for (retries = QUERY_REQ_RETRIES; retries > 0; retries--) { 1123*8f7de514SShawn Lin err = __ufshcd_query_descriptor(hba, opcode, idn, index, 1124*8f7de514SShawn Lin selector, desc_buf, buf_len); 1125*8f7de514SShawn Lin if (!err || err == -EINVAL) 1126*8f7de514SShawn Lin break; 1127*8f7de514SShawn Lin } 1128*8f7de514SShawn Lin 1129*8f7de514SShawn Lin return err; 1130*8f7de514SShawn Lin } 1131*8f7de514SShawn Lin 1132*8f7de514SShawn Lin /** 1133*8f7de514SShawn Lin * ufshcd_read_desc_length - read the specified descriptor length from header 1134*8f7de514SShawn Lin */ 1135*8f7de514SShawn Lin static int ufshcd_read_desc_length(struct ufs_hba *hba, enum desc_idn desc_id, 1136*8f7de514SShawn Lin int desc_index, int *desc_length) 1137*8f7de514SShawn Lin { 1138*8f7de514SShawn Lin int ret; 1139*8f7de514SShawn Lin u8 header[QUERY_DESC_HDR_SIZE]; 1140*8f7de514SShawn Lin int header_len = QUERY_DESC_HDR_SIZE; 1141*8f7de514SShawn Lin 1142*8f7de514SShawn Lin if (desc_id >= QUERY_DESC_IDN_MAX) 1143*8f7de514SShawn Lin return -EINVAL; 1144*8f7de514SShawn Lin 1145*8f7de514SShawn Lin ret = ufshcd_query_descriptor_retry(hba, UPIU_QUERY_OPCODE_READ_DESC, 1146*8f7de514SShawn Lin desc_id, desc_index, 0, header, 1147*8f7de514SShawn Lin &header_len); 1148*8f7de514SShawn Lin 1149*8f7de514SShawn Lin if (ret) { 1150*8f7de514SShawn Lin dev_err(hba->dev, "%s: Failed to get descriptor header id %d", 1151*8f7de514SShawn Lin __func__, desc_id); 1152*8f7de514SShawn Lin return ret; 1153*8f7de514SShawn Lin } else if (desc_id != header[QUERY_DESC_DESC_TYPE_OFFSET]) { 1154*8f7de514SShawn Lin dev_warn(hba->dev, "%s: descriptor header id %d and desc_id %d mismatch", 1155*8f7de514SShawn Lin __func__, header[QUERY_DESC_DESC_TYPE_OFFSET], 1156*8f7de514SShawn Lin desc_id); 1157*8f7de514SShawn Lin ret = -EINVAL; 1158*8f7de514SShawn Lin } 1159*8f7de514SShawn Lin 1160*8f7de514SShawn Lin *desc_length = header[QUERY_DESC_LENGTH_OFFSET]; 1161*8f7de514SShawn Lin 1162*8f7de514SShawn Lin return ret; 1163*8f7de514SShawn Lin } 1164*8f7de514SShawn Lin 1165*8f7de514SShawn Lin static void ufshcd_init_desc_sizes(struct ufs_hba *hba) 1166*8f7de514SShawn Lin { 1167*8f7de514SShawn Lin int err; 1168*8f7de514SShawn Lin 1169*8f7de514SShawn Lin err = ufshcd_read_desc_length(hba, QUERY_DESC_IDN_DEVICE, 0, 1170*8f7de514SShawn Lin &hba->desc_size.dev_desc); 1171*8f7de514SShawn Lin if (err) 1172*8f7de514SShawn Lin hba->desc_size.dev_desc = QUERY_DESC_DEVICE_DEF_SIZE; 1173*8f7de514SShawn Lin 1174*8f7de514SShawn Lin err = ufshcd_read_desc_length(hba, QUERY_DESC_IDN_POWER, 0, 1175*8f7de514SShawn Lin &hba->desc_size.pwr_desc); 1176*8f7de514SShawn Lin if (err) 1177*8f7de514SShawn Lin hba->desc_size.pwr_desc = QUERY_DESC_POWER_DEF_SIZE; 1178*8f7de514SShawn Lin 1179*8f7de514SShawn Lin err = ufshcd_read_desc_length(hba, QUERY_DESC_IDN_INTERCONNECT, 0, 1180*8f7de514SShawn Lin &hba->desc_size.interc_desc); 1181*8f7de514SShawn Lin if (err) 1182*8f7de514SShawn Lin hba->desc_size.interc_desc = QUERY_DESC_INTERCONNECT_DEF_SIZE; 1183*8f7de514SShawn Lin 1184*8f7de514SShawn Lin err = ufshcd_read_desc_length(hba, QUERY_DESC_IDN_CONFIGURATION, 0, 1185*8f7de514SShawn Lin &hba->desc_size.conf_desc); 1186*8f7de514SShawn Lin if (err) 1187*8f7de514SShawn Lin hba->desc_size.conf_desc = QUERY_DESC_CONFIGURATION_DEF_SIZE; 1188*8f7de514SShawn Lin 1189*8f7de514SShawn Lin err = ufshcd_read_desc_length(hba, QUERY_DESC_IDN_UNIT, 0, 1190*8f7de514SShawn Lin &hba->desc_size.unit_desc); 1191*8f7de514SShawn Lin if (err) 1192*8f7de514SShawn Lin hba->desc_size.unit_desc = QUERY_DESC_UNIT_DEF_SIZE; 1193*8f7de514SShawn Lin 1194*8f7de514SShawn Lin err = ufshcd_read_desc_length(hba, QUERY_DESC_IDN_GEOMETRY, 0, 1195*8f7de514SShawn Lin &hba->desc_size.geom_desc); 1196*8f7de514SShawn Lin if (err) 1197*8f7de514SShawn Lin hba->desc_size.geom_desc = QUERY_DESC_GEOMETRY_DEF_SIZE; 1198*8f7de514SShawn Lin 1199*8f7de514SShawn Lin err = ufshcd_read_desc_length(hba, QUERY_DESC_IDN_HEALTH, 0, 1200*8f7de514SShawn Lin &hba->desc_size.hlth_desc); 1201*8f7de514SShawn Lin if (err) 1202*8f7de514SShawn Lin hba->desc_size.hlth_desc = QUERY_DESC_HEALTH_DEF_SIZE; 1203*8f7de514SShawn Lin } 1204*8f7de514SShawn Lin 1205*8f7de514SShawn Lin /** 1206*8f7de514SShawn Lin * ufshcd_map_desc_id_to_length - map descriptor IDN to its length 1207*8f7de514SShawn Lin * 1208*8f7de514SShawn Lin */ 1209*8f7de514SShawn Lin int ufshcd_map_desc_id_to_length(struct ufs_hba *hba, enum desc_idn desc_id, 1210*8f7de514SShawn Lin int *desc_len) 1211*8f7de514SShawn Lin { 1212*8f7de514SShawn Lin switch (desc_id) { 1213*8f7de514SShawn Lin case QUERY_DESC_IDN_DEVICE: 1214*8f7de514SShawn Lin *desc_len = hba->desc_size.dev_desc; 1215*8f7de514SShawn Lin break; 1216*8f7de514SShawn Lin case QUERY_DESC_IDN_POWER: 1217*8f7de514SShawn Lin *desc_len = hba->desc_size.pwr_desc; 1218*8f7de514SShawn Lin break; 1219*8f7de514SShawn Lin case QUERY_DESC_IDN_GEOMETRY: 1220*8f7de514SShawn Lin *desc_len = hba->desc_size.geom_desc; 1221*8f7de514SShawn Lin break; 1222*8f7de514SShawn Lin case QUERY_DESC_IDN_CONFIGURATION: 1223*8f7de514SShawn Lin *desc_len = hba->desc_size.conf_desc; 1224*8f7de514SShawn Lin break; 1225*8f7de514SShawn Lin case QUERY_DESC_IDN_UNIT: 1226*8f7de514SShawn Lin *desc_len = hba->desc_size.unit_desc; 1227*8f7de514SShawn Lin break; 1228*8f7de514SShawn Lin case QUERY_DESC_IDN_INTERCONNECT: 1229*8f7de514SShawn Lin *desc_len = hba->desc_size.interc_desc; 1230*8f7de514SShawn Lin break; 1231*8f7de514SShawn Lin case QUERY_DESC_IDN_STRING: 1232*8f7de514SShawn Lin *desc_len = QUERY_DESC_MAX_SIZE; 1233*8f7de514SShawn Lin break; 1234*8f7de514SShawn Lin case QUERY_DESC_IDN_HEALTH: 1235*8f7de514SShawn Lin *desc_len = hba->desc_size.hlth_desc; 1236*8f7de514SShawn Lin break; 1237*8f7de514SShawn Lin case QUERY_DESC_IDN_RFU_0: 1238*8f7de514SShawn Lin case QUERY_DESC_IDN_RFU_1: 1239*8f7de514SShawn Lin *desc_len = 0; 1240*8f7de514SShawn Lin break; 1241*8f7de514SShawn Lin default: 1242*8f7de514SShawn Lin *desc_len = 0; 1243*8f7de514SShawn Lin return -EINVAL; 1244*8f7de514SShawn Lin } 1245*8f7de514SShawn Lin return 0; 1246*8f7de514SShawn Lin } 1247*8f7de514SShawn Lin EXPORT_SYMBOL(ufshcd_map_desc_id_to_length); 1248*8f7de514SShawn Lin 1249*8f7de514SShawn Lin /** 1250*8f7de514SShawn Lin * ufshcd_read_desc_param - read the specified descriptor parameter 1251*8f7de514SShawn Lin * 1252*8f7de514SShawn Lin */ 1253*8f7de514SShawn Lin int ufshcd_read_desc_param(struct ufs_hba *hba, enum desc_idn desc_id, 1254*8f7de514SShawn Lin int desc_index, u8 param_offset, u8 *param_read_buf, 1255*8f7de514SShawn Lin u8 param_size) 1256*8f7de514SShawn Lin { 1257*8f7de514SShawn Lin int ret; 1258*8f7de514SShawn Lin u8 *desc_buf; 1259*8f7de514SShawn Lin int buff_len; 1260*8f7de514SShawn Lin bool is_kmalloc = true; 1261*8f7de514SShawn Lin 1262*8f7de514SShawn Lin /* Safety check */ 1263*8f7de514SShawn Lin if (desc_id >= QUERY_DESC_IDN_MAX || !param_size) 1264*8f7de514SShawn Lin return -EINVAL; 1265*8f7de514SShawn Lin 1266*8f7de514SShawn Lin /* Get the max length of descriptor from structure filled up at probe 1267*8f7de514SShawn Lin * time. 1268*8f7de514SShawn Lin */ 1269*8f7de514SShawn Lin ret = ufshcd_map_desc_id_to_length(hba, desc_id, &buff_len); 1270*8f7de514SShawn Lin 1271*8f7de514SShawn Lin /* Sanity checks */ 1272*8f7de514SShawn Lin if (ret || !buff_len) { 1273*8f7de514SShawn Lin dev_err(hba->dev, "%s: Failed to get full descriptor length", 1274*8f7de514SShawn Lin __func__); 1275*8f7de514SShawn Lin return ret; 1276*8f7de514SShawn Lin } 1277*8f7de514SShawn Lin 1278*8f7de514SShawn Lin /* Check whether we need temp memory */ 1279*8f7de514SShawn Lin if (param_offset != 0 || param_size < buff_len) { 1280*8f7de514SShawn Lin desc_buf = kmalloc(buff_len, GFP_KERNEL); 1281*8f7de514SShawn Lin if (!desc_buf) 1282*8f7de514SShawn Lin return -ENOMEM; 1283*8f7de514SShawn Lin } else { 1284*8f7de514SShawn Lin desc_buf = param_read_buf; 1285*8f7de514SShawn Lin is_kmalloc = false; 1286*8f7de514SShawn Lin } 1287*8f7de514SShawn Lin 1288*8f7de514SShawn Lin /* Request for full descriptor */ 1289*8f7de514SShawn Lin ret = ufshcd_query_descriptor_retry(hba, UPIU_QUERY_OPCODE_READ_DESC, 1290*8f7de514SShawn Lin desc_id, desc_index, 0, desc_buf, 1291*8f7de514SShawn Lin &buff_len); 1292*8f7de514SShawn Lin 1293*8f7de514SShawn Lin if (ret) { 1294*8f7de514SShawn Lin dev_err(hba->dev, "%s: Failed reading descriptor. desc_id %d, desc_index %d, param_offset %d, ret %d", 1295*8f7de514SShawn Lin __func__, desc_id, desc_index, param_offset, ret); 1296*8f7de514SShawn Lin goto out; 1297*8f7de514SShawn Lin } 1298*8f7de514SShawn Lin 1299*8f7de514SShawn Lin /* Sanity check */ 1300*8f7de514SShawn Lin if (desc_buf[QUERY_DESC_DESC_TYPE_OFFSET] != desc_id) { 1301*8f7de514SShawn Lin dev_err(hba->dev, "%s: invalid desc_id %d in descriptor header", 1302*8f7de514SShawn Lin __func__, desc_buf[QUERY_DESC_DESC_TYPE_OFFSET]); 1303*8f7de514SShawn Lin ret = -EINVAL; 1304*8f7de514SShawn Lin goto out; 1305*8f7de514SShawn Lin } 1306*8f7de514SShawn Lin 1307*8f7de514SShawn Lin /* Check wherher we will not copy more data, than available */ 1308*8f7de514SShawn Lin if (is_kmalloc && param_size > buff_len) 1309*8f7de514SShawn Lin param_size = buff_len; 1310*8f7de514SShawn Lin 1311*8f7de514SShawn Lin if (is_kmalloc) 1312*8f7de514SShawn Lin memcpy(param_read_buf, &desc_buf[param_offset], param_size); 1313*8f7de514SShawn Lin out: 1314*8f7de514SShawn Lin if (is_kmalloc) 1315*8f7de514SShawn Lin kfree(desc_buf); 1316*8f7de514SShawn Lin return ret; 1317*8f7de514SShawn Lin } 1318*8f7de514SShawn Lin 1319*8f7de514SShawn Lin /* replace non-printable or non-ASCII characters with spaces */ 1320*8f7de514SShawn Lin static inline void ufshcd_remove_non_printable(uint8_t *val) 1321*8f7de514SShawn Lin { 1322*8f7de514SShawn Lin if (!val) 1323*8f7de514SShawn Lin return; 1324*8f7de514SShawn Lin 1325*8f7de514SShawn Lin if (*val < 0x20 || *val > 0x7e) 1326*8f7de514SShawn Lin *val = ' '; 1327*8f7de514SShawn Lin } 1328*8f7de514SShawn Lin 1329*8f7de514SShawn Lin /** 1330*8f7de514SShawn Lin * ufshcd_uic_pwr_ctrl - executes UIC commands (which affects the link power 1331*8f7de514SShawn Lin * state) and waits for it to take effect. 1332*8f7de514SShawn Lin * 1333*8f7de514SShawn Lin */ 1334*8f7de514SShawn Lin static int ufshcd_uic_pwr_ctrl(struct ufs_hba *hba, struct uic_command *cmd) 1335*8f7de514SShawn Lin { 1336*8f7de514SShawn Lin unsigned long start = 0; 1337*8f7de514SShawn Lin u8 status; 1338*8f7de514SShawn Lin int ret; 1339*8f7de514SShawn Lin 1340*8f7de514SShawn Lin ret = ufshcd_send_uic_cmd(hba, cmd); 1341*8f7de514SShawn Lin if (ret) { 1342*8f7de514SShawn Lin dev_err(hba->dev, 1343*8f7de514SShawn Lin "pwr ctrl cmd 0x%x with mode 0x%x uic error %d\n", 1344*8f7de514SShawn Lin cmd->command, cmd->argument3, ret); 1345*8f7de514SShawn Lin 1346*8f7de514SShawn Lin return ret; 1347*8f7de514SShawn Lin } 1348*8f7de514SShawn Lin 1349*8f7de514SShawn Lin start = get_timer(0); 1350*8f7de514SShawn Lin do { 1351*8f7de514SShawn Lin status = ufshcd_get_upmcrs(hba); 1352*8f7de514SShawn Lin if (get_timer(start) > UFS_UIC_CMD_TIMEOUT) { 1353*8f7de514SShawn Lin dev_err(hba->dev, 1354*8f7de514SShawn Lin "pwr ctrl cmd 0x%x failed, host upmcrs:0x%x\n", 1355*8f7de514SShawn Lin cmd->command, status); 1356*8f7de514SShawn Lin ret = (status != PWR_OK) ? status : -1; 1357*8f7de514SShawn Lin break; 1358*8f7de514SShawn Lin } 1359*8f7de514SShawn Lin } while (status != PWR_LOCAL); 1360*8f7de514SShawn Lin 1361*8f7de514SShawn Lin return ret; 1362*8f7de514SShawn Lin } 1363*8f7de514SShawn Lin 1364*8f7de514SShawn Lin /** 1365*8f7de514SShawn Lin * ufshcd_uic_change_pwr_mode - Perform the UIC power mode change 1366*8f7de514SShawn Lin * using DME_SET primitives. 1367*8f7de514SShawn Lin */ 1368*8f7de514SShawn Lin static int ufshcd_uic_change_pwr_mode(struct ufs_hba *hba, u8 mode) 1369*8f7de514SShawn Lin { 1370*8f7de514SShawn Lin struct uic_command uic_cmd = {0}; 1371*8f7de514SShawn Lin int ret; 1372*8f7de514SShawn Lin 1373*8f7de514SShawn Lin uic_cmd.command = UIC_CMD_DME_SET; 1374*8f7de514SShawn Lin uic_cmd.argument1 = UIC_ARG_MIB(PA_PWRMODE); 1375*8f7de514SShawn Lin uic_cmd.argument3 = mode; 1376*8f7de514SShawn Lin ret = ufshcd_uic_pwr_ctrl(hba, &uic_cmd); 1377*8f7de514SShawn Lin 1378*8f7de514SShawn Lin return ret; 1379*8f7de514SShawn Lin } 1380*8f7de514SShawn Lin 1381*8f7de514SShawn Lin static 1382*8f7de514SShawn Lin void ufshcd_prepare_utp_scsi_cmd_upiu(struct ufs_hba *hba, 1383*8f7de514SShawn Lin struct scsi_cmd *pccb, u32 upiu_flags) 1384*8f7de514SShawn Lin { 1385*8f7de514SShawn Lin struct utp_upiu_req *ucd_req_ptr = hba->ucd_req_ptr; 1386*8f7de514SShawn Lin unsigned int cdb_len; 1387*8f7de514SShawn Lin 1388*8f7de514SShawn Lin /* command descriptor fields */ 1389*8f7de514SShawn Lin ucd_req_ptr->header.dword_0 = 1390*8f7de514SShawn Lin UPIU_HEADER_DWORD(UPIU_TRANSACTION_COMMAND, upiu_flags, 1391*8f7de514SShawn Lin pccb->lun, TASK_TAG); 1392*8f7de514SShawn Lin ucd_req_ptr->header.dword_1 = 1393*8f7de514SShawn Lin UPIU_HEADER_DWORD(UPIU_COMMAND_SET_TYPE_SCSI, 0, 0, 0); 1394*8f7de514SShawn Lin 1395*8f7de514SShawn Lin /* Total EHS length and Data segment length will be zero */ 1396*8f7de514SShawn Lin ucd_req_ptr->header.dword_2 = 0; 1397*8f7de514SShawn Lin 1398*8f7de514SShawn Lin ucd_req_ptr->sc.exp_data_transfer_len = cpu_to_be32(pccb->datalen); 1399*8f7de514SShawn Lin 1400*8f7de514SShawn Lin cdb_len = min_t(unsigned short, pccb->cmdlen, UFS_CDB_SIZE); 1401*8f7de514SShawn Lin memset(ucd_req_ptr->sc.cdb, 0, UFS_CDB_SIZE); 1402*8f7de514SShawn Lin memcpy(ucd_req_ptr->sc.cdb, pccb->cmd, cdb_len); 1403*8f7de514SShawn Lin 1404*8f7de514SShawn Lin memset(hba->ucd_rsp_ptr, 0, sizeof(struct utp_upiu_rsp)); 1405*8f7de514SShawn Lin } 1406*8f7de514SShawn Lin 1407*8f7de514SShawn Lin static inline void prepare_prdt_desc(struct ufshcd_sg_entry *entry, 1408*8f7de514SShawn Lin unsigned char *buf, ulong len) 1409*8f7de514SShawn Lin { 1410*8f7de514SShawn Lin entry->size = cpu_to_le32(len) | GENMASK(1, 0); 1411*8f7de514SShawn Lin entry->base_addr = cpu_to_le32(lower_32_bits((unsigned long)buf)); 1412*8f7de514SShawn Lin entry->upper_addr = cpu_to_le32(upper_32_bits((unsigned long)buf)); 1413*8f7de514SShawn Lin } 1414*8f7de514SShawn Lin 1415*8f7de514SShawn Lin static void prepare_prdt_table(struct ufs_hba *hba, struct scsi_cmd *pccb) 1416*8f7de514SShawn Lin { 1417*8f7de514SShawn Lin struct utp_transfer_req_desc *req_desc = hba->utrdl; 1418*8f7de514SShawn Lin struct ufshcd_sg_entry *prd_table = hba->ucd_prdt_ptr; 1419*8f7de514SShawn Lin ulong datalen = pccb->datalen; 1420*8f7de514SShawn Lin int table_length; 1421*8f7de514SShawn Lin u8 *buf; 1422*8f7de514SShawn Lin int i; 1423*8f7de514SShawn Lin 1424*8f7de514SShawn Lin if (!datalen) { 1425*8f7de514SShawn Lin req_desc->prd_table_length = 0; 1426*8f7de514SShawn Lin return; 1427*8f7de514SShawn Lin } 1428*8f7de514SShawn Lin 1429*8f7de514SShawn Lin table_length = DIV_ROUND_UP(pccb->datalen, MAX_PRDT_ENTRY); 1430*8f7de514SShawn Lin buf = pccb->pdata; 1431*8f7de514SShawn Lin i = table_length; 1432*8f7de514SShawn Lin while (--i) { 1433*8f7de514SShawn Lin prepare_prdt_desc(&prd_table[table_length - i - 1], buf, 1434*8f7de514SShawn Lin MAX_PRDT_ENTRY - 1); 1435*8f7de514SShawn Lin buf += MAX_PRDT_ENTRY; 1436*8f7de514SShawn Lin datalen -= MAX_PRDT_ENTRY; 1437*8f7de514SShawn Lin } 1438*8f7de514SShawn Lin 1439*8f7de514SShawn Lin prepare_prdt_desc(&prd_table[table_length - i - 1], buf, datalen - 1); 1440*8f7de514SShawn Lin 1441*8f7de514SShawn Lin req_desc->prd_table_length = table_length; 1442*8f7de514SShawn Lin } 1443*8f7de514SShawn Lin 1444*8f7de514SShawn Lin static int ufs_scsi_exec(struct udevice *scsi_dev, struct scsi_cmd *pccb) 1445*8f7de514SShawn Lin { 1446*8f7de514SShawn Lin struct ufs_hba *hba = dev_get_uclass_priv(scsi_dev->parent); 1447*8f7de514SShawn Lin struct utp_transfer_req_desc *req_desc = hba->utrdl; 1448*8f7de514SShawn Lin u32 upiu_flags; 1449*8f7de514SShawn Lin int ocs, result = 0; 1450*8f7de514SShawn Lin u8 scsi_status; 1451*8f7de514SShawn Lin 1452*8f7de514SShawn Lin ufshcd_prepare_req_desc_hdr(req_desc, &upiu_flags, pccb->dma_dir); 1453*8f7de514SShawn Lin ufshcd_prepare_utp_scsi_cmd_upiu(hba, pccb, upiu_flags); 1454*8f7de514SShawn Lin prepare_prdt_table(hba, pccb); 1455*8f7de514SShawn Lin 1456*8f7de514SShawn Lin ufshcd_send_command(hba, TASK_TAG); 1457*8f7de514SShawn Lin 1458*8f7de514SShawn Lin ocs = ufshcd_get_tr_ocs(hba); 1459*8f7de514SShawn Lin switch (ocs) { 1460*8f7de514SShawn Lin case OCS_SUCCESS: 1461*8f7de514SShawn Lin result = ufshcd_get_req_rsp(hba->ucd_rsp_ptr); 1462*8f7de514SShawn Lin switch (result) { 1463*8f7de514SShawn Lin case UPIU_TRANSACTION_RESPONSE: 1464*8f7de514SShawn Lin result = ufshcd_get_rsp_upiu_result(hba->ucd_rsp_ptr); 1465*8f7de514SShawn Lin 1466*8f7de514SShawn Lin scsi_status = result & MASK_SCSI_STATUS; 1467*8f7de514SShawn Lin if (scsi_status) 1468*8f7de514SShawn Lin return -EINVAL; 1469*8f7de514SShawn Lin 1470*8f7de514SShawn Lin break; 1471*8f7de514SShawn Lin case UPIU_TRANSACTION_REJECT_UPIU: 1472*8f7de514SShawn Lin /* TODO: handle Reject UPIU Response */ 1473*8f7de514SShawn Lin dev_err(hba->dev, 1474*8f7de514SShawn Lin "Reject UPIU not fully implemented\n"); 1475*8f7de514SShawn Lin return -EINVAL; 1476*8f7de514SShawn Lin default: 1477*8f7de514SShawn Lin dev_err(hba->dev, 1478*8f7de514SShawn Lin "Unexpected request response code = %x\n", 1479*8f7de514SShawn Lin result); 1480*8f7de514SShawn Lin return -EINVAL; 1481*8f7de514SShawn Lin } 1482*8f7de514SShawn Lin break; 1483*8f7de514SShawn Lin default: 1484*8f7de514SShawn Lin dev_err(hba->dev, "OCS error from controller = %x\n", ocs); 1485*8f7de514SShawn Lin return -EINVAL; 1486*8f7de514SShawn Lin } 1487*8f7de514SShawn Lin 1488*8f7de514SShawn Lin return 0; 1489*8f7de514SShawn Lin } 1490*8f7de514SShawn Lin 1491*8f7de514SShawn Lin static inline int ufshcd_read_desc(struct ufs_hba *hba, enum desc_idn desc_id, 1492*8f7de514SShawn Lin int desc_index, u8 *buf, u32 size) 1493*8f7de514SShawn Lin { 1494*8f7de514SShawn Lin return ufshcd_read_desc_param(hba, desc_id, desc_index, 0, buf, size); 1495*8f7de514SShawn Lin } 1496*8f7de514SShawn Lin 1497*8f7de514SShawn Lin static int ufshcd_read_device_desc(struct ufs_hba *hba, u8 *buf, u32 size) 1498*8f7de514SShawn Lin { 1499*8f7de514SShawn Lin return ufshcd_read_desc(hba, QUERY_DESC_IDN_DEVICE, 0, buf, size); 1500*8f7de514SShawn Lin } 1501*8f7de514SShawn Lin 1502*8f7de514SShawn Lin /** 1503*8f7de514SShawn Lin * ufshcd_read_string_desc - read string descriptor 1504*8f7de514SShawn Lin * 1505*8f7de514SShawn Lin */ 1506*8f7de514SShawn Lin int ufshcd_read_string_desc(struct ufs_hba *hba, int desc_index, 1507*8f7de514SShawn Lin u8 *buf, u32 size, bool ascii) 1508*8f7de514SShawn Lin { 1509*8f7de514SShawn Lin int err = 0; 1510*8f7de514SShawn Lin 1511*8f7de514SShawn Lin err = ufshcd_read_desc(hba, QUERY_DESC_IDN_STRING, desc_index, buf, 1512*8f7de514SShawn Lin size); 1513*8f7de514SShawn Lin 1514*8f7de514SShawn Lin if (err) { 1515*8f7de514SShawn Lin dev_err(hba->dev, "%s: reading String Desc failed after %d retries. err = %d\n", 1516*8f7de514SShawn Lin __func__, QUERY_REQ_RETRIES, err); 1517*8f7de514SShawn Lin goto out; 1518*8f7de514SShawn Lin } 1519*8f7de514SShawn Lin 1520*8f7de514SShawn Lin if (ascii) { 1521*8f7de514SShawn Lin int desc_len; 1522*8f7de514SShawn Lin int ascii_len; 1523*8f7de514SShawn Lin int i; 1524*8f7de514SShawn Lin u8 *buff_ascii; 1525*8f7de514SShawn Lin 1526*8f7de514SShawn Lin desc_len = buf[0]; 1527*8f7de514SShawn Lin /* remove header and divide by 2 to move from UTF16 to UTF8 */ 1528*8f7de514SShawn Lin ascii_len = (desc_len - QUERY_DESC_HDR_SIZE) / 2 + 1; 1529*8f7de514SShawn Lin if (size < ascii_len + QUERY_DESC_HDR_SIZE) { 1530*8f7de514SShawn Lin dev_err(hba->dev, "%s: buffer allocated size is too small\n", 1531*8f7de514SShawn Lin __func__); 1532*8f7de514SShawn Lin err = -ENOMEM; 1533*8f7de514SShawn Lin goto out; 1534*8f7de514SShawn Lin } 1535*8f7de514SShawn Lin 1536*8f7de514SShawn Lin buff_ascii = kmalloc(ascii_len, GFP_KERNEL); 1537*8f7de514SShawn Lin if (!buff_ascii) { 1538*8f7de514SShawn Lin err = -ENOMEM; 1539*8f7de514SShawn Lin goto out; 1540*8f7de514SShawn Lin } 1541*8f7de514SShawn Lin 1542*8f7de514SShawn Lin /* 1543*8f7de514SShawn Lin * the descriptor contains string in UTF16 format 1544*8f7de514SShawn Lin * we need to convert to utf-8 so it can be displayed 1545*8f7de514SShawn Lin */ 1546*8f7de514SShawn Lin utf16_to_utf8(buff_ascii, 1547*8f7de514SShawn Lin (uint16_t *)&buf[QUERY_DESC_HDR_SIZE], ascii_len); 1548*8f7de514SShawn Lin 1549*8f7de514SShawn Lin /* replace non-printable or non-ASCII characters with spaces */ 1550*8f7de514SShawn Lin for (i = 0; i < ascii_len; i++) 1551*8f7de514SShawn Lin ufshcd_remove_non_printable(&buff_ascii[i]); 1552*8f7de514SShawn Lin 1553*8f7de514SShawn Lin memset(buf + QUERY_DESC_HDR_SIZE, 0, 1554*8f7de514SShawn Lin size - QUERY_DESC_HDR_SIZE); 1555*8f7de514SShawn Lin memcpy(buf + QUERY_DESC_HDR_SIZE, buff_ascii, ascii_len); 1556*8f7de514SShawn Lin buf[QUERY_DESC_LENGTH_OFFSET] = ascii_len + QUERY_DESC_HDR_SIZE; 1557*8f7de514SShawn Lin kfree(buff_ascii); 1558*8f7de514SShawn Lin } 1559*8f7de514SShawn Lin out: 1560*8f7de514SShawn Lin return err; 1561*8f7de514SShawn Lin } 1562*8f7de514SShawn Lin 1563*8f7de514SShawn Lin static int ufs_get_device_desc(struct ufs_hba *hba, 1564*8f7de514SShawn Lin struct ufs_dev_desc *dev_desc) 1565*8f7de514SShawn Lin { 1566*8f7de514SShawn Lin int err; 1567*8f7de514SShawn Lin size_t buff_len; 1568*8f7de514SShawn Lin u8 model_index; 1569*8f7de514SShawn Lin u8 *desc_buf; 1570*8f7de514SShawn Lin 1571*8f7de514SShawn Lin buff_len = max_t(size_t, hba->desc_size.dev_desc, 1572*8f7de514SShawn Lin QUERY_DESC_MAX_SIZE + 1); 1573*8f7de514SShawn Lin desc_buf = kmalloc(buff_len, GFP_KERNEL); 1574*8f7de514SShawn Lin if (!desc_buf) { 1575*8f7de514SShawn Lin err = -ENOMEM; 1576*8f7de514SShawn Lin goto out; 1577*8f7de514SShawn Lin } 1578*8f7de514SShawn Lin 1579*8f7de514SShawn Lin err = ufshcd_read_device_desc(hba, desc_buf, hba->desc_size.dev_desc); 1580*8f7de514SShawn Lin if (err) { 1581*8f7de514SShawn Lin dev_err(hba->dev, "%s: Failed reading Device Desc. err = %d\n", 1582*8f7de514SShawn Lin __func__, err); 1583*8f7de514SShawn Lin goto out; 1584*8f7de514SShawn Lin } 1585*8f7de514SShawn Lin 1586*8f7de514SShawn Lin /* 1587*8f7de514SShawn Lin * getting vendor (manufacturerID) and Bank Index in big endian 1588*8f7de514SShawn Lin * format 1589*8f7de514SShawn Lin */ 1590*8f7de514SShawn Lin dev_desc->wmanufacturerid = desc_buf[DEVICE_DESC_PARAM_MANF_ID] << 8 | 1591*8f7de514SShawn Lin desc_buf[DEVICE_DESC_PARAM_MANF_ID + 1]; 1592*8f7de514SShawn Lin 1593*8f7de514SShawn Lin model_index = desc_buf[DEVICE_DESC_PARAM_PRDCT_NAME]; 1594*8f7de514SShawn Lin 1595*8f7de514SShawn Lin /* Zero-pad entire buffer for string termination. */ 1596*8f7de514SShawn Lin memset(desc_buf, 0, buff_len); 1597*8f7de514SShawn Lin 1598*8f7de514SShawn Lin err = ufshcd_read_string_desc(hba, model_index, desc_buf, 1599*8f7de514SShawn Lin QUERY_DESC_MAX_SIZE, true/*ASCII*/); 1600*8f7de514SShawn Lin if (err) { 1601*8f7de514SShawn Lin dev_err(hba->dev, "%s: Failed reading Product Name. err = %d\n", 1602*8f7de514SShawn Lin __func__, err); 1603*8f7de514SShawn Lin goto out; 1604*8f7de514SShawn Lin } 1605*8f7de514SShawn Lin 1606*8f7de514SShawn Lin desc_buf[QUERY_DESC_MAX_SIZE] = '\0'; 1607*8f7de514SShawn Lin strlcpy(dev_desc->model, (char *)(desc_buf + QUERY_DESC_HDR_SIZE), 1608*8f7de514SShawn Lin min_t(u8, desc_buf[QUERY_DESC_LENGTH_OFFSET], 1609*8f7de514SShawn Lin MAX_MODEL_LEN)); 1610*8f7de514SShawn Lin 1611*8f7de514SShawn Lin /* Null terminate the model string */ 1612*8f7de514SShawn Lin dev_desc->model[MAX_MODEL_LEN] = '\0'; 1613*8f7de514SShawn Lin 1614*8f7de514SShawn Lin out: 1615*8f7de514SShawn Lin kfree(desc_buf); 1616*8f7de514SShawn Lin return err; 1617*8f7de514SShawn Lin } 1618*8f7de514SShawn Lin 1619*8f7de514SShawn Lin /** 1620*8f7de514SShawn Lin * ufshcd_get_max_pwr_mode - reads the max power mode negotiated with device 1621*8f7de514SShawn Lin */ 1622*8f7de514SShawn Lin static int ufshcd_get_max_pwr_mode(struct ufs_hba *hba) 1623*8f7de514SShawn Lin { 1624*8f7de514SShawn Lin struct ufs_pa_layer_attr *pwr_info = &hba->max_pwr_info.info; 1625*8f7de514SShawn Lin 1626*8f7de514SShawn Lin if (hba->max_pwr_info.is_valid) 1627*8f7de514SShawn Lin return 0; 1628*8f7de514SShawn Lin 1629*8f7de514SShawn Lin pwr_info->pwr_tx = FAST_MODE; 1630*8f7de514SShawn Lin pwr_info->pwr_rx = FAST_MODE; 1631*8f7de514SShawn Lin pwr_info->hs_rate = PA_HS_MODE_B; 1632*8f7de514SShawn Lin 1633*8f7de514SShawn Lin /* Get the connected lane count */ 1634*8f7de514SShawn Lin ufshcd_dme_get(hba, UIC_ARG_MIB(PA_CONNECTEDRXDATALANES), 1635*8f7de514SShawn Lin &pwr_info->lane_rx); 1636*8f7de514SShawn Lin ufshcd_dme_get(hba, UIC_ARG_MIB(PA_CONNECTEDTXDATALANES), 1637*8f7de514SShawn Lin &pwr_info->lane_tx); 1638*8f7de514SShawn Lin 1639*8f7de514SShawn Lin if (!pwr_info->lane_rx || !pwr_info->lane_tx) { 1640*8f7de514SShawn Lin dev_err(hba->dev, "%s: invalid connected lanes value. rx=%d, tx=%d\n", 1641*8f7de514SShawn Lin __func__, pwr_info->lane_rx, pwr_info->lane_tx); 1642*8f7de514SShawn Lin return -EINVAL; 1643*8f7de514SShawn Lin } 1644*8f7de514SShawn Lin 1645*8f7de514SShawn Lin /* 1646*8f7de514SShawn Lin * First, get the maximum gears of HS speed. 1647*8f7de514SShawn Lin * If a zero value, it means there is no HSGEAR capability. 1648*8f7de514SShawn Lin * Then, get the maximum gears of PWM speed. 1649*8f7de514SShawn Lin */ 1650*8f7de514SShawn Lin ufshcd_dme_get(hba, UIC_ARG_MIB(PA_MAXRXHSGEAR), &pwr_info->gear_rx); 1651*8f7de514SShawn Lin if (!pwr_info->gear_rx) { 1652*8f7de514SShawn Lin ufshcd_dme_get(hba, UIC_ARG_MIB(PA_MAXRXPWMGEAR), 1653*8f7de514SShawn Lin &pwr_info->gear_rx); 1654*8f7de514SShawn Lin if (!pwr_info->gear_rx) { 1655*8f7de514SShawn Lin dev_err(hba->dev, "%s: invalid max pwm rx gear read = %d\n", 1656*8f7de514SShawn Lin __func__, pwr_info->gear_rx); 1657*8f7de514SShawn Lin return -EINVAL; 1658*8f7de514SShawn Lin } 1659*8f7de514SShawn Lin pwr_info->pwr_rx = SLOW_MODE; 1660*8f7de514SShawn Lin } 1661*8f7de514SShawn Lin 1662*8f7de514SShawn Lin ufshcd_dme_peer_get(hba, UIC_ARG_MIB(PA_MAXRXHSGEAR), 1663*8f7de514SShawn Lin &pwr_info->gear_tx); 1664*8f7de514SShawn Lin if (!pwr_info->gear_tx) { 1665*8f7de514SShawn Lin ufshcd_dme_peer_get(hba, UIC_ARG_MIB(PA_MAXRXPWMGEAR), 1666*8f7de514SShawn Lin &pwr_info->gear_tx); 1667*8f7de514SShawn Lin if (!pwr_info->gear_tx) { 1668*8f7de514SShawn Lin dev_err(hba->dev, "%s: invalid max pwm tx gear read = %d\n", 1669*8f7de514SShawn Lin __func__, pwr_info->gear_tx); 1670*8f7de514SShawn Lin return -EINVAL; 1671*8f7de514SShawn Lin } 1672*8f7de514SShawn Lin pwr_info->pwr_tx = SLOW_MODE; 1673*8f7de514SShawn Lin } 1674*8f7de514SShawn Lin 1675*8f7de514SShawn Lin hba->max_pwr_info.is_valid = true; 1676*8f7de514SShawn Lin return 0; 1677*8f7de514SShawn Lin } 1678*8f7de514SShawn Lin 1679*8f7de514SShawn Lin static int ufshcd_change_power_mode(struct ufs_hba *hba, 1680*8f7de514SShawn Lin struct ufs_pa_layer_attr *pwr_mode) 1681*8f7de514SShawn Lin { 1682*8f7de514SShawn Lin int ret; 1683*8f7de514SShawn Lin 1684*8f7de514SShawn Lin /* if already configured to the requested pwr_mode */ 1685*8f7de514SShawn Lin if (pwr_mode->gear_rx == hba->pwr_info.gear_rx && 1686*8f7de514SShawn Lin pwr_mode->gear_tx == hba->pwr_info.gear_tx && 1687*8f7de514SShawn Lin pwr_mode->lane_rx == hba->pwr_info.lane_rx && 1688*8f7de514SShawn Lin pwr_mode->lane_tx == hba->pwr_info.lane_tx && 1689*8f7de514SShawn Lin pwr_mode->pwr_rx == hba->pwr_info.pwr_rx && 1690*8f7de514SShawn Lin pwr_mode->pwr_tx == hba->pwr_info.pwr_tx && 1691*8f7de514SShawn Lin pwr_mode->hs_rate == hba->pwr_info.hs_rate) { 1692*8f7de514SShawn Lin dev_dbg(hba->dev, "%s: power already configured\n", __func__); 1693*8f7de514SShawn Lin return 0; 1694*8f7de514SShawn Lin } 1695*8f7de514SShawn Lin 1696*8f7de514SShawn Lin /* 1697*8f7de514SShawn Lin * Configure attributes for power mode change with below. 1698*8f7de514SShawn Lin * - PA_RXGEAR, PA_ACTIVERXDATALANES, PA_RXTERMINATION, 1699*8f7de514SShawn Lin * - PA_TXGEAR, PA_ACTIVETXDATALANES, PA_TXTERMINATION, 1700*8f7de514SShawn Lin * - PA_HSSERIES 1701*8f7de514SShawn Lin */ 1702*8f7de514SShawn Lin ufshcd_dme_set(hba, UIC_ARG_MIB(PA_RXGEAR), pwr_mode->gear_rx); 1703*8f7de514SShawn Lin ufshcd_dme_set(hba, UIC_ARG_MIB(PA_ACTIVERXDATALANES), 1704*8f7de514SShawn Lin pwr_mode->lane_rx); 1705*8f7de514SShawn Lin if (pwr_mode->pwr_rx == FASTAUTO_MODE || pwr_mode->pwr_rx == FAST_MODE) 1706*8f7de514SShawn Lin ufshcd_dme_set(hba, UIC_ARG_MIB(PA_RXTERMINATION), TRUE); 1707*8f7de514SShawn Lin else 1708*8f7de514SShawn Lin ufshcd_dme_set(hba, UIC_ARG_MIB(PA_RXTERMINATION), FALSE); 1709*8f7de514SShawn Lin 1710*8f7de514SShawn Lin ufshcd_dme_set(hba, UIC_ARG_MIB(PA_TXGEAR), pwr_mode->gear_tx); 1711*8f7de514SShawn Lin ufshcd_dme_set(hba, UIC_ARG_MIB(PA_ACTIVETXDATALANES), 1712*8f7de514SShawn Lin pwr_mode->lane_tx); 1713*8f7de514SShawn Lin if (pwr_mode->pwr_tx == FASTAUTO_MODE || pwr_mode->pwr_tx == FAST_MODE) 1714*8f7de514SShawn Lin ufshcd_dme_set(hba, UIC_ARG_MIB(PA_TXTERMINATION), TRUE); 1715*8f7de514SShawn Lin else 1716*8f7de514SShawn Lin ufshcd_dme_set(hba, UIC_ARG_MIB(PA_TXTERMINATION), FALSE); 1717*8f7de514SShawn Lin 1718*8f7de514SShawn Lin if (pwr_mode->pwr_rx == FASTAUTO_MODE || 1719*8f7de514SShawn Lin pwr_mode->pwr_tx == FASTAUTO_MODE || 1720*8f7de514SShawn Lin pwr_mode->pwr_rx == FAST_MODE || 1721*8f7de514SShawn Lin pwr_mode->pwr_tx == FAST_MODE) 1722*8f7de514SShawn Lin ufshcd_dme_set(hba, UIC_ARG_MIB(PA_HSSERIES), 1723*8f7de514SShawn Lin pwr_mode->hs_rate); 1724*8f7de514SShawn Lin 1725*8f7de514SShawn Lin ret = ufshcd_uic_change_pwr_mode(hba, pwr_mode->pwr_rx << 4 | 1726*8f7de514SShawn Lin pwr_mode->pwr_tx); 1727*8f7de514SShawn Lin 1728*8f7de514SShawn Lin if (ret) { 1729*8f7de514SShawn Lin dev_err(hba->dev, 1730*8f7de514SShawn Lin "%s: power mode change failed %d\n", __func__, ret); 1731*8f7de514SShawn Lin 1732*8f7de514SShawn Lin return ret; 1733*8f7de514SShawn Lin } 1734*8f7de514SShawn Lin 1735*8f7de514SShawn Lin /* Copy new Power Mode to power info */ 1736*8f7de514SShawn Lin memcpy(&hba->pwr_info, pwr_mode, sizeof(struct ufs_pa_layer_attr)); 1737*8f7de514SShawn Lin 1738*8f7de514SShawn Lin return ret; 1739*8f7de514SShawn Lin } 1740*8f7de514SShawn Lin 1741*8f7de514SShawn Lin /** 1742*8f7de514SShawn Lin * ufshcd_verify_dev_init() - Verify device initialization 1743*8f7de514SShawn Lin * 1744*8f7de514SShawn Lin */ 1745*8f7de514SShawn Lin static int ufshcd_verify_dev_init(struct ufs_hba *hba) 1746*8f7de514SShawn Lin { 1747*8f7de514SShawn Lin int retries; 1748*8f7de514SShawn Lin int err; 1749*8f7de514SShawn Lin 1750*8f7de514SShawn Lin for (retries = NOP_OUT_RETRIES; retries > 0; retries--) { 1751*8f7de514SShawn Lin err = ufshcd_exec_dev_cmd(hba, DEV_CMD_TYPE_NOP, 1752*8f7de514SShawn Lin NOP_OUT_TIMEOUT); 1753*8f7de514SShawn Lin if (!err || err == -ETIMEDOUT) 1754*8f7de514SShawn Lin break; 1755*8f7de514SShawn Lin 1756*8f7de514SShawn Lin dev_dbg(hba->dev, "%s: error %d retrying\n", __func__, err); 1757*8f7de514SShawn Lin } 1758*8f7de514SShawn Lin 1759*8f7de514SShawn Lin if (err) 1760*8f7de514SShawn Lin dev_err(hba->dev, "%s: NOP OUT failed %d\n", __func__, err); 1761*8f7de514SShawn Lin 1762*8f7de514SShawn Lin return err; 1763*8f7de514SShawn Lin } 1764*8f7de514SShawn Lin 1765*8f7de514SShawn Lin /** 1766*8f7de514SShawn Lin * ufshcd_complete_dev_init() - checks device readiness 1767*8f7de514SShawn Lin */ 1768*8f7de514SShawn Lin static int ufshcd_complete_dev_init(struct ufs_hba *hba) 1769*8f7de514SShawn Lin { 1770*8f7de514SShawn Lin int i; 1771*8f7de514SShawn Lin int err; 1772*8f7de514SShawn Lin bool flag_res = 1; 1773*8f7de514SShawn Lin 1774*8f7de514SShawn Lin err = ufshcd_query_flag_retry(hba, UPIU_QUERY_OPCODE_SET_FLAG, 1775*8f7de514SShawn Lin QUERY_FLAG_IDN_FDEVICEINIT, NULL); 1776*8f7de514SShawn Lin if (err) { 1777*8f7de514SShawn Lin dev_err(hba->dev, 1778*8f7de514SShawn Lin "%s setting fDeviceInit flag failed with error %d\n", 1779*8f7de514SShawn Lin __func__, err); 1780*8f7de514SShawn Lin goto out; 1781*8f7de514SShawn Lin } 1782*8f7de514SShawn Lin 1783*8f7de514SShawn Lin /* poll for max. 1000 iterations for fDeviceInit flag to clear */ 1784*8f7de514SShawn Lin for (i = 0; i < 1000 && !err && flag_res; i++) 1785*8f7de514SShawn Lin err = ufshcd_query_flag_retry(hba, UPIU_QUERY_OPCODE_READ_FLAG, 1786*8f7de514SShawn Lin QUERY_FLAG_IDN_FDEVICEINIT, 1787*8f7de514SShawn Lin &flag_res); 1788*8f7de514SShawn Lin 1789*8f7de514SShawn Lin if (err) 1790*8f7de514SShawn Lin dev_err(hba->dev, 1791*8f7de514SShawn Lin "%s reading fDeviceInit flag failed with error %d\n", 1792*8f7de514SShawn Lin __func__, err); 1793*8f7de514SShawn Lin else if (flag_res) 1794*8f7de514SShawn Lin dev_err(hba->dev, 1795*8f7de514SShawn Lin "%s fDeviceInit was not cleared by the device\n", 1796*8f7de514SShawn Lin __func__); 1797*8f7de514SShawn Lin 1798*8f7de514SShawn Lin out: 1799*8f7de514SShawn Lin return err; 1800*8f7de514SShawn Lin } 1801*8f7de514SShawn Lin 1802*8f7de514SShawn Lin static void ufshcd_def_desc_sizes(struct ufs_hba *hba) 1803*8f7de514SShawn Lin { 1804*8f7de514SShawn Lin hba->desc_size.dev_desc = QUERY_DESC_DEVICE_DEF_SIZE; 1805*8f7de514SShawn Lin hba->desc_size.pwr_desc = QUERY_DESC_POWER_DEF_SIZE; 1806*8f7de514SShawn Lin hba->desc_size.interc_desc = QUERY_DESC_INTERCONNECT_DEF_SIZE; 1807*8f7de514SShawn Lin hba->desc_size.conf_desc = QUERY_DESC_CONFIGURATION_DEF_SIZE; 1808*8f7de514SShawn Lin hba->desc_size.unit_desc = QUERY_DESC_UNIT_DEF_SIZE; 1809*8f7de514SShawn Lin hba->desc_size.geom_desc = QUERY_DESC_GEOMETRY_DEF_SIZE; 1810*8f7de514SShawn Lin hba->desc_size.hlth_desc = QUERY_DESC_HEALTH_DEF_SIZE; 1811*8f7de514SShawn Lin } 1812*8f7de514SShawn Lin 1813*8f7de514SShawn Lin int ufs_start(struct ufs_hba *hba) 1814*8f7de514SShawn Lin { 1815*8f7de514SShawn Lin struct ufs_dev_desc card = {0}; 1816*8f7de514SShawn Lin int ret; 1817*8f7de514SShawn Lin 1818*8f7de514SShawn Lin ret = ufshcd_link_startup(hba); 1819*8f7de514SShawn Lin if (ret) 1820*8f7de514SShawn Lin return ret; 1821*8f7de514SShawn Lin 1822*8f7de514SShawn Lin ret = ufshcd_verify_dev_init(hba); 1823*8f7de514SShawn Lin if (ret) 1824*8f7de514SShawn Lin return ret; 1825*8f7de514SShawn Lin 1826*8f7de514SShawn Lin ret = ufshcd_complete_dev_init(hba); 1827*8f7de514SShawn Lin if (ret) 1828*8f7de514SShawn Lin return ret; 1829*8f7de514SShawn Lin 1830*8f7de514SShawn Lin /* Init check for device descriptor sizes */ 1831*8f7de514SShawn Lin ufshcd_init_desc_sizes(hba); 1832*8f7de514SShawn Lin 1833*8f7de514SShawn Lin ret = ufs_get_device_desc(hba, &card); 1834*8f7de514SShawn Lin if (ret) { 1835*8f7de514SShawn Lin dev_err(hba->dev, "%s: Failed getting device info. err = %d\n", 1836*8f7de514SShawn Lin __func__, ret); 1837*8f7de514SShawn Lin 1838*8f7de514SShawn Lin return ret; 1839*8f7de514SShawn Lin } 1840*8f7de514SShawn Lin 1841*8f7de514SShawn Lin if (ufshcd_get_max_pwr_mode(hba)) { 1842*8f7de514SShawn Lin dev_err(hba->dev, 1843*8f7de514SShawn Lin "%s: Failed getting max supported power mode\n", 1844*8f7de514SShawn Lin __func__); 1845*8f7de514SShawn Lin } else { 1846*8f7de514SShawn Lin ret = ufshcd_change_power_mode(hba, &hba->max_pwr_info.info); 1847*8f7de514SShawn Lin if (ret) { 1848*8f7de514SShawn Lin dev_err(hba->dev, "%s: Failed setting power mode, err = %d\n", 1849*8f7de514SShawn Lin __func__, ret); 1850*8f7de514SShawn Lin 1851*8f7de514SShawn Lin return ret; 1852*8f7de514SShawn Lin } 1853*8f7de514SShawn Lin 1854*8f7de514SShawn Lin printf("Device at %s up at:", hba->dev->name); 1855*8f7de514SShawn Lin ufshcd_print_pwr_info(hba); 1856*8f7de514SShawn Lin } 1857*8f7de514SShawn Lin 1858*8f7de514SShawn Lin return 0; 1859*8f7de514SShawn Lin } 1860*8f7de514SShawn Lin 1861*8f7de514SShawn Lin int ufshcd_probe(struct udevice *ufs_dev, struct ufs_hba_ops *hba_ops) 1862*8f7de514SShawn Lin { 1863*8f7de514SShawn Lin struct ufs_hba *hba = dev_get_uclass_priv(ufs_dev); 1864*8f7de514SShawn Lin struct scsi_platdata *scsi_plat; 1865*8f7de514SShawn Lin struct udevice *scsi_dev; 1866*8f7de514SShawn Lin int err; 1867*8f7de514SShawn Lin 1868*8f7de514SShawn Lin device_find_first_child(ufs_dev, &scsi_dev); 1869*8f7de514SShawn Lin if (!scsi_dev) 1870*8f7de514SShawn Lin return -ENODEV; 1871*8f7de514SShawn Lin 1872*8f7de514SShawn Lin scsi_plat = dev_get_uclass_platdata(scsi_dev); 1873*8f7de514SShawn Lin scsi_plat->max_id = UFSHCD_MAX_ID; 1874*8f7de514SShawn Lin scsi_plat->max_lun = UFS_MAX_LUNS; 1875*8f7de514SShawn Lin //scsi_plat->max_bytes_per_req = UFS_MAX_BYTES; 1876*8f7de514SShawn Lin 1877*8f7de514SShawn Lin hba->dev = ufs_dev; 1878*8f7de514SShawn Lin hba->ops = hba_ops; 1879*8f7de514SShawn Lin hba->mmio_base = (void *)dev_read_addr(ufs_dev); 1880*8f7de514SShawn Lin 1881*8f7de514SShawn Lin /* Set descriptor lengths to specification defaults */ 1882*8f7de514SShawn Lin ufshcd_def_desc_sizes(hba); 1883*8f7de514SShawn Lin 1884*8f7de514SShawn Lin ufshcd_ops_init(hba); 1885*8f7de514SShawn Lin 1886*8f7de514SShawn Lin /* Read capabilties registers */ 1887*8f7de514SShawn Lin hba->capabilities = ufshcd_readl(hba, REG_CONTROLLER_CAPABILITIES); 1888*8f7de514SShawn Lin 1889*8f7de514SShawn Lin /* Get UFS version supported by the controller */ 1890*8f7de514SShawn Lin hba->version = ufshcd_get_ufs_version(hba); 1891*8f7de514SShawn Lin if (hba->version != UFSHCI_VERSION_10 && 1892*8f7de514SShawn Lin hba->version != UFSHCI_VERSION_11 && 1893*8f7de514SShawn Lin hba->version != UFSHCI_VERSION_20 && 1894*8f7de514SShawn Lin hba->version != UFSHCI_VERSION_21) 1895*8f7de514SShawn Lin dev_err(hba->dev, "invalid UFS version 0x%x\n", 1896*8f7de514SShawn Lin hba->version); 1897*8f7de514SShawn Lin 1898*8f7de514SShawn Lin /* Get Interrupt bit mask per version */ 1899*8f7de514SShawn Lin hba->intr_mask = ufshcd_get_intr_mask(hba); 1900*8f7de514SShawn Lin 1901*8f7de514SShawn Lin /* Allocate memory for host memory space */ 1902*8f7de514SShawn Lin err = ufshcd_memory_alloc(hba); 1903*8f7de514SShawn Lin if (err) { 1904*8f7de514SShawn Lin dev_err(hba->dev, "Memory allocation failed\n"); 1905*8f7de514SShawn Lin return err; 1906*8f7de514SShawn Lin } 1907*8f7de514SShawn Lin 1908*8f7de514SShawn Lin /* Configure Local data structures */ 1909*8f7de514SShawn Lin ufshcd_host_memory_configure(hba); 1910*8f7de514SShawn Lin 1911*8f7de514SShawn Lin /* 1912*8f7de514SShawn Lin * In order to avoid any spurious interrupt immediately after 1913*8f7de514SShawn Lin * registering UFS controller interrupt handler, clear any pending UFS 1914*8f7de514SShawn Lin * interrupt status and disable all the UFS interrupts. 1915*8f7de514SShawn Lin */ 1916*8f7de514SShawn Lin ufshcd_writel(hba, ufshcd_readl(hba, REG_INTERRUPT_STATUS), 1917*8f7de514SShawn Lin REG_INTERRUPT_STATUS); 1918*8f7de514SShawn Lin ufshcd_writel(hba, 0, REG_INTERRUPT_ENABLE); 1919*8f7de514SShawn Lin 1920*8f7de514SShawn Lin err = ufshcd_hba_enable(hba); 1921*8f7de514SShawn Lin if (err) { 1922*8f7de514SShawn Lin dev_err(hba->dev, "Host controller enable failed\n"); 1923*8f7de514SShawn Lin return err; 1924*8f7de514SShawn Lin } 1925*8f7de514SShawn Lin 1926*8f7de514SShawn Lin err = ufs_start(hba); 1927*8f7de514SShawn Lin if (err) 1928*8f7de514SShawn Lin return err; 1929*8f7de514SShawn Lin 1930*8f7de514SShawn Lin return 0; 1931*8f7de514SShawn Lin } 1932*8f7de514SShawn Lin 1933*8f7de514SShawn Lin int ufs_scsi_bind(struct udevice *ufs_dev, struct udevice **scsi_devp) 1934*8f7de514SShawn Lin { 1935*8f7de514SShawn Lin int ret = device_bind_driver(ufs_dev, "ufs_scsi", "ufs_scsi", 1936*8f7de514SShawn Lin scsi_devp); 1937*8f7de514SShawn Lin 1938*8f7de514SShawn Lin return ret; 1939*8f7de514SShawn Lin } 1940*8f7de514SShawn Lin 1941*8f7de514SShawn Lin static struct scsi_ops ufs_ops = { 1942*8f7de514SShawn Lin .exec = ufs_scsi_exec, 1943*8f7de514SShawn Lin }; 1944*8f7de514SShawn Lin 1945*8f7de514SShawn Lin int ufs_probe_dev(int index) 1946*8f7de514SShawn Lin { 1947*8f7de514SShawn Lin struct udevice *dev; 1948*8f7de514SShawn Lin 1949*8f7de514SShawn Lin return uclass_get_device(UCLASS_UFS, index, &dev); 1950*8f7de514SShawn Lin } 1951*8f7de514SShawn Lin 1952*8f7de514SShawn Lin int ufs_probe(void) 1953*8f7de514SShawn Lin { 1954*8f7de514SShawn Lin struct udevice *dev; 1955*8f7de514SShawn Lin int ret, i; 1956*8f7de514SShawn Lin 1957*8f7de514SShawn Lin for (i = 0;; i++) { 1958*8f7de514SShawn Lin ret = uclass_get_device(UCLASS_UFS, i, &dev); 1959*8f7de514SShawn Lin if (ret == -ENODEV) 1960*8f7de514SShawn Lin break; 1961*8f7de514SShawn Lin } 1962*8f7de514SShawn Lin 1963*8f7de514SShawn Lin return 0; 1964*8f7de514SShawn Lin } 1965*8f7de514SShawn Lin 1966*8f7de514SShawn Lin U_BOOT_DRIVER(ufs_scsi) = { 1967*8f7de514SShawn Lin .id = UCLASS_SCSI, 1968*8f7de514SShawn Lin .name = "ufs_scsi", 1969*8f7de514SShawn Lin .ops = &ufs_ops, 1970*8f7de514SShawn Lin }; 1971