diff options
author | Seungwon Jeon <tgih.jun@samsung.com> | 2013-08-31 12:10:22 -0400 |
---|---|---|
committer | James Bottomley <JBottomley@Parallels.com> | 2013-09-06 19:06:40 -0400 |
commit | 53b3d9c3fdda94d14392dd221c67e24700b1fed6 (patch) | |
tree | a5198f3de41a71b6f2461fbf9687289254e0eaae | |
parent | 12b4fdb4f6bccb5459a2f75fbe0eab253bfceab4 (diff) |
[SCSI] ufs: add operation for the uic power mode change
Setting PA_PWRMode using DME_SET triggers the power mode
change. And then the result will be given by the HCS.UPMCRS.
This operation should be done atomically.
Signed-off-by: Seungwon Jeon <tgih.jun@samsung.com>
Reviewed-by: Subhash Jadavani <subhashj@codeaurora.org>
Tested-by: Yaniv Gardi <ygardi@codeaurora.org>
Signed-off-by: Santosh Y <santoshsy@gmail.com>
Signed-off-by: James Bottomley <JBottomley@Parallels.com>
-rw-r--r-- | drivers/scsi/ufs/ufshcd.c | 84 | ||||
-rw-r--r-- | drivers/scsi/ufs/ufshcd.h | 3 | ||||
-rw-r--r-- | drivers/scsi/ufs/ufshci.h | 12 | ||||
-rw-r--r-- | drivers/scsi/ufs/unipro.h | 130 |
4 files changed, 225 insertions, 4 deletions
diff --git a/drivers/scsi/ufs/ufshcd.c b/drivers/scsi/ufs/ufshcd.c index a4ce6c462614..1788d9cc571b 100644 --- a/drivers/scsi/ufs/ufshcd.c +++ b/drivers/scsi/ufs/ufshcd.c | |||
@@ -36,9 +36,11 @@ | |||
36 | #include <linux/async.h> | 36 | #include <linux/async.h> |
37 | 37 | ||
38 | #include "ufshcd.h" | 38 | #include "ufshcd.h" |
39 | #include "unipro.h" | ||
39 | 40 | ||
40 | #define UFSHCD_ENABLE_INTRS (UTP_TRANSFER_REQ_COMPL |\ | 41 | #define UFSHCD_ENABLE_INTRS (UTP_TRANSFER_REQ_COMPL |\ |
41 | UTP_TASK_REQ_COMPL |\ | 42 | UTP_TASK_REQ_COMPL |\ |
43 | UIC_POWER_MODE |\ | ||
42 | UFSHCD_ERROR_MASK) | 44 | UFSHCD_ERROR_MASK) |
43 | /* UIC command timeout, unit: ms */ | 45 | /* UIC command timeout, unit: ms */ |
44 | #define UIC_CMD_TIMEOUT 500 | 46 | #define UIC_CMD_TIMEOUT 500 |
@@ -470,6 +472,18 @@ static inline bool ufshcd_ready_for_uic_cmd(struct ufs_hba *hba) | |||
470 | } | 472 | } |
471 | 473 | ||
472 | /** | 474 | /** |
475 | * ufshcd_get_upmcrs - Get the power mode change request status | ||
476 | * @hba: Pointer to adapter instance | ||
477 | * | ||
478 | * This function gets the UPMCRS field of HCS register | ||
479 | * Returns value of UPMCRS field | ||
480 | */ | ||
481 | static inline u8 ufshcd_get_upmcrs(struct ufs_hba *hba) | ||
482 | { | ||
483 | return (ufshcd_readl(hba, REG_CONTROLLER_STATUS) >> 8) & 0x7; | ||
484 | } | ||
485 | |||
486 | /** | ||
473 | * ufshcd_dispatch_uic_cmd - Dispatch UIC commands to unipro layers | 487 | * ufshcd_dispatch_uic_cmd - Dispatch UIC commands to unipro layers |
474 | * @hba: per adapter instance | 488 | * @hba: per adapter instance |
475 | * @uic_cmd: UIC command | 489 | * @uic_cmd: UIC command |
@@ -1460,6 +1474,64 @@ out: | |||
1460 | EXPORT_SYMBOL_GPL(ufshcd_dme_get_attr); | 1474 | EXPORT_SYMBOL_GPL(ufshcd_dme_get_attr); |
1461 | 1475 | ||
1462 | /** | 1476 | /** |
1477 | * ufshcd_uic_change_pwr_mode - Perform the UIC power mode chage | ||
1478 | * using DME_SET primitives. | ||
1479 | * @hba: per adapter instance | ||
1480 | * @mode: powr mode value | ||
1481 | * | ||
1482 | * Returns 0 on success, non-zero value on failure | ||
1483 | */ | ||
1484 | int ufshcd_uic_change_pwr_mode(struct ufs_hba *hba, u8 mode) | ||
1485 | { | ||
1486 | struct uic_command uic_cmd = {0}; | ||
1487 | struct completion pwr_done; | ||
1488 | unsigned long flags; | ||
1489 | u8 status; | ||
1490 | int ret; | ||
1491 | |||
1492 | uic_cmd.command = UIC_CMD_DME_SET; | ||
1493 | uic_cmd.argument1 = UIC_ARG_MIB(PA_PWRMODE); | ||
1494 | uic_cmd.argument3 = mode; | ||
1495 | init_completion(&pwr_done); | ||
1496 | |||
1497 | mutex_lock(&hba->uic_cmd_mutex); | ||
1498 | |||
1499 | spin_lock_irqsave(hba->host->host_lock, flags); | ||
1500 | hba->pwr_done = &pwr_done; | ||
1501 | spin_unlock_irqrestore(hba->host->host_lock, flags); | ||
1502 | ret = __ufshcd_send_uic_cmd(hba, &uic_cmd); | ||
1503 | if (ret) { | ||
1504 | dev_err(hba->dev, | ||
1505 | "pwr mode change with mode 0x%x uic error %d\n", | ||
1506 | mode, ret); | ||
1507 | goto out; | ||
1508 | } | ||
1509 | |||
1510 | if (!wait_for_completion_timeout(hba->pwr_done, | ||
1511 | msecs_to_jiffies(UIC_CMD_TIMEOUT))) { | ||
1512 | dev_err(hba->dev, | ||
1513 | "pwr mode change with mode 0x%x completion timeout\n", | ||
1514 | mode); | ||
1515 | ret = -ETIMEDOUT; | ||
1516 | goto out; | ||
1517 | } | ||
1518 | |||
1519 | status = ufshcd_get_upmcrs(hba); | ||
1520 | if (status != PWR_LOCAL) { | ||
1521 | dev_err(hba->dev, | ||
1522 | "pwr mode change failed, host umpcrs:0x%x\n", | ||
1523 | status); | ||
1524 | ret = (status != PWR_OK) ? status : -1; | ||
1525 | } | ||
1526 | out: | ||
1527 | spin_lock_irqsave(hba->host->host_lock, flags); | ||
1528 | hba->pwr_done = NULL; | ||
1529 | spin_unlock_irqrestore(hba->host->host_lock, flags); | ||
1530 | mutex_unlock(&hba->uic_cmd_mutex); | ||
1531 | return ret; | ||
1532 | } | ||
1533 | |||
1534 | /** | ||
1463 | * ufshcd_complete_dev_init() - checks device readiness | 1535 | * ufshcd_complete_dev_init() - checks device readiness |
1464 | * hba: per-adapter instance | 1536 | * hba: per-adapter instance |
1465 | * | 1537 | * |
@@ -1988,16 +2060,20 @@ ufshcd_transfer_rsp_status(struct ufs_hba *hba, struct ufshcd_lrb *lrbp) | |||
1988 | /** | 2060 | /** |
1989 | * ufshcd_uic_cmd_compl - handle completion of uic command | 2061 | * ufshcd_uic_cmd_compl - handle completion of uic command |
1990 | * @hba: per adapter instance | 2062 | * @hba: per adapter instance |
2063 | * @intr_status: interrupt status generated by the controller | ||
1991 | */ | 2064 | */ |
1992 | static void ufshcd_uic_cmd_compl(struct ufs_hba *hba) | 2065 | static void ufshcd_uic_cmd_compl(struct ufs_hba *hba, u32 intr_status) |
1993 | { | 2066 | { |
1994 | if (hba->active_uic_cmd) { | 2067 | if ((intr_status & UIC_COMMAND_COMPL) && hba->active_uic_cmd) { |
1995 | hba->active_uic_cmd->argument2 |= | 2068 | hba->active_uic_cmd->argument2 |= |
1996 | ufshcd_get_uic_cmd_result(hba); | 2069 | ufshcd_get_uic_cmd_result(hba); |
1997 | hba->active_uic_cmd->argument3 = | 2070 | hba->active_uic_cmd->argument3 = |
1998 | ufshcd_get_dme_attr_val(hba); | 2071 | ufshcd_get_dme_attr_val(hba); |
1999 | complete(&hba->active_uic_cmd->done); | 2072 | complete(&hba->active_uic_cmd->done); |
2000 | } | 2073 | } |
2074 | |||
2075 | if ((intr_status & UIC_POWER_MODE) && hba->pwr_done) | ||
2076 | complete(hba->pwr_done); | ||
2001 | } | 2077 | } |
2002 | 2078 | ||
2003 | /** | 2079 | /** |
@@ -2343,8 +2419,8 @@ static void ufshcd_sl_intr(struct ufs_hba *hba, u32 intr_status) | |||
2343 | if (hba->errors) | 2419 | if (hba->errors) |
2344 | ufshcd_err_handler(hba); | 2420 | ufshcd_err_handler(hba); |
2345 | 2421 | ||
2346 | if (intr_status & UIC_COMMAND_COMPL) | 2422 | if (intr_status & UFSHCD_UIC_MASK) |
2347 | ufshcd_uic_cmd_compl(hba); | 2423 | ufshcd_uic_cmd_compl(hba, intr_status); |
2348 | 2424 | ||
2349 | if (intr_status & UTP_TASK_REQ_COMPL) | 2425 | if (intr_status & UTP_TASK_REQ_COMPL) |
2350 | ufshcd_tmc_handler(hba); | 2426 | ufshcd_tmc_handler(hba); |
diff --git a/drivers/scsi/ufs/ufshcd.h b/drivers/scsi/ufs/ufshcd.h index 648ab16d379c..577679a2d189 100644 --- a/drivers/scsi/ufs/ufshcd.h +++ b/drivers/scsi/ufs/ufshcd.h | |||
@@ -175,6 +175,7 @@ struct ufs_dev_cmd { | |||
175 | * @active_uic_cmd: handle of active UIC command | 175 | * @active_uic_cmd: handle of active UIC command |
176 | * @uic_cmd_mutex: mutex for uic command | 176 | * @uic_cmd_mutex: mutex for uic command |
177 | * @ufshcd_tm_wait_queue: wait queue for task management | 177 | * @ufshcd_tm_wait_queue: wait queue for task management |
178 | * @pwr_done: completion for power mode change | ||
178 | * @tm_condition: condition variable for task management | 179 | * @tm_condition: condition variable for task management |
179 | * @ufshcd_state: UFSHCD states | 180 | * @ufshcd_state: UFSHCD states |
180 | * @intr_mask: Interrupt Mask Bits | 181 | * @intr_mask: Interrupt Mask Bits |
@@ -219,6 +220,8 @@ struct ufs_hba { | |||
219 | wait_queue_head_t ufshcd_tm_wait_queue; | 220 | wait_queue_head_t ufshcd_tm_wait_queue; |
220 | unsigned long tm_condition; | 221 | unsigned long tm_condition; |
221 | 222 | ||
223 | struct completion *pwr_done; | ||
224 | |||
222 | u32 ufshcd_state; | 225 | u32 ufshcd_state; |
223 | u32 intr_mask; | 226 | u32 intr_mask; |
224 | u16 ee_ctrl_mask; | 227 | u16 ee_ctrl_mask; |
diff --git a/drivers/scsi/ufs/ufshci.h b/drivers/scsi/ufs/ufshci.h index 1e1fe2668181..0475c6619a68 100644 --- a/drivers/scsi/ufs/ufshci.h +++ b/drivers/scsi/ufs/ufshci.h | |||
@@ -124,6 +124,9 @@ enum { | |||
124 | #define CONTROLLER_FATAL_ERROR UFS_BIT(16) | 124 | #define CONTROLLER_FATAL_ERROR UFS_BIT(16) |
125 | #define SYSTEM_BUS_FATAL_ERROR UFS_BIT(17) | 125 | #define SYSTEM_BUS_FATAL_ERROR UFS_BIT(17) |
126 | 126 | ||
127 | #define UFSHCD_UIC_MASK (UIC_COMMAND_COMPL |\ | ||
128 | UIC_POWER_MODE) | ||
129 | |||
127 | #define UFSHCD_ERROR_MASK (UIC_ERROR |\ | 130 | #define UFSHCD_ERROR_MASK (UIC_ERROR |\ |
128 | DEVICE_FATAL_ERROR |\ | 131 | DEVICE_FATAL_ERROR |\ |
129 | CONTROLLER_FATAL_ERROR |\ | 132 | CONTROLLER_FATAL_ERROR |\ |
@@ -142,6 +145,15 @@ enum { | |||
142 | #define DEVICE_ERROR_INDICATOR UFS_BIT(5) | 145 | #define DEVICE_ERROR_INDICATOR UFS_BIT(5) |
143 | #define UIC_POWER_MODE_CHANGE_REQ_STATUS_MASK UFS_MASK(0x7, 8) | 146 | #define UIC_POWER_MODE_CHANGE_REQ_STATUS_MASK UFS_MASK(0x7, 8) |
144 | 147 | ||
148 | enum { | ||
149 | PWR_OK = 0x0, | ||
150 | PWR_LOCAL = 0x01, | ||
151 | PWR_REMOTE = 0x02, | ||
152 | PWR_BUSY = 0x03, | ||
153 | PWR_ERROR_CAP = 0x04, | ||
154 | PWR_FATAL_ERROR = 0x05, | ||
155 | }; | ||
156 | |||
145 | /* HCE - Host Controller Enable 34h */ | 157 | /* HCE - Host Controller Enable 34h */ |
146 | #define CONTROLLER_ENABLE UFS_BIT(0) | 158 | #define CONTROLLER_ENABLE UFS_BIT(0) |
147 | #define CONTROLLER_DISABLE 0x0 | 159 | #define CONTROLLER_DISABLE 0x0 |
diff --git a/drivers/scsi/ufs/unipro.h b/drivers/scsi/ufs/unipro.h new file mode 100644 index 000000000000..3a710eb3ec20 --- /dev/null +++ b/drivers/scsi/ufs/unipro.h | |||
@@ -0,0 +1,130 @@ | |||
1 | /* | ||
2 | * drivers/scsi/ufs/unipro.h | ||
3 | * | ||
4 | * Copyright (C) 2013 Samsung Electronics Co., Ltd. | ||
5 | * | ||
6 | * This program is free software; you can redistribute it and/or modify | ||
7 | * it under the terms of the GNU General Public License as published by | ||
8 | * the Free Software Foundation; either version 2 of the License, or | ||
9 | * (at your option) any later version. | ||
10 | */ | ||
11 | |||
12 | #ifndef _UNIPRO_H_ | ||
13 | #define _UNIPRO_H_ | ||
14 | |||
15 | /* | ||
16 | * PHY Adpater attributes | ||
17 | */ | ||
18 | #define PA_ACTIVETXDATALANES 0x1560 | ||
19 | #define PA_ACTIVERXDATALANES 0x1580 | ||
20 | #define PA_TXTRAILINGCLOCKS 0x1564 | ||
21 | #define PA_PHY_TYPE 0x1500 | ||
22 | #define PA_AVAILTXDATALANES 0x1520 | ||
23 | #define PA_AVAILRXDATALANES 0x1540 | ||
24 | #define PA_MINRXTRAILINGCLOCKS 0x1543 | ||
25 | #define PA_TXPWRSTATUS 0x1567 | ||
26 | #define PA_RXPWRSTATUS 0x1582 | ||
27 | #define PA_TXFORCECLOCK 0x1562 | ||
28 | #define PA_TXPWRMODE 0x1563 | ||
29 | #define PA_LEGACYDPHYESCDL 0x1570 | ||
30 | #define PA_MAXTXSPEEDFAST 0x1521 | ||
31 | #define PA_MAXTXSPEEDSLOW 0x1522 | ||
32 | #define PA_MAXRXSPEEDFAST 0x1541 | ||
33 | #define PA_MAXRXSPEEDSLOW 0x1542 | ||
34 | #define PA_TXLINKSTARTUPHS 0x1544 | ||
35 | #define PA_TXSPEEDFAST 0x1565 | ||
36 | #define PA_TXSPEEDSLOW 0x1566 | ||
37 | #define PA_REMOTEVERINFO 0x15A0 | ||
38 | #define PA_TXGEAR 0x1568 | ||
39 | #define PA_TXTERMINATION 0x1569 | ||
40 | #define PA_HSSERIES 0x156A | ||
41 | #define PA_PWRMODE 0x1571 | ||
42 | #define PA_RXGEAR 0x1583 | ||
43 | #define PA_RXTERMINATION 0x1584 | ||
44 | #define PA_MAXRXPWMGEAR 0x1586 | ||
45 | #define PA_MAXRXHSGEAR 0x1587 | ||
46 | #define PA_RXHSUNTERMCAP 0x15A5 | ||
47 | #define PA_RXLSTERMCAP 0x15A6 | ||
48 | #define PA_PACPREQTIMEOUT 0x1590 | ||
49 | #define PA_PACPREQEOBTIMEOUT 0x1591 | ||
50 | #define PA_HIBERN8TIME 0x15A7 | ||
51 | #define PA_LOCALVERINFO 0x15A9 | ||
52 | #define PA_TACTIVATE 0x15A8 | ||
53 | #define PA_PACPFRAMECOUNT 0x15C0 | ||
54 | #define PA_PACPERRORCOUNT 0x15C1 | ||
55 | #define PA_PHYTESTCONTROL 0x15C2 | ||
56 | #define PA_PWRMODEUSERDATA0 0x15B0 | ||
57 | #define PA_PWRMODEUSERDATA1 0x15B1 | ||
58 | #define PA_PWRMODEUSERDATA2 0x15B2 | ||
59 | #define PA_PWRMODEUSERDATA3 0x15B3 | ||
60 | #define PA_PWRMODEUSERDATA4 0x15B4 | ||
61 | #define PA_PWRMODEUSERDATA5 0x15B5 | ||
62 | #define PA_PWRMODEUSERDATA6 0x15B6 | ||
63 | #define PA_PWRMODEUSERDATA7 0x15B7 | ||
64 | #define PA_PWRMODEUSERDATA8 0x15B8 | ||
65 | #define PA_PWRMODEUSERDATA9 0x15B9 | ||
66 | #define PA_PWRMODEUSERDATA10 0x15BA | ||
67 | #define PA_PWRMODEUSERDATA11 0x15BB | ||
68 | #define PA_CONNECTEDTXDATALANES 0x1561 | ||
69 | #define PA_CONNECTEDRXDATALANES 0x1581 | ||
70 | #define PA_LOGICALLANEMAP 0x15A1 | ||
71 | #define PA_SLEEPNOCONFIGTIME 0x15A2 | ||
72 | #define PA_STALLNOCONFIGTIME 0x15A3 | ||
73 | #define PA_SAVECONFIGTIME 0x15A4 | ||
74 | |||
75 | /* | ||
76 | * Data Link Layer Attributes | ||
77 | */ | ||
78 | #define DL_TC0TXFCTHRESHOLD 0x2040 | ||
79 | #define DL_FC0PROTTIMEOUTVAL 0x2041 | ||
80 | #define DL_TC0REPLAYTIMEOUTVAL 0x2042 | ||
81 | #define DL_AFC0REQTIMEOUTVAL 0x2043 | ||
82 | #define DL_AFC0CREDITTHRESHOLD 0x2044 | ||
83 | #define DL_TC0OUTACKTHRESHOLD 0x2045 | ||
84 | #define DL_TC1TXFCTHRESHOLD 0x2060 | ||
85 | #define DL_FC1PROTTIMEOUTVAL 0x2061 | ||
86 | #define DL_TC1REPLAYTIMEOUTVAL 0x2062 | ||
87 | #define DL_AFC1REQTIMEOUTVAL 0x2063 | ||
88 | #define DL_AFC1CREDITTHRESHOLD 0x2064 | ||
89 | #define DL_TC1OUTACKTHRESHOLD 0x2065 | ||
90 | #define DL_TXPREEMPTIONCAP 0x2000 | ||
91 | #define DL_TC0TXMAXSDUSIZE 0x2001 | ||
92 | #define DL_TC0RXINITCREDITVAL 0x2002 | ||
93 | #define DL_TC0TXBUFFERSIZE 0x2005 | ||
94 | #define DL_PEERTC0PRESENT 0x2046 | ||
95 | #define DL_PEERTC0RXINITCREVAL 0x2047 | ||
96 | #define DL_TC1TXMAXSDUSIZE 0x2003 | ||
97 | #define DL_TC1RXINITCREDITVAL 0x2004 | ||
98 | #define DL_TC1TXBUFFERSIZE 0x2006 | ||
99 | #define DL_PEERTC1PRESENT 0x2066 | ||
100 | #define DL_PEERTC1RXINITCREVAL 0x2067 | ||
101 | |||
102 | /* | ||
103 | * Network Layer Attributes | ||
104 | */ | ||
105 | #define N_DEVICEID 0x3000 | ||
106 | #define N_DEVICEID_VALID 0x3001 | ||
107 | #define N_TC0TXMAXSDUSIZE 0x3020 | ||
108 | #define N_TC1TXMAXSDUSIZE 0x3021 | ||
109 | |||
110 | /* | ||
111 | * Transport Layer Attributes | ||
112 | */ | ||
113 | #define T_NUMCPORTS 0x4000 | ||
114 | #define T_NUMTESTFEATURES 0x4001 | ||
115 | #define T_CONNECTIONSTATE 0x4020 | ||
116 | #define T_PEERDEVICEID 0x4021 | ||
117 | #define T_PEERCPORTID 0x4022 | ||
118 | #define T_TRAFFICCLASS 0x4023 | ||
119 | #define T_PROTOCOLID 0x4024 | ||
120 | #define T_CPORTFLAGS 0x4025 | ||
121 | #define T_TXTOKENVALUE 0x4026 | ||
122 | #define T_RXTOKENVALUE 0x4027 | ||
123 | #define T_LOCALBUFFERSPACE 0x4028 | ||
124 | #define T_PEERBUFFERSPACE 0x4029 | ||
125 | #define T_CREDITSTOSEND 0x402A | ||
126 | #define T_CPORTMODE 0x402B | ||
127 | #define T_TC0TXMAXSDUSIZE 0x4060 | ||
128 | #define T_TC1TXMAXSDUSIZE 0x4061 | ||
129 | |||
130 | #endif /* _UNIPRO_H_ */ | ||