mirror of
https://git.codelinaro.org/clo/qsdk/oss/boot/u-boot-2016.git
synced 2025-12-10 07:44:53 +01:00
Merge "ipq5018: Add BT beaconing support"
This commit is contained in:
commit
27ebbe15c7
10 changed files with 946 additions and 1 deletions
|
|
@ -550,6 +550,85 @@ int qca_scm_secure_authenticate(void *cmd_buf, size_t cmd_len)
|
||||||
|
|
||||||
return ret;
|
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
|
#else
|
||||||
int qca_scm_call(u32 svc_id, u32 cmd_id, void *buf, size_t len)
|
int qca_scm_call(u32 svc_id, u32 cmd_id, void *buf, size_t len)
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -14,6 +14,7 @@
|
||||||
#ifndef IPQ5018_CLK_H
|
#ifndef IPQ5018_CLK_H
|
||||||
#define IPQ5018_CLK_H
|
#define IPQ5018_CLK_H
|
||||||
|
|
||||||
|
#define CLK_ENABLE 0x1
|
||||||
/* I2C clocks configuration */
|
/* I2C clocks configuration */
|
||||||
#ifdef CONFIG_IPQ5018_I2C
|
#ifdef CONFIG_IPQ5018_I2C
|
||||||
|
|
||||||
|
|
@ -26,8 +27,14 @@
|
||||||
|
|
||||||
#define CMD_UPDATE 0x1
|
#define CMD_UPDATE 0x1
|
||||||
#define ROOT_EN 0x2
|
#define ROOT_EN 0x2
|
||||||
#define CLK_ENABLE 0x1
|
|
||||||
|
|
||||||
void i2c_clock_config(void);
|
void i2c_clock_config(void);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#ifdef CONFIG_IPQ_BT_SUPPORT
|
||||||
|
#define GCC_BTSS_LPO_CBCR 0x181C004
|
||||||
|
void enable_btss_lpo_clk(void);
|
||||||
|
#endif
|
||||||
|
|
||||||
#endif /*IPQ5018_CLK_H*/
|
#endif /*IPQ5018_CLK_H*/
|
||||||
|
|
|
||||||
|
|
@ -34,6 +34,12 @@
|
||||||
#define SCM_SVC_ID_SHIFT 0xA
|
#define SCM_SVC_ID_SHIFT 0xA
|
||||||
#define IS_CALL_AVAIL_CMD 0x1
|
#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 */
|
/* scm_v8 */
|
||||||
#define SCM_VAL 0x0
|
#define SCM_VAL 0x0
|
||||||
#define SCM_IO_READ 0x1
|
#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
|
#ifdef CONFIG_IPQ_TZT
|
||||||
int qca_scm(u32 svc_id, u32 cmd_id, u32 ownr_id, u32 *addr, u32 len);
|
int qca_scm(u32 svc_id, u32 cmd_id, u32 ownr_id, u32 *addr, u32 len);
|
||||||
#endif
|
#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_RETS 3
|
||||||
#define MAX_QCA_SCM_ARGS 10
|
#define MAX_QCA_SCM_ARGS 10
|
||||||
#define SCM_READ_OP 1
|
#define SCM_READ_OP 1
|
||||||
|
|
|
||||||
|
|
@ -2,4 +2,5 @@ ccflags-y += -I$(srctree)/board/qca/arm/ipq5018
|
||||||
cppflags-y += -I$(srctree)/board/qca/arm/ipq5018
|
cppflags-y += -I$(srctree)/board/qca/arm/ipq5018
|
||||||
obj-y := ipq5018.o
|
obj-y := ipq5018.o
|
||||||
obj-y += clock.o
|
obj-y += clock.o
|
||||||
|
obj-$(CONFIG_IPQ_BT_SUPPORT) += bt_ipc.o
|
||||||
|
|
||||||
|
|
|
||||||
208
board/qca/arm/ipq5018/bt.h
Normal file
208
board/qca/arm/ipq5018/bt.h
Normal file
|
|
@ -0,0 +1,208 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2020 The Linux Foundation. All rights reserved.
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License version 2 and
|
||||||
|
* only version 2 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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef _BT_H
|
||||||
|
#define _BT_H
|
||||||
|
|
||||||
|
#include <asm/atomic.h>
|
||||||
|
|
||||||
|
#define PAS_ID 0xC
|
||||||
|
#define CMD_ID 0x14
|
||||||
|
#define BT_M0_WARM_RST_ORIDE 0x0
|
||||||
|
#define BT_M0_WARM_RST 0x4
|
||||||
|
|
||||||
|
#define IOCTL_IPC_BOOT 0xBE
|
||||||
|
#define IPC_TX_QSIZE 0x20
|
||||||
|
|
||||||
|
#define TO_APPS_ADDR(a) (btmem->virt + (int)(uintptr_t)a)
|
||||||
|
#define TO_BT_ADDR(a) (a - btmem->virt)
|
||||||
|
#define IPC_LBUF_SZ(w, x, y, z) (((TO_BT_ADDR((void *)w) + w->x) - w->y) / w->z)
|
||||||
|
|
||||||
|
#define IPC_MSG_HDR_SZ (4u)
|
||||||
|
#define IPC_MSG_PLD_SZ (40u)
|
||||||
|
#define IPC_TOTAL_MSG_SZ (IPC_MSG_HDR_SZ + IPC_MSG_PLD_SZ)
|
||||||
|
|
||||||
|
#define IPC_LMSG_MASK (0x8000u)
|
||||||
|
#define IPC_RACK_MASK (0x4000u)
|
||||||
|
#define IPC_PKT_TYPE_MASK (0x0300u)
|
||||||
|
#define IPC_MSG_ID_MASK (0x00FFu)
|
||||||
|
|
||||||
|
#define IPC_LMSG_TYPE ((uint16_t) IPC_LMSG_MASK)
|
||||||
|
#define IPC_SMSG_TYPE ((uint16_t) 0x0000u)
|
||||||
|
#define IPC_REQ_ACK ((uint16_t) IPC_RACK_MASK)
|
||||||
|
#define IPC_NO_ACK ((uint16_t) 0x0000u)
|
||||||
|
#define IPC_PKT_TYPE_CUST ((uint16_t) 0x0000u)
|
||||||
|
#define IPC_PKT_TYPE_HCI ((uint16_t) 0x0100u)
|
||||||
|
#define IPC_PKT_TYPE_AUDIO ((uint16_t) 0x0200u)
|
||||||
|
#define IPC_PKT_TYPE_RFU (IPC_PKT_TYPE_MASK)
|
||||||
|
|
||||||
|
#define IPC_LMSG_SHIFT (15u)
|
||||||
|
#define IPC_RACK_SHIFT (14u)
|
||||||
|
#define IPC_PKT_TYPE_SHIFT (8u)
|
||||||
|
|
||||||
|
#define GET_NO_OF_BLOCKS(a, b) ((a + b - 1) / b)
|
||||||
|
|
||||||
|
#define GET_RX_INDEX_FROM_BUF(x, y) ((x - btmem->rx_ctxt->lring_buf) / y)
|
||||||
|
|
||||||
|
#define GET_TX_INDEX_FROM_BUF(x, y) ((x - btmem->tx_ctxt->lring_buf) / y)
|
||||||
|
|
||||||
|
#define IS_RX_MEM_NON_CONTIGIOUS(pBuf, len, sz) \
|
||||||
|
((pBuf + len) > \
|
||||||
|
(btmem->rx_ctxt->lring_buf + \
|
||||||
|
(sz * btmem->rx_ctxt->lmsg_buf_cnt)))
|
||||||
|
|
||||||
|
/** Message header format.
|
||||||
|
*
|
||||||
|
* ---------------------------------------------------------------
|
||||||
|
* BitPos | 15 | 14 | 13 | 12 | 11 | 10 | 9 | 8 | 7 - 0 |
|
||||||
|
* ---------------------------------------------------------------
|
||||||
|
* Field | Long Msg |rAck| RFU | PktType | msgID |
|
||||||
|
* ---------------------------------------------------------------
|
||||||
|
*
|
||||||
|
* - Long Msg :
|
||||||
|
*
|
||||||
|
* - reqAck : This is interpreted by receiver for sending acknowledegement
|
||||||
|
* to sender i.e. send a ack IPC interrupt if set.
|
||||||
|
* Use @ref IS_REQ_ACK or @ref IS_NO_ACK
|
||||||
|
* to determine ack is requested or not.
|
||||||
|
*
|
||||||
|
* - RFU : Reserved for future use.
|
||||||
|
*
|
||||||
|
* - pktType :
|
||||||
|
*
|
||||||
|
* - msgID : Contains unique message ID within a Category.
|
||||||
|
* Use @ref IPC_GET_MSG_ID to get message ID.
|
||||||
|
*/
|
||||||
|
#define IPC_ConstructMsgHeader(msgID, reqAck, pktType, longMsg) \
|
||||||
|
(((uint8_t) longMsg << IPC_LMSG_SHIFT) | \
|
||||||
|
((uint8_t) reqAck << IPC_RACK_SHIFT) | \
|
||||||
|
((uint16_t) pktType << IPC_PKT_TYPE_SHIFT) | msgID)
|
||||||
|
|
||||||
|
#define IPC_GET_PKT_TYPE(hdr) \
|
||||||
|
((enum ipc_pkt_type)((hdr & IPC_PKT_TYPE_MASK) >> IPC_PKT_TYPE_SHIFT))
|
||||||
|
|
||||||
|
#define IS_LONG_MSG(hdr) ((hdr & IPC_LMSG_MASK) == IPC_LMSG_TYPE)
|
||||||
|
#define IS_SHORT_MSG(hdr) ((hdr & IPC_LMSG_MASK) == IPC_SMSG_TYPE)
|
||||||
|
|
||||||
|
#define IS_REQ_ACK(hdr) ((hdr & IPC_RACK_MASK) == IPC_REQ_ACK)
|
||||||
|
#define IS_NO_ACK(hdr) ((hdr & IPC_RACK_MASK) == IPC_NO_ACK)
|
||||||
|
|
||||||
|
#define IS_HCI_PKT(hdr) ((hdr & IPC_PKT_TYPE_MASK) == IPC_PKT_TYPE_HCI)
|
||||||
|
#define IS_CUST_PKT(hdr) ((hdr & IPC_PKT_TYPE_MASK) == IPC_PKT_TYPE_CUST)
|
||||||
|
|
||||||
|
#define IPC_GET_MSG_ID(hdr) ((uint8_t)(hdr & IPC_MSG_ID_MASK))
|
||||||
|
|
||||||
|
#define IPC_CMD_IPC_STOP (0x01)
|
||||||
|
#define IPC_CMD_SWITCH_TO_UART (0x02)
|
||||||
|
#define IPC_CMD_PREPARE_DUMP (0x03)
|
||||||
|
#define IPC_CMD_COLLECT_DUMP (0x04)
|
||||||
|
#define IPC_CMD_IPC_START (0x05)
|
||||||
|
|
||||||
|
#define BT_RAM_START 0x7000000
|
||||||
|
#define BT_RAM_PATCH 0x7020250
|
||||||
|
#define BT_RAM_SIZE 0x58000
|
||||||
|
#define SYSCON 0x0B111000
|
||||||
|
|
||||||
|
/*-------------------------------------------------------------------------
|
||||||
|
* Type Declarations
|
||||||
|
* ------------------------------------------------------------------------
|
||||||
|
*/
|
||||||
|
|
||||||
|
enum ipc_pkt_type {
|
||||||
|
IPC_CUST_PKT,
|
||||||
|
IPC_HCI_PKT,
|
||||||
|
IPC_AUDIO_PKT,
|
||||||
|
IPC_PKT_MAX
|
||||||
|
};
|
||||||
|
|
||||||
|
struct long_msg_info {
|
||||||
|
uint16_t smsg_free_cnt;
|
||||||
|
uint16_t lmsg_free_cnt;
|
||||||
|
uint8_t ridx;
|
||||||
|
uint8_t widx;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct ipc_aux_ptr {
|
||||||
|
uint32_t len;
|
||||||
|
uint32_t buf;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct ring_buffer {
|
||||||
|
uint16_t msg_hdr;
|
||||||
|
uint16_t len;
|
||||||
|
|
||||||
|
union {
|
||||||
|
uint8_t smsg_data[IPC_MSG_PLD_SZ];
|
||||||
|
uint32_t lmsg_data;
|
||||||
|
} payload;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct ring_buffer_info {
|
||||||
|
uint32_t rbuf;
|
||||||
|
uint8_t ring_buf_cnt;
|
||||||
|
uint8_t ridx;
|
||||||
|
uint8_t widx;
|
||||||
|
uint8_t tidx;
|
||||||
|
uint32_t next;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct context_info {
|
||||||
|
uint16_t TotalMemorySize;
|
||||||
|
uint8_t lmsg_buf_cnt;
|
||||||
|
uint8_t smsg_buf_cnt;
|
||||||
|
struct ring_buffer_info sring_buf_info;
|
||||||
|
uint32_t sring_buf;
|
||||||
|
uint32_t lring_buf;
|
||||||
|
uint32_t reserved;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
struct bt_mem {
|
||||||
|
phys_addr_t phys;
|
||||||
|
phys_addr_t reloc;
|
||||||
|
void __iomem *virt;
|
||||||
|
size_t size;
|
||||||
|
struct context_info *tx_ctxt;
|
||||||
|
struct context_info *rx_ctxt;
|
||||||
|
struct long_msg_info lmsg_ctxt;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct bt_ipc {
|
||||||
|
uint32_t regmap;
|
||||||
|
int offset;
|
||||||
|
int bit;
|
||||||
|
int irq;
|
||||||
|
atomic_t tx_q_cnt;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct bt_descriptor {
|
||||||
|
void __iomem *warm_reset;
|
||||||
|
struct bt_ipc ipc;
|
||||||
|
struct bt_mem btmem;
|
||||||
|
int (*sendmsg_cb)(struct bt_descriptor *, unsigned char *, int);
|
||||||
|
void (*recvmsg_cb)(struct bt_descriptor *, unsigned char *, int);
|
||||||
|
atomic_t state;
|
||||||
|
atomic_t tx_in_progress;
|
||||||
|
unsigned char *buf;
|
||||||
|
uint32_t len;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct ipc_intent {
|
||||||
|
uint8_t *buf;
|
||||||
|
uint16_t len;
|
||||||
|
};
|
||||||
|
|
||||||
|
extern int bt_ipc_sendmsg(struct bt_descriptor *btDesc, unsigned char *buf, int len );
|
||||||
|
extern void bt_ipc_init(struct bt_descriptor *btDesc);
|
||||||
|
extern void bt_ipc_worker(struct bt_descriptor *btDesc);
|
||||||
|
#endif /* _BT_H */
|
||||||
396
board/qca/arm/ipq5018/bt_ipc.c
Normal file
396
board/qca/arm/ipq5018/bt_ipc.c
Normal file
|
|
@ -0,0 +1,396 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2020 The Linux Foundation. All rights reserved.
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License version 2 and
|
||||||
|
* only version 2 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 <linux/io.h>
|
||||||
|
#include <asm/atomic.h>
|
||||||
|
#include <asm-generic/atomic-long.h>
|
||||||
|
|
||||||
|
#include <linux/ctype.h>
|
||||||
|
#include "bt.h"
|
||||||
|
|
||||||
|
#include <common.h>
|
||||||
|
#include <memalign.h>
|
||||||
|
|
||||||
|
#include <linux/err.h>
|
||||||
|
|
||||||
|
static void *bt_ipc_alloc_lmsg(struct bt_descriptor *btDesc, uint32_t len,
|
||||||
|
struct ipc_aux_ptr *aux_ptr, uint8_t *is_lbuf_full)
|
||||||
|
{
|
||||||
|
uint8_t idx;
|
||||||
|
uint8_t blks;
|
||||||
|
uint8_t blks_consumed;
|
||||||
|
struct bt_mem *btmem = &btDesc->btmem;
|
||||||
|
uint32_t lsz = IPC_LBUF_SZ(btmem->tx_ctxt, TotalMemorySize, lring_buf,
|
||||||
|
lmsg_buf_cnt);
|
||||||
|
|
||||||
|
if (btmem->tx_ctxt->lring_buf == 0) {
|
||||||
|
printf("no long message buffer not initialized\n");
|
||||||
|
return ERR_PTR(-ENODEV);
|
||||||
|
}
|
||||||
|
|
||||||
|
blks = GET_NO_OF_BLOCKS(len, lsz);
|
||||||
|
|
||||||
|
if (!btmem->lmsg_ctxt.lmsg_free_cnt ||
|
||||||
|
(blks > btmem->lmsg_ctxt.lmsg_free_cnt))
|
||||||
|
return ERR_PTR(-EAGAIN);
|
||||||
|
|
||||||
|
idx = btmem->lmsg_ctxt.widx;
|
||||||
|
|
||||||
|
if ((btmem->lmsg_ctxt.widx + blks) > btmem->tx_ctxt->lmsg_buf_cnt) {
|
||||||
|
blks_consumed = btmem->tx_ctxt->lmsg_buf_cnt - idx;
|
||||||
|
aux_ptr->len = len - (blks_consumed * lsz);
|
||||||
|
aux_ptr->buf = btmem->tx_ctxt->lring_buf;
|
||||||
|
}
|
||||||
|
|
||||||
|
btmem->lmsg_ctxt.widx = (btmem->lmsg_ctxt.widx + blks) %
|
||||||
|
btmem->tx_ctxt->lmsg_buf_cnt;
|
||||||
|
|
||||||
|
btmem->lmsg_ctxt.lmsg_free_cnt -= blks;
|
||||||
|
|
||||||
|
if (btmem->lmsg_ctxt.lmsg_free_cnt <=
|
||||||
|
((btmem->tx_ctxt->lmsg_buf_cnt * 20) / 100))
|
||||||
|
*is_lbuf_full = 1;
|
||||||
|
|
||||||
|
return (TO_APPS_ADDR(btmem->tx_ctxt->lring_buf) + (idx * lsz));
|
||||||
|
}
|
||||||
|
|
||||||
|
static struct ring_buffer_info *bt_ipc_get_tx_rbuf(struct bt_descriptor *btDesc,
|
||||||
|
uint8_t *is_sbuf_full)
|
||||||
|
{
|
||||||
|
uint8_t idx;
|
||||||
|
struct ring_buffer_info *rinfo;
|
||||||
|
struct bt_mem *btmem = &btDesc->btmem;
|
||||||
|
|
||||||
|
for (rinfo = &(btmem->tx_ctxt->sring_buf_info); rinfo != NULL;
|
||||||
|
rinfo = (struct ring_buffer_info *)(uintptr_t)(rinfo->next)) {
|
||||||
|
idx = (rinfo->widx + 1) % (btmem->tx_ctxt->smsg_buf_cnt);
|
||||||
|
|
||||||
|
if (idx != rinfo->tidx) {
|
||||||
|
btmem->lmsg_ctxt.smsg_free_cnt--;
|
||||||
|
|
||||||
|
if (btmem->lmsg_ctxt.smsg_free_cnt <=
|
||||||
|
((btmem->tx_ctxt->smsg_buf_cnt * 20) / 100))
|
||||||
|
*is_sbuf_full = 1;
|
||||||
|
|
||||||
|
return rinfo;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return ERR_PTR(-EAGAIN);
|
||||||
|
}
|
||||||
|
|
||||||
|
int bt_ipc_send_msg(struct bt_descriptor *btDesc, uint16_t msg_hdr,
|
||||||
|
const uint8_t *pData, uint16_t len, bool dequeue)
|
||||||
|
{
|
||||||
|
int ret = 0;
|
||||||
|
struct bt_mem *btmem = &btDesc->btmem;
|
||||||
|
struct ring_buffer_info *rinfo;
|
||||||
|
struct ring_buffer *rbuf;
|
||||||
|
uint8_t is_lbuf_full = 0;
|
||||||
|
uint8_t is_sbuf_full = 0;
|
||||||
|
struct ipc_aux_ptr aux_ptr;
|
||||||
|
void *lmsg_data;
|
||||||
|
|
||||||
|
rinfo = bt_ipc_get_tx_rbuf(btDesc, &is_sbuf_full);
|
||||||
|
if (IS_ERR(rinfo)) {
|
||||||
|
printf("short msg buf full, queuing msg[%d]\n",
|
||||||
|
atomic_read(&btDesc->ipc.tx_q_cnt));
|
||||||
|
ret = PTR_ERR(rinfo);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
rbuf = &((struct ring_buffer *)(TO_APPS_ADDR(
|
||||||
|
rinfo->rbuf)))[rinfo->widx];
|
||||||
|
rbuf->msg_hdr = msg_hdr;
|
||||||
|
rbuf->len = len;
|
||||||
|
|
||||||
|
if (len > IPC_MSG_PLD_SZ) {
|
||||||
|
rbuf->msg_hdr = rbuf->msg_hdr | IPC_LMSG_MASK;
|
||||||
|
|
||||||
|
aux_ptr.len = 0;
|
||||||
|
aux_ptr.buf = 0;
|
||||||
|
|
||||||
|
lmsg_data = bt_ipc_alloc_lmsg(btDesc, len,
|
||||||
|
&aux_ptr, &is_lbuf_full);
|
||||||
|
|
||||||
|
if (IS_ERR(lmsg_data)) {
|
||||||
|
printf("long msg buf full, queuing msg[%d]\n",
|
||||||
|
atomic_read(&btDesc->ipc.tx_q_cnt));
|
||||||
|
ret = PTR_ERR(lmsg_data);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
memcpy_toio(lmsg_data, pData,
|
||||||
|
(len - aux_ptr.len));
|
||||||
|
|
||||||
|
if (aux_ptr.buf) {
|
||||||
|
memcpy_toio(TO_APPS_ADDR(aux_ptr.buf),
|
||||||
|
(pData + (len - aux_ptr.len)), aux_ptr.len);
|
||||||
|
}
|
||||||
|
|
||||||
|
rbuf->payload.lmsg_data = TO_BT_ADDR(lmsg_data);
|
||||||
|
} else {
|
||||||
|
memcpy_toio(rbuf->payload.smsg_data, pData, len);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (is_sbuf_full || is_lbuf_full)
|
||||||
|
rbuf->msg_hdr = rbuf->msg_hdr | IPC_RACK_MASK;
|
||||||
|
|
||||||
|
rinfo->widx = (rinfo->widx + 1) % btmem->tx_ctxt->smsg_buf_cnt;
|
||||||
|
|
||||||
|
writel( BIT(btDesc->ipc.bit), btDesc->ipc.regmap+ btDesc->ipc.offset);
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
static
|
||||||
|
void bt_ipc_free_lmsg(struct bt_descriptor *btDesc, uint32_t lmsg, uint16_t len)
|
||||||
|
{
|
||||||
|
uint8_t idx;
|
||||||
|
uint8_t blks;
|
||||||
|
struct bt_mem *btmem = &btDesc->btmem;
|
||||||
|
uint32_t lsz = IPC_LBUF_SZ(btmem->tx_ctxt, TotalMemorySize, lring_buf,
|
||||||
|
lmsg_buf_cnt);
|
||||||
|
|
||||||
|
idx = GET_TX_INDEX_FROM_BUF(lmsg, lsz);
|
||||||
|
|
||||||
|
if (idx != btmem->lmsg_ctxt.ridx)
|
||||||
|
return;
|
||||||
|
|
||||||
|
blks = GET_NO_OF_BLOCKS(len, lsz);
|
||||||
|
|
||||||
|
btmem->lmsg_ctxt.ridx = (btmem->lmsg_ctxt.ridx + blks) %
|
||||||
|
btmem->tx_ctxt->lmsg_buf_cnt;
|
||||||
|
|
||||||
|
btmem->lmsg_ctxt.lmsg_free_cnt += blks;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void bt_ipc_cust_msg(struct bt_descriptor *btDesc, uint8_t msgid)
|
||||||
|
{
|
||||||
|
struct bt_mem *btmem = &btDesc->btmem;
|
||||||
|
uint16_t msg_hdr = 0;
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
msg_hdr |= msgid;
|
||||||
|
|
||||||
|
switch (msgid) {
|
||||||
|
case IPC_CMD_IPC_STOP:
|
||||||
|
printf("BT IPC Stopped, gracefully stopping APSS IPC\n");
|
||||||
|
break;
|
||||||
|
case IPC_CMD_SWITCH_TO_UART:
|
||||||
|
printf("Configured UART, Swithing BT to debug mode\n");
|
||||||
|
break;
|
||||||
|
case IPC_CMD_PREPARE_DUMP:
|
||||||
|
printf("IPQ crashed, inform BT to prepare dump\n");
|
||||||
|
break;
|
||||||
|
case IPC_CMD_COLLECT_DUMP:
|
||||||
|
printf("BT Crashed, gracefully stopping IPC\n");
|
||||||
|
return;
|
||||||
|
case IPC_CMD_IPC_START:
|
||||||
|
btmem->tx_ctxt = (struct context_info *)((void *)
|
||||||
|
btmem->rx_ctxt + btmem->rx_ctxt->TotalMemorySize);
|
||||||
|
btmem->lmsg_ctxt.widx = 0;
|
||||||
|
btmem->lmsg_ctxt.ridx = 0;
|
||||||
|
btmem->lmsg_ctxt.smsg_free_cnt = btmem->tx_ctxt->smsg_buf_cnt;
|
||||||
|
btmem->lmsg_ctxt.lmsg_free_cnt = btmem->tx_ctxt->lmsg_buf_cnt;
|
||||||
|
atomic_set(&btDesc->state, 1);
|
||||||
|
|
||||||
|
printf("BT IPC Started, starting APSS IPC\n");
|
||||||
|
return;
|
||||||
|
default:
|
||||||
|
printf("invalid custom message\n");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (unlikely(!atomic_read(&btDesc->state))) {
|
||||||
|
printf("BT IPC not initialized, no message sent\n");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
atomic_set(&btDesc->state, 0);
|
||||||
|
|
||||||
|
ret = bt_ipc_send_msg(btDesc, msg_hdr, NULL, 0, true);
|
||||||
|
if (ret)
|
||||||
|
printf("err: sending message\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool bt_ipc_process_peer_msgs(struct bt_descriptor *btDesc,
|
||||||
|
struct ring_buffer_info *rinfo, uint8_t *pRxMsgCount)
|
||||||
|
{
|
||||||
|
struct bt_mem *btmem = &btDesc->btmem;
|
||||||
|
struct ring_buffer *rbuf;
|
||||||
|
uint8_t ridx, lbuf_idx;
|
||||||
|
uint8_t blks_consumed;
|
||||||
|
struct ipc_aux_ptr aux_ptr;
|
||||||
|
enum ipc_pkt_type pktType = IPC_CUST_PKT;
|
||||||
|
bool ackReqd = false;
|
||||||
|
uint8_t *rxbuf = NULL;
|
||||||
|
uint32_t lsz = IPC_LBUF_SZ(btmem->rx_ctxt, TotalMemorySize, lring_buf,
|
||||||
|
lmsg_buf_cnt);
|
||||||
|
|
||||||
|
ridx = rinfo->ridx;
|
||||||
|
|
||||||
|
rbuf = &((struct ring_buffer *)(TO_APPS_ADDR(
|
||||||
|
btmem->rx_ctxt->sring_buf_info.rbuf)))[ridx];
|
||||||
|
|
||||||
|
while (ridx != rinfo->widx) {
|
||||||
|
memset(&aux_ptr, 0, sizeof(struct ipc_aux_ptr));
|
||||||
|
|
||||||
|
rbuf = &((struct ring_buffer *)(TO_APPS_ADDR(
|
||||||
|
btmem->rx_ctxt->sring_buf_info.rbuf)))[ridx];
|
||||||
|
|
||||||
|
if (IS_LONG_MSG(rbuf->msg_hdr)) {
|
||||||
|
rxbuf = TO_APPS_ADDR(rbuf->payload.lmsg_data);
|
||||||
|
|
||||||
|
if (IS_RX_MEM_NON_CONTIGIOUS(rbuf->payload.lmsg_data,
|
||||||
|
rbuf->len, lsz)) {
|
||||||
|
|
||||||
|
lbuf_idx = GET_RX_INDEX_FROM_BUF(
|
||||||
|
rbuf->payload.lmsg_data, lsz);
|
||||||
|
|
||||||
|
blks_consumed = btmem->rx_ctxt->lmsg_buf_cnt -
|
||||||
|
lbuf_idx;
|
||||||
|
aux_ptr.len = rbuf->len - (blks_consumed * lsz);
|
||||||
|
aux_ptr.buf = btmem->rx_ctxt->lring_buf;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
rxbuf = rbuf->payload.smsg_data;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (IS_REQ_ACK(rbuf->msg_hdr))
|
||||||
|
ackReqd = true;
|
||||||
|
|
||||||
|
pktType = IPC_GET_PKT_TYPE(rbuf->msg_hdr);
|
||||||
|
|
||||||
|
switch (pktType) {
|
||||||
|
case IPC_HCI_PKT:
|
||||||
|
btDesc->buf = kzalloc(rbuf->len, GFP_ATOMIC);
|
||||||
|
if (!btDesc->buf)
|
||||||
|
return -ENOMEM;
|
||||||
|
|
||||||
|
memcpy_fromio(btDesc->buf, rxbuf, (rbuf->len - aux_ptr.len));
|
||||||
|
|
||||||
|
if (aux_ptr.buf)
|
||||||
|
memcpy_fromio(btDesc->buf + (rbuf->len - aux_ptr.len),
|
||||||
|
TO_APPS_ADDR(aux_ptr.buf), aux_ptr.len);
|
||||||
|
|
||||||
|
btDesc->len = rbuf->len;
|
||||||
|
atomic_set(&btDesc->tx_in_progress, 0);
|
||||||
|
break;
|
||||||
|
case IPC_CUST_PKT:
|
||||||
|
bt_ipc_cust_msg(btDesc, IPC_GET_MSG_ID(rbuf->msg_hdr));
|
||||||
|
break;
|
||||||
|
case IPC_AUDIO_PKT:
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
ridx = (ridx + 1) % rinfo->ring_buf_cnt;
|
||||||
|
}
|
||||||
|
|
||||||
|
rinfo->ridx = ridx;
|
||||||
|
|
||||||
|
return ackReqd;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void bt_ipc_process_ack(struct bt_descriptor *btDesc)
|
||||||
|
{
|
||||||
|
struct ring_buffer_info *rinfo;
|
||||||
|
struct bt_mem *btmem = &btDesc->btmem;
|
||||||
|
|
||||||
|
for (rinfo = &btmem->tx_ctxt->sring_buf_info; rinfo != NULL;
|
||||||
|
rinfo = (struct ring_buffer_info *)(uintptr_t)(rinfo->next)) {
|
||||||
|
uint8_t tidx = rinfo->tidx;
|
||||||
|
struct ring_buffer *rbuf = (struct ring_buffer *)
|
||||||
|
TO_APPS_ADDR(rinfo->rbuf);
|
||||||
|
|
||||||
|
while (tidx != rinfo->ridx) {
|
||||||
|
if (IS_LONG_MSG(rbuf[tidx].msg_hdr)) {
|
||||||
|
bt_ipc_free_lmsg(btDesc,
|
||||||
|
rbuf[tidx].payload.lmsg_data,
|
||||||
|
rbuf[tidx].len);
|
||||||
|
}
|
||||||
|
|
||||||
|
tidx = (tidx + 1) % btmem->tx_ctxt->smsg_buf_cnt;
|
||||||
|
btmem->lmsg_ctxt.smsg_free_cnt++;
|
||||||
|
}
|
||||||
|
|
||||||
|
rinfo->tidx = tidx;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int bt_ipc_sendmsg(struct bt_descriptor *btDesc, unsigned char *buf, int len)
|
||||||
|
{
|
||||||
|
int ret;
|
||||||
|
uint16_t msg_hdr = 0x100;
|
||||||
|
|
||||||
|
if (unlikely(!atomic_read(&btDesc->state))) {
|
||||||
|
printf("BT IPC not initialized, no message sent\n");
|
||||||
|
return -ENODEV;
|
||||||
|
}
|
||||||
|
|
||||||
|
atomic_set(&btDesc->tx_in_progress, 1);
|
||||||
|
ret = bt_ipc_send_msg(btDesc, msg_hdr, (uint8_t *)buf, (uint16_t)len,
|
||||||
|
true);
|
||||||
|
if (ret)
|
||||||
|
printf("err: sending message\n");
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
void bt_ipc_worker(struct bt_descriptor *btDesc)
|
||||||
|
{
|
||||||
|
struct ring_buffer_info *rinfo;
|
||||||
|
|
||||||
|
struct bt_mem *btmem = &btDesc->btmem;
|
||||||
|
bool ackReqd = false;
|
||||||
|
|
||||||
|
if (unlikely(!atomic_read(&btDesc->state))) {
|
||||||
|
btmem->rx_ctxt = (struct context_info *)(btmem->virt + 0xe000);
|
||||||
|
if (btmem->rx_ctxt->sring_buf_info.widx != 0x1)
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
bt_ipc_process_ack(btDesc);
|
||||||
|
|
||||||
|
for (rinfo = &(btmem->rx_ctxt->sring_buf_info); rinfo != NULL;
|
||||||
|
rinfo = (struct ring_buffer_info *)(uintptr_t)(rinfo->next)) {
|
||||||
|
if (bt_ipc_process_peer_msgs(btDesc, rinfo,
|
||||||
|
&btmem->rx_ctxt->smsg_buf_cnt)) {
|
||||||
|
ackReqd = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ackReqd) {
|
||||||
|
writel( BIT(btDesc->ipc.bit), btDesc->ipc.regmap+ btDesc->ipc.offset);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
void bt_ipc_init(struct bt_descriptor *btDesc)
|
||||||
|
{
|
||||||
|
struct bt_mem *btmem;
|
||||||
|
|
||||||
|
btmem = &btDesc->btmem;
|
||||||
|
btmem->phys = BT_RAM_START;
|
||||||
|
btmem->reloc = BT_RAM_START;
|
||||||
|
btmem->size = BT_RAM_SIZE;
|
||||||
|
btmem->virt = (void __iomem *)BT_RAM_START;
|
||||||
|
|
||||||
|
btDesc->ipc.regmap = SYSCON;
|
||||||
|
btDesc->ipc.offset = 8;
|
||||||
|
btDesc->ipc.bit = 23;
|
||||||
|
atomic_set(&btDesc->state, 0);
|
||||||
|
atomic_set(&btDesc->tx_in_progress, 0);
|
||||||
|
}
|
||||||
|
|
@ -35,3 +35,9 @@ void i2c_clock_config(void)
|
||||||
}
|
}
|
||||||
#endif
|
#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
|
#ifdef CONFIG_QPIC_NAND
|
||||||
#include <asm/arch-qca-common/qpic_nand.h>
|
#include <asm/arch-qca-common/qpic_nand.h>
|
||||||
#endif
|
#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
|
#define DLOAD_MAGIC_COOKIE 0x10
|
||||||
|
|
||||||
|
|
@ -477,6 +483,180 @@ void fdt_fixup_auto_restart(void *blob)
|
||||||
return;
|
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)
|
void reset_crashdump(void)
|
||||||
{
|
{
|
||||||
unsigned int ret = 0;
|
unsigned int ret = 0;
|
||||||
|
|
@ -588,6 +768,9 @@ void board_nand_init(void)
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#ifdef CONFIG_IPQ_BT_SUPPORT
|
||||||
|
bt_init();
|
||||||
|
#endif
|
||||||
#ifdef CONFIG_QCA_SPI
|
#ifdef CONFIG_QCA_SPI
|
||||||
int gpio_node;
|
int gpio_node;
|
||||||
gpio_node = fdt_path_offset(gd->fdt_blob, "/spi/spi_gpio");
|
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_MAX_SIZE = SMEM_SPI_FLASH_ADDR_LEN + 1,
|
||||||
} smem_mem_type_t;
|
} 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_ */
|
#endif /* _IPQ5018_CDP_H_ */
|
||||||
|
|
|
||||||
|
|
@ -425,4 +425,6 @@ extern loff_t board_env_size;
|
||||||
|
|
||||||
#define INTERNAL_96MHZ
|
#define INTERNAL_96MHZ
|
||||||
|
|
||||||
|
/*#define CONFIG_IPQ_BT_SUPPORT*/
|
||||||
|
|
||||||
#endif /* _IPQ5018_H */
|
#endif /* _IPQ5018_H */
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue