kernel-brax3-ubuntu-touch/drivers/gpu/mediatek/gpueb/gpueb_ipi.c
erascape f319b992b1 kernel-5.15: Initial import brax3 UT kernel
* halium configs enabled

Signed-off-by: erascape <erascape@proton.me>
2025-09-23 15:17:10 +00:00

488 lines
No EOL
12 KiB
C

// SPDX-License-Identifier: GPL-2.0
/*
* Copyright (C) 2019 MediaTek Inc.
*/
/**
* @file gpueb_ipi_init.c
* @brief IPI init flow for gpueb
*/
#include <linux/clk.h>
#include <linux/delay.h>
#include <linux/slab.h>
#include <linux/proc_fs.h>
#include <linux/platform_device.h>
#include <linux/regulator/consumer.h>
#include <linux/of.h>
#include <linux/of_address.h>
#include <linux/uaccess.h>
#include <linux/random.h>
#include <linux/seq_file.h>
#include <linux/pm_runtime.h>
#include <mboot_params.h>
#include "gpueb_ipi.h"
#include "gpueb_helper.h"
// MTK common IPI/MBOX
#include <linux/soc/mediatek/mtk_tinysys_ipi.h>
#include <linux/soc/mediatek/mtk-mbox.h>
struct mtk_mbox_device gpueb_mboxdev;
struct mtk_ipi_device gpueb_ipidev;
struct mtk_mbox_info *gpueb_mbox_info;
struct mtk_mbox_pin_send *gpueb_mbox_pin_send;
struct mtk_mbox_pin_recv *gpueb_mbox_pin_recv;
const char *gpueb_mbox_pin_send_name[20];
const char *gpueb_mbox_pin_recv_name[20];
unsigned int g_mbox_size = 0;
unsigned int g_slot_size = 0;
unsigned int g_ts_mbox;
#if IPI_TEST
struct test_msg {
int msg;
int padding[3];
} msg_tx[32], msg_rx[32];
#endif
static int gpueb_ipi_table_init(struct platform_device *pdev)
{
enum table_item_num {
send_item_num = 3,
recv_item_num = 4
};
int ret;
u32 i, mbox_id, recv_opt, pin_name_size, cnt_elems;
// Get MBOX num
of_property_read_u32(pdev->dev.of_node, "mbox_count",
&gpueb_mboxdev.count);
if (!gpueb_mboxdev.count) {
gpueb_pr_debug("mbox count not found\n");
return false;
}
// Get MBOX size
of_property_read_u32(pdev->dev.of_node, "mbox_size",
&g_mbox_size);
if (g_mbox_size == 0) {
gpueb_pr_debug("mbox size not found\n");
return false;
}
// Get SLOT size
of_property_read_u32(pdev->dev.of_node, "slot_size",
&g_slot_size);
if (g_slot_size == 0) {
gpueb_pr_debug("slot size not found\n");
return false;
}
// Get mbox for timesync
of_property_read_u32(pdev->dev.of_node, "ts_mbox",
&g_ts_mbox);
if (g_ts_mbox > gpueb_mboxdev.count) {
gpueb_pr_debug("ts_mbox(%d) > mbox_count(%d)\n",
g_ts_mbox, gpueb_mboxdev.count);
return false;
}
// Get send PIN num
cnt_elems = of_property_count_u32_elems(
pdev->dev.of_node, "send_table");
if (cnt_elems <= 0) {
gpueb_pr_debug("send table not found\n");
return false;
}
gpueb_mboxdev.send_count = cnt_elems / send_item_num;
// Get recv PIN num
cnt_elems = of_property_count_u32_elems(
pdev->dev.of_node, "recv_table");
if (cnt_elems <= 0) {
gpueb_pr_debug("recv table not found\n");
return false;
}
gpueb_mboxdev.recv_count = cnt_elems / recv_item_num;
// Get send PIN name
ret = of_property_read_string_array(pdev->dev.of_node,
"send_name_table",
gpueb_mbox_pin_send_name,
gpueb_mboxdev.send_count);
if (ret < 0) {
gpueb_pr_debug("Could not find send_name_table in dts\n");
return false;
}
// Check if #element in gpueb_mbox_pin_send_name is enough or not
pin_name_size = ARRAY_SIZE(gpueb_mbox_pin_send_name);
if (pin_name_size < gpueb_mboxdev.send_count) {
gpueb_pr_debug("gpueb_mbox_pin_send_name size(%d) smaller than send_count:%d\n",
pin_name_size, gpueb_mboxdev.send_count);
return false;
}
for (i = 0; i < gpueb_mboxdev.send_count; i++) {
gpueb_pr_debug("send_name_table[%d] = %s\n",
i, gpueb_mbox_pin_send_name[i]);
}
// Get recv PIN name
ret = of_property_read_string_array(pdev->dev.of_node,
"recv_name_table",
gpueb_mbox_pin_recv_name,
gpueb_mboxdev.recv_count);
if (ret < 0) {
gpueb_pr_debug("Could not find recv_name_table in dts\n");
return false;
}
// Check if #element in gpueb_mbox_pin_send_name is enough or not
pin_name_size = ARRAY_SIZE(gpueb_mbox_pin_recv_name);
if (pin_name_size < gpueb_mboxdev.recv_count) {
gpueb_pr_debug("gpueb_mbox_pin_recv_name size(%d) smaller than recv_count:%d\n",
pin_name_size, gpueb_mboxdev.recv_count);
return false;
}
for (i = 0; i < gpueb_mboxdev.recv_count; i++) {
gpueb_pr_debug("recv_name_table[%d] = %s\n",
i, gpueb_mbox_pin_recv_name[i]);
}
// Alloc and init mtk_mbox_info for GPUEB
gpueb_mboxdev.info_table = vzalloc(sizeof(struct mtk_mbox_info)
* gpueb_mboxdev.count);
if (!gpueb_mboxdev.info_table)
return false;
gpueb_mbox_info = gpueb_mboxdev.info_table;
for (i = 0; i < gpueb_mboxdev.count; i++) {
gpueb_mbox_info[i].id = i;
gpueb_mbox_info[i].slot = g_mbox_size;
gpueb_mbox_info[i].enable = 1;
gpueb_mbox_info[i].is64d = 0;
gpueb_mbox_info[i].opt = MBOX_OPT_SMEM;
}
// Alloc and init send PIN table
gpueb_mboxdev.pin_send_table = vzalloc(sizeof(struct mtk_mbox_pin_send)
* gpueb_mboxdev.send_count);
if (!gpueb_mboxdev.pin_send_table)
return false;
gpueb_mbox_pin_send = gpueb_mboxdev.pin_send_table;
for (i = 0; i < gpueb_mboxdev.send_count; i++) {
ret = of_property_read_u32_index(pdev->dev.of_node,
"send_table",
i * send_item_num,
&gpueb_mbox_pin_send[i].chan_id);
if (ret) {
gpueb_pr_debug("Cannot get ipi id (%d):%d\n", i, __LINE__);
return false;
}
gpueb_mbox_pin_send[i].pin_index = gpueb_mbox_pin_send[i].chan_id;
ret = of_property_read_u32_index(pdev->dev.of_node,
"send_table",
i * send_item_num + 1,
&mbox_id);
if (ret) {
gpueb_pr_debug("Cannot get mbox id (%d):%d\n", i, __LINE__);
return false;
}
// Because mbox and recv_opt is a bit-field
gpueb_mbox_pin_send[i].mbox = mbox_id;
ret = of_property_read_u32_index(pdev->dev.of_node,
"send_table",
i * send_item_num + 2,
&gpueb_mbox_pin_send[i].msg_size);
if (ret) {
gpueb_pr_debug("Cannot get pin size (%d):%d\n", i, __LINE__);
return false;
}
}
// Alloc and init recv PIN table
gpueb_mboxdev.pin_recv_table = vzalloc(sizeof(struct mtk_mbox_pin_recv)
* gpueb_mboxdev.recv_count);
if (!gpueb_mboxdev.pin_recv_table)
return false;
gpueb_mbox_pin_recv = gpueb_mboxdev.pin_recv_table;
for (i = 0; i < gpueb_mboxdev.recv_count; ++i) {
ret = of_property_read_u32_index(pdev->dev.of_node,
"recv_table",
i * recv_item_num,
&gpueb_mbox_pin_recv[i].chan_id);
if (ret) {
gpueb_pr_debug("Cannot get ipi id (%d):%d\n", i, __LINE__);
return false;
}
gpueb_mbox_pin_recv[i].pin_index = gpueb_mbox_pin_recv[i].chan_id;
ret = of_property_read_u32_index(pdev->dev.of_node,
"recv_table",
i * recv_item_num + 1,
&mbox_id);
if (ret) {
gpueb_pr_debug("Cannot get mbox id (%d):%d\n", i, __LINE__);
return false;
}
// Because mbox and recv_opt(0:receive ,1: response) is a bit-field
gpueb_mbox_pin_recv[i].mbox = mbox_id;
ret = of_property_read_u32_index(pdev->dev.of_node,
"recv_table",
i * recv_item_num + 2,
&gpueb_mbox_pin_recv[i].msg_size);
if (ret) {
gpueb_pr_debug("Cannot get pin size (%d):%d\n", i, __LINE__);
return false;
}
ret = of_property_read_u32_index(pdev->dev.of_node,
"recv_table",
i * recv_item_num + 3,
&recv_opt);
if (ret) {
gpueb_pr_debug("Cannot get recv opt (%d):%d\n", i, __LINE__);
return false;
}
/* because mbox and recv_opt is a bit-field */
gpueb_mbox_pin_recv[i].recv_opt = recv_opt;
}
return true;
}
void gpueb_mbox_setup_pin_table(unsigned int mbox)
{
unsigned int i;
int last_ofs = 0;
for (i = 0; i < gpueb_mboxdev.send_count; i++) {
if (mbox == gpueb_mbox_pin_send[i].mbox) {
gpueb_mbox_pin_send[i].offset = last_ofs;
last_ofs += gpueb_mbox_pin_send[i].msg_size;
}
}
for (i = 0; i < gpueb_mboxdev.recv_count; i++) {
if (mbox == gpueb_mbox_pin_recv[i].mbox) {
gpueb_mbox_pin_recv[i].offset = last_ofs;
last_ofs += gpueb_mbox_pin_recv[i].msg_size;
}
}
if (last_ofs > g_mbox_size)
gpueb_pr_debug("mbox%d exceed the maximum size\n", mbox);
return;
}
void gpueb_plat_ipi_timeout_cb(int ipi_id)
{
gpueb_pr_debug("Error: possible error IPI %d\n", ipi_id);
ipi_monitor_dump(&gpueb_ipidev);
//mtk_emidbg_dump();
//BUG_ON(1);
return;
}
int gpueb_ipi_init(struct platform_device *pdev)
{
int i = 0;
int ret;
ret = gpueb_ipi_table_init(pdev);
if (ret == 0)
return -ENODEV;
// Create mbox dev
gpueb_pr_debug("mbox probe start\n");
for (i = 0; i < gpueb_mboxdev.count; i++) {
gpueb_mbox_info[i].mbdev = &gpueb_mboxdev;
ret = mtk_mbox_probe(pdev, gpueb_mbox_info[i].mbdev, i);
if (ret < 0 || gpueb_mboxdev.info_table[i].irq_num < 0) {
gpueb_pr_debug("mbox%d probe fail, ret = %d\n", i, ret);
continue;
}
ret = enable_irq_wake(gpueb_mboxdev.info_table[i].irq_num);
if (ret < 0) {
gpueb_pr_debug("mbox%d enable irq fail, ret = %d\n", i, ret);
continue;
}
gpueb_mbox_setup_pin_table(i);
}
gpueb_ipidev.name = "gpueb_ipidev";
gpueb_ipidev.id = IPI_DEV_GPUEB;
gpueb_ipidev.mbdev = &gpueb_mboxdev;
gpueb_ipidev.timeout_handler = gpueb_plat_ipi_timeout_cb;
/* initialize mbox (share memory) */
for (i = 1; i < gpueb_mboxdev.count; i++) {
ret = mtk_smem_init(pdev, gpueb_mbox_info[i].mbdev, i,
gpueb_mbox_info[i].mbdev->info_table[i].base,
gpueb_mbox_info[i].mbdev->info_table[i].set_irq_reg,
gpueb_mbox_info[i].mbdev->info_table[i].clr_irq_reg,
gpueb_mbox_info[i].mbdev->info_table[i].send_status_reg,
gpueb_mbox_info[i].mbdev->info_table[i].recv_status_reg);
if (ret) {
gpueb_pr_debug("mbox%d smem init fali, ret = %d\n", i, ret);
return ret;
}
}
/*
* IPI device register
*
* It must be noted that the number of GPUEB's
* send pin and receive pin are the same.
* If you need specific design on it, you must adjust
* the registered ipi num to the big one.
*/
ret = mtk_ipi_device_register(
&gpueb_ipidev,
pdev,
&gpueb_mboxdev,
gpueb_mboxdev.send_count);
if (ret != IPI_ACTION_DONE) {
gpueb_pr_debug("ipi devcie register fail!");
return ret;
}
gpueb_pr_debug("mbox probe done\n");
#if IPI_TEST
ret = gpueb_ipi_test_init();
if (ret) {
gpueb_pr_info("@%s: fail to init ipi register (%d)\n", __func__, ret);
WARN_ON(1);
return ret;
}
#endif
return 0;
}
#if IPI_TEST
int gpueb_ipi_test_init(void)
{
int ret = 0;
int ipi = 0;
unsigned int ipi_count = gpueb_mboxdev.send_count;
/* Register IPI channel */
for (ipi = 0; ipi < ipi_count; ipi++) {
ret = mtk_ipi_register(&gpueb_ipidev,
ipi,
NULL,
NULL,
(void *)&msg_rx[ipi]);
if (ret != IPI_ACTION_DONE) {
gpueb_pr_debug("%s: ipi:#%d register fail! ret = %d\n",
__func__, ipi, ret);
if (ret == IPI_DUPLEX) {
/* ipi already registered, unregister it and register again */
gpueb_pr_debug("%s: ipi:#%d register: IPI_DUPLEX\n",
__func__, ipi);
ret = mtk_ipi_unregister(&gpueb_ipidev, ipi);
if (ret != IPI_ACTION_DONE) {
gpueb_pr_debug("%s: ipi:#%d unregister fail! ret = %d\n",
__func__, ipi, ret);
break;
}
ret = mtk_ipi_register(&gpueb_ipidev, ipi, NULL, NULL,
(void *)&msg_rx[ipi]);
if (ret != IPI_ACTION_DONE) {
gpueb_pr_debug("%s: ipi:#%d register fail again! ret = %d\n",
__func__, ipi, ret);
break;
}
} else {
break;
}
}
}
return ret;
}
int gpueb_ipi_send_compl_test(int ipi, int msg)
{
int ret = 0;
/* Test mtk_ipi_send_compl */
msg_tx[ipi].msg = msg;
gpueb_pr_debug("%s: ipi:#%d mtk_ipi_send_compl data: %d\n",
__func__, ipi, msg_tx[ipi].msg);
ret = mtk_ipi_send_compl(
&gpueb_ipidev, // GPUEB's IPI device
ipi, // Send channel
0, // 0: wait, 1: polling
(void *)&msg_tx[ipi], // Send data
1, // 1 slot message = 1 * 4 = 4 bytes
IPI_TIMEOUT_MS); // Timeout value in milisecond
if (ret != IPI_ACTION_DONE) {
gpueb_pr_info("%s: IPI fail ret=%d\n", __func__, ret);
return ret;
}
gpueb_pr_debug("%s: ipi:#%d ack data: %d\n",
__func__, ipi, msg_rx[ipi].msg);
return msg_rx[ipi].msg;
}
int gpueb_get_send_pin_count(void)
{
return gpueb_mboxdev.send_count;
}
#endif
unsigned int gpueb_get_ts_mbox(void)
{
return g_ts_mbox;
}
int gpueb_get_send_PIN_offset_by_name(char *send_PIN_name)
{
int i;
for (i = 0; i < gpueb_mboxdev.send_count; i++) {
if (!strcmp(gpueb_mbox_pin_send_name[i], send_PIN_name))
return gpueb_mbox_pin_send[i].offset;
}
return -1;
}
int gpueb_get_send_PIN_ID_by_name(char *send_PIN_name)
{
int i;
for (i = 0; i < gpueb_mboxdev.send_count; i++) {
if (!strcmp(gpueb_mbox_pin_send_name[i], send_PIN_name))
return gpueb_mbox_pin_send[i].chan_id;
}
return -1;
}
EXPORT_SYMBOL_GPL(gpueb_get_send_PIN_ID_by_name);
int gpueb_get_recv_PIN_ID_by_name(char *recv_PIN_name)
{
int i;
for (i = 0; i < gpueb_mboxdev.recv_count; i++) {
if (!strcmp(gpueb_mbox_pin_recv_name[i], recv_PIN_name))
return gpueb_mbox_pin_recv[i].chan_id;
}
return -1;
}
EXPORT_SYMBOL_GPL(gpueb_get_recv_PIN_ID_by_name);
void *get_gpueb_ipidev(void)
{
return &gpueb_ipidev;
}
EXPORT_SYMBOL_GPL(get_gpueb_ipidev);