bcmf_sdio.c 21 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904
  1. /****************************************************************************
  2. * drivers/wireless/ieee80211/bcmf_sdio.c
  3. *
  4. * Copyright (C) 2017 Gregory Nutt. All rights reserved.
  5. * Author: Simon Piriou <spiriou31@gmail.com>
  6. *
  7. * Redistribution and use in source and binary forms, with or without
  8. * modification, are permitted provided that the following conditions
  9. * are met:
  10. *
  11. * 1. Redistributions of source code must retain the above copyright
  12. * notice, this list of conditions and the following disclaimer.
  13. * 2. Redistributions in binary form must reproduce the above copyright
  14. * notice, this list of conditions and the following disclaimer in
  15. * the documentation and/or other materials provided with the
  16. * distribution.
  17. * 3. Neither the name NuttX nor the names of its contributors may be
  18. * used to endorse or promote products derived from this software
  19. * without specific prior written permission.
  20. *
  21. * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
  22. * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
  23. * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
  24. * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
  25. * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
  26. * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
  27. * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
  28. * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
  29. * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
  30. * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
  31. * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
  32. * POSSIBILITY OF SUCH DAMAGE.
  33. *
  34. ****************************************************************************/
  35. /****************************************************************************
  36. * Included Files
  37. ****************************************************************************/
  38. #include <nuttx/config.h>
  39. #include <nuttx/compiler.h>
  40. #include <stdint.h>
  41. #include <stdbool.h>
  42. #include <string.h>
  43. #include <debug.h>
  44. #include <errno.h>
  45. #include <queue.h>
  46. #include <semaphore.h>
  47. #include <assert.h>
  48. #include <nuttx/kmalloc.h>
  49. #include <nuttx/arch.h>
  50. #include <nuttx/kthread.h>
  51. #include <nuttx/wdog.h>
  52. #include <nuttx/wireless/ieee80211/mmc_sdio.h>
  53. #include <nuttx/wireless/ieee80211/bcmf_sdio.h>
  54. #include <nuttx/wireless/ieee80211/bcmf_board.h>
  55. #include "bcmf_sdio.h"
  56. #include "bcmf_core.h"
  57. #include "bcmf_sdpcm.h"
  58. #include "bcmf_utils.h"
  59. #include "bcmf_sdio_core.h"
  60. #include "bcmf_sdio_regs.h"
  61. /* Supported chip configurations */
  62. #ifdef CONFIG_IEEE80211_BROADCOM_BCM43362
  63. extern const struct bcmf_sdio_chip bcmf_43362_config_sdio;
  64. #endif
  65. /****************************************************************************
  66. * Pre-processor Definitions
  67. ****************************************************************************/
  68. #define BCMF_DEVICE_RESET_DELAY_MS 10
  69. #define BCMF_DEVICE_START_DELAY_MS 10
  70. #define BCMF_CLOCK_SETUP_DELAY_MS 500
  71. #define BCMF_THREAD_NAME "bcmf"
  72. #define BCMF_THREAD_STACK_SIZE 2048
  73. #define BCMF_WAITDOG_TIMEOUT_TICK (5*CLOCKS_PER_SEC)
  74. /****************************************************************************
  75. * Private Types
  76. ****************************************************************************/
  77. /****************************************************************************
  78. * Private Function Prototypes
  79. ****************************************************************************/
  80. static int bcmf_probe(FAR struct bcmf_sdio_dev_s *sbus);
  81. static int bcmf_hwinitialize(FAR struct bcmf_sdio_dev_s *sbus);
  82. static void bcmf_hwuninitialize(FAR struct bcmf_sdio_dev_s *sbus);
  83. static int bcmf_chipinitialize(FAR struct bcmf_sdio_dev_s *sbus);
  84. static int bcmf_oob_irq(int irq, FAR void *context, FAR void *arg);
  85. static int bcmf_sdio_bus_sleep(FAR struct bcmf_sdio_dev_s *sbus, bool sleep);
  86. static void bcmf_sdio_waitdog_timeout(int argc, wdparm_t arg1, ...);
  87. static int bcmf_sdio_thread(int argc, char **argv);
  88. static int bcmf_sdio_find_block_size(unsigned int size);
  89. /****************************************************************************
  90. * Private Data
  91. ****************************************************************************/
  92. /* FIXME remove */
  93. FAR struct bcmf_dev_s *g_sdio_priv;
  94. /* Buffer pool for SDIO bus interface
  95. * This pool is shared between all driver devices
  96. */
  97. static struct bcmf_sdio_frame g_pktframes[BCMF_PKT_POOL_SIZE];
  98. // TODO free_queue should be static
  99. /****************************************************************************
  100. * Private Functions
  101. ****************************************************************************/
  102. int bcmf_oob_irq(int irq, FAR void *context, FAR void *arg)
  103. {
  104. FAR struct bcmf_sdio_dev_s *sbus = (struct bcmf_sdio_dev_s *)arg;
  105. if (sbus->ready)
  106. {
  107. /* Signal bmcf thread */
  108. sbus->irq_pending = true;
  109. sem_post(&sbus->thread_signal);
  110. }
  111. return OK;
  112. }
  113. int bcmf_sdio_bus_sleep(FAR struct bcmf_sdio_dev_s *sbus, bool sleep)
  114. {
  115. int ret;
  116. int loops;
  117. uint8_t value;
  118. if (sbus->sleeping == sleep)
  119. {
  120. return OK;
  121. }
  122. if (sleep)
  123. {
  124. sbus->sleeping = true;
  125. return bcmf_write_reg(sbus, 1, SBSDIO_FUNC1_CHIPCLKCSR, 0);
  126. }
  127. else
  128. {
  129. /* Request HT Avail */
  130. ret = bcmf_write_reg(sbus, 1, SBSDIO_FUNC1_CHIPCLKCSR,
  131. SBSDIO_HT_AVAIL_REQ | SBSDIO_FORCE_HT);
  132. if (ret != OK)
  133. {
  134. wlerr("HT Avail request failed %d\n", ret);
  135. return ret;
  136. }
  137. /* Wait for High Troughput clock */
  138. loops = 20;
  139. while (--loops > 0)
  140. {
  141. up_mdelay(1);
  142. ret = bcmf_read_reg(sbus, 1, SBSDIO_FUNC1_CHIPCLKCSR, &value);
  143. if (ret != OK)
  144. {
  145. return ret;
  146. }
  147. if (value & SBSDIO_HT_AVAIL)
  148. {
  149. /* High Throughput clock is ready */
  150. break;
  151. }
  152. }
  153. if (loops <= 0)
  154. {
  155. wlerr("HT clock not ready\n");
  156. return -ETIMEDOUT;
  157. }
  158. sbus->sleeping = false;
  159. }
  160. return OK;
  161. }
  162. /****************************************************************************
  163. * Name: bcmf_probe
  164. ****************************************************************************/
  165. int bcmf_probe(FAR struct bcmf_sdio_dev_s *sbus)
  166. {
  167. int ret;
  168. /* Probe sdio card compatible device */
  169. ret = sdio_probe(sbus->sdio_dev);
  170. if (ret != OK)
  171. {
  172. goto exit_error;
  173. }
  174. /* Set FN0 / FN1 / FN2 default block size */
  175. ret = sdio_set_blocksize(sbus->sdio_dev, 0, 64);
  176. if (ret != OK)
  177. {
  178. goto exit_error;
  179. }
  180. ret = sdio_set_blocksize(sbus->sdio_dev, 1, 64);
  181. if (ret != OK)
  182. {
  183. goto exit_error;
  184. }
  185. ret = sdio_set_blocksize(sbus->sdio_dev, 2, 64);
  186. if (ret != OK)
  187. {
  188. goto exit_error;
  189. }
  190. /* Enable device interrupts for FN0, FN1 and FN2 */
  191. ret = bcmf_write_reg(sbus, 0, SDIO_CCCR_INTEN,
  192. (1 << 0) | (1 << 1) | (1 << 2));
  193. if (ret != OK)
  194. {
  195. goto exit_error;
  196. }
  197. /* Default device clock speed is up to 25 Mhz
  198. * We could set EHS bit to operate at a clock rate up to 50 Mhz */
  199. SDIO_CLOCK(sbus->sdio_dev, CLOCK_SD_TRANSFER_4BIT);
  200. up_mdelay(BCMF_CLOCK_SETUP_DELAY_MS);
  201. /* Enable bus FN1 */
  202. ret = sdio_enable_function(sbus->sdio_dev, 1);
  203. if (ret != OK)
  204. {
  205. goto exit_error;
  206. }
  207. return OK;
  208. exit_error:
  209. wlerr("ERROR: failed to probe device %d\n", sbus->minor);
  210. return ret;
  211. }
  212. /****************************************************************************
  213. * Name: bcmf_businitialize
  214. ****************************************************************************/
  215. int bcmf_businitialize(FAR struct bcmf_sdio_dev_s *sbus)
  216. {
  217. int ret;
  218. int loops;
  219. uint8_t value;
  220. /* Send Active Low-Power clock request */
  221. ret = bcmf_write_reg(sbus, 1, SBSDIO_FUNC1_CHIPCLKCSR,
  222. SBSDIO_FORCE_HW_CLKREQ_OFF |
  223. SBSDIO_ALP_AVAIL_REQ |
  224. SBSDIO_FORCE_ALP);
  225. if (ret != OK)
  226. {
  227. return ret;
  228. }
  229. loops = 10;
  230. while (--loops > 0)
  231. {
  232. up_mdelay(10);
  233. ret = bcmf_read_reg(sbus, 1, SBSDIO_FUNC1_CHIPCLKCSR, &value);
  234. if (ret != OK)
  235. {
  236. return ret;
  237. }
  238. if (value & SBSDIO_ALP_AVAIL)
  239. {
  240. /* Active Low-Power clock is ready */
  241. break;
  242. }
  243. }
  244. if (loops <= 0)
  245. {
  246. wlerr("failed to enable ALP\n");
  247. return -ETIMEDOUT;
  248. }
  249. /* Clear Active Low-Power clock request */
  250. ret = bcmf_write_reg(sbus, 1, SBSDIO_FUNC1_CHIPCLKCSR, 0);
  251. if (ret != OK)
  252. {
  253. return ret;
  254. }
  255. /* Disable pull-ups on SDIO cmd, d0-2 lines */
  256. ret = bcmf_write_reg(sbus, 1, SBSDIO_FUNC1_SDIOPULLUP, 0);
  257. if (ret != OK)
  258. {
  259. return ret;
  260. }
  261. /* Do chip specific initialization */
  262. ret = bcmf_chipinitialize(sbus);
  263. if (ret != OK)
  264. {
  265. return ret;
  266. }
  267. /* Upload firmware */
  268. ret = bcmf_core_upload_firmware(sbus);
  269. if (ret != OK)
  270. {
  271. return ret;
  272. }
  273. /* Enable FN2 (frame transfers) */
  274. ret = sdio_enable_function(sbus->sdio_dev, 2);
  275. if (ret != OK)
  276. {
  277. return ret;
  278. }
  279. return OK;
  280. }
  281. int bcmf_bus_setup_interrupts(FAR struct bcmf_sdio_dev_s *sbus)
  282. {
  283. int ret;
  284. /* Configure gpio interrupt pin */
  285. bcmf_board_setup_oob_irq(sbus->minor, bcmf_oob_irq, (void *)sbus);
  286. /* Enable function 2 interrupt */
  287. ret = sdio_enable_interrupt(sbus->sdio_dev, 0);
  288. if (ret != OK)
  289. {
  290. return ret;
  291. }
  292. ret = sdio_enable_interrupt(sbus->sdio_dev, 2);
  293. if (ret != OK)
  294. {
  295. return ret;
  296. }
  297. /* Redirect, configure and enable io for out-of-band interrupt signal */
  298. ret = bcmf_write_reg(sbus, 0, SDIO_CCCR_BRCM_SEPINT,
  299. SDIO_SEPINT_MASK | SDIO_SEPINT_OE | SDIO_SEPINT_ACT_HI);
  300. if (ret != OK)
  301. {
  302. return ret;
  303. }
  304. /* Wake up chip to be sure function 2 is running */
  305. ret = bcmf_sdio_bus_sleep(sbus, false);
  306. if (ret != OK)
  307. {
  308. return ret;
  309. }
  310. /* FN2 successfully enabled, set core and enable interrupts */
  311. bcmf_write_sbregw(sbus,
  312. CORE_BUS_REG(sbus->chip->core_base[SDIOD_CORE_ID],
  313. hostintmask), I_HMB_SW_MASK);
  314. bcmf_write_sbregb(sbus,
  315. CORE_BUS_REG(sbus->chip->core_base[SDIOD_CORE_ID],
  316. funcintmask), 2);
  317. bcmf_write_reg(sbus, 1, SBSDIO_WATERMARK, 8);
  318. return OK;
  319. }
  320. /****************************************************************************
  321. * Name: bcmf_hwinitialize
  322. ****************************************************************************/
  323. int bcmf_hwinitialize(FAR struct bcmf_sdio_dev_s *sbus)
  324. {
  325. /* Attach and prepare SDIO interrupts */
  326. SDIO_ATTACH(sbus->sdio_dev);
  327. /* Set ID mode clocking (<400KHz) */
  328. SDIO_CLOCK(sbus->sdio_dev, CLOCK_IDMODE);
  329. /* Configure hardware */
  330. bcmf_board_initialize(sbus->minor);
  331. /* Reset and power device */
  332. bcmf_board_reset(sbus->minor, true);
  333. bcmf_board_power(sbus->minor, true);
  334. up_mdelay(BCMF_DEVICE_RESET_DELAY_MS);
  335. bcmf_board_reset(sbus->minor, false);
  336. /* Wait for device to start */
  337. up_mdelay(BCMF_DEVICE_START_DELAY_MS);
  338. return OK;
  339. }
  340. /****************************************************************************
  341. * Name: bcmf_hwuninitialize
  342. ****************************************************************************/
  343. void bcmf_hwuninitialize(FAR struct bcmf_sdio_dev_s *sbus)
  344. {
  345. /* Shutdown device */
  346. bcmf_board_power(sbus->minor, false);
  347. bcmf_board_reset(sbus->minor, true);
  348. }
  349. int bcmf_sdio_find_block_size(unsigned int size)
  350. {
  351. int ret = 0;
  352. int size_copy = size;
  353. while (size_copy)
  354. {
  355. size_copy >>= 1;
  356. ret++;
  357. }
  358. if (size & (size-1))
  359. {
  360. return 1 << ret;
  361. }
  362. return 1 << (ret - 1);
  363. }
  364. /****************************************************************************
  365. * Public Functions
  366. ****************************************************************************/
  367. /****************************************************************************
  368. * Name: bcmf_transfer_bytes
  369. ****************************************************************************/
  370. int bcmf_transfer_bytes(FAR struct bcmf_sdio_dev_s *sbus, bool write,
  371. uint8_t function, uint32_t address,
  372. uint8_t *buf, unsigned int len)
  373. {
  374. unsigned int blocklen;
  375. unsigned int nblocks;
  376. /* Use rw_io_direct method if len is 1 */
  377. if (len == 0)
  378. {
  379. return -EINVAL;
  380. }
  381. if (len == 1)
  382. {
  383. if (write)
  384. {
  385. return sdio_io_rw_direct(sbus->sdio_dev, write,
  386. function, address, *buf, NULL);
  387. }
  388. return sdio_io_rw_direct(sbus->sdio_dev, write,
  389. function, address, 0, buf);
  390. }
  391. /* Find best block settings for transfer */
  392. if (len >= 64)
  393. {
  394. /* Use block mode */
  395. blocklen = 64;
  396. nblocks = (len+63) / 64;
  397. }
  398. else
  399. {
  400. /* Use byte mode */
  401. blocklen = bcmf_sdio_find_block_size(len);
  402. nblocks = 0;
  403. }
  404. return sdio_io_rw_extended(sbus->sdio_dev, write,
  405. function, address, true, buf, blocklen, nblocks);
  406. }
  407. /****************************************************************************
  408. * Name: bcmf_read_reg
  409. ****************************************************************************/
  410. int bcmf_read_reg(FAR struct bcmf_sdio_dev_s *sbus, uint8_t function,
  411. uint32_t address, uint8_t *reg)
  412. {
  413. *reg = 0;
  414. return bcmf_transfer_bytes(sbus, false, function, address, reg, 1);
  415. }
  416. /****************************************************************************
  417. * Name: bcmf_write_reg
  418. ****************************************************************************/
  419. int bcmf_write_reg(FAR struct bcmf_sdio_dev_s *sbus, uint8_t function,
  420. uint32_t address, uint8_t reg)
  421. {
  422. return bcmf_transfer_bytes(sbus, true, function, address, &reg, 1);
  423. }
  424. /****************************************************************************
  425. * Name: bcmf_bus_sdio_initialize
  426. ****************************************************************************/
  427. int bcmf_bus_sdio_initialize(FAR struct bcmf_dev_s *priv,
  428. int minor, FAR struct sdio_dev_s *dev)
  429. {
  430. int ret;
  431. FAR struct bcmf_sdio_dev_s *sbus;
  432. /* Allocate sdio bus structure */
  433. sbus = (FAR struct bcmf_sdio_dev_s *)kmm_malloc(sizeof(*sbus));
  434. if (!sbus)
  435. {
  436. return -ENOMEM;
  437. }
  438. /* Initialize sdio bus device structure */
  439. memset(sbus, 0, sizeof(*sbus));
  440. sbus->sdio_dev = dev;
  441. sbus->minor = minor;
  442. sbus->ready = false;
  443. sbus->sleeping = true;
  444. sbus->bus.txframe = bcmf_sdpcm_queue_frame;
  445. sbus->bus.rxframe = bcmf_sdpcm_get_rx_frame;
  446. sbus->bus.allocate_frame = bcmf_sdpcm_alloc_frame;
  447. sbus->bus.free_frame = bcmf_sdpcm_free_frame;
  448. sbus->bus.stop = NULL; // TODO
  449. /* Init transmit frames queue */
  450. if ((ret = sem_init(&sbus->queue_mutex, 0, 1)) != OK)
  451. {
  452. goto exit_free_bus;
  453. }
  454. sq_init(&sbus->tx_queue);
  455. sq_init(&sbus->rx_queue);
  456. sq_init(&sbus->free_queue);
  457. /* Setup free buffer list */
  458. // FIXME this should be static to driver
  459. for (ret = 0; ret < BCMF_PKT_POOL_SIZE; ret++)
  460. {
  461. bcmf_dqueue_push(&sbus->free_queue, &g_pktframes[ret].list_entry);
  462. }
  463. /* Init thread semaphore */
  464. if ((ret = sem_init(&sbus->thread_signal, 0, 0)) != OK)
  465. {
  466. goto exit_free_bus;
  467. }
  468. if ((ret = sem_setprotocol(&sbus->thread_signal, SEM_PRIO_NONE)) != OK)
  469. {
  470. goto exit_free_bus;
  471. }
  472. /* Init thread waitdog */
  473. sbus->waitdog = wd_create();
  474. if (!sbus->waitdog)
  475. {
  476. ret = -ENOMEM;
  477. goto exit_free_bus;
  478. }
  479. /* Initialize device hardware */
  480. ret = bcmf_hwinitialize(sbus);
  481. if (ret != OK)
  482. {
  483. goto exit_free_waitdog;
  484. }
  485. /* Probe device */
  486. ret = bcmf_probe(sbus);
  487. if (ret != OK)
  488. {
  489. goto exit_uninit_hw;
  490. }
  491. /* Initialize device bus */
  492. ret = bcmf_businitialize(sbus);
  493. if (ret != OK)
  494. {
  495. goto exit_uninit_hw;
  496. }
  497. up_mdelay(100);
  498. sbus->ready = true;
  499. ret = bcmf_bus_setup_interrupts(sbus);
  500. if (ret != OK)
  501. {
  502. goto exit_uninit_hw;
  503. }
  504. /* FIXME global variable for now */
  505. g_sdio_priv = priv;
  506. /* Register sdio bus */
  507. priv->bus = &sbus->bus;
  508. /* Start the waitdog timer */
  509. wd_start(sbus->waitdog, BCMF_WAITDOG_TIMEOUT_TICK, bcmf_sdio_waitdog_timeout,
  510. (wdparm_t)priv);
  511. /* Spawn bcmf daemon thread */
  512. ret = kernel_thread(BCMF_THREAD_NAME, SCHED_PRIORITY_MAX,
  513. BCMF_THREAD_STACK_SIZE, bcmf_sdio_thread,
  514. (FAR char * const *)NULL);
  515. if (ret <= 0)
  516. {
  517. wlerr("Cannot spawn bcmf thread\n");
  518. ret = -EBADE;
  519. goto exit_uninit_hw;
  520. }
  521. sbus->thread_id = ret;
  522. /* sdio bus is up and running */
  523. return OK;
  524. exit_uninit_hw:
  525. bcmf_hwuninitialize(sbus);
  526. exit_free_waitdog:
  527. wd_delete(sbus->waitdog);
  528. exit_free_bus:
  529. kmm_free(sbus);
  530. priv->bus = NULL;
  531. return ret;
  532. }
  533. int bcmf_chipinitialize(FAR struct bcmf_sdio_dev_s *sbus)
  534. {
  535. int ret;
  536. uint32_t value = 0;
  537. ret = bcmf_read_sbregw(sbus, SI_ENUM_BASE, &value);
  538. if (ret != OK)
  539. {
  540. return ret;
  541. }
  542. int chipid = value & 0xffff;
  543. switch (chipid)
  544. {
  545. #ifdef CONFIG_IEEE80211_BROADCOM_BCM43362
  546. case SDIO_DEVICE_ID_BROADCOM_43362:
  547. wlinfo("bcm43362 chip detected\n");
  548. sbus->chip = (struct bcmf_sdio_chip *)&bcmf_43362_config_sdio;
  549. break;
  550. #endif
  551. default:
  552. wlerr("chip 0x%x is not supported\n", chipid);
  553. return -ENODEV;
  554. }
  555. return OK;
  556. }
  557. void bcmf_sdio_waitdog_timeout(int argc, wdparm_t arg1, ...)
  558. {
  559. FAR struct bcmf_dev_s *priv = (FAR struct bcmf_dev_s *)arg1;
  560. FAR struct bcmf_sdio_dev_s *sbus = (FAR struct bcmf_sdio_dev_s *)priv->bus;
  561. /* Notify bcmf thread */
  562. wlinfo("Notify bcmf thread\n");
  563. sem_post(&sbus->thread_signal);
  564. }
  565. int bcmf_sdio_thread(int argc, char **argv)
  566. {
  567. int ret;
  568. FAR struct bcmf_dev_s *priv = g_sdio_priv;
  569. FAR struct bcmf_sdio_dev_s *sbus = (FAR struct bcmf_sdio_dev_s *)priv->bus;
  570. wlinfo("Enter\n");
  571. /* FIXME wait for the chip to be ready to receive commands */
  572. up_mdelay(50);
  573. while (sbus->ready)
  574. {
  575. /* Wait for event (device interrupt, user request or waitdog timer) */
  576. ret = sem_wait(&sbus->thread_signal);
  577. if (ret != OK)
  578. {
  579. wlerr("Error while waiting for semaphore\n");
  580. break;
  581. }
  582. /* Restart the waitdog timer */
  583. wd_start(sbus->waitdog, BCMF_WAITDOG_TIMEOUT_TICK,
  584. bcmf_sdio_waitdog_timeout, (wdparm_t)priv);
  585. /* Wake up device */
  586. bcmf_sdio_bus_sleep(sbus, false);
  587. if (sbus->irq_pending)
  588. {
  589. /* Woken up by interrupt, read device status */
  590. sbus->irq_pending = false;
  591. bcmf_read_sbregw(sbus,
  592. CORE_BUS_REG(sbus->chip->core_base[SDIOD_CORE_ID],
  593. intstatus), &sbus->intstatus);
  594. /* Clear interrupts */
  595. bcmf_write_sbregw(sbus,
  596. CORE_BUS_REG(sbus->chip->core_base[SDIOD_CORE_ID],
  597. intstatus), sbus->intstatus);
  598. // wlinfo("intstatus %x\n", sbus->intstatus);
  599. }
  600. /* On frame indication, read available frames */
  601. if (sbus->intstatus & I_HMB_FRAME_IND)
  602. {
  603. // wlinfo("Frames available\n");
  604. do
  605. {
  606. ret = bcmf_sdpcm_readframe(priv);
  607. }
  608. while (ret == OK);
  609. if (ret == -ENODATA)
  610. {
  611. /* All frames processed */
  612. sbus->intstatus &= ~I_HMB_FRAME_IND;
  613. }
  614. }
  615. /* Send all queued frames */
  616. do
  617. {
  618. ret = bcmf_sdpcm_sendframe(priv);
  619. }
  620. while (ret == OK);
  621. /* Check if RX frames are available */
  622. if (sbus->intstatus & I_HMB_FRAME_IND)
  623. {
  624. /* Try again */
  625. wlinfo("Try read again\n");
  626. continue;
  627. }
  628. /* If we're done for now, turn off clock request. */
  629. // TODO add wakelock
  630. // bcmf_sdio_bus_sleep(sbus, true);
  631. }
  632. wlinfo("Exit\n");
  633. return 0;
  634. }
  635. struct bcmf_sdio_frame *bcmf_sdio_allocate_frame(FAR struct bcmf_dev_s *priv,
  636. bool block, bool tx)
  637. {
  638. FAR struct bcmf_sdio_dev_s *sbus = (FAR struct bcmf_sdio_dev_s *)priv->bus;
  639. struct bcmf_sdio_frame *sframe;
  640. dq_entry_t *entry = NULL;
  641. while (1)
  642. {
  643. if (sem_wait(&sbus->queue_mutex))
  644. {
  645. PANIC();
  646. }
  647. // if (!tx || sbus->tx_queue_count < BCMF_PKT_POOL_SIZE-1)
  648. {
  649. if ((entry = bcmf_dqueue_pop_tail(&sbus->free_queue)) != NULL)
  650. {
  651. if (tx)
  652. {
  653. sbus->tx_queue_count += 1;
  654. }
  655. sem_post(&sbus->queue_mutex);
  656. break;
  657. }
  658. }
  659. sem_post(&sbus->queue_mutex);
  660. if (block)
  661. {
  662. // TODO use signaling semaphore
  663. wlinfo("alloc failed %d\n", tx);
  664. up_mdelay(100);
  665. continue;
  666. }
  667. wlinfo("No avail buffer\n");
  668. return NULL;
  669. }
  670. sframe = container_of(entry, struct bcmf_sdio_frame, list_entry);
  671. sframe->header.len = HEADER_SIZE + MAX_NET_DEV_MTU;
  672. sframe->header.base = sframe->data;
  673. sframe->header.data = sframe->data;
  674. sframe->tx = tx;
  675. return sframe;
  676. }
  677. void bcmf_sdio_free_frame(FAR struct bcmf_dev_s *priv,
  678. struct bcmf_sdio_frame *sframe)
  679. {
  680. // wlinfo("free %p\n", sframe);
  681. FAR struct bcmf_sdio_dev_s *sbus = (FAR struct bcmf_sdio_dev_s *)priv->bus;
  682. if (sem_wait(&sbus->queue_mutex))
  683. {
  684. PANIC();
  685. }
  686. bcmf_dqueue_push(&sbus->free_queue, &sframe->list_entry);
  687. if (sframe->tx)
  688. {
  689. sbus->tx_queue_count -= 1;
  690. }
  691. sem_post(&sbus->queue_mutex);
  692. }