1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
|
/*
* Standard Host Controller definitions.
*
* Copyright (C) 2007 Cambridge Silicon Radio Ltd.
*
* Refer to LICENSE.txt included with this source code for details on
* the license terms.
*/
#ifndef _SLOT_SHC_H
#define _SLOT_SHC_H
#include <oska/io.h>
/* SHC registers */
#define SHC_SYSTEM_ADDRESS 0x00
#define SHC_BLOCK_SIZE 0x04
# define SHC_BLOCK_SIZE_DMA_BOUNDARY_4K (0x0 << 12)
# define SHC_BLOCK_SIZE_DMA_BOUNDARY_512K (0x7 << 12)
#define SHC_BLOCK_COUNT 0x06
#define SHC_ARG 0x08
#define SHC_TRANSFER_MODE 0x0c
# define SHC_TRANSFER_MODE_DMA_EN 0x0001
# define SHC_TRANSFER_MODE_BLK_CNT_EN 0x0002
# define SHC_TRANSFER_MODE_AUTO_CMD12_EN 0x0004
# define SHC_TRANSFER_MODE_DATA_READ 0x0010
# define SHC_TRANSFER_MODE_MULTI_BLK 0x0020
#define SHC_CMD 0x0e
# define SHC_CMD_RESP_NONE 0x0000
# define SHC_CMD_RESP_136 0x0001
# define SHC_CMD_RESP_48 0x0002
# define SHC_CMD_RESP_48B 0x0003
# define SHC_CMD_RESP_CRC_CHK 0x0008
# define SHC_CMD_RESP_IDX_CHK 0x0010
# define SHC_CMD_DATA_PRESENT 0x0020
# define SHC_CMD_TYPE_ABORT (0x3 << 6)
# define SHC_CMD_IDX(c) ((c) << 8)
#define SHC_RESPONSE_0_31 0x10
#define SHC_BUFFER_DATA_PORT 0x20
#define SHC_PRESENT_STATE 0x24
# define SHC_PRESENT_STATE_CMD_INHIBIT 0x00000001
# define SHC_PRESENT_STATE_DAT_INHIBIT 0x00000002
# define SHC_PRESENT_STATE_CARD_PRESENT 0x00010000
#define SHC_HOST_CTRL 0x28
# define SHC_HOST_CTRL_LED_ON 0x01
# define SHC_HOST_CTRL_4BIT 0x02
# define SHC_HOST_CTRL_HIGH_SPD_EN 0x04
#define SHC_PWR_CTRL 0x29
# define SHC_PWR_CTRL_3V3 0x0e
# define SHC_PWR_CTRL_ON 0x01
#define SHC_BLOCK_GAP_CTRL 0x2a
#define SHC_WAKEUP_CTRL 0x2b
#define SHC_CLOCK_CTRL 0x2c
# define SHC_CLOCK_CTRL_INT_CLK_EN 0x01
# define SHC_CLOCK_CTRL_INT_CLK_STABLE 0x02
# define SHC_CLOCK_CTRL_SD_CLK_EN 0x04
# define SHC_CLOCK_CTRL_DIV(d) (((d) >> 1) << 8) /* divisor must be power of 2 */
#define SHC_TIMEOUT_CTRL 0x2e
# define SHC_TIMEOUT_CTRL_MAX 0x0e
#define SHC_SOFTWARE_RST 0x2f
# define SHC_SOFTWARE_RST_ALL 0x01
# define SHC_SOFTWARE_RST_CMD 0x02
# define SHC_SOFTWARE_RST_DAT 0x04
#define SHC_INT_STATUS 0x30
#define SHC_INT_STATUS_EN 0x34
#define SHC_INT_SIGNAL_EN 0x38
# define SHC_INT_CMD_COMPLETE 0x00000001
# define SHC_INT_TRANSFER_COMPLETE 0x00000002
# define SHC_INT_BLOCK_GAP 0x00000004
# define SHC_INT_DMA 0x00000008
# define SHC_INT_WR_BUF_RDY 0x00000010
# define SHC_INT_RD_BUF_RDY 0x00000020
# define SHC_INT_CARD_INSERTED 0x00000040
# define SHC_INT_CARD_REMOVED 0x00000080
# define SHC_INT_CARD_INT 0x00000100
# define SHC_INT_ERR_ANY 0x00008000
# define SHC_INT_ERR_CMD_TIMEOUT 0x00010000
# define SHC_INT_ERR_CMD_CRC 0x00020000
# define SHC_INT_ERR_CMD_ENDBIT 0x00040000
# define SHC_INT_ERR_CMD_INDEX 0x00080000
# define SHC_INT_ERR_CMD_ALL 0x000f0000
# define SHC_INT_ERR_DAT_TIMEOUT 0x00100000
# define SHC_INT_ERR_DAT_CRC 0x00200000
# define SHC_INT_ERR_DAT_ENDBIT 0x00400000
# define SHC_INT_ERR_DAT_ALL 0x00700000
# define SHC_INT_ERR_CURRENT_LIMIT 0x00800000
# define SHC_INT_ERR_AUTO_CMD12 0x01000000
# define SHC_INT_ERR_ALL 0x01ff0000
# define SHC_INT_ALL 0x01ff81ff
#define SHC_AUTO_CMD12_STATUS 0x3c
#define SHC_CAPS 0x40
# define SHC_CAPS_TO_BASE_CLK_FREQ(c) (((c) & 0x00003f00) >> 8)
# define SHC_CAPS_PWR_3V3 (1 << 24)
#define SHC_MAX_CURRENT_CAPS 0x4c
/* PCI configuration registers. */
#define PCI_SHC_SLOT_INFO 0x40
/* Maximum time to wait for a software reset. */
#define SHC_RESET_TIMEOUT_MS 100 /* ms */
/* Maximum time to wait for internal clock to stabilize */
#define SHC_INT_CLK_STABLE_TIMEOUT_MS 100
/*
* No supported voltages in the capabilities register.
*
* Workaround: Assume 3.3V is supported.
*/
#define SLOT_SHC_QUIRK_NO_VOLTAGE_CAPS (1 << 0)
/*
* Commands with an R5B (busy) response do not complete.
*
* Workaround: Use R5 instead. This will only work if the busy signal
* is cleared sufficiently quickly before the next command is started.
*/
#define SLOT_SHC_QUIRK_R5B_BROKEN (1 << 1)
/*
* High speed mode doesn't work.
*
* Workaround: limit maximum bus frequency to 25 MHz.
*/
#define SLOT_SHC_QUIRK_HIGH_SPD_BROKEN (1 << 2)
/*
* Data timeout (TIMEOUT_CTRL) uses SDCLK and not TMCLK.
*
* Workaround: set TIMEOUT_CTRL using SDCLK.
*/
#define SLOT_SHC_QUIRK_DATA_TIMEOUT_USES_SDCLK (1 << 3)
/*
* Controller can only start DMA on dword (32 bit) aligned addresses.
*
* Workaround: PIO is used on data transfers with a non-dword aligned
* address.
*/
#define SHC_QUIRK_DMA_NEEDS_DWORD_ALIGNED_ADDR (1 << 4)
/*
* Controller is unreliable following multiple transfers
*
* Workaround: The controller is reset following every command, not just
* erroneous ones
*/
#define SHC_QUIRK_RESET_EVERY_CMD_COMPLETE (1 << 5)
/*
* JMicron JMB381 to JMB385 controllers require some non-standard PCI
* config space writes.
*/
#define SHC_QUIRK_JMICRON_JMB38X (1 << 6)
/*
* Controller can only do DMA if the length is a whole number of
* dwords.
*
* Controller with this quirk probably also need
* SHC_QUIRK_DMA_NEEDS_DWORD_ALIGNED_ADDR.
*
* Workaround: PIO is used on data transfers that don't end on an
* aligned address.
*/
#define SHC_QUIRK_DMA_NEEDS_DWORD_ALIGNED_LEN (1 << 7)
struct sdioemb_shc {
struct sdioemb_slot *slot;
void (*enable_int)(struct sdioemb_slot *slot, uint32_t ints);
void (*disable_int)(struct sdioemb_slot *slot, uint32_t ints);
void (*cmd_complete)(struct sdioemb_slot *slot, struct sdioemb_cmd *cmd);
uint32_t quirks;
os_io_mem_t addr;
os_spinlock_t lock;
os_timer_t lockup_timer;
uint32_t base_clk;
struct sdioemb_cmd *current_cmd;
uint8_t *data;
size_t remaining;
size_t block_size;
};
void sdioemb_shc_init(struct sdioemb_shc *shc);
void sdioemb_shc_clean_up(struct sdioemb_shc *shc);
int sdioemb_shc_start(struct sdioemb_shc *shc);
void sdioemb_shc_stop(struct sdioemb_shc *shc);
bool sdioemb_shc_isr(struct sdioemb_shc *shc, uint32_t *int_stat);
void sdioemb_shc_dsr(struct sdioemb_shc *shc, uint32_t int_stat);
int sdioemb_shc_set_bus_freq(struct sdioemb_shc *shc, int clk);
int sdioemb_shc_set_bus_width(struct sdioemb_shc *shc, int bus_width);
int sdioemb_shc_start_cmd(struct sdioemb_shc *shc, struct sdioemb_cmd *cmd,
bool use_dma, uint64_t dma_addr);
int sdioemb_shc_card_present(struct sdioemb_shc *shc);
int sdioemb_shc_card_power(struct sdioemb_shc *shc, enum sdioemb_power power);
void sdioemb_shc_enable_card_int(struct sdioemb_shc *shc);
void sdioemb_shc_disable_card_int(struct sdioemb_shc *shc);
int sdioemb_shc_hard_reset(struct sdioemb_shc *shc);
void sdioemb_shc_show_quirks(struct sdioemb_shc *shc);
#endif /* #ifndef _SLOT_SHC_H */
|