From 884142dddaf03302b325226720df52ff5fcb5789 Mon Sep 17 00:00:00 2001 From: Akash Asthana Date: Thu, 29 Oct 2020 15:46:01 +0530 Subject: [PATCH] msm: msm-geni-se: Add proxy votes to fix earlycon crash QUP core clock is shared among all the SE drivers present on particular QUP wrapper, the system will reset(unclocked access) if earlycon used after QUP core clock is put to 0 from other SE drivers before real console comes up. As earlycon can't vote for it's QUP core need, to fix this put vote for QUP core from common driver probe on behalf of earlycon and remove vote during real console probe after uart_add_one_port call because by this time real console is up and voted for it's resources. Change-Id: I4362fec8ef798de30beae4d608626ae409607b84 Signed-off-by: Akash Asthana --- drivers/platform/msm/msm-geni-se.c | 54 ++++++++++++++++++++++++++++ drivers/tty/serial/msm_geni_serial.c | 10 ++++++ include/linux/msm-geni-se.h | 6 ++++ 3 files changed, 70 insertions(+) diff --git a/drivers/platform/msm/msm-geni-se.c b/drivers/platform/msm/msm-geni-se.c index b5d5aa995cbe..83a25efdc62b 100644 --- a/drivers/platform/msm/msm-geni-se.c +++ b/drivers/platform/msm/msm-geni-se.c @@ -103,6 +103,7 @@ struct geni_se_device { struct bus_vectors *vectors; int num_paths; bool vote_for_bw; + struct se_geni_rsc wrapper_rsc; }; #define HW_VER_MAJOR_MASK GENMASK(31, 28) @@ -1642,6 +1643,34 @@ out: return NULL; } +void geni_se_remove_earlycon_icc_vote(struct device *dev) +{ + struct platform_device *pdev; + struct device_node *parent; + struct device_node *child; + struct geni_se_device *geni_se_dev; + int ret; + + parent = of_get_next_parent(dev->of_node); + for_each_child_of_node(parent, child) { + if (!of_device_is_compatible(child, "qcom,qupv3-geni-se")) + continue; + + pdev = of_find_device_by_node(child); + if (!pdev) + continue; + + geni_se_dev = platform_get_drvdata(pdev); + ret = geni_se_rmv_ab_ib(geni_se_dev, &geni_se_dev->wrapper_rsc); + + if (ret) + dev_err(dev, "%s: Error %d during bus_bw_update\n", __func__, + ret); + } + of_node_put(parent); +} +EXPORT_SYMBOL(geni_se_remove_earlycon_icc_vote); + static int geni_se_iommu_probe(struct device *dev) { struct geni_se_device *geni_se_dev; @@ -1731,6 +1760,31 @@ static int geni_se_probe(struct platform_device *pdev) dev_set_drvdata(dev, geni_se_dev); + /* + * TBD: Proxy vote on QUP core path on behalf of earlycon. + * Once the ICC sync state feature is implemented, we can make + * console UART as dummy consumer of ICC to get rid of this HACK + */ +#if IS_ENABLED(CONFIG_SERIAL_MSM_GENI_CONSOLE) + geni_se_dev->wrapper_rsc.wrapper_dev = dev; + geni_se_dev->wrapper_rsc.ctrl_dev = dev; + + ret = geni_se_resources_init(&geni_se_dev->wrapper_rsc, + UART_CONSOLE_CORE2X_VOTE, + (DEFAULT_SE_CLK * DEFAULT_BUS_WIDTH)); + if (ret) { + dev_err(dev, "Resources init failed: %d\n", ret); + return ret; + } + + ret = geni_se_add_ab_ib(geni_se_dev, &geni_se_dev->wrapper_rsc); + if (ret) { + dev_err(dev, "%s: Error %d during bus_bw_update\n", __func__, + ret); + return ret; + } +#endif + ret = of_platform_populate(dev->of_node, geni_se_dt_match, NULL, dev); if (ret) { dev_err(dev, "%s: Error populating children\n", __func__); diff --git a/drivers/tty/serial/msm_geni_serial.c b/drivers/tty/serial/msm_geni_serial.c index 37dd85279f8c..71bfd5b9811d 100644 --- a/drivers/tty/serial/msm_geni_serial.c +++ b/drivers/tty/serial/msm_geni_serial.c @@ -3168,6 +3168,16 @@ static int msm_geni_serial_probe(struct platform_device *pdev) } ret = uart_add_one_port(drv, uport); + if (ret) + dev_err(&pdev->dev, "Failed to register uart_port: %d\n", + ret); + /* + * Remove proxy vote from QUP core which was kept from common driver + * probe on behalf of earlycon + */ + if (uart_console(uport)) + geni_se_remove_earlycon_icc_vote(dev_port->wrapper_dev); + exit_geni_serial_probe: IPC_LOG_MSG(dev_port->ipc_log_misc, "%s: ret:%d\n", __func__, ret); diff --git a/include/linux/msm-geni-se.h b/include/linux/msm-geni-se.h index e8355caf1631..5b5de47d6d34 100644 --- a/include/linux/msm-geni-se.h +++ b/include/linux/msm-geni-se.h @@ -823,6 +823,12 @@ int geni_se_iommu_free_buf(struct device *wrapper_dev, dma_addr_t *iova, */ void geni_se_dump_dbg_regs(struct se_geni_rsc *rsc, void __iomem *base, void *ipc); + +/* + * This function is used to remove proxy ICC BW vote put from common driver + * probe on behalf of earlycon usecase. + */ +void geni_se_remove_earlycon_icc_vote(struct device *dev); #else static inline unsigned int geni_read_reg_nolog(void __iomem *base, int offset) {