diff --git a/arch/riscv/boot/dts/thead/th1520-lichee-pi-4a.dts b/arch/riscv/boot/dts/thead/th1520-lichee-pi-4a.dts index 0e3d7535cf5af..d5e4cdca1afa1 100644 --- a/arch/riscv/boot/dts/thead/th1520-lichee-pi-4a.dts +++ b/arch/riscv/boot/dts/thead/th1520-lichee-pi-4a.dts @@ -518,6 +518,10 @@ status = "okay"; }; +&aon { + log-memory-region = <&aon_log_mem>; + status = "okay"; +}; &resmem { #address-cells = <2>; @@ -541,5 +545,8 @@ rpmsgmem: memory@1E000000 { reg = <0x0 0x1E000000 0x0 0x10000>; }; + aon_log_mem: memory@33600000 { + reg = <0x0 0x33600000 0x0 0x200000>; + }; }; \ No newline at end of file diff --git a/arch/riscv/boot/dts/thead/th1520.dtsi b/arch/riscv/boot/dts/thead/th1520.dtsi index ac44d83e486d2..bd37103542d58 100644 --- a/arch/riscv/boot/dts/thead/th1520.dtsi +++ b/arch/riscv/boot/dts/thead/th1520.dtsi @@ -266,7 +266,7 @@ snps,blen = <0 0 64 32 0 0 0>; }; - aon { + aon: aon_subsys { compatible = "thead,th1520-aon"; mbox-names = "aon"; mboxes = <&mbox_910t 1 0>; diff --git a/drivers/firmware/thead/th1520_aon.c b/drivers/firmware/thead/th1520_aon.c index c12e047210f93..66b66036bc3f0 100644 --- a/drivers/firmware/thead/th1520_aon.c +++ b/drivers/firmware/thead/th1520_aon.c @@ -16,11 +16,12 @@ #include #include #include +#include #include /* wait for response for 3000ms instead of 300ms (fix me pls)*/ -#define MAX_RX_TIMEOUT (msecs_to_jiffies(3000)) -#define MAX_TX_TIMEOUT (msecs_to_jiffies(500)) +#define MAX_RX_TIMEOUT (msecs_to_jiffies(3000)) +#define MAX_TX_TIMEOUT (msecs_to_jiffies(500)) struct th1520_aon_chan { struct th1520_aon_ipc *aon_ipc; @@ -28,6 +29,12 @@ struct th1520_aon_chan { struct mbox_client cl; struct mbox_chan *ch; struct completion tx_done; + /*for log proc*/ + phys_addr_t log_phy; + size_t log_size; + void __iomem *log_mem; + void *log_ctrl; + struct proc_dir_entry *proc_dir; }; struct th1520_aon_ipc { @@ -42,23 +49,23 @@ struct th1520_aon_ipc { * This type is used to indicate error response for most functions. */ enum th1520_aon_error_codes { - TH1520_AON_ERR_NONE = 0, /* Success */ - TH1520_AON_ERR_VERSION = 1, /* Incompatible API version */ - TH1520_AON_ERR_CONFIG = 2, /* Configuration error */ - TH1520_AON_ERR_PARM = 3, /* Bad parameter */ - TH1520_AON_ERR_NOACCESS = 4, /* Permission error (no access) */ - TH1520_AON_ERR_LOCKED = 5, /* Permission error (locked) */ - TH1520_AON_ERR_UNAVAILABLE = 6, /* Unavailable (out of resources) */ - TH1520_AON_ERR_NOTFOUND = 7, /* Not found */ - TH1520_AON_ERR_NOPOWER = 8, /* No power */ - TH1520_AON_ERR_IPC = 9, /* Generic IPC error */ - TH1520_AON_ERR_BUSY = 10, /* Resource is currently busy/active */ - TH1520_AON_ERR_FAIL = 11, /* General I/O failure */ + TH1520_AON_ERR_NONE = 0, /* Success */ + TH1520_AON_ERR_VERSION = 1, /* Incompatible API version */ + TH1520_AON_ERR_CONFIG = 2, /* Configuration error */ + TH1520_AON_ERR_PARM = 3, /* Bad parameter */ + TH1520_AON_ERR_NOACCESS = 4, /* Permission error (no access) */ + TH1520_AON_ERR_LOCKED = 5, /* Permission error (locked) */ + TH1520_AON_ERR_UNAVAILABLE = 6, /* Unavailable (out of resources) */ + TH1520_AON_ERR_NOTFOUND = 7, /* Not found */ + TH1520_AON_ERR_NOPOWER = 8, /* No power */ + TH1520_AON_ERR_IPC = 9, /* Generic IPC error */ + TH1520_AON_ERR_BUSY = 10, /* Resource is currently busy/active */ + TH1520_AON_ERR_FAIL = 11, /* General I/O failure */ TH1520_AON_ERR_LAST }; static int th1520_aon_linux_errmap[TH1520_AON_ERR_LAST] = { - 0, /* TH1520_AON_ERR_NONE */ + 0, /* TH1520_AON_ERR_NONE */ -EINVAL, /* TH1520_AON_ERR_VERSION */ -EINVAL, /* TH1520_AON_ERR_CONFIG */ -EINVAL, /* TH1520_AON_ERR_PARM */ @@ -66,10 +73,10 @@ static int th1520_aon_linux_errmap[TH1520_AON_ERR_LAST] = { -EACCES, /* TH1520_AON_ERR_LOCKED */ -ERANGE, /* TH1520_AON_ERR_UNAVAILABLE */ -EEXIST, /* TH1520_AON_ERR_NOTFOUND */ - -EPERM, /* TH1520_AON_ERR_NOPOWER */ - -EPIPE, /* TH1520_AON_ERR_IPC */ - -EBUSY, /* TH1520_AON_ERR_BUSY */ - -EIO, /* TH1520_AON_ERR_FAIL */ + -EPERM, /* TH1520_AON_ERR_NOPOWER */ + -EPIPE, /* TH1520_AON_ERR_IPC */ + -EBUSY, /* TH1520_AON_ERR_BUSY */ + -EIO, /* TH1520_AON_ERR_FAIL */ }; static struct th1520_aon_ipc *th1520_aon_ipc_handle; @@ -107,13 +114,13 @@ static void th1520_aon_rx_callback(struct mbox_client *c, void *msg) struct th1520_aon_chan *aon_chan = container_of(c, struct th1520_aon_chan, cl); struct th1520_aon_ipc *aon_ipc = aon_chan->aon_ipc; - struct th1520_aon_rpc_msg_hdr* hdr = - (struct th1520_aon_rpc_msg_hdr*)msg; - uint8_t recv_size = sizeof(struct th1520_aon_rpc_msg_hdr) + hdr->size; + struct th1520_aon_rpc_msg_hdr *hdr = + (struct th1520_aon_rpc_msg_hdr *)msg; + uint8_t recv_size = sizeof(struct th1520_aon_rpc_msg_hdr) + hdr->size; memcpy(aon_ipc->msg, msg, recv_size); - dev_dbg(aon_ipc->dev, "msg head: 0x%x, size:%d\n", - *((u32 *)msg), recv_size); + dev_dbg(aon_ipc->dev, "msg head: 0x%x, size:%d\n", *((u32 *)msg), + recv_size); complete(&aon_ipc->done); } @@ -133,8 +140,7 @@ static int th1520_aon_ipc_write(struct th1520_aon_ipc *aon_ipc, void *msg) aon_chan = &aon_ipc->chans; - if (!wait_for_completion_timeout(&aon_chan->tx_done, - MAX_TX_TIMEOUT)) { + if (!wait_for_completion_timeout(&aon_chan->tx_done, MAX_TX_TIMEOUT)) { dev_err(aon_ipc->dev, "tx_done timeout\n"); return -ETIMEDOUT; } @@ -150,8 +156,8 @@ static int th1520_aon_ipc_write(struct th1520_aon_ipc *aon_ipc, void *msg) /* * RPC command/response */ -int th1520_aon_call_rpc(struct th1520_aon_ipc *aon_ipc, - void *msg, void *ack_msg, bool have_resp) +int th1520_aon_call_rpc(struct th1520_aon_ipc *aon_ipc, void *msg, + void *ack_msg, bool have_resp) { struct th1520_aon_rpc_msg_hdr *hdr = msg; int ret = 0; @@ -159,8 +165,8 @@ int th1520_aon_call_rpc(struct th1520_aon_ipc *aon_ipc, if (WARN_ON(!aon_ipc || !msg)) return -EINVAL; - if(have_resp && WARN_ON(!ack_msg)) - return -EINVAL; + if (have_resp && WARN_ON(!ack_msg)) + return -EINVAL; mutex_lock(&aon_ipc->lock); reinit_completion(&aon_ipc->done); @@ -169,8 +175,8 @@ int th1520_aon_call_rpc(struct th1520_aon_ipc *aon_ipc, RPC_SET_SVC_ID(hdr, hdr->svc); RPC_SET_SVC_FLAG_MSG_TYPE(hdr, RPC_SVC_MSG_TYPE_DATA); - if (have_resp){ - aon_ipc->msg = ack_msg; + if (have_resp) { + aon_ipc->msg = ack_msg; RPC_SET_SVC_FLAG_ACK_TYPE(hdr, RPC_SVC_MSG_NEED_ACK); } else { RPC_SET_SVC_FLAG_ACK_TYPE(hdr, RPC_SVC_MSG_NO_NEED_ACK); @@ -191,7 +197,7 @@ int th1520_aon_call_rpc(struct th1520_aon_ipc *aon_ipc, } /* response status is stored in msg data[0] field */ - struct th1520_aon_rpc_ack_common* ack = ack_msg; + struct th1520_aon_rpc_ack_common *ack = ack_msg; ret = ack->err_code; } @@ -204,12 +210,39 @@ int th1520_aon_call_rpc(struct th1520_aon_ipc *aon_ipc, } EXPORT_SYMBOL(th1520_aon_call_rpc); +int get_aon_log_mem(struct device *dev, phys_addr_t *mem, size_t *mem_size) +{ + struct resource r; + struct device_node *node; + int ret; + + *mem = 0; + *mem_size = 0; + + node = of_parse_phandle(dev->of_node, "log-memory-region", 0); + if (!node) { + dev_err(dev, "no memory-region specified\n"); + return -EINVAL; + } + + ret = of_address_to_resource(node, 0, &r); + if (ret) { + dev_err(dev, "memory-region get resource faild\n"); + return -EINVAL; + } + + *mem = r.start; + *mem_size = resource_size(&r); + return 0; +} + static int th1520_aon_probe(struct platform_device *pdev) { struct device *dev = &pdev->dev; struct th1520_aon_ipc *aon_ipc; struct th1520_aon_chan *aon_chan; struct mbox_client *cl; + char dir_name[32] = { 0x0 }; int ret; aon_ipc = devm_kzalloc(dev, sizeof(*aon_ipc), GFP_KERNEL); @@ -233,8 +266,8 @@ static int th1520_aon_probe(struct platform_device *pdev) if (IS_ERR(aon_chan->ch)) { ret = PTR_ERR(aon_chan->ch); if (ret != -EPROBE_DEFER) - dev_err(dev, - "Failed to request aon mbox chan ret %d\n", ret); + dev_err(dev, "Failed to request aon mbox chan ret %d\n", + ret); return ret; } @@ -243,14 +276,40 @@ static int th1520_aon_probe(struct platform_device *pdev) aon_ipc->dev = dev; mutex_init(&aon_ipc->lock); init_completion(&aon_ipc->done); + aon_chan->log_ctrl = NULL; + + ret = get_aon_log_mem(dev, &aon_chan->log_phy, &aon_chan->log_size); + if (ret) { + return ret; + } + aon_chan->log_mem = ioremap(aon_chan->log_phy, aon_chan->log_size); + if (!IS_ERR(aon_chan->log_mem)) { + pr_info("virtual_log_mem=0x%p, phy base=0x%pa\n",aon_chan->log_mem, &aon_chan->log_phy); + } else { + aon_chan->log_mem = NULL; + dev_err(dev, "%s:get aon log region fail\n", __func__); + return -1; + } + sprintf(dir_name, "aon_proc"); + aon_chan->proc_dir = proc_mkdir(dir_name, NULL); + if (NULL != aon_chan->proc_dir) { + aon_chan->log_ctrl = th1520_create_panic_log_proc( + aon_chan->log_phy, aon_chan->proc_dir, + aon_chan->log_mem, aon_chan->log_size); + } else { + dev_err(dev, "create %s fail\n", dir_name); + return ret; + } th1520_aon_ipc_handle = aon_ipc; return devm_of_platform_populate(dev); } static const struct of_device_id th1520_aon_match[] = { - { .compatible = "thead,th1520-aon", }, + { + .compatible = "thead,th1520-aon", + }, { /* Sentinel */ } }; @@ -265,8 +324,7 @@ static int __maybe_unused th1520_aon_resume_noirq(struct device *dev) } static const struct dev_pm_ops th1520_aon_pm_ops = { - SET_NOIRQ_SYSTEM_SLEEP_PM_OPS(NULL, - th1520_aon_resume_noirq) + SET_NOIRQ_SYSTEM_SLEEP_PM_OPS(NULL, th1520_aon_resume_noirq) }; static struct platform_driver th1520_aon_driver = { .driver = {