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} |