card->reg = data->reg;
card->max_ports = data->max_ports;
card->mp_agg_pkt_limit = data->mp_agg_pkt_limit;
+ card->supports_sdio_new_mode = data->supports_sdio_new_mode;
+ card->has_control_mask = data->has_control_mask;
}
sdio_claim_host(func);
#define SDIO_DEVICE_ID_MARVELL_8787 (0x9119)
/* Device ID for SD8797 */
#define SDIO_DEVICE_ID_MARVELL_8797 (0x9129)
+/* Device ID for SD8897 */
+#define SDIO_DEVICE_ID_MARVELL_8897 (0x912d)
/* WLAN IDs */
static const struct sdio_device_id mwifiex_ids[] = {
.driver_data = (unsigned long) &mwifiex_sdio_sd8787},
{SDIO_DEVICE(SDIO_VENDOR_ID_MARVELL, SDIO_DEVICE_ID_MARVELL_8797),
.driver_data = (unsigned long) &mwifiex_sdio_sd8797},
+ {SDIO_DEVICE(SDIO_VENDOR_ID_MARVELL, SDIO_DEVICE_ID_MARVELL_8897),
+ .driver_data = (unsigned long) &mwifiex_sdio_sd8897},
{},
};
}
/*
- * This function initializes the IO ports.
+ * This function is used to initialize IO ports for the
+ * chipsets supporting SDIO new mode eg SD8897.
+ */
+static int mwifiex_init_sdio_new_mode(struct mwifiex_adapter *adapter)
+{
+ u8 reg;
+
+ adapter->ioport = MEM_PORT;
+
+ /* enable sdio new mode */
+ if (mwifiex_read_reg(adapter, CARD_CONFIG_2_1_REG, ®))
+ return -1;
+ if (mwifiex_write_reg(adapter, CARD_CONFIG_2_1_REG,
+ reg | CMD53_NEW_MODE))
+ return -1;
+
+ /* Configure cmd port and enable reading rx length from the register */
+ if (mwifiex_read_reg(adapter, CMD_CONFIG_0, ®))
+ return -1;
+ if (mwifiex_write_reg(adapter, CMD_CONFIG_0, reg | CMD_PORT_RD_LEN_EN))
+ return -1;
+
+ /* Enable Dnld/Upld ready auto reset for cmd port after cmd53 is
+ * completed
+ */
+ if (mwifiex_read_reg(adapter, CMD_CONFIG_1, ®))
+ return -1;
+ if (mwifiex_write_reg(adapter, CMD_CONFIG_1, reg | CMD_PORT_AUTO_EN))
+ return -1;
+
+ return 0;
+}
+
+/* This function initializes the IO ports.
*
* The following operations are performed -
* - Read the IO ports (0, 1 and 2)
adapter->ioport = 0;
+ if (card->supports_sdio_new_mode) {
+ if (mwifiex_init_sdio_new_mode(adapter))
+ return -1;
+ goto cont;
+ }
+
/* Read the IO port */
if (!mwifiex_read_reg(adapter, IO_PORT_0_REG, ®))
adapter->ioport |= (reg & 0xff);
adapter->ioport |= ((reg & 0xff) << 16);
else
return -1;
-
+cont:
pr_debug("info: SDIO FUNC1 IO port: %#x\n", adapter->ioport);
/* Set Host interrupt reset to read to clear */
dev_dbg(adapter->dev, "data: mp_rd_bitmap=0x%08x\n", rd_bitmap);
- if (!(rd_bitmap & (CTRL_PORT_MASK | reg->data_port_mask)))
- return -1;
+ if (card->supports_sdio_new_mode) {
+ if (!(rd_bitmap & reg->data_port_mask))
+ return -1;
+ } else {
+ if (!(rd_bitmap & (CTRL_PORT_MASK | reg->data_port_mask)))
+ return -1;
+ }
- if (card->mp_rd_bitmap & CTRL_PORT_MASK) {
+ if ((card->has_control_mask) &&
+ (card->mp_rd_bitmap & CTRL_PORT_MASK)) {
card->mp_rd_bitmap &= (u32) (~CTRL_PORT_MASK);
*port = CTRL_PORT;
dev_dbg(adapter->dev, "data: port=%d mp_rd_bitmap=0x%08x\n",
* increased (provided it does not reach the maximum limit, in which
* case it is reset to 1)
*/
-static int mwifiex_get_wr_port_data(struct mwifiex_adapter *adapter, u8 *port)
+static int mwifiex_get_wr_port_data(struct mwifiex_adapter *adapter, u32 *port)
{
struct sdio_mmc_card *card = adapter->card;
+ const struct mwifiex_sdio_card_reg *reg = card->reg;
u32 wr_bitmap = card->mp_wr_bitmap;
dev_dbg(adapter->dev, "data: mp_wr_bitmap=0x%08x\n", wr_bitmap);
- if (!(wr_bitmap & card->mp_data_port_mask))
+ if (card->supports_sdio_new_mode &&
+ !(wr_bitmap & reg->data_port_mask)) {
+ adapter->data_sent = true;
+ return -EBUSY;
+ } else if (!card->supports_sdio_new_mode &&
+ !(wr_bitmap & card->mp_data_port_mask)) {
return -1;
+ }
if (card->mp_wr_bitmap & (1 << card->curr_wr_port)) {
card->mp_wr_bitmap &= (u32) (~(1 << card->curr_wr_port));
*port = card->curr_wr_port;
- if (++card->curr_wr_port == card->mp_end_port)
- card->curr_wr_port = card->reg->start_wr_port;
+ if (((card->supports_sdio_new_mode) &&
+ (++card->curr_wr_port == card->max_ports)) ||
+ ((!card->supports_sdio_new_mode) &&
+ (++card->curr_wr_port == card->mp_end_port)))
+ card->curr_wr_port = reg->start_wr_port;
} else {
adapter->data_sent = true;
return -EBUSY;
}
- if (*port == CTRL_PORT) {
+ if ((card->has_control_mask) && (*port == CTRL_PORT)) {
dev_err(adapter->dev,
"invalid data port=%d cur port=%d mp_wr_bitmap=0x%08x -> 0x%08x\n",
*port, card->curr_wr_port, wr_bitmap,
if (sdio_ireg) {
/*
* DN_LD_HOST_INT_STATUS and/or UP_LD_HOST_INT_STATUS
+ * For SDIO new mode CMD port interrupts
+ * DN_LD_CMD_PORT_HOST_INT_STATUS and/or
+ * UP_LD_CMD_PORT_HOST_INT_STATUS
* Clear the interrupt status register
*/
dev_dbg(adapter->dev, "int: sdio_ireg = %#x\n", sdio_ireg);
s32 f_aggr_cur = 0;
struct sk_buff *skb_deaggr;
u32 pind;
- u32 pkt_len, pkt_type = 0;
+ u32 pkt_len, pkt_type, mport;
u8 *curr_ptr;
u32 rx_len = skb->len;
- if (port == CTRL_PORT) {
+ if ((card->has_control_mask) && (port == CTRL_PORT)) {
/* Read the command Resp without aggr */
dev_dbg(adapter->dev, "info: %s: no aggregation for cmd "
"response\n", __func__);
goto rx_curr_single;
}
- if (card->mp_rd_bitmap & (~((u32) CTRL_PORT_MASK))) {
+ if ((!card->has_control_mask && (card->mp_rd_bitmap &
+ card->reg->data_port_mask)) ||
+ (card->has_control_mask && (card->mp_rd_bitmap &
+ (~((u32) CTRL_PORT_MASK))))) {
/* Some more data RX pending */
dev_dbg(adapter->dev, "info: %s: not last packet\n", __func__);
if (f_aggr_cur) {
dev_dbg(adapter->dev, "info: current packet aggregation\n");
/* Curr pkt can be aggregated */
- MP_RX_AGGR_SETUP(card, skb, port);
+ mp_rx_aggr_setup(card, skb, port);
if (MP_RX_AGGR_PKT_LIMIT_REACHED(card) ||
- MP_RX_AGGR_PORT_LIMIT_REACHED(card)) {
+ mp_rx_aggr_port_limit_reached(card)) {
dev_dbg(adapter->dev, "info: %s: aggregated packet "
"limit reached\n", __func__);
/* No more pkts allowed in Aggr buf, rx it */
dev_dbg(adapter->dev, "info: do_rx_aggr: num of packets: %d\n",
card->mpa_rx.pkt_cnt);
+ if (card->supports_sdio_new_mode) {
+ int i;
+ u32 port_count;
+
+ for (i = 0, port_count = 0; i < card->max_ports; i++)
+ if (card->mpa_rx.ports & BIT(i))
+ port_count++;
+
+ /* Reading data from "start_port + 0" to "start_port +
+ * port_count -1", so decrease the count by 1
+ */
+ port_count--;
+ mport = (adapter->ioport | SDIO_MPA_ADDR_BASE |
+ (port_count << 8)) + card->mpa_rx.start_port;
+ } else {
+ mport = (adapter->ioport | SDIO_MPA_ADDR_BASE |
+ (card->mpa_rx.ports << 4)) +
+ card->mpa_rx.start_port;
+ }
+
if (mwifiex_read_data_sync(adapter, card->mpa_rx.buf,
- card->mpa_rx.buf_len,
- (adapter->ioport | 0x1000 |
- (card->mpa_rx.ports << 4)) +
- card->mpa_rx.start_port, 1))
+ card->mpa_rx.buf_len, mport, 1))
goto error;
curr_ptr = card->mpa_rx.buf;
u32 rx_blocks;
u16 rx_len;
unsigned long flags;
+ u32 bitmap;
+ u8 cr;
spin_lock_irqsave(&adapter->int_lock, flags);
sdio_ireg = adapter->int_status;
if (!sdio_ireg)
return ret;
+ /* Following interrupt is only for SDIO new mode */
+ if (sdio_ireg & DN_LD_CMD_PORT_HOST_INT_STATUS && adapter->cmd_sent)
+ adapter->cmd_sent = false;
+
+ /* Following interrupt is only for SDIO new mode */
+ if (sdio_ireg & UP_LD_CMD_PORT_HOST_INT_STATUS) {
+ u32 pkt_type;
+
+ /* read the len of control packet */
+ rx_len = card->mp_regs[CMD_RD_LEN_1] << 8;
+ rx_len |= (u16) card->mp_regs[CMD_RD_LEN_0];
+ rx_blocks = DIV_ROUND_UP(rx_len, MWIFIEX_SDIO_BLOCK_SIZE);
+ if (rx_len <= INTF_HEADER_LEN ||
+ (rx_blocks * MWIFIEX_SDIO_BLOCK_SIZE) >
+ MWIFIEX_RX_DATA_BUF_SIZE)
+ return -1;
+ rx_len = (u16) (rx_blocks * MWIFIEX_SDIO_BLOCK_SIZE);
+
+ skb = dev_alloc_skb(rx_len);
+ if (!skb)
+ return -1;
+
+ skb_put(skb, rx_len);
+
+ if (mwifiex_sdio_card_to_host(adapter, &pkt_type, skb->data,
+ skb->len, adapter->ioport |
+ CMD_PORT_SLCT)) {
+ dev_err(adapter->dev,
+ "%s: failed to card_to_host", __func__);
+ dev_kfree_skb_any(skb);
+ goto term_cmd;
+ }
+
+ if ((pkt_type != MWIFIEX_TYPE_CMD) &&
+ (pkt_type != MWIFIEX_TYPE_EVENT))
+ dev_err(adapter->dev,
+ "%s:Received wrong packet on cmd port",
+ __func__);
+
+ mwifiex_decode_rx_packet(adapter, skb, pkt_type);
+ }
+
if (sdio_ireg & DN_LD_HOST_INT_STATUS) {
- card->mp_wr_bitmap =
- ((u32) card->mp_regs[reg->wr_bitmap_u]) << 8;
- card->mp_wr_bitmap |=
- (u32) card->mp_regs[reg->wr_bitmap_l];
- dev_dbg(adapter->dev, "int: DNLD: wr_bitmap=0x%08x\n",
+ bitmap = (u32) card->mp_regs[reg->wr_bitmap_l];
+ bitmap |= ((u32) card->mp_regs[reg->wr_bitmap_u]) << 8;
+ if (card->supports_sdio_new_mode) {
+ bitmap |=
+ ((u32) card->mp_regs[reg->wr_bitmap_1l]) << 16;
+ bitmap |=
+ ((u32) card->mp_regs[reg->wr_bitmap_1u]) << 24;
+ }
+ card->mp_wr_bitmap = bitmap;
+
+ dev_dbg(adapter->dev, "int: DNLD: wr_bitmap=0x%x\n",
card->mp_wr_bitmap);
if (adapter->data_sent &&
(card->mp_wr_bitmap & card->mp_data_port_mask)) {
/* As firmware will not generate download ready interrupt if the port
updated is command port only, cmd_sent should be done for any SDIO
interrupt. */
- if (adapter->cmd_sent) {
+ if (card->has_control_mask && adapter->cmd_sent) {
/* Check if firmware has attach buffer at command port and
update just that in wr_bit_map. */
card->mp_wr_bitmap |=
dev_dbg(adapter->dev, "info: cmd_sent=%d data_sent=%d\n",
adapter->cmd_sent, adapter->data_sent);
if (sdio_ireg & UP_LD_HOST_INT_STATUS) {
- card->mp_rd_bitmap =
- ((u32) card->mp_regs[reg->rd_bitmap_u]) << 8;
- card->mp_rd_bitmap |= (u32) card->mp_regs[reg->rd_bitmap_l];
- dev_dbg(adapter->dev, "int: UPLD: rd_bitmap=0x%08x\n",
+ bitmap = (u32) card->mp_regs[reg->rd_bitmap_l];
+ bitmap |= ((u32) card->mp_regs[reg->rd_bitmap_u]) << 8;
+ if (card->supports_sdio_new_mode) {
+ bitmap |=
+ ((u32) card->mp_regs[reg->rd_bitmap_1l]) << 16;
+ bitmap |=
+ ((u32) card->mp_regs[reg->rd_bitmap_1u]) << 24;
+ }
+ card->mp_rd_bitmap = bitmap;
+ dev_dbg(adapter->dev, "int: UPLD: rd_bitmap=0x%x\n",
card->mp_rd_bitmap);
while (true) {
if (mwifiex_sdio_card_to_host_mp_aggr(adapter, skb,
port)) {
- u8 cr = 0;
-
dev_err(adapter->dev, "card_to_host_mpa failed:"
" int status=%#x\n", sdio_ireg);
- if (mwifiex_read_reg(adapter,
- CONFIGURATION_REG, &cr))
- dev_err(adapter->dev,
- "read CFG reg failed\n");
-
- dev_dbg(adapter->dev,
- "info: CFG reg val = %d\n", cr);
- if (mwifiex_write_reg(adapter,
- CONFIGURATION_REG,
- (cr | 0x04)))
- dev_err(adapter->dev,
- "write CFG reg failed\n");
-
- dev_dbg(adapter->dev, "info: write success\n");
- if (mwifiex_read_reg(adapter,
- CONFIGURATION_REG, &cr))
- dev_err(adapter->dev,
- "read CFG reg failed\n");
-
- dev_dbg(adapter->dev,
- "info: CFG reg val =%x\n", cr);
- return -1;
+ goto term_cmd;
}
}
}
return 0;
+
+term_cmd:
+ /* terminate cmd */
+ if (mwifiex_read_reg(adapter, CONFIGURATION_REG, &cr))
+ dev_err(adapter->dev, "read CFG reg failed\n");
+ else
+ dev_dbg(adapter->dev, "info: CFG reg val = %d\n", cr);
+
+ if (mwifiex_write_reg(adapter, CONFIGURATION_REG, (cr | 0x04)))
+ dev_err(adapter->dev, "write CFG reg failed\n");
+ else
+ dev_dbg(adapter->dev, "info: write success\n");
+
+ if (mwifiex_read_reg(adapter, CONFIGURATION_REG, &cr))
+ dev_err(adapter->dev, "read CFG reg failed\n");
+ else
+ dev_dbg(adapter->dev, "info: CFG reg val =%x\n", cr);
+
+ return -1;
}
/*
* and return.
*/
static int mwifiex_host_to_card_mp_aggr(struct mwifiex_adapter *adapter,
- u8 *payload, u32 pkt_len, u8 port,
+ u8 *payload, u32 pkt_len, u32 port,
u32 next_pkt_len)
{
struct sdio_mmc_card *card = adapter->card;
s32 f_send_cur_buf = 0;
s32 f_precopy_cur_buf = 0;
s32 f_postcopy_cur_buf = 0;
+ u32 mport;
- if ((!card->mpa_tx.enabled) || (port == CTRL_PORT)) {
+ if (!card->mpa_tx.enabled ||
+ (card->has_control_mask && (port == CTRL_PORT)) ||
+ (card->supports_sdio_new_mode && (port == CMD_PORT_SLCT))) {
dev_dbg(adapter->dev, "info: %s: tx aggregation disabled\n",
__func__);
__func__);
if (MP_TX_AGGR_IN_PROGRESS(card)) {
- if (!MP_TX_AGGR_PORT_LIMIT_REACHED(card) &&
+ if (!mp_tx_aggr_port_limit_reached(card) &&
MP_TX_AGGR_BUF_HAS_ROOM(card, pkt_len)) {
f_precopy_cur_buf = 1;
/* No room in Aggr buf, send it */
f_send_aggr_buf = 1;
- if (MP_TX_AGGR_PORT_LIMIT_REACHED(card) ||
+ if (mp_tx_aggr_port_limit_reached(card) ||
!(card->mp_wr_bitmap &
(1 << card->curr_wr_port)))
f_send_cur_buf = 1;
MP_TX_AGGR_BUF_PUT(card, payload, pkt_len, port);
if (MP_TX_AGGR_PKT_LIMIT_REACHED(card) ||
- MP_TX_AGGR_PORT_LIMIT_REACHED(card))
+ mp_tx_aggr_port_limit_reached(card))
/* No more pkts allowed in Aggr buf, send it */
f_send_aggr_buf = 1;
}
dev_dbg(adapter->dev, "data: %s: send aggr buffer: %d %d\n",
__func__,
card->mpa_tx.start_port, card->mpa_tx.ports);
+ if (card->supports_sdio_new_mode) {
+ u32 port_count;
+ int i;
+
+ for (i = 0, port_count = 0; i < card->max_ports; i++)
+ if (card->mpa_tx.ports & BIT(i))
+ port_count++;
+
+ /* Writing data from "start_port + 0" to "start_port +
+ * port_count -1", so decrease the count by 1
+ */
+ port_count--;
+ mport = (adapter->ioport | SDIO_MPA_ADDR_BASE |
+ (port_count << 8)) + card->mpa_tx.start_port;
+ } else {
+ mport = (adapter->ioport | SDIO_MPA_ADDR_BASE |
+ (card->mpa_tx.ports << 4)) +
+ card->mpa_tx.start_port;
+ }
+
ret = mwifiex_write_data_to_card(adapter, card->mpa_tx.buf,
- card->mpa_tx.buf_len,
- (adapter->ioport | 0x1000 |
- (card->mpa_tx.ports << 4)) +
- card->mpa_tx.start_port);
+ card->mpa_tx.buf_len, mport);
MP_TX_AGGR_BUF_RESET(card);
}
int ret;
u32 buf_block_len;
u32 blk_size;
- u8 port = CTRL_PORT;
+ u32 port = CTRL_PORT;
u8 *payload = (u8 *)skb->data;
u32 pkt_len = skb->len;
pkt_len > MWIFIEX_UPLD_SIZE)
dev_err(adapter->dev, "%s: payload=%p, nb=%d\n",
__func__, payload, pkt_len);
+
+ if (card->supports_sdio_new_mode)
+ port = CMD_PORT_SLCT;
}
/* Transfer data to card */
if (!card->mp_regs)
return -ENOMEM;
+ /* Allocate skb pointer buffers */
+ card->mpa_rx.skb_arr = kzalloc((sizeof(void *)) *
+ card->mp_agg_pkt_limit, GFP_KERNEL);
+ card->mpa_rx.len_arr = kzalloc(sizeof(*card->mpa_rx.len_arr) *
+ card->mp_agg_pkt_limit, GFP_KERNEL);
ret = mwifiex_alloc_sdio_mpa_buffers(adapter,
SDIO_MP_TX_AGGR_DEF_BUF_SIZE,
SDIO_MP_RX_AGGR_DEF_BUF_SIZE);
struct sdio_mmc_card *card = adapter->card;
kfree(card->mp_regs);
+ kfree(card->mpa_rx.skb_arr);
+ kfree(card->mpa_rx.len_arr);
kfree(card->mpa_tx.buf);
kfree(card->mpa_rx.buf);
}
card->mp_data_port_mask = reg->data_port_mask;
- for (i = 1; i <= card->max_ports - card->mp_end_port; i++)
- card->mp_data_port_mask &= ~(1 << (card->max_ports - i));
+ if (reg->start_wr_port) {
+ for (i = 1; i <= card->max_ports - card->mp_end_port; i++)
+ card->mp_data_port_mask &=
+ ~(1 << (card->max_ports - i));
+ }
card->curr_wr_port = reg->start_wr_port;
MODULE_FIRMWARE(SD8786_DEFAULT_FW_NAME);
MODULE_FIRMWARE(SD8787_DEFAULT_FW_NAME);
MODULE_FIRMWARE(SD8797_DEFAULT_FW_NAME);
+MODULE_FIRMWARE(SD8897_DEFAULT_FW_NAME);