mirror of
https://git.codelinaro.org/clo/qsdk/oss/boot/u-boot-2016.git
synced 2025-12-10 07:44:53 +01:00
ipq5018: Add BT beaconing support
Signed-off-by: Rajkumar Ayyasamy <arajkuma@codeaurora.org> Change-Id: Ibe8dc716d0f4bafbbf1ec7f3b776bb4a6f891f45
This commit is contained in:
parent
5f474cadf3
commit
2343ff363f
7 changed files with 341 additions and 1 deletions
|
|
@ -550,6 +550,85 @@ int qca_scm_secure_authenticate(void *cmd_buf, size_t cmd_len)
|
|||
|
||||
return ret;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_IPQ_BT_SUPPORT
|
||||
int qti_scm_otp(u32 peripheral)
|
||||
{
|
||||
int ret;
|
||||
|
||||
if (is_scm_armv8())
|
||||
{
|
||||
struct qca_scm_desc desc = {0};
|
||||
|
||||
desc.arginfo = QCA_SCM_ARGS(1);
|
||||
desc.args[0] = peripheral;
|
||||
|
||||
ret = scm_call_64(SCM_SVC_PIL, SCM_CMD_OTP, &desc);
|
||||
}
|
||||
else
|
||||
{
|
||||
u32 cmd = peripheral;
|
||||
|
||||
ret = scm_call(SCM_SVC_PIL, SCM_CMD_OTP, &cmd, sizeof(cmd),
|
||||
NULL, 0);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
int qti_scm_pas_init_image(u32 peripheral, u32 addr)
|
||||
{
|
||||
int ret;
|
||||
|
||||
if (is_scm_armv8())
|
||||
{
|
||||
struct qca_scm_desc desc = {0};
|
||||
|
||||
desc.arginfo = QCA_SCM_ARGS(2, SCM_VAL, SCM_IO_WRITE);
|
||||
desc.args[0] = peripheral;
|
||||
desc.args[1] = addr;
|
||||
|
||||
ret = scm_call_64(SCM_SVC_PIL, SCM_PAS_INIT_IMAGE_CMD, &desc);
|
||||
}
|
||||
else
|
||||
{
|
||||
struct {
|
||||
u32 proc;
|
||||
u32 image_addr;
|
||||
} request;
|
||||
request.proc = peripheral;
|
||||
request.image_addr = addr;
|
||||
ret = scm_call(SCM_SVC_PIL, SCM_PAS_INIT_IMAGE_CMD, &request,
|
||||
sizeof(request), NULL, 0);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
int qti_pas_and_auth_reset(u32 peripheral)
|
||||
{
|
||||
int ret;
|
||||
u32 cmd = peripheral;
|
||||
|
||||
if (is_scm_armv8())
|
||||
{
|
||||
struct qca_scm_desc desc = {0};
|
||||
|
||||
desc.arginfo = QCA_SCM_ARGS(1);
|
||||
desc.args[0] = peripheral;
|
||||
|
||||
ret = scm_call_64(SCM_SVC_PIL, SCM_PAS_AUTH_AND_RESET_CMD, &desc);
|
||||
}
|
||||
else
|
||||
{
|
||||
ret = scm_call(SCM_SVC_PIL, SCM_PAS_AUTH_AND_RESET_CMD, &cmd, sizeof(cmd),
|
||||
NULL, 0);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
#endif
|
||||
|
||||
#else
|
||||
int qca_scm_call(u32 svc_id, u32 cmd_id, void *buf, size_t len)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -14,6 +14,7 @@
|
|||
#ifndef IPQ5018_CLK_H
|
||||
#define IPQ5018_CLK_H
|
||||
|
||||
#define CLK_ENABLE 0x1
|
||||
/* I2C clocks configuration */
|
||||
#ifdef CONFIG_IPQ5018_I2C
|
||||
|
||||
|
|
@ -26,8 +27,14 @@
|
|||
|
||||
#define CMD_UPDATE 0x1
|
||||
#define ROOT_EN 0x2
|
||||
#define CLK_ENABLE 0x1
|
||||
|
||||
|
||||
void i2c_clock_config(void);
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_IPQ_BT_SUPPORT
|
||||
#define GCC_BTSS_LPO_CBCR 0x181C004
|
||||
void enable_btss_lpo_clk(void);
|
||||
#endif
|
||||
|
||||
#endif /*IPQ5018_CLK_H*/
|
||||
|
|
|
|||
|
|
@ -34,6 +34,12 @@
|
|||
#define SCM_SVC_ID_SHIFT 0xA
|
||||
#define IS_CALL_AVAIL_CMD 0x1
|
||||
|
||||
#ifdef CONFIG_IPQ_BT_SUPPORT
|
||||
#define SCM_PAS_INIT_IMAGE_CMD 0x1
|
||||
#define SCM_PAS_AUTH_AND_RESET_CMD 0x5
|
||||
#define SCM_CMD_OTP 0x15
|
||||
#endif
|
||||
|
||||
/* scm_v8 */
|
||||
#define SCM_VAL 0x0
|
||||
#define SCM_IO_READ 0x1
|
||||
|
|
@ -130,6 +136,11 @@ int is_scm_sec_auth_available(u32 svc_id, u32 cmd_id);
|
|||
#ifdef CONFIG_IPQ_TZT
|
||||
int qca_scm(u32 svc_id, u32 cmd_id, u32 ownr_id, u32 *addr, u32 len);
|
||||
#endif
|
||||
#ifdef CONFIG_IPQ_BT_SUPPORT
|
||||
int qti_scm_otp(u32 peripheral);
|
||||
int qti_scm_pas_init_image(u32 peripheral, u32 addr);
|
||||
int qti_pas_and_auth_reset(u32 peripheral);
|
||||
#endif
|
||||
#define MAX_QCA_SCM_RETS 3
|
||||
#define MAX_QCA_SCM_ARGS 10
|
||||
#define SCM_READ_OP 1
|
||||
|
|
|
|||
|
|
@ -35,3 +35,9 @@ void i2c_clock_config(void)
|
|||
}
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_IPQ_BT_SUPPORT
|
||||
void enable_btss_lpo_clk(void)
|
||||
{
|
||||
writel(CLK_ENABLE, GCC_BTSS_LPO_CBCR);
|
||||
}
|
||||
#endif
|
||||
|
|
|
|||
|
|
@ -32,6 +32,12 @@
|
|||
#ifdef CONFIG_QPIC_NAND
|
||||
#include <asm/arch-qca-common/qpic_nand.h>
|
||||
#endif
|
||||
#ifdef CONFIG_IPQ_BT_SUPPORT
|
||||
#include <malloc.h>
|
||||
#include "bt.h"
|
||||
#include "bt_binary_array.h"
|
||||
#include <linux/compat.h>
|
||||
#endif
|
||||
|
||||
#define DLOAD_MAGIC_COOKIE 0x10
|
||||
|
||||
|
|
@ -477,6 +483,180 @@ void fdt_fixup_auto_restart(void *blob)
|
|||
return;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_IPQ_BT_SUPPORT
|
||||
unsigned char hci_reset[] =
|
||||
{0x01, 0x03, 0x0c, 0x00};
|
||||
|
||||
unsigned char adv_data[] =
|
||||
{0x01, 0X08, 0X20, 0X20, 0X1F, 0X0A, 0X09, 0X71,
|
||||
0X75, 0X61, 0X6c, 0X63, 0X6f, 0X6d, 0X6d, 0X00,
|
||||
0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00,
|
||||
0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00,
|
||||
0X00, 0X00, 0X00, 0X00};
|
||||
|
||||
unsigned char set_interval[] =
|
||||
{0X01, 0X06, 0X20, 0X0F, 0X20, 0X00, 0X20, 0X00,
|
||||
0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00,
|
||||
0X00, 0X07, 0X00};
|
||||
|
||||
unsigned char start_beacon[] =
|
||||
{0x01, 0x0A, 0x20, 0x01, 0x01};
|
||||
|
||||
unsigned char *hci_cmds[] = {
|
||||
hci_reset,
|
||||
adv_data,
|
||||
set_interval,
|
||||
start_beacon
|
||||
};
|
||||
|
||||
int wait_for_bt_event(struct bt_descriptor *btDesc, u8 bt_wait)
|
||||
{
|
||||
int val, timeout = 0;
|
||||
|
||||
do{
|
||||
udelay(10);
|
||||
bt_ipc_worker(btDesc);
|
||||
|
||||
if (bt_wait == BT_WAIT_FOR_START)
|
||||
val = !atomic_read(&btDesc->state);
|
||||
else
|
||||
val = atomic_read(&btDesc->tx_in_progress);
|
||||
|
||||
if (timeout++ >= BT_TIMEOUT_US/10) {
|
||||
printf(" %s timed out \n", __func__);
|
||||
return -ETIMEDOUT;
|
||||
}
|
||||
|
||||
} while (val);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int initialize_nvm(struct bt_descriptor *btDesc,
|
||||
void *fileaddr, u32 filesize)
|
||||
{
|
||||
unsigned char *buffer = fileaddr;
|
||||
int bytes_read = 0, bytes_consumed = 0, ret;
|
||||
HCI_Packet_t *hci_packet = NULL;
|
||||
|
||||
while(bytes_consumed < filesize )
|
||||
{
|
||||
bytes_read = (filesize - bytes_consumed) > NVM_SEGMENT_SIZE ?
|
||||
NVM_SEGMENT_SIZE : filesize - bytes_consumed;
|
||||
/* Constructing a HCI Packet to write NVM Segments to BTSS */
|
||||
hci_packet = (HCI_Packet_t*)malloc(sizeof(HCI_Packet_t) +
|
||||
NVM_SEGMENT_SIZE);
|
||||
|
||||
if(!hci_packet)
|
||||
{
|
||||
printf("Cannot allocate memory to HCI Packet \n");
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
/* Initializing HCI Packet Header */
|
||||
hci_packet->HCIPacketType = ptHCICommandPacket;
|
||||
|
||||
/* Populating TLV Request Packet in HCI */
|
||||
LE_UNALIGNED(&(hci_packet->HCIPayload.opcode), TLV_REQ_OPCODE);
|
||||
LE_UNALIGNED(&(hci_packet->HCIPayload.parameter_total_length),
|
||||
(bytes_read + DATA_REMAINING_LENGTH));
|
||||
hci_packet->HCIPayload.command_request = TLV_COMMAND_REQUEST;
|
||||
hci_packet->HCIPayload.tlv_segment_length = bytes_read;
|
||||
memcpy(hci_packet->HCIPayload.tlv_segment_data, buffer,
|
||||
bytes_read);
|
||||
|
||||
bt_ipc_sendmsg(btDesc, (u8*)hci_packet,
|
||||
sizeof(HCI_Packet_t) + bytes_read);
|
||||
|
||||
free(hci_packet);
|
||||
bytes_consumed += bytes_read;
|
||||
buffer = fileaddr + bytes_consumed;
|
||||
|
||||
ret = wait_for_bt_event(btDesc, BT_WAIT_FOR_TX_COMPLETE);
|
||||
if(ret || *((u8 *)btDesc->buf + TLV_RESPONSE_STATUS_INDEX) != 0)
|
||||
{
|
||||
printf( "\n NVM download failed\n");
|
||||
if (!ret) {
|
||||
kfree(btDesc->buf);
|
||||
btDesc->buf = NULL;
|
||||
}
|
||||
return -EINVAL;
|
||||
}
|
||||
kfree(btDesc->buf);
|
||||
btDesc->buf = NULL;
|
||||
}
|
||||
|
||||
printf("NVM download successful \n");
|
||||
bt_ipc_worker(btDesc);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int send_bt_hci_cmds(struct bt_descriptor *btDesc)
|
||||
{
|
||||
int ret, i;
|
||||
int count = sizeof hci_cmds/ sizeof(unsigned char *);
|
||||
|
||||
for (i = 0; i < count; i++) {
|
||||
bt_ipc_sendmsg(btDesc, hci_cmds[i], sizeof hci_cmds[i]);
|
||||
ret = wait_for_bt_event(btDesc, BT_WAIT_FOR_TX_COMPLETE);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
/*btDesc->buf will have response data with length btDesc->len*/
|
||||
kfree(btDesc->buf);
|
||||
btDesc->buf = NULL;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int bt_init(void)
|
||||
{
|
||||
struct bt_descriptor *btDesc;
|
||||
int ret;
|
||||
|
||||
btDesc = kzalloc(sizeof(*btDesc), GFP_KERNEL);
|
||||
if (!btDesc)
|
||||
return -ENOMEM;
|
||||
|
||||
bt_ipc_init(btDesc);
|
||||
|
||||
enable_btss_lpo_clk();
|
||||
ret = qti_scm_pas_init_image(PAS_ID, (u32)bt_fw_patchmdt);
|
||||
if (ret) {
|
||||
printf("patch auth failed\n");
|
||||
return ret;
|
||||
}
|
||||
|
||||
printf("patch authenticated successfully\n");
|
||||
|
||||
memcpy((void*)BT_RAM_PATCH, (void*)bt_fw_patchb02,
|
||||
sizeof bt_fw_patchb02);
|
||||
|
||||
ret = qti_pas_and_auth_reset(PAS_ID);
|
||||
|
||||
if (ret) {
|
||||
printf("BT out of reset failed\n");
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret = wait_for_bt_event(btDesc, BT_WAIT_FOR_START);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ret = initialize_nvm(btDesc, (void*)mpnv10bin, sizeof mpnv10bin);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ret = wait_for_bt_event(btDesc, BT_WAIT_FOR_START);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
send_bt_hci_cmds(btDesc);
|
||||
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
void reset_crashdump(void)
|
||||
{
|
||||
unsigned int ret = 0;
|
||||
|
|
@ -588,6 +768,9 @@ void board_nand_init(void)
|
|||
}
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_IPQ_BT_SUPPORT
|
||||
bt_init();
|
||||
#endif
|
||||
#ifdef CONFIG_QCA_SPI
|
||||
int gpio_node;
|
||||
gpio_node = fdt_path_offset(gd->fdt_blob, "/spi/spi_gpio");
|
||||
|
|
|
|||
|
|
@ -588,4 +588,56 @@ typedef enum {
|
|||
SMEM_MAX_SIZE = SMEM_SPI_FLASH_ADDR_LEN + 1,
|
||||
} smem_mem_type_t;
|
||||
|
||||
#ifdef CONFIG_IPQ_BT_SUPPORT
|
||||
#define NVM_SEGMENT_SIZE 243
|
||||
#define TLV_REQ_OPCODE 0xFC00
|
||||
#define TLV_COMMAND_REQUEST 0x1E
|
||||
#define DATA_REMAINING_LENGTH 2
|
||||
#define TLV_RESPONSE_PACKET_SIZE 8
|
||||
#define TLV_RESPONSE_STATUS_INDEX 6
|
||||
|
||||
#define PACKED_STRUCT __attribute__((__packed__))
|
||||
|
||||
#define LE_UNALIGNED(x, y) \
|
||||
{ \
|
||||
((u8 *)(x))[0] = ((u8)(((u32)(y)) & 0xFF)); \
|
||||
((u8 *)(x))[1] = ((u8)((((u32)(y)) >> 8) & 0xFF)); \
|
||||
}
|
||||
|
||||
typedef enum
|
||||
{
|
||||
ptHCICommandPacket = 0x01, /* Simple HCI Command Packet */
|
||||
ptHCIACLDataPacket = 0x02, /* HCI ACL Data Packet Type. */
|
||||
ptHCISCODataPacket = 0x03, /* HCI SCO Data Packet Type. */
|
||||
ptHCIeSCODataPacket= 0x03, /* HCI eSCO Data Packet Type. */
|
||||
ptHCIEventPacket = 0x04, /* HCI Event Packet Type. */
|
||||
ptHCIAdditional = 0x05 /* Starting Point for Additional*/
|
||||
} HCI_PacketType_t;
|
||||
|
||||
typedef struct _tlv_download_req
|
||||
{
|
||||
u16 opcode;
|
||||
u8 parameter_total_length;
|
||||
u8 command_request;
|
||||
u8 tlv_segment_length;
|
||||
u8 tlv_segment_data[0];
|
||||
|
||||
} PACKED_STRUCT tlv_download_req;
|
||||
|
||||
typedef struct _tagHCI_Packet_t
|
||||
{
|
||||
u8 HCIPacketType;
|
||||
tlv_download_req HCIPayload;
|
||||
} PACKED_STRUCT HCI_Packet_t;
|
||||
|
||||
typedef enum {
|
||||
BT_WAIT_FOR_START = 0,
|
||||
BT_WAIT_FOR_TX_COMPLETE = 1,
|
||||
BT_WAIT_FOR_STOP = 2,
|
||||
} bt_wait;
|
||||
|
||||
#define BT_TIMEOUT_US 50000
|
||||
|
||||
int bt_init(void);
|
||||
#endif
|
||||
#endif /* _IPQ5018_CDP_H_ */
|
||||
|
|
|
|||
|
|
@ -425,4 +425,6 @@ extern loff_t board_env_size;
|
|||
|
||||
#define INTERNAL_96MHZ
|
||||
|
||||
/*#define CONFIG_IPQ_BT_SUPPORT*/
|
||||
|
||||
#endif /* _IPQ5018_H */
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue