1*1349a733SJaeyoon Choi /*-
2*1349a733SJaeyoon Choi * Copyright (c) 2025, Samsung Electronics Co., Ltd.
3*1349a733SJaeyoon Choi * Written by Jaeyoon Choi
4*1349a733SJaeyoon Choi *
5*1349a733SJaeyoon Choi * SPDX-License-Identifier: BSD-2-Clause
6*1349a733SJaeyoon Choi */
7*1349a733SJaeyoon Choi
8*1349a733SJaeyoon Choi #include <sys/param.h>
9*1349a733SJaeyoon Choi #include <sys/bus.h>
10*1349a733SJaeyoon Choi #include <sys/conf.h>
11*1349a733SJaeyoon Choi
12*1349a733SJaeyoon Choi #include "ufshci_private.h"
13*1349a733SJaeyoon Choi #include "ufshci_reg.h"
14*1349a733SJaeyoon Choi
15*1349a733SJaeyoon Choi static int
ufshci_dev_read_descriptor(struct ufshci_controller * ctrlr,enum ufshci_descriptor_type desc_type,uint8_t index,uint8_t selector,void * desc,size_t desc_size)16*1349a733SJaeyoon Choi ufshci_dev_read_descriptor(struct ufshci_controller *ctrlr,
17*1349a733SJaeyoon Choi enum ufshci_descriptor_type desc_type, uint8_t index, uint8_t selector,
18*1349a733SJaeyoon Choi void *desc, size_t desc_size)
19*1349a733SJaeyoon Choi {
20*1349a733SJaeyoon Choi struct ufshci_completion_poll_status status;
21*1349a733SJaeyoon Choi struct ufshci_query_param param;
22*1349a733SJaeyoon Choi
23*1349a733SJaeyoon Choi param.function = UFSHCI_QUERY_FUNC_STANDARD_READ_REQUEST;
24*1349a733SJaeyoon Choi param.opcode = UFSHCI_QUERY_OPCODE_READ_DESCRIPTOR;
25*1349a733SJaeyoon Choi param.type = desc_type;
26*1349a733SJaeyoon Choi param.index = index;
27*1349a733SJaeyoon Choi param.selector = selector;
28*1349a733SJaeyoon Choi param.value = 0;
29*1349a733SJaeyoon Choi param.desc_size = desc_size;
30*1349a733SJaeyoon Choi
31*1349a733SJaeyoon Choi status.done = 0;
32*1349a733SJaeyoon Choi ufshci_ctrlr_cmd_send_query_request(ctrlr, ufshci_completion_poll_cb,
33*1349a733SJaeyoon Choi &status, param);
34*1349a733SJaeyoon Choi ufshci_completion_poll(&status);
35*1349a733SJaeyoon Choi if (status.error) {
36*1349a733SJaeyoon Choi ufshci_printf(ctrlr, "ufshci_dev_read_descriptor failed!\n");
37*1349a733SJaeyoon Choi return (ENXIO);
38*1349a733SJaeyoon Choi }
39*1349a733SJaeyoon Choi
40*1349a733SJaeyoon Choi memcpy(desc, status.cpl.response_upiu.query_response_upiu.command_data,
41*1349a733SJaeyoon Choi desc_size);
42*1349a733SJaeyoon Choi
43*1349a733SJaeyoon Choi return (0);
44*1349a733SJaeyoon Choi }
45*1349a733SJaeyoon Choi
46*1349a733SJaeyoon Choi static int
ufshci_dev_read_device_descriptor(struct ufshci_controller * ctrlr,struct ufshci_device_descriptor * desc)47*1349a733SJaeyoon Choi ufshci_dev_read_device_descriptor(struct ufshci_controller *ctrlr,
48*1349a733SJaeyoon Choi struct ufshci_device_descriptor *desc)
49*1349a733SJaeyoon Choi {
50*1349a733SJaeyoon Choi return (ufshci_dev_read_descriptor(ctrlr, UFSHCI_DESC_TYPE_DEVICE, 0, 0,
51*1349a733SJaeyoon Choi desc, sizeof(struct ufshci_device_descriptor)));
52*1349a733SJaeyoon Choi }
53*1349a733SJaeyoon Choi
54*1349a733SJaeyoon Choi static int
ufshci_dev_read_geometry_descriptor(struct ufshci_controller * ctrlr,struct ufshci_geometry_descriptor * desc)55*1349a733SJaeyoon Choi ufshci_dev_read_geometry_descriptor(struct ufshci_controller *ctrlr,
56*1349a733SJaeyoon Choi struct ufshci_geometry_descriptor *desc)
57*1349a733SJaeyoon Choi {
58*1349a733SJaeyoon Choi return (ufshci_dev_read_descriptor(ctrlr, UFSHCI_DESC_TYPE_GEOMETRY, 0,
59*1349a733SJaeyoon Choi 0, desc, sizeof(struct ufshci_geometry_descriptor)));
60*1349a733SJaeyoon Choi }
61*1349a733SJaeyoon Choi
62*1349a733SJaeyoon Choi static int
ufshci_dev_read_flag(struct ufshci_controller * ctrlr,enum ufshci_flags flag_type,uint8_t * flag)63*1349a733SJaeyoon Choi ufshci_dev_read_flag(struct ufshci_controller *ctrlr,
64*1349a733SJaeyoon Choi enum ufshci_flags flag_type, uint8_t *flag)
65*1349a733SJaeyoon Choi {
66*1349a733SJaeyoon Choi struct ufshci_completion_poll_status status;
67*1349a733SJaeyoon Choi struct ufshci_query_param param;
68*1349a733SJaeyoon Choi
69*1349a733SJaeyoon Choi param.function = UFSHCI_QUERY_FUNC_STANDARD_READ_REQUEST;
70*1349a733SJaeyoon Choi param.opcode = UFSHCI_QUERY_OPCODE_READ_FLAG;
71*1349a733SJaeyoon Choi param.type = flag_type;
72*1349a733SJaeyoon Choi param.index = 0;
73*1349a733SJaeyoon Choi param.selector = 0;
74*1349a733SJaeyoon Choi param.value = 0;
75*1349a733SJaeyoon Choi
76*1349a733SJaeyoon Choi status.done = 0;
77*1349a733SJaeyoon Choi ufshci_ctrlr_cmd_send_query_request(ctrlr, ufshci_completion_poll_cb,
78*1349a733SJaeyoon Choi &status, param);
79*1349a733SJaeyoon Choi ufshci_completion_poll(&status);
80*1349a733SJaeyoon Choi if (status.error) {
81*1349a733SJaeyoon Choi ufshci_printf(ctrlr, "ufshci_dev_read_flag failed!\n");
82*1349a733SJaeyoon Choi return (ENXIO);
83*1349a733SJaeyoon Choi }
84*1349a733SJaeyoon Choi
85*1349a733SJaeyoon Choi *flag = status.cpl.response_upiu.query_response_upiu.flag_value;
86*1349a733SJaeyoon Choi
87*1349a733SJaeyoon Choi return (0);
88*1349a733SJaeyoon Choi }
89*1349a733SJaeyoon Choi
90*1349a733SJaeyoon Choi static int
ufshci_dev_set_flag(struct ufshci_controller * ctrlr,enum ufshci_flags flag_type)91*1349a733SJaeyoon Choi ufshci_dev_set_flag(struct ufshci_controller *ctrlr,
92*1349a733SJaeyoon Choi enum ufshci_flags flag_type)
93*1349a733SJaeyoon Choi {
94*1349a733SJaeyoon Choi struct ufshci_completion_poll_status status;
95*1349a733SJaeyoon Choi struct ufshci_query_param param;
96*1349a733SJaeyoon Choi
97*1349a733SJaeyoon Choi param.function = UFSHCI_QUERY_FUNC_STANDARD_WRITE_REQUEST;
98*1349a733SJaeyoon Choi param.opcode = UFSHCI_QUERY_OPCODE_SET_FLAG;
99*1349a733SJaeyoon Choi param.type = flag_type;
100*1349a733SJaeyoon Choi param.index = 0;
101*1349a733SJaeyoon Choi param.selector = 0;
102*1349a733SJaeyoon Choi param.value = 0;
103*1349a733SJaeyoon Choi
104*1349a733SJaeyoon Choi status.done = 0;
105*1349a733SJaeyoon Choi ufshci_ctrlr_cmd_send_query_request(ctrlr, ufshci_completion_poll_cb,
106*1349a733SJaeyoon Choi &status, param);
107*1349a733SJaeyoon Choi ufshci_completion_poll(&status);
108*1349a733SJaeyoon Choi if (status.error) {
109*1349a733SJaeyoon Choi ufshci_printf(ctrlr, "ufshci_dev_set_flag failed!\n");
110*1349a733SJaeyoon Choi return (ENXIO);
111*1349a733SJaeyoon Choi }
112*1349a733SJaeyoon Choi
113*1349a733SJaeyoon Choi return (0);
114*1349a733SJaeyoon Choi }
115*1349a733SJaeyoon Choi
116*1349a733SJaeyoon Choi static int
ufshci_dev_write_attribute(struct ufshci_controller * ctrlr,enum ufshci_attributes attr_type,uint8_t index,uint8_t selector,uint64_t value)117*1349a733SJaeyoon Choi ufshci_dev_write_attribute(struct ufshci_controller *ctrlr,
118*1349a733SJaeyoon Choi enum ufshci_attributes attr_type, uint8_t index, uint8_t selector,
119*1349a733SJaeyoon Choi uint64_t value)
120*1349a733SJaeyoon Choi {
121*1349a733SJaeyoon Choi struct ufshci_completion_poll_status status;
122*1349a733SJaeyoon Choi struct ufshci_query_param param;
123*1349a733SJaeyoon Choi
124*1349a733SJaeyoon Choi param.function = UFSHCI_QUERY_FUNC_STANDARD_WRITE_REQUEST;
125*1349a733SJaeyoon Choi param.opcode = UFSHCI_QUERY_OPCODE_WRITE_ATTRIBUTE;
126*1349a733SJaeyoon Choi param.type = attr_type;
127*1349a733SJaeyoon Choi param.index = index;
128*1349a733SJaeyoon Choi param.selector = selector;
129*1349a733SJaeyoon Choi param.value = value;
130*1349a733SJaeyoon Choi
131*1349a733SJaeyoon Choi status.done = 0;
132*1349a733SJaeyoon Choi ufshci_ctrlr_cmd_send_query_request(ctrlr, ufshci_completion_poll_cb,
133*1349a733SJaeyoon Choi &status, param);
134*1349a733SJaeyoon Choi ufshci_completion_poll(&status);
135*1349a733SJaeyoon Choi if (status.error) {
136*1349a733SJaeyoon Choi ufshci_printf(ctrlr, "ufshci_dev_write_attribute failed!\n");
137*1349a733SJaeyoon Choi return (ENXIO);
138*1349a733SJaeyoon Choi }
139*1349a733SJaeyoon Choi
140*1349a733SJaeyoon Choi return (0);
141*1349a733SJaeyoon Choi }
142*1349a733SJaeyoon Choi
143*1349a733SJaeyoon Choi int
ufshci_dev_init(struct ufshci_controller * ctrlr)144*1349a733SJaeyoon Choi ufshci_dev_init(struct ufshci_controller *ctrlr)
145*1349a733SJaeyoon Choi {
146*1349a733SJaeyoon Choi int timeout = ticks + MSEC_2_TICKS(ctrlr->device_init_timeout_in_ms);
147*1349a733SJaeyoon Choi sbintime_t delta_t = SBT_1US;
148*1349a733SJaeyoon Choi uint8_t flag;
149*1349a733SJaeyoon Choi int error;
150*1349a733SJaeyoon Choi const uint8_t device_init_completed = 0;
151*1349a733SJaeyoon Choi
152*1349a733SJaeyoon Choi error = ufshci_dev_set_flag(ctrlr, UFSHCI_FLAG_F_DEVICE_INIT);
153*1349a733SJaeyoon Choi if (error)
154*1349a733SJaeyoon Choi return (error);
155*1349a733SJaeyoon Choi
156*1349a733SJaeyoon Choi /* Wait for the UFSHCI_FLAG_F_DEVICE_INIT flag to change */
157*1349a733SJaeyoon Choi while (1) {
158*1349a733SJaeyoon Choi error = ufshci_dev_read_flag(ctrlr, UFSHCI_FLAG_F_DEVICE_INIT,
159*1349a733SJaeyoon Choi &flag);
160*1349a733SJaeyoon Choi if (error)
161*1349a733SJaeyoon Choi return (error);
162*1349a733SJaeyoon Choi if (flag == device_init_completed)
163*1349a733SJaeyoon Choi break;
164*1349a733SJaeyoon Choi if (timeout - ticks < 0) {
165*1349a733SJaeyoon Choi ufshci_printf(ctrlr,
166*1349a733SJaeyoon Choi "device init did not become %d "
167*1349a733SJaeyoon Choi "within %d ms\n",
168*1349a733SJaeyoon Choi device_init_completed,
169*1349a733SJaeyoon Choi ctrlr->device_init_timeout_in_ms);
170*1349a733SJaeyoon Choi return (ENXIO);
171*1349a733SJaeyoon Choi }
172*1349a733SJaeyoon Choi
173*1349a733SJaeyoon Choi pause_sbt("ufshciinit", delta_t, 0, C_PREL(1));
174*1349a733SJaeyoon Choi delta_t = min(SBT_1MS, delta_t * 3 / 2);
175*1349a733SJaeyoon Choi }
176*1349a733SJaeyoon Choi
177*1349a733SJaeyoon Choi return (0);
178*1349a733SJaeyoon Choi }
179*1349a733SJaeyoon Choi
180*1349a733SJaeyoon Choi int
ufshci_dev_reset(struct ufshci_controller * ctrlr)181*1349a733SJaeyoon Choi ufshci_dev_reset(struct ufshci_controller *ctrlr)
182*1349a733SJaeyoon Choi {
183*1349a733SJaeyoon Choi if (ufshci_uic_send_dme_endpoint_reset(ctrlr))
184*1349a733SJaeyoon Choi return (ENXIO);
185*1349a733SJaeyoon Choi
186*1349a733SJaeyoon Choi return (ufshci_dev_init(ctrlr));
187*1349a733SJaeyoon Choi }
188*1349a733SJaeyoon Choi
189*1349a733SJaeyoon Choi int
ufshci_dev_init_reference_clock(struct ufshci_controller * ctrlr)190*1349a733SJaeyoon Choi ufshci_dev_init_reference_clock(struct ufshci_controller *ctrlr)
191*1349a733SJaeyoon Choi {
192*1349a733SJaeyoon Choi int error;
193*1349a733SJaeyoon Choi uint8_t index, selector;
194*1349a733SJaeyoon Choi
195*1349a733SJaeyoon Choi index = 0; /* bRefClkFreq is device type attribute */
196*1349a733SJaeyoon Choi selector = 0; /* bRefClkFreq is device type attribute */
197*1349a733SJaeyoon Choi
198*1349a733SJaeyoon Choi error = ufshci_dev_write_attribute(ctrlr, UFSHCI_ATTR_B_REF_CLK_FREQ,
199*1349a733SJaeyoon Choi index, selector, ctrlr->ref_clk);
200*1349a733SJaeyoon Choi if (error)
201*1349a733SJaeyoon Choi return (error);
202*1349a733SJaeyoon Choi
203*1349a733SJaeyoon Choi return (0);
204*1349a733SJaeyoon Choi }
205*1349a733SJaeyoon Choi
206*1349a733SJaeyoon Choi int
ufshci_dev_init_unipro(struct ufshci_controller * ctrlr)207*1349a733SJaeyoon Choi ufshci_dev_init_unipro(struct ufshci_controller *ctrlr)
208*1349a733SJaeyoon Choi {
209*1349a733SJaeyoon Choi uint32_t pa_granularity, peer_pa_granularity;
210*1349a733SJaeyoon Choi uint32_t t_activate, pear_t_activate;
211*1349a733SJaeyoon Choi
212*1349a733SJaeyoon Choi /*
213*1349a733SJaeyoon Choi * Unipro Version:
214*1349a733SJaeyoon Choi * - 7~15 = Above 2.0, 6 = 2.0, 5 = 1.8, 4 = 1.61, 3 = 1.6, 2 = 1.41,
215*1349a733SJaeyoon Choi * 1 = 1.40, 0 = Reserved
216*1349a733SJaeyoon Choi */
217*1349a733SJaeyoon Choi if (ufshci_uic_send_dme_get(ctrlr, PA_LocalVerInfo,
218*1349a733SJaeyoon Choi &ctrlr->unipro_version))
219*1349a733SJaeyoon Choi return (ENXIO);
220*1349a733SJaeyoon Choi if (ufshci_uic_send_dme_get(ctrlr, PA_RemoteVerInfo,
221*1349a733SJaeyoon Choi &ctrlr->ufs_dev.unipro_version))
222*1349a733SJaeyoon Choi return (ENXIO);
223*1349a733SJaeyoon Choi
224*1349a733SJaeyoon Choi /*
225*1349a733SJaeyoon Choi * PA_Granularity: Granularity for PA_TActivate and PA_Hibern8Time
226*1349a733SJaeyoon Choi * - 1=1us, 2=4us, 3=8us, 4=16us, 5=32us, 6=100us
227*1349a733SJaeyoon Choi */
228*1349a733SJaeyoon Choi if (ufshci_uic_send_dme_get(ctrlr, PA_Granularity, &pa_granularity))
229*1349a733SJaeyoon Choi return (ENXIO);
230*1349a733SJaeyoon Choi if (ufshci_uic_send_dme_peer_get(ctrlr, PA_Granularity,
231*1349a733SJaeyoon Choi &peer_pa_granularity))
232*1349a733SJaeyoon Choi return (ENXIO);
233*1349a733SJaeyoon Choi
234*1349a733SJaeyoon Choi /*
235*1349a733SJaeyoon Choi * PA_TActivate: Time to wait before activating a burst in order to
236*1349a733SJaeyoon Choi * wake-up peer M-RX
237*1349a733SJaeyoon Choi * UniPro automatically sets timing information such as PA_TActivate
238*1349a733SJaeyoon Choi * through the PACP_CAP_EXT1_ind command during Link Startup operation.
239*1349a733SJaeyoon Choi */
240*1349a733SJaeyoon Choi if (ufshci_uic_send_dme_get(ctrlr, PA_TActivate, &t_activate))
241*1349a733SJaeyoon Choi return (ENXIO);
242*1349a733SJaeyoon Choi if (ufshci_uic_send_dme_peer_get(ctrlr, PA_TActivate, &pear_t_activate))
243*1349a733SJaeyoon Choi return (ENXIO);
244*1349a733SJaeyoon Choi
245*1349a733SJaeyoon Choi if (ctrlr->quirks & UFSHCI_QUIRK_LONG_PEER_PA_TACTIVATE) {
246*1349a733SJaeyoon Choi /*
247*1349a733SJaeyoon Choi * Intel Lake-field UFSHCI has a quirk. We need to add 200us to
248*1349a733SJaeyoon Choi * the PEER's PA_TActivate.
249*1349a733SJaeyoon Choi */
250*1349a733SJaeyoon Choi if (pa_granularity == peer_pa_granularity) {
251*1349a733SJaeyoon Choi pear_t_activate = t_activate + 2;
252*1349a733SJaeyoon Choi if (ufshci_uic_send_dme_peer_set(ctrlr, PA_TActivate,
253*1349a733SJaeyoon Choi pear_t_activate))
254*1349a733SJaeyoon Choi return (ENXIO);
255*1349a733SJaeyoon Choi }
256*1349a733SJaeyoon Choi }
257*1349a733SJaeyoon Choi
258*1349a733SJaeyoon Choi return (0);
259*1349a733SJaeyoon Choi }
260*1349a733SJaeyoon Choi
261*1349a733SJaeyoon Choi int
ufshci_dev_init_uic_power_mode(struct ufshci_controller * ctrlr)262*1349a733SJaeyoon Choi ufshci_dev_init_uic_power_mode(struct ufshci_controller *ctrlr)
263*1349a733SJaeyoon Choi {
264*1349a733SJaeyoon Choi /* HSSerise: A = 1, B = 2 */
265*1349a733SJaeyoon Choi const uint32_t hs_series = 2;
266*1349a733SJaeyoon Choi /*
267*1349a733SJaeyoon Choi * TX/RX PWRMode:
268*1349a733SJaeyoon Choi * - TX[3:0], RX[7:4]
269*1349a733SJaeyoon Choi * - Fast Mode = 1, Slow Mode = 2, FastAuto Mode = 4, SlowAuto Mode = 5
270*1349a733SJaeyoon Choi */
271*1349a733SJaeyoon Choi const uint32_t fast_mode = 1;
272*1349a733SJaeyoon Choi const uint32_t rx_bit_shift = 4;
273*1349a733SJaeyoon Choi const uint32_t power_mode = (fast_mode << rx_bit_shift) | fast_mode;
274*1349a733SJaeyoon Choi
275*1349a733SJaeyoon Choi /* Update lanes with available TX/RX lanes */
276*1349a733SJaeyoon Choi if (ufshci_uic_send_dme_get(ctrlr, PA_AvailTxDataLanes,
277*1349a733SJaeyoon Choi &ctrlr->max_tx_lanes))
278*1349a733SJaeyoon Choi return (ENXIO);
279*1349a733SJaeyoon Choi if (ufshci_uic_send_dme_get(ctrlr, PA_AvailRxDataLanes,
280*1349a733SJaeyoon Choi &ctrlr->max_rx_lanes))
281*1349a733SJaeyoon Choi return (ENXIO);
282*1349a733SJaeyoon Choi
283*1349a733SJaeyoon Choi /* Get max HS-GEAR value */
284*1349a733SJaeyoon Choi if (ufshci_uic_send_dme_get(ctrlr, PA_MaxRxHSGear,
285*1349a733SJaeyoon Choi &ctrlr->max_rx_hs_gear))
286*1349a733SJaeyoon Choi return (ENXIO);
287*1349a733SJaeyoon Choi
288*1349a733SJaeyoon Choi /* Set the data lane to max */
289*1349a733SJaeyoon Choi ctrlr->tx_lanes = ctrlr->max_tx_lanes;
290*1349a733SJaeyoon Choi ctrlr->rx_lanes = ctrlr->max_rx_lanes;
291*1349a733SJaeyoon Choi if (ufshci_uic_send_dme_set(ctrlr, PA_ActiveTxDataLanes,
292*1349a733SJaeyoon Choi ctrlr->tx_lanes))
293*1349a733SJaeyoon Choi return (ENXIO);
294*1349a733SJaeyoon Choi if (ufshci_uic_send_dme_set(ctrlr, PA_ActiveRxDataLanes,
295*1349a733SJaeyoon Choi ctrlr->rx_lanes))
296*1349a733SJaeyoon Choi return (ENXIO);
297*1349a733SJaeyoon Choi
298*1349a733SJaeyoon Choi /* Set HS-GEAR to max gear */
299*1349a733SJaeyoon Choi ctrlr->hs_gear = ctrlr->max_rx_hs_gear;
300*1349a733SJaeyoon Choi if (ufshci_uic_send_dme_set(ctrlr, PA_TxGear, ctrlr->hs_gear))
301*1349a733SJaeyoon Choi return (ENXIO);
302*1349a733SJaeyoon Choi if (ufshci_uic_send_dme_set(ctrlr, PA_RxGear, ctrlr->hs_gear))
303*1349a733SJaeyoon Choi return (ENXIO);
304*1349a733SJaeyoon Choi
305*1349a733SJaeyoon Choi /*
306*1349a733SJaeyoon Choi * Set termination
307*1349a733SJaeyoon Choi * - HS-MODE = ON / LS-MODE = OFF
308*1349a733SJaeyoon Choi */
309*1349a733SJaeyoon Choi if (ufshci_uic_send_dme_set(ctrlr, PA_TxTermination, true))
310*1349a733SJaeyoon Choi return (ENXIO);
311*1349a733SJaeyoon Choi if (ufshci_uic_send_dme_set(ctrlr, PA_RxTermination, true))
312*1349a733SJaeyoon Choi return (ENXIO);
313*1349a733SJaeyoon Choi
314*1349a733SJaeyoon Choi /* Set HSSerise (A = 1, B = 2) */
315*1349a733SJaeyoon Choi if (ufshci_uic_send_dme_set(ctrlr, PA_HSSeries, hs_series))
316*1349a733SJaeyoon Choi return (ENXIO);
317*1349a733SJaeyoon Choi
318*1349a733SJaeyoon Choi /* Set Timeout values */
319*1349a733SJaeyoon Choi if (ufshci_uic_send_dme_set(ctrlr, PA_PWRModeUserData0,
320*1349a733SJaeyoon Choi DL_FC0ProtectionTimeOutVal_Default))
321*1349a733SJaeyoon Choi return (ENXIO);
322*1349a733SJaeyoon Choi if (ufshci_uic_send_dme_set(ctrlr, PA_PWRModeUserData1,
323*1349a733SJaeyoon Choi DL_TC0ReplayTimeOutVal_Default))
324*1349a733SJaeyoon Choi return (ENXIO);
325*1349a733SJaeyoon Choi if (ufshci_uic_send_dme_set(ctrlr, PA_PWRModeUserData2,
326*1349a733SJaeyoon Choi DL_AFC0ReqTimeOutVal_Default))
327*1349a733SJaeyoon Choi return (ENXIO);
328*1349a733SJaeyoon Choi if (ufshci_uic_send_dme_set(ctrlr, PA_PWRModeUserData3,
329*1349a733SJaeyoon Choi DL_FC0ProtectionTimeOutVal_Default))
330*1349a733SJaeyoon Choi return (ENXIO);
331*1349a733SJaeyoon Choi if (ufshci_uic_send_dme_set(ctrlr, PA_PWRModeUserData4,
332*1349a733SJaeyoon Choi DL_TC0ReplayTimeOutVal_Default))
333*1349a733SJaeyoon Choi return (ENXIO);
334*1349a733SJaeyoon Choi if (ufshci_uic_send_dme_set(ctrlr, PA_PWRModeUserData5,
335*1349a733SJaeyoon Choi DL_AFC0ReqTimeOutVal_Default))
336*1349a733SJaeyoon Choi return (ENXIO);
337*1349a733SJaeyoon Choi
338*1349a733SJaeyoon Choi if (ufshci_uic_send_dme_set(ctrlr, DME_LocalFC0ProtectionTimeOutVal,
339*1349a733SJaeyoon Choi DL_FC0ProtectionTimeOutVal_Default))
340*1349a733SJaeyoon Choi return (ENXIO);
341*1349a733SJaeyoon Choi if (ufshci_uic_send_dme_set(ctrlr, DME_LocalTC0ReplayTimeOutVal,
342*1349a733SJaeyoon Choi DL_TC0ReplayTimeOutVal_Default))
343*1349a733SJaeyoon Choi return (ENXIO);
344*1349a733SJaeyoon Choi if (ufshci_uic_send_dme_set(ctrlr, DME_LocalAFC0ReqTimeOutVal,
345*1349a733SJaeyoon Choi DL_AFC0ReqTimeOutVal_Default))
346*1349a733SJaeyoon Choi return (ENXIO);
347*1349a733SJaeyoon Choi
348*1349a733SJaeyoon Choi /* Set TX/RX PWRMode */
349*1349a733SJaeyoon Choi if (ufshci_uic_send_dme_set(ctrlr, PA_PWRMode, power_mode))
350*1349a733SJaeyoon Choi return (ENXIO);
351*1349a733SJaeyoon Choi
352*1349a733SJaeyoon Choi /* Wait for power mode changed. */
353*1349a733SJaeyoon Choi if (ufshci_uic_power_mode_ready(ctrlr)) {
354*1349a733SJaeyoon Choi ufshci_reg_dump(ctrlr);
355*1349a733SJaeyoon Choi return (ENXIO);
356*1349a733SJaeyoon Choi }
357*1349a733SJaeyoon Choi
358*1349a733SJaeyoon Choi /* Clear 'Power Mode completion status' */
359*1349a733SJaeyoon Choi ufshci_mmio_write_4(ctrlr, is, UFSHCIM(UFSHCI_IS_REG_UPMS));
360*1349a733SJaeyoon Choi
361*1349a733SJaeyoon Choi if (ctrlr->quirks & UFSHCI_QUIRK_WAIT_AFTER_POWER_MODE_CHANGE) {
362*1349a733SJaeyoon Choi /*
363*1349a733SJaeyoon Choi * Intel Lake-field UFSHCI has a quirk.
364*1349a733SJaeyoon Choi * We need to wait 1250us and clear dme error.
365*1349a733SJaeyoon Choi */
366*1349a733SJaeyoon Choi pause_sbt("ufshci", ustosbt(1250), 0, C_PREL(1));
367*1349a733SJaeyoon Choi
368*1349a733SJaeyoon Choi /* Test with dme_peer_get to make sure there are no errors. */
369*1349a733SJaeyoon Choi if (ufshci_uic_send_dme_peer_get(ctrlr, PA_Granularity, NULL))
370*1349a733SJaeyoon Choi return (ENXIO);
371*1349a733SJaeyoon Choi }
372*1349a733SJaeyoon Choi
373*1349a733SJaeyoon Choi return (0);
374*1349a733SJaeyoon Choi }
375*1349a733SJaeyoon Choi
376*1349a733SJaeyoon Choi int
ufshci_dev_init_ufs_power_mode(struct ufshci_controller * ctrlr)377*1349a733SJaeyoon Choi ufshci_dev_init_ufs_power_mode(struct ufshci_controller *ctrlr)
378*1349a733SJaeyoon Choi {
379*1349a733SJaeyoon Choi /* TODO: Need to implement */
380*1349a733SJaeyoon Choi
381*1349a733SJaeyoon Choi return (0);
382*1349a733SJaeyoon Choi }
383*1349a733SJaeyoon Choi
384*1349a733SJaeyoon Choi int
ufshci_dev_get_descriptor(struct ufshci_controller * ctrlr)385*1349a733SJaeyoon Choi ufshci_dev_get_descriptor(struct ufshci_controller *ctrlr)
386*1349a733SJaeyoon Choi {
387*1349a733SJaeyoon Choi struct ufshci_device *device = &ctrlr->ufs_dev;
388*1349a733SJaeyoon Choi /*
389*1349a733SJaeyoon Choi * The kDeviceDensityUnit is defined in the spec as 512.
390*1349a733SJaeyoon Choi * qTotalRawDeviceCapacity use big-endian byte ordering.
391*1349a733SJaeyoon Choi */
392*1349a733SJaeyoon Choi const uint32_t device_density_unit = 512;
393*1349a733SJaeyoon Choi uint32_t ver;
394*1349a733SJaeyoon Choi int error;
395*1349a733SJaeyoon Choi
396*1349a733SJaeyoon Choi error = ufshci_dev_read_device_descriptor(ctrlr, &device->dev_desc);
397*1349a733SJaeyoon Choi if (error)
398*1349a733SJaeyoon Choi return (error);
399*1349a733SJaeyoon Choi
400*1349a733SJaeyoon Choi ver = be16toh(device->dev_desc.wSpecVersion);
401*1349a733SJaeyoon Choi ufshci_printf(ctrlr, "UFS device spec version %u.%u%u\n",
402*1349a733SJaeyoon Choi UFSHCIV(UFSHCI_VER_REG_MJR, ver), UFSHCIV(UFSHCI_VER_REG_MNR, ver),
403*1349a733SJaeyoon Choi UFSHCIV(UFSHCI_VER_REG_VS, ver));
404*1349a733SJaeyoon Choi ufshci_printf(ctrlr, "%u enabled LUNs found\n",
405*1349a733SJaeyoon Choi device->dev_desc.bNumberLU);
406*1349a733SJaeyoon Choi
407*1349a733SJaeyoon Choi error = ufshci_dev_read_geometry_descriptor(ctrlr, &device->geo_desc);
408*1349a733SJaeyoon Choi if (error)
409*1349a733SJaeyoon Choi return (error);
410*1349a733SJaeyoon Choi
411*1349a733SJaeyoon Choi if (device->geo_desc.bMaxNumberLU == 0) {
412*1349a733SJaeyoon Choi device->max_lun_count = 8;
413*1349a733SJaeyoon Choi } else if (device->geo_desc.bMaxNumberLU == 1) {
414*1349a733SJaeyoon Choi device->max_lun_count = 32;
415*1349a733SJaeyoon Choi } else {
416*1349a733SJaeyoon Choi ufshci_printf(ctrlr,
417*1349a733SJaeyoon Choi "Invalid Geometry Descriptor bMaxNumberLU value=%d\n",
418*1349a733SJaeyoon Choi device->geo_desc.bMaxNumberLU);
419*1349a733SJaeyoon Choi return (ENXIO);
420*1349a733SJaeyoon Choi }
421*1349a733SJaeyoon Choi ctrlr->max_lun_count = device->max_lun_count;
422*1349a733SJaeyoon Choi
423*1349a733SJaeyoon Choi ufshci_printf(ctrlr, "UFS device total size is %lu bytes\n",
424*1349a733SJaeyoon Choi be64toh(device->geo_desc.qTotalRawDeviceCapacity) *
425*1349a733SJaeyoon Choi device_density_unit);
426*1349a733SJaeyoon Choi
427*1349a733SJaeyoon Choi return (0);
428*1349a733SJaeyoon Choi }
429