2024-04-28 06:49:01 -07:00
|
|
|
/*
|
|
|
|
* Copyright (C) 2020, Samsung Electronics Co. Ltd. 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 as published by
|
|
|
|
* the Free Software Foundation; either version 2 of the License, or
|
|
|
|
* (at your option) any later version.
|
|
|
|
*
|
|
|
|
* 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 "../comm/shub_comm.h"
|
|
|
|
#include "../sensorhub/shub_device.h"
|
|
|
|
#include "../sensormanager/shub_sensor_type.h"
|
|
|
|
#include "../utility/shub_utility.h"
|
|
|
|
#include "../debug/shub_dump.h"
|
|
|
|
#include "shub_mtk.h"
|
|
|
|
|
|
|
|
#include <linux/delay.h>
|
|
|
|
#include <linux/notifier.h>
|
|
|
|
#include <linux/version.h>
|
|
|
|
|
|
|
|
#define IPI_SHUB IPI_SENSOR
|
|
|
|
#define IPI_DMA_LEN 8
|
|
|
|
|
|
|
|
static DEFINE_SPINLOCK(scp_state_lock);
|
|
|
|
static uint8_t scp_system_ready;
|
|
|
|
|
|
|
|
static phys_addr_t shub_dram_phys;
|
|
|
|
static phys_addr_t shub_dram_virt;
|
|
|
|
static phys_addr_t shub_dram_size;
|
|
|
|
#if !defined(CONFIG_MTK_TINYSYS_SCP_RV_SUPPORT) && (LINUX_VERSION_CODE <= KERNEL_VERSION(5, 0, 0))
|
|
|
|
void scp_wdt_reset(enum scp_core_id cpu_id);
|
|
|
|
#endif
|
|
|
|
|
|
|
|
static void sensorhub_IPI_handler(int id, void *packet, unsigned int len)
|
|
|
|
{
|
|
|
|
struct shub_data_t *data = get_shub_data();
|
|
|
|
|
|
|
|
if (!data->is_probe_done) {
|
|
|
|
shub_infof("shub is not working");
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (id == IPI_SHUB) {
|
|
|
|
if (len == IPI_DMA_LEN) {
|
|
|
|
uint32_t dma_info[2] = {0, }; /* address, size */
|
|
|
|
|
|
|
|
memcpy(dma_info, packet, len);
|
|
|
|
handle_packet((void *)(shub_dram_virt + dma_info[0]), dma_info[1]);
|
|
|
|
} else {
|
|
|
|
handle_packet(packet, len);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static int notify_scp_state(struct notifier_block *this, unsigned long event, void *ptr)
|
|
|
|
{
|
|
|
|
unsigned long flags = 0;
|
|
|
|
|
|
|
|
shub_infof("notify event %d", event);
|
|
|
|
|
|
|
|
if (event == SCP_EVENT_STOP) { // 1
|
|
|
|
spin_lock_irqsave(&scp_state_lock, flags);
|
|
|
|
WRITE_ONCE(scp_system_ready, false);
|
|
|
|
spin_unlock_irqrestore(&scp_state_lock, flags);
|
|
|
|
sensorhub_stop();
|
|
|
|
}
|
|
|
|
|
|
|
|
if (event == SCP_EVENT_READY) { // 0
|
|
|
|
spin_lock_irqsave(&scp_state_lock, flags);
|
|
|
|
WRITE_ONCE(scp_system_ready, true);
|
|
|
|
spin_unlock_irqrestore(&scp_state_lock, flags);
|
|
|
|
queue_refresh_task();
|
|
|
|
}
|
|
|
|
|
|
|
|
return NOTIFY_DONE;
|
|
|
|
}
|
|
|
|
|
|
|
|
static struct notifier_block scp_state_notifier = {
|
|
|
|
.notifier_call = notify_scp_state,
|
|
|
|
};
|
|
|
|
|
2024-04-28 06:51:13 -07:00
|
|
|
void shub_dump_write_file(void *dump_data, int dump_size)
|
|
|
|
{
|
|
|
|
struct shub_data_t *data = get_shub_data();
|
|
|
|
int dump_type;
|
|
|
|
|
|
|
|
if (!data) {
|
|
|
|
shub_infof("shub is not probed yet !");
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (data->reset_type < RESET_TYPE_MAX)
|
|
|
|
dump_type = DUMP_TYPE_BASE + data->reset_type;
|
|
|
|
else {
|
|
|
|
shub_errf("hub crash");
|
|
|
|
dump_type = 1;
|
|
|
|
data->hub_crash_timestamp = get_current_timestamp();
|
|
|
|
}
|
|
|
|
|
|
|
|
write_shub_dump_file((char *)dump_data, dump_size, dump_type, 4);
|
|
|
|
}
|
|
|
|
|
|
|
|
#if (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 19, 0))
|
|
|
|
static int shub_dump_notifier(struct notifier_block *nb, unsigned long val, void *data)
|
|
|
|
{
|
|
|
|
struct shub_data_t *shub_data = get_shub_data();
|
|
|
|
struct shub_dump *dump_data = (struct shub_dump *)data;
|
|
|
|
|
|
|
|
shub_infof("ram_dump : %x mini_dump : %x", dump_data->dump, dump_data->mini_dump);
|
|
|
|
shub_dump_write_file(dump_data->dump, dump_data->size);
|
|
|
|
memcpy(shub_data->mini_dump, dump_data->mini_dump, MINI_DUMP_LENGTH);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
struct notifier_block shub_dump_nb = {
|
|
|
|
.notifier_call = shub_dump_notifier,
|
|
|
|
};
|
|
|
|
#endif
|
|
|
|
|
2024-04-28 06:49:01 -07:00
|
|
|
int sensorhub_probe(void)
|
|
|
|
{
|
|
|
|
scp_ipi_registration(IPI_SHUB, sensorhub_IPI_handler, "shub_sensorhub");
|
|
|
|
scp_A_register_notify(&scp_state_notifier);
|
2024-04-28 06:51:13 -07:00
|
|
|
#if (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 19, 0))
|
|
|
|
shub_dump_notifier_register(&shub_dump_nb);
|
|
|
|
#endif
|
2024-04-28 06:49:01 -07:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
int sensorhub_shutdown(void)
|
|
|
|
{
|
|
|
|
scp_A_unregister_notify(&scp_state_notifier);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
int sensorhub_refresh_func(void)
|
|
|
|
{
|
|
|
|
int ret;
|
|
|
|
|
|
|
|
int dram_info[2];
|
|
|
|
shub_dram_phys = scp_get_reserve_mem_phys(SENS_MEM_ID);
|
|
|
|
shub_dram_virt = scp_get_reserve_mem_virt(SENS_MEM_ID);
|
|
|
|
shub_dram_size = scp_get_reserve_mem_size(SENS_MEM_ID);
|
|
|
|
|
|
|
|
dram_info[0] = shub_dram_phys;
|
|
|
|
dram_info[1] = shub_dram_size;
|
|
|
|
|
|
|
|
shub_infof("dma address phys 0x%llx virt 0x%llx size 0x%llx", shub_dram_phys, shub_dram_virt, shub_dram_size);
|
|
|
|
// ret = shub_send_command(CMD_SETVALUE, TYPE_HUB, DMA_ADDRESS, (char *)&shub_dram_phys, sizeof(shub_dram_phys));
|
|
|
|
ret = shub_send_command(CMD_SETVALUE, TYPE_HUB, DMA_ADDRESS, (char *)dram_info, sizeof(dram_info));
|
|
|
|
|
|
|
|
if (ret < 0)
|
|
|
|
shub_errf("DMA_ADDRESS CMD fail %d", ret);
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
int sensorhub_comms_write(u8 *buf, int length)
|
|
|
|
{
|
|
|
|
int status = 0, retry = 0;
|
|
|
|
|
|
|
|
do {
|
|
|
|
status = scp_ipi_send(IPI_SHUB, (unsigned char *)buf, length, 0, SCP_A_ID);
|
|
|
|
if (status == SCP_IPI_ERROR) {
|
|
|
|
shub_errf("scp_ipi_send fail");
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
if (status == SCP_IPI_BUSY) {
|
|
|
|
if (retry++ == 1000) {
|
|
|
|
shub_errf("retry fail");
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
if (retry % 100 == 0)
|
|
|
|
usleep_range(1000, 2000);
|
|
|
|
}
|
|
|
|
} while (status == SCP_IPI_BUSY);
|
|
|
|
|
|
|
|
return status;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool sensorhub_is_working(void)
|
|
|
|
{
|
|
|
|
struct shub_data_t *data = get_shub_data();
|
|
|
|
|
|
|
|
return READ_ONCE(scp_system_ready) && data->is_probe_done && !work_busy(&data->work_reset);
|
|
|
|
}
|
|
|
|
|
|
|
|
int sensorhub_reset(void)
|
|
|
|
{
|
|
|
|
scp_wdt_reset(SCP_A_ID);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
void sensorhub_fs_ready(void)
|
|
|
|
{
|
|
|
|
}
|
|
|
|
|
|
|
|
void sensorhub_save_ram_dump(void)
|
|
|
|
{
|
|
|
|
}
|
|
|
|
|
|
|
|
int sensorhub_get_dump_size(void)
|
|
|
|
{
|
|
|
|
int dump_size = get_scp_dump_size();
|
|
|
|
|
|
|
|
shub_infof("scp dump size : %d", dump_size);
|
|
|
|
|
|
|
|
return dump_size;
|
|
|
|
}
|