1 // SPDX-License-Identifier: GPL-2.0
2 /* Copyright(c) 2007 - 2011 Realtek Corporation. */
3
4 #include "../include/HalPwrSeqCmd.h"
5
6 #define PWR_CMD_WRITE 0x01
7 /* offset: the read register offset */
8 /* msk: the mask of the write bits */
9 /* value: write value */
10 /* note: driver shall implement this cmd by read & msk after write */
11
12 #define PWR_CMD_POLLING 0x02
13 /* offset: the read register offset */
14 /* msk: the mask of the polled value */
15 /* value: the value to be polled, masked by the msd field. */
16 /* note: driver shall implement this cmd by */
17 /* do{ */
18 /* if ( (Read(offset) & msk) == (value & msk) ) */
19 /* break; */
20 /* } while (not timeout); */
21
22 #define PWR_CMD_DELAY 0x03
23 /* offset: the value to delay (in us) */
24 /* msk: N/A */
25 /* value: N/A */
26
27 struct wl_pwr_cfg {
28 u16 offset;
29 u8 cmd:4;
30 u8 msk;
31 u8 value;
32 };
33
34 #define GET_PWR_CFG_OFFSET(__PWR_CMD) __PWR_CMD.offset
35 #define GET_PWR_CFG_CMD(__PWR_CMD) __PWR_CMD.cmd
36 #define GET_PWR_CFG_MASK(__PWR_CMD) __PWR_CMD.msk
37 #define GET_PWR_CFG_VALUE(__PWR_CMD) __PWR_CMD.value
38
39 static struct wl_pwr_cfg rtl8188E_power_on_flow[] = {
40 { 0x0006, PWR_CMD_POLLING, BIT(1), BIT(1) },
41 { 0x0002, PWR_CMD_WRITE, BIT(0) | BIT(1), 0 }, /* reset BB */
42 { 0x0026, PWR_CMD_WRITE, BIT(7), BIT(7) }, /* schmitt trigger */
43 { 0x0005, PWR_CMD_WRITE, BIT(7), 0 }, /* disable HWPDN (control by DRV)*/
44 { 0x0005, PWR_CMD_WRITE, BIT(4) | BIT(3), 0 }, /* disable WL suspend*/
45 { 0x0005, PWR_CMD_WRITE, BIT(0), BIT(0) },
46 { 0x0005, PWR_CMD_POLLING, BIT(0), 0 },
47 { 0x0023, PWR_CMD_WRITE, BIT(4), 0 },
48 };
49
50 static struct wl_pwr_cfg rtl8188E_card_disable_flow[] = {
51 { 0x001F, PWR_CMD_WRITE, 0xFF, 0 }, /* turn off RF */
52 { 0x0023, PWR_CMD_WRITE, BIT(4), BIT(4) }, /* LDO Sleep mode */
53 { 0x0005, PWR_CMD_WRITE, BIT(1), BIT(1) }, /* turn off MAC by HW state machine */
54 { 0x0005, PWR_CMD_POLLING, BIT(1), 0 },
55 { 0x0026, PWR_CMD_WRITE, BIT(7), BIT(7) }, /* schmitt trigger */
56 { 0x0005, PWR_CMD_WRITE, BIT(3) | BIT(4), BIT(3) }, /* enable WL suspend */
57 { 0x0007, PWR_CMD_WRITE, 0xFF, 0 }, /* enable bandgap mbias in suspend */
58 { 0x0041, PWR_CMD_WRITE, BIT(4), 0 }, /* Clear SIC_EN register */
59 { 0xfe10, PWR_CMD_WRITE, BIT(4), BIT(4) }, /* Set USB suspend enable local register */
60 };
61
62 /* This is used by driver for LPSRadioOff Procedure, not for FW LPS Step */
63 static struct wl_pwr_cfg rtl8188E_enter_lps_flow[] = {
64 { 0x0522, PWR_CMD_WRITE, 0xFF, 0x7F },/* Tx Pause */
65 { 0x05F8, PWR_CMD_POLLING, 0xFF, 0 }, /* Should be zero if no packet is transmitted */
66 { 0x05F9, PWR_CMD_POLLING, 0xFF, 0 }, /* Should be zero if no packet is transmitted */
67 { 0x05FA, PWR_CMD_POLLING, 0xFF, 0 }, /* Should be zero if no packet is transmitted */
68 { 0x05FB, PWR_CMD_POLLING, 0xFF, 0 }, /* Should be zero if no packet is transmitted */
69 { 0x0002, PWR_CMD_WRITE, BIT(0), 0 }, /* CCK and OFDM are disabled, clocks are gated */
70 { 0x0002, PWR_CMD_DELAY, 0, 0 },
71 { 0x0100, PWR_CMD_WRITE, 0xFF, 0x3F }, /* Reset MAC TRX */
72 { 0x0101, PWR_CMD_WRITE, BIT(1), 0 }, /* check if removed later */
73 { 0x0553, PWR_CMD_WRITE, BIT(5), BIT(5) }, /* Respond TxOK to scheduler */
74 };
75
HalPwrSeqCmdParsing(struct adapter * padapter,enum r8188eu_pwr_seq seq)76 u8 HalPwrSeqCmdParsing(struct adapter *padapter, enum r8188eu_pwr_seq seq)
77 {
78 struct wl_pwr_cfg pwrcfgcmd = {0};
79 struct wl_pwr_cfg *pwrseqcmd;
80 u8 poll_bit = false;
81 u8 idx, num_steps;
82 u8 value = 0;
83 u32 offset = 0;
84 u32 poll_count = 0; /* polling autoload done. */
85 u32 max_poll_count = 5000;
86 int res;
87
88 switch (seq) {
89 case PWR_ON_FLOW:
90 pwrseqcmd = rtl8188E_power_on_flow;
91 num_steps = ARRAY_SIZE(rtl8188E_power_on_flow);
92 break;
93 case DISABLE_FLOW:
94 pwrseqcmd = rtl8188E_card_disable_flow;
95 num_steps = ARRAY_SIZE(rtl8188E_card_disable_flow);
96 break;
97 case LPS_ENTER_FLOW:
98 pwrseqcmd = rtl8188E_enter_lps_flow;
99 num_steps = ARRAY_SIZE(rtl8188E_enter_lps_flow);
100 break;
101 default:
102 return false;
103 }
104
105 for (idx = 0; idx < num_steps; idx++) {
106 pwrcfgcmd = pwrseqcmd[idx];
107
108 switch (GET_PWR_CFG_CMD(pwrcfgcmd)) {
109 case PWR_CMD_WRITE:
110 offset = GET_PWR_CFG_OFFSET(pwrcfgcmd);
111
112 /* Read the value from system register */
113 res = rtw_read8(padapter, offset, &value);
114 if (res)
115 return false;
116
117 value &= ~(GET_PWR_CFG_MASK(pwrcfgcmd));
118 value |= (GET_PWR_CFG_VALUE(pwrcfgcmd) & GET_PWR_CFG_MASK(pwrcfgcmd));
119
120 /* Write the value back to system register */
121 rtw_write8(padapter, offset, value);
122 break;
123 case PWR_CMD_POLLING:
124 poll_bit = false;
125 offset = GET_PWR_CFG_OFFSET(pwrcfgcmd);
126 do {
127 res = rtw_read8(padapter, offset, &value);
128 if (res)
129 return false;
130
131 value &= GET_PWR_CFG_MASK(pwrcfgcmd);
132 if (value == (GET_PWR_CFG_VALUE(pwrcfgcmd) & GET_PWR_CFG_MASK(pwrcfgcmd)))
133 poll_bit = true;
134 else
135 udelay(10);
136
137 if (poll_count++ > max_poll_count)
138 return false;
139 } while (!poll_bit);
140 break;
141 case PWR_CMD_DELAY:
142 udelay(GET_PWR_CFG_OFFSET(pwrcfgcmd));
143 break;
144 default:
145 break;
146 }
147 }
148 return true;
149 }
150