Author: kibab
Date: Mon Sep 18 20:01:01 2017
New Revision: 323717
URL: https://svnweb.freebsd.org/changeset/base/323717

Log:
  Make basic Broadcom I/O space reading functions work
  
  It's now possible to use Broadcom functions to read the I/O registers of
  SDIO card. The functions were copied from the BSD-licensed Broadcom Linux 
driver
  as-is. To make it possible, a small Linux compatibility layer was introduced.
  
  Currently the card responds with the correct version number ("magic")
  when reading the corresponding address.
  
  Approved by:  imp (mentor)
  Differential Revision:        https://reviews.freebsd.org/D12111

Added:
  head/usr.bin/sdiotool/brcmfmac_bus.h   (contents, props changed)
  head/usr.bin/sdiotool/brcmfmac_sdio.h   (contents, props changed)
  head/usr.bin/sdiotool/cam_sdio.c   (contents, props changed)
  head/usr.bin/sdiotool/cam_sdio.h   (contents, props changed)
  head/usr.bin/sdiotool/linux_compat.h   (contents, props changed)
  head/usr.bin/sdiotool/linux_sdio_compat.c   (contents, props changed)
  head/usr.bin/sdiotool/linux_sdio_compat.h   (contents, props changed)
Modified:
  head/usr.bin/sdiotool/Makefile
  head/usr.bin/sdiotool/sdiotool.c

Modified: head/usr.bin/sdiotool/Makefile
==============================================================================
--- head/usr.bin/sdiotool/Makefile      Mon Sep 18 19:56:05 2017        
(r323716)
+++ head/usr.bin/sdiotool/Makefile      Mon Sep 18 20:01:01 2017        
(r323717)
@@ -1,7 +1,7 @@
 # $FreeBSD$
 
 PROG=  sdiotool
-SRCS=  sdiotool.c
+SRCS=  sdiotool.c cam_sdio.c linux_sdio_compat.c
 
 LIBADD= cam util
 MAN=

Added: head/usr.bin/sdiotool/brcmfmac_bus.h
==============================================================================
--- /dev/null   00:00:00 1970   (empty, because file is newly added)
+++ head/usr.bin/sdiotool/brcmfmac_bus.h        Mon Sep 18 20:01:01 2017        
(r323717)
@@ -0,0 +1,26 @@
+/*
+ * Copyright (c) 2010 Broadcom Corporation
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
+ * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
+ * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
+ * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ *
+ * $FreeBSD$
+ */
+/* The level of bus communication with the dongle */
+enum brcmf_bus_state {
+       BRCMF_BUS_DOWN,         /* Not ready for frame transfers */
+       BRCMF_BUS_UP            /* Ready for frame transfers */
+};
+
+struct brcmf_bus {
+       enum brcmf_bus_state state;
+};

Added: head/usr.bin/sdiotool/brcmfmac_sdio.h
==============================================================================
--- /dev/null   00:00:00 1970   (empty, because file is newly added)
+++ head/usr.bin/sdiotool/brcmfmac_sdio.h       Mon Sep 18 20:01:01 2017        
(r323717)
@@ -0,0 +1,160 @@
+/*
+ * Copyright (c) 2010 Broadcom Corporation
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
+ * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
+ * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
+ * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ *
+ * $FreeBSD$
+ */
+#define SDIO_FUNC_0            0
+#define SDIO_FUNC_1            1
+#define SDIO_FUNC_2            2
+
+#define SDIOD_FBR_SIZE         0x100
+
+/* io_en */
+#define SDIO_FUNC_ENABLE_1     0x02
+#define SDIO_FUNC_ENABLE_2     0x04
+
+/* io_rdys */
+#define SDIO_FUNC_READY_1      0x02
+#define SDIO_FUNC_READY_2      0x04
+
+/* intr_status */
+#define INTR_STATUS_FUNC1      0x2
+#define INTR_STATUS_FUNC2      0x4
+
+/* Maximum number of I/O funcs */
+#define SDIOD_MAX_IOFUNCS      7
+
+/* mask of register map */
+#define REG_F0_REG_MASK                0x7FF
+#define REG_F1_MISC_MASK       0x1FFFF
+
+/* as of sdiod rev 0, supports 3 functions */
+#define SBSDIO_NUM_FUNCTION            3
+
+/* function 0 vendor specific CCCR registers */
+#define SDIO_CCCR_BRCM_CARDCAP                 0xf0
+#define SDIO_CCCR_BRCM_CARDCAP_CMD14_SUPPORT   0x02
+#define SDIO_CCCR_BRCM_CARDCAP_CMD14_EXT       0x04
+#define SDIO_CCCR_BRCM_CARDCAP_CMD_NODEC       0x08
+#define SDIO_CCCR_BRCM_CARDCTRL                0xf1
+#define SDIO_CCCR_BRCM_CARDCTRL_WLANRESET      0x02
+#define SDIO_CCCR_BRCM_SEPINT                  0xf2
+
+#define  SDIO_SEPINT_MASK              0x01
+#define  SDIO_SEPINT_OE                        0x02
+#define  SDIO_SEPINT_ACT_HI            0x04
+
+/* function 1 miscellaneous registers */
+
+/* sprom command and status */
+#define SBSDIO_SPROM_CS                        0x10000
+/* sprom info register */
+#define SBSDIO_SPROM_INFO              0x10001
+/* sprom indirect access data byte 0 */
+#define SBSDIO_SPROM_DATA_LOW          0x10002
+/* sprom indirect access data byte 1 */
+#define SBSDIO_SPROM_DATA_HIGH         0x10003
+/* sprom indirect access addr byte 0 */
+#define SBSDIO_SPROM_ADDR_LOW          0x10004
+/* gpio select */
+#define SBSDIO_GPIO_SELECT             0x10005
+/* gpio output */
+#define SBSDIO_GPIO_OUT                        0x10006
+/* gpio enable */
+#define SBSDIO_GPIO_EN                 0x10007
+/* rev < 7, watermark for sdio device */
+#define SBSDIO_WATERMARK               0x10008
+/* control busy signal generation */
+#define SBSDIO_DEVICE_CTL              0x10009
+
+/* SB Address Window Low (b15) */
+#define SBSDIO_FUNC1_SBADDRLOW         0x1000A
+/* SB Address Window Mid (b23:b16) */
+#define SBSDIO_FUNC1_SBADDRMID         0x1000B
+/* SB Address Window High (b31:b24)    */
+#define SBSDIO_FUNC1_SBADDRHIGH                0x1000C
+/* Frame Control (frame term/abort) */
+#define SBSDIO_FUNC1_FRAMECTRL         0x1000D
+/* ChipClockCSR (ALP/HT ctl/status) */
+#define SBSDIO_FUNC1_CHIPCLKCSR                0x1000E
+/* SdioPullUp (on cmd, d0-d2) */
+#define SBSDIO_FUNC1_SDIOPULLUP                0x1000F
+/* Write Frame Byte Count Low */
+#define SBSDIO_FUNC1_WFRAMEBCLO                0x10019
+/* Write Frame Byte Count High */
+#define SBSDIO_FUNC1_WFRAMEBCHI                0x1001A
+/* Read Frame Byte Count Low */
+#define SBSDIO_FUNC1_RFRAMEBCLO                0x1001B
+/* Read Frame Byte Count High */
+#define SBSDIO_FUNC1_RFRAMEBCHI                0x1001C
+/* MesBusyCtl (rev 11) */
+#define SBSDIO_FUNC1_MESBUSYCTRL       0x1001D
+/* Sdio Core Rev 12 */
+#define SBSDIO_FUNC1_WAKEUPCTRL                0x1001E
+#define SBSDIO_FUNC1_WCTRL_ALPWAIT_MASK                0x1
+#define SBSDIO_FUNC1_WCTRL_ALPWAIT_SHIFT       0
+#define SBSDIO_FUNC1_WCTRL_HTWAIT_MASK         0x2
+#define SBSDIO_FUNC1_WCTRL_HTWAIT_SHIFT                1
+#define SBSDIO_FUNC1_SLEEPCSR          0x1001F
+#define SBSDIO_FUNC1_SLEEPCSR_KSO_MASK         0x1
+#define SBSDIO_FUNC1_SLEEPCSR_KSO_SHIFT                0
+#define SBSDIO_FUNC1_SLEEPCSR_KSO_EN           1
+#define SBSDIO_FUNC1_SLEEPCSR_DEVON_MASK       0x2
+#define SBSDIO_FUNC1_SLEEPCSR_DEVON_SHIFT      1
+
+#define SBSDIO_FUNC1_MISC_REG_START    0x10000 /* f1 misc register start */
+#define SBSDIO_FUNC1_MISC_REG_LIMIT    0x1001F /* f1 misc register end */
+
+/* function 1 OCP space */
+
+/* sb offset addr is <= 15 bits, 32k */
+#define SBSDIO_SB_OFT_ADDR_MASK                0x07FFF
+#define SBSDIO_SB_OFT_ADDR_LIMIT       0x08000
+/* with b15, maps to 32-bit SB access */
+#define SBSDIO_SB_ACCESS_2_4B_FLAG     0x08000
+
+/* valid bits in SBSDIO_FUNC1_SBADDRxxx regs */
+
+#define SBSDIO_SBADDRLOW_MASK          0x80    /* Valid bits in SBADDRLOW */
+#define SBSDIO_SBADDRMID_MASK          0xff    /* Valid bits in SBADDRMID */
+#define SBSDIO_SBADDRHIGH_MASK         0xffU   /* Valid bits in SBADDRHIGH */
+/* Address bits from SBADDR regs */
+#define SBSDIO_SBWINDOW_MASK           0xffff8000
+
+#define SDIOH_READ              0      /* Read request */
+#define SDIOH_WRITE             1      /* Write request */
+
+#define SDIOH_DATA_FIX          0      /* Fixed addressing */
+#define SDIOH_DATA_INC          1      /* Incremental addressing */
+
+/* internal return code */
+#define SUCCESS        0
+#define ERROR  1
+
+/* Packet alignment for most efficient SDIO (can change based on platform) */
+#define BRCMF_SDALIGN  (1 << 6)
+
+/**
+ * enum brcmf_sdiod_state - the state of the bus.
+ *
+ * @BRCMF_SDIOD_DOWN: Device can be accessed, no DPC.
+ * @BRCMF_SDIOD_DATA: Ready for data transfers, DPC enabled.
+ * @BRCMF_SDIOD_NOMEDIUM: No medium access to dongle possible.
+ */
+enum brcmf_sdiod_state {
+       BRCMF_SDIOD_DOWN,
+       BRCMF_SDIOD_DATA,
+       BRCMF_SDIOD_NOMEDIUM
+};

Added: head/usr.bin/sdiotool/cam_sdio.c
==============================================================================
--- /dev/null   00:00:00 1970   (empty, because file is newly added)
+++ head/usr.bin/sdiotool/cam_sdio.c    Mon Sep 18 20:01:01 2017        
(r323717)
@@ -0,0 +1,440 @@
+/*-
+ * Copyright (c) 2017 Ilya Bakulin
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $FreeBSD$
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include "cam_sdio.h"
+
+/* Use CMD52 to read or write a single byte */
+int
+sdio_rw_direct(struct cam_device *dev,
+              uint8_t func_number,
+              uint32_t addr,
+              uint8_t is_write,
+              uint8_t *data, uint8_t *resp) {
+       union ccb *ccb;
+       uint32_t flags;
+       uint32_t arg;
+       int retval = 0;
+
+       ccb = cam_getccb(dev);
+       if (ccb == NULL) {
+               warnx("%s: error allocating CCB", __func__);
+               return (-1);
+       }
+       bzero(&(&ccb->ccb_h)[1],
+             sizeof(union ccb) - sizeof(struct ccb_hdr));
+
+       flags = MMC_RSP_R5 | MMC_CMD_AC;
+       arg = SD_IO_RW_FUNC(func_number) | SD_IO_RW_ADR(addr);
+       if (is_write)
+               arg |= SD_IO_RW_WR | SD_IO_RW_RAW | SD_IO_RW_DAT(*data);
+
+       cam_fill_mmcio(&ccb->mmcio,
+                      /*retries*/ 0,
+                      /*cbfcnp*/ NULL,
+                      /*flags*/ CAM_DIR_NONE,
+                      /*mmc_opcode*/ SD_IO_RW_DIRECT,
+                      /*mmc_arg*/ arg,
+                      /*mmc_flags*/ flags,
+                      /*mmc_data*/ 0,
+                      /*timeout*/ 5000);
+
+       if (((retval = cam_send_ccb(dev, ccb)) < 0)
+           || ((ccb->ccb_h.status & CAM_STATUS_MASK) != CAM_REQ_CMP)) {
+               const char warnstr[] = "error sending command";
+
+               if (retval < 0)
+                       warn(warnstr);
+               else
+                       warnx(warnstr);
+               return (-1);
+       }
+
+       *resp = ccb->mmcio.cmd.resp[0] & 0xFF;
+       cam_freeccb(ccb);
+       return (retval);
+}
+
+/*
+ * CMD53 -- IO_RW_EXTENDED
+ * Use to read or write memory blocks
+ *
+ * is_increment=1: FIFO mode
+ * blk_count > 0: block mode
+ */
+int
+sdio_rw_extended(struct cam_device *dev,
+                uint8_t func_number,
+                uint32_t addr,
+                uint8_t is_write,
+                caddr_t data, size_t datalen,
+                uint8_t is_increment,
+                uint16_t blk_count) {
+       union ccb *ccb;
+       uint32_t flags;
+       uint32_t arg;
+       uint32_t cam_flags;
+       uint8_t resp;
+       struct mmc_data mmcd;
+       int retval = 0;
+
+       if (blk_count != 0) {
+               warnx("%s: block mode is not supported yet", __func__);
+               return (-1);
+       }
+
+       ccb = cam_getccb(dev);
+       if (ccb == NULL) {
+               warnx("%s: error allocating CCB", __func__);
+               return (-1);
+       }
+       bzero(&(&ccb->ccb_h)[1],
+             sizeof(union ccb) - sizeof(struct ccb_hdr));
+
+       flags = MMC_RSP_R5 | MMC_CMD_ADTC;
+       arg = SD_IO_RW_FUNC(func_number) | SD_IO_RW_ADR(addr) |
+               SD_IOE_RW_LEN(datalen);
+
+       if (is_increment)
+               arg |= SD_IO_RW_INCR;
+
+       mmcd.data = data;
+       mmcd.len = datalen;
+       mmcd.xfer_len = 0; /* not used by MMCCAM */
+       mmcd.mrq = NULL; /* not used by MMCCAM */
+
+       if (is_write) {
+               arg |= SD_IO_RW_WR;
+               cam_flags = CAM_DIR_OUT;
+               mmcd.flags = MMC_DATA_WRITE;
+       } else {
+               cam_flags = CAM_DIR_IN;
+               mmcd.flags = MMC_DATA_READ;
+       }
+       cam_fill_mmcio(&ccb->mmcio,
+                      /*retries*/ 0,
+                      /*cbfcnp*/ NULL,
+                      /*flags*/ cam_flags,
+                      /*mmc_opcode*/ SD_IO_RW_EXTENDED,
+                      /*mmc_arg*/ arg,
+                      /*mmc_flags*/ flags,
+                      /*mmc_data*/ &mmcd,
+                      /*timeout*/ 5000);
+
+       if (((retval = cam_send_ccb(dev, ccb)) < 0)
+           || ((ccb->ccb_h.status & CAM_STATUS_MASK) != CAM_REQ_CMP)) {
+               const char warnstr[] = "error sending command";
+
+               if (retval < 0)
+                       warn(warnstr);
+               else
+                       warnx(warnstr);
+               return (-1);
+       }
+
+       resp = ccb->mmcio.cmd.resp[0] & 0xFF;
+       if (resp != 0)
+               warn("Response from CMD53 is not 0?!");
+       cam_freeccb(ccb);
+       return (retval);
+}
+
+
+int
+sdio_read_bool_for_func(struct cam_device *dev, uint32_t addr, uint8_t 
func_number, uint8_t *is_enab) {
+       uint8_t resp;
+       int ret;
+
+       ret = sdio_rw_direct(dev, 0, addr, 0, NULL, &resp);
+       if (ret < 0)
+               return ret;
+
+       *is_enab = (resp & (1 << func_number)) > 0 ? 1 : 0;
+
+       return (0);
+}
+
+int
+sdio_set_bool_for_func(struct cam_device *dev, uint32_t addr, uint8_t 
func_number, int enable) {
+       uint8_t resp;
+       int ret;
+       uint8_t is_enabled;
+
+       ret = sdio_rw_direct(dev, 0, addr, 0, NULL, &resp);
+       if (ret != 0)
+               return ret;
+
+       is_enabled = resp & (1 << func_number);
+       if ((is_enabled !=0 && enable == 1) || (is_enabled == 0 && enable == 0))
+               return 0;
+
+       if (enable)
+               resp |= 1 << func_number;
+       else
+               resp &= ~ (1 << func_number);
+
+       ret = sdio_rw_direct(dev, 0, addr, 1, &resp, &resp);
+
+       return ret;
+}
+
+/* Conventional I/O functions */
+uint8_t
+sdio_read_1(struct cam_device *dev, uint8_t func_number, uint32_t addr, int 
*ret) {
+       uint8_t val;
+       *ret = sdio_rw_direct(dev, func_number, addr, 0, NULL, &val);
+       return val;
+}
+
+int
+sdio_write_1(struct cam_device *dev, uint8_t func_number, uint32_t addr, 
uint8_t val) {
+       uint8_t _val;
+       return sdio_rw_direct(dev, func_number, addr, 0, &val, &_val);
+}
+
+uint16_t
+sdio_read_2(struct cam_device *dev, uint8_t func_number, uint32_t addr, int 
*ret) {
+       uint16_t val;
+       *ret = sdio_rw_extended(dev, func_number, addr,
+                               /* is_write */ 0,
+                               /* data */ (caddr_t) &val,
+                               /* datalen */ sizeof(val),
+                               /* is_increment */ 1,
+                               /* blk_count */ 0
+               );
+       return val;
+}
+
+
+int
+sdio_write_2(struct cam_device *dev, uint8_t func_number, uint32_t addr, 
uint16_t val) {
+       return sdio_rw_extended(dev, func_number, addr,
+                               /* is_write */ 1,
+                               /* data */ (caddr_t) &val,
+                               /* datalen */ sizeof(val),
+                               /* is_increment */ 1,
+                               /* blk_count */ 0
+               );
+}
+
+uint32_t
+sdio_read_4(struct cam_device *dev, uint8_t func_number, uint32_t addr, int 
*ret) {
+       uint32_t val;
+       *ret = sdio_rw_extended(dev, func_number, addr,
+                               /* is_write */ 0,
+                               /* data */ (caddr_t) &val,
+                               /* datalen */ sizeof(val),
+                               /* is_increment */ 1,
+                               /* blk_count */ 0
+               );
+       return val;
+}
+
+
+int
+sdio_write_4(struct cam_device *dev, uint8_t func_number, uint32_t addr, 
uint32_t val) {
+       return sdio_rw_extended(dev, func_number, addr,
+                               /* is_write */ 1,
+                               /* data */ (caddr_t) &val,
+                               /* datalen */ sizeof(val),
+                               /* is_increment */ 1,
+                               /* blk_count */ 0
+               );
+}
+
+/* Higher-level wrappers for certain management operations */
+int
+sdio_is_func_ready(struct cam_device *dev, uint8_t func_number, uint8_t 
*is_enab) {
+       return sdio_read_bool_for_func(dev, SD_IO_CCCR_FN_READY, func_number, 
is_enab);
+}
+
+int
+sdio_is_func_enabled(struct cam_device *dev, uint8_t func_number, uint8_t 
*is_enab) {
+       return sdio_read_bool_for_func(dev, SD_IO_CCCR_FN_ENABLE, func_number, 
is_enab);
+}
+
+int
+sdio_func_enable(struct cam_device *dev, uint8_t func_number, int enable) {
+       return sdio_set_bool_for_func(dev, SD_IO_CCCR_FN_ENABLE, func_number, 
enable);
+}
+
+int
+sdio_is_func_intr_enabled(struct cam_device *dev, uint8_t func_number, uint8_t 
*is_enab) {
+       return sdio_read_bool_for_func(dev, SD_IO_CCCR_INT_ENABLE, func_number, 
is_enab);
+}
+
+int
+sdio_func_intr_enable(struct cam_device *dev, uint8_t func_number, int enable) 
{
+       return sdio_set_bool_for_func(dev, SD_IO_CCCR_INT_ENABLE, func_number, 
enable);
+}
+
+int
+sdio_card_set_bus_width(struct cam_device *dev, enum mmc_bus_width bw) {
+       int ret;
+       uint8_t ctl_val;
+       ret = sdio_rw_direct(dev, 0, SD_IO_CCCR_BUS_WIDTH, 0, NULL, &ctl_val);
+       if (ret < 0) {
+               warn("Error getting CCCR_BUS_WIDTH value");
+               return ret;
+       }
+       ctl_val &= ~0x3;
+       switch (bw) {
+       case bus_width_1:
+               /* Already set to 1-bit */
+               break;
+       case bus_width_4:
+               ctl_val |= CCCR_BUS_WIDTH_4;
+               break;
+       case bus_width_8:
+               warn("Cannot do 8-bit on SDIO yet");
+               return -1;
+               break;
+       }
+       ret = sdio_rw_direct(dev, 0, SD_IO_CCCR_BUS_WIDTH, 1, &ctl_val, 
&ctl_val);
+       if (ret < 0) {
+               warn("Error setting CCCR_BUS_WIDTH value");
+               return ret;
+       }
+       return ret;
+}
+
+int
+sdio_func_read_cis(struct cam_device *dev, uint8_t func_number,
+                  uint32_t cis_addr, struct cis_info *info) {
+       uint8_t tuple_id, tuple_len, tuple_count;
+       uint32_t addr;
+
+       char *cis1_info[4];
+       int start, i, ch, count, ret;
+       char cis1_info_buf[256];
+
+       tuple_count = 0; /* Use to prevent infinite loop in case of parse 
errors */
+       memset(cis1_info_buf, 0, 256);
+       do {
+               addr = cis_addr;
+               tuple_id = sdio_read_1(dev, 0, addr++, &ret);
+               if (tuple_id == SD_IO_CISTPL_END)
+                       break;
+               if (tuple_id == 0) {
+                       cis_addr++;
+                       continue;
+               }
+               tuple_len = sdio_read_1(dev, 0, addr++, &ret);
+               if (tuple_len == 0 && tuple_id != 0x00) {
+                       warn("Parse error: 0-length tuple %02X\n", tuple_id);
+                       return -1;
+               }
+
+               switch (tuple_id) {
+               case SD_IO_CISTPL_VERS_1:
+                       addr += 2;
+                       for (count = 0, start = 0, i = 0;
+                            (count < 4) && ((i + 4) < 256); i++) {
+                               ch = sdio_read_1(dev, 0, addr + i, &ret);
+                               printf("count=%d, start=%d, i=%d, Got %c 
(0x%02x)\n", count, start, i, ch, ch);
+                               if (ch == 0xff)
+                                       break;
+                               cis1_info_buf[i] = ch;
+                               if (ch == 0) {
+                                       cis1_info[count] =
+                                               cis1_info_buf + start;
+                                       start = i + 1;
+                                       count++;
+                               }
+                       }
+                       printf("Card info:");
+                       for (i=0; i<4; i++)
+                               if (cis1_info[i])
+                                       printf(" %s", cis1_info[i]);
+                       printf("\n");
+                       break;
+               case SD_IO_CISTPL_MANFID:
+                       info->man_id =  sdio_read_1(dev, 0, addr++, &ret);
+                       info->man_id |= sdio_read_1(dev, 0, addr++, &ret) << 8;
+
+                       info->prod_id =  sdio_read_1(dev, 0, addr++, &ret);
+                       info->prod_id |= sdio_read_1(dev, 0, addr++, &ret) << 8;
+                       break;
+               case SD_IO_CISTPL_FUNCID:
+                       /* not sure if we need to parse it? */
+                       break;
+               case SD_IO_CISTPL_FUNCE:
+                       if (tuple_len < 4) {
+                               printf("FUNCE is too short: %d\n", tuple_len);
+                               break;
+                       }
+                       if (func_number == 0) {
+                               /* skip extended_data */
+                               addr++;
+                               info->max_block_size  = sdio_read_1(dev, 0, 
addr++, &ret);
+                               info->max_block_size |= sdio_read_1(dev, 0, 
addr++, &ret) << 8;
+                       } else {
+                               info->max_block_size  = sdio_read_1(dev, 0, 
addr + 0xC, &ret);
+                               info->max_block_size |= sdio_read_1(dev, 0, 
addr + 0xD, &ret) << 8;
+                       }
+                       break;
+               default:
+                       warnx("Skipping tuple ID %02X len %02X\n", tuple_id, 
tuple_len);
+               }
+               cis_addr += tuple_len + 2;
+               tuple_count++;
+       } while (tuple_count < 20);
+
+       return 0;
+}
+
+uint32_t
+sdio_get_common_cis_addr(struct cam_device *dev) {
+       uint32_t addr;
+       int ret;
+
+       addr =  sdio_read_1(dev, 0, SD_IO_CCCR_CISPTR, &ret);
+       addr |= sdio_read_1(dev, 0, SD_IO_CCCR_CISPTR + 1, &ret) << 8;
+       addr |= sdio_read_1(dev, 0, SD_IO_CCCR_CISPTR + 2, &ret) << 16;
+
+       if (addr < SD_IO_CIS_START || addr > SD_IO_CIS_START + SD_IO_CIS_SIZE) {
+               warn("Bad CIS address: %04X\n", addr);
+               addr = 0;
+       }
+
+       return addr;
+}
+
+void sdio_card_reset(struct cam_device *dev) {
+       int ret;
+       uint8_t ctl_val;
+       ret = sdio_rw_direct(dev, 0, SD_IO_CCCR_CTL, 0, NULL, &ctl_val);
+       if (ret < 0)
+               errx(1, "Error getting CCCR_CTL value");
+       ctl_val |= CCCR_CTL_RES;
+       ret = sdio_rw_direct(dev, 0, SD_IO_CCCR_CTL, 1, &ctl_val, &ctl_val);
+       if (ret < 0)
+               errx(1, "Error setting CCCR_CTL value");
+}

Added: head/usr.bin/sdiotool/cam_sdio.h
==============================================================================
--- /dev/null   00:00:00 1970   (empty, because file is newly added)
+++ head/usr.bin/sdiotool/cam_sdio.h    Mon Sep 18 20:01:01 2017        
(r323717)
@@ -0,0 +1,95 @@
+/*-
+ * Copyright (c) 2017 Ilya Bakulin
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $FreeBSD$
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <sys/ioctl.h>
+#include <sys/stdint.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/endian.h>
+#include <sys/sbuf.h>
+#include <sys/mman.h>
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <inttypes.h>
+#include <limits.h>
+#include <fcntl.h>
+#include <ctype.h>
+#include <err.h>
+#include <libutil.h>
+#include <unistd.h>
+
+#include <cam/cam.h>
+#include <cam/cam_debug.h>
+#include <cam/cam_ccb.h>
+#include <cam/mmc/mmc_all.h>
+#include <camlib.h>
+
+struct cis_info {
+       uint16_t man_id;
+       uint16_t prod_id;
+       uint16_t max_block_size;
+};
+
+int sdio_rw_direct(struct cam_device *dev,
+                         uint8_t func_number,
+                         uint32_t addr,
+                         uint8_t is_write,
+                         uint8_t *data,
+                         uint8_t *resp);
+int
+sdio_rw_extended(struct cam_device *dev,
+                uint8_t func_number,
+                uint32_t addr,
+                uint8_t is_write,
+                caddr_t data, size_t datalen,
+                uint8_t is_increment,
+                uint16_t blk_count);
+uint8_t sdio_read_1(struct cam_device *dev, uint8_t func_number, uint32_t 
addr, int *ret);
+int sdio_write_1(struct cam_device *dev, uint8_t func_number, uint32_t addr, 
uint8_t val);
+uint16_t sdio_read_2(struct cam_device *dev, uint8_t func_number, uint32_t 
addr, int *ret);
+int sdio_write_2(struct cam_device *dev, uint8_t func_number, uint32_t addr, 
uint16_t val);
+uint32_t sdio_read_4(struct cam_device *dev, uint8_t func_number, uint32_t 
addr, int *ret);
+int sdio_write_4(struct cam_device *dev, uint8_t func_number, uint32_t addr, 
uint32_t val);
+int sdio_read_bool_for_func(struct cam_device *dev, uint32_t addr, uint8_t 
func_number, uint8_t *is_enab);
+int sdio_set_bool_for_func(struct cam_device *dev, uint32_t addr, uint8_t 
func_number, int enable);
+int sdio_is_func_ready(struct cam_device *dev, uint8_t func_number, uint8_t 
*is_enab);
+int sdio_is_func_enabled(struct cam_device *dev, uint8_t func_number, uint8_t 
*is_enab);
+int sdio_func_enable(struct cam_device *dev, uint8_t func_number, int enable);
+int sdio_is_func_intr_enabled(struct cam_device *dev, uint8_t func_number, 
uint8_t *is_enab);
+int sdio_func_intr_enable(struct cam_device *dev, uint8_t func_number, int 
enable);
+void sdio_card_reset(struct cam_device *dev);
+uint32_t sdio_get_common_cis_addr(struct cam_device *dev);
+int sdio_func_read_cis(struct cam_device *dev, uint8_t func_number,
+                      uint32_t cis_addr, struct cis_info *info);
+int sdio_card_set_bus_width(struct cam_device *dev, enum mmc_bus_width bw);

Added: head/usr.bin/sdiotool/linux_compat.h
==============================================================================
--- /dev/null   00:00:00 1970   (empty, because file is newly added)
+++ head/usr.bin/sdiotool/linux_compat.h        Mon Sep 18 20:01:01 2017        
(r323717)
@@ -0,0 +1,58 @@
+/*-
+ * Copyright (c) 2016-2017 Ilya Bakulin
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $FreeBSD$
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#ifndef _LINUX_COMPAT_H_
+#define _LINUX_COMPAT_H_
+
+/* Linux compatibility shims */
+#define uint unsigned int
+#define u32 uint32_t
+#define u8 uint8_t
+#define u16 uint16_t
+#define s32 int32_t
+#define bool int8_t
+#define true 1
+#define false 0
+
+#define usleep_range(a, b) usleep(a)
+#define ENOMEDIUM -1
+#define EINVAL -2
+
+#define WARN_ON(cond) ({                                        \
+      bool __ret = (cond);                                      \
+      if (__ret) {                                              \
+             printf("WARNING %s failed at %s:%d\n",            \
+                    #cond, __FILE__, __LINE__);                \
+      }                                                         \
+      (__ret);                                                  \
+})
+
+#endif

Added: head/usr.bin/sdiotool/linux_sdio_compat.c
==============================================================================
--- /dev/null   00:00:00 1970   (empty, because file is newly added)
+++ head/usr.bin/sdiotool/linux_sdio_compat.c   Mon Sep 18 20:01:01 2017        
(r323717)
@@ -0,0 +1,104 @@
+/*-
+ * Copyright (c) 2016-2017 Ilya Bakulin
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $FreeBSD$
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <sys/ioctl.h>
+#include <sys/stdint.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/endian.h>
+#include <sys/sbuf.h>
+#include <sys/mman.h>
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <inttypes.h>
+#include <limits.h>
+#include <fcntl.h>
+#include <ctype.h>
+#include <err.h>
+#include <libutil.h>
+#include <unistd.h>
+
+#include <cam/cam.h>
+#include <cam/cam_debug.h>
+#include <cam/cam_ccb.h>
+#include <cam/mmc/mmc_all.h>
+#include <camlib.h>
+
+#include "linux_compat.h"
+#include "linux_sdio_compat.h"
+#include "cam_sdio.h"
+
+u8 sdio_readb(struct sdio_func *func, unsigned int addr, int *err_ret) {
+       return sdio_read_1(func->dev, func->num, addr, err_ret);
+}
+
+unsigned char sdio_f0_readb(struct sdio_func *func, unsigned int addr, int 
*err_ret) {
+       return sdio_readb(func, addr, err_ret);
+}
+
+u16 sdio_readw(struct sdio_func *func, unsigned int addr, int *err_ret) {
+       return sdio_read_2(func->dev, func->num, addr, err_ret);
+}
+
+u32 sdio_readl(struct sdio_func *func, unsigned int addr, int *err_ret) {
+       return sdio_read_4(func->dev, func->num, addr, err_ret);
+}
+
+void sdio_writeb(struct sdio_func *func, u8 b,
+                unsigned int addr, int *err_ret) {
+       *err_ret = sdio_write_1(func->dev, func->num, addr, b);
+}
+
+/* Only writes to the vendor specific CCCR registers
+ * (0xF0 - 0xFF) are permiited. */
+void sdio_f0_writeb(struct sdio_func *func, unsigned char b,
+                   unsigned int addr, int *err_ret)
+{
+       if (addr < 0xF0 || addr > 0xFF) {
+               if (err_ret)
+                       *err_ret = -EINVAL;
+               return;
+       }
+       sdio_writeb(func, b, addr, err_ret);
+}
+
+void sdio_writew(struct sdio_func *func, u16 b,
+                unsigned int addr, int *err_ret) {
+       *err_ret = sdio_write_2(func->dev, func->num, addr, b);
+}
+
+void sdio_writel(struct sdio_func *func, u32 b,
+                unsigned int addr, int *err_ret) {
+       *err_ret = sdio_write_4(func->dev, func->num, addr, b);
+}

Added: head/usr.bin/sdiotool/linux_sdio_compat.h
==============================================================================
--- /dev/null   00:00:00 1970   (empty, because file is newly added)
+++ head/usr.bin/sdiotool/linux_sdio_compat.h   Mon Sep 18 20:01:01 2017        
(r323717)
@@ -0,0 +1,63 @@
+/*-
+ * Copyright (c) 2017 Ilya Bakulin
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $FreeBSD$
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#ifndef _LINUX_SDIO_COMPAT_H_
+#define _LINUX_SDIO_COMPAT_H_
+
+#include <sys/types.h>
+#include "linux_compat.h"
+
+/* Linux SDIO stack functions and definitions */
+#define SDIO_CCCR_ABORT SD_IO_CCCR_CTL
+#define SDIO_CCCR_IENx  SD_IO_CCCR_INT_ENABLE
+
+struct sdio_func {
+       struct cam_device *dev;
+       uint8_t num;
+};
+
+u8 sdio_readb(struct sdio_func *func, unsigned int addr, int *err_ret);
+unsigned char sdio_f0_readb(struct sdio_func *func,
+                           unsigned int addr, int *err_ret);
+u16 sdio_readw(struct sdio_func *func, unsigned int addr, int *err_ret);
+u32 sdio_readl(struct sdio_func *func, unsigned int addr, int *err_ret);
+
+void sdio_writeb(struct sdio_func *func, u8 b,
+       unsigned int addr, int *err_ret);
+void sdio_f0_writeb(struct sdio_func *func, unsigned char b,
+                   unsigned int addr, int *err_ret);
+void sdio_writew(struct sdio_func *func, u16 b,
+       unsigned int addr, int *err_ret);
+void sdio_writel(struct sdio_func *func, u32 b,
+       unsigned int addr, int *err_ret);
+
+
+#endif

Modified: head/usr.bin/sdiotool/sdiotool.c
==============================================================================
--- head/usr.bin/sdiotool/sdiotool.c    Mon Sep 18 19:56:05 2017        
(r323716)
+++ head/usr.bin/sdiotool/sdiotool.c    Mon Sep 18 20:01:01 2017        
(r323717)
@@ -23,6 +23,20 @@
  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  * SUCH DAMAGE.
  *
+ * Copyright (c) 2010 Broadcom Corporation
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
+ * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
+ * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
+ * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ *
  * $FreeBSD$
  */

*** DIFF OUTPUT TRUNCATED AT 1000 LINES ***
_______________________________________________
svn-src-head@freebsd.org mailing list
https://lists.freebsd.org/mailman/listinfo/svn-src-head
To unsubscribe, send any mail to "svn-src-head-unsubscr...@freebsd.org"

Reply via email to