RTL88x2BU-Linux-Driver/hal/halmac/halmac_88xx/halmac_usb_88xx.c

521 lines
13 KiB
C
Raw Normal View History

/******************************************************************************
*
* Copyright(c) 2016 - 2018 Realtek Corporation. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of version 2 of the GNU General Public License as
* published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
******************************************************************************/
#include "halmac_usb_88xx.h"
2019-09-21 09:30:30 +00:00
#if (HALMAC_88XX_SUPPORT && HALMAC_USB_SUPPORT)
enum usb_burst_size {
USB_BURST_SIZE_3_0 = 0x0,
USB_BURST_SIZE_2_0_HS = 0x1,
USB_BURST_SIZE_2_0_FS = 0x2,
USB_BURST_SIZE_2_0_OTHERS = 0x3,
USB_BURST_SIZE_UNDEFINE = 0x7F,
};
/**
* init_usb_cfg_88xx() - init USB
* @adapter : the adapter of halmac
* Author : KaiYuan Chang/Ivan Lin
* Return : enum halmac_ret_status
* More details of status code can be found in prototype document
*/
enum halmac_ret_status
init_usb_cfg_88xx(struct halmac_adapter *adapter)
{
u8 value8 = 0;
struct halmac_api *api = (struct halmac_api *)adapter->halmac_api;
PLTFM_MSG_TRACE("[TRACE]%s ===>\n", __func__);
value8 |= (BIT_DMA_MODE | (0x3 << BIT_SHIFT_BURST_CNT));
if (HALMAC_REG_R8(REG_SYS_CFG2 + 3) == 0x20) {
/* usb3.0 */
value8 |= (USB_BURST_SIZE_3_0 << BIT_SHIFT_BURST_SIZE);
} else {
if ((HALMAC_REG_R8(REG_USB_USBSTAT) & 0x3) == 0x1)/* usb2.0 */
value8 |= USB_BURST_SIZE_2_0_HS << BIT_SHIFT_BURST_SIZE;
else /* usb1.1 */
value8 |= USB_BURST_SIZE_2_0_FS << BIT_SHIFT_BURST_SIZE;
}
HALMAC_REG_W8(REG_RXDMA_MODE, value8);
2019-09-21 09:30:30 +00:00
HALMAC_REG_W16_SET(REG_TXDMA_OFFSET_CHK, BIT_DROP_DATA_EN);
PLTFM_MSG_TRACE("[TRACE]%s <===\n", __func__);
return HALMAC_RET_SUCCESS;
}
/**
* deinit_usb_cfg_88xx() - deinit USB
* @adapter : the adapter of halmac
* Author : KaiYuan Chang/Ivan Lin
* Return : enum halmac_ret_status
* More details of status code can be found in prototype document
*/
enum halmac_ret_status
deinit_usb_cfg_88xx(struct halmac_adapter *adapter)
{
return HALMAC_RET_SUCCESS;
}
/**
* cfg_usb_rx_agg_88xx() - config rx aggregation
* @adapter : the adapter of halmac
* @halmac_rx_agg_mode
* Author : KaiYuan Chang/Ivan Lin
* Return : enum halmac_ret_status
* More details of status code can be found in prototype document
*/
enum halmac_ret_status
cfg_usb_rx_agg_88xx(struct halmac_adapter *adapter,
struct halmac_rxagg_cfg *cfg)
{
u8 dma_usb_agg;
u8 size;
u8 timeout;
u8 agg_enable;
u32 value32;
struct halmac_api *api = (struct halmac_api *)adapter->halmac_api;
PLTFM_MSG_TRACE("[TRACE]%s ===>\n", __func__);
dma_usb_agg = HALMAC_REG_R8(REG_RXDMA_AGG_PG_TH + 3);
agg_enable = HALMAC_REG_R8(REG_TXDMA_PQ_MAP);
switch (cfg->mode) {
case HALMAC_RX_AGG_MODE_NONE:
agg_enable &= ~BIT_RXDMA_AGG_EN;
break;
case HALMAC_RX_AGG_MODE_DMA:
agg_enable |= BIT_RXDMA_AGG_EN;
dma_usb_agg |= BIT(7);
break;
case HALMAC_RX_AGG_MODE_USB:
agg_enable |= BIT_RXDMA_AGG_EN;
dma_usb_agg &= ~BIT(7);
break;
default:
PLTFM_MSG_ERR("[ERR]unsupported mode\n");
agg_enable &= ~BIT_RXDMA_AGG_EN;
break;
}
2019-09-21 09:30:30 +00:00
if (cfg->threshold.drv_define == 0) {
if (HALMAC_REG_R8(REG_SYS_CFG2 + 3) == 0x20) {
/* usb3.0 */
size = 0x5;
timeout = 0xA;
} else {
/* usb2.0 */
size = 0x5;
timeout = 0x20;
}
} else {
size = cfg->threshold.size;
timeout = cfg->threshold.timeout;
}
value32 = HALMAC_REG_R32(REG_RXDMA_AGG_PG_TH);
2019-09-21 09:30:30 +00:00
if (cfg->threshold.size_limit_en == 0)
HALMAC_REG_W32(REG_RXDMA_AGG_PG_TH, value32 & ~BIT_EN_PRE_CALC);
else
HALMAC_REG_W32(REG_RXDMA_AGG_PG_TH, value32 | BIT_EN_PRE_CALC);
HALMAC_REG_W8(REG_TXDMA_PQ_MAP, agg_enable);
HALMAC_REG_W8(REG_RXDMA_AGG_PG_TH + 3, dma_usb_agg);
HALMAC_REG_W16(REG_RXDMA_AGG_PG_TH,
(u16)(size | (timeout << BIT_SHIFT_DMA_AGG_TO_V1)));
PLTFM_MSG_TRACE("[TRACE]%s <===\n", __func__);
return HALMAC_RET_SUCCESS;
}
/**
* reg_r8_usb_88xx() - read 1byte register
* @adapter : the adapter of halmac
* @offset : register offset
* Author : KaiYuan Chang/Ivan Lin
* Return : enum halmac_ret_status
* More details of status code can be found in prototype document
*/
u8
reg_r8_usb_88xx(struct halmac_adapter *adapter, u32 offset)
{
2019-09-21 09:30:30 +00:00
return PLTFM_REG_R8(offset);
}
/**
* reg_w8_usb_88xx() - write 1byte register
* @adapter : the adapter of halmac
* @offset : register offset
* @value : register value
* Author : KaiYuan Chang/Ivan Lin
* Return : enum halmac_ret_status
* More details of status code can be found in prototype document
*/
enum halmac_ret_status
reg_w8_usb_88xx(struct halmac_adapter *adapter, u32 offset, u8 value)
{
PLTFM_REG_W8(offset, value);
return HALMAC_RET_SUCCESS;
}
/**
* reg_r16_usb_88xx() - read 2byte register
* @adapter : the adapter of halmac
* @offset : register offset
* Author : KaiYuan Chang/Ivan Lin
* Return : enum halmac_ret_status
* More details of status code can be found in prototype document
*/
u16
reg_r16_usb_88xx(struct halmac_adapter *adapter, u32 offset)
{
2019-09-21 09:30:30 +00:00
return PLTFM_REG_R16(offset);
}
/**
* reg_w16_usb_88xx() - write 2byte register
* @adapter : the adapter of halmac
* @offset : register offset
* @value : register value
* Author : KaiYuan Chang/Ivan Lin
* Return : enum halmac_ret_status
* More details of status code can be found in prototype document
*/
enum halmac_ret_status
reg_w16_usb_88xx(struct halmac_adapter *adapter, u32 offset, u16 value)
{
PLTFM_REG_W16(offset, value);
return HALMAC_RET_SUCCESS;
}
/**
* reg_r32_usb_88xx() - read 4byte register
* @adapter : the adapter of halmac
* @offset : register offset
* Author : KaiYuan Chang/Ivan Lin
* Return : enum halmac_ret_status
* More details of status code can be found in prototype document
*/
u32
reg_r32_usb_88xx(struct halmac_adapter *adapter, u32 offset)
{
2019-09-21 09:30:30 +00:00
return PLTFM_REG_R32(offset);
}
/**
* reg_w32_usb_88xx() - write 4byte register
* @adapter : the adapter of halmac
* @offset : register offset
* @value : register value
* Author : KaiYuan Chang/Ivan Lin
* Return : enum halmac_ret_status
* More details of status code can be found in prototype document
*/
enum halmac_ret_status
reg_w32_usb_88xx(struct halmac_adapter *adapter, u32 offset, u32 value)
{
PLTFM_REG_W32(offset, value);
return HALMAC_RET_SUCCESS;
}
/**
* set_usb_bulkout_num_88xx() - inform bulk-out num
* @adapter : the adapter of halmac
* @bulkout_num : usb bulk-out number
* Author : KaiYuan Chang
* Return : enum halmac_ret_status
* More details of status code can be found in prototype document
*/
enum halmac_ret_status
set_usb_bulkout_num_88xx(struct halmac_adapter *adapter, u8 num)
{
adapter->bulkout_num = num;
return HALMAC_RET_SUCCESS;
}
/**
* get_usb_bulkout_id_88xx() - get bulk out id for the TX packet
* @adapter : the adapter of halmac
* @buf : tx packet, include txdesc
* @size : tx packet size
* @id : usb bulk-out id
* Author : KaiYuan Chang
* Return : enum halmac_ret_status
* More details of status code can be found in prototype document
*/
enum halmac_ret_status
get_usb_bulkout_id_88xx(struct halmac_adapter *adapter, u8 *buf, u32 size,
u8 *id)
{
enum halmac_qsel queue_sel;
enum halmac_dma_mapping dma_mapping;
PLTFM_MSG_TRACE("[TRACE]%s ===>\n", __func__);
if (!buf) {
PLTFM_MSG_ERR("[ERR]buf is NULL!!\n");
return HALMAC_RET_DATA_BUF_NULL;
}
if (size == 0) {
PLTFM_MSG_ERR("[ERR]size is 0!!\n");
return HALMAC_RET_DATA_SIZE_INCORRECT;
}
queue_sel = (enum halmac_qsel)GET_TX_DESC_QSEL(buf);
switch (queue_sel) {
case HALMAC_QSEL_VO:
case HALMAC_QSEL_VO_V2:
dma_mapping = adapter->pq_map[HALMAC_PQ_MAP_VO];
break;
case HALMAC_QSEL_VI:
case HALMAC_QSEL_VI_V2:
dma_mapping = adapter->pq_map[HALMAC_PQ_MAP_VI];
break;
case HALMAC_QSEL_BE:
case HALMAC_QSEL_BE_V2:
dma_mapping = adapter->pq_map[HALMAC_PQ_MAP_BE];
break;
case HALMAC_QSEL_BK:
case HALMAC_QSEL_BK_V2:
dma_mapping = adapter->pq_map[HALMAC_PQ_MAP_BK];
break;
case HALMAC_QSEL_MGNT:
dma_mapping = adapter->pq_map[HALMAC_PQ_MAP_MG];
break;
case HALMAC_QSEL_HIGH:
case HALMAC_QSEL_BCN:
case HALMAC_QSEL_CMD:
dma_mapping = HALMAC_DMA_MAPPING_HIGH;
break;
default:
PLTFM_MSG_ERR("[ERR]Qsel is out of range\n");
return HALMAC_RET_QSEL_INCORRECT;
}
switch (dma_mapping) {
case HALMAC_DMA_MAPPING_HIGH:
*id = 0;
break;
case HALMAC_DMA_MAPPING_NORMAL:
*id = 1;
break;
case HALMAC_DMA_MAPPING_LOW:
*id = 2;
break;
case HALMAC_DMA_MAPPING_EXTRA:
*id = 3;
break;
default:
PLTFM_MSG_ERR("[ERR]out of range\n");
return HALMAC_RET_DMA_MAP_INCORRECT;
}
PLTFM_MSG_TRACE("[TRACE]%s <===\n", __func__);
return HALMAC_RET_SUCCESS;
}
/**
* cfg_txagg_usb_align_88xx() -config sdio bus tx agg alignment
* @adapter : the adapter of halmac
* @enable : function enable(1)/disable(0)
* @align_size : sdio bus tx agg alignment size (2^n, n = 3~11)
* Author : Soar Tu
* Return : enum halmac_ret_status
* More details of status code can be found in prototype document
*/
enum halmac_ret_status
cfg_txagg_usb_align_88xx(struct halmac_adapter *adapter, u8 enable,
u16 align_size)
{
return HALMAC_RET_NOT_SUPPORT;
}
/**
* tx_allowed_usb_88xx() - check tx status
* @adapter : the adapter of halmac
* @buf : tx packet, include txdesc
* @size : tx packet size, include txdesc
* Author : Ivan Lin
* Return : enum halmac_ret_status
* More details of status code can be found in prototype document
*/
enum halmac_ret_status
tx_allowed_usb_88xx(struct halmac_adapter *adapter, u8 *buf, u32 size)
{
return HALMAC_RET_NOT_SUPPORT;
}
/**
* usb_indirect_reg_r32_88xx() - read MAC reg by SDIO reg
* @adapter : the adapter of halmac
* @offset : register offset
* Author : Soar
* Return : enum halmac_ret_status
* More details of status code can be found in prototype document
*/
u32
usb_indirect_reg_r32_88xx(struct halmac_adapter *adapter, u32 offset)
{
return 0xFFFFFFFF;
}
/**
* usb_reg_rn_88xx() - read n byte register
* @adapter : the adapter of halmac
* @offset : register offset
* @size : register value size
* @value : register value
* Author : Soar
* Return : enum halmac_ret_status
* More details of status code can be found in prototype document
*/
enum halmac_ret_status
usb_reg_rn_88xx(struct halmac_adapter *adapter, u32 offset, u32 size,
u8 *value)
{
return HALMAC_RET_NOT_SUPPORT;
}
/**
* get_usb_tx_addr_88xx() - get CMD53 addr for the TX packet
* @adapter : the adapter of halmac
* @buf : tx packet, include txdesc
* @size : tx packet size
* @pcmd53_addr : cmd53 addr value
* Author : KaiYuan Chang/Ivan Lin
* Return : enum halmac_ret_status
* More details of status code can be found in prototype document
*/
enum halmac_ret_status
get_usb_tx_addr_88xx(struct halmac_adapter *adapter, u8 *buf, u32 size,
u32 *cmd53_addr)
{
return HALMAC_RET_NOT_SUPPORT;
}
enum halmac_ret_status
set_usb_mode_88xx(struct halmac_adapter *adapter, enum halmac_usb_mode mode)
{
u32 usb_tmp;
struct halmac_api *api = (struct halmac_api *)adapter->halmac_api;
enum halmac_usb_mode cur_mode;
cur_mode = (HALMAC_REG_R8(REG_SYS_CFG2 + 3) == 0x20) ?
HALMAC_USB_MODE_U3 : HALMAC_USB_MODE_U2;
2019-09-21 09:30:30 +00:00
/* check if HW supports usb2_usb3 switch */
usb_tmp = HALMAC_REG_R32(REG_PAD_CTRL2);
2019-09-21 09:30:30 +00:00
if (0 == (BIT_GET_USB23_SW_MODE_V1(usb_tmp) |
(usb_tmp & BIT_USB3_USB2_TRANSITION))) {
PLTFM_MSG_ERR("[ERR]u2/u3 switch\n");
return HALMAC_RET_USB2_3_SWITCH_UNSUPPORT;
}
if (mode == cur_mode) {
PLTFM_MSG_ERR("[ERR]u2/u3 unchange\n");
return HALMAC_RET_USB_MODE_UNCHANGE;
}
/* Enable IO wrapper timeout */
if (adapter->chip_id == HALMAC_CHIP_ID_8822B ||
adapter->chip_id == HALMAC_CHIP_ID_8821C)
HALMAC_REG_W8_CLR(REG_SW_MDIO + 3, BIT(0));
usb_tmp &= ~(BIT_USB23_SW_MODE_V1(0x3));
if (mode == HALMAC_USB_MODE_U2)
HALMAC_REG_W32(REG_PAD_CTRL2,
usb_tmp |
BIT_USB23_SW_MODE_V1(HALMAC_USB_MODE_U2) |
BIT_RSM_EN_V1);
else
HALMAC_REG_W32(REG_PAD_CTRL2,
usb_tmp |
BIT_USB23_SW_MODE_V1(HALMAC_USB_MODE_U3) |
BIT_RSM_EN_V1);
HALMAC_REG_W8(REG_PAD_CTRL2 + 1, 4);
HALMAC_REG_W16_SET(REG_SYS_PW_CTRL, BIT_APFM_OFFMAC);
PLTFM_DELAY_US(1000);
HALMAC_REG_W32_SET(REG_PAD_CTRL2, BIT_NO_PDN_CHIPOFF_V1);
return HALMAC_RET_SUCCESS;
}
enum halmac_ret_status
usbphy_write_88xx(struct halmac_adapter *adapter, u8 addr, u16 data, u8 speed)
{
struct halmac_api *api = (struct halmac_api *)adapter->halmac_api;
if (speed == HAL_INTF_PHY_USB3) {
HALMAC_REG_W8(0xff0d, (u8)data);
HALMAC_REG_W8(0xff0e, (u8)(data >> 8));
HALMAC_REG_W8(0xff0c, addr | BIT(7));
} else if (speed == HAL_INTF_PHY_USB2) {
HALMAC_REG_W8(0xfe41, (u8)data);
HALMAC_REG_W8(0xfe40, addr);
HALMAC_REG_W8(0xfe42, 0x81);
} else {
PLTFM_MSG_ERR("[ERR]Error USB Speed !\n");
return HALMAC_RET_NOT_SUPPORT;
}
return HALMAC_RET_SUCCESS;
}
u16
usbphy_read_88xx(struct halmac_adapter *adapter, u8 addr, u8 speed)
{
struct halmac_api *api = (struct halmac_api *)adapter->halmac_api;
u16 value = 0;
if (speed == HAL_INTF_PHY_USB3) {
HALMAC_REG_W8(0xff0c, addr | BIT(6));
value = (u16)(HALMAC_REG_R32(0xff0c) >> 8);
} else if (speed == HAL_INTF_PHY_USB2) {
2019-09-21 09:30:30 +00:00
if (addr >= 0xE0)
addr -= 0x20;
if (addr >= 0xC0 && addr <= 0xDF) {
HALMAC_REG_W8(0xfe40, addr);
HALMAC_REG_W8(0xfe42, 0x81);
value = HALMAC_REG_R8(0xfe43);
} else {
PLTFM_MSG_ERR("[ERR]phy offset\n");
return HALMAC_RET_NOT_SUPPORT;
}
} else {
PLTFM_MSG_ERR("[ERR]usb speed !\n");
return HALMAC_RET_NOT_SUPPORT;
}
return value;
}
#endif /* HALMAC_88XX_SUPPORT */