2 * Copyright (c) 2016-2017 Ilya Bakulin
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
14 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
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
29 #include <sys/cdefs.h>
30 __FBSDID("$FreeBSD$");
32 #include <sys/ioctl.h>
33 #include <sys/stdint.h>
34 #include <sys/types.h>
36 #include <sys/endian.h>
53 #include <cam/cam_debug.h>
54 #include <cam/cam_ccb.h>
55 #include <cam/mmc/mmc_all.h>
61 uint16_t max_block_size;
64 static int sdio_rw_direct(struct cam_device *dev,
70 static uint8_t sdio_read_1(struct cam_device *dev, uint8_t func_number, uint32_t addr);
71 static void sdio_write_1(struct cam_device *dev, uint8_t func_number, uint32_t addr, uint8_t val);
72 static int sdio_is_func_ready(struct cam_device *dev, uint8_t func_number, uint8_t *is_enab);
73 static int sdio_is_func_enabled(struct cam_device *dev, uint8_t func_number, uint8_t *is_enab);
74 static int sdio_func_enable(struct cam_device *dev, uint8_t func_number, int enable);
75 static int sdio_is_func_intr_enabled(struct cam_device *dev, uint8_t func_number, uint8_t *is_enab);
76 static int sdio_func_intr_enable(struct cam_device *dev, uint8_t func_number, int enable);
77 static void sdio_card_reset(struct cam_device *dev);
78 static uint32_t sdio_get_common_cis_addr(struct cam_device *dev);
79 static void probe_bcrm(struct cam_device *dev);
81 /* Use CMD52 to read or write a single byte */
83 sdio_rw_direct(struct cam_device *dev,
87 uint8_t *data, uint8_t *resp) {
93 ccb = cam_getccb(dev);
95 warnx("%s: error allocating CCB", __func__);
98 bzero(&(&ccb->ccb_h)[1],
99 sizeof(union ccb) - sizeof(struct ccb_hdr));
101 flags = MMC_RSP_R5 | MMC_CMD_AC;
102 arg = SD_IO_RW_FUNC(func_number) | SD_IO_RW_ADR(addr);
104 arg |= SD_IO_RW_WR | SD_IO_RW_RAW | SD_IO_RW_DAT(*data);
106 cam_fill_mmcio(&ccb->mmcio,
109 /*flags*/ CAM_DIR_NONE,
110 /*mmc_opcode*/ SD_IO_RW_DIRECT,
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";
127 *resp = ccb->mmcio.cmd.resp[0] & 0xFF;
134 * CMD53 -- IO_RW_EXTENDED
135 * Use to read or write memory blocks
137 * is_increment=1: FIFO mode
138 * blk_count > 0: block mode
141 sdio_rw_extended(struct cam_device *dev,
145 uint8_t *data, size_t datalen,
146 uint8_t is_increment,
147 uint16_t blk_count) {
153 if (blk_count != 0) {
154 warnx("%s: block mode is not supported yet", __func__);
158 ccb = cam_getccb(dev);
160 warnx("%s: error allocating CCB", __func__);
163 bzero(&(&ccb->ccb_h)[1],
164 sizeof(union ccb) - sizeof(struct ccb_hdr));
166 flags = MMC_RSP_R5 | MMC_CMD_AC;
167 arg = SD_IO_RW_FUNC(func_number) | SD_IO_RW_ADR(addr);
171 cam_fill_mmcio(&ccb->mmcio,
174 /*flags*/ CAM_DIR_NONE,
175 /*mmc_opcode*/ SD_IO_RW_DIRECT,
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";
192 *resp = ccb->mmcio.cmd.resp[0] & 0xFF;
199 sdio_read_bool_for_func(struct cam_device *dev, uint32_t addr, uint8_t func_number, uint8_t *is_enab) {
203 ret = sdio_rw_direct(dev, 0, addr, 0, NULL, &resp);
207 *is_enab = (resp & (1 << func_number)) > 0 ? 1 : 0;
213 sdio_set_bool_for_func(struct cam_device *dev, uint32_t addr, uint8_t func_number, int enable) {
218 ret = sdio_rw_direct(dev, 0, addr, 0, NULL, &resp);
222 is_enabled = resp & (1 << func_number);
223 if ((is_enabled !=0 && enable == 1) || (is_enabled == 0 && enable == 0))
227 resp |= 1 << func_number;
229 resp &= ~ (1 << func_number);
231 ret = sdio_rw_direct(dev, 0, addr, 1, &resp, &resp);
237 sdio_read_1(struct cam_device *dev, uint8_t func_number, uint32_t addr) {
239 sdio_rw_direct(dev, func_number, addr, 0, NULL, &val);
244 sdio_write_1(struct cam_device *dev, uint8_t func_number, uint32_t addr, uint8_t val) {
246 sdio_rw_direct(dev, func_number, addr, 0, &val, &_val);
250 sdio_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);
255 sdio_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);
260 sdio_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);
265 sdio_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);
270 sdio_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);
275 sdio_card_set_bus_width(struct cam_device *dev, enum mmc_bus_width bw) {
278 ret = sdio_rw_direct(dev, 0, SD_IO_CCCR_BUS_WIDTH, 0, NULL, &ctl_val);
280 warn("Error getting CCCR_BUS_WIDTH value");
286 /* Already set to 1-bit */
289 ctl_val |= CCCR_BUS_WIDTH_4;
292 warn("Cannot do 8-bit on SDIO yet");
296 ret = sdio_rw_direct(dev, 0, SD_IO_CCCR_BUS_WIDTH, 1, &ctl_val, &ctl_val);
298 warn("Error setting CCCR_BUS_WIDTH value");
305 sdio_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;
311 int start, i, ch, count;
312 char cis1_info_buf[256];
314 tuple_count = 0; /* Use to prevent infinite loop in case of parse errors */
315 memset(cis1_info_buf, 0, 256);
318 tuple_id = sdio_read_1(dev, 0, addr++);
319 if (tuple_id == SD_IO_CISTPL_END)
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);
332 case SD_IO_CISTPL_VERS_1:
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);
340 cis1_info_buf[i] = ch;
343 cis1_info_buf + start;
348 printf("Card info:");
351 printf(" %s", cis1_info[i]);
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;
358 info->prod_id = sdio_read_1(dev, 0, addr++);
359 info->prod_id |= sdio_read_1(dev, 0, addr++) << 8;
361 case SD_IO_CISTPL_FUNCID:
362 /* not sure if we need to parse it? */
364 case SD_IO_CISTPL_FUNCE:
366 printf("FUNCE is too short: %d\n", tuple_len);
369 if (func_number == 0) {
370 /* skip extended_data */
372 info->max_block_size = sdio_read_1(dev, 0, addr++);
373 info->max_block_size |= sdio_read_1(dev, 0, addr++) << 8;
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;
380 printf("Skipping tuple ID %02X len %02X\n", tuple_id, tuple_len);
382 cis_addr += tuple_len + 2;
384 } while (tuple_count < 20);
390 sdio_get_common_cis_addr(struct cam_device *dev) {
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;
397 if (addr < SD_IO_CIS_START || addr > SD_IO_CIS_START + SD_IO_CIS_SIZE) {
398 warn("Bad CIS address: %04X\n", addr);
405 static void sdio_card_reset(struct cam_device *dev) {
408 ret = sdio_rw_direct(dev, 0, SD_IO_CCCR_CTL, 0, NULL, &ctl_val);
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);
414 errx(1, "Error setting CCCR_CTL value");
418 * How Linux driver works
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
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).
426 * brcmf_sdiod_probe() sets block sizes for F1 and F2. It sets F1 block size to 64 and F2 to 512, not consulting the values stored in SDIO CCCR / FBR registers!
427 * Then it increases timeout for F2 (what is this?!)
429 * Then it attaches "freezer" (without PM this is NOP)
430 * Finally it calls brcmf_sdio_probe() http://lxr.free-electrons.com/source/drivers/net/wireless/broadcom/brcm80211/brcmfmac/sdio.c#L4082
432 * Here high-level workqueues and sg tables are allocated.
433 * It then calls brcmf_sdio_probe_attach()
435 * Here at the beginning there is a pr_debug() call with brcmf_sdiod_regrl() inside to addr #define SI_ENUM_BASE 0x18000000.
436 * Return value is 0x16044330.
437 * Then turns off PLL: byte-write BRCMF_INIT_CLKCTL1 (0x28) -> SBSDIO_FUNC1_CHIPCLKCSR (0x1000E)
438 * Then it reads value back, should be 0xe8.
439 * Then calls brcmf_chip_attach()
441 * http://lxr.free-electrons.com/source/drivers/net/wireless/broadcom/brcm80211/brcmfmac/chip.c#L1054
442 * This func enumerates and resets all the cores on the dongle.
443 * - brcmf_sdio_buscoreprep(): force clock to ALPAvail req only:
444 * SBSDIO_FORCE_HW_CLKREQ_OFF | SBSDIO_ALP_AVAIL_REQ -> SBSDIO_FUNC1_CHIPCLKCSR
445 * Wait up to 15ms to !SBSDIO_ALPAV(clkval) of the value from CLKCSR.
447 * SBSDIO_FORCE_HW_CLKREQ_OFF | SBSDIO_FORCE_ALP (0x21)-> SBSDIO_FUNC1_CHIPCLKCSR
448 * Disaable SDIO pullups:
449 * byte 0 -> SBSDIO_FUNC1_SDIOPULLUP (0x0001000f)
451 * Calls brcmf_chip_recognition()
452 * http://lxr.free-electrons.com/source/drivers/net/wireless/broadcom/brcm80211/brcmfmac/chip.c#L908
453 * Read 0x18000000. Get 0x16044330: chip 4330 rev 4
454 * AXI chip, call brcmf_chip_dmp_erom_scan() to get info about all cores.
455 * Then brcmf_chip_cores_check() to check that CPU and RAM are found,
457 * Setting cores to passive: not clear which of CR4/CA7/CM3 our chip has.
458 * Quite a few r/w calls to different parts of the chip to reset cores....
459 * Finally get_raminfo() called to fill in RAM info:
460 * brcmf_chip_get_raminfo: RAM: base=0x0 size=294912 (0x48000) sr=0 (0x0)
461 * http://lxr.free-electrons.com/source/drivers/net/wireless/broadcom/brcm80211/brcmfmac/chip.c#L700
463 * Then brcmf_chip_setup() is called, this prints and fills in chipcommon rev and PMU caps:
464 * brcmf_chip_setup: ccrev=39, pmurev=12, pmucaps=0x19583c0c
465 * http://lxr.free-electrons.com/source/drivers/net/wireless/broadcom/brcm80211/brcmfmac/chip.c#L1015
466 * Bus-specific setup code is NOP for SDIO.
468 * brcmf_sdio_kso_init() is called.
469 * Here it first reads 0x1 from SBSDIO_FUNC1_SLEEPCSR 0x18000650 and then writes it back... WTF?
471 * brcmf_sdio_drivestrengthinit() is called
472 * http://lxr.free-electrons.com/source/drivers/net/wireless/broadcom/brcm80211/brcmfmac/sdio.c#L3630
474 * Set card control so an SDIO card reset does a WLAN backplane reset
475 * set PMUControl so a backplane reset does PMU state reload
476 * === end of brcmf_sdio_probe_attach ===
478 **** Finished reading at http://lxr.free-electrons.com/source/drivers/net/wireless/broadcom/brcm80211/brcmfmac/sdio.c#L4152, line 2025 in the dump
480 * === How register reading works ===
481 * http://lxr.free-electrons.com/source/drivers/net/wireless/broadcom/brcm80211/brcmfmac/bcmsdh.c#L357
482 * The address to read from is written to three byte-sized registers of F1:
483 * - SBSDIO_FUNC1_SBADDRLOW 0x1000A
484 * - SBSDIO_FUNC1_SBADDRMID 0x1000B
485 * - SBSDIO_FUNC1_SBADDRHIGH 0x1000C
486 * If this is 32-bit read , a flag is set. The address is ANDed with SBSDIO_SB_OFT_ADDR_MASK which is 0x07FFF.
487 * Then brcmf_sdiod_regrw_helper() is called to read the reply.
488 * http://lxr.free-electrons.com/source/drivers/net/wireless/broadcom/brcm80211/brcmfmac/bcmsdh.c#L306
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 * ==================================
499 probe_bcrm(struct cam_device *dev) {
501 struct cis_info info;
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);
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);
514 const char fw_path[] = "/home/kibab/repos/fbsd-bbb/brcm-firmware/brcmfmac4330-sdio.bin";
518 int fd = open(fw_path, O_RDONLY);
520 errx(1, "Cannot open firmware file");
521 if (fstat(fd, &sb) < 0)
522 errx(1, "Cannot get file stat");
523 fw_ptr = mmap(NULL, sb.st_size, PROT_READ, 0, fd, 0);
524 if (fw_ptr == MAP_FAILED)
525 errx(1, "Cannot map the file");
532 printf("sdiotool -u <pass_dev_unit>\n");
537 get_sdio_card_info(struct cam_device *dev) {
540 struct cis_info info;
542 cis_addr = sdio_get_common_cis_addr(dev);
544 memset(&info, 0, sizeof(info));
545 sdio_func_read_cis(dev, 0, cis_addr, &info);
546 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++) {
549 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);
555 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);
560 /* Test interrupt delivery when select() */
562 sdio_signal_intr(struct cam_device *dev) {
566 ret = sdio_rw_direct(dev, 0, 0x666, 0, NULL, &resp);
573 do_intr_test(__unused struct cam_device *dev) {
577 main(int argc, char **argv) {
578 char device[] = "pass";
583 __unused uint8_t *fw_ptr;
585 struct cam_device *cam_dev;
586 int is_intr_test = 0;
588 //fw_ptr = mmap_fw();
590 while ((ch = getopt(argc, argv, "Iu:")) != -1) {
593 unit = (int) strtol(optarg, NULL, 10);
596 func = (int) strtol(optarg, NULL, 10);
607 if ((cam_dev = cam_open_spec_device(device, unit, O_RDWR, NULL)) == NULL)
608 errx(1, "Cannot open device");
610 get_sdio_card_info(cam_dev);
611 if (is_intr_test > 0)
612 do_intr_test(cam_dev);
614 sdio_card_reset(cam_dev);
616 /* Read Addr 7 of func 0 */
617 int ret = sdio_rw_direct(cam_dev, 0, 7, 0, NULL, &resp);
619 errx(1, "Error sending CAM command");
620 printf("Result: %02x\n", resp);
622 /* Check if func 1 is enabled */
623 ret = sdio_is_func_enabled(cam_dev, 1, &is_enab);
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);
629 errx(1, "Cannot enable/disable func");
630 printf("F1 en/dis result: %d\n", ret);
632 /* Check if func 1 is ready */
633 ret = sdio_is_func_ready(cam_dev, 1, &is_enab);
635 errx(1, "Cannot check if func is ready");
636 printf("F1 ready: %d\n", is_enab);
638 /* Check if interrupts are enabled */
639 ret = sdio_is_func_intr_enabled(cam_dev, 1, &is_enab);
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);
645 errx(1, "Cannot enable/disable func intr");
646 printf("F1 intr en/dis result: %d\n", ret);
648 cam_close_spec_device(cam_dev);