sdiotool.c (531c2d7af3cd2e64eec94aa1b19c4b2f16fce515) sdiotool.c (029c02a3ae427d24da090c91e5728fcc7c293d2c)
1/*-
2 * Copyright (c) 2016-2017 Ilya Bakulin
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright

--- 9 unchanged lines hidden (view full) ---

18 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24 * SUCH DAMAGE.
25 *
1/*-
2 * Copyright (c) 2016-2017 Ilya Bakulin
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright

--- 9 unchanged lines hidden (view full) ---

18 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24 * SUCH DAMAGE.
25 *
26 * Copyright (c) 2010 Broadcom Corporation
27 *
28 * Permission to use, copy, modify, and/or distribute this software for any
29 * purpose with or without fee is hereby granted, provided that the above
30 * copyright notice and this permission notice appear in all copies.
31 *
32 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
33 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
34 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
35 * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
36 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
37 * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
38 * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
39 *
26 * $FreeBSD$
27 */
28
29#include <sys/cdefs.h>
30__FBSDID("$FreeBSD$");
31
32#include <sys/ioctl.h>
33#include <sys/stdint.h>

--- 16 unchanged lines hidden (view full) ---

50#include <unistd.h>
51
52#include <cam/cam.h>
53#include <cam/cam_debug.h>
54#include <cam/cam_ccb.h>
55#include <cam/mmc/mmc_all.h>
56#include <camlib.h>
57
40 * $FreeBSD$
41 */
42
43#include <sys/cdefs.h>
44__FBSDID("$FreeBSD$");
45
46#include <sys/ioctl.h>
47#include <sys/stdint.h>

--- 16 unchanged lines hidden (view full) ---

64#include <unistd.h>
65
66#include <cam/cam.h>
67#include <cam/cam_debug.h>
68#include <cam/cam_ccb.h>
69#include <cam/mmc/mmc_all.h>
70#include <camlib.h>
71
58struct cis_info {
59 uint16_t man_id;
60 uint16_t prod_id;
61 uint16_t max_block_size;
62};
72#include "linux_compat.h"
73#include "linux_sdio_compat.h"
74#include "cam_sdio.h"
75#include "brcmfmac_sdio.h"
76#include "brcmfmac_bus.h"
63
77
64static int sdio_rw_direct(struct cam_device *dev,
65 uint8_t func_number,
66 uint32_t addr,
67 uint8_t is_write,
68 uint8_t *data,
69 uint8_t *resp);
70static uint8_t sdio_read_1(struct cam_device *dev, uint8_t func_number, uint32_t addr);
71static void sdio_write_1(struct cam_device *dev, uint8_t func_number, uint32_t addr, uint8_t val);
72static int sdio_is_func_ready(struct cam_device *dev, uint8_t func_number, uint8_t *is_enab);
73static int sdio_is_func_enabled(struct cam_device *dev, uint8_t func_number, uint8_t *is_enab);
74static int sdio_func_enable(struct cam_device *dev, uint8_t func_number, int enable);
75static int sdio_is_func_intr_enabled(struct cam_device *dev, uint8_t func_number, uint8_t *is_enab);
76static int sdio_func_intr_enable(struct cam_device *dev, uint8_t func_number, int enable);
77static void sdio_card_reset(struct cam_device *dev);
78static uint32_t sdio_get_common_cis_addr(struct cam_device *dev);
79static void probe_bcrm(struct cam_device *dev);
80
78static void probe_bcrm(struct cam_device *dev);
79
81/* Use CMD52 to read or write a single byte */
82int
83sdio_rw_direct(struct cam_device *dev,
84 uint8_t func_number,
85 uint32_t addr,
86 uint8_t is_write,
87 uint8_t *data, uint8_t *resp) {
88 union ccb *ccb;
89 uint32_t flags;
90 uint32_t arg;
91 int retval = 0;
92
93 ccb = cam_getccb(dev);
94 if (ccb == NULL) {
95 warnx("%s: error allocating CCB", __func__);
96 return (1);
97 }
98 bzero(&(&ccb->ccb_h)[1],
99 sizeof(union ccb) - sizeof(struct ccb_hdr));
100
101 flags = MMC_RSP_R5 | MMC_CMD_AC;
102 arg = SD_IO_RW_FUNC(func_number) | SD_IO_RW_ADR(addr);
103 if (is_write)
104 arg |= SD_IO_RW_WR | SD_IO_RW_RAW | SD_IO_RW_DAT(*data);
105
106 cam_fill_mmcio(&ccb->mmcio,
107 /*retries*/ 0,
108 /*cbfcnp*/ NULL,
109 /*flags*/ CAM_DIR_NONE,
110 /*mmc_opcode*/ SD_IO_RW_DIRECT,
111 /*mmc_arg*/ arg,
112 /*mmc_flags*/ flags,
113 /*mmc_data*/ 0,
114 /*timeout*/ 5000);
115
116 if (((retval = cam_send_ccb(dev, ccb)) < 0)
117 || ((ccb->ccb_h.status & CAM_STATUS_MASK) != CAM_REQ_CMP)) {
118 const char warnstr[] = "error sending command";
119
120 if (retval < 0)
121 warn(warnstr);
122 else
123 warnx(warnstr);
124 return (-1);
125 }
126
127 *resp = ccb->mmcio.cmd.resp[0] & 0xFF;
128 cam_freeccb(ccb);
129 return (retval);
130}
131
132#if 0
133/*
80/*
134 * CMD53 -- IO_RW_EXTENDED
135 * Use to read or write memory blocks
136 *
137 * is_increment=1: FIFO mode
138 * blk_count > 0: block mode
139 */
140int
141sdio_rw_extended(struct cam_device *dev,
142 uint8_t func_number,
143 uint32_t addr,
144 uint8_t is_write,
145 uint8_t *data, size_t datalen,
146 uint8_t is_increment,
147 uint16_t blk_count) {
148 union ccb *ccb;
149 uint32_t flags;
150 uint32_t arg;
151 int retval = 0;
152
153 if (blk_count != 0) {
154 warnx("%s: block mode is not supported yet", __func__);
155 return (1);
156 }
157
158 ccb = cam_getccb(dev);
159 if (ccb == NULL) {
160 warnx("%s: error allocating CCB", __func__);
161 return (1);
162 }
163 bzero(&(&ccb->ccb_h)[1],
164 sizeof(union ccb) - sizeof(struct ccb_hdr));
165
166 flags = MMC_RSP_R5 | MMC_CMD_AC;
167 arg = SD_IO_RW_FUNC(func_number) | SD_IO_RW_ADR(addr);
168 if (is_write)
169 arg |= SD_IO_RW_WR;
170
171 cam_fill_mmcio(&ccb->mmcio,
172 /*retries*/ 0,
173 /*cbfcnp*/ NULL,
174 /*flags*/ CAM_DIR_NONE,
175 /*mmc_opcode*/ SD_IO_RW_DIRECT,
176 /*mmc_arg*/ arg,
177 /*mmc_flags*/ flags,
178 /*mmc_data*/ 0,
179 /*timeout*/ 5000);
180
181 if (((retval = cam_send_ccb(dev, ccb)) < 0)
182 || ((ccb->ccb_h.status & CAM_STATUS_MASK) != CAM_REQ_CMP)) {
183 const char warnstr[] = "error sending command";
184
185 if (retval < 0)
186 warn(warnstr);
187 else
188 warnx(warnstr);
189 return (-1);
190 }
191
192 *resp = ccb->mmcio.cmd.resp[0] & 0xFF;
193 cam_freeccb(ccb);
194 return (retval);
195}
196#endif
197
198static int
199sdio_read_bool_for_func(struct cam_device *dev, uint32_t addr, uint8_t func_number, uint8_t *is_enab) {
200 uint8_t resp;
201 int ret;
202
203 ret = sdio_rw_direct(dev, 0, addr, 0, NULL, &resp);
204 if (ret < 0)
205 return ret;
206
207 *is_enab = (resp & (1 << func_number)) > 0 ? 1 : 0;
208
209 return (0);
210}
211
212static int
213sdio_set_bool_for_func(struct cam_device *dev, uint32_t addr, uint8_t func_number, int enable) {
214 uint8_t resp;
215 int ret;
216 uint8_t is_enabled;
217
218 ret = sdio_rw_direct(dev, 0, addr, 0, NULL, &resp);
219 if (ret != 0)
220 return ret;
221
222 is_enabled = resp & (1 << func_number);
223 if ((is_enabled !=0 && enable == 1) || (is_enabled == 0 && enable == 0))
224 return 0;
225
226 if (enable)
227 resp |= 1 << func_number;
228 else
229 resp &= ~ (1 << func_number);
230
231 ret = sdio_rw_direct(dev, 0, addr, 1, &resp, &resp);
232
233 return ret;
234}
235
236static uint8_t
237sdio_read_1(struct cam_device *dev, uint8_t func_number, uint32_t addr) {
238 uint8_t val;
239 sdio_rw_direct(dev, func_number, addr, 0, NULL, &val);
240 return val;
241}
242
243__unused static void
244sdio_write_1(struct cam_device *dev, uint8_t func_number, uint32_t addr, uint8_t val) {
245 uint8_t _val;
246 sdio_rw_direct(dev, func_number, addr, 0, &val, &_val);
247}
248
249static int
250sdio_is_func_ready(struct cam_device *dev, uint8_t func_number, uint8_t *is_enab) {
251 return sdio_read_bool_for_func(dev, SD_IO_CCCR_FN_READY, func_number, is_enab);
252}
253
254static int
255sdio_is_func_enabled(struct cam_device *dev, uint8_t func_number, uint8_t *is_enab) {
256 return sdio_read_bool_for_func(dev, SD_IO_CCCR_FN_ENABLE, func_number, is_enab);
257}
258
259static int
260sdio_func_enable(struct cam_device *dev, uint8_t func_number, int enable) {
261 return sdio_set_bool_for_func(dev, SD_IO_CCCR_FN_ENABLE, func_number, enable);
262}
263
264static int
265sdio_is_func_intr_enabled(struct cam_device *dev, uint8_t func_number, uint8_t *is_enab) {
266 return sdio_read_bool_for_func(dev, SD_IO_CCCR_INT_ENABLE, func_number, is_enab);
267}
268
269static int
270sdio_func_intr_enable(struct cam_device *dev, uint8_t func_number, int enable) {
271 return sdio_set_bool_for_func(dev, SD_IO_CCCR_INT_ENABLE, func_number, enable);
272}
273
274static int
275sdio_card_set_bus_width(struct cam_device *dev, enum mmc_bus_width bw) {
276 int ret;
277 uint8_t ctl_val;
278 ret = sdio_rw_direct(dev, 0, SD_IO_CCCR_BUS_WIDTH, 0, NULL, &ctl_val);
279 if (ret < 0) {
280 warn("Error getting CCCR_BUS_WIDTH value");
281 return ret;
282 }
283 ctl_val &= ~0x3;
284 switch (bw) {
285 case bus_width_1:
286 /* Already set to 1-bit */
287 break;
288 case bus_width_4:
289 ctl_val |= CCCR_BUS_WIDTH_4;
290 break;
291 case bus_width_8:
292 warn("Cannot do 8-bit on SDIO yet");
293 return -1;
294 break;
295 }
296 ret = sdio_rw_direct(dev, 0, SD_IO_CCCR_BUS_WIDTH, 1, &ctl_val, &ctl_val);
297 if (ret < 0) {
298 warn("Error setting CCCR_BUS_WIDTH value");
299 return ret;
300 }
301 return ret;
302}
303
304static int
305sdio_func_read_cis(struct cam_device *dev, uint8_t func_number,
306 uint32_t cis_addr, struct cis_info *info) {
307 uint8_t tuple_id, tuple_len, tuple_count;
308 uint32_t addr;
309
310 char *cis1_info[4];
311 int start, i, ch, count;
312 char cis1_info_buf[256];
313
314 tuple_count = 0; /* Use to prevent infinite loop in case of parse errors */
315 memset(cis1_info_buf, 0, 256);
316 do {
317 addr = cis_addr;
318 tuple_id = sdio_read_1(dev, 0, addr++);
319 if (tuple_id == SD_IO_CISTPL_END)
320 break;
321 if (tuple_id == 0) {
322 cis_addr++;
323 continue;
324 }
325 tuple_len = sdio_read_1(dev, 0, addr++);
326 if (tuple_len == 0 && tuple_id != 0x00) {
327 warn("Parse error: 0-length tuple %02X\n", tuple_id);
328 return -1;
329 }
330
331 switch (tuple_id) {
332 case SD_IO_CISTPL_VERS_1:
333 addr += 2;
334 for (count = 0, start = 0, i = 0;
335 (count < 4) && ((i + 4) < 256); i++) {
336 ch = sdio_read_1(dev, 0, addr + i);
337 printf("count=%d, start=%d, i=%d, Got %c (0x%02x)\n", count, start, i, ch, ch);
338 if (ch == 0xff)
339 break;
340 cis1_info_buf[i] = ch;
341 if (ch == 0) {
342 cis1_info[count] =
343 cis1_info_buf + start;
344 start = i + 1;
345 count++;
346 }
347 }
348 printf("Card info:");
349 for (i=0; i<4; i++)
350 if (cis1_info[i])
351 printf(" %s", cis1_info[i]);
352 printf("\n");
353 break;
354 case SD_IO_CISTPL_MANFID:
355 info->man_id = sdio_read_1(dev, 0, addr++);
356 info->man_id |= sdio_read_1(dev, 0, addr++) << 8;
357
358 info->prod_id = sdio_read_1(dev, 0, addr++);
359 info->prod_id |= sdio_read_1(dev, 0, addr++) << 8;
360 break;
361 case SD_IO_CISTPL_FUNCID:
362 /* not sure if we need to parse it? */
363 break;
364 case SD_IO_CISTPL_FUNCE:
365 if (tuple_len < 4) {
366 printf("FUNCE is too short: %d\n", tuple_len);
367 break;
368 }
369 if (func_number == 0) {
370 /* skip extended_data */
371 addr++;
372 info->max_block_size = sdio_read_1(dev, 0, addr++);
373 info->max_block_size |= sdio_read_1(dev, 0, addr++) << 8;
374 } else {
375 info->max_block_size = sdio_read_1(dev, 0, addr + 0xC);
376 info->max_block_size |= sdio_read_1(dev, 0, addr + 0xD) << 8;
377 }
378 break;
379 default:
380 printf("Skipping tuple ID %02X len %02X\n", tuple_id, tuple_len);
381 }
382 cis_addr += tuple_len + 2;
383 tuple_count++;
384 } while (tuple_count < 20);
385
386 return 0;
387}
388
389static uint32_t
390sdio_get_common_cis_addr(struct cam_device *dev) {
391 uint32_t addr;
392
393 addr = sdio_read_1(dev, 0, SD_IO_CCCR_CISPTR);
394 addr |= sdio_read_1(dev, 0, SD_IO_CCCR_CISPTR + 1) << 8;
395 addr |= sdio_read_1(dev, 0, SD_IO_CCCR_CISPTR + 2) << 16;
396
397 if (addr < SD_IO_CIS_START || addr > SD_IO_CIS_START + SD_IO_CIS_SIZE) {
398 warn("Bad CIS address: %04X\n", addr);
399 addr = 0;
400 }
401
402 return addr;
403}
404
405static void sdio_card_reset(struct cam_device *dev) {
406 int ret;
407 uint8_t ctl_val;
408 ret = sdio_rw_direct(dev, 0, SD_IO_CCCR_CTL, 0, NULL, &ctl_val);
409 if (ret < 0)
410 errx(1, "Error getting CCCR_CTL value");
411 ctl_val |= CCCR_CTL_RES;
412 ret = sdio_rw_direct(dev, 0, SD_IO_CCCR_CTL, 1, &ctl_val, &ctl_val);
413 if (ret < 0)
414 errx(1, "Error setting CCCR_CTL value");
415}
416
417/*
418 * How Linux driver works
419 *
420 * The probing begins by calling brcmf_ops_sdio_probe() which is defined as probe function in struct sdio_driver. http://lxr.free-electrons.com/source/drivers/net/wireless/broadcom/brcm80211/brcmfmac/bcmsdh.c#L1126
421 *
422 * The driver does black magic by copying func struct for F2 and setting func number to zero there, to create an F0 func structure :)
423 * Driver state changes to BRCMF_SDIOD_DOWN.
424 * ops_sdio_probe() then calls brcmf_sdio_probe() -- at this point it has filled in sdiodev struct with the pointers to all three functions (F0, F1, F2).
425 *

--- 63 unchanged lines hidden (view full) ---

489 * Based on the address it figures out where to read it from (CCCR / FBR in F0, or somewhere in F1).
490 * Reads are retried three times.
491 * 1-byte IO is done with CMD52, more is read with CMD53 with address increment (not FIFO mode).
492 * http://lxr.free-electrons.com/source/drivers/mmc/core/sdio_io.c#L458
493 * ==================================
494 *
495 *
496 */
81 * How Linux driver works
82 *
83 * The probing begins by calling brcmf_ops_sdio_probe() which is defined as probe function in struct sdio_driver. http://lxr.free-electrons.com/source/drivers/net/wireless/broadcom/brcm80211/brcmfmac/bcmsdh.c#L1126
84 *
85 * The driver does black magic by copying func struct for F2 and setting func number to zero there, to create an F0 func structure :)
86 * Driver state changes to BRCMF_SDIOD_DOWN.
87 * ops_sdio_probe() then calls brcmf_sdio_probe() -- at this point it has filled in sdiodev struct with the pointers to all three functions (F0, F1, F2).
88 *

--- 63 unchanged lines hidden (view full) ---

152 * Based on the address it figures out where to read it from (CCCR / FBR in F0, or somewhere in F1).
153 * Reads are retried three times.
154 * 1-byte IO is done with CMD52, more is read with CMD53 with address increment (not FIFO mode).
155 * http://lxr.free-electrons.com/source/drivers/mmc/core/sdio_io.c#L458
156 * ==================================
157 *
158 *
159 */
160
161/* BRCM-specific functions */
162#define SDIOH_API_ACCESS_RETRY_LIMIT 2
163#define SI_ENUM_BASE 0x18000000
164#define REPLY_MAGIC 0x16044330
165#define brcmf_err(fmt, ...) brcmf_dbg(0, fmt, ##__VA_ARGS__)
166#define brcmf_dbg(level, fmt, ...) printf(fmt, ##__VA_ARGS__)
167
168struct brcmf_sdio_dev {
169 struct cam_device *cam_dev;
170 u32 sbwad; /* Save backplane window address */
171 struct brcmf_bus *bus_if;
172 enum brcmf_sdiod_state state;
173 struct sdio_func *func[8];
174};
175
176void brcmf_bus_change_state(struct brcmf_bus *bus, enum brcmf_bus_state state);
177void brcmf_sdiod_change_state(struct brcmf_sdio_dev *sdiodev,
178 enum brcmf_sdiod_state state);
179static int brcmf_sdiod_request_data(struct brcmf_sdio_dev *sdiodev, u8 fn, u32 addr,
180 u8 regsz, void *data, bool write);
181static int brcmf_sdiod_set_sbaddr_window(struct brcmf_sdio_dev *sdiodev, u32 address);
182static int brcmf_sdiod_addrprep(struct brcmf_sdio_dev *sdiodev, uint width, u32 *addr);
183u32 brcmf_sdiod_regrl(struct brcmf_sdio_dev *sdiodev, u32 addr, int *ret);
184
185static void bailout(int ret);
186
187static void
188bailout(int ret) {
189 if (ret == 0)
190 return;
191 errx(1, "Operation returned error %d", ret);
192}
193
194void
195brcmf_bus_change_state(struct brcmf_bus *bus, enum brcmf_bus_state state)
196{
197 bus->state = state;
198}
199
200void brcmf_sdiod_change_state(struct brcmf_sdio_dev *sdiodev,
201 enum brcmf_sdiod_state state)
202{
203 if (sdiodev->state == BRCMF_SDIOD_NOMEDIUM ||
204 state == sdiodev->state)
205 return;
206
207 //brcmf_dbg(TRACE, "%d -> %d\n", sdiodev->state, state);
208 switch (sdiodev->state) {
209 case BRCMF_SDIOD_DATA:
210 /* any other state means bus interface is down */
211 brcmf_bus_change_state(sdiodev->bus_if, BRCMF_BUS_DOWN);
212 break;
213 case BRCMF_SDIOD_DOWN:
214 /* transition from DOWN to DATA means bus interface is up */
215 if (state == BRCMF_SDIOD_DATA)
216 brcmf_bus_change_state(sdiodev->bus_if, BRCMF_BUS_UP);
217 break;
218 default:
219 break;
220 }
221 sdiodev->state = state;
222}
223
224static inline int brcmf_sdiod_f0_writeb(struct sdio_func *func,
225 uint regaddr, u8 byte) {
226 int err_ret;
227
228 /*
229 * Can only directly write to some F0 registers.
230 * Handle CCCR_IENx and CCCR_ABORT command
231 * as a special case.
232 */
233 if ((regaddr == SDIO_CCCR_ABORT) ||
234 (regaddr == SDIO_CCCR_IENx))
235 sdio_writeb(func, byte, regaddr, &err_ret);
236 else
237 sdio_f0_writeb(func, byte, regaddr, &err_ret);
238
239 return err_ret;
240}
241
242static int brcmf_sdiod_request_data(struct brcmf_sdio_dev *sdiodev, u8 fn, u32 addr, u8 regsz, void *data, bool write)
243{
244 struct sdio_func *func;
245 int ret = -EINVAL;
246
247 brcmf_dbg(SDIO, "rw=%d, func=%d, addr=0x%05x, nbytes=%d\n",
248 write, fn, addr, regsz);
249
250 /* only allow byte access on F0 */
251 if (WARN_ON(regsz > 1 && !fn))
252 return -EINVAL;
253 func = sdiodev->func[fn];
254
255 switch (regsz) {
256 case sizeof(u8):
257 if (write) {
258 if (fn)
259 sdio_writeb(func, *(u8 *)data, addr, &ret);
260 else
261 ret = brcmf_sdiod_f0_writeb(func, addr,
262 *(u8 *)data);
263 } else {
264 if (fn)
265 *(u8 *)data = sdio_readb(func, addr, &ret);
266 else
267 *(u8 *)data = sdio_f0_readb(func, addr, &ret);
268 }
269 break;
270 case sizeof(u16):
271 if (write)
272 sdio_writew(func, *(u16 *)data, addr, &ret);
273 else
274 *(u16 *)data = sdio_readw(func, addr, &ret);
275 break;
276 case sizeof(u32):
277 if (write)
278 sdio_writel(func, *(u32 *)data, addr, &ret);
279 else
280 *(u32 *)data = sdio_readl(func, addr, &ret);
281 break;
282 default:
283 brcmf_err("invalid size: %d\n", regsz);
284 break;
285 }
286
287 if (ret)
288 brcmf_dbg(SDIO, "failed to %s data F%d@0x%05x, err: %d\n",
289 write ? "write" : "read", fn, addr, ret);
290
291 return ret;
292}
293
294static int
295brcmf_sdiod_addrprep(struct brcmf_sdio_dev *sdiodev, uint width, u32 *addr)
296{
297 uint bar0 = *addr & ~SBSDIO_SB_OFT_ADDR_MASK;
298 int err = 0;
299
300 if (bar0 != sdiodev->sbwad) {
301 err = brcmf_sdiod_set_sbaddr_window(sdiodev, bar0);
302 if (err)
303 return err;
304
305 sdiodev->sbwad = bar0;
306 }
307
308 *addr &= SBSDIO_SB_OFT_ADDR_MASK;
309
310 if (width == 4)
311 *addr |= SBSDIO_SB_ACCESS_2_4B_FLAG;
312
313 return 0;
314}
315
316static int brcmf_sdiod_regrw_helper(struct brcmf_sdio_dev *sdiodev, u32 addr, u8 regsz, void *data, bool write) {
317 u8 func;
318 s32 retry = 0;
319 int ret;
320
321 if (sdiodev->state == BRCMF_SDIOD_NOMEDIUM)
322 return -ENOMEDIUM;
323
324 /*
325 * figure out how to read the register based on address range
326 * 0x00 ~ 0x7FF: function 0 CCCR and FBR
327 * 0x10000 ~ 0x1FFFF: function 1 miscellaneous registers
328 * The rest: function 1 silicon backplane core registers
329 */
330 if ((addr & ~REG_F0_REG_MASK) == 0)
331 func = SDIO_FUNC_0;
332 else
333 func = SDIO_FUNC_1;
334
335 do {
336 if (!write)
337 memset(data, 0, regsz);
338 /* for retry wait for 1 ms till bus get settled down */
339 if (retry)
340 usleep_range(1000, 2000);
341 ret = brcmf_sdiod_request_data(sdiodev, func, addr, regsz,
342 data, write);
343 } while (ret != 0 && ret != -ENOMEDIUM &&
344 retry++ < SDIOH_API_ACCESS_RETRY_LIMIT);
345
346 if (ret == -ENOMEDIUM)
347 brcmf_sdiod_change_state(sdiodev, BRCMF_SDIOD_NOMEDIUM);
348 else if (ret != 0) {
349 /*
350 * SleepCSR register access can fail when
351 * waking up the device so reduce this noise
352 * in the logs.
353 */
354 if (addr != SBSDIO_FUNC1_SLEEPCSR)
355 brcmf_err("failed to %s data F%d@0x%05x, err: %d\n",
356 write ? "write" : "read", func, addr, ret);
357 else
358 brcmf_dbg(SDIO, "failed to %s data F%d@0x%05x, err: %d\n",
359 write ? "write" : "read", func, addr, ret);
360 }
361 return ret;
362}
363
364static int
365brcmf_sdiod_set_sbaddr_window(struct brcmf_sdio_dev *sdiodev, u32 address)
366{
367 int err = 0, i;
368 u8 addr[3];
369
370 if (sdiodev->state == BRCMF_SDIOD_NOMEDIUM)
371 return -ENOMEDIUM;
372
373 addr[0] = (address >> 8) & SBSDIO_SBADDRLOW_MASK;
374 addr[1] = (address >> 16) & SBSDIO_SBADDRMID_MASK;
375 addr[2] = (address >> 24) & SBSDIO_SBADDRHIGH_MASK;
376
377 for (i = 0; i < 3; i++) {
378 err = brcmf_sdiod_regrw_helper(sdiodev,
379 SBSDIO_FUNC1_SBADDRLOW + i,
380 sizeof(u8), &addr[i], true);
381 if (err) {
382 brcmf_err("failed at addr: 0x%0x\n",
383 SBSDIO_FUNC1_SBADDRLOW + i);
384 break;
385 }
386 }
387
388 return err;
389}
390
391u32 brcmf_sdiod_regrl(struct brcmf_sdio_dev *sdiodev, u32 addr, int *ret)
392{
393 u32 data = 0;
394 int retval;
395
396 brcmf_dbg(SDIO, "addr:0x%08x\n", addr);
397 retval = brcmf_sdiod_addrprep(sdiodev, sizeof(data), &addr);
398 if (retval)
399 goto done;
400 retval = brcmf_sdiod_regrw_helper(sdiodev, addr, sizeof(data), &data,
401 false);
402 brcmf_dbg(SDIO, "data:0x%08x\n", data);
403
404done:
405 if (ret)
406 *ret = retval;
407
408 return data;
409}
410
411/********************************************************/
497__unused
498static void
499probe_bcrm(struct cam_device *dev) {
500 uint32_t cis_addr;
501 struct cis_info info;
502
503 sdio_card_set_bus_width(dev, bus_width_4);
504 cis_addr = sdio_get_common_cis_addr(dev);
505 printf("CIS address: %04X\n", cis_addr);
506
507 memset(&info, 0, sizeof(info));
508 sdio_func_read_cis(dev, 0, cis_addr, &info);
509 printf("Vendor 0x%04X product 0x%04X\n", info.man_id, info.prod_id);
510}
412__unused
413static void
414probe_bcrm(struct cam_device *dev) {
415 uint32_t cis_addr;
416 struct cis_info info;
417
418 sdio_card_set_bus_width(dev, bus_width_4);
419 cis_addr = sdio_get_common_cis_addr(dev);
420 printf("CIS address: %04X\n", cis_addr);
421
422 memset(&info, 0, sizeof(info));
423 sdio_func_read_cis(dev, 0, cis_addr, &info);
424 printf("Vendor 0x%04X product 0x%04X\n", info.man_id, info.prod_id);
425}
511__unused
512static uint8_t *
426
427__unused static uint8_t*
513mmap_fw() {
514 const char fw_path[] = "/home/kibab/repos/fbsd-bbb/brcm-firmware/brcmfmac4330-sdio.bin";
515 struct stat sb;
516 uint8_t *fw_ptr;
517
518 int fd = open(fw_path, O_RDONLY);
519 if (fd < 0)
520 errx(1, "Cannot open firmware file");

--- 7 unchanged lines hidden (view full) ---

528}
529
530static void
531usage() {
532 printf("sdiotool -u <pass_dev_unit>\n");
533 exit(0);
534}
535
428mmap_fw() {
429 const char fw_path[] = "/home/kibab/repos/fbsd-bbb/brcm-firmware/brcmfmac4330-sdio.bin";
430 struct stat sb;
431 uint8_t *fw_ptr;
432
433 int fd = open(fw_path, O_RDONLY);
434 if (fd < 0)
435 errx(1, "Cannot open firmware file");

--- 7 unchanged lines hidden (view full) ---

443}
444
445static void
446usage() {
447 printf("sdiotool -u <pass_dev_unit>\n");
448 exit(0);
449}
450
451struct card_info {
452 uint8_t num_funcs;
453 struct cis_info f[8];
454};
455
456/*
457 * TODO: We should add SDIO card info about at least number of
458 * available functions to struct cam_device and use it instead
459 * of checking for man_id = 0x00 for detecting number of functions
460 */
536static void
461static void
537get_sdio_card_info(struct cam_device *dev) {
462get_sdio_card_info(struct cam_device *dev, struct card_info *ci) {
538 uint32_t cis_addr;
539 uint32_t fbr_addr;
463 uint32_t cis_addr;
464 uint32_t fbr_addr;
540 struct cis_info info;
465 int ret;
541
542 cis_addr = sdio_get_common_cis_addr(dev);
543
466
467 cis_addr = sdio_get_common_cis_addr(dev);
468
544 memset(&info, 0, sizeof(info));
545 sdio_func_read_cis(dev, 0, cis_addr, &info);
469 memset(ci, 0, sizeof(struct card_info));
470 sdio_func_read_cis(dev, 0, cis_addr, &ci->f[0]);
546 printf("F0: Vendor 0x%04X product 0x%04X max block size %d bytes\n",
471 printf("F0: Vendor 0x%04X product 0x%04X max block size %d bytes\n",
547 info.man_id, info.prod_id, info.max_block_size);
548 for (int i = 1; i <= 2; i++) {
472 ci->f[0].man_id, ci->f[0].prod_id, ci->f[0].max_block_size);
473 for (int i = 1; i <= 7; i++) {
549 fbr_addr = SD_IO_FBR_START * i + 0x9;
474 fbr_addr = SD_IO_FBR_START * i + 0x9;
550 cis_addr = sdio_read_1(dev, 0, fbr_addr++);
551 cis_addr |= sdio_read_1(dev, 0, fbr_addr++) << 8;
552 cis_addr |= sdio_read_1(dev, 0, fbr_addr++) << 16;
553 memset(&info, 0, sizeof(info));
554 sdio_func_read_cis(dev, i, cis_addr, &info);
475 cis_addr = sdio_read_1(dev, 0, fbr_addr++, &ret);bailout(ret);
476 cis_addr |= sdio_read_1(dev, 0, fbr_addr++, &ret) << 8;
477 cis_addr |= sdio_read_1(dev, 0, fbr_addr++, &ret) << 16;
478 sdio_func_read_cis(dev, i, cis_addr, &ci->f[i]);
555 printf("F%d: Vendor 0x%04X product 0x%04X max block size %d bytes\n",
479 printf("F%d: Vendor 0x%04X product 0x%04X max block size %d bytes\n",
556 i, info.man_id, info.prod_id, info.max_block_size);
480 i, ci->f[i].man_id, ci->f[i].prod_id, ci->f[i].max_block_size);
481 if (ci->f[i].man_id == 0) {
482 printf("F%d doesn't exist\n", i);
483 break;
484 }
485 ci->num_funcs++;
557 }
558}
559
486 }
487}
488
560/* Test interrupt delivery when select() */
561__unused static int
562sdio_signal_intr(struct cam_device *dev) {
563 uint8_t resp;
564 int ret;
565
566 ret = sdio_rw_direct(dev, 0, 0x666, 0, NULL, &resp);
567 if (ret < 0)
568 return ret;
569 return (0);
570}
571
572static void
573do_intr_test(__unused struct cam_device *dev) {
574}
575
576int
577main(int argc, char **argv) {
578 char device[] = "pass";
579 int unit = 0;
580 int func = 0;
489int
490main(int argc, char **argv) {
491 char device[] = "pass";
492 int unit = 0;
493 int func = 0;
581 uint8_t resp;
582 uint8_t is_enab;
583 __unused uint8_t *fw_ptr;
584 int ch;
585 struct cam_device *cam_dev;
494 __unused uint8_t *fw_ptr;
495 int ch;
496 struct cam_device *cam_dev;
586 int is_intr_test = 0;
497 int ret;
498 struct card_info ci;
587
588 //fw_ptr = mmap_fw();
589
499
500 //fw_ptr = mmap_fw();
501
590 while ((ch = getopt(argc, argv, "Iu:")) != -1) {
502 while ((ch = getopt(argc, argv, "fu:")) != -1) {
591 switch (ch) {
592 case 'u':
593 unit = (int) strtol(optarg, NULL, 10);
594 break;
595 case 'f':
596 func = (int) strtol(optarg, NULL, 10);
503 switch (ch) {
504 case 'u':
505 unit = (int) strtol(optarg, NULL, 10);
506 break;
507 case 'f':
508 func = (int) strtol(optarg, NULL, 10);
597 case 'I':
598 is_intr_test = 1;
509 break;
599 case '?':
600 default:
601 usage();
602 }
603 }
604 argc -= optind;
605 argv += optind;
606
607 if ((cam_dev = cam_open_spec_device(device, unit, O_RDWR, NULL)) == NULL)
608 errx(1, "Cannot open device");
609
510 case '?':
511 default:
512 usage();
513 }
514 }
515 argc -= optind;
516 argv += optind;
517
518 if ((cam_dev = cam_open_spec_device(device, unit, O_RDWR, NULL)) == NULL)
519 errx(1, "Cannot open device");
520
610 get_sdio_card_info(cam_dev);
611 if (is_intr_test > 0)
612 do_intr_test(cam_dev);
613 exit(0);
614 sdio_card_reset(cam_dev);
521 get_sdio_card_info(cam_dev, &ci);
615
522
616 /* Read Addr 7 of func 0 */
617 int ret = sdio_rw_direct(cam_dev, 0, 7, 0, NULL, &resp);
618 if (ret < 0)
619 errx(1, "Error sending CAM command");
620 printf("Result: %02x\n", resp);
523 /* For now, everything non-broadcom is out of the question */
524 if (ci.f[0].man_id != 0x02D0) {
525 printf("The card is not a Broadcom device\n");
526 exit(1);
527 }
528 /* Init structures */
529 struct brcmf_sdio_dev brcmf_dev;
530 struct brcmf_bus bus_if;
531 struct sdio_func f0, f1, f2;
532 bus_if.state = BRCMF_BUS_DOWN;
533 brcmf_dev.cam_dev = cam_dev;
534 brcmf_dev.bus_if = &bus_if;
535 brcmf_dev.state = BRCMF_SDIOD_DOWN;
621
536
622 /* Check if func 1 is enabled */
623 ret = sdio_is_func_enabled(cam_dev, 1, &is_enab);
624 if (ret < 0)
625 errx(1, "Cannot check if func is enabled");
626 printf("F1 enabled: %d\n", is_enab);
627 ret = sdio_func_enable(cam_dev, 1, 1 - is_enab);
628 if (ret < 0)
629 errx(1, "Cannot enable/disable func");
630 printf("F1 en/dis result: %d\n", ret);
537 /* Fill in functions */
538 brcmf_dev.func[0] = &f0;
539 brcmf_dev.func[1] = &f1;
540 brcmf_dev.func[2] = &f2;
631
541
632 /* Check if func 1 is ready */
633 ret = sdio_is_func_ready(cam_dev, 1, &is_enab);
634 if (ret < 0)
635 errx(1, "Cannot check if func is ready");
636 printf("F1 ready: %d\n", is_enab);
542 brcmf_dev.func[0]->dev = brcmf_dev.func[1]->dev
543 = brcmf_dev.func[2]->dev = cam_dev;
544 brcmf_dev.func[0]->num = 0;
545 brcmf_dev.func[1]->num = 1;
546 brcmf_dev.func[2]->num = 2;
637
547
638 /* Check if interrupts are enabled */
639 ret = sdio_is_func_intr_enabled(cam_dev, 1, &is_enab);
640 if (ret < 0)
641 errx(1, "Cannot check if func intr is enabled");
642 printf("F1 intr enabled: %d\n", is_enab);
643 ret = sdio_func_intr_enable(cam_dev, 1, 1 - is_enab);
644 if (ret < 0)
645 errx(1, "Cannot enable/disable func intr");
646 printf("F1 intr en/dis result: %d\n", ret);
647
548 ret = sdio_func_enable(cam_dev, 1, 1);bailout(ret);
549 uint32_t magic = brcmf_sdiod_regrl(&brcmf_dev, 0x18000000, &ret);
550 printf("Magic = %08x\n", magic);
551 if (magic != REPLY_MAGIC) {
552 errx(1, "Reply magic is incorrect: expected %08x, got %08x",
553 REPLY_MAGIC, magic);
554 }
648 cam_close_spec_device(cam_dev);
649}
555 cam_close_spec_device(cam_dev);
556}